[
  {
    "path": ".buildpacks",
    "content": "https://github.com/heroku/heroku-buildpack-apt\nhttps://github.com/Scalingo/ffmpeg-buildpack\nhttps://github.com/Scalingo/nodejs-buildpack\nhttps://github.com/Scalingo/ruby-buildpack\n"
  },
  {
    "path": ".circleci/config.yml",
    "content": "version: 2\n\naliases:\n  - &defaults\n    docker:\n      - image: circleci/ruby:2.6.0-stretch-node\n        environment: &ruby_environment\n          BUNDLE_APP_CONFIG: ./.bundle/\n          DB_HOST: localhost\n          DB_USER: root\n          RAILS_ENV: test\n          PARALLEL_TEST_PROCESSORS: 4\n          ALLOW_NOPAM: true\n          CONTINUOUS_INTEGRATION: true\n          DISABLE_SIMPLECOV: true\n          PAM_ENABLED: true\n          PAM_DEFAULT_SERVICE: pam_test\n          PAM_CONTROLLED_SERVICE: pam_test_controlled\n    working_directory: ~/projects/mastodon/\n\n  - &attach_workspace\n    attach_workspace:\n      at: ~/projects/\n\n  - &persist_to_workspace\n    persist_to_workspace:\n      root: ~/projects/\n      paths:\n        - ./mastodon/\n\n  - &restore_ruby_dependencies\n    restore_cache:\n      keys:\n        - v2-ruby-dependencies-{{ checksum \"/tmp/.ruby-version\" }}-{{ checksum \"Gemfile.lock\" }}\n        - v2-ruby-dependencies-{{ checksum \"/tmp/.ruby-version\" }}-\n        - v2-ruby-dependencies-\n\n  - &install_steps\n    steps:\n      - checkout\n      - *attach_workspace\n\n      - restore_cache:\n          keys:\n            - v1-node-dependencies-{{ checksum \"yarn.lock\" }}\n            - v1-node-dependencies-\n      - run: yarn install --frozen-lockfile\n      - save_cache:\n          key: v1-node-dependencies-{{ checksum \"yarn.lock\" }}\n          paths:\n            - ./node_modules/\n\n      - *persist_to_workspace\n\n  - &install_system_dependencies\n      run:\n        name: Install system dependencies\n        command: |\n          sudo apt-get update\n          sudo apt-get install -y libicu-dev libidn11-dev libprotobuf-dev protobuf-compiler\n\n  - &install_ruby_dependencies\n      steps:\n        - *attach_workspace\n\n        - *install_system_dependencies\n\n        - run: ruby -e 'puts RUBY_VERSION' | tee /tmp/.ruby-version\n        - *restore_ruby_dependencies\n        - run: bundle install --clean --jobs 16 --path ./vendor/bundle/ --retry 3 --with pam_authentication --without development production && bundle clean\n        - save_cache:\n            key: v2-ruby-dependencies-{{ checksum \"/tmp/.ruby-version\" }}-{{ checksum \"Gemfile.lock\" }}\n            paths:\n              - ./.bundle/\n              - ./vendor/bundle/\n        - persist_to_workspace:\n            root: ~/projects/\n            paths:\n                - ./mastodon/.bundle/\n                - ./mastodon/vendor/bundle/\n\n  - &test_steps\n      steps:\n        - *attach_workspace\n\n        - *install_system_dependencies\n        - run: sudo apt-get install -y ffmpeg\n\n        - run:\n            name: Prepare Tests\n            command: ./bin/rails parallel:create parallel:load_schema parallel:prepare\n        - run:\n            name: Run Tests\n            command: ./bin/retry bundle exec parallel_test ./spec/ --group-by filesize --type rspec\n\njobs:\n  install:\n    <<: *defaults\n    <<: *install_steps\n\n  install-ruby2.6:\n    <<: *defaults\n    <<: *install_ruby_dependencies\n\n  install-ruby2.5:\n    <<: *defaults\n    docker:\n      - image: circleci/ruby:2.5.3-stretch-node\n        environment: *ruby_environment\n    <<: *install_ruby_dependencies\n\n  install-ruby2.4:\n    <<: *defaults\n    docker:\n      - image: circleci/ruby:2.4.5-stretch-node\n        environment: *ruby_environment\n    <<: *install_ruby_dependencies\n\n  build:\n    <<: *defaults\n    steps:\n      - *attach_workspace\n      - *install_system_dependencies\n      - run: ./bin/rails assets:precompile\n      - persist_to_workspace:\n          root: ~/projects/\n          paths:\n              - ./mastodon/public/assets\n              - ./mastodon/public/packs-test/\n\n  test-ruby2.6:\n    <<: *defaults\n    docker:\n      - image: circleci/ruby:2.6.0-stretch-node\n        environment: *ruby_environment\n      - image: circleci/postgres:10.6-alpine\n        environment:\n          POSTGRES_USER: root\n      - image: circleci/redis:5.0.3-alpine3.8\n    <<: *test_steps\n\n  test-ruby2.5:\n    <<: *defaults\n    docker:\n      - image: circleci/ruby:2.5.3-stretch-node\n        environment: *ruby_environment\n      - image: circleci/postgres:10.6-alpine\n        environment:\n          POSTGRES_USER: root\n      - image: circleci/redis:4.0.12-alpine\n    <<: *test_steps\n\n  test-ruby2.4:\n    <<: *defaults\n    docker:\n      - image: circleci/ruby:2.4.5-stretch-node\n        environment: *ruby_environment\n      - image: circleci/postgres:10.6-alpine\n        environment:\n          POSTGRES_USER: root\n      - image: circleci/redis:4.0.12-alpine\n    <<: *test_steps\n\n  test-webui:\n    <<: *defaults\n    docker:\n      - image: circleci/node:8.15.0-stretch\n    steps:\n      - *attach_workspace\n      - run: ./bin/retry yarn test:jest\n\n  check-i18n:\n    <<: *defaults\n    steps:\n      - *attach_workspace\n      - run: bundle exec i18n-tasks check-normalized\n      - run: bundle exec i18n-tasks unused -l en\n      - run: bundle exec i18n-tasks check-consistent-interpolations\n\nworkflows:\n  version: 2\n  build-and-test:\n    jobs:\n      - install\n      - install-ruby2.6:\n          requires:\n            - install\n      - install-ruby2.5:\n          requires:\n            - install\n            - install-ruby2.6\n      - install-ruby2.4:\n          requires:\n            - install\n            - install-ruby2.6\n      - build:\n          requires:\n            - install-ruby2.6\n      - test-ruby2.6:\n          requires:\n            - install-ruby2.6\n            - build\n      - test-ruby2.5:\n          requires:\n            - install-ruby2.5\n            - build\n      - test-ruby2.4:\n          requires:\n            - install-ruby2.4\n            - build\n      - test-webui:\n          requires:\n            - install\n      - check-i18n:\n          requires:\n            - install-ruby2.6\n"
  },
  {
    "path": ".codeclimate.yml",
    "content": "version: \"2\"\nchecks:\n  argument-count:\n    enabled: false\n  complex-logic:\n    enabled: false\n  file-lines:\n    enabled: false\n  method-complexity:\n    enabled: false\n  method-count:\n    enabled: false\n  method-lines:\n    enabled: false\n  nested-control-flow:\n    enabled: false\n  return-statements:\n    enabled: false\n  similar-code:\n    enabled: false\n  identical-code:\n    enabled: false\nplugins:\n  brakeman:\n    enabled: true\n  bundler-audit:\n    enabled: true\n  eslint:\n    enabled: true\n    channel: eslint-5\n  rubocop:\n    enabled: true\n    channel: rubocop-0-71\n  sass-lint:\n    enabled: true\nexclude_patterns:\n- spec/\n- vendor/asset\n"
  },
  {
    "path": ".dependabot/config.yml",
    "content": "version: 1\n\nupdate_configs:\n  - package_manager: \"ruby:bundler\"\n    directory: \"/\"\n    update_schedule: \"weekly\"\n\n  - package_manager: \"javascript\"\n    directory: \"/\"\n    update_schedule: \"weekly\"\n"
  },
  {
    "path": ".dockerignore",
    "content": ".bundle\n.env\n.env.*\npublic/system\npublic/assets\npublic/packs\nnode_modules\nneo4j\nvendor/bundle\n.DS_Store\n*.swp\n*~\npostgres\nredis\nelasticsearch\n"
  },
  {
    "path": ".editorconfig",
    "content": "# EditorConfig is awesome: http://EditorConfig.org\n\n# top-most EditorConfig file\nroot = true\n\n# Unix-style newlines with a newline ending every file\n[*]\nend_of_line = lf\ninsert_final_newline = true\ncharset = utf-8\nindent_style = space\nindent_size = 2\n"
  },
  {
    "path": ".eslintignore",
    "content": "/build/**\n/coverage/**\n/db/**\n/lib/**\n/log/**\n/node_modules/**\n/nonobox/**\n/public/**\n!/public/embed.js\n/spec/**\n/tmp/**\n/vendor/**\n!.eslintrc.js\n"
  },
  {
    "path": ".eslintrc.js",
    "content": "module.exports = {\n  root: true,\n\n  env: {\n    browser: true,\n    node: true,\n    es6: true,\n    jest: true,\n  },\n\n  globals: {\n    ATTACHMENT_HOST: false,\n  },\n\n  parser: 'babel-eslint',\n\n  plugins: [\n    'react',\n    'jsx-a11y',\n    'import',\n    'promise',\n  ],\n\n  parserOptions: {\n    sourceType: 'module',\n    ecmaFeatures: {\n      experimentalObjectRestSpread: true,\n      jsx: true,\n    },\n    ecmaVersion: 2018,\n  },\n\n  settings: {\n    react: {\n      version: 'detect',\n    },\n    'import/extensions': [\n      '.js',\n    ],\n    'import/ignore': [\n      'node_modules',\n      '\\\\.(css|scss|json)$',\n    ],\n    'import/resolver': {\n      node: {\n        paths: ['app/javascript'],\n      },\n    },\n  },\n\n  rules: {\n    'brace-style': 'warn',\n    'comma-dangle': ['error', 'always-multiline'],\n    'comma-spacing': [\n      'warn',\n      {\n        before: false,\n        after: true,\n      },\n    ],\n    'comma-style': ['warn', 'last'],\n    'consistent-return': 'error',\n    'dot-notation': 'error',\n    eqeqeq: 'error',\n    indent: ['warn', 2],\n    'jsx-quotes': ['error', 'prefer-single'],\n    'no-catch-shadow': 'error',\n    'no-cond-assign': 'error',\n    'no-console': [\n      'warn',\n      {\n        allow: [\n          'error',\n          'warn',\n        ],\n      },\n    ],\n    'no-fallthrough': 'error',\n    'no-irregular-whitespace': 'error',\n    'no-mixed-spaces-and-tabs': 'warn',\n    'no-nested-ternary': 'warn',\n    'no-trailing-spaces': 'warn',\n    'no-undef': 'error',\n    'no-unreachable': 'error',\n    'no-unused-expressions': 'error',\n    'no-unused-vars': [\n      'error',\n      {\n        vars: 'all',\n        args: 'after-used',\n        ignoreRestSiblings: true,\n      },\n    ],\n    'object-curly-spacing': ['error', 'always'],\n    'padded-blocks': [\n      'error',\n      {\n        classes: 'always',\n      },\n    ],\n    quotes: ['error', 'single'],\n    semi: 'error',\n    strict: 'off',\n    'valid-typeof': 'error',\n\n    'react/jsx-boolean-value': 'error',\n    'react/jsx-closing-bracket-location': ['error', 'line-aligned'],\n    'react/jsx-curly-spacing': 'error',\n    'react/jsx-equals-spacing': 'error',\n    'react/jsx-first-prop-new-line': ['error', 'multiline-multiprop'],\n    'react/jsx-indent': ['error', 2],\n    'react/jsx-no-bind': 'error',\n    'react/jsx-no-duplicate-props': 'error',\n    'react/jsx-no-undef': 'error',\n    'react/jsx-tag-spacing': 'error',\n    'react/jsx-uses-react': 'error',\n    'react/jsx-uses-vars': 'error',\n    'react/jsx-wrap-multilines': 'error',\n    'react/no-multi-comp': 'off',\n    'react/no-string-refs': 'error',\n    'react/prop-types': 'error',\n    'react/self-closing-comp': 'error',\n\n    'jsx-a11y/accessible-emoji': 'warn',\n    'jsx-a11y/alt-text': 'warn',\n    'jsx-a11y/anchor-has-content': 'warn',\n    'jsx-a11y/anchor-is-valid': [\n      'warn',\n      {\n        components: [\n          'Link',\n          'NavLink',\n        ],\n        specialLink: [\n          'to',\n        ],\n        aspect: [\n          'noHref',\n          'invalidHref',\n          'preferButton',\n        ],\n      },\n    ],\n    'jsx-a11y/aria-activedescendant-has-tabindex': 'warn',\n    'jsx-a11y/aria-props': 'warn',\n    'jsx-a11y/aria-proptypes': 'warn',\n    'jsx-a11y/aria-role': 'warn',\n    'jsx-a11y/aria-unsupported-elements': 'warn',\n    'jsx-a11y/heading-has-content': 'warn',\n    'jsx-a11y/html-has-lang': 'warn',\n    'jsx-a11y/iframe-has-title': 'warn',\n    'jsx-a11y/img-redundant-alt': 'warn',\n    'jsx-a11y/interactive-supports-focus': 'warn',\n    'jsx-a11y/label-has-for': 'off',\n    'jsx-a11y/mouse-events-have-key-events': 'warn',\n    'jsx-a11y/no-access-key': 'warn',\n    'jsx-a11y/no-distracting-elements': 'warn',\n    'jsx-a11y/no-noninteractive-element-interactions': [\n      'warn',\n      {\n        handlers: [\n          'onClick',\n        ],\n      },\n    ],\n    'jsx-a11y/no-onchange': 'warn',\n    'jsx-a11y/no-redundant-roles': 'warn',\n    'jsx-a11y/no-static-element-interactions': [\n      'warn',\n      {\n        handlers: [\n          'onClick',\n        ],\n      },\n    ],\n    'jsx-a11y/role-has-required-aria-props': 'warn',\n    'jsx-a11y/role-supports-aria-props': 'off',\n    'jsx-a11y/scope': 'warn',\n    'jsx-a11y/tabindex-no-positive': 'warn',\n\n    'import/extensions': [\n      'error',\n      'always',\n      {\n        js: 'never',\n      },\n    ],\n    'import/newline-after-import': 'error',\n    'import/no-extraneous-dependencies': [\n      'error',\n      {\n        devDependencies: [\n          'config/webpack/**',\n          'app/javascript/mastodon/test_setup.js',\n          'app/javascript/**/__tests__/**',\n        ],\n      },\n    ],\n    'import/no-unresolved': 'error',\n    'import/no-webpack-loader-syntax': 'error',\n\n    'promise/catch-or-return': 'error',\n  },\n};\n"
  },
  {
    "path": ".foreman",
    "content": "procfile: Procfile.dev\n"
  },
  {
    "path": ".gitattributes",
    "content": "*                             text=auto eol=lf\n*.eot                         -text\n*.gif                         -text\n*.gz                          -text\n*.ico                         -text\n*.jpg                         -text\n*.mp3                         -text\n*.ogg                         -text\n*.png                         -text\n*.ttf                         -text\n*.webm                        -text\n*.woff                        -text\n*.woff2                       -text\nspec/fixtures/requests/**     -text !eol\n"
  },
  {
    "path": ".gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files for more about ignoring files.\n#\n# If you find yourself ignoring temporary files generated by your text editor\n# or operating system, you probably want to add a global ignore instead:\n#   git config --global core.excludesfile '~/.gitignore_global'\n\n# Ignore bundler config and downloaded libraries.\n/.bundle\n/vendor/bundle\n\n# Ignore the default SQLite database.\n/db/*.sqlite3\n/db/*.sqlite3-journal\n\n# Ignore all logfiles and tempfiles.\n/log/*\n!/log/.keep\n/tmp\ncoverage\npublic/system\npublic/assets\npublic/packs\npublic/packs-test\n.env\n.env.production\nnode_modules/\nbuild/\n\n# Ignore Vagrant files\n.vagrant/\n\n# Ignore Capistrano customizations\nconfig/deploy/*\n\n# Ignore IDE files\n.vscode/\n.idea/\n\n# Ignore postgres + redis + elasticsearch volume optionally created by docker-compose\npostgres\nredis\nelasticsearch\n\n# Ignore Apple files\n.DS_Store\n\n# Ignore vim files\n*~\n*.swp\n\n# Ignore npm debug log\nnpm-debug.log\n\n# Ignore yarn log files\nyarn-error.log\nyarn-debug.log\n\n# Ignore Docker option files\ndocker-compose.override.yml\n\n"
  },
  {
    "path": ".haml-lint.yml",
    "content": "# Whether to ignore frontmatter at the beginning of HAML documents for\n# frameworks such as Jekyll/Middleman\nskip_frontmatter: false\n\nexclude:\n  - 'vendor/**/*'\n  - 'spec/**/*'\n  - 'lib/templates/**/*'\n  - 'app/views/kaminari/**/*'\n\nlinters:\n  AltText:\n    enabled: false\n\n  ClassAttributeWithStaticValue:\n    enabled: true\n\n  ClassesBeforeIds:\n    enabled: true\n\n  ConsecutiveComments:\n    enabled: true\n\n  ConsecutiveSilentScripts:\n    enabled: true\n    max_consecutive: 2\n\n  EmptyObjectReference:\n    enabled: true\n\n  EmptyScript:\n    enabled: true\n\n  FinalNewline:\n    enabled: true\n    present: true\n\n  HtmlAttributes:\n    enabled: true\n\n  ImplicitDiv:\n    enabled: true\n\n  LeadingCommentSpace:\n    enabled: true\n\n  LineLength:\n    enabled: false\n    max: 80\n\n  MultilinePipe:\n    enabled: true\n\n  MultilineScript:\n    enabled: true\n\n  ObjectReferenceAttributes:\n    enabled: true\n\n  RuboCop:\n    enabled: true\n    # These cops are incredibly noisy when it comes to HAML templates, so we\n    # ignore them.\n    ignored_cops:\n      - Lint/BlockAlignment\n      - Lint/EndAlignment\n      - Lint/Void\n      - Metrics/BlockLength\n      - Metrics/LineLength\n      - Style/AlignParameters\n      - Style/BlockNesting\n      - Style/ElseAlignment\n      - Style/EndOfLine\n      - Style/FileName\n      - Style/FinalNewline\n      - Style/FrozenStringLiteralComment\n      - Style/IfUnlessModifier\n      - Style/IndentationWidth\n      - Style/Next\n      - Style/TrailingBlankLines\n      - Style/TrailingWhitespace\n      - Style/WhileUntilModifier\n\n  RubyComments:\n    enabled: true\n\n  SpaceBeforeScript:\n    enabled: true\n\n  SpaceInsideHashAttributes:\n    enabled: true\n    style: space\n\n  Indentation:\n    enabled: true\n    character: space # or tab\n\n  TagName:\n    enabled: true\n\n  TrailingWhitespace:\n    enabled: true\n\n  UnnecessaryInterpolation:\n    enabled: true\n\n  UnnecessaryStringOutput:\n    enabled: true\n"
  },
  {
    "path": ".nanoignore",
    "content": ".DS_Store\n.git/\n.gitignore\n\n.bundle/\n.cache/\nconfig/deploy/*\ncoverage\ndocs/\n.env\nlog/*.log\nneo4j/\nnode_modules/\npublic/assets/\npublic/system/\nspec/\ntmp/\n.vagrant/\nvendor/bundle/\n"
  },
  {
    "path": ".nvmrc",
    "content": "8\n"
  },
  {
    "path": ".profile",
    "content": "LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/app/.apt/lib/x86_64-linux-gnu:/app/.apt/usr/lib/x86_64-linux-gnu/mesa:/app/.apt/usr/lib/x86_64-linux-gnu/pulseaudio\n"
  },
  {
    "path": ".rspec",
    "content": "--color\n--require spec_helper\n--format Fuubar\n"
  },
  {
    "path": ".rubocop.yml",
    "content": "require:\n  - rubocop-rails\n\nAllCops:\n  TargetRubyVersion: 2.3\n  Exclude:\n  - 'spec/**/*'\n  - 'db/**/*'\n  - 'app/views/**/*'\n  - 'config/**/*'\n  - 'bin/*'\n  - 'Rakefile'\n  - 'node_modules/**/*'\n  - 'Vagrantfile'\n  - 'vendor/**/*'\n  - 'lib/json_ld/*'\n  - 'lib/templates/**/*'\n\nBundler/OrderedGems:\n  Enabled: false\n\nLayout/AccessModifierIndentation:\n  EnforcedStyle: indent\n\nLayout/EmptyLineAfterMagicComment:\n  Enabled: false\n\nLayout/SpaceInsideHashLiteralBraces:\n  EnforcedStyle: space\n\nMetrics/AbcSize:\n  Max: 100\n\nMetrics/BlockLength:\n  Max: 35\n  Exclude:\n    - 'lib/tasks/**/*'\n\nMetrics/BlockNesting:\n  Max: 3\n\nMetrics/ClassLength:\n  CountComments: false\n  Max: 300\n\nMetrics/CyclomaticComplexity:\n  Max: 25\n\nMetrics/LineLength:\n  AllowURI: true\n  Enabled: false\n\nMetrics/MethodLength:\n  CountComments: false\n  Max: 55\n\nMetrics/ModuleLength:\n  CountComments: false\n  Max: 200\n\nMetrics/ParameterLists:\n  Max: 5\n  CountKeywordArgs: true\n\nMetrics/PerceivedComplexity:\n  Max: 20\n\nNaming/MemoizedInstanceVariableName:\n  Enabled: false\n\nRails:\n  Enabled: true\n\nRails/HasAndBelongsToMany:\n  Enabled: false\n\nRails/SkipsModelValidations:\n  Enabled: false\n\nRails/HttpStatus:\n  Enabled: false\n\nRails/Exit:\n  Exclude:\n    - 'lib/mastodon/*'\n    - 'lib/cli.rb'\n\nRails/HelperInstanceVariable:\n  Enabled: false\n\nStyle/ClassAndModuleChildren:\n  Enabled: false\n\nStyle/CollectionMethods:\n  Enabled: true\n  PreferredMethods:\n    find_all: 'select'\n\nStyle/Documentation:\n  Enabled: false\n\nStyle/DoubleNegation:\n  Enabled: true\n\nStyle/FrozenStringLiteralComment:\n  Enabled: true\n\nStyle/GuardClause:\n  Enabled: false\n\nStyle/Lambda:\n  Enabled: false\n\nStyle/PercentLiteralDelimiters:\n  PreferredDelimiters:\n    '%i': '()'\n    '%w': '()'\n\nStyle/PerlBackrefs:\n  AutoCorrect: false\n\nStyle/RegexpLiteral:\n  Enabled: false\n\nStyle/SymbolArray:\n  Enabled: false\n\nStyle/TrailingCommaInArrayLiteral:\n  EnforcedStyleForMultiline: 'comma'\n\nStyle/TrailingCommaInHashLiteral:\n  EnforcedStyleForMultiline: 'comma'\n"
  },
  {
    "path": ".ruby-version",
    "content": "2.6.1\n"
  },
  {
    "path": ".sass-lint.yml",
    "content": "# Linter Documentation:\n# https://github.com/sasstools/sass-lint/tree/v1.13.1/docs/options\n\nfiles:\n  include: app/javascript/styles/**/*.scss\n  ignore:\n    - app/javascript/styles/mastodon/reset.scss\n\nrules:\n  # Disallows\n  no-color-literals: 0\n  no-css-comments: 0\n  no-duplicate-properties: 0\n  no-ids: 0\n  no-important: 0\n  no-mergeable-selectors: 0\n  no-misspelled-properties: 0\n  no-qualifying-elements: 0\n  no-transition-all: 0\n  no-vendor-prefixes: 0\n\n  # Nesting\n  force-element-nesting: 0\n  force-attribute-nesting: 0\n  force-pseudo-nesting: 0\n\n  # Name Formats\n  class-name-format: 0\n  leading-zero: 0\n\n  # Style Guide\n  attribute-quotes: 0\n  hex-length: 0\n  indentation: 0\n  nesting-depth: 0\n  property-sort-order: 0\n  quotes: 0\n"
  },
  {
    "path": ".slugignore",
    "content": "node_modules/\n.cache/\ndocs/\nspec/\n"
  },
  {
    "path": ".yarnclean",
    "content": "# test directories\n__tests__\ntest\ntests\npowered-test\n\n# asset directories\ndocs\ndoc\nwebsite\nimages\n# assets\n\n# examples\nexample\nexamples\n\n# code coverage directories\ncoverage\n.nyc_output\n\n# build scripts\nMakefile\nGulpfile.js\nGruntfile.js\n\n# configs\n.tern-project\n.gitattributes\n.editorconfig\n.*ignore\n.eslintrc\n.jshintrc\n.flowconfig\n.documentup.json\n.yarn-metadata.json\n.*.yml\n*.yml\n\n# misc\n*.gz\n*.md\n\n# for specific ignore\n!.svgo.yml\n!sass-lint/**/*.yml\n"
  },
  {
    "path": "AUTHORS.md",
    "content": "Authors\n=======\n\nMastodon is available on [GitHub](https://github.com/tootsuite/mastodon)\nand provided thanks to the work of the following contributors:\n\n* [Gargron](https://github.com/Gargron)\n* [ykzts](https://github.com/ykzts)\n* [ThibG](https://github.com/ThibG)\n* [akihikodaki](https://github.com/akihikodaki)\n* [mjankowski](https://github.com/mjankowski)\n* [dependabot[bot]](https://github.com/apps/dependabot)\n* [unarist](https://github.com/unarist)\n* [m4sk1n](https://github.com/m4sk1n)\n* [yiskah](https://github.com/yiskah)\n* [nolanlawson](https://github.com/nolanlawson)\n* [ysksn](https://github.com/ysksn)\n* [sorin-davidoi](https://github.com/sorin-davidoi)\n* [abcang](https://github.com/abcang)\n* [lynlynlynx](https://github.com/lynlynlynx)\n* [mayaeh](https://github.com/mayaeh)\n* [renatolond](https://github.com/renatolond)\n* [alpaca-tc](https://github.com/alpaca-tc)\n* [nclm](https://github.com/nclm)\n* [ineffyble](https://github.com/ineffyble)\n* [jeroenpraat](https://github.com/jeroenpraat)\n* [blackle](https://github.com/blackle)\n* [Quent-in](https://github.com/Quent-in)\n* [JantsoP](https://github.com/JantsoP)\n* [Kjwon15](https://github.com/Kjwon15)\n* [mabkenar](https://github.com/mabkenar)\n* [nullkal](https://github.com/nullkal)\n* [yookoala](https://github.com/yookoala)\n* [shuheiktgw](https://github.com/shuheiktgw)\n* [ashfurrow](https://github.com/ashfurrow)\n* [zunda](https://github.com/zunda)\n* [Quenty31](https://github.com/Quenty31)\n* [eramdam](https://github.com/eramdam)\n* [takayamaki](https://github.com/takayamaki)\n* [masarakki](https://github.com/masarakki)\n* [ticky](https://github.com/ticky)\n* [danhunsaker](https://github.com/danhunsaker)\n* [ThisIsMissEm](https://github.com/ThisIsMissEm)\n* [hcmiya](https://github.com/hcmiya)\n* [stephenburgess8](https://github.com/stephenburgess8)\n* [Wonderfall](https://github.com/Wonderfall)\n* [matteoaquila](https://github.com/matteoaquila)\n* [yukimochi](https://github.com/yukimochi)\n* [rkarabut](https://github.com/rkarabut)\n* [Artoria2e5](https://github.com/Artoria2e5)\n* [nightpool](https://github.com/nightpool)\n* [marrus-sh](https://github.com/marrus-sh)\n* [krainboltgreene](https://github.com/krainboltgreene)\n* [pfigel](https://github.com/pfigel)\n* [Aldarone](https://github.com/Aldarone)\n* [BoFFire](https://github.com/BoFFire)\n* [clworld](https://github.com/clworld)\n* [dracos](https://github.com/dracos)\n* [SerCom_KC](mailto:sercom-kc@users.noreply.github.com)\n* [Sylvhem](https://github.com/Sylvhem)\n* [MasterGroosha](https://github.com/MasterGroosha)\n* [JeanGauthier](https://github.com/JeanGauthier)\n* [kschaper](https://github.com/kschaper)\n* [MaciekBaron](https://github.com/MaciekBaron)\n* [MitarashiDango](mailto:mitarashidango@users.noreply.github.com)\n* [beatrix-bitrot](https://github.com/beatrix-bitrot)\n* [Aditoo17](https://github.com/Aditoo17)\n* [adbelle](https://github.com/adbelle)\n* [evanminto](https://github.com/evanminto)\n* [MightyPork](https://github.com/MightyPork)\n* [yhirano55](https://github.com/yhirano55)\n* [rinsuki](https://github.com/rinsuki)\n* [camponez](https://github.com/camponez)\n* [hinaloe](https://github.com/hinaloe)\n* [SerCom-KC](https://github.com/SerCom-KC)\n* [aschmitz](https://github.com/aschmitz)\n* [devkral](https://github.com/devkral)\n* [fpiesche](https://github.com/fpiesche)\n* [gandaro](https://github.com/gandaro)\n* [johnsudaar](https://github.com/johnsudaar)\n* [trebmuh](https://github.com/trebmuh)\n* [Rakib Hasan](mailto:rmhasan@gmail.com)\n* [ashleyhull-versent](https://github.com/ashleyhull-versent)\n* [lindwurm](https://github.com/lindwurm)\n* [victorhck](mailto:victorhck@geeko.site)\n* [voidsatisfaction](https://github.com/voidsatisfaction)\n* [hikari-no-yume](https://github.com/hikari-no-yume)\n* [angristan](https://github.com/angristan)\n* [seefood](https://github.com/seefood)\n* [jackjennings](https://github.com/jackjennings)\n* [spla](mailto:spla@mastodont.cat)\n* [expenses](https://github.com/expenses)\n* [walf443](https://github.com/walf443)\n* [JoelQ](https://github.com/JoelQ)\n* [mistydemeo](https://github.com/mistydemeo)\n* [dunn](https://github.com/dunn)\n* [xqus](https://github.com/xqus)\n* [hugogameiro](https://github.com/hugogameiro)\n* [ariasuni](https://github.com/ariasuni)\n* [pfm-eyesightjp](https://github.com/pfm-eyesightjp)\n* [fakenine](https://github.com/fakenine)\n* [tsuwatch](https://github.com/tsuwatch)\n* [victorhck](https://github.com/victorhck)\n* [kedamaDQ](https://github.com/kedamaDQ)\n* [puckipedia](https://github.com/puckipedia)\n* [trwnh](https://github.com/trwnh)\n* [fvh-P](https://github.com/fvh-P)\n* [Anna e só](mailto:contraexemplos@gmail.com)\n* [BenLubar](https://github.com/BenLubar)\n* [kazu9su](https://github.com/kazu9su)\n* [Komic](https://github.com/Komic)\n* [lmorchard](https://github.com/lmorchard)\n* [diomed](https://github.com/diomed)\n* [Neetshin](mailto:neetshin@neetsh.in)\n* [rainyday](https://github.com/rainyday)\n* [ProgVal](https://github.com/ProgVal)\n* [valentin2105](https://github.com/valentin2105)\n* [yuntan](https://github.com/yuntan)\n* [goofy-bz](mailto:goofy@babelzilla.org)\n* [kadiix](https://github.com/kadiix)\n* [kodacs](https://github.com/kodacs)\n* [JMendyk](https://github.com/JMendyk)\n* [KScl](https://github.com/KScl)\n* [sterdev](https://github.com/sterdev)\n* [TheKinrar](https://github.com/TheKinrar)\n* [AA4ch1](https://github.com/AA4ch1)\n* [alexgleason](https://github.com/alexgleason)\n* [cpytel](https://github.com/cpytel)\n* [northerner](https://github.com/northerner)\n* [fhemberger](https://github.com/fhemberger)\n* [greysteil](https://github.com/greysteil)\n* [hensmith](https://github.com/hensmith)\n* [d6rkaiz](https://github.com/d6rkaiz)\n* [Reverite](https://github.com/Reverite)\n* [JohnD28](https://github.com/JohnD28)\n* [znz](https://github.com/znz)\n* [marek-lach](https://github.com/marek-lach)\n* [Naouak](https://github.com/Naouak)\n* [pawelngei](https://github.com/pawelngei)\n* [rtucker](https://github.com/rtucker)\n* [reneklacan](https://github.com/reneklacan)\n* [ekiru](https://github.com/ekiru)\n* [noellabo](https://github.com/noellabo)\n* [tcitworld](https://github.com/tcitworld)\n* [geta6](https://github.com/geta6)\n* [happycoloredbanana](https://github.com/happycoloredbanana)\n* [leopku](https://github.com/leopku)\n* [SansPseudoFix](https://github.com/SansPseudoFix)\n* [tomfhowe](https://github.com/tomfhowe)\n* [noraworld](https://github.com/noraworld)\n* [theboss](https://github.com/theboss)\n* [178inaba](https://github.com/178inaba)\n* [alyssais](https://github.com/alyssais)\n* [hiphref](https://github.com/hiphref)\n* [stalker314314](https://github.com/stalker314314)\n* [huertanix](https://github.com/huertanix)\n* [genesixx](https://github.com/genesixx)\n* [halkeye](https://github.com/halkeye)\n* [treby](https://github.com/treby)\n* [jpdevries](https://github.com/jpdevries)\n* [gdpelican](https://github.com/gdpelican)\n* [kmichl](https://github.com/kmichl)\n* [Kurtis Rainbolt-Greene](mailto:me@kurtisrainboltgreene.name)\n* [saper](https://github.com/saper)\n* [nevillepark](https://github.com/nevillepark)\n* [ornithocoder](https://github.com/ornithocoder)\n* [pierreozoux](https://github.com/pierreozoux)\n* [qguv](https://github.com/qguv)\n* [Ram Lmn](mailto:ramlmn@users.noreply.github.com)\n* [sascha-sl](https://github.com/sascha-sl)\n* [harukasan](https://github.com/harukasan)\n* [stamak](https://github.com/stamak)\n* [Technowix](mailto:technowix@users.noreply.github.com)\n* [Zoeille](https://github.com/Zoeille)\n* [Thor Harald Johansen](mailto:thj@thj.no)\n* [0x70b1a5](https://github.com/0x70b1a5)\n* [gled-rs](https://github.com/gled-rs)\n* [Valentin_NC](mailto:valentin.ouvrard@nautile.sarl)\n* [R0ckweb](https://github.com/R0ckweb)\n* [caasi](https://github.com/caasi)\n* [chr-1x](https://github.com/chr-1x)\n* [esetomo](https://github.com/esetomo)\n* [foxiehkins](https://github.com/foxiehkins)\n* [hoodie](mailto:hoodiekitten@outlook.com)\n* [luzi82](https://github.com/luzi82)\n* [duxovni](https://github.com/duxovni)\n* [tmm576](https://github.com/tmm576)\n* [unsmell](https://github.com/unsmell)\n* [valerauko](https://github.com/valerauko)\n* [chriswmartin](https://github.com/chriswmartin)\n* [vahnj](https://github.com/vahnj)\n* [ikuradon](https://github.com/ikuradon)\n* [AndreLewin](https://github.com/AndreLewin)\n* [0xflotus](https://github.com/0xflotus)\n* [redtachyons](https://github.com/redtachyons)\n* [thurloat](https://github.com/thurloat)\n* [aaribaud](https://github.com/aaribaud)\n* [pointlessone](https://github.com/pointlessone)\n* [Andrew](mailto:andrewlchronister@gmail.com)\n* [estuans](https://github.com/estuans)\n* [dissolve](https://github.com/dissolve)\n* [PurpleBooth](https://github.com/PurpleBooth)\n* [bradurani](https://github.com/bradurani)\n* [wavebeem](https://github.com/wavebeem)\n* [bruwalfas](https://github.com/bruwalfas)\n* [foxsan48](https://github.com/foxsan48)\n* [wchristian](https://github.com/wchristian)\n* [muffinista](https://github.com/muffinista)\n* [cdutson](https://github.com/cdutson)\n* [farlistener](https://github.com/farlistener)\n* [DavidLibeau](https://github.com/DavidLibeau)\n* [ddevault](https://github.com/ddevault)\n* [Fjoerfoks](https://github.com/Fjoerfoks)\n* [fmauNeko](https://github.com/fmauNeko)\n* [gloaec](https://github.com/gloaec)\n* [Gomasy](https://github.com/Gomasy)\n* [unstabler](https://github.com/unstabler)\n* [potato4d](https://github.com/potato4d)\n* [h-izumi](https://github.com/h-izumi)\n* [ErikXXon](https://github.com/ErikXXon)\n* [ian-kelling](https://github.com/ian-kelling)\n* [immae](https://github.com/immae)\n* [J0WI](https://github.com/J0WI)\n* [foozmeat](https://github.com/foozmeat)\n* [jasonrhodes](https://github.com/jasonrhodes)\n* [Jason Snell](mailto:jason@newrelic.com)\n* [jviide](https://github.com/jviide)\n* [YuleZ](https://github.com/YuleZ)\n* [crakaC](https://github.com/crakaC)\n* [tkbky](https://github.com/tkbky)\n* [Kaylee](mailto:kaylee@codethat.sucks)\n* [Kazhnuz](https://github.com/Kazhnuz)\n* [connyduck](https://github.com/connyduck)\n* [Lindsey Bieda](mailto:lindseyb@users.noreply.github.com)\n* [Lorenz Diener](mailto:halcyon@icosahedron.website)\n* [alimony](https://github.com/alimony)\n* [mig5](https://github.com/mig5)\n* [moritzheiber](https://github.com/moritzheiber)\n* [ndarville](https://github.com/ndarville)\n* [Abzol](https://github.com/Abzol)\n* [pwoolcoc](https://github.com/pwoolcoc)\n* [xPaw](https://github.com/xPaw)\n* [petzah](https://github.com/petzah)\n* [ignisf](https://github.com/ignisf)\n* [raymestalez](https://github.com/raymestalez)\n* [remram44](https://github.com/remram44)\n* [sts10](https://github.com/sts10)\n* [u1-liquid](https://github.com/u1-liquid)\n* [sim6](https://github.com/sim6)\n* [Sir-Boops](https://github.com/Sir-Boops)\n* [stemid](https://github.com/stemid)\n* [sumdog](https://github.com/sumdog)\n* [ThomasLeister](https://github.com/ThomasLeister)\n* [mcat-ee](https://github.com/mcat-ee)\n* [tototoshi](https://github.com/tototoshi)\n* [TrashMacNugget](https://github.com/TrashMacNugget)\n* [VirtuBox](https://github.com/VirtuBox)\n* [Vladyslav](mailto:vaden@tuta.io)\n* [kaniini](https://github.com/kaniini)\n* [vayan](https://github.com/vayan)\n* [yannicka](https://github.com/yannicka)\n* [ikasoumen](https://github.com/ikasoumen)\n* [zacanger](https://github.com/zacanger)\n* [amazedkoumei](https://github.com/amazedkoumei)\n* [anon5r](https://github.com/anon5r)\n* [aus-social](https://github.com/aus-social)\n* [imbsky](https://github.com/imbsky)\n* [bsky](mailto:me@imbsky.net)\n* [codl](https://github.com/codl)\n* [cpsdqs](https://github.com/cpsdqs)\n* [barzamin](https://github.com/barzamin)\n* [fhalna](https://github.com/fhalna)\n* [haoyayoi](https://github.com/haoyayoi)\n* [ik11235](https://github.com/ik11235)\n* [kawax](https://github.com/kawax)\n* [007lva](https://github.com/007lva)\n* [mbajur](https://github.com/mbajur)\n* [matsurai25](https://github.com/matsurai25)\n* [mecab](https://github.com/mecab)\n* [nicobz25](https://github.com/nicobz25)\n* [oliverkeeble](https://github.com/oliverkeeble)\n* [pinfort](https://github.com/pinfort)\n* [rbaumert](https://github.com/rbaumert)\n* [rhoio](https://github.com/rhoio)\n* [usagi-f](https://github.com/usagi-f)\n* [vidarlee](https://github.com/vidarlee)\n* [vjackson725](https://github.com/vjackson725)\n* [wxcafe](https://github.com/wxcafe)\n* [新都心(Neet Shin)](mailto:nucx@dio-vox.com)\n* [cygnan](https://github.com/cygnan)\n* [Awea](https://github.com/Awea)\n* [halcy](https://github.com/halcy)\n* [naaaaaaaaaaaf](https://github.com/naaaaaaaaaaaf)\n* [8398a7](https://github.com/8398a7)\n* [857b](https://github.com/857b)\n* [insom](https://github.com/insom)\n* [tachyons](https://github.com/tachyons)\n* [acid-chicken](https://github.com/acid-chicken)\n* [Esteth](https://github.com/Esteth)\n* [unascribed](https://github.com/unascribed)\n* [Aguay-val](https://github.com/Aguay-val)\n* [Akihiko Odaki](mailto:nekomanma@pixiv.co.jp)\n* [knu](https://github.com/knu)\n* [h3poteto](https://github.com/h3poteto)\n* [unleashed](https://github.com/unleashed)\n* [alxrcs](https://github.com/alxrcs)\n* [console-cowboy](https://github.com/console-cowboy)\n* [Alkarex](https://github.com/Alkarex)\n* [a2](https://github.com/a2)\n* [0xa](https://github.com/0xa)\n* [palindromordnilap](https://github.com/palindromordnilap)\n* [virtualpain](https://github.com/virtualpain)\n* [sapphirus](https://github.com/sapphirus)\n* [amandavisconti](https://github.com/amandavisconti)\n* [ameliavoncat](https://github.com/ameliavoncat)\n* [ilpianista](https://github.com/ilpianista)\n* [Andreas Drop](mailto:andy@remline.de)\n* [andi1984](https://github.com/andi1984)\n* [schas002](https://github.com/schas002)\n* [contraexemplo](https://github.com/contraexemplo)\n* [abackstrom](https://github.com/abackstrom)\n* [armandfardeau](https://github.com/armandfardeau)\n* [jumbosushi](https://github.com/jumbosushi)\n* [aurelien-reeves](https://github.com/aurelien-reeves)\n* [ayumin](https://github.com/ayumin)\n* [BaptisteGelez](https://github.com/BaptisteGelez)\n* [bzg](https://github.com/bzg)\n* [benediktg](https://github.com/benediktg)\n* [blakebarnett](https://github.com/blakebarnett)\n* [bradj](https://github.com/bradj)\n* [brycied00d](https://github.com/brycied00d)\n* [carlosjs23](https://github.com/carlosjs23)\n* [cgxxx](https://github.com/cgxxx)\n* [kibitan](https://github.com/kibitan)\n* [chrisheninger](https://github.com/chrisheninger)\n* [chris-martin](https://github.com/chris-martin)\n* [DoubleMalt](https://github.com/DoubleMalt)\n* [Moosh-be](https://github.com/Moosh-be)\n* [Motoma](https://github.com/Motoma)\n* [chriswk](https://github.com/chriswk)\n* [csu](https://github.com/csu)\n* [clarfon](https://github.com/clarfon)\n* [kklleemm](https://github.com/kklleemm)\n* [colindean](https://github.com/colindean)\n* [dachinat](https://github.com/dachinat)\n* [multiple-creatures](https://github.com/multiple-creatures)\n* [watilde](https://github.com/watilde)\n* [daprice](https://github.com/daprice)\n* [dar5hak](https://github.com/dar5hak)\n* [kant](https://github.com/kant)\n* [maxolasersquad](https://github.com/maxolasersquad)\n* [singingwolfboy](https://github.com/singingwolfboy)\n* [davidcelis](https://github.com/davidcelis)\n* [davefp](https://github.com/davefp)\n* [yipdw](https://github.com/yipdw)\n* [debanshuk](https://github.com/debanshuk)\n* [Derek Lewis](mailto:derekcecillewis@gmail.com)\n* [dblandin](https://github.com/dblandin)\n* [Drew Gates](mailto:aranaur@users.noreply.github.com)\n* [dtschust](https://github.com/dtschust)\n* [Dryusdan](https://github.com/Dryusdan)\n* [eai04191](https://github.com/eai04191)\n* [d3vgru](https://github.com/d3vgru)\n* [Elizafox](https://github.com/Elizafox)\n* [enewhuis](https://github.com/enewhuis)\n* [ericblade](https://github.com/ericblade)\n* [mikoim](https://github.com/mikoim)\n* [espenronnevik](https://github.com/espenronnevik)\n* [Finariel](https://github.com/Finariel)\n* [siuying](https://github.com/siuying)\n* [zoc](https://github.com/zoc)\n* [fwenzel](https://github.com/fwenzel)\n* [GenbuHase](https://github.com/GenbuHase)\n* [hattori6789](https://github.com/hattori6789)\n* [algernon](https://github.com/algernon)\n* [Fastbyte01](https://github.com/Fastbyte01)\n* [myfreeweb](https://github.com/myfreeweb)\n* [gfaivre](https://github.com/gfaivre)\n* [Fiaxhs](https://github.com/Fiaxhs)\n* [reedcourty](https://github.com/reedcourty)\n* [anneau](https://github.com/anneau)\n* [lanodan](https://github.com/lanodan)\n* [Harmon758](https://github.com/Harmon758)\n* [HellPie](https://github.com/HellPie)\n* [Habu-Kagumba](https://github.com/Habu-Kagumba)\n* [suzukaze](https://github.com/suzukaze)\n* [Hiromi-Kai](https://github.com/Hiromi-Kai)\n* [hishamhm](https://github.com/hishamhm)\n* [musashino205](https://github.com/musashino205)\n* [iwaim](https://github.com/iwaim)\n* [valrus](https://github.com/valrus)\n* [IMcD23](https://github.com/IMcD23)\n* [yi0713](https://github.com/yi0713)\n* [iblech](https://github.com/iblech)\n* [usbsnowcrash](https://github.com/usbsnowcrash)\n* [jack-michaud](https://github.com/jack-michaud)\n* [Floppy](https://github.com/Floppy)\n* [loomchild](https://github.com/loomchild)\n* [jenkr55](https://github.com/jenkr55)\n* [press5](https://github.com/press5)\n* [TrollDecker](https://github.com/TrollDecker)\n* [jmontane](https://github.com/jmontane)\n* [jonathanklee](https://github.com/jonathanklee)\n* [jguerder](https://github.com/jguerder)\n* [Jehops](https://github.com/Jehops)\n* [joshuap](https://github.com/joshuap)\n* [Tiwy57](https://github.com/Tiwy57)\n* [xuv](https://github.com/xuv)\n* [June Sallou](mailto:jnsll@users.noreply.github.com)\n* [j0k3r](https://github.com/j0k3r)\n* [KEINOS](https://github.com/KEINOS)\n* [futoase](https://github.com/futoase)\n* [Pneumaticat](https://github.com/Pneumaticat)\n* [Kit Redgrave](mailto:qwertyitis@gmail.com)\n* [Knut Erik](mailto:abjectio@users.noreply.github.com)\n* [mkody](https://github.com/mkody)\n* [k0ta0uchi](https://github.com/k0ta0uchi)\n* [KrzysiekJ](https://github.com/KrzysiekJ)\n* [leowzukw](https://github.com/leowzukw)\n* [Tak](https://github.com/Tak)\n* [cacheflow](https://github.com/cacheflow)\n* [ldidry](https://github.com/ldidry)\n* [jemus42](https://github.com/jemus42)\n* [lfuelling](https://github.com/lfuelling)\n* [Grabacr07](https://github.com/Grabacr07)\n* [mistermantas](https://github.com/mistermantas)\n* [mareklach](https://github.com/mareklach)\n* [wirehack7](https://github.com/wirehack7)\n* [martymcguire](https://github.com/martymcguire)\n* [marvinkopf](https://github.com/marvinkopf)\n* [otsune](https://github.com/otsune)\n* [mbugowski](https://github.com/mbugowski)\n* [Mathias B](mailto:10813340+mathias-b@users.noreply.github.com)\n* [matt-auckland](https://github.com/matt-auckland)\n* [webroo](https://github.com/webroo)\n* [matthiasbeyer](https://github.com/matthiasbeyer)\n* [mattjmattj](https://github.com/mattjmattj)\n* [mtparet](https://github.com/mtparet)\n* [maximeborges](https://github.com/maximeborges)\n* [minacle](https://github.com/minacle)\n* [michaeljdeeb](https://github.com/michaeljdeeb)\n* [Themimitoof](https://github.com/Themimitoof)\n* [cyweo](https://github.com/cyweo)\n* [Midgard](mailto:m1dgard@users.noreply.github.com)\n* [mike-burns](https://github.com/mike-burns)\n* [verymilan](https://github.com/verymilan)\n* [milmazz](https://github.com/milmazz)\n* [premist](https://github.com/premist)\n* [Mnkai](https://github.com/Mnkai)\n* [mitchhentges](https://github.com/mitchhentges)\n* [mouse-reeve](https://github.com/mouse-reeve)\n* [Mozinet-fr](https://github.com/Mozinet-fr)\n* [lae](https://github.com/lae)\n* [nosada](https://github.com/nosada)\n* [Nanamachi](https://github.com/Nanamachi)\n* [orinthe](https://github.com/orinthe)\n* [NecroTechno](https://github.com/NecroTechno)\n* [Dar13](https://github.com/Dar13)\n* [ngerakines](https://github.com/ngerakines)\n* [vonneudeck](https://github.com/vonneudeck)\n* [Ninetailed](https://github.com/Ninetailed)\n* [k24](https://github.com/k24)\n* [noiob](https://github.com/noiob)\n* [kwaio](https://github.com/kwaio)\n* [norayr](https://github.com/norayr)\n* [joyeusenoelle](https://github.com/joyeusenoelle)\n* [OlivierNicole](https://github.com/OlivierNicole)\n* [noppa](https://github.com/noppa)\n* [Otakan951](https://github.com/Otakan951)\n* [fahy](https://github.com/fahy)\n* [PatrickRWells](mailto:32802366+patrickrwells@users.noreply.github.com)\n* [Paul](mailto:naydex.mc+github@gmail.com)\n* [Pete Keen](mailto:pete@petekeen.net)\n* [Pierre-Morgan Gate](mailto:pgate@users.noreply.github.com)\n* [Ratmir Karabut](mailto:rkarabut@sfmodern.ru)\n* [Reto Kromer](mailto:retokromer@users.noreply.github.com)\n* [Rey Tucker](mailto:git@reytucker.us)\n* [Rob Watson](mailto:rfwatson@users.noreply.github.com)\n* [Ryan Freebern](mailto:ryan@freebern.org)\n* [Ryan Wade](mailto:ryan.wade@protonmail.com)\n* [Ryo Kajiwara](mailto:kfe-fecn6.prussian@s01.info)\n* [S.H](mailto:gamelinks007@gmail.com)\n* [Sadiq Saif](mailto:staticsafe@users.noreply.github.com)\n* [Sam Hewitt](mailto:hewittsamuel@gmail.com)\n* [Satoshi KOJIMA](mailto:skoji@mac.com)\n* [ScienJus](mailto:i@scienjus.com)\n* [Scott Larkin](mailto:scott@codeclimate.com)\n* [Sebastian Hübner](mailto:imolein@users.noreply.github.com)\n* [Sebastian Morr](mailto:sebastian@morr.cc)\n* [Sergei Č](mailto:noiwex1911@gmail.com)\n* [Setuu](mailto:yuki764setuu@gmail.com)\n* [Shaun Gillies](mailto:me@shaungillies.net)\n* [Shin Adachi](mailto:shn@glucose.jp)\n* [Shin Kojima](mailto:shin@kojima.org)\n* [Sho Kusano](mailto:rosylilly@aduca.org)\n* [Shouko Yu](mailto:imshouko@gmail.com)\n* [Sina Mashek](mailto:sina@mashek.xyz)\n* [Soshi Kato](mailto:mail@sossii.com)\n* [Spanky](mailto:2788886+spankyworks@users.noreply.github.com)\n* [Stanislas](mailto:angristan@pm.me)\n* [StefOfficiel](mailto:pichard.stephane@free.fr)\n* [Steven Tappert](mailto:admin@dark-it.net)\n* [Svetlozar Todorov](mailto:svetlik@users.noreply.github.com)\n* [Sébastien Santoro](mailto:dereckson@espace-win.org)\n* [Tad Thorley](mailto:phaedryx@users.noreply.github.com)\n* [Takayoshi Nishida](mailto:takayoshi.nishida@gmail.com)\n* [Takayuki KUSANO](mailto:github@tkusano.jp)\n* [TakesxiSximada](mailto:takesxi.sximada@gmail.com)\n* [TheInventrix](mailto:theinventrix@users.noreply.github.com)\n* [Thomas Alberola](mailto:thomas@needacoffee.fr)\n* [Toby Deshane](mailto:fortyseven@users.noreply.github.com)\n* [Toby Pinder](mailto:gigitrix@gmail.com)\n* [Tomonori Murakami](mailto:crosslife777@gmail.com)\n* [TomoyaShibata](mailto:wind.of.hometown@gmail.com)\n* [Treyssat-Vincent Nino](mailto:treyssatvincent@users.noreply.github.com)\n* [Udo Kramer](mailto:optik@fluffel.io)\n* [Una](mailto:una@unascribed.com)\n* [Ushitora Anqou](mailto:ushitora_anqou@yahoo.co.jp)\n* [Valentin Lorentz](mailto:progval+git@progval.net)\n* [Vladimir Mincev](mailto:vladimir@canicinteractive.com)\n* [Waldir Pimenta](mailto:waldyrious@gmail.com)\n* [Wesley Ellis](mailto:tahnok@gmail.com)\n* [Wiktor](mailto:wiktor@metacode.biz)\n* [Wonderfall](mailto:wonderfall@schrodinger.io)\n* [YDrogen](mailto:ydrogen45@gmail.com)\n* [YMHuang](mailto:ymhuang@fmbase.tw)\n* [YOSHIOKA Eiichiro](mailto:yoshioka.eiichiro@gmail.com)\n* [YOU](mailto:stackexchange.you@gmail.com)\n* [YaQ](mailto:i_k_o_m_a_7@yahoo.co.jp)\n* [Yanaken](mailto:yanakend@gmail.com)\n* [Yann Klis](mailto:yann.klis@gmail.com)\n* [Yeechan Lu](mailto:wz.bluesnow@gmail.com)\n* [Yusuke Abe](mailto:moonset20@gmail.com)\n* [Zachary Spector](mailto:logicaldash@gmail.com)\n* [ZiiX](mailto:ziix@users.noreply.github.com)\n* [asria-jp](mailto:is@alicematic.com)\n* [ava](mailto:vladooku@users.noreply.github.com)\n* [benklop](mailto:benklop@gmail.com)\n* [bsky](mailto:git@imbsky.net)\n* [caesarologia](mailto:lopesgemelli.1@gmail.com)\n* [cbayerlein](mailto:c.bayerlein@gmail.com)\n* [chrolis](mailto:chrolis@users.noreply.github.com)\n* [cormo](mailto:cormorant2+github@gmail.com)\n* [d0p1](mailto:dopi-sama@hush.com)\n* [evilny0](mailto:evilny0@moomoocamp.net)\n* [febrezo](mailto:felixbrezo@gmail.com)\n* [fsubal](mailto:fsubal@users.noreply.github.com)\n* [fusshi-](mailto:dikky1218@users.noreply.github.com)\n* [gentaro](mailto:gentaroooo@gmail.com)\n* [gol-cha](mailto:info@mevo.xyz)\n* [hakoai](mailto:hk--76@qa2.so-net.ne.jp)\n* [haosbvnker](mailto:github@chaosbunker.com)\n* [isati](mailto:phil@juchnowi.cz)\n* [jacob](mailto:jacobherringtondeveloper@gmail.com)\n* [jenn kaplan](mailto:me@jkap.io)\n* [jirayudech](mailto:jirayudech@gmail.com)\n* [jomo](mailto:github@jomo.tv)\n* [jooops](mailto:joops@autistici.org)\n* [jukper](mailto:jukkaperanto@gmail.com)\n* [jumoru](mailto:jumoru@mailbox.org)\n* [karlyeurl](mailto:karl.yeurl@gmail.com)\n* [kedama](mailto:32974885+kedamadq@users.noreply.github.com)\n* [kodai](mailto:shirafuta.kodai@gmail.com)\n* [koyu](mailto:me@koyu.space)\n* [kuro5hin](mailto:rusty@kuro5hin.org)\n* [luzpaz](mailto:luzpaz@users.noreply.github.com)\n* [maxypy](mailto:maxime@mpigou.fr)\n* [mhe](mailto:mail@marcus-herrmann.com)\n* [mike castleman](mailto:m@mlcastle.net)\n* [mimikun](mailto:dzdzble_effort_311@outlook.jp)\n* [mohemohe](mailto:mohemohe@users.noreply.github.com)\n* [mshrtkch](mailto:mshrtkch@users.noreply.github.com)\n* [muan](mailto:muan@github.com)\n* [namelessGonbai](mailto:43787036+namelessgonbai@users.noreply.github.com)\n* [neetshin](mailto:neetshin@neetsh.in)\n* [rch850](mailto:rich850@gmail.com)\n* [roikale](mailto:roikale@users.noreply.github.com)\n* [rysiekpl](mailto:rysiek@hackerspace.pl)\n* [saturday06](mailto:dyob@lunaport.net)\n* [scriptjunkie](mailto:scriptjunkie@scriptjunkie.us)\n* [seekr](mailto:mario.drs@gmail.com)\n* [sundevour](mailto:31990469+sundevour@users.noreply.github.com)\n* [syui](mailto:syui@users.noreply.github.com)\n* [tackeyy](mailto:mailto.takita.yusuke@gmail.com)\n* [tateisu](mailto:tateisu@gmail.com)\n* [tmyt](mailto:shigure@refy.net)\n* [trevDev()](mailto:trev@trevdev.ca)\n* [utam0k](mailto:k0ma@utam0k.jp)\n* [vpzomtrrfrt](mailto:vpzomtrrfrt@gmail.com)\n* [walfie](mailto:walfington@gmail.com)\n* [y-temp4](mailto:y.temp4@gmail.com)\n* [ymmtmdk](mailto:ymmtmdk@gmail.com)\n* [yoshipc](mailto:yoooo@yoshipc.net)\n* [Özcan Zafer AYAN](mailto:ozcanzaferayan@gmail.com)\n* [ばん](mailto:detteiu0321@gmail.com)\n* [みたらしだんご](mailto:mitarashidango@users.noreply.github.com)\n* [りんすき](mailto:6533808+rinsuki@users.noreply.github.com)\n* [ヨイツの賢狼ホロ | 3rd style](mailto:horo@yoitsu.moe)\n* [猫吸血鬼ディフリス / 猫ロキP](mailto:deflis@gmail.com)\n* [艮 鮟鱇](mailto:ushitora_anqou@yahoo.co.jp)\n* [西小倉宏信](mailto:nishiko@mindia.jp)\n* [雨宮美羽](mailto:k737566@gmail.com)\n\nThis document is provided for informational purposes only. Since it is only updated once per release, the version you are looking at may be currently out of date. To see the full list of contributors, consider looking at the [git history](https://github.com/tootsuite/mastodon/graphs/contributors) instead.\n\n## Translators\n\nFollowing people have contributed to translation of Mastodon:\n\n- **Albanian**\n  - Besnik Bleta\n  - Aditoo\n- **Arabic**\n  - ButterflyOfFire\n  - Aditoo\n  - Amrz0\n- **Asturian**\n  - ButterflyOfFire\n  - Enol P.\n  - Aditoo\n- **Basque**\n  - Osoitz\n  - Aditoo\n  - Aitzol\n  - ButterflyOfFire\n  - Peru Iparragirre\n  - Gorka Azkarate\n- **Bengali**\n  - dxwc\n- **Bulgarian**\n  - ButterflyOfFire\n  - Aditoo\n- **Catalan**\n  - spla\n  - Aditoo\n  - ButterflyOfFire\n  - Joan Montané\n  - Jose Luis\n- **Chinese (Hong Kong)**\n  - ButterflyOfFire\n  - Luzi Leung\n  - Aditoo\n- **Chinese (Simplified)**\n  - Allen Zhong\n  - ButterflyOfFire\n  - SerCom_KC\n  - martialarts\n  - Kaitian Xie\n  - Aditoo\n  - pan93412\n- **Chinese (Traditional)**\n  - Aditoo\n  - ButterflyOfFire\n  - James58899\n  - pan93412\n  - S1ttidoe477\n  - SHA265\n  - Jeff Huang\n- **Corsican**\n  - Alix D. R.\n  - Aditoo\n  - ButterflyOfFire\n- **Croatian**\n  - ButterflyOfFire\n  - Aditoo\n- **Czech**\n  - Aditoo\n  - Marek Ľach\n  - ButterflyOfFire\n- **Danish**\n  - Einhjeriar\n  - Rasmus Sæderup\n  - Aditoo\n  - ButterflyOfFire\n- **Dutch**\n  - Albakham\n  - ButterflyOfFire\n  - jeroenpraat\n  - rscmbbng\n  - Aditoo\n  - Jelv\n- **English**\n  - ButterflyOfFire\n  - Renato \"Lond\" Cerqueira\n- **English (United Kingdom)**\n  - Albakham\n- **Esperanto**\n  - Aditoo\n  - ButterflyOfFire\n  - Becci Cat\n  - Jeong Arm\n  - Mélanie Chauvel\n  - Vanege\n  - Martin Bodin\n  - tuxayo/Victor Grousset\n- **Finnish**\n  - ButterflyOfFire\n  - Mikko Poussu\n  - Taru Luojola\n  - S Heija\n  - Aditoo\n  - Jonne Arjoranta\n- **French**\n  - Albakham\n  - Alix D. R.\n  - ButterflyOfFire\n  - codl\n  - Leia\n  - Alda Marteau-Hardi\n  - Mélanie Chauvel\n  - Paul Marques Mota\n  - azenet\n  - Olivier Humbert\n  - Aditoo\n  - Jonathan Chan\n  - Letiteuf55\n  - Baptiste Jonglez\n  - goofy-mdn\n  - Jean-Baptiste Holcroft\n  - Technowix\n  - Martin Bodin\n  - Théodore\n  - Thibaut Girka\n  - Franck Paul\n  - Sylvhem\n- **Galician**\n  - ButterflyOfFire\n  - Xose M.\n  - Aditoo\n  - manequim\n- **Georgian**\n  - ButterflyOfFire\n  - Aditoo\n- **German**\n  - Aditoo\n  - ButterflyOfFire\n  - Daniel\n  - averageunicorn\n  - Koyu Berteon\n  - larsreineke\n  - koyu\n  - Austin Jones\n  - lilo\n  - Benedikt Geißler\n  - ePirat\n  - Eugen Rochko\n  - Weblate Admin\n  - Patrick Figel\n- **Greek**\n  - Dimitris Maroulidis\n  - Antonis\n  - Aditoo\n  - ButterflyOfFire\n  - Konstantinos Grevenitis\n- **Hebrew**\n  - ButterflyOfFire\n  - Aditoo\n  - Ira\n  - Yaron Shahrabani\n- **Hungarian**\n  - ButterflyOfFire\n  - Adam Paszternak\n  - Aditoo\n  - Tibike Miklós\n- **Ido**\n  - ButterflyOfFire\n  - Aditoo\n- **Indonesian**\n  - afachri\n  - ButterflyOfFire\n  - Dito Kurnia Pratama\n  - Eirworks\n  - Aditoo\n  - Alfiana Sibuea\n  - se7entime\n- **Irish**\n  - Albakham\n  - Kevin Houlihan\n- **Italian**\n  - Alessandro Levati\n  - Albakham\n  - ButterflyOfFire\n  - Marcin Mikołajczak\n  - Aditoo\n  - Giuseppe Pignataro\n  - Stefano\n- **Japanese**\n  - Hinaloe\n  - 小鳥遊まりあ\n  - mayaeh\n  - osapon\n  - 森の子リスのミーコの大冒険\n  - Kumasun Morino\n  - Yamagishi Kazutoshi\n  - Aditoo\n  - ButterflyOfFire\n  - Jeong Arm\n  - unarist\n- **Kazakh**\n  - arshat\n  - Aditoo\n- **Korean**\n  - Aditoo\n  - Jeong Arm\n  - ButterflyOfFire\n  - Minori Hiraoka\n  - Yamagishi Kazutoshi\n- **Lithuanian**\n  - Sarunas Medeikis\n- **Malay**\n  - Muhammad Nur Hidayat (MNH48)\n  - Aditoo\n  - ButterflyOfFire\n- **Norwegian (old code)**\n  - ButterflyOfFire\n  - Espen Rønnevik\n  - Aditoo\n  - Tale\n- **Occitan**\n  - Aditoo\n  - ButterflyOfFire\n  - Quenti2\n  - Quentí\n  - Maxenç\n- **Persian**\n  - Masoud Abkenar\n  - Aditoo\n  - ButterflyOfFire\n- **Polish**\n  - Aditoo\n  - Albakham\n  - ButterflyOfFire\n  - Stasiek Michalski\n  - Marcin Mikołajczak\n  - Jakub Mendyk\n  - Marek Ľach\n  - krkk\n- **Portuguese**\n  - Albakham\n  - João Pinheiro\n  - manequim\n  - Aditoo\n  - ButterflyOfFire\n  - Hugo Gameiro\n- **Portuguese (Brazil)**\n  - Aditoo\n  - Albakham\n  - Anna e só\n  - Renato \"Lond\" Cerqueira\n  - André Andrade\n  - ButterflyOfFire\n- **Romanian**\n  - adrianbblk\n  - ButterflyOfFire\n  - Aditoo\n- **Russian**\n  - Albakham\n  - ButterflyOfFire\n  - Evgeny Petrov\n  - Aditoo\n  - Павел Гастелло\n  - Andrew Zyabin\n  - Yaron Shahrabani\n- **Serbian**\n  - Branko Kokanovic\n  - Burekz Finezt\n  - Aditoo\n  - ButterflyOfFire\n- **Serbian (latin)**\n  - ButterflyOfFire\n  - Aditoo\n- **Slovak**\n  - Aditoo\n  - ButterflyOfFire\n  - Ivan Pleva\n  - Marek Ľach\n  - Peter\n- **Slovenian**\n  - Kristijan Tkalec\n  - Aditoo\n  - ButterflyOfFire\n- **Spanish**\n  - Albakham\n  - ButterflyOfFire\n  - Carlos Mondragon\n  - Antón López\n  - Max Winkler\n  - Pablo de la Concepción Sanz\n  - Sergio Soriano\n  - Angeles Broullón\n  - Lothar Wolf\n  - Aditoo\n  - David Charte\n  - Emmanuel\n- **Swedish**\n  - ButterflyOfFire\n  - Isak Holmström\n  - Shellkr\n  - Aditoo\n  - Elias Mårtenson\n  - Stefan Midjich\n  - Tim Stahel\n  - Jonas Hultén\n- **Telugu**\n  - avndp\n  - Ranjith Tellakula\n  - Aditoo\n  - ButterflyOfFire\n  - Joseph Nuthalapati\n- **Thai**\n  - ButterflyOfFire\n  - parnikkapore\n  - Thai Localization\n  - Aditoo\n- **Turkish**\n  - Ali Demirtas\n  - ButterflyOfFire\n  - Aditoo\n- **Ukrainian**\n  - alexcleac\n  - ButterflyOfFire\n  - Aditoo\n  - Ivan Verchenko\n- **Welsh**\n  - carl morris\n  - Jaz-Michael King\n  - Owain Rhys Lewis\n  - Rhoslyn Prys\n  - Aditoo\n  - ButterflyOfFire\n  - Renato \"Lond\" Cerqueira\n  - Albakham\n  - Kevin Beynon\n- **Armenian**\n  - Aditoo\n  - ButterflyOfFire\n- **Latvian**\n  - Aditoo\n  - ButterflyOfFire\n  - Maigonis\n- **Tamil**\n  - Aditoo\n  - ButterflyOfFire\n  - Prasanna Venkadesh\n"
  },
  {
    "path": "Aptfile",
    "content": "ffmpeg\nlibicu[0-9][0-9]\nlibicu-dev\nlibidn11\nlibidn11-dev\nlibpq-dev\nlibprotobuf-dev\nlibssl-dev\nlibxdamage1\nlibxfixes3\nprotobuf-compiler\nzlib1g-dev\nlibcairo2\nlibcroco3\nlibdatrie1\nlibgdk-pixbuf2.0-0\nlibgraphite2-3\nlibharfbuzz0b\nlibpango-1.0-0\nlibpangocairo-1.0-0\nlibpangoft2-1.0-0\nlibpixman-1-0\nlibrsvg2-2\nlibthai-data\nlibthai0\nlibvpx5\nlibxcb-render0\nlibxcb-shm0\nlibxrender1\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\nThis changelog will only include differences from upstream Mastodon. [You can find the upstream\nchangelog here.](https://github.com/tootsuite/mastodon/blob/master/CHANGELOG.md)\n\nPlease note that this project doesn't follow semantic versioning— for details please have a look at\nour [README file].\n\n[README file]: ./README.md\n\n## Pre-Release 0.1.2 [2019-08-18 / v0.0.1.2]\n\nThis release fixes a bug from 0.1.1 before the 0.2.0 release.\n\nIt doesn't add any upstream changes, and is still based off of [Mastodon 2.9.0] plus the commits\nup to [65efe892cf].\n\n### Fixed\n\n* Toot and biography lengths are offered as integers in the API instead of strings\n    * Thanks to [mthld] and [DagAgren] for finding the bug\n    * Thanks to [1011X] for the fix\n\n[mthld]: https://github.com/mthld\n[DagAgren]: https://github.com/DagAgren\n\n## Pre-Release 0.1.1 [2019-07-28 / v0.0.1.1]\n\nThis release fixes a few bugs from 0.1.0 before the 0.2.0 release.\n\nIt doesn't add any upstream changes, and is still based off of [Mastodon 2.9.0] plus the commits\nup to [65efe892cf].\n\n### Fixed\n\n* Toot and biography lengths are now on /api/v1/instance API, for better app integration\n    * Thanks to [ElliotBerriot] for testing 0.1.0 and finding the bug\n    * Thanks to [1011X] for the fix\n* Toot and biography lengths can actually be saved in the admin UI\n    * Thanks to [ElliotBerriot] for testing 0.1.0 and finding the bug\n    * Thanks to [clarfon] for the fix\n* All of the code has been fixed to include the proper project URL and docker image\n    * Thanks to [ElliotBerriot] for debugging 0.1.0 and finding the errors with the Docker files\n    * Thanks to [clarfon] for the fix\n* Broadcasted version has been reverted to the Mastodon version, so that mastodon.py and other\n  libraries work until we find a better solution\n    * Thanks to [Frinkel] for testing 0.1.0 and finding the bug\n    * Thanks to [halcy] for providing insight into how mastodon.py works\n    * Thanks to [1011X] for the fix\n* Blocking entire instance domains now gives a less judgmental message in the English locale\n    * Thanks to [TrechNex] for the fix\n    * Thanks to [mal0ki] and [clarfon] for reviewing the wording\n* Florence-specific settings have been translated into Dutch\n    * Thanks to [rscmbbng] for the translations\n* The [lastest typo] in the README was corrected\n    * Thanks to [ciderpunx] for the fix\n* A few dependencies were updated to fix various security issues\n    * Prototype pollution vulnerabilities were fixed for handlebars and lodash\n    * Thanks to [1011X] for future-proofing CVE-2015-9284 (OAuth vulnerability)\n\n[lastest typo]: https://github.com/florence-social/mastodon-fork/pull/106/files\n\n[ciderpunx]: https://github.com/ciderpunx\n[ElliotBerriot]: https://github.com/ElliotBerriot\n[Frinkel]: https://github.com/Frinkel\n[halcy]: https://github.com/halcy\n[mal0ki]: https://github.com/mal0ki\n[rscmbbng]: https://github.com/rscmbbng\n[TrechNex]: https://github.com/TrechNex\n\n### Special Thanks\n\n* Thank you to everyone who jumped on the Florence train and set up their own instances! We'll try\n  and compile a list of Florence Mastodon instances some time before the next release.\n* Thank you to @TrechNex for helping set up [installation instructions] on his website!\n\n[installation instructions]: https://bobbymoss.com/index.html#install-florence-prerelease\n\n## Pre-Release 0.1.0 [2019-06-18 / v0.0.1.0]\n\nThis release is based off of [Mastodon 2.9.0] plus the commits up to [65efe892cf].\n\n[Mastodon 2.9.0]: https://github.com/tootsuite/mastodon/blob/v2.9.0/CHANGELOG.md\n[65efe892cf]: https://github.com/tootsuite/mastodon/compare/c9eeb2e832b5b36a86028bbec7a353c32be510a7..65efe892cf56cd4f998de885bccc36e9231d8144\n\n### Added\n\n* Toot length can now be configured by an admin; default is 500\n    * Thanks to glitch.social and many other forks for the original code\n    * Thanks to [usbsnowcrash] for the Florence-specific code\n    * Thanks to [m4sk1n] for the Polish translation\n    * Thanks to [clarfon] and [Feufochmar] for the French translation\n    * Thanks to [1011X] and [skrlet13] for the Spanish translation\n* Biography length can now be configured by an admin; default is 500\n    * Thanks to glitch.social and many other forks for the original code\n    * Thanks to [usbsnowcrash] for the Florence-specific code\n    * Thanks to [clarfon] and [Feufochmar] for the French translation\n    * Thanks to [1011X] and [skrlet13] for the Spanish translation\n* Users can choose whether to receive DMs on the home timeline in their settings\n    * Thanks to glitch.social and many other forks for the original code\n    * Thanks to [usbsnowcrash] for the Florence-specific code\n    * Thanks to [clarfon] and [Feufochmar] for the French translation\n    * Thanks to [1011X] and [skrlet13] for the Spanish translation\n* Spanish translations were updated to be more formal\n    * Thanks to [1011X] for the inital changes\n    * Thanks to [skrlet13] for offering feedback and further changes\n\n[1011X]: https://github.com/1011X\n[clarfon]: https://github.com/clarfon\n[Feufochmar]: https://github.com/Feufochmar\n[m4sk1n]: https://github.com/m4sk1n\n[skrlet13]: https://github.com/skrlet13\n[usbsnowcrash]: https://github.com/usbsnowcrash\n\n### Special Thanks\n\n* Thank you to @1011x, @jhaye, @lightdark, @maloki, @skrlet13, @melody, @stolas, @hak, @mecaka:\n  those who've been helping with governance, offering advice, and/or been working on this for the\n  past few months.\n* Thank you to @woozle for hosting both the Wiki and Mattermost for us on their servers.\n* Thank you to all the forkers out there who are providing us both with inspiration, actual code,\n  and conversation about how we can make the Fediverse a little bit better.\n* Thank you to everyone that has been cheerleading us for the past year, helped us have the courage\n  to \"Fork Off\" from Mastodon, and also understood that we are working towards different\n  objectives. That is after all why you all joined us in the first place!\n* Thank you to @mecaka who joined the team while @maloki was getting diagnosed, who helped push\n  through that time and bring us to where we are now.\n* An additional thank you to those that joined the Mattermost server to keep the conversation alive\n  with us after we moved on from Discord!\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "### Table of Contents\n\n- [Code of Conduct](#code-of-conduct)\n  - [Positive participation and communication](#positive-participation-and-communication)\n  - [Prohibited Behavior](#prohibited-behavior)\n    - [Discrimination](#discrimination)\n    - [Harassment and privacy violation](#harassment-and-privacy-violation)\n    - [Harmful and/or adult content](#harmful-andor-adult-content)\n  - [Where does this CoC apply and who does this CoC apply to?](#where-does-this-coc-apply-and-who-does-this-coc-apply-to)\n  - [What if someone violates this Code of Conduct while outside of Florence instances, or in a space or medium to which the Code does not apply?](#what-if-someone-violates-this-code-of-conduct-while-outside-of-florence-instances-or-in-a-space-or-medium-to-which-the-code-does-not-apply)\n  - [When Something Happens](#when-something-happens)\n    - [Example](#example)\n  - [How to make a Code Of Conduct Report](#how-to-make-a-code-of-conduct-report)\n    - [Information to include in your report](#information-to-include-in-your-report)\n  - [Code of Conduct Reporting Guide](#code-of-conduct-reporting-guide)\n  - [What happens after you file a report?](#what-happens-after-you-file-a-report)\n    - [Example](#example-1)\n  - [What if your report concerns a possible violation by a moderator?](#what-if-your-report-concerns-a-possible-violation-by-a-moderator)\n  - [How CoC Reports are handled by moderators](#how-coc-reports-are-handled-by-moderators)\n  - [Accountability for board members and moderators](#accountability-for-board-members-and-moderators)\n  - [Definition of Terms](#definition-of-terms)\n  - [Reference Codes of Conduct](#reference-codes-of-conduct)\n  \n# Code of Conduct\n\nWe strive to reduce barriers to access of our organization, our software and our community, as well as to dismantle any ableist assumptions and practices in our process. We recognize that there is no one solution for universal accessibility, and strive to provide alternatives and choices whenever possible.\nThe stakeholders of this project pledge to institute and abide by a consistent, transparent and accountable human-centered resolution process with a low bar to entry that allows every stakeholder a voice on decisions to do with structural changes and features of both the project's organization and software protocol.\nIf you support an idea, we would like you to help implement it. If you reject an idea, we ask you to help find alternatives.\n\n## Positive participation and communication\n\nFlorence wants to encourage positive participation and communication, in order to make people feel welcome. Positive communication doesn't mean tone policing or that everyone always has to be positive about everything. It means that we want people to feel safe when bringing up their concerns, and create a space where people can have the difficult conversations. To attain this together, we want to:\n\n* Maintain respectful and effective communication.\n* Use welcoming and inclusive language.\n* Show kindness and respect towards others.\n* Encourage and promote the ideas of others.\n* Be respectful of differing viewpoints and experiences.\n* Assume good faith.\n* Understand the challenges in online discussion.\n* Give others the chance to improve.\n* Keep criticism constructive.\n* Take criticism constructively.\n* Respect others’ privacy.\n* Avoid sexualized language without consent of all parties involved.\n* Don’t resort to personal attacks or condescension.\n* No hate speech or similar.\n* Promote and teach respectful, effective communication.\n* Welcome contributions to the project in all the forms they take.\n\n## Prohibited Behavior\n\nThere is also going to be behaviour that will be more strictly prohibited.\n\n### Discrimination\n\n* Do not participate in discrimination or comments promoting or reinforcing the existing systems of oppression of any groups or people based on gender, gender expression, race, ethnicity, nationality, sexuality, religion, disability, mental illness, neurodivergence, personal appearance, physical appearance, body size, age, or class.\n* Do not claim “reverse-isms,” e.g. “reverse racism”\n* Do not participate in xenophobia or violent nationalism.\n\n### Harassment and privacy violation\n\n* Do not contribute to behaviour intended to stalk, harass, or intimidate other users.\n* Do not continue to engage with a user that has specifically asked you to stop, regardless of whether they have blocked or muted you. Do not ask others to engage with them on your behalf.\n* Do not participate in aggregating, posting, and/or disseminating a person’s demographic, personal, or private data without their express permission.\n* Do not post or circulate disseminate a person’s posts, including screen captures or any other content, without their express permission, unless to protect others from the bad behaviour displayed.\n* Do not post or circulate libel, slander, or other known disinformation.\n\n### Harmful and/or adult content\n\n* Do not distribute sexual or violent imagery without a Content Warning.\n* Do not distribute any sexualized depictions of minors, in any way. (This includes drawings and 3D renders.)\n\n## Where does this CoC apply and who does this CoC apply to?\n\nThis code of conduct applies to all official public discussion forums related to this project, including but not limited to public chat, forums, and comments on code.\n\nThis code applies to any member of the community participating in discussions, contributing to the project, or otherwise discussing the project publicly.\n\nIt also would apply in the future main Florence instance. Members of the instance must agree to the CoC.\n\n## What if someone violates this Code of Conduct while outside of Florence instances, or in a space or medium to which the Code does not apply?\n\nUse your judgement, but always feel free to let us know -- we’d rather know more than less. If the person who violates the Code of Conduct intersects with the Florence community in any way, we encourage you to make a report, even if the offending behavior itself was outside of our space.\n\n## When Something Happens\n\nIf you see behavior that is not aligned with this Code of Conduct, here's how you can handle it.\n\nConsider the situation and if it might be useful to screenshot messages in case the messages in question are deleted.\n\nThe person may not be completely aware of the Code of Conduct or specific items within it. **If you consider it safe** and you are comfortable in doing so you can start by letting them know that their actions weren't appropriate and point them to specific parts of the Code of Conduct. One suggestion is to send a private message first, because this can avoid potentially embarrassing someone. Politely and patiently let the person know that their behavior isn’t in line with the Code of Conduct. Share the code of conduct with them and refer to specific parts which you think their behavior is not in line with. You may ask them to adjust their behavior or possibly edit or delete a message.\n\n**If you don’t feel safe or comfortable** telling that person, or they refuse to change their behavior or delete text which is not in line with the CoC, it may be time to report the incident. See how to report an incident in the following section. You may also directly contact admins or moderators, especially if the behavior requires immediate attention\n\n### Example\n\nMary calls John an ableist slur in a discussion chat because he made a mistake. Ana tells Mary via DM that she shouldn't do that because it reinforces the oppression of disabled or neurodivergent people, but Mary calls Ana the same slur, and says that she shouldn't take this so seriously. Then, Ana proceeds to report Mary to a moderator.\n\n## How to make a Code Of Conduct Report\n\nIf you would like to report a Code of Conduct violation contact our moderators via email at report@florencesoc.org. Regardless of outcome, they (or committee) will respond in private to  first acknowledge your report within three days and later with an explanation of the actions taken within a time frame of 14 days.\n\nPlease include any relevant details, links, screenshots, context, or other information that may be used to better understand and resolve the situation.\n\n### Information to include in your report\n\n* Contact information for the reporter including name, email and username.\n* You may report incidents anonymously if you are uncomfortable providing your contact information. However, this may hamper the investigation.\n* The names of all people directly involved in the incident, including relevant nicknames or pseudonyms.\n* Include witness names if possible.\n* Time and forum/location where the incident occurred. Be specific.\n* Details about what happened. Note any supporting materials, such as message screencaps, IRC logs, or emails.\n* Additional context for the situation, if appropriate.\n* Whether or not the incident is ongoing.\n* Any additional information that is relevant to investigating and resolving the incident.\n\n## Code of Conduct Reporting Guide\n\nMost people will feel more comfortable reporting the code of conduct violation rather than directly confronting it, and we encourage those people to email report@florencesoc.org. **All reports will be kept confidential.** In some cases we may determine that a public statement will need to be made in order to inform the broader community. If this need arises, the identities of all parties involved will remain confidential unless those individuals instruct us otherwise.\n\n**If you believe anyone is in physical danger, please notify appropriate law enforcement first.** If you are unsure what law enforcement agency is appropriate, please include this in your report and we will attempt to notify them.\n\nWe encourage you to report incidents, even if you are unsure whether the incident is a violation, or whether the space where it happened is covered by this Code of Conduct. We would much rather have a few extra reports where we decide to take no action, than miss a report of an actual violation. We do not look negatively on you if we find the incident is not a violation. Knowing about incidents that are not violations, or happen outside our spaces, can help us to improve the Code of Conduct and the processes surrounding it.\n\n## What happens after you file a report?\n\nYou will receive an email from the moderators acknowledging receipt. The current Working Group members are [@1011X@mastodon.social](https://mastodon.social/@1011X), [@jhaye@social.libre.fi](https://social.libre.fi/jhaye), and [@skrlet13@chile.masto.host](https://chile.masto.host/@skrlet13).\n\nThe moderators will meet to review the incident and determine:\n\n* What happened based on the perspective of all involved.\n* Whether this event constitutes a code of conduct violation.\n* Who the bad actor was.\n* Whether this is an ongoing situation, or if there is a threat to anyone's physical safety.\n\nWe promise to acknowledge receipt within 72 hours (and will aim for a faster response). If this is determined to be an ongoing incident or a threat to physical safety, the working groups' immediate priority will be to protect everyone involved. This means we may delay an \"official\" response until we believe that the situation has ended and that everyone is physically safe.\n\nOnce the moderators have a complete account of the events, they will make a decision as to how to respond. Responses may include:\n\n* Nothing (if we determine no violation occurred).\n* A private gentle reminder of the code of conduct.\n* A public gentle reminder of the code of conduct.\n* A private reprimand from the working group to the individual(s) involved.\n* A public reprimand.\n* An imposed vacation (i.e. asking someone to \"take a week off\" from a space).\n* A temporary (for a specified time) or indefinite ban from some or all Florence Work Spaces.\n\nWe'll respond within one week to the person who filed the report with either a resolution or an explanation of why the situation is not yet resolved.\n\nOnce we've determined our final action, we'll contact the original reporter to let them know what action (if any) we'll be taking. We'll take into account feedback from the reporter on the appropriateness of our response, but we don't guarantee we'll act on it.\n\n### Example\n\nAna reports Mary. She explains the situation and gives the links and screenshots as proof to the moderator. The moderator examines the case and decides to give Mary a warning. Mary is told this and she will no longer be able to participate if she does that again. Ana is notified of the actions taken by the moderator.\n\n## What if your report concerns a possible violation by a moderator?\n\nThe entire code of conduct working group will see all incident reports sent to report@florencesoc.org. Anyone directly involved in the incident will be immediately recused and will not participate in any discussions of the incident or its resolution.\n\n* If you are uncomfortable submitting a report that will be seen by a person involved in the incident, you can instead send the report directly to the other moderators for resolution.\n\n## How CoC Reports are handled by moderators\n\nWhen a Code of Conduct report is made, moderators should take the issue seriously. If it’s not possible to deal with the report immediately, moderators should send a response saying that the report was received and is being looked into.\n\nModerators will take all reports seriously and prioritize the well-being and comfort of the person making the report recipients of the violation over the comfort of the violator.\n\nAs soon as available, a moderator will join, identify themselves, and take further action.\n\nYou should offer people the kind of support they ask for. If you aren't sure what you're offering will be helpful, ask if that type of thing would be useful.\n\n## Accountability for board members and moderators\n\nBoard members, moderators, and other community members who contributed to running this project will be held to the same code of conduct. Reports against those in positions of power will be taken seriously and handled with respect, prioritizing the safety and well-being of anyone who makes such a report.\n\n## Definition of Terms\n\nWe acknowledge that systemic (structural) oppression works on a society-wide level, enacted by laws and policies, institutions, and culture. It is reflected in and reinforced by individuals’ discriminatory beliefs and actions.  As such, we expect people’s commitment to ending oppression to extend to their own behaviour.\n\n* **Ableism**: Discrimination against disabled, ill, and/or neurodivergent people.\n* **Disability**: A physical or mental condition that limits a person's abilities to interact with their environment.\n* **Gender**: Social construct tied to the perception of social and cultural roles. The most common are male and female.\n* **Gender expression**: Includes personal behavior, mannerisms, interests, and appearance associated with gender in a particular cultural context.\n* **Harassment**: Behaviour towards a person that causes mental or emotional suffering, which includes repeated unwanted contacts without a reasonable purpose, insults, threats, touching, or offensive language.\n* **Hate speech (includes Holocaust denial or Nazi symbolism)**: Speech that oppresses, dehumanizes, and endangers marginalized people or anyone perceived to have a particular marginalization.\n* **Homophobia**: Discrimination against gay people and people who are thought to be gay, incl. the use of homophobic terms where they cause harm.\n* **Inclusivity**: Attitude that recognises and considers people's differences in order to create a welcoming environment without requiring minority assimilation to the majority.\n* **Marginalization**: A social phenomenon by which a minority or sub-group is excluded, and their needs or desires ignored.\n* **Mental illness**: Behavioral or mental pattern that causes significant distress or impairment of personal functioning.\n* **Microaggressions**: brief and commonplace daily verbal, behavioural, or environmental indignities, whether intentional or unintentional, that communicate hostile, derogatory, or negative prejudicial slights and insults toward any group, particularly culturally marginalized groups.\n* **Neurodivergence**: Behavioral or mental pattern that doesn't cause distress but affects the way the person interacts with the environment.\n* **Race**: Social construct tied to phenotypical and social characteristics of a group of people.\n* **Racism**: Discrimination against people of color, including but not limited to microaggressions, tone policing and slurs.\n* **Reverse-isms** (like “reverse racism”): Claims by people privileged  on an axis that they are somehow oppressed by people marginalized  on the same axis.\n* **Sexism**: Discrimination against women and non-binary people. Including derogatory language about women or people perceived as women.\n* **Sexual orientation**: The pattern of attraction to 0 or more genders.\n* **Transphobia**: Discrimination against trans people. This includes arguing someone’s gender, policing their presentation, and malicious misgendering.\n* **Tone Policing**: Attempts to dismiss marginalized people's perspectives by claiming their tone, rather than the content, is unappealing.\n\n## Reference Codes of Conduct\n\n* http://open-zfs.org/wiki/Reporting_Guide\n* https://wiki.snowdrift.coop/community/conduct\n* https://wealljs.org/code-of-conduct\n* https://us.pycon.org/2018/about/code-of-conduct/\n* https://www.coc-handbook.com/\n* https://github.com/ayojs/ayo/blob/latest/CODE_OF_CONDUCT.md\n* https://www.freebsd.org/internal/code-of-conduct.html\n* http://geekfeminism.wikia.com/wiki/Code_of_conduct_evaluations\n* https://www.rust-lang.org/en-US/conduct.html\n* https://docs.google.com/document/d/1V2-YNCRW-Ya2tFzapwLMPMbqWAJZNw4qE40cIWqZti8/edit# (NOVA DSA Socialist Meetings: Participation Guide) This ones nice because it's specifically designed for meetings run with a similar format to ours, though theirs take place offline.\n\n<a rel=\"license\" href=\"http://creativecommons.org/licenses/by-sa/4.0/\"><img alt=\"Creative Commons License\" style=\"border-width:0\" src=\"https://i.creativecommons.org/l/by-sa/4.0/80x15.png\" /></a><br />This work is licensed under a <a rel=\"license\" href=\"http://creativecommons.org/licenses/by-sa/4.0/\">Creative Commons Attribution-ShareAlike 4.0 International License</a>.\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "Contributing\n============\n\nThank you for considering contributing to Florence Mastodon\n\nYou can contribute in the following ways:\n\n- Finding and reporting bugs\n- Translating the Mastodon interface into various languages\n- Contributing code to Mastodon by fixing bugs or implementing features\n- Improving the documentation\n- Joining the conversation on our [Chat]\n- Participate in OutReach or other activities\n- Proof-read\n- And much more\n\nIf you want to contribute with monetary support you can do so via our [Open Collective](https://opencollective.com/florence-social) (which isn't publicly launched yet)\n\n## Adding an Issue for Bug Report or Feature Request\n\nBug reports and feature suggestions can be submitted to [GitHub Issues](https://github.com/florence-social/mastodon-fork/issues). Do not worry about submitting duplicates, but please make a cursory search to see if any similar reports or request have already been resolved or rejected in the past using the search function. If you find a bug or feature request which matches yours you can join the conversation by adding your commentary to that issue.\n\nTry to describe your issue, the use-case, and additional considerations when submitting a feature request.\n\n## Translations\n\nWe will be using Weblate for translations in the near future, but we're waiting for a free account for Open Source Projects via Weblate themselves, in the meanwhile you can submit PRs with translations, or wait. We will update this document as soon as Weblate is available for translations, and will make public announcements elsewhere.\n\n## Documentation\n\nDocumentation work will be added soon, and in the meanwhile you can join us in our [Chat] for documentation.\n\n[Chat]: https://chat.florencesoc.org/signup_user_complete/?id=2a7237f68937b2c4a99ca25c156e6915\n"
  },
  {
    "path": "Capfile",
    "content": "# frozen_string_literal: true\nrequire 'capistrano/setup'\nrequire 'capistrano/deploy'\nrequire 'capistrano/scm/git'\n\ninstall_plugin Capistrano::SCM::Git\n\nrequire 'capistrano/rbenv'\nrequire 'capistrano/bundler'\nrequire 'capistrano/yarn'\nrequire 'capistrano/rails/assets'\nrequire 'capistrano/rails/migrations'\n\nDir.glob('lib/capistrano/tasks/*.rake').each { |r| import r }\n"
  },
  {
    "path": "Dockerfile",
    "content": "FROM ubuntu:18.04 as build-dep\n\n# Use bash for the shell\nSHELL [\"bash\", \"-c\"]\n\n# Install Node\nENV NODE_VER=\"8.15.0\"\nRUN\techo \"Etc/UTC\" > /etc/localtime && \\\n\tapt update && \\\n\tapt -y install wget make gcc g++ python && \\\n\tcd ~ && \\\n\twget https://nodejs.org/download/release/v$NODE_VER/node-v$NODE_VER.tar.gz && \\\n\ttar xf node-v$NODE_VER.tar.gz && \\\n\tcd node-v$NODE_VER && \\\n\t./configure --prefix=/opt/node && \\\n\tmake -j$(nproc) > /dev/null && \\\n\tmake install\n\n# Install jemalloc\nENV JE_VER=\"5.1.0\"\nRUN apt update && \\\n\tapt -y install autoconf && \\\n\tcd ~ && \\\n\twget https://github.com/jemalloc/jemalloc/archive/$JE_VER.tar.gz && \\\n\ttar xf $JE_VER.tar.gz && \\\n\tcd jemalloc-$JE_VER && \\\n\t./autogen.sh && \\\n\t./configure --prefix=/opt/jemalloc && \\\n\tmake -j$(nproc) > /dev/null && \\\n\tmake install_bin install_include install_lib\n\n# Install ruby\nENV RUBY_VER=\"2.6.1\"\nENV CPPFLAGS=\"-I/opt/jemalloc/include\"\nENV LDFLAGS=\"-L/opt/jemalloc/lib/\"\nRUN apt update && \\\n\tapt -y install build-essential \\\n\t\tbison libyaml-dev libgdbm-dev libreadline-dev \\\n\t\tlibncurses5-dev libffi-dev zlib1g-dev libssl-dev && \\\n\tcd ~ && \\\n\twget https://cache.ruby-lang.org/pub/ruby/${RUBY_VER%.*}/ruby-$RUBY_VER.tar.gz && \\\n\ttar xf ruby-$RUBY_VER.tar.gz && \\\n\tcd ruby-$RUBY_VER && \\\n\t./configure --prefix=/opt/ruby \\\n\t  --with-jemalloc \\\n\t  --with-shared \\\n\t  --disable-install-doc && \\\n\tln -s /opt/jemalloc/lib/* /usr/lib/ && \\\n\tmake -j$(nproc) > /dev/null && \\\n\tmake install\n\nENV PATH=\"${PATH}:/opt/ruby/bin:/opt/node/bin\"\n\nRUN npm install -g yarn && \\\n\tgem install bundler && \\\n\tapt update && \\\n\tapt -y install git libicu-dev libidn11-dev \\\n\tlibpq-dev libprotobuf-dev protobuf-compiler\n\nCOPY Gemfile* package.json yarn.lock /opt/mastodon/\n\nRUN cd /opt/mastodon && \\\n\tbundle install -j$(nproc) --deployment --without development test && \\\n\tyarn install --pure-lockfile\n\nFROM ubuntu:18.04\n\n# Copy over all the langs needed for runtime\nCOPY --from=build-dep /opt/node /opt/node\nCOPY --from=build-dep /opt/ruby /opt/ruby\nCOPY --from=build-dep /opt/jemalloc /opt/jemalloc\n\n# Add more PATHs to the PATH\nENV PATH=\"${PATH}:/opt/ruby/bin:/opt/node/bin:/opt/mastodon/bin\"\n\n# Create the mastodon user\nARG UID=991\nARG GID=991\nRUN apt update && \\\n\techo \"Etc/UTC\" > /etc/localtime && \\\n\tln -s /opt/jemalloc/lib/* /usr/lib/ && \\\n\tapt install -y whois wget && \\\n\taddgroup --gid $GID mastodon && \\\n\tuseradd -m -u $UID -g $GID -d /opt/mastodon mastodon && \\\n\techo \"mastodon:`head /dev/urandom | tr -dc A-Za-z0-9 | head -c 24 | mkpasswd -s -m sha-256`\" | chpasswd\n\n# Install mastodon runtime deps\nRUN apt -y --no-install-recommends install \\\n\t  libssl1.1 libpq5 imagemagick ffmpeg \\\n\t  libicu60 libprotobuf10 libidn11 libyaml-0-2 \\\n\t  file ca-certificates tzdata libreadline7 && \\\n\tapt -y install gcc && \\\n\tln -s /opt/mastodon /mastodon && \\\n\tgem install bundler && \\\n\trm -rf /var/cache && \\\n\trm -rf /var/lib/apt/lists/*\n\n# Add tini\nENV TINI_VERSION=\"0.18.0\"\nENV TINI_SUM=\"12d20136605531b09a2c2dac02ccee85e1b874eb322ef6baf7561cd93f93c855\"\nADD https://github.com/krallin/tini/releases/download/v${TINI_VERSION}/tini /tini\nRUN echo \"$TINI_SUM tini\" | sha256sum -c -\nRUN chmod +x /tini\n\n# Copy over mastodon source, and dependencies from building, and set permissions\nCOPY --chown=mastodon:mastodon . /opt/mastodon\nCOPY --from=build-dep --chown=mastodon:mastodon /opt/mastodon /opt/mastodon\n\n# Run mastodon services in prod mode\nENV RAILS_ENV=\"production\"\nENV NODE_ENV=\"production\"\n\n# Tell rails to serve static files\nENV RAILS_SERVE_STATIC_FILES=\"true\"\n\n# Set the run user\nUSER mastodon\n\n# Precompile assets\nRUN cd ~ && \\\n\tOTP_SECRET=precompile_placeholder SECRET_KEY_BASE=precompile_placeholder rails assets:precompile && \\\n\tyarn cache clean\n\n# Set the work dir and the container entry point\nWORKDIR /opt/mastodon\nENTRYPOINT [\"/tini\", \"--\"]\n"
  },
  {
    "path": "Gemfile",
    "content": "# frozen_string_literal: true\n\nsource 'https://rubygems.org'\nruby '>= 2.4.0', '< 2.7.0'\n\ngem 'pkg-config', '~> 1.3'\n\ngem 'puma', '~> 3.12'\ngem 'rails', '~> 5.2.3'\ngem 'thor', '~> 0.20'\n\ngem 'hamlit-rails', '~> 0.2'\ngem 'pg', '~> 1.1'\ngem 'makara', '~> 0.4'\ngem 'pghero', '~> 2.2'\ngem 'dotenv-rails', '~> 2.7'\n\ngem 'aws-sdk-s3', '~> 1.41', require: false\ngem 'fog-core', '<= 2.1.0'\ngem 'fog-openstack', '~> 0.3', require: false\ngem 'paperclip', '~> 6.0'\ngem 'paperclip-av-transcoder', '~> 0.6'\ngem 'streamio-ffmpeg', '~> 3.0'\ngem 'blurhash', '~> 0.1'\n\ngem 'active_model_serializers', '~> 0.10'\ngem 'addressable', '~> 2.6'\ngem 'bootsnap', '~> 1.4', require: false\ngem 'browser'\ngem 'charlock_holmes', '~> 0.7.6'\ngem 'iso-639'\ngem 'chewy', '~> 5.0'\ngem 'cld3', '~> 3.2.4'\ngem 'devise', '~> 4.7'\ngem 'devise-two-factor', '~> 3.0'\n\ngroup :pam_authentication, optional: true do\n  gem 'devise_pam_authenticatable2', '~> 9.2'\nend\n\ngem 'net-ldap', '~> 0.10'\ngem 'omniauth-cas', '~> 1.1'\ngem 'omniauth-rails_csrf_protection', '~> 0.1'\ngem 'omniauth-saml', '~> 1.10'\ngem 'omniauth', '~> 1.9'\n\ngem 'doorkeeper', '~> 5.1'\ngem 'fast_blank', '~> 1.0'\ngem 'fastimage'\ngem 'goldfinger', '~> 2.1'\ngem 'hiredis', '~> 0.6'\ngem 'redis-namespace', '~> 1.5'\ngem 'htmlentities', '~> 4.3'\ngem 'http', '~> 3.3'\ngem 'http_accept_language', '~> 2.1'\ngem 'http_parser.rb', '~> 0.6', git: 'https://github.com/tmm1/http_parser.rb', ref: '54b17ba8c7d8d20a16dfc65d1775241833219cf2'\ngem 'httplog', '~> 1.3'\ngem 'idn-ruby', require: 'idn'\ngem 'kaminari', '~> 1.1'\ngem 'link_header', '~> 0.0'\ngem 'mime-types', '~> 3.2', require: 'mime/types/columnar'\ngem 'nokogiri', '~> 1.10'\ngem 'nsa', '~> 0.2'\ngem 'oj', '~> 3.7'\ngem 'ostatus2', '~> 2.0'\ngem 'ox', '~> 2.10'\ngem 'posix-spawn', git: 'https://github.com/rtomayko/posix-spawn', ref: '58465d2e213991f8afb13b984854a49fcdcc980c'\ngem 'pundit', '~> 2.0'\ngem 'premailer-rails'\ngem 'rack-attack', '~> 6.0'\ngem 'rack-cors', '~> 1.0', require: 'rack/cors'\ngem 'rails-i18n', '~> 5.1'\ngem 'rails-settings-cached', '~> 0.6'\ngem 'redis', '~> 4.1', require: ['redis', 'redis/connection/hiredis']\ngem 'mario-redis-lock', '~> 1.2', require: 'redis_lock'\ngem 'rqrcode', '~> 0.10'\ngem 'sanitize', '~> 5.0'\ngem 'sidekiq', '~> 5.2'\ngem 'sidekiq-scheduler', '~> 3.0'\ngem 'sidekiq-unique-jobs', '~> 6.0'\ngem 'sidekiq-bulk', '~>0.2.0'\ngem 'simple-navigation', '~> 4.0'\ngem 'simple_form', '~> 4.1'\ngem 'sprockets-rails', '~> 3.2', require: 'sprockets/railtie'\ngem 'stoplight', '~> 2.1.3'\ngem 'strong_migrations', '~> 0.4'\ngem 'tty-command', '~> 0.8', require: false\ngem 'tty-prompt', '~> 0.19', require: false\ngem 'twitter-text', '~> 1.14'\ngem 'tzinfo-data', '~> 1.2019'\ngem 'webpacker', '~> 4.0'\ngem 'webpush'\n\ngem 'json-ld', '~> 3.0'\ngem 'json-ld-preloaded', '~> 3.0'\ngem 'rdf-normalize', '~> 0.3'\n\ngroup :development, :test do\n  gem 'fabrication', '~> 2.20'\n  gem 'fuubar', '~> 2.4'\n  gem 'i18n-tasks', '~> 0.9', require: false\n  gem 'pry-byebug', '~> 3.7'\n  gem 'pry-rails', '~> 0.3'\n  gem 'rspec-rails', '~> 3.8'\nend\n\ngroup :production, :test do\n  gem 'private_address_check', '~> 0.5'\nend\n\ngroup :test do\n  gem 'capybara', '~> 3.22'\n  gem 'climate_control', '~> 0.2'\n  gem 'faker', '~> 1.9'\n  gem 'microformats', '~> 4.1'\n  gem 'rails-controller-testing', '~> 1.0'\n  gem 'rspec-sidekiq', '~> 3.0'\n  gem 'simplecov', '~> 0.16', require: false\n  gem 'webmock', '~> 3.5'\n  gem 'parallel_tests', '~> 2.29'\nend\n\ngroup :development do\n  gem 'active_record_query_trace', '~> 1.6'\n  gem 'annotate', '~> 2.7'\n  gem 'better_errors', '~> 2.5'\n  gem 'binding_of_caller', '~> 0.7'\n  gem 'bullet', '~> 6.0'\n  gem 'letter_opener', '~> 1.7'\n  gem 'letter_opener_web', '~> 1.3'\n  gem 'memory_profiler'\n  gem 'rubocop', '~> 0.71', require: false\n  gem 'rubocop-rails', '~> 2.0', require: false\n  gem 'brakeman', '~> 4.5', require: false\n  gem 'bundler-audit', '~> 0.6', require: false\n\n  gem 'capistrano', '~> 3.11'\n  gem 'capistrano-rails', '~> 1.4'\n  gem 'capistrano-rbenv', '~> 2.1'\n  gem 'capistrano-yarn', '~> 2.0'\n\n  gem 'derailed_benchmarks'\n  gem 'stackprof'\nend\n\ngroup :production do\n  gem 'lograge', '~> 0.11'\n  gem 'redis-rails', '~> 5.0'\nend\n\ngem 'concurrent-ruby', require: false\n"
  },
  {
    "path": "LICENSE",
    "content": "                    GNU AFFERO GENERAL PUBLIC LICENSE\n                       Version 3, 19 November 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU Affero General Public License is a free, copyleft license for\nsoftware and other kinds of works, specifically designed to ensure\ncooperation with the community in the case of network server software.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nour General Public Licenses are intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  Developers that use our General Public Licenses protect your rights\nwith two steps: (1) assert copyright on the software, and (2) offer\nyou this License which gives you legal permission to copy, distribute\nand/or modify the software.\n\n  A secondary benefit of defending all users' freedom is that\nimprovements made in alternate versions of the program, if they\nreceive widespread use, become available for other developers to\nincorporate.  Many developers of free software are heartened and\nencouraged by the resulting cooperation.  However, in the case of\nsoftware used on network servers, this result may fail to come about.\nThe GNU General Public License permits making a modified version and\nletting the public access it on a server without ever releasing its\nsource code to the public.\n\n  The GNU Affero General Public License is designed specifically to\nensure that, in such cases, the modified source code becomes available\nto the community.  It requires the operator of a network server to\nprovide the source code of the modified version running there to the\nusers of that server.  Therefore, public use of a modified version, on\na publicly accessible server, gives the public access to the source\ncode of the modified version.\n\n  An older license, called the Affero General Public License and\npublished by Affero, was designed to accomplish similar goals.  This is\na different license, not a version of the Affero GPL, but Affero has\nreleased a new version of the Affero GPL which permits relicensing under\nthis license.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU Affero General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Remote Network Interaction; Use with the GNU General Public License.\n\n  Notwithstanding any other provision of this License, if you modify the\nProgram, your modified version must prominently offer all users\ninteracting with it remotely through a computer network (if your version\nsupports such interaction) an opportunity to receive the Corresponding\nSource of your version by providing access to the Corresponding Source\nfrom a network server at no charge, through some standard or customary\nmeans of facilitating copying of software.  This Corresponding Source\nshall include the Corresponding Source for any work covered by version 3\nof the GNU General Public License that is incorporated pursuant to the\nfollowing paragraph.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the work with which it is combined will remain governed by version\n3 of the GNU General Public License.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU Affero General Public License from time to time.  Such new versions\nwill be similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU Affero General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU Affero General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU Affero General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU Affero General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU Affero General Public License for more details.\n\n    You should have received a copy of the GNU Affero General Public License\n    along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If your software can interact with users remotely through a computer\nnetwork, you should also make sure that it provides a way for users to\nget its source.  For example, if your program is a web application, its\ninterface could display a \"Source\" link that leads users to an archive\nof the code.  There are many ways you could offer source, and different\nsolutions will be better for different programs; see section 13 for the\nspecific requirements.\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU AGPL, see\n<http://www.gnu.org/licenses/>.\n"
  },
  {
    "path": "Procfile",
    "content": "web: bundle exec puma -C config/puma.rb\nworker: bundle exec sidekiq\n"
  },
  {
    "path": "Procfile.dev",
    "content": "web: env PORT=3000 bundle exec puma -C config/puma.rb\nsidekiq: env PORT=3000 bundle exec sidekiq\nstream: env PORT=4000 yarn run start\nwebpack: ./bin/webpack-dev-server --listen-host 0.0.0.0\n"
  },
  {
    "path": "README.md",
    "content": "Florence Mastodon\n=================\n\nMastodon is a **free, open-source social network server** based on ActivityPub. This is *not* the\nofficial version of Mastodon; this is a separate version (i.e. a fork) maintained by Florence. For\nmore information on Mastodon, you can see the [official website] and the [upstream repo].\n\n[official website]: https://joinmastodon.org\n[upstream repo]: https://github.com/tootsuite/mastodon\n\nThis version of Mastodon will include much-wanted changes by the community that are not included\nin the upstream version of Mastodon. Migrating from the latest stable release of Mastodon to\nFlorence's Mastodon will always be possible, to ensure that everyone can benefit from these\nchanges.\n\n## Versioning\n\nFlorence Mastodon uses a four-numbered versioning system, loosely based upon [semantic\nversioning]. The four numbers are:\n* **Compatibility**: Increased when federation, app compatibility, etc. are changed in a\n  non-compatibile way.\n* **Feel**: Increased when user experience is changed strongly enough to feel different, i.e. more\n  than just small new features.\n* **Features**: Increased when new features are added. Reset to zero when **feel** version is\n  bumped.\n* **Hotfixes**: Increased when fixes are substantial enough to release a new version without any new\n  features. Reset to zero when **feature** version is bumped.\n\nFor now, because this versioning system hasn't been strongly adopted, releases will be annotated as\n**Pre-Release x.y.z**, which is equivalent to version 0.x.y.z.\n\n[semantic versioning]: https://semver.org\n\n## Release timeline\n\nPre-release 0.1.0 is mostly equivalent to Mastodon 2.9.0, with some extra changes added in.\nRight now, the goal before pre-release 1.0.0 is to incorporate existing, already-developed changes\ninto the fork so that people have a central version to upgrade to. Once we've finally gotten the\nsoftware to the point where we like it, we will release the first official release, which will be\nnamed something special. Stay tuned!\n\n## License\n\nCopyright (C) 2016-2019 Florence, Eugen Rochko, and many other Mastodon contributors; see [AUTHORS.md](AUTHORS.md).\n\nThis program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.\n\nYou should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.\n"
  },
  {
    "path": "Rakefile",
    "content": "# Add your own tasks in files placed in lib/tasks ending in .rake,\n# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.\n\nrequire File.expand_path('../config/application', __FILE__)\n\nRails.application.load_tasks\n"
  },
  {
    "path": "Vagrantfile",
    "content": "# -*- mode: ruby -*-\n# vi: set ft=ruby :\n\nENV[\"PORT\"] ||= \"3000\"\n\n$provision = <<SCRIPT\n\ncd /vagrant # This is where the host folder/repo is mounted\n\n# Add the yarn repo + yarn repo keys\ncurl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -\nsudo apt-add-repository 'deb https://dl.yarnpkg.com/debian/ stable main'\n\n# Add repo for NodeJS\ncurl -sL https://deb.nodesource.com/setup_8.x | sudo bash -\n\n# Add firewall rule to redirect 80 to PORT and save\nsudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port #{ENV[\"PORT\"]}\necho iptables-persistent iptables-persistent/autosave_v4 boolean true | sudo debconf-set-selections\necho iptables-persistent iptables-persistent/autosave_v6 boolean true | sudo debconf-set-selections\nsudo apt-get install iptables-persistent -y\n\n# Add packages to build and run Mastodon\nsudo apt-get install \\\n  git-core \\\n  g++ \\\n  libpq-dev \\\n  libxml2-dev \\\n  libxslt1-dev \\\n  imagemagick \\\n  nodejs \\\n  redis-server \\\n  redis-tools \\\n  postgresql \\\n  postgresql-contrib \\\n  protobuf-compiler \\\n  yarn \\\n  libicu-dev \\\n  libidn11-dev \\\n  libprotobuf-dev \\\n  libreadline-dev \\\n  libpam0g-dev \\\n  -y\n\n# Install rvm\nread RUBY_VERSION < .ruby-version\n\ngpg_command=\"gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB\"\n$($gpg_command)\nif [ $? -ne 0 ];then\n  echo \"GPG command failed, This prevented RVM from installing.\"\n  echo \"Retrying once...\" && $($gpg_command)\n  if [ $? -ne 0 ];then\n    echo \"GPG failed for the second time, please ensure network connectivity.\"\n    echo \"Exiting...\" && exit 1\n  fi\nfi\n\ncurl -sSL https://raw.githubusercontent.com/rvm/rvm/stable/binscripts/rvm-installer | bash -s stable --ruby=$RUBY_VERSION\nsource /home/vagrant/.rvm/scripts/rvm\n\n# Install Ruby\nrvm reinstall ruby-$RUBY_VERSION --disable-binary\n\n# Configure database\nsudo -u postgres createuser -U postgres vagrant -s\nsudo -u postgres createdb -U postgres mastodon_development\n\n# Install gems and node modules\ngem install bundler foreman\nbundle install\nyarn install\n\n# Build Mastodon\nexport $(cat \".env.vagrant\" | xargs)\nbundle exec rails db:setup\n\n# Configure automatic loading of environment variable\necho 'export $(cat \"/vagrant/.env.vagrant\" | xargs)' >> ~/.bash_profile\n\nSCRIPT\n\n$start = <<SCRIPT\n\necho 'To start server'\necho '  $ vagrant ssh -c \"cd /vagrant && foreman start\"'\n\nSCRIPT\n\nVAGRANTFILE_API_VERSION = \"2\"\n\nVagrant.configure(VAGRANTFILE_API_VERSION) do |config|\n\n  config.vm.box = \"ubuntu/xenial64\"\n\n  config.vm.provider :virtualbox do |vb|\n    vb.name = \"mastodon\"\n    vb.customize [\"modifyvm\", :id, \"--memory\", \"2048\"]\n    # Increase the number of CPUs. Uncomment and adjust to\n    # increase performance\n    # vb.customize [\"modifyvm\", :id, \"--cpus\", \"3\"]\n\n    # Disable VirtualBox DNS proxy to skip long-delay IPv6 resolutions.\n    # https://github.com/mitchellh/vagrant/issues/1172\n    vb.customize [\"modifyvm\", :id, \"--natdnsproxy1\", \"off\"]\n    vb.customize [\"modifyvm\", :id, \"--natdnshostresolver1\", \"off\"]\n\n    # Use \"virtio\" network interfaces for better performance.\n    vb.customize [\"modifyvm\", :id, \"--nictype1\", \"virtio\"]\n    vb.customize [\"modifyvm\", :id, \"--nictype2\", \"virtio\"]\n\n  end\n\n  # This uses the vagrant-hostsupdater plugin, and lets you\n  # access the development site at http://mastodon.local.\n  # If you change it, also change it in .env.vagrant before provisioning\n  # the vagrant server to update the development build.\n  #\n  # To install:\n  #   $ vagrant plugin install vagrant-hostsupdater\n  config.vm.hostname = \"mastodon.local\"\n\n  if defined?(VagrantPlugins::HostsUpdater)\n    config.vm.network :private_network, ip: \"192.168.42.42\", nictype: \"virtio\"\n    config.hostsupdater.remove_on_suspend = false\n  end\n\n  if config.vm.networks.any? { |type, options| type == :private_network }\n    config.vm.synced_folder \".\", \"/vagrant\", type: \"nfs\", mount_options: ['rw', 'vers=3', 'tcp', 'actimeo=1']\n  else\n    config.vm.synced_folder \".\", \"/vagrant\"\n  end\n\n  # Otherwise, you can access the site at http://localhost:3000 and http://localhost:4000 , http://localhost:8080\n  config.vm.network :forwarded_port, guest: 3000, host: 3000\n  config.vm.network :forwarded_port, guest: 4000, host: 4000\n  config.vm.network :forwarded_port, guest: 8080, host: 8080\n\n  # Full provisioning script, only runs on first 'vagrant up' or with 'vagrant provision'\n  config.vm.provision :shell, inline: $provision, privileged: false\n\n  # Start up script, runs on every 'vagrant up'\n  config.vm.provision :shell, inline: $start, run: 'always', privileged: false\n\nend\n"
  },
  {
    "path": "app/chewy/statuses_index.rb",
    "content": "# frozen_string_literal: true\n\nclass StatusesIndex < Chewy::Index\n  settings index: { refresh_interval: '15m' }, analysis: {\n    filter: {\n      english_stop: {\n        type: 'stop',\n        stopwords: '_english_',\n      },\n      english_stemmer: {\n        type: 'stemmer',\n        language: 'english',\n      },\n      english_possessive_stemmer: {\n        type: 'stemmer',\n        language: 'possessive_english',\n      },\n    },\n    analyzer: {\n      content: {\n        tokenizer: 'uax_url_email',\n        filter: %w(\n          english_possessive_stemmer\n          lowercase\n          asciifolding\n          cjk_width\n          english_stop\n          english_stemmer\n        ),\n      },\n    },\n  }\n\n  define_type ::Status.unscoped.without_reblogs.includes(:media_attachments) do\n    crutch :mentions do |collection|\n      data = ::Mention.where(status_id: collection.map(&:id)).pluck(:status_id, :account_id)\n      data.each.with_object({}) { |(id, name), result| (result[id] ||= []).push(name) }\n    end\n\n    crutch :favourites do |collection|\n      data = ::Favourite.where(status_id: collection.map(&:id)).pluck(:status_id, :account_id)\n      data.each.with_object({}) { |(id, name), result| (result[id] ||= []).push(name) }\n    end\n\n    crutch :reblogs do |collection|\n      data = ::Status.where(reblog_of_id: collection.map(&:id)).pluck(:reblog_of_id, :account_id)\n      data.each.with_object({}) { |(id, name), result| (result[id] ||= []).push(name) }\n    end\n\n    root date_detection: false do\n      field :id, type: 'long'\n      field :account_id, type: 'long'\n\n      field :text, type: 'text', value: ->(status) { [status.spoiler_text, Formatter.instance.plaintext(status)].concat(status.media_attachments.map(&:description)).join(\"\\n\\n\") } do\n        field :stemmed, type: 'text', analyzer: 'content'\n      end\n\n      field :searchable_by, type: 'long', value: ->(status, crutches) { status.searchable_by(crutches) }\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/about_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass AboutController < ApplicationController\n  layout 'public'\n\n  before_action :set_instance_presenter, only: [:show, :more, :terms]\n\n  def show\n    @hide_navbar = true\n  end\n\n  def more; end\n\n  def terms; end\n\n  private\n\n  def new_user\n    User.new.tap do |user|\n      user.build_account\n      user.build_invite_request\n    end\n  end\n\n  helper_method :new_user\n\n  def set_instance_presenter\n    @instance_presenter = InstancePresenter.new\n  end\nend\n"
  },
  {
    "path": "app/controllers/account_follow_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass AccountFollowController < ApplicationController\n  include AccountControllerConcern\n\n  before_action :authenticate_user!\n\n  def create\n    FollowService.new.call(current_user.account, @account.acct)\n    redirect_to account_path(@account)\n  end\nend\n"
  },
  {
    "path": "app/controllers/account_unfollow_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass AccountUnfollowController < ApplicationController\n  include AccountControllerConcern\n\n  before_action :authenticate_user!\n\n  def create\n    UnfollowService.new.call(current_user.account, @account)\n    redirect_to account_path(@account)\n  end\nend\n"
  },
  {
    "path": "app/controllers/accounts_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass AccountsController < ApplicationController\n  PAGE_SIZE = 20\n\n  include AccountControllerConcern\n\n  before_action :set_cache_headers\n\n  def show\n    respond_to do |format|\n      format.html do\n        mark_cacheable! unless user_signed_in?\n\n        @body_classes      = 'with-modals'\n        @pinned_statuses   = []\n        @endorsed_accounts = @account.endorsed_accounts.to_a.sample(4)\n\n        if current_account && @account.blocking?(current_account)\n          @statuses = []\n          return\n        end\n\n        @pinned_statuses = cache_collection(@account.pinned_statuses, Status) if show_pinned_statuses?\n        @statuses        = filtered_status_page(params)\n        @statuses        = cache_collection(@statuses, Status)\n\n        unless @statuses.empty?\n          @older_url = older_url if @statuses.last.id > filtered_statuses.last.id\n          @newer_url = newer_url if @statuses.first.id < filtered_statuses.first.id\n        end\n      end\n\n      format.atom do\n        mark_cacheable!\n\n        @entries = @account.stream_entries.where(hidden: false).with_includes.paginate_by_max_id(PAGE_SIZE, params[:max_id], params[:since_id])\n        render xml: OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.feed(@account, @entries.reject { |entry| entry.status.nil? }))\n      end\n\n      format.rss do\n        mark_cacheable!\n\n        @statuses = cache_collection(default_statuses.without_reblogs.without_replies.limit(PAGE_SIZE), Status)\n        render xml: RSS::AccountSerializer.render(@account, @statuses)\n      end\n\n      format.json do\n        render_cached_json(['activitypub', 'actor', @account], content_type: 'application/activity+json') do\n          ActiveModelSerializers::SerializableResource.new(@account, serializer: ActivityPub::ActorSerializer, adapter: ActivityPub::Adapter)\n        end\n      end\n    end\n  end\n\n  private\n\n  def show_pinned_statuses?\n    [replies_requested?, media_requested?, tag_requested?, params[:max_id].present?, params[:min_id].present?].none?\n  end\n\n  def filtered_statuses\n    default_statuses.tap do |statuses|\n      statuses.merge!(hashtag_scope)    if tag_requested?\n      statuses.merge!(only_media_scope) if media_requested?\n      statuses.merge!(no_replies_scope) unless replies_requested?\n    end\n  end\n\n  def default_statuses\n    @account.statuses.where(visibility: [:public, :unlisted])\n  end\n\n  def only_media_scope\n    Status.where(id: account_media_status_ids)\n  end\n\n  def account_media_status_ids\n    @account.media_attachments.attached.reorder(nil).select(:status_id).distinct\n  end\n\n  def no_replies_scope\n    Status.without_replies\n  end\n\n  def hashtag_scope\n    tag = Tag.find_normalized(params[:tag])\n\n    if tag\n      Status.tagged_with(tag.id)\n    else\n      Status.none\n    end\n  end\n\n  def username_param\n    params[:username]\n  end\n\n  def older_url\n    pagination_url(max_id: @statuses.last.id)\n  end\n\n  def newer_url\n    pagination_url(min_id: @statuses.first.id)\n  end\n\n  def pagination_url(max_id: nil, min_id: nil)\n    if tag_requested?\n      short_account_tag_url(@account, params[:tag], max_id: max_id, min_id: min_id)\n    elsif media_requested?\n      short_account_media_url(@account, max_id: max_id, min_id: min_id)\n    elsif replies_requested?\n      short_account_with_replies_url(@account, max_id: max_id, min_id: min_id)\n    else\n      short_account_url(@account, max_id: max_id, min_id: min_id)\n    end\n  end\n\n  def media_requested?\n    request.path.ends_with?('/media')\n  end\n\n  def replies_requested?\n    request.path.ends_with?('/with_replies')\n  end\n\n  def tag_requested?\n    request.path.ends_with?(Addressable::URI.parse(\"/tagged/#{params[:tag]}\").normalize)\n  end\n\n  def filtered_status_page(params)\n    if params[:min_id].present?\n      filtered_statuses.paginate_by_min_id(PAGE_SIZE, params[:min_id]).reverse\n    else\n      filtered_statuses.paginate_by_max_id(PAGE_SIZE, params[:max_id], params[:since_id]).to_a\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/activitypub/collections_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::CollectionsController < Api::BaseController\n  include SignatureVerification\n\n  before_action :set_account\n  before_action :set_size\n  before_action :set_statuses\n  before_action :set_cache_headers\n\n  def show\n    render_cached_json(['activitypub', 'collection', @account, params[:id]], content_type: 'application/activity+json') do\n      ActiveModelSerializers::SerializableResource.new(\n        collection_presenter,\n        serializer: ActivityPub::CollectionSerializer,\n        adapter: ActivityPub::Adapter,\n        skip_activities: true\n      )\n    end\n  end\n\n  private\n\n  def set_account\n    @account = Account.find_local!(params[:account_username])\n  end\n\n  def set_statuses\n    @statuses = scope_for_collection\n    @statuses = cache_collection(@statuses, Status)\n  end\n\n  def set_size\n    case params[:id]\n    when 'featured'\n      @account.pinned_statuses.count\n    else\n      raise ActiveRecord::RecordNotFound\n    end\n  end\n\n  def scope_for_collection\n    case params[:id]\n    when 'featured'\n      @account.statuses.permitted_for(@account, signed_request_account).tap do |scope|\n        scope.merge!(@account.pinned_statuses)\n      end\n    else\n      raise ActiveRecord::RecordNotFound\n    end\n  end\n\n  def collection_presenter\n    ActivityPub::CollectionPresenter.new(\n      id: account_collection_url(@account, params[:id]),\n      type: :ordered,\n      size: @size,\n      items: @statuses\n    )\n  end\nend\n"
  },
  {
    "path": "app/controllers/activitypub/inboxes_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::InboxesController < Api::BaseController\n  include SignatureVerification\n  include JsonLdHelper\n\n  before_action :set_account\n\n  def create\n    if unknown_deleted_account?\n      head 202\n    elsif signed_request_account\n      upgrade_account\n      process_payload\n      head 202\n    else\n      render plain: signature_verification_failure_reason, status: 401\n    end\n  end\n\n  private\n\n  def unknown_deleted_account?\n    json = Oj.load(body, mode: :strict)\n    json['type'] == 'Delete' && json['actor'].present? && json['actor'] == value_or_id(json['object']) && !Account.where(uri: json['actor']).exists?\n  rescue Oj::ParseError\n    false\n  end\n\n  def set_account\n    @account = Account.find_local!(params[:account_username]) if params[:account_username]\n  end\n\n  def body\n    return @body if defined?(@body)\n    @body = request.body.read.force_encoding('UTF-8')\n    request.body.rewind if request.body.respond_to?(:rewind)\n    @body\n  end\n\n  def upgrade_account\n    if signed_request_account.ostatus?\n      signed_request_account.update(last_webfingered_at: nil)\n      ResolveAccountWorker.perform_async(signed_request_account.acct)\n    end\n\n    Pubsubhubbub::UnsubscribeWorker.perform_async(signed_request_account.id) if signed_request_account.subscribed?\n    DeliveryFailureTracker.track_inverse_success!(signed_request_account)\n  end\n\n  def process_payload\n    ActivityPub::ProcessingWorker.perform_async(signed_request_account.id, body, @account&.id)\n  end\nend\n"
  },
  {
    "path": "app/controllers/activitypub/outboxes_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::OutboxesController < Api::BaseController\n  LIMIT = 20\n\n  include SignatureVerification\n\n  before_action :set_account\n  before_action :set_statuses\n  before_action :set_cache_headers\n\n  def show\n    expires_in 1.minute, public: true unless page_requested?\n\n    render json: outbox_presenter, serializer: ActivityPub::OutboxSerializer, adapter: ActivityPub::Adapter, content_type: 'application/activity+json'\n  end\n\n  private\n\n  def set_account\n    @account = Account.find_local!(params[:account_username])\n  end\n\n  def outbox_presenter\n    if page_requested?\n      ActivityPub::CollectionPresenter.new(\n        id: account_outbox_url(@account, page_params),\n        type: :ordered,\n        part_of: account_outbox_url(@account),\n        prev: prev_page,\n        next: next_page,\n        items: @statuses\n      )\n    else\n      ActivityPub::CollectionPresenter.new(\n        id: account_outbox_url(@account),\n        type: :ordered,\n        size: @account.statuses_count,\n        first: account_outbox_url(@account, page: true),\n        last: account_outbox_url(@account, page: true, min_id: 0)\n      )\n    end\n  end\n\n  def next_page\n    account_outbox_url(@account, page: true, max_id: @statuses.last.id) if @statuses.size == LIMIT\n  end\n\n  def prev_page\n    account_outbox_url(@account, page: true, min_id: @statuses.first.id) unless @statuses.empty?\n  end\n\n  def set_statuses\n    return unless page_requested?\n\n    @statuses = @account.statuses.permitted_for(@account, signed_request_account)\n    @statuses = params[:min_id].present? ? @statuses.paginate_by_min_id(LIMIT, params[:min_id]).reverse : @statuses.paginate_by_max_id(LIMIT, params[:max_id])\n    @statuses = cache_collection(@statuses, Status)\n  end\n\n  def page_requested?\n    params[:page] == 'true'\n  end\n\n  def page_params\n    { page: true, max_id: params[:max_id], min_id: params[:min_id] }.compact\n  end\nend\n"
  },
  {
    "path": "app/controllers/admin/account_actions_controller.rb",
    "content": "# frozen_string_literal: true\n\nmodule Admin\n  class AccountActionsController < BaseController\n    before_action :set_account\n\n    def new\n      @account_action  = Admin::AccountAction.new(type: params[:type], report_id: params[:report_id], send_email_notification: true)\n      @warning_presets = AccountWarningPreset.all\n    end\n\n    def create\n      account_action                 = Admin::AccountAction.new(resource_params)\n      account_action.target_account  = @account\n      account_action.current_account = current_account\n\n      account_action.save!\n\n      if account_action.with_report?\n        redirect_to admin_reports_path\n      else\n        redirect_to admin_account_path(@account.id)\n      end\n    end\n\n    private\n\n    def set_account\n      @account = Account.find(params[:account_id])\n    end\n\n    def resource_params\n      params.require(:admin_account_action).permit(:type, :report_id, :warning_preset_id, :text, :send_email_notification)\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/admin/account_moderation_notes_controller.rb",
    "content": "# frozen_string_literal: true\n\nmodule Admin\n  class AccountModerationNotesController < BaseController\n    before_action :set_account_moderation_note, only: [:destroy]\n\n    def create\n      authorize AccountModerationNote, :create?\n\n      @account_moderation_note = current_account.account_moderation_notes.new(resource_params)\n\n      if @account_moderation_note.save\n        redirect_to admin_account_path(@account_moderation_note.target_account_id), notice: I18n.t('admin.account_moderation_notes.created_msg')\n      else\n        @account          = @account_moderation_note.target_account\n        @moderation_notes = @account.targeted_moderation_notes.latest\n        @warnings         = @account.targeted_account_warnings.latest.custom\n\n        render template: 'admin/accounts/show'\n      end\n    end\n\n    def destroy\n      authorize @account_moderation_note, :destroy?\n      @account_moderation_note.destroy!\n      redirect_to admin_account_path(@account_moderation_note.target_account_id), notice: I18n.t('admin.account_moderation_notes.destroyed_msg')\n    end\n\n    private\n\n    def resource_params\n      params.require(:account_moderation_note).permit(\n        :content,\n        :target_account_id\n      )\n    end\n\n    def set_account_moderation_note\n      @account_moderation_note = AccountModerationNote.find(params[:id])\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/admin/accounts_controller.rb",
    "content": "# frozen_string_literal: true\n\nmodule Admin\n  class AccountsController < BaseController\n    before_action :set_account, only: [:show, :subscribe, :unsubscribe, :redownload, :remove_avatar, :remove_header, :enable, :unsilence, :unsuspend, :memorialize, :approve, :reject]\n    before_action :require_remote_account!, only: [:subscribe, :unsubscribe, :redownload]\n    before_action :require_local_account!, only: [:enable, :memorialize, :approve, :reject]\n\n    def index\n      authorize :account, :index?\n      @accounts = filtered_accounts.page(params[:page])\n    end\n\n    def show\n      authorize @account, :show?\n\n      @account_moderation_note = current_account.account_moderation_notes.new(target_account: @account)\n      @moderation_notes        = @account.targeted_moderation_notes.latest\n      @warnings                = @account.targeted_account_warnings.latest.custom\n    end\n\n    def subscribe\n      authorize @account, :subscribe?\n      Pubsubhubbub::SubscribeWorker.perform_async(@account.id)\n      redirect_to admin_account_path(@account.id)\n    end\n\n    def unsubscribe\n      authorize @account, :unsubscribe?\n      Pubsubhubbub::UnsubscribeWorker.perform_async(@account.id)\n      redirect_to admin_account_path(@account.id)\n    end\n\n    def memorialize\n      authorize @account, :memorialize?\n      @account.memorialize!\n      log_action :memorialize, @account\n      redirect_to admin_account_path(@account.id)\n    end\n\n    def enable\n      authorize @account.user, :enable?\n      @account.user.enable!\n      log_action :enable, @account.user\n      redirect_to admin_account_path(@account.id)\n    end\n\n    def approve\n      authorize @account.user, :approve?\n      @account.user.approve!\n      redirect_to admin_pending_accounts_path\n    end\n\n    def reject\n      authorize @account.user, :reject?\n      SuspendAccountService.new.call(@account, including_user: true, destroy: true, skip_distribution: true)\n      redirect_to admin_pending_accounts_path\n    end\n\n    def unsilence\n      authorize @account, :unsilence?\n      @account.unsilence!\n      log_action :unsilence, @account\n      redirect_to admin_account_path(@account.id)\n    end\n\n    def unsuspend\n      authorize @account, :unsuspend?\n      @account.unsuspend!\n      log_action :unsuspend, @account\n      redirect_to admin_account_path(@account.id)\n    end\n\n    def redownload\n      authorize @account, :redownload?\n\n      @account.update!(last_webfingered_at: nil)\n      ResolveAccountService.new.call(@account)\n\n      redirect_to admin_account_path(@account.id)\n    end\n\n    def remove_avatar\n      authorize @account, :remove_avatar?\n\n      @account.avatar = nil\n      @account.save!\n\n      log_action :remove_avatar, @account.user\n\n      redirect_to admin_account_path(@account.id)\n    end\n\n    def remove_header\n      authorize @account, :remove_header?\n\n      @account.header = nil\n      @account.save!\n\n      log_action :remove_header, @account.user\n\n      redirect_to admin_account_path(@account.id)\n    end\n\n    private\n\n    def set_account\n      @account = Account.find(params[:id])\n    end\n\n    def require_remote_account!\n      redirect_to admin_account_path(@account.id) if @account.local?\n    end\n\n    def require_local_account!\n      redirect_to admin_account_path(@account.id) unless @account.local? && @account.user.present?\n    end\n\n    def filtered_accounts\n      AccountFilter.new(filter_params).results\n    end\n\n    def filter_params\n      params.permit(\n        :local,\n        :remote,\n        :by_domain,\n        :active,\n        :pending,\n        :silenced,\n        :suspended,\n        :username,\n        :display_name,\n        :email,\n        :ip,\n        :staff\n      )\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/admin/action_logs_controller.rb",
    "content": "# frozen_string_literal: true\n\nmodule Admin\n  class ActionLogsController < BaseController\n    def index\n      @action_logs = Admin::ActionLog.page(params[:page])\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/admin/base_controller.rb",
    "content": "# frozen_string_literal: true\n\nmodule Admin\n  class BaseController < ApplicationController\n    include Authorization\n    include AccountableConcern\n\n    layout 'admin'\n\n    before_action :require_staff!\n    before_action :set_body_classes\n\n    private\n\n    def set_body_classes\n      @body_classes = 'admin'\n    end\n\n    def set_user\n      @user = Account.find(params[:account_id]).user || raise(ActiveRecord::RecordNotFound)\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/admin/change_emails_controller.rb",
    "content": "# frozen_string_literal: true\n\nmodule Admin\n  class ChangeEmailsController < BaseController\n    before_action :set_account\n    before_action :require_local_account!\n\n    def show\n      authorize @user, :change_email?\n    end\n\n    def update\n      authorize @user, :change_email?\n\n      new_email = resource_params.fetch(:unconfirmed_email)\n\n      if new_email != @user.email\n        @user.update!(\n          unconfirmed_email: new_email,\n          # Regenerate the confirmation token:\n          confirmation_token: nil\n        )\n\n        log_action :change_email, @user\n\n        @user.send_confirmation_instructions\n      end\n\n      redirect_to admin_account_path(@account.id), notice: I18n.t('admin.accounts.change_email.changed_msg')\n    end\n\n    private\n\n    def set_account\n      @account = Account.find(params[:account_id])\n      @user = @account.user\n    end\n\n    def require_local_account!\n      redirect_to admin_account_path(@account.id) unless @account.local? && @account.user.present?\n    end\n\n    def resource_params\n      params.require(:user).permit(\n        :unconfirmed_email\n      )\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/admin/confirmations_controller.rb",
    "content": "# frozen_string_literal: true\n\nmodule Admin\n  class ConfirmationsController < BaseController\n    before_action :set_user\n    before_action :check_confirmation, only: [:resend]\n\n    def create\n      authorize @user, :confirm?\n      @user.confirm!\n      log_action :confirm, @user\n      redirect_to admin_accounts_path\n    end\n\n    def resend\n      authorize @user, :confirm?\n\n      @user.resend_confirmation_instructions\n\n      log_action :confirm, @user\n\n      flash[:notice] = I18n.t('admin.accounts.resend_confirmation.success')\n      redirect_to admin_accounts_path\n    end\n\n    private\n\n    def check_confirmation\n      if @user.confirmed?\n        flash[:error] = I18n.t('admin.accounts.resend_confirmation.already_confirmed')\n        redirect_to admin_accounts_path\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/admin/custom_emojis_controller.rb",
    "content": "# frozen_string_literal: true\n\nmodule Admin\n  class CustomEmojisController < BaseController\n    before_action :set_custom_emoji, except: [:index, :new, :create]\n    before_action :set_filter_params\n\n    include ObfuscateFilename\n    obfuscate_filename [:custom_emoji, :image]\n\n    def index\n      authorize :custom_emoji, :index?\n      @custom_emojis = filtered_custom_emojis.eager_load(:local_counterpart).page(params[:page])\n    end\n\n    def new\n      authorize :custom_emoji, :create?\n      @custom_emoji = CustomEmoji.new\n    end\n\n    def create\n      authorize :custom_emoji, :create?\n\n      @custom_emoji = CustomEmoji.new(resource_params)\n\n      if @custom_emoji.save\n        log_action :create, @custom_emoji\n        redirect_to admin_custom_emojis_path, notice: I18n.t('admin.custom_emojis.created_msg')\n      else\n        render :new\n      end\n    end\n\n    def update\n      authorize @custom_emoji, :update?\n\n      if @custom_emoji.update(resource_params)\n        log_action :update, @custom_emoji\n        flash[:notice] = I18n.t('admin.custom_emojis.updated_msg')\n      else\n        flash[:alert] =  I18n.t('admin.custom_emojis.update_failed_msg')\n      end\n      redirect_to admin_custom_emojis_path(page: params[:page], **@filter_params)\n    end\n\n    def destroy\n      authorize @custom_emoji, :destroy?\n      @custom_emoji.destroy!\n      log_action :destroy, @custom_emoji\n      flash[:notice] = I18n.t('admin.custom_emojis.destroyed_msg')\n      redirect_to admin_custom_emojis_path(page: params[:page], **@filter_params)\n    end\n\n    def copy\n      authorize @custom_emoji, :copy?\n\n      emoji = CustomEmoji.find_or_initialize_by(domain: nil,\n                                                shortcode: @custom_emoji.shortcode)\n      emoji.image = @custom_emoji.image\n\n      if emoji.save\n        log_action :create, emoji\n        flash[:notice] = I18n.t('admin.custom_emojis.copied_msg')\n      else\n        flash[:alert] = I18n.t('admin.custom_emojis.copy_failed_msg')\n      end\n\n      redirect_to admin_custom_emojis_path(page: params[:page], **@filter_params)\n    end\n\n    def enable\n      authorize @custom_emoji, :enable?\n      @custom_emoji.update!(disabled: false)\n      log_action :enable, @custom_emoji\n      flash[:notice] = I18n.t('admin.custom_emojis.enabled_msg')\n      redirect_to admin_custom_emojis_path(page: params[:page], **@filter_params)\n    end\n\n    def disable\n      authorize @custom_emoji, :disable?\n      @custom_emoji.update!(disabled: true)\n      log_action :disable, @custom_emoji\n      flash[:notice] = I18n.t('admin.custom_emojis.disabled_msg')\n      redirect_to admin_custom_emojis_path(page: params[:page], **@filter_params)\n    end\n\n    private\n\n    def set_custom_emoji\n      @custom_emoji = CustomEmoji.find(params[:id])\n    end\n\n    def set_filter_params\n      @filter_params = filter_params.to_hash.symbolize_keys\n    end\n\n    def resource_params\n      params.require(:custom_emoji).permit(:shortcode, :image, :visible_in_picker)\n    end\n\n    def filtered_custom_emojis\n      CustomEmojiFilter.new(filter_params).results\n    end\n\n    def filter_params\n      params.permit(\n        :local,\n        :remote,\n        :by_domain,\n        :shortcode\n      )\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/admin/dashboard_controller.rb",
    "content": "# frozen_string_literal: true\nrequire 'sidekiq/api'\n\nmodule Admin\n  class DashboardController < BaseController\n    def index\n      @users_count           = User.count\n      @registrations_week    = Redis.current.get(\"activity:accounts:local:#{current_week}\") || 0\n      @logins_week           = Redis.current.pfcount(\"activity:logins:#{current_week}\")\n      @interactions_week     = Redis.current.get(\"activity:interactions:#{current_week}\") || 0\n      @relay_enabled         = Relay.enabled.exists?\n      @single_user_mode      = Rails.configuration.x.single_user_mode\n      @registrations_enabled = Setting.registrations_mode != 'none'\n      @max_bio_chars         = Setting.max_bio_chars\n      @max_toot_chars        = Setting.max_toot_chars\n      @deletions_enabled     = Setting.open_deletion\n      @invites_enabled       = Setting.min_invite_role == 'user'\n      @search_enabled        = Chewy.enabled?\n      @version               = Florence::Version.to_s\n      @masto_version         = Mastodon::Version.to_s\n      @database_version      = ActiveRecord::Base.connection.execute('SELECT VERSION()').first['version'].match(/\\A(?:PostgreSQL |)([^\\s]+).*\\z/)[1]\n      @redis_version         = redis_info['redis_version']\n      @reports_count         = Report.unresolved.count\n      @queue_backlog         = Sidekiq::Stats.new.enqueued\n      @recent_users          = User.confirmed.recent.includes(:account).limit(4)\n      @database_size         = ActiveRecord::Base.connection.execute('SELECT pg_database_size(current_database())').first['pg_database_size']\n      @redis_size            = redis_info['used_memory']\n      @ldap_enabled          = ENV['LDAP_ENABLED'] == 'true'\n      @cas_enabled           = ENV['CAS_ENABLED'] == 'true'\n      @saml_enabled          = ENV['SAML_ENABLED'] == 'true'\n      @pam_enabled           = ENV['PAM_ENABLED'] == 'true'\n      @hidden_service        = ENV['ALLOW_ACCESS_TO_HIDDEN_SERVICE'] == 'true'\n      @trending_hashtags     = TrendingTags.get(7)\n      @profile_directory     = Setting.profile_directory\n      @timeline_preview      = Setting.timeline_preview\n    end\n\n    private\n\n    def current_week\n      @current_week ||= Time.now.utc.to_date.cweek\n    end\n\n    def redis_info\n      @redis_info ||= Redis.current.info\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/admin/domain_blocks_controller.rb",
    "content": "# frozen_string_literal: true\n\nmodule Admin\n  class DomainBlocksController < BaseController\n    before_action :set_domain_block, only: [:show, :destroy]\n\n    def new\n      authorize :domain_block, :create?\n      @domain_block = DomainBlock.new(domain: params[:_domain])\n    end\n\n    def create\n      authorize :domain_block, :create?\n\n      @domain_block = DomainBlock.new(resource_params)\n      existing_domain_block = resource_params[:domain].present? ? DomainBlock.find_by(domain: resource_params[:domain]) : nil\n\n      if existing_domain_block.present? && !@domain_block.stricter_than?(existing_domain_block)\n        @domain_block.save\n        flash[:alert] = I18n.t('admin.domain_blocks.existing_domain_block_html', name: existing_domain_block.domain, unblock_url: admin_domain_block_path(existing_domain_block)).html_safe # rubocop:disable Rails/OutputSafety\n        @domain_block.errors[:domain].clear\n        render :new\n      else\n        if existing_domain_block.present?\n          @domain_block = existing_domain_block\n          @domain_block.update(resource_params)\n        end\n        if @domain_block.save\n          DomainBlockWorker.perform_async(@domain_block.id)\n          log_action :create, @domain_block\n          redirect_to admin_instances_path(limited: '1'), notice: I18n.t('admin.domain_blocks.created_msg')\n        else\n          render :new\n        end\n      end\n    end\n\n    def show\n      authorize @domain_block, :show?\n    end\n\n    def destroy\n      authorize @domain_block, :destroy?\n      UnblockDomainService.new.call(@domain_block)\n      log_action :destroy, @domain_block\n      redirect_to admin_instances_path(limited: '1'), notice: I18n.t('admin.domain_blocks.destroyed_msg')\n    end\n\n    private\n\n    def set_domain_block\n      @domain_block = DomainBlock.find(params[:id])\n    end\n\n    def resource_params\n      params.require(:domain_block).permit(:domain, :severity, :reject_media, :reject_reports)\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/admin/email_domain_blocks_controller.rb",
    "content": "# frozen_string_literal: true\n\nmodule Admin\n  class EmailDomainBlocksController < BaseController\n    before_action :set_email_domain_block, only: [:show, :destroy]\n\n    def index\n      authorize :email_domain_block, :index?\n      @email_domain_blocks = EmailDomainBlock.page(params[:page])\n    end\n\n    def new\n      authorize :email_domain_block, :create?\n      @email_domain_block = EmailDomainBlock.new\n    end\n\n    def create\n      authorize :email_domain_block, :create?\n\n      @email_domain_block = EmailDomainBlock.new(resource_params)\n\n      if @email_domain_block.save\n        log_action :create, @email_domain_block\n        redirect_to admin_email_domain_blocks_path, notice: I18n.t('admin.email_domain_blocks.created_msg')\n      else\n        render :new\n      end\n    end\n\n    def destroy\n      authorize @email_domain_block, :destroy?\n      @email_domain_block.destroy!\n      log_action :destroy, @email_domain_block\n      redirect_to admin_email_domain_blocks_path, notice: I18n.t('admin.email_domain_blocks.destroyed_msg')\n    end\n\n    private\n\n    def set_email_domain_block\n      @email_domain_block = EmailDomainBlock.find(params[:id])\n    end\n\n    def resource_params\n      params.require(:email_domain_block).permit(:domain)\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/admin/followers_controller.rb",
    "content": "# frozen_string_literal: true\n\nmodule Admin\n  class FollowersController < BaseController\n    before_action :set_account\n\n    PER_PAGE = 40\n\n    def index\n      authorize :account, :index?\n      @followers = @account.followers.local.recent.page(params[:page]).per(PER_PAGE)\n    end\n\n    def set_account\n      @account = Account.find(params[:account_id])\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/admin/instances_controller.rb",
    "content": "# frozen_string_literal: true\n\nmodule Admin\n  class InstancesController < BaseController\n    def index\n      authorize :instance, :index?\n\n      @instances = ordered_instances\n    end\n\n    def show\n      authorize :instance, :show?\n\n      @instance        = Instance.new(Account.by_domain_accounts.find_by(domain: params[:id]) || DomainBlock.find_by!(domain: params[:id]))\n      @following_count = Follow.where(account: Account.where(domain: params[:id])).count\n      @followers_count = Follow.where(target_account: Account.where(domain: params[:id])).count\n      @reports_count   = Report.where(target_account: Account.where(domain: params[:id])).count\n      @blocks_count    = Block.where(target_account: Account.where(domain: params[:id])).count\n      @available       = DeliveryFailureTracker.available?(Account.select(:shared_inbox_url).where(domain: params[:id]).first&.shared_inbox_url)\n      @media_storage   = MediaAttachment.where(account: Account.where(domain: params[:id])).sum(:file_file_size)\n      @domain_block    = DomainBlock.find_by(domain: params[:id])\n    end\n\n    private\n\n    def filtered_instances\n      InstanceFilter.new(filter_params).results\n    end\n\n    def paginated_instances\n      filtered_instances.page(params[:page])\n    end\n\n    helper_method :paginated_instances\n\n    def ordered_instances\n      paginated_instances.map { |resource| Instance.new(resource) }\n    end\n\n    def filter_params\n      params.permit(:limited, :by_domain)\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/admin/invites_controller.rb",
    "content": "# frozen_string_literal: true\n\nmodule Admin\n  class InvitesController < BaseController\n    def index\n      authorize :invite, :index?\n\n      @invites = filtered_invites.includes(user: :account).page(params[:page])\n      @invite  = Invite.new\n    end\n\n    def create\n      authorize :invite, :create?\n\n      @invite      = Invite.new(resource_params)\n      @invite.user = current_user\n\n      if @invite.save\n        redirect_to admin_invites_path\n      else\n        @invites = Invite.page(params[:page])\n        render :index\n      end\n    end\n\n    def destroy\n      @invite = Invite.find(params[:id])\n      authorize @invite, :destroy?\n      @invite.expire!\n      redirect_to admin_invites_path\n    end\n\n    def deactivate_all\n      authorize :invite, :deactivate_all?\n      Invite.available.in_batches.update_all(expires_at: Time.now.utc)\n      redirect_to admin_invites_path\n    end\n\n    private\n\n    def resource_params\n      params.require(:invite).permit(:max_uses, :expires_in)\n    end\n\n    def filtered_invites\n      InviteFilter.new(filter_params).results\n    end\n\n    def filter_params\n      params.permit(:available, :expired)\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/admin/pending_accounts_controller.rb",
    "content": "# frozen_string_literal: true\n\nmodule Admin\n  class PendingAccountsController < BaseController\n    before_action :set_accounts, only: :index\n\n    def index\n      @form = Form::AccountBatch.new\n    end\n\n    def batch\n      @form = Form::AccountBatch.new(form_account_batch_params.merge(current_account: current_account, action: action_from_button))\n      @form.save\n    rescue ActionController::ParameterMissing\n      flash[:alert] = I18n.t('admin.accounts.no_account_selected')\n    ensure\n      redirect_to admin_pending_accounts_path(current_params)\n    end\n\n    def approve_all\n      Form::AccountBatch.new(current_account: current_account, account_ids: User.pending.pluck(:account_id), action: 'approve').save\n      redirect_to admin_pending_accounts_path(current_params)\n    end\n\n    def reject_all\n      Form::AccountBatch.new(current_account: current_account, account_ids: User.pending.pluck(:account_id), action: 'reject').save\n      redirect_to admin_pending_accounts_path(current_params)\n    end\n\n    private\n\n    def set_accounts\n      @accounts = Account.joins(:user).merge(User.pending.recent).includes(user: :invite_request).page(params[:page])\n    end\n\n    def form_account_batch_params\n      params.require(:form_account_batch).permit(:action, account_ids: [])\n    end\n\n    def action_from_button\n      if params[:approve]\n        'approve'\n      elsif params[:reject]\n        'reject'\n      end\n    end\n\n    def current_params\n      params.slice(:page).permit(:page)\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/admin/relays_controller.rb",
    "content": "# frozen_string_literal: true\n\nmodule Admin\n  class RelaysController < BaseController\n    before_action :set_relay, except: [:index, :new, :create]\n\n    def index\n      authorize :relay, :update?\n      @relays = Relay.all\n    end\n\n    def new\n      authorize :relay, :update?\n      @relay = Relay.new(inbox_url: Relay::PRESET_RELAY)\n    end\n\n    def create\n      authorize :relay, :update?\n\n      @relay = Relay.new(resource_params)\n\n      if @relay.save\n        @relay.enable!\n        redirect_to admin_relays_path\n      else\n        render action: :new\n      end\n    end\n\n    def destroy\n      authorize :relay, :update?\n      @relay.destroy\n      redirect_to admin_relays_path\n    end\n\n    def enable\n      authorize :relay, :update?\n      @relay.enable!\n      redirect_to admin_relays_path\n    end\n\n    def disable\n      authorize :relay, :update?\n      @relay.disable!\n      redirect_to admin_relays_path\n    end\n\n    private\n\n    def set_relay\n      @relay = Relay.find(params[:id])\n    end\n\n    def resource_params\n      params.require(:relay).permit(:inbox_url)\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/admin/report_notes_controller.rb",
    "content": "# frozen_string_literal: true\n\nmodule Admin\n  class ReportNotesController < BaseController\n    before_action :set_report_note, only: [:destroy]\n\n    def create\n      authorize ReportNote, :create?\n\n      @report_note = current_account.report_notes.new(resource_params)\n      @report = @report_note.report\n\n      if @report_note.save\n        if params[:create_and_resolve]\n          @report.resolve!(current_account)\n          log_action :resolve, @report\n\n          redirect_to admin_reports_path, notice: I18n.t('admin.reports.resolved_msg')\n          return\n        end\n\n        if params[:create_and_unresolve]\n          @report.unresolve!\n          log_action :reopen, @report\n        end\n\n        redirect_to admin_report_path(@report), notice: I18n.t('admin.report_notes.created_msg')\n      else\n        @report_notes = @report.notes.latest\n        @report_history = @report.history\n        @form = Form::StatusBatch.new\n\n        render template: 'admin/reports/show'\n      end\n    end\n\n    def destroy\n      authorize @report_note, :destroy?\n      @report_note.destroy!\n      redirect_to admin_report_path(@report_note.report_id), notice: I18n.t('admin.report_notes.destroyed_msg')\n    end\n\n    private\n\n    def resource_params\n      params.require(:report_note).permit(\n        :content,\n        :report_id\n      )\n    end\n\n    def set_report_note\n      @report_note = ReportNote.find(params[:id])\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/admin/reported_statuses_controller.rb",
    "content": "# frozen_string_literal: true\n\nmodule Admin\n  class ReportedStatusesController < BaseController\n    before_action :set_report\n\n    def create\n      authorize :status, :update?\n\n      @form         = Form::StatusBatch.new(form_status_batch_params.merge(current_account: current_account, action: action_from_button))\n      flash[:alert] = I18n.t('admin.statuses.failed_to_execute') unless @form.save\n\n      redirect_to admin_report_path(@report)\n    rescue ActionController::ParameterMissing\n      flash[:alert] = I18n.t('admin.statuses.no_status_selected')\n\n      redirect_to admin_report_path(@report)\n    end\n\n    private\n\n    def status_params\n      params.require(:status).permit(:sensitive)\n    end\n\n    def form_status_batch_params\n      params.require(:form_status_batch).permit(status_ids: [])\n    end\n\n    def action_from_button\n      if params[:nsfw_on]\n        'nsfw_on'\n      elsif params[:nsfw_off]\n        'nsfw_off'\n      elsif params[:delete]\n        'delete'\n      end\n    end\n\n    def set_report\n      @report = Report.find(params[:report_id])\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/admin/reports_controller.rb",
    "content": "# frozen_string_literal: true\n\nmodule Admin\n  class ReportsController < BaseController\n    before_action :set_report, except: [:index]\n\n    def index\n      authorize :report, :index?\n      @reports = filtered_reports.page(params[:page])\n    end\n\n    def show\n      authorize @report, :show?\n\n      @report_note  = @report.notes.new\n      @report_notes = (@report.notes.latest + @report.history + @report.target_account.targeted_account_warnings.latest.custom).sort_by(&:created_at)\n      @form         = Form::StatusBatch.new\n    end\n\n    def assign_to_self\n      authorize @report, :update?\n      @report.update!(assigned_account_id: current_account.id)\n      log_action :assigned_to_self, @report\n      redirect_to admin_report_path(@report)\n    end\n\n    def unassign\n      authorize @report, :update?\n      @report.update!(assigned_account_id: nil)\n      log_action :unassigned, @report\n      redirect_to admin_report_path(@report)\n    end\n\n    def reopen\n      authorize @report, :update?\n      @report.unresolve!\n      log_action :reopen, @report\n      redirect_to admin_report_path(@report)\n    end\n\n    def resolve\n      authorize @report, :update?\n      @report.resolve!(current_account)\n      log_action :resolve, @report\n      redirect_to admin_reports_path, notice: I18n.t('admin.reports.resolved_msg')\n    end\n\n    private\n\n    def filtered_reports\n      ReportFilter.new(filter_params).results.order(id: :desc).includes(:account, :target_account)\n    end\n\n    def filter_params\n      params.permit(\n        :account_id,\n        :resolved,\n        :target_account_id\n      )\n    end\n\n    def set_report\n      @report = Report.find(params[:id])\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/admin/resets_controller.rb",
    "content": "# frozen_string_literal: true\n\nmodule Admin\n  class ResetsController < BaseController\n    before_action :set_user\n\n    def create\n      authorize @user, :reset_password?\n      @user.send_reset_password_instructions\n      log_action :reset_password, @user\n      redirect_to admin_accounts_path\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/admin/roles_controller.rb",
    "content": "# frozen_string_literal: true\n\nmodule Admin\n  class RolesController < BaseController\n    before_action :set_user\n\n    def promote\n      authorize @user, :promote?\n      @user.promote!\n      log_action :promote, @user\n      redirect_to admin_account_path(@user.account_id)\n    end\n\n    def demote\n      authorize @user, :demote?\n      @user.demote!\n      log_action :demote, @user\n      redirect_to admin_account_path(@user.account_id)\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/admin/settings_controller.rb",
    "content": "# frozen_string_literal: true\n\nmodule Admin\n  class SettingsController < BaseController\n    ADMIN_SETTINGS = %w(\n      site_contact_username\n      site_contact_email\n      site_title\n      site_short_description\n      site_description\n      site_extended_description\n      site_terms\n      open_registrations\n      max_bio_chars\n      max_toot_chars\n      closed_registrations_message\n      open_deletion\n      timeline_preview\n      show_staff_badge\n      bootstrap_timeline_accounts\n      theme\n      thumbnail\n      hero\n      mascot\n      min_invite_role\n      activity_api_enabled\n      peers_api_enabled\n      show_known_fediverse_at_about_page\n      preview_sensitive_media\n      custom_css\n      profile_directory\n    ).freeze\n\n    BOOLEAN_SETTINGS = %w(\n      open_registrations\n      open_deletion\n      timeline_preview\n      show_staff_badge\n      activity_api_enabled\n      peers_api_enabled\n      show_known_fediverse_at_about_page\n      preview_sensitive_media\n      profile_directory\n    ).freeze\n  \n    INTEGER_SETTINGS = %w(\n      max_bio_chars\n      max_toot_chars\n    ).freeze\n\n    UPLOAD_SETTINGS = %w(\n      thumbnail\n      hero\n      mascot\n    ).freeze\n\n    def edit\n      authorize :settings, :show?\n\n      @admin_settings = Form::AdminSettings.new\n    end\n\n    def update\n      authorize :settings, :update?\n\n      @admin_settings = Form::AdminSettings.new(settings_params)\n\n      if @admin_settings.save\n        flash[:notice] = I18n.t('generic.changes_saved_msg')\n        redirect_to edit_admin_settings_path\n      else\n        render :edit\n      end\n    end\n\n    private\n\n    def settings_params\n      params.require(:form_admin_settings).permit(*Form::AdminSettings::KEYS)\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/admin/statuses_controller.rb",
    "content": "# frozen_string_literal: true\n\nmodule Admin\n  class StatusesController < BaseController\n    helper_method :current_params\n\n    before_action :set_account\n\n    PER_PAGE = 20\n\n    def index\n      authorize :status, :index?\n\n      @statuses = @account.statuses.where(visibility: [:public, :unlisted])\n\n      if params[:media]\n        account_media_status_ids = @account.media_attachments.attached.reorder(nil).select(:status_id).distinct\n        @statuses.merge!(Status.where(id: account_media_status_ids))\n      end\n\n      @statuses = @statuses.preload(:media_attachments, :mentions).page(params[:page]).per(PER_PAGE)\n      @form     = Form::StatusBatch.new\n    end\n\n    def show\n      authorize :status, :index?\n\n      @statuses = @account.statuses.where(id: params[:id])\n      authorize @statuses.first, :show?\n\n      @form = Form::StatusBatch.new\n    end\n\n    def create\n      authorize :status, :update?\n\n      @form         = Form::StatusBatch.new(form_status_batch_params.merge(current_account: current_account, action: action_from_button))\n      flash[:alert] = I18n.t('admin.statuses.failed_to_execute') unless @form.save\n\n      redirect_to admin_account_statuses_path(@account.id, current_params)\n    rescue ActionController::ParameterMissing\n      flash[:alert] = I18n.t('admin.statuses.no_status_selected')\n\n      redirect_to admin_account_statuses_path(@account.id, current_params)\n    end\n\n    private\n\n    def form_status_batch_params\n      params.require(:form_status_batch).permit(:action, status_ids: [])\n    end\n\n    def set_account\n      @account = Account.find(params[:account_id])\n    end\n\n    def current_params\n      page = (params[:page] || 1).to_i\n\n      {\n        media: params[:media],\n        page: page > 1 && page,\n      }.select { |_, value| value.present? }\n    end\n\n    def action_from_button\n      if params[:nsfw_on]\n        'nsfw_on'\n      elsif params[:nsfw_off]\n        'nsfw_off'\n      elsif params[:delete]\n        'delete'\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/admin/subscriptions_controller.rb",
    "content": "# frozen_string_literal: true\n\nmodule Admin\n  class SubscriptionsController < BaseController\n    def index\n      authorize :subscription, :index?\n      @subscriptions = ordered_subscriptions.page(requested_page)\n    end\n\n    private\n\n    def ordered_subscriptions\n      Subscription.order(id: :desc).includes(:account)\n    end\n\n    def requested_page\n      params[:page].to_i\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/admin/tags_controller.rb",
    "content": "# frozen_string_literal: true\n\nmodule Admin\n  class TagsController < BaseController\n    before_action :set_tags, only: :index\n    before_action :set_tag, except: :index\n    before_action :set_filter_params\n\n    def index\n      authorize :tag, :index?\n    end\n\n    def hide\n      authorize @tag, :hide?\n      @tag.account_tag_stat.update!(hidden: true)\n      redirect_to admin_tags_path(@filter_params)\n    end\n\n    def unhide\n      authorize @tag, :unhide?\n      @tag.account_tag_stat.update!(hidden: false)\n      redirect_to admin_tags_path(@filter_params)\n    end\n\n    private\n\n    def set_tags\n      @tags = Tag.discoverable\n      @tags.merge!(Tag.hidden) if filter_params[:hidden]\n    end\n\n    def set_tag\n      @tag = Tag.find(params[:id])\n    end\n\n    def set_filter_params\n      @filter_params = filter_params.to_hash.symbolize_keys\n    end\n\n    def filter_params\n      params.permit(:hidden)\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/admin/two_factor_authentications_controller.rb",
    "content": "# frozen_string_literal: true\n\nmodule Admin\n  class TwoFactorAuthenticationsController < BaseController\n    before_action :set_target_user\n\n    def destroy\n      authorize @user, :disable_2fa?\n      @user.disable_two_factor!\n      log_action :disable_2fa, @user\n      redirect_to admin_accounts_path\n    end\n\n    private\n\n    def set_target_user\n      @user = User.find(params[:user_id])\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/admin/warning_presets_controller.rb",
    "content": "# frozen_string_literal: true\n\nmodule Admin\n  class WarningPresetsController < BaseController\n    before_action :set_warning_preset, except: [:index, :create]\n\n    def index\n      authorize :account_warning_preset, :index?\n\n      @warning_presets = AccountWarningPreset.all\n      @warning_preset  = AccountWarningPreset.new\n    end\n\n    def create\n      authorize :account_warning_preset, :create?\n\n      @warning_preset = AccountWarningPreset.new(warning_preset_params)\n\n      if @warning_preset.save\n        redirect_to admin_warning_presets_path\n      else\n        @warning_presets = AccountWarningPreset.all\n        render :index\n      end\n    end\n\n    def edit\n      authorize @warning_preset, :update?\n    end\n\n    def update\n      authorize @warning_preset, :update?\n\n      if @warning_preset.update(warning_preset_params)\n        redirect_to admin_warning_presets_path\n      else\n        render :edit\n      end\n    end\n\n    def destroy\n      authorize @warning_preset, :destroy?\n\n      @warning_preset.destroy!\n      redirect_to admin_warning_presets_path\n    end\n\n    private\n\n    def set_warning_preset\n      @warning_preset = AccountWarningPreset.find(params[:id])\n    end\n\n    def warning_preset_params\n      params.require(:account_warning_preset).permit(:text)\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/base_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::BaseController < ApplicationController\n  DEFAULT_STATUSES_LIMIT = 20\n  DEFAULT_ACCOUNTS_LIMIT = 40\n\n  include RateLimitHeaders\n\n  skip_before_action :store_current_location\n  skip_before_action :check_user_permissions\n\n  before_action :set_cache_headers\n\n  protect_from_forgery with: :null_session\n\n  rescue_from ActiveRecord::RecordInvalid, Mastodon::ValidationError do |e|\n    render json: { error: e.to_s }, status: 422\n  end\n\n  rescue_from ActiveRecord::RecordNotFound do\n    render json: { error: 'Record not found' }, status: 404\n  end\n\n  rescue_from HTTP::Error, Mastodon::UnexpectedResponseError do\n    render json: { error: 'Remote data could not be fetched' }, status: 503\n  end\n\n  rescue_from OpenSSL::SSL::SSLError do\n    render json: { error: 'Remote SSL certificate could not be verified' }, status: 503\n  end\n\n  rescue_from Mastodon::NotPermittedError do\n    render json: { error: 'This action is not allowed' }, status: 403\n  end\n\n  def doorkeeper_unauthorized_render_options(error: nil)\n    { json: { error: (error.try(:description) || 'Not authorized') } }\n  end\n\n  def doorkeeper_forbidden_render_options(*)\n    { json: { error: 'This action is outside the authorized scopes' } }\n  end\n\n  protected\n\n  def set_pagination_headers(next_path = nil, prev_path = nil)\n    links = []\n    links << [next_path, [%w(rel next)]] if next_path\n    links << [prev_path, [%w(rel prev)]] if prev_path\n    response.headers['Link'] = LinkHeader.new(links) unless links.empty?\n  end\n\n  def limit_param(default_limit)\n    return default_limit unless params[:limit]\n    [params[:limit].to_i.abs, default_limit * 2].min\n  end\n\n  def params_slice(*keys)\n    params.slice(*keys).permit(*keys)\n  end\n\n  def current_resource_owner\n    @current_user ||= User.find(doorkeeper_token.resource_owner_id) if doorkeeper_token\n  end\n\n  def current_user\n    current_resource_owner || super\n  rescue ActiveRecord::RecordNotFound\n    nil\n  end\n\n  def require_user!\n    if !current_user\n      render json: { error: 'This method requires an authenticated user' }, status: 422\n    elsif current_user.disabled?\n      render json: { error: 'Your login is currently disabled' }, status: 403\n    elsif !current_user.confirmed?\n      render json: { error: 'Your login is missing a confirmed e-mail address' }, status: 403\n    elsif !current_user.approved?\n      render json: { error: 'Your login is currently pending approval' }, status: 403\n    else\n      set_user_activity\n    end\n  end\n\n  def render_empty\n    render json: {}, status: 200\n  end\n\n  def authorize_if_got_token!(*scopes)\n    doorkeeper_authorize!(*scopes) if doorkeeper_token\n  end\n\n  def set_cache_headers\n    response.headers['Cache-Control'] = 'no-cache, no-store, max-age=0, must-revalidate'\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/oembed_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::OEmbedController < Api::BaseController\n  respond_to :json\n\n  def show\n    @status = status_finder.status\n    render json: @status, serializer: OEmbedSerializer, width: maxwidth_or_default, height: maxheight_or_default\n  end\n\n  private\n\n  def status_finder\n    StatusFinder.new(params[:url])\n  end\n\n  def maxwidth_or_default\n    (params[:maxwidth].presence || 400).to_i\n  end\n\n  def maxheight_or_default\n    params[:maxheight].present? ? params[:maxheight].to_i : nil\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/proofs_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::ProofsController < Api::BaseController\n  before_action :set_account\n  before_action :set_provider\n  before_action :check_account_approval\n  before_action :check_account_suspension\n\n  def index\n    render json: @account, serializer: @provider.serializer_class\n  end\n\n  private\n\n  def set_provider\n    @provider = ProofProvider.find(params[:provider]) || raise(ActiveRecord::RecordNotFound)\n  end\n\n  def set_account\n    @account = Account.find_local!(params[:username])\n  end\n\n  def check_account_approval\n    not_found if @account.user_pending?\n  end\n\n  def check_account_suspension\n    gone if @account.suspended?\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/push_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::PushController < Api::BaseController\n  include SignatureVerification\n\n  def update\n    response, status = process_push_request\n    render plain: response, status: status\n  end\n\n  private\n\n  def process_push_request\n    case hub_mode\n    when 'subscribe'\n      Pubsubhubbub::SubscribeService.new.call(account_from_topic, hub_callback, hub_secret, hub_lease_seconds, verified_domain)\n    when 'unsubscribe'\n      Pubsubhubbub::UnsubscribeService.new.call(account_from_topic, hub_callback)\n    else\n      [\"Unknown mode: #{hub_mode}\", 422]\n    end\n  end\n\n  def hub_mode\n    params['hub.mode']\n  end\n\n  def hub_topic\n    params['hub.topic']\n  end\n\n  def hub_callback\n    params['hub.callback']\n  end\n\n  def hub_lease_seconds\n    params['hub.lease_seconds']\n  end\n\n  def hub_secret\n    params['hub.secret']\n  end\n\n  def account_from_topic\n    if hub_topic.present? && local_domain? && account_feed_path?\n      Account.find_local(hub_topic_params[:username])\n    end\n  end\n\n  def hub_topic_params\n    @_hub_topic_params ||= Rails.application.routes.recognize_path(hub_topic_uri.path)\n  end\n\n  def hub_topic_uri\n    @_hub_topic_uri ||= Addressable::URI.parse(hub_topic).normalize\n  end\n\n  def local_domain?\n    TagManager.instance.web_domain?(hub_topic_domain)\n  end\n\n  def verified_domain\n    return signed_request_account.domain if signed_request_account\n  end\n\n  def hub_topic_domain\n    hub_topic_uri.host + (hub_topic_uri.port ? \":#{hub_topic_uri.port}\" : '')\n  end\n\n  def account_feed_path?\n    hub_topic_params[:controller] == 'accounts' && hub_topic_params[:action] == 'show' && hub_topic_params[:format] == 'atom'\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/salmon_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::SalmonController < Api::BaseController\n  include SignatureVerification\n\n  before_action :set_account\n  respond_to :txt\n\n  def update\n    if verify_payload?\n      process_salmon\n      head 202\n    elsif payload.present?\n      render plain: signature_verification_failure_reason, status: 401\n    else\n      head 400\n    end\n  end\n\n  private\n\n  def set_account\n    @account = Account.find(params[:id])\n  end\n\n  def payload\n    @_payload ||= request.body.read\n  end\n\n  def verify_payload?\n    payload.present? && VerifySalmonService.new.call(payload)\n  end\n\n  def process_salmon\n    SalmonWorker.perform_async(@account.id, payload.force_encoding('UTF-8'))\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/subscriptions_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::SubscriptionsController < Api::BaseController\n  before_action :set_account\n  respond_to :txt\n\n  def show\n    if subscription.valid?(params['hub.topic'])\n      @account.update(subscription_expires_at: future_expires)\n      render plain: encoded_challenge, status: 200\n    else\n      head 404\n    end\n  end\n\n  def update\n    if subscription.verify(body, request.headers['HTTP_X_HUB_SIGNATURE'])\n      ProcessingWorker.perform_async(@account.id, body.force_encoding('UTF-8'))\n    end\n\n    head 200\n  end\n\n  private\n\n  def subscription\n    @_subscription ||= @account.subscription(\n      api_subscription_url(@account.id)\n    )\n  end\n\n  def body\n    @_body ||= request.body.read\n  end\n\n  def encoded_challenge\n    HTMLEntities.new.encode(params['hub.challenge'])\n  end\n\n  def future_expires\n    Time.now.utc + lease_seconds_or_default\n  end\n\n  def lease_seconds_or_default\n    (params['hub.lease_seconds'] || 1.day).to_i.seconds\n  end\n\n  def set_account\n    @account = Account.find(params[:id])\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/accounts/credentials_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::Accounts::CredentialsController < Api::BaseController\n  before_action -> { doorkeeper_authorize! :read, :'read:accounts' }, except: [:update]\n  before_action -> { doorkeeper_authorize! :write, :'write:accounts' }, only: [:update]\n  before_action :require_user!\n\n  def show\n    @account = current_account\n    render json: @account, serializer: REST::CredentialAccountSerializer\n  end\n\n  def update\n    @account = current_account\n    UpdateAccountService.new.call(@account, account_params, raise_error: true)\n    UserSettingsDecorator.new(current_user).update(user_settings_params) if user_settings_params\n    ActivityPub::UpdateDistributionWorker.perform_async(@account.id)\n    render json: @account, serializer: REST::CredentialAccountSerializer\n  end\n\n  private\n\n  def account_params\n    params.permit(:display_name, :note, :avatar, :header, :locked, :bot, :discoverable, fields_attributes: [:name, :value])\n  end\n\n  def user_settings_params\n    return nil unless params.key?(:source)\n\n    source_params = params.require(:source)\n\n    {\n      'setting_default_privacy' => source_params.fetch(:privacy, @account.user.setting_default_privacy),\n      'setting_default_sensitive' => source_params.fetch(:sensitive, @account.user.setting_default_sensitive),\n      'setting_default_language' => source_params.fetch(:language, @account.user.setting_default_language),\n    }\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/accounts/follower_accounts_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::Accounts::FollowerAccountsController < Api::BaseController\n  before_action -> { doorkeeper_authorize! :read, :'read:accounts' }\n  before_action :set_account\n  after_action :insert_pagination_headers\n\n  respond_to :json\n\n  def index\n    @accounts = load_accounts\n    render json: @accounts, each_serializer: REST::AccountSerializer\n  end\n\n  private\n\n  def set_account\n    @account = Account.find(params[:account_id])\n  end\n\n  def load_accounts\n    return [] if hide_results?\n\n    default_accounts.merge(paginated_follows).to_a\n  end\n\n  def hide_results?\n    (@account.user_hides_network? && current_account.id != @account.id) || (current_account && @account.blocking?(current_account))\n  end\n\n  def default_accounts\n    Account.includes(:active_relationships, :account_stat).references(:active_relationships)\n  end\n\n  def paginated_follows\n    Follow.where(target_account: @account).paginate_by_max_id(\n      limit_param(DEFAULT_ACCOUNTS_LIMIT),\n      params[:max_id],\n      params[:since_id]\n    )\n  end\n\n  def insert_pagination_headers\n    set_pagination_headers(next_path, prev_path)\n  end\n\n  def next_path\n    if records_continue?\n      api_v1_account_followers_url pagination_params(max_id: pagination_max_id)\n    end\n  end\n\n  def prev_path\n    unless @accounts.empty?\n      api_v1_account_followers_url pagination_params(since_id: pagination_since_id)\n    end\n  end\n\n  def pagination_max_id\n    @accounts.last.active_relationships.first.id\n  end\n\n  def pagination_since_id\n    @accounts.first.active_relationships.first.id\n  end\n\n  def records_continue?\n    @accounts.size == limit_param(DEFAULT_ACCOUNTS_LIMIT)\n  end\n\n  def pagination_params(core_params)\n    params.slice(:limit).permit(:limit).merge(core_params)\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/accounts/following_accounts_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::Accounts::FollowingAccountsController < Api::BaseController\n  before_action -> { doorkeeper_authorize! :read, :'read:accounts' }\n  before_action :set_account\n  after_action :insert_pagination_headers\n\n  respond_to :json\n\n  def index\n    @accounts = load_accounts\n    render json: @accounts, each_serializer: REST::AccountSerializer\n  end\n\n  private\n\n  def set_account\n    @account = Account.find(params[:account_id])\n  end\n\n  def load_accounts\n    return [] if hide_results?\n\n    default_accounts.merge(paginated_follows).to_a\n  end\n\n  def hide_results?\n    (@account.user_hides_network? && current_account.id != @account.id) || (current_account && @account.blocking?(current_account))\n  end\n\n  def default_accounts\n    Account.includes(:passive_relationships, :account_stat).references(:passive_relationships)\n  end\n\n  def paginated_follows\n    Follow.where(account: @account).paginate_by_max_id(\n      limit_param(DEFAULT_ACCOUNTS_LIMIT),\n      params[:max_id],\n      params[:since_id]\n    )\n  end\n\n  def insert_pagination_headers\n    set_pagination_headers(next_path, prev_path)\n  end\n\n  def next_path\n    if records_continue?\n      api_v1_account_following_index_url pagination_params(max_id: pagination_max_id)\n    end\n  end\n\n  def prev_path\n    unless @accounts.empty?\n      api_v1_account_following_index_url pagination_params(since_id: pagination_since_id)\n    end\n  end\n\n  def pagination_max_id\n    @accounts.last.passive_relationships.first.id\n  end\n\n  def pagination_since_id\n    @accounts.first.passive_relationships.first.id\n  end\n\n  def records_continue?\n    @accounts.size == limit_param(DEFAULT_ACCOUNTS_LIMIT)\n  end\n\n  def pagination_params(core_params)\n    params.slice(:limit).permit(:limit).merge(core_params)\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/accounts/identity_proofs_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::Accounts::IdentityProofsController < Api::BaseController\n  before_action :require_user!\n  before_action :set_account\n\n  respond_to :json\n\n  def index\n    @proofs = @account.identity_proofs.active\n    render json: @proofs, each_serializer: REST::IdentityProofSerializer\n  end\n\n  private\n\n  def set_account\n    @account = Account.find(params[:account_id])\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/accounts/lists_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::Accounts::ListsController < Api::BaseController\n  before_action -> { doorkeeper_authorize! :read, :'read:lists' }\n  before_action :require_user!\n  before_action :set_account\n\n  respond_to :json\n\n  def index\n    @lists = @account.lists.where(account: current_account)\n    render json: @lists, each_serializer: REST::ListSerializer\n  end\n\n  private\n\n  def set_account\n    @account = Account.find(params[:account_id])\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/accounts/pins_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::Accounts::PinsController < Api::BaseController\n  include Authorization\n\n  before_action -> { doorkeeper_authorize! :write, :'write:accounts' }\n  before_action :require_user!\n  before_action :set_account\n\n  respond_to :json\n\n  def create\n    AccountPin.create!(account: current_account, target_account: @account)\n    render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships_presenter\n  end\n\n  def destroy\n    pin = AccountPin.find_by(account: current_account, target_account: @account)\n    pin&.destroy!\n    render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships_presenter\n  end\n\n  private\n\n  def set_account\n    @account = Account.find(params[:account_id])\n  end\n\n  def relationships_presenter\n    AccountRelationshipsPresenter.new([@account.id], current_user.account_id)\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/accounts/relationships_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::Accounts::RelationshipsController < Api::BaseController\n  before_action -> { doorkeeper_authorize! :read, :'read:follows' }\n  before_action :require_user!\n\n  respond_to :json\n\n  def index\n    accounts = Account.where(id: account_ids).select('id')\n    # .where doesn't guarantee that our results are in the same order\n    # we requested them, so return the \"right\" order to the requestor.\n    @accounts = accounts.index_by(&:id).values_at(*account_ids).compact\n    render json: @accounts, each_serializer: REST::RelationshipSerializer, relationships: relationships\n  end\n\n  private\n\n  def relationships\n    AccountRelationshipsPresenter.new(@accounts, current_user.account_id)\n  end\n\n  def account_ids\n    Array(params[:id]).map(&:to_i)\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/accounts/search_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::Accounts::SearchController < Api::BaseController\n  before_action -> { doorkeeper_authorize! :read, :'read:accounts' }\n  before_action :require_user!\n\n  respond_to :json\n\n  def show\n    @accounts = account_search\n    render json: @accounts, each_serializer: REST::AccountSerializer\n  end\n\n  private\n\n  def account_search\n    AccountSearchService.new.call(\n      params[:q],\n      current_account,\n      limit: limit_param(DEFAULT_ACCOUNTS_LIMIT),\n      resolve: truthy_param?(:resolve),\n      following: truthy_param?(:following),\n      offset: params[:offset]\n    )\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/accounts/statuses_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::Accounts::StatusesController < Api::BaseController\n  before_action -> { authorize_if_got_token! :read, :'read:statuses' }\n  before_action :set_account\n  after_action :insert_pagination_headers\n\n  respond_to :json\n\n  def index\n    @statuses = load_statuses\n    render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id)\n  end\n\n  private\n\n  def set_account\n    @account = Account.find(params[:account_id])\n  end\n\n  def load_statuses\n    cached_account_statuses\n  end\n\n  def cached_account_statuses\n    cache_collection account_statuses, Status\n  end\n\n  def account_statuses\n    statuses = truthy_param?(:pinned) ? pinned_scope : permitted_account_statuses\n    statuses = statuses.paginate_by_id(limit_param(DEFAULT_STATUSES_LIMIT), params_slice(:max_id, :since_id, :min_id))\n\n    statuses.merge!(only_media_scope) if truthy_param?(:only_media)\n    statuses.merge!(no_replies_scope) if truthy_param?(:exclude_replies)\n    statuses.merge!(no_reblogs_scope) if truthy_param?(:exclude_reblogs)\n    statuses.merge!(hashtag_scope)    if params[:tagged].present?\n\n    statuses\n  end\n\n  def permitted_account_statuses\n    @account.statuses.permitted_for(@account, current_account)\n  end\n\n  def only_media_scope\n    Status.where(id: account_media_status_ids)\n  end\n\n  def account_media_status_ids\n    # `SELECT DISTINCT id, updated_at` is too slow, so pluck ids at first, and then select id, updated_at with ids.\n    # Also, Avoid getting slow by not narrowing down by `statuses.account_id`.\n    # When narrowing down by `statuses.account_id`, `index_statuses_20180106` will be used\n    # and the table will be joined by `Merge Semi Join`, so the query will be slow.\n    @account.statuses.joins(:media_attachments).merge(@account.media_attachments).permitted_for(@account, current_account)\n            .paginate_by_max_id(limit_param(DEFAULT_STATUSES_LIMIT), params[:max_id], params[:since_id])\n            .reorder(id: :desc).distinct(:id).pluck(:id)\n  end\n\n  def pinned_scope\n    @account.pinned_statuses\n  end\n\n  def no_replies_scope\n    Status.without_replies\n  end\n\n  def no_reblogs_scope\n    Status.without_reblogs\n  end\n\n  def hashtag_scope\n    tag = Tag.find_normalized(params[:tagged])\n\n    if tag\n      Status.tagged_with(tag.id)\n    else\n      Status.none\n    end\n  end\n\n  def pagination_params(core_params)\n    params.slice(:limit, :only_media, :exclude_replies).permit(:limit, :only_media, :exclude_replies).merge(core_params)\n  end\n\n  def insert_pagination_headers\n    set_pagination_headers(next_path, prev_path)\n  end\n\n  def next_path\n    if records_continue?\n      api_v1_account_statuses_url pagination_params(max_id: pagination_max_id)\n    end\n  end\n\n  def prev_path\n    unless @statuses.empty?\n      api_v1_account_statuses_url pagination_params(min_id: pagination_since_id)\n    end\n  end\n\n  def records_continue?\n    @statuses.size == limit_param(DEFAULT_STATUSES_LIMIT)\n  end\n\n  def pagination_max_id\n    @statuses.last.id\n  end\n\n  def pagination_since_id\n    @statuses.first.id\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/accounts_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::AccountsController < Api::BaseController\n  before_action -> { authorize_if_got_token! :read, :'read:accounts' }, except: [:create, :follow, :unfollow, :block, :unblock, :mute, :unmute]\n  before_action -> { doorkeeper_authorize! :follow, :'write:follows' }, only: [:follow, :unfollow]\n  before_action -> { doorkeeper_authorize! :follow, :'write:mutes' }, only: [:mute, :unmute]\n  before_action -> { doorkeeper_authorize! :follow, :'write:blocks' }, only: [:block, :unblock]\n  before_action -> { doorkeeper_authorize! :write, :'write:accounts' }, only: [:create]\n\n  before_action :require_user!, except: [:show, :create]\n  before_action :set_account, except: [:create]\n  before_action :check_account_suspension, only: [:show]\n  before_action :check_enabled_registrations, only: [:create]\n\n  respond_to :json\n\n  def show\n    render json: @account, serializer: REST::AccountSerializer\n  end\n\n  def create\n    token    = AppSignUpService.new.call(doorkeeper_token.application, account_params)\n    response = Doorkeeper::OAuth::TokenResponse.new(token)\n\n    headers.merge!(response.headers)\n\n    self.response_body = Oj.dump(response.body)\n    self.status        = response.status\n  end\n\n  def follow\n    FollowService.new.call(current_user.account, @account, reblogs: truthy_param?(:reblogs))\n\n    options = @account.locked? ? {} : { following_map: { @account.id => { reblogs: truthy_param?(:reblogs) } }, requested_map: { @account.id => false } }\n\n    render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships(options)\n  end\n\n  def block\n    BlockService.new.call(current_user.account, @account)\n    render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships\n  end\n\n  def mute\n    MuteService.new.call(current_user.account, @account, notifications: truthy_param?(:notifications))\n    render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships\n  end\n\n  def unfollow\n    UnfollowService.new.call(current_user.account, @account)\n    render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships\n  end\n\n  def unblock\n    UnblockService.new.call(current_user.account, @account)\n    render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships\n  end\n\n  def unmute\n    UnmuteService.new.call(current_user.account, @account)\n    render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships\n  end\n\n  private\n\n  def set_account\n    @account = Account.find(params[:id])\n  end\n\n  def relationships(**options)\n    AccountRelationshipsPresenter.new([@account.id], current_user.account_id, options)\n  end\n\n  def check_account_suspension\n    gone if @account.suspended?\n  end\n\n  def account_params\n    params.permit(:username, :email, :password, :agreement, :locale)\n  end\n\n  def check_enabled_registrations\n    forbidden if single_user_mode? || !allowed_registrations?\n  end\n\n  def allowed_registrations?\n    Setting.registrations_mode != 'none'\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/apps/credentials_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::Apps::CredentialsController < Api::BaseController\n  before_action -> { doorkeeper_authorize! :read }\n\n  respond_to :json\n\n  def show\n    render json: doorkeeper_token.application, serializer: REST::ApplicationSerializer, fields: %i(name website vapid_key)\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/apps_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::AppsController < Api::BaseController\n  def create\n    @app = Doorkeeper::Application.create!(application_options)\n    render json: @app, serializer: REST::ApplicationSerializer\n  end\n\n  private\n\n  def application_options\n    {\n      name: app_params[:client_name],\n      redirect_uri: app_params[:redirect_uris],\n      scopes: app_scopes_or_default,\n      website: app_params[:website],\n    }\n  end\n\n  def app_scopes_or_default\n    app_params[:scopes] || Doorkeeper.configuration.default_scopes\n  end\n\n  def app_params\n    params.permit(:client_name, :redirect_uris, :scopes, :website)\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/blocks_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::BlocksController < Api::BaseController\n  before_action -> { doorkeeper_authorize! :follow, :'read:blocks' }\n  before_action :require_user!\n  after_action :insert_pagination_headers\n\n  respond_to :json\n\n  def index\n    @accounts = load_accounts\n    render json: @accounts, each_serializer: REST::AccountSerializer\n  end\n\n  private\n\n  def load_accounts\n    paginated_blocks.map(&:target_account)\n  end\n\n  def paginated_blocks\n    @paginated_blocks ||= Block.eager_load(target_account: :account_stat)\n                               .where(account: current_account)\n                               .paginate_by_max_id(\n                                 limit_param(DEFAULT_ACCOUNTS_LIMIT),\n                                 params[:max_id],\n                                 params[:since_id]\n                               )\n  end\n\n  def insert_pagination_headers\n    set_pagination_headers(next_path, prev_path)\n  end\n\n  def next_path\n    if records_continue?\n      api_v1_blocks_url pagination_params(max_id: pagination_max_id)\n    end\n  end\n\n  def prev_path\n    unless paginated_blocks.empty?\n      api_v1_blocks_url pagination_params(since_id: pagination_since_id)\n    end\n  end\n\n  def pagination_max_id\n    paginated_blocks.last.id\n  end\n\n  def pagination_since_id\n    paginated_blocks.first.id\n  end\n\n  def records_continue?\n    paginated_blocks.size == limit_param(DEFAULT_ACCOUNTS_LIMIT)\n  end\n\n  def pagination_params(core_params)\n    params.slice(:limit).permit(:limit).merge(core_params)\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/conversations_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::ConversationsController < Api::BaseController\n  LIMIT = 20\n\n  before_action -> { doorkeeper_authorize! :read, :'read:statuses' }, only: :index\n  before_action -> { doorkeeper_authorize! :write, :'write:conversations' }, except: :index\n  before_action :require_user!\n  before_action :set_conversation, except: :index\n  after_action :insert_pagination_headers, only: :index\n\n  respond_to :json\n\n  def index\n    @conversations = paginated_conversations\n    render json: @conversations, each_serializer: REST::ConversationSerializer\n  end\n\n  def read\n    @conversation.update!(unread: false)\n    render json: @conversation, serializer: REST::ConversationSerializer\n  end\n\n  def destroy\n    @conversation.destroy!\n    render_empty\n  end\n\n  private\n\n  def set_conversation\n    @conversation = AccountConversation.where(account: current_account).find(params[:id])\n  end\n\n  def paginated_conversations\n    AccountConversation.where(account: current_account)\n                       .paginate_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id))\n  end\n\n  def insert_pagination_headers\n    set_pagination_headers(next_path, prev_path)\n  end\n\n  def next_path\n    if records_continue?\n      api_v1_conversations_url pagination_params(max_id: pagination_max_id)\n    end\n  end\n\n  def prev_path\n    unless @conversations.empty?\n      api_v1_conversations_url pagination_params(min_id: pagination_since_id)\n    end\n  end\n\n  def pagination_max_id\n    @conversations.last.last_status_id\n  end\n\n  def pagination_since_id\n    @conversations.first.last_status_id\n  end\n\n  def records_continue?\n    @conversations.size == limit_param(LIMIT)\n  end\n\n  def pagination_params(core_params)\n    params.slice(:limit).permit(:limit).merge(core_params)\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/custom_emojis_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::CustomEmojisController < Api::BaseController\n  respond_to :json\n\n  skip_before_action :set_cache_headers\n\n  def index\n    render_cached_json('api:v1:custom_emojis', expires_in: 1.minute) do\n      ActiveModelSerializers::SerializableResource.new(CustomEmoji.local.where(disabled: false), each_serializer: REST::CustomEmojiSerializer)\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/domain_blocks_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::DomainBlocksController < Api::BaseController\n  BLOCK_LIMIT = 100\n\n  before_action -> { doorkeeper_authorize! :follow, :'read:blocks' }, only: :show\n  before_action -> { doorkeeper_authorize! :follow, :'write:blocks' }, except: :show\n  before_action :require_user!\n  after_action :insert_pagination_headers, only: :show\n\n  respond_to :json\n\n  def show\n    @blocks = load_domain_blocks\n    render json: @blocks.map(&:domain)\n  end\n\n  def create\n    current_account.block_domain!(domain_block_params[:domain])\n    AfterAccountDomainBlockWorker.perform_async(current_account.id, domain_block_params[:domain])\n    render_empty\n  end\n\n  def destroy\n    current_account.unblock_domain!(domain_block_params[:domain])\n    render_empty\n  end\n\n  private\n\n  def load_domain_blocks\n    account_domain_blocks.paginate_by_max_id(\n      limit_param(BLOCK_LIMIT),\n      params[:max_id],\n      params[:since_id]\n    )\n  end\n\n  def account_domain_blocks\n    current_account.domain_blocks\n  end\n\n  def insert_pagination_headers\n    set_pagination_headers(next_path, prev_path)\n  end\n\n  def next_path\n    if records_continue?\n      api_v1_domain_blocks_url pagination_params(max_id: pagination_max_id)\n    end\n  end\n\n  def prev_path\n    unless @blocks.empty?\n      api_v1_domain_blocks_url pagination_params(since_id: pagination_since_id)\n    end\n  end\n\n  def pagination_max_id\n    @blocks.last.id\n  end\n\n  def pagination_since_id\n    @blocks.first.id\n  end\n\n  def records_continue?\n    @blocks.size == limit_param(BLOCK_LIMIT)\n  end\n\n  def pagination_params(core_params)\n    params.slice(:limit).permit(:limit).merge(core_params)\n  end\n\n  def domain_block_params\n    params.permit(:domain)\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/endorsements_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::EndorsementsController < Api::BaseController\n  before_action -> { doorkeeper_authorize! :read, :'read:accounts' }\n  before_action :require_user!\n  after_action :insert_pagination_headers\n\n  respond_to :json\n\n  def index\n    @accounts = load_accounts\n    render json: @accounts, each_serializer: REST::AccountSerializer\n  end\n\n  private\n\n  def load_accounts\n    if unlimited?\n      endorsed_accounts.all\n    else\n      endorsed_accounts.paginate_by_max_id(\n        limit_param(DEFAULT_ACCOUNTS_LIMIT),\n        params[:max_id],\n        params[:since_id]\n      )\n    end\n  end\n\n  def endorsed_accounts\n    current_account.endorsed_accounts.includes(:account_stat)\n  end\n\n  def insert_pagination_headers\n    set_pagination_headers(next_path, prev_path)\n  end\n\n  def next_path\n    return if unlimited?\n\n    if records_continue?\n      api_v1_endorsements_url pagination_params(max_id: pagination_max_id)\n    end\n  end\n\n  def prev_path\n    return if unlimited?\n\n    unless @accounts.empty?\n      api_v1_endorsements_url pagination_params(since_id: pagination_since_id)\n    end\n  end\n\n  def pagination_max_id\n    @accounts.last.id\n  end\n\n  def pagination_since_id\n    @accounts.first.id\n  end\n\n  def records_continue?\n    @accounts.size == limit_param(DEFAULT_ACCOUNTS_LIMIT)\n  end\n\n  def pagination_params(core_params)\n    params.slice(:limit).permit(:limit).merge(core_params)\n  end\n\n  def unlimited?\n    params[:limit] == '0'\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/favourites_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::FavouritesController < Api::BaseController\n  before_action -> { doorkeeper_authorize! :read, :'read:favourites' }\n  before_action :require_user!\n  after_action :insert_pagination_headers\n\n  respond_to :json\n\n  def index\n    @statuses = load_statuses\n    render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id)\n  end\n\n  private\n\n  def load_statuses\n    cached_favourites\n  end\n\n  def cached_favourites\n    cache_collection(\n      Status.reorder(nil).joins(:favourites).merge(results),\n      Status\n    )\n  end\n\n  def results\n    @_results ||= account_favourites.paginate_by_id(\n      limit_param(DEFAULT_STATUSES_LIMIT),\n      params_slice(:max_id, :since_id, :min_id)\n    )\n  end\n\n  def account_favourites\n    current_account.favourites\n  end\n\n  def insert_pagination_headers\n    set_pagination_headers(next_path, prev_path)\n  end\n\n  def next_path\n    if records_continue?\n      api_v1_favourites_url pagination_params(max_id: pagination_max_id)\n    end\n  end\n\n  def prev_path\n    unless results.empty?\n      api_v1_favourites_url pagination_params(min_id: pagination_since_id)\n    end\n  end\n\n  def pagination_max_id\n    results.last.id\n  end\n\n  def pagination_since_id\n    results.first.id\n  end\n\n  def records_continue?\n    results.size == limit_param(DEFAULT_STATUSES_LIMIT)\n  end\n\n  def pagination_params(core_params)\n    params.slice(:limit).permit(:limit).merge(core_params)\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/filters_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::FiltersController < Api::BaseController\n  before_action -> { doorkeeper_authorize! :read, :'read:filters' }, only: [:index, :show]\n  before_action -> { doorkeeper_authorize! :write, :'write:filters' }, except: [:index, :show]\n  before_action :require_user!\n  before_action :set_filters, only: :index\n  before_action :set_filter, only: [:show, :update, :destroy]\n\n  respond_to :json\n\n  def index\n    render json: @filters, each_serializer: REST::FilterSerializer\n  end\n\n  def create\n    @filter = current_account.custom_filters.create!(resource_params)\n    render json: @filter, serializer: REST::FilterSerializer\n  end\n\n  def show\n    render json: @filter, serializer: REST::FilterSerializer\n  end\n\n  def update\n    @filter.update!(resource_params)\n    render json: @filter, serializer: REST::FilterSerializer\n  end\n\n  def destroy\n    @filter.destroy!\n    render_empty\n  end\n\n  private\n\n  def set_filters\n    @filters = current_account.custom_filters\n  end\n\n  def set_filter\n    @filter = current_account.custom_filters.find(params[:id])\n  end\n\n  def resource_params\n    params.permit(:phrase, :expires_in, :irreversible, :whole_word, context: [])\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/follow_requests_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::FollowRequestsController < Api::BaseController\n  before_action -> { doorkeeper_authorize! :follow, :'read:follows' }, only: :index\n  before_action -> { doorkeeper_authorize! :follow, :'write:follows' }, except: :index\n  before_action :require_user!\n  after_action :insert_pagination_headers, only: :index\n\n  def index\n    @accounts = load_accounts\n    render json: @accounts, each_serializer: REST::AccountSerializer\n  end\n\n  def authorize\n    AuthorizeFollowService.new.call(account, current_account)\n    NotifyService.new.call(current_account, Follow.find_by(account: account, target_account: current_account))\n    render_empty\n  end\n\n  def reject\n    RejectFollowService.new.call(account, current_account)\n    render_empty\n  end\n\n  private\n\n  def account\n    Account.find(params[:id])\n  end\n\n  def load_accounts\n    default_accounts.merge(paginated_follow_requests).to_a\n  end\n\n  def default_accounts\n    Account.includes(:follow_requests, :account_stat).references(:follow_requests)\n  end\n\n  def paginated_follow_requests\n    FollowRequest.where(target_account: current_account).paginate_by_max_id(\n      limit_param(DEFAULT_ACCOUNTS_LIMIT),\n      params[:max_id],\n      params[:since_id]\n    )\n  end\n\n  def insert_pagination_headers\n    set_pagination_headers(next_path, prev_path)\n  end\n\n  def next_path\n    if records_continue?\n      api_v1_follow_requests_url pagination_params(max_id: pagination_max_id)\n    end\n  end\n\n  def prev_path\n    unless @accounts.empty?\n      api_v1_follow_requests_url pagination_params(since_id: pagination_since_id)\n    end\n  end\n\n  def pagination_max_id\n    @accounts.last.follow_requests.last.id\n  end\n\n  def pagination_since_id\n    @accounts.first.follow_requests.first.id\n  end\n\n  def records_continue?\n    @accounts.size == limit_param(DEFAULT_ACCOUNTS_LIMIT)\n  end\n\n  def pagination_params(core_params)\n    params.slice(:limit).permit(:limit).merge(core_params)\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/follows_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::FollowsController < Api::BaseController\n  before_action -> { doorkeeper_authorize! :follow, :'write:follows' }\n  before_action :require_user!\n\n  respond_to :json\n\n  def create\n    raise ActiveRecord::RecordNotFound if follow_params[:uri].blank?\n\n    @account = FollowService.new.call(current_user.account, target_uri).try(:target_account)\n\n    if @account.nil?\n      username, domain = target_uri.split('@')\n      @account         = Account.find_remote!(username, domain)\n    end\n\n    render json: @account, serializer: REST::AccountSerializer\n  end\n\n  private\n\n  def target_uri\n    follow_params[:uri].strip.gsub(/\\A@/, '')\n  end\n\n  def follow_params\n    params.permit(:uri)\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/instances/activity_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::Instances::ActivityController < Api::BaseController\n  before_action :require_enabled_api!\n  skip_before_action :set_cache_headers\n\n  respond_to :json\n\n  def show\n    render_cached_json('api:v1:instances:activity:show', expires_in: 1.day) { activity }\n  end\n\n  private\n\n  def activity\n    weeks = []\n\n    12.times do |i|\n      day     = i.weeks.ago.to_date\n      week_id = day.cweek\n      week    = Date.commercial(day.cwyear, week_id)\n\n      weeks << {\n        week: week.to_time.to_i.to_s,\n        statuses: Redis.current.get(\"activity:statuses:local:#{week_id}\") || '0',\n        logins: Redis.current.pfcount(\"activity:logins:#{week_id}\").to_s,\n        registrations: Redis.current.get(\"activity:accounts:local:#{week_id}\") || '0',\n      }\n    end\n\n    weeks\n  end\n\n  def require_enabled_api!\n    head 404 unless Setting.activity_api_enabled\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/instances/peers_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::Instances::PeersController < Api::BaseController\n  before_action :require_enabled_api!\n  skip_before_action :set_cache_headers\n\n  respond_to :json\n\n  def index\n    render_cached_json('api:v1:instances:peers:index', expires_in: 1.day) { Account.remote.domains }\n  end\n\n  private\n\n  def require_enabled_api!\n    head 404 unless Setting.peers_api_enabled\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/instances_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::InstancesController < Api::BaseController\n  respond_to :json\n  skip_before_action :set_cache_headers\n\n  def show\n    render_cached_json('api:v1:instances', expires_in: 5.minutes) do\n      ActiveModelSerializers::SerializableResource.new({}, serializer: REST::InstanceSerializer)\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/lists/accounts_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::Lists::AccountsController < Api::BaseController\n  before_action -> { doorkeeper_authorize! :read, :'read:lists' }, only: [:show]\n  before_action -> { doorkeeper_authorize! :write, :'write:lists' }, except: [:show]\n\n  before_action :require_user!\n  before_action :set_list\n\n  after_action :insert_pagination_headers, only: :show\n\n  def show\n    @accounts = load_accounts\n    render json: @accounts, each_serializer: REST::AccountSerializer\n  end\n\n  def create\n    ApplicationRecord.transaction do\n      list_accounts.each do |account|\n        @list.accounts << account\n      end\n    end\n\n    render_empty\n  end\n\n  def destroy\n    ListAccount.where(list: @list, account_id: account_ids).destroy_all\n    render_empty\n  end\n\n  private\n\n  def set_list\n    @list = List.where(account: current_account).find(params[:list_id])\n  end\n\n  def load_accounts\n    if unlimited?\n      @list.accounts.includes(:account_stat).all\n    else\n      @list.accounts.includes(:account_stat).paginate_by_max_id(limit_param(DEFAULT_ACCOUNTS_LIMIT), params[:max_id], params[:since_id])\n    end\n  end\n\n  def list_accounts\n    Account.find(account_ids)\n  end\n\n  def account_ids\n    Array(resource_params[:account_ids])\n  end\n\n  def resource_params\n    params.permit(account_ids: [])\n  end\n\n  def insert_pagination_headers\n    set_pagination_headers(next_path, prev_path)\n  end\n\n  def next_path\n    return if unlimited?\n\n    if records_continue?\n      api_v1_list_accounts_url pagination_params(max_id: pagination_max_id)\n    end\n  end\n\n  def prev_path\n    return if unlimited?\n\n    unless @accounts.empty?\n      api_v1_list_accounts_url pagination_params(since_id: pagination_since_id)\n    end\n  end\n\n  def pagination_max_id\n    @accounts.last.id\n  end\n\n  def pagination_since_id\n    @accounts.first.id\n  end\n\n  def records_continue?\n    @accounts.size == limit_param(DEFAULT_ACCOUNTS_LIMIT)\n  end\n\n  def pagination_params(core_params)\n    params.slice(:limit).permit(:limit).merge(core_params)\n  end\n\n  def unlimited?\n    params[:limit] == '0'\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/lists_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::ListsController < Api::BaseController\n  before_action -> { doorkeeper_authorize! :read, :'read:lists' }, only: [:index, :show]\n  before_action -> { doorkeeper_authorize! :write, :'write:lists' }, except: [:index, :show]\n\n  before_action :require_user!\n  before_action :set_list, except: [:index, :create]\n\n  def index\n    @lists = List.where(account: current_account).all\n    render json: @lists, each_serializer: REST::ListSerializer\n  end\n\n  def show\n    render json: @list, serializer: REST::ListSerializer\n  end\n\n  def create\n    @list = List.create!(list_params.merge(account: current_account))\n    render json: @list, serializer: REST::ListSerializer\n  end\n\n  def update\n    @list.update!(list_params)\n    render json: @list, serializer: REST::ListSerializer\n  end\n\n  def destroy\n    @list.destroy!\n    render_empty\n  end\n\n  private\n\n  def set_list\n    @list = List.where(account: current_account).find(params[:id])\n  end\n\n  def list_params\n    params.permit(:title)\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/media_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::MediaController < Api::BaseController\n  before_action -> { doorkeeper_authorize! :write, :'write:media' }\n  before_action :require_user!\n\n  include ObfuscateFilename\n  obfuscate_filename :file\n\n  respond_to :json\n\n  def create\n    @media = current_account.media_attachments.create!(media_params)\n    render json: @media, serializer: REST::MediaAttachmentSerializer\n  rescue Paperclip::Errors::NotIdentifiedByImageMagickError\n    render json: file_type_error, status: 422\n  rescue Paperclip::Error\n    render json: processing_error, status: 500\n  end\n\n  def update\n    @media = current_account.media_attachments.where(status_id: nil).find(params[:id])\n    @media.update!(media_params)\n    render json: @media, serializer: REST::MediaAttachmentSerializer\n  end\n\n  private\n\n  def media_params\n    params.permit(:file, :description, :focus)\n  end\n\n  def file_type_error\n    { error: 'File type of uploaded media could not be verified' }\n  end\n\n  def processing_error\n    { error: 'Error processing thumbnail for uploaded media' }\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/mutes_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::MutesController < Api::BaseController\n  before_action -> { doorkeeper_authorize! :follow, :'read:mutes' }\n  before_action :require_user!\n  after_action :insert_pagination_headers\n\n  respond_to :json\n\n  def index\n    @accounts = load_accounts\n    render json: @accounts, each_serializer: REST::AccountSerializer\n  end\n\n  private\n\n  def load_accounts\n    paginated_mutes.map(&:target_account)\n  end\n\n  def paginated_mutes\n    @paginated_mutes ||= Mute.eager_load(:target_account)\n                             .where(account: current_account)\n                             .paginate_by_max_id(\n                               limit_param(DEFAULT_ACCOUNTS_LIMIT),\n                               params[:max_id],\n                               params[:since_id]\n                             )\n  end\n\n  def insert_pagination_headers\n    set_pagination_headers(next_path, prev_path)\n  end\n\n  def next_path\n    if records_continue?\n      api_v1_mutes_url pagination_params(max_id: pagination_max_id)\n    end\n  end\n\n  def prev_path\n    unless paginated_mutes.empty?\n      api_v1_mutes_url pagination_params(since_id: pagination_since_id)\n    end\n  end\n\n  def pagination_max_id\n    paginated_mutes.last.id\n  end\n\n  def pagination_since_id\n    paginated_mutes.first.id\n  end\n\n  def records_continue?\n    paginated_mutes.size == limit_param(DEFAULT_ACCOUNTS_LIMIT)\n  end\n\n  def pagination_params(core_params)\n    params.slice(:limit).permit(:limit).merge(core_params)\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/notifications_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::NotificationsController < Api::BaseController\n  before_action -> { doorkeeper_authorize! :read, :'read:notifications' }, except: [:clear, :dismiss]\n  before_action -> { doorkeeper_authorize! :write, :'write:notifications' }, only: [:clear, :dismiss]\n  before_action :require_user!\n  after_action :insert_pagination_headers, only: :index\n\n  respond_to :json\n\n  DEFAULT_NOTIFICATIONS_LIMIT = 15\n\n  def index\n    @notifications = load_notifications\n    render json: @notifications, each_serializer: REST::NotificationSerializer, relationships: StatusRelationshipsPresenter.new(target_statuses_from_notifications, current_user&.account_id)\n  end\n\n  def show\n    @notification = current_account.notifications.find(params[:id])\n    render json: @notification, serializer: REST::NotificationSerializer\n  end\n\n  def clear\n    current_account.notifications.delete_all\n    render_empty\n  end\n\n  def dismiss\n    current_account.notifications.find_by!(id: params[:id]).destroy!\n    render_empty\n  end\n\n  private\n\n  def load_notifications\n    cache_collection paginated_notifications, Notification\n  end\n\n  def paginated_notifications\n    browserable_account_notifications.paginate_by_id(\n      limit_param(DEFAULT_NOTIFICATIONS_LIMIT),\n      params_slice(:max_id, :since_id, :min_id)\n    )\n  end\n\n  def browserable_account_notifications\n    current_account.notifications.browserable(exclude_types, from_account)\n  end\n\n  def target_statuses_from_notifications\n    @notifications.reject { |notification| notification.target_status.nil? }.map(&:target_status)\n  end\n\n  def insert_pagination_headers\n    set_pagination_headers(next_path, prev_path)\n  end\n\n  def next_path\n    unless @notifications.empty?\n      api_v1_notifications_url pagination_params(max_id: pagination_max_id)\n    end\n  end\n\n  def prev_path\n    unless @notifications.empty?\n      api_v1_notifications_url pagination_params(min_id: pagination_since_id)\n    end\n  end\n\n  def pagination_max_id\n    @notifications.last.id\n  end\n\n  def pagination_since_id\n    @notifications.first.id\n  end\n\n  def exclude_types\n    val = params.permit(exclude_types: [])[:exclude_types] || []\n    val = [val] unless val.is_a?(Enumerable)\n    val\n  end\n\n  def from_account\n    params[:account_id]\n  end\n\n  def pagination_params(core_params)\n    params.slice(:limit, :exclude_types).permit(:limit, exclude_types: []).merge(core_params)\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/polls/votes_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::Polls::VotesController < Api::BaseController\n  include Authorization\n\n  before_action -> { doorkeeper_authorize! :write, :'write:statuses' }\n  before_action :require_user!\n  before_action :set_poll\n\n  respond_to :json\n\n  def create\n    VoteService.new.call(current_account, @poll, vote_params[:choices])\n    render json: @poll, serializer: REST::PollSerializer\n  end\n\n  private\n\n  def set_poll\n    @poll = Poll.attached.find(params[:poll_id])\n    authorize @poll.status, :show?\n  rescue Mastodon::NotPermittedError\n    raise ActiveRecord::RecordNotFound\n  end\n\n  def vote_params\n    params.permit(choices: [])\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/polls_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::PollsController < Api::BaseController\n  include Authorization\n\n  before_action -> { authorize_if_got_token! :read, :'read:statuses' }, only: :show\n  before_action :set_poll\n  before_action :refresh_poll\n\n  respond_to :json\n\n  def show\n    render json: @poll, serializer: REST::PollSerializer, include_results: true\n  end\n\n  private\n\n  def set_poll\n    @poll = Poll.attached.find(params[:id])\n    authorize @poll.status, :show?\n  rescue Mastodon::NotPermittedError\n    raise ActiveRecord::RecordNotFound\n  end\n\n  def refresh_poll\n    ActivityPub::FetchRemotePollService.new.call(@poll, current_account) if user_signed_in? && @poll.possibly_stale?\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/preferences_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::PreferencesController < Api::BaseController\n  before_action -> { doorkeeper_authorize! :read, :'read:accounts' }\n  before_action :require_user!\n\n  respond_to :json\n\n  def index\n    render json: current_account, serializer: REST::PreferencesSerializer\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/push/subscriptions_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::Push::SubscriptionsController < Api::BaseController\n  before_action -> { doorkeeper_authorize! :push }\n  before_action :require_user!\n  before_action :set_web_push_subscription\n\n  def create\n    @web_subscription&.destroy!\n\n    @web_subscription = ::Web::PushSubscription.create!(\n      endpoint: subscription_params[:endpoint],\n      key_p256dh: subscription_params[:keys][:p256dh],\n      key_auth: subscription_params[:keys][:auth],\n      data: data_params,\n      user_id: current_user.id,\n      access_token_id: doorkeeper_token.id\n    )\n\n    render json: @web_subscription, serializer: REST::WebPushSubscriptionSerializer\n  end\n\n  def show\n    raise ActiveRecord::RecordNotFound if @web_subscription.nil?\n\n    render json: @web_subscription, serializer: REST::WebPushSubscriptionSerializer\n  end\n\n  def update\n    raise ActiveRecord::RecordNotFound if @web_subscription.nil?\n\n    @web_subscription.update!(data: data_params)\n\n    render json: @web_subscription, serializer: REST::WebPushSubscriptionSerializer\n  end\n\n  def destroy\n    @web_subscription&.destroy!\n    render_empty\n  end\n\n  private\n\n  def set_web_push_subscription\n    @web_subscription = ::Web::PushSubscription.find_by(access_token_id: doorkeeper_token.id)\n  end\n\n  def subscription_params\n    params.require(:subscription).permit(:endpoint, keys: [:auth, :p256dh])\n  end\n\n  def data_params\n    return {} if params[:data].blank?\n    params.require(:data).permit(alerts: [:follow, :favourite, :reblog, :mention, :poll])\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/reports_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::ReportsController < Api::BaseController\n  before_action -> { doorkeeper_authorize! :write, :'write:reports' }, only: [:create]\n  before_action :require_user!\n\n  respond_to :json\n\n  def create\n    @report = ReportService.new.call(\n      current_account,\n      reported_account,\n      status_ids: reported_status_ids,\n      comment: report_params[:comment],\n      forward: report_params[:forward]\n    )\n\n    render json: @report, serializer: REST::ReportSerializer\n  end\n\n  private\n\n  def reported_status_ids\n    reported_account.statuses.find(status_ids).pluck(:id)\n  end\n\n  def status_ids\n    Array(report_params[:status_ids])\n  end\n\n  def reported_account\n    Account.find(report_params[:account_id])\n  end\n\n  def report_params\n    params.permit(:account_id, :comment, :forward, status_ids: [])\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/scheduled_statuses_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::ScheduledStatusesController < Api::BaseController\n  include Authorization\n\n  before_action -> { doorkeeper_authorize! :read, :'read:statuses' }, except: [:update, :destroy]\n  before_action -> { doorkeeper_authorize! :write, :'write:statuses' }, only: [:update, :destroy]\n\n  before_action :set_statuses, only: :index\n  before_action :set_status, except: :index\n\n  after_action :insert_pagination_headers, only: :index\n\n  def index\n    render json: @statuses, each_serializer: REST::ScheduledStatusSerializer\n  end\n\n  def show\n    render json: @status, serializer: REST::ScheduledStatusSerializer\n  end\n\n  def update\n    @status.update!(scheduled_status_params)\n    render json: @status, serializer: REST::ScheduledStatusSerializer\n  end\n\n  def destroy\n    @status.destroy!\n    render_empty\n  end\n\n  private\n\n  def set_statuses\n    @statuses = current_account.scheduled_statuses.paginate_by_id(limit_param(DEFAULT_STATUSES_LIMIT), params_slice(:max_id, :since_id, :min_id))\n  end\n\n  def set_status\n    @status = current_account.scheduled_statuses.find(params[:id])\n  end\n\n  def scheduled_status_params\n    params.permit(:scheduled_at)\n  end\n\n  def pagination_params(core_params)\n    params.slice(:limit).permit(:limit).merge(core_params)\n  end\n\n  def insert_pagination_headers\n    set_pagination_headers(next_path, prev_path)\n  end\n\n  def next_path\n    if records_continue?\n      api_v1_scheduled_statuses_url pagination_params(max_id: pagination_max_id)\n    end\n  end\n\n  def prev_path\n    unless @statuses.empty?\n      api_v1_scheduled_statuses_url pagination_params(min_id: pagination_since_id)\n    end\n  end\n\n  def records_continue?\n    @statuses.size == limit_param(DEFAULT_STATUSES_LIMIT)\n  end\n\n  def pagination_max_id\n    @statuses.last.id\n  end\n\n  def pagination_since_id\n    @statuses.first.id\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/search_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::SearchController < Api::BaseController\n  include Authorization\n\n  RESULTS_LIMIT = 20\n\n  before_action -> { doorkeeper_authorize! :read, :'read:search' }\n  before_action :require_user!\n\n  respond_to :json\n\n  def index\n    @search = Search.new(search_results)\n    render json: @search, serializer: REST::SearchSerializer\n  end\n\n  private\n\n  def search_results\n    SearchService.new.call(\n      params[:q],\n      current_account,\n      limit_param(RESULTS_LIMIT),\n      search_params.merge(resolve: truthy_param?(:resolve))\n    )\n  end\n\n  def search_params\n    params.permit(:type, :offset, :min_id, :max_id, :account_id)\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/statuses/favourited_by_accounts_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::Statuses::FavouritedByAccountsController < Api::BaseController\n  include Authorization\n\n  before_action -> { authorize_if_got_token! :read, :'read:accounts' }\n  before_action :set_status\n  after_action :insert_pagination_headers\n\n  respond_to :json\n\n  def index\n    @accounts = load_accounts\n    render json: @accounts, each_serializer: REST::AccountSerializer\n  end\n\n  private\n\n  def load_accounts\n    default_accounts.merge(paginated_favourites).to_a\n  end\n\n  def default_accounts\n    Account\n      .includes(:favourites, :account_stat)\n      .references(:favourites)\n      .where(favourites: { status_id: @status.id })\n  end\n\n  def paginated_favourites\n    Favourite.paginate_by_max_id(\n      limit_param(DEFAULT_ACCOUNTS_LIMIT),\n      params[:max_id],\n      params[:since_id]\n    )\n  end\n\n  def insert_pagination_headers\n    set_pagination_headers(next_path, prev_path)\n  end\n\n  def next_path\n    if records_continue?\n      api_v1_status_favourited_by_index_url pagination_params(max_id: pagination_max_id)\n    end\n  end\n\n  def prev_path\n    unless @accounts.empty?\n      api_v1_status_favourited_by_index_url pagination_params(since_id: pagination_since_id)\n    end\n  end\n\n  def pagination_max_id\n    @accounts.last.favourites.last.id\n  end\n\n  def pagination_since_id\n    @accounts.first.favourites.first.id\n  end\n\n  def records_continue?\n    @accounts.size == limit_param(DEFAULT_ACCOUNTS_LIMIT)\n  end\n\n  def set_status\n    @status = Status.find(params[:status_id])\n    authorize @status, :show?\n  rescue Mastodon::NotPermittedError\n    # Reraise in order to get a 404 instead of a 403 error code\n    raise ActiveRecord::RecordNotFound\n  end\n\n  def pagination_params(core_params)\n    params.slice(:limit).permit(:limit).merge(core_params)\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/statuses/favourites_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::Statuses::FavouritesController < Api::BaseController\n  include Authorization\n\n  before_action -> { doorkeeper_authorize! :write, :'write:favourites' }\n  before_action :require_user!\n\n  respond_to :json\n\n  def create\n    @status = favourited_status\n    render json: @status, serializer: REST::StatusSerializer\n  end\n\n  def destroy\n    @status = requested_status\n    @favourites_map = { @status.id => false }\n\n    UnfavouriteWorker.perform_async(current_user.account_id, @status.id)\n\n    render json: @status, serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new([@status], current_user&.account_id, favourites_map: @favourites_map)\n  end\n\n  private\n\n  def favourited_status\n    service_result.status.reload\n  end\n\n  def service_result\n    FavouriteService.new.call(current_user.account, requested_status)\n  end\n\n  def requested_status\n    Status.find(params[:status_id])\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/statuses/mutes_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::Statuses::MutesController < Api::BaseController\n  include Authorization\n\n  before_action -> { doorkeeper_authorize! :write, :'write:mutes' }\n  before_action :require_user!\n  before_action :set_status\n  before_action :set_conversation\n\n  respond_to :json\n\n  def create\n    current_account.mute_conversation!(@conversation)\n    @mutes_map = { @conversation.id => true }\n\n    render json: @status, serializer: REST::StatusSerializer\n  end\n\n  def destroy\n    current_account.unmute_conversation!(@conversation)\n    @mutes_map = { @conversation.id => false }\n\n    render json: @status, serializer: REST::StatusSerializer\n  end\n\n  private\n\n  def set_status\n    @status = Status.find(params[:status_id])\n    authorize @status, :show?\n  rescue Mastodon::NotPermittedError\n    # Reraise in order to get a 404 instead of a 403 error code\n    raise ActiveRecord::RecordNotFound\n  end\n\n  def set_conversation\n    @conversation = @status.conversation\n    raise Mastodon::ValidationError if @conversation.nil?\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/statuses/pins_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::Statuses::PinsController < Api::BaseController\n  include Authorization\n\n  before_action -> { doorkeeper_authorize! :write, :'write:accounts' }\n  before_action :require_user!\n  before_action :set_status\n\n  respond_to :json\n\n  def create\n    StatusPin.create!(account: current_account, status: @status)\n    distribute_add_activity!\n    render json: @status, serializer: REST::StatusSerializer\n  end\n\n  def destroy\n    pin = StatusPin.find_by(account: current_account, status: @status)\n\n    if pin\n      pin.destroy!\n      distribute_remove_activity!\n    end\n\n    render json: @status, serializer: REST::StatusSerializer\n  end\n\n  private\n\n  def set_status\n    @status = Status.find(params[:status_id])\n  end\n\n  def distribute_add_activity!\n    json = ActiveModelSerializers::SerializableResource.new(\n      @status,\n      serializer: ActivityPub::AddSerializer,\n      adapter: ActivityPub::Adapter\n    ).as_json\n\n    ActivityPub::RawDistributionWorker.perform_async(Oj.dump(json), current_account.id)\n  end\n\n  def distribute_remove_activity!\n    json = ActiveModelSerializers::SerializableResource.new(\n      @status,\n      serializer: ActivityPub::RemoveSerializer,\n      adapter: ActivityPub::Adapter\n    ).as_json\n\n    ActivityPub::RawDistributionWorker.perform_async(Oj.dump(json), current_account.id)\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/statuses/reblogged_by_accounts_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::Statuses::RebloggedByAccountsController < Api::BaseController\n  include Authorization\n\n  before_action -> { authorize_if_got_token! :read, :'read:accounts' }\n  before_action :set_status\n  after_action :insert_pagination_headers\n\n  respond_to :json\n\n  def index\n    @accounts = load_accounts\n    render json: @accounts, each_serializer: REST::AccountSerializer\n  end\n\n  private\n\n  def load_accounts\n    default_accounts.merge(paginated_statuses).to_a\n  end\n\n  def default_accounts\n    Account.includes(:statuses, :account_stat).references(:statuses)\n  end\n\n  def paginated_statuses\n    Status.where(reblog_of_id: @status.id).where(visibility: [:public, :unlisted]).paginate_by_max_id(\n      limit_param(DEFAULT_ACCOUNTS_LIMIT),\n      params[:max_id],\n      params[:since_id]\n    )\n  end\n\n  def insert_pagination_headers\n    set_pagination_headers(next_path, prev_path)\n  end\n\n  def next_path\n    if records_continue?\n      api_v1_status_reblogged_by_index_url pagination_params(max_id: pagination_max_id)\n    end\n  end\n\n  def prev_path\n    unless @accounts.empty?\n      api_v1_status_reblogged_by_index_url pagination_params(since_id: pagination_since_id)\n    end\n  end\n\n  def pagination_max_id\n    @accounts.last.statuses.last.id\n  end\n\n  def pagination_since_id\n    @accounts.first.statuses.first.id\n  end\n\n  def records_continue?\n    @accounts.size == limit_param(DEFAULT_ACCOUNTS_LIMIT)\n  end\n\n  def set_status\n    @status = Status.find(params[:status_id])\n    authorize @status, :show?\n  rescue Mastodon::NotPermittedError\n    # Reraise in order to get a 404 instead of a 403 error code\n    raise ActiveRecord::RecordNotFound\n  end\n\n  def pagination_params(core_params)\n    params.slice(:limit).permit(:limit).merge(core_params)\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/statuses/reblogs_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::Statuses::ReblogsController < Api::BaseController\n  include Authorization\n\n  before_action -> { doorkeeper_authorize! :write, :'write:statuses' }\n  before_action :require_user!\n\n  respond_to :json\n\n  def create\n    @status = ReblogService.new.call(current_user.account, status_for_reblog, reblog_params)\n    render json: @status, serializer: REST::StatusSerializer\n  end\n\n  def destroy\n    @status = status_for_destroy.reblog\n    @reblogs_map = { @status.id => false }\n\n    authorize status_for_destroy, :unreblog?\n    RemovalWorker.perform_async(status_for_destroy.id)\n\n    render json: @status, serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new([@status], current_user&.account_id, reblogs_map: @reblogs_map)\n  end\n\n  private\n\n  def status_for_reblog\n    Status.find params[:status_id]\n  end\n\n  def status_for_destroy\n    current_user.account.statuses.where(reblog_of_id: params[:status_id]).first!\n  end\n\n  def reblog_params\n    params.permit(:visibility)\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/statuses_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::StatusesController < Api::BaseController\n  include Authorization\n\n  before_action -> { authorize_if_got_token! :read, :'read:statuses' }, except: [:create, :destroy]\n  before_action -> { doorkeeper_authorize! :write, :'write:statuses' }, only:   [:create, :destroy]\n  before_action :require_user!, except:  [:show, :context, :card]\n  before_action :set_status, only:       [:show, :context, :card]\n\n  respond_to :json\n\n  # This API was originally unlimited, pagination cannot be introduced without\n  # breaking backwards-compatibility. Arbitrarily high number to cover most\n  # conversations as quasi-unlimited, it would be too much work to render more\n  # than this anyway\n  CONTEXT_LIMIT = 4_096\n\n  def show\n    @status = cache_collection([@status], Status).first\n    render json: @status, serializer: REST::StatusSerializer\n  end\n\n  def context\n    ancestors_results   = @status.in_reply_to_id.nil? ? [] : @status.ancestors(CONTEXT_LIMIT, current_account)\n    descendants_results = @status.descendants(CONTEXT_LIMIT, current_account)\n    loaded_ancestors    = cache_collection(ancestors_results, Status)\n    loaded_descendants  = cache_collection(descendants_results, Status)\n\n    @context = Context.new(ancestors: loaded_ancestors, descendants: loaded_descendants)\n    statuses = [@status] + @context.ancestors + @context.descendants\n\n    render json: @context, serializer: REST::ContextSerializer, relationships: StatusRelationshipsPresenter.new(statuses, current_user&.account_id)\n  end\n\n  def card\n    @card = @status.preview_cards.first\n\n    if @card.nil?\n      render_empty\n    else\n      render json: @card, serializer: REST::PreviewCardSerializer\n    end\n  end\n\n  def create\n    @status = PostStatusService.new.call(current_user.account,\n                                         text: status_params[:status],\n                                         thread: status_params[:in_reply_to_id].blank? ? nil : Status.find(status_params[:in_reply_to_id]),\n                                         media_ids: status_params[:media_ids],\n                                         sensitive: status_params[:sensitive],\n                                         spoiler_text: status_params[:spoiler_text],\n                                         visibility: status_params[:visibility],\n                                         scheduled_at: status_params[:scheduled_at],\n                                         application: doorkeeper_token.application,\n                                         poll: status_params[:poll],\n                                         idempotency: request.headers['Idempotency-Key'])\n\n    render json: @status, serializer: @status.is_a?(ScheduledStatus) ? REST::ScheduledStatusSerializer : REST::StatusSerializer\n  end\n\n  def destroy\n    @status = Status.where(account_id: current_user.account).find(params[:id])\n    authorize @status, :destroy?\n\n    RemovalWorker.perform_async(@status.id)\n\n    render json: @status, serializer: REST::StatusSerializer, source_requested: true\n  end\n\n  private\n\n  def set_status\n    @status = Status.find(params[:id])\n    authorize @status, :show?\n  rescue Mastodon::NotPermittedError\n    raise ActiveRecord::RecordNotFound\n  end\n\n  def status_params\n    params.permit(\n      :status,\n      :in_reply_to_id,\n      :sensitive,\n      :spoiler_text,\n      :visibility,\n      :scheduled_at,\n      media_ids: [],\n      poll: [\n        :multiple,\n        :hide_totals,\n        :expires_in,\n        options: [],\n      ]\n    )\n  end\n\n  def pagination_params(core_params)\n    params.slice(:limit).permit(:limit).merge(core_params)\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/streaming_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::StreamingController < Api::BaseController\n  respond_to :json\n\n  def index\n    if Rails.configuration.x.streaming_api_base_url != request.host\n      uri = URI.parse(request.url)\n      uri.host = URI.parse(Rails.configuration.x.streaming_api_base_url).host\n      redirect_to uri.to_s, status: 301\n    else\n      raise ActiveRecord::RecordNotFound\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/suggestions_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::SuggestionsController < Api::BaseController\n  include Authorization\n\n  before_action -> { doorkeeper_authorize! :read }\n  before_action :require_user!\n  before_action :set_accounts\n\n  respond_to :json\n\n  def index\n    render json: @accounts, each_serializer: REST::AccountSerializer\n  end\n\n  def destroy\n    PotentialFriendshipTracker.remove(current_account.id, params[:id])\n    render_empty\n  end\n\n  private\n\n  def set_accounts\n    @accounts = PotentialFriendshipTracker.get(current_account.id, limit: limit_param(DEFAULT_ACCOUNTS_LIMIT))\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/timelines/direct_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::Timelines::DirectController < Api::BaseController\n  before_action -> { doorkeeper_authorize! :read, :'read:statuses' }, only: [:show]\n  before_action :require_user!, only: [:show]\n  after_action :insert_pagination_headers, unless: -> { @statuses.empty? }\n\n  respond_to :json\n\n  def show\n    @statuses = load_statuses\n    render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id)\n  end\n\n  private\n\n  def load_statuses\n    cached_direct_statuses\n  end\n\n  def cached_direct_statuses\n    cache_collection direct_statuses, Status\n  end\n\n  def direct_statuses\n    direct_timeline_statuses\n  end\n\n  def direct_timeline_statuses\n    # this query requires built in pagination.\n    Status.as_direct_timeline(\n      current_account,\n      limit_param(DEFAULT_STATUSES_LIMIT),\n      params[:max_id],\n      params[:since_id],\n      true # returns array of cache_ids object\n    )\n  end\n\n  def insert_pagination_headers\n    set_pagination_headers(next_path, prev_path)\n  end\n\n  def pagination_params(core_params)\n    params.permit(:local, :limit).merge(core_params)\n  end\n\n  def next_path\n    api_v1_timelines_direct_url pagination_params(max_id: pagination_max_id)\n  end\n\n  def prev_path\n    api_v1_timelines_direct_url pagination_params(since_id: pagination_since_id)\n  end\n\n  def pagination_max_id\n    @statuses.last.id\n  end\n\n  def pagination_since_id\n    @statuses.first.id\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/timelines/home_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::Timelines::HomeController < Api::BaseController\n  before_action -> { doorkeeper_authorize! :read, :'read:statuses' }, only: [:show]\n  before_action :require_user!, only: [:show]\n  after_action :insert_pagination_headers, unless: -> { @statuses.empty? }\n\n  respond_to :json\n\n  def show\n    @statuses = load_statuses\n\n    render json: @statuses,\n           each_serializer: REST::StatusSerializer,\n           relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id),\n           status: regeneration_in_progress? ? 206 : 200\n  end\n\n  private\n\n  def load_statuses\n    cached_home_statuses\n  end\n\n  def cached_home_statuses\n    cache_collection home_statuses, Status\n  end\n\n  def home_statuses\n    account_home_feed.get(\n      limit_param(DEFAULT_STATUSES_LIMIT),\n      params[:max_id],\n      params[:since_id],\n      params[:min_id]\n    )\n  end\n\n  def account_home_feed\n    HomeFeed.new(current_account)\n  end\n\n  def insert_pagination_headers\n    set_pagination_headers(next_path, prev_path)\n  end\n\n  def pagination_params(core_params)\n    params.slice(:local, :limit).permit(:local, :limit).merge(core_params)\n  end\n\n  def next_path\n    api_v1_timelines_home_url pagination_params(max_id: pagination_max_id)\n  end\n\n  def prev_path\n    api_v1_timelines_home_url pagination_params(min_id: pagination_since_id)\n  end\n\n  def pagination_max_id\n    @statuses.last.id\n  end\n\n  def pagination_since_id\n    @statuses.first.id\n  end\n\n  def regeneration_in_progress?\n    Redis.current.exists(\"account:#{current_account.id}:regeneration\")\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/timelines/list_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::Timelines::ListController < Api::BaseController\n  before_action -> { doorkeeper_authorize! :read, :'read:lists' }\n  before_action :require_user!\n  before_action :set_list\n  before_action :set_statuses\n\n  after_action :insert_pagination_headers, unless: -> { @statuses.empty? }\n\n  def show\n    render json: @statuses,\n           each_serializer: REST::StatusSerializer,\n           relationships: StatusRelationshipsPresenter.new(@statuses, current_user.account_id)\n  end\n\n  private\n\n  def set_list\n    @list = List.where(account: current_account).find(params[:id])\n  end\n\n  def set_statuses\n    @statuses = cached_list_statuses\n  end\n\n  def cached_list_statuses\n    cache_collection list_statuses, Status\n  end\n\n  def list_statuses\n    list_feed.get(\n      limit_param(DEFAULT_STATUSES_LIMIT),\n      params[:max_id],\n      params[:since_id],\n      params[:min_id]\n    )\n  end\n\n  def list_feed\n    ListFeed.new(@list)\n  end\n\n  def insert_pagination_headers\n    set_pagination_headers(next_path, prev_path)\n  end\n\n  def pagination_params(core_params)\n    params.slice(:limit).permit(:limit).merge(core_params)\n  end\n\n  def next_path\n    api_v1_timelines_list_url params[:id], pagination_params(max_id: pagination_max_id)\n  end\n\n  def prev_path\n    api_v1_timelines_list_url params[:id], pagination_params(min_id: pagination_since_id)\n  end\n\n  def pagination_max_id\n    @statuses.last.id\n  end\n\n  def pagination_since_id\n    @statuses.first.id\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/timelines/public_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::Timelines::PublicController < Api::BaseController\n  after_action :insert_pagination_headers, unless: -> { @statuses.empty? }\n\n  respond_to :json\n\n  def show\n    @statuses = load_statuses\n    render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id)\n  end\n\n  private\n\n  def load_statuses\n    cached_public_statuses\n  end\n\n  def cached_public_statuses\n    cache_collection public_statuses, Status\n  end\n\n  def public_statuses\n    statuses = public_timeline_statuses.paginate_by_id(\n      limit_param(DEFAULT_STATUSES_LIMIT),\n      params_slice(:max_id, :since_id, :min_id)\n    )\n\n    if truthy_param?(:only_media)\n      # `SELECT DISTINCT id, updated_at` is too slow, so pluck ids at first, and then select id, updated_at with ids.\n      status_ids = statuses.joins(:media_attachments).distinct(:id).pluck(:id)\n      statuses.where(id: status_ids)\n    else\n      statuses\n    end\n  end\n\n  def public_timeline_statuses\n    Status.as_public_timeline(current_account, truthy_param?(:local))\n  end\n\n  def insert_pagination_headers\n    set_pagination_headers(next_path, prev_path)\n  end\n\n  def pagination_params(core_params)\n    params.slice(:local, :limit, :only_media).permit(:local, :limit, :only_media).merge(core_params)\n  end\n\n  def next_path\n    api_v1_timelines_public_url pagination_params(max_id: pagination_max_id)\n  end\n\n  def prev_path\n    api_v1_timelines_public_url pagination_params(min_id: pagination_since_id)\n  end\n\n  def pagination_max_id\n    @statuses.last.id\n  end\n\n  def pagination_since_id\n    @statuses.first.id\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v1/timelines/tag_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V1::Timelines::TagController < Api::BaseController\n  before_action :load_tag\n  after_action :insert_pagination_headers, unless: -> { @statuses.empty? }\n\n  respond_to :json\n\n  def show\n    @statuses = load_statuses\n    render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id)\n  end\n\n  private\n\n  def load_tag\n    @tag = Tag.find_normalized(params[:id])\n  end\n\n  def load_statuses\n    cached_tagged_statuses\n  end\n\n  def cached_tagged_statuses\n    cache_collection tagged_statuses, Status\n  end\n\n  def tagged_statuses\n    if @tag.nil?\n      []\n    else\n      statuses = tag_timeline_statuses.paginate_by_id(\n        limit_param(DEFAULT_STATUSES_LIMIT),\n        params_slice(:max_id, :since_id, :min_id)\n      )\n\n      if truthy_param?(:only_media)\n        # `SELECT DISTINCT id, updated_at` is too slow, so pluck ids at first, and then select id, updated_at with ids.\n        status_ids = statuses.joins(:media_attachments).distinct(:id).pluck(:id)\n        statuses.where(id: status_ids)\n      else\n        statuses\n      end\n    end\n  end\n\n  def tag_timeline_statuses\n    HashtagQueryService.new.call(@tag, params.slice(:any, :all, :none), current_account, truthy_param?(:local))\n  end\n\n  def insert_pagination_headers\n    set_pagination_headers(next_path, prev_path)\n  end\n\n  def pagination_params(core_params)\n    params.slice(:local, :limit, :only_media).permit(:local, :limit, :only_media).merge(core_params)\n  end\n\n  def next_path\n    api_v1_timelines_tag_url params[:id], pagination_params(max_id: pagination_max_id)\n  end\n\n  def prev_path\n    api_v1_timelines_tag_url params[:id], pagination_params(min_id: pagination_since_id)\n  end\n\n  def pagination_max_id\n    @statuses.last.id\n  end\n\n  def pagination_since_id\n    @statuses.first.id\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/v2/search_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::V2::SearchController < Api::V1::SearchController\n  def index\n    @search = Search.new(search_results)\n    render json: @search, serializer: REST::V2::SearchSerializer\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/web/base_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::Web::BaseController < Api::BaseController\n  protect_from_forgery with: :exception\n\n  rescue_from ActionController::InvalidAuthenticityToken do\n    render json: { error: \"Can't verify CSRF token authenticity.\" }, status: 422\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/web/embeds_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::Web::EmbedsController < Api::Web::BaseController\n  respond_to :json\n\n  before_action :require_user!\n\n  def create\n    status = StatusFinder.new(params[:url]).status\n    render json: status, serializer: OEmbedSerializer, width: 400\n  rescue ActiveRecord::RecordNotFound\n    oembed = FetchOEmbedService.new.call(params[:url])\n    oembed[:html] = Formatter.instance.sanitize(oembed[:html], Sanitize::Config::MASTODON_OEMBED) if oembed[:html].present?\n\n    if oembed\n      render json: oembed\n    else\n      render json: {}, status: :not_found\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/web/push_subscriptions_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::Web::PushSubscriptionsController < Api::Web::BaseController\n  respond_to :json\n\n  before_action :require_user!\n\n  def create\n    active_session = current_session\n\n    unless active_session.web_push_subscription.nil?\n      active_session.web_push_subscription.destroy!\n      active_session.update!(web_push_subscription: nil)\n    end\n\n    # Mobile devices do not support regular notifications, so we enable push notifications by default\n    alerts_enabled = active_session.detection.device.mobile? || active_session.detection.device.tablet?\n\n    data = {\n      alerts: {\n        follow: alerts_enabled,\n        favourite: alerts_enabled,\n        reblog: alerts_enabled,\n        mention: alerts_enabled,\n        poll: alerts_enabled,\n      },\n    }\n\n    data.deep_merge!(data_params) if params[:data]\n\n    web_subscription = ::Web::PushSubscription.create!(\n      endpoint: subscription_params[:endpoint],\n      key_p256dh: subscription_params[:keys][:p256dh],\n      key_auth: subscription_params[:keys][:auth],\n      data: data,\n      user_id: active_session.user_id,\n      access_token_id: active_session.access_token_id\n    )\n\n    active_session.update!(web_push_subscription: web_subscription)\n\n    render json: web_subscription, serializer: REST::WebPushSubscriptionSerializer\n  end\n\n  def update\n    params.require([:id])\n\n    web_subscription = ::Web::PushSubscription.find(params[:id])\n    web_subscription.update!(data: data_params)\n\n    render json: web_subscription, serializer: REST::WebPushSubscriptionSerializer\n  end\n\n  private\n\n  def subscription_params\n    @subscription_params ||= params.require(:subscription).permit(:endpoint, keys: [:auth, :p256dh])\n  end\n\n  def data_params\n    @data_params ||= params.require(:data).permit(alerts: [:follow, :favourite, :reblog, :mention, :poll])\n  end\nend\n"
  },
  {
    "path": "app/controllers/api/web/settings_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Api::Web::SettingsController < Api::Web::BaseController\n  respond_to :json\n\n  before_action :require_user!\n\n  def update\n    setting.data = params[:data]\n    setting.save!\n\n    render_empty\n  end\n\n  private\n\n  def setting\n    @_setting ||= ::Web::Setting.where(user: current_user).first_or_initialize(user: current_user)\n  end\nend\n"
  },
  {
    "path": "app/controllers/application_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass ApplicationController < ActionController::Base\n  # Prevent CSRF attacks by raising an exception.\n  # For APIs, you may want to use :null_session instead.\n  protect_from_forgery with: :exception\n\n  force_ssl if: :https_enabled?\n\n  include Localized\n  include UserTrackingConcern\n  include SessionTrackingConcern\n\n  helper_method :current_account\n  helper_method :current_session\n  helper_method :current_theme\n  helper_method :single_user_mode?\n  helper_method :use_seamless_external_login?\n\n  rescue_from ActionController::RoutingError, with: :not_found\n  rescue_from ActiveRecord::RecordNotFound, with: :not_found\n  rescue_from ActionController::InvalidAuthenticityToken, with: :unprocessable_entity\n  rescue_from ActionController::UnknownFormat, with: :not_acceptable\n  rescue_from Mastodon::NotPermittedError, with: :forbidden\n\n  before_action :store_current_location, except: :raise_not_found, unless: :devise_controller?\n  before_action :check_user_permissions, if: :user_signed_in?\n\n  def raise_not_found\n    raise ActionController::RoutingError, \"No route matches #{params[:unmatched_route]}\"\n  end\n\n  private\n\n  def https_enabled?\n    Rails.env.production?\n  end\n\n  def store_current_location\n    store_location_for(:user, request.url) unless request.format == :json\n  end\n\n  def require_admin!\n    forbidden unless current_user&.admin?\n  end\n\n  def require_staff!\n    forbidden unless current_user&.staff?\n  end\n\n  def check_user_permissions\n    forbidden if current_user.disabled? || current_user.account.suspended?\n  end\n\n  def after_sign_out_path_for(_resource_or_scope)\n    new_user_session_path\n  end\n\n  protected\n\n  def truthy_param?(key)\n    ActiveModel::Type::Boolean.new.cast(params[key])\n  end\n\n  def forbidden\n    respond_with_error(403)\n  end\n\n  def not_found\n    respond_with_error(404)\n  end\n\n  def gone\n    respond_with_error(410)\n  end\n\n  def unprocessable_entity\n    respond_with_error(422)\n  end\n\n  def not_acceptable\n    respond_with_error(406)\n  end\n\n  def single_user_mode?\n    @single_user_mode ||= Rails.configuration.x.single_user_mode && Account.exists?\n  end\n\n  def use_seamless_external_login?\n    Devise.pam_authentication || Devise.ldap_authentication\n  end\n\n  def current_account\n    @current_account ||= current_user.try(:account)\n  end\n\n  def current_session\n    @current_session ||= SessionActivation.find_by(session_id: cookies.signed['_session_id'])\n  end\n\n  def current_theme\n    return Setting.theme unless Themes.instance.names.include? current_user&.setting_theme\n    current_user.setting_theme\n  end\n\n  def cache_collection(raw, klass)\n    return raw unless klass.respond_to?(:with_includes)\n\n    raw                    = raw.cache_ids.to_a if raw.is_a?(ActiveRecord::Relation)\n    cached_keys_with_value = Rails.cache.read_multi(*raw).transform_keys(&:id)\n    uncached_ids           = raw.map(&:id) - cached_keys_with_value.keys\n\n    klass.reload_stale_associations!(cached_keys_with_value.values) if klass.respond_to?(:reload_stale_associations!)\n\n    unless uncached_ids.empty?\n      uncached = klass.where(id: uncached_ids).with_includes.each_with_object({}) { |item, h| h[item.id] = item }\n\n      uncached.each_value do |item|\n        Rails.cache.write(item, item)\n      end\n    end\n\n    raw.map { |item| cached_keys_with_value[item.id] || uncached[item.id] }.compact\n  end\n\n  def respond_with_error(code)\n    respond_to do |format|\n      format.any  { head code }\n\n      format.html do\n        set_locale\n        render \"errors/#{code}\", layout: 'error', status: code\n      end\n    end\n  end\n\n  def render_cached_json(cache_key, **options)\n    options[:expires_in] ||= 3.minutes\n    cache_public           = options.key?(:public) ? options.delete(:public) : true\n    content_type           = options.delete(:content_type) || 'application/json'\n\n    data = Rails.cache.fetch(cache_key, { raw: true }.merge(options)) do\n      yield.to_json\n    end\n\n    expires_in options[:expires_in], public: cache_public\n    render json: data, content_type: content_type\n  end\n\n  def set_cache_headers\n    response.headers['Vary'] = 'Accept'\n  end\n\n  def mark_cacheable!\n    expires_in 0, public: true\n  end\nend\n"
  },
  {
    "path": "app/controllers/auth/confirmations_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Auth::ConfirmationsController < Devise::ConfirmationsController\n  layout 'auth'\n\n  before_action :set_body_classes\n  before_action :set_user, only: [:finish_signup]\n\n  def finish_signup\n    return unless request.patch? && params[:user]\n\n    if @user.update(user_params)\n      @user.skip_reconfirmation!\n      bypass_sign_in(@user)\n      redirect_to root_path, notice: I18n.t('devise.confirmations.send_instructions')\n    else\n      @show_errors = true\n    end\n  end\n\n  private\n\n  def set_user\n    @user = current_user\n  end\n\n  def set_body_classes\n    @body_classes = 'lighter'\n  end\n\n  def user_params\n    params.require(:user).permit(:email)\n  end\n\n  def after_confirmation_path_for(_resource_name, user)\n    if user.created_by_application && truthy_param?(:redirect_to_app)\n      user.created_by_application.redirect_uri\n    else\n      super\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/auth/omniauth_callbacks_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Auth::OmniauthCallbacksController < Devise::OmniauthCallbacksController\n  skip_before_action :verify_authenticity_token\n\n  def self.provides_callback_for(provider)\n    provider_id = provider.to_s.chomp '_oauth2'\n\n    define_method provider do\n      @user = User.find_for_oauth(request.env['omniauth.auth'], current_user)\n\n      if @user.persisted?\n        sign_in_and_redirect @user, event: :authentication\n        set_flash_message(:notice, :success, kind: provider_id.capitalize) if is_navigational_format?\n      else\n        session[\"devise.#{provider}_data\"] = request.env['omniauth.auth']\n        redirect_to new_user_registration_url\n      end\n    end\n  end\n\n  Devise.omniauth_configs.each_key do |provider|\n    provides_callback_for provider\n  end\n\n  def after_sign_in_path_for(resource)\n    if resource.email_verified?\n      root_path\n    else\n      finish_signup_path\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/auth/passwords_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Auth::PasswordsController < Devise::PasswordsController\n  before_action :check_validity_of_reset_password_token, only: :edit\n  before_action :set_body_classes\n\n  layout 'auth'\n\n  private\n\n  def check_validity_of_reset_password_token\n    unless reset_password_token_is_valid?\n      flash[:error] = I18n.t('auth.invalid_reset_password_token')\n      redirect_to new_password_path(resource_name)\n    end\n  end\n\n  def set_body_classes\n    @body_classes = 'lighter'\n  end\n\n  def reset_password_token_is_valid?\n    resource_class.with_reset_password_token(params[:reset_password_token]).present?\n  end\nend\n"
  },
  {
    "path": "app/controllers/auth/registrations_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Auth::RegistrationsController < Devise::RegistrationsController\n  layout :determine_layout\n\n  before_action :set_invite, only: [:new, :create]\n  before_action :check_enabled_registrations, only: [:new, :create]\n  before_action :configure_sign_up_params, only: [:create]\n  before_action :set_sessions, only: [:edit, :update]\n  before_action :set_instance_presenter, only: [:new, :create, :update]\n  before_action :set_body_classes, only: [:new, :create, :edit, :update]\n\n  def new\n    super(&:build_invite_request)\n  end\n\n  def destroy\n    not_found\n  end\n\n  protected\n\n  def update_resource(resource, params)\n    params[:password] = nil if Devise.pam_authentication && resource.encrypted_password.blank?\n    super\n  end\n\n  def build_resource(hash = nil)\n    super(hash)\n\n    resource.locale             = I18n.locale\n    resource.invite_code        = params[:invite_code] if resource.invite_code.blank?\n    resource.agreement          = true\n    resource.current_sign_in_ip = request.remote_ip\n\n    resource.build_account if resource.account.nil?\n  end\n\n  def configure_sign_up_params\n    devise_parameter_sanitizer.permit(:sign_up) do |u|\n      u.permit({ account_attributes: [:username], invite_request_attributes: [:text] }, :email, :password, :password_confirmation, :invite_code)\n    end\n  end\n\n  def after_sign_up_path_for(_resource)\n    new_user_session_path\n  end\n\n  def after_sign_in_path_for(_resource)\n    set_invite\n\n    if @invite&.autofollow?\n      short_account_path(@invite.user.account)\n    else\n      super\n    end\n  end\n\n  def after_inactive_sign_up_path_for(_resource)\n    new_user_session_path\n  end\n\n  def after_update_path_for(_resource)\n    edit_user_registration_path\n  end\n\n  def check_enabled_registrations\n    redirect_to root_path if single_user_mode? || !allowed_registrations?\n  end\n\n  def allowed_registrations?\n    Setting.registrations_mode != 'none' || @invite&.valid_for_use?\n  end\n\n  def invite_code\n    if params[:user]\n      params[:user][:invite_code]\n    else\n      params[:invite_code]\n    end\n  end\n\n  private\n\n  def set_instance_presenter\n    @instance_presenter = InstancePresenter.new\n  end\n\n  def set_body_classes\n    @body_classes = %w(edit update).include?(action_name) ? 'admin' : 'lighter'\n  end\n\n  def set_invite\n    invite = invite_code.present? ? Invite.find_by(code: invite_code) : nil\n    @invite = invite&.valid_for_use? ? invite : nil\n  end\n\n  def determine_layout\n    %w(edit update).include?(action_name) ? 'admin' : 'auth'\n  end\n\n  def set_sessions\n    @sessions = current_user.session_activations\n  end\nend\n"
  },
  {
    "path": "app/controllers/auth/sessions_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Auth::SessionsController < Devise::SessionsController\n  include Devise::Controllers::Rememberable\n\n  layout 'auth'\n\n  skip_before_action :require_no_authentication, only: [:create]\n  skip_before_action :check_user_permissions, only: [:destroy]\n  prepend_before_action :authenticate_with_two_factor, if: :two_factor_enabled?, only: [:create]\n  before_action :set_instance_presenter, only: [:new]\n  before_action :set_body_classes\n\n  def new\n    Devise.omniauth_configs.each do |provider, config|\n      return redirect_to(omniauth_authorize_path(resource_name, provider)) if config.strategy.redirect_at_sign_in\n    end\n\n    super\n  end\n\n  def create\n    super do |resource|\n      remember_me(resource)\n      flash.delete(:notice)\n    end\n  end\n\n  def destroy\n    tmp_stored_location = stored_location_for(:user)\n    super\n    flash.delete(:notice)\n    store_location_for(:user, tmp_stored_location) if continue_after?\n  end\n\n  protected\n\n  def find_user\n    if session[:otp_user_id]\n      User.find(session[:otp_user_id])\n    elsif user_params[:email]\n      if use_seamless_external_login? && Devise.check_at_sign && user_params[:email].index('@').nil?\n        User.joins(:account).find_by(accounts: { username: user_params[:email] })\n      else\n        User.find_for_authentication(email: user_params[:email])\n      end\n    end\n  end\n\n  def user_params\n    params.require(:user).permit(:email, :password, :otp_attempt)\n  end\n\n  def after_sign_in_path_for(resource)\n    last_url = stored_location_for(:user)\n\n    if home_paths(resource).include?(last_url)\n      root_path\n    else\n      last_url || root_path\n    end\n  end\n\n  def after_sign_out_path_for(_resource_or_scope)\n    Devise.omniauth_configs.each_value do |config|\n      return root_path if config.strategy.redirect_at_sign_in\n    end\n\n    super\n  end\n\n  def two_factor_enabled?\n    find_user.try(:otp_required_for_login?)\n  end\n\n  def valid_otp_attempt?(user)\n    user.validate_and_consume_otp!(user_params[:otp_attempt]) ||\n      user.invalidate_otp_backup_code!(user_params[:otp_attempt])\n  rescue OpenSSL::Cipher::CipherError => _error\n    false\n  end\n\n  def authenticate_with_two_factor\n    user = self.resource = find_user\n\n    if user_params[:otp_attempt].present? && session[:otp_user_id]\n      authenticate_with_two_factor_via_otp(user)\n    elsif user&.valid_password?(user_params[:password])\n      prompt_for_two_factor(user)\n    end\n  end\n\n  def authenticate_with_two_factor_via_otp(user)\n    if valid_otp_attempt?(user)\n      session.delete(:otp_user_id)\n      remember_me(user)\n      sign_in(user)\n    else\n      flash.now[:alert] = I18n.t('users.invalid_otp_token')\n      prompt_for_two_factor(user)\n    end\n  end\n\n  def prompt_for_two_factor(user)\n    session[:otp_user_id] = user.id\n    render :two_factor\n  end\n\n  private\n\n  def set_instance_presenter\n    @instance_presenter = InstancePresenter.new\n  end\n\n  def set_body_classes\n    @body_classes = 'lighter'\n  end\n\n  def home_paths(resource)\n    paths = [about_path]\n    if single_user_mode? && resource.is_a?(User)\n      paths << short_account_path(username: resource.account)\n    end\n    paths\n  end\n\n  def continue_after?\n    truthy_param?(:continue)\n  end\nend\n"
  },
  {
    "path": "app/controllers/authorize_interactions_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass AuthorizeInteractionsController < ApplicationController\n  include Authorization\n\n  layout 'modal'\n\n  before_action :authenticate_user!\n  before_action :set_body_classes\n  before_action :set_resource\n\n  def show\n    if @resource.is_a?(Account)\n      render :show\n    elsif @resource.is_a?(Status)\n      redirect_to web_url(\"statuses/#{@resource.id}\")\n    else\n      render :error\n    end\n  end\n\n  def create\n    if @resource.is_a?(Account) && FollowService.new.call(current_account, @resource)\n      render :success\n    else\n      render :error\n    end\n  rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError\n    render :error\n  end\n\n  private\n\n  def set_resource\n    @resource = located_resource || render(:error)\n    authorize(@resource, :show?) if @resource.is_a?(Status)\n  end\n\n  def located_resource\n    if uri_param_is_url?\n      ResolveURLService.new.call(uri_param)\n    else\n      account_from_remote_follow\n    end\n  end\n\n  def account_from_remote_follow\n    ResolveAccountService.new.call(uri_param)\n  end\n\n  def uri_param_is_url?\n    parsed_uri.path && %w(http https).include?(parsed_uri.scheme)\n  end\n\n  def parsed_uri\n    Addressable::URI.parse(uri_param).normalize\n  end\n\n  def uri_param\n    params[:uri] || params.fetch(:acct, '').gsub(/\\Aacct:/, '')\n  end\n\n  def set_body_classes\n    @body_classes = 'modal-layout'\n  end\nend\n"
  },
  {
    "path": "app/controllers/concerns/account_controller_concern.rb",
    "content": "# frozen_string_literal: true\n\nmodule AccountControllerConcern\n  extend ActiveSupport::Concern\n\n  FOLLOW_PER_PAGE = 12\n\n  included do\n    layout 'public'\n\n    before_action :set_account\n    before_action :check_account_approval\n    before_action :check_account_suspension\n    before_action :set_instance_presenter\n    before_action :set_link_headers\n  end\n\n  private\n\n  def set_account\n    @account = Account.find_local!(username_param)\n  end\n\n  def set_instance_presenter\n    @instance_presenter = InstancePresenter.new\n  end\n\n  def set_link_headers\n    response.headers['Link'] = LinkHeader.new(\n      [\n        webfinger_account_link,\n        atom_account_url_link,\n        actor_url_link,\n      ]\n    )\n  end\n\n  def username_param\n    params[:account_username]\n  end\n\n  def webfinger_account_link\n    [\n      webfinger_account_url,\n      [%w(rel lrdd), %w(type application/xrd+xml)],\n    ]\n  end\n\n  def atom_account_url_link\n    [\n      account_url(@account, format: 'atom'),\n      [%w(rel alternate), %w(type application/atom+xml)],\n    ]\n  end\n\n  def actor_url_link\n    [\n      ActivityPub::TagManager.instance.uri_for(@account),\n      [%w(rel alternate), %w(type application/activity+json)],\n    ]\n  end\n\n  def webfinger_account_url\n    webfinger_url(resource: @account.to_webfinger_s)\n  end\n\n  def check_account_approval\n    not_found if @account.user_pending?\n  end\n\n  def check_account_suspension\n    if @account.suspended?\n      expires_in(3.minutes, public: true)\n      gone\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/concerns/accountable_concern.rb",
    "content": "# frozen_string_literal: true\n\nmodule AccountableConcern\n  extend ActiveSupport::Concern\n\n  def log_action(action, target)\n    Admin::ActionLog.create(account: current_account, action: action, target: target)\n  end\nend\n"
  },
  {
    "path": "app/controllers/concerns/authorization.rb",
    "content": "# frozen_string_literal: true\n\nmodule Authorization\n  extend ActiveSupport::Concern\n\n  include Pundit\n\n  def pundit_user\n    current_account\n  end\n\n  def authorize(*)\n    super\n  rescue Pundit::NotAuthorizedError\n    raise Mastodon::NotPermittedError\n  end\n\n  def authorize_with(user, record, query)\n    Pundit.authorize(user, record, query)\n  rescue Pundit::NotAuthorizedError\n    raise Mastodon::NotPermittedError\n  end\nend\n"
  },
  {
    "path": "app/controllers/concerns/export_controller_concern.rb",
    "content": "# frozen_string_literal: true\n\nmodule ExportControllerConcern\n  extend ActiveSupport::Concern\n\n  included do\n    before_action :authenticate_user!\n    before_action :load_export\n  end\n\n  private\n\n  def load_export\n    @export = Export.new(current_account)\n  end\n\n  def send_export_file\n    respond_to do |format|\n      format.csv { send_data export_data, filename: export_filename }\n    end\n  end\n\n  def export_data\n    raise 'Override in controller'\n  end\n\n  def export_filename\n    \"#{controller_name}.csv\"\n  end\nend\n"
  },
  {
    "path": "app/controllers/concerns/localized.rb",
    "content": "# frozen_string_literal: true\n\nmodule Localized\n  extend ActiveSupport::Concern\n\n  included do\n    before_action :set_locale\n  end\n\n  private\n\n  def set_locale\n    I18n.locale = default_locale\n    I18n.locale = current_user.locale if user_signed_in?\n  rescue I18n::InvalidLocale\n    I18n.locale = default_locale\n  end\n\n  def default_locale\n    if ENV['DEFAULT_LOCALE'].present?\n      I18n.default_locale\n    else\n      request_locale || I18n.default_locale\n    end\n  end\n\n  def request_locale\n    preferred_locale || compatible_locale\n  end\n\n  def preferred_locale\n    http_accept_language.preferred_language_from(available_locales)\n  end\n\n  def compatible_locale\n    http_accept_language.compatible_language_from(available_locales)\n  end\n\n  def available_locales\n    I18n.available_locales.reverse\n  end\nend\n"
  },
  {
    "path": "app/controllers/concerns/obfuscate_filename.rb",
    "content": "# frozen_string_literal: true\n\nmodule ObfuscateFilename\n  extend ActiveSupport::Concern\n\n  class_methods do\n    def obfuscate_filename(path)\n      before_action do\n        file = params.dig(*path)\n        next if file.nil?\n\n        file.original_filename = SecureRandom.hex(8) + File.extname(file.original_filename)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/concerns/rate_limit_headers.rb",
    "content": "# frozen_string_literal: true\n\nmodule RateLimitHeaders\n  extend ActiveSupport::Concern\n\n  included do\n    before_action :set_rate_limit_headers, if: :rate_limited_request?\n  end\n\n  private\n\n  def set_rate_limit_headers\n    apply_header_limit\n    apply_header_remaining\n    apply_header_reset\n  end\n\n  def rate_limited_request?\n    !request.env['rack.attack.throttle_data'].nil?\n  end\n\n  def apply_header_limit\n    response.headers['X-RateLimit-Limit'] = rate_limit_limit\n  end\n\n  def rate_limit_limit\n    api_throttle_data[:limit].to_s\n  end\n\n  def apply_header_remaining\n    response.headers['X-RateLimit-Remaining'] = rate_limit_remaining\n  end\n\n  def rate_limit_remaining\n    (api_throttle_data[:limit] - api_throttle_data[:count]).to_s\n  end\n\n  def apply_header_reset\n    response.headers['X-RateLimit-Reset'] = rate_limit_reset\n  end\n\n  def rate_limit_reset\n    (request_time + reset_period_offset).iso8601(6)\n  end\n\n  def api_throttle_data\n    most_limited_type, = request.env['rack.attack.throttle_data'].min_by { |_, v| v[:limit] }\n    request.env['rack.attack.throttle_data'][most_limited_type]\n  end\n\n  def request_time\n    @_request_time ||= Time.now.utc\n  end\n\n  def reset_period_offset\n    api_throttle_data[:period] - request_time.to_i % api_throttle_data[:period]\n  end\nend\n"
  },
  {
    "path": "app/controllers/concerns/session_tracking_concern.rb",
    "content": "# frozen_string_literal: true\n\nmodule SessionTrackingConcern\n  extend ActiveSupport::Concern\n\n  UPDATE_SIGN_IN_HOURS = 24\n\n  included do\n    before_action :set_session_activity\n  end\n\n  private\n\n  def set_session_activity\n    return unless session_needs_update?\n    current_session.touch\n  end\n\n  def session_needs_update?\n    !current_session.nil? && current_session.updated_at < UPDATE_SIGN_IN_HOURS.hours.ago\n  end\nend\n"
  },
  {
    "path": "app/controllers/concerns/signature_authentication.rb",
    "content": "# frozen_string_literal: true\n\nmodule SignatureAuthentication\n  extend ActiveSupport::Concern\n\n  include SignatureVerification\n\n  def current_account\n    super || signed_request_account\n  end\nend\n"
  },
  {
    "path": "app/controllers/concerns/signature_verification.rb",
    "content": "# frozen_string_literal: true\n\n# Implemented according to HTTP signatures (Draft 6)\n# <https://tools.ietf.org/html/draft-cavage-http-signatures-06>\nmodule SignatureVerification\n  extend ActiveSupport::Concern\n\n  def signed_request?\n    request.headers['Signature'].present?\n  end\n\n  def signature_verification_failure_reason\n    return @signature_verification_failure_reason if defined?(@signature_verification_failure_reason)\n  end\n\n  def signed_request_account\n    return @signed_request_account if defined?(@signed_request_account)\n\n    unless signed_request?\n      @signature_verification_failure_reason = 'Request not signed'\n      @signed_request_account = nil\n      return\n    end\n\n    if request.headers['Date'].present? && !matches_time_window?\n      @signature_verification_failure_reason = 'Signed request date outside acceptable time window'\n      @signed_request_account = nil\n      return\n    end\n\n    raw_signature    = request.headers['Signature']\n    signature_params = {}\n\n    raw_signature.split(',').each do |part|\n      parsed_parts = part.match(/([a-z]+)=\"([^\"]+)\"/i)\n      next if parsed_parts.nil? || parsed_parts.size != 3\n      signature_params[parsed_parts[1]] = parsed_parts[2]\n    end\n\n    if incompatible_signature?(signature_params)\n      @signature_verification_failure_reason = 'Incompatible request signature'\n      @signed_request_account = nil\n      return\n    end\n\n    account = account_from_key_id(signature_params['keyId'])\n\n    if account.nil?\n      @signature_verification_failure_reason = \"Public key not found for key #{signature_params['keyId']}\"\n      @signed_request_account = nil\n      return\n    end\n\n    signature             = Base64.decode64(signature_params['signature'])\n    compare_signed_string = build_signed_string(signature_params['headers'])\n\n    return account unless verify_signature(account, signature, compare_signed_string).nil?\n\n    account = stoplight_wrap_request { account.possibly_stale? ? account.refresh! : account_refresh_key(account) }\n\n    if account.nil?\n      @signature_verification_failure_reason = \"Public key not found for key #{signature_params['keyId']}\"\n      @signed_request_account = nil\n      return\n    end\n\n    return account unless verify_signature(account, signature, compare_signed_string).nil?\n\n    @signature_verification_failure_reason = \"Verification failed for #{account.username}@#{account.domain} #{account.uri}\"\n    @signed_request_account = nil\n  end\n\n  def request_body\n    @request_body ||= request.raw_post\n  end\n\n  private\n\n  def verify_signature(account, signature, compare_signed_string)\n    if account.keypair.public_key.verify(OpenSSL::Digest::SHA256.new, signature, compare_signed_string)\n      @signed_request_account = account\n      @signed_request_account\n    end\n  rescue OpenSSL::PKey::RSAError\n    nil\n  end\n\n  def build_signed_string(signed_headers)\n    signed_headers = 'date' if signed_headers.blank?\n\n    signed_headers.downcase.split(' ').map do |signed_header|\n      if signed_header == Request::REQUEST_TARGET\n        \"#{Request::REQUEST_TARGET}: #{request.method.downcase} #{request.path}\"\n      elsif signed_header == 'digest'\n        \"digest: #{body_digest}\"\n      else\n        \"#{signed_header}: #{request.headers[to_header_name(signed_header)]}\"\n      end\n    end.join(\"\\n\")\n  end\n\n  def matches_time_window?\n    begin\n      time_sent = Time.httpdate(request.headers['Date'])\n    rescue ArgumentError\n      return false\n    end\n\n    (Time.now.utc - time_sent).abs <= 12.hours\n  end\n\n  def body_digest\n    \"SHA-256=#{Digest::SHA256.base64digest(request_body)}\"\n  end\n\n  def to_header_name(name)\n    name.split(/-/).map(&:capitalize).join('-')\n  end\n\n  def incompatible_signature?(signature_params)\n    signature_params['keyId'].blank? ||\n      signature_params['signature'].blank?\n  end\n\n  def account_from_key_id(key_id)\n    if key_id.start_with?('acct:')\n      stoplight_wrap_request { ResolveAccountService.new.call(key_id.gsub(/\\Aacct:/, '')) }\n    elsif !ActivityPub::TagManager.instance.local_uri?(key_id)\n      account   = ActivityPub::TagManager.instance.uri_to_resource(key_id, Account)\n      account ||= stoplight_wrap_request { ActivityPub::FetchRemoteKeyService.new.call(key_id, id: false) }\n      account\n    end\n  end\n\n  def stoplight_wrap_request(&block)\n    Stoplight(\"source:#{request.remote_ip}\", &block)\n      .with_fallback { nil }\n      .with_threshold(1)\n      .with_cool_off_time(5.minutes.seconds)\n      .with_error_handler { |error, handle| error.is_a?(HTTP::Error) ? handle.call(error) : raise(error) }\n      .run\n  end\n\n  def account_refresh_key(account)\n    return if account.local? || !account.activitypub?\n    ActivityPub::FetchRemoteAccountService.new.call(account.uri, only_key: true)\n  end\nend\n"
  },
  {
    "path": "app/controllers/concerns/user_tracking_concern.rb",
    "content": "# frozen_string_literal: true\n\nmodule UserTrackingConcern\n  extend ActiveSupport::Concern\n\n  UPDATE_SIGN_IN_HOURS = 24\n\n  included do\n    before_action :set_user_activity\n  end\n\n  private\n\n  def set_user_activity\n    return unless user_needs_sign_in_update?\n    current_user.update_tracked_fields!(request)\n  end\n\n  def user_needs_sign_in_update?\n    user_signed_in? && (current_user.current_sign_in_at.nil? || current_user.current_sign_in_at < UPDATE_SIGN_IN_HOURS.hours.ago)\n  end\nend\n"
  },
  {
    "path": "app/controllers/custom_css_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass CustomCssController < ApplicationController\n  skip_before_action :store_current_location\n\n  before_action :set_cache_headers\n\n  def show\n    render plain: Setting.custom_css || '', content_type: 'text/css'\n  end\nend\n"
  },
  {
    "path": "app/controllers/directories_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass DirectoriesController < ApplicationController\n  layout 'public'\n\n  before_action :check_enabled\n  before_action :set_instance_presenter\n  before_action :set_tag, only: :show\n  before_action :set_tags\n  before_action :set_accounts\n\n  def index\n    render :index\n  end\n\n  def show\n    render :index\n  end\n\n  private\n\n  def check_enabled\n    return not_found unless Setting.profile_directory\n  end\n\n  def set_tag\n    @tag = Tag.discoverable.find_by!(name: params[:id].downcase)\n  end\n\n  def set_tags\n    @tags = Tag.discoverable.limit(30).reject { |tag| tag.cached_sample_accounts.empty? }\n  end\n\n  def set_accounts\n    @accounts = Account.discoverable.by_recent_status.page(params[:page]).per(40).tap do |query|\n      query.merge!(Account.tagged_with(@tag.id)) if @tag\n    end\n  end\n\n  def set_instance_presenter\n    @instance_presenter = InstancePresenter.new\n  end\nend\n"
  },
  {
    "path": "app/controllers/emojis_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass EmojisController < ApplicationController\n  before_action :set_emoji\n  before_action :set_cache_headers\n\n  def show\n    respond_to do |format|\n      format.json do\n        render_cached_json(['activitypub', 'emoji', @emoji], content_type: 'application/activity+json') do\n          ActiveModelSerializers::SerializableResource.new(@emoji, serializer: ActivityPub::EmojiSerializer, adapter: ActivityPub::Adapter)\n        end\n      end\n    end\n  end\n\n  private\n\n  def set_emoji\n    @emoji = CustomEmoji.local.find(params[:id])\n  end\nend\n"
  },
  {
    "path": "app/controllers/filters_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass FiltersController < ApplicationController\n  include Authorization\n\n  layout 'admin'\n\n  before_action :set_filters, only: :index\n  before_action :set_filter, only: [:edit, :update, :destroy]\n  before_action :set_body_classes\n\n  def index\n    @filters = current_account.custom_filters\n  end\n\n  def new\n    @filter = current_account.custom_filters.build\n  end\n\n  def create\n    @filter = current_account.custom_filters.build(resource_params)\n\n    if @filter.save\n      redirect_to filters_path\n    else\n      render action: :new\n    end\n  end\n\n  def edit; end\n\n  def update\n    if @filter.update(resource_params)\n      redirect_to filters_path\n    else\n      render action: :edit\n    end\n  end\n\n  def destroy\n    @filter.destroy\n    redirect_to filters_path\n  end\n\n  private\n\n  def set_filters\n    @filters = current_account.custom_filters\n  end\n\n  def set_filter\n    @filter = current_account.custom_filters.find(params[:id])\n  end\n\n  def resource_params\n    params.require(:custom_filter).permit(:phrase, :expires_in, :irreversible, :whole_word, context: [])\n  end\n\n  def set_body_classes\n    @body_classes = 'admin'\n  end\nend\n"
  },
  {
    "path": "app/controllers/follower_accounts_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass FollowerAccountsController < ApplicationController\n  include AccountControllerConcern\n\n  before_action :set_cache_headers\n\n  def index\n    respond_to do |format|\n      format.html do\n        mark_cacheable! unless user_signed_in?\n\n        next if @account.user_hides_network?\n\n        follows\n        @relationships = AccountRelationshipsPresenter.new(follows.map(&:account_id), current_user.account_id) if user_signed_in?\n      end\n\n      format.json do\n        raise Mastodon::NotPermittedError if params[:page].present? && @account.user_hides_network?\n\n        expires_in 3.minutes, public: true if params[:page].blank?\n\n        render json: collection_presenter,\n               serializer: ActivityPub::CollectionSerializer,\n               adapter: ActivityPub::Adapter,\n               content_type: 'application/activity+json'\n      end\n    end\n  end\n\n  private\n\n  def follows\n    @follows ||= Follow.where(target_account: @account).recent.page(params[:page]).per(FOLLOW_PER_PAGE).preload(:account)\n  end\n\n  def page_url(page)\n    account_followers_url(@account, page: page) unless page.nil?\n  end\n\n  def collection_presenter\n    if params[:page].present?\n      ActivityPub::CollectionPresenter.new(\n        id: account_followers_url(@account, page: params.fetch(:page, 1)),\n        type: :ordered,\n        size: @account.followers_count,\n        items: follows.map { |f| ActivityPub::TagManager.instance.uri_for(f.account) },\n        part_of: account_followers_url(@account),\n        next: page_url(follows.next_page),\n        prev: page_url(follows.prev_page)\n      )\n    else\n      ActivityPub::CollectionPresenter.new(\n        id: account_followers_url(@account),\n        type: :ordered,\n        size: @account.followers_count,\n        first: page_url(1)\n      )\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/following_accounts_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass FollowingAccountsController < ApplicationController\n  include AccountControllerConcern\n\n  before_action :set_cache_headers\n\n  def index\n    respond_to do |format|\n      format.html do\n        mark_cacheable! unless user_signed_in?\n\n        next if @account.user_hides_network?\n\n        follows\n        @relationships = AccountRelationshipsPresenter.new(follows.map(&:target_account_id), current_user.account_id) if user_signed_in?\n      end\n\n      format.json do\n        raise Mastodon::NotPermittedError if params[:page].present? && @account.user_hides_network?\n\n        expires_in 3.minutes, public: true if params[:page].blank?\n\n        render json: collection_presenter,\n               serializer: ActivityPub::CollectionSerializer,\n               adapter: ActivityPub::Adapter,\n               content_type: 'application/activity+json'\n      end\n    end\n  end\n\n  private\n\n  def follows\n    @follows ||= Follow.where(account: @account).recent.page(params[:page]).per(FOLLOW_PER_PAGE).preload(:target_account)\n  end\n\n  def page_url(page)\n    account_following_index_url(@account, page: page) unless page.nil?\n  end\n\n  def collection_presenter\n    if params[:page].present?\n      ActivityPub::CollectionPresenter.new(\n        id: account_following_index_url(@account, page: params.fetch(:page, 1)),\n        type: :ordered,\n        size: @account.following_count,\n        items: follows.map { |f| ActivityPub::TagManager.instance.uri_for(f.target_account) },\n        part_of: account_following_index_url(@account),\n        next: page_url(follows.next_page),\n        prev: page_url(follows.prev_page)\n      )\n    else\n      ActivityPub::CollectionPresenter.new(\n        id: account_following_index_url(@account),\n        type: :ordered,\n        size: @account.following_count,\n        first: page_url(1)\n      )\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/home_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass HomeController < ApplicationController\n  before_action :authenticate_user!\n  before_action :set_referrer_policy_header\n  before_action :set_initial_state_json\n\n  def index\n    @body_classes = 'app-body'\n  end\n\n  private\n\n  def authenticate_user!\n    return if user_signed_in?\n\n    matches = request.path.match(/\\A\\/web\\/(statuses|accounts)\\/([\\d]+)\\z/)\n\n    if matches\n      case matches[1]\n      when 'statuses'\n        status = Status.find_by(id: matches[2])\n\n        if status && (status.public_visibility? || status.unlisted_visibility?)\n          redirect_to(ActivityPub::TagManager.instance.url_for(status))\n          return\n        end\n      when 'accounts'\n        account = Account.find_by(id: matches[2])\n\n        if account\n          redirect_to(ActivityPub::TagManager.instance.url_for(account))\n          return\n        end\n      end\n    end\n\n    matches = request.path.match(%r{\\A/web/timelines/tag/(?<tag>.+)\\z})\n    redirect_to(matches ? tag_path(CGI.unescape(matches[:tag])) : default_redirect_path)\n  end\n\n  def set_initial_state_json\n    serializable_resource = ActiveModelSerializers::SerializableResource.new(InitialStatePresenter.new(initial_state_params), serializer: InitialStateSerializer)\n    @initial_state_json   = serializable_resource.to_json\n  end\n\n  def initial_state_params\n    {\n      settings: Web::Setting.find_by(user: current_user)&.data || {},\n      push_subscription: current_account.user.web_push_subscription(current_session),\n      current_account: current_account,\n      token: current_session.token,\n      admin: Account.find_local(Setting.site_contact_username.strip.gsub(/\\A@/, '')),\n    }\n  end\n\n  def default_redirect_path\n    if request.path.start_with?('/web')\n      new_user_session_path\n    elsif single_user_mode?\n      short_account_path(Account.local.without_suspended.first)\n    else\n      about_path\n    end\n  end\n\n  def set_referrer_policy_header\n    response.headers['Referrer-Policy'] = 'origin'\n  end\nend\n"
  },
  {
    "path": "app/controllers/intents_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass IntentsController < ApplicationController\n  before_action :check_uri\n  rescue_from Addressable::URI::InvalidURIError, with: :handle_invalid_uri\n\n  def show\n    if uri.scheme == 'web+mastodon'\n      case uri.host\n      when 'follow'\n        return redirect_to authorize_interaction_path(uri: uri.query_values['uri'].gsub(/\\Aacct:/, ''))\n      when 'share'\n        return redirect_to share_path(text: uri.query_values['text'])\n      end\n    end\n\n    not_found\n  end\n\n  private\n\n  def check_uri\n    not_found if uri.blank?\n  end\n\n  def handle_invalid_uri\n    not_found\n  end\n\n  def uri\n    @uri ||= Addressable::URI.parse(params[:uri])\n  end\nend\n"
  },
  {
    "path": "app/controllers/invites_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass InvitesController < ApplicationController\n  include Authorization\n\n  layout 'admin'\n\n  before_action :authenticate_user!\n  before_action :set_body_classes\n\n  def index\n    authorize :invite, :create?\n\n    @invites = invites\n    @invite  = Invite.new\n  end\n\n  def create\n    authorize :invite, :create?\n\n    @invite      = Invite.new(resource_params)\n    @invite.user = current_user\n\n    if @invite.save\n      redirect_to invites_path\n    else\n      @invites = invites\n      render :index\n    end\n  end\n\n  def destroy\n    @invite = invites.find(params[:id])\n    authorize @invite, :destroy?\n    @invite.expire!\n    redirect_to invites_path\n  end\n\n  private\n\n  def invites\n    Invite.where(user: current_user).order(id: :desc)\n  end\n\n  def resource_params\n    params.require(:invite).permit(:max_uses, :expires_in, :autofollow)\n  end\n\n  def set_body_classes\n    @body_classes = 'admin'\n  end\nend\n"
  },
  {
    "path": "app/controllers/manifests_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass ManifestsController < ApplicationController\n  skip_before_action :store_current_location\n\n  def show\n    render json: InstancePresenter.new, serializer: ManifestSerializer\n  end\nend\n"
  },
  {
    "path": "app/controllers/media_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass MediaController < ApplicationController\n  include Authorization\n\n  skip_before_action :store_current_location\n\n  before_action :set_media_attachment\n  before_action :verify_permitted_status!\n\n  content_security_policy only: :player do |p|\n    p.frame_ancestors(false)\n  end\n\n  def show\n    redirect_to @media_attachment.file.url(:original)\n  end\n\n  def player\n    @body_classes = 'player'\n    response.headers['X-Frame-Options'] = 'ALLOWALL'\n    raise ActiveRecord::RecordNotFound unless @media_attachment.video? || @media_attachment.gifv?\n  end\n\n  private\n\n  def set_media_attachment\n    @media_attachment = MediaAttachment.attached.find_by!(shortcode: params[:id] || params[:medium_id])\n  end\n\n  def verify_permitted_status!\n    authorize @media_attachment.status, :show?\n  rescue Mastodon::NotPermittedError\n    # Reraise in order to get a 404 instead of a 403 error code\n    raise ActiveRecord::RecordNotFound\n  end\nend\n"
  },
  {
    "path": "app/controllers/media_proxy_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass MediaProxyController < ApplicationController\n  include RoutingHelper\n\n  skip_before_action :store_current_location\n\n  def show\n    RedisLock.acquire(lock_options) do |lock|\n      if lock.acquired?\n        @media_attachment = MediaAttachment.remote.find(params[:id])\n        redownload! if @media_attachment.needs_redownload? && !reject_media?\n      else\n        raise Mastodon::RaceConditionError\n      end\n    end\n\n    redirect_to full_asset_url(@media_attachment.file.url(version))\n  end\n\n  private\n\n  def redownload!\n    @media_attachment.file_remote_url = @media_attachment.remote_url\n    @media_attachment.created_at      = Time.now.utc\n    @media_attachment.save!\n  end\n\n  def version\n    if request.path.ends_with?('/small')\n      :small\n    else\n      :original\n    end\n  end\n\n  def lock_options\n    { redis: Redis.current, key: \"media_download:#{params[:id]}\" }\n  end\n\n  def reject_media?\n    DomainBlock.find_by(domain: @media_attachment.account.domain)&.reject_media?\n  end\nend\n"
  },
  {
    "path": "app/controllers/oauth/authorizations_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Oauth::AuthorizationsController < Doorkeeper::AuthorizationsController\n  skip_before_action :authenticate_resource_owner!\n\n  before_action :store_current_location\n  before_action :authenticate_resource_owner!\n\n  include Localized\n\n  private\n\n  def store_current_location\n    store_location_for(:user, request.url)\n  end\n\n  def render_success\n    if skip_authorization? || (matching_token? && !truthy_param?('force_login'))\n      redirect_or_render authorize_response\n    elsif Doorkeeper.configuration.api_only\n      render json: pre_auth\n    else\n      render :new\n    end\n  end\n\n  def truthy_param?(key)\n    ActiveModel::Type::Boolean.new.cast(params[key])\n  end\nend\n"
  },
  {
    "path": "app/controllers/oauth/authorized_applications_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Oauth::AuthorizedApplicationsController < Doorkeeper::AuthorizedApplicationsController\n  skip_before_action :authenticate_resource_owner!\n\n  before_action :store_current_location\n  before_action :authenticate_resource_owner!\n  before_action :set_body_classes\n\n  include Localized\n\n  def destroy\n    Web::PushSubscription.unsubscribe_for(params[:id], current_resource_owner)\n    super\n  end\n\n  private\n\n  def set_body_classes\n    @body_classes = 'admin'\n  end\n\n  def store_current_location\n    store_location_for(:user, request.url)\n  end\nend\n"
  },
  {
    "path": "app/controllers/oauth/tokens_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Oauth::TokensController < Doorkeeper::TokensController\n  def revoke\n    unsubscribe_for_token if authorized? && token.accessible?\n    super\n  end\n\n  private\n\n  def unsubscribe_for_token\n    Web::PushSubscription.where(access_token_id: token.id).delete_all\n  end\nend\n"
  },
  {
    "path": "app/controllers/public_timelines_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass PublicTimelinesController < ApplicationController\n  layout 'public'\n\n  before_action :check_enabled\n  before_action :set_body_classes\n  before_action :set_instance_presenter\n\n  def show\n    respond_to do |format|\n      format.html do\n        @initial_state_json = ActiveModelSerializers::SerializableResource.new(\n          InitialStatePresenter.new(settings: { known_fediverse: Setting.show_known_fediverse_at_about_page }, token: current_session&.token),\n          serializer: InitialStateSerializer\n        ).to_json\n      end\n    end\n  end\n\n  private\n\n  def check_enabled\n    raise ActiveRecord::RecordNotFound unless Setting.timeline_preview\n  end\n\n  def set_body_classes\n    @body_classes = 'with-modals'\n  end\n\n  def set_instance_presenter\n    @instance_presenter = InstancePresenter.new\n  end\nend\n"
  },
  {
    "path": "app/controllers/relationships_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass RelationshipsController < ApplicationController\n  layout 'admin'\n\n  before_action :authenticate_user!\n  before_action :set_accounts, only: :show\n  before_action :set_body_classes\n\n  helper_method :following_relationship?, :followed_by_relationship?, :mutual_relationship?\n\n  def show\n    @form = Form::AccountBatch.new\n  end\n\n  def update\n    @form = Form::AccountBatch.new(form_account_batch_params.merge(current_account: current_account, action: action_from_button))\n    @form.save\n  rescue ActionController::ParameterMissing\n    # Do nothing\n  ensure\n    redirect_to relationships_path(current_params)\n  end\n\n  private\n\n  def set_accounts\n    @accounts = relationships_scope.page(params[:page]).per(40)\n  end\n\n  def relationships_scope\n    scope = begin\n      if following_relationship?\n        current_account.following.eager_load(:account_stat).reorder(nil)\n      else\n        current_account.followers.eager_load(:account_stat).reorder(nil)\n      end\n    end\n\n    scope.merge!(Follow.recent)             if params[:order].blank? || params[:order] == 'recent'\n    scope.merge!(Account.by_recent_status)  if params[:order] == 'active'\n    scope.merge!(mutual_relationship_scope) if mutual_relationship?\n    scope.merge!(moved_account_scope)       if params[:status] == 'moved'\n    scope.merge!(primary_account_scope)     if params[:status] == 'primary'\n    scope.merge!(by_domain_scope)           if params[:by_domain].present?\n    scope.merge!(dormant_account_scope)     if params[:activity] == 'dormant'\n\n    scope\n  end\n\n  def mutual_relationship_scope\n    Account.where(id: current_account.following)\n  end\n\n  def moved_account_scope\n    Account.where.not(moved_to_account_id: nil)\n  end\n\n  def primary_account_scope\n    Account.where(moved_to_account_id: nil)\n  end\n\n  def dormant_account_scope\n    AccountStat.where(last_status_at: nil).or(AccountStat.where(AccountStat.arel_table[:last_status_at].lt(1.month.ago)))\n  end\n\n  def by_domain_scope\n    Account.where(domain: params[:by_domain])\n  end\n\n  def form_account_batch_params\n    params.require(:form_account_batch).permit(:action, account_ids: [])\n  end\n\n  def following_relationship?\n    params[:relationship].blank? || params[:relationship] == 'following'\n  end\n\n  def mutual_relationship?\n    params[:relationship] == 'mutual'\n  end\n\n  def followed_by_relationship?\n    params[:relationship] == 'followed_by'\n  end\n\n  def current_params\n    params.slice(:page, :status, :relationship, :by_domain, :activity, :order).permit(:page, :status, :relationship, :by_domain, :activity, :order)\n  end\n\n  def action_from_button\n    if params[:unfollow]\n      'unfollow'\n    elsif params[:remove_from_followers]\n      'remove_from_followers'\n    elsif params[:block_domains]\n      'block_domains'\n    end\n  end\n\n  def set_body_classes\n    @body_classes = 'admin'\n  end\nend\n"
  },
  {
    "path": "app/controllers/remote_follow_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass RemoteFollowController < ApplicationController\n  layout 'modal'\n\n  before_action :set_account\n  before_action :gone, if: :suspended_account?\n  before_action :set_body_classes\n\n  def new\n    @remote_follow = RemoteFollow.new(session_params)\n  end\n\n  def create\n    @remote_follow = RemoteFollow.new(resource_params)\n\n    if @remote_follow.valid?\n      session[:remote_follow] = @remote_follow.acct\n      redirect_to @remote_follow.subscribe_address_for(@account)\n    else\n      render :new\n    end\n  end\n\n  private\n\n  def resource_params\n    params.require(:remote_follow).permit(:acct)\n  end\n\n  def session_params\n    { acct: session[:remote_follow] }\n  end\n\n  def set_account\n    @account = Account.find_local!(params[:account_username])\n  end\n\n  def suspended_account?\n    @account.suspended?\n  end\n\n  def set_body_classes\n    @body_classes = 'modal-layout'\n    @hide_header  = true\n  end\nend\n"
  },
  {
    "path": "app/controllers/remote_interaction_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass RemoteInteractionController < ApplicationController\n  include Authorization\n\n  layout 'modal'\n\n  before_action :set_interaction_type\n  before_action :set_status\n  before_action :set_body_classes\n\n  def new\n    @remote_follow = RemoteFollow.new(session_params)\n  end\n\n  def create\n    @remote_follow = RemoteFollow.new(resource_params)\n\n    if @remote_follow.valid?\n      session[:remote_follow] = @remote_follow.acct\n      redirect_to @remote_follow.interact_address_for(@status)\n    else\n      render :new\n    end\n  end\n\n  private\n\n  def resource_params\n    params.require(:remote_follow).permit(:acct)\n  end\n\n  def session_params\n    { acct: session[:remote_follow] }\n  end\n\n  def set_status\n    @status = Status.find(params[:id])\n    authorize @status, :show?\n  rescue Mastodon::NotPermittedError\n    # Reraise in order to get a 404\n    raise ActiveRecord::RecordNotFound\n  end\n\n  def set_body_classes\n    @body_classes = 'modal-layout'\n    @hide_header  = true\n  end\n\n  def set_interaction_type\n    @interaction_type = %w(reply reblog favourite).include?(params[:type]) ? params[:type] : 'reply'\n  end\nend\n"
  },
  {
    "path": "app/controllers/remote_unfollows_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass RemoteUnfollowsController < ApplicationController\n  layout 'modal'\n\n  before_action :authenticate_user!\n  before_action :set_body_classes\n\n  def create\n    @account = unfollow_attempt.try(:target_account)\n\n    if @account.nil?\n      render :error\n    else\n      render :success\n    end\n  rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError\n    render :error\n  end\n\n  private\n\n  def unfollow_attempt\n    username, domain = acct_without_prefix.split('@')\n    UnfollowService.new.call(current_account, Account.find_remote!(username, domain))\n  end\n\n  def acct_without_prefix\n    acct_params.gsub(/\\Aacct:/, '')\n  end\n\n  def acct_params\n    params.fetch(:acct, '')\n  end\n\n  def set_body_classes\n    @body_classes = 'modal-layout'\n  end\nend\n"
  },
  {
    "path": "app/controllers/settings/applications_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Settings::ApplicationsController < Settings::BaseController\n  layout 'admin'\n\n  before_action :authenticate_user!\n  before_action :set_application, only: [:show, :update, :destroy, :regenerate]\n  before_action :prepare_scopes, only: [:create, :update]\n\n  def index\n    @applications = current_user.applications.order(id: :desc).page(params[:page])\n  end\n\n  def new\n    @application = Doorkeeper::Application.new(\n      redirect_uri: Doorkeeper.configuration.native_redirect_uri,\n      scopes: 'read write follow'\n    )\n  end\n\n  def show; end\n\n  def create\n    @application = current_user.applications.build(application_params)\n\n    if @application.save\n      redirect_to settings_applications_path, notice: I18n.t('applications.created')\n    else\n      render :new\n    end\n  end\n\n  def update\n    if @application.update(application_params)\n      redirect_to settings_applications_path, notice: I18n.t('generic.changes_saved_msg')\n    else\n      render :show\n    end\n  end\n\n  def destroy\n    @application.destroy\n    redirect_to settings_applications_path, notice: I18n.t('applications.destroyed')\n  end\n\n  def regenerate\n    @access_token = current_user.token_for_app(@application)\n    @access_token.destroy\n\n    redirect_to settings_application_path(@application), notice: I18n.t('applications.token_regenerated')\n  end\n\n  private\n\n  def set_application\n    @application = current_user.applications.find(params[:id])\n  end\n\n  def application_params\n    params.require(:doorkeeper_application).permit(\n      :name,\n      :redirect_uri,\n      :scopes,\n      :website\n    )\n  end\n\n  def prepare_scopes\n    scopes = params.fetch(:doorkeeper_application, {}).fetch(:scopes, nil)\n    params[:doorkeeper_application][:scopes] = scopes.join(' ') if scopes.is_a? Array\n  end\nend\n"
  },
  {
    "path": "app/controllers/settings/base_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Settings::BaseController < ApplicationController\n  before_action :set_body_classes\n\n  private\n\n  def set_body_classes\n    @body_classes = 'admin'\n  end\nend\n"
  },
  {
    "path": "app/controllers/settings/deletes_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Settings::DeletesController < Settings::BaseController\n  layout 'admin'\n\n  before_action :check_enabled_deletion\n  before_action :authenticate_user!\n\n  def show\n    @confirmation = Form::DeleteConfirmation.new\n  end\n\n  def destroy\n    if current_user.valid_password?(delete_params[:password])\n      Admin::SuspensionWorker.perform_async(current_user.account_id, true)\n      sign_out\n      redirect_to new_user_session_path, notice: I18n.t('deletes.success_msg')\n    else\n      redirect_to settings_delete_path, alert: I18n.t('deletes.bad_password_msg')\n    end\n  end\n\n  private\n\n  def check_enabled_deletion\n    redirect_to root_path unless Setting.open_deletion\n  end\n\n  def delete_params\n    params.require(:form_delete_confirmation).permit(:password)\n  end\nend\n"
  },
  {
    "path": "app/controllers/settings/exports/blocked_accounts_controller.rb",
    "content": "# frozen_string_literal: true\n\nmodule Settings\n  module Exports\n    class BlockedAccountsController < ApplicationController\n      include ExportControllerConcern\n\n      def index\n        send_export_file\n      end\n\n      private\n\n      def export_data\n        @export.to_blocked_accounts_csv\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/settings/exports/blocked_domains_controller.rb",
    "content": "# frozen_string_literal: true\n\nmodule Settings\n  module Exports\n    class BlockedDomainsController < ApplicationController\n      include ExportControllerConcern\n\n      def index\n        send_export_file\n      end\n\n      private\n\n      def export_data\n        @export.to_blocked_domains_csv\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/settings/exports/following_accounts_controller.rb",
    "content": "# frozen_string_literal: true\n\nmodule Settings\n  module Exports\n    class FollowingAccountsController < ApplicationController\n      include ExportControllerConcern\n\n      def index\n        send_export_file\n      end\n\n      private\n\n      def export_data\n        @export.to_following_accounts_csv\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/settings/exports/lists_controller.rb",
    "content": "# frozen_string_literal: true\n\nmodule Settings\n  module Exports\n    class ListsController < ApplicationController\n      include ExportControllerConcern\n\n      def index\n        send_export_file\n      end\n\n      private\n\n      def export_data\n        @export.to_lists_csv\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/settings/exports/muted_accounts_controller.rb",
    "content": "# frozen_string_literal: true\n\nmodule Settings\n  module Exports\n    class MutedAccountsController < ApplicationController\n      include ExportControllerConcern\n\n      def index\n        send_export_file\n      end\n\n      private\n\n      def export_data\n        @export.to_muted_accounts_csv\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/settings/exports_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Settings::ExportsController < Settings::BaseController\n  include Authorization\n\n  layout 'admin'\n\n  before_action :authenticate_user!\n\n  def show\n    @export  = Export.new(current_account)\n    @backups = current_user.backups\n  end\n\n  def create\n    raise Mastodon::NotPermittedError unless user_signed_in?\n\n    backup = nil\n\n    RedisLock.acquire(lock_options) do |lock|\n      if lock.acquired?\n        authorize :backup, :create?\n        backup = current_user.backups.create!\n      else\n        raise Mastodon::RaceConditionError\n      end\n    end\n\n    BackupWorker.perform_async(backup.id)\n\n    redirect_to settings_export_path\n  end\n\n  def lock_options\n    { redis: Redis.current, key: \"backup:#{current_user.id}\" }\n  end\nend\n"
  },
  {
    "path": "app/controllers/settings/featured_tags_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Settings::FeaturedTagsController < Settings::BaseController\n  layout 'admin'\n\n  before_action :authenticate_user!\n  before_action :set_featured_tags, only: :index\n  before_action :set_featured_tag, except: [:index, :create]\n  before_action :set_most_used_tags, only: :index\n\n  def index\n    @featured_tag = FeaturedTag.new\n  end\n\n  def create\n    @featured_tag = current_account.featured_tags.new(featured_tag_params)\n    @featured_tag.reset_data\n\n    if @featured_tag.save\n      redirect_to settings_featured_tags_path\n    else\n      set_featured_tags\n      set_most_used_tags\n\n      render :index\n    end\n  end\n\n  def destroy\n    @featured_tag.destroy!\n    redirect_to settings_featured_tags_path\n  end\n\n  private\n\n  def set_featured_tag\n    @featured_tag = current_account.featured_tags.find(params[:id])\n  end\n\n  def set_featured_tags\n    @featured_tags = current_account.featured_tags.order(statuses_count: :desc).reject(&:new_record?)\n  end\n\n  def set_most_used_tags\n    @most_used_tags = Tag.most_used(current_account).where.not(id: @featured_tags.map(&:id)).limit(10)\n  end\n\n  def featured_tag_params\n    params.require(:featured_tag).permit(:name)\n  end\nend\n"
  },
  {
    "path": "app/controllers/settings/identity_proofs_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Settings::IdentityProofsController < Settings::BaseController\n  layout 'admin'\n\n  before_action :authenticate_user!\n  before_action :check_required_params, only: :new\n\n  def index\n    @proofs = AccountIdentityProof.where(account: current_account).order(provider: :asc, provider_username: :asc)\n    @proofs.each(&:refresh!)\n  end\n\n  def new\n    @proof = current_account.identity_proofs.new(\n      token: params[:token],\n      provider: params[:provider],\n      provider_username: params[:provider_username]\n    )\n\n    if current_account.username.casecmp(params[:username]).zero?\n      render layout: 'auth'\n    else\n      flash[:alert] = I18n.t('identity_proofs.errors.wrong_user', proving: params[:username], current: current_account.username)\n      redirect_to settings_identity_proofs_path\n    end\n  end\n\n  def create\n    @proof = current_account.identity_proofs.where(provider: resource_params[:provider], provider_username: resource_params[:provider_username]).first_or_initialize(resource_params)\n    @proof.token = resource_params[:token]\n\n    if @proof.save\n      PostStatusService.new.call(current_user.account, text: post_params[:status_text]) if publish_proof?\n      redirect_to @proof.on_success_path(params[:user_agent])\n    else\n      flash[:alert] = I18n.t('identity_proofs.errors.failed', provider: @proof.provider.capitalize)\n      redirect_to settings_identity_proofs_path\n    end\n  end\n\n  private\n\n  def check_required_params\n    redirect_to settings_identity_proofs_path unless [:provider, :provider_username, :username, :token].all? { |k| params[k].present? }\n  end\n\n  def resource_params\n    params.require(:account_identity_proof).permit(:provider, :provider_username, :token)\n  end\n\n  def publish_proof?\n    ActiveModel::Type::Boolean.new.cast(post_params[:post_status])\n  end\n\n  def post_params\n    params.require(:account_identity_proof).permit(:post_status, :status_text)\n  end\n\n  def set_body_classes\n    @body_classes = ''\n  end\nend\n"
  },
  {
    "path": "app/controllers/settings/imports_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Settings::ImportsController < Settings::BaseController\n  layout 'admin'\n\n  before_action :authenticate_user!\n  before_action :set_account\n\n  def show\n    @import = Import.new\n  end\n\n  def create\n    @import = Import.new(import_params)\n    @import.account = @account\n\n    if @import.save\n      ImportWorker.perform_async(@import.id)\n      redirect_to settings_import_path, notice: I18n.t('imports.success')\n    else\n      render :show\n    end\n  end\n\n  private\n\n  def set_account\n    @account = current_user.account\n  end\n\n  def import_params\n    params.require(:import).permit(:data, :type)\n  end\nend\n"
  },
  {
    "path": "app/controllers/settings/migrations_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Settings::MigrationsController < Settings::BaseController\n  layout 'admin'\n\n  before_action :authenticate_user!\n\n  def show\n    @migration = Form::Migration.new(account: current_account.moved_to_account)\n  end\n\n  def update\n    @migration = Form::Migration.new(resource_params)\n\n    if @migration.valid? && migration_account_changed?\n      current_account.update!(moved_to_account: @migration.account)\n      ActivityPub::UpdateDistributionWorker.perform_async(current_account.id)\n      redirect_to settings_migration_path, notice: I18n.t('migrations.updated_msg')\n    else\n      render :show\n    end\n  end\n\n  private\n\n  def resource_params\n    params.require(:migration).permit(:acct)\n  end\n\n  def migration_account_changed?\n    current_account.moved_to_account_id != @migration.account&.id &&\n      current_account.id != @migration.account&.id\n  end\nend\n"
  },
  {
    "path": "app/controllers/settings/preferences/appearance_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Settings::Preferences::AppearanceController < Settings::PreferencesController\n  private\n\n  def after_update_redirect_path\n    settings_preferences_appearance_path\n  end\nend\n"
  },
  {
    "path": "app/controllers/settings/preferences/notifications_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Settings::Preferences::NotificationsController < Settings::PreferencesController\n  private\n\n  def after_update_redirect_path\n    settings_preferences_notifications_path\n  end\nend\n"
  },
  {
    "path": "app/controllers/settings/preferences/other_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Settings::Preferences::OtherController < Settings::PreferencesController\n  private\n\n  def after_update_redirect_path\n    settings_preferences_other_path\n  end\nend\n"
  },
  {
    "path": "app/controllers/settings/preferences_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Settings::PreferencesController < Settings::BaseController\n  layout 'admin'\n\n  before_action :authenticate_user!\n\n  def show; end\n\n  def update\n    user_settings.update(user_settings_params.to_h)\n\n    if current_user.update(user_params)\n      I18n.locale = current_user.locale\n      redirect_to after_update_redirect_path, notice: I18n.t('generic.changes_saved_msg')\n    else\n      render :show\n    end\n  end\n\n  private\n\n  def after_update_redirect_path\n    settings_preferences_path\n  end\n\n  def user_settings\n    UserSettingsDecorator.new(current_user)\n  end\n\n  def user_params\n    params.require(:user).permit(\n      :locale,\n      chosen_languages: []\n    )\n  end\n\n  def user_settings_params\n    params.require(:user).permit(\n      :setting_default_privacy,\n      :setting_default_sensitive,\n      :setting_default_language,\n      :setting_unfollow_modal,\n      :setting_boost_modal,\n      :setting_delete_modal,\n      :setting_auto_play_gif,\n      :setting_display_media,\n      :setting_expand_spoilers,\n      :setting_reduce_motion,\n      :setting_system_font_ui,\n      :setting_noindex,\n      :setting_theme,\n      :setting_hide_network,\n      :setting_aggregate_reblogs,\n      :setting_home_dms,\n      :setting_show_application,\n      :setting_advanced_layout,\n      notification_emails: %i(follow follow_request reblog favourite mention digest report pending_account),\n      interactions: %i(must_be_follower must_be_following must_be_following_dm)\n    )\n  end\nend\n"
  },
  {
    "path": "app/controllers/settings/profiles_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Settings::ProfilesController < Settings::BaseController\n  include ObfuscateFilename\n\n  layout 'admin'\n\n  before_action :authenticate_user!\n  before_action :set_account\n\n  obfuscate_filename [:account, :avatar]\n  obfuscate_filename [:account, :header]\n\n  def show\n    @account.build_fields\n  end\n\n  def update\n    if UpdateAccountService.new.call(@account, account_params)\n      ActivityPub::UpdateDistributionWorker.perform_async(@account.id)\n      redirect_to settings_profile_path, notice: I18n.t('generic.changes_saved_msg')\n    else\n      @account.build_fields\n      render :show\n    end\n  end\n\n  private\n\n  def account_params\n    params.require(:account).permit(:display_name, :note, :avatar, :header, :locked, :bot, :discoverable, fields_attributes: [:name, :value])\n  end\n\n  def set_account\n    @account = current_account\n  end\nend\n"
  },
  {
    "path": "app/controllers/settings/sessions_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass Settings::SessionsController < Settings::BaseController\n  before_action :authenticate_user!\n  before_action :set_session, only: :destroy\n\n  def destroy\n    @session.destroy!\n    flash[:notice] = I18n.t('sessions.revoke_success')\n    redirect_to edit_user_registration_path\n  end\n\n  private\n\n  def set_session\n    @session = current_user.session_activations.find(params[:id])\n  end\nend\n"
  },
  {
    "path": "app/controllers/settings/two_factor_authentication/confirmations_controller.rb",
    "content": "# frozen_string_literal: true\n\nmodule Settings\n  module TwoFactorAuthentication\n    class ConfirmationsController < BaseController\n      layout 'admin'\n\n      before_action :authenticate_user!\n      before_action :ensure_otp_secret\n\n      def new\n        prepare_two_factor_form\n      end\n\n      def create\n        if current_user.validate_and_consume_otp!(confirmation_params[:code])\n          flash[:notice] = I18n.t('two_factor_authentication.enabled_success')\n\n          current_user.otp_required_for_login = true\n          @recovery_codes = current_user.generate_otp_backup_codes!\n          current_user.save!\n\n          render 'settings/two_factor_authentication/recovery_codes/index'\n        else\n          flash.now[:alert] = I18n.t('two_factor_authentication.wrong_code')\n          prepare_two_factor_form\n          render :new\n        end\n      end\n\n      private\n\n      def confirmation_params\n        params.require(:form_two_factor_confirmation).permit(:code)\n      end\n\n      def prepare_two_factor_form\n        @confirmation = Form::TwoFactorConfirmation.new\n        @provision_url = current_user.otp_provisioning_uri(current_user.email, issuer: Rails.configuration.x.local_domain)\n        @qrcode = RQRCode::QRCode.new(@provision_url)\n      end\n\n      def ensure_otp_secret\n        redirect_to settings_two_factor_authentication_path unless current_user.otp_secret\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/settings/two_factor_authentication/recovery_codes_controller.rb",
    "content": "# frozen_string_literal: true\n\nmodule Settings\n  module TwoFactorAuthentication\n    class RecoveryCodesController < BaseController\n      layout 'admin'\n\n      before_action :authenticate_user!\n\n      def create\n        @recovery_codes = current_user.generate_otp_backup_codes!\n        current_user.save!\n        flash[:notice] = I18n.t('two_factor_authentication.recovery_codes_regenerated')\n        render :index\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/settings/two_factor_authentications_controller.rb",
    "content": "# frozen_string_literal: true\n\nmodule Settings\n  class TwoFactorAuthenticationsController < BaseController\n    layout 'admin'\n\n    before_action :authenticate_user!\n    before_action :verify_otp_required, only: [:create]\n\n    def show\n      @confirmation = Form::TwoFactorConfirmation.new\n    end\n\n    def create\n      current_user.otp_secret = User.generate_otp_secret(32)\n      current_user.save!\n      redirect_to new_settings_two_factor_authentication_confirmation_path\n    end\n\n    def destroy\n      if acceptable_code?\n        current_user.otp_required_for_login = false\n        current_user.save!\n        redirect_to settings_two_factor_authentication_path\n      else\n        flash.now[:alert] = I18n.t('two_factor_authentication.wrong_code')\n        @confirmation = Form::TwoFactorConfirmation.new\n        render :show\n      end\n    end\n\n    private\n\n    def confirmation_params\n      params.require(:form_two_factor_confirmation).permit(:code)\n    end\n\n    def verify_otp_required\n      redirect_to settings_two_factor_authentication_path if current_user.otp_required_for_login?\n    end\n\n    def acceptable_code?\n      current_user.validate_and_consume_otp!(confirmation_params[:code]) ||\n        current_user.invalidate_otp_backup_code!(confirmation_params[:code])\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/shares_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass SharesController < ApplicationController\n  layout 'modal'\n\n  before_action :authenticate_user!\n  before_action :set_body_classes\n\n  def show\n    serializable_resource = ActiveModelSerializers::SerializableResource.new(InitialStatePresenter.new(initial_state_params), serializer: InitialStateSerializer)\n    @initial_state_json   = serializable_resource.to_json\n  end\n\n  private\n\n  def initial_state_params\n    text = [params[:title], params[:text], params[:url]].compact.join(' ')\n\n    {\n      settings: Web::Setting.find_by(user: current_user)&.data || {},\n      push_subscription: current_account.user.web_push_subscription(current_session),\n      current_account: current_account,\n      token: current_session.token,\n      admin: Account.find_local(Setting.site_contact_username.strip.gsub(/\\A@/, '')),\n      text: text,\n    }\n  end\n\n  def set_body_classes\n    @body_classes = 'modal-layout compose-standalone'\n  end\nend\n"
  },
  {
    "path": "app/controllers/statuses_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass StatusesController < ApplicationController\n  include SignatureAuthentication\n  include Authorization\n\n  ANCESTORS_LIMIT         = 40\n  DESCENDANTS_LIMIT       = 60\n  DESCENDANTS_DEPTH_LIMIT = 20\n\n  layout 'public'\n\n  before_action :set_account\n  before_action :set_status\n  before_action :set_instance_presenter\n  before_action :set_link_headers\n  before_action :check_account_suspension\n  before_action :redirect_to_original, only: [:show]\n  before_action :set_referrer_policy_header, only: [:show]\n  before_action :set_cache_headers\n  before_action :set_replies, only: [:replies]\n\n  content_security_policy only: :embed do |p|\n    p.frame_ancestors(false)\n  end\n\n  def show\n    respond_to do |format|\n      format.html do\n        expires_in 10.seconds, public: true if current_account.nil?\n\n        @body_classes = 'with-modals'\n\n        set_ancestors\n        set_descendants\n\n        render 'stream_entries/show'\n      end\n\n      format.json do\n        render_cached_json(['activitypub', 'note', @status], content_type: 'application/activity+json', public: !@stream_entry.hidden?) do\n          ActiveModelSerializers::SerializableResource.new(@status, serializer: ActivityPub::NoteSerializer, adapter: ActivityPub::Adapter)\n        end\n      end\n    end\n  end\n\n  def activity\n    render_cached_json(['activitypub', 'activity', @status], content_type: 'application/activity+json', public: !@stream_entry.hidden?) do\n      ActiveModelSerializers::SerializableResource.new(@status, serializer: ActivityPub::ActivitySerializer, adapter: ActivityPub::Adapter)\n    end\n  end\n\n  def embed\n    raise ActiveRecord::RecordNotFound if @status.hidden?\n\n    expires_in 180, public: true\n    response.headers['X-Frame-Options'] = 'ALLOWALL'\n    @autoplay = ActiveModel::Type::Boolean.new.cast(params[:autoplay])\n\n    render 'stream_entries/embed', layout: 'embedded'\n  end\n\n  def replies\n    render json: replies_collection_presenter,\n           serializer: ActivityPub::CollectionSerializer,\n           adapter: ActivityPub::Adapter,\n           content_type: 'application/activity+json',\n           skip_activities: true\n  end\n\n  private\n\n  def replies_collection_presenter\n    page = ActivityPub::CollectionPresenter.new(\n      id: replies_account_status_url(@account, @status, page_params),\n      type: :unordered,\n      part_of: replies_account_status_url(@account, @status),\n      next: next_page,\n      items: @replies.map { |status| status.local ? status : status.id }\n    )\n    if page_requested?\n      page\n    else\n      ActivityPub::CollectionPresenter.new(\n        id: replies_account_status_url(@account, @status),\n        type: :unordered,\n        first: page\n      )\n    end\n  end\n\n  def create_descendant_thread(starting_depth, statuses)\n    depth = starting_depth + statuses.size\n    if depth < DESCENDANTS_DEPTH_LIMIT\n      { statuses: statuses, starting_depth: starting_depth }\n    else\n      next_status = statuses.pop\n      { statuses: statuses, starting_depth: starting_depth, next_status: next_status }\n    end\n  end\n\n  def set_account\n    @account = Account.find_local!(params[:account_username])\n  end\n\n  def set_ancestors\n    @ancestors     = @status.reply? ? cache_collection(@status.ancestors(ANCESTORS_LIMIT, current_account), Status) : []\n    @next_ancestor = @ancestors.size < ANCESTORS_LIMIT ? nil : @ancestors.shift\n  end\n\n  def set_descendants\n    @max_descendant_thread_id   = params[:max_descendant_thread_id]&.to_i\n    @since_descendant_thread_id = params[:since_descendant_thread_id]&.to_i\n\n    descendants = cache_collection(\n      @status.descendants(\n        DESCENDANTS_LIMIT,\n        current_account,\n        @max_descendant_thread_id,\n        @since_descendant_thread_id,\n        DESCENDANTS_DEPTH_LIMIT\n      ),\n      Status\n    )\n\n    @descendant_threads = []\n\n    if descendants.present?\n      statuses       = [descendants.first]\n      starting_depth = 0\n\n      descendants.drop(1).each_with_index do |descendant, index|\n        if descendants[index].id == descendant.in_reply_to_id\n          statuses << descendant\n        else\n          @descendant_threads << create_descendant_thread(starting_depth, statuses)\n\n          # The thread is broken, assume it's a reply to the root status\n          starting_depth = 0\n\n          # ... unless we can find its ancestor in one of the already-processed threads\n          @descendant_threads.reverse_each do |descendant_thread|\n            statuses = descendant_thread[:statuses]\n\n            index = statuses.find_index do |thread_status|\n              thread_status.id == descendant.in_reply_to_id\n            end\n\n            if index.present?\n              starting_depth = descendant_thread[:starting_depth] + index + 1\n              break\n            end\n          end\n\n          statuses = [descendant]\n        end\n      end\n\n      @descendant_threads << create_descendant_thread(starting_depth, statuses)\n    end\n\n    @max_descendant_thread_id = @descendant_threads.pop[:statuses].first.id if descendants.size >= DESCENDANTS_LIMIT\n  end\n\n  def set_link_headers\n    response.headers['Link'] = LinkHeader.new(\n      [\n        [account_stream_entry_url(@account, @status.stream_entry, format: 'atom'), [%w(rel alternate), %w(type application/atom+xml)]],\n        [ActivityPub::TagManager.instance.uri_for(@status), [%w(rel alternate), %w(type application/activity+json)]],\n      ]\n    )\n  end\n\n  def set_status\n    @status       = @account.statuses.find(params[:id])\n    @stream_entry = @status.stream_entry\n    @type         = @stream_entry.activity_type.downcase\n\n    authorize @status, :show?\n  rescue Mastodon::NotPermittedError\n    # Reraise in order to get a 404\n    raise ActiveRecord::RecordNotFound\n  end\n\n  def set_instance_presenter\n    @instance_presenter = InstancePresenter.new\n  end\n\n  def check_account_suspension\n    gone if @account.suspended?\n  end\n\n  def redirect_to_original\n    redirect_to ::TagManager.instance.url_for(@status.reblog) if @status.reblog?\n  end\n\n  def set_referrer_policy_header\n    return if @status.public_visibility? || @status.unlisted_visibility?\n    response.headers['Referrer-Policy'] = 'origin'\n  end\n\n  def page_requested?\n    params[:page] == 'true'\n  end\n\n  def set_replies\n    @replies = page_params[:other_accounts] ? Status.where.not(account_id: @account.id) : @account.statuses\n    @replies = @replies.where(in_reply_to_id: @status.id, visibility: [:public, :unlisted])\n    @replies = @replies.paginate_by_min_id(DESCENDANTS_LIMIT, params[:min_id])\n  end\n\n  def next_page\n    last_reply = @replies.last\n    return if last_reply.nil?\n    same_account = last_reply.account_id == @account.id\n    return unless same_account || @replies.size == DESCENDANTS_LIMIT\n    same_account = false unless @replies.size == DESCENDANTS_LIMIT\n    replies_account_status_url(@account, @status, page: true, min_id: last_reply.id, other_accounts: !same_account)\n  end\n\n  def page_params\n    { page: true, other_accounts: params[:other_accounts], min_id: params[:min_id] }.compact\n  end\nend\n"
  },
  {
    "path": "app/controllers/stream_entries_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass StreamEntriesController < ApplicationController\n  include Authorization\n  include SignatureVerification\n\n  layout 'public'\n\n  before_action :set_account\n  before_action :set_stream_entry\n  before_action :set_link_headers\n  before_action :check_account_suspension\n  before_action :set_cache_headers\n\n  def show\n    respond_to do |format|\n      format.html do\n        expires_in 5.minutes, public: true unless @stream_entry.hidden?\n\n        redirect_to short_account_status_url(params[:account_username], @stream_entry.activity)\n      end\n\n      format.atom do\n        expires_in 3.minutes, public: true unless @stream_entry.hidden?\n\n        render xml: OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.entry(@stream_entry, true))\n      end\n    end\n  end\n\n  def embed\n    redirect_to embed_short_account_status_url(@account, @stream_entry.activity), status: 301\n  end\n\n  private\n\n  def set_account\n    @account = Account.find_local!(params[:account_username])\n  end\n\n  def set_link_headers\n    response.headers['Link'] = LinkHeader.new(\n      [\n        [account_stream_entry_url(@account, @stream_entry, format: 'atom'), [%w(rel alternate), %w(type application/atom+xml)]],\n        [ActivityPub::TagManager.instance.uri_for(@stream_entry.activity), [%w(rel alternate), %w(type application/activity+json)]],\n      ]\n    )\n  end\n\n  def set_stream_entry\n    @stream_entry = @account.stream_entries.where(activity_type: 'Status').find(params[:id])\n    @type         = 'status'\n\n    raise ActiveRecord::RecordNotFound if @stream_entry.activity.nil?\n    authorize @stream_entry.activity, :show? if @stream_entry.hidden?\n  rescue Mastodon::NotPermittedError\n    # Reraise in order to get a 404\n    raise ActiveRecord::RecordNotFound\n  end\n\n  def check_account_suspension\n    gone if @account.suspended?\n  end\nend\n"
  },
  {
    "path": "app/controllers/tags_controller.rb",
    "content": "# frozen_string_literal: true\n\nclass TagsController < ApplicationController\n  PAGE_SIZE = 20\n\n  layout 'public'\n\n  before_action :set_body_classes\n  before_action :set_instance_presenter\n\n  def show\n    @tag = Tag.find_normalized!(params[:id])\n\n    respond_to do |format|\n      format.html do\n        @initial_state_json = ActiveModelSerializers::SerializableResource.new(\n          InitialStatePresenter.new(settings: {}, token: current_session&.token),\n          serializer: InitialStateSerializer\n        ).to_json\n      end\n\n      format.rss do\n        @statuses = HashtagQueryService.new.call(@tag, params.slice(:any, :all, :none)).limit(PAGE_SIZE)\n        @statuses = cache_collection(@statuses, Status)\n\n        render xml: RSS::TagSerializer.render(@tag, @statuses)\n      end\n\n      format.json do\n        @statuses = HashtagQueryService.new.call(@tag, params.slice(:any, :all, :none), current_account, params[:local]).paginate_by_max_id(PAGE_SIZE, params[:max_id])\n        @statuses = cache_collection(@statuses, Status)\n\n        render json: collection_presenter,\n               serializer: ActivityPub::CollectionSerializer,\n               adapter: ActivityPub::Adapter,\n               content_type: 'application/activity+json'\n      end\n    end\n  end\n\n  private\n\n  def set_body_classes\n    @body_classes = 'with-modals'\n  end\n\n  def set_instance_presenter\n    @instance_presenter = InstancePresenter.new\n  end\n\n  def collection_presenter\n    ActivityPub::CollectionPresenter.new(\n      id: tag_url(@tag, params.slice(:any, :all, :none)),\n      type: :ordered,\n      size: @tag.statuses.count,\n      items: @statuses.map { |s| ActivityPub::TagManager.instance.uri_for(s) }\n    )\n  end\nend\n"
  },
  {
    "path": "app/controllers/well_known/host_meta_controller.rb",
    "content": "# frozen_string_literal: true\n\nmodule WellKnown\n  class HostMetaController < ActionController::Base\n    include RoutingHelper\n\n    before_action { response.headers['Vary'] = 'Accept' }\n\n    def show\n      @webfinger_template = \"#{webfinger_url}?resource={uri}\"\n\n      respond_to do |format|\n        format.xml { render content_type: 'application/xrd+xml' }\n      end\n\n      expires_in(3.days, public: true)\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/well_known/keybase_proof_config_controller.rb",
    "content": "# frozen_string_literal: true\n\nmodule WellKnown\n  class KeybaseProofConfigController < ActionController::Base\n    def show\n      render json: {}, serializer: ProofProvider::Keybase::ConfigSerializer\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/well_known/webfinger_controller.rb",
    "content": "# frozen_string_literal: true\n\nmodule WellKnown\n  class WebfingerController < ActionController::Base\n    include RoutingHelper\n\n    before_action { response.headers['Vary'] = 'Accept' }\n\n    def show\n      @account = Account.find_local!(username_from_resource)\n\n      respond_to do |format|\n        format.any(:json, :html) do\n          render json: @account, serializer: WebfingerSerializer, content_type: 'application/jrd+json'\n        end\n\n        format.xml do\n          render content_type: 'application/xrd+xml'\n        end\n      end\n\n      expires_in(3.days, public: true)\n    rescue ActiveRecord::RecordNotFound\n      head 404\n    end\n\n    private\n\n    def username_from_resource\n      resource_user = resource_param\n\n      username, domain = resource_user.split('@')\n      if Rails.configuration.x.alternate_domains.include?(domain)\n        resource_user = \"#{username}@#{Rails.configuration.x.local_domain}\"\n      end\n\n      WebfingerResource.new(resource_user).username\n    end\n\n    def resource_param\n      params.require(:resource)\n    end\n  end\nend\n"
  },
  {
    "path": "app/helpers/admin/account_moderation_notes_helper.rb",
    "content": "# frozen_string_literal: true\n\nmodule Admin::AccountModerationNotesHelper\n  def admin_account_link_to(account)\n    return if account.nil?\n\n    link_to admin_account_path(account.id), class: name_tag_classes(account), title: account.acct do\n      safe_join([\n                  image_tag(account.avatar.url, width: 15, height: 15, alt: display_name(account), class: 'avatar'),\n                  content_tag(:span, account.acct, class: 'username'),\n                ], ' ')\n    end\n  end\n\n  def admin_account_inline_link_to(account)\n    return if account.nil?\n\n    link_to admin_account_path(account.id), class: name_tag_classes(account, true), title: account.acct do\n      content_tag(:span, account.acct, class: 'username')\n    end\n  end\n\n  private\n\n  def name_tag_classes(account, inline = false)\n    classes = [inline ? 'inline-name-tag' : 'name-tag']\n    classes << 'suspended' if account.suspended? || (account.local? && account.user.nil?)\n    classes.join(' ')\n  end\nend\n"
  },
  {
    "path": "app/helpers/admin/action_logs_helper.rb",
    "content": "# frozen_string_literal: true\n\nmodule Admin::ActionLogsHelper\n  def log_target(log)\n    if log.target\n      linkable_log_target(log.target)\n    else\n      log_target_from_history(log.target_type, log.recorded_changes)\n    end\n  end\n\n  def relevant_log_changes(log)\n    if log.target_type == 'CustomEmoji' && [:enable, :disable, :destroy].include?(log.action)\n      log.recorded_changes.slice('domain')\n    elsif log.target_type == 'CustomEmoji' && log.action == :update\n      log.recorded_changes.slice('domain', 'visible_in_picker')\n    elsif log.target_type == 'User' && [:promote, :demote].include?(log.action)\n      log.recorded_changes.slice('moderator', 'admin')\n    elsif log.target_type == 'User' && [:change_email].include?(log.action)\n      log.recorded_changes.slice('email', 'unconfirmed_email')\n    elsif log.target_type == 'DomainBlock'\n      log.recorded_changes.slice('severity', 'reject_media')\n    elsif log.target_type == 'Status' && log.action == :update\n      log.recorded_changes.slice('sensitive')\n    end\n  end\n\n  def log_extra_attributes(hash)\n    safe_join(hash.to_a.map { |key, value| safe_join([content_tag(:span, key, class: 'diff-key'), '=', log_change(value)]) }, ' ')\n  end\n\n  def log_change(val)\n    return content_tag(:span, val, class: 'diff-neutral') unless val.is_a?(Array)\n    safe_join([content_tag(:span, val.first, class: 'diff-old'), content_tag(:span, val.last, class: 'diff-new')], '→')\n  end\n\n  def icon_for_log(log)\n    case log.target_type\n    when 'Account', 'User'\n      'user'\n    when 'CustomEmoji'\n      'file'\n    when 'Report'\n      'flag'\n    when 'DomainBlock'\n      'lock'\n    when 'EmailDomainBlock'\n      'envelope'\n    when 'Status'\n      'pencil'\n    when 'AccountWarning'\n      'warning'\n    end\n  end\n\n  def class_for_log_icon(log)\n    case log.action\n    when :enable, :unsuspend, :unsilence, :confirm, :promote, :resolve\n      'positive'\n    when :create\n      opposite_verbs?(log) ? 'negative' : 'positive'\n    when :update, :reset_password, :disable_2fa, :memorialize, :change_email\n      'neutral'\n    when :demote, :silence, :disable, :suspend, :remove_avatar, :remove_header, :reopen\n      'negative'\n    when :destroy\n      opposite_verbs?(log) ? 'positive' : 'negative'\n    else\n      ''\n    end\n  end\n\n  private\n\n  def opposite_verbs?(log)\n    %w(DomainBlock EmailDomainBlock AccountWarning).include?(log.target_type)\n  end\n\n  def linkable_log_target(record)\n    case record.class.name\n    when 'Account'\n      link_to record.acct, admin_account_path(record.id)\n    when 'User'\n      link_to record.account.acct, admin_account_path(record.account_id)\n    when 'CustomEmoji'\n      record.shortcode\n    when 'Report'\n      link_to \"##{record.id}\", admin_report_path(record)\n    when 'DomainBlock', 'EmailDomainBlock'\n      link_to record.domain, \"https://#{record.domain}\"\n    when 'Status'\n      link_to record.account.acct, TagManager.instance.url_for(record)\n    when 'AccountWarning'\n      link_to record.target_account.acct, admin_account_path(record.target_account_id)\n    end\n  end\n\n  def log_target_from_history(type, attributes)\n    case type\n    when 'CustomEmoji'\n      attributes['shortcode']\n    when 'DomainBlock', 'EmailDomainBlock'\n      link_to attributes['domain'], \"https://#{attributes['domain']}\"\n    when 'Status'\n      tmp_status = Status.new(attributes.except('reblogs_count', 'favourites_count'))\n\n      if tmp_status.account\n        link_to tmp_status.account&.acct || \"##{tmp_status.account_id}\", admin_account_path(tmp_status.account_id)\n      else\n        I18n.t('admin.action_logs.deleted_status')\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "app/helpers/admin/dashboard_helper.rb",
    "content": "# frozen_string_literal: true\n\nmodule Admin::DashboardHelper\n  def feature_hint(feature, enabled)\n    indicator   = safe_join([enabled ? t('simple_form.yes') : t('simple_form.no'), fa_icon('power-off fw')], ' ')\n    class_names = enabled ? 'pull-right positive-hint' : 'pull-right neutral-hint'\n\n    safe_join([feature, content_tag(:span, indicator, class: class_names)])\n  end\nend\n"
  },
  {
    "path": "app/helpers/admin/filter_helper.rb",
    "content": "# frozen_string_literal: true\n\nmodule Admin::FilterHelper\n  ACCOUNT_FILTERS      = %i(local remote by_domain active pending silenced suspended username display_name email ip staff).freeze\n  REPORT_FILTERS       = %i(resolved account_id target_account_id).freeze\n  INVITE_FILTER        = %i(available expired).freeze\n  CUSTOM_EMOJI_FILTERS = %i(local remote by_domain shortcode).freeze\n  TAGS_FILTERS         = %i(hidden).freeze\n  INSTANCES_FILTERS    = %i(limited by_domain).freeze\n  FOLLOWERS_FILTERS    = %i(relationship status by_domain activity order).freeze\n\n  FILTERS = ACCOUNT_FILTERS + REPORT_FILTERS + INVITE_FILTER + CUSTOM_EMOJI_FILTERS + TAGS_FILTERS + INSTANCES_FILTERS + FOLLOWERS_FILTERS\n\n  def filter_link_to(text, link_to_params, link_class_params = link_to_params)\n    new_url = filtered_url_for(link_to_params)\n    new_class = filtered_url_for(link_class_params)\n    link_to text, new_url, class: filter_link_class(new_class)\n  end\n\n  def table_link_to(icon, text, path, **options)\n    link_to safe_join([fa_icon(icon), text]), path, options.merge(class: 'table-action-link')\n  end\n\n  def selected?(more_params)\n    new_url = filtered_url_for(more_params)\n    filter_link_class(new_url) == 'selected'\n  end\n\n  private\n\n  def filter_params(more_params)\n    controller_request_params.merge(more_params)\n  end\n\n  def filter_link_class(new_url)\n    filtered_url_for(controller_request_params) == new_url ? 'selected' : ''\n  end\n\n  def filtered_url_for(url_params)\n    url_for filter_params(url_params)\n  end\n\n  def controller_request_params\n    params.permit(FILTERS)\n  end\nend\n"
  },
  {
    "path": "app/helpers/application_helper.rb",
    "content": "# frozen_string_literal: true\n\nmodule ApplicationHelper\n  DANGEROUS_SCOPES = %w(\n    read\n    write\n    follow\n  ).freeze\n\n  def active_nav_class(*paths)\n    paths.any? { |path| current_page?(path) } ? 'active' : ''\n  end\n\n  def active_link_to(label, path, **options)\n    link_to label, path, options.merge(class: active_nav_class(path))\n  end\n\n  def show_landing_strip?\n    !user_signed_in? && !single_user_mode?\n  end\n\n  def open_registrations?\n    Setting.registrations_mode == 'open'\n  end\n\n  def approved_registrations?\n    Setting.registrations_mode == 'approved'\n  end\n\n  def closed_registrations?\n    Setting.registrations_mode == 'none'\n  end\n\n  def available_sign_up_path\n    if closed_registrations?\n      'https://joinmastodon.org/#getting-started'\n    else\n      new_user_registration_path\n    end\n  end\n\n  def max_bio_chars\n    Setting.max_bio_chars\n  end\n\n  def max_toot_chars\n    Setting.max_toot_chars\n  end\n\n  def open_deletion?\n    Setting.open_deletion\n  end\n\n  def locale_direction\n    if [:ar, :fa, :he].include?(I18n.locale)\n      'rtl'\n    else\n      'ltr'\n    end\n  end\n\n  def favicon_path\n    env_suffix = Rails.env.production? ? '' : '-dev'\n    \"/favicon#{env_suffix}.ico\"\n  end\n\n  def title\n    Rails.env.production? ? site_title : \"#{site_title} (Dev)\"\n  end\n\n  def class_for_scope(scope)\n    'scope-danger' if DANGEROUS_SCOPES.include?(scope.to_s)\n  end\n\n  def can?(action, record)\n    return false if record.nil?\n    policy(record).public_send(\"#{action}?\")\n  end\n\n  def fa_icon(icon, attributes = {})\n    class_names = attributes[:class]&.split(' ') || []\n    class_names << 'fa'\n    class_names += icon.split(' ').map { |cl| \"fa-#{cl}\" }\n\n    content_tag(:i, nil, attributes.merge(class: class_names.join(' ')))\n  end\n\n  def custom_emoji_tag(custom_emoji)\n    image_tag(custom_emoji.image.url, class: 'emojione', alt: \":#{custom_emoji.shortcode}:\")\n  end\n\n  def opengraph(property, content)\n    tag(:meta, content: content, property: property)\n  end\n\n  def react_component(name, props = {}, &block)\n    if block.nil?\n      content_tag(:div, nil, data: { component: name.to_s.camelcase, props: Oj.dump(props) })\n    else\n      content_tag(:div, data: { component: name.to_s.camelcase, props: Oj.dump(props) }, &block)\n    end\n  end\n\n  def body_classes\n    output = (@body_classes || '').split(' ')\n    output << \"theme-#{current_theme.parameterize}\"\n    output << 'system-font' if current_account&.user&.setting_system_font_ui\n    output << (current_account&.user&.setting_reduce_motion ? 'reduce-motion' : 'no-reduce-motion')\n    output << 'rtl' if locale_direction == 'rtl'\n    output.reject(&:blank?).join(' ')\n  end\n\n  def cdn_host\n    Rails.configuration.action_controller.asset_host\n  end\n\n  def cdn_host?\n    cdn_host.present?\n  end\n\n  def storage_host\n    \"https://#{ENV['S3_ALIAS_HOST'].presence || ENV['S3_CLOUDFRONT_HOST']}\"\n  end\n\n  def storage_host?\n    ENV['S3_ALIAS_HOST'].present? || ENV['S3_CLOUDFRONT_HOST'].present?\n  end\n\n  def quote_wrap(text, line_width: 80, break_sequence: \"\\n\")\n    text = word_wrap(text, line_width: line_width - 2, break_sequence: break_sequence)\n    text.split(\"\\n\").map { |line| '> ' + line }.join(\"\\n\")\n  end\nend\n"
  },
  {
    "path": "app/helpers/flashes_helper.rb",
    "content": "# frozen_string_literal: true\n\nmodule FlashesHelper\n  def user_facing_flashes\n    flash.to_hash.slice('alert', 'error', 'notice', 'success')\n  end\nend\n"
  },
  {
    "path": "app/helpers/home_helper.rb",
    "content": "# frozen_string_literal: true\n\nmodule HomeHelper\n  def default_props\n    {\n      locale: I18n.locale,\n    }\n  end\n\n  def account_link_to(account, button = '', size: 36, path: nil)\n    content_tag(:div, class: 'account') do\n      content_tag(:div, class: 'account__wrapper') do\n        section = if account.nil?\n                    content_tag(:div, class: 'account__display-name') do\n                      content_tag(:div, class: 'account__avatar-wrapper') do\n                        content_tag(:div, '', class: 'account__avatar', style: \"width: #{size}px; height: #{size}px; background-size: #{size}px #{size}px; background-image: url(#{full_asset_url('avatars/original/missing.png', skip_pipeline: true)})\")\n                      end +\n                        content_tag(:span, class: 'display-name') do\n                          content_tag(:strong, t('about.contact_missing')) +\n                            content_tag(:span, t('about.contact_unavailable'), class: 'display-name__account')\n                        end\n                    end\n                  else\n                    link_to(path || TagManager.instance.url_for(account), class: 'account__display-name') do\n                      content_tag(:div, class: 'account__avatar-wrapper') do\n                        content_tag(:div, '', class: 'account__avatar', style: \"width: #{size}px; height: #{size}px; background-size: #{size}px #{size}px; background-image: url(#{full_asset_url(current_account&.user&.setting_auto_play_gif ? account.avatar_original_url : account.avatar_static_url)})\")\n                      end +\n                        content_tag(:span, class: 'display-name') do\n                          content_tag(:bdi) do\n                            content_tag(:strong, display_name(account, custom_emojify: true), class: 'display-name__html emojify')\n                          end +\n                            content_tag(:span, \"@#{account.acct}\", class: 'display-name__account')\n                        end\n                    end\n                  end\n\n        section + button\n      end\n    end\n  end\n\n  def obscured_counter(count)\n    if count <= 0\n      0\n    elsif count == 1\n      1\n    else\n      '1+'\n    end\n  end\n\n  def custom_field_classes(field)\n    if field.verified?\n      'verified'\n    else\n      'emojify'\n    end\n  end\n\n  def optional_link_to(condition, path, options = {}, &block)\n    if condition\n      link_to(path, options, &block)\n    else\n      content_tag(:div, &block)\n    end\n  end\n\n  def sign_up_message\n    if closed_registrations?\n      t('auth.registration_closed', instance: site_hostname)\n    elsif open_registrations?\n      t('auth.register')\n    elsif approved_registrations?\n      t('auth.apply_for_account')\n    end\n  end\nend\n"
  },
  {
    "path": "app/helpers/instance_helper.rb",
    "content": "# frozen_string_literal: true\n\nmodule InstanceHelper\n  def site_title\n    Setting.site_title\n  end\n\n  def site_hostname\n    @site_hostname ||= Addressable::URI.parse(\"//#{Rails.configuration.x.local_domain}\").display_uri.host\n  end\nend\n"
  },
  {
    "path": "app/helpers/jsonld_helper.rb",
    "content": "# frozen_string_literal: true\n\nmodule JsonLdHelper\n  def equals_or_includes?(haystack, needle)\n    haystack.is_a?(Array) ? haystack.include?(needle) : haystack == needle\n  end\n\n  def equals_or_includes_any?(haystack, needles)\n    needles.any? { |needle| equals_or_includes?(haystack, needle) }\n  end\n\n  def first_of_value(value)\n    value.is_a?(Array) ? value.first : value\n  end\n\n  # The url attribute can be a string, an array of strings, or an array of objects.\n  # The objects could include a mimeType. Not-included mimeType means it's text/html.\n  def url_to_href(value, preferred_type = nil)\n    single_value = if value.is_a?(Array) && !value.first.is_a?(String)\n                     value.find { |link| preferred_type.nil? || ((link['mimeType'].presence || 'text/html') == preferred_type) }\n                   elsif value.is_a?(Array)\n                     value.first\n                   else\n                     value\n                   end\n\n    if single_value.nil? || single_value.is_a?(String)\n      single_value\n    else\n      single_value['href']\n    end\n  end\n\n  def as_array(value)\n    value.is_a?(Array) ? value : [value]\n  end\n\n  def value_or_id(value)\n    value.is_a?(String) || value.nil? ? value : value['id']\n  end\n\n  def supported_context?(json)\n    !json.nil? && equals_or_includes?(json['@context'], ActivityPub::TagManager::CONTEXT)\n  end\n\n  def unsupported_uri_scheme?(uri)\n    !uri.start_with?('http://', 'https://')\n  end\n\n  def invalid_origin?(url)\n    return true if unsupported_uri_scheme?(url)\n\n    needle   = Addressable::URI.parse(url).host\n    haystack = Addressable::URI.parse(@account.uri).host\n\n    !haystack.casecmp(needle).zero?\n  end\n\n  def canonicalize(json)\n    graph = RDF::Graph.new << JSON::LD::API.toRdf(json, documentLoader: method(:load_jsonld_context))\n    graph.dump(:normalize)\n  end\n\n  def fetch_resource(uri, id, on_behalf_of = nil)\n    unless id\n      json = fetch_resource_without_id_validation(uri, on_behalf_of)\n      return unless json\n      uri = json['id']\n    end\n\n    json = fetch_resource_without_id_validation(uri, on_behalf_of)\n    json.present? && json['id'] == uri ? json : nil\n  end\n\n  def fetch_resource_without_id_validation(uri, on_behalf_of = nil, raise_on_temporary_error = false)\n    build_request(uri, on_behalf_of).perform do |response|\n      unless response_successful?(response) || response_error_unsalvageable?(response) || !raise_on_temporary_error\n        raise Mastodon::UnexpectedResponseError, response\n      end\n      return body_to_json(response.body_with_limit) if response.code == 200\n    end\n    # If request failed, retry without doing it on behalf of a user\n    return if on_behalf_of.nil?\n    build_request(uri).perform do |response|\n      unless response_successful?(response) || response_error_unsalvageable?(response) || !raise_on_temporary_error\n        raise Mastodon::UnexpectedResponseError, response\n      end\n      response.code == 200 ? body_to_json(response.body_with_limit) : nil\n    end\n  end\n\n  def body_to_json(body, compare_id: nil)\n    json = body.is_a?(String) ? Oj.load(body, mode: :strict) : body\n    return if compare_id.present? && json['id'] != compare_id\n    json\n  rescue Oj::ParseError\n    nil\n  end\n\n  def merge_context(context, new_context)\n    if context.is_a?(Array)\n      context << new_context\n    else\n      [context, new_context]\n    end\n  end\n\n  private\n\n  def response_successful?(response)\n    (200...300).cover?(response.code)\n  end\n\n  def response_error_unsalvageable?(response)\n    (400...500).cover?(response.code) && response.code != 429\n  end\n\n  def build_request(uri, on_behalf_of = nil)\n    request = Request.new(:get, uri)\n    request.on_behalf_of(on_behalf_of) if on_behalf_of\n    request.add_headers('Accept' => 'application/activity+json, application/ld+json')\n    request\n  end\n\n  def load_jsonld_context(url, _options = {}, &_block)\n    json = Rails.cache.fetch(\"jsonld:context:#{url}\", expires_in: 30.days, raw: true) do\n      request = Request.new(:get, url)\n      request.add_headers('Accept' => 'application/ld+json')\n\n      request.perform do |res|\n        raise JSON::LD::JsonLdError::LoadingDocumentFailed unless res.code == 200 && res.mime_type == 'application/ld+json'\n        res.body_with_limit\n      end\n    end\n\n    doc = JSON::LD::API::RemoteDocument.new(url, json)\n    block_given? ? yield(doc) : doc\n  end\nend\n"
  },
  {
    "path": "app/helpers/routing_helper.rb",
    "content": "# frozen_string_literal: true\n\nmodule RoutingHelper\n  extend ActiveSupport::Concern\n  include Rails.application.routes.url_helpers\n  include ActionView::Helpers::AssetTagHelper\n  include Webpacker::Helper\n\n  included do\n    def default_url_options\n      ActionMailer::Base.default_url_options\n    end\n  end\n\n  def full_asset_url(source, **options)\n    source = ActionController::Base.helpers.asset_url(source, options) unless use_storage?\n\n    URI.join(root_url, source).to_s\n  end\n\n  def full_pack_url(source, **options)\n    full_asset_url(asset_pack_path(source, options))\n  end\n\n  private\n\n  def use_storage?\n    Rails.configuration.x.use_s3 || Rails.configuration.x.use_swift\n  end\nend\n"
  },
  {
    "path": "app/helpers/settings_helper.rb",
    "content": "# frozen_string_literal: true\n\nmodule SettingsHelper\n  HUMAN_LOCALES = {\n    en: 'English',\n    ar: 'العربية',\n    ast: 'Asturianu',\n    bg: 'Български',\n    bn: 'বাংলা',\n    ca: 'Català',\n    co: 'Corsu',\n    cs: 'Čeština',\n    cy: 'Cymraeg',\n    da: 'Dansk',\n    de: 'Deutsch',\n    el: 'Ελληνικά',\n    eo: 'Esperanto',\n    es: 'Español',\n    eu: 'Euskara',\n    fa: 'فارسی',\n    fi: 'Suomi',\n    fr: 'Français',\n    ga: 'Gaeilge',\n    gl: 'Galego',\n    he: 'עברית',\n    hi: 'हिन्दी',\n    hr: 'Hrvatski',\n    hu: 'Magyar',\n    hy: 'Հայերեն',\n    id: 'Bahasa Indonesia',\n    io: 'Ido',\n    it: 'Italiano',\n    ja: '日本語',\n    ka: 'ქართული',\n    kk: 'Қазақша',\n    ko: '한국어',\n    lt: 'Lietuvių',\n    lv: 'Latviešu',\n    ml: 'മലയാളം',\n    ms: 'Bahasa Melayu',\n    nl: 'Nederlands',\n    no: 'Norsk',\n    oc: 'Occitan',\n    pl: 'Polski',\n    pt: 'Português',\n    'pt-BR': 'Português do Brasil',\n    ro: 'Română',\n    ru: 'Русский',\n    sk: 'Slovenčina',\n    sl: 'Slovenščina',\n    sq: 'Shqip',\n    sr: 'Српски',\n    'sr-Latn': 'Srpski (latinica)',\n    sv: 'Svenska',\n    ta: 'தமிழ்',\n    te: 'తెలుగు',\n    th: 'ไทย',\n    tr: 'Türkçe',\n    uk: 'Українська',\n    zh: '中文',\n    'zh-CN': '简体中文',\n    'zh-HK': '繁體中文（香港）',\n    'zh-TW': '繁體中文（臺灣）',\n  }.freeze\n\n  def human_locale(locale)\n    HUMAN_LOCALES[locale]\n  end\n\n  def filterable_languages\n    LanguageDetector.instance.language_names.select(&HUMAN_LOCALES.method(:key?))\n  end\n\n  def hash_to_object(hash)\n    HashObject.new(hash)\n  end\n\n  def session_device_icon(session)\n    device = session.detection.device\n\n    if device.mobile?\n      'mobile'\n    elsif device.tablet?\n      'tablet'\n    else\n      'desktop'\n    end\n  end\nend\n"
  },
  {
    "path": "app/helpers/stream_entries_helper.rb",
    "content": "# frozen_string_literal: true\n\nmodule StreamEntriesHelper\n  EMBEDDED_CONTROLLER = 'statuses'\n  EMBEDDED_ACTION = 'embed'\n\n  def display_name(account, **options)\n    if options[:custom_emojify]\n      Formatter.instance.format_display_name(account, options)\n    else\n      account.display_name.presence || account.username\n    end\n  end\n\n  def account_action_button(account)\n    if user_signed_in?\n      if account.id == current_user.account_id\n        link_to settings_profile_url, class: 'button logo-button' do\n          safe_join([svg_logo, t('settings.edit_profile')])\n        end\n      elsif current_account.following?(account) || current_account.requested?(account)\n        link_to account_unfollow_path(account), class: 'button logo-button button--destructive', data: { method: :post } do\n          safe_join([svg_logo, t('accounts.unfollow')])\n        end\n      elsif !(account.memorial? || account.moved?)\n        link_to account_follow_path(account), class: \"button logo-button#{account.blocking?(current_account) ? ' disabled' : ''}\", data: { method: :post } do\n          safe_join([svg_logo, t('accounts.follow')])\n        end\n      end\n    elsif !(account.memorial? || account.moved?)\n      link_to account_remote_follow_path(account), class: 'button logo-button modal-button', target: '_new' do\n        safe_join([svg_logo, t('accounts.follow')])\n      end\n    end\n  end\n\n  def svg_logo\n    content_tag(:svg, tag(:use, 'xlink:href' => '#mastodon-svg-logo'), 'viewBox' => '0 0 216.4144 232.00976')\n  end\n\n  def svg_logo_full\n    content_tag(:svg, tag(:use, 'xlink:href' => '#mastodon-svg-logo-full'), 'viewBox' => '0 0 713.35878 175.8678')\n  end\n\n  def account_badge(account, all: false)\n    if account.bot?\n      content_tag(:div, content_tag(:div, t('accounts.roles.bot'), class: 'account-role bot'), class: 'roles')\n    elsif (Setting.show_staff_badge && account.user_staff?) || all\n      content_tag(:div, class: 'roles') do\n        if all && !account.user_staff?\n          content_tag(:div, t('admin.accounts.roles.user'), class: 'account-role')\n        elsif account.user_admin?\n          content_tag(:div, t('accounts.roles.admin'), class: 'account-role admin')\n        elsif account.user_moderator?\n          content_tag(:div, t('accounts.roles.moderator'), class: 'account-role moderator')\n        end\n      end\n    end\n  end\n\n  def link_to_more(url)\n    link_to t('statuses.show_more'), url, class: 'load-more load-gap'\n  end\n\n  def nothing_here(extra_classes = '')\n    content_tag(:div, class: \"nothing-here #{extra_classes}\") do\n      t('accounts.nothing_here')\n    end\n  end\n\n  def account_description(account)\n    prepend_str = [\n      [\n        number_to_human(account.statuses_count, strip_insignificant_zeros: true),\n        I18n.t('accounts.posts', count: account.statuses_count),\n      ].join(' '),\n\n      [\n        number_to_human(account.following_count, strip_insignificant_zeros: true),\n        I18n.t('accounts.following', count: account.following_count),\n      ].join(' '),\n\n      [\n        number_to_human(account.followers_count, strip_insignificant_zeros: true),\n        I18n.t('accounts.followers', count: account.followers_count),\n      ].join(' '),\n    ].join(', ')\n\n    [prepend_str, account.note].join(' · ')\n  end\n\n  def media_summary(status)\n    attachments = { image: 0, video: 0 }\n\n    status.media_attachments.each do |media|\n      if media.video?\n        attachments[:video] += 1\n      else\n        attachments[:image] += 1\n      end\n    end\n\n    text = attachments.to_a.reject { |_, value| value.zero? }.map { |key, value| I18n.t(\"statuses.attached.#{key}\", count: value) }.join(' · ')\n\n    return if text.blank?\n\n    I18n.t('statuses.attached.description', attached: text)\n  end\n\n  def status_text_summary(status)\n    return if status.spoiler_text.blank?\n    I18n.t('statuses.content_warning', warning: status.spoiler_text)\n  end\n\n  def poll_summary(status)\n    return unless status.preloadable_poll\n    status.preloadable_poll.options.map { |o| \"[ ] #{o}\" }.join(\"\\n\")\n  end\n\n  def status_description(status)\n    components = [[media_summary(status), status_text_summary(status)].reject(&:blank?).join(' · ')]\n\n    if status.spoiler_text.blank?\n      components << status.text\n      components << poll_summary(status)\n    end\n\n    components.reject(&:blank?).join(\"\\n\\n\")\n  end\n\n  def stream_link_target\n    embedded_view? ? '_blank' : nil\n  end\n\n  def acct(account)\n    if account.local?\n      \"@#{account.acct}@#{Rails.configuration.x.local_domain}\"\n    else\n      \"@#{account.acct}\"\n    end\n  end\n\n  def style_classes(status, is_predecessor, is_successor, include_threads)\n    classes = ['entry']\n    classes << 'entry-predecessor' if is_predecessor\n    classes << 'entry-reblog' if status.reblog?\n    classes << 'entry-successor' if is_successor\n    classes << 'entry-center' if include_threads\n    classes.join(' ')\n  end\n\n  def microformats_classes(status, is_direct_parent, is_direct_child)\n    classes = []\n    classes << 'p-in-reply-to' if is_direct_parent\n    classes << 'p-repost-of' if status.reblog? && is_direct_parent\n    classes << 'p-comment' if is_direct_child\n    classes.join(' ')\n  end\n\n  def microformats_h_class(status, is_predecessor, is_successor, include_threads)\n    if is_predecessor || status.reblog? || is_successor\n      'h-cite'\n    elsif include_threads\n      ''\n    else\n      'h-entry'\n    end\n  end\n\n  def rtl_status?(status)\n    status.local? ? rtl?(status.text) : rtl?(strip_tags(status.text))\n  end\n\n  def rtl?(text)\n    text = simplified_text(text)\n    rtl_words = text.scan(/[\\p{Hebrew}\\p{Arabic}\\p{Syriac}\\p{Thaana}\\p{Nko}]+/m)\n\n    if rtl_words.present?\n      total_size = text.size.to_f\n      rtl_size(rtl_words) / total_size > 0.3\n    else\n      false\n    end\n  end\n\n  def fa_visibility_icon(status)\n    case status.visibility\n    when 'public'\n      fa_icon 'globe fw'\n    when 'unlisted'\n      fa_icon 'unlock fw'\n    when 'private'\n      fa_icon 'lock fw'\n    when 'direct'\n      fa_icon 'envelope fw'\n    end\n  end\n\n  private\n\n  def simplified_text(text)\n    text.dup.tap do |new_text|\n      URI.extract(new_text).each do |url|\n        new_text.gsub!(url, '')\n      end\n\n      new_text.gsub!(Account::MENTION_RE, '')\n      new_text.gsub!(Tag::HASHTAG_RE, '')\n      new_text.gsub!(/\\s+/, '')\n    end\n  end\n\n  def rtl_size(words)\n    words.reduce(0) { |acc, elem| acc + elem.size }.to_f\n  end\n\n  def embedded_view?\n    params[:controller] == EMBEDDED_CONTROLLER && params[:action] == EMBEDDED_ACTION\n  end\nend\n"
  },
  {
    "path": "app/javascript/mastodon/actions/accounts.js",
    "content": "import api, { getLinks } from '../api';\nimport openDB from '../storage/db';\nimport { importAccount, importFetchedAccount, importFetchedAccounts } from './importer';\n\nexport const ACCOUNT_FETCH_REQUEST = 'ACCOUNT_FETCH_REQUEST';\nexport const ACCOUNT_FETCH_SUCCESS = 'ACCOUNT_FETCH_SUCCESS';\nexport const ACCOUNT_FETCH_FAIL    = 'ACCOUNT_FETCH_FAIL';\n\nexport const ACCOUNT_FOLLOW_REQUEST = 'ACCOUNT_FOLLOW_REQUEST';\nexport const ACCOUNT_FOLLOW_SUCCESS = 'ACCOUNT_FOLLOW_SUCCESS';\nexport const ACCOUNT_FOLLOW_FAIL    = 'ACCOUNT_FOLLOW_FAIL';\n\nexport const ACCOUNT_UNFOLLOW_REQUEST = 'ACCOUNT_UNFOLLOW_REQUEST';\nexport const ACCOUNT_UNFOLLOW_SUCCESS = 'ACCOUNT_UNFOLLOW_SUCCESS';\nexport const ACCOUNT_UNFOLLOW_FAIL    = 'ACCOUNT_UNFOLLOW_FAIL';\n\nexport const ACCOUNT_BLOCK_REQUEST = 'ACCOUNT_BLOCK_REQUEST';\nexport const ACCOUNT_BLOCK_SUCCESS = 'ACCOUNT_BLOCK_SUCCESS';\nexport const ACCOUNT_BLOCK_FAIL    = 'ACCOUNT_BLOCK_FAIL';\n\nexport const ACCOUNT_UNBLOCK_REQUEST = 'ACCOUNT_UNBLOCK_REQUEST';\nexport const ACCOUNT_UNBLOCK_SUCCESS = 'ACCOUNT_UNBLOCK_SUCCESS';\nexport const ACCOUNT_UNBLOCK_FAIL    = 'ACCOUNT_UNBLOCK_FAIL';\n\nexport const ACCOUNT_MUTE_REQUEST = 'ACCOUNT_MUTE_REQUEST';\nexport const ACCOUNT_MUTE_SUCCESS = 'ACCOUNT_MUTE_SUCCESS';\nexport const ACCOUNT_MUTE_FAIL    = 'ACCOUNT_MUTE_FAIL';\n\nexport const ACCOUNT_UNMUTE_REQUEST = 'ACCOUNT_UNMUTE_REQUEST';\nexport const ACCOUNT_UNMUTE_SUCCESS = 'ACCOUNT_UNMUTE_SUCCESS';\nexport const ACCOUNT_UNMUTE_FAIL    = 'ACCOUNT_UNMUTE_FAIL';\n\nexport const ACCOUNT_PIN_REQUEST = 'ACCOUNT_PIN_REQUEST';\nexport const ACCOUNT_PIN_SUCCESS = 'ACCOUNT_PIN_SUCCESS';\nexport const ACCOUNT_PIN_FAIL    = 'ACCOUNT_PIN_FAIL';\n\nexport const ACCOUNT_UNPIN_REQUEST = 'ACCOUNT_UNPIN_REQUEST';\nexport const ACCOUNT_UNPIN_SUCCESS = 'ACCOUNT_UNPIN_SUCCESS';\nexport const ACCOUNT_UNPIN_FAIL    = 'ACCOUNT_UNPIN_FAIL';\n\nexport const FOLLOWERS_FETCH_REQUEST = 'FOLLOWERS_FETCH_REQUEST';\nexport const FOLLOWERS_FETCH_SUCCESS = 'FOLLOWERS_FETCH_SUCCESS';\nexport const FOLLOWERS_FETCH_FAIL    = 'FOLLOWERS_FETCH_FAIL';\n\nexport const FOLLOWERS_EXPAND_REQUEST = 'FOLLOWERS_EXPAND_REQUEST';\nexport const FOLLOWERS_EXPAND_SUCCESS = 'FOLLOWERS_EXPAND_SUCCESS';\nexport const FOLLOWERS_EXPAND_FAIL    = 'FOLLOWERS_EXPAND_FAIL';\n\nexport const FOLLOWING_FETCH_REQUEST = 'FOLLOWING_FETCH_REQUEST';\nexport const FOLLOWING_FETCH_SUCCESS = 'FOLLOWING_FETCH_SUCCESS';\nexport const FOLLOWING_FETCH_FAIL    = 'FOLLOWING_FETCH_FAIL';\n\nexport const FOLLOWING_EXPAND_REQUEST = 'FOLLOWING_EXPAND_REQUEST';\nexport const FOLLOWING_EXPAND_SUCCESS = 'FOLLOWING_EXPAND_SUCCESS';\nexport const FOLLOWING_EXPAND_FAIL    = 'FOLLOWING_EXPAND_FAIL';\n\nexport const RELATIONSHIPS_FETCH_REQUEST = 'RELATIONSHIPS_FETCH_REQUEST';\nexport const RELATIONSHIPS_FETCH_SUCCESS = 'RELATIONSHIPS_FETCH_SUCCESS';\nexport const RELATIONSHIPS_FETCH_FAIL    = 'RELATIONSHIPS_FETCH_FAIL';\n\nexport const FOLLOW_REQUESTS_FETCH_REQUEST = 'FOLLOW_REQUESTS_FETCH_REQUEST';\nexport const FOLLOW_REQUESTS_FETCH_SUCCESS = 'FOLLOW_REQUESTS_FETCH_SUCCESS';\nexport const FOLLOW_REQUESTS_FETCH_FAIL    = 'FOLLOW_REQUESTS_FETCH_FAIL';\n\nexport const FOLLOW_REQUESTS_EXPAND_REQUEST = 'FOLLOW_REQUESTS_EXPAND_REQUEST';\nexport const FOLLOW_REQUESTS_EXPAND_SUCCESS = 'FOLLOW_REQUESTS_EXPAND_SUCCESS';\nexport const FOLLOW_REQUESTS_EXPAND_FAIL    = 'FOLLOW_REQUESTS_EXPAND_FAIL';\n\nexport const FOLLOW_REQUEST_AUTHORIZE_REQUEST = 'FOLLOW_REQUEST_AUTHORIZE_REQUEST';\nexport const FOLLOW_REQUEST_AUTHORIZE_SUCCESS = 'FOLLOW_REQUEST_AUTHORIZE_SUCCESS';\nexport const FOLLOW_REQUEST_AUTHORIZE_FAIL    = 'FOLLOW_REQUEST_AUTHORIZE_FAIL';\n\nexport const FOLLOW_REQUEST_REJECT_REQUEST = 'FOLLOW_REQUEST_REJECT_REQUEST';\nexport const FOLLOW_REQUEST_REJECT_SUCCESS = 'FOLLOW_REQUEST_REJECT_SUCCESS';\nexport const FOLLOW_REQUEST_REJECT_FAIL    = 'FOLLOW_REQUEST_REJECT_FAIL';\n\nfunction getFromDB(dispatch, getState, index, id) {\n  return new Promise((resolve, reject) => {\n    const request = index.get(id);\n\n    request.onerror = reject;\n\n    request.onsuccess = () => {\n      if (!request.result) {\n        reject();\n        return;\n      }\n\n      dispatch(importAccount(request.result));\n      resolve(request.result.moved && getFromDB(dispatch, getState, index, request.result.moved));\n    };\n  });\n}\n\nexport function fetchAccount(id) {\n  return (dispatch, getState) => {\n    dispatch(fetchRelationships([id]));\n\n    if (getState().getIn(['accounts', id], null) !== null) {\n      return;\n    }\n\n    dispatch(fetchAccountRequest(id));\n\n    openDB().then(db => getFromDB(\n      dispatch,\n      getState,\n      db.transaction('accounts', 'read').objectStore('accounts').index('id'),\n      id\n    ).then(() => db.close(), error => {\n      db.close();\n      throw error;\n    })).catch(() => api(getState).get(`/api/v1/accounts/${id}`).then(response => {\n      dispatch(importFetchedAccount(response.data));\n    })).then(() => {\n      dispatch(fetchAccountSuccess());\n    }).catch(error => {\n      dispatch(fetchAccountFail(id, error));\n    });\n  };\n};\n\nexport function fetchAccountRequest(id) {\n  return {\n    type: ACCOUNT_FETCH_REQUEST,\n    id,\n  };\n};\n\nexport function fetchAccountSuccess() {\n  return {\n    type: ACCOUNT_FETCH_SUCCESS,\n  };\n};\n\nexport function fetchAccountFail(id, error) {\n  return {\n    type: ACCOUNT_FETCH_FAIL,\n    id,\n    error,\n    skipAlert: true,\n  };\n};\n\nexport function followAccount(id, reblogs = true) {\n  return (dispatch, getState) => {\n    const alreadyFollowing = getState().getIn(['relationships', id, 'following']);\n    const locked = getState().getIn(['accounts', id, 'locked'], false);\n\n    dispatch(followAccountRequest(id, locked));\n\n    api(getState).post(`/api/v1/accounts/${id}/follow`, { reblogs }).then(response => {\n      dispatch(followAccountSuccess(response.data, alreadyFollowing));\n    }).catch(error => {\n      dispatch(followAccountFail(error, locked));\n    });\n  };\n};\n\nexport function unfollowAccount(id) {\n  return (dispatch, getState) => {\n    dispatch(unfollowAccountRequest(id));\n\n    api(getState).post(`/api/v1/accounts/${id}/unfollow`).then(response => {\n      dispatch(unfollowAccountSuccess(response.data, getState().get('statuses')));\n    }).catch(error => {\n      dispatch(unfollowAccountFail(error));\n    });\n  };\n};\n\nexport function followAccountRequest(id, locked) {\n  return {\n    type: ACCOUNT_FOLLOW_REQUEST,\n    id,\n    locked,\n    skipLoading: true,\n  };\n};\n\nexport function followAccountSuccess(relationship, alreadyFollowing) {\n  return {\n    type: ACCOUNT_FOLLOW_SUCCESS,\n    relationship,\n    alreadyFollowing,\n    skipLoading: true,\n  };\n};\n\nexport function followAccountFail(error, locked) {\n  return {\n    type: ACCOUNT_FOLLOW_FAIL,\n    error,\n    locked,\n    skipLoading: true,\n  };\n};\n\nexport function unfollowAccountRequest(id) {\n  return {\n    type: ACCOUNT_UNFOLLOW_REQUEST,\n    id,\n    skipLoading: true,\n  };\n};\n\nexport function unfollowAccountSuccess(relationship, statuses) {\n  return {\n    type: ACCOUNT_UNFOLLOW_SUCCESS,\n    relationship,\n    statuses,\n    skipLoading: true,\n  };\n};\n\nexport function unfollowAccountFail(error) {\n  return {\n    type: ACCOUNT_UNFOLLOW_FAIL,\n    error,\n    skipLoading: true,\n  };\n};\n\nexport function blockAccount(id) {\n  return (dispatch, getState) => {\n    dispatch(blockAccountRequest(id));\n\n    api(getState).post(`/api/v1/accounts/${id}/block`).then(response => {\n      // Pass in entire statuses map so we can use it to filter stuff in different parts of the reducers\n      dispatch(blockAccountSuccess(response.data, getState().get('statuses')));\n    }).catch(error => {\n      dispatch(blockAccountFail(id, error));\n    });\n  };\n};\n\nexport function unblockAccount(id) {\n  return (dispatch, getState) => {\n    dispatch(unblockAccountRequest(id));\n\n    api(getState).post(`/api/v1/accounts/${id}/unblock`).then(response => {\n      dispatch(unblockAccountSuccess(response.data));\n    }).catch(error => {\n      dispatch(unblockAccountFail(id, error));\n    });\n  };\n};\n\nexport function blockAccountRequest(id) {\n  return {\n    type: ACCOUNT_BLOCK_REQUEST,\n    id,\n  };\n};\n\nexport function blockAccountSuccess(relationship, statuses) {\n  return {\n    type: ACCOUNT_BLOCK_SUCCESS,\n    relationship,\n    statuses,\n  };\n};\n\nexport function blockAccountFail(error) {\n  return {\n    type: ACCOUNT_BLOCK_FAIL,\n    error,\n  };\n};\n\nexport function unblockAccountRequest(id) {\n  return {\n    type: ACCOUNT_UNBLOCK_REQUEST,\n    id,\n  };\n};\n\nexport function unblockAccountSuccess(relationship) {\n  return {\n    type: ACCOUNT_UNBLOCK_SUCCESS,\n    relationship,\n  };\n};\n\nexport function unblockAccountFail(error) {\n  return {\n    type: ACCOUNT_UNBLOCK_FAIL,\n    error,\n  };\n};\n\n\nexport function muteAccount(id, notifications) {\n  return (dispatch, getState) => {\n    dispatch(muteAccountRequest(id));\n\n    api(getState).post(`/api/v1/accounts/${id}/mute`, { notifications }).then(response => {\n      // Pass in entire statuses map so we can use it to filter stuff in different parts of the reducers\n      dispatch(muteAccountSuccess(response.data, getState().get('statuses')));\n    }).catch(error => {\n      dispatch(muteAccountFail(id, error));\n    });\n  };\n};\n\nexport function unmuteAccount(id) {\n  return (dispatch, getState) => {\n    dispatch(unmuteAccountRequest(id));\n\n    api(getState).post(`/api/v1/accounts/${id}/unmute`).then(response => {\n      dispatch(unmuteAccountSuccess(response.data));\n    }).catch(error => {\n      dispatch(unmuteAccountFail(id, error));\n    });\n  };\n};\n\nexport function muteAccountRequest(id) {\n  return {\n    type: ACCOUNT_MUTE_REQUEST,\n    id,\n  };\n};\n\nexport function muteAccountSuccess(relationship, statuses) {\n  return {\n    type: ACCOUNT_MUTE_SUCCESS,\n    relationship,\n    statuses,\n  };\n};\n\nexport function muteAccountFail(error) {\n  return {\n    type: ACCOUNT_MUTE_FAIL,\n    error,\n  };\n};\n\nexport function unmuteAccountRequest(id) {\n  return {\n    type: ACCOUNT_UNMUTE_REQUEST,\n    id,\n  };\n};\n\nexport function unmuteAccountSuccess(relationship) {\n  return {\n    type: ACCOUNT_UNMUTE_SUCCESS,\n    relationship,\n  };\n};\n\nexport function unmuteAccountFail(error) {\n  return {\n    type: ACCOUNT_UNMUTE_FAIL,\n    error,\n  };\n};\n\n\nexport function fetchFollowers(id) {\n  return (dispatch, getState) => {\n    dispatch(fetchFollowersRequest(id));\n\n    api(getState).get(`/api/v1/accounts/${id}/followers`).then(response => {\n      const next = getLinks(response).refs.find(link => link.rel === 'next');\n\n      dispatch(importFetchedAccounts(response.data));\n      dispatch(fetchFollowersSuccess(id, response.data, next ? next.uri : null));\n      dispatch(fetchRelationships(response.data.map(item => item.id)));\n    }).catch(error => {\n      dispatch(fetchFollowersFail(id, error));\n    });\n  };\n};\n\nexport function fetchFollowersRequest(id) {\n  return {\n    type: FOLLOWERS_FETCH_REQUEST,\n    id,\n  };\n};\n\nexport function fetchFollowersSuccess(id, accounts, next) {\n  return {\n    type: FOLLOWERS_FETCH_SUCCESS,\n    id,\n    accounts,\n    next,\n  };\n};\n\nexport function fetchFollowersFail(id, error) {\n  return {\n    type: FOLLOWERS_FETCH_FAIL,\n    id,\n    error,\n  };\n};\n\nexport function expandFollowers(id) {\n  return (dispatch, getState) => {\n    const url = getState().getIn(['user_lists', 'followers', id, 'next']);\n\n    if (url === null) {\n      return;\n    }\n\n    dispatch(expandFollowersRequest(id));\n\n    api(getState).get(url).then(response => {\n      const next = getLinks(response).refs.find(link => link.rel === 'next');\n\n      dispatch(importFetchedAccounts(response.data));\n      dispatch(expandFollowersSuccess(id, response.data, next ? next.uri : null));\n      dispatch(fetchRelationships(response.data.map(item => item.id)));\n    }).catch(error => {\n      dispatch(expandFollowersFail(id, error));\n    });\n  };\n};\n\nexport function expandFollowersRequest(id) {\n  return {\n    type: FOLLOWERS_EXPAND_REQUEST,\n    id,\n  };\n};\n\nexport function expandFollowersSuccess(id, accounts, next) {\n  return {\n    type: FOLLOWERS_EXPAND_SUCCESS,\n    id,\n    accounts,\n    next,\n  };\n};\n\nexport function expandFollowersFail(id, error) {\n  return {\n    type: FOLLOWERS_EXPAND_FAIL,\n    id,\n    error,\n  };\n};\n\nexport function fetchFollowing(id) {\n  return (dispatch, getState) => {\n    dispatch(fetchFollowingRequest(id));\n\n    api(getState).get(`/api/v1/accounts/${id}/following`).then(response => {\n      const next = getLinks(response).refs.find(link => link.rel === 'next');\n\n      dispatch(importFetchedAccounts(response.data));\n      dispatch(fetchFollowingSuccess(id, response.data, next ? next.uri : null));\n      dispatch(fetchRelationships(response.data.map(item => item.id)));\n    }).catch(error => {\n      dispatch(fetchFollowingFail(id, error));\n    });\n  };\n};\n\nexport function fetchFollowingRequest(id) {\n  return {\n    type: FOLLOWING_FETCH_REQUEST,\n    id,\n  };\n};\n\nexport function fetchFollowingSuccess(id, accounts, next) {\n  return {\n    type: FOLLOWING_FETCH_SUCCESS,\n    id,\n    accounts,\n    next,\n  };\n};\n\nexport function fetchFollowingFail(id, error) {\n  return {\n    type: FOLLOWING_FETCH_FAIL,\n    id,\n    error,\n  };\n};\n\nexport function expandFollowing(id) {\n  return (dispatch, getState) => {\n    const url = getState().getIn(['user_lists', 'following', id, 'next']);\n\n    if (url === null) {\n      return;\n    }\n\n    dispatch(expandFollowingRequest(id));\n\n    api(getState).get(url).then(response => {\n      const next = getLinks(response).refs.find(link => link.rel === 'next');\n\n      dispatch(importFetchedAccounts(response.data));\n      dispatch(expandFollowingSuccess(id, response.data, next ? next.uri : null));\n      dispatch(fetchRelationships(response.data.map(item => item.id)));\n    }).catch(error => {\n      dispatch(expandFollowingFail(id, error));\n    });\n  };\n};\n\nexport function expandFollowingRequest(id) {\n  return {\n    type: FOLLOWING_EXPAND_REQUEST,\n    id,\n  };\n};\n\nexport function expandFollowingSuccess(id, accounts, next) {\n  return {\n    type: FOLLOWING_EXPAND_SUCCESS,\n    id,\n    accounts,\n    next,\n  };\n};\n\nexport function expandFollowingFail(id, error) {\n  return {\n    type: FOLLOWING_EXPAND_FAIL,\n    id,\n    error,\n  };\n};\n\nexport function fetchRelationships(accountIds) {\n  return (dispatch, getState) => {\n    const loadedRelationships = getState().get('relationships');\n    const newAccountIds = accountIds.filter(id => loadedRelationships.get(id, null) === null);\n\n    if (newAccountIds.length === 0) {\n      return;\n    }\n\n    dispatch(fetchRelationshipsRequest(newAccountIds));\n\n    api(getState).get(`/api/v1/accounts/relationships?${newAccountIds.map(id => `id[]=${id}`).join('&')}`).then(response => {\n      dispatch(fetchRelationshipsSuccess(response.data));\n    }).catch(error => {\n      dispatch(fetchRelationshipsFail(error));\n    });\n  };\n};\n\nexport function fetchRelationshipsRequest(ids) {\n  return {\n    type: RELATIONSHIPS_FETCH_REQUEST,\n    ids,\n    skipLoading: true,\n  };\n};\n\nexport function fetchRelationshipsSuccess(relationships) {\n  return {\n    type: RELATIONSHIPS_FETCH_SUCCESS,\n    relationships,\n    skipLoading: true,\n  };\n};\n\nexport function fetchRelationshipsFail(error) {\n  return {\n    type: RELATIONSHIPS_FETCH_FAIL,\n    error,\n    skipLoading: true,\n  };\n};\n\nexport function fetchFollowRequests() {\n  return (dispatch, getState) => {\n    dispatch(fetchFollowRequestsRequest());\n\n    api(getState).get('/api/v1/follow_requests').then(response => {\n      const next = getLinks(response).refs.find(link => link.rel === 'next');\n      dispatch(importFetchedAccounts(response.data));\n      dispatch(fetchFollowRequestsSuccess(response.data, next ? next.uri : null));\n    }).catch(error => dispatch(fetchFollowRequestsFail(error)));\n  };\n};\n\nexport function fetchFollowRequestsRequest() {\n  return {\n    type: FOLLOW_REQUESTS_FETCH_REQUEST,\n  };\n};\n\nexport function fetchFollowRequestsSuccess(accounts, next) {\n  return {\n    type: FOLLOW_REQUESTS_FETCH_SUCCESS,\n    accounts,\n    next,\n  };\n};\n\nexport function fetchFollowRequestsFail(error) {\n  return {\n    type: FOLLOW_REQUESTS_FETCH_FAIL,\n    error,\n  };\n};\n\nexport function expandFollowRequests() {\n  return (dispatch, getState) => {\n    const url = getState().getIn(['user_lists', 'follow_requests', 'next']);\n\n    if (url === null) {\n      return;\n    }\n\n    dispatch(expandFollowRequestsRequest());\n\n    api(getState).get(url).then(response => {\n      const next = getLinks(response).refs.find(link => link.rel === 'next');\n      dispatch(importFetchedAccounts(response.data));\n      dispatch(expandFollowRequestsSuccess(response.data, next ? next.uri : null));\n    }).catch(error => dispatch(expandFollowRequestsFail(error)));\n  };\n};\n\nexport function expandFollowRequestsRequest() {\n  return {\n    type: FOLLOW_REQUESTS_EXPAND_REQUEST,\n  };\n};\n\nexport function expandFollowRequestsSuccess(accounts, next) {\n  return {\n    type: FOLLOW_REQUESTS_EXPAND_SUCCESS,\n    accounts,\n    next,\n  };\n};\n\nexport function expandFollowRequestsFail(error) {\n  return {\n    type: FOLLOW_REQUESTS_EXPAND_FAIL,\n    error,\n  };\n};\n\nexport function authorizeFollowRequest(id) {\n  return (dispatch, getState) => {\n    dispatch(authorizeFollowRequestRequest(id));\n\n    api(getState)\n      .post(`/api/v1/follow_requests/${id}/authorize`)\n      .then(() => dispatch(authorizeFollowRequestSuccess(id)))\n      .catch(error => dispatch(authorizeFollowRequestFail(id, error)));\n  };\n};\n\nexport function authorizeFollowRequestRequest(id) {\n  return {\n    type: FOLLOW_REQUEST_AUTHORIZE_REQUEST,\n    id,\n  };\n};\n\nexport function authorizeFollowRequestSuccess(id) {\n  return {\n    type: FOLLOW_REQUEST_AUTHORIZE_SUCCESS,\n    id,\n  };\n};\n\nexport function authorizeFollowRequestFail(id, error) {\n  return {\n    type: FOLLOW_REQUEST_AUTHORIZE_FAIL,\n    id,\n    error,\n  };\n};\n\n\nexport function rejectFollowRequest(id) {\n  return (dispatch, getState) => {\n    dispatch(rejectFollowRequestRequest(id));\n\n    api(getState)\n      .post(`/api/v1/follow_requests/${id}/reject`)\n      .then(() => dispatch(rejectFollowRequestSuccess(id)))\n      .catch(error => dispatch(rejectFollowRequestFail(id, error)));\n  };\n};\n\nexport function rejectFollowRequestRequest(id) {\n  return {\n    type: FOLLOW_REQUEST_REJECT_REQUEST,\n    id,\n  };\n};\n\nexport function rejectFollowRequestSuccess(id) {\n  return {\n    type: FOLLOW_REQUEST_REJECT_SUCCESS,\n    id,\n  };\n};\n\nexport function rejectFollowRequestFail(id, error) {\n  return {\n    type: FOLLOW_REQUEST_REJECT_FAIL,\n    id,\n    error,\n  };\n};\n\nexport function pinAccount(id) {\n  return (dispatch, getState) => {\n    dispatch(pinAccountRequest(id));\n\n    api(getState).post(`/api/v1/accounts/${id}/pin`).then(response => {\n      dispatch(pinAccountSuccess(response.data));\n    }).catch(error => {\n      dispatch(pinAccountFail(error));\n    });\n  };\n};\n\nexport function unpinAccount(id) {\n  return (dispatch, getState) => {\n    dispatch(unpinAccountRequest(id));\n\n    api(getState).post(`/api/v1/accounts/${id}/unpin`).then(response => {\n      dispatch(unpinAccountSuccess(response.data));\n    }).catch(error => {\n      dispatch(unpinAccountFail(error));\n    });\n  };\n};\n\nexport function pinAccountRequest(id) {\n  return {\n    type: ACCOUNT_PIN_REQUEST,\n    id,\n  };\n};\n\nexport function pinAccountSuccess(relationship) {\n  return {\n    type: ACCOUNT_PIN_SUCCESS,\n    relationship,\n  };\n};\n\nexport function pinAccountFail(error) {\n  return {\n    type: ACCOUNT_PIN_FAIL,\n    error,\n  };\n};\n\nexport function unpinAccountRequest(id) {\n  return {\n    type: ACCOUNT_UNPIN_REQUEST,\n    id,\n  };\n};\n\nexport function unpinAccountSuccess(relationship) {\n  return {\n    type: ACCOUNT_UNPIN_SUCCESS,\n    relationship,\n  };\n};\n\nexport function unpinAccountFail(error) {\n  return {\n    type: ACCOUNT_UNPIN_FAIL,\n    error,\n  };\n};\n"
  },
  {
    "path": "app/javascript/mastodon/actions/alerts.js",
    "content": "import { defineMessages } from 'react-intl';\n\nconst messages = defineMessages({\n  unexpectedTitle: { id: 'alert.unexpected.title', defaultMessage: 'Oops!' },\n  unexpectedMessage: { id: 'alert.unexpected.message', defaultMessage: 'An unexpected error occurred.' },\n});\n\nexport const ALERT_SHOW    = 'ALERT_SHOW';\nexport const ALERT_DISMISS = 'ALERT_DISMISS';\nexport const ALERT_CLEAR   = 'ALERT_CLEAR';\nexport const ALERT_NOOP    = 'ALERT_NOOP';\n\nexport function dismissAlert(alert) {\n  return {\n    type: ALERT_DISMISS,\n    alert,\n  };\n};\n\nexport function clearAlert() {\n  return {\n    type: ALERT_CLEAR,\n  };\n};\n\nexport function showAlert(title = messages.unexpectedTitle, message = messages.unexpectedMessage) {\n  return {\n    type: ALERT_SHOW,\n    title,\n    message,\n  };\n};\n\nexport function showAlertForError(error) {\n  if (error.response) {\n    const { data, status, statusText } = error.response;\n\n    if (status === 404 || status === 410) {\n      // Skip these errors as they are reflected in the UI\n      return { type: ALERT_NOOP };\n    }\n\n    let message = statusText;\n    let title   = `${status}`;\n\n    if (data.error) {\n      message = data.error;\n    }\n\n    return showAlert(title, message);\n  } else {\n    console.error(error);\n    return showAlert();\n  }\n}\n"
  },
  {
    "path": "app/javascript/mastodon/actions/blocks.js",
    "content": "import api, { getLinks } from '../api';\nimport { fetchRelationships } from './accounts';\nimport { importFetchedAccounts } from './importer';\n\nexport const BLOCKS_FETCH_REQUEST = 'BLOCKS_FETCH_REQUEST';\nexport const BLOCKS_FETCH_SUCCESS = 'BLOCKS_FETCH_SUCCESS';\nexport const BLOCKS_FETCH_FAIL    = 'BLOCKS_FETCH_FAIL';\n\nexport const BLOCKS_EXPAND_REQUEST = 'BLOCKS_EXPAND_REQUEST';\nexport const BLOCKS_EXPAND_SUCCESS = 'BLOCKS_EXPAND_SUCCESS';\nexport const BLOCKS_EXPAND_FAIL    = 'BLOCKS_EXPAND_FAIL';\n\nexport function fetchBlocks() {\n  return (dispatch, getState) => {\n    dispatch(fetchBlocksRequest());\n\n    api(getState).get('/api/v1/blocks').then(response => {\n      const next = getLinks(response).refs.find(link => link.rel === 'next');\n      dispatch(importFetchedAccounts(response.data));\n      dispatch(fetchBlocksSuccess(response.data, next ? next.uri : null));\n      dispatch(fetchRelationships(response.data.map(item => item.id)));\n    }).catch(error => dispatch(fetchBlocksFail(error)));\n  };\n};\n\nexport function fetchBlocksRequest() {\n  return {\n    type: BLOCKS_FETCH_REQUEST,\n  };\n};\n\nexport function fetchBlocksSuccess(accounts, next) {\n  return {\n    type: BLOCKS_FETCH_SUCCESS,\n    accounts,\n    next,\n  };\n};\n\nexport function fetchBlocksFail(error) {\n  return {\n    type: BLOCKS_FETCH_FAIL,\n    error,\n  };\n};\n\nexport function expandBlocks() {\n  return (dispatch, getState) => {\n    const url = getState().getIn(['user_lists', 'blocks', 'next']);\n\n    if (url === null) {\n      return;\n    }\n\n    dispatch(expandBlocksRequest());\n\n    api(getState).get(url).then(response => {\n      const next = getLinks(response).refs.find(link => link.rel === 'next');\n      dispatch(importFetchedAccounts(response.data));\n      dispatch(expandBlocksSuccess(response.data, next ? next.uri : null));\n      dispatch(fetchRelationships(response.data.map(item => item.id)));\n    }).catch(error => dispatch(expandBlocksFail(error)));\n  };\n};\n\nexport function expandBlocksRequest() {\n  return {\n    type: BLOCKS_EXPAND_REQUEST,\n  };\n};\n\nexport function expandBlocksSuccess(accounts, next) {\n  return {\n    type: BLOCKS_EXPAND_SUCCESS,\n    accounts,\n    next,\n  };\n};\n\nexport function expandBlocksFail(error) {\n  return {\n    type: BLOCKS_EXPAND_FAIL,\n    error,\n  };\n};\n"
  },
  {
    "path": "app/javascript/mastodon/actions/bundles.js",
    "content": "export const BUNDLE_FETCH_REQUEST = 'BUNDLE_FETCH_REQUEST';\nexport const BUNDLE_FETCH_SUCCESS = 'BUNDLE_FETCH_SUCCESS';\nexport const BUNDLE_FETCH_FAIL = 'BUNDLE_FETCH_FAIL';\n\nexport function fetchBundleRequest(skipLoading) {\n  return {\n    type: BUNDLE_FETCH_REQUEST,\n    skipLoading,\n  };\n}\n\nexport function fetchBundleSuccess(skipLoading) {\n  return {\n    type: BUNDLE_FETCH_SUCCESS,\n    skipLoading,\n  };\n}\n\nexport function fetchBundleFail(error, skipLoading) {\n  return {\n    type: BUNDLE_FETCH_FAIL,\n    error,\n    skipLoading,\n  };\n}\n"
  },
  {
    "path": "app/javascript/mastodon/actions/columns.js",
    "content": "import { saveSettings } from './settings';\n\nexport const COLUMN_ADD           = 'COLUMN_ADD';\nexport const COLUMN_REMOVE        = 'COLUMN_REMOVE';\nexport const COLUMN_MOVE          = 'COLUMN_MOVE';\nexport const COLUMN_PARAMS_CHANGE = 'COLUMN_PARAMS_CHANGE';\n\nexport function addColumn(id, params) {\n  return dispatch => {\n    dispatch({\n      type: COLUMN_ADD,\n      id,\n      params,\n    });\n\n    dispatch(saveSettings());\n  };\n};\n\nexport function removeColumn(uuid) {\n  return dispatch => {\n    dispatch({\n      type: COLUMN_REMOVE,\n      uuid,\n    });\n\n    dispatch(saveSettings());\n  };\n};\n\nexport function moveColumn(uuid, direction) {\n  return dispatch => {\n    dispatch({\n      type: COLUMN_MOVE,\n      uuid,\n      direction,\n    });\n\n    dispatch(saveSettings());\n  };\n};\n\nexport function changeColumnParams(uuid, path, value) {\n  return dispatch => {\n    dispatch({\n      type: COLUMN_PARAMS_CHANGE,\n      uuid,\n      path,\n      value,\n    });\n\n    dispatch(saveSettings());\n  };\n}\n"
  },
  {
    "path": "app/javascript/mastodon/actions/compose.js",
    "content": "import api from '../api';\nimport { CancelToken, isCancel } from 'axios';\nimport { throttle } from 'lodash';\nimport { search as emojiSearch } from '../features/emoji/emoji_mart_search_light';\nimport { tagHistory } from '../settings';\nimport { useEmoji } from './emojis';\nimport resizeImage from '../utils/resize_image';\nimport { importFetchedAccounts } from './importer';\nimport { updateTimeline } from './timelines';\nimport { showAlertForError } from './alerts';\nimport { showAlert } from './alerts';\nimport { defineMessages } from 'react-intl';\n\nlet cancelFetchComposeSuggestionsAccounts;\n\nexport const COMPOSE_CHANGE          = 'COMPOSE_CHANGE';\nexport const COMPOSE_SUBMIT_REQUEST  = 'COMPOSE_SUBMIT_REQUEST';\nexport const COMPOSE_SUBMIT_SUCCESS  = 'COMPOSE_SUBMIT_SUCCESS';\nexport const COMPOSE_SUBMIT_FAIL     = 'COMPOSE_SUBMIT_FAIL';\nexport const COMPOSE_REPLY           = 'COMPOSE_REPLY';\nexport const COMPOSE_REPLY_CANCEL    = 'COMPOSE_REPLY_CANCEL';\nexport const COMPOSE_DIRECT          = 'COMPOSE_DIRECT';\nexport const COMPOSE_MENTION         = 'COMPOSE_MENTION';\nexport const COMPOSE_RESET           = 'COMPOSE_RESET';\nexport const COMPOSE_UPLOAD_REQUEST  = 'COMPOSE_UPLOAD_REQUEST';\nexport const COMPOSE_UPLOAD_SUCCESS  = 'COMPOSE_UPLOAD_SUCCESS';\nexport const COMPOSE_UPLOAD_FAIL     = 'COMPOSE_UPLOAD_FAIL';\nexport const COMPOSE_UPLOAD_PROGRESS = 'COMPOSE_UPLOAD_PROGRESS';\nexport const COMPOSE_UPLOAD_UNDO     = 'COMPOSE_UPLOAD_UNDO';\n\nexport const COMPOSE_SUGGESTIONS_CLEAR = 'COMPOSE_SUGGESTIONS_CLEAR';\nexport const COMPOSE_SUGGESTIONS_READY = 'COMPOSE_SUGGESTIONS_READY';\nexport const COMPOSE_SUGGESTION_SELECT = 'COMPOSE_SUGGESTION_SELECT';\nexport const COMPOSE_SUGGESTION_TAGS_UPDATE = 'COMPOSE_SUGGESTION_TAGS_UPDATE';\n\nexport const COMPOSE_TAG_HISTORY_UPDATE = 'COMPOSE_TAG_HISTORY_UPDATE';\n\nexport const COMPOSE_MOUNT   = 'COMPOSE_MOUNT';\nexport const COMPOSE_UNMOUNT = 'COMPOSE_UNMOUNT';\n\nexport const COMPOSE_SENSITIVITY_CHANGE = 'COMPOSE_SENSITIVITY_CHANGE';\nexport const COMPOSE_SPOILERNESS_CHANGE = 'COMPOSE_SPOILERNESS_CHANGE';\nexport const COMPOSE_SPOILER_TEXT_CHANGE = 'COMPOSE_SPOILER_TEXT_CHANGE';\nexport const COMPOSE_VISIBILITY_CHANGE  = 'COMPOSE_VISIBILITY_CHANGE';\nexport const COMPOSE_LISTABILITY_CHANGE = 'COMPOSE_LISTABILITY_CHANGE';\nexport const COMPOSE_COMPOSING_CHANGE = 'COMPOSE_COMPOSING_CHANGE';\n\nexport const COMPOSE_EMOJI_INSERT = 'COMPOSE_EMOJI_INSERT';\n\nexport const COMPOSE_UPLOAD_CHANGE_REQUEST     = 'COMPOSE_UPLOAD_UPDATE_REQUEST';\nexport const COMPOSE_UPLOAD_CHANGE_SUCCESS     = 'COMPOSE_UPLOAD_UPDATE_SUCCESS';\nexport const COMPOSE_UPLOAD_CHANGE_FAIL        = 'COMPOSE_UPLOAD_UPDATE_FAIL';\n\nexport const COMPOSE_POLL_ADD             = 'COMPOSE_POLL_ADD';\nexport const COMPOSE_POLL_REMOVE          = 'COMPOSE_POLL_REMOVE';\nexport const COMPOSE_POLL_OPTION_ADD      = 'COMPOSE_POLL_OPTION_ADD';\nexport const COMPOSE_POLL_OPTION_CHANGE   = 'COMPOSE_POLL_OPTION_CHANGE';\nexport const COMPOSE_POLL_OPTION_REMOVE   = 'COMPOSE_POLL_OPTION_REMOVE';\nexport const COMPOSE_POLL_SETTINGS_CHANGE = 'COMPOSE_POLL_SETTINGS_CHANGE';\n\nconst messages = defineMessages({\n  uploadErrorLimit: { id: 'upload_error.limit', defaultMessage: 'File upload limit exceeded.' },\n  uploadErrorPoll:  { id: 'upload_error.poll', defaultMessage: 'File upload not allowed with polls.' },\n});\n\nconst COMPOSE_PANEL_BREAKPOINT = 600 + (285 * 1) + (10 * 1);\n\nexport const ensureComposeIsVisible = (getState, routerHistory) => {\n  if (!getState().getIn(['compose', 'mounted']) && window.innerWidth < COMPOSE_PANEL_BREAKPOINT) {\n    routerHistory.push('/statuses/new');\n  }\n};\n\nexport function changeCompose(text) {\n  return {\n    type: COMPOSE_CHANGE,\n    text: text,\n  };\n};\n\nexport function replyCompose(status, routerHistory) {\n  return (dispatch, getState) => {\n    dispatch({\n      type: COMPOSE_REPLY,\n      status: status,\n    });\n\n    ensureComposeIsVisible(getState, routerHistory);\n  };\n};\n\nexport function cancelReplyCompose() {\n  return {\n    type: COMPOSE_REPLY_CANCEL,\n  };\n};\n\nexport function resetCompose() {\n  return {\n    type: COMPOSE_RESET,\n  };\n};\n\nexport function mentionCompose(account, routerHistory) {\n  return (dispatch, getState) => {\n    dispatch({\n      type: COMPOSE_MENTION,\n      account: account,\n    });\n\n    ensureComposeIsVisible(getState, routerHistory);\n  };\n};\n\nexport function directCompose(account, routerHistory) {\n  return (dispatch, getState) => {\n    dispatch({\n      type: COMPOSE_DIRECT,\n      account: account,\n    });\n\n    ensureComposeIsVisible(getState, routerHistory);\n  };\n};\n\nexport function submitCompose(routerHistory) {\n  return function (dispatch, getState) {\n    const status = getState().getIn(['compose', 'text'], '');\n    const media  = getState().getIn(['compose', 'media_attachments']);\n\n    if ((!status || !status.length) && media.size === 0) {\n      return;\n    }\n\n    dispatch(submitComposeRequest());\n\n    api(getState).post('/api/v1/statuses', {\n      status,\n      in_reply_to_id: getState().getIn(['compose', 'in_reply_to'], null),\n      media_ids: media.map(item => item.get('id')),\n      sensitive: getState().getIn(['compose', 'sensitive']),\n      spoiler_text: getState().getIn(['compose', 'spoiler_text'], ''),\n      visibility: getState().getIn(['compose', 'privacy']),\n      poll: getState().getIn(['compose', 'poll'], null),\n    }, {\n      headers: {\n        'Idempotency-Key': getState().getIn(['compose', 'idempotencyKey']),\n      },\n    }).then(function (response) {\n      if (response.data.visibility === 'direct' && getState().getIn(['conversations', 'mounted']) <= 0 && routerHistory) {\n        routerHistory.push('/timelines/direct');\n      } else if (routerHistory && routerHistory.location.pathname === '/statuses/new' && window.history.state) {\n        routerHistory.goBack();\n      }\n\n      dispatch(insertIntoTagHistory(response.data.tags, status));\n      dispatch(submitComposeSuccess({ ...response.data }));\n\n      // To make the app more responsive, immediately push the status\n      // into the columns\n\n      const insertIfOnline = timelineId => {\n        const timeline = getState().getIn(['timelines', timelineId]);\n\n        if (timeline && timeline.get('items').size > 0 && timeline.getIn(['items', 0]) !== null && timeline.get('online')) {\n          dispatch(updateTimeline(timelineId, { ...response.data }));\n        }\n      };\n\n      if (response.data.visibility !== 'direct') {\n        insertIfOnline('home');\n      }\n\n      if (response.data.in_reply_to_id === null && response.data.visibility === 'public') {\n        insertIfOnline('community');\n        insertIfOnline('public');\n      }\n    }).catch(function (error) {\n      dispatch(submitComposeFail(error));\n    });\n  };\n};\n\nexport function submitComposeRequest() {\n  return {\n    type: COMPOSE_SUBMIT_REQUEST,\n  };\n};\n\nexport function submitComposeSuccess(status) {\n  return {\n    type: COMPOSE_SUBMIT_SUCCESS,\n    status: status,\n  };\n};\n\nexport function submitComposeFail(error) {\n  return {\n    type: COMPOSE_SUBMIT_FAIL,\n    error: error,\n  };\n};\n\nexport function uploadCompose(files) {\n  return function (dispatch, getState) {\n    const uploadLimit = 4;\n    const media  = getState().getIn(['compose', 'media_attachments']);\n    const progress = new Array(files.length).fill(0);\n    let total = Array.from(files).reduce((a, v) => a + v.size, 0);\n\n    if (files.length + media.size > uploadLimit) {\n      dispatch(showAlert(undefined, messages.uploadErrorLimit));\n      return;\n    }\n\n    if (getState().getIn(['compose', 'poll'])) {\n      dispatch(showAlert(undefined, messages.uploadErrorPoll));\n      return;\n    }\n\n    dispatch(uploadComposeRequest());\n\n    for (const [i, f] of Array.from(files).entries()) {\n      if (media.size + i > 3) break;\n\n      resizeImage(f).then(file => {\n        const data = new FormData();\n        data.append('file', file);\n        // Account for disparity in size of original image and resized data\n        total += file.size - f.size;\n\n        return api(getState).post('/api/v1/media', data, {\n          onUploadProgress: function({ loaded }){\n            progress[i] = loaded;\n            dispatch(uploadComposeProgress(progress.reduce((a, v) => a + v, 0), total));\n          },\n        }).then(({ data }) => dispatch(uploadComposeSuccess(data)));\n      }).catch(error => dispatch(uploadComposeFail(error)));\n    };\n  };\n};\n\nexport function changeUploadCompose(id, params) {\n  return (dispatch, getState) => {\n    dispatch(changeUploadComposeRequest());\n\n    api(getState).put(`/api/v1/media/${id}`, params).then(response => {\n      dispatch(changeUploadComposeSuccess(response.data));\n    }).catch(error => {\n      dispatch(changeUploadComposeFail(id, error));\n    });\n  };\n};\n\nexport function changeUploadComposeRequest() {\n  return {\n    type: COMPOSE_UPLOAD_CHANGE_REQUEST,\n    skipLoading: true,\n  };\n};\nexport function changeUploadComposeSuccess(media) {\n  return {\n    type: COMPOSE_UPLOAD_CHANGE_SUCCESS,\n    media: media,\n    skipLoading: true,\n  };\n};\n\nexport function changeUploadComposeFail(error) {\n  return {\n    type: COMPOSE_UPLOAD_CHANGE_FAIL,\n    error: error,\n    skipLoading: true,\n  };\n};\n\nexport function uploadComposeRequest() {\n  return {\n    type: COMPOSE_UPLOAD_REQUEST,\n    skipLoading: true,\n  };\n};\n\nexport function uploadComposeProgress(loaded, total) {\n  return {\n    type: COMPOSE_UPLOAD_PROGRESS,\n    loaded: loaded,\n    total: total,\n  };\n};\n\nexport function uploadComposeSuccess(media) {\n  return {\n    type: COMPOSE_UPLOAD_SUCCESS,\n    media: media,\n    skipLoading: true,\n  };\n};\n\nexport function uploadComposeFail(error) {\n  return {\n    type: COMPOSE_UPLOAD_FAIL,\n    error: error,\n    skipLoading: true,\n  };\n};\n\nexport function undoUploadCompose(media_id) {\n  return {\n    type: COMPOSE_UPLOAD_UNDO,\n    media_id: media_id,\n  };\n};\n\nexport function clearComposeSuggestions() {\n  if (cancelFetchComposeSuggestionsAccounts) {\n    cancelFetchComposeSuggestionsAccounts();\n  }\n  return {\n    type: COMPOSE_SUGGESTIONS_CLEAR,\n  };\n};\n\nconst fetchComposeSuggestionsAccounts = throttle((dispatch, getState, token) => {\n  if (cancelFetchComposeSuggestionsAccounts) {\n    cancelFetchComposeSuggestionsAccounts();\n  }\n  api(getState).get('/api/v1/accounts/search', {\n    cancelToken: new CancelToken(cancel => {\n      cancelFetchComposeSuggestionsAccounts = cancel;\n    }),\n    params: {\n      q: token.slice(1),\n      resolve: false,\n      limit: 4,\n    },\n  }).then(response => {\n    dispatch(importFetchedAccounts(response.data));\n    dispatch(readyComposeSuggestionsAccounts(token, response.data));\n  }).catch(error => {\n    if (!isCancel(error)) {\n      dispatch(showAlertForError(error));\n    }\n  });\n}, 200, { leading: true, trailing: true });\n\nconst fetchComposeSuggestionsEmojis = (dispatch, getState, token) => {\n  const results = emojiSearch(token.replace(':', ''), { maxResults: 5 });\n  dispatch(readyComposeSuggestionsEmojis(token, results));\n};\n\nconst fetchComposeSuggestionsTags = (dispatch, getState, token) => {\n  dispatch(updateSuggestionTags(token));\n};\n\nexport function fetchComposeSuggestions(token) {\n  return (dispatch, getState) => {\n    switch (token[0]) {\n    case ':':\n      fetchComposeSuggestionsEmojis(dispatch, getState, token);\n      break;\n    case '#':\n      fetchComposeSuggestionsTags(dispatch, getState, token);\n      break;\n    default:\n      fetchComposeSuggestionsAccounts(dispatch, getState, token);\n      break;\n    }\n  };\n};\n\nexport function readyComposeSuggestionsEmojis(token, emojis) {\n  return {\n    type: COMPOSE_SUGGESTIONS_READY,\n    token,\n    emojis,\n  };\n};\n\nexport function readyComposeSuggestionsAccounts(token, accounts) {\n  return {\n    type: COMPOSE_SUGGESTIONS_READY,\n    token,\n    accounts,\n  };\n};\n\nexport function selectComposeSuggestion(position, token, suggestion, path) {\n  return (dispatch, getState) => {\n    let completion, startPosition;\n\n    if (typeof suggestion === 'object' && suggestion.id) {\n      completion    = suggestion.native || suggestion.colons;\n      startPosition = position - 1;\n\n      dispatch(useEmoji(suggestion));\n    } else if (suggestion[0] === '#') {\n      completion    = suggestion;\n      startPosition = position - 1;\n    } else {\n      completion    = getState().getIn(['accounts', suggestion, 'acct']);\n      startPosition = position;\n    }\n\n    dispatch({\n      type: COMPOSE_SUGGESTION_SELECT,\n      position: startPosition,\n      token,\n      completion,\n      path,\n    });\n  };\n};\n\nexport function updateSuggestionTags(token) {\n  return {\n    type: COMPOSE_SUGGESTION_TAGS_UPDATE,\n    token,\n  };\n}\n\nexport function updateTagHistory(tags) {\n  return {\n    type: COMPOSE_TAG_HISTORY_UPDATE,\n    tags,\n  };\n}\n\nexport function hydrateCompose() {\n  return (dispatch, getState) => {\n    const me = getState().getIn(['meta', 'me']);\n    const history = tagHistory.get(me);\n\n    if (history !== null) {\n      dispatch(updateTagHistory(history));\n    }\n  };\n}\n\nfunction insertIntoTagHistory(recognizedTags, text) {\n  return (dispatch, getState) => {\n    const state = getState();\n    const oldHistory = state.getIn(['compose', 'tagHistory']);\n    const me = state.getIn(['meta', 'me']);\n    const names = recognizedTags.map(tag => text.match(new RegExp(`#${tag.name}`, 'i'))[0].slice(1));\n    const intersectedOldHistory = oldHistory.filter(name => names.findIndex(newName => newName.toLowerCase() === name.toLowerCase()) === -1);\n\n    names.push(...intersectedOldHistory.toJS());\n\n    const newHistory = names.slice(0, 1000);\n\n    tagHistory.set(me, newHistory);\n    dispatch(updateTagHistory(newHistory));\n  };\n}\n\nexport function mountCompose() {\n  return {\n    type: COMPOSE_MOUNT,\n  };\n};\n\nexport function unmountCompose() {\n  return {\n    type: COMPOSE_UNMOUNT,\n  };\n};\n\nexport function changeComposeSensitivity() {\n  return {\n    type: COMPOSE_SENSITIVITY_CHANGE,\n  };\n};\n\nexport function changeComposeSpoilerness() {\n  return {\n    type: COMPOSE_SPOILERNESS_CHANGE,\n  };\n};\n\nexport function changeComposeSpoilerText(text) {\n  return {\n    type: COMPOSE_SPOILER_TEXT_CHANGE,\n    text,\n  };\n};\n\nexport function changeComposeVisibility(value) {\n  return {\n    type: COMPOSE_VISIBILITY_CHANGE,\n    value,\n  };\n};\n\nexport function insertEmojiCompose(position, emoji, needsSpace) {\n  return {\n    type: COMPOSE_EMOJI_INSERT,\n    position,\n    emoji,\n    needsSpace,\n  };\n};\n\nexport function changeComposing(value) {\n  return {\n    type: COMPOSE_COMPOSING_CHANGE,\n    value,\n  };\n};\n\nexport function addPoll() {\n  return {\n    type: COMPOSE_POLL_ADD,\n  };\n};\n\nexport function removePoll() {\n  return {\n    type: COMPOSE_POLL_REMOVE,\n  };\n};\n\nexport function addPollOption(title) {\n  return {\n    type: COMPOSE_POLL_OPTION_ADD,\n    title,\n  };\n};\n\nexport function changePollOption(index, title) {\n  return {\n    type: COMPOSE_POLL_OPTION_CHANGE,\n    index,\n    title,\n  };\n};\n\nexport function removePollOption(index) {\n  return {\n    type: COMPOSE_POLL_OPTION_REMOVE,\n    index,\n  };\n};\n\nexport function changePollSettings(expiresIn, isMultiple) {\n  return {\n    type: COMPOSE_POLL_SETTINGS_CHANGE,\n    expiresIn,\n    isMultiple,\n  };\n};\n"
  },
  {
    "path": "app/javascript/mastodon/actions/conversations.js",
    "content": "import api, { getLinks } from '../api';\nimport {\n  importFetchedAccounts,\n  importFetchedStatuses,\n  importFetchedStatus,\n} from './importer';\n\nexport const CONVERSATIONS_MOUNT   = 'CONVERSATIONS_MOUNT';\nexport const CONVERSATIONS_UNMOUNT = 'CONVERSATIONS_UNMOUNT';\n\nexport const CONVERSATIONS_FETCH_REQUEST = 'CONVERSATIONS_FETCH_REQUEST';\nexport const CONVERSATIONS_FETCH_SUCCESS = 'CONVERSATIONS_FETCH_SUCCESS';\nexport const CONVERSATIONS_FETCH_FAIL    = 'CONVERSATIONS_FETCH_FAIL';\nexport const CONVERSATIONS_UPDATE        = 'CONVERSATIONS_UPDATE';\n\nexport const CONVERSATIONS_READ = 'CONVERSATIONS_READ';\n\nexport const mountConversations = () => ({\n  type: CONVERSATIONS_MOUNT,\n});\n\nexport const unmountConversations = () => ({\n  type: CONVERSATIONS_UNMOUNT,\n});\n\nexport const markConversationRead = conversationId => (dispatch, getState) => {\n  dispatch({\n    type: CONVERSATIONS_READ,\n    id: conversationId,\n  });\n\n  api(getState).post(`/api/v1/conversations/${conversationId}/read`);\n};\n\nexport const expandConversations = ({ maxId } = {}) => (dispatch, getState) => {\n  dispatch(expandConversationsRequest());\n\n  const params = { max_id: maxId };\n\n  if (!maxId) {\n    params.since_id = getState().getIn(['conversations', 'items', 0, 'last_status']);\n  }\n\n  const isLoadingRecent = !!params.since_id;\n\n  api(getState).get('/api/v1/conversations', { params })\n    .then(response => {\n      const next = getLinks(response).refs.find(link => link.rel === 'next');\n\n      dispatch(importFetchedAccounts(response.data.reduce((aggr, item) => aggr.concat(item.accounts), [])));\n      dispatch(importFetchedStatuses(response.data.map(item => item.last_status).filter(x => !!x)));\n      dispatch(expandConversationsSuccess(response.data, next ? next.uri : null, isLoadingRecent));\n    })\n    .catch(err => dispatch(expandConversationsFail(err)));\n};\n\nexport const expandConversationsRequest = () => ({\n  type: CONVERSATIONS_FETCH_REQUEST,\n});\n\nexport const expandConversationsSuccess = (conversations, next, isLoadingRecent) => ({\n  type: CONVERSATIONS_FETCH_SUCCESS,\n  conversations,\n  next,\n  isLoadingRecent,\n});\n\nexport const expandConversationsFail = error => ({\n  type: CONVERSATIONS_FETCH_FAIL,\n  error,\n});\n\nexport const updateConversations = conversation => dispatch => {\n  dispatch(importFetchedAccounts(conversation.accounts));\n\n  if (conversation.last_status) {\n    dispatch(importFetchedStatus(conversation.last_status));\n  }\n\n  dispatch({\n    type: CONVERSATIONS_UPDATE,\n    conversation,\n  });\n};\n"
  },
  {
    "path": "app/javascript/mastodon/actions/custom_emojis.js",
    "content": "import api from '../api';\n\nexport const CUSTOM_EMOJIS_FETCH_REQUEST = 'CUSTOM_EMOJIS_FETCH_REQUEST';\nexport const CUSTOM_EMOJIS_FETCH_SUCCESS = 'CUSTOM_EMOJIS_FETCH_SUCCESS';\nexport const CUSTOM_EMOJIS_FETCH_FAIL = 'CUSTOM_EMOJIS_FETCH_FAIL';\n\nexport function fetchCustomEmojis() {\n  return (dispatch, getState) => {\n    dispatch(fetchCustomEmojisRequest());\n\n    api(getState).get('/api/v1/custom_emojis').then(response => {\n      dispatch(fetchCustomEmojisSuccess(response.data));\n    }).catch(error => {\n      dispatch(fetchCustomEmojisFail(error));\n    });\n  };\n};\n\nexport function fetchCustomEmojisRequest() {\n  return {\n    type: CUSTOM_EMOJIS_FETCH_REQUEST,\n    skipLoading: true,\n  };\n};\n\nexport function fetchCustomEmojisSuccess(custom_emojis) {\n  return {\n    type: CUSTOM_EMOJIS_FETCH_SUCCESS,\n    custom_emojis,\n    skipLoading: true,\n  };\n};\n\nexport function fetchCustomEmojisFail(error) {\n  return {\n    type: CUSTOM_EMOJIS_FETCH_FAIL,\n    error,\n    skipLoading: true,\n  };\n};\n"
  },
  {
    "path": "app/javascript/mastodon/actions/domain_blocks.js",
    "content": "import api, { getLinks } from '../api';\n\nexport const DOMAIN_BLOCK_REQUEST = 'DOMAIN_BLOCK_REQUEST';\nexport const DOMAIN_BLOCK_SUCCESS = 'DOMAIN_BLOCK_SUCCESS';\nexport const DOMAIN_BLOCK_FAIL    = 'DOMAIN_BLOCK_FAIL';\n\nexport const DOMAIN_UNBLOCK_REQUEST = 'DOMAIN_UNBLOCK_REQUEST';\nexport const DOMAIN_UNBLOCK_SUCCESS = 'DOMAIN_UNBLOCK_SUCCESS';\nexport const DOMAIN_UNBLOCK_FAIL    = 'DOMAIN_UNBLOCK_FAIL';\n\nexport const DOMAIN_BLOCKS_FETCH_REQUEST = 'DOMAIN_BLOCKS_FETCH_REQUEST';\nexport const DOMAIN_BLOCKS_FETCH_SUCCESS = 'DOMAIN_BLOCKS_FETCH_SUCCESS';\nexport const DOMAIN_BLOCKS_FETCH_FAIL    = 'DOMAIN_BLOCKS_FETCH_FAIL';\n\nexport const DOMAIN_BLOCKS_EXPAND_REQUEST = 'DOMAIN_BLOCKS_EXPAND_REQUEST';\nexport const DOMAIN_BLOCKS_EXPAND_SUCCESS = 'DOMAIN_BLOCKS_EXPAND_SUCCESS';\nexport const DOMAIN_BLOCKS_EXPAND_FAIL    = 'DOMAIN_BLOCKS_EXPAND_FAIL';\n\nexport function blockDomain(domain) {\n  return (dispatch, getState) => {\n    dispatch(blockDomainRequest(domain));\n\n    api(getState).post('/api/v1/domain_blocks', { domain }).then(() => {\n      const at_domain = '@' + domain;\n      const accounts = getState().get('accounts').filter(item => item.get('acct').endsWith(at_domain)).valueSeq().map(item => item.get('id'));\n      dispatch(blockDomainSuccess(domain, accounts));\n    }).catch(err => {\n      dispatch(blockDomainFail(domain, err));\n    });\n  };\n};\n\nexport function blockDomainRequest(domain) {\n  return {\n    type: DOMAIN_BLOCK_REQUEST,\n    domain,\n  };\n};\n\nexport function blockDomainSuccess(domain, accounts) {\n  return {\n    type: DOMAIN_BLOCK_SUCCESS,\n    domain,\n    accounts,\n  };\n};\n\nexport function blockDomainFail(domain, error) {\n  return {\n    type: DOMAIN_BLOCK_FAIL,\n    domain,\n    error,\n  };\n};\n\nexport function unblockDomain(domain) {\n  return (dispatch, getState) => {\n    dispatch(unblockDomainRequest(domain));\n\n    api(getState).delete('/api/v1/domain_blocks', { params: { domain } }).then(() => {\n      const at_domain = '@' + domain;\n      const accounts = getState().get('accounts').filter(item => item.get('acct').endsWith(at_domain)).valueSeq().map(item => item.get('id'));\n      dispatch(unblockDomainSuccess(domain, accounts));\n    }).catch(err => {\n      dispatch(unblockDomainFail(domain, err));\n    });\n  };\n};\n\nexport function unblockDomainRequest(domain) {\n  return {\n    type: DOMAIN_UNBLOCK_REQUEST,\n    domain,\n  };\n};\n\nexport function unblockDomainSuccess(domain, accounts) {\n  return {\n    type: DOMAIN_UNBLOCK_SUCCESS,\n    domain,\n    accounts,\n  };\n};\n\nexport function unblockDomainFail(domain, error) {\n  return {\n    type: DOMAIN_UNBLOCK_FAIL,\n    domain,\n    error,\n  };\n};\n\nexport function fetchDomainBlocks() {\n  return (dispatch, getState) => {\n    dispatch(fetchDomainBlocksRequest());\n\n    api(getState).get('/api/v1/domain_blocks').then(response => {\n      const next = getLinks(response).refs.find(link => link.rel === 'next');\n      dispatch(fetchDomainBlocksSuccess(response.data, next ? next.uri : null));\n    }).catch(err => {\n      dispatch(fetchDomainBlocksFail(err));\n    });\n  };\n};\n\nexport function fetchDomainBlocksRequest() {\n  return {\n    type: DOMAIN_BLOCKS_FETCH_REQUEST,\n  };\n};\n\nexport function fetchDomainBlocksSuccess(domains, next) {\n  return {\n    type: DOMAIN_BLOCKS_FETCH_SUCCESS,\n    domains,\n    next,\n  };\n};\n\nexport function fetchDomainBlocksFail(error) {\n  return {\n    type: DOMAIN_BLOCKS_FETCH_FAIL,\n    error,\n  };\n};\n\nexport function expandDomainBlocks() {\n  return (dispatch, getState) => {\n    const url = getState().getIn(['domain_lists', 'blocks', 'next']);\n\n    if (!url) {\n      return;\n    }\n\n    dispatch(expandDomainBlocksRequest());\n\n    api(getState).get(url).then(response => {\n      const next = getLinks(response).refs.find(link => link.rel === 'next');\n      dispatch(expandDomainBlocksSuccess(response.data, next ? next.uri : null));\n    }).catch(err => {\n      dispatch(expandDomainBlocksFail(err));\n    });\n  };\n};\n\nexport function expandDomainBlocksRequest() {\n  return {\n    type: DOMAIN_BLOCKS_EXPAND_REQUEST,\n  };\n};\n\nexport function expandDomainBlocksSuccess(domains, next) {\n  return {\n    type: DOMAIN_BLOCKS_EXPAND_SUCCESS,\n    domains,\n    next,\n  };\n};\n\nexport function expandDomainBlocksFail(error) {\n  return {\n    type: DOMAIN_BLOCKS_EXPAND_FAIL,\n    error,\n  };\n};\n"
  },
  {
    "path": "app/javascript/mastodon/actions/dropdown_menu.js",
    "content": "export const DROPDOWN_MENU_OPEN = 'DROPDOWN_MENU_OPEN';\nexport const DROPDOWN_MENU_CLOSE = 'DROPDOWN_MENU_CLOSE';\n\nexport function openDropdownMenu(id, placement, keyboard) {\n  return { type: DROPDOWN_MENU_OPEN, id, placement, keyboard };\n}\n\nexport function closeDropdownMenu(id) {\n  return { type: DROPDOWN_MENU_CLOSE, id };\n}\n"
  },
  {
    "path": "app/javascript/mastodon/actions/emojis.js",
    "content": "import { saveSettings } from './settings';\n\nexport const EMOJI_USE = 'EMOJI_USE';\n\nexport function useEmoji(emoji) {\n  return dispatch => {\n    dispatch({\n      type: EMOJI_USE,\n      emoji,\n    });\n\n    dispatch(saveSettings());\n  };\n};\n"
  },
  {
    "path": "app/javascript/mastodon/actions/favourites.js",
    "content": "import api, { getLinks } from '../api';\nimport { importFetchedStatuses } from './importer';\n\nexport const FAVOURITED_STATUSES_FETCH_REQUEST = 'FAVOURITED_STATUSES_FETCH_REQUEST';\nexport const FAVOURITED_STATUSES_FETCH_SUCCESS = 'FAVOURITED_STATUSES_FETCH_SUCCESS';\nexport const FAVOURITED_STATUSES_FETCH_FAIL    = 'FAVOURITED_STATUSES_FETCH_FAIL';\n\nexport const FAVOURITED_STATUSES_EXPAND_REQUEST = 'FAVOURITED_STATUSES_EXPAND_REQUEST';\nexport const FAVOURITED_STATUSES_EXPAND_SUCCESS = 'FAVOURITED_STATUSES_EXPAND_SUCCESS';\nexport const FAVOURITED_STATUSES_EXPAND_FAIL    = 'FAVOURITED_STATUSES_EXPAND_FAIL';\n\nexport function fetchFavouritedStatuses() {\n  return (dispatch, getState) => {\n    if (getState().getIn(['status_lists', 'favourites', 'isLoading'])) {\n      return;\n    }\n\n    dispatch(fetchFavouritedStatusesRequest());\n\n    api(getState).get('/api/v1/favourites').then(response => {\n      const next = getLinks(response).refs.find(link => link.rel === 'next');\n      dispatch(importFetchedStatuses(response.data));\n      dispatch(fetchFavouritedStatusesSuccess(response.data, next ? next.uri : null));\n    }).catch(error => {\n      dispatch(fetchFavouritedStatusesFail(error));\n    });\n  };\n};\n\nexport function fetchFavouritedStatusesRequest() {\n  return {\n    type: FAVOURITED_STATUSES_FETCH_REQUEST,\n    skipLoading: true,\n  };\n};\n\nexport function fetchFavouritedStatusesSuccess(statuses, next) {\n  return {\n    type: FAVOURITED_STATUSES_FETCH_SUCCESS,\n    statuses,\n    next,\n    skipLoading: true,\n  };\n};\n\nexport function fetchFavouritedStatusesFail(error) {\n  return {\n    type: FAVOURITED_STATUSES_FETCH_FAIL,\n    error,\n    skipLoading: true,\n  };\n};\n\nexport function expandFavouritedStatuses() {\n  return (dispatch, getState) => {\n    const url = getState().getIn(['status_lists', 'favourites', 'next'], null);\n\n    if (url === null || getState().getIn(['status_lists', 'favourites', 'isLoading'])) {\n      return;\n    }\n\n    dispatch(expandFavouritedStatusesRequest());\n\n    api(getState).get(url).then(response => {\n      const next = getLinks(response).refs.find(link => link.rel === 'next');\n      dispatch(importFetchedStatuses(response.data));\n      dispatch(expandFavouritedStatusesSuccess(response.data, next ? next.uri : null));\n    }).catch(error => {\n      dispatch(expandFavouritedStatusesFail(error));\n    });\n  };\n};\n\nexport function expandFavouritedStatusesRequest() {\n  return {\n    type: FAVOURITED_STATUSES_EXPAND_REQUEST,\n  };\n};\n\nexport function expandFavouritedStatusesSuccess(statuses, next) {\n  return {\n    type: FAVOURITED_STATUSES_EXPAND_SUCCESS,\n    statuses,\n    next,\n  };\n};\n\nexport function expandFavouritedStatusesFail(error) {\n  return {\n    type: FAVOURITED_STATUSES_EXPAND_FAIL,\n    error,\n  };\n};\n"
  },
  {
    "path": "app/javascript/mastodon/actions/filters.js",
    "content": "import api from '../api';\n\nexport const FILTERS_FETCH_REQUEST = 'FILTERS_FETCH_REQUEST';\nexport const FILTERS_FETCH_SUCCESS = 'FILTERS_FETCH_SUCCESS';\nexport const FILTERS_FETCH_FAIL    = 'FILTERS_FETCH_FAIL';\n\nexport const fetchFilters = () => (dispatch, getState) => {\n  dispatch({\n    type: FILTERS_FETCH_REQUEST,\n    skipLoading: true,\n  });\n\n  api(getState)\n    .get('/api/v1/filters')\n    .then(({ data }) => dispatch({\n      type: FILTERS_FETCH_SUCCESS,\n      filters: data,\n      skipLoading: true,\n    }))\n    .catch(err => dispatch({\n      type: FILTERS_FETCH_FAIL,\n      err,\n      skipLoading: true,\n      skipAlert: true,\n    }));\n};\n"
  },
  {
    "path": "app/javascript/mastodon/actions/height_cache.js",
    "content": "export const HEIGHT_CACHE_SET = 'HEIGHT_CACHE_SET';\nexport const HEIGHT_CACHE_CLEAR = 'HEIGHT_CACHE_CLEAR';\n\nexport function setHeight (key, id, height) {\n  return {\n    type: HEIGHT_CACHE_SET,\n    key,\n    id,\n    height,\n  };\n};\n\nexport function clearHeight () {\n  return {\n    type: HEIGHT_CACHE_CLEAR,\n  };\n};\n"
  },
  {
    "path": "app/javascript/mastodon/actions/identity_proofs.js",
    "content": "import api from '../api';\n\nexport const IDENTITY_PROOFS_ACCOUNT_FETCH_REQUEST = 'IDENTITY_PROOFS_ACCOUNT_FETCH_REQUEST';\nexport const IDENTITY_PROOFS_ACCOUNT_FETCH_SUCCESS = 'IDENTITY_PROOFS_ACCOUNT_FETCH_SUCCESS';\nexport const IDENTITY_PROOFS_ACCOUNT_FETCH_FAIL    = 'IDENTITY_PROOFS_ACCOUNT_FETCH_FAIL';\n\nexport const fetchAccountIdentityProofs = accountId => (dispatch, getState) => {\n  dispatch(fetchAccountIdentityProofsRequest(accountId));\n\n  api(getState).get(`/api/v1/accounts/${accountId}/identity_proofs`)\n    .then(({ data }) => dispatch(fetchAccountIdentityProofsSuccess(accountId, data)))\n    .catch(err => dispatch(fetchAccountIdentityProofsFail(accountId, err)));\n};\n\nexport const fetchAccountIdentityProofsRequest = id => ({\n  type: IDENTITY_PROOFS_ACCOUNT_FETCH_REQUEST,\n  id,\n});\n\nexport const fetchAccountIdentityProofsSuccess = (accountId, identity_proofs) => ({\n  type: IDENTITY_PROOFS_ACCOUNT_FETCH_SUCCESS,\n  accountId,\n  identity_proofs,\n});\n\nexport const fetchAccountIdentityProofsFail = (accountId, err) => ({\n  type: IDENTITY_PROOFS_ACCOUNT_FETCH_FAIL,\n  accountId,\n  err,\n});\n"
  },
  {
    "path": "app/javascript/mastodon/actions/importer/index.js",
    "content": "import { normalizeAccount, normalizeStatus, normalizePoll } from './normalizer';\n\nexport const ACCOUNT_IMPORT  = 'ACCOUNT_IMPORT';\nexport const ACCOUNTS_IMPORT = 'ACCOUNTS_IMPORT';\nexport const STATUS_IMPORT   = 'STATUS_IMPORT';\nexport const STATUSES_IMPORT = 'STATUSES_IMPORT';\nexport const POLLS_IMPORT    = 'POLLS_IMPORT';\n\nfunction pushUnique(array, object) {\n  if (array.every(element => element.id !== object.id)) {\n    array.push(object);\n  }\n}\n\nexport function importAccount(account) {\n  return { type: ACCOUNT_IMPORT, account };\n}\n\nexport function importAccounts(accounts) {\n  return { type: ACCOUNTS_IMPORT, accounts };\n}\n\nexport function importStatus(status) {\n  return { type: STATUS_IMPORT, status };\n}\n\nexport function importStatuses(statuses) {\n  return { type: STATUSES_IMPORT, statuses };\n}\n\nexport function importPolls(polls) {\n  return { type: POLLS_IMPORT, polls };\n}\n\nexport function importFetchedAccount(account) {\n  return importFetchedAccounts([account]);\n}\n\nexport function importFetchedAccounts(accounts) {\n  const normalAccounts = [];\n\n  function processAccount(account) {\n    pushUnique(normalAccounts, normalizeAccount(account));\n\n    if (account.moved) {\n      processAccount(account.moved);\n    }\n  }\n\n  accounts.forEach(processAccount);\n\n  return importAccounts(normalAccounts);\n}\n\nexport function importFetchedStatus(status) {\n  return importFetchedStatuses([status]);\n}\n\nexport function importFetchedStatuses(statuses) {\n  return (dispatch, getState) => {\n    const accounts = [];\n    const normalStatuses = [];\n    const polls = [];\n\n    function processStatus(status) {\n      pushUnique(normalStatuses, normalizeStatus(status, getState().getIn(['statuses', status.id])));\n      pushUnique(accounts, status.account);\n\n      if (status.reblog && status.reblog.id) {\n        processStatus(status.reblog);\n      }\n\n      if (status.poll && status.poll.id) {\n        pushUnique(polls, normalizePoll(status.poll));\n      }\n    }\n\n    statuses.forEach(processStatus);\n\n    dispatch(importPolls(polls));\n    dispatch(importFetchedAccounts(accounts));\n    dispatch(importStatuses(normalStatuses));\n  };\n}\n\nexport function importFetchedPoll(poll) {\n  return dispatch => {\n    dispatch(importPolls([normalizePoll(poll)]));\n  };\n}\n"
  },
  {
    "path": "app/javascript/mastodon/actions/importer/normalizer.js",
    "content": "import escapeTextContentForBrowser from 'escape-html';\nimport emojify from '../../features/emoji/emoji';\nimport { unescapeHTML } from '../../utils/html';\nimport { expandSpoilers } from '../../initial_state';\n\nconst domParser = new DOMParser();\n\nconst makeEmojiMap = record => record.emojis.reduce((obj, emoji) => {\n  obj[`:${emoji.shortcode}:`] = emoji;\n  return obj;\n}, {});\n\nexport function normalizeAccount(account) {\n  account = { ...account };\n\n  const emojiMap = makeEmojiMap(account);\n  const displayName = account.display_name.trim().length === 0 ? account.username : account.display_name;\n\n  account.display_name_html = emojify(escapeTextContentForBrowser(displayName), emojiMap);\n  account.note_emojified = emojify(account.note, emojiMap);\n\n  if (account.fields) {\n    account.fields = account.fields.map(pair => ({\n      ...pair,\n      name_emojified: emojify(escapeTextContentForBrowser(pair.name)),\n      value_emojified: emojify(pair.value, emojiMap),\n      value_plain: unescapeHTML(pair.value),\n    }));\n  }\n\n  if (account.moved) {\n    account.moved = account.moved.id;\n  }\n\n  return account;\n}\n\nexport function normalizeStatus(status, normalOldStatus) {\n  const normalStatus   = { ...status };\n  normalStatus.account = status.account.id;\n\n  if (status.reblog && status.reblog.id) {\n    normalStatus.reblog = status.reblog.id;\n  }\n\n  if (status.poll && status.poll.id) {\n    normalStatus.poll = status.poll.id;\n  }\n\n  // Only calculate these values when status first encountered\n  // Otherwise keep the ones already in the reducer\n  if (normalOldStatus) {\n    normalStatus.search_index = normalOldStatus.get('search_index');\n    normalStatus.contentHtml = normalOldStatus.get('contentHtml');\n    normalStatus.spoilerHtml = normalOldStatus.get('spoilerHtml');\n    normalStatus.hidden = normalOldStatus.get('hidden');\n  } else {\n    const spoilerText   = normalStatus.spoiler_text || '';\n    const searchContent = [spoilerText, status.content].join('\\n\\n').replace(/<br\\s*\\/?>/g, '\\n').replace(/<\\/p><p>/g, '\\n\\n');\n    const emojiMap      = makeEmojiMap(normalStatus);\n\n    normalStatus.search_index = domParser.parseFromString(searchContent, 'text/html').documentElement.textContent;\n    normalStatus.contentHtml  = emojify(normalStatus.content, emojiMap);\n    normalStatus.spoilerHtml  = emojify(escapeTextContentForBrowser(spoilerText), emojiMap);\n    normalStatus.hidden       = expandSpoilers ? false : spoilerText.length > 0 || normalStatus.sensitive;\n  }\n\n  return normalStatus;\n}\n\nexport function normalizePoll(poll) {\n  const normalPoll = { ...poll };\n\n  const emojiMap = makeEmojiMap(normalPoll);\n\n  normalPoll.options = poll.options.map(option => ({\n    ...option,\n    title_emojified: emojify(escapeTextContentForBrowser(option.title), emojiMap),\n  }));\n\n  return normalPoll;\n}\n"
  },
  {
    "path": "app/javascript/mastodon/actions/interactions.js",
    "content": "import api from '../api';\nimport { importFetchedAccounts, importFetchedStatus } from './importer';\n\nexport const REBLOG_REQUEST = 'REBLOG_REQUEST';\nexport const REBLOG_SUCCESS = 'REBLOG_SUCCESS';\nexport const REBLOG_FAIL    = 'REBLOG_FAIL';\n\nexport const FAVOURITE_REQUEST = 'FAVOURITE_REQUEST';\nexport const FAVOURITE_SUCCESS = 'FAVOURITE_SUCCESS';\nexport const FAVOURITE_FAIL    = 'FAVOURITE_FAIL';\n\nexport const UNREBLOG_REQUEST = 'UNREBLOG_REQUEST';\nexport const UNREBLOG_SUCCESS = 'UNREBLOG_SUCCESS';\nexport const UNREBLOG_FAIL    = 'UNREBLOG_FAIL';\n\nexport const UNFAVOURITE_REQUEST = 'UNFAVOURITE_REQUEST';\nexport const UNFAVOURITE_SUCCESS = 'UNFAVOURITE_SUCCESS';\nexport const UNFAVOURITE_FAIL    = 'UNFAVOURITE_FAIL';\n\nexport const REBLOGS_FETCH_REQUEST = 'REBLOGS_FETCH_REQUEST';\nexport const REBLOGS_FETCH_SUCCESS = 'REBLOGS_FETCH_SUCCESS';\nexport const REBLOGS_FETCH_FAIL    = 'REBLOGS_FETCH_FAIL';\n\nexport const FAVOURITES_FETCH_REQUEST = 'FAVOURITES_FETCH_REQUEST';\nexport const FAVOURITES_FETCH_SUCCESS = 'FAVOURITES_FETCH_SUCCESS';\nexport const FAVOURITES_FETCH_FAIL    = 'FAVOURITES_FETCH_FAIL';\n\nexport const PIN_REQUEST = 'PIN_REQUEST';\nexport const PIN_SUCCESS = 'PIN_SUCCESS';\nexport const PIN_FAIL    = 'PIN_FAIL';\n\nexport const UNPIN_REQUEST = 'UNPIN_REQUEST';\nexport const UNPIN_SUCCESS = 'UNPIN_SUCCESS';\nexport const UNPIN_FAIL    = 'UNPIN_FAIL';\n\nexport function reblog(status) {\n  return function (dispatch, getState) {\n    dispatch(reblogRequest(status));\n\n    api(getState).post(`/api/v1/statuses/${status.get('id')}/reblog`).then(function (response) {\n      // The reblog API method returns a new status wrapped around the original. In this case we are only\n      // interested in how the original is modified, hence passing it skipping the wrapper\n      dispatch(importFetchedStatus(response.data.reblog));\n      dispatch(reblogSuccess(status));\n    }).catch(function (error) {\n      dispatch(reblogFail(status, error));\n    });\n  };\n};\n\nexport function unreblog(status) {\n  return (dispatch, getState) => {\n    dispatch(unreblogRequest(status));\n\n    api(getState).post(`/api/v1/statuses/${status.get('id')}/unreblog`).then(response => {\n      dispatch(importFetchedStatus(response.data));\n      dispatch(unreblogSuccess(status));\n    }).catch(error => {\n      dispatch(unreblogFail(status, error));\n    });\n  };\n};\n\nexport function reblogRequest(status) {\n  return {\n    type: REBLOG_REQUEST,\n    status: status,\n    skipLoading: true,\n  };\n};\n\nexport function reblogSuccess(status) {\n  return {\n    type: REBLOG_SUCCESS,\n    status: status,\n    skipLoading: true,\n  };\n};\n\nexport function reblogFail(status, error) {\n  return {\n    type: REBLOG_FAIL,\n    status: status,\n    error: error,\n    skipLoading: true,\n  };\n};\n\nexport function unreblogRequest(status) {\n  return {\n    type: UNREBLOG_REQUEST,\n    status: status,\n    skipLoading: true,\n  };\n};\n\nexport function unreblogSuccess(status) {\n  return {\n    type: UNREBLOG_SUCCESS,\n    status: status,\n    skipLoading: true,\n  };\n};\n\nexport function unreblogFail(status, error) {\n  return {\n    type: UNREBLOG_FAIL,\n    status: status,\n    error: error,\n    skipLoading: true,\n  };\n};\n\nexport function favourite(status) {\n  return function (dispatch, getState) {\n    dispatch(favouriteRequest(status));\n\n    api(getState).post(`/api/v1/statuses/${status.get('id')}/favourite`).then(function (response) {\n      dispatch(importFetchedStatus(response.data));\n      dispatch(favouriteSuccess(status));\n    }).catch(function (error) {\n      dispatch(favouriteFail(status, error));\n    });\n  };\n};\n\nexport function unfavourite(status) {\n  return (dispatch, getState) => {\n    dispatch(unfavouriteRequest(status));\n\n    api(getState).post(`/api/v1/statuses/${status.get('id')}/unfavourite`).then(response => {\n      dispatch(importFetchedStatus(response.data));\n      dispatch(unfavouriteSuccess(status));\n    }).catch(error => {\n      dispatch(unfavouriteFail(status, error));\n    });\n  };\n};\n\nexport function favouriteRequest(status) {\n  return {\n    type: FAVOURITE_REQUEST,\n    status: status,\n    skipLoading: true,\n  };\n};\n\nexport function favouriteSuccess(status) {\n  return {\n    type: FAVOURITE_SUCCESS,\n    status: status,\n    skipLoading: true,\n  };\n};\n\nexport function favouriteFail(status, error) {\n  return {\n    type: FAVOURITE_FAIL,\n    status: status,\n    error: error,\n    skipLoading: true,\n  };\n};\n\nexport function unfavouriteRequest(status) {\n  return {\n    type: UNFAVOURITE_REQUEST,\n    status: status,\n    skipLoading: true,\n  };\n};\n\nexport function unfavouriteSuccess(status) {\n  return {\n    type: UNFAVOURITE_SUCCESS,\n    status: status,\n    skipLoading: true,\n  };\n};\n\nexport function unfavouriteFail(status, error) {\n  return {\n    type: UNFAVOURITE_FAIL,\n    status: status,\n    error: error,\n    skipLoading: true,\n  };\n};\n\nexport function fetchReblogs(id) {\n  return (dispatch, getState) => {\n    dispatch(fetchReblogsRequest(id));\n\n    api(getState).get(`/api/v1/statuses/${id}/reblogged_by`).then(response => {\n      dispatch(importFetchedAccounts(response.data));\n      dispatch(fetchReblogsSuccess(id, response.data));\n    }).catch(error => {\n      dispatch(fetchReblogsFail(id, error));\n    });\n  };\n};\n\nexport function fetchReblogsRequest(id) {\n  return {\n    type: REBLOGS_FETCH_REQUEST,\n    id,\n  };\n};\n\nexport function fetchReblogsSuccess(id, accounts) {\n  return {\n    type: REBLOGS_FETCH_SUCCESS,\n    id,\n    accounts,\n  };\n};\n\nexport function fetchReblogsFail(id, error) {\n  return {\n    type: REBLOGS_FETCH_FAIL,\n    error,\n  };\n};\n\nexport function fetchFavourites(id) {\n  return (dispatch, getState) => {\n    dispatch(fetchFavouritesRequest(id));\n\n    api(getState).get(`/api/v1/statuses/${id}/favourited_by`).then(response => {\n      dispatch(importFetchedAccounts(response.data));\n      dispatch(fetchFavouritesSuccess(id, response.data));\n    }).catch(error => {\n      dispatch(fetchFavouritesFail(id, error));\n    });\n  };\n};\n\nexport function fetchFavouritesRequest(id) {\n  return {\n    type: FAVOURITES_FETCH_REQUEST,\n    id,\n  };\n};\n\nexport function fetchFavouritesSuccess(id, accounts) {\n  return {\n    type: FAVOURITES_FETCH_SUCCESS,\n    id,\n    accounts,\n  };\n};\n\nexport function fetchFavouritesFail(id, error) {\n  return {\n    type: FAVOURITES_FETCH_FAIL,\n    error,\n  };\n};\n\nexport function pin(status) {\n  return (dispatch, getState) => {\n    dispatch(pinRequest(status));\n\n    api(getState).post(`/api/v1/statuses/${status.get('id')}/pin`).then(response => {\n      dispatch(importFetchedStatus(response.data));\n      dispatch(pinSuccess(status));\n    }).catch(error => {\n      dispatch(pinFail(status, error));\n    });\n  };\n};\n\nexport function pinRequest(status) {\n  return {\n    type: PIN_REQUEST,\n    status,\n    skipLoading: true,\n  };\n};\n\nexport function pinSuccess(status) {\n  return {\n    type: PIN_SUCCESS,\n    status,\n    skipLoading: true,\n  };\n};\n\nexport function pinFail(status, error) {\n  return {\n    type: PIN_FAIL,\n    status,\n    error,\n    skipLoading: true,\n  };\n};\n\nexport function unpin (status) {\n  return (dispatch, getState) => {\n    dispatch(unpinRequest(status));\n\n    api(getState).post(`/api/v1/statuses/${status.get('id')}/unpin`).then(response => {\n      dispatch(importFetchedStatus(response.data));\n      dispatch(unpinSuccess(status));\n    }).catch(error => {\n      dispatch(unpinFail(status, error));\n    });\n  };\n};\n\nexport function unpinRequest(status) {\n  return {\n    type: UNPIN_REQUEST,\n    status,\n    skipLoading: true,\n  };\n};\n\nexport function unpinSuccess(status) {\n  return {\n    type: UNPIN_SUCCESS,\n    status,\n    skipLoading: true,\n  };\n};\n\nexport function unpinFail(status, error) {\n  return {\n    type: UNPIN_FAIL,\n    status,\n    error,\n    skipLoading: true,\n  };\n};\n"
  },
  {
    "path": "app/javascript/mastodon/actions/lists.js",
    "content": "import api from '../api';\nimport { importFetchedAccounts } from './importer';\nimport { showAlertForError } from './alerts';\n\nexport const LIST_FETCH_REQUEST = 'LIST_FETCH_REQUEST';\nexport const LIST_FETCH_SUCCESS = 'LIST_FETCH_SUCCESS';\nexport const LIST_FETCH_FAIL    = 'LIST_FETCH_FAIL';\n\nexport const LISTS_FETCH_REQUEST = 'LISTS_FETCH_REQUEST';\nexport const LISTS_FETCH_SUCCESS = 'LISTS_FETCH_SUCCESS';\nexport const LISTS_FETCH_FAIL    = 'LISTS_FETCH_FAIL';\n\nexport const LIST_EDITOR_TITLE_CHANGE = 'LIST_EDITOR_TITLE_CHANGE';\nexport const LIST_EDITOR_RESET        = 'LIST_EDITOR_RESET';\nexport const LIST_EDITOR_SETUP        = 'LIST_EDITOR_SETUP';\n\nexport const LIST_CREATE_REQUEST = 'LIST_CREATE_REQUEST';\nexport const LIST_CREATE_SUCCESS = 'LIST_CREATE_SUCCESS';\nexport const LIST_CREATE_FAIL    = 'LIST_CREATE_FAIL';\n\nexport const LIST_UPDATE_REQUEST = 'LIST_UPDATE_REQUEST';\nexport const LIST_UPDATE_SUCCESS = 'LIST_UPDATE_SUCCESS';\nexport const LIST_UPDATE_FAIL    = 'LIST_UPDATE_FAIL';\n\nexport const LIST_DELETE_REQUEST = 'LIST_DELETE_REQUEST';\nexport const LIST_DELETE_SUCCESS = 'LIST_DELETE_SUCCESS';\nexport const LIST_DELETE_FAIL    = 'LIST_DELETE_FAIL';\n\nexport const LIST_ACCOUNTS_FETCH_REQUEST = 'LIST_ACCOUNTS_FETCH_REQUEST';\nexport const LIST_ACCOUNTS_FETCH_SUCCESS = 'LIST_ACCOUNTS_FETCH_SUCCESS';\nexport const LIST_ACCOUNTS_FETCH_FAIL    = 'LIST_ACCOUNTS_FETCH_FAIL';\n\nexport const LIST_EDITOR_SUGGESTIONS_CHANGE = 'LIST_EDITOR_SUGGESTIONS_CHANGE';\nexport const LIST_EDITOR_SUGGESTIONS_READY  = 'LIST_EDITOR_SUGGESTIONS_READY';\nexport const LIST_EDITOR_SUGGESTIONS_CLEAR  = 'LIST_EDITOR_SUGGESTIONS_CLEAR';\n\nexport const LIST_EDITOR_ADD_REQUEST = 'LIST_EDITOR_ADD_REQUEST';\nexport const LIST_EDITOR_ADD_SUCCESS = 'LIST_EDITOR_ADD_SUCCESS';\nexport const LIST_EDITOR_ADD_FAIL    = 'LIST_EDITOR_ADD_FAIL';\n\nexport const LIST_EDITOR_REMOVE_REQUEST = 'LIST_EDITOR_REMOVE_REQUEST';\nexport const LIST_EDITOR_REMOVE_SUCCESS = 'LIST_EDITOR_REMOVE_SUCCESS';\nexport const LIST_EDITOR_REMOVE_FAIL    = 'LIST_EDITOR_REMOVE_FAIL';\n\nexport const LIST_ADDER_RESET = 'LIST_ADDER_RESET';\nexport const LIST_ADDER_SETUP = 'LIST_ADDER_SETUP';\n\nexport const LIST_ADDER_LISTS_FETCH_REQUEST = 'LIST_ADDER_LISTS_FETCH_REQUEST';\nexport const LIST_ADDER_LISTS_FETCH_SUCCESS = 'LIST_ADDER_LISTS_FETCH_SUCCESS';\nexport const LIST_ADDER_LISTS_FETCH_FAIL    = 'LIST_ADDER_LISTS_FETCH_FAIL';\n\nexport const fetchList = id => (dispatch, getState) => {\n  if (getState().getIn(['lists', id])) {\n    return;\n  }\n\n  dispatch(fetchListRequest(id));\n\n  api(getState).get(`/api/v1/lists/${id}`)\n    .then(({ data }) => dispatch(fetchListSuccess(data)))\n    .catch(err => dispatch(fetchListFail(id, err)));\n};\n\nexport const fetchListRequest = id => ({\n  type: LIST_FETCH_REQUEST,\n  id,\n});\n\nexport const fetchListSuccess = list => ({\n  type: LIST_FETCH_SUCCESS,\n  list,\n});\n\nexport const fetchListFail = (id, error) => ({\n  type: LIST_FETCH_FAIL,\n  id,\n  error,\n});\n\nexport const fetchLists = () => (dispatch, getState) => {\n  dispatch(fetchListsRequest());\n\n  api(getState).get('/api/v1/lists')\n    .then(({ data }) => dispatch(fetchListsSuccess(data)))\n    .catch(err => dispatch(fetchListsFail(err)));\n};\n\nexport const fetchListsRequest = () => ({\n  type: LISTS_FETCH_REQUEST,\n});\n\nexport const fetchListsSuccess = lists => ({\n  type: LISTS_FETCH_SUCCESS,\n  lists,\n});\n\nexport const fetchListsFail = error => ({\n  type: LISTS_FETCH_FAIL,\n  error,\n});\n\nexport const submitListEditor = shouldReset => (dispatch, getState) => {\n  const listId = getState().getIn(['listEditor', 'listId']);\n  const title  = getState().getIn(['listEditor', 'title']);\n\n  if (listId === null) {\n    dispatch(createList(title, shouldReset));\n  } else {\n    dispatch(updateList(listId, title, shouldReset));\n  }\n};\n\nexport const setupListEditor = listId => (dispatch, getState) => {\n  dispatch({\n    type: LIST_EDITOR_SETUP,\n    list: getState().getIn(['lists', listId]),\n  });\n\n  dispatch(fetchListAccounts(listId));\n};\n\nexport const changeListEditorTitle = value => ({\n  type: LIST_EDITOR_TITLE_CHANGE,\n  value,\n});\n\nexport const createList = (title, shouldReset) => (dispatch, getState) => {\n  dispatch(createListRequest());\n\n  api(getState).post('/api/v1/lists', { title }).then(({ data }) => {\n    dispatch(createListSuccess(data));\n\n    if (shouldReset) {\n      dispatch(resetListEditor());\n    }\n  }).catch(err => dispatch(createListFail(err)));\n};\n\nexport const createListRequest = () => ({\n  type: LIST_CREATE_REQUEST,\n});\n\nexport const createListSuccess = list => ({\n  type: LIST_CREATE_SUCCESS,\n  list,\n});\n\nexport const createListFail = error => ({\n  type: LIST_CREATE_FAIL,\n  error,\n});\n\nexport const updateList = (id, title, shouldReset) => (dispatch, getState) => {\n  dispatch(updateListRequest(id));\n\n  api(getState).put(`/api/v1/lists/${id}`, { title }).then(({ data }) => {\n    dispatch(updateListSuccess(data));\n\n    if (shouldReset) {\n      dispatch(resetListEditor());\n    }\n  }).catch(err => dispatch(updateListFail(id, err)));\n};\n\nexport const updateListRequest = id => ({\n  type: LIST_UPDATE_REQUEST,\n  id,\n});\n\nexport const updateListSuccess = list => ({\n  type: LIST_UPDATE_SUCCESS,\n  list,\n});\n\nexport const updateListFail = (id, error) => ({\n  type: LIST_UPDATE_FAIL,\n  id,\n  error,\n});\n\nexport const resetListEditor = () => ({\n  type: LIST_EDITOR_RESET,\n});\n\nexport const deleteList = id => (dispatch, getState) => {\n  dispatch(deleteListRequest(id));\n\n  api(getState).delete(`/api/v1/lists/${id}`)\n    .then(() => dispatch(deleteListSuccess(id)))\n    .catch(err => dispatch(deleteListFail(id, err)));\n};\n\nexport const deleteListRequest = id => ({\n  type: LIST_DELETE_REQUEST,\n  id,\n});\n\nexport const deleteListSuccess = id => ({\n  type: LIST_DELETE_SUCCESS,\n  id,\n});\n\nexport const deleteListFail = (id, error) => ({\n  type: LIST_DELETE_FAIL,\n  id,\n  error,\n});\n\nexport const fetchListAccounts = listId => (dispatch, getState) => {\n  dispatch(fetchListAccountsRequest(listId));\n\n  api(getState).get(`/api/v1/lists/${listId}/accounts`, { params: { limit: 0 } }).then(({ data }) => {\n    dispatch(importFetchedAccounts(data));\n    dispatch(fetchListAccountsSuccess(listId, data));\n  }).catch(err => dispatch(fetchListAccountsFail(listId, err)));\n};\n\nexport const fetchListAccountsRequest = id => ({\n  type: LIST_ACCOUNTS_FETCH_REQUEST,\n  id,\n});\n\nexport const fetchListAccountsSuccess = (id, accounts, next) => ({\n  type: LIST_ACCOUNTS_FETCH_SUCCESS,\n  id,\n  accounts,\n  next,\n});\n\nexport const fetchListAccountsFail = (id, error) => ({\n  type: LIST_ACCOUNTS_FETCH_FAIL,\n  id,\n  error,\n});\n\nexport const fetchListSuggestions = q => (dispatch, getState) => {\n  const params = {\n    q,\n    resolve: false,\n    limit: 4,\n    following: true,\n  };\n\n  api(getState).get('/api/v1/accounts/search', { params }).then(({ data }) => {\n    dispatch(importFetchedAccounts(data));\n    dispatch(fetchListSuggestionsReady(q, data));\n  }).catch(error => dispatch(showAlertForError(error)));\n};\n\nexport const fetchListSuggestionsReady = (query, accounts) => ({\n  type: LIST_EDITOR_SUGGESTIONS_READY,\n  query,\n  accounts,\n});\n\nexport const clearListSuggestions = () => ({\n  type: LIST_EDITOR_SUGGESTIONS_CLEAR,\n});\n\nexport const changeListSuggestions = value => ({\n  type: LIST_EDITOR_SUGGESTIONS_CHANGE,\n  value,\n});\n\nexport const addToListEditor = accountId => (dispatch, getState) => {\n  dispatch(addToList(getState().getIn(['listEditor', 'listId']), accountId));\n};\n\nexport const addToList = (listId, accountId) => (dispatch, getState) => {\n  dispatch(addToListRequest(listId, accountId));\n\n  api(getState).post(`/api/v1/lists/${listId}/accounts`, { account_ids: [accountId] })\n    .then(() => dispatch(addToListSuccess(listId, accountId)))\n    .catch(err => dispatch(addToListFail(listId, accountId, err)));\n};\n\nexport const addToListRequest = (listId, accountId) => ({\n  type: LIST_EDITOR_ADD_REQUEST,\n  listId,\n  accountId,\n});\n\nexport const addToListSuccess = (listId, accountId) => ({\n  type: LIST_EDITOR_ADD_SUCCESS,\n  listId,\n  accountId,\n});\n\nexport const addToListFail = (listId, accountId, error) => ({\n  type: LIST_EDITOR_ADD_FAIL,\n  listId,\n  accountId,\n  error,\n});\n\nexport const removeFromListEditor = accountId => (dispatch, getState) => {\n  dispatch(removeFromList(getState().getIn(['listEditor', 'listId']), accountId));\n};\n\nexport const removeFromList = (listId, accountId) => (dispatch, getState) => {\n  dispatch(removeFromListRequest(listId, accountId));\n\n  api(getState).delete(`/api/v1/lists/${listId}/accounts`, { params: { account_ids: [accountId] } })\n    .then(() => dispatch(removeFromListSuccess(listId, accountId)))\n    .catch(err => dispatch(removeFromListFail(listId, accountId, err)));\n};\n\nexport const removeFromListRequest = (listId, accountId) => ({\n  type: LIST_EDITOR_REMOVE_REQUEST,\n  listId,\n  accountId,\n});\n\nexport const removeFromListSuccess = (listId, accountId) => ({\n  type: LIST_EDITOR_REMOVE_SUCCESS,\n  listId,\n  accountId,\n});\n\nexport const removeFromListFail = (listId, accountId, error) => ({\n  type: LIST_EDITOR_REMOVE_FAIL,\n  listId,\n  accountId,\n  error,\n});\n\nexport const resetListAdder = () => ({\n  type: LIST_ADDER_RESET,\n});\n\nexport const setupListAdder = accountId => (dispatch, getState) => {\n  dispatch({\n    type: LIST_ADDER_SETUP,\n    account: getState().getIn(['accounts', accountId]),\n  });\n  dispatch(fetchLists());\n  dispatch(fetchAccountLists(accountId));\n};\n\nexport const fetchAccountLists = accountId => (dispatch, getState) => {\n  dispatch(fetchAccountListsRequest(accountId));\n\n  api(getState).get(`/api/v1/accounts/${accountId}/lists`)\n    .then(({ data }) => dispatch(fetchAccountListsSuccess(accountId, data)))\n    .catch(err => dispatch(fetchAccountListsFail(accountId, err)));\n};\n\nexport const fetchAccountListsRequest = id => ({\n  type:LIST_ADDER_LISTS_FETCH_REQUEST,\n  id,\n});\n\nexport const fetchAccountListsSuccess = (id, lists) => ({\n  type: LIST_ADDER_LISTS_FETCH_SUCCESS,\n  id,\n  lists,\n});\n\nexport const fetchAccountListsFail = (id, err) => ({\n  type: LIST_ADDER_LISTS_FETCH_FAIL,\n  id,\n  err,\n});\n\nexport const addToListAdder = listId => (dispatch, getState) => {\n  dispatch(addToList(listId, getState().getIn(['listAdder', 'accountId'])));\n};\n\nexport const removeFromListAdder = listId => (dispatch, getState) => {\n  dispatch(removeFromList(listId, getState().getIn(['listAdder', 'accountId'])));\n};\n\n"
  },
  {
    "path": "app/javascript/mastodon/actions/modal.js",
    "content": "export const MODAL_OPEN  = 'MODAL_OPEN';\nexport const MODAL_CLOSE = 'MODAL_CLOSE';\n\nexport function openModal(type, props) {\n  return {\n    type: MODAL_OPEN,\n    modalType: type,\n    modalProps: props,\n  };\n};\n\nexport function closeModal() {\n  return {\n    type: MODAL_CLOSE,\n  };\n};\n"
  },
  {
    "path": "app/javascript/mastodon/actions/mutes.js",
    "content": "import api, { getLinks } from '../api';\nimport { fetchRelationships } from './accounts';\nimport { importFetchedAccounts } from './importer';\nimport { openModal } from './modal';\n\nexport const MUTES_FETCH_REQUEST = 'MUTES_FETCH_REQUEST';\nexport const MUTES_FETCH_SUCCESS = 'MUTES_FETCH_SUCCESS';\nexport const MUTES_FETCH_FAIL    = 'MUTES_FETCH_FAIL';\n\nexport const MUTES_EXPAND_REQUEST = 'MUTES_EXPAND_REQUEST';\nexport const MUTES_EXPAND_SUCCESS = 'MUTES_EXPAND_SUCCESS';\nexport const MUTES_EXPAND_FAIL    = 'MUTES_EXPAND_FAIL';\n\nexport const MUTES_INIT_MODAL = 'MUTES_INIT_MODAL';\nexport const MUTES_TOGGLE_HIDE_NOTIFICATIONS = 'MUTES_TOGGLE_HIDE_NOTIFICATIONS';\n\nexport function fetchMutes() {\n  return (dispatch, getState) => {\n    dispatch(fetchMutesRequest());\n\n    api(getState).get('/api/v1/mutes').then(response => {\n      const next = getLinks(response).refs.find(link => link.rel === 'next');\n      dispatch(importFetchedAccounts(response.data));\n      dispatch(fetchMutesSuccess(response.data, next ? next.uri : null));\n      dispatch(fetchRelationships(response.data.map(item => item.id)));\n    }).catch(error => dispatch(fetchMutesFail(error)));\n  };\n};\n\nexport function fetchMutesRequest() {\n  return {\n    type: MUTES_FETCH_REQUEST,\n  };\n};\n\nexport function fetchMutesSuccess(accounts, next) {\n  return {\n    type: MUTES_FETCH_SUCCESS,\n    accounts,\n    next,\n  };\n};\n\nexport function fetchMutesFail(error) {\n  return {\n    type: MUTES_FETCH_FAIL,\n    error,\n  };\n};\n\nexport function expandMutes() {\n  return (dispatch, getState) => {\n    const url = getState().getIn(['user_lists', 'mutes', 'next']);\n\n    if (url === null) {\n      return;\n    }\n\n    dispatch(expandMutesRequest());\n\n    api(getState).get(url).then(response => {\n      const next = getLinks(response).refs.find(link => link.rel === 'next');\n      dispatch(importFetchedAccounts(response.data));\n      dispatch(expandMutesSuccess(response.data, next ? next.uri : null));\n      dispatch(fetchRelationships(response.data.map(item => item.id)));\n    }).catch(error => dispatch(expandMutesFail(error)));\n  };\n};\n\nexport function expandMutesRequest() {\n  return {\n    type: MUTES_EXPAND_REQUEST,\n  };\n};\n\nexport function expandMutesSuccess(accounts, next) {\n  return {\n    type: MUTES_EXPAND_SUCCESS,\n    accounts,\n    next,\n  };\n};\n\nexport function expandMutesFail(error) {\n  return {\n    type: MUTES_EXPAND_FAIL,\n    error,\n  };\n};\n\nexport function initMuteModal(account) {\n  return dispatch => {\n    dispatch({\n      type: MUTES_INIT_MODAL,\n      account,\n    });\n\n    dispatch(openModal('MUTE'));\n  };\n}\n\nexport function toggleHideNotifications() {\n  return dispatch => {\n    dispatch({ type: MUTES_TOGGLE_HIDE_NOTIFICATIONS });\n  };\n}\n"
  },
  {
    "path": "app/javascript/mastodon/actions/notifications.js",
    "content": "import api, { getLinks } from '../api';\nimport IntlMessageFormat from 'intl-messageformat';\nimport { fetchRelationships } from './accounts';\nimport {\n  importFetchedAccount,\n  importFetchedAccounts,\n  importFetchedStatus,\n  importFetchedStatuses,\n} from './importer';\nimport { saveSettings } from './settings';\nimport { defineMessages } from 'react-intl';\nimport { List as ImmutableList } from 'immutable';\nimport { unescapeHTML } from '../utils/html';\nimport { getFilters, regexFromFilters } from '../selectors';\n\nexport const NOTIFICATIONS_UPDATE      = 'NOTIFICATIONS_UPDATE';\nexport const NOTIFICATIONS_UPDATE_NOOP = 'NOTIFICATIONS_UPDATE_NOOP';\n\nexport const NOTIFICATIONS_EXPAND_REQUEST = 'NOTIFICATIONS_EXPAND_REQUEST';\nexport const NOTIFICATIONS_EXPAND_SUCCESS = 'NOTIFICATIONS_EXPAND_SUCCESS';\nexport const NOTIFICATIONS_EXPAND_FAIL    = 'NOTIFICATIONS_EXPAND_FAIL';\n\nexport const NOTIFICATIONS_FILTER_SET = 'NOTIFICATIONS_FILTER_SET';\n\nexport const NOTIFICATIONS_CLEAR      = 'NOTIFICATIONS_CLEAR';\nexport const NOTIFICATIONS_SCROLL_TOP = 'NOTIFICATIONS_SCROLL_TOP';\n\ndefineMessages({\n  mention: { id: 'notification.mention', defaultMessage: '{name} mentioned you' },\n  group: { id: 'notifications.group', defaultMessage: '{count} notifications' },\n});\n\nconst fetchRelatedRelationships = (dispatch, notifications) => {\n  const accountIds = notifications.filter(item => item.type === 'follow').map(item => item.account.id);\n\n  if (accountIds.length > 0) {\n    dispatch(fetchRelationships(accountIds));\n  }\n};\n\nexport function updateNotifications(notification, intlMessages, intlLocale) {\n  return (dispatch, getState) => {\n    const showInColumn = getState().getIn(['settings', 'notifications', 'shows', notification.type], true);\n    const showAlert    = getState().getIn(['settings', 'notifications', 'alerts', notification.type], true);\n    const playSound    = getState().getIn(['settings', 'notifications', 'sounds', notification.type], true);\n    const filters      = getFilters(getState(), { contextType: 'notifications' });\n\n    let filtered = false;\n\n    if (notification.type === 'mention') {\n      const regex       = regexFromFilters(filters);\n      const searchIndex = notification.status.spoiler_text + '\\n' + unescapeHTML(notification.status.content);\n\n      filtered = regex && regex.test(searchIndex);\n    }\n\n    if (showInColumn) {\n      dispatch(importFetchedAccount(notification.account));\n\n      if (notification.status) {\n        dispatch(importFetchedStatus(notification.status));\n      }\n\n      dispatch({\n        type: NOTIFICATIONS_UPDATE,\n        notification,\n        meta: (playSound && !filtered) ? { sound: 'boop' } : undefined,\n      });\n\n      fetchRelatedRelationships(dispatch, [notification]);\n    } else if (playSound && !filtered) {\n      dispatch({\n        type: NOTIFICATIONS_UPDATE_NOOP,\n        meta: { sound: 'boop' },\n      });\n    }\n\n    // Desktop notifications\n    if (typeof window.Notification !== 'undefined' && showAlert && !filtered) {\n      const title = new IntlMessageFormat(intlMessages[`notification.${notification.type}`], intlLocale).format({ name: notification.account.display_name.length > 0 ? notification.account.display_name : notification.account.username });\n      const body  = (notification.status && notification.status.spoiler_text.length > 0) ? notification.status.spoiler_text : unescapeHTML(notification.status ? notification.status.content : '');\n\n      const notify = new Notification(title, { body, icon: notification.account.avatar, tag: notification.id });\n\n      notify.addEventListener('click', () => {\n        window.focus();\n        notify.close();\n      });\n    }\n  };\n};\n\nconst excludeTypesFromSettings = state => state.getIn(['settings', 'notifications', 'shows']).filter(enabled => !enabled).keySeq().toJS();\n\nconst excludeTypesFromFilter = filter => {\n  const allTypes = ImmutableList(['follow', 'favourite', 'reblog', 'mention', 'poll']);\n  return allTypes.filterNot(item => item === filter).toJS();\n};\n\nconst noOp = () => {};\n\nexport function expandNotifications({ maxId } = {}, done = noOp) {\n  return (dispatch, getState) => {\n    const activeFilter = getState().getIn(['settings', 'notifications', 'quickFilter', 'active']);\n    const notifications = getState().get('notifications');\n    const isLoadingMore = !!maxId;\n\n    if (notifications.get('isLoading')) {\n      done();\n      return;\n    }\n\n    const params = {\n      max_id: maxId,\n      exclude_types: activeFilter === 'all'\n        ? excludeTypesFromSettings(getState())\n        : excludeTypesFromFilter(activeFilter),\n    };\n\n    if (!maxId && notifications.get('items').size > 0) {\n      params.since_id = notifications.getIn(['items', 0, 'id']);\n    }\n\n    dispatch(expandNotificationsRequest(isLoadingMore));\n\n    api(getState).get('/api/v1/notifications', { params }).then(response => {\n      const next = getLinks(response).refs.find(link => link.rel === 'next');\n\n      dispatch(importFetchedAccounts(response.data.map(item => item.account)));\n      dispatch(importFetchedStatuses(response.data.map(item => item.status).filter(status => !!status)));\n\n      dispatch(expandNotificationsSuccess(response.data, next ? next.uri : null, isLoadingMore));\n      fetchRelatedRelationships(dispatch, response.data);\n      done();\n    }).catch(error => {\n      dispatch(expandNotificationsFail(error, isLoadingMore));\n      done();\n    });\n  };\n};\n\nexport function expandNotificationsRequest(isLoadingMore) {\n  return {\n    type: NOTIFICATIONS_EXPAND_REQUEST,\n    skipLoading: !isLoadingMore,\n  };\n};\n\nexport function expandNotificationsSuccess(notifications, next, isLoadingMore) {\n  return {\n    type: NOTIFICATIONS_EXPAND_SUCCESS,\n    notifications,\n    next,\n    skipLoading: !isLoadingMore,\n  };\n};\n\nexport function expandNotificationsFail(error, isLoadingMore) {\n  return {\n    type: NOTIFICATIONS_EXPAND_FAIL,\n    error,\n    skipLoading: !isLoadingMore,\n  };\n};\n\nexport function clearNotifications() {\n  return (dispatch, getState) => {\n    dispatch({\n      type: NOTIFICATIONS_CLEAR,\n    });\n\n    api(getState).post('/api/v1/notifications/clear');\n  };\n};\n\nexport function scrollTopNotifications(top) {\n  return {\n    type: NOTIFICATIONS_SCROLL_TOP,\n    top,\n  };\n};\n\nexport function setFilter (filterType) {\n  return dispatch => {\n    dispatch({\n      type: NOTIFICATIONS_FILTER_SET,\n      path: ['notifications', 'quickFilter', 'active'],\n      value: filterType,\n    });\n    dispatch(expandNotifications());\n    dispatch(saveSettings());\n  };\n};\n"
  },
  {
    "path": "app/javascript/mastodon/actions/onboarding.js",
    "content": "import { changeSetting, saveSettings } from './settings';\n\nexport const INTRODUCTION_VERSION = 20181216044202;\n\nexport const closeOnboarding = () => dispatch => {\n  dispatch(changeSetting(['introductionVersion'], INTRODUCTION_VERSION));\n  dispatch(saveSettings());\n};\n"
  },
  {
    "path": "app/javascript/mastodon/actions/pin_statuses.js",
    "content": "import api from '../api';\nimport { importFetchedStatuses } from './importer';\n\nexport const PINNED_STATUSES_FETCH_REQUEST = 'PINNED_STATUSES_FETCH_REQUEST';\nexport const PINNED_STATUSES_FETCH_SUCCESS = 'PINNED_STATUSES_FETCH_SUCCESS';\nexport const PINNED_STATUSES_FETCH_FAIL = 'PINNED_STATUSES_FETCH_FAIL';\n\nimport { me } from '../initial_state';\n\nexport function fetchPinnedStatuses() {\n  return (dispatch, getState) => {\n    dispatch(fetchPinnedStatusesRequest());\n\n    api(getState).get(`/api/v1/accounts/${me}/statuses`, { params: { pinned: true } }).then(response => {\n      dispatch(importFetchedStatuses(response.data));\n      dispatch(fetchPinnedStatusesSuccess(response.data, null));\n    }).catch(error => {\n      dispatch(fetchPinnedStatusesFail(error));\n    });\n  };\n};\n\nexport function fetchPinnedStatusesRequest() {\n  return {\n    type: PINNED_STATUSES_FETCH_REQUEST,\n  };\n};\n\nexport function fetchPinnedStatusesSuccess(statuses, next) {\n  return {\n    type: PINNED_STATUSES_FETCH_SUCCESS,\n    statuses,\n    next,\n  };\n};\n\nexport function fetchPinnedStatusesFail(error) {\n  return {\n    type: PINNED_STATUSES_FETCH_FAIL,\n    error,\n  };\n};\n"
  },
  {
    "path": "app/javascript/mastodon/actions/polls.js",
    "content": "import api from '../api';\nimport { importFetchedPoll } from './importer';\n\nexport const POLL_VOTE_REQUEST = 'POLL_VOTE_REQUEST';\nexport const POLL_VOTE_SUCCESS = 'POLL_VOTE_SUCCESS';\nexport const POLL_VOTE_FAIL    = 'POLL_VOTE_FAIL';\n\nexport const POLL_FETCH_REQUEST = 'POLL_FETCH_REQUEST';\nexport const POLL_FETCH_SUCCESS = 'POLL_FETCH_SUCCESS';\nexport const POLL_FETCH_FAIL    = 'POLL_FETCH_FAIL';\n\nexport const vote = (pollId, choices) => (dispatch, getState) => {\n  dispatch(voteRequest());\n\n  api(getState).post(`/api/v1/polls/${pollId}/votes`, { choices })\n    .then(({ data }) => {\n      dispatch(importFetchedPoll(data));\n      dispatch(voteSuccess(data));\n    })\n    .catch(err => dispatch(voteFail(err)));\n};\n\nexport const fetchPoll = pollId => (dispatch, getState) => {\n  dispatch(fetchPollRequest());\n\n  api(getState).get(`/api/v1/polls/${pollId}`)\n    .then(({ data }) => {\n      dispatch(importFetchedPoll(data));\n      dispatch(fetchPollSuccess(data));\n    })\n    .catch(err => dispatch(fetchPollFail(err)));\n};\n\nexport const voteRequest = () => ({\n  type: POLL_VOTE_REQUEST,\n});\n\nexport const voteSuccess = poll => ({\n  type: POLL_VOTE_SUCCESS,\n  poll,\n});\n\nexport const voteFail = error => ({\n  type: POLL_VOTE_FAIL,\n  error,\n});\n\nexport const fetchPollRequest = () => ({\n  type: POLL_FETCH_REQUEST,\n});\n\nexport const fetchPollSuccess = poll => ({\n  type: POLL_FETCH_SUCCESS,\n  poll,\n});\n\nexport const fetchPollFail = error => ({\n  type: POLL_FETCH_FAIL,\n  error,\n});\n"
  },
  {
    "path": "app/javascript/mastodon/actions/push_notifications/index.js",
    "content": "import {\n  SET_BROWSER_SUPPORT,\n  SET_SUBSCRIPTION,\n  CLEAR_SUBSCRIPTION,\n  SET_ALERTS,\n  setAlerts,\n} from './setter';\nimport { register, saveSettings } from './registerer';\n\nexport {\n  SET_BROWSER_SUPPORT,\n  SET_SUBSCRIPTION,\n  CLEAR_SUBSCRIPTION,\n  SET_ALERTS,\n  register,\n};\n\nexport function changeAlerts(path, value) {\n  return dispatch => {\n    dispatch(setAlerts(path, value));\n    dispatch(saveSettings());\n  };\n}\n"
  },
  {
    "path": "app/javascript/mastodon/actions/push_notifications/registerer.js",
    "content": "import api from '../../api';\nimport { decode as decodeBase64 } from '../../utils/base64';\nimport { pushNotificationsSetting } from '../../settings';\nimport { setBrowserSupport, setSubscription, clearSubscription } from './setter';\nimport { me } from '../../initial_state';\n\n// Taken from https://www.npmjs.com/package/web-push\nconst urlBase64ToUint8Array = (base64String) => {\n  const padding = '='.repeat((4 - base64String.length % 4) % 4);\n  const base64 = (base64String + padding)\n    .replace(/\\-/g, '+')\n    .replace(/_/g, '/');\n\n  return decodeBase64(base64);\n};\n\nconst getApplicationServerKey = () => document.querySelector('[name=\"applicationServerKey\"]').getAttribute('content');\n\nconst getRegistration = () => navigator.serviceWorker.ready;\n\nconst getPushSubscription = (registration) =>\n  registration.pushManager.getSubscription()\n    .then(subscription => ({ registration, subscription }));\n\nconst subscribe = (registration) =>\n  registration.pushManager.subscribe({\n    userVisibleOnly: true,\n    applicationServerKey: urlBase64ToUint8Array(getApplicationServerKey()),\n  });\n\nconst unsubscribe = ({ registration, subscription }) =>\n  subscription ? subscription.unsubscribe().then(() => registration) : registration;\n\nconst sendSubscriptionToBackend = (subscription) => {\n  const params = { subscription };\n\n  if (me) {\n    const data = pushNotificationsSetting.get(me);\n    if (data) {\n      params.data = data;\n    }\n  }\n\n  return api().post('/api/web/push_subscriptions', params).then(response => response.data);\n};\n\n// Last one checks for payload support: https://web-push-book.gauntface.com/chapter-06/01-non-standards-browsers/#no-payload\nconst supportsPushNotifications = ('serviceWorker' in navigator && 'PushManager' in window && 'getKey' in PushSubscription.prototype);\n\nexport function register () {\n  return (dispatch, getState) => {\n    dispatch(setBrowserSupport(supportsPushNotifications));\n\n    if (supportsPushNotifications) {\n      if (!getApplicationServerKey()) {\n        console.error('The VAPID public key is not set. You will not be able to receive Web Push Notifications.');\n        return;\n      }\n\n      getRegistration()\n        .then(getPushSubscription)\n        .then(({ registration, subscription }) => {\n          if (subscription !== null) {\n            // We have a subscription, check if it is still valid\n            const currentServerKey = (new Uint8Array(subscription.options.applicationServerKey)).toString();\n            const subscriptionServerKey = urlBase64ToUint8Array(getApplicationServerKey()).toString();\n            const serverEndpoint = getState().getIn(['push_notifications', 'subscription', 'endpoint']);\n\n            // If the VAPID public key did not change and the endpoint corresponds\n            // to the endpoint saved in the backend, the subscription is valid\n            if (subscriptionServerKey === currentServerKey && subscription.endpoint === serverEndpoint) {\n              return subscription;\n            } else {\n              // Something went wrong, try to subscribe again\n              return unsubscribe({ registration, subscription }).then(subscribe).then(\n                subscription => sendSubscriptionToBackend(subscription));\n            }\n          }\n\n          // No subscription, try to subscribe\n          return subscribe(registration).then(\n            subscription => sendSubscriptionToBackend(subscription));\n        })\n        .then(subscription => {\n          // If we got a PushSubscription (and not a subscription object from the backend)\n          // it means that the backend subscription is valid (and was set during hydration)\n          if (!(subscription instanceof PushSubscription)) {\n            dispatch(setSubscription(subscription));\n            if (me) {\n              pushNotificationsSetting.set(me, { alerts: subscription.alerts });\n            }\n          }\n        })\n        .catch(error => {\n          if (error.code === 20 && error.name === 'AbortError') {\n            console.warn('Your browser supports Web Push Notifications, but does not seem to implement the VAPID protocol.');\n          } else if (error.code === 5 && error.name === 'InvalidCharacterError') {\n            console.error('The VAPID public key seems to be invalid:', getApplicationServerKey());\n          }\n\n          // Clear alerts and hide UI settings\n          dispatch(clearSubscription());\n          if (me) {\n            pushNotificationsSetting.remove(me);\n          }\n\n          return getRegistration()\n            .then(getPushSubscription)\n            .then(unsubscribe);\n        })\n        .catch(console.warn);\n    } else {\n      console.warn('Your browser does not support Web Push Notifications.');\n    }\n  };\n}\n\nexport function saveSettings() {\n  return (_, getState) => {\n    const state = getState().get('push_notifications');\n    const subscription = state.get('subscription');\n    const alerts = state.get('alerts');\n    const data = { alerts };\n\n    api().put(`/api/web/push_subscriptions/${subscription.get('id')}`, {\n      data,\n    }).then(() => {\n      if (me) {\n        pushNotificationsSetting.set(me, data);\n      }\n    }).catch(console.warn);\n  };\n}\n"
  },
  {
    "path": "app/javascript/mastodon/actions/push_notifications/setter.js",
    "content": "export const SET_BROWSER_SUPPORT = 'PUSH_NOTIFICATIONS_SET_BROWSER_SUPPORT';\nexport const SET_SUBSCRIPTION = 'PUSH_NOTIFICATIONS_SET_SUBSCRIPTION';\nexport const CLEAR_SUBSCRIPTION = 'PUSH_NOTIFICATIONS_CLEAR_SUBSCRIPTION';\nexport const SET_ALERTS = 'PUSH_NOTIFICATIONS_SET_ALERTS';\n\nexport function setBrowserSupport (value) {\n  return {\n    type: SET_BROWSER_SUPPORT,\n    value,\n  };\n}\n\nexport function setSubscription (subscription) {\n  return {\n    type: SET_SUBSCRIPTION,\n    subscription,\n  };\n}\n\nexport function clearSubscription () {\n  return {\n    type: CLEAR_SUBSCRIPTION,\n  };\n}\n\nexport function setAlerts (path, value) {\n  return dispatch => {\n    dispatch({\n      type: SET_ALERTS,\n      path,\n      value,\n    });\n  };\n}\n"
  },
  {
    "path": "app/javascript/mastodon/actions/reports.js",
    "content": "import api from '../api';\nimport { openModal, closeModal } from './modal';\n\nexport const REPORT_INIT   = 'REPORT_INIT';\nexport const REPORT_CANCEL = 'REPORT_CANCEL';\n\nexport const REPORT_SUBMIT_REQUEST = 'REPORT_SUBMIT_REQUEST';\nexport const REPORT_SUBMIT_SUCCESS = 'REPORT_SUBMIT_SUCCESS';\nexport const REPORT_SUBMIT_FAIL    = 'REPORT_SUBMIT_FAIL';\n\nexport const REPORT_STATUS_TOGGLE  = 'REPORT_STATUS_TOGGLE';\nexport const REPORT_COMMENT_CHANGE = 'REPORT_COMMENT_CHANGE';\nexport const REPORT_FORWARD_CHANGE = 'REPORT_FORWARD_CHANGE';\n\nexport function initReport(account, status) {\n  return dispatch => {\n    dispatch({\n      type: REPORT_INIT,\n      account,\n      status,\n    });\n\n    dispatch(openModal('REPORT'));\n  };\n};\n\nexport function cancelReport() {\n  return {\n    type: REPORT_CANCEL,\n  };\n};\n\nexport function toggleStatusReport(statusId, checked) {\n  return {\n    type: REPORT_STATUS_TOGGLE,\n    statusId,\n    checked,\n  };\n};\n\nexport function submitReport() {\n  return (dispatch, getState) => {\n    dispatch(submitReportRequest());\n\n    api(getState).post('/api/v1/reports', {\n      account_id: getState().getIn(['reports', 'new', 'account_id']),\n      status_ids: getState().getIn(['reports', 'new', 'status_ids']),\n      comment: getState().getIn(['reports', 'new', 'comment']),\n      forward: getState().getIn(['reports', 'new', 'forward']),\n    }).then(response => {\n      dispatch(closeModal());\n      dispatch(submitReportSuccess(response.data));\n    }).catch(error => dispatch(submitReportFail(error)));\n  };\n};\n\nexport function submitReportRequest() {\n  return {\n    type: REPORT_SUBMIT_REQUEST,\n  };\n};\n\nexport function submitReportSuccess(report) {\n  return {\n    type: REPORT_SUBMIT_SUCCESS,\n    report,\n  };\n};\n\nexport function submitReportFail(error) {\n  return {\n    type: REPORT_SUBMIT_FAIL,\n    error,\n  };\n};\n\nexport function changeReportComment(comment) {\n  return {\n    type: REPORT_COMMENT_CHANGE,\n    comment,\n  };\n};\n\nexport function changeReportForward(forward) {\n  return {\n    type: REPORT_FORWARD_CHANGE,\n    forward,\n  };\n};\n"
  },
  {
    "path": "app/javascript/mastodon/actions/search.js",
    "content": "import api from '../api';\nimport { fetchRelationships } from './accounts';\nimport { importFetchedAccounts, importFetchedStatuses } from './importer';\n\nexport const SEARCH_CHANGE = 'SEARCH_CHANGE';\nexport const SEARCH_CLEAR  = 'SEARCH_CLEAR';\nexport const SEARCH_SHOW   = 'SEARCH_SHOW';\n\nexport const SEARCH_FETCH_REQUEST = 'SEARCH_FETCH_REQUEST';\nexport const SEARCH_FETCH_SUCCESS = 'SEARCH_FETCH_SUCCESS';\nexport const SEARCH_FETCH_FAIL    = 'SEARCH_FETCH_FAIL';\n\nexport function changeSearch(value) {\n  return {\n    type: SEARCH_CHANGE,\n    value,\n  };\n};\n\nexport function clearSearch() {\n  return {\n    type: SEARCH_CLEAR,\n  };\n};\n\nexport function submitSearch() {\n  return (dispatch, getState) => {\n    const value = getState().getIn(['search', 'value']);\n\n    if (value.length === 0) {\n      return;\n    }\n\n    dispatch(fetchSearchRequest());\n\n    api(getState).get('/api/v2/search', {\n      params: {\n        q: value,\n        resolve: true,\n        limit: 5,\n      },\n    }).then(response => {\n      if (response.data.accounts) {\n        dispatch(importFetchedAccounts(response.data.accounts));\n      }\n\n      if (response.data.statuses) {\n        dispatch(importFetchedStatuses(response.data.statuses));\n      }\n\n      dispatch(fetchSearchSuccess(response.data));\n      dispatch(fetchRelationships(response.data.accounts.map(item => item.id)));\n    }).catch(error => {\n      dispatch(fetchSearchFail(error));\n    });\n  };\n};\n\nexport function fetchSearchRequest() {\n  return {\n    type: SEARCH_FETCH_REQUEST,\n  };\n};\n\nexport function fetchSearchSuccess(results) {\n  return {\n    type: SEARCH_FETCH_SUCCESS,\n    results,\n  };\n};\n\nexport function fetchSearchFail(error) {\n  return {\n    type: SEARCH_FETCH_FAIL,\n    error,\n  };\n};\n\nexport function showSearch() {\n  return {\n    type: SEARCH_SHOW,\n  };\n};\n"
  },
  {
    "path": "app/javascript/mastodon/actions/settings.js",
    "content": "import api from '../api';\nimport { debounce } from 'lodash';\nimport { showAlertForError } from './alerts';\n\nexport const SETTING_CHANGE = 'SETTING_CHANGE';\nexport const SETTING_SAVE   = 'SETTING_SAVE';\n\nexport function changeSetting(path, value) {\n  return dispatch => {\n    dispatch({\n      type: SETTING_CHANGE,\n      path,\n      value,\n    });\n\n    dispatch(saveSettings());\n  };\n};\n\nconst debouncedSave = debounce((dispatch, getState) => {\n  if (getState().getIn(['settings', 'saved'])) {\n    return;\n  }\n\n  const data = getState().get('settings').filter((_, path) => path !== 'saved').toJS();\n\n  api().put('/api/web/settings', { data })\n    .then(() => dispatch({ type: SETTING_SAVE }))\n    .catch(error => dispatch(showAlertForError(error)));\n}, 5000, { trailing: true });\n\nexport function saveSettings() {\n  return (dispatch, getState) => debouncedSave(dispatch, getState);\n};\n"
  },
  {
    "path": "app/javascript/mastodon/actions/statuses.js",
    "content": "import api from '../api';\nimport openDB from '../storage/db';\nimport { evictStatus } from '../storage/modifier';\n\nimport { deleteFromTimelines } from './timelines';\nimport { importFetchedStatus, importFetchedStatuses, importAccount, importStatus } from './importer';\nimport { ensureComposeIsVisible } from './compose';\n\nexport const STATUS_FETCH_REQUEST = 'STATUS_FETCH_REQUEST';\nexport const STATUS_FETCH_SUCCESS = 'STATUS_FETCH_SUCCESS';\nexport const STATUS_FETCH_FAIL    = 'STATUS_FETCH_FAIL';\n\nexport const STATUS_DELETE_REQUEST = 'STATUS_DELETE_REQUEST';\nexport const STATUS_DELETE_SUCCESS = 'STATUS_DELETE_SUCCESS';\nexport const STATUS_DELETE_FAIL    = 'STATUS_DELETE_FAIL';\n\nexport const CONTEXT_FETCH_REQUEST = 'CONTEXT_FETCH_REQUEST';\nexport const CONTEXT_FETCH_SUCCESS = 'CONTEXT_FETCH_SUCCESS';\nexport const CONTEXT_FETCH_FAIL    = 'CONTEXT_FETCH_FAIL';\n\nexport const STATUS_MUTE_REQUEST = 'STATUS_MUTE_REQUEST';\nexport const STATUS_MUTE_SUCCESS = 'STATUS_MUTE_SUCCESS';\nexport const STATUS_MUTE_FAIL    = 'STATUS_MUTE_FAIL';\n\nexport const STATUS_UNMUTE_REQUEST = 'STATUS_UNMUTE_REQUEST';\nexport const STATUS_UNMUTE_SUCCESS = 'STATUS_UNMUTE_SUCCESS';\nexport const STATUS_UNMUTE_FAIL    = 'STATUS_UNMUTE_FAIL';\n\nexport const STATUS_REVEAL = 'STATUS_REVEAL';\nexport const STATUS_HIDE   = 'STATUS_HIDE';\n\nexport const REDRAFT = 'REDRAFT';\n\nexport function fetchStatusRequest(id, skipLoading) {\n  return {\n    type: STATUS_FETCH_REQUEST,\n    id,\n    skipLoading,\n  };\n};\n\nfunction getFromDB(dispatch, getState, accountIndex, index, id) {\n  return new Promise((resolve, reject) => {\n    const request = index.get(id);\n\n    request.onerror = reject;\n\n    request.onsuccess = () => {\n      const promises = [];\n\n      if (!request.result) {\n        reject();\n        return;\n      }\n\n      dispatch(importStatus(request.result));\n\n      if (getState().getIn(['accounts', request.result.account], null) === null) {\n        promises.push(new Promise((accountResolve, accountReject) => {\n          const accountRequest = accountIndex.get(request.result.account);\n\n          accountRequest.onerror = accountReject;\n          accountRequest.onsuccess = () => {\n            if (!request.result) {\n              accountReject();\n              return;\n            }\n\n            dispatch(importAccount(accountRequest.result));\n            accountResolve();\n          };\n        }));\n      }\n\n      if (request.result.reblog && getState().getIn(['statuses', request.result.reblog], null) === null) {\n        promises.push(getFromDB(dispatch, getState, accountIndex, index, request.result.reblog));\n      }\n\n      resolve(Promise.all(promises));\n    };\n  });\n}\n\nexport function fetchStatus(id) {\n  return (dispatch, getState) => {\n    const skipLoading = getState().getIn(['statuses', id], null) !== null;\n\n    dispatch(fetchContext(id));\n\n    if (skipLoading) {\n      return;\n    }\n\n    dispatch(fetchStatusRequest(id, skipLoading));\n\n    openDB().then(db => {\n      const transaction = db.transaction(['accounts', 'statuses'], 'read');\n      const accountIndex = transaction.objectStore('accounts').index('id');\n      const index = transaction.objectStore('statuses').index('id');\n\n      return getFromDB(dispatch, getState, accountIndex, index, id).then(() => {\n        db.close();\n      }, error => {\n        db.close();\n        throw error;\n      });\n    }).then(() => {\n      dispatch(fetchStatusSuccess(skipLoading));\n    }, () => api(getState).get(`/api/v1/statuses/${id}`).then(response => {\n      dispatch(importFetchedStatus(response.data));\n      dispatch(fetchStatusSuccess(skipLoading));\n    })).catch(error => {\n      dispatch(fetchStatusFail(id, error, skipLoading));\n    });\n  };\n};\n\nexport function fetchStatusSuccess(skipLoading) {\n  return {\n    type: STATUS_FETCH_SUCCESS,\n    skipLoading,\n  };\n};\n\nexport function fetchStatusFail(id, error, skipLoading) {\n  return {\n    type: STATUS_FETCH_FAIL,\n    id,\n    error,\n    skipLoading,\n    skipAlert: true,\n  };\n};\n\nexport function redraft(status, raw_text) {\n  return {\n    type: REDRAFT,\n    status,\n    raw_text,\n  };\n};\n\nexport function deleteStatus(id, routerHistory, withRedraft = false) {\n  return (dispatch, getState) => {\n    let status = getState().getIn(['statuses', id]);\n\n    if (status.get('poll')) {\n      status = status.set('poll', getState().getIn(['polls', status.get('poll')]));\n    }\n\n    dispatch(deleteStatusRequest(id));\n\n    api(getState).delete(`/api/v1/statuses/${id}`).then(response => {\n      evictStatus(id);\n      dispatch(deleteStatusSuccess(id));\n      dispatch(deleteFromTimelines(id));\n\n      if (withRedraft) {\n        dispatch(redraft(status, response.data.text));\n        ensureComposeIsVisible(getState, routerHistory);\n      }\n    }).catch(error => {\n      dispatch(deleteStatusFail(id, error));\n    });\n  };\n};\n\nexport function deleteStatusRequest(id) {\n  return {\n    type: STATUS_DELETE_REQUEST,\n    id: id,\n  };\n};\n\nexport function deleteStatusSuccess(id) {\n  return {\n    type: STATUS_DELETE_SUCCESS,\n    id: id,\n  };\n};\n\nexport function deleteStatusFail(id, error) {\n  return {\n    type: STATUS_DELETE_FAIL,\n    id: id,\n    error: error,\n  };\n};\n\nexport function fetchContext(id) {\n  return (dispatch, getState) => {\n    dispatch(fetchContextRequest(id));\n\n    api(getState).get(`/api/v1/statuses/${id}/context`).then(response => {\n      dispatch(importFetchedStatuses(response.data.ancestors.concat(response.data.descendants)));\n      dispatch(fetchContextSuccess(id, response.data.ancestors, response.data.descendants));\n\n    }).catch(error => {\n      if (error.response && error.response.status === 404) {\n        dispatch(deleteFromTimelines(id));\n      }\n\n      dispatch(fetchContextFail(id, error));\n    });\n  };\n};\n\nexport function fetchContextRequest(id) {\n  return {\n    type: CONTEXT_FETCH_REQUEST,\n    id,\n  };\n};\n\nexport function fetchContextSuccess(id, ancestors, descendants) {\n  return {\n    type: CONTEXT_FETCH_SUCCESS,\n    id,\n    ancestors,\n    descendants,\n    statuses: ancestors.concat(descendants),\n  };\n};\n\nexport function fetchContextFail(id, error) {\n  return {\n    type: CONTEXT_FETCH_FAIL,\n    id,\n    error,\n    skipAlert: true,\n  };\n};\n\nexport function muteStatus(id) {\n  return (dispatch, getState) => {\n    dispatch(muteStatusRequest(id));\n\n    api(getState).post(`/api/v1/statuses/${id}/mute`).then(() => {\n      dispatch(muteStatusSuccess(id));\n    }).catch(error => {\n      dispatch(muteStatusFail(id, error));\n    });\n  };\n};\n\nexport function muteStatusRequest(id) {\n  return {\n    type: STATUS_MUTE_REQUEST,\n    id,\n  };\n};\n\nexport function muteStatusSuccess(id) {\n  return {\n    type: STATUS_MUTE_SUCCESS,\n    id,\n  };\n};\n\nexport function muteStatusFail(id, error) {\n  return {\n    type: STATUS_MUTE_FAIL,\n    id,\n    error,\n  };\n};\n\nexport function unmuteStatus(id) {\n  return (dispatch, getState) => {\n    dispatch(unmuteStatusRequest(id));\n\n    api(getState).post(`/api/v1/statuses/${id}/unmute`).then(() => {\n      dispatch(unmuteStatusSuccess(id));\n    }).catch(error => {\n      dispatch(unmuteStatusFail(id, error));\n    });\n  };\n};\n\nexport function unmuteStatusRequest(id) {\n  return {\n    type: STATUS_UNMUTE_REQUEST,\n    id,\n  };\n};\n\nexport function unmuteStatusSuccess(id) {\n  return {\n    type: STATUS_UNMUTE_SUCCESS,\n    id,\n  };\n};\n\nexport function unmuteStatusFail(id, error) {\n  return {\n    type: STATUS_UNMUTE_FAIL,\n    id,\n    error,\n  };\n};\n\nexport function hideStatus(ids) {\n  if (!Array.isArray(ids)) {\n    ids = [ids];\n  }\n\n  return {\n    type: STATUS_HIDE,\n    ids,\n  };\n};\n\nexport function revealStatus(ids) {\n  if (!Array.isArray(ids)) {\n    ids = [ids];\n  }\n\n  return {\n    type: STATUS_REVEAL,\n    ids,\n  };\n};\n"
  },
  {
    "path": "app/javascript/mastodon/actions/store.js",
    "content": "import { Iterable, fromJS } from 'immutable';\nimport { hydrateCompose } from './compose';\nimport { importFetchedAccounts } from './importer';\n\nexport const STORE_HYDRATE = 'STORE_HYDRATE';\nexport const STORE_HYDRATE_LAZY = 'STORE_HYDRATE_LAZY';\n\nconst convertState = rawState =>\n  fromJS(rawState, (k, v) =>\n    Iterable.isIndexed(v) ? v.toList() : v.toMap());\n\nexport function hydrateStore(rawState) {\n  return dispatch => {\n    const state = convertState(rawState);\n\n    dispatch({\n      type: STORE_HYDRATE,\n      state,\n    });\n\n    dispatch(hydrateCompose());\n    dispatch(importFetchedAccounts(Object.values(rawState.accounts)));\n  };\n};\n"
  },
  {
    "path": "app/javascript/mastodon/actions/streaming.js",
    "content": "import { connectStream } from '../stream';\nimport {\n  updateTimeline,\n  deleteFromTimelines,\n  expandHomeTimeline,\n  connectTimeline,\n  disconnectTimeline,\n} from './timelines';\nimport { updateNotifications, expandNotifications } from './notifications';\nimport { updateConversations } from './conversations';\nimport { fetchFilters } from './filters';\nimport { getLocale } from '../locales';\n\nconst { messages } = getLocale();\n\nexport function connectTimelineStream (timelineId, path, pollingRefresh = null, accept = null) {\n\n  return connectStream (path, pollingRefresh, (dispatch, getState) => {\n    const locale = getState().getIn(['meta', 'locale']);\n\n    return {\n      onConnect() {\n        dispatch(connectTimeline(timelineId));\n      },\n\n      onDisconnect() {\n        dispatch(disconnectTimeline(timelineId));\n      },\n\n      onReceive (data) {\n        switch(data.event) {\n        case 'update':\n          dispatch(updateTimeline(timelineId, JSON.parse(data.payload), accept));\n          break;\n        case 'delete':\n          dispatch(deleteFromTimelines(data.payload));\n          break;\n        case 'notification':\n          dispatch(updateNotifications(JSON.parse(data.payload), messages, locale));\n          break;\n        case 'conversation':\n          dispatch(updateConversations(JSON.parse(data.payload)));\n          break;\n        case 'filters_changed':\n          dispatch(fetchFilters());\n          break;\n        }\n      },\n    };\n  });\n}\n\nconst refreshHomeTimelineAndNotification = (dispatch, done) => {\n  dispatch(expandHomeTimeline({}, () => dispatch(expandNotifications({}, done))));\n};\n\nexport const connectUserStream      = () => connectTimelineStream('home', 'user', refreshHomeTimelineAndNotification);\nexport const connectCommunityStream = ({ onlyMedia } = {}) => connectTimelineStream(`community${onlyMedia ? ':media' : ''}`, `public:local${onlyMedia ? ':media' : ''}`);\nexport const connectPublicStream    = ({ onlyMedia } = {}) => connectTimelineStream(`public${onlyMedia ? ':media' : ''}`, `public${onlyMedia ? ':media' : ''}`);\nexport const connectHashtagStream   = (id, tag, accept) => connectTimelineStream(`hashtag:${id}`, `hashtag&tag=${tag}`, null, accept);\nexport const connectDirectStream    = () => connectTimelineStream('direct', 'direct');\nexport const connectListStream      = id => connectTimelineStream(`list:${id}`, `list&list=${id}`);\n"
  },
  {
    "path": "app/javascript/mastodon/actions/suggestions.js",
    "content": "import api from '../api';\nimport { importFetchedAccounts } from './importer';\n\nexport const SUGGESTIONS_FETCH_REQUEST = 'SUGGESTIONS_FETCH_REQUEST';\nexport const SUGGESTIONS_FETCH_SUCCESS = 'SUGGESTIONS_FETCH_SUCCESS';\nexport const SUGGESTIONS_FETCH_FAIL    = 'SUGGESTIONS_FETCH_FAIL';\n\nexport const SUGGESTIONS_DISMISS = 'SUGGESTIONS_DISMISS';\n\nexport function fetchSuggestions() {\n  return (dispatch, getState) => {\n    dispatch(fetchSuggestionsRequest());\n\n    api(getState).get('/api/v1/suggestions').then(response => {\n      dispatch(importFetchedAccounts(response.data));\n      dispatch(fetchSuggestionsSuccess(response.data));\n    }).catch(error => dispatch(fetchSuggestionsFail(error)));\n  };\n};\n\nexport function fetchSuggestionsRequest() {\n  return {\n    type: SUGGESTIONS_FETCH_REQUEST,\n    skipLoading: true,\n  };\n};\n\nexport function fetchSuggestionsSuccess(accounts) {\n  return {\n    type: SUGGESTIONS_FETCH_SUCCESS,\n    accounts,\n    skipLoading: true,\n  };\n};\n\nexport function fetchSuggestionsFail(error) {\n  return {\n    type: SUGGESTIONS_FETCH_FAIL,\n    error,\n    skipLoading: true,\n    skipAlert: true,\n  };\n};\n\nexport const dismissSuggestion = accountId => (dispatch, getState) => {\n  dispatch({\n    type: SUGGESTIONS_DISMISS,\n    id: accountId,\n  });\n\n  api(getState).delete(`/api/v1/suggestions/${accountId}`);\n};\n"
  },
  {
    "path": "app/javascript/mastodon/actions/timelines.js",
    "content": "import { importFetchedStatus, importFetchedStatuses } from './importer';\nimport api, { getLinks } from '../api';\nimport { Map as ImmutableMap, List as ImmutableList } from 'immutable';\n\nexport const TIMELINE_UPDATE  = 'TIMELINE_UPDATE';\nexport const TIMELINE_DELETE  = 'TIMELINE_DELETE';\nexport const TIMELINE_CLEAR   = 'TIMELINE_CLEAR';\n\nexport const TIMELINE_EXPAND_REQUEST = 'TIMELINE_EXPAND_REQUEST';\nexport const TIMELINE_EXPAND_SUCCESS = 'TIMELINE_EXPAND_SUCCESS';\nexport const TIMELINE_EXPAND_FAIL    = 'TIMELINE_EXPAND_FAIL';\n\nexport const TIMELINE_SCROLL_TOP = 'TIMELINE_SCROLL_TOP';\n\nexport const TIMELINE_CONNECT    = 'TIMELINE_CONNECT';\nexport const TIMELINE_DISCONNECT = 'TIMELINE_DISCONNECT';\n\nexport function updateTimeline(timeline, status, accept) {\n  return dispatch => {\n    if (typeof accept === 'function' && !accept(status)) {\n      return;\n    }\n\n    dispatch(importFetchedStatus(status));\n\n    dispatch({\n      type: TIMELINE_UPDATE,\n      timeline,\n      status,\n    });\n  };\n};\n\nexport function deleteFromTimelines(id) {\n  return (dispatch, getState) => {\n    const accountId  = getState().getIn(['statuses', id, 'account']);\n    const references = getState().get('statuses').filter(status => status.get('reblog') === id).map(status => [status.get('id'), status.get('account')]);\n    const reblogOf   = getState().getIn(['statuses', id, 'reblog'], null);\n\n    dispatch({\n      type: TIMELINE_DELETE,\n      id,\n      accountId,\n      references,\n      reblogOf,\n    });\n  };\n};\n\nexport function clearTimeline(timeline) {\n  return (dispatch) => {\n    dispatch({ type: TIMELINE_CLEAR, timeline });\n  };\n};\n\nconst noOp = () => {};\n\nconst parseTags = (tags = {}, mode) => {\n  return (tags[mode] || []).map((tag) => {\n    return tag.value;\n  });\n};\n\nexport function expandTimeline(timelineId, path, params = {}, done = noOp) {\n  return (dispatch, getState) => {\n    const timeline = getState().getIn(['timelines', timelineId], ImmutableMap());\n    const isLoadingMore = !!params.max_id;\n\n    if (timeline.get('isLoading')) {\n      done();\n      return;\n    }\n\n    if (!params.max_id && !params.pinned && timeline.get('items', ImmutableList()).size > 0) {\n      params.since_id = timeline.getIn(['items', 0]);\n    }\n\n    const isLoadingRecent = !!params.since_id;\n\n    dispatch(expandTimelineRequest(timelineId, isLoadingMore));\n\n    api(getState).get(path, { params }).then(response => {\n      const next = getLinks(response).refs.find(link => link.rel === 'next');\n      dispatch(importFetchedStatuses(response.data));\n      dispatch(expandTimelineSuccess(timelineId, response.data, next ? next.uri : null, response.code === 206, isLoadingRecent, isLoadingMore));\n      done();\n    }).catch(error => {\n      dispatch(expandTimelineFail(timelineId, error, isLoadingMore));\n      done();\n    });\n  };\n};\n\nexport const expandHomeTimeline            = ({ maxId } = {}, done = noOp) => expandTimeline('home', '/api/v1/timelines/home', { max_id: maxId }, done);\nexport const expandPublicTimeline          = ({ maxId, onlyMedia } = {}, done = noOp) => expandTimeline(`public${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { max_id: maxId, only_media: !!onlyMedia }, done);\nexport const expandCommunityTimeline       = ({ maxId, onlyMedia } = {}, done = noOp) => expandTimeline(`community${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { local: true, max_id: maxId, only_media: !!onlyMedia }, done);\nexport const expandAccountTimeline         = (accountId, { maxId, withReplies } = {}) => expandTimeline(`account:${accountId}${withReplies ? ':with_replies' : ''}`, `/api/v1/accounts/${accountId}/statuses`, { exclude_replies: !withReplies, max_id: maxId });\nexport const expandAccountFeaturedTimeline = accountId => expandTimeline(`account:${accountId}:pinned`, `/api/v1/accounts/${accountId}/statuses`, { pinned: true });\nexport const expandAccountMediaTimeline    = (accountId, { maxId } = {}) => expandTimeline(`account:${accountId}:media`, `/api/v1/accounts/${accountId}/statuses`, { max_id: maxId, only_media: true, limit: 40 });\nexport const expandListTimeline            = (id, { maxId } = {}, done = noOp) => expandTimeline(`list:${id}`, `/api/v1/timelines/list/${id}`, { max_id: maxId }, done);\nexport const expandHashtagTimeline         = (hashtag, { maxId, tags } = {}, done = noOp) => {\n  return expandTimeline(`hashtag:${hashtag}`, `/api/v1/timelines/tag/${hashtag}`, {\n    max_id: maxId,\n    any:    parseTags(tags, 'any'),\n    all:    parseTags(tags, 'all'),\n    none:   parseTags(tags, 'none'),\n  }, done);\n};\n\nexport function expandTimelineRequest(timeline, isLoadingMore) {\n  return {\n    type: TIMELINE_EXPAND_REQUEST,\n    timeline,\n    skipLoading: !isLoadingMore,\n  };\n};\n\nexport function expandTimelineSuccess(timeline, statuses, next, partial, isLoadingRecent, isLoadingMore) {\n  return {\n    type: TIMELINE_EXPAND_SUCCESS,\n    timeline,\n    statuses,\n    next,\n    partial,\n    isLoadingRecent,\n    skipLoading: !isLoadingMore,\n  };\n};\n\nexport function expandTimelineFail(timeline, error, isLoadingMore) {\n  return {\n    type: TIMELINE_EXPAND_FAIL,\n    timeline,\n    error,\n    skipLoading: !isLoadingMore,\n  };\n};\n\nexport function scrollTopTimeline(timeline, top) {\n  return {\n    type: TIMELINE_SCROLL_TOP,\n    timeline,\n    top,\n  };\n};\n\nexport function connectTimeline(timeline) {\n  return {\n    type: TIMELINE_CONNECT,\n    timeline,\n  };\n};\n\nexport function disconnectTimeline(timeline) {\n  return {\n    type: TIMELINE_DISCONNECT,\n    timeline,\n  };\n};\n"
  },
  {
    "path": "app/javascript/mastodon/api.js",
    "content": "import axios from 'axios';\nimport LinkHeader from 'http-link-header';\nimport ready from './ready';\n\nexport const getLinks = response => {\n  const value = response.headers.link;\n\n  if (!value) {\n    return { refs: [] };\n  }\n\n  return LinkHeader.parse(value);\n};\n\nlet csrfHeader = {};\n\nfunction setCSRFHeader() {\n  const csrfToken = document.querySelector('meta[name=csrf-token]');\n  if (csrfToken) {\n    csrfHeader['X-CSRF-Token'] = csrfToken.content;\n  }\n}\n\nready(setCSRFHeader);\n\nexport default getState => axios.create({\n  headers: Object.assign(csrfHeader, getState ? {\n    'Authorization': `Bearer ${getState().getIn(['meta', 'access_token'], '')}`,\n  } : {}),\n\n  transformResponse: [function (data) {\n    try {\n      return JSON.parse(data);\n    } catch(Exception) {\n      return data;\n    }\n  }],\n});\n"
  },
  {
    "path": "app/javascript/mastodon/base_polyfills.js",
    "content": "import 'intl';\nimport 'intl/locale-data/jsonp/en';\nimport 'es6-symbol/implement';\nimport includes from 'array-includes';\nimport assign from 'object-assign';\nimport values from 'object.values';\nimport isNaN from 'is-nan';\nimport { decode as decodeBase64 } from './utils/base64';\n\nif (!Array.prototype.includes) {\n  includes.shim();\n}\n\nif (!Object.assign) {\n  Object.assign = assign;\n}\n\nif (!Object.values) {\n  values.shim();\n}\n\nif (!Number.isNaN) {\n  Number.isNaN = isNaN;\n}\n\nif (!HTMLCanvasElement.prototype.toBlob) {\n  const BASE64_MARKER = ';base64,';\n\n  Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', {\n    value(callback, type = 'image/png', quality) {\n      const dataURL = this.toDataURL(type, quality);\n      let data;\n\n      if (dataURL.indexOf(BASE64_MARKER) >= 0) {\n        const [, base64] = dataURL.split(BASE64_MARKER);\n        data = decodeBase64(base64);\n      } else {\n        [, data] = dataURL.split(',');\n      }\n\n      callback(new Blob([data], { type }));\n    },\n  });\n}\n"
  },
  {
    "path": "app/javascript/mastodon/common.js",
    "content": "import Rails from 'rails-ujs';\n\nexport function start() {\n  require('font-awesome/css/font-awesome.css');\n  require.context('../images/', true);\n\n  try {\n    Rails.start();\n  } catch (e) {\n    // If called twice\n  }\n};\n"
  },
  {
    "path": "app/javascript/mastodon/compare_id.js",
    "content": "export default function compareId(id1, id2) {\n  if (id1 === id2) {\n    return 0;\n  }\n  if (id1.length === id2.length) {\n    return id1 > id2 ? 1 : -1;\n  } else {\n    return id1.length > id2.length ? 1 : -1;\n  }\n}\n"
  },
  {
    "path": "app/javascript/mastodon/components/__tests__/__snapshots__/autosuggest_emoji-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`<AutosuggestEmoji /> renders emoji with custom url 1`] = `\n<div\n  className=\"autosuggest-emoji\"\n>\n  <img\n    alt=\"foobar\"\n    className=\"emojione\"\n    src=\"http://example.com/emoji.png\"\n  />\n  :foobar:\n</div>\n`;\n\nexports[`<AutosuggestEmoji /> renders native emoji 1`] = `\n<div\n  className=\"autosuggest-emoji\"\n>\n  <img\n    alt=\"💙\"\n    className=\"emojione\"\n    src=\"/emoji/1f499.svg\"\n  />\n  :foobar:\n</div>\n`;\n"
  },
  {
    "path": "app/javascript/mastodon/components/__tests__/__snapshots__/avatar-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`<Avatar /> Autoplay renders a animated avatar 1`] = `\n<div\n  className=\"account__avatar\"\n  onMouseEnter={[Function]}\n  onMouseLeave={[Function]}\n  style={\n    Object {\n      \"backgroundImage\": \"url(/animated/alice.gif)\",\n      \"backgroundSize\": \"100px 100px\",\n      \"height\": \"100px\",\n      \"width\": \"100px\",\n    }\n  }\n/>\n`;\n\nexports[`<Avatar /> Still renders a still avatar 1`] = `\n<div\n  className=\"account__avatar\"\n  onMouseEnter={[Function]}\n  onMouseLeave={[Function]}\n  style={\n    Object {\n      \"backgroundImage\": \"url(/static/alice.jpg)\",\n      \"backgroundSize\": \"100px 100px\",\n      \"height\": \"100px\",\n      \"width\": \"100px\",\n    }\n  }\n/>\n`;\n"
  },
  {
    "path": "app/javascript/mastodon/components/__tests__/__snapshots__/avatar_overlay-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`<AvatarOverlay renders a overlay avatar 1`] = `\n<div\n  className=\"account__avatar-overlay\"\n>\n  <div\n    className=\"account__avatar-overlay-base\"\n    style={\n      Object {\n        \"backgroundImage\": \"url(/static/alice.jpg)\",\n      }\n    }\n  />\n  <div\n    className=\"account__avatar-overlay-overlay\"\n    style={\n      Object {\n        \"backgroundImage\": \"url(/static/eve.jpg)\",\n      }\n    }\n  />\n</div>\n`;\n"
  },
  {
    "path": "app/javascript/mastodon/components/__tests__/__snapshots__/button-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`<Button /> adds class \"button-secondary\" if props.secondary given 1`] = `\n<button\n  className=\"button button-secondary\"\n  onClick={[Function]}\n  style={\n    Object {\n      \"height\": \"36px\",\n      \"lineHeight\": \"36px\",\n      \"padding\": \"0 16px\",\n    }\n  }\n/>\n`;\n\nexports[`<Button /> renders a button element 1`] = `\n<button\n  className=\"button\"\n  onClick={[Function]}\n  style={\n    Object {\n      \"height\": \"36px\",\n      \"lineHeight\": \"36px\",\n      \"padding\": \"0 16px\",\n    }\n  }\n/>\n`;\n\nexports[`<Button /> renders a disabled attribute if props.disabled given 1`] = `\n<button\n  className=\"button\"\n  disabled={true}\n  onClick={[Function]}\n  style={\n    Object {\n      \"height\": \"36px\",\n      \"lineHeight\": \"36px\",\n      \"padding\": \"0 16px\",\n    }\n  }\n/>\n`;\n\nexports[`<Button /> renders class=\"button--block\" if props.block given 1`] = `\n<button\n  className=\"button button--block\"\n  onClick={[Function]}\n  style={\n    Object {\n      \"height\": \"36px\",\n      \"lineHeight\": \"36px\",\n      \"padding\": \"0 16px\",\n    }\n  }\n/>\n`;\n\nexports[`<Button /> renders the children 1`] = `\n<button\n  className=\"button\"\n  onClick={[Function]}\n  style={\n    Object {\n      \"height\": \"36px\",\n      \"lineHeight\": \"36px\",\n      \"padding\": \"0 16px\",\n    }\n  }\n>\n  <p>\n    children\n  </p>\n</button>\n`;\n\nexports[`<Button /> renders the given text 1`] = `\n<button\n  className=\"button\"\n  onClick={[Function]}\n  style={\n    Object {\n      \"height\": \"36px\",\n      \"lineHeight\": \"36px\",\n      \"padding\": \"0 16px\",\n    }\n  }\n>\n  foo\n</button>\n`;\n\nexports[`<Button /> renders the props.text instead of children 1`] = `\n<button\n  className=\"button\"\n  onClick={[Function]}\n  style={\n    Object {\n      \"height\": \"36px\",\n      \"lineHeight\": \"36px\",\n      \"padding\": \"0 16px\",\n    }\n  }\n>\n  foo\n</button>\n`;\n"
  },
  {
    "path": "app/javascript/mastodon/components/__tests__/__snapshots__/display_name-test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`<DisplayName /> renders display name + account name 1`] = `\n<span\n  className=\"display-name\"\n>\n  <bdi>\n    <strong\n      className=\"display-name__html\"\n      dangerouslySetInnerHTML={\n        Object {\n          \"__html\": \"<p>Foo</p>\",\n        }\n      }\n    />\n  </bdi>\n   \n  <span\n    className=\"display-name__account\"\n  >\n    @\n    bar@baz\n  </span>\n</span>\n`;\n"
  },
  {
    "path": "app/javascript/mastodon/components/__tests__/autosuggest_emoji-test.js",
    "content": "import React from 'react';\nimport renderer from 'react-test-renderer';\nimport AutosuggestEmoji from '../autosuggest_emoji';\n\ndescribe('<AutosuggestEmoji />', () => {\n  it('renders native emoji', () => {\n    const emoji = {\n      native: '💙',\n      colons: ':foobar:',\n    };\n    const component = renderer.create(<AutosuggestEmoji emoji={emoji} />);\n    const tree      = component.toJSON();\n\n    expect(tree).toMatchSnapshot();\n  });\n\n  it('renders emoji with custom url', () => {\n    const emoji = {\n      custom: true,\n      imageUrl: 'http://example.com/emoji.png',\n      native: 'foobar',\n      colons: ':foobar:',\n    };\n    const component = renderer.create(<AutosuggestEmoji emoji={emoji} />);\n    const tree      = component.toJSON();\n\n    expect(tree).toMatchSnapshot();\n  });\n});\n"
  },
  {
    "path": "app/javascript/mastodon/components/__tests__/avatar-test.js",
    "content": "import React from 'react';\nimport renderer from 'react-test-renderer';\nimport { fromJS } from 'immutable';\nimport Avatar from '../avatar';\n\ndescribe('<Avatar />', () => {\n  const account = fromJS({\n    username: 'alice',\n    acct: 'alice',\n    display_name: 'Alice',\n    avatar: '/animated/alice.gif',\n    avatar_static: '/static/alice.jpg',\n  });\n\n  const size     = 100;\n\n  describe('Autoplay', () => {\n    it('renders a animated avatar', () => {\n      const component = renderer.create(<Avatar account={account} animate size={size} />);\n      const tree      = component.toJSON();\n\n      expect(tree).toMatchSnapshot();\n    });\n  });\n\n  describe('Still', () => {\n    it('renders a still avatar', () => {\n      const component = renderer.create(<Avatar account={account} size={size} />);\n      const tree      = component.toJSON();\n\n      expect(tree).toMatchSnapshot();\n    });\n  });\n\n  // TODO add autoplay test if possible\n});\n"
  },
  {
    "path": "app/javascript/mastodon/components/__tests__/avatar_overlay-test.js",
    "content": "import React from 'react';\nimport renderer from 'react-test-renderer';\nimport { fromJS } from 'immutable';\nimport AvatarOverlay from '../avatar_overlay';\n\ndescribe('<AvatarOverlay', () => {\n  const account = fromJS({\n    username: 'alice',\n    acct: 'alice',\n    display_name: 'Alice',\n    avatar: '/animated/alice.gif',\n    avatar_static: '/static/alice.jpg',\n  });\n\n  const friend = fromJS({\n    username: 'eve',\n    acct: 'eve@blackhat.lair',\n    display_name: 'Evelyn',\n    avatar: '/animated/eve.gif',\n    avatar_static: '/static/eve.jpg',\n  });\n\n  it('renders a overlay avatar', () => {\n    const component = renderer.create(<AvatarOverlay account={account} friend={friend} />);\n    const tree      = component.toJSON();\n\n    expect(tree).toMatchSnapshot();\n  });\n});\n"
  },
  {
    "path": "app/javascript/mastodon/components/__tests__/button-test.js",
    "content": "import { shallow } from 'enzyme';\nimport React from 'react';\nimport renderer from 'react-test-renderer';\nimport Button from '../button';\n\ndescribe('<Button />', () => {\n  it('renders a button element', () => {\n    const component = renderer.create(<Button />);\n    const tree      = component.toJSON();\n\n    expect(tree).toMatchSnapshot();\n  });\n\n  it('renders the given text', () => {\n    const text      = 'foo';\n    const component = renderer.create(<Button text={text} />);\n    const tree      = component.toJSON();\n\n    expect(tree).toMatchSnapshot();\n  });\n\n  it('handles click events using the given handler', () => {\n    const handler = jest.fn();\n    const button  = shallow(<Button onClick={handler} />);\n    button.find('button').simulate('click');\n\n    expect(handler.mock.calls.length).toEqual(1);\n  });\n\n  it('does not handle click events if props.disabled given', () => {\n    const handler = jest.fn();\n    const button  = shallow(<Button onClick={handler} disabled />);\n    button.find('button').simulate('click');\n\n    expect(handler.mock.calls.length).toEqual(0);\n  });\n\n  it('renders a disabled attribute if props.disabled given', () => {\n    const component = renderer.create(<Button disabled />);\n    const tree      = component.toJSON();\n\n    expect(tree).toMatchSnapshot();\n  });\n\n  it('renders the children', () => {\n    const children  = <p>children</p>;\n    const component = renderer.create(<Button>{children}</Button>);\n    const tree      = component.toJSON();\n\n    expect(tree).toMatchSnapshot();\n  });\n\n  it('renders the props.text instead of children', () => {\n    const text      = 'foo';\n    const children  = <p>children</p>;\n    const component = renderer.create(<Button text={text}>{children}</Button>);\n    const tree      = component.toJSON();\n\n    expect(tree).toMatchSnapshot();\n  });\n\n  it('renders class=\"button--block\" if props.block given', () => {\n    const component = renderer.create(<Button block />);\n    const tree      = component.toJSON();\n\n    expect(tree).toMatchSnapshot();\n  });\n\n  it('adds class \"button-secondary\" if props.secondary given', () => {\n    const component = renderer.create(<Button secondary />);\n    const tree      = component.toJSON();\n\n    expect(tree).toMatchSnapshot();\n  });\n});\n"
  },
  {
    "path": "app/javascript/mastodon/components/__tests__/display_name-test.js",
    "content": "import React from 'react';\nimport renderer from 'react-test-renderer';\nimport { fromJS }  from 'immutable';\nimport DisplayName from '../display_name';\n\ndescribe('<DisplayName />', () => {\n  it('renders display name + account name', () => {\n    const account = fromJS({\n      username: 'bar',\n      acct: 'bar@baz',\n      display_name_html: '<p>Foo</p>',\n    });\n    const component = renderer.create(<DisplayName account={account} />);\n    const tree      = component.toJSON();\n\n    expect(tree).toMatchSnapshot();\n  });\n});\n"
  },
  {
    "path": "app/javascript/mastodon/components/account.js",
    "content": "import React, { Fragment } from 'react';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport PropTypes from 'prop-types';\nimport Avatar from './avatar';\nimport DisplayName from './display_name';\nimport Permalink from './permalink';\nimport IconButton from './icon_button';\nimport { defineMessages, injectIntl } from 'react-intl';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport { me } from '../initial_state';\n\nconst messages = defineMessages({\n  follow: { id: 'account.follow', defaultMessage: 'Follow' },\n  unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' },\n  requested: { id: 'account.requested', defaultMessage: 'Awaiting approval' },\n  unblock: { id: 'account.unblock', defaultMessage: 'Unblock @{name}' },\n  unmute: { id: 'account.unmute', defaultMessage: 'Unmute @{name}' },\n  mute_notifications: { id: 'account.mute_notifications', defaultMessage: 'Mute notifications from @{name}' },\n  unmute_notifications: { id: 'account.unmute_notifications', defaultMessage: 'Unmute notifications from @{name}' },\n});\n\nexport default @injectIntl\nclass Account extends ImmutablePureComponent {\n\n  static propTypes = {\n    account: ImmutablePropTypes.map.isRequired,\n    onFollow: PropTypes.func.isRequired,\n    onBlock: PropTypes.func.isRequired,\n    onMute: PropTypes.func.isRequired,\n    onMuteNotifications: PropTypes.func.isRequired,\n    intl: PropTypes.object.isRequired,\n    hidden: PropTypes.bool,\n    actionIcon: PropTypes.string,\n    actionTitle: PropTypes.string,\n    onActionClick: PropTypes.func,\n  };\n\n  handleFollow = () => {\n    this.props.onFollow(this.props.account);\n  }\n\n  handleBlock = () => {\n    this.props.onBlock(this.props.account);\n  }\n\n  handleMute = () => {\n    this.props.onMute(this.props.account);\n  }\n\n  handleMuteNotifications = () => {\n    this.props.onMuteNotifications(this.props.account, true);\n  }\n\n  handleUnmuteNotifications = () => {\n    this.props.onMuteNotifications(this.props.account, false);\n  }\n\n  handleAction = () => {\n    this.props.onActionClick(this.props.account);\n  }\n\n  render () {\n    const { account, intl, hidden, onActionClick, actionIcon, actionTitle } = this.props;\n\n    if (!account) {\n      return <div />;\n    }\n\n    if (hidden) {\n      return (\n        <Fragment>\n          {account.get('display_name')}\n          {account.get('username')}\n        </Fragment>\n      );\n    }\n\n    let buttons;\n\n    if (onActionClick && actionIcon) {\n      buttons = <IconButton icon={actionIcon} title={actionTitle} onClick={this.handleAction} />;\n    } else if (account.get('id') !== me && account.get('relationship', null) !== null) {\n      const following = account.getIn(['relationship', 'following']);\n      const requested = account.getIn(['relationship', 'requested']);\n      const blocking  = account.getIn(['relationship', 'blocking']);\n      const muting  = account.getIn(['relationship', 'muting']);\n\n      if (requested) {\n        buttons = <IconButton disabled icon='hourglass' title={intl.formatMessage(messages.requested)} />;\n      } else if (blocking) {\n        buttons = <IconButton active icon='unlock' title={intl.formatMessage(messages.unblock, { name: account.get('username') })} onClick={this.handleBlock} />;\n      } else if (muting) {\n        let hidingNotificationsButton;\n        if (account.getIn(['relationship', 'muting_notifications'])) {\n          hidingNotificationsButton = <IconButton active icon='bell' title={intl.formatMessage(messages.unmute_notifications, { name: account.get('username') })} onClick={this.handleUnmuteNotifications} />;\n        } else {\n          hidingNotificationsButton = <IconButton active icon='bell-slash' title={intl.formatMessage(messages.mute_notifications, { name: account.get('username')  })} onClick={this.handleMuteNotifications} />;\n        }\n        buttons = (\n          <Fragment>\n            <IconButton active icon='volume-up' title={intl.formatMessage(messages.unmute, { name: account.get('username') })} onClick={this.handleMute} />\n            {hidingNotificationsButton}\n          </Fragment>\n        );\n      } else if (!account.get('moved') || following) {\n        buttons = <IconButton icon={following ? 'user-times' : 'user-plus'} title={intl.formatMessage(following ? messages.unfollow : messages.follow)} onClick={this.handleFollow} active={following} />;\n      }\n    }\n\n    return (\n      <div className='account'>\n        <div className='account__wrapper'>\n          <Permalink key={account.get('id')} className='account__display-name' title={account.get('acct')} href={account.get('url')} to={`/accounts/${account.get('id')}`}>\n            <div className='account__avatar-wrapper'><Avatar account={account} size={36} /></div>\n            <DisplayName account={account} />\n          </Permalink>\n\n          <div className='account__relationship'>\n            {buttons}\n          </div>\n        </div>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/components/attachment_list.js",
    "content": "import React from 'react';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport PropTypes from 'prop-types';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport Icon from 'mastodon/components/icon';\n\nconst filename = url => url.split('/').pop().split('#')[0].split('?')[0];\n\nexport default class AttachmentList extends ImmutablePureComponent {\n\n  static propTypes = {\n    media: ImmutablePropTypes.list.isRequired,\n    compact: PropTypes.bool,\n  };\n\n  render () {\n    const { media, compact } = this.props;\n\n    if (compact) {\n      return (\n        <div className='attachment-list compact'>\n          <ul className='attachment-list__list'>\n            {media.map(attachment => {\n              const displayUrl = attachment.get('remote_url') || attachment.get('url');\n\n              return (\n                <li key={attachment.get('id')}>\n                  <a href={displayUrl} target='_blank' rel='noopener'><Icon id='link' /> {filename(displayUrl)}</a>\n                </li>\n              );\n            })}\n          </ul>\n        </div>\n      );\n    }\n\n    return (\n      <div className='attachment-list'>\n        <div className='attachment-list__icon'>\n          <Icon id='link' />\n        </div>\n\n        <ul className='attachment-list__list'>\n          {media.map(attachment => {\n            const displayUrl = attachment.get('remote_url') || attachment.get('url');\n\n            return (\n              <li key={attachment.get('id')}>\n                <a href={displayUrl} target='_blank' rel='noopener'>{filename(displayUrl)}</a>\n              </li>\n            );\n          })}\n        </ul>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/components/autosuggest_emoji.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport unicodeMapping from '../features/emoji/emoji_unicode_mapping_light';\n\nconst assetHost = process.env.CDN_HOST || '';\n\nexport default class AutosuggestEmoji extends React.PureComponent {\n\n  static propTypes = {\n    emoji: PropTypes.object.isRequired,\n  };\n\n  render () {\n    const { emoji } = this.props;\n    let url;\n\n    if (emoji.custom) {\n      url = emoji.imageUrl;\n    } else {\n      const mapping = unicodeMapping[emoji.native] || unicodeMapping[emoji.native.replace(/\\uFE0F$/, '')];\n\n      if (!mapping) {\n        return null;\n      }\n\n      url = `${assetHost}/emoji/${mapping.filename}.svg`;\n    }\n\n    return (\n      <div className='autosuggest-emoji'>\n        <img\n          className='emojione'\n          src={url}\n          alt={emoji.native || emoji.colons}\n        />\n\n        {emoji.colons}\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/components/autosuggest_input.js",
    "content": "import React from 'react';\nimport AutosuggestAccountContainer from '../features/compose/containers/autosuggest_account_container';\nimport AutosuggestEmoji from './autosuggest_emoji';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport PropTypes from 'prop-types';\nimport { isRtl } from '../rtl';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport classNames from 'classnames';\nimport { List as ImmutableList } from 'immutable';\n\nconst textAtCursorMatchesToken = (str, caretPosition, searchTokens) => {\n  let word;\n\n  let left  = str.slice(0, caretPosition).search(/\\S+$/);\n  let right = str.slice(caretPosition).search(/\\s/);\n\n  if (right < 0) {\n    word = str.slice(left);\n  } else {\n    word = str.slice(left, right + caretPosition);\n  }\n\n  if (!word || word.trim().length < 3 || searchTokens.indexOf(word[0]) === -1) {\n    return [null, null];\n  }\n\n  word = word.trim().toLowerCase();\n\n  if (word.length > 0) {\n    return [left + 1, word];\n  } else {\n    return [null, null];\n  }\n};\n\nexport default class AutosuggestInput extends ImmutablePureComponent {\n\n  static propTypes = {\n    value: PropTypes.string,\n    suggestions: ImmutablePropTypes.list,\n    disabled: PropTypes.bool,\n    placeholder: PropTypes.string,\n    onSuggestionSelected: PropTypes.func.isRequired,\n    onSuggestionsClearRequested: PropTypes.func.isRequired,\n    onSuggestionsFetchRequested: PropTypes.func.isRequired,\n    onChange: PropTypes.func.isRequired,\n    onKeyUp: PropTypes.func,\n    onKeyDown: PropTypes.func,\n    autoFocus: PropTypes.bool,\n    className: PropTypes.string,\n    id: PropTypes.string,\n    searchTokens: PropTypes.arrayOf(PropTypes.string),\n    maxLength: PropTypes.number,\n  };\n\n  static defaultProps = {\n    autoFocus: true,\n    searchTokens: ImmutableList(['@', ':', '#']),\n  };\n\n  state = {\n    suggestionsHidden: true,\n    focused: false,\n    selectedSuggestion: 0,\n    lastToken: null,\n    tokenStart: 0,\n  };\n\n  onChange = (e) => {\n    const [ tokenStart, token ] = textAtCursorMatchesToken(e.target.value, e.target.selectionStart, this.props.searchTokens);\n\n    if (token !== null && this.state.lastToken !== token) {\n      this.setState({ lastToken: token, selectedSuggestion: 0, tokenStart });\n      this.props.onSuggestionsFetchRequested(token);\n    } else if (token === null) {\n      this.setState({ lastToken: null });\n      this.props.onSuggestionsClearRequested();\n    }\n\n    this.props.onChange(e);\n  }\n\n  onKeyDown = (e) => {\n    const { suggestions, disabled } = this.props;\n    const { selectedSuggestion, suggestionsHidden } = this.state;\n\n    if (disabled) {\n      e.preventDefault();\n      return;\n    }\n\n    if (e.which === 229 || e.isComposing) {\n      // Ignore key events during text composition\n      // e.key may be a name of the physical key even in this case (e.x. Safari / Chrome on Mac)\n      return;\n    }\n\n    switch(e.key) {\n    case 'Escape':\n      if (suggestions.size === 0 || suggestionsHidden) {\n        document.querySelector('.ui').parentElement.focus();\n      } else {\n        e.preventDefault();\n        this.setState({ suggestionsHidden: true });\n      }\n\n      break;\n    case 'ArrowDown':\n      if (suggestions.size > 0 && !suggestionsHidden) {\n        e.preventDefault();\n        this.setState({ selectedSuggestion: Math.min(selectedSuggestion + 1, suggestions.size - 1) });\n      }\n\n      break;\n    case 'ArrowUp':\n      if (suggestions.size > 0 && !suggestionsHidden) {\n        e.preventDefault();\n        this.setState({ selectedSuggestion: Math.max(selectedSuggestion - 1, 0) });\n      }\n\n      break;\n    case 'Enter':\n    case 'Tab':\n      // Select suggestion\n      if (this.state.lastToken !== null && suggestions.size > 0 && !suggestionsHidden) {\n        e.preventDefault();\n        e.stopPropagation();\n        this.props.onSuggestionSelected(this.state.tokenStart, this.state.lastToken, suggestions.get(selectedSuggestion));\n      }\n\n      break;\n    }\n\n    if (e.defaultPrevented || !this.props.onKeyDown) {\n      return;\n    }\n\n    this.props.onKeyDown(e);\n  }\n\n  onBlur = () => {\n    this.setState({ suggestionsHidden: true, focused: false });\n  }\n\n  onFocus = () => {\n    this.setState({ focused: true });\n  }\n\n  onSuggestionClick = (e) => {\n    const suggestion = this.props.suggestions.get(e.currentTarget.getAttribute('data-index'));\n    e.preventDefault();\n    this.props.onSuggestionSelected(this.state.tokenStart, this.state.lastToken, suggestion);\n    this.input.focus();\n  }\n\n  componentWillReceiveProps (nextProps) {\n    if (nextProps.suggestions !== this.props.suggestions && nextProps.suggestions.size > 0 && this.state.suggestionsHidden && this.state.focused) {\n      this.setState({ suggestionsHidden: false });\n    }\n  }\n\n  setInput = (c) => {\n    this.input = c;\n  }\n\n  renderSuggestion = (suggestion, i) => {\n    const { selectedSuggestion } = this.state;\n    let inner, key;\n\n    if (typeof suggestion === 'object') {\n      inner = <AutosuggestEmoji emoji={suggestion} />;\n      key   = suggestion.id;\n    } else if (suggestion[0] === '#') {\n      inner = suggestion;\n      key   = suggestion;\n    } else {\n      inner = <AutosuggestAccountContainer id={suggestion} />;\n      key   = suggestion;\n    }\n\n    return (\n      <div role='button' tabIndex='0' key={key} data-index={i} className={classNames('autosuggest-textarea__suggestions__item', { selected: i === selectedSuggestion })} onMouseDown={this.onSuggestionClick}>\n        {inner}\n      </div>\n    );\n  }\n\n  render () {\n    const { value, suggestions, disabled, placeholder, onKeyUp, autoFocus, className, id, maxLength } = this.props;\n    const { suggestionsHidden } = this.state;\n    const style = { direction: 'ltr' };\n\n    if (isRtl(value)) {\n      style.direction = 'rtl';\n    }\n\n    return (\n      <div className='autosuggest-input'>\n        <label>\n          <span style={{ display: 'none' }}>{placeholder}</span>\n\n          <input\n            type='text'\n            ref={this.setInput}\n            disabled={disabled}\n            placeholder={placeholder}\n            autoFocus={autoFocus}\n            value={value}\n            onChange={this.onChange}\n            onKeyDown={this.onKeyDown}\n            onKeyUp={onKeyUp}\n            onFocus={this.onFocus}\n            onBlur={this.onBlur}\n            style={style}\n            aria-autocomplete='list'\n            id={id}\n            className={className}\n            maxLength={maxLength}\n          />\n        </label>\n\n        <div className={`autosuggest-textarea__suggestions ${suggestionsHidden || suggestions.isEmpty() ? '' : 'autosuggest-textarea__suggestions--visible'}`}>\n          {suggestions.map(this.renderSuggestion)}\n        </div>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/components/autosuggest_textarea.js",
    "content": "import React from 'react';\nimport AutosuggestAccountContainer from '../features/compose/containers/autosuggest_account_container';\nimport AutosuggestEmoji from './autosuggest_emoji';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport PropTypes from 'prop-types';\nimport { isRtl } from '../rtl';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport Textarea from 'react-textarea-autosize';\nimport classNames from 'classnames';\n\nconst textAtCursorMatchesToken = (str, caretPosition) => {\n  let word;\n\n  let left  = str.slice(0, caretPosition).search(/\\S+$/);\n  let right = str.slice(caretPosition).search(/\\s/);\n\n  if (right < 0) {\n    word = str.slice(left);\n  } else {\n    word = str.slice(left, right + caretPosition);\n  }\n\n  if (!word || word.trim().length < 3 || ['@', ':', '#'].indexOf(word[0]) === -1) {\n    return [null, null];\n  }\n\n  word = word.trim().toLowerCase();\n\n  if (word.length > 0) {\n    return [left + 1, word];\n  } else {\n    return [null, null];\n  }\n};\n\nexport default class AutosuggestTextarea extends ImmutablePureComponent {\n\n  static propTypes = {\n    value: PropTypes.string,\n    suggestions: ImmutablePropTypes.list,\n    disabled: PropTypes.bool,\n    placeholder: PropTypes.string,\n    onSuggestionSelected: PropTypes.func.isRequired,\n    onSuggestionsClearRequested: PropTypes.func.isRequired,\n    onSuggestionsFetchRequested: PropTypes.func.isRequired,\n    onChange: PropTypes.func.isRequired,\n    onKeyUp: PropTypes.func,\n    onKeyDown: PropTypes.func,\n    onPaste: PropTypes.func.isRequired,\n    autoFocus: PropTypes.bool,\n  };\n\n  static defaultProps = {\n    autoFocus: true,\n  };\n\n  state = {\n    suggestionsHidden: true,\n    focused: false,\n    selectedSuggestion: 0,\n    lastToken: null,\n    tokenStart: 0,\n  };\n\n  onChange = (e) => {\n    const [ tokenStart, token ] = textAtCursorMatchesToken(e.target.value, e.target.selectionStart);\n\n    if (token !== null && this.state.lastToken !== token) {\n      this.setState({ lastToken: token, selectedSuggestion: 0, tokenStart });\n      this.props.onSuggestionsFetchRequested(token);\n    } else if (token === null) {\n      this.setState({ lastToken: null });\n      this.props.onSuggestionsClearRequested();\n    }\n\n    this.props.onChange(e);\n  }\n\n  onKeyDown = (e) => {\n    const { suggestions, disabled } = this.props;\n    const { selectedSuggestion, suggestionsHidden } = this.state;\n\n    if (disabled) {\n      e.preventDefault();\n      return;\n    }\n\n    if (e.which === 229 || e.isComposing) {\n      // Ignore key events during text composition\n      // e.key may be a name of the physical key even in this case (e.x. Safari / Chrome on Mac)\n      return;\n    }\n\n    switch(e.key) {\n    case 'Escape':\n      if (suggestions.size === 0 || suggestionsHidden) {\n        document.querySelector('.ui').parentElement.focus();\n      } else {\n        e.preventDefault();\n        this.setState({ suggestionsHidden: true });\n      }\n\n      break;\n    case 'ArrowDown':\n      if (suggestions.size > 0 && !suggestionsHidden) {\n        e.preventDefault();\n        this.setState({ selectedSuggestion: Math.min(selectedSuggestion + 1, suggestions.size - 1) });\n      }\n\n      break;\n    case 'ArrowUp':\n      if (suggestions.size > 0 && !suggestionsHidden) {\n        e.preventDefault();\n        this.setState({ selectedSuggestion: Math.max(selectedSuggestion - 1, 0) });\n      }\n\n      break;\n    case 'Enter':\n    case 'Tab':\n      // Select suggestion\n      if (this.state.lastToken !== null && suggestions.size > 0 && !suggestionsHidden) {\n        e.preventDefault();\n        e.stopPropagation();\n        this.props.onSuggestionSelected(this.state.tokenStart, this.state.lastToken, suggestions.get(selectedSuggestion));\n      }\n\n      break;\n    }\n\n    if (e.defaultPrevented || !this.props.onKeyDown) {\n      return;\n    }\n\n    this.props.onKeyDown(e);\n  }\n\n  onBlur = () => {\n    this.setState({ suggestionsHidden: true, focused: false });\n  }\n\n  onFocus = (e) => {\n    this.setState({ focused: true });\n    if (this.props.onFocus) {\n      this.props.onFocus(e);\n    }\n  }\n\n  onSuggestionClick = (e) => {\n    const suggestion = this.props.suggestions.get(e.currentTarget.getAttribute('data-index'));\n    e.preventDefault();\n    this.props.onSuggestionSelected(this.state.tokenStart, this.state.lastToken, suggestion);\n    this.textarea.focus();\n  }\n\n  componentWillReceiveProps (nextProps) {\n    if (nextProps.suggestions !== this.props.suggestions && nextProps.suggestions.size > 0 && this.state.suggestionsHidden && this.state.focused) {\n      this.setState({ suggestionsHidden: false });\n    }\n  }\n\n  setTextarea = (c) => {\n    this.textarea = c;\n  }\n\n  onPaste = (e) => {\n    if (e.clipboardData && e.clipboardData.files.length === 1) {\n      this.props.onPaste(e.clipboardData.files);\n      e.preventDefault();\n    }\n  }\n\n  renderSuggestion = (suggestion, i) => {\n    const { selectedSuggestion } = this.state;\n    let inner, key;\n\n    if (typeof suggestion === 'object') {\n      inner = <AutosuggestEmoji emoji={suggestion} />;\n      key   = suggestion.id;\n    } else if (suggestion[0] === '#') {\n      inner = suggestion;\n      key   = suggestion;\n    } else {\n      inner = <AutosuggestAccountContainer id={suggestion} />;\n      key   = suggestion;\n    }\n\n    return (\n      <div role='button' tabIndex='0' key={key} data-index={i} className={classNames('autosuggest-textarea__suggestions__item', { selected: i === selectedSuggestion })} onMouseDown={this.onSuggestionClick}>\n        {inner}\n      </div>\n    );\n  }\n\n  render () {\n    const { value, suggestions, disabled, placeholder, onKeyUp, autoFocus, children } = this.props;\n    const { suggestionsHidden } = this.state;\n    const style = { direction: 'ltr' };\n\n    if (isRtl(value)) {\n      style.direction = 'rtl';\n    }\n\n    return [\n      <div className='compose-form__autosuggest-wrapper' key='autosuggest-wrapper'>\n        <div className='autosuggest-textarea'>\n          <label>\n            <span style={{ display: 'none' }}>{placeholder}</span>\n\n            <Textarea\n              inputRef={this.setTextarea}\n              className='autosuggest-textarea__textarea'\n              disabled={disabled}\n              placeholder={placeholder}\n              autoFocus={autoFocus}\n              value={value}\n              onChange={this.onChange}\n              onKeyDown={this.onKeyDown}\n              onKeyUp={onKeyUp}\n              onFocus={this.onFocus}\n              onBlur={this.onBlur}\n              onPaste={this.onPaste}\n              style={style}\n              aria-autocomplete='list'\n            />\n          </label>\n        </div>\n        {children}\n      </div>,\n\n      <div className='autosuggest-textarea__suggestions-wrapper' key='suggestions-wrapper'>\n        <div className={`autosuggest-textarea__suggestions ${suggestionsHidden || suggestions.isEmpty() ? '' : 'autosuggest-textarea__suggestions--visible'}`}>\n          {suggestions.map(this.renderSuggestion)}\n        </div>\n      </div>,\n    ];\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/components/avatar.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport { autoPlayGif } from '../initial_state';\n\nexport default class Avatar extends React.PureComponent {\n\n  static propTypes = {\n    account: ImmutablePropTypes.map.isRequired,\n    size: PropTypes.number.isRequired,\n    style: PropTypes.object,\n    inline: PropTypes.bool,\n    animate: PropTypes.bool,\n  };\n\n  static defaultProps = {\n    animate: autoPlayGif,\n    size: 20,\n    inline: false,\n  };\n\n  state = {\n    hovering: false,\n  };\n\n  handleMouseEnter = () => {\n    if (this.props.animate) return;\n    this.setState({ hovering: true });\n  }\n\n  handleMouseLeave = () => {\n    if (this.props.animate) return;\n    this.setState({ hovering: false });\n  }\n\n  render () {\n    const { account, size, animate, inline } = this.props;\n    const { hovering } = this.state;\n\n    const src = account.get('avatar');\n    const staticSrc = account.get('avatar_static');\n\n    let className = 'account__avatar';\n\n    if (inline) {\n      className = className + ' account__avatar-inline';\n    }\n\n    const style = {\n      ...this.props.style,\n      width: `${size}px`,\n      height: `${size}px`,\n      backgroundSize: `${size}px ${size}px`,\n    };\n\n    if (hovering || animate) {\n      style.backgroundImage = `url(${src})`;\n    } else {\n      style.backgroundImage = `url(${staticSrc})`;\n    }\n\n    return (\n      <div\n        className={className}\n        onMouseEnter={this.handleMouseEnter}\n        onMouseLeave={this.handleMouseLeave}\n        style={style}\n      />\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/components/avatar_composite.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport { autoPlayGif } from '../initial_state';\n\nexport default class AvatarComposite extends React.PureComponent {\n\n  static propTypes = {\n    accounts: ImmutablePropTypes.list.isRequired,\n    animate: PropTypes.bool,\n    size: PropTypes.number.isRequired,\n  };\n\n  static defaultProps = {\n    animate: autoPlayGif,\n  };\n\n  renderItem (account, size, index) {\n    const { animate } = this.props;\n\n    let width  = 50;\n    let height = 100;\n    let top    = 'auto';\n    let left   = 'auto';\n    let bottom = 'auto';\n    let right  = 'auto';\n\n    if (size === 1) {\n      width = 100;\n    }\n\n    if (size === 4 || (size === 3 && index > 0)) {\n      height = 50;\n    }\n\n    if (size === 2) {\n      if (index === 0) {\n        right = '2px';\n      } else {\n        left = '2px';\n      }\n    } else if (size === 3) {\n      if (index === 0) {\n        right = '2px';\n      } else if (index > 0) {\n        left = '2px';\n      }\n\n      if (index === 1) {\n        bottom = '2px';\n      } else if (index > 1) {\n        top = '2px';\n      }\n    } else if (size === 4) {\n      if (index === 0 || index === 2) {\n        right = '2px';\n      }\n\n      if (index === 1 || index === 3) {\n        left = '2px';\n      }\n\n      if (index < 2) {\n        bottom = '2px';\n      } else {\n        top = '2px';\n      }\n    }\n\n    const style = {\n      left: left,\n      top: top,\n      right: right,\n      bottom: bottom,\n      width: `${width}%`,\n      height: `${height}%`,\n      backgroundSize: 'cover',\n      backgroundImage: `url(${account.get(animate ? 'avatar' : 'avatar_static')})`,\n    };\n\n    return (\n      <div key={account.get('id')} style={style} />\n    );\n  }\n\n  render() {\n    const { accounts, size } = this.props;\n\n    return (\n      <div className='account__avatar-composite' style={{ width: `${size}px`, height: `${size}px` }}>\n        {accounts.take(4).map((account, i) => this.renderItem(account, accounts.size, i))}\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/components/avatar_overlay.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport { autoPlayGif } from '../initial_state';\n\nexport default class AvatarOverlay extends React.PureComponent {\n\n  static propTypes = {\n    account: ImmutablePropTypes.map.isRequired,\n    friend: ImmutablePropTypes.map.isRequired,\n    animate: PropTypes.bool,\n  };\n\n  static defaultProps = {\n    animate: autoPlayGif,\n  };\n\n  render() {\n    const { account, friend, animate } = this.props;\n\n    const baseStyle = {\n      backgroundImage: `url(${account.get(animate ? 'avatar' : 'avatar_static')})`,\n    };\n\n    const overlayStyle = {\n      backgroundImage: `url(${friend.get(animate ? 'avatar' : 'avatar_static')})`,\n    };\n\n    return (\n      <div className='account__avatar-overlay'>\n        <div className='account__avatar-overlay-base' style={baseStyle} />\n        <div className='account__avatar-overlay-overlay' style={overlayStyle} />\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/components/button.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport classNames from 'classnames';\n\nexport default class Button extends React.PureComponent {\n\n  static propTypes = {\n    text: PropTypes.node,\n    onClick: PropTypes.func,\n    disabled: PropTypes.bool,\n    block: PropTypes.bool,\n    secondary: PropTypes.bool,\n    size: PropTypes.number,\n    className: PropTypes.string,\n    style: PropTypes.object,\n    children: PropTypes.node,\n  };\n\n  static defaultProps = {\n    size: 36,\n  };\n\n  handleClick = (e) => {\n    if (!this.props.disabled) {\n      this.props.onClick(e);\n    }\n  }\n\n  setRef = (c) => {\n    this.node = c;\n  }\n\n  focus() {\n    this.node.focus();\n  }\n\n  render () {\n    const style = {\n      padding: `0 ${this.props.size / 2.25}px`,\n      height: `${this.props.size}px`,\n      lineHeight: `${this.props.size}px`,\n      ...this.props.style,\n    };\n\n    const className = classNames('button', this.props.className, {\n      'button-secondary': this.props.secondary,\n      'button--block': this.props.block,\n    });\n\n    return (\n      <button\n        className={className}\n        disabled={this.props.disabled}\n        onClick={this.handleClick}\n        ref={this.setRef}\n        style={style}\n      >\n        {this.props.text || this.props.children}\n      </button>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/components/column.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport detectPassiveEvents from 'detect-passive-events';\nimport { scrollTop } from '../scroll';\n\nexport default class Column extends React.PureComponent {\n\n  static propTypes = {\n    children: PropTypes.node,\n    label: PropTypes.string,\n  };\n\n  scrollTop () {\n    const scrollable = this.node.querySelector('.scrollable');\n\n    if (!scrollable) {\n      return;\n    }\n\n    this._interruptScrollAnimation = scrollTop(scrollable);\n  }\n\n  handleWheel = () => {\n    if (typeof this._interruptScrollAnimation !== 'function') {\n      return;\n    }\n\n    this._interruptScrollAnimation();\n  }\n\n  setRef = c => {\n    this.node = c;\n  }\n\n  componentDidMount () {\n    this.node.addEventListener('wheel', this.handleWheel,  detectPassiveEvents.hasSupport ? { passive: true } : false);\n  }\n\n  componentWillUnmount () {\n    this.node.removeEventListener('wheel', this.handleWheel);\n  }\n\n  render () {\n    const { label, children } = this.props;\n\n    return (\n      <div role='region' aria-label={label} className='column' ref={this.setRef}>\n        {children}\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/components/column_back_button.js",
    "content": "import React from 'react';\nimport { FormattedMessage } from 'react-intl';\nimport PropTypes from 'prop-types';\nimport Icon from 'mastodon/components/icon';\n\nexport default class ColumnBackButton extends React.PureComponent {\n\n  static contextTypes = {\n    router: PropTypes.object,\n  };\n\n  handleClick = () => {\n    if (window.history && window.history.length === 1) {\n      this.context.router.history.push('/');\n    } else {\n      this.context.router.history.goBack();\n    }\n  }\n\n  render () {\n    return (\n      <button onClick={this.handleClick} className='column-back-button'>\n        <Icon id='chevron-left' className='column-back-button__icon' fixedWidth />\n        <FormattedMessage id='column_back_button.label' defaultMessage='Back' />\n      </button>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/components/column_back_button_slim.js",
    "content": "import React from 'react';\nimport { FormattedMessage } from 'react-intl';\nimport ColumnBackButton from './column_back_button';\nimport Icon from 'mastodon/components/icon';\n\nexport default class ColumnBackButtonSlim extends ColumnBackButton {\n\n  render () {\n    return (\n      <div className='column-back-button--slim'>\n        <div role='button' tabIndex='0' onClick={this.handleClick} className='column-back-button column-back-button--slim-button'>\n          <Icon id='chevron-left' className='column-back-button__icon' fixedWidth />\n          <FormattedMessage id='column_back_button.label' defaultMessage='Back' />\n        </div>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/components/column_header.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport classNames from 'classnames';\nimport { FormattedMessage, injectIntl, defineMessages } from 'react-intl';\nimport Icon from 'mastodon/components/icon';\n\nconst messages = defineMessages({\n  show: { id: 'column_header.show_settings', defaultMessage: 'Show settings' },\n  hide: { id: 'column_header.hide_settings', defaultMessage: 'Hide settings' },\n  moveLeft: { id: 'column_header.moveLeft_settings', defaultMessage: 'Move column to the left' },\n  moveRight: { id: 'column_header.moveRight_settings', defaultMessage: 'Move column to the right' },\n});\n\nexport default @injectIntl\nclass ColumnHeader extends React.PureComponent {\n\n  static contextTypes = {\n    router: PropTypes.object,\n  };\n\n  static propTypes = {\n    intl: PropTypes.object.isRequired,\n    title: PropTypes.node,\n    icon: PropTypes.string,\n    active: PropTypes.bool,\n    multiColumn: PropTypes.bool,\n    extraButton: PropTypes.node,\n    showBackButton: PropTypes.bool,\n    children: PropTypes.node,\n    pinned: PropTypes.bool,\n    onPin: PropTypes.func,\n    onMove: PropTypes.func,\n    onClick: PropTypes.func,\n  };\n\n  state = {\n    collapsed: true,\n    animating: false,\n  };\n\n  historyBack = () => {\n    if (window.history && window.history.length === 1) {\n      this.context.router.history.push('/');\n    } else {\n      this.context.router.history.goBack();\n    }\n  }\n\n  handleToggleClick = (e) => {\n    e.stopPropagation();\n    this.setState({ collapsed: !this.state.collapsed, animating: true });\n  }\n\n  handleTitleClick = () => {\n    this.props.onClick();\n  }\n\n  handleMoveLeft = () => {\n    this.props.onMove(-1);\n  }\n\n  handleMoveRight = () => {\n    this.props.onMove(1);\n  }\n\n  handleBackClick = () => {\n    this.historyBack();\n  }\n\n  handleTransitionEnd = () => {\n    this.setState({ animating: false });\n  }\n\n  handlePin = () => {\n    if (!this.props.pinned) {\n      this.historyBack();\n    }\n    this.props.onPin();\n  }\n\n  render () {\n    const { title, icon, active, children, pinned, multiColumn, extraButton, showBackButton, intl: { formatMessage } } = this.props;\n    const { collapsed, animating } = this.state;\n\n    const wrapperClassName = classNames('column-header__wrapper', {\n      'active': active,\n    });\n\n    const buttonClassName = classNames('column-header', {\n      'active': active,\n    });\n\n    const collapsibleClassName = classNames('column-header__collapsible', {\n      'collapsed': collapsed,\n      'animating': animating,\n    });\n\n    const collapsibleButtonClassName = classNames('column-header__button', {\n      'active': !collapsed,\n    });\n\n    let extraContent, pinButton, moveButtons, backButton, collapseButton;\n\n    if (children) {\n      extraContent = (\n        <div key='extra-content' className='column-header__collapsible__extra'>\n          {children}\n        </div>\n      );\n    }\n\n    if (multiColumn && pinned) {\n      pinButton = <button key='pin-button' className='text-btn column-header__setting-btn' onClick={this.handlePin}><Icon id='times' /> <FormattedMessage id='column_header.unpin' defaultMessage='Unpin' /></button>;\n\n      moveButtons = (\n        <div key='move-buttons' className='column-header__setting-arrows'>\n          <button title={formatMessage(messages.moveLeft)} aria-label={formatMessage(messages.moveLeft)} className='text-btn column-header__setting-btn' onClick={this.handleMoveLeft}><Icon id='chevron-left' /></button>\n          <button title={formatMessage(messages.moveRight)} aria-label={formatMessage(messages.moveRight)} className='text-btn column-header__setting-btn' onClick={this.handleMoveRight}><Icon id='chevron-right' /></button>\n        </div>\n      );\n    } else if (multiColumn) {\n      pinButton = <button key='pin-button' className='text-btn column-header__setting-btn' onClick={this.handlePin}><Icon id='plus' /> <FormattedMessage id='column_header.pin' defaultMessage='Pin' /></button>;\n    }\n\n    if (!pinned && (multiColumn || showBackButton)) {\n      backButton = (\n        <button onClick={this.handleBackClick} className='column-header__back-button'>\n          <Icon id='chevron-left' className='column-back-button__icon' fixedWidth />\n          <FormattedMessage id='column_back_button.label' defaultMessage='Back' />\n        </button>\n      );\n    }\n\n    const collapsedContent = [\n      extraContent,\n    ];\n\n    if (multiColumn) {\n      collapsedContent.push(moveButtons);\n      collapsedContent.push(pinButton);\n    }\n\n    if (children || multiColumn) {\n      collapseButton = <button className={collapsibleButtonClassName} title={formatMessage(collapsed ? messages.show : messages.hide)} aria-label={formatMessage(collapsed ? messages.show : messages.hide)} aria-pressed={collapsed ? 'false' : 'true'} onClick={this.handleToggleClick}><Icon id='sliders' /></button>;\n    }\n\n    const hasTitle = icon && title;\n\n    return (\n      <div className={wrapperClassName}>\n        <h1 className={buttonClassName}>\n          {hasTitle && (\n            <button onClick={this.handleTitleClick}>\n              <Icon id={icon} fixedWidth className='column-header__icon' />\n              {title}\n            </button>\n          )}\n\n          {!hasTitle && backButton}\n\n          <div className='column-header__buttons'>\n            {hasTitle && backButton}\n            {extraButton}\n            {collapseButton}\n          </div>\n        </h1>\n\n        <div className={collapsibleClassName} tabIndex={collapsed ? -1 : null} onTransitionEnd={this.handleTransitionEnd}>\n          <div className='column-header__collapsible-inner'>\n            {(!collapsed || animating) && collapsedContent}\n          </div>\n        </div>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/components/display_name.js",
    "content": "import React from 'react';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport PropTypes from 'prop-types';\n\nexport default class DisplayName extends React.PureComponent {\n\n  static propTypes = {\n    account: ImmutablePropTypes.map.isRequired,\n    others: ImmutablePropTypes.list,\n    localDomain: PropTypes.string,\n  };\n\n  render () {\n    const { others, localDomain } = this.props;\n\n    let displayName, suffix, account;\n\n    if (others && others.size > 1) {\n      displayName = others.take(2).map(a => <bdi key={a.get('id')}><strong className='display-name__html' dangerouslySetInnerHTML={{ __html: a.get('display_name_html') }} /></bdi>).reduce((prev, cur) => [prev, ', ', cur]);\n\n      if (others.size - 2 > 0) {\n        suffix = `+${others.size - 2}`;\n      }\n    } else {\n      if (others && others.size > 0) {\n        account = others.first();\n      } else {\n        account = this.props.account;\n      }\n\n      let acct = account.get('acct');\n\n      if (acct.indexOf('@') === -1 && localDomain) {\n        acct = `${acct}@${localDomain}`;\n      }\n\n      displayName = <bdi><strong className='display-name__html' dangerouslySetInnerHTML={{ __html: account.get('display_name_html') }} /></bdi>;\n      suffix      = <span className='display-name__account'>@{acct}</span>;\n    }\n\n    return (\n      <span className='display-name'>\n        {displayName} {suffix}\n      </span>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/components/domain.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport IconButton from './icon_button';\nimport { defineMessages, injectIntl } from 'react-intl';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\n\nconst messages = defineMessages({\n  unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unhide {domain}' },\n});\n\nexport default @injectIntl\nclass Account extends ImmutablePureComponent {\n\n  static propTypes = {\n    domain: PropTypes.string,\n    onUnblockDomain: PropTypes.func.isRequired,\n    intl: PropTypes.object.isRequired,\n  };\n\n  handleDomainUnblock = () => {\n    this.props.onUnblockDomain(this.props.domain);\n  }\n\n  render () {\n    const { domain, intl } = this.props;\n\n    return (\n      <div className='domain'>\n        <div className='domain__wrapper'>\n          <span className='domain__domain-name'>\n            <strong>{domain}</strong>\n          </span>\n\n          <div className='domain__buttons'>\n            <IconButton active icon='unlock' title={intl.formatMessage(messages.unblockDomain, { domain })} onClick={this.handleDomainUnblock} />\n          </div>\n        </div>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/components/dropdown_menu.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport IconButton from './icon_button';\nimport Overlay from 'react-overlays/lib/Overlay';\nimport Motion from '../features/ui/util/optional_motion';\nimport spring from 'react-motion/lib/spring';\nimport detectPassiveEvents from 'detect-passive-events';\n\nconst listenerOptions = detectPassiveEvents.hasSupport ? { passive: true } : false;\nlet id = 0;\n\nclass DropdownMenu extends React.PureComponent {\n\n  static contextTypes = {\n    router: PropTypes.object,\n  };\n\n  static propTypes = {\n    items: PropTypes.array.isRequired,\n    onClose: PropTypes.func.isRequired,\n    style: PropTypes.object,\n    placement: PropTypes.string,\n    arrowOffsetLeft: PropTypes.string,\n    arrowOffsetTop: PropTypes.string,\n    openedViaKeyboard: PropTypes.bool,\n  };\n\n  static defaultProps = {\n    style: {},\n    placement: 'bottom',\n  };\n\n  state = {\n    mounted: false,\n  };\n\n  handleDocumentClick = e => {\n    if (this.node && !this.node.contains(e.target)) {\n      this.props.onClose();\n    }\n  }\n\n  componentDidMount () {\n    document.addEventListener('click', this.handleDocumentClick, false);\n    document.addEventListener('keydown', this.handleKeyDown, false);\n    document.addEventListener('touchend', this.handleDocumentClick, listenerOptions);\n    if (this.focusedItem && this.props.openedViaKeyboard) this.focusedItem.focus();\n    this.setState({ mounted: true });\n  }\n\n  componentWillUnmount () {\n    document.removeEventListener('click', this.handleDocumentClick, false);\n    document.removeEventListener('keydown', this.handleKeyDown, false);\n    document.removeEventListener('touchend', this.handleDocumentClick, listenerOptions);\n  }\n\n  setRef = c => {\n    this.node = c;\n  }\n\n  setFocusRef = c => {\n    this.focusedItem = c;\n  }\n\n  handleKeyDown = e => {\n    const items = Array.from(this.node.getElementsByTagName('a'));\n    const index = items.indexOf(document.activeElement);\n    let element;\n\n    switch(e.key) {\n    case 'ArrowDown':\n      element = items[index+1];\n      if (element) {\n        element.focus();\n      }\n      break;\n    case 'ArrowUp':\n      element = items[index-1];\n      if (element) {\n        element.focus();\n      }\n      break;\n    case 'Home':\n      element = items[0];\n      if (element) {\n        element.focus();\n      }\n      break;\n    case 'End':\n      element = items[items.length-1];\n      if (element) {\n        element.focus();\n      }\n      break;\n    }\n  }\n\n  handleItemKeyDown = e => {\n    if (e.key === 'Enter') {\n      this.handleClick(e);\n    }\n  }\n\n  handleClick = e => {\n    const i = Number(e.currentTarget.getAttribute('data-index'));\n    const { action, to } = this.props.items[i];\n\n    this.props.onClose();\n\n    if (typeof action === 'function') {\n      e.preventDefault();\n      action(e);\n    } else if (to) {\n      e.preventDefault();\n      this.context.router.history.push(to);\n    }\n  }\n\n  renderItem (option, i) {\n    if (option === null) {\n      return <li key={`sep-${i}`} className='dropdown-menu__separator' />;\n    }\n\n    const { text, href = '#' } = option;\n\n    return (\n      <li className='dropdown-menu__item' key={`${text}-${i}`}>\n        <a href={href} target='_blank' rel='noopener' role='button' tabIndex='0' ref={i === 0 ? this.setFocusRef : null} onClick={this.handleClick} onKeyDown={this.handleItemKeyDown} data-index={i}>\n          {text}\n        </a>\n      </li>\n    );\n  }\n\n  render () {\n    const { items, style, placement, arrowOffsetLeft, arrowOffsetTop } = this.props;\n    const { mounted } = this.state;\n\n    return (\n      <Motion defaultStyle={{ opacity: 0, scaleX: 0.85, scaleY: 0.75 }} style={{ opacity: spring(1, { damping: 35, stiffness: 400 }), scaleX: spring(1, { damping: 35, stiffness: 400 }), scaleY: spring(1, { damping: 35, stiffness: 400 }) }}>\n        {({ opacity, scaleX, scaleY }) => (\n          // It should not be transformed when mounting because the resulting\n          // size will be used to determine the coordinate of the menu by\n          // react-overlays\n          <div className={`dropdown-menu ${placement}`} style={{ ...style, opacity: opacity, transform: mounted ? `scale(${scaleX}, ${scaleY})` : null }} ref={this.setRef}>\n            <div className={`dropdown-menu__arrow ${placement}`} style={{ left: arrowOffsetLeft, top: arrowOffsetTop }} />\n\n            <ul>\n              {items.map((option, i) => this.renderItem(option, i))}\n            </ul>\n          </div>\n        )}\n      </Motion>\n    );\n  }\n\n}\n\nexport default class Dropdown extends React.PureComponent {\n\n  static contextTypes = {\n    router: PropTypes.object,\n  };\n\n  static propTypes = {\n    icon: PropTypes.string.isRequired,\n    items: PropTypes.array.isRequired,\n    size: PropTypes.number.isRequired,\n    title: PropTypes.string,\n    disabled: PropTypes.bool,\n    status: ImmutablePropTypes.map,\n    isUserTouching: PropTypes.func,\n    isModalOpen: PropTypes.bool.isRequired,\n    onOpen: PropTypes.func.isRequired,\n    onClose: PropTypes.func.isRequired,\n    dropdownPlacement: PropTypes.string,\n    openDropdownId: PropTypes.number,\n    openedViaKeyboard: PropTypes.bool,\n  };\n\n  static defaultProps = {\n    title: 'Menu',\n  };\n\n  state = {\n    id: id++,\n  };\n\n  handleClick = ({ target, type }) => {\n    if (this.state.id === this.props.openDropdownId) {\n      this.handleClose();\n    } else {\n      const { top } = target.getBoundingClientRect();\n      const placement = top * 2 < innerHeight ? 'bottom' : 'top';\n\n      this.props.onOpen(this.state.id, this.handleItemClick, placement, type !== 'click');\n    }\n  }\n\n  handleClose = () => {\n    this.props.onClose(this.state.id);\n  }\n\n  handleKeyDown = e => {\n    switch(e.key) {\n    case ' ':\n    case 'Enter':\n      this.handleClick(e);\n      e.preventDefault();\n      break;\n    case 'Escape':\n      this.handleClose();\n      break;\n    }\n  }\n\n  handleItemClick = e => {\n    const i = Number(e.currentTarget.getAttribute('data-index'));\n    const { action, to } = this.props.items[i];\n\n    this.handleClose();\n\n    if (typeof action === 'function') {\n      e.preventDefault();\n      action();\n    } else if (to) {\n      e.preventDefault();\n      this.context.router.history.push(to);\n    }\n  }\n\n  setTargetRef = c => {\n    this.target = c;\n  }\n\n  findTarget = () => {\n    return this.target;\n  }\n\n  componentWillUnmount = () => {\n    if (this.state.id === this.props.openDropdownId) {\n      this.handleClose();\n    }\n  }\n\n  render () {\n    const { icon, items, size, title, disabled, dropdownPlacement, openDropdownId, openedViaKeyboard } = this.props;\n    const open = this.state.id === openDropdownId;\n\n    return (\n      <div onKeyDown={this.handleKeyDown}>\n        <IconButton\n          icon={icon}\n          title={title}\n          active={open}\n          disabled={disabled}\n          size={size}\n          ref={this.setTargetRef}\n          onClick={this.handleClick}\n        />\n\n        <Overlay show={open} placement={dropdownPlacement} target={this.findTarget}>\n          <DropdownMenu items={items} onClose={this.handleClose} openedViaKeyboard={openedViaKeyboard} />\n        </Overlay>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/components/error_boundary.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport illustration from '../../images/elephant_ui_disappointed.svg';\n\nexport default class ErrorBoundary extends React.PureComponent {\n\n  static propTypes = {\n    children: PropTypes.node,\n  };\n\n  state = {\n    hasError: false,\n    stackTrace: undefined,\n    componentStack: undefined,\n  }\n\n  componentDidCatch(error, info) {\n    this.setState({\n      hasError: true,\n      stackTrace: error.stack,\n      componentStack: info && info.componentStack,\n    });\n  }\n\n  render() {\n    const { hasError } = this.state;\n\n    if (!hasError) {\n      return this.props.children;\n    }\n\n    return (\n      <div>\n        <img src={illustration} alt='' />\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/components/extended_video_player.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\n\nexport default class ExtendedVideoPlayer extends React.PureComponent {\n\n  static propTypes = {\n    src: PropTypes.string.isRequired,\n    alt: PropTypes.string,\n    width: PropTypes.number,\n    height: PropTypes.number,\n    time: PropTypes.number,\n    controls: PropTypes.bool.isRequired,\n    muted: PropTypes.bool.isRequired,\n    onClick: PropTypes.func,\n  };\n\n  handleLoadedData = () => {\n    if (this.props.time) {\n      this.video.currentTime = this.props.time;\n    }\n  }\n\n  componentDidMount () {\n    this.video.addEventListener('loadeddata', this.handleLoadedData);\n  }\n\n  componentWillUnmount () {\n    this.video.removeEventListener('loadeddata', this.handleLoadedData);\n  }\n\n  setRef = (c) => {\n    this.video = c;\n  }\n\n  handleClick = e => {\n    e.stopPropagation();\n    const handler = this.props.onClick;\n    if (handler) handler();\n  }\n\n  render () {\n    const { src, muted, controls, alt } = this.props;\n\n    return (\n      <div className='extended-video-player'>\n        <video\n          ref={this.setRef}\n          src={src}\n          autoPlay\n          role='button'\n          tabIndex='0'\n          aria-label={alt}\n          title={alt}\n          muted={muted}\n          controls={controls}\n          loop={!controls}\n          onClick={this.handleClick}\n        />\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/components/hashtag.js",
    "content": "import React from 'react';\nimport { Sparklines, SparklinesCurve } from 'react-sparklines';\nimport { FormattedMessage } from 'react-intl';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport Permalink from './permalink';\nimport { shortNumberFormat } from '../utils/numbers';\n\nconst Hashtag = ({ hashtag }) => (\n  <div className='trends__item'>\n    <div className='trends__item__name'>\n      <Permalink href={hashtag.get('url')} to={`/timelines/tag/${hashtag.get('name')}`}>\n        #<span>{hashtag.get('name')}</span>\n      </Permalink>\n\n      <FormattedMessage id='trends.count_by_accounts' defaultMessage='{count} {rawCount, plural, one {person} other {people}} talking' values={{ rawCount: hashtag.getIn(['history', 0, 'accounts']), count: <strong>{shortNumberFormat(hashtag.getIn(['history', 0, 'accounts']))}</strong> }} />\n    </div>\n\n    <div className='trends__item__current'>\n      {shortNumberFormat(hashtag.getIn(['history', 0, 'uses']))}\n    </div>\n\n    <div className='trends__item__sparkline'>\n      <Sparklines width={50} height={28} data={hashtag.get('history').reverse().map(day => day.get('uses')).toArray()}>\n        <SparklinesCurve style={{ fill: 'none' }} />\n      </Sparklines>\n    </div>\n  </div>\n);\n\nHashtag.propTypes = {\n  hashtag: ImmutablePropTypes.map.isRequired,\n};\n\nexport default Hashtag;\n"
  },
  {
    "path": "app/javascript/mastodon/components/icon.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport classNames from 'classnames';\n\nexport default class Icon extends React.PureComponent {\n\n  static propTypes = {\n    id: PropTypes.string.isRequired,\n    className: PropTypes.string,\n    fixedWidth: PropTypes.bool,\n  };\n\n  render () {\n    const { id, className, fixedWidth, ...other } = this.props;\n\n    return (\n      <i role='img' className={classNames('fa', `fa-${id}`, className, { 'fa-fw': fixedWidth })} {...other} />\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/components/icon_button.js",
    "content": "import React from 'react';\nimport Motion from '../features/ui/util/optional_motion';\nimport spring from 'react-motion/lib/spring';\nimport PropTypes from 'prop-types';\nimport classNames from 'classnames';\nimport Icon from 'mastodon/components/icon';\n\nexport default class IconButton extends React.PureComponent {\n\n  static propTypes = {\n    className: PropTypes.string,\n    title: PropTypes.string.isRequired,\n    icon: PropTypes.string.isRequired,\n    onClick: PropTypes.func,\n    size: PropTypes.number,\n    active: PropTypes.bool,\n    pressed: PropTypes.bool,\n    expanded: PropTypes.bool,\n    style: PropTypes.object,\n    activeStyle: PropTypes.object,\n    disabled: PropTypes.bool,\n    inverted: PropTypes.bool,\n    animate: PropTypes.bool,\n    overlay: PropTypes.bool,\n    tabIndex: PropTypes.string,\n  };\n\n  static defaultProps = {\n    size: 18,\n    active: false,\n    disabled: false,\n    animate: false,\n    overlay: false,\n    tabIndex: '0',\n  };\n\n  handleClick = (e) =>  {\n    e.preventDefault();\n\n    if (!this.props.disabled) {\n      this.props.onClick(e);\n    }\n  }\n\n  render () {\n    const style = {\n      fontSize: `${this.props.size}px`,\n      width: `${this.props.size * 1.28571429}px`,\n      height: `${this.props.size * 1.28571429}px`,\n      lineHeight: `${this.props.size}px`,\n      ...this.props.style,\n      ...(this.props.active ? this.props.activeStyle : {}),\n    };\n\n    const {\n      active,\n      animate,\n      className,\n      disabled,\n      expanded,\n      icon,\n      inverted,\n      overlay,\n      pressed,\n      tabIndex,\n      title,\n    } = this.props;\n\n    const classes = classNames(className, 'icon-button', {\n      active,\n      disabled,\n      inverted,\n      overlayed: overlay,\n    });\n\n    if (!animate) {\n      // Perf optimization: avoid unnecessary <Motion> components unless\n      // we actually need to animate.\n      return (\n        <button\n          aria-label={title}\n          aria-pressed={pressed}\n          aria-expanded={expanded}\n          title={title}\n          className={classes}\n          onClick={this.handleClick}\n          style={style}\n          tabIndex={tabIndex}\n          disabled={disabled}\n        >\n          <Icon id={icon} fixedWidth aria-hidden='true' />\n        </button>\n      );\n    }\n\n    return (\n      <Motion defaultStyle={{ rotate: active ? -360 : 0 }} style={{ rotate: animate ? spring(active ? -360 : 0, { stiffness: 120, damping: 7 }) : 0 }}>\n        {({ rotate }) => (\n          <button\n            aria-label={title}\n            aria-pressed={pressed}\n            aria-expanded={expanded}\n            title={title}\n            className={classes}\n            onClick={this.handleClick}\n            style={style}\n            tabIndex={tabIndex}\n            disabled={disabled}\n          >\n            <Icon id={icon} style={{ transform: `rotate(${rotate}deg)` }} fixedWidth aria-hidden='true' />\n          </button>\n        )}\n      </Motion>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/components/icon_with_badge.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport Icon from 'mastodon/components/icon';\n\nconst formatNumber = num => num > 40 ? '40+' : num;\n\nconst IconWithBadge = ({ id, count, className }) => (\n  <i className='icon-with-badge'>\n    <Icon id={id} fixedWidth className={className} />\n    {count > 0 && <i className='icon-with-badge__badge'>{formatNumber(count)}</i>}\n  </i>\n);\n\nIconWithBadge.propTypes = {\n  id: PropTypes.string.isRequired,\n  count: PropTypes.number.isRequired,\n  className: PropTypes.string,\n};\n\nexport default IconWithBadge;\n"
  },
  {
    "path": "app/javascript/mastodon/components/intersection_observer_article.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport scheduleIdleTask from '../features/ui/util/schedule_idle_task';\nimport getRectFromEntry from '../features/ui/util/get_rect_from_entry';\nimport { is } from 'immutable';\n\n// Diff these props in the \"rendered\" state\nconst updateOnPropsForRendered = ['id', 'index', 'listLength'];\n// Diff these props in the \"unrendered\" state\nconst updateOnPropsForUnrendered = ['id', 'index', 'listLength', 'cachedHeight'];\n\nexport default class IntersectionObserverArticle extends React.Component {\n\n  static propTypes = {\n    intersectionObserverWrapper: PropTypes.object.isRequired,\n    id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),\n    index: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),\n    listLength: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),\n    saveHeightKey: PropTypes.string,\n    cachedHeight: PropTypes.number,\n    onHeightChange: PropTypes.func,\n    children: PropTypes.node,\n  };\n\n  state = {\n    isHidden: false, // set to true in requestIdleCallback to trigger un-render\n  }\n\n  shouldComponentUpdate (nextProps, nextState) {\n    const isUnrendered = !this.state.isIntersecting && (this.state.isHidden || this.props.cachedHeight);\n    const willBeUnrendered = !nextState.isIntersecting && (nextState.isHidden || nextProps.cachedHeight);\n    if (!!isUnrendered !== !!willBeUnrendered) {\n      // If we're going from rendered to unrendered (or vice versa) then update\n      return true;\n    }\n    // Otherwise, diff based on props\n    const propsToDiff = isUnrendered ? updateOnPropsForUnrendered : updateOnPropsForRendered;\n    return !propsToDiff.every(prop => is(nextProps[prop], this.props[prop]));\n  }\n\n  componentDidMount () {\n    const { intersectionObserverWrapper, id } = this.props;\n\n    intersectionObserverWrapper.observe(\n      id,\n      this.node,\n      this.handleIntersection\n    );\n\n    this.componentMounted = true;\n  }\n\n  componentWillUnmount () {\n    const { intersectionObserverWrapper, id } = this.props;\n    intersectionObserverWrapper.unobserve(id, this.node);\n\n    this.componentMounted = false;\n  }\n\n  handleIntersection = (entry) => {\n    this.entry = entry;\n\n    scheduleIdleTask(this.calculateHeight);\n    this.setState(this.updateStateAfterIntersection);\n  }\n\n  updateStateAfterIntersection = (prevState) => {\n    if (prevState.isIntersecting !== false && !this.entry.isIntersecting) {\n      scheduleIdleTask(this.hideIfNotIntersecting);\n    }\n    return {\n      isIntersecting: this.entry.isIntersecting,\n      isHidden: false,\n    };\n  }\n\n  calculateHeight = () => {\n    const { onHeightChange, saveHeightKey, id } = this.props;\n    // save the height of the fully-rendered element (this is expensive\n    // on Chrome, where we need to fall back to getBoundingClientRect)\n    this.height = getRectFromEntry(this.entry).height;\n\n    if (onHeightChange && saveHeightKey) {\n      onHeightChange(saveHeightKey, id, this.height);\n    }\n  }\n\n  hideIfNotIntersecting = () => {\n    if (!this.componentMounted) {\n      return;\n    }\n\n    // When the browser gets a chance, test if we're still not intersecting,\n    // and if so, set our isHidden to true to trigger an unrender. The point of\n    // this is to save DOM nodes and avoid using up too much memory.\n    // See: https://github.com/tootsuite/mastodon/issues/2900\n    this.setState((prevState) => ({ isHidden: !prevState.isIntersecting }));\n  }\n\n  handleRef = (node) => {\n    this.node = node;\n  }\n\n  render () {\n    const { children, id, index, listLength, cachedHeight } = this.props;\n    const { isIntersecting, isHidden } = this.state;\n\n    if (!isIntersecting && (isHidden || cachedHeight)) {\n      return (\n        <article\n          ref={this.handleRef}\n          aria-posinset={index + 1}\n          aria-setsize={listLength}\n          style={{ height: `${this.height || cachedHeight}px`, opacity: 0, overflow: 'hidden' }}\n          data-id={id}\n          tabIndex='0'\n        >\n          {children && React.cloneElement(children, { hidden: true })}\n        </article>\n      );\n    }\n\n    return (\n      <article ref={this.handleRef} aria-posinset={index + 1} aria-setsize={listLength} data-id={id} tabIndex='0'>\n        {children && React.cloneElement(children, { hidden: false })}\n      </article>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/components/load_gap.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport { injectIntl, defineMessages } from 'react-intl';\nimport Icon from 'mastodon/components/icon';\n\nconst messages = defineMessages({\n  load_more: { id: 'status.load_more', defaultMessage: 'Load more' },\n});\n\nexport default @injectIntl\nclass LoadGap extends React.PureComponent {\n\n  static propTypes = {\n    disabled: PropTypes.bool,\n    maxId: PropTypes.string,\n    onClick: PropTypes.func.isRequired,\n    intl: PropTypes.object.isRequired,\n  };\n\n  handleClick = () => {\n    this.props.onClick(this.props.maxId);\n  }\n\n  render () {\n    const { disabled, intl } = this.props;\n\n    return (\n      <button className='load-more load-gap' disabled={disabled} onClick={this.handleClick} aria-label={intl.formatMessage(messages.load_more)}>\n        <Icon id='ellipsis-h' />\n      </button>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/components/load_more.js",
    "content": "import React from 'react';\nimport { FormattedMessage } from 'react-intl';\nimport PropTypes from 'prop-types';\n\nexport default class LoadMore extends React.PureComponent {\n\n  static propTypes = {\n    onClick: PropTypes.func,\n    disabled: PropTypes.bool,\n    visible: PropTypes.bool,\n  }\n\n  static defaultProps = {\n    visible: true,\n  }\n\n  render() {\n    const { disabled, visible } = this.props;\n\n    return (\n      <button className='load-more' disabled={disabled || !visible} style={{ visibility: visible ? 'visible' : 'hidden' }} onClick={this.props.onClick}>\n        <FormattedMessage id='status.load_more' defaultMessage='Load more' />\n      </button>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/components/loading_indicator.js",
    "content": "import React from 'react';\nimport { FormattedMessage } from 'react-intl';\n\nconst LoadingIndicator = () => (\n  <div className='loading-indicator'>\n    <div className='loading-indicator__figure' />\n    <FormattedMessage id='loading_indicator.label' defaultMessage='Loading...' />\n  </div>\n);\n\nexport default LoadingIndicator;\n"
  },
  {
    "path": "app/javascript/mastodon/components/media_gallery.js",
    "content": "import React from 'react';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport PropTypes from 'prop-types';\nimport { is } from 'immutable';\nimport IconButton from './icon_button';\nimport { defineMessages, injectIntl, FormattedMessage } from 'react-intl';\nimport { isIOS } from '../is_mobile';\nimport classNames from 'classnames';\nimport { autoPlayGif, displayMedia } from '../initial_state';\nimport { decode } from 'blurhash';\n\nconst messages = defineMessages({\n  toggle_visible: { id: 'media_gallery.toggle_visible', defaultMessage: 'Toggle visibility' },\n});\n\nclass Item extends React.PureComponent {\n\n  static propTypes = {\n    attachment: ImmutablePropTypes.map.isRequired,\n    standalone: PropTypes.bool,\n    index: PropTypes.number.isRequired,\n    size: PropTypes.number.isRequired,\n    onClick: PropTypes.func.isRequired,\n    displayWidth: PropTypes.number,\n    visible: PropTypes.bool.isRequired,\n  };\n\n  static defaultProps = {\n    standalone: false,\n    index: 0,\n    size: 1,\n  };\n\n  state = {\n    loaded: false,\n  };\n\n  handleMouseEnter = (e) => {\n    if (this.hoverToPlay()) {\n      e.target.play();\n    }\n  }\n\n  handleMouseLeave = (e) => {\n    if (this.hoverToPlay()) {\n      e.target.pause();\n      e.target.currentTime = 0;\n    }\n  }\n\n  hoverToPlay () {\n    const { attachment } = this.props;\n    return !autoPlayGif && attachment.get('type') === 'gifv';\n  }\n\n  handleClick = (e) => {\n    const { index, onClick } = this.props;\n\n    if (e.button === 0 && !(e.ctrlKey || e.metaKey)) {\n      if (this.hoverToPlay()) {\n        e.target.pause();\n        e.target.currentTime = 0;\n      }\n      e.preventDefault();\n      onClick(index);\n    }\n\n    e.stopPropagation();\n  }\n\n  componentDidMount () {\n    if (this.props.attachment.get('blurhash')) {\n      this._decode();\n    }\n  }\n\n  componentDidUpdate (prevProps) {\n    if (prevProps.attachment.get('blurhash') !== this.props.attachment.get('blurhash') && this.props.attachment.get('blurhash')) {\n      this._decode();\n    }\n  }\n\n  _decode () {\n    const hash   = this.props.attachment.get('blurhash');\n    const pixels = decode(hash, 32, 32);\n\n    if (pixels) {\n      const ctx       = this.canvas.getContext('2d');\n      const imageData = new ImageData(pixels, 32, 32);\n\n      ctx.putImageData(imageData, 0, 0);\n    }\n  }\n\n  setCanvasRef = c => {\n    this.canvas = c;\n  }\n\n  handleImageLoad = () => {\n    this.setState({ loaded: true });\n  }\n\n  render () {\n    const { attachment, index, size, standalone, displayWidth, visible } = this.props;\n\n    let width  = 50;\n    let height = 100;\n    let top    = 'auto';\n    let left   = 'auto';\n    let bottom = 'auto';\n    let right  = 'auto';\n\n    if (size === 1) {\n      width = 100;\n    }\n\n    if (size === 4 || (size === 3 && index > 0)) {\n      height = 50;\n    }\n\n    if (size === 2) {\n      if (index === 0) {\n        right = '2px';\n      } else {\n        left = '2px';\n      }\n    } else if (size === 3) {\n      if (index === 0) {\n        right = '2px';\n      } else if (index > 0) {\n        left = '2px';\n      }\n\n      if (index === 1) {\n        bottom = '2px';\n      } else if (index > 1) {\n        top = '2px';\n      }\n    } else if (size === 4) {\n      if (index === 0 || index === 2) {\n        right = '2px';\n      }\n\n      if (index === 1 || index === 3) {\n        left = '2px';\n      }\n\n      if (index < 2) {\n        bottom = '2px';\n      } else {\n        top = '2px';\n      }\n    }\n\n    let thumbnail = '';\n\n    if (attachment.get('type') === 'unknown') {\n      return (\n        <div className={classNames('media-gallery__item', { standalone })} key={attachment.get('id')} style={{ left: left, top: top, right: right, bottom: bottom, width: `${width}%`, height: `${height}%` }}>\n          <a className='media-gallery__item-thumbnail' href={attachment.get('remote_url')} target='_blank' style={{ cursor: 'pointer' }}>\n            <canvas width={32} height={32} ref={this.setCanvasRef} className='media-gallery__preview' />\n          </a>\n        </div>\n      );\n    } else if (attachment.get('type') === 'image') {\n      const previewUrl   = attachment.get('preview_url');\n      const previewWidth = attachment.getIn(['meta', 'small', 'width']);\n\n      const originalUrl   = attachment.get('url');\n      const originalWidth = attachment.getIn(['meta', 'original', 'width']);\n\n      const hasSize = typeof originalWidth === 'number' && typeof previewWidth === 'number';\n\n      const srcSet = hasSize ? `${originalUrl} ${originalWidth}w, ${previewUrl} ${previewWidth}w` : null;\n      const sizes  = hasSize && (displayWidth > 0) ? `${displayWidth * (width / 100)}px` : null;\n\n      const focusX = attachment.getIn(['meta', 'focus', 'x']) || 0;\n      const focusY = attachment.getIn(['meta', 'focus', 'y']) || 0;\n      const x      = ((focusX /  2) + .5) * 100;\n      const y      = ((focusY / -2) + .5) * 100;\n\n      thumbnail = (\n        <a\n          className='media-gallery__item-thumbnail'\n          href={attachment.get('remote_url') || originalUrl}\n          onClick={this.handleClick}\n          target='_blank'\n        >\n          <img\n            src={previewUrl}\n            srcSet={srcSet}\n            sizes={sizes}\n            alt={attachment.get('description')}\n            title={attachment.get('description')}\n            style={{ objectPosition: `${x}% ${y}%` }}\n            onLoad={this.handleImageLoad}\n          />\n        </a>\n      );\n    } else if (attachment.get('type') === 'gifv') {\n      const autoPlay = !isIOS() && autoPlayGif;\n\n      thumbnail = (\n        <div className={classNames('media-gallery__gifv', { autoplay: autoPlay })}>\n          <video\n            className='media-gallery__item-gifv-thumbnail'\n            aria-label={attachment.get('description')}\n            title={attachment.get('description')}\n            role='application'\n            src={attachment.get('url')}\n            onClick={this.handleClick}\n            onMouseEnter={this.handleMouseEnter}\n            onMouseLeave={this.handleMouseLeave}\n            autoPlay={autoPlay}\n            loop\n            muted\n          />\n\n          <span className='media-gallery__gifv__label'>GIF</span>\n        </div>\n      );\n    }\n\n    return (\n      <div className={classNames('media-gallery__item', { standalone })} key={attachment.get('id')} style={{ left: left, top: top, right: right, bottom: bottom, width: `${width}%`, height: `${height}%` }}>\n        <canvas width={32} height={32} ref={this.setCanvasRef} className={classNames('media-gallery__preview', { 'media-gallery__preview--hidden': visible && this.state.loaded })} />\n        {visible && thumbnail}\n      </div>\n    );\n  }\n\n}\n\nexport default @injectIntl\nclass MediaGallery extends React.PureComponent {\n\n  static propTypes = {\n    sensitive: PropTypes.bool,\n    standalone: PropTypes.bool,\n    media: ImmutablePropTypes.list.isRequired,\n    size: PropTypes.object,\n    height: PropTypes.number.isRequired,\n    onOpenMedia: PropTypes.func.isRequired,\n    intl: PropTypes.object.isRequired,\n    defaultWidth: PropTypes.number,\n    cacheWidth: PropTypes.func,\n    visible: PropTypes.bool,\n    onToggleVisibility: PropTypes.func,\n  };\n\n  static defaultProps = {\n    standalone: false,\n  };\n\n  state = {\n    visible: this.props.visible !== undefined ? this.props.visible : (displayMedia !== 'hide_all' && !this.props.sensitive || displayMedia === 'show_all'),\n    width: this.props.defaultWidth,\n  };\n\n  componentWillReceiveProps (nextProps) {\n    if (!is(nextProps.media, this.props.media) && nextProps.visible === undefined) {\n      this.setState({ visible: displayMedia !== 'hide_all' && !nextProps.sensitive || displayMedia === 'show_all' });\n    } else if (!is(nextProps.visible, this.props.visible) && nextProps.visible !== undefined) {\n      this.setState({ visible: nextProps.visible });\n    }\n  }\n\n  handleOpen = () => {\n    if (this.props.onToggleVisibility) {\n      this.props.onToggleVisibility();\n    } else {\n      this.setState({ visible: !this.state.visible });\n    }\n  }\n\n  handleClick = (index) => {\n    this.props.onOpenMedia(this.props.media, index);\n  }\n\n  handleRef = (node) => {\n    if (node /*&& this.isStandaloneEligible()*/) {\n      // offsetWidth triggers a layout, so only calculate when we need to\n      if (this.props.cacheWidth) this.props.cacheWidth(node.offsetWidth);\n\n      this.setState({\n        width: node.offsetWidth,\n      });\n    }\n  }\n\n  isStandaloneEligible() {\n    const { media, standalone } = this.props;\n    return standalone && media.size === 1 && media.getIn([0, 'meta', 'small', 'aspect']);\n  }\n\n  render () {\n    const { media, intl, sensitive, height, defaultWidth } = this.props;\n    const { visible } = this.state;\n\n    const width = this.state.width || defaultWidth;\n\n    let children, spoilerButton;\n\n    const style = {};\n\n    if (this.isStandaloneEligible()) {\n      if (width) {\n        style.height = width / this.props.media.getIn([0, 'meta', 'small', 'aspect']);\n      }\n    } else if (width) {\n      style.height = width / (16/9);\n    } else {\n      style.height = height;\n    }\n\n    const size = media.take(4).size;\n\n    if (this.isStandaloneEligible()) {\n      children = <Item standalone onClick={this.handleClick} attachment={media.get(0)} displayWidth={width} visible={visible} />;\n    } else {\n      children = media.take(4).map((attachment, i) => <Item key={attachment.get('id')} onClick={this.handleClick} attachment={attachment} index={i} size={size} displayWidth={width} visible={visible} />);\n    }\n\n    if (visible) {\n      spoilerButton = <IconButton title={intl.formatMessage(messages.toggle_visible)} icon='eye-slash' overlay onClick={this.handleOpen} />;\n    } else {\n      spoilerButton = (\n        <button type='button' onClick={this.handleOpen} className='spoiler-button__overlay'>\n          <span className='spoiler-button__overlay__label'>{sensitive ? <FormattedMessage id='status.sensitive_warning' defaultMessage='Sensitive content' /> : <FormattedMessage id='status.media_hidden' defaultMessage='Media hidden' />}</span>\n        </button>\n      );\n    }\n\n    return (\n      <div className='media-gallery' style={style} ref={this.handleRef}>\n        <div className={classNames('spoiler-button', { 'spoiler-button--minified': visible })}>\n          {spoilerButton}\n        </div>\n\n        {children}\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/components/missing_indicator.js",
    "content": "import React from 'react';\nimport { FormattedMessage } from 'react-intl';\n\nconst MissingIndicator = () => (\n  <div className='regeneration-indicator missing-indicator'>\n    <div>\n      <div className='regeneration-indicator__figure' />\n\n      <div className='regeneration-indicator__label'>\n        <FormattedMessage id='missing_indicator.label' tagName='strong' defaultMessage='Not found' />\n        <FormattedMessage id='missing_indicator.sublabel' defaultMessage='This resource could not be found' />\n      </div>\n    </div>\n  </div>\n);\n\nexport default MissingIndicator;\n"
  },
  {
    "path": "app/javascript/mastodon/components/modal_root.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\n\nexport default class ModalRoot extends React.PureComponent {\n\n  static propTypes = {\n    children: PropTypes.node,\n    onClose: PropTypes.func.isRequired,\n  };\n\n  state = {\n    revealed: !!this.props.children,\n  };\n\n  activeElement = this.state.revealed ? document.activeElement : null;\n\n  handleKeyUp = (e) => {\n    if ((e.key === 'Escape' || e.key === 'Esc' || e.keyCode === 27)\n         && !!this.props.children) {\n      this.props.onClose();\n    }\n  }\n\n  componentDidMount () {\n    window.addEventListener('keyup', this.handleKeyUp, false);\n  }\n\n  componentWillReceiveProps (nextProps) {\n    if (!!nextProps.children && !this.props.children) {\n      this.activeElement = document.activeElement;\n\n      this.getSiblings().forEach(sibling => sibling.setAttribute('inert', true));\n    } else if (!nextProps.children) {\n      this.setState({ revealed: false });\n    }\n    if (!nextProps.children && !!this.props.children) {\n      this.activeElement.focus();\n      this.activeElement = null;\n    }\n  }\n\n  componentDidUpdate (prevProps) {\n    if (!this.props.children && !!prevProps.children) {\n      this.getSiblings().forEach(sibling => sibling.removeAttribute('inert'));\n    }\n    if (this.props.children) {\n      requestAnimationFrame(() => {\n        this.setState({ revealed: true });\n      });\n    }\n  }\n\n  componentWillUnmount () {\n    window.removeEventListener('keyup', this.handleKeyUp);\n  }\n\n  getSiblings = () => {\n    return Array(...this.node.parentElement.childNodes).filter(node => node !== this.node);\n  }\n\n  setRef = ref => {\n    this.node = ref;\n  }\n\n  render () {\n    const { children, onClose } = this.props;\n    const { revealed } = this.state;\n    const visible = !!children;\n\n    if (!visible) {\n      return (\n        <div className='modal-root' ref={this.setRef} style={{ opacity: 0 }} />\n      );\n    }\n\n    return (\n      <div className='modal-root' ref={this.setRef} style={{ opacity: revealed ? 1 : 0 }}>\n        <div style={{ pointerEvents: visible ? 'auto' : 'none' }}>\n          <div role='presentation' className='modal-root__overlay' onClick={onClose} />\n          <div role='dialog' className='modal-root__container'>{children}</div>\n        </div>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/components/permalink.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\n\nexport default class Permalink extends React.PureComponent {\n\n  static contextTypes = {\n    router: PropTypes.object,\n  };\n\n  static propTypes = {\n    className: PropTypes.string,\n    href: PropTypes.string.isRequired,\n    to: PropTypes.string.isRequired,\n    children: PropTypes.node,\n    onInterceptClick: PropTypes.func,\n  };\n\n  handleClick = e => {\n    if (this.props.onInterceptClick && this.props.onInterceptClick()) {\n      e.preventDefault();\n      return;\n    }\n\n    if (this.context.router && e.button === 0 && !(e.ctrlKey || e.metaKey)) {\n      e.preventDefault();\n      this.context.router.history.push(this.props.to);\n    }\n  }\n\n  render () {\n    const { href, children, className, onInterceptClick, ...other } = this.props;\n\n    return (\n      <a target='_blank' href={href} onClick={this.handleClick} {...other} className={`permalink${className ? ' ' + className : ''}`}>\n        {children}\n      </a>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/components/poll.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport { defineMessages, injectIntl, FormattedMessage } from 'react-intl';\nimport classNames from 'classnames';\nimport { vote, fetchPoll } from 'mastodon/actions/polls';\nimport Motion from 'mastodon/features/ui/util/optional_motion';\nimport spring from 'react-motion/lib/spring';\nimport escapeTextContentForBrowser from 'escape-html';\nimport emojify from 'mastodon/features/emoji/emoji';\nimport RelativeTimestamp from './relative_timestamp';\n\nconst messages = defineMessages({\n  closed: { id: 'poll.closed', defaultMessage: 'Closed' },\n});\n\nconst makeEmojiMap = record => record.get('emojis').reduce((obj, emoji) => {\n  obj[`:${emoji.get('shortcode')}:`] = emoji.toJS();\n  return obj;\n}, {});\n\nexport default @injectIntl\nclass Poll extends ImmutablePureComponent {\n\n  static propTypes = {\n    poll: ImmutablePropTypes.map,\n    intl: PropTypes.object.isRequired,\n    dispatch: PropTypes.func,\n    disabled: PropTypes.bool,\n  };\n\n  state = {\n    selected: {},\n  };\n\n  handleOptionChange = e => {\n    const { target: { value } } = e;\n\n    if (this.props.poll.get('multiple')) {\n      const tmp = { ...this.state.selected };\n      if (tmp[value]) {\n        delete tmp[value];\n      } else {\n        tmp[value] = true;\n      }\n      this.setState({ selected: tmp });\n    } else {\n      const tmp = {};\n      tmp[value] = true;\n      this.setState({ selected: tmp });\n    }\n  };\n\n  handleVote = () => {\n    if (this.props.disabled) {\n      return;\n    }\n\n    this.props.dispatch(vote(this.props.poll.get('id'), Object.keys(this.state.selected)));\n  };\n\n  handleRefresh = () => {\n    if (this.props.disabled) {\n      return;\n    }\n\n    this.props.dispatch(fetchPoll(this.props.poll.get('id')));\n  };\n\n  renderOption (option, optionIndex) {\n    const { poll, disabled } = this.props;\n    const percent            = poll.get('votes_count') === 0 ? 0 : (option.get('votes_count') / poll.get('votes_count')) * 100;\n    const leading            = poll.get('options').filterNot(other => other.get('title') === option.get('title')).every(other => option.get('votes_count') > other.get('votes_count'));\n    const active             = !!this.state.selected[`${optionIndex}`];\n    const showResults        = poll.get('voted') || poll.get('expired');\n\n    let titleEmojified = option.get('title_emojified');\n    if (!titleEmojified) {\n      const emojiMap = makeEmojiMap(poll);\n      titleEmojified = emojify(escapeTextContentForBrowser(option.get('title')), emojiMap);\n    }\n\n    return (\n      <li key={option.get('title')}>\n        {showResults && (\n          <Motion defaultStyle={{ width: 0 }} style={{ width: spring(percent, { stiffness: 180, damping: 12 }) }}>\n            {({ width }) =>\n              <span className={classNames('poll__chart', { leading })} style={{ width: `${width}%` }} />\n            }\n          </Motion>\n        )}\n\n        <label className={classNames('poll__text', { selectable: !showResults })}>\n          <input\n            name='vote-options'\n            type={poll.get('multiple') ? 'checkbox' : 'radio'}\n            value={optionIndex}\n            checked={active}\n            onChange={this.handleOptionChange}\n            disabled={disabled}\n          />\n\n          {!showResults && <span className={classNames('poll__input', { checkbox: poll.get('multiple'), active })} />}\n          {showResults && <span className='poll__number'>{Math.round(percent)}%</span>}\n\n          <span dangerouslySetInnerHTML={{ __html: titleEmojified }} />\n        </label>\n      </li>\n    );\n  }\n\n  render () {\n    const { poll, intl } = this.props;\n\n    if (!poll) {\n      return null;\n    }\n\n    const timeRemaining = poll.get('expired') ? intl.formatMessage(messages.closed) : <RelativeTimestamp timestamp={poll.get('expires_at')} futureDate />;\n    const showResults   = poll.get('voted') || poll.get('expired');\n    const disabled      = this.props.disabled || Object.entries(this.state.selected).every(item => !item);\n\n    return (\n      <div className='poll'>\n        <ul>\n          {poll.get('options').map((option, i) => this.renderOption(option, i))}\n        </ul>\n\n        <div className='poll__footer'>\n          {!showResults && <button className='button button-secondary' disabled={disabled} onClick={this.handleVote}><FormattedMessage id='poll.vote' defaultMessage='Vote' /></button>}\n          {showResults && !this.props.disabled && <span><button className='poll__link' onClick={this.handleRefresh}><FormattedMessage id='poll.refresh' defaultMessage='Refresh' /></button> · </span>}\n          <FormattedMessage id='poll.total_votes' defaultMessage='{count, plural, one {# vote} other {# votes}}' values={{ count: poll.get('votes_count') }} />\n          {poll.get('expires_at') && <span> · {timeRemaining}</span>}\n        </div>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/components/relative_timestamp.js",
    "content": "import React from 'react';\nimport { injectIntl, defineMessages } from 'react-intl';\nimport PropTypes from 'prop-types';\n\nconst messages = defineMessages({\n  just_now: { id: 'relative_time.just_now', defaultMessage: 'now' },\n  seconds: { id: 'relative_time.seconds', defaultMessage: '{number}s' },\n  minutes: { id: 'relative_time.minutes', defaultMessage: '{number}m' },\n  hours: { id: 'relative_time.hours', defaultMessage: '{number}h' },\n  days: { id: 'relative_time.days', defaultMessage: '{number}d' },\n  moments_remaining: { id: 'time_remaining.moments', defaultMessage: 'Moments remaining' },\n  seconds_remaining: { id: 'time_remaining.seconds', defaultMessage: '{number, plural, one {# second} other {# seconds}} left' },\n  minutes_remaining: { id: 'time_remaining.minutes', defaultMessage: '{number, plural, one {# minute} other {# minutes}} left' },\n  hours_remaining: { id: 'time_remaining.hours', defaultMessage: '{number, plural, one {# hour} other {# hours}} left' },\n  days_remaining: { id: 'time_remaining.days', defaultMessage: '{number, plural, one {# day} other {# days}} left' },\n});\n\nconst dateFormatOptions = {\n  hour12: false,\n  year: 'numeric',\n  month: 'short',\n  day: '2-digit',\n  hour: '2-digit',\n  minute: '2-digit',\n};\n\nconst shortDateFormatOptions = {\n  month: 'short',\n  day: 'numeric',\n};\n\nconst SECOND = 1000;\nconst MINUTE = 1000 * 60;\nconst HOUR   = 1000 * 60 * 60;\nconst DAY    = 1000 * 60 * 60 * 24;\n\nconst MAX_DELAY = 2147483647;\n\nconst selectUnits = delta => {\n  const absDelta = Math.abs(delta);\n\n  if (absDelta < MINUTE) {\n    return 'second';\n  } else if (absDelta < HOUR) {\n    return 'minute';\n  } else if (absDelta < DAY) {\n    return 'hour';\n  }\n\n  return 'day';\n};\n\nconst getUnitDelay = units => {\n  switch (units) {\n  case 'second':\n    return SECOND;\n  case 'minute':\n    return MINUTE;\n  case 'hour':\n    return HOUR;\n  case 'day':\n    return DAY;\n  default:\n    return MAX_DELAY;\n  }\n};\n\nexport const timeAgoString = (intl, date, now, year) => {\n  const delta = now - date.getTime();\n\n  let relativeTime;\n\n  if (delta < 10 * SECOND) {\n    relativeTime = intl.formatMessage(messages.just_now);\n  } else if (delta < 7 * DAY) {\n    if (delta < MINUTE) {\n      relativeTime = intl.formatMessage(messages.seconds, { number: Math.floor(delta / SECOND) });\n    } else if (delta < HOUR) {\n      relativeTime = intl.formatMessage(messages.minutes, { number: Math.floor(delta / MINUTE) });\n    } else if (delta < DAY) {\n      relativeTime = intl.formatMessage(messages.hours, { number: Math.floor(delta / HOUR) });\n    } else {\n      relativeTime = intl.formatMessage(messages.days, { number: Math.floor(delta / DAY) });\n    }\n  } else if (date.getFullYear() === year) {\n    relativeTime = intl.formatDate(date, shortDateFormatOptions);\n  } else {\n    relativeTime = intl.formatDate(date, { ...shortDateFormatOptions, year: 'numeric' });\n  }\n\n  return relativeTime;\n};\n\nconst timeRemainingString = (intl, date, now) => {\n  const delta = date.getTime() - now;\n\n  let relativeTime;\n\n  if (delta < 10 * SECOND) {\n    relativeTime = intl.formatMessage(messages.moments_remaining);\n  } else if (delta < MINUTE) {\n    relativeTime = intl.formatMessage(messages.seconds_remaining, { number: Math.floor(delta / SECOND) });\n  } else if (delta < HOUR) {\n    relativeTime = intl.formatMessage(messages.minutes_remaining, { number: Math.floor(delta / MINUTE) });\n  } else if (delta < DAY) {\n    relativeTime = intl.formatMessage(messages.hours_remaining, { number: Math.floor(delta / HOUR) });\n  } else {\n    relativeTime = intl.formatMessage(messages.days_remaining, { number: Math.floor(delta / DAY) });\n  }\n\n  return relativeTime;\n};\n\nexport default @injectIntl\nclass RelativeTimestamp extends React.Component {\n\n  static propTypes = {\n    intl: PropTypes.object.isRequired,\n    timestamp: PropTypes.string.isRequired,\n    year: PropTypes.number.isRequired,\n    futureDate: PropTypes.bool,\n  };\n\n  state = {\n    now: this.props.intl.now(),\n  };\n\n  static defaultProps = {\n    year: (new Date()).getFullYear(),\n  };\n\n  shouldComponentUpdate (nextProps, nextState) {\n    // As of right now the locale doesn't change without a new page load,\n    // but we might as well check in case that ever changes.\n    return this.props.timestamp !== nextProps.timestamp ||\n      this.props.intl.locale !== nextProps.intl.locale ||\n      this.state.now !== nextState.now;\n  }\n\n  componentWillReceiveProps (nextProps) {\n    if (this.props.timestamp !== nextProps.timestamp) {\n      this.setState({ now: this.props.intl.now() });\n    }\n  }\n\n  componentDidMount () {\n    this._scheduleNextUpdate(this.props, this.state);\n  }\n\n  componentWillUpdate (nextProps, nextState) {\n    this._scheduleNextUpdate(nextProps, nextState);\n  }\n\n  componentWillUnmount () {\n    clearTimeout(this._timer);\n  }\n\n  _scheduleNextUpdate (props, state) {\n    clearTimeout(this._timer);\n\n    const { timestamp }  = props;\n    const delta          = (new Date(timestamp)).getTime() - state.now;\n    const unitDelay      = getUnitDelay(selectUnits(delta));\n    const unitRemainder  = Math.abs(delta % unitDelay);\n    const updateInterval = 1000 * 10;\n    const delay          = delta < 0 ? Math.max(updateInterval, unitDelay - unitRemainder) : Math.max(updateInterval, unitRemainder);\n\n    this._timer = setTimeout(() => {\n      this.setState({ now: this.props.intl.now() });\n    }, delay);\n  }\n\n  render () {\n    const { timestamp, intl, year, futureDate } = this.props;\n\n    const date         = new Date(timestamp);\n    const relativeTime = futureDate ? timeRemainingString(intl, date, this.state.now) : timeAgoString(intl, date, this.state.now, year);\n\n    return (\n      <time dateTime={timestamp} title={intl.formatDate(date, dateFormatOptions)}>\n        {relativeTime}\n      </time>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/components/scrollable_list.js",
    "content": "import React, { PureComponent } from 'react';\nimport { ScrollContainer } from 'react-router-scroll-4';\nimport PropTypes from 'prop-types';\nimport IntersectionObserverArticleContainer from '../containers/intersection_observer_article_container';\nimport LoadMore from './load_more';\nimport IntersectionObserverWrapper from '../features/ui/util/intersection_observer_wrapper';\nimport { throttle } from 'lodash';\nimport { List as ImmutableList } from 'immutable';\nimport classNames from 'classnames';\nimport { attachFullscreenListener, detachFullscreenListener, isFullscreen } from '../features/ui/util/fullscreen';\nimport LoadingIndicator from './loading_indicator';\n\nconst MOUSE_IDLE_DELAY = 300;\n\nexport default class ScrollableList extends PureComponent {\n\n  static contextTypes = {\n    router: PropTypes.object,\n  };\n\n  static propTypes = {\n    scrollKey: PropTypes.string.isRequired,\n    onLoadMore: PropTypes.func,\n    onScrollToTop: PropTypes.func,\n    onScroll: PropTypes.func,\n    trackScroll: PropTypes.bool,\n    shouldUpdateScroll: PropTypes.func,\n    isLoading: PropTypes.bool,\n    showLoading: PropTypes.bool,\n    hasMore: PropTypes.bool,\n    prepend: PropTypes.node,\n    alwaysPrepend: PropTypes.bool,\n    emptyMessage: PropTypes.node,\n    children: PropTypes.node,\n  };\n\n  static defaultProps = {\n    trackScroll: true,\n  };\n\n  state = {\n    fullscreen: null,\n    cachedMediaWidth: 250, // Default media/card width using default Mastodon theme\n  };\n\n  intersectionObserverWrapper = new IntersectionObserverWrapper();\n\n  handleScroll = throttle(() => {\n    if (this.node) {\n      const { scrollTop, scrollHeight, clientHeight } = this.node;\n      const offset = scrollHeight - scrollTop - clientHeight;\n\n      if (400 > offset && this.props.onLoadMore && this.props.hasMore && !this.props.isLoading) {\n        this.props.onLoadMore();\n      }\n\n      if (scrollTop < 100 && this.props.onScrollToTop) {\n        this.props.onScrollToTop();\n      } else if (this.props.onScroll) {\n        this.props.onScroll();\n      }\n\n      if (!this.lastScrollWasSynthetic) {\n        // If the last scroll wasn't caused by setScrollTop(), assume it was\n        // intentional and cancel any pending scroll reset on mouse idle\n        this.scrollToTopOnMouseIdle = false;\n      }\n      this.lastScrollWasSynthetic = false;\n    }\n  }, 150, {\n    trailing: true,\n  });\n\n  mouseIdleTimer = null;\n  mouseMovedRecently = false;\n  lastScrollWasSynthetic = false;\n  scrollToTopOnMouseIdle = false;\n\n  setScrollTop = newScrollTop => {\n    if (this.node.scrollTop !== newScrollTop) {\n      this.lastScrollWasSynthetic = true;\n      this.node.scrollTop = newScrollTop;\n    }\n  };\n\n  clearMouseIdleTimer = () => {\n    if (this.mouseIdleTimer === null) {\n      return;\n    }\n\n    clearTimeout(this.mouseIdleTimer);\n    this.mouseIdleTimer = null;\n  };\n\n  handleMouseMove = throttle(() => {\n    // As long as the mouse keeps moving, clear and restart the idle timer.\n    this.clearMouseIdleTimer();\n    this.mouseIdleTimer = setTimeout(this.handleMouseIdle, MOUSE_IDLE_DELAY);\n\n    if (!this.mouseMovedRecently && this.node.scrollTop === 0) {\n      // Only set if we just started moving and are scrolled to the top.\n      this.scrollToTopOnMouseIdle = true;\n    }\n\n    // Save setting this flag for last, so we can do the comparison above.\n    this.mouseMovedRecently = true;\n  }, MOUSE_IDLE_DELAY / 2);\n\n  handleWheel = throttle(() => {\n    this.scrollToTopOnMouseIdle = false;\n  }, 150, {\n    trailing: true,\n  });\n\n  handleMouseIdle = () => {\n    if (this.scrollToTopOnMouseIdle) {\n      this.setScrollTop(0);\n    }\n\n    this.mouseMovedRecently = false;\n    this.scrollToTopOnMouseIdle = false;\n  }\n\n  componentDidMount () {\n    this.attachScrollListener();\n    this.attachIntersectionObserver();\n\n    attachFullscreenListener(this.onFullScreenChange);\n\n    // Handle initial scroll posiiton\n    this.handleScroll();\n  }\n\n  getScrollPosition = () => {\n    if (this.node && (this.node.scrollTop > 0 || this.mouseMovedRecently)) {\n      return { height: this.node.scrollHeight, top: this.node.scrollTop };\n    } else {\n      return null;\n    }\n  }\n\n  updateScrollBottom = (snapshot) => {\n    const newScrollTop = this.node.scrollHeight - snapshot;\n\n    this.setScrollTop(newScrollTop);\n  }\n\n  getSnapshotBeforeUpdate (prevProps) {\n    const someItemInserted = React.Children.count(prevProps.children) > 0 &&\n      React.Children.count(prevProps.children) < React.Children.count(this.props.children) &&\n      this.getFirstChildKey(prevProps) !== this.getFirstChildKey(this.props);\n\n    if (someItemInserted && (this.node.scrollTop > 0 || this.mouseMovedRecently)) {\n      return this.node.scrollHeight - this.node.scrollTop;\n    } else {\n      return null;\n    }\n  }\n\n  componentDidUpdate (prevProps, prevState, snapshot) {\n    // Reset the scroll position when a new child comes in in order not to\n    // jerk the scrollbar around if you're already scrolled down the page.\n    if (snapshot !== null) {\n      this.setScrollTop(this.node.scrollHeight - snapshot);\n    }\n  }\n\n  cacheMediaWidth = (width) => {\n    if (width && this.state.cachedMediaWidth !== width) {\n      this.setState({ cachedMediaWidth: width });\n    }\n  }\n\n  componentWillUnmount () {\n    this.clearMouseIdleTimer();\n    this.detachScrollListener();\n    this.detachIntersectionObserver();\n    detachFullscreenListener(this.onFullScreenChange);\n  }\n\n  onFullScreenChange = () => {\n    this.setState({ fullscreen: isFullscreen() });\n  }\n\n  attachIntersectionObserver () {\n    this.intersectionObserverWrapper.connect({\n      root: this.node,\n      rootMargin: '300% 0px',\n    });\n  }\n\n  detachIntersectionObserver () {\n    this.intersectionObserverWrapper.disconnect();\n  }\n\n  attachScrollListener () {\n    this.node.addEventListener('scroll', this.handleScroll);\n    this.node.addEventListener('wheel', this.handleWheel);\n  }\n\n  detachScrollListener () {\n    this.node.removeEventListener('scroll', this.handleScroll);\n    this.node.removeEventListener('wheel', this.handleWheel);\n  }\n\n  getFirstChildKey (props) {\n    const { children } = props;\n    let firstChild     = children;\n\n    if (children instanceof ImmutableList) {\n      firstChild = children.get(0);\n    } else if (Array.isArray(children)) {\n      firstChild = children[0];\n    }\n\n    return firstChild && firstChild.key;\n  }\n\n  setRef = (c) => {\n    this.node = c;\n  }\n\n  handleLoadMore = e => {\n    e.preventDefault();\n    this.props.onLoadMore();\n  }\n\n  render () {\n    const { children, scrollKey, trackScroll, shouldUpdateScroll, showLoading, isLoading, hasMore, prepend, alwaysPrepend, emptyMessage, onLoadMore } = this.props;\n    const { fullscreen } = this.state;\n    const childrenCount = React.Children.count(children);\n\n    const loadMore     = (hasMore && onLoadMore) ? <LoadMore visible={!isLoading} onClick={this.handleLoadMore} /> : null;\n    let scrollableArea = null;\n\n    if (showLoading) {\n      scrollableArea = (\n        <div className='scrollable scrollable--flex' ref={this.setRef}>\n          <div role='feed' className='item-list'>\n            {prepend}\n          </div>\n\n          <div className='scrollable__append'>\n            <LoadingIndicator />\n          </div>\n        </div>\n      );\n    } else if (isLoading || childrenCount > 0 || hasMore || !emptyMessage) {\n      scrollableArea = (\n        <div className={classNames('scrollable', { fullscreen })} ref={this.setRef} onMouseMove={this.handleMouseMove}>\n          <div role='feed' className='item-list'>\n            {prepend}\n\n            {React.Children.map(this.props.children, (child, index) => (\n              <IntersectionObserverArticleContainer\n                key={child.key}\n                id={child.key}\n                index={index}\n                listLength={childrenCount}\n                intersectionObserverWrapper={this.intersectionObserverWrapper}\n                saveHeightKey={trackScroll ? `${this.context.router.route.location.key}:${scrollKey}` : null}\n              >\n                {React.cloneElement(child, {\n                  getScrollPosition: this.getScrollPosition,\n                  updateScrollBottom: this.updateScrollBottom,\n                  cachedMediaWidth: this.state.cachedMediaWidth,\n                  cacheMediaWidth: this.cacheMediaWidth,\n                })}\n              </IntersectionObserverArticleContainer>\n            ))}\n\n            {loadMore}\n          </div>\n        </div>\n      );\n    } else {\n      scrollableArea = (\n        <div className={classNames('scrollable scrollable--flex', { fullscreen })} ref={this.setRef}>\n          {alwaysPrepend && prepend}\n\n          <div className='empty-column-indicator'>\n            {emptyMessage}\n          </div>\n        </div>\n      );\n    }\n\n    if (trackScroll) {\n      return (\n        <ScrollContainer scrollKey={scrollKey} shouldUpdateScroll={shouldUpdateScroll}>\n          {scrollableArea}\n        </ScrollContainer>\n      );\n    } else {\n      return scrollableArea;\n    }\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/components/setting_text.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\n\nexport default class SettingText extends React.PureComponent {\n\n  static propTypes = {\n    settings: ImmutablePropTypes.map.isRequired,\n    settingKey: PropTypes.array.isRequired,\n    label: PropTypes.string.isRequired,\n    onChange: PropTypes.func.isRequired,\n  };\n\n  handleChange = (e) => {\n    this.props.onChange(this.props.settingKey, e.target.value);\n  }\n\n  render () {\n    const { settings, settingKey, label } = this.props;\n\n    return (\n      <label>\n        <span style={{ display: 'none' }}>{label}</span>\n        <input\n          className='setting-text'\n          value={settings.getIn(settingKey)}\n          onChange={this.handleChange}\n          placeholder={label}\n        />\n      </label>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/components/status.js",
    "content": "import React from 'react';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport PropTypes from 'prop-types';\nimport Avatar from './avatar';\nimport AvatarOverlay from './avatar_overlay';\nimport AvatarComposite from './avatar_composite';\nimport RelativeTimestamp from './relative_timestamp';\nimport DisplayName from './display_name';\nimport StatusContent from './status_content';\nimport StatusActionBar from './status_action_bar';\nimport AttachmentList from './attachment_list';\nimport Card from '../features/status/components/card';\nimport { injectIntl, FormattedMessage } from 'react-intl';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport { MediaGallery, Video } from '../features/ui/util/async-components';\nimport { HotKeys } from 'react-hotkeys';\nimport classNames from 'classnames';\nimport Icon from 'mastodon/components/icon';\nimport { displayMedia } from '../initial_state';\n\n// We use the component (and not the container) since we do not want\n// to use the progress bar to show download progress\nimport Bundle from '../features/ui/components/bundle';\n\nexport const textForScreenReader = (intl, status, rebloggedByText = false) => {\n  const displayName = status.getIn(['account', 'display_name']);\n\n  const values = [\n    displayName.length === 0 ? status.getIn(['account', 'acct']).split('@')[0] : displayName,\n    status.get('spoiler_text') && status.get('hidden') ? status.get('spoiler_text') : status.get('search_index').slice(status.get('spoiler_text').length),\n    intl.formatDate(status.get('created_at'), { hour: '2-digit', minute: '2-digit', month: 'short', day: 'numeric' }),\n    status.getIn(['account', 'acct']),\n  ];\n\n  if (rebloggedByText) {\n    values.push(rebloggedByText);\n  }\n\n  return values.join(', ');\n};\n\nexport const defaultMediaVisibility = (status) => {\n  if (!status) {\n    return undefined;\n  }\n\n  if (status.get('reblog', null) !== null && typeof status.get('reblog') === 'object') {\n    status = status.get('reblog');\n  }\n\n  return (displayMedia !== 'hide_all' && !status.get('sensitive') || displayMedia === 'show_all');\n};\n\nexport default @injectIntl\nclass Status extends ImmutablePureComponent {\n\n  static contextTypes = {\n    router: PropTypes.object,\n  };\n\n  static propTypes = {\n    status: ImmutablePropTypes.map,\n    account: ImmutablePropTypes.map,\n    otherAccounts: ImmutablePropTypes.list,\n    onClick: PropTypes.func,\n    onReply: PropTypes.func,\n    onFavourite: PropTypes.func,\n    onReblog: PropTypes.func,\n    onDelete: PropTypes.func,\n    onDirect: PropTypes.func,\n    onMention: PropTypes.func,\n    onPin: PropTypes.func,\n    onOpenMedia: PropTypes.func,\n    onOpenVideo: PropTypes.func,\n    onBlock: PropTypes.func,\n    onEmbed: PropTypes.func,\n    onHeightChange: PropTypes.func,\n    onToggleHidden: PropTypes.func,\n    muted: PropTypes.bool,\n    hidden: PropTypes.bool,\n    unread: PropTypes.bool,\n    onMoveUp: PropTypes.func,\n    onMoveDown: PropTypes.func,\n    showThread: PropTypes.bool,\n    getScrollPosition: PropTypes.func,\n    updateScrollBottom: PropTypes.func,\n    cacheMediaWidth: PropTypes.func,\n    cachedMediaWidth: PropTypes.number,\n  };\n\n  // Avoid checking props that are functions (and whose equality will always\n  // evaluate to false. See react-immutable-pure-component for usage.\n  updateOnProps = [\n    'status',\n    'account',\n    'muted',\n    'hidden',\n  ];\n\n  state = {\n    showMedia: defaultMediaVisibility(this.props.status),\n    statusId: undefined,\n  };\n\n  // Track height changes we know about to compensate scrolling\n  componentDidMount () {\n    this.didShowCard = !this.props.muted && !this.props.hidden && this.props.status && this.props.status.get('card');\n  }\n\n  getSnapshotBeforeUpdate () {\n    if (this.props.getScrollPosition) {\n      return this.props.getScrollPosition();\n    } else {\n      return null;\n    }\n  }\n\n  static getDerivedStateFromProps(nextProps, prevState) {\n    if (nextProps.status && nextProps.status.get('id') !== prevState.statusId) {\n      return {\n        showMedia: defaultMediaVisibility(nextProps.status),\n        statusId: nextProps.status.get('id'),\n      };\n    } else {\n      return null;\n    }\n  }\n\n  // Compensate height changes\n  componentDidUpdate (prevProps, prevState, snapshot) {\n    const doShowCard  = !this.props.muted && !this.props.hidden && this.props.status && this.props.status.get('card');\n\n    if (doShowCard && !this.didShowCard) {\n      this.didShowCard = true;\n\n      if (snapshot !== null && this.props.updateScrollBottom) {\n        if (this.node && this.node.offsetTop < snapshot.top) {\n          this.props.updateScrollBottom(snapshot.height - snapshot.top);\n        }\n      }\n    }\n  }\n\n  componentWillUnmount() {\n    if (this.node && this.props.getScrollPosition) {\n      const position = this.props.getScrollPosition();\n      if (position !== null && this.node.offsetTop < position.top) {\n        requestAnimationFrame(() => {\n          this.props.updateScrollBottom(position.height - position.top);\n        });\n      }\n    }\n  }\n\n  handleToggleMediaVisibility = () => {\n    this.setState({ showMedia: !this.state.showMedia });\n  }\n\n  handleClick = () => {\n    if (this.props.onClick) {\n      this.props.onClick();\n      return;\n    }\n\n    if (!this.context.router) {\n      return;\n    }\n\n    const { status } = this.props;\n    this.context.router.history.push(`/statuses/${status.getIn(['reblog', 'id'], status.get('id'))}`);\n  }\n\n  handleExpandClick = (e) => {\n    if (this.props.onClick) {\n      this.props.onClick();\n      return;\n    }\n\n    if (e.button === 0) {\n      if (!this.context.router) {\n        return;\n      }\n\n      const { status } = this.props;\n      this.context.router.history.push(`/statuses/${status.getIn(['reblog', 'id'], status.get('id'))}`);\n    }\n  }\n\n  handleAccountClick = (e) => {\n    if (this.context.router && e.button === 0 && !(e.ctrlKey || e.metaKey)) {\n      const id = e.currentTarget.getAttribute('data-id');\n      e.preventDefault();\n      this.context.router.history.push(`/accounts/${id}`);\n    }\n  }\n\n  handleExpandedToggle = () => {\n    this.props.onToggleHidden(this._properStatus());\n  };\n\n  renderLoadingMediaGallery () {\n    return <div className='media_gallery' style={{ height: '110px' }} />;\n  }\n\n  renderLoadingVideoPlayer () {\n    return <div className='media-spoiler-video' style={{ height: '110px' }} />;\n  }\n\n  handleOpenVideo = (media, startTime) => {\n    this.props.onOpenVideo(media, startTime);\n  }\n\n  handleHotkeyReply = e => {\n    e.preventDefault();\n    this.props.onReply(this._properStatus(), this.context.router.history);\n  }\n\n  handleHotkeyFavourite = () => {\n    this.props.onFavourite(this._properStatus());\n  }\n\n  handleHotkeyBoost = e => {\n    this.props.onReblog(this._properStatus(), e);\n  }\n\n  handleHotkeyMention = e => {\n    e.preventDefault();\n    this.props.onMention(this._properStatus().get('account'), this.context.router.history);\n  }\n\n  handleHotkeyOpen = () => {\n    this.context.router.history.push(`/statuses/${this._properStatus().get('id')}`);\n  }\n\n  handleHotkeyOpenProfile = () => {\n    this.context.router.history.push(`/accounts/${this._properStatus().getIn(['account', 'id'])}`);\n  }\n\n  handleHotkeyMoveUp = e => {\n    this.props.onMoveUp(this.props.status.get('id'), e.target.getAttribute('data-featured'));\n  }\n\n  handleHotkeyMoveDown = e => {\n    this.props.onMoveDown(this.props.status.get('id'), e.target.getAttribute('data-featured'));\n  }\n\n  handleHotkeyToggleHidden = () => {\n    this.props.onToggleHidden(this._properStatus());\n  }\n\n  handleHotkeyToggleSensitive = () => {\n    this.handleToggleMediaVisibility();\n  }\n\n  _properStatus () {\n    const { status } = this.props;\n\n    if (status.get('reblog', null) !== null && typeof status.get('reblog') === 'object') {\n      return status.get('reblog');\n    } else {\n      return status;\n    }\n  }\n\n  handleRef = c => {\n    this.node = c;\n  }\n\n  render () {\n    let media = null;\n    let statusAvatar, prepend, rebloggedByText;\n\n    const { intl, hidden, featured, otherAccounts, unread, showThread } = this.props;\n\n    let { status, account, ...other } = this.props;\n\n    if (status === null) {\n      return null;\n    }\n\n    if (hidden) {\n      return (\n        <div ref={this.handleRef}>\n          {status.getIn(['account', 'display_name']) || status.getIn(['account', 'username'])}\n          {status.get('content')}\n        </div>\n      );\n    }\n\n    if (status.get('filtered') || status.getIn(['reblog', 'filtered'])) {\n      const minHandlers = this.props.muted ? {} : {\n        moveUp: this.handleHotkeyMoveUp,\n        moveDown: this.handleHotkeyMoveDown,\n      };\n\n      return (\n        <HotKeys handlers={minHandlers}>\n          <div className='status__wrapper status__wrapper--filtered focusable' tabIndex='0' ref={this.handleRef}>\n            <FormattedMessage id='status.filtered' defaultMessage='Filtered' />\n          </div>\n        </HotKeys>\n      );\n    }\n\n    if (featured) {\n      prepend = (\n        <div className='status__prepend'>\n          <div className='status__prepend-icon-wrapper'><Icon id='thumb-tack' className='status__prepend-icon' fixedWidth /></div>\n          <FormattedMessage id='status.pinned' defaultMessage='Pinned toot' />\n        </div>\n      );\n    } else if (status.get('reblog', null) !== null && typeof status.get('reblog') === 'object') {\n      const display_name_html = { __html: status.getIn(['account', 'display_name_html']) };\n\n      prepend = (\n        <div className='status__prepend'>\n          <div className='status__prepend-icon-wrapper'><Icon id='retweet' className='status__prepend-icon' fixedWidth /></div>\n          <FormattedMessage id='status.reblogged_by' defaultMessage='{name} boosted' values={{ name: <a onClick={this.handleAccountClick} data-id={status.getIn(['account', 'id'])} href={status.getIn(['account', 'url'])} className='status__display-name muted'><bdi><strong dangerouslySetInnerHTML={display_name_html} /></bdi></a> }} />\n        </div>\n      );\n\n      rebloggedByText = intl.formatMessage({ id: 'status.reblogged_by', defaultMessage: '{name} boosted' }, { name: status.getIn(['account', 'acct']) });\n\n      account = status.get('account');\n      status  = status.get('reblog');\n    }\n\n    if (status.get('media_attachments').size > 0) {\n      if (this.props.muted) {\n        media = (\n          <AttachmentList\n            compact\n            media={status.get('media_attachments')}\n          />\n        );\n      } else if (status.getIn(['media_attachments', 0, 'type']) === 'video') {\n        const video = status.getIn(['media_attachments', 0]);\n\n        media = (\n          <Bundle fetchComponent={Video} loading={this.renderLoadingVideoPlayer} >\n            {Component => (\n              <Component\n                preview={video.get('preview_url')}\n                blurhash={video.get('blurhash')}\n                src={video.get('url')}\n                alt={video.get('description')}\n                width={this.props.cachedMediaWidth}\n                height={110}\n                inline\n                sensitive={status.get('sensitive')}\n                onOpenVideo={this.handleOpenVideo}\n                cacheWidth={this.props.cacheMediaWidth}\n                visible={this.state.showMedia}\n                onToggleVisibility={this.handleToggleMediaVisibility}\n              />\n            )}\n          </Bundle>\n        );\n      } else {\n        media = (\n          <Bundle fetchComponent={MediaGallery} loading={this.renderLoadingMediaGallery}>\n            {Component => (\n              <Component\n                media={status.get('media_attachments')}\n                sensitive={status.get('sensitive')}\n                height={110}\n                onOpenMedia={this.props.onOpenMedia}\n                cacheWidth={this.props.cacheMediaWidth}\n                defaultWidth={this.props.cachedMediaWidth}\n                visible={this.state.showMedia}\n                onToggleVisibility={this.handleToggleMediaVisibility}\n              />\n            )}\n          </Bundle>\n        );\n      }\n    } else if (status.get('spoiler_text').length === 0 && status.get('card')) {\n      media = (\n        <Card\n          onOpenMedia={this.props.onOpenMedia}\n          card={status.get('card')}\n          compact\n          cacheWidth={this.props.cacheMediaWidth}\n          defaultWidth={this.props.cachedMediaWidth}\n        />\n      );\n    }\n\n    if (otherAccounts && otherAccounts.size > 0) {\n      statusAvatar = <AvatarComposite accounts={otherAccounts} size={48} />;\n    } else if (account === undefined || account === null) {\n      statusAvatar = <Avatar account={status.get('account')} size={48} />;\n    } else {\n      statusAvatar = <AvatarOverlay account={status.get('account')} friend={account} />;\n    }\n\n    const handlers = this.props.muted ? {} : {\n      reply: this.handleHotkeyReply,\n      favourite: this.handleHotkeyFavourite,\n      boost: this.handleHotkeyBoost,\n      mention: this.handleHotkeyMention,\n      open: this.handleHotkeyOpen,\n      openProfile: this.handleHotkeyOpenProfile,\n      moveUp: this.handleHotkeyMoveUp,\n      moveDown: this.handleHotkeyMoveDown,\n      toggleHidden: this.handleHotkeyToggleHidden,\n      toggleSensitive: this.handleHotkeyToggleSensitive,\n    };\n\n    return (\n      <HotKeys handlers={handlers}>\n        <div className={classNames('status__wrapper', `status__wrapper-${status.get('visibility')}`, { 'status__wrapper-reply': !!status.get('in_reply_to_id'), read: unread === false, focusable: !this.props.muted })} tabIndex={this.props.muted ? null : 0} data-featured={featured ? 'true' : null} aria-label={textForScreenReader(intl, status, rebloggedByText)} ref={this.handleRef}>\n          {prepend}\n\n          <div className={classNames('status', `status-${status.get('visibility')}`, { 'status-reply': !!status.get('in_reply_to_id'), muted: this.props.muted, read: unread === false })} data-id={status.get('id')}>\n            <div className='status__expand' onClick={this.handleExpandClick} role='presentation' />\n            <div className='status__info'>\n              <a href={status.get('url')} className='status__relative-time' target='_blank' rel='noopener'><RelativeTimestamp timestamp={status.get('created_at')} /></a>\n\n              <a onClick={this.handleAccountClick} target='_blank' data-id={status.getIn(['account', 'id'])} href={status.getIn(['account', 'url'])} title={status.getIn(['account', 'acct'])} className='status__display-name'>\n                <div className='status__avatar'>\n                  {statusAvatar}\n                </div>\n\n                <DisplayName account={status.get('account')} others={otherAccounts} />\n              </a>\n            </div>\n\n            <StatusContent status={status} onClick={this.handleClick} expanded={!status.get('hidden')} onExpandedToggle={this.handleExpandedToggle} collapsable />\n\n            {media}\n\n            {showThread && status.get('in_reply_to_id') && status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) && (\n              <button className='status__content__read-more-button' onClick={this.handleClick}>\n                <FormattedMessage id='status.show_thread' defaultMessage='Show thread' />\n              </button>\n            )}\n\n            <StatusActionBar status={status} account={account} {...other} />\n          </div>\n        </div>\n      </HotKeys>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/components/status_action_bar.js",
    "content": "import React from 'react';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport PropTypes from 'prop-types';\nimport IconButton from './icon_button';\nimport DropdownMenuContainer from '../containers/dropdown_menu_container';\nimport { defineMessages, injectIntl } from 'react-intl';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport { me, isStaff } from '../initial_state';\n\nconst messages = defineMessages({\n  delete: { id: 'status.delete', defaultMessage: 'Delete' },\n  redraft: { id: 'status.redraft', defaultMessage: 'Delete & re-draft' },\n  direct: { id: 'status.direct', defaultMessage: 'Direct message @{name}' },\n  mention: { id: 'status.mention', defaultMessage: 'Mention @{name}' },\n  mute: { id: 'account.mute', defaultMessage: 'Mute @{name}' },\n  block: { id: 'account.block', defaultMessage: 'Block @{name}' },\n  reply: { id: 'status.reply', defaultMessage: 'Reply' },\n  share: { id: 'status.share', defaultMessage: 'Share' },\n  more: { id: 'status.more', defaultMessage: 'More' },\n  replyAll: { id: 'status.replyAll', defaultMessage: 'Reply to thread' },\n  reblog: { id: 'status.reblog', defaultMessage: 'Boost' },\n  reblog_private: { id: 'status.reblog_private', defaultMessage: 'Boost to original audience' },\n  cancel_reblog_private: { id: 'status.cancel_reblog_private', defaultMessage: 'Unboost' },\n  cannot_reblog: { id: 'status.cannot_reblog', defaultMessage: 'This post cannot be boosted' },\n  favourite: { id: 'status.favourite', defaultMessage: 'Favourite' },\n  open: { id: 'status.open', defaultMessage: 'Expand this status' },\n  report: { id: 'status.report', defaultMessage: 'Report @{name}' },\n  muteConversation: { id: 'status.mute_conversation', defaultMessage: 'Mute conversation' },\n  unmuteConversation: { id: 'status.unmute_conversation', defaultMessage: 'Unmute conversation' },\n  pin: { id: 'status.pin', defaultMessage: 'Pin on profile' },\n  unpin: { id: 'status.unpin', defaultMessage: 'Unpin from profile' },\n  embed: { id: 'status.embed', defaultMessage: 'Embed' },\n  admin_account: { id: 'status.admin_account', defaultMessage: 'Open moderation interface for @{name}' },\n  admin_status: { id: 'status.admin_status', defaultMessage: 'Open this status in the moderation interface' },\n  copy: { id: 'status.copy', defaultMessage: 'Copy link to status' },\n});\n\nconst obfuscatedCount = count => {\n  if (count < 0) {\n    return 0;\n  } else if (count <= 1) {\n    return count;\n  } else {\n    return '1+';\n  }\n};\n\nexport default @injectIntl\nclass StatusActionBar extends ImmutablePureComponent {\n\n  static contextTypes = {\n    router: PropTypes.object,\n  };\n\n  static propTypes = {\n    status: ImmutablePropTypes.map.isRequired,\n    onReply: PropTypes.func,\n    onFavourite: PropTypes.func,\n    onReblog: PropTypes.func,\n    onDelete: PropTypes.func,\n    onDirect: PropTypes.func,\n    onMention: PropTypes.func,\n    onMute: PropTypes.func,\n    onBlock: PropTypes.func,\n    onReport: PropTypes.func,\n    onEmbed: PropTypes.func,\n    onMuteConversation: PropTypes.func,\n    onPin: PropTypes.func,\n    withDismiss: PropTypes.bool,\n    intl: PropTypes.object.isRequired,\n  };\n\n  // Avoid checking props that are functions (and whose equality will always\n  // evaluate to false. See react-immutable-pure-component for usage.\n  updateOnProps = [\n    'status',\n    'withDismiss',\n  ]\n\n  handleReplyClick = () => {\n    if (me) {\n      this.props.onReply(this.props.status, this.context.router.history);\n    } else {\n      this._openInteractionDialog('reply');\n    }\n  }\n\n  handleShareClick = () => {\n    navigator.share({\n      text: this.props.status.get('search_index'),\n      url: this.props.status.get('url'),\n    }).catch((e) => {\n      if (e.name !== 'AbortError') console.error(e);\n    });\n  }\n\n  handleFavouriteClick = () => {\n    if (me) {\n      this.props.onFavourite(this.props.status);\n    } else {\n      this._openInteractionDialog('favourite');\n    }\n  }\n\n  handleReblogClick = e => {\n    if (me) {\n      this.props.onReblog(this.props.status, e);\n    } else {\n      this._openInteractionDialog('reblog');\n    }\n  }\n\n  _openInteractionDialog = type => {\n    window.open(`/interact/${this.props.status.get('id')}?type=${type}`, 'mastodon-intent', 'width=445,height=600,resizable=no,menubar=no,status=no,scrollbars=yes');\n  }\n\n  handleDeleteClick = () => {\n    this.props.onDelete(this.props.status, this.context.router.history);\n  }\n\n  handleRedraftClick = () => {\n    this.props.onDelete(this.props.status, this.context.router.history, true);\n  }\n\n  handlePinClick = () => {\n    this.props.onPin(this.props.status);\n  }\n\n  handleMentionClick = () => {\n    this.props.onMention(this.props.status.get('account'), this.context.router.history);\n  }\n\n  handleDirectClick = () => {\n    this.props.onDirect(this.props.status.get('account'), this.context.router.history);\n  }\n\n  handleMuteClick = () => {\n    this.props.onMute(this.props.status.get('account'));\n  }\n\n  handleBlockClick = () => {\n    this.props.onBlock(this.props.status);\n  }\n\n  handleOpen = () => {\n    this.context.router.history.push(`/statuses/${this.props.status.get('id')}`);\n  }\n\n  handleEmbed = () => {\n    this.props.onEmbed(this.props.status);\n  }\n\n  handleReport = () => {\n    this.props.onReport(this.props.status);\n  }\n\n  handleConversationMuteClick = () => {\n    this.props.onMuteConversation(this.props.status);\n  }\n\n  handleCopy = () => {\n    const url      = this.props.status.get('url');\n    const textarea = document.createElement('textarea');\n\n    textarea.textContent    = url;\n    textarea.style.position = 'fixed';\n\n    document.body.appendChild(textarea);\n\n    try {\n      textarea.select();\n      document.execCommand('copy');\n    } catch (e) {\n\n    } finally {\n      document.body.removeChild(textarea);\n    }\n  }\n\n  render () {\n    const { status, intl, withDismiss } = this.props;\n\n    const mutingConversation = status.get('muted');\n    const anonymousAccess    = !me;\n    const publicStatus       = ['public', 'unlisted'].includes(status.get('visibility'));\n\n    let menu = [];\n    let reblogIcon = 'retweet';\n    let replyIcon;\n    let replyTitle;\n\n    menu.push({ text: intl.formatMessage(messages.open), action: this.handleOpen });\n\n    if (publicStatus) {\n      menu.push({ text: intl.formatMessage(messages.copy), action: this.handleCopy });\n      menu.push({ text: intl.formatMessage(messages.embed), action: this.handleEmbed });\n    }\n\n    menu.push(null);\n\n    if (status.getIn(['account', 'id']) === me || withDismiss) {\n      menu.push({ text: intl.formatMessage(mutingConversation ? messages.unmuteConversation : messages.muteConversation), action: this.handleConversationMuteClick });\n      menu.push(null);\n    }\n\n    if (status.getIn(['account', 'id']) === me) {\n      if (publicStatus) {\n        menu.push({ text: intl.formatMessage(status.get('pinned') ? messages.unpin : messages.pin), action: this.handlePinClick });\n      } else {\n        if (status.get('visibility') === 'private') {\n          menu.push({ text: intl.formatMessage(status.get('reblogged') ? messages.cancel_reblog_private : messages.reblog_private), action: this.handleReblogClick });\n        }\n      }\n\n      menu.push({ text: intl.formatMessage(messages.delete), action: this.handleDeleteClick });\n      menu.push({ text: intl.formatMessage(messages.redraft), action: this.handleRedraftClick });\n    } else {\n      menu.push({ text: intl.formatMessage(messages.mention, { name: status.getIn(['account', 'username']) }), action: this.handleMentionClick });\n      menu.push({ text: intl.formatMessage(messages.direct, { name: status.getIn(['account', 'username']) }), action: this.handleDirectClick });\n      menu.push(null);\n      menu.push({ text: intl.formatMessage(messages.mute, { name: status.getIn(['account', 'username']) }), action: this.handleMuteClick });\n      menu.push({ text: intl.formatMessage(messages.block, { name: status.getIn(['account', 'username']) }), action: this.handleBlockClick });\n      menu.push({ text: intl.formatMessage(messages.report, { name: status.getIn(['account', 'username']) }), action: this.handleReport });\n\n      if (isStaff) {\n        menu.push(null);\n        menu.push({ text: intl.formatMessage(messages.admin_account, { name: status.getIn(['account', 'username']) }), href: `/admin/accounts/${status.getIn(['account', 'id'])}` });\n        menu.push({ text: intl.formatMessage(messages.admin_status), href: `/admin/accounts/${status.getIn(['account', 'id'])}/statuses/${status.get('id')}` });\n      }\n    }\n\n    if (status.get('visibility') === 'direct') {\n      reblogIcon = 'envelope';\n    } else if (status.get('visibility') === 'private') {\n      reblogIcon = 'lock';\n    }\n\n    if (status.get('in_reply_to_id', null) === null) {\n      replyIcon = 'reply';\n      replyTitle = intl.formatMessage(messages.reply);\n    } else {\n      replyIcon = 'reply-all';\n      replyTitle = intl.formatMessage(messages.replyAll);\n    }\n\n    const shareButton = ('share' in navigator) && status.get('visibility') === 'public' && (\n      <IconButton className='status__action-bar-button' title={intl.formatMessage(messages.share)} icon='share-alt' onClick={this.handleShareClick} />\n    );\n\n    return (\n      <div className='status__action-bar'>\n        <div className='status__action-bar__counter'><IconButton className='status__action-bar-button' title={replyTitle} icon={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? 'reply' : replyIcon} onClick={this.handleReplyClick} /><span className='status__action-bar__counter__label' >{obfuscatedCount(status.get('replies_count'))}</span></div>\n        <IconButton className='status__action-bar-button' disabled={!publicStatus} active={status.get('reblogged')} pressed={status.get('reblogged')} title={!publicStatus ? intl.formatMessage(messages.cannot_reblog) : intl.formatMessage(messages.reblog)} icon={reblogIcon} onClick={this.handleReblogClick} />\n        <IconButton className='status__action-bar-button star-icon' animate active={status.get('favourited')} pressed={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} />\n        {shareButton}\n\n        <div className='status__action-bar-dropdown'>\n          <DropdownMenuContainer disabled={anonymousAccess} status={status} items={menu} icon='ellipsis-h' size={18} direction='right' title={intl.formatMessage(messages.more)} />\n        </div>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/components/status_content.js",
    "content": "import React from 'react';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport PropTypes from 'prop-types';\nimport { isRtl } from '../rtl';\nimport { FormattedMessage } from 'react-intl';\nimport Permalink from './permalink';\nimport classnames from 'classnames';\nimport PollContainer from 'mastodon/containers/poll_container';\nimport Icon from 'mastodon/components/icon';\n\nconst MAX_HEIGHT = 642; // 20px * 32 (+ 2px padding at the top)\n\nexport default class StatusContent extends React.PureComponent {\n\n  static contextTypes = {\n    router: PropTypes.object,\n  };\n\n  static propTypes = {\n    status: ImmutablePropTypes.map.isRequired,\n    expanded: PropTypes.bool,\n    onExpandedToggle: PropTypes.func,\n    onClick: PropTypes.func,\n    collapsable: PropTypes.bool,\n  };\n\n  state = {\n    hidden: true,\n    collapsed: null, //  `collapsed: null` indicates that an element doesn't need collapsing, while `true` or `false` indicates that it does (and is/isn't).\n  };\n\n  _updateStatusLinks () {\n    const node = this.node;\n\n    if (!node) {\n      return;\n    }\n\n    const links = node.querySelectorAll('a');\n\n    for (var i = 0; i < links.length; ++i) {\n      let link = links[i];\n      if (link.classList.contains('status-link')) {\n        continue;\n      }\n      link.classList.add('status-link');\n\n      let mention = this.props.status.get('mentions').find(item => link.href === item.get('url'));\n\n      if (mention) {\n        link.addEventListener('click', this.onMentionClick.bind(this, mention), false);\n        link.setAttribute('title', mention.get('acct'));\n      } else if (link.textContent[0] === '#' || (link.previousSibling && link.previousSibling.textContent && link.previousSibling.textContent[link.previousSibling.textContent.length - 1] === '#')) {\n        link.addEventListener('click', this.onHashtagClick.bind(this, link.text), false);\n      } else {\n        link.setAttribute('title', link.href);\n      }\n\n      link.setAttribute('target', '_blank');\n      link.setAttribute('rel', 'noopener');\n    }\n\n    if (\n      this.props.collapsable\n      && this.props.onClick\n      && this.state.collapsed === null\n      && node.clientHeight > MAX_HEIGHT\n      && this.props.status.get('spoiler_text').length === 0\n    ) {\n      this.setState({ collapsed: true });\n    }\n  }\n\n  componentDidMount () {\n    this._updateStatusLinks();\n  }\n\n  componentDidUpdate () {\n    this._updateStatusLinks();\n  }\n\n  onMentionClick = (mention, e) => {\n    if (this.context.router && e.button === 0 && !(e.ctrlKey || e.metaKey)) {\n      e.preventDefault();\n      this.context.router.history.push(`/accounts/${mention.get('id')}`);\n    }\n  }\n\n  onHashtagClick = (hashtag, e) => {\n    hashtag = hashtag.replace(/^#/, '').toLowerCase();\n\n    if (this.context.router && e.button === 0 && !(e.ctrlKey || e.metaKey)) {\n      e.preventDefault();\n      this.context.router.history.push(`/timelines/tag/${hashtag}`);\n    }\n  }\n\n  handleMouseDown = (e) => {\n    this.startXY = [e.clientX, e.clientY];\n  }\n\n  handleMouseUp = (e) => {\n    if (!this.startXY) {\n      return;\n    }\n\n    const [ startX, startY ] = this.startXY;\n    const [ deltaX, deltaY ] = [Math.abs(e.clientX - startX), Math.abs(e.clientY - startY)];\n\n    let element = e.target;\n    while (element) {\n      if (element.localName === 'button' || element.localName === 'a' || element.localName === 'label') {\n        return;\n      }\n      element = element.parentNode;\n    }\n\n    if (deltaX + deltaY < 5 && e.button === 0 && this.props.onClick) {\n      this.props.onClick();\n    }\n\n    this.startXY = null;\n  }\n\n  handleSpoilerClick = (e) => {\n    e.preventDefault();\n\n    if (this.props.onExpandedToggle) {\n      // The parent manages the state\n      this.props.onExpandedToggle();\n    } else {\n      this.setState({ hidden: !this.state.hidden });\n    }\n  }\n\n  handleCollapsedClick = (e) => {\n    e.preventDefault();\n    this.setState({ collapsed: !this.state.collapsed });\n  }\n\n  setRef = (c) => {\n    this.node = c;\n  }\n\n  render () {\n    const { status } = this.props;\n\n    if (status.get('content').length === 0) {\n      return null;\n    }\n\n    const hidden = this.props.onExpandedToggle ? !this.props.expanded : this.state.hidden;\n\n    const content = { __html: status.get('contentHtml') };\n    const spoilerContent = { __html: status.get('spoilerHtml') };\n    const directionStyle = { direction: 'ltr' };\n    const classNames = classnames('status__content', {\n      'status__content--with-action': this.props.onClick && this.context.router,\n      'status__content--with-spoiler': status.get('spoiler_text').length > 0,\n      'status__content--collapsed': this.state.collapsed === true,\n    });\n\n    if (isRtl(status.get('search_index'))) {\n      directionStyle.direction = 'rtl';\n    }\n\n    const readMoreButton = (\n      <button className='status__content__read-more-button' onClick={this.props.onClick} key='read-more'>\n        <FormattedMessage id='status.read_more' defaultMessage='Read more' /><Icon id='angle-right' fixedWidth />\n      </button>\n    );\n\n    if (status.get('spoiler_text').length > 0) {\n      let mentionsPlaceholder = '';\n\n      const mentionLinks = status.get('mentions').map(item => (\n        <Permalink to={`/accounts/${item.get('id')}`} href={item.get('url')} key={item.get('id')} className='mention'>\n          @<span>{item.get('username')}</span>\n        </Permalink>\n      )).reduce((aggregate, item) => [...aggregate, item, ' '], []);\n\n      const toggleText = hidden ? <FormattedMessage id='status.show_more' defaultMessage='Show more' /> : <FormattedMessage id='status.show_less' defaultMessage='Show less' />;\n\n      if (hidden) {\n        mentionsPlaceholder = <div>{mentionLinks}</div>;\n      }\n\n      return (\n        <div className={classNames} ref={this.setRef} tabIndex='0' style={directionStyle} onMouseDown={this.handleMouseDown} onMouseUp={this.handleMouseUp}>\n          <p style={{ marginBottom: hidden && status.get('mentions').isEmpty() ? '0px' : null }}>\n            <span dangerouslySetInnerHTML={spoilerContent} lang={status.get('language')} />\n            {' '}\n            <button tabIndex='0' className={`status__content__spoiler-link ${hidden ? 'status__content__spoiler-link--show-more' : 'status__content__spoiler-link--show-less'}`} onClick={this.handleSpoilerClick}>{toggleText}</button>\n          </p>\n\n          {mentionsPlaceholder}\n\n          <div tabIndex={!hidden ? 0 : null} className={`status__content__text ${!hidden ? 'status__content__text--visible' : ''}`} style={directionStyle} dangerouslySetInnerHTML={content} lang={status.get('language')} />\n\n          {!hidden && !!status.get('poll') && <PollContainer pollId={status.get('poll')} />}\n        </div>\n      );\n    } else if (this.props.onClick) {\n      const output = [\n        <div\n          ref={this.setRef}\n          tabIndex='0'\n          key='content'\n          className={classNames}\n          style={directionStyle}\n          dangerouslySetInnerHTML={content}\n          lang={status.get('language')}\n          onMouseDown={this.handleMouseDown}\n          onMouseUp={this.handleMouseUp}\n        />,\n      ];\n\n      if (this.state.collapsed) {\n        output.push(readMoreButton);\n      }\n\n      if (status.get('poll')) {\n        output.push(<PollContainer pollId={status.get('poll')} />);\n      }\n\n      return output;\n    } else {\n      const output = [\n        <div\n          tabIndex='0'\n          ref={this.setRef}\n          className='status__content'\n          style={directionStyle}\n          dangerouslySetInnerHTML={content}\n          lang={status.get('language')}\n        />,\n      ];\n\n      if (status.get('poll')) {\n        output.push(<PollContainer pollId={status.get('poll')} />);\n      }\n\n      return output;\n    }\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/components/status_list.js",
    "content": "import { debounce } from 'lodash';\nimport React from 'react';\nimport { FormattedMessage } from 'react-intl';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport PropTypes from 'prop-types';\nimport StatusContainer from '../containers/status_container';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport LoadGap from './load_gap';\nimport ScrollableList from './scrollable_list';\n\nexport default class StatusList extends ImmutablePureComponent {\n\n  static propTypes = {\n    scrollKey: PropTypes.string.isRequired,\n    statusIds: ImmutablePropTypes.list.isRequired,\n    featuredStatusIds: ImmutablePropTypes.list,\n    onLoadMore: PropTypes.func,\n    onScrollToTop: PropTypes.func,\n    onScroll: PropTypes.func,\n    trackScroll: PropTypes.bool,\n    shouldUpdateScroll: PropTypes.func,\n    isLoading: PropTypes.bool,\n    isPartial: PropTypes.bool,\n    hasMore: PropTypes.bool,\n    prepend: PropTypes.node,\n    emptyMessage: PropTypes.node,\n    alwaysPrepend: PropTypes.bool,\n    timelineId: PropTypes.string,\n  };\n\n  static defaultProps = {\n    trackScroll: true,\n  };\n\n  getFeaturedStatusCount = () => {\n    return this.props.featuredStatusIds ? this.props.featuredStatusIds.size : 0;\n  }\n\n  getCurrentStatusIndex = (id, featured) => {\n    if (featured) {\n      return this.props.featuredStatusIds.indexOf(id);\n    } else {\n      return this.props.statusIds.indexOf(id) + this.getFeaturedStatusCount();\n    }\n  }\n\n  handleMoveUp = (id, featured) => {\n    const elementIndex = this.getCurrentStatusIndex(id, featured) - 1;\n    this._selectChild(elementIndex, true);\n  }\n\n  handleMoveDown = (id, featured) => {\n    const elementIndex = this.getCurrentStatusIndex(id, featured) + 1;\n    this._selectChild(elementIndex, false);\n  }\n\n  handleLoadOlder = debounce(() => {\n    this.props.onLoadMore(this.props.statusIds.size > 0 ? this.props.statusIds.last() : undefined);\n  }, 300, { leading: true })\n\n  _selectChild (index, align_top) {\n    const container = this.node.node;\n    const element = container.querySelector(`article:nth-of-type(${index + 1}) .focusable`);\n\n    if (element) {\n      if (align_top && container.scrollTop > element.offsetTop) {\n        element.scrollIntoView(true);\n      } else if (!align_top && container.scrollTop + container.clientHeight < element.offsetTop + element.offsetHeight) {\n        element.scrollIntoView(false);\n      }\n      element.focus();\n    }\n  }\n\n  setRef = c => {\n    this.node = c;\n  }\n\n  render () {\n    const { statusIds, featuredStatusIds, shouldUpdateScroll, onLoadMore, timelineId, ...other }  = this.props;\n    const { isLoading, isPartial } = other;\n\n    if (isPartial) {\n      return (\n        <div className='regeneration-indicator'>\n          <div>\n            <div className='regeneration-indicator__figure' />\n\n            <div className='regeneration-indicator__label'>\n              <FormattedMessage id='regeneration_indicator.label' tagName='strong' defaultMessage='Loading&hellip;' />\n              <FormattedMessage id='regeneration_indicator.sublabel' defaultMessage='Your home feed is being prepared!' />\n            </div>\n          </div>\n        </div>\n      );\n    }\n\n    let scrollableContent = (isLoading || statusIds.size > 0) ? (\n      statusIds.map((statusId, index) => statusId === null ? (\n        <LoadGap\n          key={'gap:' + statusIds.get(index + 1)}\n          disabled={isLoading}\n          maxId={index > 0 ? statusIds.get(index - 1) : null}\n          onClick={onLoadMore}\n        />\n      ) : (\n        <StatusContainer\n          key={statusId}\n          id={statusId}\n          onMoveUp={this.handleMoveUp}\n          onMoveDown={this.handleMoveDown}\n          contextType={timelineId}\n          showThread\n        />\n      ))\n    ) : null;\n\n    if (scrollableContent && featuredStatusIds) {\n      scrollableContent = featuredStatusIds.map(statusId => (\n        <StatusContainer\n          key={`f-${statusId}`}\n          id={statusId}\n          featured\n          onMoveUp={this.handleMoveUp}\n          onMoveDown={this.handleMoveDown}\n          contextType={timelineId}\n          showThread\n        />\n      )).concat(scrollableContent);\n    }\n\n    return (\n      <ScrollableList {...other} showLoading={isLoading && statusIds.size === 0} onLoadMore={onLoadMore && this.handleLoadOlder} shouldUpdateScroll={shouldUpdateScroll} ref={this.setRef}>\n        {scrollableContent}\n      </ScrollableList>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/containers/account_container.js",
    "content": "import React from 'react';\nimport { connect } from 'react-redux';\nimport { defineMessages, injectIntl, FormattedMessage } from 'react-intl';\nimport { makeGetAccount } from '../selectors';\nimport Account from '../components/account';\nimport {\n  followAccount,\n  unfollowAccount,\n  blockAccount,\n  unblockAccount,\n  muteAccount,\n  unmuteAccount,\n} from '../actions/accounts';\nimport { openModal } from '../actions/modal';\nimport { initMuteModal } from '../actions/mutes';\nimport { unfollowModal } from '../initial_state';\n\nconst messages = defineMessages({\n  unfollowConfirm: { id: 'confirmations.unfollow.confirm', defaultMessage: 'Unfollow' },\n});\n\nconst makeMapStateToProps = () => {\n  const getAccount = makeGetAccount();\n\n  const mapStateToProps = (state, props) => ({\n    account: getAccount(state, props.id),\n  });\n\n  return mapStateToProps;\n};\n\nconst mapDispatchToProps = (dispatch, { intl }) => ({\n\n  onFollow (account) {\n    if (account.getIn(['relationship', 'following']) || account.getIn(['relationship', 'requested'])) {\n      if (unfollowModal) {\n        dispatch(openModal('CONFIRM', {\n          message: <FormattedMessage id='confirmations.unfollow.message' defaultMessage='Are you sure you want to unfollow {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,\n          confirm: intl.formatMessage(messages.unfollowConfirm),\n          onConfirm: () => dispatch(unfollowAccount(account.get('id'))),\n        }));\n      } else {\n        dispatch(unfollowAccount(account.get('id')));\n      }\n    } else {\n      dispatch(followAccount(account.get('id')));\n    }\n  },\n\n  onBlock (account) {\n    if (account.getIn(['relationship', 'blocking'])) {\n      dispatch(unblockAccount(account.get('id')));\n    } else {\n      dispatch(blockAccount(account.get('id')));\n    }\n  },\n\n  onMute (account) {\n    if (account.getIn(['relationship', 'muting'])) {\n      dispatch(unmuteAccount(account.get('id')));\n    } else {\n      dispatch(initMuteModal(account));\n    }\n  },\n\n\n  onMuteNotifications (account, notifications) {\n    dispatch(muteAccount(account.get('id'), notifications));\n  },\n});\n\nexport default injectIntl(connect(makeMapStateToProps, mapDispatchToProps)(Account));\n"
  },
  {
    "path": "app/javascript/mastodon/containers/compose_container.js",
    "content": "import React from 'react';\nimport { Provider } from 'react-redux';\nimport PropTypes from 'prop-types';\nimport configureStore from '../store/configureStore';\nimport { hydrateStore } from '../actions/store';\nimport { IntlProvider, addLocaleData } from 'react-intl';\nimport { getLocale } from '../locales';\nimport Compose from '../features/standalone/compose';\nimport initialState from '../initial_state';\nimport { fetchCustomEmojis } from '../actions/custom_emojis';\n\nconst { localeData, messages } = getLocale();\naddLocaleData(localeData);\n\nconst store = configureStore();\n\nif (initialState) {\n  store.dispatch(hydrateStore(initialState));\n}\n\nstore.dispatch(fetchCustomEmojis());\n\nexport default class TimelineContainer extends React.PureComponent {\n\n  static propTypes = {\n    locale: PropTypes.string.isRequired,\n  };\n\n  render () {\n    const { locale } = this.props;\n\n    return (\n      <IntlProvider locale={locale} messages={messages}>\n        <Provider store={store}>\n          <Compose />\n        </Provider>\n      </IntlProvider>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/containers/domain_container.js",
    "content": "import React from 'react';\nimport { connect } from 'react-redux';\nimport { blockDomain, unblockDomain } from '../actions/domain_blocks';\nimport { defineMessages, injectIntl, FormattedMessage } from 'react-intl';\nimport Domain from '../components/domain';\nimport { openModal } from '../actions/modal';\n\nconst messages = defineMessages({\n  blockDomainConfirm: { id: 'confirmations.domain_block.confirm', defaultMessage: 'Hide entire domain' },\n});\n\nconst makeMapStateToProps = () => {\n  const mapStateToProps = () => ({});\n\n  return mapStateToProps;\n};\n\nconst mapDispatchToProps = (dispatch, { intl }) => ({\n  onBlockDomain (domain) {\n    dispatch(openModal('CONFIRM', {\n      message: <FormattedMessage id='confirmations.domain_block.message' defaultMessage='Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.' values={{ domain: <strong>{domain}</strong> }} />,\n      confirm: intl.formatMessage(messages.blockDomainConfirm),\n      onConfirm: () => dispatch(blockDomain(domain)),\n    }));\n  },\n\n  onUnblockDomain (domain) {\n    dispatch(unblockDomain(domain));\n  },\n});\n\nexport default injectIntl(connect(makeMapStateToProps, mapDispatchToProps)(Domain));\n"
  },
  {
    "path": "app/javascript/mastodon/containers/dropdown_menu_container.js",
    "content": "import { openDropdownMenu, closeDropdownMenu } from '../actions/dropdown_menu';\nimport { openModal, closeModal } from '../actions/modal';\nimport { connect } from 'react-redux';\nimport DropdownMenu from '../components/dropdown_menu';\nimport { isUserTouching } from '../is_mobile';\n\nconst mapStateToProps = state => ({\n  isModalOpen: state.get('modal').modalType === 'ACTIONS',\n  dropdownPlacement: state.getIn(['dropdown_menu', 'placement']),\n  openDropdownId: state.getIn(['dropdown_menu', 'openId']),\n  openedViaKeyboard: state.getIn(['dropdown_menu', 'keyboard']),\n});\n\nconst mapDispatchToProps = (dispatch, { status, items }) => ({\n  onOpen(id, onItemClick, dropdownPlacement, keyboard) {\n    dispatch(isUserTouching() ? openModal('ACTIONS', {\n      status,\n      actions: items,\n      onClick: onItemClick,\n    }) : openDropdownMenu(id, dropdownPlacement, keyboard));\n  },\n  onClose(id) {\n    dispatch(closeModal());\n    dispatch(closeDropdownMenu(id));\n  },\n});\n\nexport default connect(mapStateToProps, mapDispatchToProps)(DropdownMenu);\n"
  },
  {
    "path": "app/javascript/mastodon/containers/intersection_observer_article_container.js",
    "content": "import { connect } from 'react-redux';\nimport IntersectionObserverArticle from '../components/intersection_observer_article';\nimport { setHeight } from '../actions/height_cache';\n\nconst makeMapStateToProps = (state, props) => ({\n  cachedHeight: state.getIn(['height_cache', props.saveHeightKey, props.id]),\n});\n\nconst mapDispatchToProps = (dispatch) => ({\n\n  onHeightChange (key, id, height) {\n    dispatch(setHeight(key, id, height));\n  },\n\n});\n\nexport default connect(makeMapStateToProps, mapDispatchToProps)(IntersectionObserverArticle);\n"
  },
  {
    "path": "app/javascript/mastodon/containers/mastodon.js",
    "content": "import React from 'react';\nimport { Provider, connect } from 'react-redux';\nimport PropTypes from 'prop-types';\nimport configureStore from '../store/configureStore';\nimport { INTRODUCTION_VERSION } from '../actions/onboarding';\nimport { BrowserRouter, Route } from 'react-router-dom';\nimport { ScrollContext } from 'react-router-scroll-4';\nimport UI from '../features/ui';\nimport Introduction from '../features/introduction';\nimport { fetchCustomEmojis } from '../actions/custom_emojis';\nimport { hydrateStore } from '../actions/store';\nimport { connectUserStream } from '../actions/streaming';\nimport { IntlProvider, addLocaleData } from 'react-intl';\nimport { getLocale } from '../locales';\nimport initialState from '../initial_state';\nimport ErrorBoundary from '../components/error_boundary';\n\nconst { localeData, messages } = getLocale();\naddLocaleData(localeData);\n\nexport const store = configureStore();\nconst hydrateAction = hydrateStore(initialState);\n\nstore.dispatch(hydrateAction);\nstore.dispatch(fetchCustomEmojis());\n\nconst mapStateToProps = state => ({\n  showIntroduction: state.getIn(['settings', 'introductionVersion'], 0) < INTRODUCTION_VERSION,\n});\n\n@connect(mapStateToProps)\nclass MastodonMount extends React.PureComponent {\n\n  static propTypes = {\n    showIntroduction: PropTypes.bool,\n  };\n\n  render () {\n    const { showIntroduction } = this.props;\n\n    if (showIntroduction) {\n      return <Introduction />;\n    }\n\n    return (\n      <BrowserRouter basename='/web'>\n        <ScrollContext>\n          <Route path='/' component={UI} />\n        </ScrollContext>\n      </BrowserRouter>\n    );\n  }\n\n}\n\nexport default class Mastodon extends React.PureComponent {\n\n  static propTypes = {\n    locale: PropTypes.string.isRequired,\n  };\n\n  componentDidMount() {\n    this.disconnect = store.dispatch(connectUserStream());\n  }\n\n  componentWillUnmount () {\n    if (this.disconnect) {\n      this.disconnect();\n      this.disconnect = null;\n    }\n  }\n\n  render () {\n    const { locale } = this.props;\n\n    return (\n      <IntlProvider locale={locale} messages={messages}>\n        <Provider store={store}>\n          <ErrorBoundary>\n            <MastodonMount />\n          </ErrorBoundary>\n        </Provider>\n      </IntlProvider>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/containers/media_container.js",
    "content": "import React, { PureComponent, Fragment } from 'react';\nimport ReactDOM from 'react-dom';\nimport PropTypes from 'prop-types';\nimport { IntlProvider, addLocaleData } from 'react-intl';\nimport { getLocale } from '../locales';\nimport MediaGallery from '../components/media_gallery';\nimport Video from '../features/video';\nimport Card from '../features/status/components/card';\nimport Poll from 'mastodon/components/poll';\nimport ModalRoot from '../components/modal_root';\nimport MediaModal from '../features/ui/components/media_modal';\nimport { List as ImmutableList, fromJS } from 'immutable';\n\nconst { localeData, messages } = getLocale();\naddLocaleData(localeData);\n\nconst MEDIA_COMPONENTS = { MediaGallery, Video, Card, Poll };\n\nexport default class MediaContainer extends PureComponent {\n\n  static propTypes = {\n    locale: PropTypes.string.isRequired,\n    components: PropTypes.object.isRequired,\n  };\n\n  state = {\n    media: null,\n    index: null,\n    time: null,\n  };\n\n  handleOpenMedia = (media, index) => {\n    document.body.classList.add('with-modals--active');\n    this.setState({ media, index });\n  }\n\n  handleOpenVideo = (video, time) => {\n    const media = ImmutableList([video]);\n\n    document.body.classList.add('with-modals--active');\n    this.setState({ media, time });\n  }\n\n  handleCloseMedia = () => {\n    document.body.classList.remove('with-modals--active');\n    this.setState({ media: null, index: null, time: null });\n  }\n\n  render () {\n    const { locale, components } = this.props;\n\n    return (\n      <IntlProvider locale={locale} messages={messages}>\n        <Fragment>\n          {[].map.call(components, (component, i) => {\n            const componentName = component.getAttribute('data-component');\n            const Component = MEDIA_COMPONENTS[componentName];\n            const { media, card, poll, ...props } = JSON.parse(component.getAttribute('data-props'));\n\n            Object.assign(props, {\n              ...(media ? { media: fromJS(media) } : {}),\n              ...(card  ? { card:  fromJS(card)  } : {}),\n              ...(poll  ? { poll:  fromJS(poll)  } : {}),\n\n              ...(componentName === 'Video' ? {\n                onOpenVideo: this.handleOpenVideo,\n              } : {\n                onOpenMedia: this.handleOpenMedia,\n              }),\n            });\n\n            return ReactDOM.createPortal(\n              <Component {...props} key={`media-${i}`} />,\n              component,\n            );\n          })}\n          <ModalRoot onClose={this.handleCloseMedia}>\n            {this.state.media && (\n              <MediaModal\n                media={this.state.media}\n                index={this.state.index || 0}\n                time={this.state.time}\n                onClose={this.handleCloseMedia}\n              />\n            )}\n          </ModalRoot>\n        </Fragment>\n      </IntlProvider>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/containers/poll_container.js",
    "content": "import { connect } from 'react-redux';\nimport Poll from 'mastodon/components/poll';\n\nconst mapStateToProps = (state, { pollId }) => ({\n  poll: state.getIn(['polls', pollId]),\n});\n\nexport default connect(mapStateToProps)(Poll);\n"
  },
  {
    "path": "app/javascript/mastodon/containers/status_container.js",
    "content": "import React from 'react';\nimport { connect } from 'react-redux';\nimport Status from '../components/status';\nimport { makeGetStatus } from '../selectors';\nimport {\n  replyCompose,\n  mentionCompose,\n  directCompose,\n} from '../actions/compose';\nimport {\n  reblog,\n  favourite,\n  unreblog,\n  unfavourite,\n  pin,\n  unpin,\n} from '../actions/interactions';\nimport { blockAccount } from '../actions/accounts';\nimport {\n  muteStatus,\n  unmuteStatus,\n  deleteStatus,\n  hideStatus,\n  revealStatus,\n} from '../actions/statuses';\nimport { initMuteModal } from '../actions/mutes';\nimport { initReport } from '../actions/reports';\nimport { openModal } from '../actions/modal';\nimport { defineMessages, injectIntl, FormattedMessage } from 'react-intl';\nimport { boostModal, deleteModal } from '../initial_state';\nimport { showAlertForError } from '../actions/alerts';\n\nconst messages = defineMessages({\n  deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' },\n  deleteMessage: { id: 'confirmations.delete.message', defaultMessage: 'Are you sure you want to delete this status?' },\n  redraftConfirm: { id: 'confirmations.redraft.confirm', defaultMessage: 'Delete & redraft' },\n  redraftMessage: { id: 'confirmations.redraft.message', defaultMessage: 'Are you sure you want to delete this status and re-draft it? Favourites and boosts will be lost, and replies to the original post will be orphaned.' },\n  blockConfirm: { id: 'confirmations.block.confirm', defaultMessage: 'Block' },\n  replyConfirm: { id: 'confirmations.reply.confirm', defaultMessage: 'Reply' },\n  replyMessage: { id: 'confirmations.reply.message', defaultMessage: 'Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?' },\n  blockAndReport: { id: 'confirmations.block.block_and_report', defaultMessage: 'Block & Report' },\n});\n\nconst makeMapStateToProps = () => {\n  const getStatus = makeGetStatus();\n\n  const mapStateToProps = (state, props) => ({\n    status: getStatus(state, props),\n  });\n\n  return mapStateToProps;\n};\n\nconst mapDispatchToProps = (dispatch, { intl }) => ({\n\n  onReply (status, router) {\n    dispatch((_, getState) => {\n      let state = getState();\n      if (state.getIn(['compose', 'text']).trim().length !== 0) {\n        dispatch(openModal('CONFIRM', {\n          message: intl.formatMessage(messages.replyMessage),\n          confirm: intl.formatMessage(messages.replyConfirm),\n          onConfirm: () => dispatch(replyCompose(status, router)),\n        }));\n      } else {\n        dispatch(replyCompose(status, router));\n      }\n    });\n  },\n\n  onModalReblog (status) {\n    if (status.get('reblogged')) {\n      dispatch(unreblog(status));\n    } else {\n      dispatch(reblog(status));\n    }\n  },\n\n  onReblog (status, e) {\n    if (e.shiftKey || !boostModal) {\n      this.onModalReblog(status);\n    } else {\n      dispatch(openModal('BOOST', { status, onReblog: this.onModalReblog }));\n    }\n  },\n\n  onFavourite (status) {\n    if (status.get('favourited')) {\n      dispatch(unfavourite(status));\n    } else {\n      dispatch(favourite(status));\n    }\n  },\n\n  onPin (status) {\n    if (status.get('pinned')) {\n      dispatch(unpin(status));\n    } else {\n      dispatch(pin(status));\n    }\n  },\n\n  onEmbed (status) {\n    dispatch(openModal('EMBED', {\n      url: status.get('url'),\n      onError: error => dispatch(showAlertForError(error)),\n    }));\n  },\n\n  onDelete (status, history, withRedraft = false) {\n    if (!deleteModal) {\n      dispatch(deleteStatus(status.get('id'), history, withRedraft));\n    } else {\n      dispatch(openModal('CONFIRM', {\n        message: intl.formatMessage(withRedraft ? messages.redraftMessage : messages.deleteMessage),\n        confirm: intl.formatMessage(withRedraft ? messages.redraftConfirm : messages.deleteConfirm),\n        onConfirm: () => dispatch(deleteStatus(status.get('id'), history, withRedraft)),\n      }));\n    }\n  },\n\n  onDirect (account, router) {\n    dispatch(directCompose(account, router));\n  },\n\n  onMention (account, router) {\n    dispatch(mentionCompose(account, router));\n  },\n\n  onOpenMedia (media, index) {\n    dispatch(openModal('MEDIA', { media, index }));\n  },\n\n  onOpenVideo (media, time) {\n    dispatch(openModal('VIDEO', { media, time }));\n  },\n\n  onBlock (status) {\n    const account = status.get('account');\n    dispatch(openModal('CONFIRM', {\n      message: <FormattedMessage id='confirmations.block.message' defaultMessage='Are you sure you want to block {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,\n      confirm: intl.formatMessage(messages.blockConfirm),\n      onConfirm: () => dispatch(blockAccount(account.get('id'))),\n      secondary: intl.formatMessage(messages.blockAndReport),\n      onSecondary: () => {\n        dispatch(blockAccount(account.get('id')));\n        dispatch(initReport(account, status));\n      },\n    }));\n  },\n\n  onReport (status) {\n    dispatch(initReport(status.get('account'), status));\n  },\n\n  onMute (account) {\n    dispatch(initMuteModal(account));\n  },\n\n  onMuteConversation (status) {\n    if (status.get('muted')) {\n      dispatch(unmuteStatus(status.get('id')));\n    } else {\n      dispatch(muteStatus(status.get('id')));\n    }\n  },\n\n  onToggleHidden (status) {\n    if (status.get('hidden')) {\n      dispatch(revealStatus(status.get('id')));\n    } else {\n      dispatch(hideStatus(status.get('id')));\n    }\n  },\n\n});\n\nexport default injectIntl(connect(makeMapStateToProps, mapDispatchToProps)(Status));\n"
  },
  {
    "path": "app/javascript/mastodon/containers/timeline_container.js",
    "content": "import React, { Fragment } from 'react';\nimport ReactDOM from 'react-dom';\nimport { Provider } from 'react-redux';\nimport PropTypes from 'prop-types';\nimport configureStore from '../store/configureStore';\nimport { hydrateStore } from '../actions/store';\nimport { IntlProvider, addLocaleData } from 'react-intl';\nimport { getLocale } from '../locales';\nimport PublicTimeline from '../features/standalone/public_timeline';\nimport HashtagTimeline from '../features/standalone/hashtag_timeline';\nimport ModalContainer from '../features/ui/containers/modal_container';\nimport initialState from '../initial_state';\n\nconst { localeData, messages } = getLocale();\naddLocaleData(localeData);\n\nconst store = configureStore();\n\nif (initialState) {\n  store.dispatch(hydrateStore(initialState));\n}\n\nexport default class TimelineContainer extends React.PureComponent {\n\n  static propTypes = {\n    locale: PropTypes.string.isRequired,\n    hashtag: PropTypes.string,\n    local: PropTypes.bool,\n  };\n\n  static defaultProps = {\n    local: !initialState.settings.known_fediverse,\n  };\n\n  render () {\n    const { locale, hashtag, local } = this.props;\n\n    let timeline;\n\n    if (hashtag) {\n      timeline = <HashtagTimeline hashtag={hashtag} />;\n    } else {\n      timeline = <PublicTimeline local={local} />;\n    }\n\n    return (\n      <IntlProvider locale={locale} messages={messages}>\n        <Provider store={store}>\n          <Fragment>\n            {timeline}\n\n            {ReactDOM.createPortal(\n              <ModalContainer />,\n              document.getElementById('modal-container'),\n            )}\n          </Fragment>\n        </Provider>\n      </IntlProvider>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/extra_polyfills.js",
    "content": "import 'intersection-observer';\nimport 'requestidlecallback';\nimport objectFitImages  from 'object-fit-images';\n\nobjectFitImages();\n"
  },
  {
    "path": "app/javascript/mastodon/features/account/components/header.js",
    "content": "import React from 'react';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport PropTypes from 'prop-types';\nimport { defineMessages, injectIntl, FormattedMessage } from 'react-intl';\nimport Button from 'mastodon/components/button';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport { autoPlayGif, me, isStaff } from 'mastodon/initial_state';\nimport classNames from 'classnames';\nimport Icon from 'mastodon/components/icon';\nimport Avatar from 'mastodon/components/avatar';\nimport { shortNumberFormat } from 'mastodon/utils/numbers';\nimport { NavLink } from 'react-router-dom';\nimport DropdownMenuContainer from 'mastodon/containers/dropdown_menu_container';\n\nconst messages = defineMessages({\n  unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' },\n  follow: { id: 'account.follow', defaultMessage: 'Follow' },\n  requested: { id: 'account.requested', defaultMessage: 'Awaiting approval. Click to cancel follow request' },\n  unblock: { id: 'account.unblock', defaultMessage: 'Unblock @{name}' },\n  edit_profile: { id: 'account.edit_profile', defaultMessage: 'Edit profile' },\n  linkVerifiedOn: { id: 'account.link_verified_on', defaultMessage: 'Ownership of this link was checked on {date}' },\n  account_locked: { id: 'account.locked_info', defaultMessage: 'This account privacy status is set to locked. The owner manually reviews who can follow them.' },\n  mention: { id: 'account.mention', defaultMessage: 'Mention @{name}' },\n  direct: { id: 'account.direct', defaultMessage: 'Direct message @{name}' },\n  unmute: { id: 'account.unmute', defaultMessage: 'Unmute @{name}' },\n  block: { id: 'account.block', defaultMessage: 'Block @{name}' },\n  mute: { id: 'account.mute', defaultMessage: 'Mute @{name}' },\n  report: { id: 'account.report', defaultMessage: 'Report @{name}' },\n  share: { id: 'account.share', defaultMessage: 'Share @{name}\\'s profile' },\n  media: { id: 'account.media', defaultMessage: 'Media' },\n  blockDomain: { id: 'account.block_domain', defaultMessage: 'Hide everything from {domain}' },\n  unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unhide {domain}' },\n  hideReblogs: { id: 'account.hide_reblogs', defaultMessage: 'Hide boosts from @{name}' },\n  showReblogs: { id: 'account.show_reblogs', defaultMessage: 'Show boosts from @{name}' },\n  pins: { id: 'navigation_bar.pins', defaultMessage: 'Pinned toots' },\n  preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' },\n  follow_requests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' },\n  favourites: { id: 'navigation_bar.favourites', defaultMessage: 'Favourites' },\n  lists: { id: 'navigation_bar.lists', defaultMessage: 'Lists' },\n  blocks: { id: 'navigation_bar.blocks', defaultMessage: 'Blocked users' },\n  domain_blocks: { id: 'navigation_bar.domain_blocks', defaultMessage: 'Hidden domains' },\n  mutes: { id: 'navigation_bar.mutes', defaultMessage: 'Muted users' },\n  endorse: { id: 'account.endorse', defaultMessage: 'Feature on profile' },\n  unendorse: { id: 'account.unendorse', defaultMessage: 'Don\\'t feature on profile' },\n  add_or_remove_from_list: { id: 'account.add_or_remove_from_list', defaultMessage: 'Add or Remove from lists' },\n  admin_account: { id: 'status.admin_account', defaultMessage: 'Open moderation interface for @{name}' },\n});\n\nconst dateFormatOptions = {\n  month: 'short',\n  day: 'numeric',\n  year: 'numeric',\n  hour12: false,\n  hour: '2-digit',\n  minute: '2-digit',\n};\n\nexport default @injectIntl\nclass Header extends ImmutablePureComponent {\n\n  static propTypes = {\n    account: ImmutablePropTypes.map,\n    identity_props: ImmutablePropTypes.list,\n    onFollow: PropTypes.func.isRequired,\n    onBlock: PropTypes.func.isRequired,\n    intl: PropTypes.object.isRequired,\n    domain: PropTypes.string.isRequired,\n  };\n\n  openEditProfile = () => {\n    window.open('/settings/profile', '_blank');\n  }\n\n  isStatusesPageActive = (match, location) => {\n    if (!match) {\n      return false;\n    }\n\n    return !location.pathname.match(/\\/(followers|following)\\/?$/);\n  }\n\n  render () {\n    const { account, intl, domain, identity_proofs } = this.props;\n\n    if (!account) {\n      return null;\n    }\n\n    let info        = [];\n    let actionBtn   = '';\n    let lockedIcon  = '';\n    let menu        = [];\n\n    if (me !== account.get('id') && account.getIn(['relationship', 'followed_by'])) {\n      info.push(<span key='followed_by' className='relationship-tag'><FormattedMessage id='account.follows_you' defaultMessage='Follows you' /></span>);\n    } else if (me !== account.get('id') && account.getIn(['relationship', 'blocking'])) {\n      info.push(<span key='blocked' className='relationship-tag'><FormattedMessage id='account.blocked' defaultMessage='Blocked' /></span>);\n    }\n\n    if (me !== account.get('id') && account.getIn(['relationship', 'muting'])) {\n      info.push(<span key='muted' className='relationship-tag'><FormattedMessage id='account.muted' defaultMessage='Muted' /></span>);\n    } else if (me !== account.get('id') && account.getIn(['relationship', 'domain_blocking'])) {\n      info.push(<span key='domain_blocked' className='relationship-tag'><FormattedMessage id='account.domain_blocked' defaultMessage='Domain hidden' /></span>);\n    }\n\n    if (me !== account.get('id')) {\n      if (!account.get('relationship')) { // Wait until the relationship is loaded\n        actionBtn = '';\n      } else if (account.getIn(['relationship', 'requested'])) {\n        actionBtn = <Button className='logo-button' text={intl.formatMessage(messages.requested)} onClick={this.props.onFollow} />;\n      } else if (!account.getIn(['relationship', 'blocking'])) {\n        actionBtn = <Button disabled={account.getIn(['relationship', 'blocked_by'])} className={classNames('logo-button', { 'button--destructive': account.getIn(['relationship', 'following']) })} text={intl.formatMessage(account.getIn(['relationship', 'following']) ? messages.unfollow : messages.follow)} onClick={this.props.onFollow} />;\n      } else if (account.getIn(['relationship', 'blocking'])) {\n        actionBtn = <Button className='logo-button' text={intl.formatMessage(messages.unblock, { name: account.get('username') })} onClick={this.props.onBlock} />;\n      }\n    } else {\n      actionBtn = <Button className='logo-button' text={intl.formatMessage(messages.edit_profile)} onClick={this.openEditProfile} />;\n    }\n\n    if (account.get('moved') && !account.getIn(['relationship', 'following'])) {\n      actionBtn = '';\n    }\n\n    if (account.get('locked')) {\n      lockedIcon = <Icon id='lock' title={intl.formatMessage(messages.account_locked)} />;\n    }\n\n    if (account.get('id') !== me) {\n      menu.push({ text: intl.formatMessage(messages.mention, { name: account.get('username') }), action: this.props.onMention });\n      menu.push({ text: intl.formatMessage(messages.direct, { name: account.get('username') }), action: this.props.onDirect });\n      menu.push(null);\n    }\n\n    if ('share' in navigator) {\n      menu.push({ text: intl.formatMessage(messages.share, { name: account.get('username') }), action: this.handleShare });\n      menu.push(null);\n    }\n\n    if (account.get('id') === me) {\n      menu.push({ text: intl.formatMessage(messages.edit_profile), href: '/settings/profile' });\n      menu.push({ text: intl.formatMessage(messages.preferences), href: '/settings/preferences' });\n      menu.push({ text: intl.formatMessage(messages.pins), to: '/pinned' });\n      menu.push(null);\n      menu.push({ text: intl.formatMessage(messages.follow_requests), to: '/follow_requests' });\n      menu.push({ text: intl.formatMessage(messages.favourites), to: '/favourites' });\n      menu.push({ text: intl.formatMessage(messages.lists), to: '/lists' });\n      menu.push(null);\n      menu.push({ text: intl.formatMessage(messages.mutes), to: '/mutes' });\n      menu.push({ text: intl.formatMessage(messages.blocks), to: '/blocks' });\n      menu.push({ text: intl.formatMessage(messages.domain_blocks), to: '/domain_blocks' });\n    } else {\n      if (account.getIn(['relationship', 'following'])) {\n        if (account.getIn(['relationship', 'showing_reblogs'])) {\n          menu.push({ text: intl.formatMessage(messages.hideReblogs, { name: account.get('username') }), action: this.props.onReblogToggle });\n        } else {\n          menu.push({ text: intl.formatMessage(messages.showReblogs, { name: account.get('username') }), action: this.props.onReblogToggle });\n        }\n\n        menu.push({ text: intl.formatMessage(account.getIn(['relationship', 'endorsed']) ? messages.unendorse : messages.endorse), action: this.props.onEndorseToggle });\n        menu.push({ text: intl.formatMessage(messages.add_or_remove_from_list), action: this.props.onAddToList });\n        menu.push(null);\n      }\n\n      if (account.getIn(['relationship', 'muting'])) {\n        menu.push({ text: intl.formatMessage(messages.unmute, { name: account.get('username') }), action: this.props.onMute });\n      } else {\n        menu.push({ text: intl.formatMessage(messages.mute, { name: account.get('username') }), action: this.props.onMute });\n      }\n\n      if (account.getIn(['relationship', 'blocking'])) {\n        menu.push({ text: intl.formatMessage(messages.unblock, { name: account.get('username') }), action: this.props.onBlock });\n      } else {\n        menu.push({ text: intl.formatMessage(messages.block, { name: account.get('username') }), action: this.props.onBlock });\n      }\n\n      menu.push({ text: intl.formatMessage(messages.report, { name: account.get('username') }), action: this.props.onReport });\n    }\n\n    if (account.get('acct') !== account.get('username')) {\n      const domain = account.get('acct').split('@')[1];\n\n      menu.push(null);\n\n      if (account.getIn(['relationship', 'domain_blocking'])) {\n        menu.push({ text: intl.formatMessage(messages.unblockDomain, { domain }), action: this.props.onUnblockDomain });\n      } else {\n        menu.push({ text: intl.formatMessage(messages.blockDomain, { domain }), action: this.props.onBlockDomain });\n      }\n    }\n\n    if (account.get('id') !== me && isStaff) {\n      menu.push(null);\n      menu.push({ text: intl.formatMessage(messages.admin_account, { name: account.get('username') }), href: `/admin/accounts/${account.get('id')}` });\n    }\n\n    const content         = { __html: account.get('note_emojified') };\n    const displayNameHtml = { __html: account.get('display_name_html') };\n    const fields          = account.get('fields');\n    const badge           = account.get('bot') ? (<div className='account-role bot'><FormattedMessage id='account.badges.bot' defaultMessage='Bot' /></div>) : null;\n    const acct            = account.get('acct').indexOf('@') === -1 && domain ? `${account.get('acct')}@${domain}` : account.get('acct');\n\n    return (\n      <div className={classNames('account__header', { inactive: !!account.get('moved') })}>\n        <div className='account__header__image'>\n          <div className='account__header__info'>\n            {info}\n          </div>\n\n          <img src={autoPlayGif ? account.get('header') : account.get('header_static')} alt='' className='parallax' />\n        </div>\n\n        <div className='account__header__bar'>\n          <div className='account__header__tabs'>\n            <a className='avatar' href={account.get('url')} rel='noopener' target='_blank'>\n              <Avatar account={account} size={90} />\n            </a>\n\n            <div className='spacer' />\n\n            <div className='account__header__tabs__buttons'>\n              {actionBtn}\n\n              <DropdownMenuContainer items={menu} icon='ellipsis-v' size={24} direction='right' />\n            </div>\n          </div>\n\n          <div className='account__header__tabs__name'>\n            <h1>\n              <span dangerouslySetInnerHTML={displayNameHtml} /> {badge}\n              <small>@{acct} {lockedIcon}</small>\n            </h1>\n          </div>\n\n          <div className='account__header__extra'>\n            <div className='account__header__bio'>\n              { (fields.size > 0 || identity_proofs.size > 0) && (\n                <div className='account__header__fields'>\n                  {identity_proofs.map((proof, i) => (\n                    <dl key={i}>\n                      <dt dangerouslySetInnerHTML={{ __html: proof.get('provider') }} />\n\n                      <dd className='verified'>\n                        <a href={proof.get('proof_url')} target='_blank' rel='noopener'><span title={intl.formatMessage(messages.linkVerifiedOn, { date: intl.formatDate(proof.get('updated_at'), dateFormatOptions) })}>\n                          <Icon id='check' className='verified__mark' />\n                        </span></a>\n                        <a href={proof.get('profile_url')} target='_blank' rel='noopener'><span dangerouslySetInnerHTML={{ __html: ' '+proof.get('provider_username') }} /></a>\n                      </dd>\n                    </dl>\n                  ))}\n                  {fields.map((pair, i) => (\n                    <dl key={i}>\n                      <dt dangerouslySetInnerHTML={{ __html: pair.get('name_emojified') }} title={pair.get('name')} />\n\n                      <dd className={pair.get('verified_at') && 'verified'} title={pair.get('value_plain')}>\n                        {pair.get('verified_at') && <span title={intl.formatMessage(messages.linkVerifiedOn, { date: intl.formatDate(pair.get('verified_at'), dateFormatOptions) })}><Icon id='check' className='verified__mark' /></span>} <span dangerouslySetInnerHTML={{ __html: pair.get('value_emojified') }} />\n                      </dd>\n                    </dl>\n                  ))}\n                </div>\n              )}\n\n              {account.get('note').length > 0 && account.get('note') !== '<p></p>' && <div className='account__header__content' dangerouslySetInnerHTML={content} />}\n            </div>\n\n            <div className='account__header__extra__links'>\n              <NavLink isActive={this.isStatusesPageActive} activeClassName='active' to={`/accounts/${account.get('id')}`} title={intl.formatNumber(account.get('statuses_count'))}>\n                <strong>{shortNumberFormat(account.get('statuses_count'))}</strong> <FormattedMessage id='account.posts' defaultMessage='Toots' />\n              </NavLink>\n\n              <NavLink exact activeClassName='active' to={`/accounts/${account.get('id')}/following`} title={intl.formatNumber(account.get('following_count'))}>\n                <strong>{shortNumberFormat(account.get('following_count'))}</strong> <FormattedMessage id='account.follows' defaultMessage='Follows' />\n              </NavLink>\n\n              <NavLink exact activeClassName='active' to={`/accounts/${account.get('id')}/followers`} title={intl.formatNumber(account.get('followers_count'))}>\n                <strong>{shortNumberFormat(account.get('followers_count'))}</strong> <FormattedMessage id='account.followers' defaultMessage='Followers' />\n              </NavLink>\n            </div>\n          </div>\n        </div>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/account_gallery/components/media_item.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport Icon from 'mastodon/components/icon';\nimport { autoPlayGif, displayMedia } from 'mastodon/initial_state';\nimport classNames from 'classnames';\nimport { decode } from 'blurhash';\nimport { isIOS } from 'mastodon/is_mobile';\n\nexport default class MediaItem extends ImmutablePureComponent {\n\n  static propTypes = {\n    attachment: ImmutablePropTypes.map.isRequired,\n    displayWidth: PropTypes.number.isRequired,\n    onOpenMedia: PropTypes.func.isRequired,\n  };\n\n  state = {\n    visible: displayMedia !== 'hide_all' && !this.props.attachment.getIn(['status', 'sensitive']) || displayMedia === 'show_all',\n    loaded: false,\n  };\n\n  componentDidMount () {\n    if (this.props.attachment.get('blurhash')) {\n      this._decode();\n    }\n  }\n\n  componentDidUpdate (prevProps) {\n    if (prevProps.attachment.get('blurhash') !== this.props.attachment.get('blurhash') && this.props.attachment.get('blurhash')) {\n      this._decode();\n    }\n  }\n\n  _decode () {\n    const hash   = this.props.attachment.get('blurhash');\n    const pixels = decode(hash, 32, 32);\n\n    if (pixels) {\n      const ctx       = this.canvas.getContext('2d');\n      const imageData = new ImageData(pixels, 32, 32);\n\n      ctx.putImageData(imageData, 0, 0);\n    }\n  }\n\n  setCanvasRef = c => {\n    this.canvas = c;\n  }\n\n  handleImageLoad = () => {\n    this.setState({ loaded: true });\n  }\n\n  handleMouseEnter = e => {\n    if (this.hoverToPlay()) {\n      e.target.play();\n    }\n  }\n\n  handleMouseLeave = e => {\n    if (this.hoverToPlay()) {\n      e.target.pause();\n      e.target.currentTime = 0;\n    }\n  }\n\n  hoverToPlay () {\n    return !autoPlayGif && ['gifv', 'video'].indexOf(this.props.attachment.get('type')) !== -1;\n  }\n\n  handleClick = e => {\n    if (e.button === 0 && !(e.ctrlKey || e.metaKey)) {\n      e.preventDefault();\n\n      if (this.state.visible) {\n        this.props.onOpenMedia(this.props.attachment);\n      } else {\n        this.setState({ visible: true });\n      }\n    }\n  }\n\n  render () {\n    const { attachment, displayWidth } = this.props;\n    const { visible, loaded } = this.state;\n\n    const width  = `${Math.floor((displayWidth - 4) / 3) - 4}px`;\n    const height = width;\n    const status = attachment.get('status');\n    const title = status.get('spoiler_text') || attachment.get('description');\n\n    let thumbnail = '';\n    let icon;\n\n    if (attachment.get('type') === 'unknown') {\n      // Skip\n    } else if (attachment.get('type') === 'image') {\n      const focusX = attachment.getIn(['meta', 'focus', 'x']) || 0;\n      const focusY = attachment.getIn(['meta', 'focus', 'y']) || 0;\n      const x      = ((focusX /  2) + .5) * 100;\n      const y      = ((focusY / -2) + .5) * 100;\n\n      thumbnail = (\n        <img\n          src={attachment.get('preview_url')}\n          alt={attachment.get('description')}\n          title={attachment.get('description')}\n          style={{ objectPosition: `${x}% ${y}%` }}\n          onLoad={this.handleImageLoad}\n        />\n      );\n    } else if (['gifv', 'video'].indexOf(attachment.get('type')) !== -1) {\n      const autoPlay = !isIOS() && autoPlayGif;\n\n      thumbnail = (\n        <div className={classNames('media-gallery__gifv', { autoplay: autoPlay })}>\n          <video\n            className='media-gallery__item-gifv-thumbnail'\n            aria-label={attachment.get('description')}\n            title={attachment.get('description')}\n            role='application'\n            src={attachment.get('url')}\n            onMouseEnter={this.handleMouseEnter}\n            onMouseLeave={this.handleMouseLeave}\n            autoPlay={autoPlay}\n            loop\n            muted\n          />\n\n          <span className='media-gallery__gifv__label'>GIF</span>\n        </div>\n      );\n    }\n\n    if (!visible) {\n      icon = (\n        <span className='account-gallery__item__icons'>\n          <Icon id='eye-slash' />\n        </span>\n      );\n    }\n\n    return (\n      <div className='account-gallery__item' style={{ width, height }}>\n        <a className='media-gallery__item-thumbnail' href={status.get('url')} target='_blank' onClick={this.handleClick} title={title}>\n          <canvas width={32} height={32} ref={this.setCanvasRef} className={classNames('media-gallery__preview', { 'media-gallery__preview--hidden': visible && loaded })} />\n          {visible && thumbnail}\n          {!visible && icon}\n        </a>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/account_gallery/index.js",
    "content": "import React from 'react';\nimport { connect } from 'react-redux';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport PropTypes from 'prop-types';\nimport { fetchAccount } from 'mastodon/actions/accounts';\nimport { expandAccountMediaTimeline } from '../../actions/timelines';\nimport LoadingIndicator from 'mastodon/components/loading_indicator';\nimport Column from '../ui/components/column';\nimport ColumnBackButton from 'mastodon/components/column_back_button';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport { getAccountGallery } from 'mastodon/selectors';\nimport MediaItem from './components/media_item';\nimport HeaderContainer from '../account_timeline/containers/header_container';\nimport { ScrollContainer } from 'react-router-scroll-4';\nimport LoadMore from 'mastodon/components/load_more';\nimport MissingIndicator from 'mastodon/components/missing_indicator';\nimport { openModal } from 'mastodon/actions/modal';\n\nconst mapStateToProps = (state, props) => ({\n  isAccount: !!state.getIn(['accounts', props.params.accountId]),\n  attachments: getAccountGallery(state, props.params.accountId),\n  isLoading: state.getIn(['timelines', `account:${props.params.accountId}:media`, 'isLoading']),\n  hasMore: state.getIn(['timelines', `account:${props.params.accountId}:media`, 'hasMore']),\n});\n\nclass LoadMoreMedia extends ImmutablePureComponent {\n\n  static propTypes = {\n    shouldUpdateScroll: PropTypes.func,\n    maxId: PropTypes.string,\n    onLoadMore: PropTypes.func.isRequired,\n  };\n\n  handleLoadMore = () => {\n    this.props.onLoadMore(this.props.maxId);\n  }\n\n  render () {\n    return (\n      <LoadMore\n        disabled={this.props.disabled}\n        onClick={this.handleLoadMore}\n      />\n    );\n  }\n\n}\n\nexport default @connect(mapStateToProps)\nclass AccountGallery extends ImmutablePureComponent {\n\n  static propTypes = {\n    params: PropTypes.object.isRequired,\n    dispatch: PropTypes.func.isRequired,\n    attachments: ImmutablePropTypes.list.isRequired,\n    isLoading: PropTypes.bool,\n    hasMore: PropTypes.bool,\n    isAccount: PropTypes.bool,\n  };\n\n  state = {\n    width: 323,\n  };\n\n  componentDidMount () {\n    this.props.dispatch(fetchAccount(this.props.params.accountId));\n    this.props.dispatch(expandAccountMediaTimeline(this.props.params.accountId));\n  }\n\n  componentWillReceiveProps (nextProps) {\n    if (nextProps.params.accountId !== this.props.params.accountId && nextProps.params.accountId) {\n      this.props.dispatch(fetchAccount(nextProps.params.accountId));\n      this.props.dispatch(expandAccountMediaTimeline(this.props.params.accountId));\n    }\n  }\n\n  handleScrollToBottom = () => {\n    if (this.props.hasMore) {\n      this.handleLoadMore(this.props.attachments.size > 0 ? this.props.attachments.last().getIn(['status', 'id']) : undefined);\n    }\n  }\n\n  handleScroll = e => {\n    const { scrollTop, scrollHeight, clientHeight } = e.target;\n    const offset = scrollHeight - scrollTop - clientHeight;\n\n    if (150 > offset && !this.props.isLoading) {\n      this.handleScrollToBottom();\n    }\n  }\n\n  handleLoadMore = maxId => {\n    this.props.dispatch(expandAccountMediaTimeline(this.props.params.accountId, { maxId }));\n  };\n\n  handleLoadOlder = e => {\n    e.preventDefault();\n    this.handleScrollToBottom();\n  }\n\n  handleOpenMedia = attachment => {\n    if (attachment.get('type') === 'video') {\n      this.props.dispatch(openModal('VIDEO', { media: attachment, status: attachment.get('status') }));\n    } else {\n      const media = attachment.getIn(['status', 'media_attachments']);\n      const index = media.findIndex(x => x.get('id') === attachment.get('id'));\n\n      this.props.dispatch(openModal('MEDIA', { media, index, status: attachment.get('status') }));\n    }\n  }\n\n  handleRef = c => {\n    if (c) {\n      this.setState({ width: c.offsetWidth });\n    }\n  }\n\n  render () {\n    const { attachments, shouldUpdateScroll, isLoading, hasMore, isAccount } = this.props;\n    const { width } = this.state;\n\n    if (!isAccount) {\n      return (\n        <Column>\n          <MissingIndicator />\n        </Column>\n      );\n    }\n\n    if (!attachments && isLoading) {\n      return (\n        <Column>\n          <LoadingIndicator />\n        </Column>\n      );\n    }\n\n    let loadOlder = null;\n\n    if (hasMore && !(isLoading && attachments.size === 0)) {\n      loadOlder = <LoadMore visible={!isLoading} onClick={this.handleLoadOlder} />;\n    }\n\n    return (\n      <Column>\n        <ColumnBackButton />\n\n        <ScrollContainer scrollKey='account_gallery' shouldUpdateScroll={shouldUpdateScroll}>\n          <div className='scrollable scrollable--flex' onScroll={this.handleScroll}>\n            <HeaderContainer accountId={this.props.params.accountId} />\n\n            <div role='feed' className='account-gallery__container' ref={this.handleRef}>\n              {attachments.map((attachment, index) => attachment === null ? (\n                <LoadMoreMedia key={'more:' + attachments.getIn(index + 1, 'id')} maxId={index > 0 ? attachments.getIn(index - 1, 'id') : null} onLoadMore={this.handleLoadMore} />\n              ) : (\n                <MediaItem key={attachment.get('id')} attachment={attachment} displayWidth={width} onOpenMedia={this.handleOpenMedia} />\n              ))}\n\n              {loadOlder}\n            </div>\n\n            {isLoading && attachments.size === 0 && (\n              <div className='scrollable__append'>\n                <LoadingIndicator />\n              </div>\n            )}\n          </div>\n        </ScrollContainer>\n      </Column>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/account_timeline/components/header.js",
    "content": "import React from 'react';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport PropTypes from 'prop-types';\nimport InnerHeader from '../../account/components/header';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport MovedNote from './moved_note';\nimport { FormattedMessage } from 'react-intl';\nimport { NavLink } from 'react-router-dom';\n\nexport default class Header extends ImmutablePureComponent {\n\n  static propTypes = {\n    account: ImmutablePropTypes.map,\n    identity_proofs: ImmutablePropTypes.list,\n    onFollow: PropTypes.func.isRequired,\n    onBlock: PropTypes.func.isRequired,\n    onMention: PropTypes.func.isRequired,\n    onDirect: PropTypes.func.isRequired,\n    onReblogToggle: PropTypes.func.isRequired,\n    onReport: PropTypes.func.isRequired,\n    onMute: PropTypes.func.isRequired,\n    onBlockDomain: PropTypes.func.isRequired,\n    onUnblockDomain: PropTypes.func.isRequired,\n    onEndorseToggle: PropTypes.func.isRequired,\n    onAddToList: PropTypes.func.isRequired,\n    hideTabs: PropTypes.bool,\n    domain: PropTypes.string.isRequired,\n  };\n\n  static contextTypes = {\n    router: PropTypes.object,\n  };\n\n  handleFollow = () => {\n    this.props.onFollow(this.props.account);\n  }\n\n  handleBlock = () => {\n    this.props.onBlock(this.props.account);\n  }\n\n  handleMention = () => {\n    this.props.onMention(this.props.account, this.context.router.history);\n  }\n\n  handleDirect = () => {\n    this.props.onDirect(this.props.account, this.context.router.history);\n  }\n\n  handleReport = () => {\n    this.props.onReport(this.props.account);\n  }\n\n  handleReblogToggle = () => {\n    this.props.onReblogToggle(this.props.account);\n  }\n\n  handleMute = () => {\n    this.props.onMute(this.props.account);\n  }\n\n  handleBlockDomain = () => {\n    const domain = this.props.account.get('acct').split('@')[1];\n\n    if (!domain) return;\n\n    this.props.onBlockDomain(domain);\n  }\n\n  handleUnblockDomain = () => {\n    const domain = this.props.account.get('acct').split('@')[1];\n\n    if (!domain) return;\n\n    this.props.onUnblockDomain(domain);\n  }\n\n  handleEndorseToggle = () => {\n    this.props.onEndorseToggle(this.props.account);\n  }\n\n  handleAddToList = () => {\n    this.props.onAddToList(this.props.account);\n  }\n\n  render () {\n    const { account, hideTabs, identity_proofs } = this.props;\n\n    if (account === null) {\n      return null;\n    }\n\n    return (\n      <div className='account-timeline__header'>\n        {account.get('moved') && <MovedNote from={account} to={account.get('moved')} />}\n\n        <InnerHeader\n          account={account}\n          identity_proofs={identity_proofs}\n          onFollow={this.handleFollow}\n          onBlock={this.handleBlock}\n          onMention={this.handleMention}\n          onDirect={this.handleDirect}\n          onReblogToggle={this.handleReblogToggle}\n          onReport={this.handleReport}\n          onMute={this.handleMute}\n          onBlockDomain={this.handleBlockDomain}\n          onUnblockDomain={this.handleUnblockDomain}\n          onEndorseToggle={this.handleEndorseToggle}\n          onAddToList={this.handleAddToList}\n          domain={this.props.domain}\n        />\n\n        {!hideTabs && (\n          <div className='account__section-headline'>\n            <NavLink exact to={`/accounts/${account.get('id')}`}><FormattedMessage id='account.posts' defaultMessage='Toots' /></NavLink>\n            <NavLink exact to={`/accounts/${account.get('id')}/with_replies`}><FormattedMessage id='account.posts_with_replies' defaultMessage='Toots and replies' /></NavLink>\n            <NavLink exact to={`/accounts/${account.get('id')}/media`}><FormattedMessage id='account.media' defaultMessage='Media' /></NavLink>\n          </div>\n        )}\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/account_timeline/components/moved_note.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport { FormattedMessage } from 'react-intl';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport AvatarOverlay from '../../../components/avatar_overlay';\nimport DisplayName from '../../../components/display_name';\nimport Icon from 'mastodon/components/icon';\n\nexport default class MovedNote extends ImmutablePureComponent {\n\n  static contextTypes = {\n    router: PropTypes.object,\n  };\n\n  static propTypes = {\n    from: ImmutablePropTypes.map.isRequired,\n    to: ImmutablePropTypes.map.isRequired,\n  };\n\n  handleAccountClick = e => {\n    if (e.button === 0) {\n      e.preventDefault();\n      this.context.router.history.push(`/accounts/${this.props.to.get('id')}`);\n    }\n\n    e.stopPropagation();\n  }\n\n  render () {\n    const { from, to } = this.props;\n    const displayNameHtml = { __html: from.get('display_name_html') };\n\n    return (\n      <div className='account__moved-note'>\n        <div className='account__moved-note__message'>\n          <div className='account__moved-note__icon-wrapper'><Icon id='suitcase' className='account__moved-note__icon' fixedWidth /></div>\n          <FormattedMessage id='account.moved_to' defaultMessage='{name} has moved to:' values={{ name: <bdi><strong dangerouslySetInnerHTML={displayNameHtml} /></bdi> }} />\n        </div>\n\n        <a href={to.get('url')} onClick={this.handleAccountClick} className='detailed-status__display-name'>\n          <div className='detailed-status__display-avatar'><AvatarOverlay account={to} friend={from} /></div>\n          <DisplayName account={to} />\n        </a>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/account_timeline/containers/header_container.js",
    "content": "import React from 'react';\nimport { connect } from 'react-redux';\nimport { makeGetAccount } from '../../../selectors';\nimport Header from '../components/header';\nimport {\n  followAccount,\n  unfollowAccount,\n  blockAccount,\n  unblockAccount,\n  unmuteAccount,\n  pinAccount,\n  unpinAccount,\n} from '../../../actions/accounts';\nimport {\n  mentionCompose,\n  directCompose,\n} from '../../../actions/compose';\nimport { initMuteModal } from '../../../actions/mutes';\nimport { initReport } from '../../../actions/reports';\nimport { openModal } from '../../../actions/modal';\nimport { blockDomain, unblockDomain } from '../../../actions/domain_blocks';\nimport { defineMessages, injectIntl, FormattedMessage } from 'react-intl';\nimport { unfollowModal } from '../../../initial_state';\nimport { List as ImmutableList } from 'immutable';\n\nconst messages = defineMessages({\n  unfollowConfirm: { id: 'confirmations.unfollow.confirm', defaultMessage: 'Unfollow' },\n  blockConfirm: { id: 'confirmations.block.confirm', defaultMessage: 'Block' },\n  blockDomainConfirm: { id: 'confirmations.domain_block.confirm', defaultMessage: 'Hide entire domain' },\n  blockAndReport: { id: 'confirmations.block.block_and_report', defaultMessage: 'Block & Report' },\n});\n\nconst makeMapStateToProps = () => {\n  const getAccount = makeGetAccount();\n\n  const mapStateToProps = (state, { accountId }) => ({\n    account: getAccount(state, accountId),\n    domain: state.getIn(['meta', 'domain']),\n    identity_proofs: state.getIn(['identity_proofs', accountId], ImmutableList()),\n  });\n\n  return mapStateToProps;\n};\n\nconst mapDispatchToProps = (dispatch, { intl }) => ({\n\n  onFollow (account) {\n    if (account.getIn(['relationship', 'following']) || account.getIn(['relationship', 'requested'])) {\n      if (unfollowModal) {\n        dispatch(openModal('CONFIRM', {\n          message: <FormattedMessage id='confirmations.unfollow.message' defaultMessage='Are you sure you want to unfollow {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,\n          confirm: intl.formatMessage(messages.unfollowConfirm),\n          onConfirm: () => dispatch(unfollowAccount(account.get('id'))),\n        }));\n      } else {\n        dispatch(unfollowAccount(account.get('id')));\n      }\n    } else {\n      dispatch(followAccount(account.get('id')));\n    }\n  },\n\n  onBlock (account) {\n    if (account.getIn(['relationship', 'blocking'])) {\n      dispatch(unblockAccount(account.get('id')));\n    } else {\n      dispatch(openModal('CONFIRM', {\n        message: <FormattedMessage id='confirmations.block.message' defaultMessage='Are you sure you want to block {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,\n        confirm: intl.formatMessage(messages.blockConfirm),\n        onConfirm: () => dispatch(blockAccount(account.get('id'))),\n        secondary: intl.formatMessage(messages.blockAndReport),\n        onSecondary: () => {\n          dispatch(blockAccount(account.get('id')));\n          dispatch(initReport(account));\n        },\n      }));\n    }\n  },\n\n  onMention (account, router) {\n    dispatch(mentionCompose(account, router));\n  },\n\n  onDirect (account, router) {\n    dispatch(directCompose(account, router));\n  },\n\n  onReblogToggle (account) {\n    if (account.getIn(['relationship', 'showing_reblogs'])) {\n      dispatch(followAccount(account.get('id'), false));\n    } else {\n      dispatch(followAccount(account.get('id'), true));\n    }\n  },\n\n  onEndorseToggle (account) {\n    if (account.getIn(['relationship', 'endorsed'])) {\n      dispatch(unpinAccount(account.get('id')));\n    } else {\n      dispatch(pinAccount(account.get('id')));\n    }\n  },\n\n  onReport (account) {\n    dispatch(initReport(account));\n  },\n\n  onMute (account) {\n    if (account.getIn(['relationship', 'muting'])) {\n      dispatch(unmuteAccount(account.get('id')));\n    } else {\n      dispatch(initMuteModal(account));\n    }\n  },\n\n  onBlockDomain (domain) {\n    dispatch(openModal('CONFIRM', {\n      message: <FormattedMessage id='confirmations.domain_block.message' defaultMessage='Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain in any public timelines or your notifications. Your followers from that domain will be removed.' values={{ domain: <strong>{domain}</strong> }} />,\n      confirm: intl.formatMessage(messages.blockDomainConfirm),\n      onConfirm: () => dispatch(blockDomain(domain)),\n    }));\n  },\n\n  onUnblockDomain (domain) {\n    dispatch(unblockDomain(domain));\n  },\n\n  onAddToList(account){\n    dispatch(openModal('LIST_ADDER', {\n      accountId: account.get('id'),\n    }));\n  },\n\n});\n\nexport default injectIntl(connect(makeMapStateToProps, mapDispatchToProps)(Header));\n"
  },
  {
    "path": "app/javascript/mastodon/features/account_timeline/index.js",
    "content": "import React from 'react';\nimport { connect } from 'react-redux';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport PropTypes from 'prop-types';\nimport { fetchAccount } from '../../actions/accounts';\nimport { expandAccountFeaturedTimeline, expandAccountTimeline } from '../../actions/timelines';\nimport StatusList from '../../components/status_list';\nimport LoadingIndicator from '../../components/loading_indicator';\nimport Column from '../ui/components/column';\nimport HeaderContainer from './containers/header_container';\nimport ColumnBackButton from '../../components/column_back_button';\nimport { List as ImmutableList } from 'immutable';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport { FormattedMessage } from 'react-intl';\nimport { fetchAccountIdentityProofs } from '../../actions/identity_proofs';\nimport MissingIndicator from 'mastodon/components/missing_indicator';\n\nconst emptyList = ImmutableList();\n\nconst mapStateToProps = (state, { params: { accountId }, withReplies = false }) => {\n  const path = withReplies ? `${accountId}:with_replies` : accountId;\n\n  return {\n    isAccount: !!state.getIn(['accounts', accountId]),\n    statusIds: state.getIn(['timelines', `account:${path}`, 'items'], emptyList),\n    featuredStatusIds: withReplies ? ImmutableList() : state.getIn(['timelines', `account:${accountId}:pinned`, 'items'], emptyList),\n    isLoading: state.getIn(['timelines', `account:${path}`, 'isLoading']),\n    hasMore: state.getIn(['timelines', `account:${path}`, 'hasMore']),\n    blockedBy: state.getIn(['relationships', accountId, 'blocked_by'], false),\n  };\n};\n\nexport default @connect(mapStateToProps)\nclass AccountTimeline extends ImmutablePureComponent {\n\n  static propTypes = {\n    params: PropTypes.object.isRequired,\n    dispatch: PropTypes.func.isRequired,\n    shouldUpdateScroll: PropTypes.func,\n    statusIds: ImmutablePropTypes.list,\n    featuredStatusIds: ImmutablePropTypes.list,\n    isLoading: PropTypes.bool,\n    hasMore: PropTypes.bool,\n    withReplies: PropTypes.bool,\n    blockedBy: PropTypes.bool,\n    isAccount: PropTypes.bool,\n  };\n\n  componentWillMount () {\n    const { params: { accountId }, withReplies } = this.props;\n\n    this.props.dispatch(fetchAccount(accountId));\n    this.props.dispatch(fetchAccountIdentityProofs(accountId));\n\n    if (!withReplies) {\n      this.props.dispatch(expandAccountFeaturedTimeline(accountId));\n    }\n\n    this.props.dispatch(expandAccountTimeline(accountId, { withReplies }));\n  }\n\n  componentWillReceiveProps (nextProps) {\n    if ((nextProps.params.accountId !== this.props.params.accountId && nextProps.params.accountId) || nextProps.withReplies !== this.props.withReplies) {\n      this.props.dispatch(fetchAccount(nextProps.params.accountId));\n      this.props.dispatch(fetchAccountIdentityProofs(nextProps.params.accountId));\n\n      if (!nextProps.withReplies) {\n        this.props.dispatch(expandAccountFeaturedTimeline(nextProps.params.accountId));\n      }\n\n      this.props.dispatch(expandAccountTimeline(nextProps.params.accountId, { withReplies: nextProps.params.withReplies }));\n    }\n  }\n\n  handleLoadMore = maxId => {\n    this.props.dispatch(expandAccountTimeline(this.props.params.accountId, { maxId, withReplies: this.props.withReplies }));\n  }\n\n  render () {\n    const { shouldUpdateScroll, statusIds, featuredStatusIds, isLoading, hasMore, blockedBy, isAccount } = this.props;\n\n    if (!isAccount) {\n      return (\n        <Column>\n          <MissingIndicator />\n        </Column>\n      );\n    }\n\n    if (!statusIds && isLoading) {\n      return (\n        <Column>\n          <LoadingIndicator />\n        </Column>\n      );\n    }\n\n    const emptyMessage = blockedBy ? <FormattedMessage id='empty_column.account_unavailable' defaultMessage='Profile unavailable' /> : <FormattedMessage id='empty_column.account_timeline' defaultMessage='No toots here!' />;\n\n    return (\n      <Column>\n        <ColumnBackButton />\n\n        <StatusList\n          prepend={<HeaderContainer accountId={this.props.params.accountId} />}\n          alwaysPrepend\n          scrollKey='account_timeline'\n          statusIds={blockedBy ? emptyList : statusIds}\n          featuredStatusIds={featuredStatusIds}\n          isLoading={isLoading}\n          hasMore={hasMore}\n          onLoadMore={this.handleLoadMore}\n          shouldUpdateScroll={shouldUpdateScroll}\n          emptyMessage={emptyMessage}\n        />\n      </Column>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/blocks/index.js",
    "content": "import React from 'react';\nimport { connect } from 'react-redux';\nimport { defineMessages, injectIntl, FormattedMessage } from 'react-intl';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport { debounce } from 'lodash';\nimport PropTypes from 'prop-types';\nimport LoadingIndicator from '../../components/loading_indicator';\nimport Column from '../ui/components/column';\nimport ColumnBackButtonSlim from '../../components/column_back_button_slim';\nimport AccountContainer from '../../containers/account_container';\nimport { fetchBlocks, expandBlocks } from '../../actions/blocks';\nimport ScrollableList from '../../components/scrollable_list';\n\nconst messages = defineMessages({\n  heading: { id: 'column.blocks', defaultMessage: 'Blocked users' },\n});\n\nconst mapStateToProps = state => ({\n  accountIds: state.getIn(['user_lists', 'blocks', 'items']),\n  hasMore: !!state.getIn(['user_lists', 'blocks', 'next']),\n});\n\nexport default @connect(mapStateToProps)\n@injectIntl\nclass Blocks extends ImmutablePureComponent {\n\n  static propTypes = {\n    params: PropTypes.object.isRequired,\n    dispatch: PropTypes.func.isRequired,\n    shouldUpdateScroll: PropTypes.func,\n    accountIds: ImmutablePropTypes.list,\n    hasMore: PropTypes.bool,\n    intl: PropTypes.object.isRequired,\n  };\n\n  componentWillMount () {\n    this.props.dispatch(fetchBlocks());\n  }\n\n  handleLoadMore = debounce(() => {\n    this.props.dispatch(expandBlocks());\n  }, 300, { leading: true });\n\n  render () {\n    const { intl, accountIds, shouldUpdateScroll, hasMore } = this.props;\n\n    if (!accountIds) {\n      return (\n        <Column>\n          <LoadingIndicator />\n        </Column>\n      );\n    }\n\n    const emptyMessage = <FormattedMessage id='empty_column.blocks' defaultMessage=\"You haven't blocked any users yet.\" />;\n\n    return (\n      <Column icon='ban' heading={intl.formatMessage(messages.heading)}>\n        <ColumnBackButtonSlim />\n        <ScrollableList\n          scrollKey='blocks'\n          onLoadMore={this.handleLoadMore}\n          hasMore={hasMore}\n          shouldUpdateScroll={shouldUpdateScroll}\n          emptyMessage={emptyMessage}\n        >\n          {accountIds.map(id =>\n            <AccountContainer key={id} id={id} />\n          )}\n        </ScrollableList>\n      </Column>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/community_timeline/components/column_settings.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport { injectIntl, FormattedMessage } from 'react-intl';\nimport SettingToggle from '../../notifications/components/setting_toggle';\n\nexport default @injectIntl\nclass ColumnSettings extends React.PureComponent {\n\n  static propTypes = {\n    settings: ImmutablePropTypes.map.isRequired,\n    onChange: PropTypes.func.isRequired,\n    intl: PropTypes.object.isRequired,\n    columnId: PropTypes.string,\n  };\n\n  render () {\n    const { settings, onChange } = this.props;\n\n    return (\n      <div>\n        <div className='column-settings__row'>\n          <SettingToggle settings={settings} settingPath={['other', 'onlyMedia']} onChange={onChange} label={<FormattedMessage id='community.column_settings.media_only' defaultMessage='Media Only' />} />\n        </div>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/community_timeline/containers/column_settings_container.js",
    "content": "import { connect } from 'react-redux';\nimport ColumnSettings from '../components/column_settings';\nimport { changeSetting } from '../../../actions/settings';\nimport { changeColumnParams } from '../../../actions/columns';\n\nconst mapStateToProps = (state, { columnId }) => {\n  const uuid = columnId;\n  const columns = state.getIn(['settings', 'columns']);\n  const index = columns.findIndex(c => c.get('uuid') === uuid);\n\n  return {\n    settings: (uuid && index >= 0) ? columns.get(index).get('params') : state.getIn(['settings', 'community']),\n  };\n};\n\nconst mapDispatchToProps = (dispatch, { columnId }) => {\n  return {\n    onChange (key, checked) {\n      if (columnId) {\n        dispatch(changeColumnParams(columnId, key, checked));\n      } else {\n        dispatch(changeSetting(['community', ...key], checked));\n      }\n    },\n  };\n};\n\nexport default connect(mapStateToProps, mapDispatchToProps)(ColumnSettings);\n"
  },
  {
    "path": "app/javascript/mastodon/features/community_timeline/index.js",
    "content": "import React from 'react';\nimport { connect } from 'react-redux';\nimport { defineMessages, injectIntl, FormattedMessage } from 'react-intl';\nimport PropTypes from 'prop-types';\nimport StatusListContainer from '../ui/containers/status_list_container';\nimport Column from '../../components/column';\nimport ColumnHeader from '../../components/column_header';\nimport { expandCommunityTimeline } from '../../actions/timelines';\nimport { addColumn, removeColumn, moveColumn } from '../../actions/columns';\nimport ColumnSettingsContainer from './containers/column_settings_container';\nimport { connectCommunityStream } from '../../actions/streaming';\n\nconst messages = defineMessages({\n  title: { id: 'column.community', defaultMessage: 'Local timeline' },\n});\n\nconst mapStateToProps = (state, { onlyMedia, columnId }) => {\n  const uuid = columnId;\n  const columns = state.getIn(['settings', 'columns']);\n  const index = columns.findIndex(c => c.get('uuid') === uuid);\n\n  return {\n    hasUnread: state.getIn(['timelines', `community${onlyMedia ? ':media' : ''}`, 'unread']) > 0,\n    onlyMedia: (columnId && index >= 0) ? columns.get(index).getIn(['params', 'other', 'onlyMedia']) : state.getIn(['settings', 'community', 'other', 'onlyMedia']),\n  };\n};\n\nexport default @connect(mapStateToProps)\n@injectIntl\nclass CommunityTimeline extends React.PureComponent {\n\n  static contextTypes = {\n    router: PropTypes.object,\n  };\n\n  static defaultProps = {\n    onlyMedia: false,\n  };\n\n  static propTypes = {\n    dispatch: PropTypes.func.isRequired,\n    shouldUpdateScroll: PropTypes.func,\n    columnId: PropTypes.string,\n    intl: PropTypes.object.isRequired,\n    hasUnread: PropTypes.bool,\n    multiColumn: PropTypes.bool,\n    onlyMedia: PropTypes.bool,\n  };\n\n  handlePin = () => {\n    const { columnId, dispatch, onlyMedia } = this.props;\n\n    if (columnId) {\n      dispatch(removeColumn(columnId));\n    } else {\n      dispatch(addColumn('COMMUNITY', { other: { onlyMedia } }));\n    }\n  }\n\n  handleMove = (dir) => {\n    const { columnId, dispatch } = this.props;\n    dispatch(moveColumn(columnId, dir));\n  }\n\n  handleHeaderClick = () => {\n    this.column.scrollTop();\n  }\n\n  componentDidMount () {\n    const { dispatch, onlyMedia } = this.props;\n\n    dispatch(expandCommunityTimeline({ onlyMedia }));\n    this.disconnect = dispatch(connectCommunityStream({ onlyMedia }));\n  }\n\n  componentDidUpdate (prevProps) {\n    if (prevProps.onlyMedia !== this.props.onlyMedia) {\n      const { dispatch, onlyMedia } = this.props;\n\n      this.disconnect();\n      dispatch(expandCommunityTimeline({ onlyMedia }));\n      this.disconnect = dispatch(connectCommunityStream({ onlyMedia }));\n    }\n  }\n\n  componentWillUnmount () {\n    if (this.disconnect) {\n      this.disconnect();\n      this.disconnect = null;\n    }\n  }\n\n  setRef = c => {\n    this.column = c;\n  }\n\n  handleLoadMore = maxId => {\n    const { dispatch, onlyMedia } = this.props;\n\n    dispatch(expandCommunityTimeline({ maxId, onlyMedia }));\n  }\n\n  render () {\n    const { intl, shouldUpdateScroll, hasUnread, columnId, multiColumn, onlyMedia } = this.props;\n    const pinned = !!columnId;\n\n    return (\n      <Column ref={this.setRef} label={intl.formatMessage(messages.title)}>\n        <ColumnHeader\n          icon='users'\n          active={hasUnread}\n          title={intl.formatMessage(messages.title)}\n          onPin={this.handlePin}\n          onMove={this.handleMove}\n          onClick={this.handleHeaderClick}\n          pinned={pinned}\n          multiColumn={multiColumn}\n        >\n          <ColumnSettingsContainer columnId={columnId} />\n        </ColumnHeader>\n\n        <StatusListContainer\n          trackScroll={!pinned}\n          scrollKey={`community_timeline-${columnId}`}\n          timelineId={`community${onlyMedia ? ':media' : ''}`}\n          onLoadMore={this.handleLoadMore}\n          emptyMessage={<FormattedMessage id='empty_column.community' defaultMessage='The local timeline is empty. Write something publicly to get the ball rolling!' />}\n          shouldUpdateScroll={shouldUpdateScroll}\n        />\n      </Column>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/compose/components/action_bar.js",
    "content": "import React from 'react';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport PropTypes from 'prop-types';\nimport DropdownMenuContainer from '../../../containers/dropdown_menu_container';\nimport { defineMessages, injectIntl } from 'react-intl';\n\nconst messages = defineMessages({\n  edit_profile: { id: 'account.edit_profile', defaultMessage: 'Edit profile' },\n  pins: { id: 'navigation_bar.pins', defaultMessage: 'Pinned toots' },\n  preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' },\n  follow_requests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' },\n  favourites: { id: 'navigation_bar.favourites', defaultMessage: 'Favourites' },\n  lists: { id: 'navigation_bar.lists', defaultMessage: 'Lists' },\n  blocks: { id: 'navigation_bar.blocks', defaultMessage: 'Blocked users' },\n  domain_blocks: { id: 'navigation_bar.domain_blocks', defaultMessage: 'Hidden domains' },\n  mutes: { id: 'navigation_bar.mutes', defaultMessage: 'Muted users' },\n  filters: { id: 'navigation_bar.filters', defaultMessage: 'Muted words' },\n});\n\nexport default @injectIntl\nclass ActionBar extends React.PureComponent {\n\n  static propTypes = {\n    account: ImmutablePropTypes.map.isRequired,\n    intl: PropTypes.object.isRequired,\n  };\n\n  render () {\n    const { intl } = this.props;\n\n    let menu = [];\n\n    menu.push({ text: intl.formatMessage(messages.edit_profile), href: '/settings/profile' });\n    menu.push({ text: intl.formatMessage(messages.preferences), href: '/settings/preferences' });\n    menu.push({ text: intl.formatMessage(messages.pins), to: '/pinned' });\n    menu.push(null);\n    menu.push({ text: intl.formatMessage(messages.follow_requests), to: '/follow_requests' });\n    menu.push({ text: intl.formatMessage(messages.favourites), to: '/favourites' });\n    menu.push({ text: intl.formatMessage(messages.lists), to: '/lists' });\n    menu.push(null);\n    menu.push({ text: intl.formatMessage(messages.mutes), to: '/mutes' });\n    menu.push({ text: intl.formatMessage(messages.blocks), to: '/blocks' });\n    menu.push({ text: intl.formatMessage(messages.domain_blocks), to: '/domain_blocks' });\n    menu.push({ text: intl.formatMessage(messages.filters), href: '/filters' });\n\n    return (\n      <div className='compose__action-bar'>\n        <div className='compose__action-bar-dropdown'>\n          <DropdownMenuContainer items={menu} icon='chevron-down' size={16} direction='right' />\n        </div>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/compose/components/autosuggest_account.js",
    "content": "import React from 'react';\nimport Avatar from '../../../components/avatar';\nimport DisplayName from '../../../components/display_name';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\n\nexport default class AutosuggestAccount extends ImmutablePureComponent {\n\n  static propTypes = {\n    account: ImmutablePropTypes.map.isRequired,\n  };\n\n  render () {\n    const { account } = this.props;\n\n    return (\n      <div className='autosuggest-account' title={account.get('acct')}>\n        <div className='autosuggest-account-icon'><Avatar account={account} size={18} /></div>\n        <DisplayName account={account} />\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/compose/components/character_counter.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport { length } from 'stringz';\n\nexport default class CharacterCounter extends React.PureComponent {\n\n  static propTypes = {\n    text: PropTypes.string.isRequired,\n    max: PropTypes.number.isRequired,\n  };\n\n  checkRemainingText (diff) {\n    if (diff < 0) {\n      return <span className='character-counter character-counter--over'>{diff}</span>;\n    }\n\n    return <span className='character-counter'>{diff}</span>;\n  }\n\n  render () {\n    const diff = this.props.max - length(this.props.text);\n    return this.checkRemainingText(diff);\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/compose/components/compose_form.js",
    "content": "import React from 'react';\nimport CharacterCounter from './character_counter';\nimport Button from '../../../components/button';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport PropTypes from 'prop-types';\nimport ReplyIndicatorContainer from '../containers/reply_indicator_container';\nimport AutosuggestTextarea from '../../../components/autosuggest_textarea';\nimport AutosuggestInput from '../../../components/autosuggest_input';\nimport PollButtonContainer from '../containers/poll_button_container';\nimport UploadButtonContainer from '../containers/upload_button_container';\nimport { defineMessages, injectIntl } from 'react-intl';\nimport SpoilerButtonContainer from '../containers/spoiler_button_container';\nimport PrivacyDropdownContainer from '../containers/privacy_dropdown_container';\nimport EmojiPickerDropdown from '../containers/emoji_picker_dropdown_container';\nimport PollFormContainer from '../containers/poll_form_container';\nimport UploadFormContainer from '../containers/upload_form_container';\nimport WarningContainer from '../containers/warning_container';\nimport { isMobile } from '../../../is_mobile';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport { length } from 'stringz';\nimport { countableText } from '../util/counter';\nimport Icon from 'mastodon/components/icon';\nimport { maxChars } from '../../../initial_state';\n\nconst allowedAroundShortCode = '><\\u0085\\u0020\\u00a0\\u1680\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\u2028\\u2029\\u0009\\u000a\\u000b\\u000c\\u000d';\n\nconst messages = defineMessages({\n  placeholder: { id: 'compose_form.placeholder', defaultMessage: 'What is on your mind?' },\n  spoiler_placeholder: { id: 'compose_form.spoiler_placeholder', defaultMessage: 'Write your warning here' },\n  publish: { id: 'compose_form.publish', defaultMessage: 'Toot' },\n  publishLoud: { id: 'compose_form.publish_loud', defaultMessage: '{publish}!' },\n});\n\nexport default @injectIntl\nclass ComposeForm extends ImmutablePureComponent {\n\n  static contextTypes = {\n    router: PropTypes.object,\n  };\n\n  static propTypes = {\n    intl: PropTypes.object.isRequired,\n    text: PropTypes.string.isRequired,\n    suggestions: ImmutablePropTypes.list,\n    spoiler: PropTypes.bool,\n    privacy: PropTypes.string,\n    spoilerText: PropTypes.string,\n    focusDate: PropTypes.instanceOf(Date),\n    caretPosition: PropTypes.number,\n    preselectDate: PropTypes.instanceOf(Date),\n    isSubmitting: PropTypes.bool,\n    isChangingUpload: PropTypes.bool,\n    isUploading: PropTypes.bool,\n    onChange: PropTypes.func.isRequired,\n    onSubmit: PropTypes.func.isRequired,\n    onClearSuggestions: PropTypes.func.isRequired,\n    onFetchSuggestions: PropTypes.func.isRequired,\n    onSuggestionSelected: PropTypes.func.isRequired,\n    onChangeSpoilerText: PropTypes.func.isRequired,\n    onPaste: PropTypes.func.isRequired,\n    onPickEmoji: PropTypes.func.isRequired,\n    showSearch: PropTypes.bool,\n    anyMedia: PropTypes.bool,\n    singleColumn: PropTypes.bool,\n  };\n\n  static defaultProps = {\n    showSearch: false,\n  };\n\n  handleChange = (e) => {\n    this.props.onChange(e.target.value);\n  }\n\n  handleKeyDown = (e) => {\n    if (e.keyCode === 13 && (e.ctrlKey || e.metaKey)) {\n      this.handleSubmit();\n    }\n  }\n\n  handleSubmit = () => {\n    if (this.props.text !== this.autosuggestTextarea.textarea.value) {\n      // Something changed the text inside the textarea (e.g. browser extensions like Grammarly)\n      // Update the state to match the current text\n      this.props.onChange(this.autosuggestTextarea.textarea.value);\n    }\n\n    // Submit disabled:\n    const { isSubmitting, isChangingUpload, isUploading, anyMedia } = this.props;\n    const fulltext = [this.props.spoilerText, countableText(this.props.text)].join('');\n\n    if (isSubmitting || isUploading || isChangingUpload || length(fulltext) > maxChars || (fulltext.length !== 0 && fulltext.trim().length === 0 && !anyMedia)) {\n      return;\n    }\n\n    this.props.onSubmit(this.context.router ? this.context.router.history : null);\n  }\n\n  onSuggestionsClearRequested = () => {\n    this.props.onClearSuggestions();\n  }\n\n  onSuggestionsFetchRequested = (token) => {\n    this.props.onFetchSuggestions(token);\n  }\n\n  onSuggestionSelected = (tokenStart, token, value) => {\n    this.props.onSuggestionSelected(tokenStart, token, value, ['text']);\n  }\n\n  onSpoilerSuggestionSelected = (tokenStart, token, value) => {\n    this.props.onSuggestionSelected(tokenStart, token, value, ['spoiler_text']);\n  }\n\n  handleChangeSpoilerText = (e) => {\n    this.props.onChangeSpoilerText(e.target.value);\n  }\n\n  handleFocus = () => {\n    if (this.composeForm && !this.props.singleColumn) {\n      this.composeForm.scrollIntoView();\n    }\n  }\n\n  componentDidUpdate (prevProps) {\n    // This statement does several things:\n    // - If we're beginning a reply, and,\n    //     - Replying to zero or one users, places the cursor at the end of the textbox.\n    //     - Replying to more than one user, selects any usernames past the first;\n    //       this provides a convenient shortcut to drop everyone else from the conversation.\n    if (this.props.focusDate !== prevProps.focusDate) {\n      let selectionEnd, selectionStart;\n\n      if (this.props.preselectDate !== prevProps.preselectDate) {\n        selectionEnd   = this.props.text.length;\n        selectionStart = this.props.text.search(/\\s/) + 1;\n      } else if (typeof this.props.caretPosition === 'number') {\n        selectionStart = this.props.caretPosition;\n        selectionEnd   = this.props.caretPosition;\n      } else {\n        selectionEnd   = this.props.text.length;\n        selectionStart = selectionEnd;\n      }\n\n      this.autosuggestTextarea.textarea.setSelectionRange(selectionStart, selectionEnd);\n      this.autosuggestTextarea.textarea.focus();\n    } else if(prevProps.isSubmitting && !this.props.isSubmitting) {\n      this.autosuggestTextarea.textarea.focus();\n    } else if (this.props.spoiler !== prevProps.spoiler) {\n      if (this.props.spoiler) {\n        this.spoilerText.input.focus();\n      } else {\n        this.autosuggestTextarea.textarea.focus();\n      }\n    }\n  }\n\n  setAutosuggestTextarea = (c) => {\n    this.autosuggestTextarea = c;\n  }\n\n  setSpoilerText = (c) => {\n    this.spoilerText = c;\n  }\n\n  setRef = c => {\n    this.composeForm = c;\n  };\n\n  handleEmojiPick = (data) => {\n    const { text }     = this.props;\n    const position     = this.autosuggestTextarea.textarea.selectionStart;\n    const needsSpace   = data.custom && position > 0 && !allowedAroundShortCode.includes(text[position - 1]);\n\n    this.props.onPickEmoji(position, data, needsSpace);\n  }\n\n  render () {\n    const { intl, onPaste, showSearch, anyMedia } = this.props;\n    const disabled = this.props.isSubmitting;\n    const text     = [this.props.spoilerText, countableText(this.props.text)].join('');\n    const disabledButton = disabled || this.props.isUploading || this.props.isChangingUpload || length(text) > maxChars || (text.length !== 0 && text.trim().length === 0 && !anyMedia);\n    let publishText = '';\n\n    if (this.props.privacy === 'private' || this.props.privacy === 'direct') {\n      publishText = <span className='compose-form__publish-private'><Icon id='lock' /> {intl.formatMessage(messages.publish)}</span>;\n    } else {\n      publishText = this.props.privacy !== 'unlisted' ? intl.formatMessage(messages.publishLoud, { publish: intl.formatMessage(messages.publish) }) : intl.formatMessage(messages.publish);\n    }\n\n    return (\n      <div className='compose-form' ref={this.setRef}>\n        <WarningContainer />\n\n        <ReplyIndicatorContainer />\n\n        <div className={`spoiler-input ${this.props.spoiler ? 'spoiler-input--visible' : ''}`}>\n          <AutosuggestInput\n            placeholder={intl.formatMessage(messages.spoiler_placeholder)}\n            value={this.props.spoilerText}\n            onChange={this.handleChangeSpoilerText}\n            onKeyDown={this.handleKeyDown}\n            disabled={!this.props.spoiler}\n            ref={this.setSpoilerText}\n            suggestions={this.props.suggestions}\n            onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}\n            onSuggestionsClearRequested={this.onSuggestionsClearRequested}\n            onSuggestionSelected={this.onSpoilerSuggestionSelected}\n            searchTokens={[':']}\n            id='cw-spoiler-input'\n            className='spoiler-input__input'\n          />\n        </div>\n\n        <AutosuggestTextarea\n          ref={this.setAutosuggestTextarea}\n          placeholder={intl.formatMessage(messages.placeholder)}\n          disabled={disabled}\n          value={this.props.text}\n          onChange={this.handleChange}\n          suggestions={this.props.suggestions}\n          onFocus={this.handleFocus}\n          onKeyDown={this.handleKeyDown}\n          onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}\n          onSuggestionsClearRequested={this.onSuggestionsClearRequested}\n          onSuggestionSelected={this.onSuggestionSelected}\n          onPaste={onPaste}\n          autoFocus={!showSearch && !isMobile(window.innerWidth)}\n        >\n          <EmojiPickerDropdown onPickEmoji={this.handleEmojiPick} />\n          <div className='compose-form__modifiers'>\n            <UploadFormContainer />\n            <PollFormContainer />\n          </div>\n        </AutosuggestTextarea>\n\n        <div className='compose-form__buttons-wrapper'>\n          <div className='compose-form__buttons'>\n            <UploadButtonContainer />\n            <PollButtonContainer />\n            <PrivacyDropdownContainer />\n            <SpoilerButtonContainer />\n          </div>\n          <div className='character-counter__wrapper'><CharacterCounter max={maxChars} text={text} /></div>\n        </div>\n\n        <div className='compose-form__publish'>\n          <div className='compose-form__publish-button-wrapper'><Button text={publishText} onClick={this.handleSubmit} disabled={disabledButton} block /></div>\n        </div>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport { defineMessages, injectIntl } from 'react-intl';\nimport { EmojiPicker as EmojiPickerAsync } from '../../ui/util/async-components';\nimport Overlay from 'react-overlays/lib/Overlay';\nimport classNames from 'classnames';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport detectPassiveEvents from 'detect-passive-events';\nimport { buildCustomEmojis } from '../../emoji/emoji';\n\nconst messages = defineMessages({\n  emoji: { id: 'emoji_button.label', defaultMessage: 'Insert emoji' },\n  emoji_search: { id: 'emoji_button.search', defaultMessage: 'Search...' },\n  emoji_not_found: { id: 'emoji_button.not_found', defaultMessage: 'No emojos!! (╯°□°）╯︵ ┻━┻' },\n  custom: { id: 'emoji_button.custom', defaultMessage: 'Custom' },\n  recent: { id: 'emoji_button.recent', defaultMessage: 'Frequently used' },\n  search_results: { id: 'emoji_button.search_results', defaultMessage: 'Search results' },\n  people: { id: 'emoji_button.people', defaultMessage: 'People' },\n  nature: { id: 'emoji_button.nature', defaultMessage: 'Nature' },\n  food: { id: 'emoji_button.food', defaultMessage: 'Food & Drink' },\n  activity: { id: 'emoji_button.activity', defaultMessage: 'Activity' },\n  travel: { id: 'emoji_button.travel', defaultMessage: 'Travel & Places' },\n  objects: { id: 'emoji_button.objects', defaultMessage: 'Objects' },\n  symbols: { id: 'emoji_button.symbols', defaultMessage: 'Symbols' },\n  flags: { id: 'emoji_button.flags', defaultMessage: 'Flags' },\n});\n\nconst assetHost = process.env.CDN_HOST || '';\nlet EmojiPicker, Emoji; // load asynchronously\n\nconst backgroundImageFn = () => `${assetHost}/emoji/sheet_10.png`;\nconst listenerOptions = detectPassiveEvents.hasSupport ? { passive: true } : false;\n\nconst categoriesSort = [\n  'recent',\n  'custom',\n  'people',\n  'nature',\n  'foods',\n  'activity',\n  'places',\n  'objects',\n  'symbols',\n  'flags',\n];\n\nclass ModifierPickerMenu extends React.PureComponent {\n\n  static propTypes = {\n    active: PropTypes.bool,\n    onSelect: PropTypes.func.isRequired,\n    onClose: PropTypes.func.isRequired,\n  };\n\n  handleClick = e => {\n    this.props.onSelect(e.currentTarget.getAttribute('data-index') * 1);\n  }\n\n  componentWillReceiveProps (nextProps) {\n    if (nextProps.active) {\n      this.attachListeners();\n    } else {\n      this.removeListeners();\n    }\n  }\n\n  componentWillUnmount () {\n    this.removeListeners();\n  }\n\n  handleDocumentClick = e => {\n    if (this.node && !this.node.contains(e.target)) {\n      this.props.onClose();\n    }\n  }\n\n  attachListeners () {\n    document.addEventListener('click', this.handleDocumentClick, false);\n    document.addEventListener('touchend', this.handleDocumentClick, listenerOptions);\n  }\n\n  removeListeners () {\n    document.removeEventListener('click', this.handleDocumentClick, false);\n    document.removeEventListener('touchend', this.handleDocumentClick, listenerOptions);\n  }\n\n  setRef = c => {\n    this.node = c;\n  }\n\n  render () {\n    const { active } = this.props;\n\n    return (\n      <div className='emoji-picker-dropdown__modifiers__menu' style={{ display: active ? 'block' : 'none' }} ref={this.setRef}>\n        <button onClick={this.handleClick} data-index={1}><Emoji emoji='fist' set='twitter' size={22} sheetSize={32} skin={1} backgroundImageFn={backgroundImageFn} /></button>\n        <button onClick={this.handleClick} data-index={2}><Emoji emoji='fist' set='twitter' size={22} sheetSize={32} skin={2} backgroundImageFn={backgroundImageFn} /></button>\n        <button onClick={this.handleClick} data-index={3}><Emoji emoji='fist' set='twitter' size={22} sheetSize={32} skin={3} backgroundImageFn={backgroundImageFn} /></button>\n        <button onClick={this.handleClick} data-index={4}><Emoji emoji='fist' set='twitter' size={22} sheetSize={32} skin={4} backgroundImageFn={backgroundImageFn} /></button>\n        <button onClick={this.handleClick} data-index={5}><Emoji emoji='fist' set='twitter' size={22} sheetSize={32} skin={5} backgroundImageFn={backgroundImageFn} /></button>\n        <button onClick={this.handleClick} data-index={6}><Emoji emoji='fist' set='twitter' size={22} sheetSize={32} skin={6} backgroundImageFn={backgroundImageFn} /></button>\n      </div>\n    );\n  }\n\n}\n\nclass ModifierPicker extends React.PureComponent {\n\n  static propTypes = {\n    active: PropTypes.bool,\n    modifier: PropTypes.number,\n    onChange: PropTypes.func,\n    onClose: PropTypes.func,\n    onOpen: PropTypes.func,\n  };\n\n  handleClick = () => {\n    if (this.props.active) {\n      this.props.onClose();\n    } else {\n      this.props.onOpen();\n    }\n  }\n\n  handleSelect = modifier => {\n    this.props.onChange(modifier);\n    this.props.onClose();\n  }\n\n  render () {\n    const { active, modifier } = this.props;\n\n    return (\n      <div className='emoji-picker-dropdown__modifiers'>\n        <Emoji emoji='fist' set='twitter' size={22} sheetSize={32} skin={modifier} onClick={this.handleClick} backgroundImageFn={backgroundImageFn} />\n        <ModifierPickerMenu active={active} onSelect={this.handleSelect} onClose={this.props.onClose} />\n      </div>\n    );\n  }\n\n}\n\n@injectIntl\nclass EmojiPickerMenu extends React.PureComponent {\n\n  static propTypes = {\n    custom_emojis: ImmutablePropTypes.list,\n    frequentlyUsedEmojis: PropTypes.arrayOf(PropTypes.string),\n    loading: PropTypes.bool,\n    onClose: PropTypes.func.isRequired,\n    onPick: PropTypes.func.isRequired,\n    style: PropTypes.object,\n    placement: PropTypes.string,\n    arrowOffsetLeft: PropTypes.string,\n    arrowOffsetTop: PropTypes.string,\n    intl: PropTypes.object.isRequired,\n    skinTone: PropTypes.number.isRequired,\n    onSkinTone: PropTypes.func.isRequired,\n  };\n\n  static defaultProps = {\n    style: {},\n    loading: true,\n    frequentlyUsedEmojis: [],\n  };\n\n  state = {\n    modifierOpen: false,\n    placement: null,\n  };\n\n  handleDocumentClick = e => {\n    if (this.node && !this.node.contains(e.target)) {\n      this.props.onClose();\n    }\n  }\n\n  componentDidMount () {\n    document.addEventListener('click', this.handleDocumentClick, false);\n    document.addEventListener('touchend', this.handleDocumentClick, listenerOptions);\n  }\n\n  componentWillUnmount () {\n    document.removeEventListener('click', this.handleDocumentClick, false);\n    document.removeEventListener('touchend', this.handleDocumentClick, listenerOptions);\n  }\n\n  setRef = c => {\n    this.node = c;\n  }\n\n  getI18n = () => {\n    const { intl } = this.props;\n\n    return {\n      search: intl.formatMessage(messages.emoji_search),\n      notfound: intl.formatMessage(messages.emoji_not_found),\n      categories: {\n        search: intl.formatMessage(messages.search_results),\n        recent: intl.formatMessage(messages.recent),\n        people: intl.formatMessage(messages.people),\n        nature: intl.formatMessage(messages.nature),\n        foods: intl.formatMessage(messages.food),\n        activity: intl.formatMessage(messages.activity),\n        places: intl.formatMessage(messages.travel),\n        objects: intl.formatMessage(messages.objects),\n        symbols: intl.formatMessage(messages.symbols),\n        flags: intl.formatMessage(messages.flags),\n        custom: intl.formatMessage(messages.custom),\n      },\n    };\n  }\n\n  handleClick = emoji => {\n    if (!emoji.native) {\n      emoji.native = emoji.colons;\n    }\n\n    this.props.onClose();\n    this.props.onPick(emoji);\n  }\n\n  handleModifierOpen = () => {\n    this.setState({ modifierOpen: true });\n  }\n\n  handleModifierClose = () => {\n    this.setState({ modifierOpen: false });\n  }\n\n  handleModifierChange = modifier => {\n    this.props.onSkinTone(modifier);\n  }\n\n  render () {\n    const { loading, style, intl, custom_emojis, skinTone, frequentlyUsedEmojis } = this.props;\n\n    if (loading) {\n      return <div style={{ width: 299 }} />;\n    }\n\n    const title = intl.formatMessage(messages.emoji);\n    const { modifierOpen } = this.state;\n\n    return (\n      <div className={classNames('emoji-picker-dropdown__menu', { selecting: modifierOpen })} style={style} ref={this.setRef}>\n        <EmojiPicker\n          perLine={8}\n          emojiSize={22}\n          sheetSize={32}\n          custom={buildCustomEmojis(custom_emojis)}\n          color=''\n          emoji=''\n          set='twitter'\n          title={title}\n          i18n={this.getI18n()}\n          onClick={this.handleClick}\n          include={categoriesSort}\n          recent={frequentlyUsedEmojis}\n          skin={skinTone}\n          showPreview={false}\n          backgroundImageFn={backgroundImageFn}\n          autoFocus\n          emojiTooltip\n        />\n\n        <ModifierPicker\n          active={modifierOpen}\n          modifier={skinTone}\n          onOpen={this.handleModifierOpen}\n          onClose={this.handleModifierClose}\n          onChange={this.handleModifierChange}\n        />\n      </div>\n    );\n  }\n\n}\n\nexport default @injectIntl\nclass EmojiPickerDropdown extends React.PureComponent {\n\n  static propTypes = {\n    custom_emojis: ImmutablePropTypes.list,\n    frequentlyUsedEmojis: PropTypes.arrayOf(PropTypes.string),\n    intl: PropTypes.object.isRequired,\n    onPickEmoji: PropTypes.func.isRequired,\n    onSkinTone: PropTypes.func.isRequired,\n    skinTone: PropTypes.number.isRequired,\n  };\n\n  state = {\n    active: false,\n    loading: false,\n  };\n\n  setRef = (c) => {\n    this.dropdown = c;\n  }\n\n  onShowDropdown = ({ target }) => {\n    this.setState({ active: true });\n\n    if (!EmojiPicker) {\n      this.setState({ loading: true });\n\n      EmojiPickerAsync().then(EmojiMart => {\n        EmojiPicker = EmojiMart.Picker;\n        Emoji       = EmojiMart.Emoji;\n\n        this.setState({ loading: false });\n      }).catch(() => {\n        this.setState({ loading: false });\n      });\n    }\n\n    const { top } = target.getBoundingClientRect();\n    this.setState({ placement: top * 2 < innerHeight ? 'bottom' : 'top' });\n  }\n\n  onHideDropdown = () => {\n    this.setState({ active: false });\n  }\n\n  onToggle = (e) => {\n    if (!this.state.loading && (!e.key || e.key === 'Enter')) {\n      if (this.state.active) {\n        this.onHideDropdown();\n      } else {\n        this.onShowDropdown(e);\n      }\n    }\n  }\n\n  handleKeyDown = e => {\n    if (e.key === 'Escape') {\n      this.onHideDropdown();\n    }\n  }\n\n  setTargetRef = c => {\n    this.target = c;\n  }\n\n  findTarget = () => {\n    return this.target;\n  }\n\n  render () {\n    const { intl, onPickEmoji, onSkinTone, skinTone, frequentlyUsedEmojis } = this.props;\n    const title = intl.formatMessage(messages.emoji);\n    const { active, loading, placement } = this.state;\n\n    return (\n      <div className='emoji-picker-dropdown' onKeyDown={this.handleKeyDown}>\n        <div ref={this.setTargetRef} className='emoji-button' title={title} aria-label={title} aria-expanded={active} role='button' onClick={this.onToggle} onKeyDown={this.onToggle} tabIndex={0}>\n          <img\n            className={classNames('emojione', { 'pulse-loading': active && loading })}\n            alt='🙂'\n            src={`${assetHost}/emoji/1f602.svg`}\n          />\n        </div>\n\n        <Overlay show={active} placement={placement} target={this.findTarget}>\n          <EmojiPickerMenu\n            custom_emojis={this.props.custom_emojis}\n            loading={loading}\n            onClose={this.onHideDropdown}\n            onPick={onPickEmoji}\n            onSkinTone={onSkinTone}\n            skinTone={skinTone}\n            frequentlyUsedEmojis={frequentlyUsedEmojis}\n          />\n        </Overlay>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/compose/components/navigation_bar.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport ActionBar from './action_bar';\nimport Avatar from '../../../components/avatar';\nimport Permalink from '../../../components/permalink';\nimport IconButton from '../../../components/icon_button';\nimport { FormattedMessage } from 'react-intl';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\n\nexport default class NavigationBar extends ImmutablePureComponent {\n\n  static propTypes = {\n    account: ImmutablePropTypes.map.isRequired,\n    onClose: PropTypes.func,\n  };\n\n  render () {\n    return (\n      <div className='navigation-bar'>\n        <Permalink href={this.props.account.get('url')} to={`/accounts/${this.props.account.get('id')}`}>\n          <span style={{ display: 'none' }}>{this.props.account.get('acct')}</span>\n          <Avatar account={this.props.account} size={48} />\n        </Permalink>\n\n        <div className='navigation-bar__profile'>\n          <Permalink href={this.props.account.get('url')} to={`/accounts/${this.props.account.get('id')}`}>\n            <strong className='navigation-bar__profile-account'>@{this.props.account.get('acct')}</strong>\n          </Permalink>\n\n          <a href='/settings/profile' className='navigation-bar__profile-edit'><FormattedMessage id='navigation_bar.edit_profile' defaultMessage='Edit profile' /></a>\n        </div>\n\n        <div className='navigation-bar__actions'>\n          <IconButton className='close' title='' icon='close' onClick={this.props.onClose} />\n          <ActionBar account={this.props.account} />\n        </div>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/compose/components/poll_button.js",
    "content": "import React from 'react';\nimport IconButton from '../../../components/icon_button';\nimport PropTypes from 'prop-types';\nimport { defineMessages, injectIntl } from 'react-intl';\n\nconst messages = defineMessages({\n  add_poll: { id: 'poll_button.add_poll', defaultMessage: 'Add a poll' },\n  remove_poll: { id: 'poll_button.remove_poll', defaultMessage: 'Remove poll' },\n});\n\nconst iconStyle = {\n  height: null,\n  lineHeight: '27px',\n};\n\nexport default\n@injectIntl\nclass PollButton extends React.PureComponent {\n\n  static propTypes = {\n    disabled: PropTypes.bool,\n    unavailable: PropTypes.bool,\n    active: PropTypes.bool,\n    onClick: PropTypes.func.isRequired,\n    intl: PropTypes.object.isRequired,\n  };\n\n  handleClick = () => {\n    this.props.onClick();\n  }\n\n  render () {\n    const { intl, active, unavailable, disabled } = this.props;\n\n    if (unavailable) {\n      return null;\n    }\n\n    return (\n      <div className='compose-form__poll-button'>\n        <IconButton\n          icon='tasks'\n          title={intl.formatMessage(active ? messages.remove_poll : messages.add_poll)}\n          disabled={disabled}\n          onClick={this.handleClick}\n          className={`compose-form__poll-button-icon ${active ? 'active' : ''}`}\n          size={18}\n          inverted\n          style={iconStyle}\n        />\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/compose/components/poll_form.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport { defineMessages, injectIntl, FormattedMessage } from 'react-intl';\nimport IconButton from 'mastodon/components/icon_button';\nimport Icon from 'mastodon/components/icon';\nimport AutosuggestInput from 'mastodon/components/autosuggest_input';\nimport classNames from 'classnames';\n\nconst messages = defineMessages({\n  option_placeholder: { id: 'compose_form.poll.option_placeholder', defaultMessage: 'Choice {number}' },\n  add_option: { id: 'compose_form.poll.add_option', defaultMessage: 'Add a choice' },\n  remove_option: { id: 'compose_form.poll.remove_option', defaultMessage: 'Remove this choice' },\n  poll_duration: { id: 'compose_form.poll.duration', defaultMessage: 'Poll duration' },\n  minutes: { id: 'intervals.full.minutes', defaultMessage: '{number, plural, one {# minute} other {# minutes}}' },\n  hours: { id: 'intervals.full.hours', defaultMessage: '{number, plural, one {# hour} other {# hours}}' },\n  days: { id: 'intervals.full.days', defaultMessage: '{number, plural, one {# day} other {# days}}' },\n});\n\n@injectIntl\nclass Option extends React.PureComponent {\n\n  static propTypes = {\n    title: PropTypes.string.isRequired,\n    index: PropTypes.number.isRequired,\n    isPollMultiple: PropTypes.bool,\n    onChange: PropTypes.func.isRequired,\n    onRemove: PropTypes.func.isRequired,\n    onToggleMultiple: PropTypes.func.isRequired,\n    suggestions: ImmutablePropTypes.list,\n    onClearSuggestions: PropTypes.func.isRequired,\n    onFetchSuggestions: PropTypes.func.isRequired,\n    onSuggestionSelected: PropTypes.func.isRequired,\n    intl: PropTypes.object.isRequired,\n  };\n\n  handleOptionTitleChange = e => {\n    this.props.onChange(this.props.index, e.target.value);\n  };\n\n  handleOptionRemove = () => {\n    this.props.onRemove(this.props.index);\n  };\n\n\n  handleToggleMultiple = e => {\n    this.props.onToggleMultiple();\n    e.preventDefault();\n    e.stopPropagation();\n  };\n\n  onSuggestionsClearRequested = () => {\n    this.props.onClearSuggestions();\n  }\n\n  onSuggestionsFetchRequested = (token) => {\n    this.props.onFetchSuggestions(token);\n  }\n\n  onSuggestionSelected = (tokenStart, token, value) => {\n    this.props.onSuggestionSelected(tokenStart, token, value, ['poll', 'options', this.props.index]);\n  }\n\n  render () {\n    const { isPollMultiple, title, index, intl } = this.props;\n\n    return (\n      <li>\n        <label className='poll__text editable'>\n          <span\n            className={classNames('poll__input', { checkbox: isPollMultiple })}\n            onClick={this.handleToggleMultiple}\n            role='button'\n            tabIndex='0'\n          />\n\n          <AutosuggestInput\n            placeholder={intl.formatMessage(messages.option_placeholder, { number: index + 1 })}\n            maxLength={25}\n            value={title}\n            onChange={this.handleOptionTitleChange}\n            suggestions={this.props.suggestions}\n            onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}\n            onSuggestionsClearRequested={this.onSuggestionsClearRequested}\n            onSuggestionSelected={this.onSuggestionSelected}\n            searchTokens={[':']}\n          />\n        </label>\n\n        <div className='poll__cancel'>\n          <IconButton disabled={index <= 1} title={intl.formatMessage(messages.remove_option)} icon='times' onClick={this.handleOptionRemove} />\n        </div>\n      </li>\n    );\n  }\n\n}\n\nexport default\n@injectIntl\nclass PollForm extends ImmutablePureComponent {\n\n  static propTypes = {\n    options: ImmutablePropTypes.list,\n    expiresIn: PropTypes.number,\n    isMultiple: PropTypes.bool,\n    onChangeOption: PropTypes.func.isRequired,\n    onAddOption: PropTypes.func.isRequired,\n    onRemoveOption: PropTypes.func.isRequired,\n    onChangeSettings: PropTypes.func.isRequired,\n    suggestions: ImmutablePropTypes.list,\n    onClearSuggestions: PropTypes.func.isRequired,\n    onFetchSuggestions: PropTypes.func.isRequired,\n    onSuggestionSelected: PropTypes.func.isRequired,\n    intl: PropTypes.object.isRequired,\n  };\n\n  handleAddOption = () => {\n    this.props.onAddOption('');\n  };\n\n  handleSelectDuration = e => {\n    this.props.onChangeSettings(e.target.value, this.props.isMultiple);\n  };\n\n  handleToggleMultiple = () => {\n    this.props.onChangeSettings(this.props.expiresIn, !this.props.isMultiple);\n  };\n\n  render () {\n    const { options, expiresIn, isMultiple, onChangeOption, onRemoveOption, intl, ...other } = this.props;\n\n    if (!options) {\n      return null;\n    }\n\n    return (\n      <div className='compose-form__poll-wrapper'>\n        <ul>\n          {options.map((title, i) => <Option title={title} key={i} index={i} onChange={onChangeOption} onRemove={onRemoveOption} isPollMultiple={isMultiple} onToggleMultiple={this.handleToggleMultiple} {...other} />)}\n        </ul>\n\n        <div className='poll__footer'>\n          {options.size < 4 && (\n            <button className='button button-secondary' onClick={this.handleAddOption}><Icon id='plus' /> <FormattedMessage {...messages.add_option} /></button>\n          )}\n\n          <select value={expiresIn} onChange={this.handleSelectDuration}>\n            <option value={300}>{intl.formatMessage(messages.minutes, { number: 5 })}</option>\n            <option value={1800}>{intl.formatMessage(messages.minutes, { number: 30 })}</option>\n            <option value={3600}>{intl.formatMessage(messages.hours, { number: 1 })}</option>\n            <option value={21600}>{intl.formatMessage(messages.hours, { number: 6 })}</option>\n            <option value={86400}>{intl.formatMessage(messages.days, { number: 1 })}</option>\n            <option value={259200}>{intl.formatMessage(messages.days, { number: 3 })}</option>\n            <option value={604800}>{intl.formatMessage(messages.days, { number: 7 })}</option>\n          </select>\n        </div>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/compose/components/privacy_dropdown.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport { injectIntl, defineMessages } from 'react-intl';\nimport IconButton from '../../../components/icon_button';\nimport Overlay from 'react-overlays/lib/Overlay';\nimport Motion from '../../ui/util/optional_motion';\nimport spring from 'react-motion/lib/spring';\nimport detectPassiveEvents from 'detect-passive-events';\nimport classNames from 'classnames';\nimport Icon from 'mastodon/components/icon';\n\nconst messages = defineMessages({\n  public_short: { id: 'privacy.public.short', defaultMessage: 'Public' },\n  public_long: { id: 'privacy.public.long', defaultMessage: 'Post to public timelines' },\n  unlisted_short: { id: 'privacy.unlisted.short', defaultMessage: 'Unlisted' },\n  unlisted_long: { id: 'privacy.unlisted.long', defaultMessage: 'Do not show in public timelines' },\n  private_short: { id: 'privacy.private.short', defaultMessage: 'Followers-only' },\n  private_long: { id: 'privacy.private.long', defaultMessage: 'Post to followers only' },\n  direct_short: { id: 'privacy.direct.short', defaultMessage: 'Direct' },\n  direct_long: { id: 'privacy.direct.long', defaultMessage: 'Post to mentioned users only' },\n  change_privacy: { id: 'privacy.change', defaultMessage: 'Adjust status privacy' },\n});\n\nconst listenerOptions = detectPassiveEvents.hasSupport ? { passive: true } : false;\n\nclass PrivacyDropdownMenu extends React.PureComponent {\n\n  static propTypes = {\n    style: PropTypes.object,\n    items: PropTypes.array.isRequired,\n    value: PropTypes.string.isRequired,\n    placement: PropTypes.string.isRequired,\n    onClose: PropTypes.func.isRequired,\n    onChange: PropTypes.func.isRequired,\n  };\n\n  state = {\n    mounted: false,\n  };\n\n  handleDocumentClick = e => {\n    if (this.node && !this.node.contains(e.target)) {\n      this.props.onClose();\n    }\n  }\n\n  handleKeyDown = e => {\n    const { items } = this.props;\n    const value = e.currentTarget.getAttribute('data-index');\n    const index = items.findIndex(item => {\n      return (item.value === value);\n    });\n    let element;\n\n    switch(e.key) {\n    case 'Escape':\n      this.props.onClose();\n      break;\n    case 'Enter':\n      this.handleClick(e);\n      break;\n    case 'ArrowDown':\n      element = this.node.childNodes[index + 1];\n      if (element) {\n        element.focus();\n        this.props.onChange(element.getAttribute('data-index'));\n      }\n      break;\n    case 'ArrowUp':\n      element = this.node.childNodes[index - 1];\n      if (element) {\n        element.focus();\n        this.props.onChange(element.getAttribute('data-index'));\n      }\n      break;\n    case 'Home':\n      element = this.node.firstChild;\n      if (element) {\n        element.focus();\n        this.props.onChange(element.getAttribute('data-index'));\n      }\n      break;\n    case 'End':\n      element = this.node.lastChild;\n      if (element) {\n        element.focus();\n        this.props.onChange(element.getAttribute('data-index'));\n      }\n      break;\n    }\n  }\n\n  handleClick = e => {\n    const value = e.currentTarget.getAttribute('data-index');\n\n    e.preventDefault();\n\n    this.props.onClose();\n    this.props.onChange(value);\n  }\n\n  componentDidMount () {\n    document.addEventListener('click', this.handleDocumentClick, false);\n    document.addEventListener('touchend', this.handleDocumentClick, listenerOptions);\n    if (this.focusedItem) this.focusedItem.focus();\n    this.setState({ mounted: true });\n  }\n\n  componentWillUnmount () {\n    document.removeEventListener('click', this.handleDocumentClick, false);\n    document.removeEventListener('touchend', this.handleDocumentClick, listenerOptions);\n  }\n\n  setRef = c => {\n    this.node = c;\n  }\n\n  setFocusRef = c => {\n    this.focusedItem = c;\n  }\n\n  render () {\n    const { mounted } = this.state;\n    const { style, items, placement, value } = this.props;\n\n    return (\n      <Motion defaultStyle={{ opacity: 0, scaleX: 0.85, scaleY: 0.75 }} style={{ opacity: spring(1, { damping: 35, stiffness: 400 }), scaleX: spring(1, { damping: 35, stiffness: 400 }), scaleY: spring(1, { damping: 35, stiffness: 400 }) }}>\n        {({ opacity, scaleX, scaleY }) => (\n          // It should not be transformed when mounting because the resulting\n          // size will be used to determine the coordinate of the menu by\n          // react-overlays\n          <div className={`privacy-dropdown__dropdown ${placement}`} style={{ ...style, opacity: opacity, transform: mounted ? `scale(${scaleX}, ${scaleY})` : null, zIndex: 2 }} role='listbox' ref={this.setRef}>\n            {items.map(item => (\n              <div role='option' tabIndex='0' key={item.value} data-index={item.value} onKeyDown={this.handleKeyDown} onClick={this.handleClick} className={classNames('privacy-dropdown__option', { active: item.value === value })} aria-selected={item.value === value} ref={item.value === value ? this.setFocusRef : null}>\n                <div className='privacy-dropdown__option__icon'>\n                  <Icon id={item.icon} fixedWidth />\n                </div>\n\n                <div className='privacy-dropdown__option__content'>\n                  <strong>{item.text}</strong>\n                  {item.meta}\n                </div>\n              </div>\n            ))}\n          </div>\n        )}\n      </Motion>\n    );\n  }\n\n}\n\nexport default @injectIntl\nclass PrivacyDropdown extends React.PureComponent {\n\n  static propTypes = {\n    isUserTouching: PropTypes.func,\n    isModalOpen: PropTypes.bool.isRequired,\n    onModalOpen: PropTypes.func,\n    onModalClose: PropTypes.func,\n    value: PropTypes.string.isRequired,\n    onChange: PropTypes.func.isRequired,\n    intl: PropTypes.object.isRequired,\n  };\n\n  state = {\n    open: false,\n    placement: 'bottom',\n  };\n\n  handleToggle = ({ target }) => {\n    if (this.props.isUserTouching()) {\n      if (this.state.open) {\n        this.props.onModalClose();\n      } else {\n        this.props.onModalOpen({\n          actions: this.options.map(option => ({ ...option, active: option.value === this.props.value })),\n          onClick: this.handleModalActionClick,\n        });\n      }\n    } else {\n      const { top } = target.getBoundingClientRect();\n      this.setState({ placement: top * 2 < innerHeight ? 'bottom' : 'top' });\n      this.setState({ open: !this.state.open });\n    }\n  }\n\n  handleModalActionClick = (e) => {\n    e.preventDefault();\n\n    const { value } = this.options[e.currentTarget.getAttribute('data-index')];\n\n    this.props.onModalClose();\n    this.props.onChange(value);\n  }\n\n  handleKeyDown = e => {\n    switch(e.key) {\n    case 'Escape':\n      this.handleClose();\n      break;\n    }\n  }\n\n  handleClose = () => {\n    this.setState({ open: false });\n  }\n\n  handleChange = value => {\n    this.props.onChange(value);\n  }\n\n  componentWillMount () {\n    const { intl: { formatMessage } } = this.props;\n\n    this.options = [\n      { icon: 'globe', value: 'public', text: formatMessage(messages.public_short), meta: formatMessage(messages.public_long) },\n      { icon: 'unlock', value: 'unlisted', text: formatMessage(messages.unlisted_short), meta: formatMessage(messages.unlisted_long) },\n      { icon: 'lock', value: 'private', text: formatMessage(messages.private_short), meta: formatMessage(messages.private_long) },\n      { icon: 'envelope', value: 'direct', text: formatMessage(messages.direct_short), meta: formatMessage(messages.direct_long) },\n    ];\n  }\n\n  render () {\n    const { value, intl } = this.props;\n    const { open, placement } = this.state;\n\n    const valueOption = this.options.find(item => item.value === value);\n\n    return (\n      <div className={classNames('privacy-dropdown', placement, { active: open })} onKeyDown={this.handleKeyDown}>\n        <div className={classNames('privacy-dropdown__value', { active: this.options.indexOf(valueOption) === 0 })}>\n          <IconButton\n            className='privacy-dropdown__value-icon'\n            icon={valueOption.icon}\n            title={intl.formatMessage(messages.change_privacy)}\n            size={18}\n            expanded={open}\n            active={open}\n            inverted\n            onClick={this.handleToggle}\n            style={{ height: null, lineHeight: '27px' }}\n          />\n        </div>\n\n        <Overlay show={open} placement={placement} target={this}>\n          <PrivacyDropdownMenu\n            items={this.options}\n            value={value}\n            onClose={this.handleClose}\n            onChange={this.handleChange}\n            placement={placement}\n          />\n        </Overlay>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/compose/components/reply_indicator.js",
    "content": "import React from 'react';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport PropTypes from 'prop-types';\nimport Avatar from '../../../components/avatar';\nimport IconButton from '../../../components/icon_button';\nimport DisplayName from '../../../components/display_name';\nimport { defineMessages, injectIntl } from 'react-intl';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport { isRtl } from '../../../rtl';\nimport AttachmentList from 'mastodon/components/attachment_list';\n\nconst messages = defineMessages({\n  cancel: { id: 'reply_indicator.cancel', defaultMessage: 'Cancel' },\n});\n\nexport default @injectIntl\nclass ReplyIndicator extends ImmutablePureComponent {\n\n  static contextTypes = {\n    router: PropTypes.object,\n  };\n\n  static propTypes = {\n    status: ImmutablePropTypes.map,\n    onCancel: PropTypes.func.isRequired,\n    intl: PropTypes.object.isRequired,\n  };\n\n  handleClick = () => {\n    this.props.onCancel();\n  }\n\n  handleAccountClick = (e) => {\n    if (e.button === 0 && !(e.ctrlKey || e.metaKey)) {\n      e.preventDefault();\n      this.context.router.history.push(`/accounts/${this.props.status.getIn(['account', 'id'])}`);\n    }\n  }\n\n  render () {\n    const { status, intl } = this.props;\n\n    if (!status) {\n      return null;\n    }\n\n    const content = { __html: status.get('contentHtml') };\n    const style   = {\n      direction: isRtl(status.get('search_index')) ? 'rtl' : 'ltr',\n    };\n\n    return (\n      <div className='reply-indicator'>\n        <div className='reply-indicator__header'>\n          <div className='reply-indicator__cancel'><IconButton title={intl.formatMessage(messages.cancel)} icon='times' onClick={this.handleClick} inverted /></div>\n\n          <a href={status.getIn(['account', 'url'])} onClick={this.handleAccountClick} className='reply-indicator__display-name'>\n            <div className='reply-indicator__display-avatar'><Avatar account={status.get('account')} size={24} /></div>\n            <DisplayName account={status.get('account')} />\n          </a>\n        </div>\n\n        <div className='reply-indicator__content' style={style} dangerouslySetInnerHTML={content} />\n\n        {status.get('media_attachments').size > 0 && (\n          <AttachmentList\n            compact\n            media={status.get('media_attachments')}\n          />\n        )}\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/compose/components/search.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport { defineMessages, injectIntl, FormattedMessage } from 'react-intl';\nimport Overlay from 'react-overlays/lib/Overlay';\nimport Motion from '../../ui/util/optional_motion';\nimport spring from 'react-motion/lib/spring';\nimport { searchEnabled } from '../../../initial_state';\nimport Icon from 'mastodon/components/icon';\n\nconst messages = defineMessages({\n  placeholder: { id: 'search.placeholder', defaultMessage: 'Search' },\n});\n\nclass SearchPopout extends React.PureComponent {\n\n  static propTypes = {\n    style: PropTypes.object,\n  };\n\n  render () {\n    const { style } = this.props;\n    const extraInformation = searchEnabled ? <FormattedMessage id='search_popout.tips.full_text' defaultMessage='Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.' /> : <FormattedMessage id='search_popout.tips.text' defaultMessage='Simple text returns matching display names, usernames and hashtags' />;\n    return (\n      <div style={{ ...style, position: 'absolute', width: 285, zIndex: 2 }}>\n        <Motion defaultStyle={{ opacity: 0, scaleX: 0.85, scaleY: 0.75 }} style={{ opacity: spring(1, { damping: 35, stiffness: 400 }), scaleX: spring(1, { damping: 35, stiffness: 400 }), scaleY: spring(1, { damping: 35, stiffness: 400 }) }}>\n          {({ opacity, scaleX, scaleY }) => (\n            <div className='search-popout' style={{ opacity: opacity, transform: `scale(${scaleX}, ${scaleY})` }}>\n              <h4><FormattedMessage id='search_popout.search_format' defaultMessage='Advanced search format' /></h4>\n\n              <ul>\n                <li><em>#example</em> <FormattedMessage id='search_popout.tips.hashtag' defaultMessage='hashtag' /></li>\n                <li><em>@username@domain</em> <FormattedMessage id='search_popout.tips.user' defaultMessage='user' /></li>\n                <li><em>URL</em> <FormattedMessage id='search_popout.tips.user' defaultMessage='user' /></li>\n                <li><em>URL</em> <FormattedMessage id='search_popout.tips.status' defaultMessage='status' /></li>\n              </ul>\n\n              {extraInformation}\n            </div>\n          )}\n        </Motion>\n      </div>\n    );\n  }\n\n}\n\nexport default @injectIntl\nclass Search extends React.PureComponent {\n\n  static contextTypes = {\n    router: PropTypes.object.isRequired,\n  };\n\n  static propTypes = {\n    value: PropTypes.string.isRequired,\n    submitted: PropTypes.bool,\n    onChange: PropTypes.func.isRequired,\n    onSubmit: PropTypes.func.isRequired,\n    onClear: PropTypes.func.isRequired,\n    onShow: PropTypes.func.isRequired,\n    openInRoute: PropTypes.bool,\n    intl: PropTypes.object.isRequired,\n  };\n\n  state = {\n    expanded: false,\n  };\n\n  handleChange = (e) => {\n    this.props.onChange(e.target.value);\n  }\n\n  handleClear = (e) => {\n    e.preventDefault();\n\n    if (this.props.value.length > 0 || this.props.submitted) {\n      this.props.onClear();\n    }\n  }\n\n  handleKeyUp = (e) => {\n    if (e.key === 'Enter') {\n      e.preventDefault();\n\n      this.props.onSubmit();\n\n      if (this.props.openInRoute) {\n        this.context.router.history.push('/search');\n      }\n    } else if (e.key === 'Escape') {\n      document.querySelector('.ui').parentElement.focus();\n    }\n  }\n\n  handleFocus = () => {\n    this.setState({ expanded: true });\n    this.props.onShow();\n  }\n\n  handleBlur = () => {\n    this.setState({ expanded: false });\n  }\n\n  render () {\n    const { intl, value, submitted } = this.props;\n    const { expanded } = this.state;\n    const hasValue = value.length > 0 || submitted;\n\n    return (\n      <div className='search'>\n        <label>\n          <span style={{ display: 'none' }}>{intl.formatMessage(messages.placeholder)}</span>\n          <input\n            className='search__input'\n            type='text'\n            placeholder={intl.formatMessage(messages.placeholder)}\n            value={value}\n            onChange={this.handleChange}\n            onKeyUp={this.handleKeyUp}\n            onFocus={this.handleFocus}\n            onBlur={this.handleBlur}\n          />\n        </label>\n\n        <div role='button' tabIndex='0' className='search__icon' onClick={this.handleClear}>\n          <Icon id='search' className={hasValue ? '' : 'active'} />\n          <Icon id='times-circle' className={hasValue ? 'active' : ''} aria-label={intl.formatMessage(messages.placeholder)} />\n        </div>\n\n        <Overlay show={expanded && !hasValue} placement='bottom' target={this}>\n          <SearchPopout />\n        </Overlay>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/compose/components/search_results.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport { FormattedMessage, defineMessages, injectIntl } from 'react-intl';\nimport AccountContainer from '../../../containers/account_container';\nimport StatusContainer from '../../../containers/status_container';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport Hashtag from '../../../components/hashtag';\nimport Icon from 'mastodon/components/icon';\n\nconst messages = defineMessages({\n  dismissSuggestion: { id: 'suggestions.dismiss', defaultMessage: 'Dismiss suggestion' },\n});\n\nexport default @injectIntl\nclass SearchResults extends ImmutablePureComponent {\n\n  static propTypes = {\n    results: ImmutablePropTypes.map.isRequired,\n    suggestions: ImmutablePropTypes.list.isRequired,\n    fetchSuggestions: PropTypes.func.isRequired,\n    dismissSuggestion: PropTypes.func.isRequired,\n    intl: PropTypes.object.isRequired,\n  };\n\n  componentDidMount () {\n    this.props.fetchSuggestions();\n  }\n\n  render () {\n    const { intl, results, suggestions, dismissSuggestion } = this.props;\n\n    if (results.isEmpty() && !suggestions.isEmpty()) {\n      return (\n        <div className='search-results'>\n          <div className='trends'>\n            <div className='trends__header'>\n              <Icon id='user-plus' fixedWidth />\n              <FormattedMessage id='suggestions.header' defaultMessage='You might be interested in…' />\n            </div>\n\n            {suggestions && suggestions.map(accountId => (\n              <AccountContainer\n                key={accountId}\n                id={accountId}\n                actionIcon='times'\n                actionTitle={intl.formatMessage(messages.dismissSuggestion)}\n                onActionClick={dismissSuggestion}\n              />\n            ))}\n          </div>\n        </div>\n      );\n    }\n\n    let accounts, statuses, hashtags;\n    let count = 0;\n\n    if (results.get('accounts') && results.get('accounts').size > 0) {\n      count   += results.get('accounts').size;\n      accounts = (\n        <div className='search-results__section'>\n          <h5><Icon id='users' fixedWidth /><FormattedMessage id='search_results.accounts' defaultMessage='People' /></h5>\n\n          {results.get('accounts').map(accountId => <AccountContainer key={accountId} id={accountId} />)}\n        </div>\n      );\n    }\n\n    if (results.get('statuses') && results.get('statuses').size > 0) {\n      count   += results.get('statuses').size;\n      statuses = (\n        <div className='search-results__section'>\n          <h5><Icon id='quote-right' fixedWidth /><FormattedMessage id='search_results.statuses' defaultMessage='Toots' /></h5>\n\n          {results.get('statuses').map(statusId => <StatusContainer key={statusId} id={statusId} />)}\n        </div>\n      );\n    }\n\n    if (results.get('hashtags') && results.get('hashtags').size > 0) {\n      count += results.get('hashtags').size;\n      hashtags = (\n        <div className='search-results__section'>\n          <h5><Icon id='hashtag' fixedWidth /><FormattedMessage id='search_results.hashtags' defaultMessage='Hashtags' /></h5>\n\n          {results.get('hashtags').map(hashtag => <Hashtag key={hashtag.get('name')} hashtag={hashtag} />)}\n        </div>\n      );\n    }\n\n    return (\n      <div className='search-results'>\n        <div className='search-results__header'>\n          <Icon id='search' fixedWidth />\n          <FormattedMessage id='search_results.total' defaultMessage='{count, number} {count, plural, one {result} other {results}}' values={{ count }} />\n        </div>\n\n        {accounts}\n        {statuses}\n        {hashtags}\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/compose/components/text_icon_button.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\n\nexport default class TextIconButton extends React.PureComponent {\n\n  static propTypes = {\n    label: PropTypes.string.isRequired,\n    title: PropTypes.string,\n    active: PropTypes.bool,\n    onClick: PropTypes.func.isRequired,\n    ariaControls: PropTypes.string,\n  };\n\n  handleClick = (e) => {\n    e.preventDefault();\n    this.props.onClick();\n  }\n\n  render () {\n    const { label, title, active, ariaControls } = this.props;\n\n    return (\n      <button title={title} aria-label={title} className={`text-icon-button ${active ? 'active' : ''}`} aria-expanded={active} onClick={this.handleClick} aria-controls={ariaControls}>\n        {label}\n      </button>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/compose/components/upload.js",
    "content": "import React from 'react';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport PropTypes from 'prop-types';\nimport Motion from '../../ui/util/optional_motion';\nimport spring from 'react-motion/lib/spring';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport { defineMessages, injectIntl, FormattedMessage } from 'react-intl';\nimport classNames from 'classnames';\nimport Icon from 'mastodon/components/icon';\n\nconst messages = defineMessages({\n  description: { id: 'upload_form.description', defaultMessage: 'Describe for the visually impaired' },\n});\n\nexport default @injectIntl\nclass Upload extends ImmutablePureComponent {\n\n  static contextTypes = {\n    router: PropTypes.object,\n  };\n\n  static propTypes = {\n    media: ImmutablePropTypes.map.isRequired,\n    intl: PropTypes.object.isRequired,\n    onUndo: PropTypes.func.isRequired,\n    onDescriptionChange: PropTypes.func.isRequired,\n    onOpenFocalPoint: PropTypes.func.isRequired,\n    onSubmit: PropTypes.func.isRequired,\n  };\n\n  state = {\n    hovered: false,\n    focused: false,\n    dirtyDescription: null,\n  };\n\n  handleKeyDown = (e) => {\n    if (e.keyCode === 13 && (e.ctrlKey || e.metaKey)) {\n      this.handleSubmit();\n    }\n  }\n\n  handleSubmit = () => {\n    this.handleInputBlur();\n    this.props.onSubmit(this.context.router.history);\n  }\n\n  handleUndoClick = e => {\n    e.stopPropagation();\n    this.props.onUndo(this.props.media.get('id'));\n  }\n\n  handleFocalPointClick = e => {\n    e.stopPropagation();\n    this.props.onOpenFocalPoint(this.props.media.get('id'));\n  }\n\n  handleInputChange = e => {\n    this.setState({ dirtyDescription: e.target.value });\n  }\n\n  handleMouseEnter = () => {\n    this.setState({ hovered: true });\n  }\n\n  handleMouseLeave = () => {\n    this.setState({ hovered: false });\n  }\n\n  handleInputFocus = () => {\n    this.setState({ focused: true });\n  }\n\n  handleClick = () => {\n    this.setState({ focused: true });\n  }\n\n  handleInputBlur = () => {\n    const { dirtyDescription } = this.state;\n\n    this.setState({ focused: false, dirtyDescription: null });\n\n    if (dirtyDescription !== null) {\n      this.props.onDescriptionChange(this.props.media.get('id'), dirtyDescription);\n    }\n  }\n\n  render () {\n    const { intl, media } = this.props;\n    const active          = this.state.hovered || this.state.focused;\n    const description     = this.state.dirtyDescription || (this.state.dirtyDescription !== '' && media.get('description')) || '';\n    const focusX = media.getIn(['meta', 'focus', 'x']);\n    const focusY = media.getIn(['meta', 'focus', 'y']);\n    const x = ((focusX /  2) + .5) * 100;\n    const y = ((focusY / -2) + .5) * 100;\n\n    return (\n      <div className='compose-form__upload' tabIndex='0' onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave} onClick={this.handleClick} role='button'>\n        <Motion defaultStyle={{ scale: 0.8 }} style={{ scale: spring(1, { stiffness: 180, damping: 12 }) }}>\n          {({ scale }) => (\n            <div className='compose-form__upload-thumbnail' style={{ transform: `scale(${scale})`, backgroundImage: `url(${media.get('preview_url')})`, backgroundPosition: `${x}% ${y}%` }}>\n              <div className={classNames('compose-form__upload__actions', { active })}>\n                <button className='icon-button' onClick={this.handleUndoClick}><Icon id='times' /> <FormattedMessage id='upload_form.undo' defaultMessage='Delete' /></button>\n                {media.get('type') === 'image' && <button className='icon-button' onClick={this.handleFocalPointClick}><Icon id='crosshairs' /> <FormattedMessage id='upload_form.focus' defaultMessage='Crop' /></button>}\n              </div>\n\n              <div className={classNames('compose-form__upload-description', { active })}>\n                <label>\n                  <span style={{ display: 'none' }}>{intl.formatMessage(messages.description)}</span>\n\n                  <textarea\n                    placeholder={intl.formatMessage(messages.description)}\n                    value={description}\n                    maxLength={420}\n                    onFocus={this.handleInputFocus}\n                    onChange={this.handleInputChange}\n                    onBlur={this.handleInputBlur}\n                    onKeyDown={this.handleKeyDown}\n                  />\n                </label>\n              </div>\n            </div>\n          )}\n        </Motion>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/compose/components/upload_button.js",
    "content": "import React from 'react';\nimport IconButton from '../../../components/icon_button';\nimport PropTypes from 'prop-types';\nimport { defineMessages, injectIntl } from 'react-intl';\nimport { connect } from 'react-redux';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\n\nconst messages = defineMessages({\n  upload: { id: 'upload_button.label', defaultMessage: 'Add media (JPEG, PNG, GIF, WebM, MP4, MOV)' },\n});\n\nconst makeMapStateToProps = () => {\n  const mapStateToProps = state => ({\n    acceptContentTypes: state.getIn(['media_attachments', 'accept_content_types']),\n  });\n\n  return mapStateToProps;\n};\n\nconst iconStyle = {\n  height: null,\n  lineHeight: '27px',\n};\n\nexport default @connect(makeMapStateToProps)\n@injectIntl\nclass UploadButton extends ImmutablePureComponent {\n\n  static propTypes = {\n    disabled: PropTypes.bool,\n    unavailable: PropTypes.bool,\n    onSelectFile: PropTypes.func.isRequired,\n    style: PropTypes.object,\n    resetFileKey: PropTypes.number,\n    acceptContentTypes: ImmutablePropTypes.listOf(PropTypes.string).isRequired,\n    intl: PropTypes.object.isRequired,\n  };\n\n  handleChange = (e) => {\n    if (e.target.files.length > 0) {\n      this.props.onSelectFile(e.target.files);\n    }\n  }\n\n  handleClick = () => {\n    this.fileElement.click();\n  }\n\n  setRef = (c) => {\n    this.fileElement = c;\n  }\n\n  render () {\n    const { intl, resetFileKey, unavailable, disabled, acceptContentTypes } = this.props;\n\n    if (unavailable) {\n      return null;\n    }\n\n    return (\n      <div className='compose-form__upload-button'>\n        <IconButton icon='camera' title={intl.formatMessage(messages.upload)} disabled={disabled} onClick={this.handleClick} className='compose-form__upload-button-icon' size={18} inverted style={iconStyle} />\n        <label>\n          <span style={{ display: 'none' }}>{intl.formatMessage(messages.upload)}</span>\n          <input\n            key={resetFileKey}\n            ref={this.setRef}\n            type='file'\n            multiple\n            accept={acceptContentTypes.toArray().join(',')}\n            onChange={this.handleChange}\n            disabled={disabled}\n            style={{ display: 'none' }}\n          />\n        </label>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/compose/components/upload_form.js",
    "content": "import React from 'react';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport UploadProgressContainer from '../containers/upload_progress_container';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport UploadContainer from '../containers/upload_container';\nimport SensitiveButtonContainer from '../containers/sensitive_button_container';\n\nexport default class UploadForm extends ImmutablePureComponent {\n\n  static propTypes = {\n    mediaIds: ImmutablePropTypes.list.isRequired,\n  };\n\n  render () {\n    const { mediaIds } = this.props;\n\n    return (\n      <div className='compose-form__upload-wrapper'>\n        <UploadProgressContainer />\n\n        <div className='compose-form__uploads-wrapper'>\n          {mediaIds.map(id => (\n            <UploadContainer id={id} key={id} />\n          ))}\n        </div>\n\n        {!mediaIds.isEmpty() && <SensitiveButtonContainer />}\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/compose/components/upload_progress.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport Motion from '../../ui/util/optional_motion';\nimport spring from 'react-motion/lib/spring';\nimport { FormattedMessage } from 'react-intl';\nimport Icon from 'mastodon/components/icon';\n\nexport default class UploadProgress extends React.PureComponent {\n\n  static propTypes = {\n    active: PropTypes.bool,\n    progress: PropTypes.number,\n  };\n\n  render () {\n    const { active, progress } = this.props;\n\n    if (!active) {\n      return null;\n    }\n\n    return (\n      <div className='upload-progress'>\n        <div className='upload-progress__icon'>\n          <Icon id='upload' />\n        </div>\n\n        <div className='upload-progress__message'>\n          <FormattedMessage id='upload_progress.label' defaultMessage='Uploading...' />\n\n          <div className='upload-progress__backdrop'>\n            <Motion defaultStyle={{ width: 0 }} style={{ width: spring(progress) }}>\n              {({ width }) =>\n                <div className='upload-progress__tracker' style={{ width: `${width}%` }} />\n              }\n            </Motion>\n          </div>\n        </div>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/compose/components/warning.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport Motion from '../../ui/util/optional_motion';\nimport spring from 'react-motion/lib/spring';\n\nexport default class Warning extends React.PureComponent {\n\n  static propTypes = {\n    message: PropTypes.node.isRequired,\n  };\n\n  render () {\n    const { message } = this.props;\n\n    return (\n      <Motion defaultStyle={{ opacity: 0, scaleX: 0.85, scaleY: 0.75 }} style={{ opacity: spring(1, { damping: 35, stiffness: 400 }), scaleX: spring(1, { damping: 35, stiffness: 400 }), scaleY: spring(1, { damping: 35, stiffness: 400 }) }}>\n        {({ opacity, scaleX, scaleY }) => (\n          <div className='compose-form__warning' style={{ opacity: opacity, transform: `scale(${scaleX}, ${scaleY})` }}>\n            {message}\n          </div>\n        )}\n      </Motion>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/compose/containers/autosuggest_account_container.js",
    "content": "import { connect } from 'react-redux';\nimport AutosuggestAccount from '../components/autosuggest_account';\nimport { makeGetAccount } from '../../../selectors';\n\nconst makeMapStateToProps = () => {\n  const getAccount = makeGetAccount();\n\n  const mapStateToProps = (state, { id }) => ({\n    account: getAccount(state, id),\n  });\n\n  return mapStateToProps;\n};\n\nexport default connect(makeMapStateToProps)(AutosuggestAccount);\n"
  },
  {
    "path": "app/javascript/mastodon/features/compose/containers/compose_form_container.js",
    "content": "import { connect } from 'react-redux';\nimport ComposeForm from '../components/compose_form';\nimport {\n  changeCompose,\n  submitCompose,\n  clearComposeSuggestions,\n  fetchComposeSuggestions,\n  selectComposeSuggestion,\n  changeComposeSpoilerText,\n  insertEmojiCompose,\n  uploadCompose,\n} from '../../../actions/compose';\n\nconst mapStateToProps = state => ({\n  text: state.getIn(['compose', 'text']),\n  suggestions: state.getIn(['compose', 'suggestions']),\n  spoiler: state.getIn(['compose', 'spoiler']),\n  spoilerText: state.getIn(['compose', 'spoiler_text']),\n  privacy: state.getIn(['compose', 'privacy']),\n  focusDate: state.getIn(['compose', 'focusDate']),\n  caretPosition: state.getIn(['compose', 'caretPosition']),\n  preselectDate: state.getIn(['compose', 'preselectDate']),\n  isSubmitting: state.getIn(['compose', 'is_submitting']),\n  isChangingUpload: state.getIn(['compose', 'is_changing_upload']),\n  isUploading: state.getIn(['compose', 'is_uploading']),\n  showSearch: state.getIn(['search', 'submitted']) && !state.getIn(['search', 'hidden']),\n  anyMedia: state.getIn(['compose', 'media_attachments']).size > 0,\n});\n\nconst mapDispatchToProps = (dispatch) => ({\n\n  onChange (text) {\n    dispatch(changeCompose(text));\n  },\n\n  onSubmit (router) {\n    dispatch(submitCompose(router));\n  },\n\n  onClearSuggestions () {\n    dispatch(clearComposeSuggestions());\n  },\n\n  onFetchSuggestions (token) {\n    dispatch(fetchComposeSuggestions(token));\n  },\n\n  onSuggestionSelected (position, token, suggestion, path) {\n    dispatch(selectComposeSuggestion(position, token, suggestion, path));\n  },\n\n  onChangeSpoilerText (checked) {\n    dispatch(changeComposeSpoilerText(checked));\n  },\n\n  onPaste (files) {\n    dispatch(uploadCompose(files));\n  },\n\n  onPickEmoji (position, data, needsSpace) {\n    dispatch(insertEmojiCompose(position, data, needsSpace));\n  },\n\n});\n\nexport default connect(mapStateToProps, mapDispatchToProps)(ComposeForm);\n"
  },
  {
    "path": "app/javascript/mastodon/features/compose/containers/emoji_picker_dropdown_container.js",
    "content": "import { connect } from 'react-redux';\nimport EmojiPickerDropdown from '../components/emoji_picker_dropdown';\nimport { changeSetting } from '../../../actions/settings';\nimport { createSelector } from 'reselect';\nimport { Map as ImmutableMap } from 'immutable';\nimport { useEmoji } from '../../../actions/emojis';\n\nconst perLine = 8;\nconst lines   = 2;\n\nconst DEFAULTS = [\n  '+1',\n  'grinning',\n  'kissing_heart',\n  'heart_eyes',\n  'laughing',\n  'stuck_out_tongue_winking_eye',\n  'sweat_smile',\n  'joy',\n  'yum',\n  'disappointed',\n  'thinking_face',\n  'weary',\n  'sob',\n  'sunglasses',\n  'heart',\n  'ok_hand',\n];\n\nconst getFrequentlyUsedEmojis = createSelector([\n  state => state.getIn(['settings', 'frequentlyUsedEmojis'], ImmutableMap()),\n], emojiCounters => {\n  let emojis = emojiCounters\n    .keySeq()\n    .sort((a, b) => emojiCounters.get(a) - emojiCounters.get(b))\n    .reverse()\n    .slice(0, perLine * lines)\n    .toArray();\n\n  if (emojis.length < DEFAULTS.length) {\n    let uniqueDefaults = DEFAULTS.filter(emoji => !emojis.includes(emoji));\n    emojis = emojis.concat(uniqueDefaults.slice(0, DEFAULTS.length - emojis.length));\n  }\n\n  return emojis;\n});\n\nconst getCustomEmojis = createSelector([\n  state => state.get('custom_emojis'),\n], emojis => emojis.filter(e => e.get('visible_in_picker')).sort((a, b) => {\n  const aShort = a.get('shortcode').toLowerCase();\n  const bShort = b.get('shortcode').toLowerCase();\n\n  if (aShort < bShort) {\n    return -1;\n  } else if (aShort > bShort ) {\n    return 1;\n  } else {\n    return 0;\n  }\n}));\n\nconst mapStateToProps = state => ({\n  custom_emojis: getCustomEmojis(state),\n  skinTone: state.getIn(['settings', 'skinTone']),\n  frequentlyUsedEmojis: getFrequentlyUsedEmojis(state),\n});\n\nconst mapDispatchToProps = (dispatch, { onPickEmoji }) => ({\n  onSkinTone: skinTone => {\n    dispatch(changeSetting(['skinTone'], skinTone));\n  },\n\n  onPickEmoji: emoji => {\n    dispatch(useEmoji(emoji));\n\n    if (onPickEmoji) {\n      onPickEmoji(emoji);\n    }\n  },\n});\n\nexport default connect(mapStateToProps, mapDispatchToProps)(EmojiPickerDropdown);\n"
  },
  {
    "path": "app/javascript/mastodon/features/compose/containers/navigation_container.js",
    "content": "import { connect }   from 'react-redux';\nimport NavigationBar from '../components/navigation_bar';\nimport { me } from '../../../initial_state';\n\nconst mapStateToProps = state => {\n  return {\n    account: state.getIn(['accounts', me]),\n  };\n};\n\nexport default connect(mapStateToProps)(NavigationBar);\n"
  },
  {
    "path": "app/javascript/mastodon/features/compose/containers/poll_button_container.js",
    "content": "import { connect } from 'react-redux';\nimport PollButton from '../components/poll_button';\nimport { addPoll, removePoll } from '../../../actions/compose';\n\nconst mapStateToProps = state => ({\n  unavailable: state.getIn(['compose', 'is_uploading']) || (state.getIn(['compose', 'media_attachments']).size > 0),\n  active: state.getIn(['compose', 'poll']) !== null,\n});\n\nconst mapDispatchToProps = dispatch => ({\n\n  onClick () {\n    dispatch((_, getState) => {\n      if (getState().getIn(['compose', 'poll'])) {\n        dispatch(removePoll());\n      } else {\n        dispatch(addPoll());\n      }\n    });\n  },\n\n});\n\nexport default connect(mapStateToProps, mapDispatchToProps)(PollButton);\n"
  },
  {
    "path": "app/javascript/mastodon/features/compose/containers/poll_form_container.js",
    "content": "import { connect } from 'react-redux';\nimport PollForm from '../components/poll_form';\nimport { addPollOption, removePollOption, changePollOption, changePollSettings } from '../../../actions/compose';\nimport {\n  clearComposeSuggestions,\n  fetchComposeSuggestions,\n  selectComposeSuggestion,\n} from '../../../actions/compose';\n\nconst mapStateToProps = state => ({\n  suggestions: state.getIn(['compose', 'suggestions']),\n  options: state.getIn(['compose', 'poll', 'options']),\n  expiresIn: state.getIn(['compose', 'poll', 'expires_in']),\n  isMultiple: state.getIn(['compose', 'poll', 'multiple']),\n});\n\nconst mapDispatchToProps = dispatch => ({\n  onAddOption(title) {\n    dispatch(addPollOption(title));\n  },\n\n  onRemoveOption(index) {\n    dispatch(removePollOption(index));\n  },\n\n  onChangeOption(index, title) {\n    dispatch(changePollOption(index, title));\n  },\n\n  onChangeSettings(expiresIn, isMultiple) {\n    dispatch(changePollSettings(expiresIn, isMultiple));\n  },\n\n  onClearSuggestions () {\n    dispatch(clearComposeSuggestions());\n  },\n\n  onFetchSuggestions (token) {\n    dispatch(fetchComposeSuggestions(token));\n  },\n\n  onSuggestionSelected (position, token, accountId, path) {\n    dispatch(selectComposeSuggestion(position, token, accountId, path));\n  },\n\n});\n\nexport default connect(mapStateToProps, mapDispatchToProps)(PollForm);\n"
  },
  {
    "path": "app/javascript/mastodon/features/compose/containers/privacy_dropdown_container.js",
    "content": "import { connect } from 'react-redux';\nimport PrivacyDropdown from '../components/privacy_dropdown';\nimport { changeComposeVisibility } from '../../../actions/compose';\nimport { openModal, closeModal } from '../../../actions/modal';\nimport { isUserTouching } from '../../../is_mobile';\n\nconst mapStateToProps = state => ({\n  isModalOpen: state.get('modal').modalType === 'ACTIONS',\n  value: state.getIn(['compose', 'privacy']),\n});\n\nconst mapDispatchToProps = dispatch => ({\n\n  onChange (value) {\n    dispatch(changeComposeVisibility(value));\n  },\n\n  isUserTouching,\n  onModalOpen: props => dispatch(openModal('ACTIONS', props)),\n  onModalClose: () => dispatch(closeModal()),\n\n});\n\nexport default connect(mapStateToProps, mapDispatchToProps)(PrivacyDropdown);\n"
  },
  {
    "path": "app/javascript/mastodon/features/compose/containers/reply_indicator_container.js",
    "content": "import { connect } from 'react-redux';\nimport { cancelReplyCompose } from '../../../actions/compose';\nimport { makeGetStatus } from '../../../selectors';\nimport ReplyIndicator from '../components/reply_indicator';\n\nconst makeMapStateToProps = () => {\n  const getStatus = makeGetStatus();\n\n  const mapStateToProps = state => ({\n    status: getStatus(state, { id: state.getIn(['compose', 'in_reply_to']) }),\n  });\n\n  return mapStateToProps;\n};\n\nconst mapDispatchToProps = dispatch => ({\n\n  onCancel () {\n    dispatch(cancelReplyCompose());\n  },\n\n});\n\nexport default connect(makeMapStateToProps, mapDispatchToProps)(ReplyIndicator);\n"
  },
  {
    "path": "app/javascript/mastodon/features/compose/containers/search_container.js",
    "content": "import { connect } from 'react-redux';\nimport {\n  changeSearch,\n  clearSearch,\n  submitSearch,\n  showSearch,\n} from '../../../actions/search';\nimport Search from '../components/search';\n\nconst mapStateToProps = state => ({\n  value: state.getIn(['search', 'value']),\n  submitted: state.getIn(['search', 'submitted']),\n});\n\nconst mapDispatchToProps = dispatch => ({\n\n  onChange (value) {\n    dispatch(changeSearch(value));\n  },\n\n  onClear () {\n    dispatch(clearSearch());\n  },\n\n  onSubmit () {\n    dispatch(submitSearch());\n  },\n\n  onShow () {\n    dispatch(showSearch());\n  },\n\n});\n\nexport default connect(mapStateToProps, mapDispatchToProps)(Search);\n"
  },
  {
    "path": "app/javascript/mastodon/features/compose/containers/search_results_container.js",
    "content": "import { connect } from 'react-redux';\nimport SearchResults from '../components/search_results';\nimport { fetchSuggestions, dismissSuggestion } from '../../../actions/suggestions';\n\nconst mapStateToProps = state => ({\n  results: state.getIn(['search', 'results']),\n  suggestions: state.getIn(['suggestions', 'items']),\n});\n\nconst mapDispatchToProps = dispatch => ({\n  fetchSuggestions: () => dispatch(fetchSuggestions()),\n  dismissSuggestion: account => dispatch(dismissSuggestion(account.get('id'))),\n});\n\nexport default connect(mapStateToProps, mapDispatchToProps)(SearchResults);\n"
  },
  {
    "path": "app/javascript/mastodon/features/compose/containers/sensitive_button_container.js",
    "content": "import React from 'react';\nimport { connect } from 'react-redux';\nimport PropTypes from 'prop-types';\nimport classNames from 'classnames';\nimport { changeComposeSensitivity } from 'mastodon/actions/compose';\nimport { injectIntl, defineMessages, FormattedMessage } from 'react-intl';\n\nconst messages = defineMessages({\n  marked: { id: 'compose_form.sensitive.marked', defaultMessage: 'Media is marked as sensitive' },\n  unmarked: { id: 'compose_form.sensitive.unmarked', defaultMessage: 'Media is not marked as sensitive' },\n});\n\nconst mapStateToProps = state => ({\n  active: state.getIn(['compose', 'sensitive']),\n  disabled: state.getIn(['compose', 'spoiler']),\n});\n\nconst mapDispatchToProps = dispatch => ({\n\n  onClick () {\n    dispatch(changeComposeSensitivity());\n  },\n\n});\n\nclass SensitiveButton extends React.PureComponent {\n\n  static propTypes = {\n    active: PropTypes.bool,\n    disabled: PropTypes.bool,\n    onClick: PropTypes.func.isRequired,\n    intl: PropTypes.object.isRequired,\n  };\n\n  render () {\n    const { active, disabled, onClick, intl } = this.props;\n\n    return (\n      <div className='compose-form__sensitive-button'>\n        <label className={classNames('icon-button', { active })} title={intl.formatMessage(active ? messages.marked : messages.unmarked)}>\n          <input\n            name='mark-sensitive'\n            type='checkbox'\n            checked={active}\n            onChange={onClick}\n            disabled={disabled}\n          />\n\n          <span className={classNames('checkbox', { active })} />\n\n          <FormattedMessage id='compose_form.sensitive.hide' defaultMessage='Mark media as sensitive' />\n        </label>\n      </div>\n    );\n  }\n\n}\n\nexport default connect(mapStateToProps, mapDispatchToProps)(injectIntl(SensitiveButton));\n"
  },
  {
    "path": "app/javascript/mastodon/features/compose/containers/spoiler_button_container.js",
    "content": "import { connect } from 'react-redux';\nimport TextIconButton from '../components/text_icon_button';\nimport { changeComposeSpoilerness } from '../../../actions/compose';\nimport { injectIntl, defineMessages } from 'react-intl';\n\nconst messages = defineMessages({\n  marked: { id: 'compose_form.spoiler.marked', defaultMessage: 'Text is hidden behind warning' },\n  unmarked: { id: 'compose_form.spoiler.unmarked', defaultMessage: 'Text is not hidden' },\n});\n\nconst mapStateToProps = (state, { intl }) => ({\n  label: 'CW',\n  title: intl.formatMessage(state.getIn(['compose', 'spoiler']) ? messages.marked : messages.unmarked),\n  active: state.getIn(['compose', 'spoiler']),\n  ariaControls: 'cw-spoiler-input',\n});\n\nconst mapDispatchToProps = dispatch => ({\n\n  onClick () {\n    dispatch(changeComposeSpoilerness());\n  },\n\n});\n\nexport default injectIntl(connect(mapStateToProps, mapDispatchToProps)(TextIconButton));\n"
  },
  {
    "path": "app/javascript/mastodon/features/compose/containers/upload_button_container.js",
    "content": "import { connect } from 'react-redux';\nimport UploadButton from '../components/upload_button';\nimport { uploadCompose } from '../../../actions/compose';\n\nconst mapStateToProps = state => ({\n  disabled: state.getIn(['compose', 'is_uploading']) || (state.getIn(['compose', 'media_attachments']).size > 3 || state.getIn(['compose', 'media_attachments']).some(m => m.get('type') === 'video')),\n  unavailable: state.getIn(['compose', 'poll']) !== null,\n  resetFileKey: state.getIn(['compose', 'resetFileKey']),\n});\n\nconst mapDispatchToProps = dispatch => ({\n\n  onSelectFile (files) {\n    dispatch(uploadCompose(files));\n  },\n\n});\n\nexport default connect(mapStateToProps, mapDispatchToProps)(UploadButton);\n"
  },
  {
    "path": "app/javascript/mastodon/features/compose/containers/upload_container.js",
    "content": "import { connect } from 'react-redux';\nimport Upload from '../components/upload';\nimport { undoUploadCompose, changeUploadCompose } from '../../../actions/compose';\nimport { openModal } from '../../../actions/modal';\nimport { submitCompose } from '../../../actions/compose';\n\nconst mapStateToProps = (state, { id }) => ({\n  media: state.getIn(['compose', 'media_attachments']).find(item => item.get('id') === id),\n});\n\nconst mapDispatchToProps = dispatch => ({\n\n  onUndo: id => {\n    dispatch(undoUploadCompose(id));\n  },\n\n  onDescriptionChange: (id, description) => {\n    dispatch(changeUploadCompose(id, { description }));\n  },\n\n  onOpenFocalPoint: id => {\n    dispatch(openModal('FOCAL_POINT', { id }));\n  },\n\n  onSubmit (router) {\n    dispatch(submitCompose(router));\n  },\n\n});\n\nexport default connect(mapStateToProps, mapDispatchToProps)(Upload);\n"
  },
  {
    "path": "app/javascript/mastodon/features/compose/containers/upload_form_container.js",
    "content": "import { connect } from 'react-redux';\nimport UploadForm from '../components/upload_form';\n\nconst mapStateToProps = state => ({\n  mediaIds: state.getIn(['compose', 'media_attachments']).map(item => item.get('id')),\n});\n\nexport default connect(mapStateToProps)(UploadForm);\n"
  },
  {
    "path": "app/javascript/mastodon/features/compose/containers/upload_progress_container.js",
    "content": "import { connect } from 'react-redux';\nimport UploadProgress from '../components/upload_progress';\n\nconst mapStateToProps = state => ({\n  active: state.getIn(['compose', 'is_uploading']),\n  progress: state.getIn(['compose', 'progress']),\n});\n\nexport default connect(mapStateToProps)(UploadProgress);\n"
  },
  {
    "path": "app/javascript/mastodon/features/compose/containers/warning_container.js",
    "content": "import React from 'react';\nimport { connect } from 'react-redux';\nimport Warning from '../components/warning';\nimport PropTypes from 'prop-types';\nimport { FormattedMessage } from 'react-intl';\nimport { me } from '../../../initial_state';\n\nconst APPROX_HASHTAG_RE = /(?:^|[^\\/\\)\\w])#(\\w*[a-zA-Z·]\\w*)/i;\n\nconst mapStateToProps = state => ({\n  needsLockWarning: state.getIn(['compose', 'privacy']) === 'private' && !state.getIn(['accounts', me, 'locked']),\n  hashtagWarning: state.getIn(['compose', 'privacy']) !== 'public' && APPROX_HASHTAG_RE.test(state.getIn(['compose', 'text'])),\n  directMessageWarning: state.getIn(['compose', 'privacy']) === 'direct',\n});\n\nconst WarningWrapper = ({ needsLockWarning, hashtagWarning, directMessageWarning }) => {\n  if (needsLockWarning) {\n    return <Warning message={<FormattedMessage id='compose_form.lock_disclaimer' defaultMessage='Your account is not {locked}. Anyone can follow you to view your follower-only posts.' values={{ locked: <a href='/settings/profile'><FormattedMessage id='compose_form.lock_disclaimer.lock' defaultMessage='locked' /></a> }} />} />;\n  }\n\n  if (hashtagWarning) {\n    return <Warning message={<FormattedMessage id='compose_form.hashtag_warning' defaultMessage=\"This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.\" />} />;\n  }\n\n  if (directMessageWarning) {\n    const message = (\n      <span>\n        <FormattedMessage id='compose_form.direct_message_warning' defaultMessage='This toot will only be sent to all the mentioned users.' /> <a href='/terms' target='_blank'><FormattedMessage id='compose_form.direct_message_warning_learn_more' defaultMessage='Learn more' /></a>\n      </span>\n    );\n\n    return <Warning message={message} />;\n  }\n\n  return null;\n};\n\nWarningWrapper.propTypes = {\n  needsLockWarning: PropTypes.bool,\n  hashtagWarning: PropTypes.bool,\n  directMessageWarning: PropTypes.bool,\n};\n\nexport default connect(mapStateToProps)(WarningWrapper);\n"
  },
  {
    "path": "app/javascript/mastodon/features/compose/index.js",
    "content": "import React from 'react';\nimport ComposeFormContainer from './containers/compose_form_container';\nimport NavigationContainer from './containers/navigation_container';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport { connect } from 'react-redux';\nimport { mountCompose, unmountCompose } from '../../actions/compose';\nimport { Link } from 'react-router-dom';\nimport { injectIntl, defineMessages } from 'react-intl';\nimport SearchContainer from './containers/search_container';\nimport Motion from '../ui/util/optional_motion';\nimport spring from 'react-motion/lib/spring';\nimport SearchResultsContainer from './containers/search_results_container';\nimport { changeComposing } from '../../actions/compose';\nimport elephantUIPlane from '../../../images/elephant_ui_plane.svg';\nimport { mascot } from '../../initial_state';\nimport Icon from 'mastodon/components/icon';\n\nconst messages = defineMessages({\n  start: { id: 'getting_started.heading', defaultMessage: 'Getting started' },\n  home_timeline: { id: 'tabs_bar.home', defaultMessage: 'Home' },\n  notifications: { id: 'tabs_bar.notifications', defaultMessage: 'Notifications' },\n  public: { id: 'navigation_bar.public_timeline', defaultMessage: 'Federated timeline' },\n  community: { id: 'navigation_bar.community_timeline', defaultMessage: 'Local timeline' },\n  preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' },\n  logout: { id: 'navigation_bar.logout', defaultMessage: 'Logout' },\n  compose: { id: 'navigation_bar.compose', defaultMessage: 'Compose new toot' },\n});\n\nconst mapStateToProps = (state, ownProps) => ({\n  columns: state.getIn(['settings', 'columns']),\n  showSearch: ownProps.multiColumn ? state.getIn(['search', 'submitted']) && !state.getIn(['search', 'hidden']) : ownProps.isSearchPage,\n});\n\nexport default @connect(mapStateToProps)\n@injectIntl\nclass Compose extends React.PureComponent {\n\n  static propTypes = {\n    dispatch: PropTypes.func.isRequired,\n    columns: ImmutablePropTypes.list.isRequired,\n    multiColumn: PropTypes.bool,\n    showSearch: PropTypes.bool,\n    isSearchPage: PropTypes.bool,\n    intl: PropTypes.object.isRequired,\n  };\n\n  componentDidMount () {\n    const { isSearchPage } = this.props;\n\n    if (!isSearchPage) {\n      this.props.dispatch(mountCompose());\n    }\n  }\n\n  componentWillUnmount () {\n    const { isSearchPage } = this.props;\n\n    if (!isSearchPage) {\n      this.props.dispatch(unmountCompose());\n    }\n  }\n\n  onFocus = () => {\n    this.props.dispatch(changeComposing(true));\n  }\n\n  onBlur = () => {\n    this.props.dispatch(changeComposing(false));\n  }\n\n  render () {\n    const { multiColumn, showSearch, isSearchPage, intl } = this.props;\n\n    let header = '';\n\n    if (multiColumn) {\n      const { columns } = this.props;\n      header = (\n        <nav className='drawer__header'>\n          <Link to='/getting-started' className='drawer__tab' title={intl.formatMessage(messages.start)} aria-label={intl.formatMessage(messages.start)}><Icon id='bars' fixedWidth /></Link>\n          {!columns.some(column => column.get('id') === 'HOME') && (\n            <Link to='/timelines/home' className='drawer__tab' title={intl.formatMessage(messages.home_timeline)} aria-label={intl.formatMessage(messages.home_timeline)}><Icon id='home' fixedWidth /></Link>\n          )}\n          {!columns.some(column => column.get('id') === 'NOTIFICATIONS') && (\n            <Link to='/notifications' className='drawer__tab' title={intl.formatMessage(messages.notifications)} aria-label={intl.formatMessage(messages.notifications)}><Icon id='bell' fixedWidth /></Link>\n          )}\n          {!columns.some(column => column.get('id') === 'COMMUNITY') && (\n            <Link to='/timelines/public/local' className='drawer__tab' title={intl.formatMessage(messages.community)} aria-label={intl.formatMessage(messages.community)}><Icon id='users' fixedWidth /></Link>\n          )}\n          {!columns.some(column => column.get('id') === 'PUBLIC') && (\n            <Link to='/timelines/public' className='drawer__tab' title={intl.formatMessage(messages.public)} aria-label={intl.formatMessage(messages.public)}><Icon id='globe' fixedWidth /></Link>\n          )}\n          <a href='/settings/preferences' className='drawer__tab' title={intl.formatMessage(messages.preferences)} aria-label={intl.formatMessage(messages.preferences)}><Icon id='cog' fixedWidth /></a>\n          <a href='/auth/sign_out' className='drawer__tab' data-method='delete' title={intl.formatMessage(messages.logout)} aria-label={intl.formatMessage(messages.logout)}><Icon id='sign-out' fixedWidth /></a>\n        </nav>\n      );\n    }\n\n    return (\n      <div className='drawer' role='region' aria-label={intl.formatMessage(messages.compose)}>\n        {header}\n\n        {(multiColumn || isSearchPage) && <SearchContainer /> }\n\n        <div className='drawer__pager'>\n          {!isSearchPage && <div className='drawer__inner' onFocus={this.onFocus}>\n            <NavigationContainer onClose={this.onBlur} />\n\n            <ComposeFormContainer />\n\n            <div className='drawer__inner__mastodon'>\n              <img alt='' draggable='false' src={mascot || elephantUIPlane} />\n            </div>\n          </div>}\n\n          <Motion defaultStyle={{ x: isSearchPage ? 0 : -100 }} style={{ x: spring(showSearch || isSearchPage ? 0 : -100, { stiffness: 210, damping: 20 }) }}>\n            {({ x }) => (\n              <div className='drawer__inner darker' style={{ transform: `translateX(${x}%)`, visibility: x === -100 ? 'hidden' : 'visible' }}>\n                <SearchResultsContainer />\n              </div>\n            )}\n          </Motion>\n        </div>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/compose/util/counter.js",
    "content": "import { urlRegex } from './url_regex';\n\nconst urlPlaceholder = 'xxxxxxxxxxxxxxxxxxxxxxx';\n\nexport function countableText(inputText) {\n  return inputText\n    .replace(urlRegex, urlPlaceholder)\n    .replace(/(^|[^\\/\\w])@(([a-z0-9_]+)@[a-z0-9\\.\\-]+[a-z0-9]+)/ig, '$1@$3');\n};\n"
  },
  {
    "path": "app/javascript/mastodon/features/compose/util/url_regex.js",
    "content": "const regexen = {};\n\nconst regexSupplant = function(regex, flags) {\n  flags = flags || '';\n  if (typeof regex !== 'string') {\n    if (regex.global && flags.indexOf('g') < 0) {\n      flags += 'g';\n    }\n    if (regex.ignoreCase && flags.indexOf('i') < 0) {\n      flags += 'i';\n    }\n    if (regex.multiline && flags.indexOf('m') < 0) {\n      flags += 'm';\n    }\n\n    regex = regex.source;\n  }\n  return new RegExp(regex.replace(/#\\{(\\w+)\\}/g, function(match, name) {\n    var newRegex = regexen[name] || '';\n    if (typeof newRegex !== 'string') {\n      newRegex = newRegex.source;\n    }\n    return newRegex;\n  }), flags);\n};\n\nconst stringSupplant = function(str, values) {\n  return str.replace(/#\\{(\\w+)\\}/g, function(match, name) {\n    return values[name] || '';\n  });\n};\n\nexport const urlRegex = (function() {\n  regexen.spaces_group = /\\x09-\\x0D\\x20\\x85\\xA0\\u1680\\u180E\\u2000-\\u200A\\u2028\\u2029\\u202F\\u205F\\u3000/;\n  regexen.invalid_chars_group = /\\uFFFE\\uFEFF\\uFFFF\\u202A-\\u202E/;\n  regexen.punct = /\\!'#%&'\\(\\)*\\+,\\\\\\-\\.\\/:;<=>\\?@\\[\\]\\^_{|}~\\$/;\n  regexen.validUrlPrecedingChars = regexSupplant(/(?:[^A-Za-z0-9@＠$#＃#{invalid_chars_group}]|^)/);\n  regexen.invalidDomainChars = stringSupplant('#{punct}#{spaces_group}#{invalid_chars_group}', regexen);\n  regexen.validDomainChars = regexSupplant(/[^#{invalidDomainChars}]/);\n  regexen.validSubdomain = regexSupplant(/(?:(?:#{validDomainChars}(?:[_-]|#{validDomainChars})*)?#{validDomainChars}\\.)/);\n  regexen.validDomainName = regexSupplant(/(?:(?:#{validDomainChars}(?:-|#{validDomainChars})*)?#{validDomainChars}\\.)/);\n  regexen.validGTLD = regexSupplant(RegExp(\n    '(?:(?:' +\n      '삼성|닷컴|닷넷|香格里拉|餐厅|食品|飞利浦|電訊盈科|集团|通販|购物|谷歌|诺基亚|联通|网络|网站|网店|网址|组织机构|移动|珠宝|点看|游戏|淡马锡|机构|書籍|时尚|新闻|政府|' +\n      '政务|手表|手机|我爱你|慈善|微博|广东|工行|家電|娱乐|天主教|大拿|大众汽车|在线|嘉里大酒店|嘉里|商标|商店|商城|公益|公司|八卦|健康|信息|佛山|企业|中文网|中信|世界|' +\n      'ポイント|ファッション|セール|ストア|コム|グーグル|クラウド|みんな|คอม|संगठन|नेट|कॉम|همراه|موقع|موبايلي|كوم|كاثوليك|عرب|شبكة|' +\n      'بيتك|بازار|العليان|ارامكو|اتصالات|ابوظبي|קום|сайт|рус|орг|онлайн|москва|ком|католик|дети|' +\n      'zuerich|zone|zippo|zip|zero|zara|zappos|yun|youtube|you|yokohama|yoga|yodobashi|yandex|yamaxun|' +\n      'yahoo|yachts|xyz|xxx|xperia|xin|xihuan|xfinity|xerox|xbox|wtf|wtc|wow|world|works|work|woodside|' +\n      'wolterskluwer|wme|winners|wine|windows|win|williamhill|wiki|wien|whoswho|weir|weibo|wedding|wed|' +\n      'website|weber|webcam|weatherchannel|weather|watches|watch|warman|wanggou|wang|walter|walmart|' +\n      'wales|vuelos|voyage|voto|voting|vote|volvo|volkswagen|vodka|vlaanderen|vivo|viva|vistaprint|' +\n      'vista|vision|visa|virgin|vip|vin|villas|viking|vig|video|viajes|vet|versicherung|' +\n      'vermögensberatung|vermögensberater|verisign|ventures|vegas|vanguard|vana|vacations|ups|uol|uno|' +\n      'university|unicom|uconnect|ubs|ubank|tvs|tushu|tunes|tui|tube|trv|trust|travelersinsurance|' +\n      'travelers|travelchannel|travel|training|trading|trade|toys|toyota|town|tours|total|toshiba|' +\n      'toray|top|tools|tokyo|today|tmall|tkmaxx|tjx|tjmaxx|tirol|tires|tips|tiffany|tienda|tickets|' +\n      'tiaa|theatre|theater|thd|teva|tennis|temasek|telefonica|telecity|tel|technology|tech|team|tdk|' +\n      'tci|taxi|tax|tattoo|tatar|tatamotors|target|taobao|talk|taipei|tab|systems|symantec|sydney|' +\n      'swiss|swiftcover|swatch|suzuki|surgery|surf|support|supply|supplies|sucks|style|study|studio|' +\n      'stream|store|storage|stockholm|stcgroup|stc|statoil|statefarm|statebank|starhub|star|staples|' +\n      'stada|srt|srl|spreadbetting|spot|spiegel|space|soy|sony|song|solutions|solar|sohu|software|' +\n      'softbank|social|soccer|sncf|smile|smart|sling|skype|sky|skin|ski|site|singles|sina|silk|shriram|' +\n      'showtime|show|shouji|shopping|shop|shoes|shiksha|shia|shell|shaw|sharp|shangrila|sfr|sexy|sex|' +\n      'sew|seven|ses|services|sener|select|seek|security|secure|seat|search|scot|scor|scjohnson|' +\n      'science|schwarz|schule|school|scholarships|schmidt|schaeffler|scb|sca|sbs|sbi|saxo|save|sas|' +\n      'sarl|sapo|sap|sanofi|sandvikcoromant|sandvik|samsung|samsclub|salon|sale|sakura|safety|safe|' +\n      'saarland|ryukyu|rwe|run|ruhr|rugby|rsvp|room|rogers|rodeo|rocks|rocher|rmit|rip|rio|ril|' +\n      'rightathome|ricoh|richardli|rich|rexroth|reviews|review|restaurant|rest|republican|report|' +\n      'repair|rentals|rent|ren|reliance|reit|reisen|reise|rehab|redumbrella|redstone|red|recipes|' +\n      'realty|realtor|realestate|read|raid|radio|racing|qvc|quest|quebec|qpon|pwc|pub|prudential|pru|' +\n      'protection|property|properties|promo|progressive|prof|productions|prod|pro|prime|press|praxi|' +\n      'pramerica|post|porn|politie|poker|pohl|pnc|plus|plumbing|playstation|play|place|pizza|pioneer|' +\n      'pink|ping|pin|pid|pictures|pictet|pics|piaget|physio|photos|photography|photo|phone|philips|phd|' +\n      'pharmacy|pfizer|pet|pccw|pay|passagens|party|parts|partners|pars|paris|panerai|panasonic|' +\n      'pamperedchef|page|ovh|ott|otsuka|osaka|origins|orientexpress|organic|org|orange|oracle|open|ooo|' +\n      'onyourside|online|onl|ong|one|omega|ollo|oldnavy|olayangroup|olayan|okinawa|office|off|observer|' +\n      'obi|nyc|ntt|nrw|nra|nowtv|nowruz|now|norton|northwesternmutual|nokia|nissay|nissan|ninja|nikon|' +\n      'nike|nico|nhk|ngo|nfl|nexus|nextdirect|next|news|newholland|new|neustar|network|netflix|netbank|' +\n      'net|nec|nba|navy|natura|nationwide|name|nagoya|nadex|nab|mutuelle|mutual|museum|mtr|mtpc|mtn|' +\n      'msd|movistar|movie|mov|motorcycles|moto|moscow|mortgage|mormon|mopar|montblanc|monster|money|' +\n      'monash|mom|moi|moe|moda|mobily|mobile|mobi|mma|mls|mlb|mitsubishi|mit|mint|mini|mil|microsoft|' +\n      'miami|metlife|merckmsd|meo|menu|men|memorial|meme|melbourne|meet|media|med|mckinsey|mcdonalds|' +\n      'mcd|mba|mattel|maserati|marshalls|marriott|markets|marketing|market|map|mango|management|man|' +\n      'makeup|maison|maif|madrid|macys|luxury|luxe|lupin|lundbeck|ltda|ltd|lplfinancial|lpl|love|lotto|' +\n      'lotte|london|lol|loft|locus|locker|loans|loan|lixil|living|live|lipsy|link|linde|lincoln|limo|' +\n      'limited|lilly|like|lighting|lifestyle|lifeinsurance|life|lidl|liaison|lgbt|lexus|lego|legal|' +\n      'lefrak|leclerc|lease|lds|lawyer|law|latrobe|latino|lat|lasalle|lanxess|landrover|land|lancome|' +\n      'lancia|lancaster|lamer|lamborghini|ladbrokes|lacaixa|kyoto|kuokgroup|kred|krd|kpn|kpmg|kosher|' +\n      'komatsu|koeln|kiwi|kitchen|kindle|kinder|kim|kia|kfh|kerryproperties|kerrylogistics|kerryhotels|' +\n      'kddi|kaufen|juniper|juegos|jprs|jpmorgan|joy|jot|joburg|jobs|jnj|jmp|jll|jlc|jio|jewelry|jetzt|' +\n      'jeep|jcp|jcb|java|jaguar|iwc|iveco|itv|itau|istanbul|ist|ismaili|iselect|irish|ipiranga|' +\n      'investments|intuit|international|intel|int|insure|insurance|institute|ink|ing|info|infiniti|' +\n      'industries|immobilien|immo|imdb|imamat|ikano|iinet|ifm|ieee|icu|ice|icbc|ibm|hyundai|hyatt|' +\n      'hughes|htc|hsbc|how|house|hotmail|hotels|hoteles|hot|hosting|host|hospital|horse|honeywell|' +\n      'honda|homesense|homes|homegoods|homedepot|holiday|holdings|hockey|hkt|hiv|hitachi|hisamitsu|' +\n      'hiphop|hgtv|hermes|here|helsinki|help|healthcare|health|hdfcbank|hdfc|hbo|haus|hangout|hamburg|' +\n      'hair|guru|guitars|guide|guge|gucci|guardian|group|grocery|gripe|green|gratis|graphics|grainger|' +\n      'gov|got|gop|google|goog|goodyear|goodhands|goo|golf|goldpoint|gold|godaddy|gmx|gmo|gmbh|gmail|' +\n      'globo|global|gle|glass|glade|giving|gives|gifts|gift|ggee|george|genting|gent|gea|gdn|gbiz|' +\n      'garden|gap|games|game|gallup|gallo|gallery|gal|fyi|futbol|furniture|fund|fun|fujixerox|fujitsu|' +\n      'ftr|frontier|frontdoor|frogans|frl|fresenius|free|fox|foundation|forum|forsale|forex|ford|' +\n      'football|foodnetwork|food|foo|fly|flsmidth|flowers|florist|flir|flights|flickr|fitness|fit|' +\n      'fishing|fish|firmdale|firestone|fire|financial|finance|final|film|fido|fidelity|fiat|ferrero|' +\n      'ferrari|feedback|fedex|fast|fashion|farmers|farm|fans|fan|family|faith|fairwinds|fail|fage|' +\n      'extraspace|express|exposed|expert|exchange|everbank|events|eus|eurovision|etisalat|esurance|' +\n      'estate|esq|erni|ericsson|equipment|epson|epost|enterprises|engineering|engineer|energy|emerck|' +\n      'email|education|edu|edeka|eco|eat|earth|dvr|dvag|durban|dupont|duns|dunlop|duck|dubai|dtv|drive|' +\n      'download|dot|doosan|domains|doha|dog|dodge|doctor|docs|dnp|diy|dish|discover|discount|directory|' +\n      'direct|digital|diet|diamonds|dhl|dev|design|desi|dentist|dental|democrat|delta|deloitte|dell|' +\n      'delivery|degree|deals|dealer|deal|dds|dclk|day|datsun|dating|date|data|dance|dad|dabur|cyou|' +\n      'cymru|cuisinella|csc|cruises|cruise|crs|crown|cricket|creditunion|creditcard|credit|courses|' +\n      'coupons|coupon|country|corsica|coop|cool|cookingchannel|cooking|contractors|contact|consulting|' +\n      'construction|condos|comsec|computer|compare|company|community|commbank|comcast|com|cologne|' +\n      'college|coffee|codes|coach|clubmed|club|cloud|clothing|clinique|clinic|click|cleaning|claims|' +\n      'cityeats|city|citic|citi|citadel|cisco|circle|cipriani|church|chrysler|chrome|christmas|chloe|' +\n      'chintai|cheap|chat|chase|channel|chanel|cfd|cfa|cern|ceo|center|ceb|cbs|cbre|cbn|cba|catholic|' +\n      'catering|cat|casino|cash|caseih|case|casa|cartier|cars|careers|career|care|cards|caravan|car|' +\n      'capitalone|capital|capetown|canon|cancerresearch|camp|camera|cam|calvinklein|call|cal|cafe|cab|' +\n      'bzh|buzz|buy|business|builders|build|bugatti|budapest|brussels|brother|broker|broadway|' +\n      'bridgestone|bradesco|box|boutique|bot|boston|bostik|bosch|boots|booking|book|boo|bond|bom|bofa|' +\n      'boehringer|boats|bnpparibas|bnl|bmw|bms|blue|bloomberg|blog|blockbuster|blanco|blackfriday|' +\n      'black|biz|bio|bingo|bing|bike|bid|bible|bharti|bet|bestbuy|best|berlin|bentley|beer|beauty|' +\n      'beats|bcn|bcg|bbva|bbt|bbc|bayern|bauhaus|basketball|baseball|bargains|barefoot|barclays|' +\n      'barclaycard|barcelona|bar|bank|band|bananarepublic|banamex|baidu|baby|azure|axa|aws|avianca|' +\n      'autos|auto|author|auspost|audio|audible|audi|auction|attorney|athleta|associates|asia|asda|arte|' +\n      'art|arpa|army|archi|aramco|arab|aquarelle|apple|app|apartments|aol|anz|anquan|android|analytics|' +\n      'amsterdam|amica|amfam|amex|americanfamily|americanexpress|alstom|alsace|ally|allstate|allfinanz|' +\n      'alipay|alibaba|alfaromeo|akdn|airtel|airforce|airbus|aigo|aig|agency|agakhan|africa|afl|' +\n      'afamilycompany|aetna|aero|aeg|adult|ads|adac|actor|active|aco|accountants|accountant|accenture|' +\n      'academy|abudhabi|abogado|able|abc|abbvie|abbott|abb|abarth|aarp|aaa|onion' +\n    ')(?=[^0-9a-zA-Z@]|$))'));\n  regexen.validCCTLD = regexSupplant(RegExp(\n    '(?:(?:' +\n      '한국|香港|澳門|新加坡|台灣|台湾|中國|中国|გე|ไทย|ලංකා|ഭാരതം|ಭಾರತ|భారత్|சிங்கப்பூர்|இலங்கை|இந்தியா|ଭାରତ|ભારત|ਭਾਰਤ|' +\n      'ভাৰত|ভারত|বাংলা|भारोत|भारतम्|भारत|ڀارت|پاکستان|مليسيا|مصر|قطر|فلسطين|عمان|عراق|سورية|سودان|تونس|' +\n      'بھارت|بارت|ایران|امارات|المغرب|السعودية|الجزائر|الاردن|հայ|қаз|укр|срб|рф|мон|мкд|ею|бел|бг|ελ|' +\n      'zw|zm|za|yt|ye|ws|wf|vu|vn|vi|vg|ve|vc|va|uz|uy|us|um|uk|ug|ua|tz|tw|tv|tt|tr|tp|to|tn|tm|tl|tk|' +\n      'tj|th|tg|tf|td|tc|sz|sy|sx|sv|su|st|ss|sr|so|sn|sm|sl|sk|sj|si|sh|sg|se|sd|sc|sb|sa|rw|ru|rs|ro|' +\n      're|qa|py|pw|pt|ps|pr|pn|pm|pl|pk|ph|pg|pf|pe|pa|om|nz|nu|nr|np|no|nl|ni|ng|nf|ne|nc|na|mz|my|mx|' +\n      'mw|mv|mu|mt|ms|mr|mq|mp|mo|mn|mm|ml|mk|mh|mg|mf|me|md|mc|ma|ly|lv|lu|lt|ls|lr|lk|li|lc|lb|la|kz|' +\n      'ky|kw|kr|kp|kn|km|ki|kh|kg|ke|jp|jo|jm|je|it|is|ir|iq|io|in|im|il|ie|id|hu|ht|hr|hn|hm|hk|gy|gw|' +\n      'gu|gt|gs|gr|gq|gp|gn|gm|gl|gi|gh|gg|gf|ge|gd|gb|ga|fr|fo|fm|fk|fj|fi|eu|et|es|er|eh|eg|ee|ec|dz|' +\n      'do|dm|dk|dj|de|cz|cy|cx|cw|cv|cu|cr|co|cn|cm|cl|ck|ci|ch|cg|cf|cd|cc|ca|bz|by|bw|bv|bt|bs|br|bq|' +\n      'bo|bn|bm|bl|bj|bi|bh|bg|bf|be|bd|bb|ba|az|ax|aw|au|at|as|ar|aq|ao|an|am|al|ai|ag|af|ae|ad|ac' +\n    ')(?=[^0-9a-zA-Z@]|$))'));\n  regexen.validPunycode = /(?:xn--[0-9a-z]+)/;\n  regexen.validSpecialCCTLD = /(?:(?:co|tv)(?=[^0-9a-zA-Z@]|$))/;\n  regexen.validDomain = regexSupplant(/(?:#{validSubdomain}*#{validDomainName}(?:#{validGTLD}|#{validCCTLD}|#{validPunycode}))/);\n  regexen.validPortNumber = /[0-9]+/;\n  regexen.pd = /\\u002d\\u058a\\u05be\\u1400\\u1806\\u2010-\\u2015\\u2e17\\u2e1a\\u2e3a\\u2e40\\u301c\\u3030\\u30a0\\ufe31\\ufe58\\ufe63\\uff0d/;\n  regexen.validGeneralUrlPathChars = regexSupplant(/[^#{spaces_group}\\(\\)\\?]/i);\n  // Allow URL paths to contain up to two nested levels of balanced parens\n  //  1. Used in Wikipedia URLs like /Primer_(film)\n  //  2. Used in IIS sessions like /S(dfd346)/\n  //  3. Used in Rdio URLs like /track/We_Up_(Album_Version_(Edited))/\n  regexen.validUrlBalancedParens = regexSupplant(\n    '\\\\('                                   +\n      '(?:'                                 +\n        '#{validGeneralUrlPathChars}+'      +\n        '|'                                 +\n        // allow one nested level of balanced parentheses\n        '(?:'                               +\n          '#{validGeneralUrlPathChars}*'    +\n          '\\\\('                             +\n            '#{validGeneralUrlPathChars}+'  +\n          '\\\\)'                             +\n          '#{validGeneralUrlPathChars}*'    +\n        ')'                                 +\n      ')'                                   +\n    '\\\\)',\n    'i');\n  // Valid end-of-path characters (so /foo. does not gobble the period).\n  // 1. Allow =&# for empty URL parameters and other URL-join artifacts\n  regexen.validUrlPathEndingChars = regexSupplant(/[^#{spaces_group}\\(\\)\\?!\\*';:=\\,\\.\\$%\\[\\]#{pd}~&\\|@]|(?:#{validUrlBalancedParens})/i);\n  // Allow @ in a url, but only in the middle. Catch things like http://example.com/@user/\n  regexen.validUrlPath = regexSupplant('(?:' +\n    '(?:' +\n      '#{validGeneralUrlPathChars}*' +\n        '(?:#{validUrlBalancedParens}#{validGeneralUrlPathChars}*)*' +\n        '#{validUrlPathEndingChars}'+\n      ')|(?:@#{validGeneralUrlPathChars}+\\/)'+\n    ')', 'i');\n  regexen.validUrlQueryChars = /[a-z0-9!?\\*'@\\(\\);:&=\\+\\$\\/%#\\[\\]\\-_\\.,~|]/i;\n  regexen.validUrlQueryEndingChars = /[a-z0-9_&=#\\/]/i;\n  regexen.validUrl = regexSupplant(\n    '('                                                          + // $1 URL\n      '(https?:\\\\/\\\\/)'                                          + // $2 Protocol\n      '(#{validDomain})'                                         + // $3 Domain(s)\n      '(?::(#{validPortNumber}))?'                               + // $4 Port number (optional)\n      '(\\\\/#{validUrlPath}*)?'                                   + // $5 URL Path\n      '(\\\\?#{validUrlQueryChars}*#{validUrlQueryEndingChars})?'  + // $6 Query String\n    ')',\n    'gi');\n  return regexen.validUrl;\n}());\n"
  },
  {
    "path": "app/javascript/mastodon/features/direct_timeline/components/conversation.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport StatusContainer from '../../../containers/status_container';\n\nexport default class Conversation extends ImmutablePureComponent {\n\n  static contextTypes = {\n    router: PropTypes.object,\n  };\n\n  static propTypes = {\n    conversationId: PropTypes.string.isRequired,\n    accounts: ImmutablePropTypes.list.isRequired,\n    lastStatusId: PropTypes.string,\n    unread:PropTypes.bool.isRequired,\n    onMoveUp: PropTypes.func,\n    onMoveDown: PropTypes.func,\n    markRead: PropTypes.func.isRequired,\n  };\n\n  handleClick = () => {\n    if (!this.context.router) {\n      return;\n    }\n\n    const { lastStatusId, unread, markRead } = this.props;\n\n    if (unread) {\n      markRead();\n    }\n\n    this.context.router.history.push(`/statuses/${lastStatusId}`);\n  }\n\n  handleHotkeyMoveUp = () => {\n    this.props.onMoveUp(this.props.conversationId);\n  }\n\n  handleHotkeyMoveDown = () => {\n    this.props.onMoveDown(this.props.conversationId);\n  }\n\n  render () {\n    const { accounts, lastStatusId, unread } = this.props;\n\n    if (lastStatusId === null) {\n      return null;\n    }\n\n    return (\n      <StatusContainer\n        id={lastStatusId}\n        unread={unread}\n        otherAccounts={accounts}\n        onMoveUp={this.handleHotkeyMoveUp}\n        onMoveDown={this.handleHotkeyMoveDown}\n        onClick={this.handleClick}\n      />\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/direct_timeline/components/conversations_list.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport ConversationContainer from '../containers/conversation_container';\nimport ScrollableList from '../../../components/scrollable_list';\nimport { debounce } from 'lodash';\n\nexport default class ConversationsList extends ImmutablePureComponent {\n\n  static propTypes = {\n    conversations: ImmutablePropTypes.list.isRequired,\n    hasMore: PropTypes.bool,\n    isLoading: PropTypes.bool,\n    onLoadMore: PropTypes.func,\n    shouldUpdateScroll: PropTypes.func,\n  };\n\n  getCurrentIndex = id => this.props.conversations.findIndex(x => x.get('id') === id)\n\n  handleMoveUp = id => {\n    const elementIndex = this.getCurrentIndex(id) - 1;\n    this._selectChild(elementIndex, true);\n  }\n\n  handleMoveDown = id => {\n    const elementIndex = this.getCurrentIndex(id) + 1;\n    this._selectChild(elementIndex, false);\n  }\n\n  _selectChild (index, align_top) {\n    const container = this.node.node;\n    const element = container.querySelector(`article:nth-of-type(${index + 1}) .focusable`);\n\n    if (element) {\n      if (align_top && container.scrollTop > element.offsetTop) {\n        element.scrollIntoView(true);\n      } else if (!align_top && container.scrollTop + container.clientHeight < element.offsetTop + element.offsetHeight) {\n        element.scrollIntoView(false);\n      }\n      element.focus();\n    }\n  }\n\n  setRef = c => {\n    this.node = c;\n  }\n\n  handleLoadOlder = debounce(() => {\n    const last = this.props.conversations.last();\n\n    if (last && last.get('last_status')) {\n      this.props.onLoadMore(last.get('last_status'));\n    }\n  }, 300, { leading: true })\n\n  render () {\n    const { conversations, onLoadMore, ...other } = this.props;\n\n    return (\n      <ScrollableList {...other} onLoadMore={onLoadMore && this.handleLoadOlder} scrollKey='direct' ref={this.setRef}>\n        {conversations.map(item => (\n          <ConversationContainer\n            key={item.get('id')}\n            conversationId={item.get('id')}\n            onMoveUp={this.handleMoveUp}\n            onMoveDown={this.handleMoveDown}\n          />\n        ))}\n      </ScrollableList>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/direct_timeline/containers/conversation_container.js",
    "content": "import { connect } from 'react-redux';\nimport Conversation from '../components/conversation';\nimport { markConversationRead } from '../../../actions/conversations';\n\nconst mapStateToProps = (state, { conversationId }) => {\n  const conversation = state.getIn(['conversations', 'items']).find(x => x.get('id') === conversationId);\n\n  return {\n    accounts: conversation.get('accounts').map(accountId => state.getIn(['accounts', accountId], null)),\n    unread: conversation.get('unread'),\n    lastStatusId: conversation.get('last_status', null),\n  };\n};\n\nconst mapDispatchToProps = (dispatch, { conversationId }) => ({\n  markRead: () => dispatch(markConversationRead(conversationId)),\n});\n\nexport default connect(mapStateToProps, mapDispatchToProps)(Conversation);\n"
  },
  {
    "path": "app/javascript/mastodon/features/direct_timeline/containers/conversations_list_container.js",
    "content": "import { connect } from 'react-redux';\nimport ConversationsList from '../components/conversations_list';\nimport { expandConversations } from '../../../actions/conversations';\n\nconst mapStateToProps = state => ({\n  conversations: state.getIn(['conversations', 'items']),\n  isLoading: state.getIn(['conversations', 'isLoading'], true),\n  hasMore: state.getIn(['conversations', 'hasMore'], false),\n});\n\nconst mapDispatchToProps = dispatch => ({\n  onLoadMore: maxId => dispatch(expandConversations({ maxId })),\n});\n\nexport default connect(mapStateToProps, mapDispatchToProps)(ConversationsList);\n"
  },
  {
    "path": "app/javascript/mastodon/features/direct_timeline/index.js",
    "content": "import React from 'react';\nimport { connect } from 'react-redux';\nimport PropTypes from 'prop-types';\nimport Column from '../../components/column';\nimport ColumnHeader from '../../components/column_header';\nimport { mountConversations, unmountConversations, expandConversations } from '../../actions/conversations';\nimport { addColumn, removeColumn, moveColumn } from '../../actions/columns';\nimport { defineMessages, injectIntl, FormattedMessage } from 'react-intl';\nimport { connectDirectStream } from '../../actions/streaming';\nimport ConversationsListContainer from './containers/conversations_list_container';\n\nconst messages = defineMessages({\n  title: { id: 'column.direct', defaultMessage: 'Direct messages' },\n});\n\nexport default @connect()\n@injectIntl\nclass DirectTimeline extends React.PureComponent {\n\n  static propTypes = {\n    dispatch: PropTypes.func.isRequired,\n    shouldUpdateScroll: PropTypes.func,\n    columnId: PropTypes.string,\n    intl: PropTypes.object.isRequired,\n    hasUnread: PropTypes.bool,\n    multiColumn: PropTypes.bool,\n  };\n\n  handlePin = () => {\n    const { columnId, dispatch } = this.props;\n\n    if (columnId) {\n      dispatch(removeColumn(columnId));\n    } else {\n      dispatch(addColumn('DIRECT', {}));\n    }\n  }\n\n  handleMove = (dir) => {\n    const { columnId, dispatch } = this.props;\n    dispatch(moveColumn(columnId, dir));\n  }\n\n  handleHeaderClick = () => {\n    this.column.scrollTop();\n  }\n\n  componentDidMount () {\n    const { dispatch } = this.props;\n\n    dispatch(mountConversations());\n    dispatch(expandConversations());\n    this.disconnect = dispatch(connectDirectStream());\n  }\n\n  componentWillUnmount () {\n    this.props.dispatch(unmountConversations());\n\n    if (this.disconnect) {\n      this.disconnect();\n      this.disconnect = null;\n    }\n  }\n\n  setRef = c => {\n    this.column = c;\n  }\n\n  handleLoadMore = maxId => {\n    this.props.dispatch(expandConversations({ maxId }));\n  }\n\n  render () {\n    const { intl, hasUnread, columnId, multiColumn, shouldUpdateScroll } = this.props;\n    const pinned = !!columnId;\n\n    return (\n      <Column ref={this.setRef} label={intl.formatMessage(messages.title)}>\n        <ColumnHeader\n          icon='envelope'\n          active={hasUnread}\n          title={intl.formatMessage(messages.title)}\n          onPin={this.handlePin}\n          onMove={this.handleMove}\n          onClick={this.handleHeaderClick}\n          pinned={pinned}\n          multiColumn={multiColumn}\n        />\n\n        <ConversationsListContainer\n          trackScroll={!pinned}\n          scrollKey={`direct_timeline-${columnId}`}\n          timelineId='direct'\n          onLoadMore={this.handleLoadMore}\n          emptyMessage={<FormattedMessage id='empty_column.direct' defaultMessage=\"You don't have any direct messages yet. When you send or receive one, it will show up here.\" />}\n          shouldUpdateScroll={shouldUpdateScroll}\n        />\n      </Column>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/domain_blocks/index.js",
    "content": "import React from 'react';\nimport { connect } from 'react-redux';\nimport { defineMessages, injectIntl, FormattedMessage } from 'react-intl';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport { debounce } from 'lodash';\nimport LoadingIndicator from '../../components/loading_indicator';\nimport Column from '../ui/components/column';\nimport ColumnBackButtonSlim from '../../components/column_back_button_slim';\nimport DomainContainer from '../../containers/domain_container';\nimport { fetchDomainBlocks, expandDomainBlocks } from '../../actions/domain_blocks';\nimport ScrollableList from '../../components/scrollable_list';\n\nconst messages = defineMessages({\n  heading: { id: 'column.domain_blocks', defaultMessage: 'Hidden domains' },\n  unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unhide {domain}' },\n});\n\nconst mapStateToProps = state => ({\n  domains: state.getIn(['domain_lists', 'blocks', 'items']),\n  hasMore: !!state.getIn(['domain_lists', 'blocks', 'next']),\n});\n\nexport default @connect(mapStateToProps)\n@injectIntl\nclass Blocks extends ImmutablePureComponent {\n\n  static propTypes = {\n    params: PropTypes.object.isRequired,\n    dispatch: PropTypes.func.isRequired,\n    shouldUpdateScroll: PropTypes.func,\n    hasMore: PropTypes.bool,\n    domains: ImmutablePropTypes.orderedSet,\n    intl: PropTypes.object.isRequired,\n  };\n\n  componentWillMount () {\n    this.props.dispatch(fetchDomainBlocks());\n  }\n\n  handleLoadMore = debounce(() => {\n    this.props.dispatch(expandDomainBlocks());\n  }, 300, { leading: true });\n\n  render () {\n    const { intl, domains, shouldUpdateScroll, hasMore } = this.props;\n\n    if (!domains) {\n      return (\n        <Column>\n          <LoadingIndicator />\n        </Column>\n      );\n    }\n\n    const emptyMessage = <FormattedMessage id='empty_column.domain_blocks' defaultMessage='There are no hidden domains yet.' />;\n\n    return (\n      <Column icon='minus-circle' heading={intl.formatMessage(messages.heading)}>\n        <ColumnBackButtonSlim />\n        <ScrollableList\n          scrollKey='domain_blocks'\n          onLoadMore={this.handleLoadMore}\n          hasMore={hasMore}\n          shouldUpdateScroll={shouldUpdateScroll}\n          emptyMessage={emptyMessage}\n        >\n          {domains.map(domain =>\n            <DomainContainer key={domain} domain={domain} />\n          )}\n        </ScrollableList>\n      </Column>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/emoji/__tests__/emoji-test.js",
    "content": "import emojify from '../emoji';\n\ndescribe('emoji', () => {\n  describe('.emojify', () => {\n    it('ignores unknown shortcodes', () => {\n      expect(emojify(':foobarbazfake:')).toEqual(':foobarbazfake:');\n    });\n\n    it('ignores shortcodes inside of tags', () => {\n      expect(emojify('<p data-foo=\":smile:\"></p>')).toEqual('<p data-foo=\":smile:\"></p>');\n    });\n\n    it('works with unclosed tags', () => {\n      expect(emojify('hello>')).toEqual('hello>');\n      expect(emojify('<hello')).toEqual('<hello');\n    });\n\n    it('works with unclosed shortcodes', () => {\n      expect(emojify('smile:')).toEqual('smile:');\n      expect(emojify(':smile')).toEqual(':smile');\n    });\n\n    it('does unicode', () => {\n      expect(emojify('\\uD83D\\uDC69\\u200D\\uD83D\\uDC69\\u200D\\uD83D\\uDC66\\u200D\\uD83D\\uDC66')).toEqual(\n        '<img draggable=\"false\" class=\"emojione\" alt=\"👩‍👩‍👦‍👦\" title=\":woman-woman-boy-boy:\" src=\"/emoji/1f469-200d-1f469-200d-1f466-200d-1f466.svg\" />');\n      expect(emojify('👨‍👩‍👧‍👧')).toEqual(\n        '<img draggable=\"false\" class=\"emojione\" alt=\"👨‍👩‍👧‍👧\" title=\":man-woman-girl-girl:\" src=\"/emoji/1f468-200d-1f469-200d-1f467-200d-1f467.svg\" />');\n      expect(emojify('👩‍👩‍👦')).toEqual('<img draggable=\"false\" class=\"emojione\" alt=\"👩‍👩‍👦\" title=\":woman-woman-boy:\" src=\"/emoji/1f469-200d-1f469-200d-1f466.svg\" />');\n      expect(emojify('\\u2757')).toEqual(\n        '<img draggable=\"false\" class=\"emojione\" alt=\"❗\" title=\":exclamation:\" src=\"/emoji/2757.svg\" />');\n    });\n\n    it('does multiple unicode', () => {\n      expect(emojify('\\u2757 #\\uFE0F\\u20E3')).toEqual(\n        '<img draggable=\"false\" class=\"emojione\" alt=\"❗\" title=\":exclamation:\" src=\"/emoji/2757.svg\" /> <img draggable=\"false\" class=\"emojione\" alt=\"#️⃣\" title=\":hash:\" src=\"/emoji/23-20e3.svg\" />');\n      expect(emojify('\\u2757#\\uFE0F\\u20E3')).toEqual(\n        '<img draggable=\"false\" class=\"emojione\" alt=\"❗\" title=\":exclamation:\" src=\"/emoji/2757.svg\" /><img draggable=\"false\" class=\"emojione\" alt=\"#️⃣\" title=\":hash:\" src=\"/emoji/23-20e3.svg\" />');\n      expect(emojify('\\u2757 #\\uFE0F\\u20E3 \\u2757')).toEqual(\n        '<img draggable=\"false\" class=\"emojione\" alt=\"❗\" title=\":exclamation:\" src=\"/emoji/2757.svg\" /> <img draggable=\"false\" class=\"emojione\" alt=\"#️⃣\" title=\":hash:\" src=\"/emoji/23-20e3.svg\" /> <img draggable=\"false\" class=\"emojione\" alt=\"❗\" title=\":exclamation:\" src=\"/emoji/2757.svg\" />');\n      expect(emojify('foo \\u2757 #\\uFE0F\\u20E3 bar')).toEqual(\n        'foo <img draggable=\"false\" class=\"emojione\" alt=\"❗\" title=\":exclamation:\" src=\"/emoji/2757.svg\" /> <img draggable=\"false\" class=\"emojione\" alt=\"#️⃣\" title=\":hash:\" src=\"/emoji/23-20e3.svg\" /> bar');\n    });\n\n    it('ignores unicode inside of tags', () => {\n      expect(emojify('<p data-foo=\"\\uD83D\\uDC69\\uD83D\\uDC69\\uD83D\\uDC66\"></p>')).toEqual('<p data-foo=\"\\uD83D\\uDC69\\uD83D\\uDC69\\uD83D\\uDC66\"></p>');\n    });\n\n    it('does multiple emoji properly (issue 5188)', () => {\n      expect(emojify('👌🌈💕')).toEqual('<img draggable=\"false\" class=\"emojione\" alt=\"👌\" title=\":ok_hand:\" src=\"/emoji/1f44c.svg\" /><img draggable=\"false\" class=\"emojione\" alt=\"🌈\" title=\":rainbow:\" src=\"/emoji/1f308.svg\" /><img draggable=\"false\" class=\"emojione\" alt=\"💕\" title=\":two_hearts:\" src=\"/emoji/1f495.svg\" />');\n      expect(emojify('👌 🌈 💕')).toEqual('<img draggable=\"false\" class=\"emojione\" alt=\"👌\" title=\":ok_hand:\" src=\"/emoji/1f44c.svg\" /> <img draggable=\"false\" class=\"emojione\" alt=\"🌈\" title=\":rainbow:\" src=\"/emoji/1f308.svg\" /> <img draggable=\"false\" class=\"emojione\" alt=\"💕\" title=\":two_hearts:\" src=\"/emoji/1f495.svg\" />');\n    });\n\n    it('does an emoji that has no shortcode', () => {\n      expect(emojify('👁‍🗨')).toEqual('<img draggable=\"false\" class=\"emojione\" alt=\"👁‍🗨\" title=\"\" src=\"/emoji/1f441-200d-1f5e8.svg\" />');\n    });\n\n    it('does an emoji whose filename is irregular', () => {\n      expect(emojify('↙️')).toEqual('<img draggable=\"false\" class=\"emojione\" alt=\"↙️\" title=\":arrow_lower_left:\" src=\"/emoji/2199.svg\" />');\n    });\n\n    it('avoid emojifying on invisible text', () => {\n      expect(emojify('<a href=\"http://example.com/test%F0%9F%98%84\"><span class=\"invisible\">http://</span><span class=\"ellipsis\">example.com/te</span><span class=\"invisible\">st😄</span></a>'))\n        .toEqual('<a href=\"http://example.com/test%F0%9F%98%84\"><span class=\"invisible\">http://</span><span class=\"ellipsis\">example.com/te</span><span class=\"invisible\">st😄</span></a>');\n      expect(emojify('<span class=\"invisible\">:luigi:</span>', { ':luigi:': { static_url: 'luigi.exe' } }))\n        .toEqual('<span class=\"invisible\">:luigi:</span>');\n    });\n\n    it('avoid emojifying on invisible text with nested tags', () => {\n      expect(emojify('<span class=\"invisible\">😄<span class=\"foo\">bar</span>😴</span>😇'))\n        .toEqual('<span class=\"invisible\">😄<span class=\"foo\">bar</span>😴</span><img draggable=\"false\" class=\"emojione\" alt=\"😇\" title=\":innocent:\" src=\"/emoji/1f607.svg\" />');\n      expect(emojify('<span class=\"invisible\">😄<span class=\"invisible\">😕</span>😴</span>😇'))\n        .toEqual('<span class=\"invisible\">😄<span class=\"invisible\">😕</span>😴</span><img draggable=\"false\" class=\"emojione\" alt=\"😇\" title=\":innocent:\" src=\"/emoji/1f607.svg\" />');\n      expect(emojify('<span class=\"invisible\">😄<br/>😴</span>😇'))\n        .toEqual('<span class=\"invisible\">😄<br/>😴</span><img draggable=\"false\" class=\"emojione\" alt=\"😇\" title=\":innocent:\" src=\"/emoji/1f607.svg\" />');\n    });\n\n    it('skips the textual presentation VS15 character', () => {\n      expect(emojify('✴︎')) // This is U+2734 EIGHT POINTED BLACK STAR then U+FE0E VARIATION SELECTOR-15\n        .toEqual('<img draggable=\"false\" class=\"emojione\" alt=\"✴\" title=\":eight_pointed_black_star:\" src=\"/emoji/2734.svg\" />');\n    });\n  });\n});\n"
  },
  {
    "path": "app/javascript/mastodon/features/emoji/__tests__/emoji_index-test.js",
    "content": "import { pick } from 'lodash';\nimport { emojiIndex } from 'emoji-mart';\nimport { search } from '../emoji_mart_search_light';\n\nconst trimEmojis = emoji => pick(emoji, ['id', 'unified', 'native', 'custom']);\n\ndescribe('emoji_index', () => {\n  it('should give same result for emoji_index_light and emoji-mart', () => {\n    const expected = [\n      {\n        id: 'pineapple',\n        unified: '1f34d',\n        native: '🍍',\n      },\n    ];\n    expect(search('pineapple').map(trimEmojis)).toEqual(expected);\n    expect(emojiIndex.search('pineapple').map(trimEmojis)).toEqual(expected);\n  });\n\n  it('orders search results correctly', () => {\n    const expected = [\n      {\n        id: 'apple',\n        unified: '1f34e',\n        native: '🍎',\n      },\n      {\n        id: 'pineapple',\n        unified: '1f34d',\n        native: '🍍',\n      },\n      {\n        id: 'green_apple',\n        unified: '1f34f',\n        native: '🍏',\n      },\n      {\n        id: 'iphone',\n        unified: '1f4f1',\n        native: '📱',\n      },\n    ];\n    expect(search('apple').map(trimEmojis)).toEqual(expected);\n    expect(emojiIndex.search('apple').map(trimEmojis)).toEqual(expected);\n  });\n\n  it('can include/exclude categories', () => {\n    expect(search('flag', { include: ['people'] })).toEqual([]);\n    expect(emojiIndex.search('flag', { include: ['people'] })).toEqual([]);\n  });\n\n  it('(different behavior from emoji-mart) do not erases custom emoji if not passed again', () => {\n    const custom = [\n      {\n        id: 'mastodon',\n        name: 'mastodon',\n        short_names: ['mastodon'],\n        text: '',\n        emoticons: [],\n        keywords: ['mastodon'],\n        imageUrl: 'http://example.com',\n        custom: true,\n      },\n    ];\n    search('', { custom });\n    emojiIndex.search('', { custom });\n    const expected = [];\n    const lightExpected = [\n      {\n        id: 'mastodon',\n        custom: true,\n      },\n    ];\n    expect(search('masto').map(trimEmojis)).toEqual(lightExpected);\n    expect(emojiIndex.search('masto').map(trimEmojis)).toEqual(expected);\n  });\n\n  it('(different behavior from emoji-mart) erases custom emoji if another is passed', () => {\n    const custom = [\n      {\n        id: 'mastodon',\n        name: 'mastodon',\n        short_names: ['mastodon'],\n        text: '',\n        emoticons: [],\n        keywords: ['mastodon'],\n        imageUrl: 'http://example.com',\n        custom: true,\n      },\n    ];\n    search('', { custom });\n    emojiIndex.search('', { custom });\n    const expected = [];\n    expect(search('masto', { custom: [] }).map(trimEmojis)).toEqual(expected);\n    expect(emojiIndex.search('masto').map(trimEmojis)).toEqual(expected);\n  });\n\n  it('handles custom emoji', () => {\n    const custom = [\n      {\n        id: 'mastodon',\n        name: 'mastodon',\n        short_names: ['mastodon'],\n        text: '',\n        emoticons: [],\n        keywords: ['mastodon'],\n        imageUrl: 'http://example.com',\n        custom: true,\n      },\n    ];\n    search('', { custom });\n    emojiIndex.search('', { custom });\n    const expected = [\n      {\n        id: 'mastodon',\n        custom: true,\n      },\n    ];\n    expect(search('masto', { custom }).map(trimEmojis)).toEqual(expected);\n    expect(emojiIndex.search('masto', { custom }).map(trimEmojis)).toEqual(expected);\n  });\n\n  it('should filter only emojis we care about, exclude pineapple', () => {\n    const emojisToShowFilter = emoji => emoji.unified !== '1F34D';\n    expect(search('apple', { emojisToShowFilter }).map((obj) => obj.id))\n      .not.toContain('pineapple');\n    expect(emojiIndex.search('apple', { emojisToShowFilter }).map((obj) => obj.id))\n      .not.toContain('pineapple');\n  });\n\n  it('does an emoji whose unified name is irregular', () => {\n    const expected = [\n      {\n        'id': 'water_polo',\n        'unified': '1f93d',\n        'native': '🤽',\n      },\n      {\n        'id': 'man-playing-water-polo',\n        'unified': '1f93d-200d-2642-fe0f',\n        'native': '🤽‍♂️',\n      },\n      {\n        'id': 'woman-playing-water-polo',\n        'unified': '1f93d-200d-2640-fe0f',\n        'native': '🤽‍♀️',\n      },\n    ];\n    expect(search('polo').map(trimEmojis)).toEqual(expected);\n    expect(emojiIndex.search('polo').map(trimEmojis)).toEqual(expected);\n  });\n\n  it('can search for thinking_face', () => {\n    const expected = [\n      {\n        id: 'thinking_face',\n        unified: '1f914',\n        native: '🤔',\n      },\n    ];\n    expect(search('thinking_fac').map(trimEmojis)).toEqual(expected);\n    expect(emojiIndex.search('thinking_fac').map(trimEmojis)).toEqual(expected);\n  });\n\n  it('can search for woman-facepalming', () => {\n    const expected = [\n      {\n        id: 'woman-facepalming',\n        unified: '1f926-200d-2640-fe0f',\n        native: '🤦‍♀️',\n      },\n    ];\n    expect(search('woman-facep').map(trimEmojis)).toEqual(expected);\n    expect(emojiIndex.search('woman-facep').map(trimEmojis)).toEqual(expected);\n  });\n});\n"
  },
  {
    "path": "app/javascript/mastodon/features/emoji/emoji.js",
    "content": "import { autoPlayGif } from '../../initial_state';\nimport unicodeMapping from './emoji_unicode_mapping_light';\nimport Trie from 'substring-trie';\n\nconst trie = new Trie(Object.keys(unicodeMapping));\n\nconst assetHost = process.env.CDN_HOST || '';\n\nconst emojify = (str, customEmojis = {}) => {\n  const tagCharsWithoutEmojis = '<&';\n  const tagCharsWithEmojis = Object.keys(customEmojis).length ? '<&:' : '<&';\n  let rtn = '', tagChars = tagCharsWithEmojis, invisible = 0;\n  for (;;) {\n    let match, i = 0, tag;\n    while (i < str.length && (tag = tagChars.indexOf(str[i])) === -1 && (invisible || !(match = trie.search(str.slice(i))))) {\n      i += str.codePointAt(i) < 65536 ? 1 : 2;\n    }\n    let rend, replacement = '';\n    if (i === str.length) {\n      break;\n    } else if (str[i] === ':') {\n      if (!(() => {\n        rend = str.indexOf(':', i + 1) + 1;\n        if (!rend) return false; // no pair of ':'\n        const lt = str.indexOf('<', i + 1);\n        if (!(lt === -1 || lt >= rend)) return false; // tag appeared before closing ':'\n        const shortname = str.slice(i, rend);\n        // now got a replacee as ':shortname:'\n        // if you want additional emoji handler, add statements below which set replacement and return true.\n        if (shortname in customEmojis) {\n          const filename = autoPlayGif ? customEmojis[shortname].url : customEmojis[shortname].static_url;\n          replacement = `<img draggable=\"false\" class=\"emojione\" alt=\"${shortname}\" title=\"${shortname}\" src=\"${filename}\" />`;\n          return true;\n        }\n        return false;\n      })()) rend = ++i;\n    } else if (tag >= 0) { // <, &\n      rend = str.indexOf('>;'[tag], i + 1) + 1;\n      if (!rend) {\n        break;\n      }\n      if (tag === 0) {\n        if (invisible) {\n          if (str[i + 1] === '/') { // closing tag\n            if (!--invisible) {\n              tagChars = tagCharsWithEmojis;\n            }\n          } else if (str[rend - 2] !== '/') { // opening tag\n            invisible++;\n          }\n        } else {\n          if (str.startsWith('<span class=\"invisible\">', i)) {\n            // avoid emojifying on invisible text\n            invisible = 1;\n            tagChars = tagCharsWithoutEmojis;\n          }\n        }\n      }\n      i = rend;\n    } else { // matched to unicode emoji\n      const { filename, shortCode } = unicodeMapping[match];\n      const title = shortCode ? `:${shortCode}:` : '';\n      replacement = `<img draggable=\"false\" class=\"emojione\" alt=\"${match}\" title=\"${title}\" src=\"${assetHost}/emoji/${filename}.svg\" />`;\n      rend = i + match.length;\n      // If the matched character was followed by VS15 (for selecting text presentation), skip it.\n      if (str.codePointAt(rend) === 65038) {\n        rend += 1;\n      }\n    }\n    rtn += str.slice(0, i) + replacement;\n    str = str.slice(rend);\n  }\n  return rtn + str;\n};\n\nexport default emojify;\n\nexport const buildCustomEmojis = (customEmojis) => {\n  const emojis = [];\n\n  customEmojis.forEach(emoji => {\n    const shortcode = emoji.get('shortcode');\n    const url       = autoPlayGif ? emoji.get('url') : emoji.get('static_url');\n    const name      = shortcode.replace(':', '');\n\n    emojis.push({\n      id: name,\n      name,\n      short_names: [name],\n      text: '',\n      emoticons: [],\n      keywords: [name],\n      imageUrl: url,\n      custom: true,\n    });\n  });\n\n  return emojis;\n};\n"
  },
  {
    "path": "app/javascript/mastodon/features/emoji/emoji_compressed.js",
    "content": "// @preval\n// http://www.unicode.org/Public/emoji/5.0/emoji-test.txt\n// This file contains the compressed version of the emoji data from\n// both emoji_map.json and from emoji-mart's emojiIndex and data objects.\n// It's designed to be emitted in an array format to take up less space\n// over the wire.\n\nconst { unicodeToFilename } = require('./unicode_to_filename');\nconst { unicodeToUnifiedName } = require('./unicode_to_unified_name');\nconst emojiMap         = require('./emoji_map.json');\nconst { emojiIndex } = require('emoji-mart');\nconst { uncompress: emojiMartUncompress } = require('emoji-mart/dist/utils/data');\nlet data = require('emoji-mart/data/all.json');\n\nif(data.compressed) {\n  data = emojiMartUncompress(data);\n}\nconst emojiMartData = data;\n\nconst excluded       = ['®', '©', '™'];\nconst skins          = ['🏻', '🏼', '🏽', '🏾', '🏿'];\nconst shortcodeMap   = {};\n\nconst shortCodesToEmojiData = {};\nconst emojisWithoutShortCodes = [];\n\nObject.keys(emojiIndex.emojis).forEach(key => {\n  shortcodeMap[emojiIndex.emojis[key].native] = emojiIndex.emojis[key].id;\n});\n\nconst stripModifiers = unicode => {\n  skins.forEach(tone => {\n    unicode = unicode.replace(tone, '');\n  });\n\n  return unicode;\n};\n\nObject.keys(emojiMap).forEach(key => {\n  if (excluded.includes(key)) {\n    delete emojiMap[key];\n    return;\n  }\n\n  const normalizedKey = stripModifiers(key);\n  let shortcode       = shortcodeMap[normalizedKey];\n\n  if (!shortcode) {\n    shortcode = shortcodeMap[normalizedKey + '\\uFE0F'];\n  }\n\n  const filename = emojiMap[key];\n\n  const filenameData = [key];\n\n  if (unicodeToFilename(key) !== filename) {\n    // filename can't be derived using unicodeToFilename\n    filenameData.push(filename);\n  }\n\n  if (typeof shortcode === 'undefined') {\n    emojisWithoutShortCodes.push(filenameData);\n  } else {\n    if (!Array.isArray(shortCodesToEmojiData[shortcode])) {\n      shortCodesToEmojiData[shortcode] = [[]];\n    }\n    shortCodesToEmojiData[shortcode][0].push(filenameData);\n  }\n});\n\nObject.keys(emojiIndex.emojis).forEach(key => {\n  const { native } = emojiIndex.emojis[key];\n  let { short_names, search, unified } = emojiMartData.emojis[key];\n  if (short_names[0] !== key) {\n    throw new Error('The compresser expects the first short_code to be the ' +\n      'key. It may need to be rewritten if the emoji change such that this ' +\n      'is no longer the case.');\n  }\n\n  short_names = short_names.slice(1); // first short name can be inferred from the key\n\n  const searchData = [native, short_names, search];\n  if (unicodeToUnifiedName(native) !== unified) {\n    // unified name can't be derived from unicodeToUnifiedName\n    searchData.push(unified);\n  }\n\n  shortCodesToEmojiData[key].push(searchData);\n});\n\n// JSON.parse/stringify is to emulate what @preval is doing and avoid any\n// inconsistent behavior in dev mode\nmodule.exports = JSON.parse(JSON.stringify([\n  shortCodesToEmojiData,\n  emojiMartData.skins,\n  emojiMartData.categories,\n  emojiMartData.aliases,\n  emojisWithoutShortCodes,\n]));\n"
  },
  {
    "path": "app/javascript/mastodon/features/emoji/emoji_map.json",
    "content": "{\"😀\":\"1f600\",\"😁\":\"1f601\",\"😂\":\"1f602\",\"🤣\":\"1f923\",\"😃\":\"1f603\",\"😄\":\"1f604\",\"😅\":\"1f605\",\"😆\":\"1f606\",\"😉\":\"1f609\",\"😊\":\"1f60a\",\"😋\":\"1f60b\",\"😎\":\"1f60e\",\"😍\":\"1f60d\",\"😘\":\"1f618\",\"🥰\":\"1f970\",\"😗\":\"1f617\",\"😙\":\"1f619\",\"😚\":\"1f61a\",\"☺\":\"263a\",\"🙂\":\"1f642\",\"🤗\":\"1f917\",\"🤩\":\"1f929\",\"🤔\":\"1f914\",\"🤨\":\"1f928\",\"😐\":\"1f610\",\"😑\":\"1f611\",\"😶\":\"1f636\",\"🙄\":\"1f644\",\"😏\":\"1f60f\",\"😣\":\"1f623\",\"😥\":\"1f625\",\"😮\":\"1f62e\",\"🤐\":\"1f910\",\"😯\":\"1f62f\",\"😪\":\"1f62a\",\"😫\":\"1f62b\",\"😴\":\"1f634\",\"😌\":\"1f60c\",\"😛\":\"1f61b\",\"😜\":\"1f61c\",\"😝\":\"1f61d\",\"🤤\":\"1f924\",\"😒\":\"1f612\",\"😓\":\"1f613\",\"😔\":\"1f614\",\"😕\":\"1f615\",\"🙃\":\"1f643\",\"🤑\":\"1f911\",\"😲\":\"1f632\",\"☹\":\"2639\",\"🙁\":\"1f641\",\"😖\":\"1f616\",\"😞\":\"1f61e\",\"😟\":\"1f61f\",\"😤\":\"1f624\",\"😢\":\"1f622\",\"😭\":\"1f62d\",\"😦\":\"1f626\",\"😧\":\"1f627\",\"😨\":\"1f628\",\"😩\":\"1f629\",\"🤯\":\"1f92f\",\"😬\":\"1f62c\",\"😰\":\"1f630\",\"😱\":\"1f631\",\"🥵\":\"1f975\",\"🥶\":\"1f976\",\"😳\":\"1f633\",\"🤪\":\"1f92a\",\"😵\":\"1f635\",\"😡\":\"1f621\",\"😠\":\"1f620\",\"🤬\":\"1f92c\",\"😷\":\"1f637\",\"🤒\":\"1f912\",\"🤕\":\"1f915\",\"🤢\":\"1f922\",\"🤮\":\"1f92e\",\"🤧\":\"1f927\",\"😇\":\"1f607\",\"🤠\":\"1f920\",\"🥳\":\"1f973\",\"🥴\":\"1f974\",\"🥺\":\"1f97a\",\"🤥\":\"1f925\",\"🤫\":\"1f92b\",\"🤭\":\"1f92d\",\"🧐\":\"1f9d0\",\"🤓\":\"1f913\",\"😈\":\"1f608\",\"👿\":\"1f47f\",\"🤡\":\"1f921\",\"👹\":\"1f479\",\"👺\":\"1f47a\",\"💀\":\"1f480\",\"☠\":\"2620\",\"👻\":\"1f47b\",\"👽\":\"1f47d\",\"👾\":\"1f47e\",\"🤖\":\"1f916\",\"💩\":\"1f4a9\",\"😺\":\"1f63a\",\"😸\":\"1f638\",\"😹\":\"1f639\",\"😻\":\"1f63b\",\"😼\":\"1f63c\",\"😽\":\"1f63d\",\"🙀\":\"1f640\",\"😿\":\"1f63f\",\"😾\":\"1f63e\",\"🙈\":\"1f648\",\"🙉\":\"1f649\",\"🙊\":\"1f64a\",\"🏻\":\"1f3fb\",\"🏼\":\"1f3fc\",\"🏽\":\"1f3fd\",\"🏾\":\"1f3fe\",\"🏿\":\"1f3ff\",\"👶\":\"1f476\",\"🧒\":\"1f9d2\",\"👦\":\"1f466\",\"👧\":\"1f467\",\"🧑\":\"1f9d1\",\"👨\":\"1f468\",\"👩\":\"1f469\",\"🧓\":\"1f9d3\",\"👴\":\"1f474\",\"👵\":\"1f475\",\"👮\":\"1f46e\",\"🕵\":\"1f575\",\"💂\":\"1f482\",\"👷\":\"1f477\",\"🤴\":\"1f934\",\"👸\":\"1f478\",\"👳\":\"1f473\",\"👲\":\"1f472\",\"🧕\":\"1f9d5\",\"🧔\":\"1f9d4\",\"👱\":\"1f471\",\"🤵\":\"1f935\",\"👰\":\"1f470\",\"🤰\":\"1f930\",\"🤱\":\"1f931\",\"👼\":\"1f47c\",\"🎅\":\"1f385\",\"🤶\":\"1f936\",\"🦸\":\"1f9b8\",\"🦹\":\"1f9b9\",\"🧙\":\"1f9d9\",\"🧚\":\"1f9da\",\"🧛\":\"1f9db\",\"🧜\":\"1f9dc\",\"🧝\":\"1f9dd\",\"🧞\":\"1f9de\",\"🧟\":\"1f9df\",\"🙍\":\"1f64d\",\"🙎\":\"1f64e\",\"🙅\":\"1f645\",\"🙆\":\"1f646\",\"💁\":\"1f481\",\"🙋\":\"1f64b\",\"🙇\":\"1f647\",\"🤦\":\"1f926\",\"🤷\":\"1f937\",\"💆\":\"1f486\",\"💇\":\"1f487\",\"🚶\":\"1f6b6\",\"🏃\":\"1f3c3\",\"💃\":\"1f483\",\"🕺\":\"1f57a\",\"👯\":\"1f46f\",\"🧖\":\"1f9d6\",\"🧗\":\"1f9d7\",\"🧘\":\"1f9d8\",\"🛀\":\"1f6c0\",\"🛌\":\"1f6cc\",\"🕴\":\"1f574\",\"🗣\":\"1f5e3\",\"👤\":\"1f464\",\"👥\":\"1f465\",\"🤺\":\"1f93a\",\"🏇\":\"1f3c7\",\"⛷\":\"26f7\",\"🏂\":\"1f3c2\",\"🏌\":\"1f3cc\",\"🏄\":\"1f3c4\",\"🚣\":\"1f6a3\",\"🏊\":\"1f3ca\",\"⛹\":\"26f9\",\"🏋\":\"1f3cb\",\"🚴\":\"1f6b4\",\"🚵\":\"1f6b5\",\"🏎\":\"1f3ce\",\"🏍\":\"1f3cd\",\"🤸\":\"1f938\",\"🤼\":\"1f93c\",\"🤽\":\"1f93d\",\"🤾\":\"1f93e\",\"🤹\":\"1f939\",\"👫\":\"1f46b\",\"👬\":\"1f46c\",\"👭\":\"1f46d\",\"💏\":\"1f48f\",\"💑\":\"1f491\",\"👪\":\"1f46a\",\"🤳\":\"1f933\",\"💪\":\"1f4aa\",\"🦵\":\"1f9b5\",\"🦶\":\"1f9b6\",\"👈\":\"1f448\",\"👉\":\"1f449\",\"☝\":\"261d\",\"👆\":\"1f446\",\"🖕\":\"1f595\",\"👇\":\"1f447\",\"✌\":\"270c\",\"🤞\":\"1f91e\",\"🖖\":\"1f596\",\"🤘\":\"1f918\",\"🤙\":\"1f919\",\"🖐\":\"1f590\",\"✋\":\"270b\",\"👌\":\"1f44c\",\"👍\":\"1f44d\",\"👎\":\"1f44e\",\"✊\":\"270a\",\"👊\":\"1f44a\",\"🤛\":\"1f91b\",\"🤜\":\"1f91c\",\"🤚\":\"1f91a\",\"👋\":\"1f44b\",\"🤟\":\"1f91f\",\"✍\":\"270d\",\"👏\":\"1f44f\",\"👐\":\"1f450\",\"🙌\":\"1f64c\",\"🤲\":\"1f932\",\"🙏\":\"1f64f\",\"🤝\":\"1f91d\",\"💅\":\"1f485\",\"👂\":\"1f442\",\"👃\":\"1f443\",\"👣\":\"1f463\",\"👀\":\"1f440\",\"👁\":\"1f441\",\"🧠\":\"1f9e0\",\"🦴\":\"1f9b4\",\"🦷\":\"1f9b7\",\"👅\":\"1f445\",\"👄\":\"1f444\",\"💋\":\"1f48b\",\"💘\":\"1f498\",\"❤\":\"2764\",\"💓\":\"1f493\",\"💔\":\"1f494\",\"💕\":\"1f495\",\"💖\":\"1f496\",\"💗\":\"1f497\",\"💙\":\"1f499\",\"💚\":\"1f49a\",\"💛\":\"1f49b\",\"🧡\":\"1f9e1\",\"💜\":\"1f49c\",\"🖤\":\"1f5a4\",\"💝\":\"1f49d\",\"💞\":\"1f49e\",\"💟\":\"1f49f\",\"❣\":\"2763\",\"💌\":\"1f48c\",\"💤\":\"1f4a4\",\"💢\":\"1f4a2\",\"💣\":\"1f4a3\",\"💥\":\"1f4a5\",\"💦\":\"1f4a6\",\"💨\":\"1f4a8\",\"💫\":\"1f4ab\",\"💬\":\"1f4ac\",\"🗨\":\"1f5e8\",\"🗯\":\"1f5ef\",\"💭\":\"1f4ad\",\"🕳\":\"1f573\",\"👓\":\"1f453\",\"🕶\":\"1f576\",\"🥽\":\"1f97d\",\"🥼\":\"1f97c\",\"👔\":\"1f454\",\"👕\":\"1f455\",\"👖\":\"1f456\",\"🧣\":\"1f9e3\",\"🧤\":\"1f9e4\",\"🧥\":\"1f9e5\",\"🧦\":\"1f9e6\",\"👗\":\"1f457\",\"👘\":\"1f458\",\"👙\":\"1f459\",\"👚\":\"1f45a\",\"👛\":\"1f45b\",\"👜\":\"1f45c\",\"👝\":\"1f45d\",\"🛍\":\"1f6cd\",\"🎒\":\"1f392\",\"👞\":\"1f45e\",\"👟\":\"1f45f\",\"🥾\":\"1f97e\",\"🥿\":\"1f97f\",\"👠\":\"1f460\",\"👡\":\"1f461\",\"👢\":\"1f462\",\"👑\":\"1f451\",\"👒\":\"1f452\",\"🎩\":\"1f3a9\",\"🎓\":\"1f393\",\"🧢\":\"1f9e2\",\"⛑\":\"26d1\",\"📿\":\"1f4ff\",\"💄\":\"1f484\",\"💍\":\"1f48d\",\"💎\":\"1f48e\",\"🐵\":\"1f435\",\"🐒\":\"1f412\",\"🦍\":\"1f98d\",\"🐶\":\"1f436\",\"🐕\":\"1f415\",\"🐩\":\"1f429\",\"🐺\":\"1f43a\",\"🦊\":\"1f98a\",\"🦝\":\"1f99d\",\"🐱\":\"1f431\",\"🐈\":\"1f408\",\"🦁\":\"1f981\",\"🐯\":\"1f42f\",\"🐅\":\"1f405\",\"🐆\":\"1f406\",\"🐴\":\"1f434\",\"🐎\":\"1f40e\",\"🦄\":\"1f984\",\"🦓\":\"1f993\",\"🦌\":\"1f98c\",\"🐮\":\"1f42e\",\"🐂\":\"1f402\",\"🐃\":\"1f403\",\"🐄\":\"1f404\",\"🐷\":\"1f437\",\"🐖\":\"1f416\",\"🐗\":\"1f417\",\"🐽\":\"1f43d\",\"🐏\":\"1f40f\",\"🐑\":\"1f411\",\"🐐\":\"1f410\",\"🐪\":\"1f42a\",\"🐫\":\"1f42b\",\"🦙\":\"1f999\",\"🦒\":\"1f992\",\"🐘\":\"1f418\",\"🦏\":\"1f98f\",\"🦛\":\"1f99b\",\"🐭\":\"1f42d\",\"🐁\":\"1f401\",\"🐀\":\"1f400\",\"🐹\":\"1f439\",\"🐰\":\"1f430\",\"🐇\":\"1f407\",\"🐿\":\"1f43f\",\"🦔\":\"1f994\",\"🦇\":\"1f987\",\"🐻\":\"1f43b\",\"🐨\":\"1f428\",\"🐼\":\"1f43c\",\"🦘\":\"1f998\",\"🦡\":\"1f9a1\",\"🐾\":\"1f43e\",\"🦃\":\"1f983\",\"🐔\":\"1f414\",\"🐓\":\"1f413\",\"🐣\":\"1f423\",\"🐤\":\"1f424\",\"🐥\":\"1f425\",\"🐦\":\"1f426\",\"🐧\":\"1f427\",\"🕊\":\"1f54a\",\"🦅\":\"1f985\",\"🦆\":\"1f986\",\"🦢\":\"1f9a2\",\"🦉\":\"1f989\",\"🦚\":\"1f99a\",\"🦜\":\"1f99c\",\"🐸\":\"1f438\",\"🐊\":\"1f40a\",\"🐢\":\"1f422\",\"🦎\":\"1f98e\",\"🐍\":\"1f40d\",\"🐲\":\"1f432\",\"🐉\":\"1f409\",\"🦕\":\"1f995\",\"🦖\":\"1f996\",\"🐳\":\"1f433\",\"🐋\":\"1f40b\",\"🐬\":\"1f42c\",\"🐟\":\"1f41f\",\"🐠\":\"1f420\",\"🐡\":\"1f421\",\"🦈\":\"1f988\",\"🐙\":\"1f419\",\"🐚\":\"1f41a\",\"🦀\":\"1f980\",\"🦞\":\"1f99e\",\"🦐\":\"1f990\",\"🦑\":\"1f991\",\"🐌\":\"1f40c\",\"🦋\":\"1f98b\",\"🐛\":\"1f41b\",\"🐜\":\"1f41c\",\"🐝\":\"1f41d\",\"🐞\":\"1f41e\",\"🦗\":\"1f997\",\"🕷\":\"1f577\",\"🕸\":\"1f578\",\"🦂\":\"1f982\",\"🦟\":\"1f99f\",\"🦠\":\"1f9a0\",\"💐\":\"1f490\",\"🌸\":\"1f338\",\"💮\":\"1f4ae\",\"🏵\":\"1f3f5\",\"🌹\":\"1f339\",\"🥀\":\"1f940\",\"🌺\":\"1f33a\",\"🌻\":\"1f33b\",\"🌼\":\"1f33c\",\"🌷\":\"1f337\",\"🌱\":\"1f331\",\"🌲\":\"1f332\",\"🌳\":\"1f333\",\"🌴\":\"1f334\",\"🌵\":\"1f335\",\"🌾\":\"1f33e\",\"🌿\":\"1f33f\",\"☘\":\"2618\",\"🍀\":\"1f340\",\"🍁\":\"1f341\",\"🍂\":\"1f342\",\"🍃\":\"1f343\",\"🍇\":\"1f347\",\"🍈\":\"1f348\",\"🍉\":\"1f349\",\"🍊\":\"1f34a\",\"🍋\":\"1f34b\",\"🍌\":\"1f34c\",\"🍍\":\"1f34d\",\"🥭\":\"1f96d\",\"🍎\":\"1f34e\",\"🍏\":\"1f34f\",\"🍐\":\"1f350\",\"🍑\":\"1f351\",\"🍒\":\"1f352\",\"🍓\":\"1f353\",\"🥝\":\"1f95d\",\"🍅\":\"1f345\",\"🥥\":\"1f965\",\"🥑\":\"1f951\",\"🍆\":\"1f346\",\"🥔\":\"1f954\",\"🥕\":\"1f955\",\"🌽\":\"1f33d\",\"🌶\":\"1f336\",\"🥒\":\"1f952\",\"🥬\":\"1f96c\",\"🥦\":\"1f966\",\"🍄\":\"1f344\",\"🥜\":\"1f95c\",\"🌰\":\"1f330\",\"🍞\":\"1f35e\",\"🥐\":\"1f950\",\"🥖\":\"1f956\",\"🥨\":\"1f968\",\"🥯\":\"1f96f\",\"🥞\":\"1f95e\",\"🧀\":\"1f9c0\",\"🍖\":\"1f356\",\"🍗\":\"1f357\",\"🥩\":\"1f969\",\"🥓\":\"1f953\",\"🍔\":\"1f354\",\"🍟\":\"1f35f\",\"🍕\":\"1f355\",\"🌭\":\"1f32d\",\"🥪\":\"1f96a\",\"🌮\":\"1f32e\",\"🌯\":\"1f32f\",\"🥙\":\"1f959\",\"🥚\":\"1f95a\",\"🍳\":\"1f373\",\"🥘\":\"1f958\",\"🍲\":\"1f372\",\"🥣\":\"1f963\",\"🥗\":\"1f957\",\"🍿\":\"1f37f\",\"🧂\":\"1f9c2\",\"🥫\":\"1f96b\",\"🍱\":\"1f371\",\"🍘\":\"1f358\",\"🍙\":\"1f359\",\"🍚\":\"1f35a\",\"🍛\":\"1f35b\",\"🍜\":\"1f35c\",\"🍝\":\"1f35d\",\"🍠\":\"1f360\",\"🍢\":\"1f362\",\"🍣\":\"1f363\",\"🍤\":\"1f364\",\"🍥\":\"1f365\",\"🥮\":\"1f96e\",\"🍡\":\"1f361\",\"🥟\":\"1f95f\",\"🥠\":\"1f960\",\"🥡\":\"1f961\",\"🍦\":\"1f366\",\"🍧\":\"1f367\",\"🍨\":\"1f368\",\"🍩\":\"1f369\",\"🍪\":\"1f36a\",\"🎂\":\"1f382\",\"🍰\":\"1f370\",\"🧁\":\"1f9c1\",\"🥧\":\"1f967\",\"🍫\":\"1f36b\",\"🍬\":\"1f36c\",\"🍭\":\"1f36d\",\"🍮\":\"1f36e\",\"🍯\":\"1f36f\",\"🍼\":\"1f37c\",\"🥛\":\"1f95b\",\"☕\":\"2615\",\"🍵\":\"1f375\",\"🍶\":\"1f376\",\"🍾\":\"1f37e\",\"🍷\":\"1f377\",\"🍸\":\"1f378\",\"🍹\":\"1f379\",\"🍺\":\"1f37a\",\"🍻\":\"1f37b\",\"🥂\":\"1f942\",\"🥃\":\"1f943\",\"🥤\":\"1f964\",\"🥢\":\"1f962\",\"🍽\":\"1f37d\",\"🍴\":\"1f374\",\"🥄\":\"1f944\",\"🔪\":\"1f52a\",\"🏺\":\"1f3fa\",\"🌍\":\"1f30d\",\"🌎\":\"1f30e\",\"🌏\":\"1f30f\",\"🌐\":\"1f310\",\"🗺\":\"1f5fa\",\"🗾\":\"1f5fe\",\"🧭\":\"1f9ed\",\"🏔\":\"1f3d4\",\"⛰\":\"26f0\",\"🌋\":\"1f30b\",\"🗻\":\"1f5fb\",\"🏕\":\"1f3d5\",\"🏖\":\"1f3d6\",\"🏜\":\"1f3dc\",\"🏝\":\"1f3dd\",\"🏞\":\"1f3de\",\"🏟\":\"1f3df\",\"🏛\":\"1f3db\",\"🏗\":\"1f3d7\",\"🧱\":\"1f9f1\",\"🏘\":\"1f3d8\",\"🏚\":\"1f3da\",\"🏠\":\"1f3e0\",\"🏡\":\"1f3e1\",\"🏢\":\"1f3e2\",\"🏣\":\"1f3e3\",\"🏤\":\"1f3e4\",\"🏥\":\"1f3e5\",\"🏦\":\"1f3e6\",\"🏨\":\"1f3e8\",\"🏩\":\"1f3e9\",\"🏪\":\"1f3ea\",\"🏫\":\"1f3eb\",\"🏬\":\"1f3ec\",\"🏭\":\"1f3ed\",\"🏯\":\"1f3ef\",\"🏰\":\"1f3f0\",\"💒\":\"1f492\",\"🗼\":\"1f5fc\",\"🗽\":\"1f5fd\",\"⛪\":\"26ea\",\"🕌\":\"1f54c\",\"🕍\":\"1f54d\",\"⛩\":\"26e9\",\"🕋\":\"1f54b\",\"⛲\":\"26f2\",\"⛺\":\"26fa\",\"🌁\":\"1f301\",\"🌃\":\"1f303\",\"🏙\":\"1f3d9\",\"🌄\":\"1f304\",\"🌅\":\"1f305\",\"🌆\":\"1f306\",\"🌇\":\"1f307\",\"🌉\":\"1f309\",\"♨\":\"2668\",\"🌌\":\"1f30c\",\"🎠\":\"1f3a0\",\"🎡\":\"1f3a1\",\"🎢\":\"1f3a2\",\"💈\":\"1f488\",\"🎪\":\"1f3aa\",\"🚂\":\"1f682\",\"🚃\":\"1f683\",\"🚄\":\"1f684\",\"🚅\":\"1f685\",\"🚆\":\"1f686\",\"🚇\":\"1f687\",\"🚈\":\"1f688\",\"🚉\":\"1f689\",\"🚊\":\"1f68a\",\"🚝\":\"1f69d\",\"🚞\":\"1f69e\",\"🚋\":\"1f68b\",\"🚌\":\"1f68c\",\"🚍\":\"1f68d\",\"🚎\":\"1f68e\",\"🚐\":\"1f690\",\"🚑\":\"1f691\",\"🚒\":\"1f692\",\"🚓\":\"1f693\",\"🚔\":\"1f694\",\"🚕\":\"1f695\",\"🚖\":\"1f696\",\"🚗\":\"1f697\",\"🚘\":\"1f698\",\"🚙\":\"1f699\",\"🚚\":\"1f69a\",\"🚛\":\"1f69b\",\"🚜\":\"1f69c\",\"🚲\":\"1f6b2\",\"🛴\":\"1f6f4\",\"🛹\":\"1f6f9\",\"🛵\":\"1f6f5\",\"🚏\":\"1f68f\",\"🛣\":\"1f6e3\",\"🛤\":\"1f6e4\",\"🛢\":\"1f6e2\",\"⛽\":\"26fd\",\"🚨\":\"1f6a8\",\"🚥\":\"1f6a5\",\"🚦\":\"1f6a6\",\"🛑\":\"1f6d1\",\"🚧\":\"1f6a7\",\"⚓\":\"2693\",\"⛵\":\"26f5\",\"🛶\":\"1f6f6\",\"🚤\":\"1f6a4\",\"🛳\":\"1f6f3\",\"⛴\":\"26f4\",\"🛥\":\"1f6e5\",\"🚢\":\"1f6a2\",\"✈\":\"2708\",\"🛩\":\"1f6e9\",\"🛫\":\"1f6eb\",\"🛬\":\"1f6ec\",\"💺\":\"1f4ba\",\"🚁\":\"1f681\",\"🚟\":\"1f69f\",\"🚠\":\"1f6a0\",\"🚡\":\"1f6a1\",\"🛰\":\"1f6f0\",\"🚀\":\"1f680\",\"🛸\":\"1f6f8\",\"🛎\":\"1f6ce\",\"🧳\":\"1f9f3\",\"⌛\":\"231b\",\"⏳\":\"23f3\",\"⌚\":\"231a\",\"⏰\":\"23f0\",\"⏱\":\"23f1\",\"⏲\":\"23f2\",\"🕰\":\"1f570\",\"🕛\":\"1f55b\",\"🕧\":\"1f567\",\"🕐\":\"1f550\",\"🕜\":\"1f55c\",\"🕑\":\"1f551\",\"🕝\":\"1f55d\",\"🕒\":\"1f552\",\"🕞\":\"1f55e\",\"🕓\":\"1f553\",\"🕟\":\"1f55f\",\"🕔\":\"1f554\",\"🕠\":\"1f560\",\"🕕\":\"1f555\",\"🕡\":\"1f561\",\"🕖\":\"1f556\",\"🕢\":\"1f562\",\"🕗\":\"1f557\",\"🕣\":\"1f563\",\"🕘\":\"1f558\",\"🕤\":\"1f564\",\"🕙\":\"1f559\",\"🕥\":\"1f565\",\"🕚\":\"1f55a\",\"🕦\":\"1f566\",\"🌑\":\"1f311\",\"🌒\":\"1f312\",\"🌓\":\"1f313\",\"🌔\":\"1f314\",\"🌕\":\"1f315\",\"🌖\":\"1f316\",\"🌗\":\"1f317\",\"🌘\":\"1f318\",\"🌙\":\"1f319\",\"🌚\":\"1f31a\",\"🌛\":\"1f31b\",\"🌜\":\"1f31c\",\"🌡\":\"1f321\",\"☀\":\"2600\",\"🌝\":\"1f31d\",\"🌞\":\"1f31e\",\"⭐\":\"2b50\",\"🌟\":\"1f31f\",\"🌠\":\"1f320\",\"☁\":\"2601\",\"⛅\":\"26c5\",\"⛈\":\"26c8\",\"🌤\":\"1f324\",\"🌥\":\"1f325\",\"🌦\":\"1f326\",\"🌧\":\"1f327\",\"🌨\":\"1f328\",\"🌩\":\"1f329\",\"🌪\":\"1f32a\",\"🌫\":\"1f32b\",\"🌬\":\"1f32c\",\"🌀\":\"1f300\",\"🌈\":\"1f308\",\"🌂\":\"1f302\",\"☂\":\"2602\",\"☔\":\"2614\",\"⛱\":\"26f1\",\"⚡\":\"26a1\",\"❄\":\"2744\",\"☃\":\"2603\",\"⛄\":\"26c4\",\"☄\":\"2604\",\"🔥\":\"1f525\",\"💧\":\"1f4a7\",\"🌊\":\"1f30a\",\"🎃\":\"1f383\",\"🎄\":\"1f384\",\"🎆\":\"1f386\",\"🎇\":\"1f387\",\"🧨\":\"1f9e8\",\"✨\":\"2728\",\"🎈\":\"1f388\",\"🎉\":\"1f389\",\"🎊\":\"1f38a\",\"🎋\":\"1f38b\",\"🎍\":\"1f38d\",\"🎎\":\"1f38e\",\"🎏\":\"1f38f\",\"🎐\":\"1f390\",\"🎑\":\"1f391\",\"🧧\":\"1f9e7\",\"🎀\":\"1f380\",\"🎁\":\"1f381\",\"🎗\":\"1f397\",\"🎟\":\"1f39f\",\"🎫\":\"1f3ab\",\"🎖\":\"1f396\",\"🏆\":\"1f3c6\",\"🏅\":\"1f3c5\",\"🥇\":\"1f947\",\"🥈\":\"1f948\",\"🥉\":\"1f949\",\"⚽\":\"26bd\",\"⚾\":\"26be\",\"🥎\":\"1f94e\",\"🏀\":\"1f3c0\",\"🏐\":\"1f3d0\",\"🏈\":\"1f3c8\",\"🏉\":\"1f3c9\",\"🎾\":\"1f3be\",\"🥏\":\"1f94f\",\"🎳\":\"1f3b3\",\"🏏\":\"1f3cf\",\"🏑\":\"1f3d1\",\"🏒\":\"1f3d2\",\"🥍\":\"1f94d\",\"🏓\":\"1f3d3\",\"🏸\":\"1f3f8\",\"🥊\":\"1f94a\",\"🥋\":\"1f94b\",\"🥅\":\"1f945\",\"⛳\":\"26f3\",\"⛸\":\"26f8\",\"🎣\":\"1f3a3\",\"🎽\":\"1f3bd\",\"🎿\":\"1f3bf\",\"🛷\":\"1f6f7\",\"🥌\":\"1f94c\",\"🎯\":\"1f3af\",\"🎱\":\"1f3b1\",\"🔮\":\"1f52e\",\"🧿\":\"1f9ff\",\"🎮\":\"1f3ae\",\"🕹\":\"1f579\",\"🎰\":\"1f3b0\",\"🎲\":\"1f3b2\",\"🧩\":\"1f9e9\",\"🧸\":\"1f9f8\",\"♠\":\"2660\",\"♥\":\"2665\",\"♦\":\"2666\",\"♣\":\"2663\",\"♟\":\"265f\",\"🃏\":\"1f0cf\",\"🀄\":\"1f004\",\"🎴\":\"1f3b4\",\"🎭\":\"1f3ad\",\"🖼\":\"1f5bc\",\"🎨\":\"1f3a8\",\"🧵\":\"1f9f5\",\"🧶\":\"1f9f6\",\"🔇\":\"1f507\",\"🔈\":\"1f508\",\"🔉\":\"1f509\",\"🔊\":\"1f50a\",\"📢\":\"1f4e2\",\"📣\":\"1f4e3\",\"📯\":\"1f4ef\",\"🔔\":\"1f514\",\"🔕\":\"1f515\",\"🎼\":\"1f3bc\",\"🎵\":\"1f3b5\",\"🎶\":\"1f3b6\",\"🎙\":\"1f399\",\"🎚\":\"1f39a\",\"🎛\":\"1f39b\",\"🎤\":\"1f3a4\",\"🎧\":\"1f3a7\",\"📻\":\"1f4fb\",\"🎷\":\"1f3b7\",\"🎸\":\"1f3b8\",\"🎹\":\"1f3b9\",\"🎺\":\"1f3ba\",\"🎻\":\"1f3bb\",\"🥁\":\"1f941\",\"📱\":\"1f4f1\",\"📲\":\"1f4f2\",\"☎\":\"260e\",\"📞\":\"1f4de\",\"📟\":\"1f4df\",\"📠\":\"1f4e0\",\"🔋\":\"1f50b\",\"🔌\":\"1f50c\",\"💻\":\"1f4bb\",\"🖥\":\"1f5a5\",\"🖨\":\"1f5a8\",\"⌨\":\"2328\",\"🖱\":\"1f5b1\",\"🖲\":\"1f5b2\",\"💽\":\"1f4bd\",\"💾\":\"1f4be\",\"💿\":\"1f4bf\",\"📀\":\"1f4c0\",\"🧮\":\"1f9ee\",\"🎥\":\"1f3a5\",\"🎞\":\"1f39e\",\"📽\":\"1f4fd\",\"🎬\":\"1f3ac\",\"📺\":\"1f4fa\",\"📷\":\"1f4f7\",\"📸\":\"1f4f8\",\"📹\":\"1f4f9\",\"📼\":\"1f4fc\",\"🔍\":\"1f50d\",\"🔎\":\"1f50e\",\"🕯\":\"1f56f\",\"💡\":\"1f4a1\",\"🔦\":\"1f526\",\"🏮\":\"1f3ee\",\"📔\":\"1f4d4\",\"📕\":\"1f4d5\",\"📖\":\"1f4d6\",\"📗\":\"1f4d7\",\"📘\":\"1f4d8\",\"📙\":\"1f4d9\",\"📚\":\"1f4da\",\"📓\":\"1f4d3\",\"📒\":\"1f4d2\",\"📃\":\"1f4c3\",\"📜\":\"1f4dc\",\"📄\":\"1f4c4\",\"📰\":\"1f4f0\",\"🗞\":\"1f5de\",\"📑\":\"1f4d1\",\"🔖\":\"1f516\",\"🏷\":\"1f3f7\",\"💰\":\"1f4b0\",\"💴\":\"1f4b4\",\"💵\":\"1f4b5\",\"💶\":\"1f4b6\",\"💷\":\"1f4b7\",\"💸\":\"1f4b8\",\"💳\":\"1f4b3\",\"🧾\":\"1f9fe\",\"💹\":\"1f4b9\",\"💱\":\"1f4b1\",\"💲\":\"1f4b2\",\"✉\":\"2709\",\"📧\":\"1f4e7\",\"📨\":\"1f4e8\",\"📩\":\"1f4e9\",\"📤\":\"1f4e4\",\"📥\":\"1f4e5\",\"📦\":\"1f4e6\",\"📫\":\"1f4eb\",\"📪\":\"1f4ea\",\"📬\":\"1f4ec\",\"📭\":\"1f4ed\",\"📮\":\"1f4ee\",\"🗳\":\"1f5f3\",\"✏\":\"270f\",\"✒\":\"2712\",\"🖋\":\"1f58b\",\"🖊\":\"1f58a\",\"🖌\":\"1f58c\",\"🖍\":\"1f58d\",\"📝\":\"1f4dd\",\"💼\":\"1f4bc\",\"📁\":\"1f4c1\",\"📂\":\"1f4c2\",\"🗂\":\"1f5c2\",\"📅\":\"1f4c5\",\"📆\":\"1f4c6\",\"🗒\":\"1f5d2\",\"🗓\":\"1f5d3\",\"📇\":\"1f4c7\",\"📈\":\"1f4c8\",\"📉\":\"1f4c9\",\"📊\":\"1f4ca\",\"📋\":\"1f4cb\",\"📌\":\"1f4cc\",\"📍\":\"1f4cd\",\"📎\":\"1f4ce\",\"🖇\":\"1f587\",\"📏\":\"1f4cf\",\"📐\":\"1f4d0\",\"✂\":\"2702\",\"🗃\":\"1f5c3\",\"🗄\":\"1f5c4\",\"🗑\":\"1f5d1\",\"🔒\":\"1f512\",\"🔓\":\"1f513\",\"🔏\":\"1f50f\",\"🔐\":\"1f510\",\"🔑\":\"1f511\",\"🗝\":\"1f5dd\",\"🔨\":\"1f528\",\"⛏\":\"26cf\",\"⚒\":\"2692\",\"🛠\":\"1f6e0\",\"🗡\":\"1f5e1\",\"⚔\":\"2694\",\"🔫\":\"1f52b\",\"🏹\":\"1f3f9\",\"🛡\":\"1f6e1\",\"🔧\":\"1f527\",\"🔩\":\"1f529\",\"⚙\":\"2699\",\"🗜\":\"1f5dc\",\"⚖\":\"2696\",\"🔗\":\"1f517\",\"⛓\":\"26d3\",\"🧰\":\"1f9f0\",\"🧲\":\"1f9f2\",\"⚗\":\"2697\",\"🧪\":\"1f9ea\",\"🧫\":\"1f9eb\",\"🧬\":\"1f9ec\",\"🔬\":\"1f52c\",\"🔭\":\"1f52d\",\"📡\":\"1f4e1\",\"💉\":\"1f489\",\"💊\":\"1f48a\",\"🚪\":\"1f6aa\",\"🛏\":\"1f6cf\",\"🛋\":\"1f6cb\",\"🚽\":\"1f6bd\",\"🚿\":\"1f6bf\",\"🛁\":\"1f6c1\",\"🧴\":\"1f9f4\",\"🧷\":\"1f9f7\",\"🧹\":\"1f9f9\",\"🧺\":\"1f9fa\",\"🧻\":\"1f9fb\",\"🧼\":\"1f9fc\",\"🧽\":\"1f9fd\",\"🧯\":\"1f9ef\",\"🛒\":\"1f6d2\",\"🚬\":\"1f6ac\",\"⚰\":\"26b0\",\"⚱\":\"26b1\",\"🗿\":\"1f5ff\",\"🏧\":\"1f3e7\",\"🚮\":\"1f6ae\",\"🚰\":\"1f6b0\",\"♿\":\"267f\",\"🚹\":\"1f6b9\",\"🚺\":\"1f6ba\",\"🚻\":\"1f6bb\",\"🚼\":\"1f6bc\",\"🚾\":\"1f6be\",\"🛂\":\"1f6c2\",\"🛃\":\"1f6c3\",\"🛄\":\"1f6c4\",\"🛅\":\"1f6c5\",\"⚠\":\"26a0\",\"🚸\":\"1f6b8\",\"⛔\":\"26d4\",\"🚫\":\"1f6ab\",\"🚳\":\"1f6b3\",\"🚭\":\"1f6ad\",\"🚯\":\"1f6af\",\"🚱\":\"1f6b1\",\"🚷\":\"1f6b7\",\"📵\":\"1f4f5\",\"🔞\":\"1f51e\",\"☢\":\"2622\",\"☣\":\"2623\",\"⬆\":\"2b06\",\"↗\":\"2197\",\"➡\":\"27a1\",\"↘\":\"2198\",\"⬇\":\"2b07\",\"↙\":\"2199\",\"⬅\":\"2b05\",\"↖\":\"2196\",\"↕\":\"2195\",\"↔\":\"2194\",\"↩\":\"21a9\",\"↪\":\"21aa\",\"⤴\":\"2934\",\"⤵\":\"2935\",\"🔃\":\"1f503\",\"🔄\":\"1f504\",\"🔙\":\"1f519\",\"🔚\":\"1f51a\",\"🔛\":\"1f51b\",\"🔜\":\"1f51c\",\"🔝\":\"1f51d\",\"🛐\":\"1f6d0\",\"⚛\":\"269b\",\"🕉\":\"1f549\",\"✡\":\"2721\",\"☸\":\"2638\",\"☯\":\"262f\",\"✝\":\"271d\",\"☦\":\"2626\",\"☪\":\"262a\",\"☮\":\"262e\",\"🕎\":\"1f54e\",\"🔯\":\"1f52f\",\"♈\":\"2648\",\"♉\":\"2649\",\"♊\":\"264a\",\"♋\":\"264b\",\"♌\":\"264c\",\"♍\":\"264d\",\"♎\":\"264e\",\"♏\":\"264f\",\"♐\":\"2650\",\"♑\":\"2651\",\"♒\":\"2652\",\"♓\":\"2653\",\"⛎\":\"26ce\",\"🔀\":\"1f500\",\"🔁\":\"1f501\",\"🔂\":\"1f502\",\"▶\":\"25b6\",\"⏩\":\"23e9\",\"⏭\":\"23ed\",\"⏯\":\"23ef\",\"◀\":\"25c0\",\"⏪\":\"23ea\",\"⏮\":\"23ee\",\"🔼\":\"1f53c\",\"⏫\":\"23eb\",\"🔽\":\"1f53d\",\"⏬\":\"23ec\",\"⏸\":\"23f8\",\"⏹\":\"23f9\",\"⏺\":\"23fa\",\"⏏\":\"23cf\",\"🎦\":\"1f3a6\",\"🔅\":\"1f505\",\"🔆\":\"1f506\",\"📶\":\"1f4f6\",\"📳\":\"1f4f3\",\"📴\":\"1f4f4\",\"♀\":\"2640\",\"♂\":\"2642\",\"⚕\":\"2695\",\"♾\":\"267e\",\"♻\":\"267b\",\"⚜\":\"269c\",\"🔱\":\"1f531\",\"📛\":\"1f4db\",\"🔰\":\"1f530\",\"⭕\":\"2b55\",\"✅\":\"2705\",\"☑\":\"2611\",\"✔\":\"2714\",\"✖\":\"2716\",\"❌\":\"274c\",\"❎\":\"274e\",\"➕\":\"2795\",\"➖\":\"2796\",\"➗\":\"2797\",\"➰\":\"27b0\",\"➿\":\"27bf\",\"〽\":\"303d\",\"✳\":\"2733\",\"✴\":\"2734\",\"❇\":\"2747\",\"‼\":\"203c\",\"⁉\":\"2049\",\"❓\":\"2753\",\"❔\":\"2754\",\"❕\":\"2755\",\"❗\":\"2757\",\"〰\":\"3030\",\"©\":\"a9\",\"®\":\"ae\",\"™\":\"2122\",\"🔟\":\"1f51f\",\"💯\":\"1f4af\",\"🔠\":\"1f520\",\"🔡\":\"1f521\",\"🔢\":\"1f522\",\"🔣\":\"1f523\",\"🔤\":\"1f524\",\"🅰\":\"1f170\",\"🆎\":\"1f18e\",\"🅱\":\"1f171\",\"🆑\":\"1f191\",\"🆒\":\"1f192\",\"🆓\":\"1f193\",\"ℹ\":\"2139\",\"🆔\":\"1f194\",\"Ⓜ\":\"24c2\",\"🆕\":\"1f195\",\"🆖\":\"1f196\",\"🅾\":\"1f17e\",\"🆗\":\"1f197\",\"🅿\":\"1f17f\",\"🆘\":\"1f198\",\"🆙\":\"1f199\",\"🆚\":\"1f19a\",\"🈁\":\"1f201\",\"🈂\":\"1f202\",\"🈷\":\"1f237\",\"🈶\":\"1f236\",\"🈯\":\"1f22f\",\"🉐\":\"1f250\",\"🈹\":\"1f239\",\"🈚\":\"1f21a\",\"🈲\":\"1f232\",\"🉑\":\"1f251\",\"🈸\":\"1f238\",\"🈴\":\"1f234\",\"🈳\":\"1f233\",\"㊗\":\"3297\",\"㊙\":\"3299\",\"🈺\":\"1f23a\",\"🈵\":\"1f235\",\"▪\":\"25aa\",\"▫\":\"25ab\",\"◻\":\"25fb\",\"◼\":\"25fc\",\"◽\":\"25fd\",\"◾\":\"25fe\",\"⬛\":\"2b1b\",\"⬜\":\"2b1c\",\"🔶\":\"1f536\",\"🔷\":\"1f537\",\"🔸\":\"1f538\",\"🔹\":\"1f539\",\"🔺\":\"1f53a\",\"🔻\":\"1f53b\",\"💠\":\"1f4a0\",\"🔘\":\"1f518\",\"🔲\":\"1f532\",\"🔳\":\"1f533\",\"⚪\":\"26aa\",\"⚫\":\"26ab\",\"🔴\":\"1f534\",\"🔵\":\"1f535\",\"🏁\":\"1f3c1\",\"🚩\":\"1f6a9\",\"🎌\":\"1f38c\",\"🏴\":\"1f3f4\",\"🏳\":\"1f3f3\",\"☺️\":\"263a\",\"☹️\":\"2639\",\"☠️\":\"2620\",\"👶🏻\":\"1f476-1f3fb\",\"👶🏼\":\"1f476-1f3fc\",\"👶🏽\":\"1f476-1f3fd\",\"👶🏾\":\"1f476-1f3fe\",\"👶🏿\":\"1f476-1f3ff\",\"🧒🏻\":\"1f9d2-1f3fb\",\"🧒🏼\":\"1f9d2-1f3fc\",\"🧒🏽\":\"1f9d2-1f3fd\",\"🧒🏾\":\"1f9d2-1f3fe\",\"🧒🏿\":\"1f9d2-1f3ff\",\"👦🏻\":\"1f466-1f3fb\",\"👦🏼\":\"1f466-1f3fc\",\"👦🏽\":\"1f466-1f3fd\",\"👦🏾\":\"1f466-1f3fe\",\"👦🏿\":\"1f466-1f3ff\",\"👧🏻\":\"1f467-1f3fb\",\"👧🏼\":\"1f467-1f3fc\",\"👧🏽\":\"1f467-1f3fd\",\"👧🏾\":\"1f467-1f3fe\",\"👧🏿\":\"1f467-1f3ff\",\"🧑🏻\":\"1f9d1-1f3fb\",\"🧑🏼\":\"1f9d1-1f3fc\",\"🧑🏽\":\"1f9d1-1f3fd\",\"🧑🏾\":\"1f9d1-1f3fe\",\"🧑🏿\":\"1f9d1-1f3ff\",\"👨🏻\":\"1f468-1f3fb\",\"👨🏼\":\"1f468-1f3fc\",\"👨🏽\":\"1f468-1f3fd\",\"👨🏾\":\"1f468-1f3fe\",\"👨🏿\":\"1f468-1f3ff\",\"👩🏻\":\"1f469-1f3fb\",\"👩🏼\":\"1f469-1f3fc\",\"👩🏽\":\"1f469-1f3fd\",\"👩🏾\":\"1f469-1f3fe\",\"👩🏿\":\"1f469-1f3ff\",\"🧓🏻\":\"1f9d3-1f3fb\",\"🧓🏼\":\"1f9d3-1f3fc\",\"🧓🏽\":\"1f9d3-1f3fd\",\"🧓🏾\":\"1f9d3-1f3fe\",\"🧓🏿\":\"1f9d3-1f3ff\",\"👴🏻\":\"1f474-1f3fb\",\"👴🏼\":\"1f474-1f3fc\",\"👴🏽\":\"1f474-1f3fd\",\"👴🏾\":\"1f474-1f3fe\",\"👴🏿\":\"1f474-1f3ff\",\"👵🏻\":\"1f475-1f3fb\",\"👵🏼\":\"1f475-1f3fc\",\"👵🏽\":\"1f475-1f3fd\",\"👵🏾\":\"1f475-1f3fe\",\"👵🏿\":\"1f475-1f3ff\",\"👮🏻\":\"1f46e-1f3fb\",\"👮🏼\":\"1f46e-1f3fc\",\"👮🏽\":\"1f46e-1f3fd\",\"👮🏾\":\"1f46e-1f3fe\",\"👮🏿\":\"1f46e-1f3ff\",\"🕵️\":\"1f575\",\"🕵🏻\":\"1f575-1f3fb\",\"🕵🏼\":\"1f575-1f3fc\",\"🕵🏽\":\"1f575-1f3fd\",\"🕵🏾\":\"1f575-1f3fe\",\"🕵🏿\":\"1f575-1f3ff\",\"💂🏻\":\"1f482-1f3fb\",\"💂🏼\":\"1f482-1f3fc\",\"💂🏽\":\"1f482-1f3fd\",\"💂🏾\":\"1f482-1f3fe\",\"💂🏿\":\"1f482-1f3ff\",\"👷🏻\":\"1f477-1f3fb\",\"👷🏼\":\"1f477-1f3fc\",\"👷🏽\":\"1f477-1f3fd\",\"👷🏾\":\"1f477-1f3fe\",\"👷🏿\":\"1f477-1f3ff\",\"🤴🏻\":\"1f934-1f3fb\",\"🤴🏼\":\"1f934-1f3fc\",\"🤴🏽\":\"1f934-1f3fd\",\"🤴🏾\":\"1f934-1f3fe\",\"🤴🏿\":\"1f934-1f3ff\",\"👸🏻\":\"1f478-1f3fb\",\"👸🏼\":\"1f478-1f3fc\",\"👸🏽\":\"1f478-1f3fd\",\"👸🏾\":\"1f478-1f3fe\",\"👸🏿\":\"1f478-1f3ff\",\"👳🏻\":\"1f473-1f3fb\",\"👳🏼\":\"1f473-1f3fc\",\"👳🏽\":\"1f473-1f3fd\",\"👳🏾\":\"1f473-1f3fe\",\"👳🏿\":\"1f473-1f3ff\",\"👲🏻\":\"1f472-1f3fb\",\"👲🏼\":\"1f472-1f3fc\",\"👲🏽\":\"1f472-1f3fd\",\"👲🏾\":\"1f472-1f3fe\",\"👲🏿\":\"1f472-1f3ff\",\"🧕🏻\":\"1f9d5-1f3fb\",\"🧕🏼\":\"1f9d5-1f3fc\",\"🧕🏽\":\"1f9d5-1f3fd\",\"🧕🏾\":\"1f9d5-1f3fe\",\"🧕🏿\":\"1f9d5-1f3ff\",\"🧔🏻\":\"1f9d4-1f3fb\",\"🧔🏼\":\"1f9d4-1f3fc\",\"🧔🏽\":\"1f9d4-1f3fd\",\"🧔🏾\":\"1f9d4-1f3fe\",\"🧔🏿\":\"1f9d4-1f3ff\",\"👱🏻\":\"1f471-1f3fb\",\"👱🏼\":\"1f471-1f3fc\",\"👱🏽\":\"1f471-1f3fd\",\"👱🏾\":\"1f471-1f3fe\",\"👱🏿\":\"1f471-1f3ff\",\"🤵🏻\":\"1f935-1f3fb\",\"🤵🏼\":\"1f935-1f3fc\",\"🤵🏽\":\"1f935-1f3fd\",\"🤵🏾\":\"1f935-1f3fe\",\"🤵🏿\":\"1f935-1f3ff\",\"👰🏻\":\"1f470-1f3fb\",\"👰🏼\":\"1f470-1f3fc\",\"👰🏽\":\"1f470-1f3fd\",\"👰🏾\":\"1f470-1f3fe\",\"👰🏿\":\"1f470-1f3ff\",\"🤰🏻\":\"1f930-1f3fb\",\"🤰🏼\":\"1f930-1f3fc\",\"🤰🏽\":\"1f930-1f3fd\",\"🤰🏾\":\"1f930-1f3fe\",\"🤰🏿\":\"1f930-1f3ff\",\"🤱🏻\":\"1f931-1f3fb\",\"🤱🏼\":\"1f931-1f3fc\",\"🤱🏽\":\"1f931-1f3fd\",\"🤱🏾\":\"1f931-1f3fe\",\"🤱🏿\":\"1f931-1f3ff\",\"👼🏻\":\"1f47c-1f3fb\",\"👼🏼\":\"1f47c-1f3fc\",\"👼🏽\":\"1f47c-1f3fd\",\"👼🏾\":\"1f47c-1f3fe\",\"👼🏿\":\"1f47c-1f3ff\",\"🎅🏻\":\"1f385-1f3fb\",\"🎅🏼\":\"1f385-1f3fc\",\"🎅🏽\":\"1f385-1f3fd\",\"🎅🏾\":\"1f385-1f3fe\",\"🎅🏿\":\"1f385-1f3ff\",\"🤶🏻\":\"1f936-1f3fb\",\"🤶🏼\":\"1f936-1f3fc\",\"🤶🏽\":\"1f936-1f3fd\",\"🤶🏾\":\"1f936-1f3fe\",\"🤶🏿\":\"1f936-1f3ff\",\"🦸🏻\":\"1f9b8-1f3fb\",\"🦸🏼\":\"1f9b8-1f3fc\",\"🦸🏽\":\"1f9b8-1f3fd\",\"🦸🏾\":\"1f9b8-1f3fe\",\"🦸🏿\":\"1f9b8-1f3ff\",\"🦹🏻\":\"1f9b9-1f3fb\",\"🦹🏼\":\"1f9b9-1f3fc\",\"🦹🏽\":\"1f9b9-1f3fd\",\"🦹🏾\":\"1f9b9-1f3fe\",\"🦹🏿\":\"1f9b9-1f3ff\",\"🧙🏻\":\"1f9d9-1f3fb\",\"🧙🏼\":\"1f9d9-1f3fc\",\"🧙🏽\":\"1f9d9-1f3fd\",\"🧙🏾\":\"1f9d9-1f3fe\",\"🧙🏿\":\"1f9d9-1f3ff\",\"🧚🏻\":\"1f9da-1f3fb\",\"🧚🏼\":\"1f9da-1f3fc\",\"🧚🏽\":\"1f9da-1f3fd\",\"🧚🏾\":\"1f9da-1f3fe\",\"🧚🏿\":\"1f9da-1f3ff\",\"🧛🏻\":\"1f9db-1f3fb\",\"🧛🏼\":\"1f9db-1f3fc\",\"🧛🏽\":\"1f9db-1f3fd\",\"🧛🏾\":\"1f9db-1f3fe\",\"🧛🏿\":\"1f9db-1f3ff\",\"🧜🏻\":\"1f9dc-1f3fb\",\"🧜🏼\":\"1f9dc-1f3fc\",\"🧜🏽\":\"1f9dc-1f3fd\",\"🧜🏾\":\"1f9dc-1f3fe\",\"🧜🏿\":\"1f9dc-1f3ff\",\"🧝🏻\":\"1f9dd-1f3fb\",\"🧝🏼\":\"1f9dd-1f3fc\",\"🧝🏽\":\"1f9dd-1f3fd\",\"🧝🏾\":\"1f9dd-1f3fe\",\"🧝🏿\":\"1f9dd-1f3ff\",\"🙍🏻\":\"1f64d-1f3fb\",\"🙍🏼\":\"1f64d-1f3fc\",\"🙍🏽\":\"1f64d-1f3fd\",\"🙍🏾\":\"1f64d-1f3fe\",\"🙍🏿\":\"1f64d-1f3ff\",\"🙎🏻\":\"1f64e-1f3fb\",\"🙎🏼\":\"1f64e-1f3fc\",\"🙎🏽\":\"1f64e-1f3fd\",\"🙎🏾\":\"1f64e-1f3fe\",\"🙎🏿\":\"1f64e-1f3ff\",\"🙅🏻\":\"1f645-1f3fb\",\"🙅🏼\":\"1f645-1f3fc\",\"🙅🏽\":\"1f645-1f3fd\",\"🙅🏾\":\"1f645-1f3fe\",\"🙅🏿\":\"1f645-1f3ff\",\"🙆🏻\":\"1f646-1f3fb\",\"🙆🏼\":\"1f646-1f3fc\",\"🙆🏽\":\"1f646-1f3fd\",\"🙆🏾\":\"1f646-1f3fe\",\"🙆🏿\":\"1f646-1f3ff\",\"💁🏻\":\"1f481-1f3fb\",\"💁🏼\":\"1f481-1f3fc\",\"💁🏽\":\"1f481-1f3fd\",\"💁🏾\":\"1f481-1f3fe\",\"💁🏿\":\"1f481-1f3ff\",\"🙋🏻\":\"1f64b-1f3fb\",\"🙋🏼\":\"1f64b-1f3fc\",\"🙋🏽\":\"1f64b-1f3fd\",\"🙋🏾\":\"1f64b-1f3fe\",\"🙋🏿\":\"1f64b-1f3ff\",\"🙇🏻\":\"1f647-1f3fb\",\"🙇🏼\":\"1f647-1f3fc\",\"🙇🏽\":\"1f647-1f3fd\",\"🙇🏾\":\"1f647-1f3fe\",\"🙇🏿\":\"1f647-1f3ff\",\"🤦🏻\":\"1f926-1f3fb\",\"🤦🏼\":\"1f926-1f3fc\",\"🤦🏽\":\"1f926-1f3fd\",\"🤦🏾\":\"1f926-1f3fe\",\"🤦🏿\":\"1f926-1f3ff\",\"🤷🏻\":\"1f937-1f3fb\",\"🤷🏼\":\"1f937-1f3fc\",\"🤷🏽\":\"1f937-1f3fd\",\"🤷🏾\":\"1f937-1f3fe\",\"🤷🏿\":\"1f937-1f3ff\",\"💆🏻\":\"1f486-1f3fb\",\"💆🏼\":\"1f486-1f3fc\",\"💆🏽\":\"1f486-1f3fd\",\"💆🏾\":\"1f486-1f3fe\",\"💆🏿\":\"1f486-1f3ff\",\"💇🏻\":\"1f487-1f3fb\",\"💇🏼\":\"1f487-1f3fc\",\"💇🏽\":\"1f487-1f3fd\",\"💇🏾\":\"1f487-1f3fe\",\"💇🏿\":\"1f487-1f3ff\",\"🚶🏻\":\"1f6b6-1f3fb\",\"🚶🏼\":\"1f6b6-1f3fc\",\"🚶🏽\":\"1f6b6-1f3fd\",\"🚶🏾\":\"1f6b6-1f3fe\",\"🚶🏿\":\"1f6b6-1f3ff\",\"🏃🏻\":\"1f3c3-1f3fb\",\"🏃🏼\":\"1f3c3-1f3fc\",\"🏃🏽\":\"1f3c3-1f3fd\",\"🏃🏾\":\"1f3c3-1f3fe\",\"🏃🏿\":\"1f3c3-1f3ff\",\"💃🏻\":\"1f483-1f3fb\",\"💃🏼\":\"1f483-1f3fc\",\"💃🏽\":\"1f483-1f3fd\",\"💃🏾\":\"1f483-1f3fe\",\"💃🏿\":\"1f483-1f3ff\",\"🕺🏻\":\"1f57a-1f3fb\",\"🕺🏼\":\"1f57a-1f3fc\",\"🕺🏽\":\"1f57a-1f3fd\",\"🕺🏾\":\"1f57a-1f3fe\",\"🕺🏿\":\"1f57a-1f3ff\",\"🧖🏻\":\"1f9d6-1f3fb\",\"🧖🏼\":\"1f9d6-1f3fc\",\"🧖🏽\":\"1f9d6-1f3fd\",\"🧖🏾\":\"1f9d6-1f3fe\",\"🧖🏿\":\"1f9d6-1f3ff\",\"🧗🏻\":\"1f9d7-1f3fb\",\"🧗🏼\":\"1f9d7-1f3fc\",\"🧗🏽\":\"1f9d7-1f3fd\",\"🧗🏾\":\"1f9d7-1f3fe\",\"🧗🏿\":\"1f9d7-1f3ff\",\"🧘🏻\":\"1f9d8-1f3fb\",\"🧘🏼\":\"1f9d8-1f3fc\",\"🧘🏽\":\"1f9d8-1f3fd\",\"🧘🏾\":\"1f9d8-1f3fe\",\"🧘🏿\":\"1f9d8-1f3ff\",\"🛀🏻\":\"1f6c0-1f3fb\",\"🛀🏼\":\"1f6c0-1f3fc\",\"🛀🏽\":\"1f6c0-1f3fd\",\"🛀🏾\":\"1f6c0-1f3fe\",\"🛀🏿\":\"1f6c0-1f3ff\",\"🛌🏻\":\"1f6cc-1f3fb\",\"🛌🏼\":\"1f6cc-1f3fc\",\"🛌🏽\":\"1f6cc-1f3fd\",\"🛌🏾\":\"1f6cc-1f3fe\",\"🛌🏿\":\"1f6cc-1f3ff\",\"🕴️\":\"1f574\",\"🕴🏻\":\"1f574-1f3fb\",\"🕴🏼\":\"1f574-1f3fc\",\"🕴🏽\":\"1f574-1f3fd\",\"🕴🏾\":\"1f574-1f3fe\",\"🕴🏿\":\"1f574-1f3ff\",\"🗣️\":\"1f5e3\",\"🏇🏻\":\"1f3c7-1f3fb\",\"🏇🏼\":\"1f3c7-1f3fc\",\"🏇🏽\":\"1f3c7-1f3fd\",\"🏇🏾\":\"1f3c7-1f3fe\",\"🏇🏿\":\"1f3c7-1f3ff\",\"⛷️\":\"26f7\",\"🏂🏻\":\"1f3c2-1f3fb\",\"🏂🏼\":\"1f3c2-1f3fc\",\"🏂🏽\":\"1f3c2-1f3fd\",\"🏂🏾\":\"1f3c2-1f3fe\",\"🏂🏿\":\"1f3c2-1f3ff\",\"🏌️\":\"1f3cc\",\"🏌🏻\":\"1f3cc-1f3fb\",\"🏌🏼\":\"1f3cc-1f3fc\",\"🏌🏽\":\"1f3cc-1f3fd\",\"🏌🏾\":\"1f3cc-1f3fe\",\"🏌🏿\":\"1f3cc-1f3ff\",\"🏄🏻\":\"1f3c4-1f3fb\",\"🏄🏼\":\"1f3c4-1f3fc\",\"🏄🏽\":\"1f3c4-1f3fd\",\"🏄🏾\":\"1f3c4-1f3fe\",\"🏄🏿\":\"1f3c4-1f3ff\",\"🚣🏻\":\"1f6a3-1f3fb\",\"🚣🏼\":\"1f6a3-1f3fc\",\"🚣🏽\":\"1f6a3-1f3fd\",\"🚣🏾\":\"1f6a3-1f3fe\",\"🚣🏿\":\"1f6a3-1f3ff\",\"🏊🏻\":\"1f3ca-1f3fb\",\"🏊🏼\":\"1f3ca-1f3fc\",\"🏊🏽\":\"1f3ca-1f3fd\",\"🏊🏾\":\"1f3ca-1f3fe\",\"🏊🏿\":\"1f3ca-1f3ff\",\"⛹️\":\"26f9\",\"⛹🏻\":\"26f9-1f3fb\",\"⛹🏼\":\"26f9-1f3fc\",\"⛹🏽\":\"26f9-1f3fd\",\"⛹🏾\":\"26f9-1f3fe\",\"⛹🏿\":\"26f9-1f3ff\",\"🏋️\":\"1f3cb\",\"🏋🏻\":\"1f3cb-1f3fb\",\"🏋🏼\":\"1f3cb-1f3fc\",\"🏋🏽\":\"1f3cb-1f3fd\",\"🏋🏾\":\"1f3cb-1f3fe\",\"🏋🏿\":\"1f3cb-1f3ff\",\"🚴🏻\":\"1f6b4-1f3fb\",\"🚴🏼\":\"1f6b4-1f3fc\",\"🚴🏽\":\"1f6b4-1f3fd\",\"🚴🏾\":\"1f6b4-1f3fe\",\"🚴🏿\":\"1f6b4-1f3ff\",\"🚵🏻\":\"1f6b5-1f3fb\",\"🚵🏼\":\"1f6b5-1f3fc\",\"🚵🏽\":\"1f6b5-1f3fd\",\"🚵🏾\":\"1f6b5-1f3fe\",\"🚵🏿\":\"1f6b5-1f3ff\",\"🏎️\":\"1f3ce\",\"🏍️\":\"1f3cd\",\"🤸🏻\":\"1f938-1f3fb\",\"🤸🏼\":\"1f938-1f3fc\",\"🤸🏽\":\"1f938-1f3fd\",\"🤸🏾\":\"1f938-1f3fe\",\"🤸🏿\":\"1f938-1f3ff\",\"🤽🏻\":\"1f93d-1f3fb\",\"🤽🏼\":\"1f93d-1f3fc\",\"🤽🏽\":\"1f93d-1f3fd\",\"🤽🏾\":\"1f93d-1f3fe\",\"🤽🏿\":\"1f93d-1f3ff\",\"🤾🏻\":\"1f93e-1f3fb\",\"🤾🏼\":\"1f93e-1f3fc\",\"🤾🏽\":\"1f93e-1f3fd\",\"🤾🏾\":\"1f93e-1f3fe\",\"🤾🏿\":\"1f93e-1f3ff\",\"🤹🏻\":\"1f939-1f3fb\",\"🤹🏼\":\"1f939-1f3fc\",\"🤹🏽\":\"1f939-1f3fd\",\"🤹🏾\":\"1f939-1f3fe\",\"🤹🏿\":\"1f939-1f3ff\",\"🤳🏻\":\"1f933-1f3fb\",\"🤳🏼\":\"1f933-1f3fc\",\"🤳🏽\":\"1f933-1f3fd\",\"🤳🏾\":\"1f933-1f3fe\",\"🤳🏿\":\"1f933-1f3ff\",\"💪🏻\":\"1f4aa-1f3fb\",\"💪🏼\":\"1f4aa-1f3fc\",\"💪🏽\":\"1f4aa-1f3fd\",\"💪🏾\":\"1f4aa-1f3fe\",\"💪🏿\":\"1f4aa-1f3ff\",\"🦵🏻\":\"1f9b5-1f3fb\",\"🦵🏼\":\"1f9b5-1f3fc\",\"🦵🏽\":\"1f9b5-1f3fd\",\"🦵🏾\":\"1f9b5-1f3fe\",\"🦵🏿\":\"1f9b5-1f3ff\",\"🦶🏻\":\"1f9b6-1f3fb\",\"🦶🏼\":\"1f9b6-1f3fc\",\"🦶🏽\":\"1f9b6-1f3fd\",\"🦶🏾\":\"1f9b6-1f3fe\",\"🦶🏿\":\"1f9b6-1f3ff\",\"👈🏻\":\"1f448-1f3fb\",\"👈🏼\":\"1f448-1f3fc\",\"👈🏽\":\"1f448-1f3fd\",\"👈🏾\":\"1f448-1f3fe\",\"👈🏿\":\"1f448-1f3ff\",\"👉🏻\":\"1f449-1f3fb\",\"👉🏼\":\"1f449-1f3fc\",\"👉🏽\":\"1f449-1f3fd\",\"👉🏾\":\"1f449-1f3fe\",\"👉🏿\":\"1f449-1f3ff\",\"☝️\":\"261d\",\"☝🏻\":\"261d-1f3fb\",\"☝🏼\":\"261d-1f3fc\",\"☝🏽\":\"261d-1f3fd\",\"☝🏾\":\"261d-1f3fe\",\"☝🏿\":\"261d-1f3ff\",\"👆🏻\":\"1f446-1f3fb\",\"👆🏼\":\"1f446-1f3fc\",\"👆🏽\":\"1f446-1f3fd\",\"👆🏾\":\"1f446-1f3fe\",\"👆🏿\":\"1f446-1f3ff\",\"🖕🏻\":\"1f595-1f3fb\",\"🖕🏼\":\"1f595-1f3fc\",\"🖕🏽\":\"1f595-1f3fd\",\"🖕🏾\":\"1f595-1f3fe\",\"🖕🏿\":\"1f595-1f3ff\",\"👇🏻\":\"1f447-1f3fb\",\"👇🏼\":\"1f447-1f3fc\",\"👇🏽\":\"1f447-1f3fd\",\"👇🏾\":\"1f447-1f3fe\",\"👇🏿\":\"1f447-1f3ff\",\"✌️\":\"270c\",\"✌🏻\":\"270c-1f3fb\",\"✌🏼\":\"270c-1f3fc\",\"✌🏽\":\"270c-1f3fd\",\"✌🏾\":\"270c-1f3fe\",\"✌🏿\":\"270c-1f3ff\",\"🤞🏻\":\"1f91e-1f3fb\",\"🤞🏼\":\"1f91e-1f3fc\",\"🤞🏽\":\"1f91e-1f3fd\",\"🤞🏾\":\"1f91e-1f3fe\",\"🤞🏿\":\"1f91e-1f3ff\",\"🖖🏻\":\"1f596-1f3fb\",\"🖖🏼\":\"1f596-1f3fc\",\"🖖🏽\":\"1f596-1f3fd\",\"🖖🏾\":\"1f596-1f3fe\",\"🖖🏿\":\"1f596-1f3ff\",\"🤘🏻\":\"1f918-1f3fb\",\"🤘🏼\":\"1f918-1f3fc\",\"🤘🏽\":\"1f918-1f3fd\",\"🤘🏾\":\"1f918-1f3fe\",\"🤘🏿\":\"1f918-1f3ff\",\"🤙🏻\":\"1f919-1f3fb\",\"🤙🏼\":\"1f919-1f3fc\",\"🤙🏽\":\"1f919-1f3fd\",\"🤙🏾\":\"1f919-1f3fe\",\"🤙🏿\":\"1f919-1f3ff\",\"🖐️\":\"1f590\",\"🖐🏻\":\"1f590-1f3fb\",\"🖐🏼\":\"1f590-1f3fc\",\"🖐🏽\":\"1f590-1f3fd\",\"🖐🏾\":\"1f590-1f3fe\",\"🖐🏿\":\"1f590-1f3ff\",\"✋🏻\":\"270b-1f3fb\",\"✋🏼\":\"270b-1f3fc\",\"✋🏽\":\"270b-1f3fd\",\"✋🏾\":\"270b-1f3fe\",\"✋🏿\":\"270b-1f3ff\",\"👌🏻\":\"1f44c-1f3fb\",\"👌🏼\":\"1f44c-1f3fc\",\"👌🏽\":\"1f44c-1f3fd\",\"👌🏾\":\"1f44c-1f3fe\",\"👌🏿\":\"1f44c-1f3ff\",\"👍🏻\":\"1f44d-1f3fb\",\"👍🏼\":\"1f44d-1f3fc\",\"👍🏽\":\"1f44d-1f3fd\",\"👍🏾\":\"1f44d-1f3fe\",\"👍🏿\":\"1f44d-1f3ff\",\"👎🏻\":\"1f44e-1f3fb\",\"👎🏼\":\"1f44e-1f3fc\",\"👎🏽\":\"1f44e-1f3fd\",\"👎🏾\":\"1f44e-1f3fe\",\"👎🏿\":\"1f44e-1f3ff\",\"✊🏻\":\"270a-1f3fb\",\"✊🏼\":\"270a-1f3fc\",\"✊🏽\":\"270a-1f3fd\",\"✊🏾\":\"270a-1f3fe\",\"✊🏿\":\"270a-1f3ff\",\"👊🏻\":\"1f44a-1f3fb\",\"👊🏼\":\"1f44a-1f3fc\",\"👊🏽\":\"1f44a-1f3fd\",\"👊🏾\":\"1f44a-1f3fe\",\"👊🏿\":\"1f44a-1f3ff\",\"🤛🏻\":\"1f91b-1f3fb\",\"🤛🏼\":\"1f91b-1f3fc\",\"🤛🏽\":\"1f91b-1f3fd\",\"🤛🏾\":\"1f91b-1f3fe\",\"🤛🏿\":\"1f91b-1f3ff\",\"🤜🏻\":\"1f91c-1f3fb\",\"🤜🏼\":\"1f91c-1f3fc\",\"🤜🏽\":\"1f91c-1f3fd\",\"🤜🏾\":\"1f91c-1f3fe\",\"🤜🏿\":\"1f91c-1f3ff\",\"🤚🏻\":\"1f91a-1f3fb\",\"🤚🏼\":\"1f91a-1f3fc\",\"🤚🏽\":\"1f91a-1f3fd\",\"🤚🏾\":\"1f91a-1f3fe\",\"🤚🏿\":\"1f91a-1f3ff\",\"👋🏻\":\"1f44b-1f3fb\",\"👋🏼\":\"1f44b-1f3fc\",\"👋🏽\":\"1f44b-1f3fd\",\"👋🏾\":\"1f44b-1f3fe\",\"👋🏿\":\"1f44b-1f3ff\",\"🤟🏻\":\"1f91f-1f3fb\",\"🤟🏼\":\"1f91f-1f3fc\",\"🤟🏽\":\"1f91f-1f3fd\",\"🤟🏾\":\"1f91f-1f3fe\",\"🤟🏿\":\"1f91f-1f3ff\",\"✍️\":\"270d\",\"✍🏻\":\"270d-1f3fb\",\"✍🏼\":\"270d-1f3fc\",\"✍🏽\":\"270d-1f3fd\",\"✍🏾\":\"270d-1f3fe\",\"✍🏿\":\"270d-1f3ff\",\"👏🏻\":\"1f44f-1f3fb\",\"👏🏼\":\"1f44f-1f3fc\",\"👏🏽\":\"1f44f-1f3fd\",\"👏🏾\":\"1f44f-1f3fe\",\"👏🏿\":\"1f44f-1f3ff\",\"👐🏻\":\"1f450-1f3fb\",\"👐🏼\":\"1f450-1f3fc\",\"👐🏽\":\"1f450-1f3fd\",\"👐🏾\":\"1f450-1f3fe\",\"👐🏿\":\"1f450-1f3ff\",\"🙌🏻\":\"1f64c-1f3fb\",\"🙌🏼\":\"1f64c-1f3fc\",\"🙌🏽\":\"1f64c-1f3fd\",\"🙌🏾\":\"1f64c-1f3fe\",\"🙌🏿\":\"1f64c-1f3ff\",\"🤲🏻\":\"1f932-1f3fb\",\"🤲🏼\":\"1f932-1f3fc\",\"🤲🏽\":\"1f932-1f3fd\",\"🤲🏾\":\"1f932-1f3fe\",\"🤲🏿\":\"1f932-1f3ff\",\"🙏🏻\":\"1f64f-1f3fb\",\"🙏🏼\":\"1f64f-1f3fc\",\"🙏🏽\":\"1f64f-1f3fd\",\"🙏🏾\":\"1f64f-1f3fe\",\"🙏🏿\":\"1f64f-1f3ff\",\"💅🏻\":\"1f485-1f3fb\",\"💅🏼\":\"1f485-1f3fc\",\"💅🏽\":\"1f485-1f3fd\",\"💅🏾\":\"1f485-1f3fe\",\"💅🏿\":\"1f485-1f3ff\",\"👂🏻\":\"1f442-1f3fb\",\"👂🏼\":\"1f442-1f3fc\",\"👂🏽\":\"1f442-1f3fd\",\"👂🏾\":\"1f442-1f3fe\",\"👂🏿\":\"1f442-1f3ff\",\"👃🏻\":\"1f443-1f3fb\",\"👃🏼\":\"1f443-1f3fc\",\"👃🏽\":\"1f443-1f3fd\",\"👃🏾\":\"1f443-1f3fe\",\"👃🏿\":\"1f443-1f3ff\",\"👁️\":\"1f441\",\"❤️\":\"2764\",\"❣️\":\"2763\",\"🗨️\":\"1f5e8\",\"🗯️\":\"1f5ef\",\"🕳️\":\"1f573\",\"🕶️\":\"1f576\",\"🛍️\":\"1f6cd\",\"⛑️\":\"26d1\",\"🐿️\":\"1f43f\",\"🕊️\":\"1f54a\",\"🕷️\":\"1f577\",\"🕸️\":\"1f578\",\"🏵️\":\"1f3f5\",\"☘️\":\"2618\",\"🌶️\":\"1f336\",\"🍽️\":\"1f37d\",\"🗺️\":\"1f5fa\",\"🏔️\":\"1f3d4\",\"⛰️\":\"26f0\",\"🏕️\":\"1f3d5\",\"🏖️\":\"1f3d6\",\"🏜️\":\"1f3dc\",\"🏝️\":\"1f3dd\",\"🏞️\":\"1f3de\",\"🏟️\":\"1f3df\",\"🏛️\":\"1f3db\",\"🏗️\":\"1f3d7\",\"🏘️\":\"1f3d8\",\"🏚️\":\"1f3da\",\"⛩️\":\"26e9\",\"🏙️\":\"1f3d9\",\"♨️\":\"2668\",\"🛣️\":\"1f6e3\",\"🛤️\":\"1f6e4\",\"🛢️\":\"1f6e2\",\"🛳️\":\"1f6f3\",\"⛴️\":\"26f4\",\"🛥️\":\"1f6e5\",\"✈️\":\"2708\",\"🛩️\":\"1f6e9\",\"🛰️\":\"1f6f0\",\"🛎️\":\"1f6ce\",\"⏱️\":\"23f1\",\"⏲️\":\"23f2\",\"🕰️\":\"1f570\",\"🌡️\":\"1f321\",\"☀️\":\"2600\",\"☁️\":\"2601\",\"⛈️\":\"26c8\",\"🌤️\":\"1f324\",\"🌥️\":\"1f325\",\"🌦️\":\"1f326\",\"🌧️\":\"1f327\",\"🌨️\":\"1f328\",\"🌩️\":\"1f329\",\"🌪️\":\"1f32a\",\"🌫️\":\"1f32b\",\"🌬️\":\"1f32c\",\"☂️\":\"2602\",\"⛱️\":\"26f1\",\"❄️\":\"2744\",\"☃️\":\"2603\",\"☄️\":\"2604\",\"🎗️\":\"1f397\",\"🎟️\":\"1f39f\",\"🎖️\":\"1f396\",\"⛸️\":\"26f8\",\"🕹️\":\"1f579\",\"♠️\":\"2660\",\"♥️\":\"2665\",\"♦️\":\"2666\",\"♣️\":\"2663\",\"♟️\":\"265f\",\"🖼️\":\"1f5bc\",\"🎙️\":\"1f399\",\"🎚️\":\"1f39a\",\"🎛️\":\"1f39b\",\"☎️\":\"260e\",\"🖥️\":\"1f5a5\",\"🖨️\":\"1f5a8\",\"⌨️\":\"2328\",\"🖱️\":\"1f5b1\",\"🖲️\":\"1f5b2\",\"🎞️\":\"1f39e\",\"📽️\":\"1f4fd\",\"🕯️\":\"1f56f\",\"🗞️\":\"1f5de\",\"🏷️\":\"1f3f7\",\"✉️\":\"2709\",\"🗳️\":\"1f5f3\",\"✏️\":\"270f\",\"✒️\":\"2712\",\"🖋️\":\"1f58b\",\"🖊️\":\"1f58a\",\"🖌️\":\"1f58c\",\"🖍️\":\"1f58d\",\"🗂️\":\"1f5c2\",\"🗒️\":\"1f5d2\",\"🗓️\":\"1f5d3\",\"🖇️\":\"1f587\",\"✂️\":\"2702\",\"🗃️\":\"1f5c3\",\"🗄️\":\"1f5c4\",\"🗑️\":\"1f5d1\",\"🗝️\":\"1f5dd\",\"⛏️\":\"26cf\",\"⚒️\":\"2692\",\"🛠️\":\"1f6e0\",\"🗡️\":\"1f5e1\",\"⚔️\":\"2694\",\"🛡️\":\"1f6e1\",\"⚙️\":\"2699\",\"🗜️\":\"1f5dc\",\"⚖️\":\"2696\",\"⛓️\":\"26d3\",\"⚗️\":\"2697\",\"🛏️\":\"1f6cf\",\"🛋️\":\"1f6cb\",\"⚰️\":\"26b0\",\"⚱️\":\"26b1\",\"⚠️\":\"26a0\",\"☢️\":\"2622\",\"☣️\":\"2623\",\"⬆️\":\"2b06\",\"↗️\":\"2197\",\"➡️\":\"27a1\",\"↘️\":\"2198\",\"⬇️\":\"2b07\",\"↙️\":\"2199\",\"⬅️\":\"2b05\",\"↖️\":\"2196\",\"↕️\":\"2195\",\"↔️\":\"2194\",\"↩️\":\"21a9\",\"↪️\":\"21aa\",\"⤴️\":\"2934\",\"⤵️\":\"2935\",\"⚛️\":\"269b\",\"🕉️\":\"1f549\",\"✡️\":\"2721\",\"☸️\":\"2638\",\"☯️\":\"262f\",\"✝️\":\"271d\",\"☦️\":\"2626\",\"☪️\":\"262a\",\"☮️\":\"262e\",\"▶️\":\"25b6\",\"⏭️\":\"23ed\",\"⏯️\":\"23ef\",\"◀️\":\"25c0\",\"⏮️\":\"23ee\",\"⏸️\":\"23f8\",\"⏹️\":\"23f9\",\"⏺️\":\"23fa\",\"⏏️\":\"23cf\",\"♀️\":\"2640\",\"♂️\":\"2642\",\"⚕️\":\"2695\",\"♾️\":\"267e\",\"♻️\":\"267b\",\"⚜️\":\"269c\",\"☑️\":\"2611\",\"✔️\":\"2714\",\"✖️\":\"2716\",\"〽️\":\"303d\",\"✳️\":\"2733\",\"✴️\":\"2734\",\"❇️\":\"2747\",\"‼️\":\"203c\",\"⁉️\":\"2049\",\"〰️\":\"3030\",\"©️\":\"a9\",\"®️\":\"ae\",\"™️\":\"2122\",\"#⃣\":\"23-20e3\",\"*⃣\":\"2a-20e3\",\"0⃣\":\"30-20e3\",\"1⃣\":\"31-20e3\",\"2⃣\":\"32-20e3\",\"3⃣\":\"33-20e3\",\"4⃣\":\"34-20e3\",\"5⃣\":\"35-20e3\",\"6⃣\":\"36-20e3\",\"7⃣\":\"37-20e3\",\"8⃣\":\"38-20e3\",\"9⃣\":\"39-20e3\",\"🅰️\":\"1f170\",\"🅱️\":\"1f171\",\"ℹ️\":\"2139\",\"Ⓜ️\":\"24c2\",\"🅾️\":\"1f17e\",\"🅿️\":\"1f17f\",\"🈂️\":\"1f202\",\"🈷️\":\"1f237\",\"㊗️\":\"3297\",\"㊙️\":\"3299\",\"▪️\":\"25aa\",\"▫️\":\"25ab\",\"◻️\":\"25fb\",\"◼️\":\"25fc\",\"🏳️\":\"1f3f3\",\"🇦🇨\":\"1f1e6-1f1e8\",\"🇦🇩\":\"1f1e6-1f1e9\",\"🇦🇪\":\"1f1e6-1f1ea\",\"🇦🇫\":\"1f1e6-1f1eb\",\"🇦🇬\":\"1f1e6-1f1ec\",\"🇦🇮\":\"1f1e6-1f1ee\",\"🇦🇱\":\"1f1e6-1f1f1\",\"🇦🇲\":\"1f1e6-1f1f2\",\"🇦🇴\":\"1f1e6-1f1f4\",\"🇦🇶\":\"1f1e6-1f1f6\",\"🇦🇷\":\"1f1e6-1f1f7\",\"🇦🇸\":\"1f1e6-1f1f8\",\"🇦🇹\":\"1f1e6-1f1f9\",\"🇦🇺\":\"1f1e6-1f1fa\",\"🇦🇼\":\"1f1e6-1f1fc\",\"🇦🇽\":\"1f1e6-1f1fd\",\"🇦🇿\":\"1f1e6-1f1ff\",\"🇧🇦\":\"1f1e7-1f1e6\",\"🇧🇧\":\"1f1e7-1f1e7\",\"🇧🇩\":\"1f1e7-1f1e9\",\"🇧🇪\":\"1f1e7-1f1ea\",\"🇧🇫\":\"1f1e7-1f1eb\",\"🇧🇬\":\"1f1e7-1f1ec\",\"🇧🇭\":\"1f1e7-1f1ed\",\"🇧🇮\":\"1f1e7-1f1ee\",\"🇧🇯\":\"1f1e7-1f1ef\",\"🇧🇱\":\"1f1e7-1f1f1\",\"🇧🇲\":\"1f1e7-1f1f2\",\"🇧🇳\":\"1f1e7-1f1f3\",\"🇧🇴\":\"1f1e7-1f1f4\",\"🇧🇶\":\"1f1e7-1f1f6\",\"🇧🇷\":\"1f1e7-1f1f7\",\"🇧🇸\":\"1f1e7-1f1f8\",\"🇧🇹\":\"1f1e7-1f1f9\",\"🇧🇻\":\"1f1e7-1f1fb\",\"🇧🇼\":\"1f1e7-1f1fc\",\"🇧🇾\":\"1f1e7-1f1fe\",\"🇧🇿\":\"1f1e7-1f1ff\",\"🇨🇦\":\"1f1e8-1f1e6\",\"🇨🇨\":\"1f1e8-1f1e8\",\"🇨🇩\":\"1f1e8-1f1e9\",\"🇨🇫\":\"1f1e8-1f1eb\",\"🇨🇬\":\"1f1e8-1f1ec\",\"🇨🇭\":\"1f1e8-1f1ed\",\"🇨🇮\":\"1f1e8-1f1ee\",\"🇨🇰\":\"1f1e8-1f1f0\",\"🇨🇱\":\"1f1e8-1f1f1\",\"🇨🇲\":\"1f1e8-1f1f2\",\"🇨🇳\":\"1f1e8-1f1f3\",\"🇨🇴\":\"1f1e8-1f1f4\",\"🇨🇵\":\"1f1e8-1f1f5\",\"🇨🇷\":\"1f1e8-1f1f7\",\"🇨🇺\":\"1f1e8-1f1fa\",\"🇨🇻\":\"1f1e8-1f1fb\",\"🇨🇼\":\"1f1e8-1f1fc\",\"🇨🇽\":\"1f1e8-1f1fd\",\"🇨🇾\":\"1f1e8-1f1fe\",\"🇨🇿\":\"1f1e8-1f1ff\",\"🇩🇪\":\"1f1e9-1f1ea\",\"🇩🇬\":\"1f1e9-1f1ec\",\"🇩🇯\":\"1f1e9-1f1ef\",\"🇩🇰\":\"1f1e9-1f1f0\",\"🇩🇲\":\"1f1e9-1f1f2\",\"🇩🇴\":\"1f1e9-1f1f4\",\"🇩🇿\":\"1f1e9-1f1ff\",\"🇪🇦\":\"1f1ea-1f1e6\",\"🇪🇨\":\"1f1ea-1f1e8\",\"🇪🇪\":\"1f1ea-1f1ea\",\"🇪🇬\":\"1f1ea-1f1ec\",\"🇪🇭\":\"1f1ea-1f1ed\",\"🇪🇷\":\"1f1ea-1f1f7\",\"🇪🇸\":\"1f1ea-1f1f8\",\"🇪🇹\":\"1f1ea-1f1f9\",\"🇪🇺\":\"1f1ea-1f1fa\",\"🇫🇮\":\"1f1eb-1f1ee\",\"🇫🇯\":\"1f1eb-1f1ef\",\"🇫🇰\":\"1f1eb-1f1f0\",\"🇫🇲\":\"1f1eb-1f1f2\",\"🇫🇴\":\"1f1eb-1f1f4\",\"🇫🇷\":\"1f1eb-1f1f7\",\"🇬🇦\":\"1f1ec-1f1e6\",\"🇬🇧\":\"1f1ec-1f1e7\",\"🇬🇩\":\"1f1ec-1f1e9\",\"🇬🇪\":\"1f1ec-1f1ea\",\"🇬🇫\":\"1f1ec-1f1eb\",\"🇬🇬\":\"1f1ec-1f1ec\",\"🇬🇭\":\"1f1ec-1f1ed\",\"🇬🇮\":\"1f1ec-1f1ee\",\"🇬🇱\":\"1f1ec-1f1f1\",\"🇬🇲\":\"1f1ec-1f1f2\",\"🇬🇳\":\"1f1ec-1f1f3\",\"🇬🇵\":\"1f1ec-1f1f5\",\"🇬🇶\":\"1f1ec-1f1f6\",\"🇬🇷\":\"1f1ec-1f1f7\",\"🇬🇸\":\"1f1ec-1f1f8\",\"🇬🇹\":\"1f1ec-1f1f9\",\"🇬🇺\":\"1f1ec-1f1fa\",\"🇬🇼\":\"1f1ec-1f1fc\",\"🇬🇾\":\"1f1ec-1f1fe\",\"🇭🇰\":\"1f1ed-1f1f0\",\"🇭🇲\":\"1f1ed-1f1f2\",\"🇭🇳\":\"1f1ed-1f1f3\",\"🇭🇷\":\"1f1ed-1f1f7\",\"🇭🇹\":\"1f1ed-1f1f9\",\"🇭🇺\":\"1f1ed-1f1fa\",\"🇮🇨\":\"1f1ee-1f1e8\",\"🇮🇩\":\"1f1ee-1f1e9\",\"🇮🇪\":\"1f1ee-1f1ea\",\"🇮🇱\":\"1f1ee-1f1f1\",\"🇮🇲\":\"1f1ee-1f1f2\",\"🇮🇳\":\"1f1ee-1f1f3\",\"🇮🇴\":\"1f1ee-1f1f4\",\"🇮🇶\":\"1f1ee-1f1f6\",\"🇮🇷\":\"1f1ee-1f1f7\",\"🇮🇸\":\"1f1ee-1f1f8\",\"🇮🇹\":\"1f1ee-1f1f9\",\"🇯🇪\":\"1f1ef-1f1ea\",\"🇯🇲\":\"1f1ef-1f1f2\",\"🇯🇴\":\"1f1ef-1f1f4\",\"🇯🇵\":\"1f1ef-1f1f5\",\"🇰🇪\":\"1f1f0-1f1ea\",\"🇰🇬\":\"1f1f0-1f1ec\",\"🇰🇭\":\"1f1f0-1f1ed\",\"🇰🇮\":\"1f1f0-1f1ee\",\"🇰🇲\":\"1f1f0-1f1f2\",\"🇰🇳\":\"1f1f0-1f1f3\",\"🇰🇵\":\"1f1f0-1f1f5\",\"🇰🇷\":\"1f1f0-1f1f7\",\"🇰🇼\":\"1f1f0-1f1fc\",\"🇰🇾\":\"1f1f0-1f1fe\",\"🇰🇿\":\"1f1f0-1f1ff\",\"🇱🇦\":\"1f1f1-1f1e6\",\"🇱🇧\":\"1f1f1-1f1e7\",\"🇱🇨\":\"1f1f1-1f1e8\",\"🇱🇮\":\"1f1f1-1f1ee\",\"🇱🇰\":\"1f1f1-1f1f0\",\"🇱🇷\":\"1f1f1-1f1f7\",\"🇱🇸\":\"1f1f1-1f1f8\",\"🇱🇹\":\"1f1f1-1f1f9\",\"🇱🇺\":\"1f1f1-1f1fa\",\"🇱🇻\":\"1f1f1-1f1fb\",\"🇱🇾\":\"1f1f1-1f1fe\",\"🇲🇦\":\"1f1f2-1f1e6\",\"🇲🇨\":\"1f1f2-1f1e8\",\"🇲🇩\":\"1f1f2-1f1e9\",\"🇲🇪\":\"1f1f2-1f1ea\",\"🇲🇫\":\"1f1f2-1f1eb\",\"🇲🇬\":\"1f1f2-1f1ec\",\"🇲🇭\":\"1f1f2-1f1ed\",\"🇲🇰\":\"1f1f2-1f1f0\",\"🇲🇱\":\"1f1f2-1f1f1\",\"🇲🇲\":\"1f1f2-1f1f2\",\"🇲🇳\":\"1f1f2-1f1f3\",\"🇲🇴\":\"1f1f2-1f1f4\",\"🇲🇵\":\"1f1f2-1f1f5\",\"🇲🇶\":\"1f1f2-1f1f6\",\"🇲🇷\":\"1f1f2-1f1f7\",\"🇲🇸\":\"1f1f2-1f1f8\",\"🇲🇹\":\"1f1f2-1f1f9\",\"🇲🇺\":\"1f1f2-1f1fa\",\"🇲🇻\":\"1f1f2-1f1fb\",\"🇲🇼\":\"1f1f2-1f1fc\",\"🇲🇽\":\"1f1f2-1f1fd\",\"🇲🇾\":\"1f1f2-1f1fe\",\"🇲🇿\":\"1f1f2-1f1ff\",\"🇳🇦\":\"1f1f3-1f1e6\",\"🇳🇨\":\"1f1f3-1f1e8\",\"🇳🇪\":\"1f1f3-1f1ea\",\"🇳🇫\":\"1f1f3-1f1eb\",\"🇳🇬\":\"1f1f3-1f1ec\",\"🇳🇮\":\"1f1f3-1f1ee\",\"🇳🇱\":\"1f1f3-1f1f1\",\"🇳🇴\":\"1f1f3-1f1f4\",\"🇳🇵\":\"1f1f3-1f1f5\",\"🇳🇷\":\"1f1f3-1f1f7\",\"🇳🇺\":\"1f1f3-1f1fa\",\"🇳🇿\":\"1f1f3-1f1ff\",\"🇴🇲\":\"1f1f4-1f1f2\",\"🇵🇦\":\"1f1f5-1f1e6\",\"🇵🇪\":\"1f1f5-1f1ea\",\"🇵🇫\":\"1f1f5-1f1eb\",\"🇵🇬\":\"1f1f5-1f1ec\",\"🇵🇭\":\"1f1f5-1f1ed\",\"🇵🇰\":\"1f1f5-1f1f0\",\"🇵🇱\":\"1f1f5-1f1f1\",\"🇵🇲\":\"1f1f5-1f1f2\",\"🇵🇳\":\"1f1f5-1f1f3\",\"🇵🇷\":\"1f1f5-1f1f7\",\"🇵🇸\":\"1f1f5-1f1f8\",\"🇵🇹\":\"1f1f5-1f1f9\",\"🇵🇼\":\"1f1f5-1f1fc\",\"🇵🇾\":\"1f1f5-1f1fe\",\"🇶🇦\":\"1f1f6-1f1e6\",\"🇷🇪\":\"1f1f7-1f1ea\",\"🇷🇴\":\"1f1f7-1f1f4\",\"🇷🇸\":\"1f1f7-1f1f8\",\"🇷🇺\":\"1f1f7-1f1fa\",\"🇷🇼\":\"1f1f7-1f1fc\",\"🇸🇦\":\"1f1f8-1f1e6\",\"🇸🇧\":\"1f1f8-1f1e7\",\"🇸🇨\":\"1f1f8-1f1e8\",\"🇸🇩\":\"1f1f8-1f1e9\",\"🇸🇪\":\"1f1f8-1f1ea\",\"🇸🇬\":\"1f1f8-1f1ec\",\"🇸🇭\":\"1f1f8-1f1ed\",\"🇸🇮\":\"1f1f8-1f1ee\",\"🇸🇯\":\"1f1f8-1f1ef\",\"🇸🇰\":\"1f1f8-1f1f0\",\"🇸🇱\":\"1f1f8-1f1f1\",\"🇸🇲\":\"1f1f8-1f1f2\",\"🇸🇳\":\"1f1f8-1f1f3\",\"🇸🇴\":\"1f1f8-1f1f4\",\"🇸🇷\":\"1f1f8-1f1f7\",\"🇸🇸\":\"1f1f8-1f1f8\",\"🇸🇹\":\"1f1f8-1f1f9\",\"🇸🇻\":\"1f1f8-1f1fb\",\"🇸🇽\":\"1f1f8-1f1fd\",\"🇸🇾\":\"1f1f8-1f1fe\",\"🇸🇿\":\"1f1f8-1f1ff\",\"🇹🇦\":\"1f1f9-1f1e6\",\"🇹🇨\":\"1f1f9-1f1e8\",\"🇹🇩\":\"1f1f9-1f1e9\",\"🇹🇫\":\"1f1f9-1f1eb\",\"🇹🇬\":\"1f1f9-1f1ec\",\"🇹🇭\":\"1f1f9-1f1ed\",\"🇹🇯\":\"1f1f9-1f1ef\",\"🇹🇰\":\"1f1f9-1f1f0\",\"🇹🇱\":\"1f1f9-1f1f1\",\"🇹🇲\":\"1f1f9-1f1f2\",\"🇹🇳\":\"1f1f9-1f1f3\",\"🇹🇴\":\"1f1f9-1f1f4\",\"🇹🇷\":\"1f1f9-1f1f7\",\"🇹🇹\":\"1f1f9-1f1f9\",\"🇹🇻\":\"1f1f9-1f1fb\",\"🇹🇼\":\"1f1f9-1f1fc\",\"🇹🇿\":\"1f1f9-1f1ff\",\"🇺🇦\":\"1f1fa-1f1e6\",\"🇺🇬\":\"1f1fa-1f1ec\",\"🇺🇲\":\"1f1fa-1f1f2\",\"🇺🇳\":\"1f1fa-1f1f3\",\"🇺🇸\":\"1f1fa-1f1f8\",\"🇺🇾\":\"1f1fa-1f1fe\",\"🇺🇿\":\"1f1fa-1f1ff\",\"🇻🇦\":\"1f1fb-1f1e6\",\"🇻🇨\":\"1f1fb-1f1e8\",\"🇻🇪\":\"1f1fb-1f1ea\",\"🇻🇬\":\"1f1fb-1f1ec\",\"🇻🇮\":\"1f1fb-1f1ee\",\"🇻🇳\":\"1f1fb-1f1f3\",\"🇻🇺\":\"1f1fb-1f1fa\",\"🇼🇫\":\"1f1fc-1f1eb\",\"🇼🇸\":\"1f1fc-1f1f8\",\"🇽🇰\":\"1f1fd-1f1f0\",\"🇾🇪\":\"1f1fe-1f1ea\",\"🇾🇹\":\"1f1fe-1f1f9\",\"🇿🇦\":\"1f1ff-1f1e6\",\"🇿🇲\":\"1f1ff-1f1f2\",\"🇿🇼\":\"1f1ff-1f1fc\",\"👨‍⚕\":\"1f468-200d-2695-fe0f\",\"👩‍⚕\":\"1f469-200d-2695-fe0f\",\"👨‍🎓\":\"1f468-200d-1f393\",\"👩‍🎓\":\"1f469-200d-1f393\",\"👨‍🏫\":\"1f468-200d-1f3eb\",\"👩‍🏫\":\"1f469-200d-1f3eb\",\"👨‍⚖\":\"1f468-200d-2696-fe0f\",\"👩‍⚖\":\"1f469-200d-2696-fe0f\",\"👨‍🌾\":\"1f468-200d-1f33e\",\"👩‍🌾\":\"1f469-200d-1f33e\",\"👨‍🍳\":\"1f468-200d-1f373\",\"👩‍🍳\":\"1f469-200d-1f373\",\"👨‍🔧\":\"1f468-200d-1f527\",\"👩‍🔧\":\"1f469-200d-1f527\",\"👨‍🏭\":\"1f468-200d-1f3ed\",\"👩‍🏭\":\"1f469-200d-1f3ed\",\"👨‍💼\":\"1f468-200d-1f4bc\",\"👩‍💼\":\"1f469-200d-1f4bc\",\"👨‍🔬\":\"1f468-200d-1f52c\",\"👩‍🔬\":\"1f469-200d-1f52c\",\"👨‍💻\":\"1f468-200d-1f4bb\",\"👩‍💻\":\"1f469-200d-1f4bb\",\"👨‍🎤\":\"1f468-200d-1f3a4\",\"👩‍🎤\":\"1f469-200d-1f3a4\",\"👨‍🎨\":\"1f468-200d-1f3a8\",\"👩‍🎨\":\"1f469-200d-1f3a8\",\"👨‍✈\":\"1f468-200d-2708-fe0f\",\"👩‍✈\":\"1f469-200d-2708-fe0f\",\"👨‍🚀\":\"1f468-200d-1f680\",\"👩‍🚀\":\"1f469-200d-1f680\",\"👨‍🚒\":\"1f468-200d-1f692\",\"👩‍🚒\":\"1f469-200d-1f692\",\"👮‍♂\":\"1f46e-200d-2642-fe0f\",\"👮‍♀\":\"1f46e-200d-2640-fe0f\",\"🕵‍♂\":\"1f575-fe0f-200d-2642-fe0f\",\"🕵‍♀\":\"1f575-fe0f-200d-2640-fe0f\",\"💂‍♂\":\"1f482-200d-2642-fe0f\",\"💂‍♀\":\"1f482-200d-2640-fe0f\",\"👷‍♂\":\"1f477-200d-2642-fe0f\",\"👷‍♀\":\"1f477-200d-2640-fe0f\",\"👳‍♂\":\"1f473-200d-2642-fe0f\",\"👳‍♀\":\"1f473-200d-2640-fe0f\",\"👱‍♂\":\"1f471-200d-2642-fe0f\",\"👱‍♀\":\"1f471-200d-2640-fe0f\",\"👨‍🦰\":\"1f468-200d-1f9b0\",\"👩‍🦰\":\"1f469-200d-1f9b0\",\"👨‍🦱\":\"1f468-200d-1f9b1\",\"👩‍🦱\":\"1f469-200d-1f9b1\",\"👨‍🦲\":\"1f468-200d-1f9b2\",\"👩‍🦲\":\"1f469-200d-1f9b2\",\"👨‍🦳\":\"1f468-200d-1f9b3\",\"👩‍🦳\":\"1f469-200d-1f9b3\",\"🦸‍♀\":\"1f9b8-200d-2640-fe0f\",\"🦸‍♂\":\"1f9b8-200d-2642-fe0f\",\"🦹‍♀\":\"1f9b9-200d-2640-fe0f\",\"🦹‍♂\":\"1f9b9-200d-2642-fe0f\",\"🧙‍♀\":\"1f9d9-200d-2640-fe0f\",\"🧙‍♂\":\"1f9d9-200d-2642-fe0f\",\"🧚‍♀\":\"1f9da-200d-2640-fe0f\",\"🧚‍♂\":\"1f9da-200d-2642-fe0f\",\"🧛‍♀\":\"1f9db-200d-2640-fe0f\",\"🧛‍♂\":\"1f9db-200d-2642-fe0f\",\"🧜‍♀\":\"1f9dc-200d-2640-fe0f\",\"🧜‍♂\":\"1f9dc-200d-2642-fe0f\",\"🧝‍♀\":\"1f9dd-200d-2640-fe0f\",\"🧝‍♂\":\"1f9dd-200d-2642-fe0f\",\"🧞‍♀\":\"1f9de-200d-2640-fe0f\",\"🧞‍♂\":\"1f9de-200d-2642-fe0f\",\"🧟‍♀\":\"1f9df-200d-2640-fe0f\",\"🧟‍♂\":\"1f9df-200d-2642-fe0f\",\"🙍‍♂\":\"1f64d-200d-2642-fe0f\",\"🙍‍♀\":\"1f64d-200d-2640-fe0f\",\"🙎‍♂\":\"1f64e-200d-2642-fe0f\",\"🙎‍♀\":\"1f64e-200d-2640-fe0f\",\"🙅‍♂\":\"1f645-200d-2642-fe0f\",\"🙅‍♀\":\"1f645-200d-2640-fe0f\",\"🙆‍♂\":\"1f646-200d-2642-fe0f\",\"🙆‍♀\":\"1f646-200d-2640-fe0f\",\"💁‍♂\":\"1f481-200d-2642-fe0f\",\"💁‍♀\":\"1f481-200d-2640-fe0f\",\"🙋‍♂\":\"1f64b-200d-2642-fe0f\",\"🙋‍♀\":\"1f64b-200d-2640-fe0f\",\"🙇‍♂\":\"1f647-200d-2642-fe0f\",\"🙇‍♀\":\"1f647-200d-2640-fe0f\",\"🤦‍♂\":\"1f926-200d-2642-fe0f\",\"🤦‍♀\":\"1f926-200d-2640-fe0f\",\"🤷‍♂\":\"1f937-200d-2642-fe0f\",\"🤷‍♀\":\"1f937-200d-2640-fe0f\",\"💆‍♂\":\"1f486-200d-2642-fe0f\",\"💆‍♀\":\"1f486-200d-2640-fe0f\",\"💇‍♂\":\"1f487-200d-2642-fe0f\",\"💇‍♀\":\"1f487-200d-2640-fe0f\",\"🚶‍♂\":\"1f6b6-200d-2642-fe0f\",\"🚶‍♀\":\"1f6b6-200d-2640-fe0f\",\"🏃‍♂\":\"1f3c3-200d-2642-fe0f\",\"🏃‍♀\":\"1f3c3-200d-2640-fe0f\",\"👯‍♂\":\"1f46f-200d-2642-fe0f\",\"👯‍♀\":\"1f46f-200d-2640-fe0f\",\"🧖‍♀\":\"1f9d6-200d-2640-fe0f\",\"🧖‍♂\":\"1f9d6-200d-2642-fe0f\",\"🧗‍♀\":\"1f9d7-200d-2640-fe0f\",\"🧗‍♂\":\"1f9d7-200d-2642-fe0f\",\"🧘‍♀\":\"1f9d8-200d-2640-fe0f\",\"🧘‍♂\":\"1f9d8-200d-2642-fe0f\",\"🏌‍♂\":\"1f3cc-fe0f-200d-2642-fe0f\",\"🏌‍♀\":\"1f3cc-fe0f-200d-2640-fe0f\",\"🏄‍♂\":\"1f3c4-200d-2642-fe0f\",\"🏄‍♀\":\"1f3c4-200d-2640-fe0f\",\"🚣‍♂\":\"1f6a3-200d-2642-fe0f\",\"🚣‍♀\":\"1f6a3-200d-2640-fe0f\",\"🏊‍♂\":\"1f3ca-200d-2642-fe0f\",\"🏊‍♀\":\"1f3ca-200d-2640-fe0f\",\"⛹‍♂\":\"26f9-fe0f-200d-2642-fe0f\",\"⛹‍♀\":\"26f9-fe0f-200d-2640-fe0f\",\"🏋‍♂\":\"1f3cb-fe0f-200d-2642-fe0f\",\"🏋‍♀\":\"1f3cb-fe0f-200d-2640-fe0f\",\"🚴‍♂\":\"1f6b4-200d-2642-fe0f\",\"🚴‍♀\":\"1f6b4-200d-2640-fe0f\",\"🚵‍♂\":\"1f6b5-200d-2642-fe0f\",\"🚵‍♀\":\"1f6b5-200d-2640-fe0f\",\"🤸‍♂\":\"1f938-200d-2642-fe0f\",\"🤸‍♀\":\"1f938-200d-2640-fe0f\",\"🤼‍♂\":\"1f93c-200d-2642-fe0f\",\"🤼‍♀\":\"1f93c-200d-2640-fe0f\",\"🤽‍♂\":\"1f93d-200d-2642-fe0f\",\"🤽‍♀\":\"1f93d-200d-2640-fe0f\",\"🤾‍♂\":\"1f93e-200d-2642-fe0f\",\"🤾‍♀\":\"1f93e-200d-2640-fe0f\",\"🤹‍♂\":\"1f939-200d-2642-fe0f\",\"🤹‍♀\":\"1f939-200d-2640-fe0f\",\"👨‍👦\":\"1f468-200d-1f466\",\"👨‍👧\":\"1f468-200d-1f467\",\"👩‍👦\":\"1f469-200d-1f466\",\"👩‍👧\":\"1f469-200d-1f467\",\"👁‍🗨\":\"1f441-200d-1f5e8\",\"#️⃣\":\"23-20e3\",\"*️⃣\":\"2a-20e3\",\"0️⃣\":\"30-20e3\",\"1️⃣\":\"31-20e3\",\"2️⃣\":\"32-20e3\",\"3️⃣\":\"33-20e3\",\"4️⃣\":\"34-20e3\",\"5️⃣\":\"35-20e3\",\"6️⃣\":\"36-20e3\",\"7️⃣\":\"37-20e3\",\"8️⃣\":\"38-20e3\",\"9️⃣\":\"39-20e3\",\"🏳‍🌈\":\"1f3f3-fe0f-200d-1f308\",\"🏴‍☠\":\"1f3f4-200d-2620-fe0f\",\"👨‍⚕️\":\"1f468-200d-2695-fe0f\",\"👨🏻‍⚕\":\"1f468-1f3fb-200d-2695-fe0f\",\"👨🏼‍⚕\":\"1f468-1f3fc-200d-2695-fe0f\",\"👨🏽‍⚕\":\"1f468-1f3fd-200d-2695-fe0f\",\"👨🏾‍⚕\":\"1f468-1f3fe-200d-2695-fe0f\",\"👨🏿‍⚕\":\"1f468-1f3ff-200d-2695-fe0f\",\"👩‍⚕️\":\"1f469-200d-2695-fe0f\",\"👩🏻‍⚕\":\"1f469-1f3fb-200d-2695-fe0f\",\"👩🏼‍⚕\":\"1f469-1f3fc-200d-2695-fe0f\",\"👩🏽‍⚕\":\"1f469-1f3fd-200d-2695-fe0f\",\"👩🏾‍⚕\":\"1f469-1f3fe-200d-2695-fe0f\",\"👩🏿‍⚕\":\"1f469-1f3ff-200d-2695-fe0f\",\"👨🏻‍🎓\":\"1f468-1f3fb-200d-1f393\",\"👨🏼‍🎓\":\"1f468-1f3fc-200d-1f393\",\"👨🏽‍🎓\":\"1f468-1f3fd-200d-1f393\",\"👨🏾‍🎓\":\"1f468-1f3fe-200d-1f393\",\"👨🏿‍🎓\":\"1f468-1f3ff-200d-1f393\",\"👩🏻‍🎓\":\"1f469-1f3fb-200d-1f393\",\"👩🏼‍🎓\":\"1f469-1f3fc-200d-1f393\",\"👩🏽‍🎓\":\"1f469-1f3fd-200d-1f393\",\"👩🏾‍🎓\":\"1f469-1f3fe-200d-1f393\",\"👩🏿‍🎓\":\"1f469-1f3ff-200d-1f393\",\"👨🏻‍🏫\":\"1f468-1f3fb-200d-1f3eb\",\"👨🏼‍🏫\":\"1f468-1f3fc-200d-1f3eb\",\"👨🏽‍🏫\":\"1f468-1f3fd-200d-1f3eb\",\"👨🏾‍🏫\":\"1f468-1f3fe-200d-1f3eb\",\"👨🏿‍🏫\":\"1f468-1f3ff-200d-1f3eb\",\"👩🏻‍🏫\":\"1f469-1f3fb-200d-1f3eb\",\"👩🏼‍🏫\":\"1f469-1f3fc-200d-1f3eb\",\"👩🏽‍🏫\":\"1f469-1f3fd-200d-1f3eb\",\"👩🏾‍🏫\":\"1f469-1f3fe-200d-1f3eb\",\"👩🏿‍🏫\":\"1f469-1f3ff-200d-1f3eb\",\"👨‍⚖️\":\"1f468-200d-2696-fe0f\",\"👨🏻‍⚖\":\"1f468-1f3fb-200d-2696-fe0f\",\"👨🏼‍⚖\":\"1f468-1f3fc-200d-2696-fe0f\",\"👨🏽‍⚖\":\"1f468-1f3fd-200d-2696-fe0f\",\"👨🏾‍⚖\":\"1f468-1f3fe-200d-2696-fe0f\",\"👨🏿‍⚖\":\"1f468-1f3ff-200d-2696-fe0f\",\"👩‍⚖️\":\"1f469-200d-2696-fe0f\",\"👩🏻‍⚖\":\"1f469-1f3fb-200d-2696-fe0f\",\"👩🏼‍⚖\":\"1f469-1f3fc-200d-2696-fe0f\",\"👩🏽‍⚖\":\"1f469-1f3fd-200d-2696-fe0f\",\"👩🏾‍⚖\":\"1f469-1f3fe-200d-2696-fe0f\",\"👩🏿‍⚖\":\"1f469-1f3ff-200d-2696-fe0f\",\"👨🏻‍🌾\":\"1f468-1f3fb-200d-1f33e\",\"👨🏼‍🌾\":\"1f468-1f3fc-200d-1f33e\",\"👨🏽‍🌾\":\"1f468-1f3fd-200d-1f33e\",\"👨🏾‍🌾\":\"1f468-1f3fe-200d-1f33e\",\"👨🏿‍🌾\":\"1f468-1f3ff-200d-1f33e\",\"👩🏻‍🌾\":\"1f469-1f3fb-200d-1f33e\",\"👩🏼‍🌾\":\"1f469-1f3fc-200d-1f33e\",\"👩🏽‍🌾\":\"1f469-1f3fd-200d-1f33e\",\"👩🏾‍🌾\":\"1f469-1f3fe-200d-1f33e\",\"👩🏿‍🌾\":\"1f469-1f3ff-200d-1f33e\",\"👨🏻‍🍳\":\"1f468-1f3fb-200d-1f373\",\"👨🏼‍🍳\":\"1f468-1f3fc-200d-1f373\",\"👨🏽‍🍳\":\"1f468-1f3fd-200d-1f373\",\"👨🏾‍🍳\":\"1f468-1f3fe-200d-1f373\",\"👨🏿‍🍳\":\"1f468-1f3ff-200d-1f373\",\"👩🏻‍🍳\":\"1f469-1f3fb-200d-1f373\",\"👩🏼‍🍳\":\"1f469-1f3fc-200d-1f373\",\"👩🏽‍🍳\":\"1f469-1f3fd-200d-1f373\",\"👩🏾‍🍳\":\"1f469-1f3fe-200d-1f373\",\"👩🏿‍🍳\":\"1f469-1f3ff-200d-1f373\",\"👨🏻‍🔧\":\"1f468-1f3fb-200d-1f527\",\"👨🏼‍🔧\":\"1f468-1f3fc-200d-1f527\",\"👨🏽‍🔧\":\"1f468-1f3fd-200d-1f527\",\"👨🏾‍🔧\":\"1f468-1f3fe-200d-1f527\",\"👨🏿‍🔧\":\"1f468-1f3ff-200d-1f527\",\"👩🏻‍🔧\":\"1f469-1f3fb-200d-1f527\",\"👩🏼‍🔧\":\"1f469-1f3fc-200d-1f527\",\"👩🏽‍🔧\":\"1f469-1f3fd-200d-1f527\",\"👩🏾‍🔧\":\"1f469-1f3fe-200d-1f527\",\"👩🏿‍🔧\":\"1f469-1f3ff-200d-1f527\",\"👨🏻‍🏭\":\"1f468-1f3fb-200d-1f3ed\",\"👨🏼‍🏭\":\"1f468-1f3fc-200d-1f3ed\",\"👨🏽‍🏭\":\"1f468-1f3fd-200d-1f3ed\",\"👨🏾‍🏭\":\"1f468-1f3fe-200d-1f3ed\",\"👨🏿‍🏭\":\"1f468-1f3ff-200d-1f3ed\",\"👩🏻‍🏭\":\"1f469-1f3fb-200d-1f3ed\",\"👩🏼‍🏭\":\"1f469-1f3fc-200d-1f3ed\",\"👩🏽‍🏭\":\"1f469-1f3fd-200d-1f3ed\",\"👩🏾‍🏭\":\"1f469-1f3fe-200d-1f3ed\",\"👩🏿‍🏭\":\"1f469-1f3ff-200d-1f3ed\",\"👨🏻‍💼\":\"1f468-1f3fb-200d-1f4bc\",\"👨🏼‍💼\":\"1f468-1f3fc-200d-1f4bc\",\"👨🏽‍💼\":\"1f468-1f3fd-200d-1f4bc\",\"👨🏾‍💼\":\"1f468-1f3fe-200d-1f4bc\",\"👨🏿‍💼\":\"1f468-1f3ff-200d-1f4bc\",\"👩🏻‍💼\":\"1f469-1f3fb-200d-1f4bc\",\"👩🏼‍💼\":\"1f469-1f3fc-200d-1f4bc\",\"👩🏽‍💼\":\"1f469-1f3fd-200d-1f4bc\",\"👩🏾‍💼\":\"1f469-1f3fe-200d-1f4bc\",\"👩🏿‍💼\":\"1f469-1f3ff-200d-1f4bc\",\"👨🏻‍🔬\":\"1f468-1f3fb-200d-1f52c\",\"👨🏼‍🔬\":\"1f468-1f3fc-200d-1f52c\",\"👨🏽‍🔬\":\"1f468-1f3fd-200d-1f52c\",\"👨🏾‍🔬\":\"1f468-1f3fe-200d-1f52c\",\"👨🏿‍🔬\":\"1f468-1f3ff-200d-1f52c\",\"👩🏻‍🔬\":\"1f469-1f3fb-200d-1f52c\",\"👩🏼‍🔬\":\"1f469-1f3fc-200d-1f52c\",\"👩🏽‍🔬\":\"1f469-1f3fd-200d-1f52c\",\"👩🏾‍🔬\":\"1f469-1f3fe-200d-1f52c\",\"👩🏿‍🔬\":\"1f469-1f3ff-200d-1f52c\",\"👨🏻‍💻\":\"1f468-1f3fb-200d-1f4bb\",\"👨🏼‍💻\":\"1f468-1f3fc-200d-1f4bb\",\"👨🏽‍💻\":\"1f468-1f3fd-200d-1f4bb\",\"👨🏾‍💻\":\"1f468-1f3fe-200d-1f4bb\",\"👨🏿‍💻\":\"1f468-1f3ff-200d-1f4bb\",\"👩🏻‍💻\":\"1f469-1f3fb-200d-1f4bb\",\"👩🏼‍💻\":\"1f469-1f3fc-200d-1f4bb\",\"👩🏽‍💻\":\"1f469-1f3fd-200d-1f4bb\",\"👩🏾‍💻\":\"1f469-1f3fe-200d-1f4bb\",\"👩🏿‍💻\":\"1f469-1f3ff-200d-1f4bb\",\"👨🏻‍🎤\":\"1f468-1f3fb-200d-1f3a4\",\"👨🏼‍🎤\":\"1f468-1f3fc-200d-1f3a4\",\"👨🏽‍🎤\":\"1f468-1f3fd-200d-1f3a4\",\"👨🏾‍🎤\":\"1f468-1f3fe-200d-1f3a4\",\"👨🏿‍🎤\":\"1f468-1f3ff-200d-1f3a4\",\"👩🏻‍🎤\":\"1f469-1f3fb-200d-1f3a4\",\"👩🏼‍🎤\":\"1f469-1f3fc-200d-1f3a4\",\"👩🏽‍🎤\":\"1f469-1f3fd-200d-1f3a4\",\"👩🏾‍🎤\":\"1f469-1f3fe-200d-1f3a4\",\"👩🏿‍🎤\":\"1f469-1f3ff-200d-1f3a4\",\"👨🏻‍🎨\":\"1f468-1f3fb-200d-1f3a8\",\"👨🏼‍🎨\":\"1f468-1f3fc-200d-1f3a8\",\"👨🏽‍🎨\":\"1f468-1f3fd-200d-1f3a8\",\"👨🏾‍🎨\":\"1f468-1f3fe-200d-1f3a8\",\"👨🏿‍🎨\":\"1f468-1f3ff-200d-1f3a8\",\"👩🏻‍🎨\":\"1f469-1f3fb-200d-1f3a8\",\"👩🏼‍🎨\":\"1f469-1f3fc-200d-1f3a8\",\"👩🏽‍🎨\":\"1f469-1f3fd-200d-1f3a8\",\"👩🏾‍🎨\":\"1f469-1f3fe-200d-1f3a8\",\"👩🏿‍🎨\":\"1f469-1f3ff-200d-1f3a8\",\"👨‍✈️\":\"1f468-200d-2708-fe0f\",\"👨🏻‍✈\":\"1f468-1f3fb-200d-2708-fe0f\",\"👨🏼‍✈\":\"1f468-1f3fc-200d-2708-fe0f\",\"👨🏽‍✈\":\"1f468-1f3fd-200d-2708-fe0f\",\"👨🏾‍✈\":\"1f468-1f3fe-200d-2708-fe0f\",\"👨🏿‍✈\":\"1f468-1f3ff-200d-2708-fe0f\",\"👩‍✈️\":\"1f469-200d-2708-fe0f\",\"👩🏻‍✈\":\"1f469-1f3fb-200d-2708-fe0f\",\"👩🏼‍✈\":\"1f469-1f3fc-200d-2708-fe0f\",\"👩🏽‍✈\":\"1f469-1f3fd-200d-2708-fe0f\",\"👩🏾‍✈\":\"1f469-1f3fe-200d-2708-fe0f\",\"👩🏿‍✈\":\"1f469-1f3ff-200d-2708-fe0f\",\"👨🏻‍🚀\":\"1f468-1f3fb-200d-1f680\",\"👨🏼‍🚀\":\"1f468-1f3fc-200d-1f680\",\"👨🏽‍🚀\":\"1f468-1f3fd-200d-1f680\",\"👨🏾‍🚀\":\"1f468-1f3fe-200d-1f680\",\"👨🏿‍🚀\":\"1f468-1f3ff-200d-1f680\",\"👩🏻‍🚀\":\"1f469-1f3fb-200d-1f680\",\"👩🏼‍🚀\":\"1f469-1f3fc-200d-1f680\",\"👩🏽‍🚀\":\"1f469-1f3fd-200d-1f680\",\"👩🏾‍🚀\":\"1f469-1f3fe-200d-1f680\",\"👩🏿‍🚀\":\"1f469-1f3ff-200d-1f680\",\"👨🏻‍🚒\":\"1f468-1f3fb-200d-1f692\",\"👨🏼‍🚒\":\"1f468-1f3fc-200d-1f692\",\"👨🏽‍🚒\":\"1f468-1f3fd-200d-1f692\",\"👨🏾‍🚒\":\"1f468-1f3fe-200d-1f692\",\"👨🏿‍🚒\":\"1f468-1f3ff-200d-1f692\",\"👩🏻‍🚒\":\"1f469-1f3fb-200d-1f692\",\"👩🏼‍🚒\":\"1f469-1f3fc-200d-1f692\",\"👩🏽‍🚒\":\"1f469-1f3fd-200d-1f692\",\"👩🏾‍🚒\":\"1f469-1f3fe-200d-1f692\",\"👩🏿‍🚒\":\"1f469-1f3ff-200d-1f692\",\"👮‍♂️\":\"1f46e-200d-2642-fe0f\",\"👮🏻‍♂\":\"1f46e-1f3fb-200d-2642-fe0f\",\"👮🏼‍♂\":\"1f46e-1f3fc-200d-2642-fe0f\",\"👮🏽‍♂\":\"1f46e-1f3fd-200d-2642-fe0f\",\"👮🏾‍♂\":\"1f46e-1f3fe-200d-2642-fe0f\",\"👮🏿‍♂\":\"1f46e-1f3ff-200d-2642-fe0f\",\"👮‍♀️\":\"1f46e-200d-2640-fe0f\",\"👮🏻‍♀\":\"1f46e-1f3fb-200d-2640-fe0f\",\"👮🏼‍♀\":\"1f46e-1f3fc-200d-2640-fe0f\",\"👮🏽‍♀\":\"1f46e-1f3fd-200d-2640-fe0f\",\"👮🏾‍♀\":\"1f46e-1f3fe-200d-2640-fe0f\",\"👮🏿‍♀\":\"1f46e-1f3ff-200d-2640-fe0f\",\"🕵‍♂️\":\"1f575-fe0f-200d-2642-fe0f\",\"🕵️‍♂\":\"1f575-fe0f-200d-2642-fe0f\",\"🕵🏻‍♂\":\"1f575-1f3fb-200d-2642-fe0f\",\"🕵🏼‍♂\":\"1f575-1f3fc-200d-2642-fe0f\",\"🕵🏽‍♂\":\"1f575-1f3fd-200d-2642-fe0f\",\"🕵🏾‍♂\":\"1f575-1f3fe-200d-2642-fe0f\",\"🕵🏿‍♂\":\"1f575-1f3ff-200d-2642-fe0f\",\"🕵‍♀️\":\"1f575-fe0f-200d-2640-fe0f\",\"🕵️‍♀\":\"1f575-fe0f-200d-2640-fe0f\",\"🕵🏻‍♀\":\"1f575-1f3fb-200d-2640-fe0f\",\"🕵🏼‍♀\":\"1f575-1f3fc-200d-2640-fe0f\",\"🕵🏽‍♀\":\"1f575-1f3fd-200d-2640-fe0f\",\"🕵🏾‍♀\":\"1f575-1f3fe-200d-2640-fe0f\",\"🕵🏿‍♀\":\"1f575-1f3ff-200d-2640-fe0f\",\"💂‍♂️\":\"1f482-200d-2642-fe0f\",\"💂🏻‍♂\":\"1f482-1f3fb-200d-2642-fe0f\",\"💂🏼‍♂\":\"1f482-1f3fc-200d-2642-fe0f\",\"💂🏽‍♂\":\"1f482-1f3fd-200d-2642-fe0f\",\"💂🏾‍♂\":\"1f482-1f3fe-200d-2642-fe0f\",\"💂🏿‍♂\":\"1f482-1f3ff-200d-2642-fe0f\",\"💂‍♀️\":\"1f482-200d-2640-fe0f\",\"💂🏻‍♀\":\"1f482-1f3fb-200d-2640-fe0f\",\"💂🏼‍♀\":\"1f482-1f3fc-200d-2640-fe0f\",\"💂🏽‍♀\":\"1f482-1f3fd-200d-2640-fe0f\",\"💂🏾‍♀\":\"1f482-1f3fe-200d-2640-fe0f\",\"💂🏿‍♀\":\"1f482-1f3ff-200d-2640-fe0f\",\"👷‍♂️\":\"1f477-200d-2642-fe0f\",\"👷🏻‍♂\":\"1f477-1f3fb-200d-2642-fe0f\",\"👷🏼‍♂\":\"1f477-1f3fc-200d-2642-fe0f\",\"👷🏽‍♂\":\"1f477-1f3fd-200d-2642-fe0f\",\"👷🏾‍♂\":\"1f477-1f3fe-200d-2642-fe0f\",\"👷🏿‍♂\":\"1f477-1f3ff-200d-2642-fe0f\",\"👷‍♀️\":\"1f477-200d-2640-fe0f\",\"👷🏻‍♀\":\"1f477-1f3fb-200d-2640-fe0f\",\"👷🏼‍♀\":\"1f477-1f3fc-200d-2640-fe0f\",\"👷🏽‍♀\":\"1f477-1f3fd-200d-2640-fe0f\",\"👷🏾‍♀\":\"1f477-1f3fe-200d-2640-fe0f\",\"👷🏿‍♀\":\"1f477-1f3ff-200d-2640-fe0f\",\"👳‍♂️\":\"1f473-200d-2642-fe0f\",\"👳🏻‍♂\":\"1f473-1f3fb-200d-2642-fe0f\",\"👳🏼‍♂\":\"1f473-1f3fc-200d-2642-fe0f\",\"👳🏽‍♂\":\"1f473-1f3fd-200d-2642-fe0f\",\"👳🏾‍♂\":\"1f473-1f3fe-200d-2642-fe0f\",\"👳🏿‍♂\":\"1f473-1f3ff-200d-2642-fe0f\",\"👳‍♀️\":\"1f473-200d-2640-fe0f\",\"👳🏻‍♀\":\"1f473-1f3fb-200d-2640-fe0f\",\"👳🏼‍♀\":\"1f473-1f3fc-200d-2640-fe0f\",\"👳🏽‍♀\":\"1f473-1f3fd-200d-2640-fe0f\",\"👳🏾‍♀\":\"1f473-1f3fe-200d-2640-fe0f\",\"👳🏿‍♀\":\"1f473-1f3ff-200d-2640-fe0f\",\"👱‍♂️\":\"1f471-200d-2642-fe0f\",\"👱🏻‍♂\":\"1f471-1f3fb-200d-2642-fe0f\",\"👱🏼‍♂\":\"1f471-1f3fc-200d-2642-fe0f\",\"👱🏽‍♂\":\"1f471-1f3fd-200d-2642-fe0f\",\"👱🏾‍♂\":\"1f471-1f3fe-200d-2642-fe0f\",\"👱🏿‍♂\":\"1f471-1f3ff-200d-2642-fe0f\",\"👱‍♀️\":\"1f471-200d-2640-fe0f\",\"👱🏻‍♀\":\"1f471-1f3fb-200d-2640-fe0f\",\"👱🏼‍♀\":\"1f471-1f3fc-200d-2640-fe0f\",\"👱🏽‍♀\":\"1f471-1f3fd-200d-2640-fe0f\",\"👱🏾‍♀\":\"1f471-1f3fe-200d-2640-fe0f\",\"👱🏿‍♀\":\"1f471-1f3ff-200d-2640-fe0f\",\"👨🏻‍🦰\":\"1f468-1f3fb-200d-1f9b0\",\"👨🏼‍🦰\":\"1f468-1f3fc-200d-1f9b0\",\"👨🏽‍🦰\":\"1f468-1f3fd-200d-1f9b0\",\"👨🏾‍🦰\":\"1f468-1f3fe-200d-1f9b0\",\"👨🏿‍🦰\":\"1f468-1f3ff-200d-1f9b0\",\"👩🏻‍🦰\":\"1f469-1f3fb-200d-1f9b0\",\"👩🏼‍🦰\":\"1f469-1f3fc-200d-1f9b0\",\"👩🏽‍🦰\":\"1f469-1f3fd-200d-1f9b0\",\"👩🏾‍🦰\":\"1f469-1f3fe-200d-1f9b0\",\"👩🏿‍🦰\":\"1f469-1f3ff-200d-1f9b0\",\"👨🏻‍🦱\":\"1f468-1f3fb-200d-1f9b1\",\"👨🏼‍🦱\":\"1f468-1f3fc-200d-1f9b1\",\"👨🏽‍🦱\":\"1f468-1f3fd-200d-1f9b1\",\"👨🏾‍🦱\":\"1f468-1f3fe-200d-1f9b1\",\"👨🏿‍🦱\":\"1f468-1f3ff-200d-1f9b1\",\"👩🏻‍🦱\":\"1f469-1f3fb-200d-1f9b1\",\"👩🏼‍🦱\":\"1f469-1f3fc-200d-1f9b1\",\"👩🏽‍🦱\":\"1f469-1f3fd-200d-1f9b1\",\"👩🏾‍🦱\":\"1f469-1f3fe-200d-1f9b1\",\"👩🏿‍🦱\":\"1f469-1f3ff-200d-1f9b1\",\"👨🏻‍🦲\":\"1f468-1f3fb-200d-1f9b2\",\"👨🏼‍🦲\":\"1f468-1f3fc-200d-1f9b2\",\"👨🏽‍🦲\":\"1f468-1f3fd-200d-1f9b2\",\"👨🏾‍🦲\":\"1f468-1f3fe-200d-1f9b2\",\"👨🏿‍🦲\":\"1f468-1f3ff-200d-1f9b2\",\"👩🏻‍🦲\":\"1f469-1f3fb-200d-1f9b2\",\"👩🏼‍🦲\":\"1f469-1f3fc-200d-1f9b2\",\"👩🏽‍🦲\":\"1f469-1f3fd-200d-1f9b2\",\"👩🏾‍🦲\":\"1f469-1f3fe-200d-1f9b2\",\"👩🏿‍🦲\":\"1f469-1f3ff-200d-1f9b2\",\"👨🏻‍🦳\":\"1f468-1f3fb-200d-1f9b3\",\"👨🏼‍🦳\":\"1f468-1f3fc-200d-1f9b3\",\"👨🏽‍🦳\":\"1f468-1f3fd-200d-1f9b3\",\"👨🏾‍🦳\":\"1f468-1f3fe-200d-1f9b3\",\"👨🏿‍🦳\":\"1f468-1f3ff-200d-1f9b3\",\"👩🏻‍🦳\":\"1f469-1f3fb-200d-1f9b3\",\"👩🏼‍🦳\":\"1f469-1f3fc-200d-1f9b3\",\"👩🏽‍🦳\":\"1f469-1f3fd-200d-1f9b3\",\"👩🏾‍🦳\":\"1f469-1f3fe-200d-1f9b3\",\"👩🏿‍🦳\":\"1f469-1f3ff-200d-1f9b3\",\"🦸‍♀️\":\"1f9b8-200d-2640-fe0f\",\"🦸🏻‍♀\":\"1f9b8-1f3fb-200d-2640-fe0f\",\"🦸🏼‍♀\":\"1f9b8-1f3fc-200d-2640-fe0f\",\"🦸🏽‍♀\":\"1f9b8-1f3fd-200d-2640-fe0f\",\"🦸🏾‍♀\":\"1f9b8-1f3fe-200d-2640-fe0f\",\"🦸🏿‍♀\":\"1f9b8-1f3ff-200d-2640-fe0f\",\"🦸‍♂️\":\"1f9b8-200d-2642-fe0f\",\"🦸🏻‍♂\":\"1f9b8-1f3fb-200d-2642-fe0f\",\"🦸🏼‍♂\":\"1f9b8-1f3fc-200d-2642-fe0f\",\"🦸🏽‍♂\":\"1f9b8-1f3fd-200d-2642-fe0f\",\"🦸🏾‍♂\":\"1f9b8-1f3fe-200d-2642-fe0f\",\"🦸🏿‍♂\":\"1f9b8-1f3ff-200d-2642-fe0f\",\"🦹‍♀️\":\"1f9b9-200d-2640-fe0f\",\"🦹🏻‍♀\":\"1f9b9-1f3fb-200d-2640-fe0f\",\"🦹🏼‍♀\":\"1f9b9-1f3fc-200d-2640-fe0f\",\"🦹🏽‍♀\":\"1f9b9-1f3fd-200d-2640-fe0f\",\"🦹🏾‍♀\":\"1f9b9-1f3fe-200d-2640-fe0f\",\"🦹🏿‍♀\":\"1f9b9-1f3ff-200d-2640-fe0f\",\"🦹‍♂️\":\"1f9b9-200d-2642-fe0f\",\"🦹🏻‍♂\":\"1f9b9-1f3fb-200d-2642-fe0f\",\"🦹🏼‍♂\":\"1f9b9-1f3fc-200d-2642-fe0f\",\"🦹🏽‍♂\":\"1f9b9-1f3fd-200d-2642-fe0f\",\"🦹🏾‍♂\":\"1f9b9-1f3fe-200d-2642-fe0f\",\"🦹🏿‍♂\":\"1f9b9-1f3ff-200d-2642-fe0f\",\"🧙‍♀️\":\"1f9d9-200d-2640-fe0f\",\"🧙🏻‍♀\":\"1f9d9-1f3fb-200d-2640-fe0f\",\"🧙🏼‍♀\":\"1f9d9-1f3fc-200d-2640-fe0f\",\"🧙🏽‍♀\":\"1f9d9-1f3fd-200d-2640-fe0f\",\"🧙🏾‍♀\":\"1f9d9-1f3fe-200d-2640-fe0f\",\"🧙🏿‍♀\":\"1f9d9-1f3ff-200d-2640-fe0f\",\"🧙‍♂️\":\"1f9d9-200d-2642-fe0f\",\"🧙🏻‍♂\":\"1f9d9-1f3fb-200d-2642-fe0f\",\"🧙🏼‍♂\":\"1f9d9-1f3fc-200d-2642-fe0f\",\"🧙🏽‍♂\":\"1f9d9-1f3fd-200d-2642-fe0f\",\"🧙🏾‍♂\":\"1f9d9-1f3fe-200d-2642-fe0f\",\"🧙🏿‍♂\":\"1f9d9-1f3ff-200d-2642-fe0f\",\"🧚‍♀️\":\"1f9da-200d-2640-fe0f\",\"🧚🏻‍♀\":\"1f9da-1f3fb-200d-2640-fe0f\",\"🧚🏼‍♀\":\"1f9da-1f3fc-200d-2640-fe0f\",\"🧚🏽‍♀\":\"1f9da-1f3fd-200d-2640-fe0f\",\"🧚🏾‍♀\":\"1f9da-1f3fe-200d-2640-fe0f\",\"🧚🏿‍♀\":\"1f9da-1f3ff-200d-2640-fe0f\",\"🧚‍♂️\":\"1f9da-200d-2642-fe0f\",\"🧚🏻‍♂\":\"1f9da-1f3fb-200d-2642-fe0f\",\"🧚🏼‍♂\":\"1f9da-1f3fc-200d-2642-fe0f\",\"🧚🏽‍♂\":\"1f9da-1f3fd-200d-2642-fe0f\",\"🧚🏾‍♂\":\"1f9da-1f3fe-200d-2642-fe0f\",\"🧚🏿‍♂\":\"1f9da-1f3ff-200d-2642-fe0f\",\"🧛‍♀️\":\"1f9db-200d-2640-fe0f\",\"🧛🏻‍♀\":\"1f9db-1f3fb-200d-2640-fe0f\",\"🧛🏼‍♀\":\"1f9db-1f3fc-200d-2640-fe0f\",\"🧛🏽‍♀\":\"1f9db-1f3fd-200d-2640-fe0f\",\"🧛🏾‍♀\":\"1f9db-1f3fe-200d-2640-fe0f\",\"🧛🏿‍♀\":\"1f9db-1f3ff-200d-2640-fe0f\",\"🧛‍♂️\":\"1f9db-200d-2642-fe0f\",\"🧛🏻‍♂\":\"1f9db-1f3fb-200d-2642-fe0f\",\"🧛🏼‍♂\":\"1f9db-1f3fc-200d-2642-fe0f\",\"🧛🏽‍♂\":\"1f9db-1f3fd-200d-2642-fe0f\",\"🧛🏾‍♂\":\"1f9db-1f3fe-200d-2642-fe0f\",\"🧛🏿‍♂\":\"1f9db-1f3ff-200d-2642-fe0f\",\"🧜‍♀️\":\"1f9dc-200d-2640-fe0f\",\"🧜🏻‍♀\":\"1f9dc-1f3fb-200d-2640-fe0f\",\"🧜🏼‍♀\":\"1f9dc-1f3fc-200d-2640-fe0f\",\"🧜🏽‍♀\":\"1f9dc-1f3fd-200d-2640-fe0f\",\"🧜🏾‍♀\":\"1f9dc-1f3fe-200d-2640-fe0f\",\"🧜🏿‍♀\":\"1f9dc-1f3ff-200d-2640-fe0f\",\"🧜‍♂️\":\"1f9dc-200d-2642-fe0f\",\"🧜🏻‍♂\":\"1f9dc-1f3fb-200d-2642-fe0f\",\"🧜🏼‍♂\":\"1f9dc-1f3fc-200d-2642-fe0f\",\"🧜🏽‍♂\":\"1f9dc-1f3fd-200d-2642-fe0f\",\"🧜🏾‍♂\":\"1f9dc-1f3fe-200d-2642-fe0f\",\"🧜🏿‍♂\":\"1f9dc-1f3ff-200d-2642-fe0f\",\"🧝‍♀️\":\"1f9dd-200d-2640-fe0f\",\"🧝🏻‍♀\":\"1f9dd-1f3fb-200d-2640-fe0f\",\"🧝🏼‍♀\":\"1f9dd-1f3fc-200d-2640-fe0f\",\"🧝🏽‍♀\":\"1f9dd-1f3fd-200d-2640-fe0f\",\"🧝🏾‍♀\":\"1f9dd-1f3fe-200d-2640-fe0f\",\"🧝🏿‍♀\":\"1f9dd-1f3ff-200d-2640-fe0f\",\"🧝‍♂️\":\"1f9dd-200d-2642-fe0f\",\"🧝🏻‍♂\":\"1f9dd-1f3fb-200d-2642-fe0f\",\"🧝🏼‍♂\":\"1f9dd-1f3fc-200d-2642-fe0f\",\"🧝🏽‍♂\":\"1f9dd-1f3fd-200d-2642-fe0f\",\"🧝🏾‍♂\":\"1f9dd-1f3fe-200d-2642-fe0f\",\"🧝🏿‍♂\":\"1f9dd-1f3ff-200d-2642-fe0f\",\"🧞‍♀️\":\"1f9de-200d-2640-fe0f\",\"🧞‍♂️\":\"1f9de-200d-2642-fe0f\",\"🧟‍♀️\":\"1f9df-200d-2640-fe0f\",\"🧟‍♂️\":\"1f9df-200d-2642-fe0f\",\"🙍‍♂️\":\"1f64d-200d-2642-fe0f\",\"🙍🏻‍♂\":\"1f64d-1f3fb-200d-2642-fe0f\",\"🙍🏼‍♂\":\"1f64d-1f3fc-200d-2642-fe0f\",\"🙍🏽‍♂\":\"1f64d-1f3fd-200d-2642-fe0f\",\"🙍🏾‍♂\":\"1f64d-1f3fe-200d-2642-fe0f\",\"🙍🏿‍♂\":\"1f64d-1f3ff-200d-2642-fe0f\",\"🙍‍♀️\":\"1f64d-200d-2640-fe0f\",\"🙍🏻‍♀\":\"1f64d-1f3fb-200d-2640-fe0f\",\"🙍🏼‍♀\":\"1f64d-1f3fc-200d-2640-fe0f\",\"🙍🏽‍♀\":\"1f64d-1f3fd-200d-2640-fe0f\",\"🙍🏾‍♀\":\"1f64d-1f3fe-200d-2640-fe0f\",\"🙍🏿‍♀\":\"1f64d-1f3ff-200d-2640-fe0f\",\"🙎‍♂️\":\"1f64e-200d-2642-fe0f\",\"🙎🏻‍♂\":\"1f64e-1f3fb-200d-2642-fe0f\",\"🙎🏼‍♂\":\"1f64e-1f3fc-200d-2642-fe0f\",\"🙎🏽‍♂\":\"1f64e-1f3fd-200d-2642-fe0f\",\"🙎🏾‍♂\":\"1f64e-1f3fe-200d-2642-fe0f\",\"🙎🏿‍♂\":\"1f64e-1f3ff-200d-2642-fe0f\",\"🙎‍♀️\":\"1f64e-200d-2640-fe0f\",\"🙎🏻‍♀\":\"1f64e-1f3fb-200d-2640-fe0f\",\"🙎🏼‍♀\":\"1f64e-1f3fc-200d-2640-fe0f\",\"🙎🏽‍♀\":\"1f64e-1f3fd-200d-2640-fe0f\",\"🙎🏾‍♀\":\"1f64e-1f3fe-200d-2640-fe0f\",\"🙎🏿‍♀\":\"1f64e-1f3ff-200d-2640-fe0f\",\"🙅‍♂️\":\"1f645-200d-2642-fe0f\",\"🙅🏻‍♂\":\"1f645-1f3fb-200d-2642-fe0f\",\"🙅🏼‍♂\":\"1f645-1f3fc-200d-2642-fe0f\",\"🙅🏽‍♂\":\"1f645-1f3fd-200d-2642-fe0f\",\"🙅🏾‍♂\":\"1f645-1f3fe-200d-2642-fe0f\",\"🙅🏿‍♂\":\"1f645-1f3ff-200d-2642-fe0f\",\"🙅‍♀️\":\"1f645-200d-2640-fe0f\",\"🙅🏻‍♀\":\"1f645-1f3fb-200d-2640-fe0f\",\"🙅🏼‍♀\":\"1f645-1f3fc-200d-2640-fe0f\",\"🙅🏽‍♀\":\"1f645-1f3fd-200d-2640-fe0f\",\"🙅🏾‍♀\":\"1f645-1f3fe-200d-2640-fe0f\",\"🙅🏿‍♀\":\"1f645-1f3ff-200d-2640-fe0f\",\"🙆‍♂️\":\"1f646-200d-2642-fe0f\",\"🙆🏻‍♂\":\"1f646-1f3fb-200d-2642-fe0f\",\"🙆🏼‍♂\":\"1f646-1f3fc-200d-2642-fe0f\",\"🙆🏽‍♂\":\"1f646-1f3fd-200d-2642-fe0f\",\"🙆🏾‍♂\":\"1f646-1f3fe-200d-2642-fe0f\",\"🙆🏿‍♂\":\"1f646-1f3ff-200d-2642-fe0f\",\"🙆‍♀️\":\"1f646-200d-2640-fe0f\",\"🙆🏻‍♀\":\"1f646-1f3fb-200d-2640-fe0f\",\"🙆🏼‍♀\":\"1f646-1f3fc-200d-2640-fe0f\",\"🙆🏽‍♀\":\"1f646-1f3fd-200d-2640-fe0f\",\"🙆🏾‍♀\":\"1f646-1f3fe-200d-2640-fe0f\",\"🙆🏿‍♀\":\"1f646-1f3ff-200d-2640-fe0f\",\"💁‍♂️\":\"1f481-200d-2642-fe0f\",\"💁🏻‍♂\":\"1f481-1f3fb-200d-2642-fe0f\",\"💁🏼‍♂\":\"1f481-1f3fc-200d-2642-fe0f\",\"💁🏽‍♂\":\"1f481-1f3fd-200d-2642-fe0f\",\"💁🏾‍♂\":\"1f481-1f3fe-200d-2642-fe0f\",\"💁🏿‍♂\":\"1f481-1f3ff-200d-2642-fe0f\",\"💁‍♀️\":\"1f481-200d-2640-fe0f\",\"💁🏻‍♀\":\"1f481-1f3fb-200d-2640-fe0f\",\"💁🏼‍♀\":\"1f481-1f3fc-200d-2640-fe0f\",\"💁🏽‍♀\":\"1f481-1f3fd-200d-2640-fe0f\",\"💁🏾‍♀\":\"1f481-1f3fe-200d-2640-fe0f\",\"💁🏿‍♀\":\"1f481-1f3ff-200d-2640-fe0f\",\"🙋‍♂️\":\"1f64b-200d-2642-fe0f\",\"🙋🏻‍♂\":\"1f64b-1f3fb-200d-2642-fe0f\",\"🙋🏼‍♂\":\"1f64b-1f3fc-200d-2642-fe0f\",\"🙋🏽‍♂\":\"1f64b-1f3fd-200d-2642-fe0f\",\"🙋🏾‍♂\":\"1f64b-1f3fe-200d-2642-fe0f\",\"🙋🏿‍♂\":\"1f64b-1f3ff-200d-2642-fe0f\",\"🙋‍♀️\":\"1f64b-200d-2640-fe0f\",\"🙋🏻‍♀\":\"1f64b-1f3fb-200d-2640-fe0f\",\"🙋🏼‍♀\":\"1f64b-1f3fc-200d-2640-fe0f\",\"🙋🏽‍♀\":\"1f64b-1f3fd-200d-2640-fe0f\",\"🙋🏾‍♀\":\"1f64b-1f3fe-200d-2640-fe0f\",\"🙋🏿‍♀\":\"1f64b-1f3ff-200d-2640-fe0f\",\"🙇‍♂️\":\"1f647-200d-2642-fe0f\",\"🙇🏻‍♂\":\"1f647-1f3fb-200d-2642-fe0f\",\"🙇🏼‍♂\":\"1f647-1f3fc-200d-2642-fe0f\",\"🙇🏽‍♂\":\"1f647-1f3fd-200d-2642-fe0f\",\"🙇🏾‍♂\":\"1f647-1f3fe-200d-2642-fe0f\",\"🙇🏿‍♂\":\"1f647-1f3ff-200d-2642-fe0f\",\"🙇‍♀️\":\"1f647-200d-2640-fe0f\",\"🙇🏻‍♀\":\"1f647-1f3fb-200d-2640-fe0f\",\"🙇🏼‍♀\":\"1f647-1f3fc-200d-2640-fe0f\",\"🙇🏽‍♀\":\"1f647-1f3fd-200d-2640-fe0f\",\"🙇🏾‍♀\":\"1f647-1f3fe-200d-2640-fe0f\",\"🙇🏿‍♀\":\"1f647-1f3ff-200d-2640-fe0f\",\"🤦‍♂️\":\"1f926-200d-2642-fe0f\",\"🤦🏻‍♂\":\"1f926-1f3fb-200d-2642-fe0f\",\"🤦🏼‍♂\":\"1f926-1f3fc-200d-2642-fe0f\",\"🤦🏽‍♂\":\"1f926-1f3fd-200d-2642-fe0f\",\"🤦🏾‍♂\":\"1f926-1f3fe-200d-2642-fe0f\",\"🤦🏿‍♂\":\"1f926-1f3ff-200d-2642-fe0f\",\"🤦‍♀️\":\"1f926-200d-2640-fe0f\",\"🤦🏻‍♀\":\"1f926-1f3fb-200d-2640-fe0f\",\"🤦🏼‍♀\":\"1f926-1f3fc-200d-2640-fe0f\",\"🤦🏽‍♀\":\"1f926-1f3fd-200d-2640-fe0f\",\"🤦🏾‍♀\":\"1f926-1f3fe-200d-2640-fe0f\",\"🤦🏿‍♀\":\"1f926-1f3ff-200d-2640-fe0f\",\"🤷‍♂️\":\"1f937-200d-2642-fe0f\",\"🤷🏻‍♂\":\"1f937-1f3fb-200d-2642-fe0f\",\"🤷🏼‍♂\":\"1f937-1f3fc-200d-2642-fe0f\",\"🤷🏽‍♂\":\"1f937-1f3fd-200d-2642-fe0f\",\"🤷🏾‍♂\":\"1f937-1f3fe-200d-2642-fe0f\",\"🤷🏿‍♂\":\"1f937-1f3ff-200d-2642-fe0f\",\"🤷‍♀️\":\"1f937-200d-2640-fe0f\",\"🤷🏻‍♀\":\"1f937-1f3fb-200d-2640-fe0f\",\"🤷🏼‍♀\":\"1f937-1f3fc-200d-2640-fe0f\",\"🤷🏽‍♀\":\"1f937-1f3fd-200d-2640-fe0f\",\"🤷🏾‍♀\":\"1f937-1f3fe-200d-2640-fe0f\",\"🤷🏿‍♀\":\"1f937-1f3ff-200d-2640-fe0f\",\"💆‍♂️\":\"1f486-200d-2642-fe0f\",\"💆🏻‍♂\":\"1f486-1f3fb-200d-2642-fe0f\",\"💆🏼‍♂\":\"1f486-1f3fc-200d-2642-fe0f\",\"💆🏽‍♂\":\"1f486-1f3fd-200d-2642-fe0f\",\"💆🏾‍♂\":\"1f486-1f3fe-200d-2642-fe0f\",\"💆🏿‍♂\":\"1f486-1f3ff-200d-2642-fe0f\",\"💆‍♀️\":\"1f486-200d-2640-fe0f\",\"💆🏻‍♀\":\"1f486-1f3fb-200d-2640-fe0f\",\"💆🏼‍♀\":\"1f486-1f3fc-200d-2640-fe0f\",\"💆🏽‍♀\":\"1f486-1f3fd-200d-2640-fe0f\",\"💆🏾‍♀\":\"1f486-1f3fe-200d-2640-fe0f\",\"💆🏿‍♀\":\"1f486-1f3ff-200d-2640-fe0f\",\"💇‍♂️\":\"1f487-200d-2642-fe0f\",\"💇🏻‍♂\":\"1f487-1f3fb-200d-2642-fe0f\",\"💇🏼‍♂\":\"1f487-1f3fc-200d-2642-fe0f\",\"💇🏽‍♂\":\"1f487-1f3fd-200d-2642-fe0f\",\"💇🏾‍♂\":\"1f487-1f3fe-200d-2642-fe0f\",\"💇🏿‍♂\":\"1f487-1f3ff-200d-2642-fe0f\",\"💇‍♀️\":\"1f487-200d-2640-fe0f\",\"💇🏻‍♀\":\"1f487-1f3fb-200d-2640-fe0f\",\"💇🏼‍♀\":\"1f487-1f3fc-200d-2640-fe0f\",\"💇🏽‍♀\":\"1f487-1f3fd-200d-2640-fe0f\",\"💇🏾‍♀\":\"1f487-1f3fe-200d-2640-fe0f\",\"💇🏿‍♀\":\"1f487-1f3ff-200d-2640-fe0f\",\"🚶‍♂️\":\"1f6b6-200d-2642-fe0f\",\"🚶🏻‍♂\":\"1f6b6-1f3fb-200d-2642-fe0f\",\"🚶🏼‍♂\":\"1f6b6-1f3fc-200d-2642-fe0f\",\"🚶🏽‍♂\":\"1f6b6-1f3fd-200d-2642-fe0f\",\"🚶🏾‍♂\":\"1f6b6-1f3fe-200d-2642-fe0f\",\"🚶🏿‍♂\":\"1f6b6-1f3ff-200d-2642-fe0f\",\"🚶‍♀️\":\"1f6b6-200d-2640-fe0f\",\"🚶🏻‍♀\":\"1f6b6-1f3fb-200d-2640-fe0f\",\"🚶🏼‍♀\":\"1f6b6-1f3fc-200d-2640-fe0f\",\"🚶🏽‍♀\":\"1f6b6-1f3fd-200d-2640-fe0f\",\"🚶🏾‍♀\":\"1f6b6-1f3fe-200d-2640-fe0f\",\"🚶🏿‍♀\":\"1f6b6-1f3ff-200d-2640-fe0f\",\"🏃‍♂️\":\"1f3c3-200d-2642-fe0f\",\"🏃🏻‍♂\":\"1f3c3-1f3fb-200d-2642-fe0f\",\"🏃🏼‍♂\":\"1f3c3-1f3fc-200d-2642-fe0f\",\"🏃🏽‍♂\":\"1f3c3-1f3fd-200d-2642-fe0f\",\"🏃🏾‍♂\":\"1f3c3-1f3fe-200d-2642-fe0f\",\"🏃🏿‍♂\":\"1f3c3-1f3ff-200d-2642-fe0f\",\"🏃‍♀️\":\"1f3c3-200d-2640-fe0f\",\"🏃🏻‍♀\":\"1f3c3-1f3fb-200d-2640-fe0f\",\"🏃🏼‍♀\":\"1f3c3-1f3fc-200d-2640-fe0f\",\"🏃🏽‍♀\":\"1f3c3-1f3fd-200d-2640-fe0f\",\"🏃🏾‍♀\":\"1f3c3-1f3fe-200d-2640-fe0f\",\"🏃🏿‍♀\":\"1f3c3-1f3ff-200d-2640-fe0f\",\"👯‍♂️\":\"1f46f-200d-2642-fe0f\",\"👯‍♀️\":\"1f46f-200d-2640-fe0f\",\"🧖‍♀️\":\"1f9d6-200d-2640-fe0f\",\"🧖🏻‍♀\":\"1f9d6-1f3fb-200d-2640-fe0f\",\"🧖🏼‍♀\":\"1f9d6-1f3fc-200d-2640-fe0f\",\"🧖🏽‍♀\":\"1f9d6-1f3fd-200d-2640-fe0f\",\"🧖🏾‍♀\":\"1f9d6-1f3fe-200d-2640-fe0f\",\"🧖🏿‍♀\":\"1f9d6-1f3ff-200d-2640-fe0f\",\"🧖‍♂️\":\"1f9d6-200d-2642-fe0f\",\"🧖🏻‍♂\":\"1f9d6-1f3fb-200d-2642-fe0f\",\"🧖🏼‍♂\":\"1f9d6-1f3fc-200d-2642-fe0f\",\"🧖🏽‍♂\":\"1f9d6-1f3fd-200d-2642-fe0f\",\"🧖🏾‍♂\":\"1f9d6-1f3fe-200d-2642-fe0f\",\"🧖🏿‍♂\":\"1f9d6-1f3ff-200d-2642-fe0f\",\"🧗‍♀️\":\"1f9d7-200d-2640-fe0f\",\"🧗🏻‍♀\":\"1f9d7-1f3fb-200d-2640-fe0f\",\"🧗🏼‍♀\":\"1f9d7-1f3fc-200d-2640-fe0f\",\"🧗🏽‍♀\":\"1f9d7-1f3fd-200d-2640-fe0f\",\"🧗🏾‍♀\":\"1f9d7-1f3fe-200d-2640-fe0f\",\"🧗🏿‍♀\":\"1f9d7-1f3ff-200d-2640-fe0f\",\"🧗‍♂️\":\"1f9d7-200d-2642-fe0f\",\"🧗🏻‍♂\":\"1f9d7-1f3fb-200d-2642-fe0f\",\"🧗🏼‍♂\":\"1f9d7-1f3fc-200d-2642-fe0f\",\"🧗🏽‍♂\":\"1f9d7-1f3fd-200d-2642-fe0f\",\"🧗🏾‍♂\":\"1f9d7-1f3fe-200d-2642-fe0f\",\"🧗🏿‍♂\":\"1f9d7-1f3ff-200d-2642-fe0f\",\"🧘‍♀️\":\"1f9d8-200d-2640-fe0f\",\"🧘🏻‍♀\":\"1f9d8-1f3fb-200d-2640-fe0f\",\"🧘🏼‍♀\":\"1f9d8-1f3fc-200d-2640-fe0f\",\"🧘🏽‍♀\":\"1f9d8-1f3fd-200d-2640-fe0f\",\"🧘🏾‍♀\":\"1f9d8-1f3fe-200d-2640-fe0f\",\"🧘🏿‍♀\":\"1f9d8-1f3ff-200d-2640-fe0f\",\"🧘‍♂️\":\"1f9d8-200d-2642-fe0f\",\"🧘🏻‍♂\":\"1f9d8-1f3fb-200d-2642-fe0f\",\"🧘🏼‍♂\":\"1f9d8-1f3fc-200d-2642-fe0f\",\"🧘🏽‍♂\":\"1f9d8-1f3fd-200d-2642-fe0f\",\"🧘🏾‍♂\":\"1f9d8-1f3fe-200d-2642-fe0f\",\"🧘🏿‍♂\":\"1f9d8-1f3ff-200d-2642-fe0f\",\"🏌‍♂️\":\"1f3cc-fe0f-200d-2642-fe0f\",\"🏌️‍♂\":\"1f3cc-fe0f-200d-2642-fe0f\",\"🏌🏻‍♂\":\"1f3cc-1f3fb-200d-2642-fe0f\",\"🏌🏼‍♂\":\"1f3cc-1f3fc-200d-2642-fe0f\",\"🏌🏽‍♂\":\"1f3cc-1f3fd-200d-2642-fe0f\",\"🏌🏾‍♂\":\"1f3cc-1f3fe-200d-2642-fe0f\",\"🏌🏿‍♂\":\"1f3cc-1f3ff-200d-2642-fe0f\",\"🏌‍♀️\":\"1f3cc-fe0f-200d-2640-fe0f\",\"🏌️‍♀\":\"1f3cc-fe0f-200d-2640-fe0f\",\"🏌🏻‍♀\":\"1f3cc-1f3fb-200d-2640-fe0f\",\"🏌🏼‍♀\":\"1f3cc-1f3fc-200d-2640-fe0f\",\"🏌🏽‍♀\":\"1f3cc-1f3fd-200d-2640-fe0f\",\"🏌🏾‍♀\":\"1f3cc-1f3fe-200d-2640-fe0f\",\"🏌🏿‍♀\":\"1f3cc-1f3ff-200d-2640-fe0f\",\"🏄‍♂️\":\"1f3c4-200d-2642-fe0f\",\"🏄🏻‍♂\":\"1f3c4-1f3fb-200d-2642-fe0f\",\"🏄🏼‍♂\":\"1f3c4-1f3fc-200d-2642-fe0f\",\"🏄🏽‍♂\":\"1f3c4-1f3fd-200d-2642-fe0f\",\"🏄🏾‍♂\":\"1f3c4-1f3fe-200d-2642-fe0f\",\"🏄🏿‍♂\":\"1f3c4-1f3ff-200d-2642-fe0f\",\"🏄‍♀️\":\"1f3c4-200d-2640-fe0f\",\"🏄🏻‍♀\":\"1f3c4-1f3fb-200d-2640-fe0f\",\"🏄🏼‍♀\":\"1f3c4-1f3fc-200d-2640-fe0f\",\"🏄🏽‍♀\":\"1f3c4-1f3fd-200d-2640-fe0f\",\"🏄🏾‍♀\":\"1f3c4-1f3fe-200d-2640-fe0f\",\"🏄🏿‍♀\":\"1f3c4-1f3ff-200d-2640-fe0f\",\"🚣‍♂️\":\"1f6a3-200d-2642-fe0f\",\"🚣🏻‍♂\":\"1f6a3-1f3fb-200d-2642-fe0f\",\"🚣🏼‍♂\":\"1f6a3-1f3fc-200d-2642-fe0f\",\"🚣🏽‍♂\":\"1f6a3-1f3fd-200d-2642-fe0f\",\"🚣🏾‍♂\":\"1f6a3-1f3fe-200d-2642-fe0f\",\"🚣🏿‍♂\":\"1f6a3-1f3ff-200d-2642-fe0f\",\"🚣‍♀️\":\"1f6a3-200d-2640-fe0f\",\"🚣🏻‍♀\":\"1f6a3-1f3fb-200d-2640-fe0f\",\"🚣🏼‍♀\":\"1f6a3-1f3fc-200d-2640-fe0f\",\"🚣🏽‍♀\":\"1f6a3-1f3fd-200d-2640-fe0f\",\"🚣🏾‍♀\":\"1f6a3-1f3fe-200d-2640-fe0f\",\"🚣🏿‍♀\":\"1f6a3-1f3ff-200d-2640-fe0f\",\"🏊‍♂️\":\"1f3ca-200d-2642-fe0f\",\"🏊🏻‍♂\":\"1f3ca-1f3fb-200d-2642-fe0f\",\"🏊🏼‍♂\":\"1f3ca-1f3fc-200d-2642-fe0f\",\"🏊🏽‍♂\":\"1f3ca-1f3fd-200d-2642-fe0f\",\"🏊🏾‍♂\":\"1f3ca-1f3fe-200d-2642-fe0f\",\"🏊🏿‍♂\":\"1f3ca-1f3ff-200d-2642-fe0f\",\"🏊‍♀️\":\"1f3ca-200d-2640-fe0f\",\"🏊🏻‍♀\":\"1f3ca-1f3fb-200d-2640-fe0f\",\"🏊🏼‍♀\":\"1f3ca-1f3fc-200d-2640-fe0f\",\"🏊🏽‍♀\":\"1f3ca-1f3fd-200d-2640-fe0f\",\"🏊🏾‍♀\":\"1f3ca-1f3fe-200d-2640-fe0f\",\"🏊🏿‍♀\":\"1f3ca-1f3ff-200d-2640-fe0f\",\"⛹‍♂️\":\"26f9-fe0f-200d-2642-fe0f\",\"⛹️‍♂\":\"26f9-fe0f-200d-2642-fe0f\",\"⛹🏻‍♂\":\"26f9-1f3fb-200d-2642-fe0f\",\"⛹🏼‍♂\":\"26f9-1f3fc-200d-2642-fe0f\",\"⛹🏽‍♂\":\"26f9-1f3fd-200d-2642-fe0f\",\"⛹🏾‍♂\":\"26f9-1f3fe-200d-2642-fe0f\",\"⛹🏿‍♂\":\"26f9-1f3ff-200d-2642-fe0f\",\"⛹‍♀️\":\"26f9-fe0f-200d-2640-fe0f\",\"⛹️‍♀\":\"26f9-fe0f-200d-2640-fe0f\",\"⛹🏻‍♀\":\"26f9-1f3fb-200d-2640-fe0f\",\"⛹🏼‍♀\":\"26f9-1f3fc-200d-2640-fe0f\",\"⛹🏽‍♀\":\"26f9-1f3fd-200d-2640-fe0f\",\"⛹🏾‍♀\":\"26f9-1f3fe-200d-2640-fe0f\",\"⛹🏿‍♀\":\"26f9-1f3ff-200d-2640-fe0f\",\"🏋‍♂️\":\"1f3cb-fe0f-200d-2642-fe0f\",\"🏋️‍♂\":\"1f3cb-fe0f-200d-2642-fe0f\",\"🏋🏻‍♂\":\"1f3cb-1f3fb-200d-2642-fe0f\",\"🏋🏼‍♂\":\"1f3cb-1f3fc-200d-2642-fe0f\",\"🏋🏽‍♂\":\"1f3cb-1f3fd-200d-2642-fe0f\",\"🏋🏾‍♂\":\"1f3cb-1f3fe-200d-2642-fe0f\",\"🏋🏿‍♂\":\"1f3cb-1f3ff-200d-2642-fe0f\",\"🏋‍♀️\":\"1f3cb-fe0f-200d-2640-fe0f\",\"🏋️‍♀\":\"1f3cb-fe0f-200d-2640-fe0f\",\"🏋🏻‍♀\":\"1f3cb-1f3fb-200d-2640-fe0f\",\"🏋🏼‍♀\":\"1f3cb-1f3fc-200d-2640-fe0f\",\"🏋🏽‍♀\":\"1f3cb-1f3fd-200d-2640-fe0f\",\"🏋🏾‍♀\":\"1f3cb-1f3fe-200d-2640-fe0f\",\"🏋🏿‍♀\":\"1f3cb-1f3ff-200d-2640-fe0f\",\"🚴‍♂️\":\"1f6b4-200d-2642-fe0f\",\"🚴🏻‍♂\":\"1f6b4-1f3fb-200d-2642-fe0f\",\"🚴🏼‍♂\":\"1f6b4-1f3fc-200d-2642-fe0f\",\"🚴🏽‍♂\":\"1f6b4-1f3fd-200d-2642-fe0f\",\"🚴🏾‍♂\":\"1f6b4-1f3fe-200d-2642-fe0f\",\"🚴🏿‍♂\":\"1f6b4-1f3ff-200d-2642-fe0f\",\"🚴‍♀️\":\"1f6b4-200d-2640-fe0f\",\"🚴🏻‍♀\":\"1f6b4-1f3fb-200d-2640-fe0f\",\"🚴🏼‍♀\":\"1f6b4-1f3fc-200d-2640-fe0f\",\"🚴🏽‍♀\":\"1f6b4-1f3fd-200d-2640-fe0f\",\"🚴🏾‍♀\":\"1f6b4-1f3fe-200d-2640-fe0f\",\"🚴🏿‍♀\":\"1f6b4-1f3ff-200d-2640-fe0f\",\"🚵‍♂️\":\"1f6b5-200d-2642-fe0f\",\"🚵🏻‍♂\":\"1f6b5-1f3fb-200d-2642-fe0f\",\"🚵🏼‍♂\":\"1f6b5-1f3fc-200d-2642-fe0f\",\"🚵🏽‍♂\":\"1f6b5-1f3fd-200d-2642-fe0f\",\"🚵🏾‍♂\":\"1f6b5-1f3fe-200d-2642-fe0f\",\"🚵🏿‍♂\":\"1f6b5-1f3ff-200d-2642-fe0f\",\"🚵‍♀️\":\"1f6b5-200d-2640-fe0f\",\"🚵🏻‍♀\":\"1f6b5-1f3fb-200d-2640-fe0f\",\"🚵🏼‍♀\":\"1f6b5-1f3fc-200d-2640-fe0f\",\"🚵🏽‍♀\":\"1f6b5-1f3fd-200d-2640-fe0f\",\"🚵🏾‍♀\":\"1f6b5-1f3fe-200d-2640-fe0f\",\"🚵🏿‍♀\":\"1f6b5-1f3ff-200d-2640-fe0f\",\"🤸‍♂️\":\"1f938-200d-2642-fe0f\",\"🤸🏻‍♂\":\"1f938-1f3fb-200d-2642-fe0f\",\"🤸🏼‍♂\":\"1f938-1f3fc-200d-2642-fe0f\",\"🤸🏽‍♂\":\"1f938-1f3fd-200d-2642-fe0f\",\"🤸🏾‍♂\":\"1f938-1f3fe-200d-2642-fe0f\",\"🤸🏿‍♂\":\"1f938-1f3ff-200d-2642-fe0f\",\"🤸‍♀️\":\"1f938-200d-2640-fe0f\",\"🤸🏻‍♀\":\"1f938-1f3fb-200d-2640-fe0f\",\"🤸🏼‍♀\":\"1f938-1f3fc-200d-2640-fe0f\",\"🤸🏽‍♀\":\"1f938-1f3fd-200d-2640-fe0f\",\"🤸🏾‍♀\":\"1f938-1f3fe-200d-2640-fe0f\",\"🤸🏿‍♀\":\"1f938-1f3ff-200d-2640-fe0f\",\"🤼‍♂️\":\"1f93c-200d-2642-fe0f\",\"🤼‍♀️\":\"1f93c-200d-2640-fe0f\",\"🤽‍♂️\":\"1f93d-200d-2642-fe0f\",\"🤽🏻‍♂\":\"1f93d-1f3fb-200d-2642-fe0f\",\"🤽🏼‍♂\":\"1f93d-1f3fc-200d-2642-fe0f\",\"🤽🏽‍♂\":\"1f93d-1f3fd-200d-2642-fe0f\",\"🤽🏾‍♂\":\"1f93d-1f3fe-200d-2642-fe0f\",\"🤽🏿‍♂\":\"1f93d-1f3ff-200d-2642-fe0f\",\"🤽‍♀️\":\"1f93d-200d-2640-fe0f\",\"🤽🏻‍♀\":\"1f93d-1f3fb-200d-2640-fe0f\",\"🤽🏼‍♀\":\"1f93d-1f3fc-200d-2640-fe0f\",\"🤽🏽‍♀\":\"1f93d-1f3fd-200d-2640-fe0f\",\"🤽🏾‍♀\":\"1f93d-1f3fe-200d-2640-fe0f\",\"🤽🏿‍♀\":\"1f93d-1f3ff-200d-2640-fe0f\",\"🤾‍♂️\":\"1f93e-200d-2642-fe0f\",\"🤾🏻‍♂\":\"1f93e-1f3fb-200d-2642-fe0f\",\"🤾🏼‍♂\":\"1f93e-1f3fc-200d-2642-fe0f\",\"🤾🏽‍♂\":\"1f93e-1f3fd-200d-2642-fe0f\",\"🤾🏾‍♂\":\"1f93e-1f3fe-200d-2642-fe0f\",\"🤾🏿‍♂\":\"1f93e-1f3ff-200d-2642-fe0f\",\"🤾‍♀️\":\"1f93e-200d-2640-fe0f\",\"🤾🏻‍♀\":\"1f93e-1f3fb-200d-2640-fe0f\",\"🤾🏼‍♀\":\"1f93e-1f3fc-200d-2640-fe0f\",\"🤾🏽‍♀\":\"1f93e-1f3fd-200d-2640-fe0f\",\"🤾🏾‍♀\":\"1f93e-1f3fe-200d-2640-fe0f\",\"🤾🏿‍♀\":\"1f93e-1f3ff-200d-2640-fe0f\",\"🤹‍♂️\":\"1f939-200d-2642-fe0f\",\"🤹🏻‍♂\":\"1f939-1f3fb-200d-2642-fe0f\",\"🤹🏼‍♂\":\"1f939-1f3fc-200d-2642-fe0f\",\"🤹🏽‍♂\":\"1f939-1f3fd-200d-2642-fe0f\",\"🤹🏾‍♂\":\"1f939-1f3fe-200d-2642-fe0f\",\"🤹🏿‍♂\":\"1f939-1f3ff-200d-2642-fe0f\",\"🤹‍♀️\":\"1f939-200d-2640-fe0f\",\"🤹🏻‍♀\":\"1f939-1f3fb-200d-2640-fe0f\",\"🤹🏼‍♀\":\"1f939-1f3fc-200d-2640-fe0f\",\"🤹🏽‍♀\":\"1f939-1f3fd-200d-2640-fe0f\",\"🤹🏾‍♀\":\"1f939-1f3fe-200d-2640-fe0f\",\"🤹🏿‍♀\":\"1f939-1f3ff-200d-2640-fe0f\",\"👁‍🗨️\":\"1f441-200d-1f5e8\",\"👁️‍🗨\":\"1f441-200d-1f5e8\",\"🏳️‍🌈\":\"1f3f3-fe0f-200d-1f308\",\"🏴‍☠️\":\"1f3f4-200d-2620-fe0f\",\"👨🏻‍⚕️\":\"1f468-1f3fb-200d-2695-fe0f\",\"👨🏼‍⚕️\":\"1f468-1f3fc-200d-2695-fe0f\",\"👨🏽‍⚕️\":\"1f468-1f3fd-200d-2695-fe0f\",\"👨🏾‍⚕️\":\"1f468-1f3fe-200d-2695-fe0f\",\"👨🏿‍⚕️\":\"1f468-1f3ff-200d-2695-fe0f\",\"👩🏻‍⚕️\":\"1f469-1f3fb-200d-2695-fe0f\",\"👩🏼‍⚕️\":\"1f469-1f3fc-200d-2695-fe0f\",\"👩🏽‍⚕️\":\"1f469-1f3fd-200d-2695-fe0f\",\"👩🏾‍⚕️\":\"1f469-1f3fe-200d-2695-fe0f\",\"👩🏿‍⚕️\":\"1f469-1f3ff-200d-2695-fe0f\",\"👨🏻‍⚖️\":\"1f468-1f3fb-200d-2696-fe0f\",\"👨🏼‍⚖️\":\"1f468-1f3fc-200d-2696-fe0f\",\"👨🏽‍⚖️\":\"1f468-1f3fd-200d-2696-fe0f\",\"👨🏾‍⚖️\":\"1f468-1f3fe-200d-2696-fe0f\",\"👨🏿‍⚖️\":\"1f468-1f3ff-200d-2696-fe0f\",\"👩🏻‍⚖️\":\"1f469-1f3fb-200d-2696-fe0f\",\"👩🏼‍⚖️\":\"1f469-1f3fc-200d-2696-fe0f\",\"👩🏽‍⚖️\":\"1f469-1f3fd-200d-2696-fe0f\",\"👩🏾‍⚖️\":\"1f469-1f3fe-200d-2696-fe0f\",\"👩🏿‍⚖️\":\"1f469-1f3ff-200d-2696-fe0f\",\"👨🏻‍✈️\":\"1f468-1f3fb-200d-2708-fe0f\",\"👨🏼‍✈️\":\"1f468-1f3fc-200d-2708-fe0f\",\"👨🏽‍✈️\":\"1f468-1f3fd-200d-2708-fe0f\",\"👨🏾‍✈️\":\"1f468-1f3fe-200d-2708-fe0f\",\"👨🏿‍✈️\":\"1f468-1f3ff-200d-2708-fe0f\",\"👩🏻‍✈️\":\"1f469-1f3fb-200d-2708-fe0f\",\"👩🏼‍✈️\":\"1f469-1f3fc-200d-2708-fe0f\",\"👩🏽‍✈️\":\"1f469-1f3fd-200d-2708-fe0f\",\"👩🏾‍✈️\":\"1f469-1f3fe-200d-2708-fe0f\",\"👩🏿‍✈️\":\"1f469-1f3ff-200d-2708-fe0f\",\"👮🏻‍♂️\":\"1f46e-1f3fb-200d-2642-fe0f\",\"👮🏼‍♂️\":\"1f46e-1f3fc-200d-2642-fe0f\",\"👮🏽‍♂️\":\"1f46e-1f3fd-200d-2642-fe0f\",\"👮🏾‍♂️\":\"1f46e-1f3fe-200d-2642-fe0f\",\"👮🏿‍♂️\":\"1f46e-1f3ff-200d-2642-fe0f\",\"👮🏻‍♀️\":\"1f46e-1f3fb-200d-2640-fe0f\",\"👮🏼‍♀️\":\"1f46e-1f3fc-200d-2640-fe0f\",\"👮🏽‍♀️\":\"1f46e-1f3fd-200d-2640-fe0f\",\"👮🏾‍♀️\":\"1f46e-1f3fe-200d-2640-fe0f\",\"👮🏿‍♀️\":\"1f46e-1f3ff-200d-2640-fe0f\",\"🕵️‍♂️\":\"1f575-fe0f-200d-2642-fe0f\",\"🕵🏻‍♂️\":\"1f575-1f3fb-200d-2642-fe0f\",\"🕵🏼‍♂️\":\"1f575-1f3fc-200d-2642-fe0f\",\"🕵🏽‍♂️\":\"1f575-1f3fd-200d-2642-fe0f\",\"🕵🏾‍♂️\":\"1f575-1f3fe-200d-2642-fe0f\",\"🕵🏿‍♂️\":\"1f575-1f3ff-200d-2642-fe0f\",\"🕵️‍♀️\":\"1f575-fe0f-200d-2640-fe0f\",\"🕵🏻‍♀️\":\"1f575-1f3fb-200d-2640-fe0f\",\"🕵🏼‍♀️\":\"1f575-1f3fc-200d-2640-fe0f\",\"🕵🏽‍♀️\":\"1f575-1f3fd-200d-2640-fe0f\",\"🕵🏾‍♀️\":\"1f575-1f3fe-200d-2640-fe0f\",\"🕵🏿‍♀️\":\"1f575-1f3ff-200d-2640-fe0f\",\"💂🏻‍♂️\":\"1f482-1f3fb-200d-2642-fe0f\",\"💂🏼‍♂️\":\"1f482-1f3fc-200d-2642-fe0f\",\"💂🏽‍♂️\":\"1f482-1f3fd-200d-2642-fe0f\",\"💂🏾‍♂️\":\"1f482-1f3fe-200d-2642-fe0f\",\"💂🏿‍♂️\":\"1f482-1f3ff-200d-2642-fe0f\",\"💂🏻‍♀️\":\"1f482-1f3fb-200d-2640-fe0f\",\"💂🏼‍♀️\":\"1f482-1f3fc-200d-2640-fe0f\",\"💂🏽‍♀️\":\"1f482-1f3fd-200d-2640-fe0f\",\"💂🏾‍♀️\":\"1f482-1f3fe-200d-2640-fe0f\",\"💂🏿‍♀️\":\"1f482-1f3ff-200d-2640-fe0f\",\"👷🏻‍♂️\":\"1f477-1f3fb-200d-2642-fe0f\",\"👷🏼‍♂️\":\"1f477-1f3fc-200d-2642-fe0f\",\"👷🏽‍♂️\":\"1f477-1f3fd-200d-2642-fe0f\",\"👷🏾‍♂️\":\"1f477-1f3fe-200d-2642-fe0f\",\"👷🏿‍♂️\":\"1f477-1f3ff-200d-2642-fe0f\",\"👷🏻‍♀️\":\"1f477-1f3fb-200d-2640-fe0f\",\"👷🏼‍♀️\":\"1f477-1f3fc-200d-2640-fe0f\",\"👷🏽‍♀️\":\"1f477-1f3fd-200d-2640-fe0f\",\"👷🏾‍♀️\":\"1f477-1f3fe-200d-2640-fe0f\",\"👷🏿‍♀️\":\"1f477-1f3ff-200d-2640-fe0f\",\"👳🏻‍♂️\":\"1f473-1f3fb-200d-2642-fe0f\",\"👳🏼‍♂️\":\"1f473-1f3fc-200d-2642-fe0f\",\"👳🏽‍♂️\":\"1f473-1f3fd-200d-2642-fe0f\",\"👳🏾‍♂️\":\"1f473-1f3fe-200d-2642-fe0f\",\"👳🏿‍♂️\":\"1f473-1f3ff-200d-2642-fe0f\",\"👳🏻‍♀️\":\"1f473-1f3fb-200d-2640-fe0f\",\"👳🏼‍♀️\":\"1f473-1f3fc-200d-2640-fe0f\",\"👳🏽‍♀️\":\"1f473-1f3fd-200d-2640-fe0f\",\"👳🏾‍♀️\":\"1f473-1f3fe-200d-2640-fe0f\",\"👳🏿‍♀️\":\"1f473-1f3ff-200d-2640-fe0f\",\"👱🏻‍♂️\":\"1f471-1f3fb-200d-2642-fe0f\",\"👱🏼‍♂️\":\"1f471-1f3fc-200d-2642-fe0f\",\"👱🏽‍♂️\":\"1f471-1f3fd-200d-2642-fe0f\",\"👱🏾‍♂️\":\"1f471-1f3fe-200d-2642-fe0f\",\"👱🏿‍♂️\":\"1f471-1f3ff-200d-2642-fe0f\",\"👱🏻‍♀️\":\"1f471-1f3fb-200d-2640-fe0f\",\"👱🏼‍♀️\":\"1f471-1f3fc-200d-2640-fe0f\",\"👱🏽‍♀️\":\"1f471-1f3fd-200d-2640-fe0f\",\"👱🏾‍♀️\":\"1f471-1f3fe-200d-2640-fe0f\",\"👱🏿‍♀️\":\"1f471-1f3ff-200d-2640-fe0f\",\"🦸🏻‍♀️\":\"1f9b8-1f3fb-200d-2640-fe0f\",\"🦸🏼‍♀️\":\"1f9b8-1f3fc-200d-2640-fe0f\",\"🦸🏽‍♀️\":\"1f9b8-1f3fd-200d-2640-fe0f\",\"🦸🏾‍♀️\":\"1f9b8-1f3fe-200d-2640-fe0f\",\"🦸🏿‍♀️\":\"1f9b8-1f3ff-200d-2640-fe0f\",\"🦸🏻‍♂️\":\"1f9b8-1f3fb-200d-2642-fe0f\",\"🦸🏼‍♂️\":\"1f9b8-1f3fc-200d-2642-fe0f\",\"🦸🏽‍♂️\":\"1f9b8-1f3fd-200d-2642-fe0f\",\"🦸🏾‍♂️\":\"1f9b8-1f3fe-200d-2642-fe0f\",\"🦸🏿‍♂️\":\"1f9b8-1f3ff-200d-2642-fe0f\",\"🦹🏻‍♀️\":\"1f9b9-1f3fb-200d-2640-fe0f\",\"🦹🏼‍♀️\":\"1f9b9-1f3fc-200d-2640-fe0f\",\"🦹🏽‍♀️\":\"1f9b9-1f3fd-200d-2640-fe0f\",\"🦹🏾‍♀️\":\"1f9b9-1f3fe-200d-2640-fe0f\",\"🦹🏿‍♀️\":\"1f9b9-1f3ff-200d-2640-fe0f\",\"🦹🏻‍♂️\":\"1f9b9-1f3fb-200d-2642-fe0f\",\"🦹🏼‍♂️\":\"1f9b9-1f3fc-200d-2642-fe0f\",\"🦹🏽‍♂️\":\"1f9b9-1f3fd-200d-2642-fe0f\",\"🦹🏾‍♂️\":\"1f9b9-1f3fe-200d-2642-fe0f\",\"🦹🏿‍♂️\":\"1f9b9-1f3ff-200d-2642-fe0f\",\"🧙🏻‍♀️\":\"1f9d9-1f3fb-200d-2640-fe0f\",\"🧙🏼‍♀️\":\"1f9d9-1f3fc-200d-2640-fe0f\",\"🧙🏽‍♀️\":\"1f9d9-1f3fd-200d-2640-fe0f\",\"🧙🏾‍♀️\":\"1f9d9-1f3fe-200d-2640-fe0f\",\"🧙🏿‍♀️\":\"1f9d9-1f3ff-200d-2640-fe0f\",\"🧙🏻‍♂️\":\"1f9d9-1f3fb-200d-2642-fe0f\",\"🧙🏼‍♂️\":\"1f9d9-1f3fc-200d-2642-fe0f\",\"🧙🏽‍♂️\":\"1f9d9-1f3fd-200d-2642-fe0f\",\"🧙🏾‍♂️\":\"1f9d9-1f3fe-200d-2642-fe0f\",\"🧙🏿‍♂️\":\"1f9d9-1f3ff-200d-2642-fe0f\",\"🧚🏻‍♀️\":\"1f9da-1f3fb-200d-2640-fe0f\",\"🧚🏼‍♀️\":\"1f9da-1f3fc-200d-2640-fe0f\",\"🧚🏽‍♀️\":\"1f9da-1f3fd-200d-2640-fe0f\",\"🧚🏾‍♀️\":\"1f9da-1f3fe-200d-2640-fe0f\",\"🧚🏿‍♀️\":\"1f9da-1f3ff-200d-2640-fe0f\",\"🧚🏻‍♂️\":\"1f9da-1f3fb-200d-2642-fe0f\",\"🧚🏼‍♂️\":\"1f9da-1f3fc-200d-2642-fe0f\",\"🧚🏽‍♂️\":\"1f9da-1f3fd-200d-2642-fe0f\",\"🧚🏾‍♂️\":\"1f9da-1f3fe-200d-2642-fe0f\",\"🧚🏿‍♂️\":\"1f9da-1f3ff-200d-2642-fe0f\",\"🧛🏻‍♀️\":\"1f9db-1f3fb-200d-2640-fe0f\",\"🧛🏼‍♀️\":\"1f9db-1f3fc-200d-2640-fe0f\",\"🧛🏽‍♀️\":\"1f9db-1f3fd-200d-2640-fe0f\",\"🧛🏾‍♀️\":\"1f9db-1f3fe-200d-2640-fe0f\",\"🧛🏿‍♀️\":\"1f9db-1f3ff-200d-2640-fe0f\",\"🧛🏻‍♂️\":\"1f9db-1f3fb-200d-2642-fe0f\",\"🧛🏼‍♂️\":\"1f9db-1f3fc-200d-2642-fe0f\",\"🧛🏽‍♂️\":\"1f9db-1f3fd-200d-2642-fe0f\",\"🧛🏾‍♂️\":\"1f9db-1f3fe-200d-2642-fe0f\",\"🧛🏿‍♂️\":\"1f9db-1f3ff-200d-2642-fe0f\",\"🧜🏻‍♀️\":\"1f9dc-1f3fb-200d-2640-fe0f\",\"🧜🏼‍♀️\":\"1f9dc-1f3fc-200d-2640-fe0f\",\"🧜🏽‍♀️\":\"1f9dc-1f3fd-200d-2640-fe0f\",\"🧜🏾‍♀️\":\"1f9dc-1f3fe-200d-2640-fe0f\",\"🧜🏿‍♀️\":\"1f9dc-1f3ff-200d-2640-fe0f\",\"🧜🏻‍♂️\":\"1f9dc-1f3fb-200d-2642-fe0f\",\"🧜🏼‍♂️\":\"1f9dc-1f3fc-200d-2642-fe0f\",\"🧜🏽‍♂️\":\"1f9dc-1f3fd-200d-2642-fe0f\",\"🧜🏾‍♂️\":\"1f9dc-1f3fe-200d-2642-fe0f\",\"🧜🏿‍♂️\":\"1f9dc-1f3ff-200d-2642-fe0f\",\"🧝🏻‍♀️\":\"1f9dd-1f3fb-200d-2640-fe0f\",\"🧝🏼‍♀️\":\"1f9dd-1f3fc-200d-2640-fe0f\",\"🧝🏽‍♀️\":\"1f9dd-1f3fd-200d-2640-fe0f\",\"🧝🏾‍♀️\":\"1f9dd-1f3fe-200d-2640-fe0f\",\"🧝🏿‍♀️\":\"1f9dd-1f3ff-200d-2640-fe0f\",\"🧝🏻‍♂️\":\"1f9dd-1f3fb-200d-2642-fe0f\",\"🧝🏼‍♂️\":\"1f9dd-1f3fc-200d-2642-fe0f\",\"🧝🏽‍♂️\":\"1f9dd-1f3fd-200d-2642-fe0f\",\"🧝🏾‍♂️\":\"1f9dd-1f3fe-200d-2642-fe0f\",\"🧝🏿‍♂️\":\"1f9dd-1f3ff-200d-2642-fe0f\",\"🙍🏻‍♂️\":\"1f64d-1f3fb-200d-2642-fe0f\",\"🙍🏼‍♂️\":\"1f64d-1f3fc-200d-2642-fe0f\",\"🙍🏽‍♂️\":\"1f64d-1f3fd-200d-2642-fe0f\",\"🙍🏾‍♂️\":\"1f64d-1f3fe-200d-2642-fe0f\",\"🙍🏿‍♂️\":\"1f64d-1f3ff-200d-2642-fe0f\",\"🙍🏻‍♀️\":\"1f64d-1f3fb-200d-2640-fe0f\",\"🙍🏼‍♀️\":\"1f64d-1f3fc-200d-2640-fe0f\",\"🙍🏽‍♀️\":\"1f64d-1f3fd-200d-2640-fe0f\",\"🙍🏾‍♀️\":\"1f64d-1f3fe-200d-2640-fe0f\",\"🙍🏿‍♀️\":\"1f64d-1f3ff-200d-2640-fe0f\",\"🙎🏻‍♂️\":\"1f64e-1f3fb-200d-2642-fe0f\",\"🙎🏼‍♂️\":\"1f64e-1f3fc-200d-2642-fe0f\",\"🙎🏽‍♂️\":\"1f64e-1f3fd-200d-2642-fe0f\",\"🙎🏾‍♂️\":\"1f64e-1f3fe-200d-2642-fe0f\",\"🙎🏿‍♂️\":\"1f64e-1f3ff-200d-2642-fe0f\",\"🙎🏻‍♀️\":\"1f64e-1f3fb-200d-2640-fe0f\",\"🙎🏼‍♀️\":\"1f64e-1f3fc-200d-2640-fe0f\",\"🙎🏽‍♀️\":\"1f64e-1f3fd-200d-2640-fe0f\",\"🙎🏾‍♀️\":\"1f64e-1f3fe-200d-2640-fe0f\",\"🙎🏿‍♀️\":\"1f64e-1f3ff-200d-2640-fe0f\",\"🙅🏻‍♂️\":\"1f645-1f3fb-200d-2642-fe0f\",\"🙅🏼‍♂️\":\"1f645-1f3fc-200d-2642-fe0f\",\"🙅🏽‍♂️\":\"1f645-1f3fd-200d-2642-fe0f\",\"🙅🏾‍♂️\":\"1f645-1f3fe-200d-2642-fe0f\",\"🙅🏿‍♂️\":\"1f645-1f3ff-200d-2642-fe0f\",\"🙅🏻‍♀️\":\"1f645-1f3fb-200d-2640-fe0f\",\"🙅🏼‍♀️\":\"1f645-1f3fc-200d-2640-fe0f\",\"🙅🏽‍♀️\":\"1f645-1f3fd-200d-2640-fe0f\",\"🙅🏾‍♀️\":\"1f645-1f3fe-200d-2640-fe0f\",\"🙅🏿‍♀️\":\"1f645-1f3ff-200d-2640-fe0f\",\"🙆🏻‍♂️\":\"1f646-1f3fb-200d-2642-fe0f\",\"🙆🏼‍♂️\":\"1f646-1f3fc-200d-2642-fe0f\",\"🙆🏽‍♂️\":\"1f646-1f3fd-200d-2642-fe0f\",\"🙆🏾‍♂️\":\"1f646-1f3fe-200d-2642-fe0f\",\"🙆🏿‍♂️\":\"1f646-1f3ff-200d-2642-fe0f\",\"🙆🏻‍♀️\":\"1f646-1f3fb-200d-2640-fe0f\",\"🙆🏼‍♀️\":\"1f646-1f3fc-200d-2640-fe0f\",\"🙆🏽‍♀️\":\"1f646-1f3fd-200d-2640-fe0f\",\"🙆🏾‍♀️\":\"1f646-1f3fe-200d-2640-fe0f\",\"🙆🏿‍♀️\":\"1f646-1f3ff-200d-2640-fe0f\",\"💁🏻‍♂️\":\"1f481-1f3fb-200d-2642-fe0f\",\"💁🏼‍♂️\":\"1f481-1f3fc-200d-2642-fe0f\",\"💁🏽‍♂️\":\"1f481-1f3fd-200d-2642-fe0f\",\"💁🏾‍♂️\":\"1f481-1f3fe-200d-2642-fe0f\",\"💁🏿‍♂️\":\"1f481-1f3ff-200d-2642-fe0f\",\"💁🏻‍♀️\":\"1f481-1f3fb-200d-2640-fe0f\",\"💁🏼‍♀️\":\"1f481-1f3fc-200d-2640-fe0f\",\"💁🏽‍♀️\":\"1f481-1f3fd-200d-2640-fe0f\",\"💁🏾‍♀️\":\"1f481-1f3fe-200d-2640-fe0f\",\"💁🏿‍♀️\":\"1f481-1f3ff-200d-2640-fe0f\",\"🙋🏻‍♂️\":\"1f64b-1f3fb-200d-2642-fe0f\",\"🙋🏼‍♂️\":\"1f64b-1f3fc-200d-2642-fe0f\",\"🙋🏽‍♂️\":\"1f64b-1f3fd-200d-2642-fe0f\",\"🙋🏾‍♂️\":\"1f64b-1f3fe-200d-2642-fe0f\",\"🙋🏿‍♂️\":\"1f64b-1f3ff-200d-2642-fe0f\",\"🙋🏻‍♀️\":\"1f64b-1f3fb-200d-2640-fe0f\",\"🙋🏼‍♀️\":\"1f64b-1f3fc-200d-2640-fe0f\",\"🙋🏽‍♀️\":\"1f64b-1f3fd-200d-2640-fe0f\",\"🙋🏾‍♀️\":\"1f64b-1f3fe-200d-2640-fe0f\",\"🙋🏿‍♀️\":\"1f64b-1f3ff-200d-2640-fe0f\",\"🙇🏻‍♂️\":\"1f647-1f3fb-200d-2642-fe0f\",\"🙇🏼‍♂️\":\"1f647-1f3fc-200d-2642-fe0f\",\"🙇🏽‍♂️\":\"1f647-1f3fd-200d-2642-fe0f\",\"🙇🏾‍♂️\":\"1f647-1f3fe-200d-2642-fe0f\",\"🙇🏿‍♂️\":\"1f647-1f3ff-200d-2642-fe0f\",\"🙇🏻‍♀️\":\"1f647-1f3fb-200d-2640-fe0f\",\"🙇🏼‍♀️\":\"1f647-1f3fc-200d-2640-fe0f\",\"🙇🏽‍♀️\":\"1f647-1f3fd-200d-2640-fe0f\",\"🙇🏾‍♀️\":\"1f647-1f3fe-200d-2640-fe0f\",\"🙇🏿‍♀️\":\"1f647-1f3ff-200d-2640-fe0f\",\"🤦🏻‍♂️\":\"1f926-1f3fb-200d-2642-fe0f\",\"🤦🏼‍♂️\":\"1f926-1f3fc-200d-2642-fe0f\",\"🤦🏽‍♂️\":\"1f926-1f3fd-200d-2642-fe0f\",\"🤦🏾‍♂️\":\"1f926-1f3fe-200d-2642-fe0f\",\"🤦🏿‍♂️\":\"1f926-1f3ff-200d-2642-fe0f\",\"🤦🏻‍♀️\":\"1f926-1f3fb-200d-2640-fe0f\",\"🤦🏼‍♀️\":\"1f926-1f3fc-200d-2640-fe0f\",\"🤦🏽‍♀️\":\"1f926-1f3fd-200d-2640-fe0f\",\"🤦🏾‍♀️\":\"1f926-1f3fe-200d-2640-fe0f\",\"🤦🏿‍♀️\":\"1f926-1f3ff-200d-2640-fe0f\",\"🤷🏻‍♂️\":\"1f937-1f3fb-200d-2642-fe0f\",\"🤷🏼‍♂️\":\"1f937-1f3fc-200d-2642-fe0f\",\"🤷🏽‍♂️\":\"1f937-1f3fd-200d-2642-fe0f\",\"🤷🏾‍♂️\":\"1f937-1f3fe-200d-2642-fe0f\",\"🤷🏿‍♂️\":\"1f937-1f3ff-200d-2642-fe0f\",\"🤷🏻‍♀️\":\"1f937-1f3fb-200d-2640-fe0f\",\"🤷🏼‍♀️\":\"1f937-1f3fc-200d-2640-fe0f\",\"🤷🏽‍♀️\":\"1f937-1f3fd-200d-2640-fe0f\",\"🤷🏾‍♀️\":\"1f937-1f3fe-200d-2640-fe0f\",\"🤷🏿‍♀️\":\"1f937-1f3ff-200d-2640-fe0f\",\"💆🏻‍♂️\":\"1f486-1f3fb-200d-2642-fe0f\",\"💆🏼‍♂️\":\"1f486-1f3fc-200d-2642-fe0f\",\"💆🏽‍♂️\":\"1f486-1f3fd-200d-2642-fe0f\",\"💆🏾‍♂️\":\"1f486-1f3fe-200d-2642-fe0f\",\"💆🏿‍♂️\":\"1f486-1f3ff-200d-2642-fe0f\",\"💆🏻‍♀️\":\"1f486-1f3fb-200d-2640-fe0f\",\"💆🏼‍♀️\":\"1f486-1f3fc-200d-2640-fe0f\",\"💆🏽‍♀️\":\"1f486-1f3fd-200d-2640-fe0f\",\"💆🏾‍♀️\":\"1f486-1f3fe-200d-2640-fe0f\",\"💆🏿‍♀️\":\"1f486-1f3ff-200d-2640-fe0f\",\"💇🏻‍♂️\":\"1f487-1f3fb-200d-2642-fe0f\",\"💇🏼‍♂️\":\"1f487-1f3fc-200d-2642-fe0f\",\"💇🏽‍♂️\":\"1f487-1f3fd-200d-2642-fe0f\",\"💇🏾‍♂️\":\"1f487-1f3fe-200d-2642-fe0f\",\"💇🏿‍♂️\":\"1f487-1f3ff-200d-2642-fe0f\",\"💇🏻‍♀️\":\"1f487-1f3fb-200d-2640-fe0f\",\"💇🏼‍♀️\":\"1f487-1f3fc-200d-2640-fe0f\",\"💇🏽‍♀️\":\"1f487-1f3fd-200d-2640-fe0f\",\"💇🏾‍♀️\":\"1f487-1f3fe-200d-2640-fe0f\",\"💇🏿‍♀️\":\"1f487-1f3ff-200d-2640-fe0f\",\"🚶🏻‍♂️\":\"1f6b6-1f3fb-200d-2642-fe0f\",\"🚶🏼‍♂️\":\"1f6b6-1f3fc-200d-2642-fe0f\",\"🚶🏽‍♂️\":\"1f6b6-1f3fd-200d-2642-fe0f\",\"🚶🏾‍♂️\":\"1f6b6-1f3fe-200d-2642-fe0f\",\"🚶🏿‍♂️\":\"1f6b6-1f3ff-200d-2642-fe0f\",\"🚶🏻‍♀️\":\"1f6b6-1f3fb-200d-2640-fe0f\",\"🚶🏼‍♀️\":\"1f6b6-1f3fc-200d-2640-fe0f\",\"🚶🏽‍♀️\":\"1f6b6-1f3fd-200d-2640-fe0f\",\"🚶🏾‍♀️\":\"1f6b6-1f3fe-200d-2640-fe0f\",\"🚶🏿‍♀️\":\"1f6b6-1f3ff-200d-2640-fe0f\",\"🏃🏻‍♂️\":\"1f3c3-1f3fb-200d-2642-fe0f\",\"🏃🏼‍♂️\":\"1f3c3-1f3fc-200d-2642-fe0f\",\"🏃🏽‍♂️\":\"1f3c3-1f3fd-200d-2642-fe0f\",\"🏃🏾‍♂️\":\"1f3c3-1f3fe-200d-2642-fe0f\",\"🏃🏿‍♂️\":\"1f3c3-1f3ff-200d-2642-fe0f\",\"🏃🏻‍♀️\":\"1f3c3-1f3fb-200d-2640-fe0f\",\"🏃🏼‍♀️\":\"1f3c3-1f3fc-200d-2640-fe0f\",\"🏃🏽‍♀️\":\"1f3c3-1f3fd-200d-2640-fe0f\",\"🏃🏾‍♀️\":\"1f3c3-1f3fe-200d-2640-fe0f\",\"🏃🏿‍♀️\":\"1f3c3-1f3ff-200d-2640-fe0f\",\"🧖🏻‍♀️\":\"1f9d6-1f3fb-200d-2640-fe0f\",\"🧖🏼‍♀️\":\"1f9d6-1f3fc-200d-2640-fe0f\",\"🧖🏽‍♀️\":\"1f9d6-1f3fd-200d-2640-fe0f\",\"🧖🏾‍♀️\":\"1f9d6-1f3fe-200d-2640-fe0f\",\"🧖🏿‍♀️\":\"1f9d6-1f3ff-200d-2640-fe0f\",\"🧖🏻‍♂️\":\"1f9d6-1f3fb-200d-2642-fe0f\",\"🧖🏼‍♂️\":\"1f9d6-1f3fc-200d-2642-fe0f\",\"🧖🏽‍♂️\":\"1f9d6-1f3fd-200d-2642-fe0f\",\"🧖🏾‍♂️\":\"1f9d6-1f3fe-200d-2642-fe0f\",\"🧖🏿‍♂️\":\"1f9d6-1f3ff-200d-2642-fe0f\",\"🧗🏻‍♀️\":\"1f9d7-1f3fb-200d-2640-fe0f\",\"🧗🏼‍♀️\":\"1f9d7-1f3fc-200d-2640-fe0f\",\"🧗🏽‍♀️\":\"1f9d7-1f3fd-200d-2640-fe0f\",\"🧗🏾‍♀️\":\"1f9d7-1f3fe-200d-2640-fe0f\",\"🧗🏿‍♀️\":\"1f9d7-1f3ff-200d-2640-fe0f\",\"🧗🏻‍♂️\":\"1f9d7-1f3fb-200d-2642-fe0f\",\"🧗🏼‍♂️\":\"1f9d7-1f3fc-200d-2642-fe0f\",\"🧗🏽‍♂️\":\"1f9d7-1f3fd-200d-2642-fe0f\",\"🧗🏾‍♂️\":\"1f9d7-1f3fe-200d-2642-fe0f\",\"🧗🏿‍♂️\":\"1f9d7-1f3ff-200d-2642-fe0f\",\"🧘🏻‍♀️\":\"1f9d8-1f3fb-200d-2640-fe0f\",\"🧘🏼‍♀️\":\"1f9d8-1f3fc-200d-2640-fe0f\",\"🧘🏽‍♀️\":\"1f9d8-1f3fd-200d-2640-fe0f\",\"🧘🏾‍♀️\":\"1f9d8-1f3fe-200d-2640-fe0f\",\"🧘🏿‍♀️\":\"1f9d8-1f3ff-200d-2640-fe0f\",\"🧘🏻‍♂️\":\"1f9d8-1f3fb-200d-2642-fe0f\",\"🧘🏼‍♂️\":\"1f9d8-1f3fc-200d-2642-fe0f\",\"🧘🏽‍♂️\":\"1f9d8-1f3fd-200d-2642-fe0f\",\"🧘🏾‍♂️\":\"1f9d8-1f3fe-200d-2642-fe0f\",\"🧘🏿‍♂️\":\"1f9d8-1f3ff-200d-2642-fe0f\",\"🏌️‍♂️\":\"1f3cc-fe0f-200d-2642-fe0f\",\"🏌🏻‍♂️\":\"1f3cc-1f3fb-200d-2642-fe0f\",\"🏌🏼‍♂️\":\"1f3cc-1f3fc-200d-2642-fe0f\",\"🏌🏽‍♂️\":\"1f3cc-1f3fd-200d-2642-fe0f\",\"🏌🏾‍♂️\":\"1f3cc-1f3fe-200d-2642-fe0f\",\"🏌🏿‍♂️\":\"1f3cc-1f3ff-200d-2642-fe0f\",\"🏌️‍♀️\":\"1f3cc-fe0f-200d-2640-fe0f\",\"🏌🏻‍♀️\":\"1f3cc-1f3fb-200d-2640-fe0f\",\"🏌🏼‍♀️\":\"1f3cc-1f3fc-200d-2640-fe0f\",\"🏌🏽‍♀️\":\"1f3cc-1f3fd-200d-2640-fe0f\",\"🏌🏾‍♀️\":\"1f3cc-1f3fe-200d-2640-fe0f\",\"🏌🏿‍♀️\":\"1f3cc-1f3ff-200d-2640-fe0f\",\"🏄🏻‍♂️\":\"1f3c4-1f3fb-200d-2642-fe0f\",\"🏄🏼‍♂️\":\"1f3c4-1f3fc-200d-2642-fe0f\",\"🏄🏽‍♂️\":\"1f3c4-1f3fd-200d-2642-fe0f\",\"🏄🏾‍♂️\":\"1f3c4-1f3fe-200d-2642-fe0f\",\"🏄🏿‍♂️\":\"1f3c4-1f3ff-200d-2642-fe0f\",\"🏄🏻‍♀️\":\"1f3c4-1f3fb-200d-2640-fe0f\",\"🏄🏼‍♀️\":\"1f3c4-1f3fc-200d-2640-fe0f\",\"🏄🏽‍♀️\":\"1f3c4-1f3fd-200d-2640-fe0f\",\"🏄🏾‍♀️\":\"1f3c4-1f3fe-200d-2640-fe0f\",\"🏄🏿‍♀️\":\"1f3c4-1f3ff-200d-2640-fe0f\",\"🚣🏻‍♂️\":\"1f6a3-1f3fb-200d-2642-fe0f\",\"🚣🏼‍♂️\":\"1f6a3-1f3fc-200d-2642-fe0f\",\"🚣🏽‍♂️\":\"1f6a3-1f3fd-200d-2642-fe0f\",\"🚣🏾‍♂️\":\"1f6a3-1f3fe-200d-2642-fe0f\",\"🚣🏿‍♂️\":\"1f6a3-1f3ff-200d-2642-fe0f\",\"🚣🏻‍♀️\":\"1f6a3-1f3fb-200d-2640-fe0f\",\"🚣🏼‍♀️\":\"1f6a3-1f3fc-200d-2640-fe0f\",\"🚣🏽‍♀️\":\"1f6a3-1f3fd-200d-2640-fe0f\",\"🚣🏾‍♀️\":\"1f6a3-1f3fe-200d-2640-fe0f\",\"🚣🏿‍♀️\":\"1f6a3-1f3ff-200d-2640-fe0f\",\"🏊🏻‍♂️\":\"1f3ca-1f3fb-200d-2642-fe0f\",\"🏊🏼‍♂️\":\"1f3ca-1f3fc-200d-2642-fe0f\",\"🏊🏽‍♂️\":\"1f3ca-1f3fd-200d-2642-fe0f\",\"🏊🏾‍♂️\":\"1f3ca-1f3fe-200d-2642-fe0f\",\"🏊🏿‍♂️\":\"1f3ca-1f3ff-200d-2642-fe0f\",\"🏊🏻‍♀️\":\"1f3ca-1f3fb-200d-2640-fe0f\",\"🏊🏼‍♀️\":\"1f3ca-1f3fc-200d-2640-fe0f\",\"🏊🏽‍♀️\":\"1f3ca-1f3fd-200d-2640-fe0f\",\"🏊🏾‍♀️\":\"1f3ca-1f3fe-200d-2640-fe0f\",\"🏊🏿‍♀️\":\"1f3ca-1f3ff-200d-2640-fe0f\",\"⛹️‍♂️\":\"26f9-fe0f-200d-2642-fe0f\",\"⛹🏻‍♂️\":\"26f9-1f3fb-200d-2642-fe0f\",\"⛹🏼‍♂️\":\"26f9-1f3fc-200d-2642-fe0f\",\"⛹🏽‍♂️\":\"26f9-1f3fd-200d-2642-fe0f\",\"⛹🏾‍♂️\":\"26f9-1f3fe-200d-2642-fe0f\",\"⛹🏿‍♂️\":\"26f9-1f3ff-200d-2642-fe0f\",\"⛹️‍♀️\":\"26f9-fe0f-200d-2640-fe0f\",\"⛹🏻‍♀️\":\"26f9-1f3fb-200d-2640-fe0f\",\"⛹🏼‍♀️\":\"26f9-1f3fc-200d-2640-fe0f\",\"⛹🏽‍♀️\":\"26f9-1f3fd-200d-2640-fe0f\",\"⛹🏾‍♀️\":\"26f9-1f3fe-200d-2640-fe0f\",\"⛹🏿‍♀️\":\"26f9-1f3ff-200d-2640-fe0f\",\"🏋️‍♂️\":\"1f3cb-fe0f-200d-2642-fe0f\",\"🏋🏻‍♂️\":\"1f3cb-1f3fb-200d-2642-fe0f\",\"🏋🏼‍♂️\":\"1f3cb-1f3fc-200d-2642-fe0f\",\"🏋🏽‍♂️\":\"1f3cb-1f3fd-200d-2642-fe0f\",\"🏋🏾‍♂️\":\"1f3cb-1f3fe-200d-2642-fe0f\",\"🏋🏿‍♂️\":\"1f3cb-1f3ff-200d-2642-fe0f\",\"🏋️‍♀️\":\"1f3cb-fe0f-200d-2640-fe0f\",\"🏋🏻‍♀️\":\"1f3cb-1f3fb-200d-2640-fe0f\",\"🏋🏼‍♀️\":\"1f3cb-1f3fc-200d-2640-fe0f\",\"🏋🏽‍♀️\":\"1f3cb-1f3fd-200d-2640-fe0f\",\"🏋🏾‍♀️\":\"1f3cb-1f3fe-200d-2640-fe0f\",\"🏋🏿‍♀️\":\"1f3cb-1f3ff-200d-2640-fe0f\",\"🚴🏻‍♂️\":\"1f6b4-1f3fb-200d-2642-fe0f\",\"🚴🏼‍♂️\":\"1f6b4-1f3fc-200d-2642-fe0f\",\"🚴🏽‍♂️\":\"1f6b4-1f3fd-200d-2642-fe0f\",\"🚴🏾‍♂️\":\"1f6b4-1f3fe-200d-2642-fe0f\",\"🚴🏿‍♂️\":\"1f6b4-1f3ff-200d-2642-fe0f\",\"🚴🏻‍♀️\":\"1f6b4-1f3fb-200d-2640-fe0f\",\"🚴🏼‍♀️\":\"1f6b4-1f3fc-200d-2640-fe0f\",\"🚴🏽‍♀️\":\"1f6b4-1f3fd-200d-2640-fe0f\",\"🚴🏾‍♀️\":\"1f6b4-1f3fe-200d-2640-fe0f\",\"🚴🏿‍♀️\":\"1f6b4-1f3ff-200d-2640-fe0f\",\"🚵🏻‍♂️\":\"1f6b5-1f3fb-200d-2642-fe0f\",\"🚵🏼‍♂️\":\"1f6b5-1f3fc-200d-2642-fe0f\",\"🚵🏽‍♂️\":\"1f6b5-1f3fd-200d-2642-fe0f\",\"🚵🏾‍♂️\":\"1f6b5-1f3fe-200d-2642-fe0f\",\"🚵🏿‍♂️\":\"1f6b5-1f3ff-200d-2642-fe0f\",\"🚵🏻‍♀️\":\"1f6b5-1f3fb-200d-2640-fe0f\",\"🚵🏼‍♀️\":\"1f6b5-1f3fc-200d-2640-fe0f\",\"🚵🏽‍♀️\":\"1f6b5-1f3fd-200d-2640-fe0f\",\"🚵🏾‍♀️\":\"1f6b5-1f3fe-200d-2640-fe0f\",\"🚵🏿‍♀️\":\"1f6b5-1f3ff-200d-2640-fe0f\",\"🤸🏻‍♂️\":\"1f938-1f3fb-200d-2642-fe0f\",\"🤸🏼‍♂️\":\"1f938-1f3fc-200d-2642-fe0f\",\"🤸🏽‍♂️\":\"1f938-1f3fd-200d-2642-fe0f\",\"🤸🏾‍♂️\":\"1f938-1f3fe-200d-2642-fe0f\",\"🤸🏿‍♂️\":\"1f938-1f3ff-200d-2642-fe0f\",\"🤸🏻‍♀️\":\"1f938-1f3fb-200d-2640-fe0f\",\"🤸🏼‍♀️\":\"1f938-1f3fc-200d-2640-fe0f\",\"🤸🏽‍♀️\":\"1f938-1f3fd-200d-2640-fe0f\",\"🤸🏾‍♀️\":\"1f938-1f3fe-200d-2640-fe0f\",\"🤸🏿‍♀️\":\"1f938-1f3ff-200d-2640-fe0f\",\"🤽🏻‍♂️\":\"1f93d-1f3fb-200d-2642-fe0f\",\"🤽🏼‍♂️\":\"1f93d-1f3fc-200d-2642-fe0f\",\"🤽🏽‍♂️\":\"1f93d-1f3fd-200d-2642-fe0f\",\"🤽🏾‍♂️\":\"1f93d-1f3fe-200d-2642-fe0f\",\"🤽🏿‍♂️\":\"1f93d-1f3ff-200d-2642-fe0f\",\"🤽🏻‍♀️\":\"1f93d-1f3fb-200d-2640-fe0f\",\"🤽🏼‍♀️\":\"1f93d-1f3fc-200d-2640-fe0f\",\"🤽🏽‍♀️\":\"1f93d-1f3fd-200d-2640-fe0f\",\"🤽🏾‍♀️\":\"1f93d-1f3fe-200d-2640-fe0f\",\"🤽🏿‍♀️\":\"1f93d-1f3ff-200d-2640-fe0f\",\"🤾🏻‍♂️\":\"1f93e-1f3fb-200d-2642-fe0f\",\"🤾🏼‍♂️\":\"1f93e-1f3fc-200d-2642-fe0f\",\"🤾🏽‍♂️\":\"1f93e-1f3fd-200d-2642-fe0f\",\"🤾🏾‍♂️\":\"1f93e-1f3fe-200d-2642-fe0f\",\"🤾🏿‍♂️\":\"1f93e-1f3ff-200d-2642-fe0f\",\"🤾🏻‍♀️\":\"1f93e-1f3fb-200d-2640-fe0f\",\"🤾🏼‍♀️\":\"1f93e-1f3fc-200d-2640-fe0f\",\"🤾🏽‍♀️\":\"1f93e-1f3fd-200d-2640-fe0f\",\"🤾🏾‍♀️\":\"1f93e-1f3fe-200d-2640-fe0f\",\"🤾🏿‍♀️\":\"1f93e-1f3ff-200d-2640-fe0f\",\"🤹🏻‍♂️\":\"1f939-1f3fb-200d-2642-fe0f\",\"🤹🏼‍♂️\":\"1f939-1f3fc-200d-2642-fe0f\",\"🤹🏽‍♂️\":\"1f939-1f3fd-200d-2642-fe0f\",\"🤹🏾‍♂️\":\"1f939-1f3fe-200d-2642-fe0f\",\"🤹🏿‍♂️\":\"1f939-1f3ff-200d-2642-fe0f\",\"🤹🏻‍♀️\":\"1f939-1f3fb-200d-2640-fe0f\",\"🤹🏼‍♀️\":\"1f939-1f3fc-200d-2640-fe0f\",\"🤹🏽‍♀️\":\"1f939-1f3fd-200d-2640-fe0f\",\"🤹🏾‍♀️\":\"1f939-1f3fe-200d-2640-fe0f\",\"🤹🏿‍♀️\":\"1f939-1f3ff-200d-2640-fe0f\",\"👩‍❤‍👨\":\"1f469-200d-2764-fe0f-200d-1f468\",\"👨‍❤‍👨\":\"1f468-200d-2764-fe0f-200d-1f468\",\"👩‍❤‍👩\":\"1f469-200d-2764-fe0f-200d-1f469\",\"👨‍👩‍👦\":\"1f468-200d-1f469-200d-1f466\",\"👨‍👩‍👧\":\"1f468-200d-1f469-200d-1f467\",\"👨‍👨‍👦\":\"1f468-200d-1f468-200d-1f466\",\"👨‍👨‍👧\":\"1f468-200d-1f468-200d-1f467\",\"👩‍👩‍👦\":\"1f469-200d-1f469-200d-1f466\",\"👩‍👩‍👧\":\"1f469-200d-1f469-200d-1f467\",\"👨‍👦‍👦\":\"1f468-200d-1f466-200d-1f466\",\"👨‍👧‍👦\":\"1f468-200d-1f467-200d-1f466\",\"👨‍👧‍👧\":\"1f468-200d-1f467-200d-1f467\",\"👩‍👦‍👦\":\"1f469-200d-1f466-200d-1f466\",\"👩‍👧‍👦\":\"1f469-200d-1f467-200d-1f466\",\"👩‍👧‍👧\":\"1f469-200d-1f467-200d-1f467\",\"👁️‍🗨️\":\"1f441-200d-1f5e8\",\"👩‍❤️‍👨\":\"1f469-200d-2764-fe0f-200d-1f468\",\"👨‍❤️‍👨\":\"1f468-200d-2764-fe0f-200d-1f468\",\"👩‍❤️‍👩\":\"1f469-200d-2764-fe0f-200d-1f469\",\"👩‍❤‍💋‍👨\":\"1f469-200d-2764-fe0f-200d-1f48b-200d-1f468\",\"👨‍❤‍💋‍👨\":\"1f468-200d-2764-fe0f-200d-1f48b-200d-1f468\",\"👩‍❤‍💋‍👩\":\"1f469-200d-2764-fe0f-200d-1f48b-200d-1f469\",\"👨‍👩‍👧‍👦\":\"1f468-200d-1f469-200d-1f467-200d-1f466\",\"👨‍👩‍👦‍👦\":\"1f468-200d-1f469-200d-1f466-200d-1f466\",\"👨‍👩‍👧‍👧\":\"1f468-200d-1f469-200d-1f467-200d-1f467\",\"👨‍👨‍👧‍👦\":\"1f468-200d-1f468-200d-1f467-200d-1f466\",\"👨‍👨‍👦‍👦\":\"1f468-200d-1f468-200d-1f466-200d-1f466\",\"👨‍👨‍👧‍👧\":\"1f468-200d-1f468-200d-1f467-200d-1f467\",\"👩‍👩‍👧‍👦\":\"1f469-200d-1f469-200d-1f467-200d-1f466\",\"👩‍👩‍👦‍👦\":\"1f469-200d-1f469-200d-1f466-200d-1f466\",\"👩‍👩‍👧‍👧\":\"1f469-200d-1f469-200d-1f467-200d-1f467\",\"🏴󠁧󠁢󠁥󠁮󠁧󠁿\":\"1f3f4-e0067-e0062-e0065-e006e-e0067-e007f\",\"🏴󠁧󠁢󠁳󠁣󠁴󠁿\":\"1f3f4-e0067-e0062-e0073-e0063-e0074-e007f\",\"🏴󠁧󠁢󠁷󠁬󠁳󠁿\":\"1f3f4-e0067-e0062-e0077-e006c-e0073-e007f\",\"👩‍❤️‍💋‍👨\":\"1f469-200d-2764-fe0f-200d-1f48b-200d-1f468\",\"👨‍❤️‍💋‍👨\":\"1f468-200d-2764-fe0f-200d-1f48b-200d-1f468\",\"👩‍❤️‍💋‍👩\":\"1f469-200d-2764-fe0f-200d-1f48b-200d-1f469\"}"
  },
  {
    "path": "app/javascript/mastodon/features/emoji/emoji_mart_data_light.js",
    "content": "// The output of this module is designed to mimic emoji-mart's\n// \"data\" object, such that we can use it for a light version of emoji-mart's\n// emojiIndex.search functionality.\nconst { unicodeToUnifiedName } = require('./unicode_to_unified_name');\nconst [ shortCodesToEmojiData, skins, categories, short_names ] = require('./emoji_compressed');\n\nconst emojis = {};\n\n// decompress\nObject.keys(shortCodesToEmojiData).forEach((shortCode) => {\n  let [\n    filenameData, // eslint-disable-line no-unused-vars\n    searchData,\n  ] = shortCodesToEmojiData[shortCode];\n  let [\n    native,\n    short_names,\n    search,\n    unified,\n  ] = searchData;\n\n  if (!unified) {\n    // unified name can be derived from unicodeToUnifiedName\n    unified = unicodeToUnifiedName(native);\n  }\n\n  short_names = [shortCode].concat(short_names);\n  emojis[shortCode] = {\n    native,\n    search,\n    short_names,\n    unified,\n  };\n});\n\nmodule.exports = {\n  emojis,\n  skins,\n  categories,\n  short_names,\n};\n"
  },
  {
    "path": "app/javascript/mastodon/features/emoji/emoji_mart_search_light.js",
    "content": "// This code is largely borrowed from:\n// https://github.com/missive/emoji-mart/blob/5f2ffcc/src/utils/emoji-index.js\n\nimport data from './emoji_mart_data_light';\nimport { getData, getSanitizedData, uniq, intersect } from './emoji_utils';\n\nlet originalPool = {};\nlet index = {};\nlet emojisList = {};\nlet emoticonsList = {};\nlet customEmojisList = [];\n\nfor (let emoji in data.emojis) {\n  let emojiData = data.emojis[emoji];\n  let { short_names, emoticons } = emojiData;\n  let id = short_names[0];\n\n  if (emoticons) {\n    emoticons.forEach(emoticon => {\n      if (emoticonsList[emoticon]) {\n        return;\n      }\n\n      emoticonsList[emoticon] = id;\n    });\n  }\n\n  emojisList[id] = getSanitizedData(id);\n  originalPool[id] = emojiData;\n}\n\nfunction clearCustomEmojis(pool) {\n  customEmojisList.forEach((emoji) => {\n    let emojiId = emoji.id || emoji.short_names[0];\n\n    delete pool[emojiId];\n    delete emojisList[emojiId];\n  });\n}\n\nfunction addCustomToPool(custom, pool) {\n  if (customEmojisList.length) clearCustomEmojis(pool);\n\n  custom.forEach((emoji) => {\n    let emojiId = emoji.id || emoji.short_names[0];\n\n    if (emojiId && !pool[emojiId]) {\n      pool[emojiId] = getData(emoji);\n      emojisList[emojiId] = getSanitizedData(emoji);\n    }\n  });\n\n  customEmojisList = custom;\n  index = {};\n}\n\nfunction search(value, { emojisToShowFilter, maxResults, include, exclude, custom } = {}) {\n  if (custom !== undefined) {\n    if (customEmojisList !== custom)\n      addCustomToPool(custom, originalPool);\n  } else {\n    custom = [];\n  }\n\n  maxResults = maxResults || 75;\n  include = include || [];\n  exclude = exclude || [];\n\n  let results = null,\n    pool = originalPool;\n\n  if (value.length) {\n    if (value === '-' || value === '-1') {\n      return [emojisList['-1']];\n    }\n\n    let values = value.toLowerCase().split(/[\\s|,|\\-|_]+/),\n      allResults = [];\n\n    if (values.length > 2) {\n      values = [values[0], values[1]];\n    }\n\n    if (include.length || exclude.length) {\n      pool = {};\n\n      data.categories.forEach(category => {\n        let isIncluded = include && include.length ? include.indexOf(category.name.toLowerCase()) > -1 : true;\n        let isExcluded = exclude && exclude.length ? exclude.indexOf(category.name.toLowerCase()) > -1 : false;\n        if (!isIncluded || isExcluded) {\n          return;\n        }\n\n        category.emojis.forEach(emojiId => pool[emojiId] = data.emojis[emojiId]);\n      });\n\n      if (custom.length) {\n        let customIsIncluded = include && include.length ? include.indexOf('custom') > -1 : true;\n        let customIsExcluded = exclude && exclude.length ? exclude.indexOf('custom') > -1 : false;\n        if (customIsIncluded && !customIsExcluded) {\n          addCustomToPool(custom, pool);\n        }\n      }\n    }\n\n    const searchValue = (value) => {\n      let aPool = pool,\n        aIndex = index,\n        length = 0;\n\n      for (let charIndex = 0; charIndex < value.length; charIndex++) {\n        const char = value[charIndex];\n        length++;\n\n        aIndex[char] = aIndex[char] || {};\n        aIndex = aIndex[char];\n\n        if (!aIndex.results) {\n          let scores = {};\n\n          aIndex.results = [];\n          aIndex.pool = {};\n\n          for (let id in aPool) {\n            let emoji = aPool[id],\n              { search } = emoji,\n              sub = value.substr(0, length),\n              subIndex = search.indexOf(sub);\n\n            if (subIndex !== -1) {\n              let score = subIndex + 1;\n              if (sub === id) score = 0;\n\n              aIndex.results.push(emojisList[id]);\n              aIndex.pool[id] = emoji;\n\n              scores[id] = score;\n            }\n          }\n\n          aIndex.results.sort((a, b) => {\n            let aScore = scores[a.id],\n              bScore = scores[b.id];\n\n            return aScore - bScore;\n          });\n        }\n\n        aPool = aIndex.pool;\n      }\n\n      return aIndex.results;\n    };\n\n    if (values.length > 1) {\n      results = searchValue(value);\n    } else {\n      results = [];\n    }\n\n    allResults = values.map(searchValue).filter(a => a);\n\n    if (allResults.length > 1) {\n      allResults = intersect.apply(null, allResults);\n    } else if (allResults.length) {\n      allResults = allResults[0];\n    }\n\n    results = uniq(results.concat(allResults));\n  }\n\n  if (results) {\n    if (emojisToShowFilter) {\n      results = results.filter((result) => emojisToShowFilter(data.emojis[result.id]));\n    }\n\n    if (results && results.length > maxResults) {\n      results = results.slice(0, maxResults);\n    }\n  }\n\n  return results;\n}\n\nexport { search };\n"
  },
  {
    "path": "app/javascript/mastodon/features/emoji/emoji_picker.js",
    "content": "import Picker from 'emoji-mart/dist-es/components/picker/picker';\nimport Emoji from 'emoji-mart/dist-es/components/emoji/emoji';\n\nexport {\n  Picker,\n  Emoji,\n};\n"
  },
  {
    "path": "app/javascript/mastodon/features/emoji/emoji_unicode_mapping_light.js",
    "content": "// A mapping of unicode strings to an object containing the filename\n// (i.e. the svg filename) and a shortCode intended to be shown\n// as a \"title\" attribute in an HTML element (aka tooltip).\n\nconst [\n  shortCodesToEmojiData,\n  skins, // eslint-disable-line no-unused-vars\n  categories, // eslint-disable-line no-unused-vars\n  short_names, // eslint-disable-line no-unused-vars\n  emojisWithoutShortCodes,\n] = require('./emoji_compressed');\nconst { unicodeToFilename } = require('./unicode_to_filename');\n\n// decompress\nconst unicodeMapping = {};\n\nfunction processEmojiMapData(emojiMapData, shortCode) {\n  let [ native, filename ] = emojiMapData;\n  if (!filename) {\n    // filename name can be derived from unicodeToFilename\n    filename = unicodeToFilename(native);\n  }\n  unicodeMapping[native] = {\n    shortCode: shortCode,\n    filename: filename,\n  };\n}\n\nObject.keys(shortCodesToEmojiData).forEach((shortCode) => {\n  let [ filenameData ] = shortCodesToEmojiData[shortCode];\n  filenameData.forEach(emojiMapData => processEmojiMapData(emojiMapData, shortCode));\n});\nemojisWithoutShortCodes.forEach(emojiMapData => processEmojiMapData(emojiMapData));\n\nmodule.exports = unicodeMapping;\n"
  },
  {
    "path": "app/javascript/mastodon/features/emoji/emoji_utils.js",
    "content": "// This code is largely borrowed from:\n// https://github.com/missive/emoji-mart/blob/5f2ffcc/src/utils/index.js\n\nimport data from './emoji_mart_data_light';\n\nconst buildSearch = (data) => {\n  const search = [];\n\n  let addToSearch = (strings, split) => {\n    if (!strings) {\n      return;\n    }\n\n    (Array.isArray(strings) ? strings : [strings]).forEach((string) => {\n      (split ? string.split(/[-|_|\\s]+/) : [string]).forEach((s) => {\n        s = s.toLowerCase();\n\n        if (search.indexOf(s) === -1) {\n          search.push(s);\n        }\n      });\n    });\n  };\n\n  addToSearch(data.short_names, true);\n  addToSearch(data.name, true);\n  addToSearch(data.keywords, false);\n  addToSearch(data.emoticons, false);\n\n  return search.join(',');\n};\n\nconst _String = String;\n\nconst stringFromCodePoint = _String.fromCodePoint || function () {\n  let MAX_SIZE = 0x4000;\n  let codeUnits = [];\n  let highSurrogate;\n  let lowSurrogate;\n  let index = -1;\n  let length = arguments.length;\n  if (!length) {\n    return '';\n  }\n  let result = '';\n  while (++index < length) {\n    let codePoint = Number(arguments[index]);\n    if (\n      !isFinite(codePoint) ||       // `NaN`, `+Infinity`, or `-Infinity`\n      codePoint < 0 ||              // not a valid Unicode code point\n      codePoint > 0x10FFFF ||       // not a valid Unicode code point\n      Math.floor(codePoint) !== codePoint // not an integer\n    ) {\n      throw RangeError('Invalid code point: ' + codePoint);\n    }\n    if (codePoint <= 0xFFFF) { // BMP code point\n      codeUnits.push(codePoint);\n    } else { // Astral code point; split in surrogate halves\n      // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae\n      codePoint -= 0x10000;\n      highSurrogate = (codePoint >> 10) + 0xD800;\n      lowSurrogate = (codePoint % 0x400) + 0xDC00;\n      codeUnits.push(highSurrogate, lowSurrogate);\n    }\n    if (index + 1 === length || codeUnits.length > MAX_SIZE) {\n      result += String.fromCharCode.apply(null, codeUnits);\n      codeUnits.length = 0;\n    }\n  }\n  return result;\n};\n\n\nconst _JSON = JSON;\n\nconst COLONS_REGEX = /^(?:\\:([^\\:]+)\\:)(?:\\:skin-tone-(\\d)\\:)?$/;\nconst SKINS = [\n  '1F3FA', '1F3FB', '1F3FC',\n  '1F3FD', '1F3FE', '1F3FF',\n];\n\nfunction unifiedToNative(unified) {\n  let unicodes = unified.split('-'),\n    codePoints = unicodes.map((u) => `0x${u}`);\n\n  return stringFromCodePoint.apply(null, codePoints);\n}\n\nfunction sanitize(emoji) {\n  let { name, short_names, skin_tone, skin_variations, emoticons, unified, custom, imageUrl } = emoji,\n    id = emoji.id || short_names[0],\n    colons = `:${id}:`;\n\n  if (custom) {\n    return {\n      id,\n      name,\n      colons,\n      emoticons,\n      custom,\n      imageUrl,\n    };\n  }\n\n  if (skin_tone) {\n    colons += `:skin-tone-${skin_tone}:`;\n  }\n\n  return {\n    id,\n    name,\n    colons,\n    emoticons,\n    unified: unified.toLowerCase(),\n    skin: skin_tone || (skin_variations ? 1 : null),\n    native: unifiedToNative(unified),\n  };\n}\n\nfunction getSanitizedData() {\n  return sanitize(getData(...arguments));\n}\n\nfunction getData(emoji, skin, set) {\n  let emojiData = {};\n\n  if (typeof emoji === 'string') {\n    let matches = emoji.match(COLONS_REGEX);\n\n    if (matches) {\n      emoji = matches[1];\n\n      if (matches[2]) {\n        skin = parseInt(matches[2]);\n      }\n    }\n\n    if (data.short_names.hasOwnProperty(emoji)) {\n      emoji = data.short_names[emoji];\n    }\n\n    if (data.emojis.hasOwnProperty(emoji)) {\n      emojiData = data.emojis[emoji];\n    }\n  } else if (emoji.id) {\n    if (data.short_names.hasOwnProperty(emoji.id)) {\n      emoji.id = data.short_names[emoji.id];\n    }\n\n    if (data.emojis.hasOwnProperty(emoji.id)) {\n      emojiData = data.emojis[emoji.id];\n      skin = skin || emoji.skin;\n    }\n  }\n\n  if (!Object.keys(emojiData).length) {\n    emojiData = emoji;\n    emojiData.custom = true;\n\n    if (!emojiData.search) {\n      emojiData.search = buildSearch(emoji);\n    }\n  }\n\n  emojiData.emoticons = emojiData.emoticons || [];\n  emojiData.variations = emojiData.variations || [];\n\n  if (emojiData.skin_variations && skin > 1 && set) {\n    emojiData = JSON.parse(_JSON.stringify(emojiData));\n\n    let skinKey = SKINS[skin - 1],\n      variationData = emojiData.skin_variations[skinKey];\n\n    if (!variationData.variations && emojiData.variations) {\n      delete emojiData.variations;\n    }\n\n    if (variationData[`has_img_${set}`]) {\n      emojiData.skin_tone = skin;\n\n      for (let k in variationData) {\n        let v = variationData[k];\n        emojiData[k] = v;\n      }\n    }\n  }\n\n  if (emojiData.variations && emojiData.variations.length) {\n    emojiData = JSON.parse(_JSON.stringify(emojiData));\n    emojiData.unified = emojiData.variations.shift();\n  }\n\n  return emojiData;\n}\n\nfunction uniq(arr) {\n  return arr.reduce((acc, item) => {\n    if (acc.indexOf(item) === -1) {\n      acc.push(item);\n    }\n    return acc;\n  }, []);\n}\n\nfunction intersect(a, b) {\n  const uniqA = uniq(a);\n  const uniqB = uniq(b);\n\n  return uniqA.filter(item => uniqB.indexOf(item) >= 0);\n}\n\nfunction deepMerge(a, b) {\n  let o = {};\n\n  for (let key in a) {\n    let originalValue = a[key],\n      value = originalValue;\n\n    if (b.hasOwnProperty(key)) {\n      value = b[key];\n    }\n\n    if (typeof value === 'object') {\n      value = deepMerge(originalValue, value);\n    }\n\n    o[key] = value;\n  }\n\n  return o;\n}\n\n// https://github.com/sonicdoe/measure-scrollbar\nfunction measureScrollbar() {\n  const div = document.createElement('div');\n\n  div.style.width = '100px';\n  div.style.height = '100px';\n  div.style.overflow = 'scroll';\n  div.style.position = 'absolute';\n  div.style.top = '-9999px';\n\n  document.body.appendChild(div);\n  const scrollbarWidth = div.offsetWidth - div.clientWidth;\n  document.body.removeChild(div);\n\n  return scrollbarWidth;\n}\n\nexport {\n  getData,\n  getSanitizedData,\n  uniq,\n  intersect,\n  deepMerge,\n  unifiedToNative,\n  measureScrollbar,\n};\n"
  },
  {
    "path": "app/javascript/mastodon/features/emoji/unicode_to_filename.js",
    "content": "// taken from:\n// https://github.com/twitter/twemoji/blob/47732c7/twemoji-generator.js#L848-L866\nexports.unicodeToFilename = (str) => {\n  let result = '';\n  let charCode = 0;\n  let p = 0;\n  let i = 0;\n  while (i < str.length) {\n    charCode = str.charCodeAt(i++);\n    if (p) {\n      if (result.length > 0) {\n        result += '-';\n      }\n      result += (0x10000 + ((p - 0xD800) << 10) + (charCode - 0xDC00)).toString(16);\n      p = 0;\n    } else if (0xD800 <= charCode && charCode <= 0xDBFF) {\n      p = charCode;\n    } else {\n      if (result.length > 0) {\n        result += '-';\n      }\n      result += charCode.toString(16);\n    }\n  }\n  return result;\n};\n"
  },
  {
    "path": "app/javascript/mastodon/features/emoji/unicode_to_unified_name.js",
    "content": "function padLeft(str, num) {\n  while (str.length < num) {\n    str = '0' + str;\n  }\n  return str;\n}\n\nexports.unicodeToUnifiedName = (str) => {\n  let output = '';\n  for (let i = 0; i < str.length; i += 2) {\n    if (i > 0) {\n      output += '-';\n    }\n    output += padLeft(str.codePointAt(i).toString(16).toUpperCase(), 4);\n  }\n  return output;\n};\n"
  },
  {
    "path": "app/javascript/mastodon/features/favourited_statuses/index.js",
    "content": "import React from 'react';\nimport { connect } from 'react-redux';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport { fetchFavouritedStatuses, expandFavouritedStatuses } from '../../actions/favourites';\nimport Column from '../ui/components/column';\nimport ColumnHeader from '../../components/column_header';\nimport { addColumn, removeColumn, moveColumn } from '../../actions/columns';\nimport StatusList from '../../components/status_list';\nimport { defineMessages, injectIntl, FormattedMessage } from 'react-intl';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport { debounce } from 'lodash';\n\nconst messages = defineMessages({\n  heading: { id: 'column.favourites', defaultMessage: 'Favourites' },\n});\n\nconst mapStateToProps = state => ({\n  statusIds: state.getIn(['status_lists', 'favourites', 'items']),\n  isLoading: state.getIn(['status_lists', 'favourites', 'isLoading'], true),\n  hasMore: !!state.getIn(['status_lists', 'favourites', 'next']),\n});\n\nexport default @connect(mapStateToProps)\n@injectIntl\nclass Favourites extends ImmutablePureComponent {\n\n  static propTypes = {\n    dispatch: PropTypes.func.isRequired,\n    shouldUpdateScroll: PropTypes.func,\n    statusIds: ImmutablePropTypes.list.isRequired,\n    intl: PropTypes.object.isRequired,\n    columnId: PropTypes.string,\n    multiColumn: PropTypes.bool,\n    hasMore: PropTypes.bool,\n    isLoading: PropTypes.bool,\n  };\n\n  componentWillMount () {\n    this.props.dispatch(fetchFavouritedStatuses());\n  }\n\n  handlePin = () => {\n    const { columnId, dispatch } = this.props;\n\n    if (columnId) {\n      dispatch(removeColumn(columnId));\n    } else {\n      dispatch(addColumn('FAVOURITES', {}));\n    }\n  }\n\n  handleMove = (dir) => {\n    const { columnId, dispatch } = this.props;\n    dispatch(moveColumn(columnId, dir));\n  }\n\n  handleHeaderClick = () => {\n    this.column.scrollTop();\n  }\n\n  setRef = c => {\n    this.column = c;\n  }\n\n  handleLoadMore = debounce(() => {\n    this.props.dispatch(expandFavouritedStatuses());\n  }, 300, { leading: true })\n\n  render () {\n    const { intl, shouldUpdateScroll, statusIds, columnId, multiColumn, hasMore, isLoading } = this.props;\n    const pinned = !!columnId;\n\n    const emptyMessage = <FormattedMessage id='empty_column.favourited_statuses' defaultMessage=\"You don't have any favourite toots yet. When you favourite one, it will show up here.\" />;\n\n    return (\n      <Column ref={this.setRef} label={intl.formatMessage(messages.heading)}>\n        <ColumnHeader\n          icon='star'\n          title={intl.formatMessage(messages.heading)}\n          onPin={this.handlePin}\n          onMove={this.handleMove}\n          onClick={this.handleHeaderClick}\n          pinned={pinned}\n          multiColumn={multiColumn}\n          showBackButton\n        />\n\n        <StatusList\n          trackScroll={!pinned}\n          statusIds={statusIds}\n          scrollKey={`favourited_statuses-${columnId}`}\n          hasMore={hasMore}\n          isLoading={isLoading}\n          onLoadMore={this.handleLoadMore}\n          shouldUpdateScroll={shouldUpdateScroll}\n          emptyMessage={emptyMessage}\n        />\n      </Column>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/favourites/index.js",
    "content": "import React from 'react';\nimport { connect } from 'react-redux';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport LoadingIndicator from '../../components/loading_indicator';\nimport { fetchFavourites } from '../../actions/interactions';\nimport { FormattedMessage } from 'react-intl';\nimport AccountContainer from '../../containers/account_container';\nimport Column from '../ui/components/column';\nimport ColumnBackButton from '../../components/column_back_button';\nimport ScrollableList from '../../components/scrollable_list';\n\nconst mapStateToProps = (state, props) => ({\n  accountIds: state.getIn(['user_lists', 'favourited_by', props.params.statusId]),\n});\n\nexport default @connect(mapStateToProps)\nclass Favourites extends ImmutablePureComponent {\n\n  static propTypes = {\n    params: PropTypes.object.isRequired,\n    dispatch: PropTypes.func.isRequired,\n    shouldUpdateScroll: PropTypes.func,\n    accountIds: ImmutablePropTypes.list,\n  };\n\n  componentWillMount () {\n    this.props.dispatch(fetchFavourites(this.props.params.statusId));\n  }\n\n  componentWillReceiveProps (nextProps) {\n    if (nextProps.params.statusId !== this.props.params.statusId && nextProps.params.statusId) {\n      this.props.dispatch(fetchFavourites(nextProps.params.statusId));\n    }\n  }\n\n  render () {\n    const { shouldUpdateScroll, accountIds } = this.props;\n\n    if (!accountIds) {\n      return (\n        <Column>\n          <LoadingIndicator />\n        </Column>\n      );\n    }\n\n    const emptyMessage = <FormattedMessage id='empty_column.favourites' defaultMessage='No one has favourited this toot yet. When someone does, they will show up here.' />;\n\n    return (\n      <Column>\n        <ColumnBackButton />\n\n        <ScrollableList\n          scrollKey='favourites'\n          shouldUpdateScroll={shouldUpdateScroll}\n          emptyMessage={emptyMessage}\n        >\n          {accountIds.map(id =>\n            <AccountContainer key={id} id={id} withNote={false} />\n          )}\n        </ScrollableList>\n      </Column>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/follow_requests/components/account_authorize.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport Permalink from '../../../components/permalink';\nimport Avatar from '../../../components/avatar';\nimport DisplayName from '../../../components/display_name';\nimport IconButton from '../../../components/icon_button';\nimport { defineMessages, injectIntl } from 'react-intl';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\n\nconst messages = defineMessages({\n  authorize: { id: 'follow_request.authorize', defaultMessage: 'Authorize' },\n  reject: { id: 'follow_request.reject', defaultMessage: 'Reject' },\n});\n\nexport default @injectIntl\nclass AccountAuthorize extends ImmutablePureComponent {\n\n  static propTypes = {\n    account: ImmutablePropTypes.map.isRequired,\n    onAuthorize: PropTypes.func.isRequired,\n    onReject: PropTypes.func.isRequired,\n    intl: PropTypes.object.isRequired,\n  };\n\n  render () {\n    const { intl, account, onAuthorize, onReject } = this.props;\n    const content = { __html: account.get('note_emojified') };\n\n    return (\n      <div className='account-authorize__wrapper'>\n        <div className='account-authorize'>\n          <Permalink href={account.get('url')} to={`/accounts/${account.get('id')}`} className='detailed-status__display-name'>\n            <div className='account-authorize__avatar'><Avatar account={account} size={48} /></div>\n            <DisplayName account={account} />\n          </Permalink>\n\n          <div className='account__header__content' dangerouslySetInnerHTML={content} />\n        </div>\n\n        <div className='account--panel'>\n          <div className='account--panel__button'><IconButton title={intl.formatMessage(messages.authorize)} icon='check' onClick={onAuthorize} /></div>\n          <div className='account--panel__button'><IconButton title={intl.formatMessage(messages.reject)} icon='times' onClick={onReject} /></div>\n        </div>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/follow_requests/containers/account_authorize_container.js",
    "content": "import { connect } from 'react-redux';\nimport { makeGetAccount } from '../../../selectors';\nimport AccountAuthorize from '../components/account_authorize';\nimport { authorizeFollowRequest, rejectFollowRequest } from '../../../actions/accounts';\n\nconst makeMapStateToProps = () => {\n  const getAccount = makeGetAccount();\n\n  const mapStateToProps = (state, props) => ({\n    account: getAccount(state, props.id),\n  });\n\n  return mapStateToProps;\n};\n\nconst mapDispatchToProps = (dispatch, { id }) => ({\n  onAuthorize () {\n    dispatch(authorizeFollowRequest(id));\n  },\n\n  onReject () {\n    dispatch(rejectFollowRequest(id));\n  },\n});\n\nexport default connect(makeMapStateToProps, mapDispatchToProps)(AccountAuthorize);\n"
  },
  {
    "path": "app/javascript/mastodon/features/follow_requests/index.js",
    "content": "import React from 'react';\nimport { connect } from 'react-redux';\nimport { defineMessages, injectIntl, FormattedMessage } from 'react-intl';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport { debounce } from 'lodash';\nimport LoadingIndicator from '../../components/loading_indicator';\nimport Column from '../ui/components/column';\nimport ColumnBackButtonSlim from '../../components/column_back_button_slim';\nimport AccountAuthorizeContainer from './containers/account_authorize_container';\nimport { fetchFollowRequests, expandFollowRequests } from '../../actions/accounts';\nimport ScrollableList from '../../components/scrollable_list';\n\nconst messages = defineMessages({\n  heading: { id: 'column.follow_requests', defaultMessage: 'Follow requests' },\n});\n\nconst mapStateToProps = state => ({\n  accountIds: state.getIn(['user_lists', 'follow_requests', 'items']),\n  hasMore: !!state.getIn(['user_lists', 'follow_requests', 'next']),\n});\n\nexport default @connect(mapStateToProps)\n@injectIntl\nclass FollowRequests extends ImmutablePureComponent {\n\n  static propTypes = {\n    params: PropTypes.object.isRequired,\n    dispatch: PropTypes.func.isRequired,\n    shouldUpdateScroll: PropTypes.func,\n    hasMore: PropTypes.bool,\n    accountIds: ImmutablePropTypes.list,\n    intl: PropTypes.object.isRequired,\n  };\n\n  componentWillMount () {\n    this.props.dispatch(fetchFollowRequests());\n  }\n\n  handleLoadMore = debounce(() => {\n    this.props.dispatch(expandFollowRequests());\n  }, 300, { leading: true });\n\n  render () {\n    const { intl, shouldUpdateScroll, accountIds, hasMore } = this.props;\n\n    if (!accountIds) {\n      return (\n        <Column>\n          <LoadingIndicator />\n        </Column>\n      );\n    }\n\n    const emptyMessage = <FormattedMessage id='empty_column.follow_requests' defaultMessage=\"You don't have any follow requests yet. When you receive one, it will show up here.\" />;\n\n    return (\n      <Column icon='user-plus' heading={intl.formatMessage(messages.heading)}>\n        <ColumnBackButtonSlim />\n        <ScrollableList\n          scrollKey='follow_requests'\n          onLoadMore={this.handleLoadMore}\n          hasMore={hasMore}\n          shouldUpdateScroll={shouldUpdateScroll}\n          emptyMessage={emptyMessage}\n        >\n          {accountIds.map(id =>\n            <AccountAuthorizeContainer key={id} id={id} />\n          )}\n        </ScrollableList>\n      </Column>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/followers/index.js",
    "content": "import React from 'react';\nimport { connect } from 'react-redux';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport { debounce } from 'lodash';\nimport LoadingIndicator from '../../components/loading_indicator';\nimport {\n  fetchAccount,\n  fetchFollowers,\n  expandFollowers,\n} from '../../actions/accounts';\nimport { FormattedMessage } from 'react-intl';\nimport AccountContainer from '../../containers/account_container';\nimport Column from '../ui/components/column';\nimport HeaderContainer from '../account_timeline/containers/header_container';\nimport ColumnBackButton from '../../components/column_back_button';\nimport ScrollableList from '../../components/scrollable_list';\nimport MissingIndicator from 'mastodon/components/missing_indicator';\n\nconst mapStateToProps = (state, props) => ({\n  isAccount: !!state.getIn(['accounts', props.params.accountId]),\n  accountIds: state.getIn(['user_lists', 'followers', props.params.accountId, 'items']),\n  hasMore: !!state.getIn(['user_lists', 'followers', props.params.accountId, 'next']),\n  blockedBy: state.getIn(['relationships', props.params.accountId, 'blocked_by'], false),\n});\n\nexport default @connect(mapStateToProps)\nclass Followers extends ImmutablePureComponent {\n\n  static propTypes = {\n    params: PropTypes.object.isRequired,\n    dispatch: PropTypes.func.isRequired,\n    shouldUpdateScroll: PropTypes.func,\n    accountIds: ImmutablePropTypes.list,\n    hasMore: PropTypes.bool,\n    blockedBy: PropTypes.bool,\n    isAccount: PropTypes.bool,\n  };\n\n  componentWillMount () {\n    this.props.dispatch(fetchAccount(this.props.params.accountId));\n    this.props.dispatch(fetchFollowers(this.props.params.accountId));\n  }\n\n  componentWillReceiveProps (nextProps) {\n    if (nextProps.params.accountId !== this.props.params.accountId && nextProps.params.accountId) {\n      this.props.dispatch(fetchAccount(nextProps.params.accountId));\n      this.props.dispatch(fetchFollowers(nextProps.params.accountId));\n    }\n  }\n\n  handleLoadMore = debounce(() => {\n    this.props.dispatch(expandFollowers(this.props.params.accountId));\n  }, 300, { leading: true });\n\n  render () {\n    const { shouldUpdateScroll, accountIds, hasMore, blockedBy, isAccount } = this.props;\n\n    if (!isAccount) {\n      return (\n        <Column>\n          <MissingIndicator />\n        </Column>\n      );\n    }\n\n    if (!accountIds) {\n      return (\n        <Column>\n          <LoadingIndicator />\n        </Column>\n      );\n    }\n\n    const emptyMessage = blockedBy ? <FormattedMessage id='empty_column.account_unavailable' defaultMessage='Profile unavailable' /> : <FormattedMessage id='account.followers.empty' defaultMessage='No one follows this user yet.' />;\n\n    return (\n      <Column>\n        <ColumnBackButton />\n\n        <ScrollableList\n          scrollKey='followers'\n          hasMore={hasMore}\n          onLoadMore={this.handleLoadMore}\n          shouldUpdateScroll={shouldUpdateScroll}\n          prepend={<HeaderContainer accountId={this.props.params.accountId} hideTabs />}\n          alwaysPrepend\n          emptyMessage={emptyMessage}\n        >\n          {blockedBy ? [] : accountIds.map(id =>\n            <AccountContainer key={id} id={id} withNote={false} />\n          )}\n        </ScrollableList>\n      </Column>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/following/index.js",
    "content": "import React from 'react';\nimport { connect } from 'react-redux';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport { debounce } from 'lodash';\nimport LoadingIndicator from '../../components/loading_indicator';\nimport {\n  fetchAccount,\n  fetchFollowing,\n  expandFollowing,\n} from '../../actions/accounts';\nimport { FormattedMessage } from 'react-intl';\nimport AccountContainer from '../../containers/account_container';\nimport Column from '../ui/components/column';\nimport HeaderContainer from '../account_timeline/containers/header_container';\nimport ColumnBackButton from '../../components/column_back_button';\nimport ScrollableList from '../../components/scrollable_list';\nimport MissingIndicator from 'mastodon/components/missing_indicator';\n\nconst mapStateToProps = (state, props) => ({\n  isAccount: !!state.getIn(['accounts', props.params.accountId]),\n  accountIds: state.getIn(['user_lists', 'following', props.params.accountId, 'items']),\n  hasMore: !!state.getIn(['user_lists', 'following', props.params.accountId, 'next']),\n  blockedBy: state.getIn(['relationships', props.params.accountId, 'blocked_by'], false),\n});\n\nexport default @connect(mapStateToProps)\nclass Following extends ImmutablePureComponent {\n\n  static propTypes = {\n    params: PropTypes.object.isRequired,\n    dispatch: PropTypes.func.isRequired,\n    shouldUpdateScroll: PropTypes.func,\n    accountIds: ImmutablePropTypes.list,\n    hasMore: PropTypes.bool,\n    blockedBy: PropTypes.bool,\n    isAccount: PropTypes.bool,\n  };\n\n  componentWillMount () {\n    this.props.dispatch(fetchAccount(this.props.params.accountId));\n    this.props.dispatch(fetchFollowing(this.props.params.accountId));\n  }\n\n  componentWillReceiveProps (nextProps) {\n    if (nextProps.params.accountId !== this.props.params.accountId && nextProps.params.accountId) {\n      this.props.dispatch(fetchAccount(nextProps.params.accountId));\n      this.props.dispatch(fetchFollowing(nextProps.params.accountId));\n    }\n  }\n\n  handleLoadMore = debounce(() => {\n    this.props.dispatch(expandFollowing(this.props.params.accountId));\n  }, 300, { leading: true });\n\n  render () {\n    const { shouldUpdateScroll, accountIds, hasMore, blockedBy, isAccount } = this.props;\n\n    if (!isAccount) {\n      return (\n        <Column>\n          <MissingIndicator />\n        </Column>\n      );\n    }\n\n    if (!accountIds) {\n      return (\n        <Column>\n          <LoadingIndicator />\n        </Column>\n      );\n    }\n\n    const emptyMessage = blockedBy ? <FormattedMessage id='empty_column.account_unavailable' defaultMessage='Profile unavailable' /> : <FormattedMessage id='account.follows.empty' defaultMessage=\"This user doesn't follow anyone yet.\" />;\n\n    return (\n      <Column>\n        <ColumnBackButton />\n\n        <ScrollableList\n          scrollKey='following'\n          hasMore={hasMore}\n          onLoadMore={this.handleLoadMore}\n          shouldUpdateScroll={shouldUpdateScroll}\n          prepend={<HeaderContainer accountId={this.props.params.accountId} hideTabs />}\n          alwaysPrepend\n          emptyMessage={emptyMessage}\n        >\n          {blockedBy ? [] : accountIds.map(id =>\n            <AccountContainer key={id} id={id} withNote={false} />\n          )}\n        </ScrollableList>\n      </Column>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/generic_not_found/index.js",
    "content": "import React from 'react';\nimport Column from '../ui/components/column';\nimport MissingIndicator from '../../components/missing_indicator';\n\nconst GenericNotFound = () => (\n  <Column>\n    <MissingIndicator />\n  </Column>\n);\n\nexport default GenericNotFound;\n"
  },
  {
    "path": "app/javascript/mastodon/features/getting_started/index.js",
    "content": "import React from 'react';\nimport Column from '../ui/components/column';\nimport ColumnLink from '../ui/components/column_link';\nimport ColumnSubheading from '../ui/components/column_subheading';\nimport { defineMessages, injectIntl, FormattedMessage } from 'react-intl';\nimport { connect } from 'react-redux';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport { me, profile_directory } from '../../initial_state';\nimport { fetchFollowRequests } from 'mastodon/actions/accounts';\nimport { List as ImmutableList } from 'immutable';\nimport NavigationBar from '../compose/components/navigation_bar';\nimport Icon from 'mastodon/components/icon';\nimport LinkFooter from 'mastodon/features/ui/components/link_footer';\n\nconst messages = defineMessages({\n  home_timeline: { id: 'tabs_bar.home', defaultMessage: 'Home' },\n  notifications: { id: 'tabs_bar.notifications', defaultMessage: 'Notifications' },\n  public_timeline: { id: 'navigation_bar.public_timeline', defaultMessage: 'Federated timeline' },\n  settings_subheading: { id: 'column_subheading.settings', defaultMessage: 'Settings' },\n  community_timeline: { id: 'navigation_bar.community_timeline', defaultMessage: 'Local timeline' },\n  direct: { id: 'navigation_bar.direct', defaultMessage: 'Direct messages' },\n  preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' },\n  follow_requests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' },\n  favourites: { id: 'navigation_bar.favourites', defaultMessage: 'Favourites' },\n  blocks: { id: 'navigation_bar.blocks', defaultMessage: 'Blocked users' },\n  domain_blocks: { id: 'navigation_bar.domain_blocks', defaultMessage: 'Hidden domains' },\n  mutes: { id: 'navigation_bar.mutes', defaultMessage: 'Muted users' },\n  pins: { id: 'navigation_bar.pins', defaultMessage: 'Pinned toots' },\n  lists: { id: 'navigation_bar.lists', defaultMessage: 'Lists' },\n  discover: { id: 'navigation_bar.discover', defaultMessage: 'Discover' },\n  personal: { id: 'navigation_bar.personal', defaultMessage: 'Personal' },\n  security: { id: 'navigation_bar.security', defaultMessage: 'Security' },\n  menu: { id: 'getting_started.heading', defaultMessage: 'Getting started' },\n  profile_directory: { id: 'getting_started.directory', defaultMessage: 'Profile directory' },\n});\n\nconst mapStateToProps = state => ({\n  myAccount: state.getIn(['accounts', me]),\n  unreadFollowRequests: state.getIn(['user_lists', 'follow_requests', 'items'], ImmutableList()).size,\n});\n\nconst mapDispatchToProps = dispatch => ({\n  fetchFollowRequests: () => dispatch(fetchFollowRequests()),\n});\n\nconst badgeDisplay = (number, limit) => {\n  if (number === 0) {\n    return undefined;\n  } else if (limit && number >= limit) {\n    return `${limit}+`;\n  } else {\n    return number;\n  }\n};\n\nconst NAVIGATION_PANEL_BREAKPOINT = 600 + (285 * 2) + (10 * 2);\n\nexport default @connect(mapStateToProps, mapDispatchToProps)\n@injectIntl\nclass GettingStarted extends ImmutablePureComponent {\n\n  static contextTypes = {\n    router: PropTypes.object.isRequired,\n  };\n\n  static propTypes = {\n    intl: PropTypes.object.isRequired,\n    myAccount: ImmutablePropTypes.map.isRequired,\n    columns: ImmutablePropTypes.list,\n    multiColumn: PropTypes.bool,\n    fetchFollowRequests: PropTypes.func.isRequired,\n    unreadFollowRequests: PropTypes.number,\n    unreadNotifications: PropTypes.number,\n  };\n\n  componentDidMount () {\n    const { myAccount, fetchFollowRequests, multiColumn } = this.props;\n\n    if (!multiColumn && window.innerWidth >= NAVIGATION_PANEL_BREAKPOINT) {\n      this.context.router.history.replace('/timelines/home');\n      return;\n    }\n\n    if (myAccount.get('locked')) {\n      fetchFollowRequests();\n    }\n  }\n\n  render () {\n    const { intl, myAccount, multiColumn, unreadFollowRequests } = this.props;\n\n    const navItems = [];\n    let i = 1;\n    let height = (multiColumn) ? 0 : 60;\n\n    if (multiColumn) {\n      navItems.push(\n        <ColumnSubheading key={i++} text={intl.formatMessage(messages.discover)} />,\n        <ColumnLink key={i++} icon='users' text={intl.formatMessage(messages.community_timeline)} to='/timelines/public/local' />,\n        <ColumnLink key={i++} icon='globe' text={intl.formatMessage(messages.public_timeline)} to='/timelines/public' />,\n      );\n\n      height += 34 + 48*2;\n\n      if (profile_directory) {\n        navItems.push(\n          <ColumnLink key={i++} icon='address-book' text={intl.formatMessage(messages.profile_directory)} href='/explore' />\n        );\n\n        height += 48;\n      }\n\n      navItems.push(\n        <ColumnSubheading key={i++} text={intl.formatMessage(messages.personal)} />\n      );\n\n      height += 34;\n    } else if (profile_directory) {\n      navItems.push(\n        <ColumnLink key={i++} icon='address-book' text={intl.formatMessage(messages.profile_directory)} href='/explore' />\n      );\n\n      height += 48;\n    }\n\n    navItems.push(\n      <ColumnLink key={i++} icon='envelope' text={intl.formatMessage(messages.direct)} to='/timelines/direct' />,\n      <ColumnLink key={i++} icon='star' text={intl.formatMessage(messages.favourites)} to='/favourites' />,\n      <ColumnLink key={i++} icon='list-ul' text={intl.formatMessage(messages.lists)} to='/lists' />\n    );\n\n    height += 48*3;\n\n    if (myAccount.get('locked')) {\n      navItems.push(<ColumnLink key={i++} icon='user-plus' text={intl.formatMessage(messages.follow_requests)} badge={badgeDisplay(unreadFollowRequests, 40)} to='/follow_requests' />);\n      height += 48;\n    }\n\n    if (!multiColumn) {\n      navItems.push(\n        <ColumnSubheading key={i++} text={intl.formatMessage(messages.settings_subheading)} />,\n        <ColumnLink key={i++} icon='gears' text={intl.formatMessage(messages.preferences)} href='/settings/preferences' />,\n      );\n\n      height += 34 + 48;\n    }\n\n    return (\n      <Column label={intl.formatMessage(messages.menu)}>\n        {multiColumn && <div className='column-header__wrapper'>\n          <h1 className='column-header'>\n            <button>\n              <Icon id='bars' className='column-header__icon' fixedWidth />\n              <FormattedMessage id='getting_started.heading' defaultMessage='Getting started' />\n            </button>\n          </h1>\n        </div>}\n\n        <div className='getting-started'>\n          <div className='getting-started__wrapper' style={{ height }}>\n            {!multiColumn && <NavigationBar account={myAccount} />}\n            {navItems}\n          </div>\n\n          {!multiColumn && <div className='flex-spacer' />}\n\n          <LinkFooter withHotkeys={multiColumn} />\n        </div>\n      </Column>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/hashtag_timeline/components/column_settings.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport { defineMessages, injectIntl, FormattedMessage } from 'react-intl';\nimport Toggle from 'react-toggle';\nimport AsyncSelect from 'react-select/lib/Async';\n\nconst messages = defineMessages({\n  placeholder: { id: 'hashtag.column_settings.select.placeholder', defaultMessage: 'Enter hashtags…' },\n  noOptions: { id: 'hashtag.column_settings.select.no_options_message', defaultMessage: 'No suggestions found' },\n});\n\nexport default @injectIntl\nclass ColumnSettings extends React.PureComponent {\n\n  static propTypes = {\n    settings: ImmutablePropTypes.map.isRequired,\n    onChange: PropTypes.func.isRequired,\n    onLoad: PropTypes.func.isRequired,\n    intl: PropTypes.object.isRequired,\n  };\n\n  state = {\n    open: this.hasTags(),\n  };\n\n  hasTags () {\n    return ['all', 'any', 'none'].map(mode => this.tags(mode).length > 0).includes(true);\n  }\n\n  tags (mode) {\n    let tags = this.props.settings.getIn(['tags', mode]) || [];\n\n    if (tags.toJSON) {\n      return tags.toJSON();\n    } else {\n      return tags;\n    }\n  };\n\n  onSelect = mode => value => this.props.onChange(['tags', mode], value);\n\n  onToggle = () => {\n    if (this.state.open && this.hasTags()) {\n      this.props.onChange('tags', {});\n    }\n\n    this.setState({ open: !this.state.open });\n  };\n\n  noOptionsMessage = () => this.props.intl.formatMessage(messages.noOptions);\n\n  modeSelect (mode) {\n    return (\n      <div className='column-settings__row'>\n        <span className='column-settings__section'>\n          {this.modeLabel(mode)}\n        </span>\n\n        <AsyncSelect\n          isMulti\n          autoFocus\n          value={this.tags(mode)}\n          onChange={this.onSelect(mode)}\n          loadOptions={this.props.onLoad}\n          className='column-select__container'\n          classNamePrefix='column-select'\n          name='tags'\n          placeholder={this.props.intl.formatMessage(messages.placeholder)}\n          noOptionsMessage={this.noOptionsMessage}\n        />\n      </div>\n    );\n  }\n\n  modeLabel (mode) {\n    switch(mode) {\n    case 'any':\n      return <FormattedMessage id='hashtag.column_settings.tag_mode.any' defaultMessage='Any of these' />;\n    case 'all':\n      return <FormattedMessage id='hashtag.column_settings.tag_mode.all' defaultMessage='All of these' />;\n    case 'none':\n      return <FormattedMessage id='hashtag.column_settings.tag_mode.none' defaultMessage='None of these' />;\n    default:\n      return '';\n    }\n  };\n\n  render () {\n    return (\n      <div>\n        <div className='column-settings__row'>\n          <div className='setting-toggle'>\n            <Toggle id='hashtag.column_settings.tag_toggle' onChange={this.onToggle} checked={this.state.open} />\n\n            <span className='setting-toggle__label'>\n              <FormattedMessage id='hashtag.column_settings.tag_toggle' defaultMessage='Include additional tags in this column' />\n            </span>\n          </div>\n        </div>\n\n        {this.state.open && (\n          <div className='column-settings__hashtags'>\n            {this.modeSelect('any')}\n            {this.modeSelect('all')}\n            {this.modeSelect('none')}\n          </div>\n        )}\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/hashtag_timeline/containers/column_settings_container.js",
    "content": "import { connect } from 'react-redux';\nimport ColumnSettings from '../components/column_settings';\nimport { changeColumnParams } from '../../../actions/columns';\nimport api from '../../../api';\n\nconst mapStateToProps = (state, { columnId }) => {\n  const columns = state.getIn(['settings', 'columns']);\n  const index   = columns.findIndex(c => c.get('uuid') === columnId);\n\n  if (!(columnId && index >= 0)) {\n    return {};\n  }\n\n  return { settings: columns.get(index).get('params') };\n};\n\nconst mapDispatchToProps = (dispatch, { columnId }) => ({\n  onChange (key, value) {\n    dispatch(changeColumnParams(columnId, key, value));\n  },\n\n  onLoad (value) {\n    return api().get('/api/v2/search', { params: { q: value } }).then(response => {\n      return (response.data.hashtags || []).map((tag) => {\n        return { value: tag.name, label: `#${tag.name}` };\n      });\n    });\n  },\n});\n\nexport default connect(mapStateToProps, mapDispatchToProps)(ColumnSettings);\n"
  },
  {
    "path": "app/javascript/mastodon/features/hashtag_timeline/index.js",
    "content": "import React from 'react';\nimport { connect } from 'react-redux';\nimport PropTypes from 'prop-types';\nimport StatusListContainer from '../ui/containers/status_list_container';\nimport Column from '../../components/column';\nimport ColumnHeader from '../../components/column_header';\nimport ColumnSettingsContainer from './containers/column_settings_container';\nimport { expandHashtagTimeline, clearTimeline } from '../../actions/timelines';\nimport { addColumn, removeColumn, moveColumn } from '../../actions/columns';\nimport { FormattedMessage } from 'react-intl';\nimport { connectHashtagStream } from '../../actions/streaming';\nimport { isEqual } from 'lodash';\n\nconst mapStateToProps = (state, props) => ({\n  hasUnread: state.getIn(['timelines', `hashtag:${props.params.id}`, 'unread']) > 0,\n});\n\nexport default @connect(mapStateToProps)\nclass HashtagTimeline extends React.PureComponent {\n\n  disconnects = [];\n\n  static propTypes = {\n    params: PropTypes.object.isRequired,\n    columnId: PropTypes.string,\n    dispatch: PropTypes.func.isRequired,\n    shouldUpdateScroll: PropTypes.func,\n    hasUnread: PropTypes.bool,\n    multiColumn: PropTypes.bool,\n  };\n\n  handlePin = () => {\n    const { columnId, dispatch } = this.props;\n\n    if (columnId) {\n      dispatch(removeColumn(columnId));\n    } else {\n      dispatch(addColumn('HASHTAG', { id: this.props.params.id }));\n    }\n  }\n\n  title = () => {\n    let title = [this.props.params.id];\n\n    if (this.additionalFor('any')) {\n      title.push(' ', <FormattedMessage key='any' id='hashtag.column_header.tag_mode.any'  values={{ additional: this.additionalFor('any') }} defaultMessage='or {additional}' />);\n    }\n\n    if (this.additionalFor('all')) {\n      title.push(' ', <FormattedMessage key='all' id='hashtag.column_header.tag_mode.all'  values={{ additional: this.additionalFor('all') }} defaultMessage='and {additional}' />);\n    }\n\n    if (this.additionalFor('none')) {\n      title.push(' ', <FormattedMessage key='none' id='hashtag.column_header.tag_mode.none' values={{ additional: this.additionalFor('none') }} defaultMessage='without {additional}' />);\n    }\n\n    return title;\n  }\n\n  additionalFor = (mode) => {\n    const { tags } = this.props.params;\n\n    if (tags && (tags[mode] || []).length > 0) {\n      return tags[mode].map(tag => tag.value).join('/');\n    } else {\n      return '';\n    }\n  }\n\n  handleMove = (dir) => {\n    const { columnId, dispatch } = this.props;\n    dispatch(moveColumn(columnId, dir));\n  }\n\n  handleHeaderClick = () => {\n    this.column.scrollTop();\n  }\n\n  _subscribe (dispatch, id, tags = {}) {\n    let any  = (tags.any || []).map(tag => tag.value);\n    let all  = (tags.all || []).map(tag => tag.value);\n    let none = (tags.none || []).map(tag => tag.value);\n\n    [id, ...any].map(tag => {\n      this.disconnects.push(dispatch(connectHashtagStream(id, tag, status => {\n        let tags = status.tags.map(tag => tag.name);\n\n        return all.filter(tag => tags.includes(tag)).length === all.length &&\n               none.filter(tag => tags.includes(tag)).length === 0;\n      })));\n    });\n  }\n\n  _unsubscribe () {\n    this.disconnects.map(disconnect => disconnect());\n    this.disconnects = [];\n  }\n\n  componentDidMount () {\n    const { dispatch } = this.props;\n    const { id, tags } = this.props.params;\n\n    this._subscribe(dispatch, id, tags);\n    dispatch(expandHashtagTimeline(id, { tags }));\n  }\n\n  componentWillReceiveProps (nextProps) {\n    const { dispatch, params } = this.props;\n    const { id, tags } = nextProps.params;\n\n    if (id !== params.id || !isEqual(tags, params.tags)) {\n      this._unsubscribe();\n      this._subscribe(dispatch, id, tags);\n      this.props.dispatch(clearTimeline(`hashtag:${id}`));\n      this.props.dispatch(expandHashtagTimeline(id, { tags }));\n    }\n  }\n\n  componentWillUnmount () {\n    this._unsubscribe();\n  }\n\n  setRef = c => {\n    this.column = c;\n  }\n\n  handleLoadMore = maxId => {\n    const { id, tags } = this.props.params;\n    this.props.dispatch(expandHashtagTimeline(id, { maxId, tags }));\n  }\n\n  render () {\n    const { shouldUpdateScroll, hasUnread, columnId, multiColumn } = this.props;\n    const { id } = this.props.params;\n    const pinned = !!columnId;\n\n    return (\n      <Column ref={this.setRef} label={`#${id}`}>\n        <ColumnHeader\n          icon='hashtag'\n          active={hasUnread}\n          title={this.title()}\n          onPin={this.handlePin}\n          onMove={this.handleMove}\n          onClick={this.handleHeaderClick}\n          pinned={pinned}\n          multiColumn={multiColumn}\n          showBackButton\n        >\n          {columnId && <ColumnSettingsContainer columnId={columnId} />}\n        </ColumnHeader>\n\n        <StatusListContainer\n          trackScroll={!pinned}\n          scrollKey={`hashtag_timeline-${columnId}`}\n          timelineId={`hashtag:${id}`}\n          onLoadMore={this.handleLoadMore}\n          emptyMessage={<FormattedMessage id='empty_column.hashtag' defaultMessage='There is nothing in this hashtag yet.' />}\n          shouldUpdateScroll={shouldUpdateScroll}\n        />\n      </Column>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/home_timeline/components/column_settings.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport { injectIntl, FormattedMessage } from 'react-intl';\nimport SettingToggle from '../../notifications/components/setting_toggle';\n\nexport default @injectIntl\nclass ColumnSettings extends React.PureComponent {\n\n  static propTypes = {\n    settings: ImmutablePropTypes.map.isRequired,\n    onChange: PropTypes.func.isRequired,\n    intl: PropTypes.object.isRequired,\n  };\n\n  render () {\n    const { settings, onChange } = this.props;\n\n    return (\n      <div>\n        <span className='column-settings__section'><FormattedMessage id='home.column_settings.basic' defaultMessage='Basic' /></span>\n\n        <div className='column-settings__row'>\n          <SettingToggle prefix='home_timeline' settings={settings} settingPath={['shows', 'reblog']} onChange={onChange} label={<FormattedMessage id='home.column_settings.show_reblogs' defaultMessage='Show boosts' />} />\n        </div>\n\n        <div className='column-settings__row'>\n          <SettingToggle prefix='home_timeline' settings={settings} settingPath={['shows', 'reply']} onChange={onChange} label={<FormattedMessage id='home.column_settings.show_replies' defaultMessage='Show replies' />} />\n        </div>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/home_timeline/containers/column_settings_container.js",
    "content": "import { connect } from 'react-redux';\nimport ColumnSettings from '../components/column_settings';\nimport { changeSetting, saveSettings } from '../../../actions/settings';\n\nconst mapStateToProps = state => ({\n  settings: state.getIn(['settings', 'home']),\n});\n\nconst mapDispatchToProps = dispatch => ({\n\n  onChange (key, checked) {\n    dispatch(changeSetting(['home', ...key], checked));\n  },\n\n  onSave () {\n    dispatch(saveSettings());\n  },\n\n});\n\nexport default connect(mapStateToProps, mapDispatchToProps)(ColumnSettings);\n"
  },
  {
    "path": "app/javascript/mastodon/features/home_timeline/index.js",
    "content": "import React from 'react';\nimport { connect } from 'react-redux';\nimport { expandHomeTimeline } from '../../actions/timelines';\nimport PropTypes from 'prop-types';\nimport StatusListContainer from '../ui/containers/status_list_container';\nimport Column from '../../components/column';\nimport ColumnHeader from '../../components/column_header';\nimport { addColumn, removeColumn, moveColumn } from '../../actions/columns';\nimport { defineMessages, injectIntl, FormattedMessage } from 'react-intl';\nimport ColumnSettingsContainer from './containers/column_settings_container';\nimport { Link } from 'react-router-dom';\n\nconst messages = defineMessages({\n  title: { id: 'column.home', defaultMessage: 'Home' },\n});\n\nconst mapStateToProps = state => ({\n  hasUnread: state.getIn(['timelines', 'home', 'unread']) > 0,\n  isPartial: state.getIn(['timelines', 'home', 'isPartial']),\n});\n\nexport default @connect(mapStateToProps)\n@injectIntl\nclass HomeTimeline extends React.PureComponent {\n\n  static propTypes = {\n    dispatch: PropTypes.func.isRequired,\n    shouldUpdateScroll: PropTypes.func,\n    intl: PropTypes.object.isRequired,\n    hasUnread: PropTypes.bool,\n    isPartial: PropTypes.bool,\n    columnId: PropTypes.string,\n    multiColumn: PropTypes.bool,\n  };\n\n  handlePin = () => {\n    const { columnId, dispatch } = this.props;\n\n    if (columnId) {\n      dispatch(removeColumn(columnId));\n    } else {\n      dispatch(addColumn('HOME', {}));\n    }\n  }\n\n  handleMove = (dir) => {\n    const { columnId, dispatch } = this.props;\n    dispatch(moveColumn(columnId, dir));\n  }\n\n  handleHeaderClick = () => {\n    this.column.scrollTop();\n  }\n\n  setRef = c => {\n    this.column = c;\n  }\n\n  handleLoadMore = maxId => {\n    this.props.dispatch(expandHomeTimeline({ maxId }));\n  }\n\n  componentDidMount () {\n    this._checkIfReloadNeeded(false, this.props.isPartial);\n  }\n\n  componentDidUpdate (prevProps) {\n    this._checkIfReloadNeeded(prevProps.isPartial, this.props.isPartial);\n  }\n\n  componentWillUnmount () {\n    this._stopPolling();\n  }\n\n  _checkIfReloadNeeded (wasPartial, isPartial) {\n    const { dispatch } = this.props;\n\n    if (wasPartial === isPartial) {\n      return;\n    } else if (!wasPartial && isPartial) {\n      this.polling = setInterval(() => {\n        dispatch(expandHomeTimeline());\n      }, 3000);\n    } else if (wasPartial && !isPartial) {\n      this._stopPolling();\n    }\n  }\n\n  _stopPolling () {\n    if (this.polling) {\n      clearInterval(this.polling);\n      this.polling = null;\n    }\n  }\n\n  render () {\n    const { intl, shouldUpdateScroll, hasUnread, columnId, multiColumn } = this.props;\n    const pinned = !!columnId;\n\n    return (\n      <Column ref={this.setRef} label={intl.formatMessage(messages.title)}>\n        <ColumnHeader\n          icon='home'\n          active={hasUnread}\n          title={intl.formatMessage(messages.title)}\n          onPin={this.handlePin}\n          onMove={this.handleMove}\n          onClick={this.handleHeaderClick}\n          pinned={pinned}\n          multiColumn={multiColumn}\n        >\n          <ColumnSettingsContainer />\n        </ColumnHeader>\n\n        <StatusListContainer\n          trackScroll={!pinned}\n          scrollKey={`home_timeline-${columnId}`}\n          onLoadMore={this.handleLoadMore}\n          timelineId='home'\n          emptyMessage={<FormattedMessage id='empty_column.home' defaultMessage='Your home timeline is empty! Visit {public} or use search to get started and meet other users.' values={{ public: <Link to='/timelines/public'><FormattedMessage id='empty_column.home.public_timeline' defaultMessage='the public timeline' /></Link> }} />}\n          shouldUpdateScroll={shouldUpdateScroll}\n        />\n      </Column>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/introduction/index.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport ReactSwipeableViews from 'react-swipeable-views';\nimport classNames from 'classnames';\nimport { connect } from 'react-redux';\nimport { FormattedMessage } from 'react-intl';\nimport { closeOnboarding } from '../../actions/onboarding';\nimport screenHello from '../../../images/screen_hello.svg';\nimport screenFederation from '../../../images/screen_federation.svg';\nimport screenInteractions from '../../../images/screen_interactions.svg';\nimport logoTransparent from '../../../images/logo_transparent.svg';\n\nconst FrameWelcome = ({ domain, onNext }) => (\n  <div className='introduction__frame'>\n    <div className='introduction__illustration' style={{ background: `url(${logoTransparent}) no-repeat center center / auto 80%` }}>\n      <img src={screenHello} alt='' />\n    </div>\n\n    <div className='introduction__text introduction__text--centered'>\n      <h3><FormattedMessage id='introduction.welcome.headline' defaultMessage='First steps' /></h3>\n      <p><FormattedMessage id='introduction.welcome.text' defaultMessage=\"Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.\" values={{ domain: <code>{domain}</code> }} /></p>\n    </div>\n\n    <div className='introduction__action'>\n      <button className='button' onClick={onNext}><FormattedMessage id='introduction.welcome.action' defaultMessage=\"Let's go!\" /></button>\n    </div>\n  </div>\n);\n\nFrameWelcome.propTypes = {\n  domain: PropTypes.string.isRequired,\n  onNext: PropTypes.func.isRequired,\n};\n\nconst FrameFederation = ({ onNext }) => (\n  <div className='introduction__frame'>\n    <div className='introduction__illustration'>\n      <img src={screenFederation} alt='' />\n    </div>\n\n    <div className='introduction__text introduction__text--columnized'>\n      <div>\n        <h3><FormattedMessage id='introduction.federation.home.headline' defaultMessage='Home' /></h3>\n        <p><FormattedMessage id='introduction.federation.home.text' defaultMessage='Posts from people you follow will appear in your home feed. You can follow anyone on any server!' /></p>\n      </div>\n\n      <div>\n        <h3><FormattedMessage id='introduction.federation.local.headline' defaultMessage='Local' /></h3>\n        <p><FormattedMessage id='introduction.federation.local.text' defaultMessage='Public posts from people on the same server as you will appear in the local timeline.' /></p>\n      </div>\n\n      <div>\n        <h3><FormattedMessage id='introduction.federation.federated.headline' defaultMessage='Federated' /></h3>\n        <p><FormattedMessage id='introduction.federation.federated.text' defaultMessage='Public posts from other servers of the fediverse will appear in the federated timeline.' /></p>\n      </div>\n    </div>\n\n    <div className='introduction__action'>\n      <button className='button' onClick={onNext}><FormattedMessage id='introduction.federation.action' defaultMessage='Next' /></button>\n    </div>\n  </div>\n);\n\nFrameFederation.propTypes = {\n  onNext: PropTypes.func.isRequired,\n};\n\nconst FrameInteractions = ({ onNext }) => (\n  <div className='introduction__frame'>\n    <div className='introduction__illustration'>\n      <img src={screenInteractions} alt='' />\n    </div>\n\n    <div className='introduction__text introduction__text--columnized'>\n      <div>\n        <h3><FormattedMessage id='introduction.interactions.reply.headline' defaultMessage='Reply' /></h3>\n        <p><FormattedMessage id='introduction.interactions.reply.text' defaultMessage=\"You can reply to other people's and your own toots, which will chain them together in a conversation.\" /></p>\n      </div>\n\n      <div>\n        <h3><FormattedMessage id='introduction.interactions.reblog.headline' defaultMessage='Boost' /></h3>\n        <p><FormattedMessage id='introduction.interactions.reblog.text' defaultMessage=\"You can share other people's toots with your followers by boosting them.\" /></p>\n      </div>\n\n      <div>\n        <h3><FormattedMessage id='introduction.interactions.favourite.headline' defaultMessage='Favourite' /></h3>\n        <p><FormattedMessage id='introduction.interactions.favourite.text' defaultMessage='You can save a toot for later, and let the author know that you liked it, by favouriting it.' /></p>\n      </div>\n    </div>\n\n    <div className='introduction__action'>\n      <button className='button' onClick={onNext}><FormattedMessage id='introduction.interactions.action' defaultMessage='Finish toot-orial!' /></button>\n    </div>\n  </div>\n);\n\nFrameInteractions.propTypes = {\n  onNext: PropTypes.func.isRequired,\n};\n\nexport default @connect(state => ({ domain: state.getIn(['meta', 'domain']) }))\nclass Introduction extends React.PureComponent {\n\n  static propTypes = {\n    domain: PropTypes.string.isRequired,\n    dispatch: PropTypes.func.isRequired,\n  };\n\n  state = {\n    currentIndex: 0,\n  };\n\n  componentWillMount () {\n    this.pages = [\n      <FrameWelcome domain={this.props.domain} onNext={this.handleNext} />,\n      <FrameFederation onNext={this.handleNext} />,\n      <FrameInteractions onNext={this.handleFinish} />,\n    ];\n  }\n\n  componentDidMount() {\n    window.addEventListener('keyup', this.handleKeyUp);\n  }\n\n  componentWillUnmount() {\n    window.addEventListener('keyup', this.handleKeyUp);\n  }\n\n  handleDot = (e) => {\n    const i = Number(e.currentTarget.getAttribute('data-index'));\n    e.preventDefault();\n    this.setState({ currentIndex: i });\n  }\n\n  handlePrev = () => {\n    this.setState(({ currentIndex }) => ({\n      currentIndex: Math.max(0, currentIndex - 1),\n    }));\n  }\n\n  handleNext = () => {\n    const { pages } = this;\n\n    this.setState(({ currentIndex }) => ({\n      currentIndex: Math.min(currentIndex + 1, pages.length - 1),\n    }));\n  }\n\n  handleSwipe = (index) => {\n    this.setState({ currentIndex: index });\n  }\n\n  handleFinish = () => {\n    this.props.dispatch(closeOnboarding());\n  }\n\n  handleKeyUp = ({ key }) => {\n    switch (key) {\n    case 'ArrowLeft':\n      this.handlePrev();\n      break;\n    case 'ArrowRight':\n      this.handleNext();\n      break;\n    }\n  }\n\n  render () {\n    const { currentIndex } = this.state;\n    const { pages } = this;\n\n    return (\n      <div className='introduction'>\n        <ReactSwipeableViews index={currentIndex} onChangeIndex={this.handleSwipe} className='introduction__pager'>\n          {pages.map((page, i) => (\n            <div key={i} className={classNames('introduction__frame-wrapper', { 'active': i === currentIndex })}>{page}</div>\n          ))}\n        </ReactSwipeableViews>\n\n        <div className='introduction__dots'>\n          {pages.map((_, i) => (\n            <div\n              key={`dot-${i}`}\n              role='button'\n              tabIndex='0'\n              data-index={i}\n              onClick={this.handleDot}\n              className={classNames('introduction__dot', { active: i === currentIndex })}\n            />\n          ))}\n        </div>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/keyboard_shortcuts/index.js",
    "content": "import React from 'react';\nimport Column from '../ui/components/column';\nimport ColumnBackButtonSlim from '../../components/column_back_button_slim';\nimport { defineMessages, injectIntl, FormattedMessage } from 'react-intl';\nimport PropTypes from 'prop-types';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\n\nconst messages = defineMessages({\n  heading: { id: 'keyboard_shortcuts.heading', defaultMessage: 'Keyboard Shortcuts' },\n});\n\nexport default @injectIntl\nclass KeyboardShortcuts extends ImmutablePureComponent {\n\n  static propTypes = {\n    intl: PropTypes.object.isRequired,\n    multiColumn: PropTypes.bool,\n  };\n\n  render () {\n    const { intl } = this.props;\n\n    return (\n      <Column icon='question' heading={intl.formatMessage(messages.heading)}>\n        <ColumnBackButtonSlim />\n        <div className='keyboard-shortcuts scrollable optionally-scrollable'>\n          <table>\n            <thead>\n              <tr>\n                <th><FormattedMessage id='keyboard_shortcuts.hotkey' defaultMessage='Hotkey' /></th>\n                <th><FormattedMessage id='keyboard_shortcuts.description' defaultMessage='Description' /></th>\n              </tr>\n            </thead>\n            <tbody>\n              <tr>\n                <td><kbd>r</kbd></td>\n                <td><FormattedMessage id='keyboard_shortcuts.reply' defaultMessage='to reply' /></td>\n              </tr>\n              <tr>\n                <td><kbd>m</kbd></td>\n                <td><FormattedMessage id='keyboard_shortcuts.mention' defaultMessage='to mention author' /></td>\n              </tr>\n              <tr>\n                <td><kbd>p</kbd></td>\n                <td><FormattedMessage id='keyboard_shortcuts.profile' defaultMessage=\"to open author's profile\" /></td>\n              </tr>\n              <tr>\n                <td><kbd>f</kbd></td>\n                <td><FormattedMessage id='keyboard_shortcuts.favourite' defaultMessage='to favourite' /></td>\n              </tr>\n              <tr>\n                <td><kbd>b</kbd></td>\n                <td><FormattedMessage id='keyboard_shortcuts.boost' defaultMessage='to boost' /></td>\n              </tr>\n              <tr>\n                <td><kbd>enter</kbd>, <kbd>o</kbd></td>\n                <td><FormattedMessage id='keyboard_shortcuts.enter' defaultMessage='to open status' /></td>\n              </tr>\n              <tr>\n                <td><kbd>x</kbd></td>\n                <td><FormattedMessage id='keyboard_shortcuts.toggle_hidden' defaultMessage='to show/hide text behind CW' /></td>\n              </tr>\n              <tr>\n                <td><kbd>h</kbd></td>\n                <td><FormattedMessage id='keyboard_shortcuts.toggle_sensitivity' defaultMessage='to show/hide media' /></td>\n              </tr>\n              <tr>\n                <td><kbd>up</kbd>, <kbd>k</kbd></td>\n                <td><FormattedMessage id='keyboard_shortcuts.up' defaultMessage='to move up in the list' /></td>\n              </tr>\n              <tr>\n                <td><kbd>down</kbd>, <kbd>j</kbd></td>\n                <td><FormattedMessage id='keyboard_shortcuts.down' defaultMessage='to move down in the list' /></td>\n              </tr>\n              <tr>\n                <td><kbd>1</kbd>-<kbd>9</kbd></td>\n                <td><FormattedMessage id='keyboard_shortcuts.column' defaultMessage='to focus a status in one of the columns' /></td>\n              </tr>\n              <tr>\n                <td><kbd>n</kbd></td>\n                <td><FormattedMessage id='keyboard_shortcuts.compose' defaultMessage='to focus the compose textarea' /></td>\n              </tr>\n              <tr>\n                <td><kbd>alt</kbd>+<kbd>n</kbd></td>\n                <td><FormattedMessage id='keyboard_shortcuts.toot' defaultMessage='to start a brand new toot' /></td>\n              </tr>\n              <tr>\n                <td><kbd>backspace</kbd></td>\n                <td><FormattedMessage id='keyboard_shortcuts.back' defaultMessage='to navigate back' /></td>\n              </tr>\n              <tr>\n                <td><kbd>s</kbd></td>\n                <td><FormattedMessage id='keyboard_shortcuts.search' defaultMessage='to focus search' /></td>\n              </tr>\n              <tr>\n                <td><kbd>esc</kbd></td>\n                <td><FormattedMessage id='keyboard_shortcuts.unfocus' defaultMessage='to un-focus compose textarea/search' /></td>\n              </tr>\n              <tr>\n                <td><kbd>g</kbd>+<kbd>h</kbd></td>\n                <td><FormattedMessage id='keyboard_shortcuts.home' defaultMessage='to open home timeline' /></td>\n              </tr>\n              <tr>\n                <td><kbd>g</kbd>+<kbd>n</kbd></td>\n                <td><FormattedMessage id='keyboard_shortcuts.notifications' defaultMessage='to open notifications column' /></td>\n              </tr>\n              <tr>\n                <td><kbd>g</kbd>+<kbd>l</kbd></td>\n                <td><FormattedMessage id='keyboard_shortcuts.local' defaultMessage='to open local timeline' /></td>\n              </tr>\n              <tr>\n                <td><kbd>g</kbd>+<kbd>t</kbd></td>\n                <td><FormattedMessage id='keyboard_shortcuts.federated' defaultMessage='to open federated timeline' /></td>\n              </tr>\n              <tr>\n                <td><kbd>g</kbd>+<kbd>d</kbd></td>\n                <td><FormattedMessage id='keyboard_shortcuts.direct' defaultMessage='to open direct messages column' /></td>\n              </tr>\n              <tr>\n                <td><kbd>g</kbd>+<kbd>s</kbd></td>\n                <td><FormattedMessage id='keyboard_shortcuts.start' defaultMessage='to open \"get started\" column' /></td>\n              </tr>\n              <tr>\n                <td><kbd>g</kbd>+<kbd>f</kbd></td>\n                <td><FormattedMessage id='keyboard_shortcuts.favourites' defaultMessage='to open favourites list' /></td>\n              </tr>\n              <tr>\n                <td><kbd>g</kbd>+<kbd>p</kbd></td>\n                <td><FormattedMessage id='keyboard_shortcuts.pinned' defaultMessage='to open pinned toots list' /></td>\n              </tr>\n              <tr>\n                <td><kbd>g</kbd>+<kbd>u</kbd></td>\n                <td><FormattedMessage id='keyboard_shortcuts.my_profile' defaultMessage='to open your profile' /></td>\n              </tr>\n              <tr>\n                <td><kbd>g</kbd>+<kbd>b</kbd></td>\n                <td><FormattedMessage id='keyboard_shortcuts.blocked' defaultMessage='to open blocked users list' /></td>\n              </tr>\n              <tr>\n                <td><kbd>g</kbd>+<kbd>m</kbd></td>\n                <td><FormattedMessage id='keyboard_shortcuts.muted' defaultMessage='to open muted users list' /></td>\n              </tr>\n              <tr>\n                <td><kbd>g</kbd>+<kbd>r</kbd></td>\n                <td><FormattedMessage id='keyboard_shortcuts.requests' defaultMessage='to open follow requests list' /></td>\n              </tr>\n              <tr>\n                <td><kbd>?</kbd></td>\n                <td><FormattedMessage id='keyboard_shortcuts.legend' defaultMessage='to display this legend' /></td>\n              </tr>\n            </tbody>\n          </table>\n        </div>\n      </Column>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/list_adder/components/account.js",
    "content": "import React from 'react';\nimport { connect } from 'react-redux';\nimport { makeGetAccount } from '../../../selectors';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport Avatar from '../../../components/avatar';\nimport DisplayName from '../../../components/display_name';\nimport { injectIntl } from 'react-intl';\n\nconst makeMapStateToProps = () => {\n  const getAccount = makeGetAccount();\n\n  const mapStateToProps = (state, { accountId }) => ({\n    account: getAccount(state, accountId),\n  });\n\n  return mapStateToProps;\n};\n\n\nexport default @connect(makeMapStateToProps)\n@injectIntl\nclass Account extends ImmutablePureComponent {\n\n  static propTypes = {\n    account: ImmutablePropTypes.map.isRequired,\n  };\n\n  render () {\n    const { account } = this.props;\n    return (\n      <div className='account'>\n        <div className='account__wrapper'>\n          <div className='account__display-name'>\n            <div className='account__avatar-wrapper'><Avatar account={account} size={36} /></div>\n            <DisplayName account={account} />\n          </div>\n        </div>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/list_adder/components/list.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport { connect } from 'react-redux';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport IconButton from '../../../components/icon_button';\nimport { defineMessages, injectIntl } from 'react-intl';\nimport { removeFromListAdder, addToListAdder } from '../../../actions/lists';\nimport Icon from 'mastodon/components/icon';\n\nconst messages = defineMessages({\n  remove: { id: 'lists.account.remove', defaultMessage: 'Remove from list' },\n  add: { id: 'lists.account.add', defaultMessage: 'Add to list' },\n});\n\nconst MapStateToProps = (state, { listId, added }) => ({\n  list: state.get('lists').get(listId),\n  added: typeof added === 'undefined' ? state.getIn(['listAdder', 'lists', 'items']).includes(listId) : added,\n});\n\nconst mapDispatchToProps = (dispatch, { listId }) => ({\n  onRemove: () => dispatch(removeFromListAdder(listId)),\n  onAdd: () => dispatch(addToListAdder(listId)),\n});\n\nexport default @connect(MapStateToProps, mapDispatchToProps)\n@injectIntl\nclass List extends ImmutablePureComponent {\n\n  static propTypes = {\n    list: ImmutablePropTypes.map.isRequired,\n    intl: PropTypes.object.isRequired,\n    onRemove: PropTypes.func.isRequired,\n    onAdd: PropTypes.func.isRequired,\n    added: PropTypes.bool,\n  };\n\n  static defaultProps = {\n    added: false,\n  };\n\n  render () {\n    const { list, intl, onRemove, onAdd, added } = this.props;\n\n    let button;\n\n    if (added) {\n      button = <IconButton icon='times' title={intl.formatMessage(messages.remove)} onClick={onRemove} />;\n    } else {\n      button = <IconButton icon='plus' title={intl.formatMessage(messages.add)} onClick={onAdd} />;\n    }\n\n    return (\n      <div className='list'>\n        <div className='list__wrapper'>\n          <div className='list__display-name'>\n            <Icon id='list-ul' className='column-link__icon' fixedWidth />\n            {list.get('title')}\n          </div>\n\n          <div className='account__relationship'>\n            {button}\n          </div>\n        </div>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/list_adder/index.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport { connect } from 'react-redux';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport { injectIntl } from 'react-intl';\nimport { setupListAdder, resetListAdder } from '../../actions/lists';\nimport { createSelector } from 'reselect';\nimport List from './components/list';\nimport Account from './components/account';\nimport NewListForm from '../lists/components/new_list_form';\n// hack\n\nconst getOrderedLists = createSelector([state => state.get('lists')], lists => {\n  if (!lists) {\n    return lists;\n  }\n\n  return lists.toList().filter(item => !!item).sort((a, b) => a.get('title').localeCompare(b.get('title')));\n});\n\nconst mapStateToProps = state => ({\n  listIds: getOrderedLists(state).map(list=>list.get('id')),\n});\n\nconst mapDispatchToProps = dispatch => ({\n  onInitialize: accountId => dispatch(setupListAdder(accountId)),\n  onReset: () => dispatch(resetListAdder()),\n});\n\nexport default @connect(mapStateToProps, mapDispatchToProps)\n@injectIntl\nclass ListAdder extends ImmutablePureComponent {\n\n  static propTypes = {\n    accountId: PropTypes.string.isRequired,\n    onClose: PropTypes.func.isRequired,\n    intl: PropTypes.object.isRequired,\n    onInitialize: PropTypes.func.isRequired,\n    onReset: PropTypes.func.isRequired,\n    listIds: ImmutablePropTypes.list.isRequired,\n  };\n\n  componentDidMount () {\n    const { onInitialize, accountId } = this.props;\n    onInitialize(accountId);\n  }\n\n  componentWillUnmount () {\n    const { onReset } = this.props;\n    onReset();\n  }\n\n  render () {\n    const { accountId, listIds } = this.props;\n\n    return (\n      <div className='modal-root__modal list-adder'>\n        <div className='list-adder__account'>\n          <Account accountId={accountId} />\n        </div>\n\n        <NewListForm />\n\n\n        <div className='list-adder__lists'>\n          {listIds.map(ListId => <List key={ListId} listId={ListId} />)}\n        </div>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/list_editor/components/account.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport { connect } from 'react-redux';\nimport { makeGetAccount } from '../../../selectors';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport Avatar from '../../../components/avatar';\nimport DisplayName from '../../../components/display_name';\nimport IconButton from '../../../components/icon_button';\nimport { defineMessages, injectIntl } from 'react-intl';\nimport { removeFromListEditor, addToListEditor } from '../../../actions/lists';\n\nconst messages = defineMessages({\n  remove: { id: 'lists.account.remove', defaultMessage: 'Remove from list' },\n  add: { id: 'lists.account.add', defaultMessage: 'Add to list' },\n});\n\nconst makeMapStateToProps = () => {\n  const getAccount = makeGetAccount();\n\n  const mapStateToProps = (state, { accountId, added }) => ({\n    account: getAccount(state, accountId),\n    added: typeof added === 'undefined' ? state.getIn(['listEditor', 'accounts', 'items']).includes(accountId) : added,\n  });\n\n  return mapStateToProps;\n};\n\nconst mapDispatchToProps = (dispatch, { accountId }) => ({\n  onRemove: () => dispatch(removeFromListEditor(accountId)),\n  onAdd: () => dispatch(addToListEditor(accountId)),\n});\n\nexport default @connect(makeMapStateToProps, mapDispatchToProps)\n@injectIntl\nclass Account extends ImmutablePureComponent {\n\n  static propTypes = {\n    account: ImmutablePropTypes.map.isRequired,\n    intl: PropTypes.object.isRequired,\n    onRemove: PropTypes.func.isRequired,\n    onAdd: PropTypes.func.isRequired,\n    added: PropTypes.bool,\n  };\n\n  static defaultProps = {\n    added: false,\n  };\n\n  render () {\n    const { account, intl, onRemove, onAdd, added } = this.props;\n\n    let button;\n\n    if (added) {\n      button = <IconButton icon='times' title={intl.formatMessage(messages.remove)} onClick={onRemove} />;\n    } else {\n      button = <IconButton icon='plus' title={intl.formatMessage(messages.add)} onClick={onAdd} />;\n    }\n\n    return (\n      <div className='account'>\n        <div className='account__wrapper'>\n          <div className='account__display-name'>\n            <div className='account__avatar-wrapper'><Avatar account={account} size={36} /></div>\n            <DisplayName account={account} />\n          </div>\n\n          <div className='account__relationship'>\n            {button}\n          </div>\n        </div>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/list_editor/components/edit_list_form.js",
    "content": "import React from 'react';\nimport { connect } from 'react-redux';\nimport PropTypes from 'prop-types';\nimport { changeListEditorTitle, submitListEditor } from '../../../actions/lists';\nimport IconButton from '../../../components/icon_button';\nimport { defineMessages, injectIntl } from 'react-intl';\n\nconst messages = defineMessages({\n  title: { id: 'lists.edit.submit', defaultMessage: 'Change title' },\n});\n\nconst mapStateToProps = state => ({\n  value: state.getIn(['listEditor', 'title']),\n  disabled: !state.getIn(['listEditor', 'isChanged']),\n});\n\nconst mapDispatchToProps = dispatch => ({\n  onChange: value => dispatch(changeListEditorTitle(value)),\n  onSubmit: () => dispatch(submitListEditor(false)),\n});\n\nexport default @connect(mapStateToProps, mapDispatchToProps)\n@injectIntl\nclass ListForm extends React.PureComponent {\n\n  static propTypes = {\n    value: PropTypes.string.isRequired,\n    disabled: PropTypes.bool,\n    intl: PropTypes.object.isRequired,\n    onChange: PropTypes.func.isRequired,\n    onSubmit: PropTypes.func.isRequired,\n  };\n\n  handleChange = e => {\n    this.props.onChange(e.target.value);\n  }\n\n  handleSubmit = e => {\n    e.preventDefault();\n    this.props.onSubmit();\n  }\n\n  handleClick = () => {\n    this.props.onSubmit();\n  }\n\n  render () {\n    const { value, disabled, intl } = this.props;\n\n    const title = intl.formatMessage(messages.title);\n\n    return (\n      <form className='column-inline-form' onSubmit={this.handleSubmit}>\n        <input\n          className='setting-text'\n          value={value}\n          onChange={this.handleChange}\n        />\n\n        <IconButton\n          disabled={disabled}\n          icon='check'\n          title={title}\n          onClick={this.handleClick}\n        />\n      </form>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/list_editor/components/search.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport { connect } from 'react-redux';\nimport { defineMessages, injectIntl } from 'react-intl';\nimport { fetchListSuggestions, clearListSuggestions, changeListSuggestions } from '../../../actions/lists';\nimport classNames from 'classnames';\nimport Icon from 'mastodon/components/icon';\n\nconst messages = defineMessages({\n  search: { id: 'lists.search', defaultMessage: 'Search among people you follow' },\n});\n\nconst mapStateToProps = state => ({\n  value: state.getIn(['listEditor', 'suggestions', 'value']),\n});\n\nconst mapDispatchToProps = dispatch => ({\n  onSubmit: value => dispatch(fetchListSuggestions(value)),\n  onClear: () => dispatch(clearListSuggestions()),\n  onChange: value => dispatch(changeListSuggestions(value)),\n});\n\nexport default @connect(mapStateToProps, mapDispatchToProps)\n@injectIntl\nclass Search extends React.PureComponent {\n\n  static propTypes = {\n    intl: PropTypes.object.isRequired,\n    value: PropTypes.string.isRequired,\n    onChange: PropTypes.func.isRequired,\n    onSubmit: PropTypes.func.isRequired,\n    onClear: PropTypes.func.isRequired,\n  };\n\n  handleChange = e => {\n    this.props.onChange(e.target.value);\n  }\n\n  handleKeyUp = e => {\n    if (e.keyCode === 13) {\n      this.props.onSubmit(this.props.value);\n    }\n  }\n\n  handleClear = () => {\n    this.props.onClear();\n  }\n\n  render () {\n    const { value, intl } = this.props;\n    const hasValue = value.length > 0;\n\n    return (\n      <div className='list-editor__search search'>\n        <label>\n          <span style={{ display: 'none' }}>{intl.formatMessage(messages.search)}</span>\n\n          <input\n            className='search__input'\n            type='text'\n            value={value}\n            onChange={this.handleChange}\n            onKeyUp={this.handleKeyUp}\n            placeholder={intl.formatMessage(messages.search)}\n          />\n        </label>\n\n        <div role='button' tabIndex='0' className='search__icon' onClick={this.handleClear}>\n          <Icon id='search' className={classNames({ active: !hasValue })} />\n          <Icon id='times-circle' aria-label={intl.formatMessage(messages.search)} className={classNames({ active: hasValue })} />\n        </div>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/list_editor/index.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport { connect } from 'react-redux';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport { injectIntl } from 'react-intl';\nimport { setupListEditor, clearListSuggestions, resetListEditor } from '../../actions/lists';\nimport Account from './components/account';\nimport Search from './components/search';\nimport EditListForm from './components/edit_list_form';\nimport Motion from '../ui/util/optional_motion';\nimport spring from 'react-motion/lib/spring';\n\nconst mapStateToProps = state => ({\n  accountIds: state.getIn(['listEditor', 'accounts', 'items']),\n  searchAccountIds: state.getIn(['listEditor', 'suggestions', 'items']),\n});\n\nconst mapDispatchToProps = dispatch => ({\n  onInitialize: listId => dispatch(setupListEditor(listId)),\n  onClear: () => dispatch(clearListSuggestions()),\n  onReset: () => dispatch(resetListEditor()),\n});\n\nexport default @connect(mapStateToProps, mapDispatchToProps)\n@injectIntl\nclass ListEditor extends ImmutablePureComponent {\n\n  static propTypes = {\n    listId: PropTypes.string.isRequired,\n    onClose: PropTypes.func.isRequired,\n    intl: PropTypes.object.isRequired,\n    onInitialize: PropTypes.func.isRequired,\n    onClear: PropTypes.func.isRequired,\n    onReset: PropTypes.func.isRequired,\n    accountIds: ImmutablePropTypes.list.isRequired,\n    searchAccountIds: ImmutablePropTypes.list.isRequired,\n  };\n\n  componentDidMount () {\n    const { onInitialize, listId } = this.props;\n    onInitialize(listId);\n  }\n\n  componentWillUnmount () {\n    const { onReset } = this.props;\n    onReset();\n  }\n\n  render () {\n    const { accountIds, searchAccountIds, onClear } = this.props;\n    const showSearch = searchAccountIds.size > 0;\n\n    return (\n      <div className='modal-root__modal list-editor'>\n        <EditListForm />\n\n        <Search />\n\n        <div className='drawer__pager'>\n          <div className='drawer__inner list-editor__accounts'>\n            {accountIds.map(accountId => <Account key={accountId} accountId={accountId} added />)}\n          </div>\n\n          {showSearch && <div role='button' tabIndex='-1' className='drawer__backdrop' onClick={onClear} />}\n\n          <Motion defaultStyle={{ x: -100 }} style={{ x: spring(showSearch ? 0 : -100, { stiffness: 210, damping: 20 }) }}>\n            {({ x }) => (\n              <div className='drawer__inner backdrop' style={{ transform: x === 0 ? null : `translateX(${x}%)`, visibility: x === -100 ? 'hidden' : 'visible' }}>\n                {searchAccountIds.map(accountId => <Account key={accountId} accountId={accountId} />)}\n              </div>\n            )}\n          </Motion>\n        </div>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/list_timeline/index.js",
    "content": "import React from 'react';\nimport { connect } from 'react-redux';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport StatusListContainer from '../ui/containers/status_list_container';\nimport Column from '../../components/column';\nimport ColumnBackButton from '../../components/column_back_button';\nimport ColumnHeader from '../../components/column_header';\nimport { addColumn, removeColumn, moveColumn } from '../../actions/columns';\nimport { FormattedMessage, defineMessages, injectIntl } from 'react-intl';\nimport { connectListStream } from '../../actions/streaming';\nimport { expandListTimeline } from '../../actions/timelines';\nimport { fetchList, deleteList } from '../../actions/lists';\nimport { openModal } from '../../actions/modal';\nimport MissingIndicator from '../../components/missing_indicator';\nimport LoadingIndicator from '../../components/loading_indicator';\nimport Icon from 'mastodon/components/icon';\n\nconst messages = defineMessages({\n  deleteMessage: { id: 'confirmations.delete_list.message', defaultMessage: 'Are you sure you want to permanently delete this list?' },\n  deleteConfirm: { id: 'confirmations.delete_list.confirm', defaultMessage: 'Delete' },\n});\n\nconst mapStateToProps = (state, props) => ({\n  list: state.getIn(['lists', props.params.id]),\n  hasUnread: state.getIn(['timelines', `list:${props.params.id}`, 'unread']) > 0,\n});\n\nexport default @connect(mapStateToProps)\n@injectIntl\nclass ListTimeline extends React.PureComponent {\n\n  static contextTypes = {\n    router: PropTypes.object,\n  };\n\n  static propTypes = {\n    params: PropTypes.object.isRequired,\n    dispatch: PropTypes.func.isRequired,\n    shouldUpdateScroll: PropTypes.func,\n    columnId: PropTypes.string,\n    hasUnread: PropTypes.bool,\n    multiColumn: PropTypes.bool,\n    list: PropTypes.oneOfType([ImmutablePropTypes.map, PropTypes.bool]),\n    intl: PropTypes.object.isRequired,\n  };\n\n  handlePin = () => {\n    const { columnId, dispatch } = this.props;\n\n    if (columnId) {\n      dispatch(removeColumn(columnId));\n    } else {\n      dispatch(addColumn('LIST', { id: this.props.params.id }));\n      this.context.router.history.push('/');\n    }\n  }\n\n  handleMove = (dir) => {\n    const { columnId, dispatch } = this.props;\n    dispatch(moveColumn(columnId, dir));\n  }\n\n  handleHeaderClick = () => {\n    this.column.scrollTop();\n  }\n\n  componentDidMount () {\n    const { dispatch } = this.props;\n    const { id } = this.props.params;\n\n    dispatch(fetchList(id));\n    dispatch(expandListTimeline(id));\n\n    this.disconnect = dispatch(connectListStream(id));\n  }\n\n  componentWillReceiveProps (nextProps) {\n    const { dispatch } = this.props;\n    const { id } = nextProps.params;\n\n    if (id !== this.props.params.id) {\n      if (this.disconnect) {\n        this.disconnect();\n        this.disconnect = null;\n      }\n\n      dispatch(fetchList(id));\n      dispatch(expandListTimeline(id));\n\n      this.disconnect = dispatch(connectListStream(id));\n    }\n  }\n\n  componentWillUnmount () {\n    if (this.disconnect) {\n      this.disconnect();\n      this.disconnect = null;\n    }\n  }\n\n  setRef = c => {\n    this.column = c;\n  }\n\n  handleLoadMore = maxId => {\n    const { id } = this.props.params;\n    this.props.dispatch(expandListTimeline(id, { maxId }));\n  }\n\n  handleEditClick = () => {\n    this.props.dispatch(openModal('LIST_EDITOR', { listId: this.props.params.id }));\n  }\n\n  handleDeleteClick = () => {\n    const { dispatch, columnId, intl } = this.props;\n    const { id } = this.props.params;\n\n    dispatch(openModal('CONFIRM', {\n      message: intl.formatMessage(messages.deleteMessage),\n      confirm: intl.formatMessage(messages.deleteConfirm),\n      onConfirm: () => {\n        dispatch(deleteList(id));\n\n        if (!!columnId) {\n          dispatch(removeColumn(columnId));\n        } else {\n          this.context.router.history.push('/lists');\n        }\n      },\n    }));\n  }\n\n  render () {\n    const { shouldUpdateScroll, hasUnread, columnId, multiColumn, list } = this.props;\n    const { id } = this.props.params;\n    const pinned = !!columnId;\n    const title  = list ? list.get('title') : id;\n\n    if (typeof list === 'undefined') {\n      return (\n        <Column>\n          <div className='scrollable'>\n            <LoadingIndicator />\n          </div>\n        </Column>\n      );\n    } else if (list === false) {\n      return (\n        <Column>\n          <ColumnBackButton />\n          <MissingIndicator />\n        </Column>\n      );\n    }\n\n    return (\n      <Column ref={this.setRef} label={title}>\n        <ColumnHeader\n          icon='list-ul'\n          active={hasUnread}\n          title={title}\n          onPin={this.handlePin}\n          onMove={this.handleMove}\n          onClick={this.handleHeaderClick}\n          pinned={pinned}\n          multiColumn={multiColumn}\n        >\n          <div className='column-header__links'>\n            <button className='text-btn column-header__setting-btn' tabIndex='0' onClick={this.handleEditClick}>\n              <Icon id='pencil' /> <FormattedMessage id='lists.edit' defaultMessage='Edit list' />\n            </button>\n\n            <button className='text-btn column-header__setting-btn' tabIndex='0' onClick={this.handleDeleteClick}>\n              <Icon id='trash' /> <FormattedMessage id='lists.delete' defaultMessage='Delete list' />\n            </button>\n          </div>\n        </ColumnHeader>\n\n        <StatusListContainer\n          trackScroll={!pinned}\n          scrollKey={`list_timeline-${columnId}`}\n          timelineId={`list:${id}`}\n          onLoadMore={this.handleLoadMore}\n          emptyMessage={<FormattedMessage id='empty_column.list' defaultMessage='There is nothing in this list yet. When members of this list post new statuses, they will appear here.' />}\n          shouldUpdateScroll={shouldUpdateScroll}\n        />\n      </Column>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/lists/components/new_list_form.js",
    "content": "import React from 'react';\nimport { connect } from 'react-redux';\nimport PropTypes from 'prop-types';\nimport { changeListEditorTitle, submitListEditor } from '../../../actions/lists';\nimport IconButton from '../../../components/icon_button';\nimport { defineMessages, injectIntl } from 'react-intl';\n\nconst messages = defineMessages({\n  label: { id: 'lists.new.title_placeholder', defaultMessage: 'New list title' },\n  title: { id: 'lists.new.create', defaultMessage: 'Add list' },\n});\n\nconst mapStateToProps = state => ({\n  value: state.getIn(['listEditor', 'title']),\n  disabled: state.getIn(['listEditor', 'isSubmitting']),\n});\n\nconst mapDispatchToProps = dispatch => ({\n  onChange: value => dispatch(changeListEditorTitle(value)),\n  onSubmit: () => dispatch(submitListEditor(true)),\n});\n\nexport default @connect(mapStateToProps, mapDispatchToProps)\n@injectIntl\nclass NewListForm extends React.PureComponent {\n\n  static propTypes = {\n    value: PropTypes.string.isRequired,\n    disabled: PropTypes.bool,\n    intl: PropTypes.object.isRequired,\n    onChange: PropTypes.func.isRequired,\n    onSubmit: PropTypes.func.isRequired,\n  };\n\n  handleChange = e => {\n    this.props.onChange(e.target.value);\n  }\n\n  handleSubmit = e => {\n    e.preventDefault();\n    this.props.onSubmit();\n  }\n\n  handleClick = () => {\n    this.props.onSubmit();\n  }\n\n  render () {\n    const { value, disabled, intl } = this.props;\n\n    const label = intl.formatMessage(messages.label);\n    const title = intl.formatMessage(messages.title);\n\n    return (\n      <form className='column-inline-form' onSubmit={this.handleSubmit}>\n        <label>\n          <span style={{ display: 'none' }}>{label}</span>\n\n          <input\n            className='setting-text'\n            value={value}\n            disabled={disabled}\n            onChange={this.handleChange}\n            placeholder={label}\n          />\n        </label>\n\n        <IconButton\n          disabled={disabled}\n          icon='plus'\n          title={title}\n          onClick={this.handleClick}\n        />\n      </form>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/lists/index.js",
    "content": "import React from 'react';\nimport { connect } from 'react-redux';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport LoadingIndicator from '../../components/loading_indicator';\nimport Column from '../ui/components/column';\nimport ColumnBackButtonSlim from '../../components/column_back_button_slim';\nimport { fetchLists } from '../../actions/lists';\nimport { defineMessages, injectIntl, FormattedMessage } from 'react-intl';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport ColumnLink from '../ui/components/column_link';\nimport ColumnSubheading from '../ui/components/column_subheading';\nimport NewListForm from './components/new_list_form';\nimport { createSelector } from 'reselect';\nimport ScrollableList from '../../components/scrollable_list';\n\nconst messages = defineMessages({\n  heading: { id: 'column.lists', defaultMessage: 'Lists' },\n  subheading: { id: 'lists.subheading', defaultMessage: 'Your lists' },\n});\n\nconst getOrderedLists = createSelector([state => state.get('lists')], lists => {\n  if (!lists) {\n    return lists;\n  }\n\n  return lists.toList().filter(item => !!item).sort((a, b) => a.get('title').localeCompare(b.get('title')));\n});\n\nconst mapStateToProps = state => ({\n  lists: getOrderedLists(state),\n});\n\nexport default @connect(mapStateToProps)\n@injectIntl\nclass Lists extends ImmutablePureComponent {\n\n  static propTypes = {\n    params: PropTypes.object.isRequired,\n    dispatch: PropTypes.func.isRequired,\n    lists: ImmutablePropTypes.list,\n    intl: PropTypes.object.isRequired,\n  };\n\n  componentWillMount () {\n    this.props.dispatch(fetchLists());\n  }\n\n  render () {\n    const { intl, shouldUpdateScroll, lists } = this.props;\n\n    if (!lists) {\n      return (\n        <Column>\n          <LoadingIndicator />\n        </Column>\n      );\n    }\n\n    const emptyMessage = <FormattedMessage id='empty_column.lists' defaultMessage=\"You don't have any lists yet. When you create one, it will show up here.\" />;\n\n    return (\n      <Column icon='list-ul' heading={intl.formatMessage(messages.heading)}>\n        <ColumnBackButtonSlim />\n\n        <NewListForm />\n\n        <ScrollableList\n          scrollKey='lists'\n          shouldUpdateScroll={shouldUpdateScroll}\n          emptyMessage={emptyMessage}\n          prepend={<ColumnSubheading text={intl.formatMessage(messages.subheading)} />}\n        >\n          {lists.map(list =>\n            <ColumnLink key={list.get('id')} to={`/timelines/list/${list.get('id')}`} icon='list-ul' text={list.get('title')} />\n          )}\n        </ScrollableList>\n      </Column>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/mutes/index.js",
    "content": "import React from 'react';\nimport { connect } from 'react-redux';\nimport { defineMessages, injectIntl, FormattedMessage } from 'react-intl';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport { debounce } from 'lodash';\nimport LoadingIndicator from '../../components/loading_indicator';\nimport Column from '../ui/components/column';\nimport ColumnBackButtonSlim from '../../components/column_back_button_slim';\nimport AccountContainer from '../../containers/account_container';\nimport { fetchMutes, expandMutes } from '../../actions/mutes';\nimport ScrollableList from '../../components/scrollable_list';\n\nconst messages = defineMessages({\n  heading: { id: 'column.mutes', defaultMessage: 'Muted users' },\n});\n\nconst mapStateToProps = state => ({\n  accountIds: state.getIn(['user_lists', 'mutes', 'items']),\n  hasMore: !!state.getIn(['user_lists', 'mutes', 'next']),\n});\n\nexport default @connect(mapStateToProps)\n@injectIntl\nclass Mutes extends ImmutablePureComponent {\n\n  static propTypes = {\n    params: PropTypes.object.isRequired,\n    dispatch: PropTypes.func.isRequired,\n    shouldUpdateScroll: PropTypes.func,\n    hasMore: PropTypes.bool,\n    accountIds: ImmutablePropTypes.list,\n    intl: PropTypes.object.isRequired,\n  };\n\n  componentWillMount () {\n    this.props.dispatch(fetchMutes());\n  }\n\n  handleLoadMore = debounce(() => {\n    this.props.dispatch(expandMutes());\n  }, 300, { leading: true });\n\n  render () {\n    const { intl, shouldUpdateScroll, hasMore, accountIds } = this.props;\n\n    if (!accountIds) {\n      return (\n        <Column>\n          <LoadingIndicator />\n        </Column>\n      );\n    }\n\n    const emptyMessage = <FormattedMessage id='empty_column.mutes' defaultMessage=\"You haven't muted any users yet.\" />;\n\n    return (\n      <Column icon='volume-off' heading={intl.formatMessage(messages.heading)}>\n        <ColumnBackButtonSlim />\n        <ScrollableList\n          scrollKey='mutes'\n          onLoadMore={this.handleLoadMore}\n          hasMore={hasMore}\n          shouldUpdateScroll={shouldUpdateScroll}\n          emptyMessage={emptyMessage}\n        >\n          {accountIds.map(id =>\n            <AccountContainer key={id} id={id} />\n          )}\n        </ScrollableList>\n      </Column>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/notifications/components/clear_column_button.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport { FormattedMessage } from 'react-intl';\nimport Icon from 'mastodon/components/icon';\n\nexport default class ClearColumnButton extends React.PureComponent {\n\n  static propTypes = {\n    onClick: PropTypes.func.isRequired,\n  };\n\n  render () {\n    return (\n      <button className='text-btn column-header__setting-btn' tabIndex='0' onClick={this.props.onClick}><Icon id='eraser' /> <FormattedMessage id='notifications.clear' defaultMessage='Clear notifications' /></button>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/notifications/components/column_settings.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport { FormattedMessage } from 'react-intl';\nimport ClearColumnButton from './clear_column_button';\nimport SettingToggle from './setting_toggle';\n\nexport default class ColumnSettings extends React.PureComponent {\n\n  static propTypes = {\n    settings: ImmutablePropTypes.map.isRequired,\n    pushSettings: ImmutablePropTypes.map.isRequired,\n    onChange: PropTypes.func.isRequired,\n    onClear: PropTypes.func.isRequired,\n  };\n\n  onPushChange = (path, checked) => {\n    this.props.onChange(['push', ...path], checked);\n  }\n\n  render () {\n    const { settings, pushSettings, onChange, onClear } = this.props;\n\n    const filterShowStr = <FormattedMessage id='notifications.column_settings.filter_bar.show' defaultMessage='Show' />;\n    const filterAdvancedStr = <FormattedMessage id='notifications.column_settings.filter_bar.advanced' defaultMessage='Display all categories' />;\n    const alertStr  = <FormattedMessage id='notifications.column_settings.alert' defaultMessage='Desktop notifications' />;\n    const showStr   = <FormattedMessage id='notifications.column_settings.show' defaultMessage='Show in column' />;\n    const soundStr  = <FormattedMessage id='notifications.column_settings.sound' defaultMessage='Play sound' />;\n\n    const showPushSettings = pushSettings.get('browserSupport') && pushSettings.get('isSubscribed');\n    const pushStr = showPushSettings && <FormattedMessage id='notifications.column_settings.push' defaultMessage='Push notifications' />;\n\n    return (\n      <div>\n        <div className='column-settings__row'>\n          <ClearColumnButton onClick={onClear} />\n        </div>\n\n        <div role='group' aria-labelledby='notifications-filter-bar'>\n          <span id='notifications-filter-bar' className='column-settings__section'>\n            <FormattedMessage id='notifications.column_settings.filter_bar.category' defaultMessage='Quick filter bar' />\n          </span>\n          <div className='column-settings__row'>\n            <SettingToggle id='show-filter-bar' prefix='notifications' settings={settings} settingPath={['quickFilter', 'show']} onChange={onChange} label={filterShowStr} />\n            <SettingToggle id='show-filter-bar' prefix='notifications' settings={settings} settingPath={['quickFilter', 'advanced']} onChange={onChange} label={filterAdvancedStr} />\n          </div>\n        </div>\n\n        <div role='group' aria-labelledby='notifications-follow'>\n          <span id='notifications-follow' className='column-settings__section'><FormattedMessage id='notifications.column_settings.follow' defaultMessage='New followers:' /></span>\n\n          <div className='column-settings__row'>\n            <SettingToggle prefix='notifications_desktop' settings={settings} settingPath={['alerts', 'follow']} onChange={onChange} label={alertStr} />\n            {showPushSettings && <SettingToggle prefix='notifications_push' settings={pushSettings} settingPath={['alerts', 'follow']} onChange={this.onPushChange} label={pushStr} />}\n            <SettingToggle prefix='notifications' settings={settings} settingPath={['shows', 'follow']} onChange={onChange} label={showStr} />\n            <SettingToggle prefix='notifications' settings={settings} settingPath={['sounds', 'follow']} onChange={onChange} label={soundStr} />\n          </div>\n        </div>\n\n        <div role='group' aria-labelledby='notifications-favourite'>\n          <span id='notifications-favourite' className='column-settings__section'><FormattedMessage id='notifications.column_settings.favourite' defaultMessage='Favourites:' /></span>\n\n          <div className='column-settings__row'>\n            <SettingToggle prefix='notifications_desktop' settings={settings} settingPath={['alerts', 'favourite']} onChange={onChange} label={alertStr} />\n            {showPushSettings && <SettingToggle prefix='notifications_push' settings={pushSettings} settingPath={['alerts', 'favourite']} onChange={this.onPushChange} label={pushStr} />}\n            <SettingToggle prefix='notifications' settings={settings} settingPath={['shows', 'favourite']} onChange={onChange} label={showStr} />\n            <SettingToggle prefix='notifications' settings={settings} settingPath={['sounds', 'favourite']} onChange={onChange} label={soundStr} />\n          </div>\n        </div>\n\n        <div role='group' aria-labelledby='notifications-mention'>\n          <span id='notifications-mention' className='column-settings__section'><FormattedMessage id='notifications.column_settings.mention' defaultMessage='Mentions:' /></span>\n\n          <div className='column-settings__row'>\n            <SettingToggle prefix='notifications_desktop' settings={settings} settingPath={['alerts', 'mention']} onChange={onChange} label={alertStr} />\n            {showPushSettings && <SettingToggle prefix='notifications_push' settings={pushSettings} settingPath={['alerts', 'mention']} onChange={this.onPushChange} label={pushStr} />}\n            <SettingToggle prefix='notifications' settings={settings} settingPath={['shows', 'mention']} onChange={onChange} label={showStr} />\n            <SettingToggle prefix='notifications' settings={settings} settingPath={['sounds', 'mention']} onChange={onChange} label={soundStr} />\n          </div>\n        </div>\n\n        <div role='group' aria-labelledby='notifications-reblog'>\n          <span id='notifications-reblog' className='column-settings__section'><FormattedMessage id='notifications.column_settings.reblog' defaultMessage='Boosts:' /></span>\n\n          <div className='column-settings__row'>\n            <SettingToggle prefix='notifications_desktop' settings={settings} settingPath={['alerts', 'reblog']} onChange={onChange} label={alertStr} />\n            {showPushSettings && <SettingToggle prefix='notifications_push' settings={pushSettings} settingPath={['alerts', 'reblog']} onChange={this.onPushChange} label={pushStr} />}\n            <SettingToggle prefix='notifications' settings={settings} settingPath={['shows', 'reblog']} onChange={onChange} label={showStr} />\n            <SettingToggle prefix='notifications' settings={settings} settingPath={['sounds', 'reblog']} onChange={onChange} label={soundStr} />\n          </div>\n        </div>\n\n        <div role='group' aria-labelledby='notifications-poll'>\n          <span id='notifications-poll' className='column-settings__section'><FormattedMessage id='notifications.column_settings.poll' defaultMessage='Poll results:' /></span>\n\n          <div className='column-settings__row'>\n            <SettingToggle prefix='notifications_desktop' settings={settings} settingPath={['alerts', 'poll']} onChange={onChange} label={alertStr} />\n            {showPushSettings && <SettingToggle prefix='notifications_push' settings={pushSettings} settingPath={['alerts', 'poll']} onChange={this.onPushChange} label={pushStr} />}\n            <SettingToggle prefix='notifications' settings={settings} settingPath={['shows', 'poll']} onChange={onChange} label={showStr} />\n            <SettingToggle prefix='notifications' settings={settings} settingPath={['sounds', 'poll']} onChange={onChange} label={soundStr} />\n          </div>\n        </div>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/notifications/components/filter_bar.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport { defineMessages, injectIntl, FormattedMessage } from 'react-intl';\nimport Icon from 'mastodon/components/icon';\n\nconst tooltips = defineMessages({\n  mentions: { id: 'notifications.filter.mentions', defaultMessage: 'Mentions' },\n  favourites: { id: 'notifications.filter.favourites', defaultMessage: 'Favourites' },\n  boosts: { id: 'notifications.filter.boosts', defaultMessage: 'Boosts' },\n  polls: { id: 'notifications.filter.polls', defaultMessage: 'Poll results' },\n  follows: { id: 'notifications.filter.follows', defaultMessage: 'Follows' },\n});\n\nexport default @injectIntl\nclass FilterBar extends React.PureComponent {\n\n  static propTypes = {\n    selectFilter: PropTypes.func.isRequired,\n    selectedFilter: PropTypes.string.isRequired,\n    advancedMode: PropTypes.bool.isRequired,\n    intl: PropTypes.object.isRequired,\n  };\n\n  onClick (notificationType) {\n    return () => this.props.selectFilter(notificationType);\n  }\n\n  render () {\n    const { selectedFilter, advancedMode, intl } = this.props;\n    const renderedElement = !advancedMode ? (\n      <div className='notification__filter-bar'>\n        <button\n          className={selectedFilter === 'all' ? 'active' : ''}\n          onClick={this.onClick('all')}\n        >\n          <FormattedMessage\n            id='notifications.filter.all'\n            defaultMessage='All'\n          />\n        </button>\n        <button\n          className={selectedFilter === 'mention' ? 'active' : ''}\n          onClick={this.onClick('mention')}\n        >\n          <FormattedMessage\n            id='notifications.filter.mentions'\n            defaultMessage='Mentions'\n          />\n        </button>\n      </div>\n    ) : (\n      <div className='notification__filter-bar'>\n        <button\n          className={selectedFilter === 'all' ? 'active' : ''}\n          onClick={this.onClick('all')}\n        >\n          <FormattedMessage\n            id='notifications.filter.all'\n            defaultMessage='All'\n          />\n        </button>\n        <button\n          className={selectedFilter === 'mention' ? 'active' : ''}\n          onClick={this.onClick('mention')}\n          title={intl.formatMessage(tooltips.mentions)}\n        >\n          <Icon id='at' fixedWidth />\n        </button>\n        <button\n          className={selectedFilter === 'favourite' ? 'active' : ''}\n          onClick={this.onClick('favourite')}\n          title={intl.formatMessage(tooltips.favourites)}\n        >\n          <Icon id='star' fixedWidth />\n        </button>\n        <button\n          className={selectedFilter === 'reblog' ? 'active' : ''}\n          onClick={this.onClick('reblog')}\n          title={intl.formatMessage(tooltips.boosts)}\n        >\n          <Icon id='retweet' fixedWidth />\n        </button>\n        <button\n          className={selectedFilter === 'poll' ? 'active' : ''}\n          onClick={this.onClick('poll')}\n          title={intl.formatMessage(tooltips.polls)}\n        >\n          <Icon id='tasks' fixedWidth />\n        </button>\n        <button\n          className={selectedFilter === 'follow' ? 'active' : ''}\n          onClick={this.onClick('follow')}\n          title={intl.formatMessage(tooltips.follows)}\n        >\n          <Icon id='user-plus' fixedWidth />\n        </button>\n      </div>\n    );\n    return renderedElement;\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/notifications/components/notification.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport StatusContainer from '../../../containers/status_container';\nimport AccountContainer from '../../../containers/account_container';\nimport { injectIntl, FormattedMessage } from 'react-intl';\nimport Permalink from '../../../components/permalink';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport { HotKeys } from 'react-hotkeys';\nimport Icon from 'mastodon/components/icon';\n\nconst notificationForScreenReader = (intl, message, timestamp) => {\n  const output = [message];\n\n  output.push(intl.formatDate(timestamp, { hour: '2-digit', minute: '2-digit', month: 'short', day: 'numeric' }));\n\n  return output.join(', ');\n};\n\nexport default @injectIntl\nclass Notification extends ImmutablePureComponent {\n\n  static contextTypes = {\n    router: PropTypes.object,\n  };\n\n  static propTypes = {\n    notification: ImmutablePropTypes.map.isRequired,\n    hidden: PropTypes.bool,\n    onMoveUp: PropTypes.func.isRequired,\n    onMoveDown: PropTypes.func.isRequired,\n    onMention: PropTypes.func.isRequired,\n    onFavourite: PropTypes.func.isRequired,\n    onReblog: PropTypes.func.isRequired,\n    onToggleHidden: PropTypes.func.isRequired,\n    status: ImmutablePropTypes.map,\n    intl: PropTypes.object.isRequired,\n    getScrollPosition: PropTypes.func,\n    updateScrollBottom: PropTypes.func,\n    cacheMediaWidth: PropTypes.func,\n    cachedMediaWidth: PropTypes.number,\n  };\n\n  handleMoveUp = () => {\n    const { notification, onMoveUp } = this.props;\n    onMoveUp(notification.get('id'));\n  }\n\n  handleMoveDown = () => {\n    const { notification, onMoveDown } = this.props;\n    onMoveDown(notification.get('id'));\n  }\n\n  handleOpen = () => {\n    const { notification } = this.props;\n\n    if (notification.get('status')) {\n      this.context.router.history.push(`/statuses/${notification.get('status')}`);\n    } else {\n      this.handleOpenProfile();\n    }\n  }\n\n  handleOpenProfile = () => {\n    const { notification } = this.props;\n    this.context.router.history.push(`/accounts/${notification.getIn(['account', 'id'])}`);\n  }\n\n  handleMention = e => {\n    e.preventDefault();\n\n    const { notification, onMention } = this.props;\n    onMention(notification.get('account'), this.context.router.history);\n  }\n\n  handleHotkeyFavourite = () => {\n    const { status } = this.props;\n    if (status) this.props.onFavourite(status);\n  }\n\n  handleHotkeyBoost = e => {\n    const { status } = this.props;\n    if (status) this.props.onReblog(status, e);\n  }\n\n  handleHotkeyToggleHidden = () => {\n    const { status } = this.props;\n    if (status) this.props.onToggleHidden(status);\n  }\n\n  getHandlers () {\n    return {\n      reply: this.handleMention,\n      favourite: this.handleHotkeyFavourite,\n      boost: this.handleHotkeyBoost,\n      mention: this.handleMention,\n      open: this.handleOpen,\n      openProfile: this.handleOpenProfile,\n      moveUp: this.handleMoveUp,\n      moveDown: this.handleMoveDown,\n      toggleHidden: this.handleHotkeyToggleHidden,\n    };\n  }\n\n  renderFollow (notification, account, link) {\n    const { intl } = this.props;\n\n    return (\n      <HotKeys handlers={this.getHandlers()}>\n        <div className='notification notification-follow focusable' tabIndex='0' aria-label={notificationForScreenReader(intl, intl.formatMessage({ id: 'notification.follow', defaultMessage: '{name} followed you' }, { name: account.get('acct') }), notification.get('created_at'))}>\n          <div className='notification__message'>\n            <div className='notification__favourite-icon-wrapper'>\n              <Icon id='user-plus' fixedWidth />\n            </div>\n\n            <span title={notification.get('created_at')}>\n              <FormattedMessage id='notification.follow' defaultMessage='{name} followed you' values={{ name: link }} />\n            </span>\n          </div>\n\n          <AccountContainer id={account.get('id')} withNote={false} hidden={this.props.hidden} />\n        </div>\n      </HotKeys>\n    );\n  }\n\n  renderMention (notification) {\n    return (\n      <StatusContainer\n        id={notification.get('status')}\n        withDismiss\n        hidden={this.props.hidden}\n        onMoveDown={this.handleMoveDown}\n        onMoveUp={this.handleMoveUp}\n        contextType='notifications'\n        getScrollPosition={this.props.getScrollPosition}\n        updateScrollBottom={this.props.updateScrollBottom}\n        cachedMediaWidth={this.props.cachedMediaWidth}\n        cacheMediaWidth={this.props.cacheMediaWidth}\n      />\n    );\n  }\n\n  renderFavourite (notification, link) {\n    const { intl } = this.props;\n\n    return (\n      <HotKeys handlers={this.getHandlers()}>\n        <div className='notification notification-favourite focusable' tabIndex='0' aria-label={notificationForScreenReader(intl, intl.formatMessage({ id: 'notification.favourite', defaultMessage: '{name} favourited your status' }, { name: notification.getIn(['account', 'acct']) }), notification.get('created_at'))}>\n          <div className='notification__message'>\n            <div className='notification__favourite-icon-wrapper'>\n              <Icon id='star' className='star-icon' fixedWidth />\n            </div>\n\n            <span title={notification.get('created_at')}>\n              <FormattedMessage id='notification.favourite' defaultMessage='{name} favourited your status' values={{ name: link }} />\n            </span>\n          </div>\n\n          <StatusContainer\n            id={notification.get('status')}\n            account={notification.get('account')}\n            muted\n            withDismiss\n            hidden={!!this.props.hidden}\n            getScrollPosition={this.props.getScrollPosition}\n            updateScrollBottom={this.props.updateScrollBottom}\n            cachedMediaWidth={this.props.cachedMediaWidth}\n            cacheMediaWidth={this.props.cacheMediaWidth}\n          />\n        </div>\n      </HotKeys>\n    );\n  }\n\n  renderReblog (notification, link) {\n    const { intl } = this.props;\n\n    return (\n      <HotKeys handlers={this.getHandlers()}>\n        <div className='notification notification-reblog focusable' tabIndex='0' aria-label={notificationForScreenReader(intl, intl.formatMessage({ id: 'notification.reblog', defaultMessage: '{name} boosted your status' }, { name: notification.getIn(['account', 'acct']) }), notification.get('created_at'))}>\n          <div className='notification__message'>\n            <div className='notification__favourite-icon-wrapper'>\n              <Icon id='retweet' fixedWidth />\n            </div>\n\n            <span title={notification.get('created_at')}>\n              <FormattedMessage id='notification.reblog' defaultMessage='{name} boosted your status' values={{ name: link }} />\n            </span>\n          </div>\n\n          <StatusContainer\n            id={notification.get('status')}\n            account={notification.get('account')}\n            muted\n            withDismiss\n            hidden={this.props.hidden}\n            getScrollPosition={this.props.getScrollPosition}\n            updateScrollBottom={this.props.updateScrollBottom}\n            cachedMediaWidth={this.props.cachedMediaWidth}\n            cacheMediaWidth={this.props.cacheMediaWidth}\n          />\n        </div>\n      </HotKeys>\n    );\n  }\n\n  renderPoll (notification) {\n    const { intl } = this.props;\n\n    return (\n      <HotKeys handlers={this.getHandlers()}>\n        <div className='notification notification-poll focusable' tabIndex='0' aria-label={notificationForScreenReader(intl, intl.formatMessage({ id: 'notification.poll', defaultMessage: 'A poll you have voted in has ended' }), notification.get('created_at'))}>\n          <div className='notification__message'>\n            <div className='notification__favourite-icon-wrapper'>\n              <Icon id='tasks' fixedWidth />\n            </div>\n\n            <span title={notification.get('created_at')}>\n              <FormattedMessage id='notification.poll' defaultMessage='A poll you have voted in has ended' />\n            </span>\n          </div>\n\n          <StatusContainer\n            id={notification.get('status')}\n            account={notification.get('account')}\n            muted\n            withDismiss\n            hidden={this.props.hidden}\n            getScrollPosition={this.props.getScrollPosition}\n            updateScrollBottom={this.props.updateScrollBottom}\n            cachedMediaWidth={this.props.cachedMediaWidth}\n            cacheMediaWidth={this.props.cacheMediaWidth}\n          />\n        </div>\n      </HotKeys>\n    );\n  }\n\n  render () {\n    const { notification } = this.props;\n    const account          = notification.get('account');\n    const displayNameHtml  = { __html: account.get('display_name_html') };\n    const link             = <bdi><Permalink className='notification__display-name' href={account.get('url')} title={account.get('acct')} to={`/accounts/${account.get('id')}`} dangerouslySetInnerHTML={displayNameHtml} /></bdi>;\n\n    switch(notification.get('type')) {\n    case 'follow':\n      return this.renderFollow(notification, account, link);\n    case 'mention':\n      return this.renderMention(notification);\n    case 'favourite':\n      return this.renderFavourite(notification, link);\n    case 'reblog':\n      return this.renderReblog(notification, link);\n    case 'poll':\n      return this.renderPoll(notification);\n    }\n\n    return null;\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/notifications/components/setting_toggle.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport Toggle from 'react-toggle';\n\nexport default class SettingToggle extends React.PureComponent {\n\n  static propTypes = {\n    prefix: PropTypes.string,\n    settings: ImmutablePropTypes.map.isRequired,\n    settingPath: PropTypes.array.isRequired,\n    label: PropTypes.node.isRequired,\n    onChange: PropTypes.func.isRequired,\n  }\n\n  onChange = ({ target }) => {\n    this.props.onChange(this.props.settingPath, target.checked);\n  }\n\n  render () {\n    const { prefix, settings, settingPath, label } = this.props;\n    const id = ['setting-toggle', prefix, ...settingPath].filter(Boolean).join('-');\n\n    return (\n      <div className='setting-toggle'>\n        <Toggle id={id} checked={settings.getIn(settingPath)} onChange={this.onChange} onKeyDown={this.onKeyDown} />\n        <label htmlFor={id} className='setting-toggle__label'>{label}</label>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/notifications/containers/column_settings_container.js",
    "content": "import { connect } from 'react-redux';\nimport { defineMessages, injectIntl } from 'react-intl';\nimport ColumnSettings from '../components/column_settings';\nimport { changeSetting } from '../../../actions/settings';\nimport { setFilter } from '../../../actions/notifications';\nimport { clearNotifications } from '../../../actions/notifications';\nimport { changeAlerts as changePushNotifications } from '../../../actions/push_notifications';\nimport { openModal } from '../../../actions/modal';\n\nconst messages = defineMessages({\n  clearMessage: { id: 'notifications.clear_confirmation', defaultMessage: 'Are you sure you want to permanently clear all your notifications?' },\n  clearConfirm: { id: 'notifications.clear', defaultMessage: 'Clear notifications' },\n});\n\nconst mapStateToProps = state => ({\n  settings: state.getIn(['settings', 'notifications']),\n  pushSettings: state.get('push_notifications'),\n});\n\nconst mapDispatchToProps = (dispatch, { intl }) => ({\n\n  onChange (path, checked) {\n    if (path[0] === 'push') {\n      dispatch(changePushNotifications(path.slice(1), checked));\n    } else if (path[0] === 'quickFilter') {\n      dispatch(changeSetting(['notifications', ...path], checked));\n      dispatch(setFilter('all'));\n    } else {\n      dispatch(changeSetting(['notifications', ...path], checked));\n    }\n  },\n\n  onClear () {\n    dispatch(openModal('CONFIRM', {\n      message: intl.formatMessage(messages.clearMessage),\n      confirm: intl.formatMessage(messages.clearConfirm),\n      onConfirm: () => dispatch(clearNotifications()),\n    }));\n  },\n\n});\n\nexport default injectIntl(connect(mapStateToProps, mapDispatchToProps)(ColumnSettings));\n"
  },
  {
    "path": "app/javascript/mastodon/features/notifications/containers/filter_bar_container.js",
    "content": "import { connect } from 'react-redux';\nimport FilterBar from '../components/filter_bar';\nimport { setFilter } from '../../../actions/notifications';\n\nconst makeMapStateToProps = state => ({\n  selectedFilter: state.getIn(['settings', 'notifications', 'quickFilter', 'active']),\n  advancedMode: state.getIn(['settings', 'notifications', 'quickFilter', 'advanced']),\n});\n\nconst mapDispatchToProps = (dispatch) => ({\n  selectFilter (newActiveFilter) {\n    dispatch(setFilter(newActiveFilter));\n  },\n});\n\nexport default connect(makeMapStateToProps, mapDispatchToProps)(FilterBar);\n"
  },
  {
    "path": "app/javascript/mastodon/features/notifications/containers/notification_container.js",
    "content": "import { connect } from 'react-redux';\nimport { makeGetNotification, makeGetStatus } from '../../../selectors';\nimport Notification from '../components/notification';\nimport { openModal } from '../../../actions/modal';\nimport { mentionCompose } from '../../../actions/compose';\nimport {\n  reblog,\n  favourite,\n  unreblog,\n  unfavourite,\n} from '../../../actions/interactions';\nimport {\n  hideStatus,\n  revealStatus,\n} from '../../../actions/statuses';\nimport { boostModal } from '../../../initial_state';\n\nconst makeMapStateToProps = () => {\n  const getNotification = makeGetNotification();\n  const getStatus = makeGetStatus();\n\n  const mapStateToProps = (state, props) => {\n    const notification = getNotification(state, props.notification, props.accountId);\n    return {\n      notification: notification,\n      status: notification.get('status') ? getStatus(state, { id: notification.get('status') }) : null,\n    };\n  };\n\n  return mapStateToProps;\n};\n\nconst mapDispatchToProps = dispatch => ({\n  onMention: (account, router) => {\n    dispatch(mentionCompose(account, router));\n  },\n\n  onModalReblog (status) {\n    dispatch(reblog(status));\n  },\n\n  onReblog (status, e) {\n    if (status.get('reblogged')) {\n      dispatch(unreblog(status));\n    } else {\n      if (e.shiftKey || !boostModal) {\n        this.onModalReblog(status);\n      } else {\n        dispatch(openModal('BOOST', { status, onReblog: this.onModalReblog }));\n      }\n    }\n  },\n\n  onFavourite (status) {\n    if (status.get('favourited')) {\n      dispatch(unfavourite(status));\n    } else {\n      dispatch(favourite(status));\n    }\n  },\n\n  onToggleHidden (status) {\n    if (status.get('hidden')) {\n      dispatch(revealStatus(status.get('id')));\n    } else {\n      dispatch(hideStatus(status.get('id')));\n    }\n  },\n});\n\nexport default connect(makeMapStateToProps, mapDispatchToProps)(Notification);\n"
  },
  {
    "path": "app/javascript/mastodon/features/notifications/index.js",
    "content": "import React from 'react';\nimport { connect } from 'react-redux';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport Column from '../../components/column';\nimport ColumnHeader from '../../components/column_header';\nimport { expandNotifications, scrollTopNotifications } from '../../actions/notifications';\nimport { addColumn, removeColumn, moveColumn } from '../../actions/columns';\nimport NotificationContainer from './containers/notification_container';\nimport { defineMessages, injectIntl, FormattedMessage } from 'react-intl';\nimport ColumnSettingsContainer from './containers/column_settings_container';\nimport FilterBarContainer from './containers/filter_bar_container';\nimport { createSelector } from 'reselect';\nimport { List as ImmutableList } from 'immutable';\nimport { debounce } from 'lodash';\nimport ScrollableList from '../../components/scrollable_list';\nimport LoadGap from '../../components/load_gap';\n\nconst messages = defineMessages({\n  title: { id: 'column.notifications', defaultMessage: 'Notifications' },\n});\n\nconst getNotifications = createSelector([\n  state => state.getIn(['settings', 'notifications', 'quickFilter', 'show']),\n  state => state.getIn(['settings', 'notifications', 'quickFilter', 'active']),\n  state => ImmutableList(state.getIn(['settings', 'notifications', 'shows']).filter(item => !item).keys()),\n  state => state.getIn(['notifications', 'items']),\n], (showFilterBar, allowedType, excludedTypes, notifications) => {\n  if (!showFilterBar || allowedType === 'all') {\n    // used if user changed the notification settings after loading the notifications from the server\n    // otherwise a list of notifications will come pre-filtered from the backend\n    // we need to turn it off for FilterBar in order not to block ourselves from seeing a specific category\n    return notifications.filterNot(item => item !== null && excludedTypes.includes(item.get('type')));\n  }\n  return notifications.filter(item => item !== null && allowedType === item.get('type'));\n});\n\nconst mapStateToProps = state => ({\n  showFilterBar: state.getIn(['settings', 'notifications', 'quickFilter', 'show']),\n  notifications: getNotifications(state),\n  isLoading: state.getIn(['notifications', 'isLoading'], true),\n  isUnread: state.getIn(['notifications', 'unread']) > 0,\n  hasMore: state.getIn(['notifications', 'hasMore']),\n});\n\nexport default @connect(mapStateToProps)\n@injectIntl\nclass Notifications extends React.PureComponent {\n\n  static propTypes = {\n    columnId: PropTypes.string,\n    notifications: ImmutablePropTypes.list.isRequired,\n    showFilterBar: PropTypes.bool.isRequired,\n    dispatch: PropTypes.func.isRequired,\n    shouldUpdateScroll: PropTypes.func,\n    intl: PropTypes.object.isRequired,\n    isLoading: PropTypes.bool,\n    isUnread: PropTypes.bool,\n    multiColumn: PropTypes.bool,\n    hasMore: PropTypes.bool,\n  };\n\n  static defaultProps = {\n    trackScroll: true,\n  };\n\n  componentWillUnmount () {\n    this.handleLoadOlder.cancel();\n    this.handleScrollToTop.cancel();\n    this.handleScroll.cancel();\n    this.props.dispatch(scrollTopNotifications(false));\n  }\n\n  handleLoadGap = (maxId) => {\n    this.props.dispatch(expandNotifications({ maxId }));\n  };\n\n  handleLoadOlder = debounce(() => {\n    const last = this.props.notifications.last();\n    this.props.dispatch(expandNotifications({ maxId: last && last.get('id') }));\n  }, 300, { leading: true });\n\n  handleScrollToTop = debounce(() => {\n    this.props.dispatch(scrollTopNotifications(true));\n  }, 100);\n\n  handleScroll = debounce(() => {\n    this.props.dispatch(scrollTopNotifications(false));\n  }, 100);\n\n  handlePin = () => {\n    const { columnId, dispatch } = this.props;\n\n    if (columnId) {\n      dispatch(removeColumn(columnId));\n    } else {\n      dispatch(addColumn('NOTIFICATIONS', {}));\n    }\n  }\n\n  handleMove = (dir) => {\n    const { columnId, dispatch } = this.props;\n    dispatch(moveColumn(columnId, dir));\n  }\n\n  handleHeaderClick = () => {\n    this.column.scrollTop();\n  }\n\n  setColumnRef = c => {\n    this.column = c;\n  }\n\n  handleMoveUp = id => {\n    const elementIndex = this.props.notifications.findIndex(item => item !== null && item.get('id') === id) - 1;\n    this._selectChild(elementIndex, true);\n  }\n\n  handleMoveDown = id => {\n    const elementIndex = this.props.notifications.findIndex(item => item !== null && item.get('id') === id) + 1;\n    this._selectChild(elementIndex, false);\n  }\n\n  _selectChild (index, align_top) {\n    const container = this.column.node;\n    const element = container.querySelector(`article:nth-of-type(${index + 1}) .focusable`);\n\n    if (element) {\n      if (align_top && container.scrollTop > element.offsetTop) {\n        element.scrollIntoView(true);\n      } else if (!align_top && container.scrollTop + container.clientHeight < element.offsetTop + element.offsetHeight) {\n        element.scrollIntoView(false);\n      }\n      element.focus();\n    }\n  }\n\n  render () {\n    const { intl, notifications, shouldUpdateScroll, isLoading, isUnread, columnId, multiColumn, hasMore, showFilterBar } = this.props;\n    const pinned = !!columnId;\n    const emptyMessage = <FormattedMessage id='empty_column.notifications' defaultMessage=\"You don't have any notifications yet. Interact with others to start the conversation.\" />;\n\n    let scrollableContent = null;\n\n    const filterBarContainer = showFilterBar\n      ? (<FilterBarContainer />)\n      : null;\n\n    if (isLoading && this.scrollableContent) {\n      scrollableContent = this.scrollableContent;\n    } else if (notifications.size > 0 || hasMore) {\n      scrollableContent = notifications.map((item, index) => item === null ? (\n        <LoadGap\n          key={'gap:' + notifications.getIn([index + 1, 'id'])}\n          disabled={isLoading}\n          maxId={index > 0 ? notifications.getIn([index - 1, 'id']) : null}\n          onClick={this.handleLoadGap}\n        />\n      ) : (\n        <NotificationContainer\n          key={item.get('id')}\n          notification={item}\n          accountId={item.get('account')}\n          onMoveUp={this.handleMoveUp}\n          onMoveDown={this.handleMoveDown}\n        />\n      ));\n    } else {\n      scrollableContent = null;\n    }\n\n    this.scrollableContent = scrollableContent;\n\n    const scrollContainer = (\n      <ScrollableList\n        scrollKey={`notifications-${columnId}`}\n        trackScroll={!pinned}\n        isLoading={isLoading}\n        showLoading={isLoading && notifications.size === 0}\n        hasMore={hasMore}\n        emptyMessage={emptyMessage}\n        onLoadMore={this.handleLoadOlder}\n        onScrollToTop={this.handleScrollToTop}\n        onScroll={this.handleScroll}\n        shouldUpdateScroll={shouldUpdateScroll}\n      >\n        {scrollableContent}\n      </ScrollableList>\n    );\n\n    return (\n      <Column ref={this.setColumnRef} label={intl.formatMessage(messages.title)}>\n        <ColumnHeader\n          icon='bell'\n          active={isUnread}\n          title={intl.formatMessage(messages.title)}\n          onPin={this.handlePin}\n          onMove={this.handleMove}\n          onClick={this.handleHeaderClick}\n          pinned={pinned}\n          multiColumn={multiColumn}\n        >\n          <ColumnSettingsContainer />\n        </ColumnHeader>\n        {filterBarContainer}\n        {scrollContainer}\n      </Column>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/pinned_statuses/index.js",
    "content": "import React from 'react';\nimport { connect } from 'react-redux';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport { fetchPinnedStatuses } from '../../actions/pin_statuses';\nimport Column from '../ui/components/column';\nimport ColumnBackButtonSlim from '../../components/column_back_button_slim';\nimport StatusList from '../../components/status_list';\nimport { defineMessages, injectIntl } from 'react-intl';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\n\nconst messages = defineMessages({\n  heading: { id: 'column.pins', defaultMessage: 'Pinned toot' },\n});\n\nconst mapStateToProps = state => ({\n  statusIds: state.getIn(['status_lists', 'pins', 'items']),\n  hasMore: !!state.getIn(['status_lists', 'pins', 'next']),\n});\n\nexport default @connect(mapStateToProps)\n@injectIntl\nclass PinnedStatuses extends ImmutablePureComponent {\n\n  static propTypes = {\n    dispatch: PropTypes.func.isRequired,\n    shouldUpdateScroll: PropTypes.func,\n    statusIds: ImmutablePropTypes.list.isRequired,\n    intl: PropTypes.object.isRequired,\n    hasMore: PropTypes.bool.isRequired,\n  };\n\n  componentWillMount () {\n    this.props.dispatch(fetchPinnedStatuses());\n  }\n\n  handleHeaderClick = () => {\n    this.column.scrollTop();\n  }\n\n  setRef = c => {\n    this.column = c;\n  }\n\n  render () {\n    const { intl, shouldUpdateScroll, statusIds, hasMore } = this.props;\n\n    return (\n      <Column icon='thumb-tack' heading={intl.formatMessage(messages.heading)} ref={this.setRef}>\n        <ColumnBackButtonSlim />\n        <StatusList\n          statusIds={statusIds}\n          scrollKey='pinned_statuses'\n          hasMore={hasMore}\n          shouldUpdateScroll={shouldUpdateScroll}\n        />\n      </Column>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/public_timeline/containers/column_settings_container.js",
    "content": "import { connect } from 'react-redux';\nimport ColumnSettings from '../../community_timeline/components/column_settings';\nimport { changeSetting } from '../../../actions/settings';\nimport { changeColumnParams } from '../../../actions/columns';\n\nconst mapStateToProps = (state, { columnId }) => {\n  const uuid = columnId;\n  const columns = state.getIn(['settings', 'columns']);\n  const index = columns.findIndex(c => c.get('uuid') === uuid);\n\n  return {\n    settings: (uuid && index >= 0) ? columns.get(index).get('params') : state.getIn(['settings', 'public']),\n  };\n};\n\nconst mapDispatchToProps = (dispatch, { columnId }) => {\n  return {\n    onChange (key, checked) {\n      if (columnId) {\n        dispatch(changeColumnParams(columnId, key, checked));\n      } else {\n        dispatch(changeSetting(['public', ...key], checked));\n      }\n    },\n  };\n};\n\nexport default connect(mapStateToProps, mapDispatchToProps)(ColumnSettings);\n"
  },
  {
    "path": "app/javascript/mastodon/features/public_timeline/index.js",
    "content": "import React from 'react';\nimport { connect } from 'react-redux';\nimport { defineMessages, injectIntl, FormattedMessage } from 'react-intl';\nimport PropTypes from 'prop-types';\nimport StatusListContainer from '../ui/containers/status_list_container';\nimport Column from '../../components/column';\nimport ColumnHeader from '../../components/column_header';\nimport { expandPublicTimeline } from '../../actions/timelines';\nimport { addColumn, removeColumn, moveColumn } from '../../actions/columns';\nimport ColumnSettingsContainer from './containers/column_settings_container';\nimport { connectPublicStream } from '../../actions/streaming';\n\nconst messages = defineMessages({\n  title: { id: 'column.public', defaultMessage: 'Federated timeline' },\n});\n\nconst mapStateToProps = (state, { onlyMedia, columnId }) => {\n  const uuid = columnId;\n  const columns = state.getIn(['settings', 'columns']);\n  const index = columns.findIndex(c => c.get('uuid') === uuid);\n\n  return {\n    hasUnread: state.getIn(['timelines', `public${onlyMedia ? ':media' : ''}`, 'unread']) > 0,\n    onlyMedia: (columnId && index >= 0) ? columns.get(index).getIn(['params', 'other', 'onlyMedia']) : state.getIn(['settings', 'public', 'other', 'onlyMedia']),\n  };\n};\n\nexport default @connect(mapStateToProps)\n@injectIntl\nclass PublicTimeline extends React.PureComponent {\n\n  static contextTypes = {\n    router: PropTypes.object,\n  };\n\n  static defaultProps = {\n    onlyMedia: false,\n  };\n\n  static propTypes = {\n    dispatch: PropTypes.func.isRequired,\n    shouldUpdateScroll: PropTypes.func,\n    intl: PropTypes.object.isRequired,\n    columnId: PropTypes.string,\n    multiColumn: PropTypes.bool,\n    hasUnread: PropTypes.bool,\n    onlyMedia: PropTypes.bool,\n  };\n\n  handlePin = () => {\n    const { columnId, dispatch, onlyMedia } = this.props;\n\n    if (columnId) {\n      dispatch(removeColumn(columnId));\n    } else {\n      dispatch(addColumn('PUBLIC', { other: { onlyMedia } }));\n    }\n  }\n\n  handleMove = (dir) => {\n    const { columnId, dispatch } = this.props;\n    dispatch(moveColumn(columnId, dir));\n  }\n\n  handleHeaderClick = () => {\n    this.column.scrollTop();\n  }\n\n  componentDidMount () {\n    const { dispatch, onlyMedia } = this.props;\n\n    dispatch(expandPublicTimeline({ onlyMedia }));\n    this.disconnect = dispatch(connectPublicStream({ onlyMedia }));\n  }\n\n  componentDidUpdate (prevProps) {\n    if (prevProps.onlyMedia !== this.props.onlyMedia) {\n      const { dispatch, onlyMedia } = this.props;\n\n      this.disconnect();\n      dispatch(expandPublicTimeline({ onlyMedia }));\n      this.disconnect = dispatch(connectPublicStream({ onlyMedia }));\n    }\n  }\n\n  componentWillUnmount () {\n    if (this.disconnect) {\n      this.disconnect();\n      this.disconnect = null;\n    }\n  }\n\n  setRef = c => {\n    this.column = c;\n  }\n\n  handleLoadMore = maxId => {\n    const { dispatch, onlyMedia } = this.props;\n\n    dispatch(expandPublicTimeline({ maxId, onlyMedia }));\n  }\n\n  render () {\n    const { intl, shouldUpdateScroll, columnId, hasUnread, multiColumn, onlyMedia } = this.props;\n    const pinned = !!columnId;\n\n    return (\n      <Column ref={this.setRef} label={intl.formatMessage(messages.title)}>\n        <ColumnHeader\n          icon='globe'\n          active={hasUnread}\n          title={intl.formatMessage(messages.title)}\n          onPin={this.handlePin}\n          onMove={this.handleMove}\n          onClick={this.handleHeaderClick}\n          pinned={pinned}\n          multiColumn={multiColumn}\n        >\n          <ColumnSettingsContainer columnId={columnId} />\n        </ColumnHeader>\n\n        <StatusListContainer\n          timelineId={`public${onlyMedia ? ':media' : ''}`}\n          onLoadMore={this.handleLoadMore}\n          trackScroll={!pinned}\n          scrollKey={`public_timeline-${columnId}`}\n          emptyMessage={<FormattedMessage id='empty_column.public' defaultMessage='There is nothing here! Write something publicly, or manually follow users from other servers to fill it up' />}\n          shouldUpdateScroll={shouldUpdateScroll}\n        />\n      </Column>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/reblogs/index.js",
    "content": "import React from 'react';\nimport { connect } from 'react-redux';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport LoadingIndicator from '../../components/loading_indicator';\nimport { fetchReblogs } from '../../actions/interactions';\nimport { FormattedMessage } from 'react-intl';\nimport AccountContainer from '../../containers/account_container';\nimport Column from '../ui/components/column';\nimport ColumnBackButton from '../../components/column_back_button';\nimport ScrollableList from '../../components/scrollable_list';\n\nconst mapStateToProps = (state, props) => ({\n  accountIds: state.getIn(['user_lists', 'reblogged_by', props.params.statusId]),\n});\n\nexport default @connect(mapStateToProps)\nclass Reblogs extends ImmutablePureComponent {\n\n  static propTypes = {\n    params: PropTypes.object.isRequired,\n    dispatch: PropTypes.func.isRequired,\n    shouldUpdateScroll: PropTypes.func,\n    accountIds: ImmutablePropTypes.list,\n  };\n\n  componentWillMount () {\n    this.props.dispatch(fetchReblogs(this.props.params.statusId));\n  }\n\n  componentWillReceiveProps(nextProps) {\n    if (nextProps.params.statusId !== this.props.params.statusId && nextProps.params.statusId) {\n      this.props.dispatch(fetchReblogs(nextProps.params.statusId));\n    }\n  }\n\n  render () {\n    const { shouldUpdateScroll, accountIds } = this.props;\n\n    if (!accountIds) {\n      return (\n        <Column>\n          <LoadingIndicator />\n        </Column>\n      );\n    }\n\n    const emptyMessage = <FormattedMessage id='status.reblogs.empty' defaultMessage='No one has boosted this toot yet. When someone does, they will show up here.' />;\n\n    return (\n      <Column>\n        <ColumnBackButton />\n\n        <ScrollableList\n          scrollKey='reblogs'\n          shouldUpdateScroll={shouldUpdateScroll}\n          emptyMessage={emptyMessage}\n        >\n          {accountIds.map(id =>\n            <AccountContainer key={id} id={id} withNote={false} />\n          )}\n        </ScrollableList>\n      </Column>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/report/components/status_check_box.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport Toggle from 'react-toggle';\nimport noop from 'lodash/noop';\nimport StatusContent from '../../../components/status_content';\nimport { MediaGallery, Video } from '../../ui/util/async-components';\nimport Bundle from '../../ui/components/bundle';\n\nexport default class StatusCheckBox extends React.PureComponent {\n\n  static propTypes = {\n    status: ImmutablePropTypes.map.isRequired,\n    checked: PropTypes.bool,\n    onToggle: PropTypes.func.isRequired,\n    disabled: PropTypes.bool,\n  };\n\n  render () {\n    const { status, checked, onToggle, disabled } = this.props;\n    let media = null;\n\n    if (status.get('reblog')) {\n      return null;\n    }\n\n    if (status.get('media_attachments').size > 0) {\n      if (status.get('media_attachments').some(item => item.get('type') === 'unknown')) {\n\n      } else if (status.getIn(['media_attachments', 0, 'type']) === 'video') {\n        const video = status.getIn(['media_attachments', 0]);\n\n        media = (\n          <Bundle fetchComponent={Video} loading={this.renderLoadingVideoPlayer} >\n            {Component => (\n              <Component\n                preview={video.get('preview_url')}\n                blurhash={video.get('blurhash')}\n                src={video.get('url')}\n                alt={video.get('description')}\n                width={239}\n                height={110}\n                inline\n                sensitive={status.get('sensitive')}\n                onOpenVideo={noop}\n              />\n            )}\n          </Bundle>\n        );\n      } else {\n        media = (\n          <Bundle fetchComponent={MediaGallery} loading={this.renderLoadingMediaGallery} >\n            {Component => <Component media={status.get('media_attachments')} sensitive={status.get('sensitive')} height={110} onOpenMedia={noop} />}\n          </Bundle>\n        );\n      }\n    }\n\n    return (\n      <div className='status-check-box'>\n        <div className='status-check-box__status'>\n          <StatusContent status={status} />\n          {media}\n        </div>\n\n        <div className='status-check-box-toggle'>\n          <Toggle checked={checked} onChange={onToggle} disabled={disabled} />\n        </div>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/report/containers/status_check_box_container.js",
    "content": "import { connect } from 'react-redux';\nimport StatusCheckBox from '../components/status_check_box';\nimport { toggleStatusReport } from '../../../actions/reports';\nimport { Set as ImmutableSet } from 'immutable';\n\nconst mapStateToProps = (state, { id }) => ({\n  status: state.getIn(['statuses', id]),\n  checked: state.getIn(['reports', 'new', 'status_ids'], ImmutableSet()).includes(id),\n});\n\nconst mapDispatchToProps = (dispatch, { id }) => ({\n\n  onToggle (e) {\n    dispatch(toggleStatusReport(id, e.target.checked));\n  },\n\n});\n\nexport default connect(mapStateToProps, mapDispatchToProps)(StatusCheckBox);\n"
  },
  {
    "path": "app/javascript/mastodon/features/search/index.js",
    "content": "import React from 'react';\nimport SearchContainer from 'mastodon/features/compose/containers/search_container';\nimport SearchResultsContainer from 'mastodon/features/compose/containers/search_results_container';\n\nconst Search = () => (\n  <div className='column search-page'>\n    <SearchContainer />\n\n    <div className='drawer__pager'>\n      <div className='drawer__inner darker'>\n        <SearchResultsContainer />\n      </div>\n    </div>\n  </div>\n);\n\nexport default Search;\n"
  },
  {
    "path": "app/javascript/mastodon/features/standalone/compose/index.js",
    "content": "import React from 'react';\nimport ComposeFormContainer from '../../compose/containers/compose_form_container';\nimport NotificationsContainer from '../../ui/containers/notifications_container';\nimport LoadingBarContainer from '../../ui/containers/loading_bar_container';\nimport ModalContainer from '../../ui/containers/modal_container';\n\nexport default class Compose extends React.PureComponent {\n\n  render () {\n    return (\n      <div>\n        <ComposeFormContainer />\n        <NotificationsContainer />\n        <ModalContainer />\n        <LoadingBarContainer className='loading-bar' />\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/standalone/hashtag_timeline/index.js",
    "content": "import React from 'react';\nimport { connect } from 'react-redux';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport { expandHashtagTimeline } from 'mastodon/actions/timelines';\nimport Masonry from 'react-masonry-infinite';\nimport { List as ImmutableList } from 'immutable';\nimport DetailedStatusContainer from 'mastodon/features/status/containers/detailed_status_container';\nimport { debounce } from 'lodash';\nimport LoadingIndicator from 'mastodon/components/loading_indicator';\n\nconst mapStateToProps = (state, { hashtag }) => ({\n  statusIds: state.getIn(['timelines', `hashtag:${hashtag}`, 'items'], ImmutableList()),\n  isLoading: state.getIn(['timelines', `hashtag:${hashtag}`, 'isLoading'], false),\n  hasMore: state.getIn(['timelines', `hashtag:${hashtag}`, 'hasMore'], false),\n});\n\nexport default @connect(mapStateToProps)\nclass HashtagTimeline extends React.PureComponent {\n\n  static propTypes = {\n    dispatch: PropTypes.func.isRequired,\n    statusIds: ImmutablePropTypes.list.isRequired,\n    isLoading: PropTypes.bool.isRequired,\n    hasMore: PropTypes.bool.isRequired,\n    hashtag: PropTypes.string.isRequired,\n  };\n\n  componentDidMount () {\n    const { dispatch, hashtag } = this.props;\n\n    dispatch(expandHashtagTimeline(hashtag));\n  }\n\n  handleLoadMore = () => {\n    const maxId = this.props.statusIds.last();\n\n    if (maxId) {\n      this.props.dispatch(expandHashtagTimeline(this.props.hashtag, { maxId }));\n    }\n  }\n\n  setRef = c => {\n    this.masonry = c;\n  }\n\n  handleHeightChange = debounce(() => {\n    if (!this.masonry) {\n      return;\n    }\n\n    this.masonry.forcePack();\n  }, 50)\n\n  render () {\n    const { statusIds, hasMore, isLoading } = this.props;\n\n    const sizes = [\n      { columns: 1, gutter: 0 },\n      { mq: '415px', columns: 1, gutter: 10 },\n      { mq: '640px', columns: 2, gutter: 10 },\n      { mq: '960px', columns: 3, gutter: 10 },\n      { mq: '1255px', columns: 3, gutter: 10 },\n    ];\n\n    const loader = (isLoading && statusIds.isEmpty()) ? <LoadingIndicator key={0} /> : undefined;\n\n    return (\n      <Masonry ref={this.setRef} className='statuses-grid' hasMore={hasMore} loadMore={this.handleLoadMore} sizes={sizes} loader={loader}>\n        {statusIds.map(statusId => (\n          <div className='statuses-grid__item' key={statusId}>\n            <DetailedStatusContainer\n              id={statusId}\n              compact\n              measureHeight\n              onHeightChange={this.handleHeightChange}\n            />\n          </div>\n        )).toArray()}\n      </Masonry>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/standalone/public_timeline/index.js",
    "content": "import React from 'react';\nimport { connect } from 'react-redux';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport { expandPublicTimeline, expandCommunityTimeline } from 'mastodon/actions/timelines';\nimport Masonry from 'react-masonry-infinite';\nimport { List as ImmutableList, Map as ImmutableMap } from 'immutable';\nimport DetailedStatusContainer from 'mastodon/features/status/containers/detailed_status_container';\nimport { debounce } from 'lodash';\nimport LoadingIndicator from 'mastodon/components/loading_indicator';\n\nconst mapStateToProps = (state, { local }) => {\n  const timeline = state.getIn(['timelines', local ? 'community' : 'public'], ImmutableMap());\n\n  return {\n    statusIds: timeline.get('items', ImmutableList()),\n    isLoading: timeline.get('isLoading', false),\n    hasMore: timeline.get('hasMore', false),\n  };\n};\n\nexport default @connect(mapStateToProps)\nclass PublicTimeline extends React.PureComponent {\n\n  static propTypes = {\n    dispatch: PropTypes.func.isRequired,\n    statusIds: ImmutablePropTypes.list.isRequired,\n    isLoading: PropTypes.bool.isRequired,\n    hasMore: PropTypes.bool.isRequired,\n    local: PropTypes.bool,\n  };\n\n  componentDidMount () {\n    this._connect();\n  }\n\n  componentDidUpdate (prevProps) {\n    if (prevProps.local !== this.props.local) {\n      this._connect();\n    }\n  }\n\n  _connect () {\n    const { dispatch, local } = this.props;\n\n    dispatch(local ? expandCommunityTimeline() : expandPublicTimeline());\n  }\n\n  handleLoadMore = () => {\n    const { dispatch, statusIds, local } = this.props;\n    const maxId = statusIds.last();\n\n    if (maxId) {\n      dispatch(local ? expandCommunityTimeline({ maxId }) : expandPublicTimeline({ maxId }));\n    }\n  }\n\n  setRef = c => {\n    this.masonry = c;\n  }\n\n  handleHeightChange = debounce(() => {\n    if (!this.masonry) {\n      return;\n    }\n\n    this.masonry.forcePack();\n  }, 50)\n\n  render () {\n    const { statusIds, hasMore, isLoading } = this.props;\n\n    const sizes = [\n      { columns: 1, gutter: 0 },\n      { mq: '415px', columns: 1, gutter: 10 },\n      { mq: '640px', columns: 2, gutter: 10 },\n      { mq: '960px', columns: 3, gutter: 10 },\n      { mq: '1255px', columns: 3, gutter: 10 },\n    ];\n\n    const loader = (isLoading && statusIds.isEmpty()) ? <LoadingIndicator key={0} /> : undefined;\n\n    return (\n      <Masonry ref={this.setRef} className='statuses-grid' hasMore={hasMore} loadMore={this.handleLoadMore} sizes={sizes} loader={loader}>\n        {statusIds.map(statusId => (\n          <div className='statuses-grid__item' key={statusId}>\n            <DetailedStatusContainer\n              id={statusId}\n              compact\n              measureHeight\n              onHeightChange={this.handleHeightChange}\n            />\n          </div>\n        )).toArray()}\n      </Masonry>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/status/components/action_bar.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport IconButton from '../../../components/icon_button';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport DropdownMenuContainer from '../../../containers/dropdown_menu_container';\nimport { defineMessages, injectIntl } from 'react-intl';\nimport { me, isStaff } from '../../../initial_state';\n\nconst messages = defineMessages({\n  delete: { id: 'status.delete', defaultMessage: 'Delete' },\n  redraft: { id: 'status.redraft', defaultMessage: 'Delete & re-draft' },\n  direct: { id: 'status.direct', defaultMessage: 'Direct message @{name}' },\n  mention: { id: 'status.mention', defaultMessage: 'Mention @{name}' },\n  reply: { id: 'status.reply', defaultMessage: 'Reply' },\n  reblog: { id: 'status.reblog', defaultMessage: 'Boost' },\n  reblog_private: { id: 'status.reblog_private', defaultMessage: 'Boost to original audience' },\n  cancel_reblog_private: { id: 'status.cancel_reblog_private', defaultMessage: 'Unboost' },\n  cannot_reblog: { id: 'status.cannot_reblog', defaultMessage: 'This post cannot be boosted' },\n  favourite: { id: 'status.favourite', defaultMessage: 'Favourite' },\n  mute: { id: 'status.mute', defaultMessage: 'Mute @{name}' },\n  muteConversation: { id: 'status.mute_conversation', defaultMessage: 'Mute conversation' },\n  unmuteConversation: { id: 'status.unmute_conversation', defaultMessage: 'Unmute conversation' },\n  block: { id: 'status.block', defaultMessage: 'Block @{name}' },\n  report: { id: 'status.report', defaultMessage: 'Report @{name}' },\n  share: { id: 'status.share', defaultMessage: 'Share' },\n  pin: { id: 'status.pin', defaultMessage: 'Pin on profile' },\n  unpin: { id: 'status.unpin', defaultMessage: 'Unpin from profile' },\n  embed: { id: 'status.embed', defaultMessage: 'Embed' },\n  admin_account: { id: 'status.admin_account', defaultMessage: 'Open moderation interface for @{name}' },\n  admin_status: { id: 'status.admin_status', defaultMessage: 'Open this status in the moderation interface' },\n  copy: { id: 'status.copy', defaultMessage: 'Copy link to status' },\n});\n\nexport default @injectIntl\nclass ActionBar extends React.PureComponent {\n\n  static contextTypes = {\n    router: PropTypes.object,\n  };\n\n  static propTypes = {\n    status: ImmutablePropTypes.map.isRequired,\n    onReply: PropTypes.func.isRequired,\n    onReblog: PropTypes.func.isRequired,\n    onFavourite: PropTypes.func.isRequired,\n    onDelete: PropTypes.func.isRequired,\n    onDirect: PropTypes.func.isRequired,\n    onMention: PropTypes.func.isRequired,\n    onMute: PropTypes.func,\n    onMuteConversation: PropTypes.func,\n    onBlock: PropTypes.func,\n    onReport: PropTypes.func,\n    onPin: PropTypes.func,\n    onEmbed: PropTypes.func,\n    intl: PropTypes.object.isRequired,\n  };\n\n  handleReplyClick = () => {\n    this.props.onReply(this.props.status);\n  }\n\n  handleReblogClick = (e) => {\n    this.props.onReblog(this.props.status, e);\n  }\n\n  handleFavouriteClick = () => {\n    this.props.onFavourite(this.props.status);\n  }\n\n  handleDeleteClick = () => {\n    this.props.onDelete(this.props.status, this.context.router.history);\n  }\n\n  handleRedraftClick = () => {\n    this.props.onDelete(this.props.status, this.context.router.history, true);\n  }\n\n  handleDirectClick = () => {\n    this.props.onDirect(this.props.status.get('account'), this.context.router.history);\n  }\n\n  handleMentionClick = () => {\n    this.props.onMention(this.props.status.get('account'), this.context.router.history);\n  }\n\n  handleMuteClick = () => {\n    this.props.onMute(this.props.status.get('account'));\n  }\n\n  handleConversationMuteClick = () => {\n    this.props.onMuteConversation(this.props.status);\n  }\n\n  handleBlockClick = () => {\n    this.props.onBlock(this.props.status);\n  }\n\n  handleReport = () => {\n    this.props.onReport(this.props.status);\n  }\n\n  handlePinClick = () => {\n    this.props.onPin(this.props.status);\n  }\n\n  handleShare = () => {\n    navigator.share({\n      text: this.props.status.get('search_index'),\n      url: this.props.status.get('url'),\n    });\n  }\n\n  handleEmbed = () => {\n    this.props.onEmbed(this.props.status);\n  }\n\n  handleCopy = () => {\n    const url      = this.props.status.get('url');\n    const textarea = document.createElement('textarea');\n\n    textarea.textContent    = url;\n    textarea.style.position = 'fixed';\n\n    document.body.appendChild(textarea);\n\n    try {\n      textarea.select();\n      document.execCommand('copy');\n    } catch (e) {\n\n    } finally {\n      document.body.removeChild(textarea);\n    }\n  }\n\n  render () {\n    const { status, intl } = this.props;\n\n    const publicStatus = ['public', 'unlisted'].includes(status.get('visibility'));\n    const mutingConversation = status.get('muted');\n\n    let menu = [];\n\n    if (publicStatus) {\n      menu.push({ text: intl.formatMessage(messages.copy), action: this.handleCopy });\n      menu.push({ text: intl.formatMessage(messages.embed), action: this.handleEmbed });\n      menu.push(null);\n    }\n\n    if (me === status.getIn(['account', 'id'])) {\n      if (publicStatus) {\n        menu.push({ text: intl.formatMessage(status.get('pinned') ? messages.unpin : messages.pin), action: this.handlePinClick });\n      } else {\n        if (status.get('visibility') === 'private') {\n          menu.push({ text: intl.formatMessage(status.get('reblogged') ? messages.cancel_reblog_private : messages.reblog_private), action: this.handleReblogClick });\n        }\n      }\n\n      menu.push(null);\n      menu.push({ text: intl.formatMessage(mutingConversation ? messages.unmuteConversation : messages.muteConversation), action: this.handleConversationMuteClick });\n      menu.push(null);\n      menu.push({ text: intl.formatMessage(messages.delete), action: this.handleDeleteClick });\n      menu.push({ text: intl.formatMessage(messages.redraft), action: this.handleRedraftClick });\n    } else {\n      menu.push({ text: intl.formatMessage(messages.mention, { name: status.getIn(['account', 'username']) }), action: this.handleMentionClick });\n      menu.push({ text: intl.formatMessage(messages.direct, { name: status.getIn(['account', 'username']) }), action: this.handleDirectClick });\n      menu.push(null);\n      menu.push({ text: intl.formatMessage(messages.mute, { name: status.getIn(['account', 'username']) }), action: this.handleMuteClick });\n      menu.push({ text: intl.formatMessage(messages.block, { name: status.getIn(['account', 'username']) }), action: this.handleBlockClick });\n      menu.push({ text: intl.formatMessage(messages.report, { name: status.getIn(['account', 'username']) }), action: this.handleReport });\n      if (isStaff) {\n        menu.push(null);\n        menu.push({ text: intl.formatMessage(messages.admin_account, { name: status.getIn(['account', 'username']) }), href: `/admin/accounts/${status.getIn(['account', 'id'])}` });\n        menu.push({ text: intl.formatMessage(messages.admin_status), href: `/admin/accounts/${status.getIn(['account', 'id'])}/statuses/${status.get('id')}` });\n      }\n    }\n\n    const shareButton = ('share' in navigator) && status.get('visibility') === 'public' && (\n      <div className='detailed-status__button'><IconButton title={intl.formatMessage(messages.share)} icon='share-alt' onClick={this.handleShare} /></div>\n    );\n\n    let replyIcon;\n    if (status.get('in_reply_to_id', null) === null) {\n      replyIcon = 'reply';\n    } else {\n      replyIcon = 'reply-all';\n    }\n\n    let reblogIcon = 'retweet';\n    if (status.get('visibility') === 'direct') reblogIcon = 'envelope';\n    else if (status.get('visibility') === 'private') reblogIcon = 'lock';\n\n    let reblog_disabled = (status.get('visibility') === 'direct' || status.get('visibility') === 'private');\n\n    return (\n      <div className='detailed-status__action-bar'>\n        <div className='detailed-status__button'><IconButton title={intl.formatMessage(messages.reply)} icon={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? 'reply' : replyIcon} onClick={this.handleReplyClick} /></div>\n        <div className='detailed-status__button'><IconButton disabled={reblog_disabled} active={status.get('reblogged')} title={reblog_disabled ? intl.formatMessage(messages.cannot_reblog) : intl.formatMessage(messages.reblog)} icon={reblogIcon} onClick={this.handleReblogClick} /></div>\n        <div className='detailed-status__button'><IconButton className='star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} /></div>\n        {shareButton}\n\n        <div className='detailed-status__action-bar-dropdown'>\n          <DropdownMenuContainer size={18} icon='ellipsis-h' items={menu} direction='left' title='More' />\n        </div>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/status/components/card.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport Immutable from 'immutable';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport punycode from 'punycode';\nimport classnames from 'classnames';\nimport Icon from 'mastodon/components/icon';\n\nconst IDNA_PREFIX = 'xn--';\n\nconst decodeIDNA = domain => {\n  return domain\n    .split('.')\n    .map(part => part.indexOf(IDNA_PREFIX) === 0 ? punycode.decode(part.slice(IDNA_PREFIX.length)) : part)\n    .join('.');\n};\n\nconst getHostname = url => {\n  const parser = document.createElement('a');\n  parser.href = url;\n  return parser.hostname;\n};\n\nconst trim = (text, len) => {\n  const cut = text.indexOf(' ', len);\n\n  if (cut === -1) {\n    return text;\n  }\n\n  return text.substring(0, cut) + (text.length > len ? '…' : '');\n};\n\nconst domParser = new DOMParser();\n\nconst addAutoPlay = html => {\n  const document = domParser.parseFromString(html, 'text/html').documentElement;\n  const iframe = document.querySelector('iframe');\n\n  if (iframe) {\n    if (iframe.src.indexOf('?') !== -1) {\n      iframe.src += '&';\n    } else {\n      iframe.src += '?';\n    }\n\n    iframe.src += 'autoplay=1&auto_play=1';\n\n    // DOM parser creates html/body elements around original HTML fragment,\n    // so we need to get innerHTML out of the body and not the entire document\n    return document.querySelector('body').innerHTML;\n  }\n\n  return html;\n};\n\nexport default class Card extends React.PureComponent {\n\n  static propTypes = {\n    card: ImmutablePropTypes.map,\n    maxDescription: PropTypes.number,\n    onOpenMedia: PropTypes.func.isRequired,\n    compact: PropTypes.bool,\n    defaultWidth: PropTypes.number,\n    cacheWidth: PropTypes.func,\n  };\n\n  static defaultProps = {\n    maxDescription: 50,\n    compact: false,\n  };\n\n  state = {\n    width: this.props.defaultWidth || 280,\n    embedded: false,\n  };\n\n  componentWillReceiveProps (nextProps) {\n    if (!Immutable.is(this.props.card, nextProps.card)) {\n      this.setState({ embedded: false });\n    }\n  }\n\n  handlePhotoClick = () => {\n    const { card, onOpenMedia } = this.props;\n\n    onOpenMedia(\n      Immutable.fromJS([\n        {\n          type: 'image',\n          url: card.get('embed_url'),\n          description: card.get('title'),\n          meta: {\n            original: {\n              width: card.get('width'),\n              height: card.get('height'),\n            },\n          },\n        },\n      ]),\n      0\n    );\n  };\n\n  handleEmbedClick = () => {\n    const { card } = this.props;\n\n    if (card.get('type') === 'photo') {\n      this.handlePhotoClick();\n    } else {\n      this.setState({ embedded: true });\n    }\n  }\n\n  setRef = c => {\n    if (c) {\n      if (this.props.cacheWidth) this.props.cacheWidth(c.offsetWidth);\n      this.setState({ width: c.offsetWidth });\n    }\n  }\n\n  renderVideo () {\n    const { card }  = this.props;\n    const content   = { __html: addAutoPlay(card.get('html')) };\n    const { width } = this.state;\n    const ratio     = card.get('width') / card.get('height');\n    const height    = width / ratio;\n\n    return (\n      <div\n        ref={this.setRef}\n        className='status-card__image status-card-video'\n        dangerouslySetInnerHTML={content}\n        style={{ height }}\n      />\n    );\n  }\n\n  render () {\n    const { card, maxDescription, compact } = this.props;\n    const { width, embedded } = this.state;\n\n    if (card === null) {\n      return null;\n    }\n\n    const provider    = card.get('provider_name').length === 0 ? decodeIDNA(getHostname(card.get('url'))) : card.get('provider_name');\n    const horizontal  = (!compact && card.get('width') > card.get('height') && (card.get('width') + 100 >= width)) || card.get('type') !== 'link' || embedded;\n    const interactive = card.get('type') !== 'link';\n    const className   = classnames('status-card', { horizontal, compact, interactive });\n    const title       = interactive ? <a className='status-card__title' href={card.get('url')} title={card.get('title')} rel='noopener' target='_blank'><strong>{card.get('title')}</strong></a> : <strong className='status-card__title' title={card.get('title')}>{card.get('title')}</strong>;\n    const ratio       = card.get('width') / card.get('height');\n    const height      = (compact && !embedded) ? (width / (16 / 9)) : (width / ratio);\n\n    const description = (\n      <div className='status-card__content'>\n        {title}\n        {!(horizontal || compact) && <p className='status-card__description'>{trim(card.get('description') || '', maxDescription)}</p>}\n        <span className='status-card__host'>{provider}</span>\n      </div>\n    );\n\n    let embed     = '';\n    let thumbnail = <div style={{ backgroundImage: `url(${card.get('image')})`, width: horizontal ? width : null, height: horizontal ? height : null }} className='status-card__image-image' />;\n\n    if (interactive) {\n      if (embedded) {\n        embed = this.renderVideo();\n      } else {\n        let iconVariant = 'play';\n\n        if (card.get('type') === 'photo') {\n          iconVariant = 'search-plus';\n        }\n\n        embed = (\n          <div className='status-card__image'>\n            {thumbnail}\n\n            <div className='status-card__actions'>\n              <div>\n                <button onClick={this.handleEmbedClick}><Icon id={iconVariant} /></button>\n                {horizontal && <a href={card.get('url')} target='_blank' rel='noopener'><Icon id='external-link' /></a>}\n              </div>\n            </div>\n          </div>\n        );\n      }\n\n      return (\n        <div className={className} ref={this.setRef}>\n          {embed}\n          {!compact && description}\n        </div>\n      );\n    } else if (card.get('image')) {\n      embed = (\n        <div className='status-card__image'>\n          {thumbnail}\n        </div>\n      );\n    } else {\n      embed = (\n        <div className='status-card__image'>\n          <Icon id='file-text' />\n        </div>\n      );\n    }\n\n    return (\n      <a href={card.get('url')} className={className} target='_blank' rel='noopener' ref={this.setRef}>\n        {embed}\n        {description}\n      </a>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/status/components/detailed_status.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport Avatar from '../../../components/avatar';\nimport DisplayName from '../../../components/display_name';\nimport StatusContent from '../../../components/status_content';\nimport MediaGallery from '../../../components/media_gallery';\nimport { Link } from 'react-router-dom';\nimport { FormattedDate, FormattedNumber } from 'react-intl';\nimport Card from './card';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport Video from '../../video';\nimport scheduleIdleTask from '../../ui/util/schedule_idle_task';\nimport classNames from 'classnames';\nimport Icon from 'mastodon/components/icon';\n\nexport default class DetailedStatus extends ImmutablePureComponent {\n\n  static contextTypes = {\n    router: PropTypes.object,\n  };\n\n  static propTypes = {\n    status: ImmutablePropTypes.map,\n    onOpenMedia: PropTypes.func.isRequired,\n    onOpenVideo: PropTypes.func.isRequired,\n    onToggleHidden: PropTypes.func.isRequired,\n    measureHeight: PropTypes.bool,\n    onHeightChange: PropTypes.func,\n    domain: PropTypes.string.isRequired,\n    compact: PropTypes.bool,\n    showMedia: PropTypes.bool,\n    onToggleMediaVisibility: PropTypes.func,\n  };\n\n  state = {\n    height: null,\n  };\n\n  handleAccountClick = (e) => {\n    if (e.button === 0 && !(e.ctrlKey || e.metaKey) && this.context.router) {\n      e.preventDefault();\n      this.context.router.history.push(`/accounts/${this.props.status.getIn(['account', 'id'])}`);\n    }\n\n    e.stopPropagation();\n  }\n\n  handleOpenVideo = (media, startTime) => {\n    this.props.onOpenVideo(media, startTime);\n  }\n\n  handleExpandedToggle = () => {\n    this.props.onToggleHidden(this.props.status);\n  }\n\n  _measureHeight (heightJustChanged) {\n    if (this.props.measureHeight && this.node) {\n      scheduleIdleTask(() => this.node && this.setState({ height: Math.ceil(this.node.scrollHeight) + 1 }));\n\n      if (this.props.onHeightChange && heightJustChanged) {\n        this.props.onHeightChange();\n      }\n    }\n  }\n\n  setRef = c => {\n    this.node = c;\n    this._measureHeight();\n  }\n\n  componentDidUpdate (prevProps, prevState) {\n    this._measureHeight(prevState.height !== this.state.height);\n  }\n\n  handleModalLink = e => {\n    e.preventDefault();\n\n    let href;\n\n    if (e.target.nodeName !== 'A') {\n      href = e.target.parentNode.href;\n    } else {\n      href = e.target.href;\n    }\n\n    window.open(href, 'mastodon-intent', 'width=445,height=600,resizable=no,menubar=no,status=no,scrollbars=yes');\n  }\n\n  render () {\n    const status = (this.props.status && this.props.status.get('reblog')) ? this.props.status.get('reblog') : this.props.status;\n    const outerStyle = { boxSizing: 'border-box' };\n    const { compact } = this.props;\n\n    if (!status) {\n      return null;\n    }\n\n    let media           = '';\n    let applicationLink = '';\n    let reblogLink = '';\n    let reblogIcon = 'retweet';\n    let favouriteLink = '';\n\n    if (this.props.measureHeight) {\n      outerStyle.height = `${this.state.height}px`;\n    }\n\n    if (status.get('media_attachments').size > 0) {\n      if (status.getIn(['media_attachments', 0, 'type']) === 'video') {\n        const video = status.getIn(['media_attachments', 0]);\n\n        media = (\n          <Video\n            preview={video.get('preview_url')}\n            blurhash={video.get('blurhash')}\n            src={video.get('url')}\n            alt={video.get('description')}\n            width={300}\n            height={150}\n            inline\n            onOpenVideo={this.handleOpenVideo}\n            sensitive={status.get('sensitive')}\n            visible={this.props.showMedia}\n            onToggleVisibility={this.props.onToggleMediaVisibility}\n          />\n        );\n      } else {\n        media = (\n          <MediaGallery\n            standalone\n            sensitive={status.get('sensitive')}\n            media={status.get('media_attachments')}\n            height={300}\n            onOpenMedia={this.props.onOpenMedia}\n            visible={this.props.showMedia}\n            onToggleVisibility={this.props.onToggleMediaVisibility}\n          />\n        );\n      }\n    } else if (status.get('spoiler_text').length === 0) {\n      media = <Card onOpenMedia={this.props.onOpenMedia} card={status.get('card', null)} />;\n    }\n\n    if (status.get('application')) {\n      applicationLink = <span> · <a className='detailed-status__application' href={status.getIn(['application', 'website'])} target='_blank' rel='noopener'>{status.getIn(['application', 'name'])}</a></span>;\n    }\n\n    if (status.get('visibility') === 'direct') {\n      reblogIcon = 'envelope';\n    } else if (status.get('visibility') === 'private') {\n      reblogIcon = 'lock';\n    }\n\n    if (status.get('visibility') === 'private') {\n      reblogLink = <Icon id={reblogIcon} />;\n    } else if (this.context.router) {\n      reblogLink = (\n        <Link to={`/statuses/${status.get('id')}/reblogs`} className='detailed-status__link'>\n          <Icon id={reblogIcon} />\n          <span className='detailed-status__reblogs'>\n            <FormattedNumber value={status.get('reblogs_count')} />\n          </span>\n        </Link>\n      );\n    } else {\n      reblogLink = (\n        <a href={`/interact/${status.get('id')}?type=reblog`} className='detailed-status__link' onClick={this.handleModalLink}>\n          <Icon id={reblogIcon} />\n          <span className='detailed-status__reblogs'>\n            <FormattedNumber value={status.get('reblogs_count')} />\n          </span>\n        </a>\n      );\n    }\n\n    if (this.context.router) {\n      favouriteLink = (\n        <Link to={`/statuses/${status.get('id')}/favourites`} className='detailed-status__link'>\n          <Icon id='star' />\n          <span className='detailed-status__favorites'>\n            <FormattedNumber value={status.get('favourites_count')} />\n          </span>\n        </Link>\n      );\n    } else {\n      favouriteLink = (\n        <a href={`/interact/${status.get('id')}?type=favourite`} className='detailed-status__link' onClick={this.handleModalLink}>\n          <Icon id='star' />\n          <span className='detailed-status__favorites'>\n            <FormattedNumber value={status.get('favourites_count')} />\n          </span>\n        </a>\n      );\n    }\n\n    return (\n      <div style={outerStyle}>\n        <div ref={this.setRef} className={classNames('detailed-status', { compact })}>\n          <a href={status.getIn(['account', 'url'])} onClick={this.handleAccountClick} className='detailed-status__display-name'>\n            <div className='detailed-status__display-avatar'><Avatar account={status.get('account')} size={48} /></div>\n            <DisplayName account={status.get('account')} localDomain={this.props.domain} />\n          </a>\n\n          <StatusContent status={status} expanded={!status.get('hidden')} onExpandedToggle={this.handleExpandedToggle} />\n\n          {media}\n\n          <div className='detailed-status__meta'>\n            <a className='detailed-status__datetime' href={status.get('url')} target='_blank' rel='noopener'>\n              <FormattedDate value={new Date(status.get('created_at'))} hour12={false} year='numeric' month='short' day='2-digit' hour='2-digit' minute='2-digit' />\n            </a>{applicationLink} · {reblogLink} · {favouriteLink}\n          </div>\n        </div>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/status/containers/detailed_status_container.js",
    "content": "import React from 'react';\nimport { connect } from 'react-redux';\nimport DetailedStatus from '../components/detailed_status';\nimport { makeGetStatus } from '../../../selectors';\nimport {\n  replyCompose,\n  mentionCompose,\n  directCompose,\n} from '../../../actions/compose';\nimport {\n  reblog,\n  favourite,\n  unreblog,\n  unfavourite,\n  pin,\n  unpin,\n} from '../../../actions/interactions';\nimport { blockAccount } from '../../../actions/accounts';\nimport {\n  muteStatus,\n  unmuteStatus,\n  deleteStatus,\n  hideStatus,\n  revealStatus,\n} from '../../../actions/statuses';\nimport { initMuteModal } from '../../../actions/mutes';\nimport { initReport } from '../../../actions/reports';\nimport { openModal } from '../../../actions/modal';\nimport { defineMessages, injectIntl, FormattedMessage } from 'react-intl';\nimport { boostModal, deleteModal } from '../../../initial_state';\nimport { showAlertForError } from '../../../actions/alerts';\n\nconst messages = defineMessages({\n  deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' },\n  deleteMessage: { id: 'confirmations.delete.message', defaultMessage: 'Are you sure you want to delete this status?' },\n  redraftConfirm: { id: 'confirmations.redraft.confirm', defaultMessage: 'Delete & redraft' },\n  redraftMessage: { id: 'confirmations.redraft.message', defaultMessage: 'Are you sure you want to delete this status and re-draft it? Favourites and boosts will be lost, and replies to the original post will be orphaned.' },\n  blockConfirm: { id: 'confirmations.block.confirm', defaultMessage: 'Block' },\n  replyConfirm: { id: 'confirmations.reply.confirm', defaultMessage: 'Reply' },\n  replyMessage: { id: 'confirmations.reply.message', defaultMessage: 'Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?' },\n  blockAndReport: { id: 'confirmations.block.block_and_report', defaultMessage: 'Block & Report' },\n});\n\nconst makeMapStateToProps = () => {\n  const getStatus = makeGetStatus();\n\n  const mapStateToProps = (state, props) => ({\n    status: getStatus(state, props),\n    domain: state.getIn(['meta', 'domain']),\n  });\n\n  return mapStateToProps;\n};\n\nconst mapDispatchToProps = (dispatch, { intl }) => ({\n\n  onReply (status, router) {\n    dispatch((_, getState) => {\n      let state = getState();\n      if (state.getIn(['compose', 'text']).trim().length !== 0) {\n        dispatch(openModal('CONFIRM', {\n          message: intl.formatMessage(messages.replyMessage),\n          confirm: intl.formatMessage(messages.replyConfirm),\n          onConfirm: () => dispatch(replyCompose(status, router)),\n        }));\n      } else {\n        dispatch(replyCompose(status, router));\n      }\n    });\n  },\n\n  onModalReblog (status) {\n    dispatch(reblog(status));\n  },\n\n  onReblog (status, e) {\n    if (status.get('reblogged')) {\n      dispatch(unreblog(status));\n    } else {\n      if (e.shiftKey || !boostModal) {\n        this.onModalReblog(status);\n      } else {\n        dispatch(openModal('BOOST', { status, onReblog: this.onModalReblog }));\n      }\n    }\n  },\n\n  onFavourite (status) {\n    if (status.get('favourited')) {\n      dispatch(unfavourite(status));\n    } else {\n      dispatch(favourite(status));\n    }\n  },\n\n  onPin (status) {\n    if (status.get('pinned')) {\n      dispatch(unpin(status));\n    } else {\n      dispatch(pin(status));\n    }\n  },\n\n  onEmbed (status) {\n    dispatch(openModal('EMBED', {\n      url: status.get('url'),\n      onError: error => dispatch(showAlertForError(error)),\n    }));\n  },\n\n  onDelete (status, history, withRedraft = false) {\n    if (!deleteModal) {\n      dispatch(deleteStatus(status.get('id'), history, withRedraft));\n    } else {\n      dispatch(openModal('CONFIRM', {\n        message: intl.formatMessage(withRedraft ? messages.redraftMessage : messages.deleteMessage),\n        confirm: intl.formatMessage(withRedraft ? messages.redraftConfirm : messages.deleteConfirm),\n        onConfirm: () => dispatch(deleteStatus(status.get('id'), history, withRedraft)),\n      }));\n    }\n  },\n\n  onDirect (account, router) {\n    dispatch(directCompose(account, router));\n  },\n\n  onMention (account, router) {\n    dispatch(mentionCompose(account, router));\n  },\n\n  onOpenMedia (media, index) {\n    dispatch(openModal('MEDIA', { media, index }));\n  },\n\n  onOpenVideo (media, time) {\n    dispatch(openModal('VIDEO', { media, time }));\n  },\n\n  onBlock (status) {\n    const account = status.get('account');\n    dispatch(openModal('CONFIRM', {\n      message: <FormattedMessage id='confirmations.block.message' defaultMessage='Are you sure you want to block {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,\n      confirm: intl.formatMessage(messages.blockConfirm),\n      onConfirm: () => dispatch(blockAccount(account.get('id'))),\n      secondary: intl.formatMessage(messages.blockAndReport),\n      onSecondary: () => {\n        dispatch(blockAccount(account.get('id')));\n        dispatch(initReport(account, status));\n      },\n    }));\n  },\n\n  onReport (status) {\n    dispatch(initReport(status.get('account'), status));\n  },\n\n  onMute (account) {\n    dispatch(initMuteModal(account));\n  },\n\n  onMuteConversation (status) {\n    if (status.get('muted')) {\n      dispatch(unmuteStatus(status.get('id')));\n    } else {\n      dispatch(muteStatus(status.get('id')));\n    }\n  },\n\n  onToggleHidden (status) {\n    if (status.get('hidden')) {\n      dispatch(revealStatus(status.get('id')));\n    } else {\n      dispatch(hideStatus(status.get('id')));\n    }\n  },\n\n});\n\nexport default injectIntl(connect(makeMapStateToProps, mapDispatchToProps)(DetailedStatus));\n"
  },
  {
    "path": "app/javascript/mastodon/features/status/index.js",
    "content": "import Immutable from 'immutable';\nimport React from 'react';\nimport { connect } from 'react-redux';\nimport PropTypes from 'prop-types';\nimport classNames from 'classnames';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport { fetchStatus } from '../../actions/statuses';\nimport MissingIndicator from '../../components/missing_indicator';\nimport DetailedStatus from './components/detailed_status';\nimport ActionBar from './components/action_bar';\nimport Column from '../ui/components/column';\nimport {\n  favourite,\n  unfavourite,\n  reblog,\n  unreblog,\n  pin,\n  unpin,\n} from '../../actions/interactions';\nimport {\n  replyCompose,\n  mentionCompose,\n  directCompose,\n} from '../../actions/compose';\nimport { blockAccount } from '../../actions/accounts';\nimport {\n  muteStatus,\n  unmuteStatus,\n  deleteStatus,\n  hideStatus,\n  revealStatus,\n} from '../../actions/statuses';\nimport { initMuteModal } from '../../actions/mutes';\nimport { initReport } from '../../actions/reports';\nimport { makeGetStatus } from '../../selectors';\nimport { ScrollContainer } from 'react-router-scroll-4';\nimport ColumnBackButton from '../../components/column_back_button';\nimport ColumnHeader from '../../components/column_header';\nimport StatusContainer from '../../containers/status_container';\nimport { openModal } from '../../actions/modal';\nimport { defineMessages, injectIntl, FormattedMessage } from 'react-intl';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport { HotKeys } from 'react-hotkeys';\nimport { boostModal, deleteModal } from '../../initial_state';\nimport { attachFullscreenListener, detachFullscreenListener, isFullscreen } from '../ui/util/fullscreen';\nimport { textForScreenReader, defaultMediaVisibility } from '../../components/status';\nimport Icon from 'mastodon/components/icon';\n\nconst messages = defineMessages({\n  deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' },\n  deleteMessage: { id: 'confirmations.delete.message', defaultMessage: 'Are you sure you want to delete this status?' },\n  redraftConfirm: { id: 'confirmations.redraft.confirm', defaultMessage: 'Delete & redraft' },\n  redraftMessage: { id: 'confirmations.redraft.message', defaultMessage: 'Are you sure you want to delete this status and re-draft it? Favourites and boosts will be lost, and replies to the original post will be orphaned.' },\n  blockConfirm: { id: 'confirmations.block.confirm', defaultMessage: 'Block' },\n  revealAll: { id: 'status.show_more_all', defaultMessage: 'Show more for all' },\n  hideAll: { id: 'status.show_less_all', defaultMessage: 'Show less for all' },\n  detailedStatus: { id: 'status.detailed_status', defaultMessage: 'Detailed conversation view' },\n  replyConfirm: { id: 'confirmations.reply.confirm', defaultMessage: 'Reply' },\n  replyMessage: { id: 'confirmations.reply.message', defaultMessage: 'Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?' },\n  blockAndReport: { id: 'confirmations.block.block_and_report', defaultMessage: 'Block & Report' },\n});\n\nconst makeMapStateToProps = () => {\n  const getStatus = makeGetStatus();\n\n  const mapStateToProps = (state, props) => {\n    const status = getStatus(state, { id: props.params.statusId });\n    let ancestorsIds = Immutable.List();\n    let descendantsIds = Immutable.List();\n\n    if (status) {\n      ancestorsIds = ancestorsIds.withMutations(mutable => {\n        let id = status.get('in_reply_to_id');\n\n        while (id) {\n          mutable.unshift(id);\n          id = state.getIn(['contexts', 'inReplyTos', id]);\n        }\n      });\n\n      descendantsIds = descendantsIds.withMutations(mutable => {\n        const ids = [status.get('id')];\n\n        while (ids.length > 0) {\n          let id        = ids.shift();\n          const replies = state.getIn(['contexts', 'replies', id]);\n\n          if (status.get('id') !== id) {\n            mutable.push(id);\n          }\n\n          if (replies) {\n            replies.reverse().forEach(reply => {\n              ids.unshift(reply);\n            });\n          }\n        }\n      });\n    }\n\n    return {\n      status,\n      ancestorsIds,\n      descendantsIds,\n      askReplyConfirmation: state.getIn(['compose', 'text']).trim().length !== 0,\n      domain: state.getIn(['meta', 'domain']),\n    };\n  };\n\n  return mapStateToProps;\n};\n\nexport default @injectIntl\n@connect(makeMapStateToProps)\nclass Status extends ImmutablePureComponent {\n\n  static contextTypes = {\n    router: PropTypes.object,\n  };\n\n  static propTypes = {\n    params: PropTypes.object.isRequired,\n    dispatch: PropTypes.func.isRequired,\n    status: ImmutablePropTypes.map,\n    ancestorsIds: ImmutablePropTypes.list,\n    descendantsIds: ImmutablePropTypes.list,\n    intl: PropTypes.object.isRequired,\n    askReplyConfirmation: PropTypes.bool,\n    domain: PropTypes.string.isRequired,\n  };\n\n  state = {\n    fullscreen: false,\n    showMedia: defaultMediaVisibility(this.props.status),\n    loadedStatusId: undefined,\n  };\n\n  componentWillMount () {\n    this.props.dispatch(fetchStatus(this.props.params.statusId));\n  }\n\n  componentDidMount () {\n    attachFullscreenListener(this.onFullScreenChange);\n  }\n\n  componentWillReceiveProps (nextProps) {\n    if (nextProps.params.statusId !== this.props.params.statusId && nextProps.params.statusId) {\n      this._scrolledIntoView = false;\n      this.props.dispatch(fetchStatus(nextProps.params.statusId));\n    }\n\n    if (nextProps.status && nextProps.status.get('id') !== this.state.loadedStatusId) {\n      this.setState({ showMedia: defaultMediaVisibility(nextProps.status), loadedStatusId: nextProps.status.get('id') });\n    }\n  }\n\n  handleToggleMediaVisibility = () => {\n    this.setState({ showMedia: !this.state.showMedia });\n  }\n\n  handleFavouriteClick = (status) => {\n    if (status.get('favourited')) {\n      this.props.dispatch(unfavourite(status));\n    } else {\n      this.props.dispatch(favourite(status));\n    }\n  }\n\n  handlePin = (status) => {\n    if (status.get('pinned')) {\n      this.props.dispatch(unpin(status));\n    } else {\n      this.props.dispatch(pin(status));\n    }\n  }\n\n  handleReplyClick = (status) => {\n    let { askReplyConfirmation, dispatch, intl } = this.props;\n    if (askReplyConfirmation) {\n      dispatch(openModal('CONFIRM', {\n        message: intl.formatMessage(messages.replyMessage),\n        confirm: intl.formatMessage(messages.replyConfirm),\n        onConfirm: () => dispatch(replyCompose(status, this.context.router.history)),\n      }));\n    } else {\n      dispatch(replyCompose(status, this.context.router.history));\n    }\n  }\n\n  handleModalReblog = (status) => {\n    this.props.dispatch(reblog(status));\n  }\n\n  handleReblogClick = (status, e) => {\n    if (status.get('reblogged')) {\n      this.props.dispatch(unreblog(status));\n    } else {\n      if ((e && e.shiftKey) || !boostModal) {\n        this.handleModalReblog(status);\n      } else {\n        this.props.dispatch(openModal('BOOST', { status, onReblog: this.handleModalReblog }));\n      }\n    }\n  }\n\n  handleDeleteClick = (status, history, withRedraft = false) => {\n    const { dispatch, intl } = this.props;\n\n    if (!deleteModal) {\n      dispatch(deleteStatus(status.get('id'), history, withRedraft));\n    } else {\n      dispatch(openModal('CONFIRM', {\n        message: intl.formatMessage(withRedraft ? messages.redraftMessage : messages.deleteMessage),\n        confirm: intl.formatMessage(withRedraft ? messages.redraftConfirm : messages.deleteConfirm),\n        onConfirm: () => dispatch(deleteStatus(status.get('id'), history, withRedraft)),\n      }));\n    }\n  }\n\n  handleDirectClick = (account, router) => {\n    this.props.dispatch(directCompose(account, router));\n  }\n\n  handleMentionClick = (account, router) => {\n    this.props.dispatch(mentionCompose(account, router));\n  }\n\n  handleOpenMedia = (media, index) => {\n    this.props.dispatch(openModal('MEDIA', { media, index }));\n  }\n\n  handleOpenVideo = (media, time) => {\n    this.props.dispatch(openModal('VIDEO', { media, time }));\n  }\n\n  handleMuteClick = (account) => {\n    this.props.dispatch(initMuteModal(account));\n  }\n\n  handleConversationMuteClick = (status) => {\n    if (status.get('muted')) {\n      this.props.dispatch(unmuteStatus(status.get('id')));\n    } else {\n      this.props.dispatch(muteStatus(status.get('id')));\n    }\n  }\n\n  handleToggleHidden = (status) => {\n    if (status.get('hidden')) {\n      this.props.dispatch(revealStatus(status.get('id')));\n    } else {\n      this.props.dispatch(hideStatus(status.get('id')));\n    }\n  }\n\n  handleToggleAll = () => {\n    const { status, ancestorsIds, descendantsIds } = this.props;\n    const statusIds = [status.get('id')].concat(ancestorsIds.toJS(), descendantsIds.toJS());\n\n    if (status.get('hidden')) {\n      this.props.dispatch(revealStatus(statusIds));\n    } else {\n      this.props.dispatch(hideStatus(statusIds));\n    }\n  }\n\n  handleBlockClick = (status) => {\n    const { dispatch, intl } = this.props;\n    const account = status.get('account');\n\n    dispatch(openModal('CONFIRM', {\n      message: <FormattedMessage id='confirmations.block.message' defaultMessage='Are you sure you want to block {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,\n      confirm: intl.formatMessage(messages.blockConfirm),\n      onConfirm: () => dispatch(blockAccount(account.get('id'))),\n      secondary: intl.formatMessage(messages.blockAndReport),\n      onSecondary: () => {\n        dispatch(blockAccount(account.get('id')));\n        dispatch(initReport(account, status));\n      },\n    }));\n  }\n\n  handleReport = (status) => {\n    this.props.dispatch(initReport(status.get('account'), status));\n  }\n\n  handleEmbed = (status) => {\n    this.props.dispatch(openModal('EMBED', { url: status.get('url') }));\n  }\n\n  handleHotkeyMoveUp = () => {\n    this.handleMoveUp(this.props.status.get('id'));\n  }\n\n  handleHotkeyMoveDown = () => {\n    this.handleMoveDown(this.props.status.get('id'));\n  }\n\n  handleHotkeyReply = e => {\n    e.preventDefault();\n    this.handleReplyClick(this.props.status);\n  }\n\n  handleHotkeyFavourite = () => {\n    this.handleFavouriteClick(this.props.status);\n  }\n\n  handleHotkeyBoost = () => {\n    this.handleReblogClick(this.props.status);\n  }\n\n  handleHotkeyMention = e => {\n    e.preventDefault();\n    this.handleMentionClick(this.props.status.get('account'));\n  }\n\n  handleHotkeyOpenProfile = () => {\n    this.context.router.history.push(`/accounts/${this.props.status.getIn(['account', 'id'])}`);\n  }\n\n  handleHotkeyToggleHidden = () => {\n    this.handleToggleHidden(this.props.status);\n  }\n\n  handleHotkeyToggleSensitive = () => {\n    this.handleToggleMediaVisibility();\n  }\n\n  handleMoveUp = id => {\n    const { status, ancestorsIds, descendantsIds } = this.props;\n\n    if (id === status.get('id')) {\n      this._selectChild(ancestorsIds.size - 1, true);\n    } else {\n      let index = ancestorsIds.indexOf(id);\n\n      if (index === -1) {\n        index = descendantsIds.indexOf(id);\n        this._selectChild(ancestorsIds.size + index, true);\n      } else {\n        this._selectChild(index - 1, true);\n      }\n    }\n  }\n\n  handleMoveDown = id => {\n    const { status, ancestorsIds, descendantsIds } = this.props;\n\n    if (id === status.get('id')) {\n      this._selectChild(ancestorsIds.size + 1, false);\n    } else {\n      let index = ancestorsIds.indexOf(id);\n\n      if (index === -1) {\n        index = descendantsIds.indexOf(id);\n        this._selectChild(ancestorsIds.size + index + 2, false);\n      } else {\n        this._selectChild(index + 1, false);\n      }\n    }\n  }\n\n  _selectChild (index, align_top) {\n    const container = this.node;\n    const element = container.querySelectorAll('.focusable')[index];\n\n    if (element) {\n      if (align_top && container.scrollTop > element.offsetTop) {\n        element.scrollIntoView(true);\n      } else if (!align_top && container.scrollTop + container.clientHeight < element.offsetTop + element.offsetHeight) {\n        element.scrollIntoView(false);\n      }\n      element.focus();\n    }\n  }\n\n  renderChildren (list) {\n    return list.map(id => (\n      <StatusContainer\n        key={id}\n        id={id}\n        onMoveUp={this.handleMoveUp}\n        onMoveDown={this.handleMoveDown}\n        contextType='thread'\n      />\n    ));\n  }\n\n  setRef = c => {\n    this.node = c;\n  }\n\n  componentDidUpdate () {\n    if (this._scrolledIntoView) {\n      return;\n    }\n\n    const { status, ancestorsIds } = this.props;\n\n    if (status && ancestorsIds && ancestorsIds.size > 0) {\n      const element = this.node.querySelectorAll('.focusable')[ancestorsIds.size - 1];\n\n      window.requestAnimationFrame(() => {\n        element.scrollIntoView(true);\n      });\n      this._scrolledIntoView = true;\n    }\n  }\n\n  componentWillUnmount () {\n    detachFullscreenListener(this.onFullScreenChange);\n  }\n\n  onFullScreenChange = () => {\n    this.setState({ fullscreen: isFullscreen() });\n  }\n\n  render () {\n    let ancestors, descendants;\n    const { shouldUpdateScroll, status, ancestorsIds, descendantsIds, intl, domain } = this.props;\n    const { fullscreen } = this.state;\n\n    if (status === null) {\n      return (\n        <Column>\n          <ColumnBackButton />\n          <MissingIndicator />\n        </Column>\n      );\n    }\n\n    if (ancestorsIds && ancestorsIds.size > 0) {\n      ancestors = <div>{this.renderChildren(ancestorsIds)}</div>;\n    }\n\n    if (descendantsIds && descendantsIds.size > 0) {\n      descendants = <div>{this.renderChildren(descendantsIds)}</div>;\n    }\n\n    const handlers = {\n      moveUp: this.handleHotkeyMoveUp,\n      moveDown: this.handleHotkeyMoveDown,\n      reply: this.handleHotkeyReply,\n      favourite: this.handleHotkeyFavourite,\n      boost: this.handleHotkeyBoost,\n      mention: this.handleHotkeyMention,\n      openProfile: this.handleHotkeyOpenProfile,\n      toggleHidden: this.handleHotkeyToggleHidden,\n      toggleSensitive: this.handleHotkeyToggleSensitive,\n    };\n\n    return (\n      <Column label={intl.formatMessage(messages.detailedStatus)}>\n        <ColumnHeader\n          showBackButton\n          extraButton={(\n            <button className='column-header__button' title={intl.formatMessage(status.get('hidden') ? messages.revealAll : messages.hideAll)} aria-label={intl.formatMessage(status.get('hidden') ? messages.revealAll : messages.hideAll)} onClick={this.handleToggleAll} aria-pressed={status.get('hidden') ? 'false' : 'true'}><Icon id={status.get('hidden') ? 'eye-slash' : 'eye'} /></button>\n          )}\n        />\n\n        <ScrollContainer scrollKey='thread' shouldUpdateScroll={shouldUpdateScroll}>\n          <div className={classNames('scrollable', { fullscreen })} ref={this.setRef}>\n            {ancestors}\n\n            <HotKeys handlers={handlers}>\n              <div className={classNames('focusable', 'detailed-status__wrapper')} tabIndex='0' aria-label={textForScreenReader(intl, status, false)}>\n                <DetailedStatus\n                  status={status}\n                  onOpenVideo={this.handleOpenVideo}\n                  onOpenMedia={this.handleOpenMedia}\n                  onToggleHidden={this.handleToggleHidden}\n                  domain={domain}\n                  showMedia={this.state.showMedia}\n                  onToggleMediaVisibility={this.handleToggleMediaVisibility}\n                />\n\n                <ActionBar\n                  status={status}\n                  onReply={this.handleReplyClick}\n                  onFavourite={this.handleFavouriteClick}\n                  onReblog={this.handleReblogClick}\n                  onDelete={this.handleDeleteClick}\n                  onDirect={this.handleDirectClick}\n                  onMention={this.handleMentionClick}\n                  onMute={this.handleMuteClick}\n                  onMuteConversation={this.handleConversationMuteClick}\n                  onBlock={this.handleBlockClick}\n                  onReport={this.handleReport}\n                  onPin={this.handlePin}\n                  onEmbed={this.handleEmbed}\n                />\n              </div>\n            </HotKeys>\n\n            {descendants}\n          </div>\n        </ScrollContainer>\n      </Column>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/components/__tests__/column-test.js",
    "content": "import React from 'react';\nimport { mount } from 'enzyme';\nimport Column from '../column';\nimport ColumnHeader from '../column_header';\n\ndescribe('<Column />', () => {\n  describe('<ColumnHeader /> click handler', () => {\n    const originalRaf = global.requestAnimationFrame;\n\n    beforeEach(() => {\n      global.requestAnimationFrame = jest.fn();\n    });\n\n    afterAll(() => {\n      global.requestAnimationFrame = originalRaf;\n    });\n\n    it('runs the scroll animation if the column contains scrollable content', () => {\n      const wrapper = mount(\n        <Column heading='notifications'>\n          <div className='scrollable' />\n        </Column>\n      );\n      wrapper.find(ColumnHeader).find('button').simulate('click');\n      expect(global.requestAnimationFrame.mock.calls.length).toEqual(1);\n    });\n\n    it('does not try to scroll if there is no scrollable content', () => {\n      const wrapper = mount(<Column heading='notifications' />);\n      wrapper.find(ColumnHeader).find('button').simulate('click');\n      expect(global.requestAnimationFrame.mock.calls.length).toEqual(0);\n    });\n  });\n});\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/components/actions_modal.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport StatusContent from '../../../components/status_content';\nimport Avatar from '../../../components/avatar';\nimport RelativeTimestamp from '../../../components/relative_timestamp';\nimport DisplayName from '../../../components/display_name';\nimport IconButton from '../../../components/icon_button';\nimport classNames from 'classnames';\n\nexport default class ActionsModal extends ImmutablePureComponent {\n\n  static propTypes = {\n    status: ImmutablePropTypes.map,\n    actions: PropTypes.array,\n    onClick: PropTypes.func,\n  };\n\n  renderAction = (action, i) => {\n    if (action === null) {\n      return <li key={`sep-${i}`} className='dropdown-menu__separator' />;\n    }\n\n    const { icon = null, text, meta = null, active = false, href = '#' } = action;\n\n    return (\n      <li key={`${text}-${i}`}>\n        <a href={href} target='_blank' rel='noopener' onClick={this.props.onClick} data-index={i} className={classNames({ active })}>\n          {icon && <IconButton title={text} icon={icon} role='presentation' tabIndex='-1' inverted />}\n          <div>\n            <div className={classNames({ 'actions-modal__item-label': !!meta })}>{text}</div>\n            <div>{meta}</div>\n          </div>\n        </a>\n      </li>\n    );\n  }\n\n  render () {\n    const status = this.props.status && (\n      <div className='status light'>\n        <div className='boost-modal__status-header'>\n          <div className='boost-modal__status-time'>\n            <a href={this.props.status.get('url')} className='status__relative-time' target='_blank' rel='noopener'>\n              <RelativeTimestamp timestamp={this.props.status.get('created_at')} />\n            </a>\n          </div>\n\n          <a href={this.props.status.getIn(['account', 'url'])} className='status__display-name'>\n            <div className='status__avatar'>\n              <Avatar account={this.props.status.get('account')} size={48} />\n            </div>\n\n            <DisplayName account={this.props.status.get('account')} />\n          </a>\n        </div>\n\n        <StatusContent status={this.props.status} />\n      </div>\n    );\n\n    return (\n      <div className='modal-root__modal actions-modal'>\n        {status}\n\n        <ul className={classNames({ 'with-status': !!status })}>\n          {this.props.actions.map(this.renderAction)}\n        </ul>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/components/boost_modal.js",
    "content": "import React from 'react';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport PropTypes from 'prop-types';\nimport { defineMessages, injectIntl, FormattedMessage } from 'react-intl';\nimport Button from '../../../components/button';\nimport StatusContent from '../../../components/status_content';\nimport Avatar from '../../../components/avatar';\nimport RelativeTimestamp from '../../../components/relative_timestamp';\nimport DisplayName from '../../../components/display_name';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport Icon from 'mastodon/components/icon';\nimport AttachmentList from 'mastodon/components/attachment_list';\n\nconst messages = defineMessages({\n  cancel_reblog: { id: 'status.cancel_reblog_private', defaultMessage: 'Unboost' },\n  reblog: { id: 'status.reblog', defaultMessage: 'Boost' },\n});\n\nexport default @injectIntl\nclass BoostModal extends ImmutablePureComponent {\n\n  static contextTypes = {\n    router: PropTypes.object,\n  };\n\n  static propTypes = {\n    status: ImmutablePropTypes.map.isRequired,\n    onReblog: PropTypes.func.isRequired,\n    onClose: PropTypes.func.isRequired,\n    intl: PropTypes.object.isRequired,\n  };\n\n  componentDidMount() {\n    this.button.focus();\n  }\n\n  handleReblog = () => {\n    this.props.onReblog(this.props.status);\n    this.props.onClose();\n  }\n\n  handleAccountClick = (e) => {\n    if (e.button === 0 && !(e.ctrlKey || e.metaKey)) {\n      e.preventDefault();\n      this.props.onClose();\n      this.context.router.history.push(`/accounts/${this.props.status.getIn(['account', 'id'])}`);\n    }\n  }\n\n  setRef = (c) => {\n    this.button = c;\n  }\n\n  render () {\n    const { status, intl } = this.props;\n    const buttonText = status.get('reblogged') ? messages.cancel_reblog : messages.reblog;\n\n    return (\n      <div className='modal-root__modal boost-modal'>\n        <div className='boost-modal__container'>\n          <div className='status light'>\n            <div className='boost-modal__status-header'>\n              <div className='boost-modal__status-time'>\n                <a href={status.get('url')} className='status__relative-time' target='_blank' rel='noopener'><RelativeTimestamp timestamp={status.get('created_at')} /></a>\n              </div>\n\n              <a onClick={this.handleAccountClick} href={status.getIn(['account', 'url'])} className='status__display-name'>\n                <div className='status__avatar'>\n                  <Avatar account={status.get('account')} size={48} />\n                </div>\n\n                <DisplayName account={status.get('account')} />\n              </a>\n            </div>\n\n            <StatusContent status={status} />\n\n            {status.get('media_attachments').size > 0 && (\n              <AttachmentList\n                compact\n                media={status.get('media_attachments')}\n              />\n            )}\n          </div>\n        </div>\n\n        <div className='boost-modal__action-bar'>\n          <div><FormattedMessage id='boost_modal.combo' defaultMessage='You can press {combo} to skip this next time' values={{ combo: <span>Shift + <Icon id='retweet' /></span> }} /></div>\n          <Button text={intl.formatMessage(buttonText)} onClick={this.handleReblog} ref={this.setRef} />\n        </div>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/components/bundle.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\n\nconst emptyComponent = () => null;\nconst noop = () => { };\n\nclass Bundle extends React.PureComponent {\n\n  static propTypes = {\n    fetchComponent: PropTypes.func.isRequired,\n    loading: PropTypes.func,\n    error: PropTypes.func,\n    children: PropTypes.func.isRequired,\n    renderDelay: PropTypes.number,\n    onFetch: PropTypes.func,\n    onFetchSuccess: PropTypes.func,\n    onFetchFail: PropTypes.func,\n  }\n\n  static defaultProps = {\n    loading: emptyComponent,\n    error: emptyComponent,\n    renderDelay: 0,\n    onFetch: noop,\n    onFetchSuccess: noop,\n    onFetchFail: noop,\n  }\n\n  static cache = new Map\n\n  state = {\n    mod: undefined,\n    forceRender: false,\n  }\n\n  componentWillMount() {\n    this.load(this.props);\n  }\n\n  componentWillReceiveProps(nextProps) {\n    if (nextProps.fetchComponent !== this.props.fetchComponent) {\n      this.load(nextProps);\n    }\n  }\n\n  componentWillUnmount () {\n    if (this.timeout) {\n      clearTimeout(this.timeout);\n    }\n  }\n\n  load = (props) => {\n    const { fetchComponent, onFetch, onFetchSuccess, onFetchFail, renderDelay } = props || this.props;\n    const cachedMod = Bundle.cache.get(fetchComponent);\n\n    if (fetchComponent === undefined) {\n      this.setState({ mod: null });\n      return Promise.resolve();\n    }\n\n    onFetch();\n\n    if (cachedMod) {\n      this.setState({ mod: cachedMod.default });\n      onFetchSuccess();\n      return Promise.resolve();\n    }\n\n    this.setState({ mod: undefined });\n\n    if (renderDelay !== 0) {\n      this.timestamp = new Date();\n      this.timeout = setTimeout(() => this.setState({ forceRender: true }), renderDelay);\n    }\n\n    return fetchComponent()\n      .then((mod) => {\n        Bundle.cache.set(fetchComponent, mod);\n        this.setState({ mod: mod.default });\n        onFetchSuccess();\n      })\n      .catch((error) => {\n        this.setState({ mod: null });\n        onFetchFail(error);\n      });\n  }\n\n  render() {\n    const { loading: Loading, error: Error, children, renderDelay } = this.props;\n    const { mod, forceRender } = this.state;\n    const elapsed = this.timestamp ? (new Date() - this.timestamp) : renderDelay;\n\n    if (mod === undefined) {\n      return (elapsed >= renderDelay || forceRender) ? <Loading /> : null;\n    }\n\n    if (mod === null) {\n      return <Error onRetry={this.load} />;\n    }\n\n    return children(mod);\n  }\n\n}\n\nexport default Bundle;\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/components/bundle_column_error.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport { defineMessages, injectIntl } from 'react-intl';\n\nimport Column from './column';\nimport ColumnHeader from './column_header';\nimport ColumnBackButtonSlim from '../../../components/column_back_button_slim';\nimport IconButton from '../../../components/icon_button';\n\nconst messages = defineMessages({\n  title: { id: 'bundle_column_error.title', defaultMessage: 'Network error' },\n  body: { id: 'bundle_column_error.body', defaultMessage: 'Something went wrong while loading this component.' },\n  retry: { id: 'bundle_column_error.retry', defaultMessage: 'Try again' },\n});\n\nclass BundleColumnError extends React.PureComponent {\n\n  static propTypes = {\n    onRetry: PropTypes.func.isRequired,\n    intl: PropTypes.object.isRequired,\n  }\n\n  handleRetry = () => {\n    this.props.onRetry();\n  }\n\n  render () {\n    const { intl: { formatMessage } } = this.props;\n\n    return (\n      <Column>\n        <ColumnHeader icon='exclamation-circle' type={formatMessage(messages.title)} />\n        <ColumnBackButtonSlim />\n        <div className='error-column'>\n          <IconButton title={formatMessage(messages.retry)} icon='refresh' onClick={this.handleRetry} size={64} />\n          {formatMessage(messages.body)}\n        </div>\n      </Column>\n    );\n  }\n\n}\n\nexport default injectIntl(BundleColumnError);\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/components/bundle_modal_error.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport { defineMessages, injectIntl } from 'react-intl';\n\nimport IconButton from '../../../components/icon_button';\n\nconst messages = defineMessages({\n  error: { id: 'bundle_modal_error.message', defaultMessage: 'Something went wrong while loading this component.' },\n  retry: { id: 'bundle_modal_error.retry', defaultMessage: 'Try again' },\n  close: { id: 'bundle_modal_error.close', defaultMessage: 'Close' },\n});\n\nclass BundleModalError extends React.PureComponent {\n\n  static propTypes = {\n    onRetry: PropTypes.func.isRequired,\n    onClose: PropTypes.func.isRequired,\n    intl: PropTypes.object.isRequired,\n  }\n\n  handleRetry = () => {\n    this.props.onRetry();\n  }\n\n  render () {\n    const { onClose, intl: { formatMessage } } = this.props;\n\n    // Keep the markup in sync with <ModalLoading />\n    // (make sure they have the same dimensions)\n    return (\n      <div className='modal-root__modal error-modal'>\n        <div className='error-modal__body'>\n          <IconButton title={formatMessage(messages.retry)} icon='refresh' onClick={this.handleRetry} size={64} />\n          {formatMessage(messages.error)}\n        </div>\n\n        <div className='error-modal__footer'>\n          <div>\n            <button\n              onClick={onClose}\n              className='error-modal__nav onboarding-modal__skip'\n            >\n              {formatMessage(messages.close)}\n            </button>\n          </div>\n        </div>\n      </div>\n    );\n  }\n\n}\n\nexport default injectIntl(BundleModalError);\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/components/column.js",
    "content": "import React from 'react';\nimport ColumnHeader from './column_header';\nimport PropTypes from 'prop-types';\nimport { debounce } from 'lodash';\nimport { scrollTop } from '../../../scroll';\nimport { isMobile } from '../../../is_mobile';\n\nexport default class Column extends React.PureComponent {\n\n  static propTypes = {\n    heading: PropTypes.string,\n    icon: PropTypes.string,\n    children: PropTypes.node,\n    active: PropTypes.bool,\n    hideHeadingOnMobile: PropTypes.bool,\n  };\n\n  handleHeaderClick = () => {\n    const scrollable = this.node.querySelector('.scrollable');\n\n    if (!scrollable) {\n      return;\n    }\n\n    this._interruptScrollAnimation = scrollTop(scrollable);\n  }\n\n  scrollTop () {\n    const scrollable = this.node.querySelector('.scrollable');\n\n    if (!scrollable) {\n      return;\n    }\n\n    this._interruptScrollAnimation = scrollTop(scrollable);\n  }\n\n\n  handleScroll = debounce(() => {\n    if (typeof this._interruptScrollAnimation !== 'undefined') {\n      this._interruptScrollAnimation();\n    }\n  }, 200)\n\n  setRef = (c) => {\n    this.node = c;\n  }\n\n  render () {\n    const { heading, icon, children, active, hideHeadingOnMobile } = this.props;\n\n    const showHeading = heading && (!hideHeadingOnMobile || (hideHeadingOnMobile && !isMobile(window.innerWidth)));\n\n    const columnHeaderId = showHeading && heading.replace(/ /g, '-');\n    const header = showHeading && (\n      <ColumnHeader icon={icon} active={active} type={heading} onClick={this.handleHeaderClick} columnHeaderId={columnHeaderId} />\n    );\n    return (\n      <div\n        ref={this.setRef}\n        role='region'\n        aria-labelledby={columnHeaderId}\n        className='column'\n        onScroll={this.handleScroll}\n      >\n        {header}\n        {children}\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/components/column_header.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport classNames from 'classnames';\nimport Icon from 'mastodon/components/icon';\n\nexport default class ColumnHeader extends React.PureComponent {\n\n  static propTypes = {\n    icon: PropTypes.string,\n    type: PropTypes.string,\n    active: PropTypes.bool,\n    onClick: PropTypes.func,\n    columnHeaderId: PropTypes.string,\n  };\n\n  handleClick = () => {\n    this.props.onClick();\n  }\n\n  render () {\n    const { icon, type, active, columnHeaderId } = this.props;\n    let iconElement = '';\n\n    if (icon) {\n      iconElement = <Icon id={icon} fixedWidth className='column-header__icon' />;\n    }\n\n    return (\n      <h1 className={classNames('column-header', { active })} id={columnHeaderId || null}>\n        <button onClick={this.handleClick}>\n          {iconElement}\n          {type}\n        </button>\n      </h1>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/components/column_link.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport { Link } from 'react-router-dom';\nimport Icon from 'mastodon/components/icon';\n\nconst ColumnLink = ({ icon, text, to, href, method, badge }) => {\n  const badgeElement = typeof badge !== 'undefined' ? <span className='column-link__badge'>{badge}</span> : null;\n\n  if (href) {\n    return (\n      <a href={href} className='column-link' data-method={method}>\n        <Icon id={icon} fixedWidth className='column-link__icon' />\n        {text}\n        {badgeElement}\n      </a>\n    );\n  } else {\n    return (\n      <Link to={to} className='column-link'>\n        <Icon id={icon} fixedWidth className='column-link__icon' />\n        {text}\n        {badgeElement}\n      </Link>\n    );\n  }\n};\n\nColumnLink.propTypes = {\n  icon: PropTypes.string.isRequired,\n  text: PropTypes.string.isRequired,\n  to: PropTypes.string,\n  href: PropTypes.string,\n  method: PropTypes.string,\n  badge: PropTypes.node,\n};\n\nexport default ColumnLink;\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/components/column_loading.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\n\nimport Column from '../../../components/column';\nimport ColumnHeader from '../../../components/column_header';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\n\nexport default class ColumnLoading extends ImmutablePureComponent {\n\n  static propTypes = {\n    title: PropTypes.oneOfType([PropTypes.node, PropTypes.string]),\n    icon: PropTypes.string,\n  };\n\n  static defaultProps = {\n    title: '',\n    icon: '',\n  };\n\n  render() {\n    let { title, icon } = this.props;\n    return (\n      <Column>\n        <ColumnHeader icon={icon} title={title} multiColumn={false} focusable={false} />\n        <div className='scrollable' />\n      </Column>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/components/column_subheading.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\n\nconst ColumnSubheading = ({ text }) => {\n  return (\n    <div className='column-subheading'>\n      {text}\n    </div>\n  );\n};\n\nColumnSubheading.propTypes = {\n  text: PropTypes.string.isRequired,\n};\n\nexport default ColumnSubheading;\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/components/columns_area.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport { defineMessages, injectIntl } from 'react-intl';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\n\nimport ReactSwipeableViews from 'react-swipeable-views';\nimport TabsBar, { links, getIndex, getLink } from './tabs_bar';\nimport { Link } from 'react-router-dom';\n\nimport BundleContainer from '../containers/bundle_container';\nimport ColumnLoading from './column_loading';\nimport DrawerLoading from './drawer_loading';\nimport BundleColumnError from './bundle_column_error';\nimport { Compose, Notifications, HomeTimeline, CommunityTimeline, PublicTimeline, HashtagTimeline, DirectTimeline, FavouritedStatuses, ListTimeline } from '../../ui/util/async-components';\nimport Icon from 'mastodon/components/icon';\nimport ComposePanel from './compose_panel';\nimport NavigationPanel from './navigation_panel';\n\nimport detectPassiveEvents from 'detect-passive-events';\nimport { scrollRight } from '../../../scroll';\n\nconst componentMap = {\n  'COMPOSE': Compose,\n  'HOME': HomeTimeline,\n  'NOTIFICATIONS': Notifications,\n  'PUBLIC': PublicTimeline,\n  'COMMUNITY': CommunityTimeline,\n  'HASHTAG': HashtagTimeline,\n  'DIRECT': DirectTimeline,\n  'FAVOURITES': FavouritedStatuses,\n  'LIST': ListTimeline,\n};\n\nconst messages = defineMessages({\n  publish: { id: 'compose_form.publish', defaultMessage: 'Toot' },\n});\n\nconst shouldHideFAB = path => path.match(/^\\/statuses\\/|^\\/search|^\\/getting-started/);\n\nexport default @(component => injectIntl(component, { withRef: true }))\nclass ColumnsArea extends ImmutablePureComponent {\n\n  static contextTypes = {\n    router: PropTypes.object.isRequired,\n  };\n\n  static propTypes = {\n    intl: PropTypes.object.isRequired,\n    columns: ImmutablePropTypes.list.isRequired,\n    isModalOpen: PropTypes.bool.isRequired,\n    singleColumn: PropTypes.bool,\n    children: PropTypes.node,\n  };\n\n  state = {\n    shouldAnimate: false,\n  }\n\n  componentWillReceiveProps() {\n    this.setState({ shouldAnimate: false });\n  }\n\n  componentDidMount() {\n    if (!this.props.singleColumn) {\n      this.node.addEventListener('wheel', this.handleWheel,  detectPassiveEvents.hasSupport ? { passive: true } : false);\n    }\n\n    this.lastIndex   = getIndex(this.context.router.history.location.pathname);\n    this.isRtlLayout = document.getElementsByTagName('body')[0].classList.contains('rtl');\n\n    this.setState({ shouldAnimate: true });\n  }\n\n  componentWillUpdate(nextProps) {\n    if (this.props.singleColumn !== nextProps.singleColumn && nextProps.singleColumn) {\n      this.node.removeEventListener('wheel', this.handleWheel);\n    }\n  }\n\n  componentDidUpdate(prevProps) {\n    if (this.props.singleColumn !== prevProps.singleColumn && !this.props.singleColumn) {\n      this.node.addEventListener('wheel', this.handleWheel,  detectPassiveEvents.hasSupport ? { passive: true } : false);\n    }\n    this.lastIndex = getIndex(this.context.router.history.location.pathname);\n    this.setState({ shouldAnimate: true });\n  }\n\n  componentWillUnmount () {\n    if (!this.props.singleColumn) {\n      this.node.removeEventListener('wheel', this.handleWheel);\n    }\n  }\n\n  handleChildrenContentChange() {\n    if (!this.props.singleColumn) {\n      const modifier = this.isRtlLayout ? -1 : 1;\n      this._interruptScrollAnimation = scrollRight(this.node, (this.node.scrollWidth - window.innerWidth) * modifier);\n    }\n  }\n\n  handleSwipe = (index) => {\n    this.pendingIndex = index;\n\n    const nextLinkTranslationId = links[index].props['data-preview-title-id'];\n    const currentLinkSelector = '.tabs-bar__link.active';\n    const nextLinkSelector = `.tabs-bar__link[data-preview-title-id=\"${nextLinkTranslationId}\"]`;\n\n    // HACK: Remove the active class from the current link and set it to the next one\n    // React-router does this for us, but too late, feeling laggy.\n    document.querySelector(currentLinkSelector).classList.remove('active');\n    document.querySelector(nextLinkSelector).classList.add('active');\n  }\n\n  handleAnimationEnd = () => {\n    if (typeof this.pendingIndex === 'number') {\n      this.context.router.history.push(getLink(this.pendingIndex));\n      this.pendingIndex = null;\n    }\n  }\n\n  handleWheel = () => {\n    if (typeof this._interruptScrollAnimation !== 'function') {\n      return;\n    }\n\n    this._interruptScrollAnimation();\n  }\n\n  setRef = (node) => {\n    this.node = node;\n  }\n\n  renderView = (link, index) => {\n    const columnIndex = getIndex(this.context.router.history.location.pathname);\n    const title = this.props.intl.formatMessage({ id: link.props['data-preview-title-id'] });\n    const icon = link.props['data-preview-icon'];\n\n    const view = (index === columnIndex) ?\n      React.cloneElement(this.props.children) :\n      <ColumnLoading title={title} icon={icon} />;\n\n    return (\n      <div className='columns-area columns-area--mobile' key={index}>\n        {view}\n      </div>\n    );\n  }\n\n  renderLoading = columnId => () => {\n    return columnId === 'COMPOSE' ? <DrawerLoading /> : <ColumnLoading />;\n  }\n\n  renderError = (props) => {\n    return <BundleColumnError {...props} />;\n  }\n\n  render () {\n    const { columns, children, singleColumn, isModalOpen, intl } = this.props;\n    const { shouldAnimate } = this.state;\n\n    const columnIndex = getIndex(this.context.router.history.location.pathname);\n    this.pendingIndex = null;\n\n    if (singleColumn) {\n      const floatingActionButton = shouldHideFAB(this.context.router.history.location.pathname) ? null : <Link key='floating-action-button' to='/statuses/new' className='floating-action-button' aria-label={intl.formatMessage(messages.publish)}><Icon id='pencil' /></Link>;\n\n      const content = columnIndex !== -1 ? (\n        <ReactSwipeableViews key='content' index={columnIndex} onChangeIndex={this.handleSwipe} onTransitionEnd={this.handleAnimationEnd} animateTransitions={shouldAnimate} springConfig={{ duration: '400ms', delay: '0s', easeFunction: 'ease' }} style={{ height: '100%' }}>\n          {links.map(this.renderView)}\n        </ReactSwipeableViews>\n      ) : (\n        <div key='content' className='columns-area columns-area--mobile'>{children}</div>\n      );\n\n      return (\n        <div className='columns-area__panels'>\n          <div className='columns-area__panels__pane columns-area__panels__pane--compositional'>\n            <div className='columns-area__panels__pane__inner'>\n              <ComposePanel />\n            </div>\n          </div>\n\n          <div className='columns-area__panels__main'>\n            <TabsBar key='tabs' />\n            {content}\n          </div>\n\n          <div className='columns-area__panels__pane columns-area__panels__pane--start columns-area__panels__pane--navigational'>\n            <div className='columns-area__panels__pane__inner'>\n              <NavigationPanel />\n            </div>\n          </div>\n\n          {floatingActionButton}\n        </div>\n      );\n    }\n\n    return (\n      <div className={`columns-area ${ isModalOpen ? 'unscrollable' : '' }`} ref={this.setRef}>\n        {columns.map(column => {\n          const params = column.get('params', null) === null ? null : column.get('params').toJS();\n          const other  = params && params.other ? params.other : {};\n\n          return (\n            <BundleContainer key={column.get('uuid')} fetchComponent={componentMap[column.get('id')]} loading={this.renderLoading(column.get('id'))} error={this.renderError}>\n              {SpecificComponent => <SpecificComponent columnId={column.get('uuid')} params={params} multiColumn {...other} />}\n            </BundleContainer>\n          );\n        })}\n\n        {React.Children.map(children, child => React.cloneElement(child, { multiColumn: true }))}\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/components/compose_panel.js",
    "content": "import React from 'react';\nimport SearchContainer from 'mastodon/features/compose/containers/search_container';\nimport ComposeFormContainer from 'mastodon/features/compose/containers/compose_form_container';\nimport NavigationContainer from 'mastodon/features/compose/containers/navigation_container';\nimport LinkFooter from './link_footer';\n\nconst ComposePanel = () => (\n  <div className='compose-panel'>\n    <SearchContainer openInRoute />\n    <NavigationContainer />\n    <ComposeFormContainer singleColumn />\n    <LinkFooter withHotkeys />\n  </div>\n);\n\nexport default ComposePanel;\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/components/confirmation_modal.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport { injectIntl, FormattedMessage } from 'react-intl';\nimport Button from '../../../components/button';\n\nexport default @injectIntl\nclass ConfirmationModal extends React.PureComponent {\n\n  static propTypes = {\n    message: PropTypes.node.isRequired,\n    confirm: PropTypes.string.isRequired,\n    onClose: PropTypes.func.isRequired,\n    onConfirm: PropTypes.func.isRequired,\n    secondary: PropTypes.string,\n    onSecondary: PropTypes.func,\n    intl: PropTypes.object.isRequired,\n  };\n\n  componentDidMount() {\n    this.button.focus();\n  }\n\n  handleClick = () => {\n    this.props.onClose();\n    this.props.onConfirm();\n  }\n\n  handleSecondary = () => {\n    this.props.onClose();\n    this.props.onSecondary();\n  }\n\n  handleCancel = () => {\n    this.props.onClose();\n  }\n\n  setRef = (c) => {\n    this.button = c;\n  }\n\n  render () {\n    const { message, confirm, secondary } = this.props;\n\n    return (\n      <div className='modal-root__modal confirmation-modal'>\n        <div className='confirmation-modal__container'>\n          {message}\n        </div>\n\n        <div className='confirmation-modal__action-bar'>\n          <Button onClick={this.handleCancel} className='confirmation-modal__cancel-button'>\n            <FormattedMessage id='confirmation_modal.cancel' defaultMessage='Cancel' />\n          </Button>\n          {secondary !== undefined && (\n            <Button text={secondary} onClick={this.handleSecondary} className='confirmation-modal__secondary-button' />\n          )}\n          <Button text={confirm} onClick={this.handleClick} ref={this.setRef} />\n        </div>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/components/drawer_loading.js",
    "content": "import React from 'react';\n\nconst DrawerLoading = () => (\n  <div className='drawer'>\n    <div className='drawer__pager'>\n      <div className='drawer__inner' />\n    </div>\n  </div>\n);\n\nexport default DrawerLoading;\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/components/embed_modal.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport { FormattedMessage, injectIntl } from 'react-intl';\nimport api from '../../../api';\n\nexport default @injectIntl\nclass EmbedModal extends ImmutablePureComponent {\n\n  static propTypes = {\n    url: PropTypes.string.isRequired,\n    onClose: PropTypes.func.isRequired,\n    onError: PropTypes.func.isRequired,\n    intl: PropTypes.object.isRequired,\n  }\n\n  state = {\n    loading: false,\n    oembed: null,\n  };\n\n  componentDidMount () {\n    const { url } = this.props;\n\n    this.setState({ loading: true });\n\n    api().post('/api/web/embed', { url }).then(res => {\n      this.setState({ loading: false, oembed: res.data });\n\n      const iframeDocument = this.iframe.contentWindow.document;\n\n      iframeDocument.open();\n      iframeDocument.write(res.data.html);\n      iframeDocument.close();\n\n      iframeDocument.body.style.margin = 0;\n      this.iframe.width  = iframeDocument.body.scrollWidth;\n      this.iframe.height = iframeDocument.body.scrollHeight;\n    }).catch(error => {\n      this.props.onError(error);\n    });\n  }\n\n  setIframeRef = c =>  {\n    this.iframe = c;\n  }\n\n  handleTextareaClick = (e) => {\n    e.target.select();\n  }\n\n  render () {\n    const { oembed } = this.state;\n\n    return (\n      <div className='modal-root__modal embed-modal'>\n        <h4><FormattedMessage id='status.embed' defaultMessage='Embed' /></h4>\n\n        <div className='embed-modal__container'>\n          <p className='hint'>\n            <FormattedMessage id='embed.instructions' defaultMessage='Embed this status on your website by copying the code below.' />\n          </p>\n\n          <input\n            type='text'\n            className='embed-modal__html'\n            readOnly\n            value={oembed && oembed.html || ''}\n            onClick={this.handleTextareaClick}\n          />\n\n          <p className='hint'>\n            <FormattedMessage id='embed.preview' defaultMessage='Here is what it will look like:' />\n          </p>\n\n          <iframe\n            className='embed-modal__iframe'\n            frameBorder='0'\n            ref={this.setIframeRef}\n            sandbox='allow-same-origin'\n            title='preview'\n          />\n        </div>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/components/focal_point_modal.js",
    "content": "import React from 'react';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport { connect } from 'react-redux';\nimport ImageLoader from './image_loader';\nimport classNames from 'classnames';\nimport { changeUploadCompose } from '../../../actions/compose';\nimport { getPointerPosition } from '../../video';\n\nconst mapStateToProps = (state, { id }) => ({\n  media: state.getIn(['compose', 'media_attachments']).find(item => item.get('id') === id),\n});\n\nconst mapDispatchToProps = (dispatch, { id }) => ({\n\n  onSave: (x, y) => {\n    dispatch(changeUploadCompose(id, { focus: `${x.toFixed(2)},${y.toFixed(2)}` }));\n  },\n\n});\n\nexport default @connect(mapStateToProps, mapDispatchToProps)\nclass FocalPointModal extends ImmutablePureComponent {\n\n  static propTypes = {\n    media: ImmutablePropTypes.map.isRequired,\n  };\n\n  state = {\n    x: 0,\n    y: 0,\n    focusX: 0,\n    focusY: 0,\n    dragging: false,\n  };\n\n  componentWillMount () {\n    this.updatePositionFromMedia(this.props.media);\n  }\n\n  componentWillReceiveProps (nextProps) {\n    if (this.props.media.get('id') !== nextProps.media.get('id')) {\n      this.updatePositionFromMedia(nextProps.media);\n    }\n  }\n\n  componentWillUnmount () {\n    document.removeEventListener('mousemove', this.handleMouseMove);\n    document.removeEventListener('mouseup', this.handleMouseUp);\n  }\n\n  handleMouseDown = e => {\n    document.addEventListener('mousemove', this.handleMouseMove);\n    document.addEventListener('mouseup', this.handleMouseUp);\n\n    this.updatePosition(e);\n    this.setState({ dragging: true });\n  }\n\n  handleMouseMove = e => {\n    this.updatePosition(e);\n  }\n\n  handleMouseUp = () => {\n    document.removeEventListener('mousemove', this.handleMouseMove);\n    document.removeEventListener('mouseup', this.handleMouseUp);\n\n    this.setState({ dragging: false });\n    this.props.onSave(this.state.focusX, this.state.focusY);\n  }\n\n  updatePosition = e => {\n    const { x, y } = getPointerPosition(this.node, e);\n    const focusX   = (x - .5) *  2;\n    const focusY   = (y - .5) * -2;\n\n    this.setState({ x, y, focusX, focusY });\n  }\n\n  updatePositionFromMedia = media => {\n    const focusX = media.getIn(['meta', 'focus', 'x']);\n    const focusY = media.getIn(['meta', 'focus', 'y']);\n\n    if (focusX && focusY) {\n      const x = (focusX /  2) + .5;\n      const y = (focusY / -2) + .5;\n\n      this.setState({ x, y, focusX, focusY });\n    } else {\n      this.setState({ x: 0.5, y: 0.5, focusX: 0, focusY: 0 });\n    }\n  }\n\n  setRef = c => {\n    this.node = c;\n  }\n\n  render () {\n    const { media } = this.props;\n    const { x, y, dragging } = this.state;\n\n    const width  = media.getIn(['meta', 'original', 'width']) || null;\n    const height = media.getIn(['meta', 'original', 'height']) || null;\n\n    return (\n      <div className='modal-root__modal video-modal focal-point-modal'>\n        <div className={classNames('focal-point', { dragging })} ref={this.setRef}>\n          <ImageLoader\n            previewSrc={media.get('preview_url')}\n            src={media.get('url')}\n            width={width}\n            height={height}\n          />\n\n          <div className='focal-point__reticle' style={{ top: `${y * 100}%`, left: `${x * 100}%` }} />\n          <div className='focal-point__overlay' onMouseDown={this.handleMouseDown} />\n        </div>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/components/follow_requests_nav_link.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport { fetchFollowRequests } from 'mastodon/actions/accounts';\nimport { connect } from 'react-redux';\nimport { NavLink, withRouter } from 'react-router-dom';\nimport IconWithBadge from 'mastodon/components/icon_with_badge';\nimport { me } from 'mastodon/initial_state';\nimport { List as ImmutableList } from 'immutable';\nimport { FormattedMessage } from 'react-intl';\n\nconst mapStateToProps = state => ({\n  locked: state.getIn(['accounts', me, 'locked']),\n  count: state.getIn(['user_lists', 'follow_requests', 'items'], ImmutableList()).size,\n});\n\nexport default @withRouter\n@connect(mapStateToProps)\nclass FollowRequestsNavLink extends React.Component {\n\n  static propTypes = {\n    dispatch: PropTypes.func.isRequired,\n    locked: PropTypes.bool,\n    count: PropTypes.number.isRequired,\n  };\n\n  componentDidMount () {\n    const { dispatch, locked } = this.props;\n\n    if (locked) {\n      dispatch(fetchFollowRequests());\n    }\n  }\n\n  render () {\n    const { locked, count } = this.props;\n\n    if (!locked || count === 0) {\n      return null;\n    }\n\n    return <NavLink className='column-link column-link--transparent' to='/follow_requests'><IconWithBadge className='column-link__icon' id='user-plus' count={count} /><FormattedMessage id='navigation_bar.follow_requests' defaultMessage='Follow requests' /></NavLink>;\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/components/image_loader.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport classNames from 'classnames';\nimport { LoadingBar } from 'react-redux-loading-bar';\nimport ZoomableImage from './zoomable_image';\n\nexport default class ImageLoader extends React.PureComponent {\n\n  static propTypes = {\n    alt: PropTypes.string,\n    src: PropTypes.string.isRequired,\n    previewSrc: PropTypes.string,\n    width: PropTypes.number,\n    height: PropTypes.number,\n    onClick: PropTypes.func,\n  }\n\n  static defaultProps = {\n    alt: '',\n    width: null,\n    height: null,\n  };\n\n  state = {\n    loading: true,\n    error: false,\n    width: null,\n  }\n\n  removers = [];\n  canvas = null;\n\n  get canvasContext() {\n    if (!this.canvas) {\n      return null;\n    }\n    this._canvasContext = this._canvasContext || this.canvas.getContext('2d');\n    return this._canvasContext;\n  }\n\n  componentDidMount () {\n    this.loadImage(this.props);\n  }\n\n  componentWillReceiveProps (nextProps) {\n    if (this.props.src !== nextProps.src) {\n      this.loadImage(nextProps);\n    }\n  }\n\n  componentWillUnmount () {\n    this.removeEventListeners();\n  }\n\n  loadImage (props) {\n    this.removeEventListeners();\n    this.setState({ loading: true, error: false });\n    Promise.all([\n      props.previewSrc && this.loadPreviewCanvas(props),\n      this.hasSize() && this.loadOriginalImage(props),\n    ].filter(Boolean))\n      .then(() => {\n        this.setState({ loading: false, error: false });\n        this.clearPreviewCanvas();\n      })\n      .catch(() => this.setState({ loading: false, error: true }));\n  }\n\n  loadPreviewCanvas = ({ previewSrc, width, height }) => new Promise((resolve, reject) => {\n    const image = new Image();\n    const removeEventListeners = () => {\n      image.removeEventListener('error', handleError);\n      image.removeEventListener('load', handleLoad);\n    };\n    const handleError = () => {\n      removeEventListeners();\n      reject();\n    };\n    const handleLoad = () => {\n      removeEventListeners();\n      this.canvasContext.drawImage(image, 0, 0, width, height);\n      resolve();\n    };\n    image.addEventListener('error', handleError);\n    image.addEventListener('load', handleLoad);\n    image.src = previewSrc;\n    this.removers.push(removeEventListeners);\n  })\n\n  clearPreviewCanvas () {\n    const { width, height } = this.canvas;\n    this.canvasContext.clearRect(0, 0, width, height);\n  }\n\n  loadOriginalImage = ({ src }) => new Promise((resolve, reject) => {\n    const image = new Image();\n    const removeEventListeners = () => {\n      image.removeEventListener('error', handleError);\n      image.removeEventListener('load', handleLoad);\n    };\n    const handleError = () => {\n      removeEventListeners();\n      reject();\n    };\n    const handleLoad = () => {\n      removeEventListeners();\n      resolve();\n    };\n    image.addEventListener('error', handleError);\n    image.addEventListener('load', handleLoad);\n    image.src = src;\n    this.removers.push(removeEventListeners);\n  });\n\n  removeEventListeners () {\n    this.removers.forEach(listeners => listeners());\n    this.removers = [];\n  }\n\n  hasSize () {\n    const { width, height } = this.props;\n    return typeof width === 'number' && typeof height === 'number';\n  }\n\n  setCanvasRef = c => {\n    this.canvas = c;\n    if (c) this.setState({ width: c.offsetWidth });\n  }\n\n  render () {\n    const { alt, src, width, height, onClick } = this.props;\n    const { loading } = this.state;\n\n    const className = classNames('image-loader', {\n      'image-loader--loading': loading,\n      'image-loader--amorphous': !this.hasSize(),\n    });\n\n    return (\n      <div className={className}>\n        <LoadingBar loading={loading ? 1 : 0} className='loading-bar' style={{ width: this.state.width || width }} />\n        {loading ? (\n          <canvas\n            className='image-loader__preview-canvas'\n            ref={this.setCanvasRef}\n            width={width}\n            height={height}\n          />\n        ) : (\n          <ZoomableImage\n            alt={alt}\n            src={src}\n            onClick={onClick}\n          />\n        )}\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/components/link_footer.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport { FormattedMessage } from 'react-intl';\nimport { Link } from 'react-router-dom';\nimport { invitesEnabled, version, repository, source_url } from 'mastodon/initial_state';\n\nconst LinkFooter = ({ withHotkeys }) => (\n  <div className='getting-started__footer'>\n    <ul>\n      {invitesEnabled && <li><a href='/invites' target='_blank'><FormattedMessage id='getting_started.invite' defaultMessage='Invite people' /></a> · </li>}\n      {withHotkeys && <li><Link to='/keyboard-shortcuts'><FormattedMessage id='navigation_bar.keyboard_shortcuts' defaultMessage='Hotkeys' /></Link> · </li>}\n      <li><a href='/auth/edit'><FormattedMessage id='getting_started.security' defaultMessage='Security' /></a> · </li>\n      <li><a href='/about/more' target='_blank'><FormattedMessage id='navigation_bar.info' defaultMessage='About this server' /></a> · </li>\n      <li><a href='https://joinmastodon.org/apps' target='_blank'><FormattedMessage id='navigation_bar.apps' defaultMessage='Mobile apps' /></a> · </li>\n      <li><a href='/terms' target='_blank'><FormattedMessage id='getting_started.terms' defaultMessage='Terms of service' /></a> · </li>\n      <li><a href='/settings/applications' target='_blank'><FormattedMessage id='getting_started.developers' defaultMessage='Developers' /></a> · </li>\n      <li><a href='https://docs.joinmastodon.org' target='_blank'><FormattedMessage id='getting_started.documentation' defaultMessage='Documentation' /></a> · </li>\n      <li><a href='/auth/sign_out' data-method='delete'><FormattedMessage id='navigation_bar.logout' defaultMessage='Logout' /></a></li>\n    </ul>\n\n    <p>\n      <FormattedMessage\n        id='getting_started.open_source_notice'\n        defaultMessage='Mastodon is open source software. You can contribute or report issues on GitHub at {github}.'\n        values={{ github: <span><a href={source_url} rel='noopener' target='_blank'>{repository}</a> (v{version})</span> }}\n      />\n    </p>\n  </div>\n);\n\nLinkFooter.propTypes = {\n  withHotkeys: PropTypes.bool,\n};\n\nexport default LinkFooter;\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/components/list_panel.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport { fetchLists } from 'mastodon/actions/lists';\nimport { connect } from 'react-redux';\nimport { createSelector } from 'reselect';\nimport { NavLink, withRouter } from 'react-router-dom';\nimport Icon from 'mastodon/components/icon';\n\nconst getOrderedLists = createSelector([state => state.get('lists')], lists => {\n  if (!lists) {\n    return lists;\n  }\n\n  return lists.toList().filter(item => !!item).sort((a, b) => a.get('title').localeCompare(b.get('title'))).take(4);\n});\n\nconst mapStateToProps = state => ({\n  lists: getOrderedLists(state),\n});\n\nexport default @withRouter\n@connect(mapStateToProps)\nclass ListPanel extends ImmutablePureComponent {\n\n  static propTypes = {\n    dispatch: PropTypes.func.isRequired,\n    lists: ImmutablePropTypes.list,\n  };\n\n  componentDidMount () {\n    const { dispatch } = this.props;\n    dispatch(fetchLists());\n  }\n\n  render () {\n    const { lists } = this.props;\n\n    if (!lists || lists.isEmpty()) {\n      return null;\n    }\n\n    return (\n      <div>\n        <hr />\n\n        {lists.map(list => (\n          <NavLink key={list.get('id')} className='column-link column-link--transparent' strict to={`/timelines/list/${list.get('id')}`}><Icon className='column-link__icon' id='list-ul' fixedWidth />{list.get('title')}</NavLink>\n        ))}\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/components/media_modal.js",
    "content": "import React from 'react';\nimport ReactSwipeableViews from 'react-swipeable-views';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport PropTypes from 'prop-types';\nimport Video from 'mastodon/features/video';\nimport ExtendedVideoPlayer from 'mastodon/components/extended_video_player';\nimport classNames from 'classnames';\nimport { defineMessages, injectIntl, FormattedMessage } from 'react-intl';\nimport IconButton from 'mastodon/components/icon_button';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport ImageLoader from './image_loader';\nimport Icon from 'mastodon/components/icon';\n\nconst messages = defineMessages({\n  close: { id: 'lightbox.close', defaultMessage: 'Close' },\n  previous: { id: 'lightbox.previous', defaultMessage: 'Previous' },\n  next: { id: 'lightbox.next', defaultMessage: 'Next' },\n});\n\nexport const previewState = 'previewMediaModal';\n\nexport default @injectIntl\nclass MediaModal extends ImmutablePureComponent {\n\n  static propTypes = {\n    media: ImmutablePropTypes.list.isRequired,\n    status: ImmutablePropTypes.map,\n    index: PropTypes.number.isRequired,\n    onClose: PropTypes.func.isRequired,\n    intl: PropTypes.object.isRequired,\n  };\n\n  static contextTypes = {\n    router: PropTypes.object,\n  };\n\n  state = {\n    index: null,\n    navigationHidden: false,\n  };\n\n  handleSwipe = (index) => {\n    this.setState({ index: index % this.props.media.size });\n  }\n\n  handleNextClick = () => {\n    this.setState({ index: (this.getIndex() + 1) % this.props.media.size });\n  }\n\n  handlePrevClick = () => {\n    this.setState({ index: (this.props.media.size + this.getIndex() - 1) % this.props.media.size });\n  }\n\n  handleChangeIndex = (e) => {\n    const index = Number(e.currentTarget.getAttribute('data-index'));\n    this.setState({ index: index % this.props.media.size });\n  }\n\n  handleKeyDown = (e) => {\n    switch(e.key) {\n    case 'ArrowLeft':\n      this.handlePrevClick();\n      e.preventDefault();\n      e.stopPropagation();\n      break;\n    case 'ArrowRight':\n      this.handleNextClick();\n      e.preventDefault();\n      e.stopPropagation();\n      break;\n    }\n  }\n\n  componentDidMount () {\n    window.addEventListener('keydown', this.handleKeyDown, false);\n\n    if (this.context.router) {\n      const history = this.context.router.history;\n\n      history.push(history.location.pathname, previewState);\n\n      this.unlistenHistory = history.listen(() => {\n        this.props.onClose();\n      });\n    }\n  }\n\n  componentWillUnmount () {\n    window.removeEventListener('keydown', this.handleKeyDown);\n\n    if (this.context.router) {\n      this.unlistenHistory();\n\n      if (this.context.router.history.location.state === previewState) {\n        this.context.router.history.goBack();\n      }\n    }\n  }\n\n  getIndex () {\n    return this.state.index !== null ? this.state.index : this.props.index;\n  }\n\n  toggleNavigation = () => {\n    this.setState(prevState => ({\n      navigationHidden: !prevState.navigationHidden,\n    }));\n  };\n\n  handleStatusClick = e => {\n    if (e.button === 0 && !(e.ctrlKey || e.metaKey)) {\n      e.preventDefault();\n      this.context.router.history.push(`/statuses/${this.props.status.get('id')}`);\n    }\n  }\n\n  render () {\n    const { media, status, intl, onClose } = this.props;\n    const { navigationHidden } = this.state;\n\n    const index = this.getIndex();\n    let pagination = [];\n\n    const leftNav  = media.size > 1 && <button tabIndex='0' className='media-modal__nav media-modal__nav--left' onClick={this.handlePrevClick} aria-label={intl.formatMessage(messages.previous)}><Icon id='chevron-left' fixedWidth /></button>;\n    const rightNav = media.size > 1 && <button tabIndex='0' className='media-modal__nav  media-modal__nav--right' onClick={this.handleNextClick} aria-label={intl.formatMessage(messages.next)}><Icon id='chevron-right' fixedWidth /></button>;\n\n    if (media.size > 1) {\n      pagination = media.map((item, i) => {\n        const classes = ['media-modal__button'];\n        if (i === index) {\n          classes.push('media-modal__button--active');\n        }\n        return (<li className='media-modal__page-dot' key={i}><button tabIndex='0' className={classes.join(' ')} onClick={this.handleChangeIndex} data-index={i}>{i + 1}</button></li>);\n      });\n    }\n\n    const content = media.map((image) => {\n      const width  = image.getIn(['meta', 'original', 'width']) || null;\n      const height = image.getIn(['meta', 'original', 'height']) || null;\n\n      if (image.get('type') === 'image') {\n        return (\n          <ImageLoader\n            previewSrc={image.get('preview_url')}\n            src={image.get('url')}\n            width={width}\n            height={height}\n            alt={image.get('description')}\n            key={image.get('url')}\n            onClick={this.toggleNavigation}\n          />\n        );\n      } else if (image.get('type') === 'video') {\n        const { time } = this.props;\n\n        return (\n          <Video\n            preview={image.get('preview_url')}\n            blurhash={image.get('blurhash')}\n            src={image.get('url')}\n            width={image.get('width')}\n            height={image.get('height')}\n            startTime={time || 0}\n            onCloseVideo={onClose}\n            detailed\n            alt={image.get('description')}\n            key={image.get('url')}\n          />\n        );\n      } else if (image.get('type') === 'gifv') {\n        return (\n          <ExtendedVideoPlayer\n            src={image.get('url')}\n            muted\n            controls={false}\n            width={width}\n            height={height}\n            key={image.get('preview_url')}\n            alt={image.get('description')}\n            onClick={this.toggleNavigation}\n          />\n        );\n      }\n\n      return null;\n    }).toArray();\n\n    // you can't use 100vh, because the viewport height is taller\n    // than the visible part of the document in some mobile\n    // browsers when it's address bar is visible.\n    // https://developers.google.com/web/updates/2016/12/url-bar-resizing\n    const swipeableViewsStyle = {\n      width: '100%',\n      height: '100%',\n    };\n\n    const containerStyle = {\n      alignItems: 'center', // center vertically\n    };\n\n    const navigationClassName = classNames('media-modal__navigation', {\n      'media-modal__navigation--hidden': navigationHidden,\n    });\n\n    return (\n      <div className='modal-root__modal media-modal'>\n        <div\n          className='media-modal__closer'\n          role='presentation'\n          onClick={onClose}\n        >\n          <ReactSwipeableViews\n            style={swipeableViewsStyle}\n            containerStyle={containerStyle}\n            onChangeIndex={this.handleSwipe}\n            onSwitching={this.handleSwitching}\n            index={index}\n          >\n            {content}\n          </ReactSwipeableViews>\n        </div>\n\n        <div className={navigationClassName}>\n          <IconButton className='media-modal__close' title={intl.formatMessage(messages.close)} icon='times' onClick={onClose} size={40} />\n\n          {leftNav}\n          {rightNav}\n\n          {status && (\n            <div className={classNames('media-modal__meta', { 'media-modal__meta--shifted': media.size > 1 })}>\n              <a href={status.get('url')} onClick={this.handleStatusClick}><FormattedMessage id='lightbox.view_context' defaultMessage='View context' /></a>\n            </div>\n          )}\n\n          <ul className='media-modal__pagination'>\n            {pagination}\n          </ul>\n        </div>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/components/modal_loading.js",
    "content": "import React from 'react';\n\nimport LoadingIndicator from '../../../components/loading_indicator';\n\n// Keep the markup in sync with <BundleModalError />\n// (make sure they have the same dimensions)\nconst ModalLoading = () => (\n  <div className='modal-root__modal error-modal'>\n    <div className='error-modal__body'>\n      <LoadingIndicator />\n    </div>\n    <div className='error-modal__footer'>\n      <div>\n        <button className='error-modal__nav onboarding-modal__skip' />\n      </div>\n    </div>\n  </div>\n);\n\nexport default ModalLoading;\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/components/modal_root.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport Base from '../../../components/modal_root';\nimport BundleContainer from '../containers/bundle_container';\nimport BundleModalError from './bundle_modal_error';\nimport ModalLoading from './modal_loading';\nimport ActionsModal from './actions_modal';\nimport MediaModal from './media_modal';\nimport VideoModal from './video_modal';\nimport BoostModal from './boost_modal';\nimport ConfirmationModal from './confirmation_modal';\nimport FocalPointModal from './focal_point_modal';\nimport {\n  MuteModal,\n  ReportModal,\n  EmbedModal,\n  ListEditor,\n  ListAdder,\n} from '../../../features/ui/util/async-components';\n\nconst MODAL_COMPONENTS = {\n  'MEDIA': () => Promise.resolve({ default: MediaModal }),\n  'VIDEO': () => Promise.resolve({ default: VideoModal }),\n  'BOOST': () => Promise.resolve({ default: BoostModal }),\n  'CONFIRM': () => Promise.resolve({ default: ConfirmationModal }),\n  'MUTE': MuteModal,\n  'REPORT': ReportModal,\n  'ACTIONS': () => Promise.resolve({ default: ActionsModal }),\n  'EMBED': EmbedModal,\n  'LIST_EDITOR': ListEditor,\n  'FOCAL_POINT': () => Promise.resolve({ default: FocalPointModal }),\n  'LIST_ADDER':ListAdder,\n};\n\nexport default class ModalRoot extends React.PureComponent {\n\n  static propTypes = {\n    type: PropTypes.string,\n    props: PropTypes.object,\n    onClose: PropTypes.func.isRequired,\n  };\n\n  getSnapshotBeforeUpdate () {\n    return { visible: !!this.props.type };\n  }\n\n  componentDidUpdate (prevProps, prevState, { visible }) {\n    if (visible) {\n      document.body.classList.add('with-modals--active');\n    } else {\n      document.body.classList.remove('with-modals--active');\n    }\n  }\n\n  renderLoading = modalId => () => {\n    return ['MEDIA', 'VIDEO', 'BOOST', 'CONFIRM', 'ACTIONS'].indexOf(modalId) === -1 ? <ModalLoading /> : null;\n  }\n\n  renderError = (props) => {\n    const { onClose } = this.props;\n\n    return <BundleModalError {...props} onClose={onClose} />;\n  }\n\n  render () {\n    const { type, props, onClose } = this.props;\n    const visible = !!type;\n\n    return (\n      <Base onClose={onClose}>\n        {visible && (\n          <BundleContainer fetchComponent={MODAL_COMPONENTS[type]} loading={this.renderLoading(type)} error={this.renderError} renderDelay={200}>\n            {(SpecificComponent) => <SpecificComponent {...props} onClose={onClose} />}\n          </BundleContainer>\n        )}\n      </Base>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/components/mute_modal.js",
    "content": "import React from 'react';\nimport { connect } from 'react-redux';\nimport PropTypes from 'prop-types';\nimport { injectIntl, FormattedMessage } from 'react-intl';\nimport Toggle from 'react-toggle';\nimport Button from '../../../components/button';\nimport { closeModal } from '../../../actions/modal';\nimport { muteAccount } from '../../../actions/accounts';\nimport { toggleHideNotifications } from '../../../actions/mutes';\n\n\nconst mapStateToProps = state => {\n  return {\n    isSubmitting: state.getIn(['reports', 'new', 'isSubmitting']),\n    account: state.getIn(['mutes', 'new', 'account']),\n    notifications: state.getIn(['mutes', 'new', 'notifications']),\n  };\n};\n\nconst mapDispatchToProps = dispatch => {\n  return {\n    onConfirm(account, notifications) {\n      dispatch(muteAccount(account.get('id'), notifications));\n    },\n\n    onClose() {\n      dispatch(closeModal());\n    },\n\n    onToggleNotifications() {\n      dispatch(toggleHideNotifications());\n    },\n  };\n};\n\nexport default @connect(mapStateToProps, mapDispatchToProps)\n@injectIntl\nclass MuteModal extends React.PureComponent {\n\n  static propTypes = {\n    isSubmitting: PropTypes.bool.isRequired,\n    account: PropTypes.object.isRequired,\n    notifications: PropTypes.bool.isRequired,\n    onClose: PropTypes.func.isRequired,\n    onConfirm: PropTypes.func.isRequired,\n    onToggleNotifications: PropTypes.func.isRequired,\n    intl: PropTypes.object.isRequired,\n  };\n\n  componentDidMount() {\n    this.button.focus();\n  }\n\n  handleClick = () => {\n    this.props.onClose();\n    this.props.onConfirm(this.props.account, this.props.notifications);\n  }\n\n  handleCancel = () => {\n    this.props.onClose();\n  }\n\n  setRef = (c) => {\n    this.button = c;\n  }\n\n  toggleNotifications = () => {\n    this.props.onToggleNotifications();\n  }\n\n  render () {\n    const { account, notifications } = this.props;\n\n    return (\n      <div className='modal-root__modal mute-modal'>\n        <div className='mute-modal__container'>\n          <p>\n            <FormattedMessage\n              id='confirmations.mute.message'\n              defaultMessage='Are you sure you want to mute {name}?'\n              values={{ name: <strong>@{account.get('acct')}</strong> }}\n            />\n          </p>\n          <div>\n            <label htmlFor='mute-modal__hide-notifications-checkbox'>\n              <FormattedMessage id='mute_modal.hide_notifications' defaultMessage='Hide notifications from this user?' />\n              {' '}\n              <Toggle id='mute-modal__hide-notifications-checkbox' checked={notifications} onChange={this.toggleNotifications} />\n            </label>\n          </div>\n        </div>\n\n        <div className='mute-modal__action-bar'>\n          <Button onClick={this.handleCancel} className='mute-modal__cancel-button'>\n            <FormattedMessage id='confirmation_modal.cancel' defaultMessage='Cancel' />\n          </Button>\n          <Button onClick={this.handleClick} ref={this.setRef}>\n            <FormattedMessage id='confirmations.mute.confirm' defaultMessage='Mute' />\n          </Button>\n        </div>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/components/navigation_panel.js",
    "content": "import React from 'react';\nimport { NavLink, withRouter } from 'react-router-dom';\nimport { FormattedMessage } from 'react-intl';\nimport Icon from 'mastodon/components/icon';\nimport { profile_directory } from 'mastodon/initial_state';\nimport NotificationsCounterIcon from './notifications_counter_icon';\nimport FollowRequestsNavLink from './follow_requests_nav_link';\nimport ListPanel from './list_panel';\n\nconst NavigationPanel = () => (\n  <div className='navigation-panel'>\n    <NavLink className='column-link column-link--transparent' to='/timelines/home' data-preview-title-id='column.home' data-preview-icon='home' ><Icon className='column-link__icon' id='home' fixedWidth /><FormattedMessage id='tabs_bar.home' defaultMessage='Home' /></NavLink>\n    <NavLink className='column-link column-link--transparent' to='/notifications' data-preview-title-id='column.notifications' data-preview-icon='bell' ><NotificationsCounterIcon className='column-link__icon' /><FormattedMessage id='tabs_bar.notifications' defaultMessage='Notifications' /></NavLink>\n    <FollowRequestsNavLink />\n    <NavLink className='column-link column-link--transparent' to='/timelines/public/local' data-preview-title-id='column.community' data-preview-icon='users' ><Icon className='column-link__icon' id='users' fixedWidth /><FormattedMessage id='tabs_bar.local_timeline' defaultMessage='Local' /></NavLink>\n    <NavLink className='column-link column-link--transparent' exact to='/timelines/public' data-preview-title-id='column.public' data-preview-icon='globe' ><Icon className='column-link__icon' id='globe' fixedWidth /><FormattedMessage id='tabs_bar.federated_timeline' defaultMessage='Federated' /></NavLink>\n    <NavLink className='column-link column-link--transparent' to='/timelines/direct'><Icon className='column-link__icon' id='envelope' fixedWidth /><FormattedMessage id='navigation_bar.direct' defaultMessage='Direct messages' /></NavLink>\n    <NavLink className='column-link column-link--transparent' to='/favourites'><Icon className='column-link__icon' id='star' fixedWidth /><FormattedMessage id='navigation_bar.favourites' defaultMessage='Favourites' /></NavLink>\n    <NavLink className='column-link column-link--transparent' to='/lists'><Icon className='column-link__icon' id='list-ul' fixedWidth /><FormattedMessage id='navigation_bar.lists' defaultMessage='Lists' /></NavLink>\n\n    <ListPanel />\n\n    <hr />\n\n    <a className='column-link column-link--transparent' href='/settings/preferences'><Icon className='column-link__icon' id='cog' fixedWidth /><FormattedMessage id='navigation_bar.preferences' defaultMessage='Preferences' /></a>\n    <a className='column-link column-link--transparent' href='/relationships'><Icon className='column-link__icon' id='users' fixedWidth /><FormattedMessage id='navigation_bar.follows_and_followers' defaultMessage='Follows and followers' /></a>\n    {!!profile_directory && <a className='column-link column-link--transparent' href='/explore'><Icon className='column-link__icon' id='address-book-o' fixedWidth /><FormattedMessage id='navigation_bar.profile_directory' defaultMessage='Profile directory' /></a>}\n  </div>\n);\n\nexport default withRouter(NavigationPanel);\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/components/notifications_counter_icon.js",
    "content": "import { connect } from 'react-redux';\nimport IconWithBadge from 'mastodon/components/icon_with_badge';\n\nconst mapStateToProps = state => ({\n  count: state.getIn(['notifications', 'unread']),\n  id: 'bell',\n});\n\nexport default connect(mapStateToProps)(IconWithBadge);\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/components/report_modal.js",
    "content": "import React from 'react';\nimport { connect } from 'react-redux';\nimport { changeReportComment, changeReportForward, submitReport } from '../../../actions/reports';\nimport { expandAccountTimeline } from '../../../actions/timelines';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport { makeGetAccount } from '../../../selectors';\nimport { defineMessages, FormattedMessage, injectIntl } from 'react-intl';\nimport StatusCheckBox from '../../report/containers/status_check_box_container';\nimport { OrderedSet } from 'immutable';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport Button from '../../../components/button';\nimport Toggle from 'react-toggle';\nimport IconButton from '../../../components/icon_button';\n\nconst messages = defineMessages({\n  close: { id: 'lightbox.close', defaultMessage: 'Close' },\n  placeholder: { id: 'report.placeholder', defaultMessage: 'Additional comments' },\n  submit: { id: 'report.submit', defaultMessage: 'Submit' },\n});\n\nconst makeMapStateToProps = () => {\n  const getAccount = makeGetAccount();\n\n  const mapStateToProps = state => {\n    const accountId = state.getIn(['reports', 'new', 'account_id']);\n\n    return {\n      isSubmitting: state.getIn(['reports', 'new', 'isSubmitting']),\n      account: getAccount(state, accountId),\n      comment: state.getIn(['reports', 'new', 'comment']),\n      forward: state.getIn(['reports', 'new', 'forward']),\n      statusIds: OrderedSet(state.getIn(['timelines', `account:${accountId}:with_replies`, 'items'])).union(state.getIn(['reports', 'new', 'status_ids'])),\n    };\n  };\n\n  return mapStateToProps;\n};\n\nexport default @connect(makeMapStateToProps)\n@injectIntl\nclass ReportModal extends ImmutablePureComponent {\n\n  static propTypes = {\n    isSubmitting: PropTypes.bool,\n    account: ImmutablePropTypes.map,\n    statusIds: ImmutablePropTypes.orderedSet.isRequired,\n    comment: PropTypes.string.isRequired,\n    forward: PropTypes.bool,\n    dispatch: PropTypes.func.isRequired,\n    intl: PropTypes.object.isRequired,\n  };\n\n  handleCommentChange = e => {\n    this.props.dispatch(changeReportComment(e.target.value));\n  }\n\n  handleForwardChange = e => {\n    this.props.dispatch(changeReportForward(e.target.checked));\n  }\n\n  handleSubmit = () => {\n    this.props.dispatch(submitReport());\n  }\n\n  handleKeyDown = e => {\n    if (e.keyCode === 13 && (e.ctrlKey || e.metaKey)) {\n      this.handleSubmit();\n    }\n  }\n\n  componentDidMount () {\n    this.props.dispatch(expandAccountTimeline(this.props.account.get('id'), { withReplies: true }));\n  }\n\n  componentWillReceiveProps (nextProps) {\n    if (this.props.account !== nextProps.account && nextProps.account) {\n      this.props.dispatch(expandAccountTimeline(nextProps.account.get('id'), { withReplies: true }));\n    }\n  }\n\n  render () {\n    const { account, comment, intl, statusIds, isSubmitting, forward, onClose } = this.props;\n\n    if (!account) {\n      return null;\n    }\n\n    const domain = account.get('acct').split('@')[1];\n\n    return (\n      <div className='modal-root__modal report-modal'>\n        <div className='report-modal__target'>\n          <IconButton className='media-modal__close' title={intl.formatMessage(messages.close)} icon='times' onClick={onClose} size={16} />\n          <FormattedMessage id='report.target' defaultMessage='Report {target}' values={{ target: <strong>{account.get('acct')}</strong> }} />\n        </div>\n\n        <div className='report-modal__container'>\n          <div className='report-modal__comment'>\n            <p><FormattedMessage id='report.hint' defaultMessage='The report will be sent to your server moderators. You can provide an explanation of why you are reporting this account below:' /></p>\n\n            <textarea\n              className='setting-text light'\n              placeholder={intl.formatMessage(messages.placeholder)}\n              value={comment}\n              onChange={this.handleCommentChange}\n              onKeyDown={this.handleKeyDown}\n              disabled={isSubmitting}\n              autoFocus\n            />\n\n            {domain && (\n              <div>\n                <p><FormattedMessage id='report.forward_hint' defaultMessage='The account is from another server. Send an anonymized copy of the report there as well?' /></p>\n\n                <div className='setting-toggle'>\n                  <Toggle id='report-forward' checked={forward} disabled={isSubmitting} onChange={this.handleForwardChange} />\n                  <label htmlFor='report-forward' className='setting-toggle__label'><FormattedMessage id='report.forward' defaultMessage='Forward to {target}' values={{ target: domain }} /></label>\n                </div>\n              </div>\n            )}\n\n            <Button disabled={isSubmitting} text={intl.formatMessage(messages.submit)} onClick={this.handleSubmit} />\n          </div>\n\n          <div className='report-modal__statuses'>\n            <div>\n              {statusIds.map(statusId => <StatusCheckBox id={statusId} key={statusId} disabled={isSubmitting} />)}\n            </div>\n          </div>\n        </div>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/components/tabs_bar.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport { NavLink, withRouter } from 'react-router-dom';\nimport { FormattedMessage, injectIntl } from 'react-intl';\nimport { debounce } from 'lodash';\nimport { isUserTouching } from '../../../is_mobile';\nimport Icon from 'mastodon/components/icon';\nimport NotificationsCounterIcon from './notifications_counter_icon';\n\nexport const links = [\n  <NavLink className='tabs-bar__link' to='/timelines/home' data-preview-title-id='column.home' data-preview-icon='home' ><Icon id='home' fixedWidth /><FormattedMessage id='tabs_bar.home' defaultMessage='Home' /></NavLink>,\n  <NavLink className='tabs-bar__link' to='/notifications' data-preview-title-id='column.notifications' data-preview-icon='bell' ><NotificationsCounterIcon /><FormattedMessage id='tabs_bar.notifications' defaultMessage='Notifications' /></NavLink>,\n  <NavLink className='tabs-bar__link' to='/timelines/public/local' data-preview-title-id='column.community' data-preview-icon='users' ><Icon id='users' fixedWidth /><FormattedMessage id='tabs_bar.local_timeline' defaultMessage='Local' /></NavLink>,\n  <NavLink className='tabs-bar__link' exact to='/timelines/public' data-preview-title-id='column.public' data-preview-icon='globe' ><Icon id='globe' fixedWidth /><FormattedMessage id='tabs_bar.federated_timeline' defaultMessage='Federated' /></NavLink>,\n  <NavLink className='tabs-bar__link optional' to='/search' data-preview-title-id='tabs_bar.search' data-preview-icon='bell' ><Icon id='search' fixedWidth /><FormattedMessage id='tabs_bar.search' defaultMessage='Search' /></NavLink>,\n  <NavLink className='tabs-bar__link' style={{ flexGrow: '0', flexBasis: '30px' }} to='/getting-started' data-preview-title-id='getting_started.heading' data-preview-icon='bars' ><Icon id='bars' fixedWidth /></NavLink>,\n];\n\nexport function getIndex (path) {\n  return links.findIndex(link => link.props.to === path);\n}\n\nexport function getLink (index) {\n  return links[index].props.to;\n}\n\nexport default @injectIntl\n@withRouter\nclass TabsBar extends React.PureComponent {\n\n  static propTypes = {\n    intl: PropTypes.object.isRequired,\n    history: PropTypes.object.isRequired,\n  }\n\n  setRef = ref => {\n    this.node = ref;\n  }\n\n  handleClick = (e) => {\n    // Only apply optimization for touch devices, which we assume are slower\n    // We thus avoid the 250ms delay for non-touch devices and the lag for touch devices\n    if (isUserTouching()) {\n      e.preventDefault();\n      e.persist();\n\n      requestAnimationFrame(() => {\n        const tabs = Array(...this.node.querySelectorAll('.tabs-bar__link'));\n        const currentTab = tabs.find(tab => tab.classList.contains('active'));\n        const nextTab = tabs.find(tab => tab.contains(e.target));\n        const { props: { to } } = links[Array(...this.node.childNodes).indexOf(nextTab)];\n\n\n        if (currentTab !== nextTab) {\n          if (currentTab) {\n            currentTab.classList.remove('active');\n          }\n\n          const listener = debounce(() => {\n            nextTab.removeEventListener('transitionend', listener);\n            this.props.history.push(to);\n          }, 50);\n\n          nextTab.addEventListener('transitionend', listener);\n          nextTab.classList.add('active');\n        }\n      });\n    }\n\n  }\n\n  render () {\n    const { intl: { formatMessage } } = this.props;\n\n    return (\n      <nav className='tabs-bar' ref={this.setRef}>\n        {links.map(link => React.cloneElement(link, { key: link.props.to, onClick: this.handleClick, 'aria-label': formatMessage({ id: link.props['data-preview-title-id'] }) }))}\n      </nav>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/components/upload_area.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport Motion from '../../ui/util/optional_motion';\nimport spring from 'react-motion/lib/spring';\nimport { FormattedMessage } from 'react-intl';\n\nexport default class UploadArea extends React.PureComponent {\n\n  static propTypes = {\n    active: PropTypes.bool,\n    onClose: PropTypes.func,\n  };\n\n  handleKeyUp = (e) => {\n    const keyCode = e.keyCode;\n    if (this.props.active) {\n      switch(keyCode) {\n      case 27:\n        e.preventDefault();\n        e.stopPropagation();\n        this.props.onClose();\n        break;\n      }\n    }\n  }\n\n  componentDidMount () {\n    window.addEventListener('keyup', this.handleKeyUp, false);\n  }\n\n  componentWillUnmount () {\n    window.removeEventListener('keyup', this.handleKeyUp);\n  }\n\n  render () {\n    const { active } = this.props;\n\n    return (\n      <Motion defaultStyle={{ backgroundOpacity: 0, backgroundScale: 0.95 }} style={{ backgroundOpacity: spring(active ? 1 : 0, { stiffness: 150, damping: 15 }), backgroundScale: spring(active ? 1 : 0.95, { stiffness: 200, damping: 3 }) }}>\n        {({ backgroundOpacity, backgroundScale }) => (\n          <div className='upload-area' style={{ visibility: active ? 'visible' : 'hidden', opacity: backgroundOpacity }}>\n            <div className='upload-area__drop'>\n              <div className='upload-area__background' style={{ transform: `scale(${backgroundScale})` }} />\n              <div className='upload-area__content'><FormattedMessage id='upload_area.title' defaultMessage='Drag & drop to upload' /></div>\n            </div>\n          </div>\n        )}\n      </Motion>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/components/video_modal.js",
    "content": "import React from 'react';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport PropTypes from 'prop-types';\nimport Video from 'mastodon/features/video';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport { FormattedMessage } from 'react-intl';\n\nexport const previewState = 'previewVideoModal';\n\nexport default class VideoModal extends ImmutablePureComponent {\n\n  static propTypes = {\n    media: ImmutablePropTypes.map.isRequired,\n    status: ImmutablePropTypes.map,\n    time: PropTypes.number,\n    onClose: PropTypes.func.isRequired,\n  };\n\n  static contextTypes = {\n    router: PropTypes.object,\n  };\n\n  componentDidMount () {\n    if (this.context.router) {\n      const history = this.context.router.history;\n\n      history.push(history.location.pathname, previewState);\n\n      this.unlistenHistory = history.listen(() => {\n        this.props.onClose();\n      });\n    }\n  }\n\n  componentWillUnmount () {\n    if (this.context.router) {\n      this.unlistenHistory();\n\n      if (this.context.router.history.location.state === previewState) {\n        this.context.router.history.goBack();\n      }\n    }\n  }\n\n  handleStatusClick = e => {\n    if (e.button === 0 && !(e.ctrlKey || e.metaKey)) {\n      e.preventDefault();\n      this.context.router.history.push(`/statuses/${this.props.status.get('id')}`);\n    }\n  }\n\n  render () {\n    const { media, status, time, onClose } = this.props;\n\n    const link = status && <a href={status.get('url')} onClick={this.handleStatusClick}><FormattedMessage id='lightbox.view_context' defaultMessage='View context' /></a>;\n\n    return (\n      <div className='modal-root__modal video-modal'>\n        <div>\n          <Video\n            preview={media.get('preview_url')}\n            blurhash={media.get('blurhash')}\n            src={media.get('url')}\n            startTime={time}\n            onCloseVideo={onClose}\n            link={link}\n            detailed\n            alt={media.get('description')}\n          />\n        </div>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/components/zoomable_image.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\n\nconst MIN_SCALE = 1;\nconst MAX_SCALE = 4;\n\nconst getMidpoint = (p1, p2) => ({\n  x: (p1.clientX + p2.clientX) / 2,\n  y: (p1.clientY + p2.clientY) / 2,\n});\n\nconst getDistance = (p1, p2) =>\n  Math.sqrt(Math.pow(p1.clientX - p2.clientX, 2) + Math.pow(p1.clientY - p2.clientY, 2));\n\nconst clamp = (min, max, value) => Math.min(max, Math.max(min, value));\n\nexport default class ZoomableImage extends React.PureComponent {\n\n  static propTypes = {\n    alt: PropTypes.string,\n    src: PropTypes.string.isRequired,\n    width: PropTypes.number,\n    height: PropTypes.number,\n    onClick: PropTypes.func,\n  }\n\n  static defaultProps = {\n    alt: '',\n    width: null,\n    height: null,\n  };\n\n  state = {\n    scale: MIN_SCALE,\n  }\n\n  removers = [];\n  container = null;\n  image = null;\n  lastTouchEndTime = 0;\n  lastDistance = 0;\n\n  componentDidMount () {\n    let handler = this.handleTouchStart;\n    this.container.addEventListener('touchstart', handler);\n    this.removers.push(() => this.container.removeEventListener('touchstart', handler));\n    handler = this.handleTouchMove;\n    // on Chrome 56+, touch event listeners will default to passive\n    // https://www.chromestatus.com/features/5093566007214080\n    this.container.addEventListener('touchmove', handler, { passive: false });\n    this.removers.push(() => this.container.removeEventListener('touchend', handler));\n  }\n\n  componentWillUnmount () {\n    this.removeEventListeners();\n  }\n\n  removeEventListeners () {\n    this.removers.forEach(listeners => listeners());\n    this.removers = [];\n  }\n\n  handleTouchStart = e => {\n    if (e.touches.length !== 2) return;\n\n    this.lastDistance = getDistance(...e.touches);\n  }\n\n  handleTouchMove = e => {\n    const { scrollTop, scrollHeight, clientHeight } = this.container;\n    if (e.touches.length === 1 && scrollTop !== scrollHeight - clientHeight) {\n      // prevent propagating event to MediaModal\n      e.stopPropagation();\n      return;\n    }\n    if (e.touches.length !== 2) return;\n\n    e.preventDefault();\n    e.stopPropagation();\n\n    const distance = getDistance(...e.touches);\n    const midpoint = getMidpoint(...e.touches);\n    const scale = clamp(MIN_SCALE, MAX_SCALE, this.state.scale * distance / this.lastDistance);\n\n    this.zoom(scale, midpoint);\n\n    this.lastMidpoint = midpoint;\n    this.lastDistance = distance;\n  }\n\n  zoom(nextScale, midpoint) {\n    const { scale } = this.state;\n    const { scrollLeft, scrollTop } = this.container;\n\n    // math memo:\n    // x = (scrollLeft + midpoint.x) / scrollWidth\n    // x' = (nextScrollLeft + midpoint.x) / nextScrollWidth\n    // scrollWidth = clientWidth * scale\n    // scrollWidth' = clientWidth * nextScale\n    // Solve x = x' for nextScrollLeft\n    const nextScrollLeft = (scrollLeft + midpoint.x) * nextScale / scale - midpoint.x;\n    const nextScrollTop = (scrollTop + midpoint.y) * nextScale / scale - midpoint.y;\n\n    this.setState({ scale: nextScale }, () => {\n      this.container.scrollLeft = nextScrollLeft;\n      this.container.scrollTop = nextScrollTop;\n    });\n  }\n\n  handleClick = e => {\n    // don't propagate event to MediaModal\n    e.stopPropagation();\n    const handler = this.props.onClick;\n    if (handler) handler();\n  }\n\n  setContainerRef = c => {\n    this.container = c;\n  }\n\n  setImageRef = c => {\n    this.image = c;\n  }\n\n  render () {\n    const { alt, src } = this.props;\n    const { scale } = this.state;\n    const overflow = scale === 1 ? 'hidden' : 'scroll';\n\n    return (\n      <div\n        className='zoomable-image'\n        ref={this.setContainerRef}\n        style={{ overflow }}\n      >\n        <img\n          role='presentation'\n          ref={this.setImageRef}\n          alt={alt}\n          title={alt}\n          src={src}\n          style={{\n            transform: `scale(${scale})`,\n            transformOrigin: '0 0',\n          }}\n          onClick={this.handleClick}\n        />\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/containers/bundle_container.js",
    "content": "import { connect } from 'react-redux';\n\nimport Bundle from '../components/bundle';\n\nimport { fetchBundleRequest, fetchBundleSuccess, fetchBundleFail } from '../../../actions/bundles';\n\nconst mapDispatchToProps = dispatch => ({\n  onFetch () {\n    dispatch(fetchBundleRequest());\n  },\n  onFetchSuccess () {\n    dispatch(fetchBundleSuccess());\n  },\n  onFetchFail (error) {\n    dispatch(fetchBundleFail(error));\n  },\n});\n\nexport default connect(null, mapDispatchToProps)(Bundle);\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/containers/columns_area_container.js",
    "content": "import { connect } from 'react-redux';\nimport ColumnsArea from '../components/columns_area';\n\nconst mapStateToProps = state => ({\n  columns: state.getIn(['settings', 'columns']),\n  isModalOpen: !!state.get('modal').modalType,\n});\n\nexport default connect(mapStateToProps, null, null, { forwardRef: true })(ColumnsArea);\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/containers/loading_bar_container.js",
    "content": "import { connect }    from 'react-redux';\nimport LoadingBar from 'react-redux-loading-bar';\n\nconst mapStateToProps = (state, ownProps) => ({\n  loading: state.get('loadingBar')[ownProps.scope || 'default'],\n});\n\nexport default connect(mapStateToProps)(LoadingBar.WrappedComponent);\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/containers/modal_container.js",
    "content": "import { connect } from 'react-redux';\nimport { closeModal } from '../../../actions/modal';\nimport ModalRoot from '../components/modal_root';\n\nconst mapStateToProps = state => ({\n  type: state.get('modal').modalType,\n  props: state.get('modal').modalProps,\n});\n\nconst mapDispatchToProps = dispatch => ({\n  onClose () {\n    dispatch(closeModal());\n  },\n});\n\nexport default connect(mapStateToProps, mapDispatchToProps)(ModalRoot);\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/containers/notifications_container.js",
    "content": "import { injectIntl } from 'react-intl';\nimport { connect } from 'react-redux';\nimport { NotificationStack } from 'react-notification';\nimport { dismissAlert } from '../../../actions/alerts';\nimport { getAlerts } from '../../../selectors';\n\nconst mapStateToProps = (state, { intl }) => {\n  const notifications = getAlerts(state);\n\n  notifications.forEach(notification => ['title', 'message'].forEach(key => {\n    const value = notification[key];\n\n    if (typeof value === 'object') {\n      notification[key] = intl.formatMessage(value);\n    }\n  }));\n\n  return { notifications };\n};\n\nconst mapDispatchToProps = (dispatch) => {\n  return {\n    onDismiss: alert => {\n      dispatch(dismissAlert(alert));\n    },\n  };\n};\n\nexport default injectIntl(connect(mapStateToProps, mapDispatchToProps)(NotificationStack));\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/containers/status_list_container.js",
    "content": "import { connect } from 'react-redux';\nimport StatusList from '../../../components/status_list';\nimport { scrollTopTimeline } from '../../../actions/timelines';\nimport { Map as ImmutableMap, List as ImmutableList } from 'immutable';\nimport { createSelector } from 'reselect';\nimport { debounce } from 'lodash';\nimport { me } from '../../../initial_state';\n\nconst makeGetStatusIds = () => createSelector([\n  (state, { type }) => state.getIn(['settings', type], ImmutableMap()),\n  (state, { type }) => state.getIn(['timelines', type, 'items'], ImmutableList()),\n  (state)           => state.get('statuses'),\n], (columnSettings, statusIds, statuses) => {\n  return statusIds.filter(id => {\n    if (id === null) return true;\n\n    const statusForId = statuses.get(id);\n    let showStatus    = true;\n\n    if (columnSettings.getIn(['shows', 'reblog']) === false) {\n      showStatus = showStatus && statusForId.get('reblog') === null;\n    }\n\n    if (columnSettings.getIn(['shows', 'reply']) === false) {\n      showStatus = showStatus && (statusForId.get('in_reply_to_id') === null || statusForId.get('in_reply_to_account_id') === me);\n    }\n\n    return showStatus;\n  });\n});\n\nconst makeMapStateToProps = () => {\n  const getStatusIds = makeGetStatusIds();\n\n  const mapStateToProps = (state, { timelineId }) => ({\n    statusIds: getStatusIds(state, { type: timelineId }),\n    isLoading: state.getIn(['timelines', timelineId, 'isLoading'], true),\n    isPartial: state.getIn(['timelines', timelineId, 'isPartial'], false),\n    hasMore:   state.getIn(['timelines', timelineId, 'hasMore']),\n  });\n\n  return mapStateToProps;\n};\n\nconst mapDispatchToProps = (dispatch, { timelineId }) => ({\n\n  onScrollToTop: debounce(() => {\n    dispatch(scrollTopTimeline(timelineId, true));\n  }, 100),\n\n  onScroll: debounce(() => {\n    dispatch(scrollTopTimeline(timelineId, false));\n  }, 100),\n\n});\n\nexport default connect(makeMapStateToProps, mapDispatchToProps)(StatusList);\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/index.js",
    "content": "import classNames from 'classnames';\nimport React from 'react';\nimport { HotKeys } from 'react-hotkeys';\nimport { defineMessages, injectIntl } from 'react-intl';\nimport { connect } from 'react-redux';\nimport { Redirect, withRouter } from 'react-router-dom';\nimport PropTypes from 'prop-types';\nimport NotificationsContainer from './containers/notifications_container';\nimport LoadingBarContainer from './containers/loading_bar_container';\nimport ModalContainer from './containers/modal_container';\nimport { isMobile } from '../../is_mobile';\nimport { debounce } from 'lodash';\nimport { uploadCompose, resetCompose } from '../../actions/compose';\nimport { expandHomeTimeline } from '../../actions/timelines';\nimport { expandNotifications } from '../../actions/notifications';\nimport { fetchFilters } from '../../actions/filters';\nimport { clearHeight } from '../../actions/height_cache';\nimport { WrappedSwitch, WrappedRoute } from './util/react_router_helpers';\nimport UploadArea from './components/upload_area';\nimport ColumnsAreaContainer from './containers/columns_area_container';\nimport {\n  Compose,\n  Status,\n  GettingStarted,\n  KeyboardShortcuts,\n  PublicTimeline,\n  CommunityTimeline,\n  AccountTimeline,\n  AccountGallery,\n  HomeTimeline,\n  Followers,\n  Following,\n  Reblogs,\n  Favourites,\n  DirectTimeline,\n  HashtagTimeline,\n  Notifications,\n  FollowRequests,\n  GenericNotFound,\n  FavouritedStatuses,\n  ListTimeline,\n  Blocks,\n  DomainBlocks,\n  Mutes,\n  PinnedStatuses,\n  Lists,\n  Search,\n} from './util/async-components';\nimport { me, forceSingleColumn } from '../../initial_state';\nimport { previewState as previewMediaState } from './components/media_modal';\nimport { previewState as previewVideoState } from './components/video_modal';\n\n// Dummy import, to make sure that <Status /> ends up in the application bundle.\n// Without this it ends up in ~8 very commonly used bundles.\nimport '../../components/status';\n\nconst messages = defineMessages({\n  beforeUnload: { id: 'ui.beforeunload', defaultMessage: 'Your draft will be lost if you leave Mastodon.' },\n});\n\nconst mapStateToProps = state => ({\n  isComposing: state.getIn(['compose', 'is_composing']),\n  hasComposingText: state.getIn(['compose', 'text']).trim().length !== 0,\n  hasMediaAttachments: state.getIn(['compose', 'media_attachments']).size > 0,\n  dropdownMenuIsOpen: state.getIn(['dropdown_menu', 'openId']) !== null,\n});\n\nconst keyMap = {\n  help: '?',\n  new: 'n',\n  search: 's',\n  forceNew: 'option+n',\n  focusColumn: ['1', '2', '3', '4', '5', '6', '7', '8', '9'],\n  reply: 'r',\n  favourite: 'f',\n  boost: 'b',\n  mention: 'm',\n  open: ['enter', 'o'],\n  openProfile: 'p',\n  moveDown: ['down', 'j'],\n  moveUp: ['up', 'k'],\n  back: 'backspace',\n  goToHome: 'g h',\n  goToNotifications: 'g n',\n  goToLocal: 'g l',\n  goToFederated: 'g t',\n  goToDirect: 'g d',\n  goToStart: 'g s',\n  goToFavourites: 'g f',\n  goToPinned: 'g p',\n  goToProfile: 'g u',\n  goToBlocked: 'g b',\n  goToMuted: 'g m',\n  goToRequests: 'g r',\n  toggleHidden: 'x',\n  toggleSensitive: 'h',\n};\n\nclass SwitchingColumnsArea extends React.PureComponent {\n\n  static propTypes = {\n    children: PropTypes.node,\n    location: PropTypes.object,\n    onLayoutChange: PropTypes.func.isRequired,\n  };\n\n  state = {\n    mobile: isMobile(window.innerWidth),\n  };\n\n  componentWillMount () {\n    window.addEventListener('resize', this.handleResize, { passive: true });\n  }\n\n  componentDidUpdate (prevProps) {\n    if (![this.props.location.pathname, '/'].includes(prevProps.location.pathname)) {\n      this.node.handleChildrenContentChange();\n    }\n  }\n\n  componentWillUnmount () {\n    window.removeEventListener('resize', this.handleResize);\n  }\n\n  shouldUpdateScroll (_, { location }) {\n    return location.state !== previewMediaState && location.state !== previewVideoState;\n  }\n\n  handleResize = debounce(() => {\n    // The cached heights are no longer accurate, invalidate\n    this.props.onLayoutChange();\n\n    this.setState({ mobile: isMobile(window.innerWidth) });\n  }, 500, {\n    trailing: true,\n  });\n\n  setRef = c => {\n    this.node = c.getWrappedInstance();\n  }\n\n  render () {\n    const { children } = this.props;\n    const { mobile } = this.state;\n    const singleColumn = forceSingleColumn || mobile;\n    const redirect = singleColumn ? <Redirect from='/' to='/timelines/home' exact /> : <Redirect from='/' to='/getting-started' exact />;\n\n    return (\n      <ColumnsAreaContainer ref={this.setRef} singleColumn={singleColumn}>\n        <WrappedSwitch>\n          {redirect}\n          <WrappedRoute path='/getting-started' component={GettingStarted} content={children} />\n          <WrappedRoute path='/keyboard-shortcuts' component={KeyboardShortcuts} content={children} />\n          <WrappedRoute path='/timelines/home' component={HomeTimeline} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} />\n          <WrappedRoute path='/timelines/public' exact component={PublicTimeline} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} />\n          <WrappedRoute path='/timelines/public/local' exact component={CommunityTimeline} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} />\n          <WrappedRoute path='/timelines/direct' component={DirectTimeline} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} />\n          <WrappedRoute path='/timelines/tag/:id' component={HashtagTimeline} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} />\n          <WrappedRoute path='/timelines/list/:id' component={ListTimeline} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} />\n\n          <WrappedRoute path='/notifications' component={Notifications} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} />\n          <WrappedRoute path='/favourites' component={FavouritedStatuses} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} />\n          <WrappedRoute path='/pinned' component={PinnedStatuses} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} />\n\n          <WrappedRoute path='/search' component={Search} content={children} />\n\n          <WrappedRoute path='/statuses/new' component={Compose} content={children} />\n          <WrappedRoute path='/statuses/:statusId' exact component={Status} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} />\n          <WrappedRoute path='/statuses/:statusId/reblogs' component={Reblogs} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} />\n          <WrappedRoute path='/statuses/:statusId/favourites' component={Favourites} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} />\n\n          <WrappedRoute path='/accounts/:accountId' exact component={AccountTimeline} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} />\n          <WrappedRoute path='/accounts/:accountId/with_replies' component={AccountTimeline} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll, withReplies: true }} />\n          <WrappedRoute path='/accounts/:accountId/followers' component={Followers} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} />\n          <WrappedRoute path='/accounts/:accountId/following' component={Following} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} />\n          <WrappedRoute path='/accounts/:accountId/media' component={AccountGallery} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} />\n\n          <WrappedRoute path='/follow_requests' component={FollowRequests} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} />\n          <WrappedRoute path='/blocks' component={Blocks} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} />\n          <WrappedRoute path='/domain_blocks' component={DomainBlocks} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} />\n          <WrappedRoute path='/mutes' component={Mutes} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} />\n          <WrappedRoute path='/lists' component={Lists} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} />\n\n          <WrappedRoute component={GenericNotFound} content={children} />\n        </WrappedSwitch>\n      </ColumnsAreaContainer>\n    );\n  }\n\n}\n\nexport default @connect(mapStateToProps)\n@injectIntl\n@withRouter\nclass UI extends React.PureComponent {\n\n  static contextTypes = {\n    router: PropTypes.object.isRequired,\n  };\n\n  static propTypes = {\n    dispatch: PropTypes.func.isRequired,\n    children: PropTypes.node,\n    isComposing: PropTypes.bool,\n    hasComposingText: PropTypes.bool,\n    hasMediaAttachments: PropTypes.bool,\n    location: PropTypes.object,\n    intl: PropTypes.object.isRequired,\n    dropdownMenuIsOpen: PropTypes.bool,\n  };\n\n  state = {\n    draggingOver: false,\n  };\n\n  handleBeforeUnload = (e) => {\n    const { intl, isComposing, hasComposingText, hasMediaAttachments } = this.props;\n\n    if (isComposing && (hasComposingText || hasMediaAttachments)) {\n      // Setting returnValue to any string causes confirmation dialog.\n      // Many browsers no longer display this text to users,\n      // but we set user-friendly message for other browsers, e.g. Edge.\n      e.returnValue = intl.formatMessage(messages.beforeUnload);\n    }\n  }\n\n  handleLayoutChange = () => {\n    // The cached heights are no longer accurate, invalidate\n    this.props.dispatch(clearHeight());\n  }\n\n  handleDragEnter = (e) => {\n    e.preventDefault();\n\n    if (!this.dragTargets) {\n      this.dragTargets = [];\n    }\n\n    if (this.dragTargets.indexOf(e.target) === -1) {\n      this.dragTargets.push(e.target);\n    }\n\n    if (e.dataTransfer && Array.from(e.dataTransfer.types).includes('Files')) {\n      this.setState({ draggingOver: true });\n    }\n  }\n\n  handleDragOver = (e) => {\n    if (this.dataTransferIsText(e.dataTransfer)) return false;\n    e.preventDefault();\n    e.stopPropagation();\n\n    try {\n      e.dataTransfer.dropEffect = 'copy';\n    } catch (err) {\n\n    }\n\n    return false;\n  }\n\n  handleDrop = (e) => {\n    if (this.dataTransferIsText(e.dataTransfer)) return;\n    e.preventDefault();\n\n    this.setState({ draggingOver: false });\n    this.dragTargets = [];\n\n    if (e.dataTransfer && e.dataTransfer.files.length >= 1) {\n      this.props.dispatch(uploadCompose(e.dataTransfer.files));\n    }\n  }\n\n  handleDragLeave = (e) => {\n    e.preventDefault();\n    e.stopPropagation();\n\n    this.dragTargets = this.dragTargets.filter(el => el !== e.target && this.node.contains(el));\n\n    if (this.dragTargets.length > 0) {\n      return;\n    }\n\n    this.setState({ draggingOver: false });\n  }\n\n  dataTransferIsText = (dataTransfer) => {\n    return (dataTransfer && Array.from(dataTransfer.types).includes('text/plain') && dataTransfer.items.length === 1);\n  }\n\n  closeUploadModal = () => {\n    this.setState({ draggingOver: false });\n  }\n\n  handleServiceWorkerPostMessage = ({ data }) => {\n    if (data.type === 'navigate') {\n      this.context.router.history.push(data.path);\n    } else {\n      console.warn('Unknown message type:', data.type);\n    }\n  }\n\n  componentWillMount () {\n    window.addEventListener('beforeunload', this.handleBeforeUnload, false);\n\n    document.addEventListener('dragenter', this.handleDragEnter, false);\n    document.addEventListener('dragover', this.handleDragOver, false);\n    document.addEventListener('drop', this.handleDrop, false);\n    document.addEventListener('dragleave', this.handleDragLeave, false);\n    document.addEventListener('dragend', this.handleDragEnd, false);\n\n    if ('serviceWorker' in  navigator) {\n      navigator.serviceWorker.addEventListener('message', this.handleServiceWorkerPostMessage);\n    }\n\n    if (typeof window.Notification !== 'undefined' && Notification.permission === 'default') {\n      window.setTimeout(() => Notification.requestPermission(), 120 * 1000);\n    }\n\n    this.props.dispatch(expandHomeTimeline());\n    this.props.dispatch(expandNotifications());\n\n    setTimeout(() => this.props.dispatch(fetchFilters()), 500);\n  }\n\n  componentDidMount () {\n    this.hotkeys.__mousetrap__.stopCallback = (e, element) => {\n      return ['TEXTAREA', 'SELECT', 'INPUT'].includes(element.tagName);\n    };\n  }\n\n  componentWillUnmount () {\n    window.removeEventListener('beforeunload', this.handleBeforeUnload);\n    document.removeEventListener('dragenter', this.handleDragEnter);\n    document.removeEventListener('dragover', this.handleDragOver);\n    document.removeEventListener('drop', this.handleDrop);\n    document.removeEventListener('dragleave', this.handleDragLeave);\n    document.removeEventListener('dragend', this.handleDragEnd);\n  }\n\n  setRef = c => {\n    this.node = c;\n  }\n\n  handleHotkeyNew = e => {\n    e.preventDefault();\n\n    const element = this.node.querySelector('.compose-form__autosuggest-wrapper textarea');\n\n    if (element) {\n      element.focus();\n    }\n  }\n\n  handleHotkeySearch = e => {\n    e.preventDefault();\n\n    const element = this.node.querySelector('.search__input');\n\n    if (element) {\n      element.focus();\n    }\n  }\n\n  handleHotkeyForceNew = e => {\n    this.handleHotkeyNew(e);\n    this.props.dispatch(resetCompose());\n  }\n\n  handleHotkeyFocusColumn = e => {\n    const index  = (e.key * 1) + 1; // First child is drawer, skip that\n    const column = this.node.querySelector(`.column:nth-child(${index})`);\n    if (!column) return;\n    const container = column.querySelector('.scrollable');\n\n    if (container) {\n      const status = container.querySelector('.focusable');\n\n      if (status) {\n        if (container.scrollTop > status.offsetTop) {\n          status.scrollIntoView(true);\n        }\n        status.focus();\n      }\n    }\n  }\n\n  handleHotkeyBack = () => {\n    if (window.history && window.history.length === 1) {\n      this.context.router.history.push('/');\n    } else {\n      this.context.router.history.goBack();\n    }\n  }\n\n  setHotkeysRef = c => {\n    this.hotkeys = c;\n  }\n\n  handleHotkeyToggleHelp = () => {\n    if (this.props.location.pathname === '/keyboard-shortcuts') {\n      this.context.router.history.goBack();\n    } else {\n      this.context.router.history.push('/keyboard-shortcuts');\n    }\n  }\n\n  handleHotkeyGoToHome = () => {\n    this.context.router.history.push('/timelines/home');\n  }\n\n  handleHotkeyGoToNotifications = () => {\n    this.context.router.history.push('/notifications');\n  }\n\n  handleHotkeyGoToLocal = () => {\n    this.context.router.history.push('/timelines/public/local');\n  }\n\n  handleHotkeyGoToFederated = () => {\n    this.context.router.history.push('/timelines/public');\n  }\n\n  handleHotkeyGoToDirect = () => {\n    this.context.router.history.push('/timelines/direct');\n  }\n\n  handleHotkeyGoToStart = () => {\n    this.context.router.history.push('/getting-started');\n  }\n\n  handleHotkeyGoToFavourites = () => {\n    this.context.router.history.push('/favourites');\n  }\n\n  handleHotkeyGoToPinned = () => {\n    this.context.router.history.push('/pinned');\n  }\n\n  handleHotkeyGoToProfile = () => {\n    this.context.router.history.push(`/accounts/${me}`);\n  }\n\n  handleHotkeyGoToBlocked = () => {\n    this.context.router.history.push('/blocks');\n  }\n\n  handleHotkeyGoToMuted = () => {\n    this.context.router.history.push('/mutes');\n  }\n\n  handleHotkeyGoToRequests = () => {\n    this.context.router.history.push('/follow_requests');\n  }\n\n  render () {\n    const { draggingOver } = this.state;\n    const { children, isComposing, location, dropdownMenuIsOpen } = this.props;\n\n    const handlers = {\n      help: this.handleHotkeyToggleHelp,\n      new: this.handleHotkeyNew,\n      search: this.handleHotkeySearch,\n      forceNew: this.handleHotkeyForceNew,\n      focusColumn: this.handleHotkeyFocusColumn,\n      back: this.handleHotkeyBack,\n      goToHome: this.handleHotkeyGoToHome,\n      goToNotifications: this.handleHotkeyGoToNotifications,\n      goToLocal: this.handleHotkeyGoToLocal,\n      goToFederated: this.handleHotkeyGoToFederated,\n      goToDirect: this.handleHotkeyGoToDirect,\n      goToStart: this.handleHotkeyGoToStart,\n      goToFavourites: this.handleHotkeyGoToFavourites,\n      goToPinned: this.handleHotkeyGoToPinned,\n      goToProfile: this.handleHotkeyGoToProfile,\n      goToBlocked: this.handleHotkeyGoToBlocked,\n      goToMuted: this.handleHotkeyGoToMuted,\n      goToRequests: this.handleHotkeyGoToRequests,\n    };\n\n    return (\n      <HotKeys keyMap={keyMap} handlers={handlers} ref={this.setHotkeysRef} attach={window} focused>\n        <div className={classNames('ui', { 'is-composing': isComposing })} ref={this.setRef} style={{ pointerEvents: dropdownMenuIsOpen ? 'none' : null }}>\n          <SwitchingColumnsArea location={location} onLayoutChange={this.handleLayoutChange}>\n            {children}\n          </SwitchingColumnsArea>\n\n          <NotificationsContainer />\n          <LoadingBarContainer className='loading-bar' />\n          <ModalContainer />\n          <UploadArea active={draggingOver} onClose={this.closeUploadModal} />\n        </div>\n      </HotKeys>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/util/async-components.js",
    "content": "export function EmojiPicker () {\n  return import(/* webpackChunkName: \"emoji_picker\" */'../../emoji/emoji_picker');\n}\n\nexport function Compose () {\n  return import(/* webpackChunkName: \"features/compose\" */'../../compose');\n}\n\nexport function Notifications () {\n  return import(/* webpackChunkName: \"features/notifications\" */'../../notifications');\n}\n\nexport function HomeTimeline () {\n  return import(/* webpackChunkName: \"features/home_timeline\" */'../../home_timeline');\n}\n\nexport function PublicTimeline () {\n  return import(/* webpackChunkName: \"features/public_timeline\" */'../../public_timeline');\n}\n\nexport function CommunityTimeline () {\n  return import(/* webpackChunkName: \"features/community_timeline\" */'../../community_timeline');\n}\n\nexport function HashtagTimeline () {\n  return import(/* webpackChunkName: \"features/hashtag_timeline\" */'../../hashtag_timeline');\n}\n\nexport function DirectTimeline() {\n  return import(/* webpackChunkName: \"features/direct_timeline\" */'../../direct_timeline');\n}\n\nexport function ListTimeline () {\n  return import(/* webpackChunkName: \"features/list_timeline\" */'../../list_timeline');\n}\n\nexport function Lists () {\n  return import(/* webpackChunkName: \"features/lists\" */'../../lists');\n}\n\nexport function Status () {\n  return import(/* webpackChunkName: \"features/status\" */'../../status');\n}\n\nexport function GettingStarted () {\n  return import(/* webpackChunkName: \"features/getting_started\" */'../../getting_started');\n}\n\nexport function KeyboardShortcuts () {\n  return import(/* webpackChunkName: \"features/keyboard_shortcuts\" */'../../keyboard_shortcuts');\n}\n\nexport function PinnedStatuses () {\n  return import(/* webpackChunkName: \"features/pinned_statuses\" */'../../pinned_statuses');\n}\n\nexport function AccountTimeline () {\n  return import(/* webpackChunkName: \"features/account_timeline\" */'../../account_timeline');\n}\n\nexport function AccountGallery () {\n  return import(/* webpackChunkName: \"features/account_gallery\" */'../../account_gallery');\n}\n\nexport function Followers () {\n  return import(/* webpackChunkName: \"features/followers\" */'../../followers');\n}\n\nexport function Following () {\n  return import(/* webpackChunkName: \"features/following\" */'../../following');\n}\n\nexport function Reblogs () {\n  return import(/* webpackChunkName: \"features/reblogs\" */'../../reblogs');\n}\n\nexport function Favourites () {\n  return import(/* webpackChunkName: \"features/favourites\" */'../../favourites');\n}\n\nexport function FollowRequests () {\n  return import(/* webpackChunkName: \"features/follow_requests\" */'../../follow_requests');\n}\n\nexport function GenericNotFound () {\n  return import(/* webpackChunkName: \"features/generic_not_found\" */'../../generic_not_found');\n}\n\nexport function FavouritedStatuses () {\n  return import(/* webpackChunkName: \"features/favourited_statuses\" */'../../favourited_statuses');\n}\n\nexport function Blocks () {\n  return import(/* webpackChunkName: \"features/blocks\" */'../../blocks');\n}\n\nexport function DomainBlocks () {\n  return import(/* webpackChunkName: \"features/domain_blocks\" */'../../domain_blocks');\n}\n\nexport function Mutes () {\n  return import(/* webpackChunkName: \"features/mutes\" */'../../mutes');\n}\n\nexport function MuteModal () {\n  return import(/* webpackChunkName: \"modals/mute_modal\" */'../components/mute_modal');\n}\n\nexport function ReportModal () {\n  return import(/* webpackChunkName: \"modals/report_modal\" */'../components/report_modal');\n}\n\nexport function MediaGallery () {\n  return import(/* webpackChunkName: \"status/media_gallery\" */'../../../components/media_gallery');\n}\n\nexport function Video () {\n  return import(/* webpackChunkName: \"features/video\" */'../../video');\n}\n\nexport function EmbedModal () {\n  return import(/* webpackChunkName: \"modals/embed_modal\" */'../components/embed_modal');\n}\n\nexport function ListEditor () {\n  return import(/* webpackChunkName: \"features/list_editor\" */'../../list_editor');\n}\n\nexport function ListAdder () {\n  return import(/*webpackChunkName: \"features/list_adder\" */'../../list_adder');\n}\n\nexport function Search () {\n  return import(/*webpackChunkName: \"features/search\" */'../../search');\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/util/fullscreen.js",
    "content": "// APIs for normalizing fullscreen operations. Note that Edge uses\n// the WebKit-prefixed APIs currently (as of Edge 16).\n\nexport const isFullscreen = () => document.fullscreenElement ||\n  document.webkitFullscreenElement ||\n  document.mozFullScreenElement;\n\nexport const exitFullscreen = () => {\n  if (document.exitFullscreen) {\n    document.exitFullscreen();\n  } else if (document.webkitExitFullscreen) {\n    document.webkitExitFullscreen();\n  } else if (document.mozCancelFullScreen) {\n    document.mozCancelFullScreen();\n  }\n};\n\nexport const requestFullscreen = el => {\n  if (el.requestFullscreen) {\n    el.requestFullscreen();\n  } else if (el.webkitRequestFullscreen) {\n    el.webkitRequestFullscreen();\n  } else if (el.mozRequestFullScreen) {\n    el.mozRequestFullScreen();\n  }\n};\n\nexport const attachFullscreenListener = (listener) => {\n  if ('onfullscreenchange' in document) {\n    document.addEventListener('fullscreenchange', listener);\n  } else if ('onwebkitfullscreenchange' in document) {\n    document.addEventListener('webkitfullscreenchange', listener);\n  } else if ('onmozfullscreenchange' in document) {\n    document.addEventListener('mozfullscreenchange', listener);\n  }\n};\n\nexport const detachFullscreenListener = (listener) => {\n  if ('onfullscreenchange' in document) {\n    document.removeEventListener('fullscreenchange', listener);\n  } else if ('onwebkitfullscreenchange' in document) {\n    document.removeEventListener('webkitfullscreenchange', listener);\n  } else if ('onmozfullscreenchange' in document) {\n    document.removeEventListener('mozfullscreenchange', listener);\n  }\n};\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/util/get_rect_from_entry.js",
    "content": "\n// Get the bounding client rect from an IntersectionObserver entry.\n// This is to work around a bug in Chrome: https://crbug.com/737228\n\nlet hasBoundingRectBug;\n\nfunction getRectFromEntry(entry) {\n  if (typeof hasBoundingRectBug !== 'boolean') {\n    const boundingRect = entry.target.getBoundingClientRect();\n    const observerRect = entry.boundingClientRect;\n    hasBoundingRectBug = boundingRect.height !== observerRect.height ||\n      boundingRect.top !== observerRect.top ||\n      boundingRect.width !== observerRect.width ||\n      boundingRect.bottom !== observerRect.bottom ||\n      boundingRect.left !== observerRect.left ||\n      boundingRect.right !== observerRect.right;\n  }\n  return hasBoundingRectBug ? entry.target.getBoundingClientRect() : entry.boundingClientRect;\n}\n\nexport default getRectFromEntry;\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/util/intersection_observer_wrapper.js",
    "content": "// Wrapper for IntersectionObserver in order to make working with it\n// a bit easier. We also follow this performance advice:\n// \"If you need to observe multiple elements, it is both possible and\n// advised to observe multiple elements using the same IntersectionObserver\n// instance by calling observe() multiple times.\"\n// https://developers.google.com/web/updates/2016/04/intersectionobserver\n\nclass IntersectionObserverWrapper {\n\n  callbacks = {};\n  observerBacklog = [];\n  observer = null;\n\n  connect (options) {\n    const onIntersection = (entries) => {\n      entries.forEach(entry => {\n        const id = entry.target.getAttribute('data-id');\n        if (this.callbacks[id]) {\n          this.callbacks[id](entry);\n        }\n      });\n    };\n\n    this.observer = new IntersectionObserver(onIntersection, options);\n    this.observerBacklog.forEach(([ id, node, callback ]) => {\n      this.observe(id, node, callback);\n    });\n    this.observerBacklog = null;\n  }\n\n  observe (id, node, callback) {\n    if (!this.observer) {\n      this.observerBacklog.push([ id, node, callback ]);\n    } else {\n      this.callbacks[id] = callback;\n      this.observer.observe(node);\n    }\n  }\n\n  unobserve (id, node) {\n    if (this.observer) {\n      delete this.callbacks[id];\n      this.observer.unobserve(node);\n    }\n  }\n\n  disconnect () {\n    if (this.observer) {\n      this.callbacks = {};\n      this.observer.disconnect();\n      this.observer = null;\n    }\n  }\n\n}\n\nexport default IntersectionObserverWrapper;\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/util/optional_motion.js",
    "content": "import { reduceMotion } from '../../../initial_state';\nimport ReducedMotion from './reduced_motion';\nimport Motion from 'react-motion/lib/Motion';\n\nexport default reduceMotion ? ReducedMotion : Motion;\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/util/react_router_helpers.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport { Switch, Route } from 'react-router-dom';\n\nimport ColumnLoading from '../components/column_loading';\nimport BundleColumnError from '../components/bundle_column_error';\nimport BundleContainer from '../containers/bundle_container';\n\n// Small wrapper to pass multiColumn to the route components\nexport class WrappedSwitch extends React.PureComponent {\n\n  render () {\n    const { multiColumn, children } = this.props;\n\n    return (\n      <Switch>\n        {React.Children.map(children, child => React.cloneElement(child, { multiColumn }))}\n      </Switch>\n    );\n  }\n\n}\n\nWrappedSwitch.propTypes = {\n  multiColumn: PropTypes.bool,\n  children: PropTypes.node,\n};\n\n// Small Wrapper to extract the params from the route and pass\n// them to the rendered component, together with the content to\n// be rendered inside (the children)\nexport class WrappedRoute extends React.Component {\n\n  static propTypes = {\n    component: PropTypes.func.isRequired,\n    content: PropTypes.node,\n    multiColumn: PropTypes.bool,\n    componentParams: PropTypes.object,\n  };\n\n  static defaultProps = {\n    componentParams: {},\n  };\n\n  renderComponent = ({ match }) => {\n    const { component, content, multiColumn, componentParams } = this.props;\n\n    return (\n      <BundleContainer fetchComponent={component} loading={this.renderLoading} error={this.renderError}>\n        {Component => <Component params={match.params} multiColumn={multiColumn} {...componentParams}>{content}</Component>}\n      </BundleContainer>\n    );\n  }\n\n  renderLoading = () => {\n    return <ColumnLoading />;\n  }\n\n  renderError = (props) => {\n    return <BundleColumnError {...props} />;\n  }\n\n  render () {\n    const { component: Component, content, ...rest } = this.props;\n\n    return <Route {...rest} render={this.renderComponent} />;\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/util/reduced_motion.js",
    "content": "// Like react-motion's Motion, but reduces all animations to cross-fades\n// for the benefit of users with motion sickness.\nimport React from 'react';\nimport Motion from 'react-motion/lib/Motion';\nimport PropTypes from 'prop-types';\n\nconst stylesToKeep = ['opacity', 'backgroundOpacity'];\n\nconst extractValue = (value) => {\n  // This is either an object with a \"val\" property or it's a number\n  return (typeof value === 'object' && value && 'val' in value) ? value.val : value;\n};\n\nclass ReducedMotion extends React.Component {\n\n  static propTypes = {\n    defaultStyle: PropTypes.object,\n    style: PropTypes.object,\n    children: PropTypes.func,\n  }\n\n  render() {\n\n    const { style, defaultStyle, children } = this.props;\n\n    Object.keys(style).forEach(key => {\n      if (stylesToKeep.includes(key)) {\n        return;\n      }\n      // If it's setting an x or height or scale or some other value, we need\n      // to preserve the end-state value without actually animating it\n      style[key] = defaultStyle[key] = extractValue(style[key]);\n    });\n\n    return (\n      <Motion style={style} defaultStyle={defaultStyle}>\n        {children}\n      </Motion>\n    );\n  }\n\n}\n\nexport default ReducedMotion;\n"
  },
  {
    "path": "app/javascript/mastodon/features/ui/util/schedule_idle_task.js",
    "content": "// Wrapper to call requestIdleCallback() to schedule low-priority work.\n// See https://developer.mozilla.org/en-US/docs/Web/API/Background_Tasks_API\n// for a good breakdown of the concepts behind this.\n\nimport Queue from 'tiny-queue';\n\nconst taskQueue = new Queue();\nlet runningRequestIdleCallback = false;\n\nfunction runTasks(deadline) {\n  while (taskQueue.length && deadline.timeRemaining() > 0) {\n    taskQueue.shift()();\n  }\n  if (taskQueue.length) {\n    requestIdleCallback(runTasks);\n  } else {\n    runningRequestIdleCallback = false;\n  }\n}\n\nfunction scheduleIdleTask(task) {\n  taskQueue.push(task);\n  if (!runningRequestIdleCallback) {\n    runningRequestIdleCallback = true;\n    requestIdleCallback(runTasks);\n  }\n}\n\nexport default scheduleIdleTask;\n"
  },
  {
    "path": "app/javascript/mastodon/features/video/index.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport { defineMessages, injectIntl, FormattedMessage } from 'react-intl';\nimport { fromJS, is } from 'immutable';\nimport { throttle } from 'lodash';\nimport classNames from 'classnames';\nimport { isFullscreen, requestFullscreen, exitFullscreen } from '../ui/util/fullscreen';\nimport { displayMedia } from '../../initial_state';\nimport Icon from 'mastodon/components/icon';\nimport { decode } from 'blurhash';\n\nconst messages = defineMessages({\n  play: { id: 'video.play', defaultMessage: 'Play' },\n  pause: { id: 'video.pause', defaultMessage: 'Pause' },\n  mute: { id: 'video.mute', defaultMessage: 'Mute sound' },\n  unmute: { id: 'video.unmute', defaultMessage: 'Unmute sound' },\n  hide: { id: 'video.hide', defaultMessage: 'Hide video' },\n  expand: { id: 'video.expand', defaultMessage: 'Expand video' },\n  close: { id: 'video.close', defaultMessage: 'Close video' },\n  fullscreen: { id: 'video.fullscreen', defaultMessage: 'Full screen' },\n  exit_fullscreen: { id: 'video.exit_fullscreen', defaultMessage: 'Exit full screen' },\n});\n\nconst formatTime = secondsNum => {\n  let hours   = Math.floor(secondsNum / 3600);\n  let minutes = Math.floor((secondsNum - (hours * 3600)) / 60);\n  let seconds = secondsNum - (hours * 3600) - (minutes * 60);\n\n  if (hours   < 10) hours   = '0' + hours;\n  if (minutes < 10) minutes = '0' + minutes;\n  if (seconds < 10) seconds = '0' + seconds;\n\n  return (hours === '00' ? '' : `${hours}:`) + `${minutes}:${seconds}`;\n};\n\nexport const findElementPosition = el => {\n  let box;\n\n  if (el.getBoundingClientRect && el.parentNode) {\n    box = el.getBoundingClientRect();\n  }\n\n  if (!box) {\n    return {\n      left: 0,\n      top: 0,\n    };\n  }\n\n  const docEl = document.documentElement;\n  const body  = document.body;\n\n  const clientLeft = docEl.clientLeft || body.clientLeft || 0;\n  const scrollLeft = window.pageXOffset || body.scrollLeft;\n  const left       = (box.left + scrollLeft) - clientLeft;\n\n  const clientTop = docEl.clientTop || body.clientTop || 0;\n  const scrollTop = window.pageYOffset || body.scrollTop;\n  const top       = (box.top + scrollTop) - clientTop;\n\n  return {\n    left: Math.round(left),\n    top: Math.round(top),\n  };\n};\n\nexport const getPointerPosition = (el, event) => {\n  const position = {};\n  const box = findElementPosition(el);\n  const boxW = el.offsetWidth;\n  const boxH = el.offsetHeight;\n  const boxY = box.top;\n  const boxX = box.left;\n\n  let pageY = event.pageY;\n  let pageX = event.pageX;\n\n  if (event.changedTouches) {\n    pageX = event.changedTouches[0].pageX;\n    pageY = event.changedTouches[0].pageY;\n  }\n\n  position.y = Math.max(0, Math.min(1, (pageY - boxY) / boxH));\n  position.x = Math.max(0, Math.min(1, (pageX - boxX) / boxW));\n\n  return position;\n};\n\nexport default @injectIntl\nclass Video extends React.PureComponent {\n\n  static propTypes = {\n    preview: PropTypes.string,\n    src: PropTypes.string.isRequired,\n    alt: PropTypes.string,\n    width: PropTypes.number,\n    height: PropTypes.number,\n    sensitive: PropTypes.bool,\n    startTime: PropTypes.number,\n    onOpenVideo: PropTypes.func,\n    onCloseVideo: PropTypes.func,\n    detailed: PropTypes.bool,\n    inline: PropTypes.bool,\n    cacheWidth: PropTypes.func,\n    visible: PropTypes.bool,\n    onToggleVisibility: PropTypes.func,\n    intl: PropTypes.object.isRequired,\n    blurhash: PropTypes.string,\n    link: PropTypes.node,\n  };\n\n  state = {\n    currentTime: 0,\n    duration: 0,\n    volume: 0.5,\n    paused: true,\n    dragging: false,\n    containerWidth: this.props.width,\n    fullscreen: false,\n    hovered: false,\n    muted: false,\n    revealed: this.props.visible !== undefined ? this.props.visible : (displayMedia !== 'hide_all' && !this.props.sensitive || displayMedia === 'show_all'),\n  };\n\n  // hard coded in components.scss\n  // any way to get ::before values programatically?\n  volWidth = 50;\n  volOffset = 70;\n  volHandleOffset = v => {\n    const offset = v * this.volWidth + this.volOffset;\n    return (offset > 110) ? 110 : offset;\n  }\n\n  setPlayerRef = c => {\n    this.player = c;\n\n    if (c) {\n      if (this.props.cacheWidth) this.props.cacheWidth(this.player.offsetWidth);\n      this.setState({\n        containerWidth: c.offsetWidth,\n      });\n    }\n  }\n\n  setVideoRef = c => {\n    this.video = c;\n\n    if (this.video) {\n      this.setState({ volume: this.video.volume, muted: this.video.muted });\n    }\n  }\n\n  setSeekRef = c => {\n    this.seek = c;\n  }\n\n  setVolumeRef = c => {\n    this.volume = c;\n  }\n\n  setCanvasRef = c => {\n    this.canvas = c;\n  }\n\n  handleClickRoot = e => e.stopPropagation();\n\n  handlePlay = () => {\n    this.setState({ paused: false });\n  }\n\n  handlePause = () => {\n    this.setState({ paused: true });\n  }\n\n  handleTimeUpdate = () => {\n    this.setState({\n      currentTime: Math.floor(this.video.currentTime),\n      duration: Math.floor(this.video.duration),\n    });\n  }\n\n  handleVolumeMouseDown = e => {\n    document.addEventListener('mousemove', this.handleMouseVolSlide, true);\n    document.addEventListener('mouseup', this.handleVolumeMouseUp, true);\n    document.addEventListener('touchmove', this.handleMouseVolSlide, true);\n    document.addEventListener('touchend', this.handleVolumeMouseUp, true);\n\n    this.handleMouseVolSlide(e);\n\n    e.preventDefault();\n    e.stopPropagation();\n  }\n\n  handleVolumeMouseUp = () => {\n    document.removeEventListener('mousemove', this.handleMouseVolSlide, true);\n    document.removeEventListener('mouseup', this.handleVolumeMouseUp, true);\n    document.removeEventListener('touchmove', this.handleMouseVolSlide, true);\n    document.removeEventListener('touchend', this.handleVolumeMouseUp, true);\n  }\n\n  handleMouseVolSlide = throttle(e => {\n    const rect = this.volume.getBoundingClientRect();\n    const x = (e.clientX - rect.left) / this.volWidth; //x position within the element.\n\n    if(!isNaN(x)) {\n      var slideamt = x;\n      if(x > 1) {\n        slideamt = 1;\n      } else if(x < 0) {\n        slideamt = 0;\n      }\n      this.video.volume = slideamt;\n      this.setState({ volume: slideamt });\n    }\n  }, 60);\n\n  handleMouseDown = e => {\n    document.addEventListener('mousemove', this.handleMouseMove, true);\n    document.addEventListener('mouseup', this.handleMouseUp, true);\n    document.addEventListener('touchmove', this.handleMouseMove, true);\n    document.addEventListener('touchend', this.handleMouseUp, true);\n\n    this.setState({ dragging: true });\n    this.video.pause();\n    this.handleMouseMove(e);\n\n    e.preventDefault();\n    e.stopPropagation();\n  }\n\n  handleMouseUp = () => {\n    document.removeEventListener('mousemove', this.handleMouseMove, true);\n    document.removeEventListener('mouseup', this.handleMouseUp, true);\n    document.removeEventListener('touchmove', this.handleMouseMove, true);\n    document.removeEventListener('touchend', this.handleMouseUp, true);\n\n    this.setState({ dragging: false });\n    this.video.play();\n  }\n\n  handleMouseMove = throttle(e => {\n    const { x } = getPointerPosition(this.seek, e);\n    const currentTime = Math.floor(this.video.duration * x);\n\n    if (!isNaN(currentTime)) {\n      this.video.currentTime = currentTime;\n      this.setState({ currentTime });\n    }\n  }, 60);\n\n  togglePlay = () => {\n    if (this.state.paused) {\n      this.video.play();\n    } else {\n      this.video.pause();\n    }\n  }\n\n  toggleFullscreen = () => {\n    if (isFullscreen()) {\n      exitFullscreen();\n    } else {\n      requestFullscreen(this.player);\n    }\n  }\n\n  componentDidMount () {\n    document.addEventListener('fullscreenchange', this.handleFullscreenChange, true);\n    document.addEventListener('webkitfullscreenchange', this.handleFullscreenChange, true);\n    document.addEventListener('mozfullscreenchange', this.handleFullscreenChange, true);\n    document.addEventListener('MSFullscreenChange', this.handleFullscreenChange, true);\n\n    if (this.props.blurhash) {\n      this._decode();\n    }\n  }\n\n  componentWillUnmount () {\n    document.removeEventListener('fullscreenchange', this.handleFullscreenChange, true);\n    document.removeEventListener('webkitfullscreenchange', this.handleFullscreenChange, true);\n    document.removeEventListener('mozfullscreenchange', this.handleFullscreenChange, true);\n    document.removeEventListener('MSFullscreenChange', this.handleFullscreenChange, true);\n  }\n\n  componentWillReceiveProps (nextProps) {\n    if (!is(nextProps.visible, this.props.visible) && nextProps.visible !== undefined) {\n      this.setState({ revealed: nextProps.visible });\n    }\n  }\n\n  componentDidUpdate (prevProps, prevState) {\n    if (prevState.revealed && !this.state.revealed && this.video) {\n      this.video.pause();\n    }\n    if (prevProps.blurhash !== this.props.blurhash && this.props.blurhash) {\n      this._decode();\n    }\n  }\n\n  _decode () {\n    const hash   = this.props.blurhash;\n    const pixels = decode(hash, 32, 32);\n\n    if (pixels) {\n      const ctx       = this.canvas.getContext('2d');\n      const imageData = new ImageData(pixels, 32, 32);\n\n      ctx.putImageData(imageData, 0, 0);\n    }\n  }\n\n  handleFullscreenChange = () => {\n    this.setState({ fullscreen: isFullscreen() });\n  }\n\n  handleMouseEnter = () => {\n    this.setState({ hovered: true });\n  }\n\n  handleMouseLeave = () => {\n    this.setState({ hovered: false });\n  }\n\n  toggleMute = () => {\n    this.video.muted = !this.video.muted;\n    this.setState({ muted: this.video.muted });\n  }\n\n  toggleReveal = () => {\n    if (this.props.onToggleVisibility) {\n      this.props.onToggleVisibility();\n    } else {\n      this.setState({ revealed: !this.state.revealed });\n    }\n  }\n\n  handleLoadedData = () => {\n    if (this.props.startTime) {\n      this.video.currentTime = this.props.startTime;\n      this.video.play();\n    }\n  }\n\n  handleProgress = () => {\n    if (this.video.buffered.length > 0) {\n      this.setState({ buffer: this.video.buffered.end(0) / this.video.duration * 100 });\n    }\n  }\n\n  handleVolumeChange = () => {\n    this.setState({ volume: this.video.volume, muted: this.video.muted });\n  }\n\n  handleOpenVideo = () => {\n    const { src, preview, width, height, alt } = this.props;\n\n    const media = fromJS({\n      type: 'video',\n      url: src,\n      preview_url: preview,\n      description: alt,\n      width,\n      height,\n    });\n\n    this.video.pause();\n    this.props.onOpenVideo(media, this.video.currentTime);\n  }\n\n  handleCloseVideo = () => {\n    this.video.pause();\n    this.props.onCloseVideo();\n  }\n\n  render () {\n    const { preview, src, inline, startTime, onOpenVideo, onCloseVideo, intl, alt, detailed, sensitive, link } = this.props;\n    const { containerWidth, currentTime, duration, volume, buffer, dragging, paused, fullscreen, hovered, muted, revealed } = this.state;\n    const progress = (currentTime / duration) * 100;\n\n    const volumeWidth = (muted) ? 0 : volume * this.volWidth;\n    const volumeHandleLoc = (muted) ? this.volHandleOffset(0) : this.volHandleOffset(volume);\n    const playerStyle = {};\n\n    let { width, height } = this.props;\n\n    if (inline && containerWidth) {\n      width  = containerWidth;\n      height = containerWidth / (16/9);\n\n      playerStyle.height = height;\n    }\n\n    let preload;\n\n    if (startTime || fullscreen || dragging) {\n      preload = 'auto';\n    } else if (detailed) {\n      preload = 'metadata';\n    } else {\n      preload = 'none';\n    }\n\n    let warning;\n\n    if (sensitive) {\n      warning = <FormattedMessage id='status.sensitive_warning' defaultMessage='Sensitive content' />;\n    } else {\n      warning = <FormattedMessage id='status.media_hidden' defaultMessage='Media hidden' />;\n    }\n\n    return (\n      <div\n        role='menuitem'\n        className={classNames('video-player', { inactive: !revealed, detailed, inline: inline && !fullscreen, fullscreen })}\n        style={playerStyle}\n        ref={this.setPlayerRef}\n        onMouseEnter={this.handleMouseEnter}\n        onMouseLeave={this.handleMouseLeave}\n        onClick={this.handleClickRoot}\n        tabIndex={0}\n      >\n        <canvas width={32} height={32} ref={this.setCanvasRef} className={classNames('media-gallery__preview', { 'media-gallery__preview--hidden': revealed })} />\n\n        {revealed && <video\n          ref={this.setVideoRef}\n          src={src}\n          poster={preview}\n          preload={preload}\n          loop\n          role='button'\n          tabIndex='0'\n          aria-label={alt}\n          title={alt}\n          width={width}\n          height={height}\n          volume={volume}\n          onClick={this.togglePlay}\n          onPlay={this.handlePlay}\n          onPause={this.handlePause}\n          onTimeUpdate={this.handleTimeUpdate}\n          onLoadedData={this.handleLoadedData}\n          onProgress={this.handleProgress}\n          onVolumeChange={this.handleVolumeChange}\n        />}\n\n        <div className={classNames('spoiler-button', { 'spoiler-button--hidden': revealed })}>\n          <button type='button' className='spoiler-button__overlay' onClick={this.toggleReveal}>\n            <span className='spoiler-button__overlay__label'>{warning}</span>\n          </button>\n        </div>\n\n        <div className={classNames('video-player__controls', { active: paused || hovered })}>\n          <div className='video-player__seek' onMouseDown={this.handleMouseDown} ref={this.setSeekRef}>\n            <div className='video-player__seek__buffer' style={{ width: `${buffer}%` }} />\n            <div className='video-player__seek__progress' style={{ width: `${progress}%` }} />\n\n            <span\n              className={classNames('video-player__seek__handle', { active: dragging })}\n              tabIndex='0'\n              style={{ left: `${progress}%` }}\n            />\n          </div>\n\n          <div className='video-player__buttons-bar'>\n            <div className='video-player__buttons left'>\n              <button type='button' aria-label={intl.formatMessage(paused ? messages.play : messages.pause)} onClick={this.togglePlay}><Icon id={paused ? 'play' : 'pause'} fixedWidth /></button>\n              <button type='button' aria-label={intl.formatMessage(muted ? messages.unmute : messages.mute)} onClick={this.toggleMute}><Icon id={muted ? 'volume-off' : 'volume-up'} fixedWidth /></button>\n\n              <div className='video-player__volume' onMouseDown={this.handleVolumeMouseDown} ref={this.setVolumeRef}>\n                <div className='video-player__volume__current' style={{ width: `${volumeWidth}px` }} />\n                <span\n                  className={classNames('video-player__volume__handle')}\n                  tabIndex='0'\n                  style={{ left: `${volumeHandleLoc}px` }}\n                />\n              </div>\n\n              {(detailed || fullscreen) && (\n                <span>\n                  <span className='video-player__time-current'>{formatTime(currentTime)}</span>\n                  <span className='video-player__time-sep'>/</span>\n                  <span className='video-player__time-total'>{formatTime(duration)}</span>\n                </span>\n              )}\n\n              {link && <span className='video-player__link'>{link}</span>}\n            </div>\n\n            <div className='video-player__buttons right'>\n              {!onCloseVideo && <button type='button' aria-label={intl.formatMessage(messages.hide)} onClick={this.toggleReveal}><Icon id='eye-slash' fixedWidth /></button>}\n              {(!fullscreen && onOpenVideo) && <button type='button' aria-label={intl.formatMessage(messages.expand)} onClick={this.handleOpenVideo}><Icon id='expand' fixedWidth /></button>}\n              {onCloseVideo && <button type='button' aria-label={intl.formatMessage(messages.close)} onClick={this.handleCloseVideo}><Icon id='compress' fixedWidth /></button>}\n              <button type='button' aria-label={intl.formatMessage(fullscreen ? messages.exit_fullscreen : messages.fullscreen)} onClick={this.toggleFullscreen}><Icon id={fullscreen ? 'compress' : 'arrows-alt'} fixedWidth /></button>\n            </div>\n          </div>\n        </div>\n      </div>\n    );\n  }\n\n}\n"
  },
  {
    "path": "app/javascript/mastodon/initial_state.js",
    "content": "const element = document.getElementById('initial-state');\nconst initialState = element && JSON.parse(element.textContent);\n\nconst getMeta = (prop) => initialState && initialState.meta && initialState.meta[prop];\n\nexport const reduceMotion = getMeta('reduce_motion');\nexport const autoPlayGif = getMeta('auto_play_gif');\nexport const displayMedia = getMeta('display_media');\nexport const expandSpoilers = getMeta('expand_spoilers');\nexport const unfollowModal = getMeta('unfollow_modal');\nexport const boostModal = getMeta('boost_modal');\nexport const deleteModal = getMeta('delete_modal');\nexport const me = getMeta('me');\nexport const searchEnabled = getMeta('search_enabled');\nexport const maxBioChars = getMeta('max_bio_chars');\nexport const maxChars = getMeta('max_toot_chars');\nexport const invitesEnabled = getMeta('invites_enabled');\nexport const repository = getMeta('repository');\nexport const source_url = getMeta('source_url');\nexport const version = getMeta('version');\nexport const mascot = getMeta('mascot');\nexport const profile_directory = getMeta('profile_directory');\nexport const isStaff = getMeta('is_staff');\nexport const forceSingleColumn = !getMeta('advanced_layout');\n\nexport default initialState;\n"
  },
  {
    "path": "app/javascript/mastodon/is_mobile.js",
    "content": "import detectPassiveEvents from 'detect-passive-events';\n\nconst LAYOUT_BREAKPOINT = 630;\n\nexport function isMobile(width) {\n  return width <= LAYOUT_BREAKPOINT;\n};\n\nconst iOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;\n\nlet userTouching = false;\nlet listenerOptions = detectPassiveEvents.hasSupport ? { passive: true } : false;\n\nfunction touchListener() {\n  userTouching = true;\n  window.removeEventListener('touchstart', touchListener, listenerOptions);\n}\n\nwindow.addEventListener('touchstart', touchListener, listenerOptions);\n\nexport function isUserTouching() {\n  return userTouching;\n}\n\nexport function isIOS() {\n  return iOS;\n};\n"
  },
  {
    "path": "app/javascript/mastodon/load_polyfills.js",
    "content": "// Convenience function to load polyfills and return a promise when it's done.\n// If there are no polyfills, then this is just Promise.resolve() which means\n// it will execute in the same tick of the event loop (i.e. near-instant).\n\nfunction importBasePolyfills() {\n  return import(/* webpackChunkName: \"base_polyfills\" */ './base_polyfills');\n}\n\nfunction importExtraPolyfills() {\n  return import(/* webpackChunkName: \"extra_polyfills\" */ './extra_polyfills');\n}\n\nfunction loadPolyfills() {\n  const needsBasePolyfills = !(\n    Array.prototype.includes &&\n    HTMLCanvasElement.prototype.toBlob &&\n    window.Intl &&\n    Number.isNaN &&\n    Object.assign &&\n    Object.values &&\n    window.Symbol\n  );\n\n  // Latest version of Firefox and Safari do not have IntersectionObserver.\n  // Edge does not have requestIdleCallback and object-fit CSS property.\n  // This avoids shipping them all the polyfills.\n  const needsExtraPolyfills = !(\n    window.IntersectionObserver &&\n    window.IntersectionObserverEntry &&\n    'isIntersecting' in IntersectionObserverEntry.prototype &&\n    window.requestIdleCallback &&\n    'object-fit' in (new Image()).style\n  );\n\n  return Promise.all([\n    needsBasePolyfills && importBasePolyfills(),\n    needsExtraPolyfills && importExtraPolyfills(),\n  ]);\n}\n\nexport default loadPolyfills;\n"
  },
  {
    "path": "app/javascript/mastodon/locales/ar.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"أضفه أو أزله من القائمة\",\n  \"account.badges.bot\": \"روبوت\",\n  \"account.block\": \"حظر @{name}\",\n  \"account.block_domain\": \"إخفاء كل شيئ قادم من اسم النطاق {domain}\",\n  \"account.blocked\": \"محظور\",\n  \"account.direct\": \"رسالة خاصة إلى @{name}\",\n  \"account.domain_blocked\": \"النطاق مخفي\",\n  \"account.edit_profile\": \"تعديل الملف الشخصي\",\n  \"account.endorse\": \"خاصّية على الملف الشخصي\",\n  \"account.follow\": \"تابِع\",\n  \"account.followers\": \"متابعون\",\n  \"account.followers.empty\": \"لا أحد يتبع هذا الحساب بعد.\",\n  \"account.follows\": \"يتبع\",\n  \"account.follows.empty\": \"هذا الحساب لا يتبع أحدًا بعد.\",\n  \"account.follows_you\": \"يتابعك\",\n  \"account.hide_reblogs\": \"إخفاء ترقيات @{name}\",\n  \"account.link_verified_on\": \"تم التحقق مِن مِلْكية هذا الرابط بتاريخ {date}\",\n  \"account.locked_info\": \"تم تأمين خصوصية هذا الحساب عبر قفل. صاحب الحساب يُراجِع يدويا طلبات المتابَعة و الاشتراك بحسابه.\",\n  \"account.media\": \"وسائط\",\n  \"account.mention\": \"أُذكُر/ي @{name}\",\n  \"account.moved_to\": \"{name} انتقل إلى:\",\n  \"account.mute\": \"كتم @{name}\",\n  \"account.mute_notifications\": \"كتم الإخطارات من @{name}\",\n  \"account.muted\": \"مكتوم\",\n  \"account.posts\": \"التبويقات\",\n  \"account.posts_with_replies\": \"التبويقات و الردود\",\n  \"account.report\": \"أبلغ/ي عن @{name}\",\n  \"account.requested\": \"في انتظار الموافقة. اضْغَطْ/ي لإلغاء طلب المتابعة\",\n  \"account.share\": \"مشاركة حساب @{name}\",\n  \"account.show_reblogs\": \"عرض ترقيات @{name}\",\n  \"account.unblock\": \"إلغاء الحظر عن @{name}\",\n  \"account.unblock_domain\": \"فك الخْفى عن {domain}\",\n  \"account.unendorse\": \"إزالة ترويجه مِن الملف الشخصي\",\n  \"account.unfollow\": \"إلغاء المتابعة\",\n  \"account.unmute\": \"إلغاء الكتم عن @{name}\",\n  \"account.unmute_notifications\": \"إلغاء كتم إخطارات @{name}\",\n  \"alert.unexpected.message\": \"لقد طرأ هناك خطأ غير متوقّع.\",\n  \"alert.unexpected.title\": \"المعذرة!\",\n  \"boost_modal.combo\": \"يمكنك/ي ضغط {combo} لتخطّي هذه في المرّة القادمة\",\n  \"bundle_column_error.body\": \"لقد وقع هناك خطأ أثناء عملية تحميل هذا العنصر.\",\n  \"bundle_column_error.retry\": \"إعادة المحاولة\",\n  \"bundle_column_error.title\": \"خطأ في الشبكة\",\n  \"bundle_modal_error.close\": \"أغلق\",\n  \"bundle_modal_error.message\": \"لقد وقع هناك خطأ أثناء عملية تحميل هذا العنصر.\",\n  \"bundle_modal_error.retry\": \"إعادة المحاولة\",\n  \"column.blocks\": \"الحسابات المحجوبة\",\n  \"column.community\": \"التَسَلْسُل الزَمني المحلي\",\n  \"column.direct\": \"الرسائل المباشرة\",\n  \"column.domain_blocks\": \"النطاقات المخفية\",\n  \"column.favourites\": \"المفضلة\",\n  \"column.follow_requests\": \"طلبات المتابعة\",\n  \"column.home\": \"الرئيسية\",\n  \"column.lists\": \"القوائم\",\n  \"column.mutes\": \"الحسابات المكتومة\",\n  \"column.notifications\": \"الإخطارات\",\n  \"column.pins\": \"التبويقات المثبتة\",\n  \"column.public\": \"الخيط العام الموحد\",\n  \"column_back_button.label\": \"العودة\",\n  \"column_header.hide_settings\": \"إخفاء الإعدادات\",\n  \"column_header.moveLeft_settings\": \"نقل القائمة إلى اليسار\",\n  \"column_header.moveRight_settings\": \"نقل القائمة إلى اليمين\",\n  \"column_header.pin\": \"تدبيس\",\n  \"column_header.show_settings\": \"عرض الإعدادات\",\n  \"column_header.unpin\": \"فك التدبيس\",\n  \"column_subheading.settings\": \"الإعدادات\",\n  \"community.column_settings.media_only\": \"الوسائط فقط\",\n  \"compose_form.direct_message_warning\": \"لن يَظهر هذا التبويق إلا للمستخدمين المذكورين.\",\n  \"compose_form.direct_message_warning_learn_more\": \"اقرأ المزيد\",\n  \"compose_form.hashtag_warning\": \"هذا التبويق لن يُدرَج تحت أي وسم كان بما أنه غير مُدرَج. لا يُسمح بالبحث إلّا عن التبويقات العمومية عن طريق الوسوم.\",\n  \"compose_form.lock_disclaimer\": \"حسابك ليس {locked}. يمكن لأي شخص متابعتك و عرض المنشورات.\",\n  \"compose_form.lock_disclaimer.lock\": \"مقفل\",\n  \"compose_form.placeholder\": \"فيمَ تفكّر؟\",\n  \"compose_form.poll.add_option\": \"إضافة خيار\",\n  \"compose_form.poll.duration\": \"مدة استطلاع الرأي\",\n  \"compose_form.poll.option_placeholder\": \"الخيار {number}\",\n  \"compose_form.poll.remove_option\": \"إزالة هذا الخيار\",\n  \"compose_form.publish\": \"بوّق\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"تحديد الوسائط كحساسة\",\n  \"compose_form.sensitive.marked\": \"لقد تم تحديد هذه الصورة كحساسة\",\n  \"compose_form.sensitive.unmarked\": \"لم يتم تحديد الصورة كحساسة\",\n  \"compose_form.spoiler.marked\": \"إنّ النص مخفي وراء تحذير\",\n  \"compose_form.spoiler.unmarked\": \"النص غير مخفي\",\n  \"compose_form.spoiler_placeholder\": \"تنبيه عن المحتوى\",\n  \"confirmation_modal.cancel\": \"إلغاء\",\n  \"confirmations.block.block_and_report\": \"احجبه وابلغ عنه\",\n  \"confirmations.block.confirm\": \"حجب\",\n  \"confirmations.block.message\": \"هل أنت متأكد أنك تريد حجب {name} ؟\",\n  \"confirmations.delete.confirm\": \"حذف\",\n  \"confirmations.delete.message\": \"هل أنت متأكد أنك تريد حذف هذا المنشور ؟\",\n  \"confirmations.delete_list.confirm\": \"احذف\",\n  \"confirmations.delete_list.message\": \"هل تود حقا حذف هذه القائمة ؟\",\n  \"confirmations.domain_block.confirm\": \"إخفاء اسم النطاق كاملا\",\n  \"confirmations.domain_block.message\": \"متأكد من أنك تود حظر اسم النطاق {domain} بالكامل ؟ في غالب الأحيان يُستَحسَن كتم أو حظر بعض الحسابات بدلا من حظر نطاق بالكامل.\\nلن تتمكن مِن رؤية محتوى هذا النطاق لا على خيوطك العمومية و لا في إشعاراتك. سوف يتم كذلك إزالة كافة متابعيك المنتمين إلى هذا النطاق.\",\n  \"confirmations.mute.confirm\": \"أكتم\",\n  \"confirmations.mute.message\": \"هل أنت متأكد أنك تريد كتم {name} ؟\",\n  \"confirmations.redraft.confirm\": \"إزالة و إعادة الصياغة\",\n  \"confirmations.redraft.message\": \"هل أنت متأكد من أنك تريد حذف هذا المنشور و إعادة صياغته ؟ سوف تفقد جميع الإعجابات و الترقيات أما الردود المتصلة به فستُصبِح يتيمة.\",\n  \"confirmations.reply.confirm\": \"رد\",\n  \"confirmations.reply.message\": \"الرد في الحين سوف يُعيد كتابة الرسالة التي أنت بصدد كتابتها. متأكد من أنك تريد المواصلة؟\",\n  \"confirmations.unfollow.confirm\": \"إلغاء المتابعة\",\n  \"confirmations.unfollow.message\": \"متأكد من أنك تريد إلغاء متابعة {name} ؟\",\n  \"embed.instructions\": \"يمكنكم إدماج هذا المنشور على موقعكم الإلكتروني عن طريق نسخ الشفرة أدناه.\",\n  \"embed.preview\": \"هكذا ما سوف يبدو عليه:\",\n  \"emoji_button.activity\": \"الأنشطة\",\n  \"emoji_button.custom\": \"مخصص\",\n  \"emoji_button.flags\": \"الأعلام\",\n  \"emoji_button.food\": \"الطعام والشراب\",\n  \"emoji_button.label\": \"أدرج إيموجي\",\n  \"emoji_button.nature\": \"الطبيعة\",\n  \"emoji_button.not_found\": \"لا إيموجو !! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"أشياء\",\n  \"emoji_button.people\": \"الناس\",\n  \"emoji_button.recent\": \"الشائعة الاستخدام\",\n  \"emoji_button.search\": \"ابحث...\",\n  \"emoji_button.search_results\": \"نتائج البحث\",\n  \"emoji_button.symbols\": \"رموز\",\n  \"emoji_button.travel\": \"أماكن و أسفار\",\n  \"empty_column.account_timeline\": \"ليس هناك تبويقات!\",\n  \"empty_column.account_unavailable\": \"الملف الشخصي غير متوفر\",\n  \"empty_column.blocks\": \"لم تقم بحظر أي مستخدِم بعد.\",\n  \"empty_column.community\": \"الخط الزمني المحلي فارغ. أكتب شيئا ما للعامة كبداية!\",\n  \"empty_column.direct\": \"لم تتلق أية رسالة خاصة مباشِرة بعد. سوف يتم عرض الرسائل المباشرة هنا إن قمت بإرسال واحدة أو تلقيت البعض منها.\",\n  \"empty_column.domain_blocks\": \"ليس هناك نطاقات مخفية بعد.\",\n  \"empty_column.favourited_statuses\": \"ليس لديك أية تبويقات مفضلة بعد. عندما ستقوم بالإعجاب بواحد، سيظهر هنا.\",\n  \"empty_column.favourites\": \"لم يقم أي أحد بالإعجاب بهذا التبويق بعد. عندما يقوم أحدهم بذلك سوف يظهر هنا.\",\n  \"empty_column.follow_requests\": \"ليس عندك أي طلب للمتابعة بعد. سوف تظهر طلباتك هنا إن قمت بتلقي البعض منها.\",\n  \"empty_column.hashtag\": \"ليس هناك بعدُ أي محتوى ذو علاقة بهذا الوسم.\",\n  \"empty_column.home\": \"إنّ الخيط الزمني لصفحتك الرئيسية فارغ. قم بزيارة {public} أو استخدم حقل البحث لكي تكتشف مستخدمين آخرين.\",\n  \"empty_column.home.public_timeline\": \"الخيط العام\",\n  \"empty_column.list\": \"هذه القائمة فارغة مؤقتا و لكن سوف تمتلئ تدريجيا عندما يبدأ الأعضاء المُنتَمين إليها بنشر تبويقات.\",\n  \"empty_column.lists\": \"ليس عندك أية قائمة بعد. سوف تظهر قائمتك هنا إن قمت بإنشاء واحدة.\",\n  \"empty_column.mutes\": \"لم تقم بكتم أي مستخدم بعد.\",\n  \"empty_column.notifications\": \"لم تتلق أي إشعار بعدُ. تفاعل مع المستخدمين الآخرين لإنشاء محادثة.\",\n  \"empty_column.public\": \"لا يوجد أي شيء هنا! قم بنشر شيء ما للعامة، أو اتبع المستخدمين الآخرين المتواجدين على الخوادم الأخرى لملء خيط المحادثات\",\n  \"follow_request.authorize\": \"ترخيص\",\n  \"follow_request.reject\": \"رفض\",\n  \"getting_started.developers\": \"المُطوِّرون\",\n  \"getting_started.directory\": \"دليل المستخدِمين والمستخدِمات\",\n  \"getting_started.documentation\": \"الدليل\",\n  \"getting_started.heading\": \"استعدّ للبدء\",\n  \"getting_started.invite\": \"دعوة أشخاص\",\n  \"getting_started.open_source_notice\": \"ماستدون برنامج مفتوح المصدر. يمكنك المساهمة، أو الإبلاغ عن تقارير الأخطاء، على جيت هب {github}.\",\n  \"getting_started.security\": \"الأمان\",\n  \"getting_started.terms\": \"شروط الخدمة\",\n  \"hashtag.column_header.tag_mode.all\": \"و {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"أو {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"بدون {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"لم يُعثَر على أي اقتراح\",\n  \"hashtag.column_settings.select.placeholder\": \"قم بإدخال وسوم…\",\n  \"hashtag.column_settings.tag_mode.all\": \"كلها\",\n  \"hashtag.column_settings.tag_mode.any\": \"أي كان مِن هذه\",\n  \"hashtag.column_settings.tag_mode.none\": \"لا شيء مِن هذه\",\n  \"hashtag.column_settings.tag_toggle\": \"إدراج الوسوم الإضافية لهذا العمود\",\n  \"home.column_settings.basic\": \"أساسية\",\n  \"home.column_settings.show_reblogs\": \"عرض الترقيات\",\n  \"home.column_settings.show_replies\": \"عرض الردود\",\n  \"intervals.full.days\": \"{number, plural, one {# يوم} other {# أيام}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# ساعة} other {# ساعات}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# دقيقة} other {# دقائق}}\",\n  \"introduction.federation.action\": \"التالي\",\n  \"introduction.federation.federated.headline\": \"الفديرالي\",\n  \"introduction.federation.federated.text\": \"كافة المنشورات التي نُشِرت إلى العامة على الخوادم الأخرى للفديفرس سوف يتم عرضها على الخيط المُوحَّد.\",\n  \"introduction.federation.home.headline\": \"الرئيسي\",\n  \"introduction.federation.home.text\": \"سوف تُعرَض منشورات الأشخاص الذين تُتابِعهم على الخيط الرئيسي. بإمكانك متابعة أي حساب أيا كان الخادم الذي هو عليه!\",\n  \"introduction.federation.local.headline\": \"المحلي\",\n  \"introduction.federation.local.text\": \"المنشورات المُوجّهة للعامة على نفس الخادم الذي أنتم عليه ستظهر على الخيط الزمني المحلي.\",\n  \"introduction.interactions.action\": \"إنهاء العرض التوضيحي!\",\n  \"introduction.interactions.favourite.headline\": \"الإضافة إلى المفضلة\",\n  \"introduction.interactions.favourite.text\": \"يمكِنك إضافة أي تبويق إلى المفضلة و إعلام صاحبه أنك أعجِبت بذاك التبويق.\",\n  \"introduction.interactions.reblog.headline\": \"الترقية\",\n  \"introduction.interactions.reblog.text\": \"يمكنكم مشاركة تبويقات الأشخاص الآخرين مع متابِعيكم عن طريق ترقيتها.\",\n  \"introduction.interactions.reply.headline\": \"الرد\",\n  \"introduction.interactions.reply.text\": \"يمكنكم الرد على تبويقاتكم و تبويقات الآخرين على شكل سلسلة محادثة.\",\n  \"introduction.welcome.action\": \"هيا بنا!\",\n  \"introduction.welcome.headline\": \"الخطوات الأولى\",\n  \"introduction.welcome.text\": \"مرحبا بكم على الفديفرس! بعد لحظات قليلة ، سيكون بمقدوركم بث رسائل والتحدث إلى أصدقائكم عبر تشكيلة واسعة من الخوادم المختلفة. هذا الخادم ، {domain} ، يستضيف ملفكم الشخصي ، لذا يجب تذكر اسمه جيدا.\",\n  \"keyboard_shortcuts.back\": \"للعودة\",\n  \"keyboard_shortcuts.blocked\": \"لفتح قائمة المستخدمين المحظورين\",\n  \"keyboard_shortcuts.boost\": \"للترقية\",\n  \"keyboard_shortcuts.column\": \"للتركيز على منشور على أحد الأعمدة\",\n  \"keyboard_shortcuts.compose\": \"للتركيز على نافذة تحرير النصوص\",\n  \"keyboard_shortcuts.description\": \"الوصف\",\n  \"keyboard_shortcuts.direct\": \"لفتح عمود الرسائل المباشرة\",\n  \"keyboard_shortcuts.down\": \"للانتقال إلى أسفل القائمة\",\n  \"keyboard_shortcuts.enter\": \"لفتح المنشور\",\n  \"keyboard_shortcuts.favourite\": \"للإضافة إلى المفضلة\",\n  \"keyboard_shortcuts.favourites\": \"لفتح قائمة المفضلات\",\n  \"keyboard_shortcuts.federated\": \"لفتح الخيط الزمني الفديرالي\",\n  \"keyboard_shortcuts.heading\": \"Keyboard Shortcuts\",\n  \"keyboard_shortcuts.home\": \"لفتح الخيط الرئيسي\",\n  \"keyboard_shortcuts.hotkey\": \"مفتاح الاختصار\",\n  \"keyboard_shortcuts.legend\": \"لعرض هذا المفتاح\",\n  \"keyboard_shortcuts.local\": \"لفتح الخيط الزمني المحلي\",\n  \"keyboard_shortcuts.mention\": \"لذِكر الناشر\",\n  \"keyboard_shortcuts.muted\": \"لفتح قائمة المستخدِمين المكتومين\",\n  \"keyboard_shortcuts.my_profile\": \"لفتح ملفك الشخصي\",\n  \"keyboard_shortcuts.notifications\": \"لفتح عمود الإشعارات\",\n  \"keyboard_shortcuts.pinned\": \"لفتح قائمة التبويقات المدبسة\",\n  \"keyboard_shortcuts.profile\": \"لفتح رابط الناشر\",\n  \"keyboard_shortcuts.reply\": \"للردّ\",\n  \"keyboard_shortcuts.requests\": \"لفتح قائمة طلبات المتابعة\",\n  \"keyboard_shortcuts.search\": \"للتركيز على البحث\",\n  \"keyboard_shortcuts.start\": \"لفتح عمود \\\"هيا نبدأ\\\"\",\n  \"keyboard_shortcuts.toggle_hidden\": \"لعرض أو إخفاء النص مِن وراء التحذير\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"لعرض/إخفاء الوسائط\",\n  \"keyboard_shortcuts.toot\": \"لتحرير تبويق جديد\",\n  \"keyboard_shortcuts.unfocus\": \"لإلغاء التركيز على حقل النص أو نافذة البحث\",\n  \"keyboard_shortcuts.up\": \"للانتقال إلى أعلى القائمة\",\n  \"lightbox.close\": \"إغلاق\",\n  \"lightbox.next\": \"التالي\",\n  \"lightbox.previous\": \"العودة\",\n  \"lightbox.view_context\": \"اعرض السياق\",\n  \"lists.account.add\": \"أضف إلى القائمة\",\n  \"lists.account.remove\": \"احذف من القائمة\",\n  \"lists.delete\": \"احذف القائمة\",\n  \"lists.edit\": \"تعديل القائمة\",\n  \"lists.edit.submit\": \"تعديل العنوان\",\n  \"lists.new.create\": \"إنشاء قائمة\",\n  \"lists.new.title_placeholder\": \"عنوان القائمة الجديدة\",\n  \"lists.search\": \"إبحث في قائمة الحسابات التي تُتابِعها\",\n  \"lists.subheading\": \"قوائمك\",\n  \"loading_indicator.label\": \"تحميل ...\",\n  \"media_gallery.toggle_visible\": \"عرض / إخفاء\",\n  \"missing_indicator.label\": \"تعذر العثور عليه\",\n  \"missing_indicator.sublabel\": \"تعذر العثور على هذا المورد\",\n  \"mute_modal.hide_notifications\": \"هل تود إخفاء الإخطارات القادمة من هذا المستخدم ؟\",\n  \"navigation_bar.apps\": \"تطبيقات الأجهزة المحمولة\",\n  \"navigation_bar.blocks\": \"الحسابات المحجوبة\",\n  \"navigation_bar.community_timeline\": \"الخيط العام المحلي\",\n  \"navigation_bar.compose\": \"تحرير تبويق جديد\",\n  \"navigation_bar.direct\": \"الرسائل المباشِرة\",\n  \"navigation_bar.discover\": \"اكتشف\",\n  \"navigation_bar.domain_blocks\": \"النطاقات المخفية\",\n  \"navigation_bar.edit_profile\": \"تعديل الملف الشخصي\",\n  \"navigation_bar.favourites\": \"المفضلة\",\n  \"navigation_bar.filters\": \"الكلمات المكتومة\",\n  \"navigation_bar.follow_requests\": \"طلبات المتابعة\",\n  \"navigation_bar.follows_and_followers\": \"المتابِعين والمتابَعون\",\n  \"navigation_bar.info\": \"عن هذا الخادم\",\n  \"navigation_bar.keyboard_shortcuts\": \"اختصارات لوحة المفاتيح\",\n  \"navigation_bar.lists\": \"القوائم\",\n  \"navigation_bar.logout\": \"خروج\",\n  \"navigation_bar.mutes\": \"الحسابات المكتومة\",\n  \"navigation_bar.personal\": \"شخصي\",\n  \"navigation_bar.pins\": \"التبويقات المثبتة\",\n  \"navigation_bar.preferences\": \"التفضيلات\",\n  \"navigation_bar.profile_directory\": \"دليل المستخدِمين\",\n  \"navigation_bar.public_timeline\": \"الخيط العام الموحد\",\n  \"navigation_bar.security\": \"الأمان\",\n  \"notification.favourite\": \"أُعجِب {name} بمنشورك\",\n  \"notification.follow\": \"{name} يتابعك\",\n  \"notification.mention\": \"{name} ذكرك\",\n  \"notification.poll\": \"A poll you have voted in has ended\",\n  \"notification.reblog\": \"{name} قام بترقية تبويقك\",\n  \"notifications.clear\": \"امسح الإخطارات\",\n  \"notifications.clear_confirmation\": \"أمتأكد من أنك تود مسح جل الإخطارات الخاصة بك و المتلقاة إلى حد الآن ؟\",\n  \"notifications.column_settings.alert\": \"إشعارات سطح المكتب\",\n  \"notifications.column_settings.favourite\": \"المُفَضَّلة:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"عرض كافة الفئات\",\n  \"notifications.column_settings.filter_bar.category\": \"شريط الفلترة السريعة\",\n  \"notifications.column_settings.filter_bar.show\": \"عرض\",\n  \"notifications.column_settings.follow\": \"متابعُون جُدُد:\",\n  \"notifications.column_settings.mention\": \"الإشارات:\",\n  \"notifications.column_settings.poll\": \"نتائج استطلاع الرأي:\",\n  \"notifications.column_settings.push\": \"الإخطارات المدفوعة\",\n  \"notifications.column_settings.reblog\": \"الترقيّات:\",\n  \"notifications.column_settings.show\": \"اعرِضها في عمود\",\n  \"notifications.column_settings.sound\": \"أصدر صوتا\",\n  \"notifications.filter.all\": \"الكل\",\n  \"notifications.filter.boosts\": \"الترقيات\",\n  \"notifications.filter.favourites\": \"المفضلة\",\n  \"notifications.filter.follows\": \"يتابِع\",\n  \"notifications.filter.mentions\": \"الإشارات\",\n  \"notifications.filter.polls\": \"نتائج استطلاع الرأي\",\n  \"notifications.group\": \"{count} إشعارات\",\n  \"poll.closed\": \"انتهى\",\n  \"poll.refresh\": \"تحديث\",\n  \"poll.total_votes\": \"{count, plural, one {# صوت} other {# أصوات}}\",\n  \"poll.vote\": \"صَوّت\",\n  \"poll_button.add_poll\": \"إضافة استطلاع للرأي\",\n  \"poll_button.remove_poll\": \"إزالة استطلاع الرأي\",\n  \"privacy.change\": \"اضبط خصوصية المنشور\",\n  \"privacy.direct.long\": \"أنشر إلى المستخدمين المشار إليهم فقط\",\n  \"privacy.direct.short\": \"مباشر\",\n  \"privacy.private.long\": \"أنشر لمتابعيك فقط\",\n  \"privacy.private.short\": \"لمتابعيك فقط\",\n  \"privacy.public.long\": \"أنشر على الخيوط العامة\",\n  \"privacy.public.short\": \"للعامة\",\n  \"privacy.unlisted.long\": \"لا تقم بإدراجه على الخيوط العامة\",\n  \"privacy.unlisted.short\": \"غير مدرج\",\n  \"regeneration_indicator.label\": \"جارٍ التحميل…\",\n  \"regeneration_indicator.sublabel\": \"جارٍ تجهيز تغذية صفحتك الرئيسية!\",\n  \"relative_time.days\": \"{number}ي\",\n  \"relative_time.hours\": \"{number}سا\",\n  \"relative_time.just_now\": \"الآن\",\n  \"relative_time.minutes\": \"{number}د\",\n  \"relative_time.seconds\": \"{number}ثا\",\n  \"reply_indicator.cancel\": \"إلغاء\",\n  \"report.forward\": \"التحويل إلى {target}\",\n  \"report.forward_hint\": \"هذا الحساب ينتمي إلى خادوم آخَر. هل تودّ إرسال نسخة مجهولة مِن التقرير إلى هنالك أيضًا؟\",\n  \"report.hint\": \"سوف يتم إرسال التقرير إلى المُشرِفين على خادومكم. بإمكانكم الإدلاء بشرح عن سبب الإبلاغ عن الحساب أسفله:\",\n  \"report.placeholder\": \"تعليقات إضافية\",\n  \"report.submit\": \"إرسال\",\n  \"report.target\": \"ابلغ عن {target}\",\n  \"search.placeholder\": \"ابحث\",\n  \"search_popout.search_format\": \"نمط البحث المتقدم\",\n  \"search_popout.tips.full_text\": \"النص البسيط يقوم بعرض المنشورات التي كتبتها أو قمت بإرسالها أو ترقيتها أو تمت الإشارة إليك فيها من طرف آخرين ، بالإضافة إلى مطابقة أسماء المستخدمين وأسماء العرض وعلامات التصنيف.\",\n  \"search_popout.tips.hashtag\": \"وسم\",\n  \"search_popout.tips.status\": \"حالة\",\n  \"search_popout.tips.text\": \"جملة قصيرة تُمكّنُك من عرض أسماء و حسابات و كلمات رمزية\",\n  \"search_popout.tips.user\": \"مستخدِم\",\n  \"search_results.accounts\": \"أشخاص\",\n  \"search_results.hashtags\": \"الوُسوم\",\n  \"search_results.statuses\": \"التبويقات\",\n  \"search_results.total\": \"{count, number} {count, plural, one {result} و {results}}\",\n  \"status.admin_account\": \"افتح الواجهة الإدارية لـ @{name}\",\n  \"status.admin_status\": \"افتح هذا المنشور على واجهة الإشراف\",\n  \"status.block\": \"احجب @{name}\",\n  \"status.cancel_reblog_private\": \"إلغاء الترقية\",\n  \"status.cannot_reblog\": \"تعذرت ترقية هذا المنشور\",\n  \"status.copy\": \"نسخ رابط المنشور\",\n  \"status.delete\": \"احذف\",\n  \"status.detailed_status\": \"تفاصيل المحادثة\",\n  \"status.direct\": \"رسالة خاصة إلى @{name}\",\n  \"status.embed\": \"إدماج\",\n  \"status.favourite\": \"أضف إلى المفضلة\",\n  \"status.filtered\": \"مُصفّى\",\n  \"status.load_more\": \"حمّل المزيد\",\n  \"status.media_hidden\": \"الصورة مستترة\",\n  \"status.mention\": \"أذكُر @{name}\",\n  \"status.more\": \"المزيد\",\n  \"status.mute\": \"أكتم @{name}\",\n  \"status.mute_conversation\": \"كتم المحادثة\",\n  \"status.open\": \"وسع هذه المشاركة\",\n  \"status.pin\": \"تدبيس على الملف الشخصي\",\n  \"status.pinned\": \"تبويق مثبَّت\",\n  \"status.read_more\": \"اقرأ المزيد\",\n  \"status.reblog\": \"رَقِّي\",\n  \"status.reblog_private\": \"القيام بالترقية إلى الجمهور الأصلي\",\n  \"status.reblogged_by\": \"رقّاه {name}\",\n  \"status.reblogs.empty\": \"لم يقم أي أحد بترقية هذا التبويق بعد. عندما يقوم أحدهم بذلك سوف تظهر هنا.\",\n  \"status.redraft\": \"إزالة و إعادة الصياغة\",\n  \"status.reply\": \"ردّ\",\n  \"status.replyAll\": \"رُد على الخيط\",\n  \"status.report\": \"ابلِغ عن @{name}\",\n  \"status.sensitive_warning\": \"محتوى حساس\",\n  \"status.share\": \"مشاركة\",\n  \"status.show_less\": \"اعرض أقلّ\",\n  \"status.show_less_all\": \"طي الكل\",\n  \"status.show_more\": \"أظهر المزيد\",\n  \"status.show_more_all\": \"توسيع الكل\",\n  \"status.show_thread\": \"الكشف عن المحادثة\",\n  \"status.unmute_conversation\": \"فك الكتم عن المحادثة\",\n  \"status.unpin\": \"فك التدبيس من الملف الشخصي\",\n  \"suggestions.dismiss\": \"إلغاء الاقتراح\",\n  \"suggestions.header\": \"يمكن أن يهمك…\",\n  \"tabs_bar.federated_timeline\": \"الموحَّد\",\n  \"tabs_bar.home\": \"الرئيسية\",\n  \"tabs_bar.local_timeline\": \"المحلي\",\n  \"tabs_bar.notifications\": \"الإخطارات\",\n  \"tabs_bar.search\": \"البحث\",\n  \"time_remaining.days\": \"{number, plural, one {# يوم} other {# أيام}} متبقية\",\n  \"time_remaining.hours\": \"{number, plural, one {# hour} other {# hours}} left\",\n  \"time_remaining.minutes\": \"{number, plural, one {# minute} other {# minutes}} left\",\n  \"time_remaining.moments\": \"لحظات متبقية\",\n  \"time_remaining.seconds\": \"{number, plural, one {# second} other {# seconds}} left\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {person} آخرون {people}} يتحدثون\",\n  \"ui.beforeunload\": \"سوف تفقد مسودتك إن تركت ماستدون.\",\n  \"upload_area.title\": \"اسحب ثم أفلت للرفع\",\n  \"upload_button.label\": \"إضافة وسائط (JPEG، PNG، GIF، WebM، MP4، MOV)\",\n  \"upload_error.limit\": \"لقد تم بلوغ الحد الأقصى المسموح به لإرسال الملفات.\",\n  \"upload_error.poll\": \"لا يمكن إدراج ملفات في استطلاعات الرأي.\",\n  \"upload_form.description\": \"وصف للمعاقين بصريا\",\n  \"upload_form.focus\": \"قص\",\n  \"upload_form.undo\": \"حذف\",\n  \"upload_progress.label\": \"يرفع...\",\n  \"video.close\": \"إغلاق الفيديو\",\n  \"video.exit_fullscreen\": \"الخروج من وضع الشاشة المليئة\",\n  \"video.expand\": \"توسيع الفيديو\",\n  \"video.fullscreen\": \"ملء الشاشة\",\n  \"video.hide\": \"إخفاء الفيديو\",\n  \"video.mute\": \"كتم الصوت\",\n  \"video.pause\": \"إيقاف مؤقت\",\n  \"video.play\": \"تشغيل\",\n  \"video.unmute\": \"تشغيل الصوت\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/ast.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Add or Remove from lists\",\n  \"account.badges.bot\": \"Robó\",\n  \"account.block\": \"Bloquiar a @{name}\",\n  \"account.block_domain\": \"Anubrir tolo de {domain}\",\n  \"account.blocked\": \"Blocked\",\n  \"account.direct\": \"Unviar un mensaxe direutu a @{name}\",\n  \"account.domain_blocked\": \"Dominiu anubríu\",\n  \"account.edit_profile\": \"Editar el perfil\",\n  \"account.endorse\": \"Destacar nel perfil\",\n  \"account.follow\": \"Follow\",\n  \"account.followers\": \"Siguidores\",\n  \"account.followers.empty\": \"Naide sigue a esti usuariu entá.\",\n  \"account.follows\": \"Sigue a\",\n  \"account.follows.empty\": \"Esti usuariu entá nun sigue a naide.\",\n  \"account.follows_you\": \"Síguete\",\n  \"account.hide_reblogs\": \"Hide boosts from @{name}\",\n  \"account.link_verified_on\": \"Ownership of this link was checked on {date}\",\n  \"account.locked_info\": \"This account privacy status is set to locked. The owner manually reviews who can follow them.\",\n  \"account.media\": \"Media\",\n  \"account.mention\": \"Mentar a @{name}\",\n  \"account.moved_to\": \"{name} has moved to:\",\n  \"account.mute\": \"Silenciar a @{name}\",\n  \"account.mute_notifications\": \"Mute notifications from @{name}\",\n  \"account.muted\": \"Muted\",\n  \"account.posts\": \"Toots\",\n  \"account.posts_with_replies\": \"Toots y rempuestes\",\n  \"account.report\": \"Report @{name}\",\n  \"account.requested\": \"Awaiting approval. Click to cancel follow request\",\n  \"account.share\": \"Share @{name}'s profile\",\n  \"account.show_reblogs\": \"Show boosts from @{name}\",\n  \"account.unblock\": \"Desbloquiar a @{name}\",\n  \"account.unblock_domain\": \"Amosar {domain}\",\n  \"account.unendorse\": \"Don't feature on profile\",\n  \"account.unfollow\": \"Unfollow\",\n  \"account.unmute\": \"Unmute @{name}\",\n  \"account.unmute_notifications\": \"Unmute notifications from @{name}\",\n  \"alert.unexpected.message\": \"Asocedió un fallu inesperáu.\",\n  \"alert.unexpected.title\": \"¡Ups!\",\n  \"boost_modal.combo\": \"Pues primir {combo} pa saltar esto la próxima vegada\",\n  \"bundle_column_error.body\": \"Something went wrong while loading this component.\",\n  \"bundle_column_error.retry\": \"Try again\",\n  \"bundle_column_error.title\": \"Network error\",\n  \"bundle_modal_error.close\": \"Close\",\n  \"bundle_modal_error.message\": \"Something went wrong while loading this component.\",\n  \"bundle_modal_error.retry\": \"Try again\",\n  \"column.blocks\": \"Usuarios bloquiaos\",\n  \"column.community\": \"Llinia temporal llocal\",\n  \"column.direct\": \"Mensaxes direutos\",\n  \"column.domain_blocks\": \"Dominios anubríos\",\n  \"column.favourites\": \"Favoritos\",\n  \"column.follow_requests\": \"Solicitúes de siguimientu\",\n  \"column.home\": \"Aniciu\",\n  \"column.lists\": \"Llistes\",\n  \"column.mutes\": \"Usuarios silenciaos\",\n  \"column.notifications\": \"Avisos\",\n  \"column.pins\": \"Toots fixaos\",\n  \"column.public\": \"Llinia temporal federada\",\n  \"column_back_button.label\": \"Atrás\",\n  \"column_header.hide_settings\": \"Hide settings\",\n  \"column_header.moveLeft_settings\": \"Mover la columna a la esquierda\",\n  \"column_header.moveRight_settings\": \"Mover la columna a la drecha\",\n  \"column_header.pin\": \"Fixar\",\n  \"column_header.show_settings\": \"Show settings\",\n  \"column_header.unpin\": \"Desfixar\",\n  \"column_subheading.settings\": \"Axustes\",\n  \"community.column_settings.media_only\": \"Media Only\",\n  \"compose_form.direct_message_warning\": \"Esti toot namái va unviase a los usuarios mentaos.\",\n  \"compose_form.direct_message_warning_learn_more\": \"Learn more\",\n  \"compose_form.hashtag_warning\": \"This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.\",\n  \"compose_form.lock_disclaimer\": \"Your account is not {locked}. Anyone can follow you to view your follower-only posts.\",\n  \"compose_form.lock_disclaimer.lock\": \"locked\",\n  \"compose_form.placeholder\": \"¿En qué pienses?\",\n  \"compose_form.poll.add_option\": \"Add a choice\",\n  \"compose_form.poll.duration\": \"Poll duration\",\n  \"compose_form.poll.option_placeholder\": \"Choice {number}\",\n  \"compose_form.poll.remove_option\": \"Remove this choice\",\n  \"compose_form.publish\": \"Toot\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"Mark media as sensitive\",\n  \"compose_form.sensitive.marked\": \"Media is marked as sensitive\",\n  \"compose_form.sensitive.unmarked\": \"Media is not marked as sensitive\",\n  \"compose_form.spoiler.marked\": \"El testu nun va anubrise darrera d'una alvertencia\",\n  \"compose_form.spoiler.unmarked\": \"El testu va anubrise\",\n  \"compose_form.spoiler_placeholder\": \"Escribi equí l'avertencia\",\n  \"confirmation_modal.cancel\": \"Encaboxar\",\n  \"confirmations.block.block_and_report\": \"Block & Report\",\n  \"confirmations.block.confirm\": \"Block\",\n  \"confirmations.block.message\": \"¿De xuru que quies bloquiar a {name}?\",\n  \"confirmations.delete.confirm\": \"Delete\",\n  \"confirmations.delete.message\": \"¿De xuru que quies desaniciar esti estáu?\",\n  \"confirmations.delete_list.confirm\": \"Desaniciar\",\n  \"confirmations.delete_list.message\": \"¿De xuru que quies desaniciar dafechu esta llista?\",\n  \"confirmations.domain_block.confirm\": \"Anubrir tol dominiu\",\n  \"confirmations.domain_block.message\": \"Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain in any public timelines or your notifications. Your followers from that domain will be removed.\",\n  \"confirmations.mute.confirm\": \"Mute\",\n  \"confirmations.mute.message\": \"¿De xuru que quies silenciar a {name}?\",\n  \"confirmations.redraft.confirm\": \"Desaniciar y reeditar\",\n  \"confirmations.redraft.message\": \"Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.\",\n  \"confirmations.reply.confirm\": \"Reply\",\n  \"confirmations.reply.message\": \"Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?\",\n  \"confirmations.unfollow.confirm\": \"Unfollow\",\n  \"confirmations.unfollow.message\": \"¿De xuru que quies dexar de siguir a {name}?\",\n  \"embed.instructions\": \"Empotra esti estáu nun sitiu web copiando'l códigu d'embaxo.\",\n  \"embed.preview\": \"Asina ye como va vese:\",\n  \"emoji_button.activity\": \"Actividaes\",\n  \"emoji_button.custom\": \"Custom\",\n  \"emoji_button.flags\": \"Banderes\",\n  \"emoji_button.food\": \"Comida y bébora\",\n  \"emoji_button.label\": \"Insert emoji\",\n  \"emoji_button.nature\": \"Natura\",\n  \"emoji_button.not_found\": \"¡Nun hai fustaxes! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"Oxetos\",\n  \"emoji_button.people\": \"Xente\",\n  \"emoji_button.recent\": \"Úsase davezu\",\n  \"emoji_button.search\": \"Guetar...\",\n  \"emoji_button.search_results\": \"Search results\",\n  \"emoji_button.symbols\": \"Símbolos\",\n  \"emoji_button.travel\": \"Viaxes y llugares\",\n  \"empty_column.account_timeline\": \"No toots here!\",\n  \"empty_column.account_unavailable\": \"Profile unavailable\",\n  \"empty_column.blocks\": \"Entá nun bloquiesti a dengún usuariu.\",\n  \"empty_column.community\": \"The local timeline is empty. Write something publicly to get the ball rolling!\",\n  \"empty_column.direct\": \"Entá nun tienes dengún mensaxe direutu. Cuando unvies o recibas dalgún, va apaecer equí.\",\n  \"empty_column.domain_blocks\": \"Entá nun hai dominios anubríos.\",\n  \"empty_column.favourited_statuses\": \"You don't have any favourite toots yet. When you favourite one, it will show up here.\",\n  \"empty_column.favourites\": \"No one has favourited this toot yet. When someone does, they will show up here.\",\n  \"empty_column.follow_requests\": \"Entá nun tienes denguna solicitú de siguimientu. Cuando recibas una, va amosase equí.\",\n  \"empty_column.hashtag\": \"There is nothing in this hashtag yet.\",\n  \"empty_column.home\": \"¡Tienes la llinia temporal balera! Visita {public} o usa la gueta pa entamar y conocer a otros usuarios.\",\n  \"empty_column.home.public_timeline\": \"la llinia temporal pública\",\n  \"empty_column.list\": \"Entá nun hai nada nesta llista. Cuando los miembros d'esta llista espublicen estaos nuevos, van apaecer equí.\",\n  \"empty_column.lists\": \"Entá nun tienes denguna llista. Cuando crees una, va amosase equí.\",\n  \"empty_column.mutes\": \"Entá nun silenciesti a dengún usuariu.\",\n  \"empty_column.notifications\": \"Entá nun tienes dengún avisu. Interactua con otros p'aniciar la conversación.\",\n  \"empty_column.public\": \"There is nothing here! Write something publicly, or manually follow users from other instances to fill it up\",\n  \"follow_request.authorize\": \"Autorizar\",\n  \"follow_request.reject\": \"Refugar\",\n  \"getting_started.developers\": \"Desendolcadores\",\n  \"getting_started.directory\": \"Profile directory\",\n  \"getting_started.documentation\": \"Documentación\",\n  \"getting_started.heading\": \"Entamu\",\n  \"getting_started.invite\": \"Convidar xente\",\n  \"getting_started.open_source_notice\": \"Mastodon ye software de códigu abiertu. Pues collaborar o informar de fallos en {github} (GitHub).\",\n  \"getting_started.security\": \"Seguranza\",\n  \"getting_started.terms\": \"Términos del serviciu\",\n  \"hashtag.column_header.tag_mode.all\": \"and {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"or {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"without {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"No suggestions found\",\n  \"hashtag.column_settings.select.placeholder\": \"Enter hashtags…\",\n  \"hashtag.column_settings.tag_mode.all\": \"All of these\",\n  \"hashtag.column_settings.tag_mode.any\": \"Any of these\",\n  \"hashtag.column_settings.tag_mode.none\": \"None of these\",\n  \"hashtag.column_settings.tag_toggle\": \"Include additional tags in this column\",\n  \"home.column_settings.basic\": \"Basic\",\n  \"home.column_settings.show_reblogs\": \"Amosar toots compartíos\",\n  \"home.column_settings.show_replies\": \"Amosar rempuestes\",\n  \"intervals.full.days\": \"{number, plural, one {# day} other {# days}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# hour} other {# hours}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minute} other {# minutes}}\",\n  \"introduction.federation.action\": \"Next\",\n  \"introduction.federation.federated.headline\": \"Federated\",\n  \"introduction.federation.federated.text\": \"Public posts from other servers of the fediverse will appear in the federated timeline.\",\n  \"introduction.federation.home.headline\": \"Home\",\n  \"introduction.federation.home.text\": \"Posts from people you follow will appear in your home feed. You can follow anyone on any server!\",\n  \"introduction.federation.local.headline\": \"Local\",\n  \"introduction.federation.local.text\": \"Public posts from people on the same server as you will appear in the local timeline.\",\n  \"introduction.interactions.action\": \"Finish toot-orial!\",\n  \"introduction.interactions.favourite.headline\": \"Favourite\",\n  \"introduction.interactions.favourite.text\": \"You can save a toot for later, and let the author know that you liked it, by favouriting it.\",\n  \"introduction.interactions.reblog.headline\": \"Boost\",\n  \"introduction.interactions.reblog.text\": \"You can share other people's toots with your followers by boosting them.\",\n  \"introduction.interactions.reply.headline\": \"Reply\",\n  \"introduction.interactions.reply.text\": \"You can reply to other people's and your own toots, which will chain them together in a conversation.\",\n  \"introduction.welcome.action\": \"Let's go!\",\n  \"introduction.welcome.headline\": \"First steps\",\n  \"introduction.welcome.text\": \"Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.\",\n  \"keyboard_shortcuts.back\": \"pa dir p'atrás\",\n  \"keyboard_shortcuts.blocked\": \"p'abrir la llista d'usuarios bloquiaos\",\n  \"keyboard_shortcuts.boost\": \"pa compartir un toot\",\n  \"keyboard_shortcuts.column\": \"to focus a status in one of the columns\",\n  \"keyboard_shortcuts.compose\": \"to focus the compose textarea\",\n  \"keyboard_shortcuts.description\": \"Descripción\",\n  \"keyboard_shortcuts.direct\": \"p'abrir la columna de los mensaxes direutos\",\n  \"keyboard_shortcuts.down\": \"pa baxar na llista\",\n  \"keyboard_shortcuts.enter\": \"to open status\",\n  \"keyboard_shortcuts.favourite\": \"to favourite\",\n  \"keyboard_shortcuts.favourites\": \"p'abrir la llista de favoritos\",\n  \"keyboard_shortcuts.federated\": \"p'abrir la llinia temporal federada\",\n  \"keyboard_shortcuts.heading\": \"Atayos del tecláu\",\n  \"keyboard_shortcuts.home\": \"p'abrir la llinia temporal d'aniciu\",\n  \"keyboard_shortcuts.hotkey\": \"Atayu\",\n  \"keyboard_shortcuts.legend\": \"p'amosar esta lleenda\",\n  \"keyboard_shortcuts.local\": \"p'abrir la llinia temporal llocal\",\n  \"keyboard_shortcuts.mention\": \"pa mentar al autor\",\n  \"keyboard_shortcuts.muted\": \"p'abrir la llista d'usuarios silenciaos\",\n  \"keyboard_shortcuts.my_profile\": \"to open your profile\",\n  \"keyboard_shortcuts.notifications\": \"p'abrir la columna d'avisos\",\n  \"keyboard_shortcuts.pinned\": \"p'abrir la llista de toots fixaos\",\n  \"keyboard_shortcuts.profile\": \"p'abrir el perfil del autor\",\n  \"keyboard_shortcuts.reply\": \"pa responder\",\n  \"keyboard_shortcuts.requests\": \"p'abrir la llista de solicitúes de siguimientu\",\n  \"keyboard_shortcuts.search\": \"to focus search\",\n  \"keyboard_shortcuts.start\": \"p'abrir la columna «entamar»\",\n  \"keyboard_shortcuts.toggle_hidden\": \"to show/hide text behind CW\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"to show/hide media\",\n  \"keyboard_shortcuts.toot\": \"p'apenzar un toot nuevu\",\n  \"keyboard_shortcuts.unfocus\": \"to un-focus compose textarea/search\",\n  \"keyboard_shortcuts.up\": \"pa xubir na llista\",\n  \"lightbox.close\": \"Close\",\n  \"lightbox.next\": \"Siguiente\",\n  \"lightbox.previous\": \"Previous\",\n  \"lightbox.view_context\": \"View context\",\n  \"lists.account.add\": \"Amestar a la llista\",\n  \"lists.account.remove\": \"Desaniciar de la llista\",\n  \"lists.delete\": \"Desaniciar la llista\",\n  \"lists.edit\": \"Editar la llista\",\n  \"lists.edit.submit\": \"Change title\",\n  \"lists.new.create\": \"Add list\",\n  \"lists.new.title_placeholder\": \"Títulu nuevu de la llista\",\n  \"lists.search\": \"Guetar ente la xente que sigues\",\n  \"lists.subheading\": \"Les tos llistes\",\n  \"loading_indicator.label\": \"Cargando...\",\n  \"media_gallery.toggle_visible\": \"Toggle visibility\",\n  \"missing_indicator.label\": \"Nun s'alcontró\",\n  \"missing_indicator.sublabel\": \"Esti recursu nun pudo alcontrase\",\n  \"mute_modal.hide_notifications\": \"Hide notifications from this user?\",\n  \"navigation_bar.apps\": \"Aplicaciones pa móviles\",\n  \"navigation_bar.blocks\": \"Usuarios bloquiaos\",\n  \"navigation_bar.community_timeline\": \"Llinia temporal llocal\",\n  \"navigation_bar.compose\": \"Compose new toot\",\n  \"navigation_bar.direct\": \"Mensaxes direutos\",\n  \"navigation_bar.discover\": \"Discover\",\n  \"navigation_bar.domain_blocks\": \"Dominios anubríos\",\n  \"navigation_bar.edit_profile\": \"Editar el perfil\",\n  \"navigation_bar.favourites\": \"Favoritos\",\n  \"navigation_bar.filters\": \"Pallabres silenciaes\",\n  \"navigation_bar.follow_requests\": \"Solicitúes de siguimientu\",\n  \"navigation_bar.follows_and_followers\": \"Follows and followers\",\n  \"navigation_bar.info\": \"Tocante a esta instancia\",\n  \"navigation_bar.keyboard_shortcuts\": \"Atayos\",\n  \"navigation_bar.lists\": \"Llistes\",\n  \"navigation_bar.logout\": \"Zarrar sesión\",\n  \"navigation_bar.mutes\": \"Usuarios silenciaos\",\n  \"navigation_bar.personal\": \"Personal\",\n  \"navigation_bar.pins\": \"Toots fixaos\",\n  \"navigation_bar.preferences\": \"Preferencies\",\n  \"navigation_bar.profile_directory\": \"Profile directory\",\n  \"navigation_bar.public_timeline\": \"Llinia temporal federada\",\n  \"navigation_bar.security\": \"Seguranza\",\n  \"notification.favourite\": \"{name} favourited your status\",\n  \"notification.follow\": \"{name} siguióte\",\n  \"notification.mention\": \"{name} mentóte\",\n  \"notification.poll\": \"A poll you have voted in has ended\",\n  \"notification.reblog\": \"{name} compartió'l to estáu\",\n  \"notifications.clear\": \"Llimpiar avisos\",\n  \"notifications.clear_confirmation\": \"¿De xuru que quies llimpiar dafechu tolos avisos?\",\n  \"notifications.column_settings.alert\": \"Avisos d'escritoriu\",\n  \"notifications.column_settings.favourite\": \"Favoritos:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Display all categories\",\n  \"notifications.column_settings.filter_bar.category\": \"Quick filter bar\",\n  \"notifications.column_settings.filter_bar.show\": \"Show\",\n  \"notifications.column_settings.follow\": \"Siguidores nuevos:\",\n  \"notifications.column_settings.mention\": \"Menciones:\",\n  \"notifications.column_settings.poll\": \"Poll results:\",\n  \"notifications.column_settings.push\": \"Push notifications\",\n  \"notifications.column_settings.reblog\": \"Toots compartíos:\",\n  \"notifications.column_settings.show\": \"Amosar en columna\",\n  \"notifications.column_settings.sound\": \"Reproducir soníu\",\n  \"notifications.filter.all\": \"All\",\n  \"notifications.filter.boosts\": \"Boosts\",\n  \"notifications.filter.favourites\": \"Favourites\",\n  \"notifications.filter.follows\": \"Follows\",\n  \"notifications.filter.mentions\": \"Mentions\",\n  \"notifications.filter.polls\": \"Poll results\",\n  \"notifications.group\": \"{count} avisos\",\n  \"poll.closed\": \"Closed\",\n  \"poll.refresh\": \"Refresh\",\n  \"poll.total_votes\": \"{count, plural, one {# vote} other {# votes}}\",\n  \"poll.vote\": \"Vote\",\n  \"poll_button.add_poll\": \"Add a poll\",\n  \"poll_button.remove_poll\": \"Remove poll\",\n  \"privacy.change\": \"Adjust status privacy\",\n  \"privacy.direct.long\": \"Post to mentioned users only\",\n  \"privacy.direct.short\": \"Direct\",\n  \"privacy.private.long\": \"Post to followers only\",\n  \"privacy.private.short\": \"Namái siguidores\",\n  \"privacy.public.long\": \"Post to public timelines\",\n  \"privacy.public.short\": \"Public\",\n  \"privacy.unlisted.long\": \"Do not show in public timelines\",\n  \"privacy.unlisted.short\": \"Unlisted\",\n  \"regeneration_indicator.label\": \"Cargando…\",\n  \"regeneration_indicator.sublabel\": \"Your home feed is being prepared!\",\n  \"relative_time.days\": \"{number}d\",\n  \"relative_time.hours\": \"{number}h\",\n  \"relative_time.just_now\": \"agora\",\n  \"relative_time.minutes\": \"{number}m\",\n  \"relative_time.seconds\": \"{number}s\",\n  \"reply_indicator.cancel\": \"Encaboxar\",\n  \"report.forward\": \"Forward to {target}\",\n  \"report.forward_hint\": \"The account is from another server. Send an anonymized copy of the report there as well?\",\n  \"report.hint\": \"The report will be sent to your instance moderators. You can provide an explanation of why you are reporting this account below:\",\n  \"report.placeholder\": \"Comentarios adicionales\",\n  \"report.submit\": \"Submit\",\n  \"report.target\": \"Report {target}\",\n  \"search.placeholder\": \"Search\",\n  \"search_popout.search_format\": \"Formatu de gueta avanzada\",\n  \"search_popout.tips.full_text\": \"Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.\",\n  \"search_popout.tips.hashtag\": \"etiqueta\",\n  \"search_popout.tips.status\": \"estáu\",\n  \"search_popout.tips.text\": \"Simple text returns matching display names, usernames and hashtags\",\n  \"search_popout.tips.user\": \"usuariu\",\n  \"search_results.accounts\": \"Xente\",\n  \"search_results.hashtags\": \"Etiquetes\",\n  \"search_results.statuses\": \"Toots\",\n  \"search_results.total\": \"{count, number} {count, plural, one {result} other {results}}\",\n  \"status.admin_account\": \"Open moderation interface for @{name}\",\n  \"status.admin_status\": \"Open this status in the moderation interface\",\n  \"status.block\": \"Bloquiar a @{name}\",\n  \"status.cancel_reblog_private\": \"Dexar de compartir\",\n  \"status.cannot_reblog\": \"Esti artículu nun pue compartise\",\n  \"status.copy\": \"Copy link to status\",\n  \"status.delete\": \"Delete\",\n  \"status.detailed_status\": \"Detailed conversation view\",\n  \"status.direct\": \"Unviar un mensaxe direutu a @{name}\",\n  \"status.embed\": \"Empotrar\",\n  \"status.favourite\": \"Favourite\",\n  \"status.filtered\": \"Filtered\",\n  \"status.load_more\": \"Cargar más\",\n  \"status.media_hidden\": \"Mediu anubríu\",\n  \"status.mention\": \"Mentar a @{name}\",\n  \"status.more\": \"Más\",\n  \"status.mute\": \"Silenciar a @{name}\",\n  \"status.mute_conversation\": \"Silenciar la conversación\",\n  \"status.open\": \"Espander esti estáu\",\n  \"status.pin\": \"Fixar nel perfil\",\n  \"status.pinned\": \"Toot fixáu\",\n  \"status.read_more\": \"Read more\",\n  \"status.reblog\": \"Compartir\",\n  \"status.reblog_private\": \"Compartir cola audiencia orixinal\",\n  \"status.reblogged_by\": \"{name} compartió\",\n  \"status.reblogs.empty\": \"Naide nun compartió esti toot entá. Cuando daquién lo faiga, va amosase equí.\",\n  \"status.redraft\": \"Desaniciar y reeditar\",\n  \"status.reply\": \"Responder\",\n  \"status.replyAll\": \"Reply to thread\",\n  \"status.report\": \"Report @{name}\",\n  \"status.sensitive_warning\": \"Conteníu sensible\",\n  \"status.share\": \"Share\",\n  \"status.show_less\": \"Amosar menos\",\n  \"status.show_less_all\": \"Show less for all\",\n  \"status.show_more\": \"Amosar más\",\n  \"status.show_more_all\": \"Show more for all\",\n  \"status.show_thread\": \"Show thread\",\n  \"status.unmute_conversation\": \"Unmute conversation\",\n  \"status.unpin\": \"Desfixar del perfil\",\n  \"suggestions.dismiss\": \"Dismiss suggestion\",\n  \"suggestions.header\": \"You might be interested in…\",\n  \"tabs_bar.federated_timeline\": \"Federated\",\n  \"tabs_bar.home\": \"Aniciu\",\n  \"tabs_bar.local_timeline\": \"Llocal\",\n  \"tabs_bar.notifications\": \"Avisos\",\n  \"tabs_bar.search\": \"Search\",\n  \"time_remaining.days\": \"{number, plural, one {# day} other {# days}} left\",\n  \"time_remaining.hours\": \"{number, plural, one {# hour} other {# hours}} left\",\n  \"time_remaining.minutes\": \"{number, plural, one {# minute} other {# minutes}} left\",\n  \"time_remaining.moments\": \"Moments remaining\",\n  \"time_remaining.seconds\": \"{number, plural, one {# second} other {# seconds}} left\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {person} other {people}} talking\",\n  \"ui.beforeunload\": \"El borrador va perdese si coles de Mastodon.\",\n  \"upload_area.title\": \"Drag & drop to upload\",\n  \"upload_button.label\": \"Add media\",\n  \"upload_error.limit\": \"File upload limit exceeded.\",\n  \"upload_error.poll\": \"File upload not allowed with polls.\",\n  \"upload_form.description\": \"Descripción pa discapacitaos visuales\",\n  \"upload_form.focus\": \"Crop\",\n  \"upload_form.undo\": \"Desaniciar\",\n  \"upload_progress.label\": \"Xubiendo...\",\n  \"video.close\": \"Zarrar el videu\",\n  \"video.exit_fullscreen\": \"Colar de la pantalla completa\",\n  \"video.expand\": \"Espander el videu\",\n  \"video.fullscreen\": \"Pantalla completa\",\n  \"video.hide\": \"Anubrir el videu\",\n  \"video.mute\": \"Silenciar el soníu\",\n  \"video.pause\": \"Posar\",\n  \"video.play\": \"Reproducir\",\n  \"video.unmute\": \"Unmute sound\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/bg.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Add or Remove from lists\",\n  \"account.badges.bot\": \"Bot\",\n  \"account.block\": \"Блокирай\",\n  \"account.block_domain\": \"Hide everything from {domain}\",\n  \"account.blocked\": \"Blocked\",\n  \"account.direct\": \"Direct Message @{name}\",\n  \"account.domain_blocked\": \"Domain hidden\",\n  \"account.edit_profile\": \"Редактирай профила си\",\n  \"account.endorse\": \"Feature on profile\",\n  \"account.follow\": \"Последвай\",\n  \"account.followers\": \"Последователи\",\n  \"account.followers.empty\": \"No one follows this user yet.\",\n  \"account.follows\": \"Следвам\",\n  \"account.follows.empty\": \"This user doesn't follow anyone yet.\",\n  \"account.follows_you\": \"Твой последовател\",\n  \"account.hide_reblogs\": \"Hide boosts from @{name}\",\n  \"account.link_verified_on\": \"Ownership of this link was checked on {date}\",\n  \"account.locked_info\": \"This account privacy status is set to locked. The owner manually reviews who can follow them.\",\n  \"account.media\": \"Media\",\n  \"account.mention\": \"Споменаване\",\n  \"account.moved_to\": \"{name} has moved to:\",\n  \"account.mute\": \"Mute @{name}\",\n  \"account.mute_notifications\": \"Mute notifications from @{name}\",\n  \"account.muted\": \"Muted\",\n  \"account.posts\": \"Публикации\",\n  \"account.posts_with_replies\": \"Toots with replies\",\n  \"account.report\": \"Report @{name}\",\n  \"account.requested\": \"В очакване на одобрение\",\n  \"account.share\": \"Share @{name}'s profile\",\n  \"account.show_reblogs\": \"Show boosts from @{name}\",\n  \"account.unblock\": \"Не блокирай\",\n  \"account.unblock_domain\": \"Unhide {domain}\",\n  \"account.unendorse\": \"Don't feature on profile\",\n  \"account.unfollow\": \"Не следвай\",\n  \"account.unmute\": \"Unmute @{name}\",\n  \"account.unmute_notifications\": \"Unmute notifications from @{name}\",\n  \"alert.unexpected.message\": \"An unexpected error occurred.\",\n  \"alert.unexpected.title\": \"Oops!\",\n  \"boost_modal.combo\": \"You can press {combo} to skip this next time\",\n  \"bundle_column_error.body\": \"Something went wrong while loading this component.\",\n  \"bundle_column_error.retry\": \"Try again\",\n  \"bundle_column_error.title\": \"Network error\",\n  \"bundle_modal_error.close\": \"Close\",\n  \"bundle_modal_error.message\": \"Something went wrong while loading this component.\",\n  \"bundle_modal_error.retry\": \"Try again\",\n  \"column.blocks\": \"Blocked users\",\n  \"column.community\": \"Local timeline\",\n  \"column.direct\": \"Direct messages\",\n  \"column.domain_blocks\": \"Hidden domains\",\n  \"column.favourites\": \"Favourites\",\n  \"column.follow_requests\": \"Follow requests\",\n  \"column.home\": \"Начало\",\n  \"column.lists\": \"Lists\",\n  \"column.mutes\": \"Muted users\",\n  \"column.notifications\": \"Известия\",\n  \"column.pins\": \"Pinned toot\",\n  \"column.public\": \"Публичен канал\",\n  \"column_back_button.label\": \"Назад\",\n  \"column_header.hide_settings\": \"Hide settings\",\n  \"column_header.moveLeft_settings\": \"Move column to the left\",\n  \"column_header.moveRight_settings\": \"Move column to the right\",\n  \"column_header.pin\": \"Pin\",\n  \"column_header.show_settings\": \"Show settings\",\n  \"column_header.unpin\": \"Unpin\",\n  \"column_subheading.settings\": \"Settings\",\n  \"community.column_settings.media_only\": \"Media Only\",\n  \"compose_form.direct_message_warning\": \"This toot will only be visible to all the mentioned users.\",\n  \"compose_form.direct_message_warning_learn_more\": \"Learn more\",\n  \"compose_form.hashtag_warning\": \"This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.\",\n  \"compose_form.lock_disclaimer\": \"Your account is not {locked}. Anyone can follow you to view your follower-only posts.\",\n  \"compose_form.lock_disclaimer.lock\": \"locked\",\n  \"compose_form.placeholder\": \"Какво си мислиш?\",\n  \"compose_form.poll.add_option\": \"Add a choice\",\n  \"compose_form.poll.duration\": \"Poll duration\",\n  \"compose_form.poll.option_placeholder\": \"Choice {number}\",\n  \"compose_form.poll.remove_option\": \"Remove this choice\",\n  \"compose_form.publish\": \"Раздумай\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"Mark media as sensitive\",\n  \"compose_form.sensitive.marked\": \"Media is marked as sensitive\",\n  \"compose_form.sensitive.unmarked\": \"Media is not marked as sensitive\",\n  \"compose_form.spoiler.marked\": \"Text is hidden behind warning\",\n  \"compose_form.spoiler.unmarked\": \"Text is not hidden\",\n  \"compose_form.spoiler_placeholder\": \"Content warning\",\n  \"confirmation_modal.cancel\": \"Cancel\",\n  \"confirmations.block.block_and_report\": \"Block & Report\",\n  \"confirmations.block.confirm\": \"Block\",\n  \"confirmations.block.message\": \"Are you sure you want to block {name}?\",\n  \"confirmations.delete.confirm\": \"Delete\",\n  \"confirmations.delete.message\": \"Are you sure you want to delete this status?\",\n  \"confirmations.delete_list.confirm\": \"Delete\",\n  \"confirmations.delete_list.message\": \"Are you sure you want to permanently delete this list?\",\n  \"confirmations.domain_block.confirm\": \"Hide entire domain\",\n  \"confirmations.domain_block.message\": \"Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.\",\n  \"confirmations.mute.confirm\": \"Mute\",\n  \"confirmations.mute.message\": \"Are you sure you want to mute {name}?\",\n  \"confirmations.redraft.confirm\": \"Delete & redraft\",\n  \"confirmations.redraft.message\": \"Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.\",\n  \"confirmations.reply.confirm\": \"Reply\",\n  \"confirmations.reply.message\": \"Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?\",\n  \"confirmations.unfollow.confirm\": \"Unfollow\",\n  \"confirmations.unfollow.message\": \"Are you sure you want to unfollow {name}?\",\n  \"embed.instructions\": \"Embed this status on your website by copying the code below.\",\n  \"embed.preview\": \"Here is what it will look like:\",\n  \"emoji_button.activity\": \"Activity\",\n  \"emoji_button.custom\": \"Custom\",\n  \"emoji_button.flags\": \"Flags\",\n  \"emoji_button.food\": \"Food & Drink\",\n  \"emoji_button.label\": \"Insert emoji\",\n  \"emoji_button.nature\": \"Nature\",\n  \"emoji_button.not_found\": \"No emojos!! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"Objects\",\n  \"emoji_button.people\": \"People\",\n  \"emoji_button.recent\": \"Frequently used\",\n  \"emoji_button.search\": \"Search...\",\n  \"emoji_button.search_results\": \"Search results\",\n  \"emoji_button.symbols\": \"Symbols\",\n  \"emoji_button.travel\": \"Travel & Places\",\n  \"empty_column.account_timeline\": \"No toots here!\",\n  \"empty_column.account_unavailable\": \"Profile unavailable\",\n  \"empty_column.blocks\": \"You haven't blocked any users yet.\",\n  \"empty_column.community\": \"The local timeline is empty. Write something publicly to get the ball rolling!\",\n  \"empty_column.direct\": \"You don't have any direct messages yet. When you send or receive one, it will show up here.\",\n  \"empty_column.domain_blocks\": \"There are no hidden domains yet.\",\n  \"empty_column.favourited_statuses\": \"You don't have any favourite toots yet. When you favourite one, it will show up here.\",\n  \"empty_column.favourites\": \"No one has favourited this toot yet. When someone does, they will show up here.\",\n  \"empty_column.follow_requests\": \"You don't have any follow requests yet. When you receive one, it will show up here.\",\n  \"empty_column.hashtag\": \"There is nothing in this hashtag yet.\",\n  \"empty_column.home\": \"Your home timeline is empty! Visit {public} or use search to get started and meet other users.\",\n  \"empty_column.home.public_timeline\": \"the public timeline\",\n  \"empty_column.list\": \"There is nothing in this list yet.\",\n  \"empty_column.lists\": \"You don't have any lists yet. When you create one, it will show up here.\",\n  \"empty_column.mutes\": \"You haven't muted any users yet.\",\n  \"empty_column.notifications\": \"You don't have any notifications yet. Interact with others to start the conversation.\",\n  \"empty_column.public\": \"There is nothing here! Write something publicly, or manually follow users from other instances to fill it up\",\n  \"follow_request.authorize\": \"Authorize\",\n  \"follow_request.reject\": \"Reject\",\n  \"getting_started.developers\": \"Developers\",\n  \"getting_started.directory\": \"Profile directory\",\n  \"getting_started.documentation\": \"Documentation\",\n  \"getting_started.heading\": \"Първи стъпки\",\n  \"getting_started.invite\": \"Invite people\",\n  \"getting_started.open_source_notice\": \"Mastodon е софтуер с отворен код. Можеш да помогнеш или да докладваш за проблеми в Github: {github}.\",\n  \"getting_started.security\": \"Security\",\n  \"getting_started.terms\": \"Terms of service\",\n  \"hashtag.column_header.tag_mode.all\": \"and {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"or {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"without {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"No suggestions found\",\n  \"hashtag.column_settings.select.placeholder\": \"Enter hashtags…\",\n  \"hashtag.column_settings.tag_mode.all\": \"All of these\",\n  \"hashtag.column_settings.tag_mode.any\": \"Any of these\",\n  \"hashtag.column_settings.tag_mode.none\": \"None of these\",\n  \"hashtag.column_settings.tag_toggle\": \"Include additional tags in this column\",\n  \"home.column_settings.basic\": \"Basic\",\n  \"home.column_settings.show_reblogs\": \"Show boosts\",\n  \"home.column_settings.show_replies\": \"Show replies\",\n  \"intervals.full.days\": \"{number, plural, one {# day} other {# days}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# hour} other {# hours}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minute} other {# minutes}}\",\n  \"introduction.federation.action\": \"Next\",\n  \"introduction.federation.federated.headline\": \"Federated\",\n  \"introduction.federation.federated.text\": \"Public posts from other servers of the fediverse will appear in the federated timeline.\",\n  \"introduction.federation.home.headline\": \"Home\",\n  \"introduction.federation.home.text\": \"Posts from people you follow will appear in your home feed. You can follow anyone on any server!\",\n  \"introduction.federation.local.headline\": \"Local\",\n  \"introduction.federation.local.text\": \"Public posts from people on the same server as you will appear in the local timeline.\",\n  \"introduction.interactions.action\": \"Finish toot-orial!\",\n  \"introduction.interactions.favourite.headline\": \"Favourite\",\n  \"introduction.interactions.favourite.text\": \"You can save a toot for later, and let the author know that you liked it, by favouriting it.\",\n  \"introduction.interactions.reblog.headline\": \"Boost\",\n  \"introduction.interactions.reblog.text\": \"You can share other people's toots with your followers by boosting them.\",\n  \"introduction.interactions.reply.headline\": \"Reply\",\n  \"introduction.interactions.reply.text\": \"You can reply to other people's and your own toots, which will chain them together in a conversation.\",\n  \"introduction.welcome.action\": \"Let's go!\",\n  \"introduction.welcome.headline\": \"First steps\",\n  \"introduction.welcome.text\": \"Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.\",\n  \"keyboard_shortcuts.back\": \"to navigate back\",\n  \"keyboard_shortcuts.blocked\": \"to open blocked users list\",\n  \"keyboard_shortcuts.boost\": \"to boost\",\n  \"keyboard_shortcuts.column\": \"to focus a status in one of the columns\",\n  \"keyboard_shortcuts.compose\": \"to focus the compose textarea\",\n  \"keyboard_shortcuts.description\": \"Description\",\n  \"keyboard_shortcuts.direct\": \"to open direct messages column\",\n  \"keyboard_shortcuts.down\": \"to move down in the list\",\n  \"keyboard_shortcuts.enter\": \"to open status\",\n  \"keyboard_shortcuts.favourite\": \"to favourite\",\n  \"keyboard_shortcuts.favourites\": \"to open favourites list\",\n  \"keyboard_shortcuts.federated\": \"to open federated timeline\",\n  \"keyboard_shortcuts.heading\": \"Keyboard Shortcuts\",\n  \"keyboard_shortcuts.home\": \"to open home timeline\",\n  \"keyboard_shortcuts.hotkey\": \"Hotkey\",\n  \"keyboard_shortcuts.legend\": \"to display this legend\",\n  \"keyboard_shortcuts.local\": \"to open local timeline\",\n  \"keyboard_shortcuts.mention\": \"to mention author\",\n  \"keyboard_shortcuts.muted\": \"to open muted users list\",\n  \"keyboard_shortcuts.my_profile\": \"to open your profile\",\n  \"keyboard_shortcuts.notifications\": \"to open notifications column\",\n  \"keyboard_shortcuts.pinned\": \"to open pinned toots list\",\n  \"keyboard_shortcuts.profile\": \"to open author's profile\",\n  \"keyboard_shortcuts.reply\": \"to reply\",\n  \"keyboard_shortcuts.requests\": \"to open follow requests list\",\n  \"keyboard_shortcuts.search\": \"to focus search\",\n  \"keyboard_shortcuts.start\": \"to open \\\"get started\\\" column\",\n  \"keyboard_shortcuts.toggle_hidden\": \"to show/hide text behind CW\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"to show/hide media\",\n  \"keyboard_shortcuts.toot\": \"to start a brand new toot\",\n  \"keyboard_shortcuts.unfocus\": \"to un-focus compose textarea/search\",\n  \"keyboard_shortcuts.up\": \"to move up in the list\",\n  \"lightbox.close\": \"Затвори\",\n  \"lightbox.next\": \"Next\",\n  \"lightbox.previous\": \"Previous\",\n  \"lightbox.view_context\": \"View context\",\n  \"lists.account.add\": \"Add to list\",\n  \"lists.account.remove\": \"Remove from list\",\n  \"lists.delete\": \"Delete list\",\n  \"lists.edit\": \"Edit list\",\n  \"lists.edit.submit\": \"Change title\",\n  \"lists.new.create\": \"Add list\",\n  \"lists.new.title_placeholder\": \"New list title\",\n  \"lists.search\": \"Search among people you follow\",\n  \"lists.subheading\": \"Your lists\",\n  \"loading_indicator.label\": \"Зареждане...\",\n  \"media_gallery.toggle_visible\": \"Toggle visibility\",\n  \"missing_indicator.label\": \"Not found\",\n  \"missing_indicator.sublabel\": \"This resource could not be found\",\n  \"mute_modal.hide_notifications\": \"Hide notifications from this user?\",\n  \"navigation_bar.apps\": \"Mobile apps\",\n  \"navigation_bar.blocks\": \"Blocked users\",\n  \"navigation_bar.community_timeline\": \"Local timeline\",\n  \"navigation_bar.compose\": \"Compose new toot\",\n  \"navigation_bar.direct\": \"Direct messages\",\n  \"navigation_bar.discover\": \"Discover\",\n  \"navigation_bar.domain_blocks\": \"Hidden domains\",\n  \"navigation_bar.edit_profile\": \"Редактирай профил\",\n  \"navigation_bar.favourites\": \"Favourites\",\n  \"navigation_bar.filters\": \"Muted words\",\n  \"navigation_bar.follow_requests\": \"Follow requests\",\n  \"navigation_bar.follows_and_followers\": \"Follows and followers\",\n  \"navigation_bar.info\": \"Extended information\",\n  \"navigation_bar.keyboard_shortcuts\": \"Keyboard shortcuts\",\n  \"navigation_bar.lists\": \"Lists\",\n  \"navigation_bar.logout\": \"Излизане\",\n  \"navigation_bar.mutes\": \"Muted users\",\n  \"navigation_bar.personal\": \"Personal\",\n  \"navigation_bar.pins\": \"Pinned toots\",\n  \"navigation_bar.preferences\": \"Предпочитания\",\n  \"navigation_bar.profile_directory\": \"Profile directory\",\n  \"navigation_bar.public_timeline\": \"Публичен канал\",\n  \"navigation_bar.security\": \"Security\",\n  \"notification.favourite\": \"{name} хареса твоята публикация\",\n  \"notification.follow\": \"{name} те последва\",\n  \"notification.mention\": \"{name} те спомена\",\n  \"notification.poll\": \"A poll you have voted in has ended\",\n  \"notification.reblog\": \"{name} сподели твоята публикация\",\n  \"notifications.clear\": \"Clear notifications\",\n  \"notifications.clear_confirmation\": \"Are you sure you want to permanently clear all your notifications?\",\n  \"notifications.column_settings.alert\": \"Десктоп известия\",\n  \"notifications.column_settings.favourite\": \"Предпочитани:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Display all categories\",\n  \"notifications.column_settings.filter_bar.category\": \"Quick filter bar\",\n  \"notifications.column_settings.filter_bar.show\": \"Show\",\n  \"notifications.column_settings.follow\": \"Нови последователи:\",\n  \"notifications.column_settings.mention\": \"Споменавания:\",\n  \"notifications.column_settings.poll\": \"Poll results:\",\n  \"notifications.column_settings.push\": \"Push notifications\",\n  \"notifications.column_settings.reblog\": \"Споделяния:\",\n  \"notifications.column_settings.show\": \"Покажи в колона\",\n  \"notifications.column_settings.sound\": \"Play sound\",\n  \"notifications.filter.all\": \"All\",\n  \"notifications.filter.boosts\": \"Boosts\",\n  \"notifications.filter.favourites\": \"Favourites\",\n  \"notifications.filter.follows\": \"Follows\",\n  \"notifications.filter.mentions\": \"Mentions\",\n  \"notifications.filter.polls\": \"Poll results\",\n  \"notifications.group\": \"{count} notifications\",\n  \"poll.closed\": \"Closed\",\n  \"poll.refresh\": \"Refresh\",\n  \"poll.total_votes\": \"{count, plural, one {# vote} other {# votes}}\",\n  \"poll.vote\": \"Vote\",\n  \"poll_button.add_poll\": \"Add a poll\",\n  \"poll_button.remove_poll\": \"Remove poll\",\n  \"privacy.change\": \"Adjust status privacy\",\n  \"privacy.direct.long\": \"Post to mentioned users only\",\n  \"privacy.direct.short\": \"Direct\",\n  \"privacy.private.long\": \"Post to followers only\",\n  \"privacy.private.short\": \"Followers-only\",\n  \"privacy.public.long\": \"Post to public timelines\",\n  \"privacy.public.short\": \"Public\",\n  \"privacy.unlisted.long\": \"Do not show in public timelines\",\n  \"privacy.unlisted.short\": \"Unlisted\",\n  \"regeneration_indicator.label\": \"Loading…\",\n  \"regeneration_indicator.sublabel\": \"Your home feed is being prepared!\",\n  \"relative_time.days\": \"{number}d\",\n  \"relative_time.hours\": \"{number}h\",\n  \"relative_time.just_now\": \"now\",\n  \"relative_time.minutes\": \"{number}m\",\n  \"relative_time.seconds\": \"{number}s\",\n  \"reply_indicator.cancel\": \"Отказ\",\n  \"report.forward\": \"Forward to {target}\",\n  \"report.forward_hint\": \"The account is from another server. Send an anonymized copy of the report there as well?\",\n  \"report.hint\": \"The report will be sent to your instance moderators. You can provide an explanation of why you are reporting this account below:\",\n  \"report.placeholder\": \"Additional comments\",\n  \"report.submit\": \"Submit\",\n  \"report.target\": \"Reporting\",\n  \"search.placeholder\": \"Търсене\",\n  \"search_popout.search_format\": \"Advanced search format\",\n  \"search_popout.tips.full_text\": \"Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.\",\n  \"search_popout.tips.hashtag\": \"hashtag\",\n  \"search_popout.tips.status\": \"status\",\n  \"search_popout.tips.text\": \"Simple text returns matching display names, usernames and hashtags\",\n  \"search_popout.tips.user\": \"user\",\n  \"search_results.accounts\": \"People\",\n  \"search_results.hashtags\": \"Hashtags\",\n  \"search_results.statuses\": \"Toots\",\n  \"search_results.total\": \"{count, number} {count, plural, one {result} other {results}}\",\n  \"status.admin_account\": \"Open moderation interface for @{name}\",\n  \"status.admin_status\": \"Open this status in the moderation interface\",\n  \"status.block\": \"Block @{name}\",\n  \"status.cancel_reblog_private\": \"Unboost\",\n  \"status.cannot_reblog\": \"This post cannot be boosted\",\n  \"status.copy\": \"Copy link to status\",\n  \"status.delete\": \"Изтриване\",\n  \"status.detailed_status\": \"Detailed conversation view\",\n  \"status.direct\": \"Direct message @{name}\",\n  \"status.embed\": \"Embed\",\n  \"status.favourite\": \"Предпочитани\",\n  \"status.filtered\": \"Filtered\",\n  \"status.load_more\": \"Load more\",\n  \"status.media_hidden\": \"Media hidden\",\n  \"status.mention\": \"Споменаване\",\n  \"status.more\": \"More\",\n  \"status.mute\": \"Mute @{name}\",\n  \"status.mute_conversation\": \"Mute conversation\",\n  \"status.open\": \"Expand this status\",\n  \"status.pin\": \"Pin on profile\",\n  \"status.pinned\": \"Pinned toot\",\n  \"status.read_more\": \"Read more\",\n  \"status.reblog\": \"Споделяне\",\n  \"status.reblog_private\": \"Boost to original audience\",\n  \"status.reblogged_by\": \"{name} сподели\",\n  \"status.reblogs.empty\": \"No one has boosted this toot yet. When someone does, they will show up here.\",\n  \"status.redraft\": \"Delete & re-draft\",\n  \"status.reply\": \"Отговор\",\n  \"status.replyAll\": \"Reply to thread\",\n  \"status.report\": \"Report @{name}\",\n  \"status.sensitive_warning\": \"Деликатно съдържание\",\n  \"status.share\": \"Share\",\n  \"status.show_less\": \"Show less\",\n  \"status.show_less_all\": \"Show less for all\",\n  \"status.show_more\": \"Show more\",\n  \"status.show_more_all\": \"Show more for all\",\n  \"status.show_thread\": \"Show thread\",\n  \"status.unmute_conversation\": \"Unmute conversation\",\n  \"status.unpin\": \"Unpin from profile\",\n  \"suggestions.dismiss\": \"Dismiss suggestion\",\n  \"suggestions.header\": \"You might be interested in…\",\n  \"tabs_bar.federated_timeline\": \"Federated\",\n  \"tabs_bar.home\": \"Начало\",\n  \"tabs_bar.local_timeline\": \"Local\",\n  \"tabs_bar.notifications\": \"Известия\",\n  \"tabs_bar.search\": \"Search\",\n  \"time_remaining.days\": \"{number, plural, one {# day} other {# days}} left\",\n  \"time_remaining.hours\": \"{number, plural, one {# hour} other {# hours}} left\",\n  \"time_remaining.minutes\": \"{number, plural, one {# minute} other {# minutes}} left\",\n  \"time_remaining.moments\": \"Moments remaining\",\n  \"time_remaining.seconds\": \"{number, plural, one {# second} other {# seconds}} left\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {person} other {people}} talking\",\n  \"ui.beforeunload\": \"Your draft will be lost if you leave Mastodon.\",\n  \"upload_area.title\": \"Drag & drop to upload\",\n  \"upload_button.label\": \"Добави медия\",\n  \"upload_error.limit\": \"File upload limit exceeded.\",\n  \"upload_error.poll\": \"File upload not allowed with polls.\",\n  \"upload_form.description\": \"Describe for the visually impaired\",\n  \"upload_form.focus\": \"Crop\",\n  \"upload_form.undo\": \"Отмяна\",\n  \"upload_progress.label\": \"Uploading...\",\n  \"video.close\": \"Close video\",\n  \"video.exit_fullscreen\": \"Exit full screen\",\n  \"video.expand\": \"Expand video\",\n  \"video.fullscreen\": \"Full screen\",\n  \"video.hide\": \"Hide video\",\n  \"video.mute\": \"Mute sound\",\n  \"video.pause\": \"Pause\",\n  \"video.play\": \"Play\",\n  \"video.unmute\": \"Unmute sound\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/bn.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"তালিকাতে আরো যুক্ত বা মুছে ফেলুন\",\n  \"account.badges.bot\": \"রোবট\",\n  \"account.block\": \"@{name} বন্ধ করুন\",\n  \"account.block_domain\": \"{domain} থেকে সব সরিয়ে ফেলুন\",\n  \"account.blocked\": \"বন্ধ করা হয়েছে\",\n  \"account.direct\": \"@{name}কে সরকারি লিখুন\",\n  \"account.domain_blocked\": \"ওয়েবসাইট সরিয়ে ফেলা হয়েছে\",\n  \"account.edit_profile\": \"নিজের পাতা সম্পাদনা করুন\",\n  \"account.endorse\": \"নিজের পাতায় দেখান\",\n  \"account.follow\": \"অনুসরণ করুন\",\n  \"account.followers\": \"অনুসরণকারক\",\n  \"account.followers.empty\": \"এই ব্যবহারকারীকে কেও এখনো অনুসরণ করে না।\",\n  \"account.follows\": \"যাদেরকে অনুসরণ করেন\",\n  \"account.follows.empty\": \"এই ব্যবহারকারী কাওকে এখনো অনুসরণ করেন না।\",\n  \"account.follows_you\": \"আপনাকে অনুসরণ করে\",\n  \"account.hide_reblogs\": \"@{name}র সমর্থনগুলি সরিয়ে ফেলুন\",\n  \"account.link_verified_on\": \"এই লিংকের মালিকানা চেক করা হয়েছে {date} তারিকে\",\n  \"account.locked_info\": \"এই নিবন্ধনের গোপনীয়তার ক্ষেত্র তালা দেওয়া আছে। নিবন্ধনকারী অনুসরণ করার অনুমতি যাদেরকে দেবেন, শুধু তারাই অনুসরণ করতে পারবেন।\",\n  \"account.media\": \"ছবি বা ভিডিও\",\n  \"account.mention\": \"@{name} কে উল্লেখ করুন\",\n  \"account.moved_to\": \"{name} চলে গেছে এখানে:\",\n  \"account.mute\": \"@{name}র কার্যক্রম সরিয়ে ফেলুন\",\n  \"account.mute_notifications\": \"@{name}র প্রজ্ঞাপন আপনার কাছ থেকে সরিয়ে ফেলুন\",\n  \"account.muted\": \"সরানো আছে\",\n  \"account.posts\": \"টুট\",\n  \"account.posts_with_replies\": \"টুট এবং মতামত\",\n  \"account.report\": \"@{name}কে রিপোর্ট করে দিন\",\n  \"account.requested\": \"অনুমতির অপেক্ষায় আছে। অনুসরণ করার অনুরোধ বাতিল করতে এখানে ক্লিক করুন\",\n  \"account.share\": \"@{name}র পাতা অন্যদের দেখান\",\n  \"account.show_reblogs\": \"@{name}র সমর্থনগুলো দেখুন\",\n  \"account.unblock\": \"@{name}র কার্যকলাপ আবার দেখুন\",\n  \"account.unblock_domain\": \"{domain}থেকে আবার দেখুন\",\n  \"account.unendorse\": \"নিজের পাতায় এটা দেখতে চান না\",\n  \"account.unfollow\": \"অনুসরণ বন্ধ করুন\",\n  \"account.unmute\": \"@{name}র কার্যকলাপ আবার দেখুন\",\n  \"account.unmute_notifications\": \"@{name}র প্রজ্ঞাপন দেওয়ার অনুমতি দিন\",\n  \"alert.unexpected.message\": \"অপ্রত্যাশিত একটি সমস্যা হয়েছে।\",\n  \"alert.unexpected.title\": \"ওহো!\",\n  \"boost_modal.combo\": \"পরেরবার আপনি {combo} চাপ দিলে এটার শেষে চলে যেতে পারবেন\",\n  \"bundle_column_error.body\": \"এই অংশটি দেখতে যেয়ে কোনো সমস্যা হয়েছে।\",\n  \"bundle_column_error.retry\": \"আবার চেষ্টা করুন\",\n  \"bundle_column_error.title\": \"নেটওয়ার্কের সমস্যা হচ্ছে\",\n  \"bundle_modal_error.close\": \"বন্ধ করুন\",\n  \"bundle_modal_error.message\": \"এই অংশটি দেখতে যেয়ে কোনো সমস্যা হয়েছে।\",\n  \"bundle_modal_error.retry\": \"আবার চেষ্টা করুন\",\n  \"column.blocks\": \"যাদের বন্ধ করে রাখা হয়েছে\",\n  \"column.community\": \"স্থানীয় সময়সারি\",\n  \"column.direct\": \"সরাসরি লেখা\",\n  \"column.domain_blocks\": \"সরিয়ে ফেলা ওয়েবসাইট\",\n  \"column.favourites\": \"পছন্দের গুলো\",\n  \"column.follow_requests\": \"অনুসরণের অনুমতি চেয়েছে যারা\",\n  \"column.home\": \"বাড়ি\",\n  \"column.lists\": \"তালিকাগুলো\",\n  \"column.mutes\": \"যাদের কার্যক্রম দেখা বন্ধ আছে\",\n  \"column.notifications\": \"প্রজ্ঞাপনগুলো\",\n  \"column.pins\": \"পিন করা টুট\",\n  \"column.public\": \"যুক্ত সময়রেখা\",\n  \"column_back_button.label\": \"পেছনে\",\n  \"column_header.hide_settings\": \"সেটিংগুলো সরান\",\n  \"column_header.moveLeft_settings\": \"কলমটা বামে সরান\",\n  \"column_header.moveRight_settings\": \"কলমটা ডানে সরান\",\n  \"column_header.pin\": \"পিন দিয়ে রাখুন\",\n  \"column_header.show_settings\": \"সেটিং দেখান\",\n  \"column_header.unpin\": \"পিন খুলুন\",\n  \"column_subheading.settings\": \"সেটিং\",\n  \"community.column_settings.media_only\": \"শুধুমাত্র ছবি বা ভিডিও\",\n  \"compose_form.direct_message_warning\": \"শুধুমাত্র যাদেরকে উল্লেখ করা হয়েছে তাদেরকেই এই টুটটি পাঠানো হবে ।\",\n  \"compose_form.direct_message_warning_learn_more\": \"আরো জানুন\",\n  \"compose_form.hashtag_warning\": \"কোনো হ্যাশট্যাগের ভেতরে এই টুটটি থাকবেনা কারণ এটি তালিকাবহির্ভূত। শুধুমাত্র প্রকাশ্য ঠোটগুলো হ্যাশট্যাগের ভেতরে খুঁজে পাওয়া যাবে।\",\n  \"compose_form.lock_disclaimer\": \"আপনার নিবন্ধনে তালা দেওয়া নেই, যে কেও আপনাকে অনুসরণ করতে পারবে এবং অনুশারকদের জন্য লেখা দেখতে পারবে।\",\n  \"compose_form.lock_disclaimer.lock\": \"তালা দেওয়া\",\n  \"compose_form.placeholder\": \"আপনি কি ভাবছেন ?\",\n  \"compose_form.poll.add_option\": \"আরেকটি বিকল্প যোগ করুন\",\n  \"compose_form.poll.duration\": \"ভোটগ্রহনের সময়\",\n  \"compose_form.poll.option_placeholder\": \"বিকল্প {number}\",\n  \"compose_form.poll.remove_option\": \"এই বিকল্পটি মুছে ফেলুন\",\n  \"compose_form.publish\": \"টুট\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"Mark media as sensitive\",\n  \"compose_form.sensitive.marked\": \"এই ছবি বা ভিডিওটি সংবেদনশীল হিসেবে চিহ্নিত করা হয়েছে\",\n  \"compose_form.sensitive.unmarked\": \"এই ছবি বা ভিডিওটি সংবেদনশীল হিসেবে চিহ্নিত করা হয়নি\",\n  \"compose_form.spoiler.marked\": \"লেখাটি সাবধানতার পেছনে লুকানো আছে\",\n  \"compose_form.spoiler.unmarked\": \"লেখাটি লুকানো নেই\",\n  \"compose_form.spoiler_placeholder\": \"আপনার সাবধানতা এখানে লিখুন\",\n  \"confirmation_modal.cancel\": \"বাতিল করুন\",\n  \"confirmations.block.block_and_report\": \"বন্ধ করুন এবং রিপোর্ট করুন\",\n  \"confirmations.block.confirm\": \"বন্ধ করুন\",\n  \"confirmations.block.message\": \"আপনি কি নিশ্চিত {name} কে বন্ধ করতে চান ?\",\n  \"confirmations.delete.confirm\": \"মুছে ফেলুন\",\n  \"confirmations.delete.message\": \"আপনি কি নিশ্চিত যে এই লেখাটি মুছে ফেলতে চান ?\",\n  \"confirmations.delete_list.confirm\": \"মুছে ফেলুন\",\n  \"confirmations.delete_list.message\": \"আপনি কি নিশ্চিত যে আপনি এই তালিকাটি স্থায়িভাবে মুছে ফেলতে চান ?\",\n  \"confirmations.domain_block.confirm\": \"এই ওয়েবসাইট থেকে সব সরান\",\n  \"confirmations.domain_block.message\": \"আপনি কি সত্যি সত্যি নিশ্চিত যে {domain} ওয়েবসাইট থেকে সব সরাতে চান ? সাধারণত কিছু লক্ষ্যবস্তু বন্ধ এবং সরানোযা যথেষ্ট। নিশ্চিত করলে ওই ওয়েবসাইট থেকে কোনোকিছু কোনখানে দেখবেন না। যারা আপনাকে অনুসরণ করে ওই ওয়েবসাইট থেকে তাদেরকেও মুছে ফেলা হবে।\",\n  \"confirmations.mute.confirm\": \"সরিয়ে ফেলুন\",\n  \"confirmations.mute.message\": \"আপনি কি নিশ্চিত {name} সরিয়ে ফেলতে চান ?\",\n  \"confirmations.redraft.confirm\": \"মুছে ফেলুন এবং আবার সম্পাদন করুন\",\n  \"confirmations.redraft.message\": \"আপনি কি নিশ্চিত এটি মুছে ফেলে  এবং আবার সম্পাদন করতে চান ? এটাতে যা পছন্দিত, সমর্থন বা মতামত আছে সেগুলো নতুন লেখার সাথে যুক্ত থাকবে না।\",\n  \"confirmations.reply.confirm\": \"মতামত\",\n  \"confirmations.reply.message\": \"এখন মতামত লিখতে গেলে আপনার এখন যেটা লিখছেন সেটা মুছে যাবে। আপনি নি নিশ্চিত এটা করতে চান ?\",\n  \"confirmations.unfollow.confirm\": \"অনুসরণ বন্ধ করুন\",\n  \"confirmations.unfollow.message\": \"আপনি কি নিশ্চিত {name} কে আর অনুসরণ করতে চান না ?\",\n  \"embed.instructions\": \"এই লেখাটি আপনার ওয়েবসাইটে যুক্ত করতে নিচের কোডটি বেবহার করুন।\",\n  \"embed.preview\": \"সেটা দেখতে এরকম হবে:\",\n  \"emoji_button.activity\": \"কার্যকলাপ\",\n  \"emoji_button.custom\": \"প্রথা\",\n  \"emoji_button.flags\": \"পতাকা\",\n  \"emoji_button.food\": \"খাদ্য ও পানীয়\",\n  \"emoji_button.label\": \"এমজি যুক্ত করুন\",\n  \"emoji_button.nature\": \"প্রকৃতি\",\n  \"emoji_button.not_found\": \"ইমোজি পাওয়া যায়নি !! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"বস্তূ\",\n  \"emoji_button.people\": \"মানুষ\",\n  \"emoji_button.recent\": \"ঘন ব্যাবহৃত\",\n  \"emoji_button.search\": \"খুজুন...\",\n  \"emoji_button.search_results\": \"খোঁজার ফলাফল\",\n  \"emoji_button.symbols\": \"প্রতীক\",\n  \"emoji_button.travel\": \"ভ্রমণ এবং স্থান\",\n  \"empty_column.account_timeline\": \"এখানে কোনো টুট নেই!\",\n  \"empty_column.account_unavailable\": \"নিজস্ব পাতা নেই\",\n  \"empty_column.blocks\": \"আপনি কোনো ব্যবহারকারীদের বন্ধ করেন নি।\",\n  \"empty_column.community\": \"স্থানীয় সময়রেখাতে কিছু নেই। প্রকাশ্যভাবে কিছু লিখে লেখালেখির উদ্বোধন করে ফেলুন!\",\n  \"empty_column.direct\": \"আপনার কাছে সরাসরি পাঠানো কোনো লেখা নেই। যদি কেও পাঠায়, সেটা এখানে দেখা যাবে।\",\n  \"empty_column.domain_blocks\": \"এখনো কোনো সরানো ওয়েবসাইট নেই।\",\n  \"empty_column.favourited_statuses\": \"আপনার পছন্দের কোনো টুট এখনো নেই। আপনি কোনো লেখা পছন্দের হিসেবে চিহ্নিত করলে এখানে পাওয়া যাবে।\",\n  \"empty_column.favourites\": \"কেও এখনো এটাকে পছন্দের টুট হিসেবে চিহ্নিত করেনি। যদি করে, তখন তাদের এখানে পাওয়া যাবে।\",\n  \"empty_column.follow_requests\": \"আপনার এখনো কোনো অনুসরণের আবেদন পাঠানো নেই। যদি পাঠায়, এখানে পাওয়া যাবে।\",\n  \"empty_column.hashtag\": \"এই হেসটাগে এখনো কিছু নেই।\",\n  \"empty_column.home\": \"আপনার বাড়ির সময়রেখা এখনো খালি!  {public}এ ঘুরে আসুন অথবা অনুসন্ধান বেবহার করে শুরু করতে পারেন এবং অন্য ব্যবহারকারীদের সাথে সাক্ষাৎ করতে পারেন।\",\n  \"empty_column.home.public_timeline\": \"প্রকাশ্য সময়রেখা\",\n  \"empty_column.list\": \"এই তালিকাতে এখনো কিছু নেই. যখন এই তালিকায় থাকা ব্যবহারকারী নতুন কিছু লিখবে, সেগুলো এখানে পাওয়া যাবে।\",\n  \"empty_column.lists\": \"আপনার এখনো কোনো তালিকা তৈরী নেই। যদি বা যখন তৈরী করেন, সেগুলো এখানে পাওয়া যাবে।\",\n  \"empty_column.mutes\": \"আপনি এখনো কোনো ব্যবহারকারীকে সরাননি।\",\n  \"empty_column.notifications\": \"আপনার এখনো কোনো প্রজ্ঞাপন নেই। কথোপকথন শুরু করতে,  অন্যদের সাথে মেলামেশা করতে পারেন।\",\n  \"empty_column.public\": \"এখানে এখনো কিছু নেই! প্রকাশ্য ভাবে কিছু লিখুন বা অন্য সার্ভার থেকে কাওকে অনুসরণ করে এই জায়গা ভরে ফেলুন\",\n  \"follow_request.authorize\": \"অনুমতি দিন\",\n  \"follow_request.reject\": \"প্রত্যাখ্যান করুন\",\n  \"getting_started.developers\": \"তৈরিকারকদের জন্য\",\n  \"getting_started.directory\": \"নিজস্ব পাতার তালিকা\",\n  \"getting_started.documentation\": \"নথিপত্র\",\n  \"getting_started.heading\": \"শুরু করা\",\n  \"getting_started.invite\": \"অন্যদের আমন্ত্রণ করুন\",\n  \"getting_started.open_source_notice\": \"মাস্টাডন একটি মুক্ত সফটওয়্যার। আপনি তৈরিতে সাহায্য করতে পারেন অথবা সমস্যা রিপোর্ট করতে পারেন গিটহাবে {github}।\",\n  \"getting_started.security\": \"নিরাপত্তা\",\n  \"getting_started.terms\": \"ব্যবহারের নিয়মাবলী\",\n  \"hashtag.column_header.tag_mode.all\": \"এবং {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"অথবা {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"বাদ দিয়ে {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"কোনটা পাওয়া যায় নি\",\n  \"hashtag.column_settings.select.placeholder\": \"হ্যাশট্যাগের ভেতরে ঢুকুন…\",\n  \"hashtag.column_settings.tag_mode.all\": \"এগুলো সব\",\n  \"hashtag.column_settings.tag_mode.any\": \"এর ভেতরে যেকোনোটা\",\n  \"hashtag.column_settings.tag_mode.none\": \"এগুলোর একটাও না\",\n  \"hashtag.column_settings.tag_toggle\": \"আরো ট্যাগ এই কলামে যুক্ত করুন\",\n  \"home.column_settings.basic\": \"সাধারণ\",\n  \"home.column_settings.show_reblogs\": \"সমর্থনগুলো দেখান\",\n  \"home.column_settings.show_replies\": \"মতামত দেখান\",\n  \"intervals.full.days\": \"{number, plural, one {# day} other {# days}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# ঘটা} other {# ঘটা}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minute} other {# minutes}}\",\n  \"introduction.federation.action\": \"পরবর্তী\",\n  \"introduction.federation.federated.headline\": \"যুক্তবিশ্ব\",\n  \"introduction.federation.federated.text\": \"অন্যান্য যুক্তবিশ্বের সার্ভারের লেখাগুলি যুক্তবিশ্বের সময়রেখাতে আসবে ।\",\n  \"introduction.federation.home.headline\": \"বাড়ি\",\n  \"introduction.federation.home.text\": \"যাদেরকে অনুসরণ করেন তাদের লেখাগুলো  আপনার বাড়ি-সময়রেখাতে আসবে। আপনি এখান থেকে যুক্তবিশ্বে যেকোনো সার্ভারের যে কাওকে  অনুসরণ করতে পারেন!\",\n  \"introduction.federation.local.headline\": \"স্থানীয়\",\n  \"introduction.federation.local.text\": \"আপনি যে সার্ভারে আছেন সেখানকার মানুষের প্রকাশ্য লেখাগুলো স্থানীয় সময়রেখাতে আসবে।\",\n  \"introduction.interactions.action\": \"ব্যবহার জানার অংশটি শেষ করুন!\",\n  \"introduction.interactions.favourite.headline\": \"পছন্দের\",\n  \"introduction.interactions.favourite.text\": \"পরে পড়ার জন্য বা লেখা পছন্ধ হয়েছে সেটা লেখককে জানাতে, কোনো লেখা পছন্দের হিসেবে চিহ্নিত করতে পারেন।\",\n  \"introduction.interactions.reblog.headline\": \"সমর্থন\",\n  \"introduction.interactions.reblog.text\": \"কারোর লেখা সমর্থন দিয়ে চিহ্নিত করে সেটা আপনার অনুসরণকারীদের দেখতে পারেন।\",\n  \"introduction.interactions.reply.headline\": \"মতামত\",\n  \"introduction.interactions.reply.text\": \"আপনি অন্যদের এবং নিজের লেখায় মতামত টুট করতে পারেন, যেগুলো লেখার সাথে কথোপকথন হিসেবে যুক্ত থাকবে।\",\n  \"introduction.welcome.action\": \"শুরু করা যাক!\",\n  \"introduction.welcome.headline\": \"প্রথম ধাপ\",\n  \"introduction.welcome.text\": \"যুক্তবিশ্বে স্বাগতম! কিছুক্ষনের মধ্যেই আপনি আপনার লেখা বিভিন্ন সার্ভারে সম্প্রচার করতে পারবেন। কিন্তু মনে রাখবে যে এটা একটা বিশেষ সার্ভার, {domain} কারণ এখানে আপনার নিজেস্ব পাতা রাখা হচ্ছে।\",\n  \"keyboard_shortcuts.back\": \"পেছনে যেতে\",\n  \"keyboard_shortcuts.blocked\": \"বন্ধ করা ব্যবহারকারীদের তালিকা দেখতে\",\n  \"keyboard_shortcuts.boost\": \"সমর্থন করতে\",\n  \"keyboard_shortcuts.column\": \"কোনো কলামএ কোনো লেখা ফোকাস করতে\",\n  \"keyboard_shortcuts.compose\": \"লেখা সম্পদনার জায়গায় ফোকাস করতে\",\n  \"keyboard_shortcuts.description\": \"বিবরণ\",\n  \"keyboard_shortcuts.direct\": \"সরাসরি পাঠানো লেখা দেখতে\",\n  \"keyboard_shortcuts.down\": \"তালিকার ভেতরে নিচে যেতে\",\n  \"keyboard_shortcuts.enter\": \"অবস্থা দেখতে\",\n  \"keyboard_shortcuts.favourite\": \"পছন্দের দেখতে\",\n  \"keyboard_shortcuts.favourites\": \"পছন্দের তালিকা বের করতে\",\n  \"keyboard_shortcuts.federated\": \"যুক্তবিশ্বের সময়রেখাতে যেতে\",\n  \"keyboard_shortcuts.heading\": \"কিবোর্ডের দ্রুতকারক (শর্টকাট)\",\n  \"keyboard_shortcuts.home\": \"বাড়ির সময়রেখা খুলতে\",\n  \"keyboard_shortcuts.hotkey\": \"দ্রুতকারক ছবিগুলো\",\n  \"keyboard_shortcuts.legend\": \"এই প্রদর্শনঅর্থ(legend) দেখতে\",\n  \"keyboard_shortcuts.local\": \"স্থানীয় সময়রেখাতে যেতে\",\n  \"keyboard_shortcuts.mention\": \"লেখককে উল্লেখ করতে\",\n  \"keyboard_shortcuts.muted\": \"বন্ধ করা ব্যবহারকারীদের তালিকা খুলতে\",\n  \"keyboard_shortcuts.my_profile\": \"নিজের পাতা দেখতে\",\n  \"keyboard_shortcuts.notifications\": \"প্রজ্ঞাপনের কলাম খুলতে\",\n  \"keyboard_shortcuts.pinned\": \"পিন দেওয়া টুটের তালিকা খুলতে\",\n  \"keyboard_shortcuts.profile\": \"লেখকের পাতা দেখতে\",\n  \"keyboard_shortcuts.reply\": \"মতামত দিতে\",\n  \"keyboard_shortcuts.requests\": \"অনুসরণ অনুরোধের তালিকা দেখতে\",\n  \"keyboard_shortcuts.search\": \"খোঁজার অংশে ফোকাস করতে\",\n  \"keyboard_shortcuts.start\": \"\\\"প্রথম শুরুর\\\" কলাম বের করতে\",\n  \"keyboard_shortcuts.toggle_hidden\": \"CW লেখা দেখতে বা লুকাতে\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"to show/hide media\",\n  \"keyboard_shortcuts.toot\": \"নতুন একটা টুট লেখা শুরু করতে\",\n  \"keyboard_shortcuts.unfocus\": \"লেখা বা খোঁজার জায়গায় ফোকাস না করতে\",\n  \"keyboard_shortcuts.up\": \"তালিকার উপরের দিকে যেতে\",\n  \"lightbox.close\": \"বন্ধ\",\n  \"lightbox.next\": \"পরবর্তী\",\n  \"lightbox.previous\": \"পূর্ববর্তী\",\n  \"lightbox.view_context\": \"View context\",\n  \"lists.account.add\": \"তালিকাতে যুক্ত করতে\",\n  \"lists.account.remove\": \"তালিকা থেকে বাদ দিতে\",\n  \"lists.delete\": \"তালিকা মুছে ফেলতে\",\n  \"lists.edit\": \"তালিকা সম্পাদনা করতে\",\n  \"lists.edit.submit\": \"শিরোনাম সম্পাদনা করতে\",\n  \"lists.new.create\": \"তালিকাতে যুক্ত করতে\",\n  \"lists.new.title_placeholder\": \"তালিকার নতুন শিরোনাম দিতে\",\n  \"lists.search\": \"যাদের অনুসরণ করেন তাদের ভেতরে খুঁজুন\",\n  \"lists.subheading\": \"আপনার তালিকা\",\n  \"loading_indicator.label\": \"আসছে...\",\n  \"media_gallery.toggle_visible\": \"দৃশ্যতার অবস্থা বদলান\",\n  \"missing_indicator.label\": \"খুঁজে পাওয়া যায়নি\",\n  \"missing_indicator.sublabel\": \"জিনিসটা খুঁজে পাওয়া যায়নি\",\n  \"mute_modal.hide_notifications\": \"এই ব্যবহারকারীর প্রজ্ঞাপন বন্ধ করবেন ?\",\n  \"navigation_bar.apps\": \"মোবাইলের আপ্প\",\n  \"navigation_bar.blocks\": \"বন্ধ করা ব্যবহারকারী\",\n  \"navigation_bar.community_timeline\": \"স্থানীয় সময়রেখা\",\n  \"navigation_bar.compose\": \"নতুন টুট লিখুন\",\n  \"navigation_bar.direct\": \"সরাসরি লেখা\",\n  \"navigation_bar.discover\": \"ঘুরে দেখুন\",\n  \"navigation_bar.domain_blocks\": \"বন্ধ করা ওয়েবসাইট\",\n  \"navigation_bar.edit_profile\": \"নিজের পাতা সম্পাদনা করুন\",\n  \"navigation_bar.favourites\": \"পছন্দের\",\n  \"navigation_bar.filters\": \"বন্ধ করা শব্দ\",\n  \"navigation_bar.follow_requests\": \"অনুসরণের অনুরোধগুলি\",\n  \"navigation_bar.follows_and_followers\": \"Follows and followers\",\n  \"navigation_bar.info\": \"এই সার্ভার সম্পর্কে\",\n  \"navigation_bar.keyboard_shortcuts\": \"চাবি ব্যবহার\",\n  \"navigation_bar.lists\": \"তালিকাগুলো\",\n  \"navigation_bar.logout\": \"বাইরে যান\",\n  \"navigation_bar.mutes\": \"যেসব বেভহারকারীদের কার্যক্রম বন্ধ করা আছে\",\n  \"navigation_bar.personal\": \"নিজস্ব\",\n  \"navigation_bar.pins\": \"পিন দেওয়া টুট\",\n  \"navigation_bar.preferences\": \"পছন্দসমূহ\",\n  \"navigation_bar.profile_directory\": \"Profile directory\",\n  \"navigation_bar.public_timeline\": \"যুক্তবিশ্বের সময়রেখা\",\n  \"navigation_bar.security\": \"নিরাপত্তা\",\n  \"notification.favourite\": \"{name} আপনার কার্যক্রম পছন্দ করেছেন\",\n  \"notification.follow\": \"{name} আপনাকে অনুসরণ করেছেন\",\n  \"notification.mention\": \"{name} আপনাকে উল্লেখ করেছেন\",\n  \"notification.poll\": \"আপনি ভোট দিয়েছিলেন এমন এক  নির্বাচনের ভোটের সময় শেষ হয়েছে\",\n  \"notification.reblog\": \"{name} আপনার কার্যক্রমে সমর্থন দেখিয়েছেন\",\n  \"notifications.clear\": \"প্রজ্ঞাপনগুলো মুছে ফেলতে\",\n  \"notifications.clear_confirmation\": \"আপনি কি নির্চিত প্রজ্ঞাপনগুলো মুছে ফেলতে চান ?\",\n  \"notifications.column_settings.alert\": \"কম্পিউটারে প্রজ্ঞাপন\",\n  \"notifications.column_settings.favourite\": \"পছন্দের:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"সব শ্রেণীগুলো দেখতে\",\n  \"notifications.column_settings.filter_bar.category\": \"দ্রুত ছাঁকনি বার\",\n  \"notifications.column_settings.filter_bar.show\": \"দেখতে\",\n  \"notifications.column_settings.follow\": \"নতুন অনুসরণকারীরা:\",\n  \"notifications.column_settings.mention\": \"প্রজ্ঞাপনগুলো:\",\n  \"notifications.column_settings.poll\": \"নির্বাচনের ফলাফল:\",\n  \"notifications.column_settings.push\": \"পুশ প্রজ্ঞাপন\",\n  \"notifications.column_settings.reblog\": \"সমর্থনগুলো:\",\n  \"notifications.column_settings.show\": \"কলামে দেখান\",\n  \"notifications.column_settings.sound\": \"শব্দ বাজাতে\",\n  \"notifications.filter.all\": \"সব\",\n  \"notifications.filter.boosts\": \"সমর্থনগুলো\",\n  \"notifications.filter.favourites\": \"পছন্দের গুলো\",\n  \"notifications.filter.follows\": \"অনুসরণের\",\n  \"notifications.filter.mentions\": \"উল্লেখিত\",\n  \"notifications.filter.polls\": \"নির্বাচনের ফলাফল\",\n  \"notifications.group\": \"{count} প্রজ্ঞাপন\",\n  \"poll.closed\": \"বন্ধ\",\n  \"poll.refresh\": \"আবার সতেজ করতে\",\n  \"poll.total_votes\": \"{count, plural, one {# ভোট} other {# ভোট}}\",\n  \"poll.vote\": \"ভোট\",\n  \"poll_button.add_poll\": \"একটা নির্বাচন যোগ করতে\",\n  \"poll_button.remove_poll\": \"নির্বাচন বাদ দিতে\",\n  \"privacy.change\": \"লেখার গোপনীয়তা অবস্থা ঠিক করতে\",\n  \"privacy.direct.long\": \"শুধুমাত্র উল্লেখিত ব্যবহারকারীদের কাছে লিখতে\",\n  \"privacy.direct.short\": \"সরাসরি\",\n  \"privacy.private.long\": \"শুধুমাত্র আপনার অনুসরণকারীদের লিখতে\",\n  \"privacy.private.short\": \"শুধুমাত্র অনুসরণকারীদের জন্য\",\n  \"privacy.public.long\": \"সর্বজনীন প্রকাশ্য সময়রেখাতে লিখতে\",\n  \"privacy.public.short\": \"সর্বজনীন প্রকাশ্য\",\n  \"privacy.unlisted.long\": \"সর্বজনীন প্রকাশ্য সময়রেখাতে না দেখাতে\",\n  \"privacy.unlisted.short\": \"প্রকাশ্য নয়\",\n  \"regeneration_indicator.label\": \"আসছে…\",\n  \"regeneration_indicator.sublabel\": \"আপনার বাড়ির-সময়রেখা প্রস্তূত করা হচ্ছে!\",\n  \"relative_time.days\": \"{number} দিন\",\n  \"relative_time.hours\": \"{number} ঘন্টা\",\n  \"relative_time.just_now\": \"এখন\",\n  \"relative_time.minutes\": \"{number}ম\",\n  \"relative_time.seconds\": \"{number} সেকেন্ড\",\n  \"reply_indicator.cancel\": \"বাতিল করতে\",\n  \"report.forward\": \"এটা আরো পাঠান {target} তে\",\n  \"report.forward_hint\": \"এই নিবন্ধনটি অন্য একটি সার্ভারে। অপ্রকাশিতনামাভাবে রিপোর্টের কপি সেখানেও কি পাঠাতে চান ?\",\n  \"report.hint\": \"রিপোর্টটি আপনার সার্ভারের পরিচালকের কাছে পাঠানো হবে। রিপোর্ট পাঠানোর কারণ নিচে বিস্তারিত লিখতে পারেন:\",\n  \"report.placeholder\": \"অন্য কোনো মন্তব্য\",\n  \"report.submit\": \"জমা দিন\",\n  \"report.target\": \"{target} রিপোর্ট করুন\",\n  \"search.placeholder\": \"খুঁজতে\",\n  \"search_popout.search_format\": \"বিস্তারিতভাবে খোঁজার পদ্ধতি\",\n  \"search_popout.tips.full_text\": \"সাধারণ লেখা দিয়ে খুঁজলে বের হবে সেরকম আপনার লেখা, পছন্দের লেখা, সমর্থন করা লেখা, আপনাকে উল্লেখকরা কোনো লেখা,  যা খুঁজছেন সেরকম কোনো ব্যবহারকারীর নাম বা কোনো হ্যাশট্যাগগুলো।\",\n  \"search_popout.tips.hashtag\": \"হ্যাশট্যাগ\",\n  \"search_popout.tips.status\": \"লেখা\",\n  \"search_popout.tips.text\": \"সাধারণ লেখা দিয়ে খুঁজলে বের হবে সেরকম ব্যবহারকারীর নাম বা কোনো হ্যাশট্যাগগুলো\",\n  \"search_popout.tips.user\": \"ব্যবহারকারী\",\n  \"search_results.accounts\": \"মানুষ\",\n  \"search_results.hashtags\": \"হ্যাশট্যাগগুলি\",\n  \"search_results.statuses\": \"টুট\",\n  \"search_results.total\": \"{count, number} {count, plural, one {ফলাফল} other {ফলাফল}}\",\n  \"status.admin_account\": \"@{name} র জন্য পরিচালনার ইন্টারফেসে ঢুকুন\",\n  \"status.admin_status\": \"যায় লেখাটি পরিচালনার ইন্টারফেসে খুলুন\",\n  \"status.block\": \"@{name}কে বন্ধ করুন\",\n  \"status.cancel_reblog_private\": \"সমর্থন বাতিল করতে\",\n  \"status.cannot_reblog\": \"এটিতে সমর্থন দেওয়া যাবেনা\",\n  \"status.copy\": \"লেখাটির লিংক কপি করতে\",\n  \"status.delete\": \"মুছে ফেলতে\",\n  \"status.detailed_status\": \"বিস্তারিত কথোপকথনের হিসেবে দেখতে\",\n  \"status.direct\": \"@{name} কে সরাসরি পাঠান\",\n  \"status.embed\": \"এমবেড করতে\",\n  \"status.favourite\": \"পছন্দের করতে\",\n  \"status.filtered\": \"ছাঁকনিদিত\",\n  \"status.load_more\": \"আরো দেখুন\",\n  \"status.media_hidden\": \"ছবি বা ভিডিও পেছনে\",\n  \"status.mention\": \"@{name}কে উল্লেখ করতে\",\n  \"status.more\": \"আরো\",\n  \"status.mute\": \"@{name}র কার্যক্রম সরিয়ে ফেলতে\",\n  \"status.mute_conversation\": \"কথোপকথননের প্রজ্ঞাপন সরিয়ে ফেলতে\",\n  \"status.open\": \"এটার সম্পূর্ণটা দেখতে\",\n  \"status.pin\": \"নিজের পাতায় এটা পিন করতে\",\n  \"status.pinned\": \"পিন করা টুট\",\n  \"status.read_more\": \"আরো পড়ুন\",\n  \"status.reblog\": \"সমর্থন দিতে\",\n  \"status.reblog_private\": \"আপনার অনুসরণকারীদের কাছে এটার সমর্থন দেখাতে\",\n  \"status.reblogged_by\": \"{name} সমর্থন দিয়েছে\",\n  \"status.reblogs.empty\": \"এখনো কেও এটাতে সমর্থন দেয়নি। যখন কেও দেয়, সেটা তখন এখানে দেখা যাবে।\",\n  \"status.redraft\": \"মুছে আবার নতুন করে লিখতে\",\n  \"status.reply\": \"মতামত জানাতে\",\n  \"status.replyAll\": \"লেখাযুক্ত সবার কাছে মতামত জানাতে\",\n  \"status.report\": \"@{name}কে রিপোর্ট করতে\",\n  \"status.sensitive_warning\": \"সংবেদনশীল কিছু\",\n  \"status.share\": \"অন্যদের জানান\",\n  \"status.show_less\": \"কম দেখতে\",\n  \"status.show_less_all\": \"সবগুলোতে কম দেখতে\",\n  \"status.show_more\": \"আরো দেখাতে\",\n  \"status.show_more_all\": \"সবগুলোতে আরো দেখতে\",\n  \"status.show_thread\": \"আলোচনা দেখতে\",\n  \"status.unmute_conversation\": \"আলোচনার প্রজ্ঞাপন চালু করতে\",\n  \"status.unpin\": \"নিজের পাতা থেকে পিন করে রাখাটির পিন খুলতে\",\n  \"suggestions.dismiss\": \"সাহায্যের জন্য পরামর্শগুলো সরাতে\",\n  \"suggestions.header\": \"আপনি হয়তোবা এগুলোতে আগ্রহী হতে পারেন…\",\n  \"tabs_bar.federated_timeline\": \"যুক্তবিশ্ব\",\n  \"tabs_bar.home\": \"বাড়ি\",\n  \"tabs_bar.local_timeline\": \"স্থানীয়\",\n  \"tabs_bar.notifications\": \"প্রজ্ঞাপনগুলো\",\n  \"tabs_bar.search\": \"খুঁজতে\",\n  \"time_remaining.days\": \"{number, plural, one {# day} other {# days}} বাকি আছে\",\n  \"time_remaining.hours\": \"{number, plural, one {# hour} other {# hours}} বাকি আছে\",\n  \"time_remaining.minutes\": \"{number, plural, one {# minute} other {# minutes}} বাকি আছে\",\n  \"time_remaining.moments\": \"সময় বাকি আছে\",\n  \"time_remaining.seconds\": \"{number, plural, one {# second} other {# seconds}} বাকি আছে\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {person} other {people}} কথা বলছে\",\n  \"ui.beforeunload\": \"যে পর্যন্ত এটা লেখা হয়েছে, মাস্টাডন থেকে চলে গেলে এটা মুছে যাবে।\",\n  \"upload_area.title\": \"টেনে এখানে ছেড়ে দিলে এখানে যুক্ত করা যাবে\",\n  \"upload_button.label\": \"ছবি বা ভিডিও যুক্ত করতে (এসব ধরণের JPEG, PNG, GIF, WebM, MP4, MOV)\",\n  \"upload_error.limit\": \"যা যুক্ত করতে চাচ্ছেন সেটি বেশি বড়, এখানকার সর্বাধিকের মেমোরির উপরে চলে গেছে।\",\n  \"upload_error.poll\": \"নির্বাচনক্ষেত্রে কোনো ফাইল যুক্ত করা যাবেনা।\",\n  \"upload_form.description\": \"যারা দেখতে পায়না তাদের জন্য এটা বর্ণনা করতে\",\n  \"upload_form.focus\": \"সাধারণ দেখাটি পরিবর্তন করতে\",\n  \"upload_form.undo\": \"মুছে ফেলতে\",\n  \"upload_progress.label\": \"যুক্ত করতে পাঠানো হচ্ছে...\",\n  \"video.close\": \"ভিডিওটি বন্ধ করতে\",\n  \"video.exit_fullscreen\": \"পূর্ণ পর্দা থেকে বাইরে বের হতে\",\n  \"video.expand\": \"ভিডিওটি বড়ো করতে\",\n  \"video.fullscreen\": \"পূর্ণ পর্দা করতে\",\n  \"video.hide\": \"ভিডিওটি লুকাতে\",\n  \"video.mute\": \"শব্দ বন্ধ করতে\",\n  \"video.pause\": \"থামাতে\",\n  \"video.play\": \"শুরু করতে\",\n  \"video.unmute\": \"শব্দ চালু করতে\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/ca.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Afegir o Treure de les llistes\",\n  \"account.badges.bot\": \"Bot\",\n  \"account.block\": \"Bloqueja @{name}\",\n  \"account.block_domain\": \"Amaga-ho tot de {domain}\",\n  \"account.blocked\": \"Bloquejat\",\n  \"account.direct\": \"Missatge directe @{name}\",\n  \"account.domain_blocked\": \"Domini ocult\",\n  \"account.edit_profile\": \"Editar el perfil\",\n  \"account.endorse\": \"Recomanar en el teu perfil\",\n  \"account.follow\": \"Segueix\",\n  \"account.followers\": \"Seguidors\",\n  \"account.followers.empty\": \"Encara ningú no segueix aquest usuari.\",\n  \"account.follows\": \"Seguiments\",\n  \"account.follows.empty\": \"Aquest usuari encara no segueix a ningú.\",\n  \"account.follows_you\": \"Et segueix\",\n  \"account.hide_reblogs\": \"Amaga els impulsos de @{name}\",\n  \"account.link_verified_on\": \"La propietat d'aquest enllaç es va verificar el dia {date}\",\n  \"account.locked_info\": \"Aquest estat de privadesa del compte està definit com a bloquejat. El propietari revisa manualment qui pot seguir-lo.\",\n  \"account.media\": \"Mèdia\",\n  \"account.mention\": \"Esmentar @{name}\",\n  \"account.moved_to\": \"{name} s'ha mogut a:\",\n  \"account.mute\": \"Silencia @{name}\",\n  \"account.mute_notifications\": \"Notificacions desactivades de @{name}\",\n  \"account.muted\": \"Silenciat\",\n  \"account.posts\": \"Toots\",\n  \"account.posts_with_replies\": \"Toots i respostes\",\n  \"account.report\": \"Informe @{name}\",\n  \"account.requested\": \"Esperant aprovació. Clic per a cancel·lar la petició de seguiment\",\n  \"account.share\": \"Comparteix el perfil de @{name}\",\n  \"account.show_reblogs\": \"Mostra els impulsos de @{name}\",\n  \"account.unblock\": \"Desbloca @{name}\",\n  \"account.unblock_domain\": \"Mostra {domain}\",\n  \"account.unendorse\": \"No es mostren al perfil\",\n  \"account.unfollow\": \"Deixa de seguir\",\n  \"account.unmute\": \"Treure silenci de @{name}\",\n  \"account.unmute_notifications\": \"Activar notificacions de @{name}\",\n  \"alert.unexpected.message\": \"S'ha produït un error inesperat.\",\n  \"alert.unexpected.title\": \"Vaja!\",\n  \"boost_modal.combo\": \"Pots premer {combo} per saltar-te això el proper cop\",\n  \"bundle_column_error.body\": \"S'ha produït un error en carregar aquest component.\",\n  \"bundle_column_error.retry\": \"Torna-ho a provar\",\n  \"bundle_column_error.title\": \"Error de connexió\",\n  \"bundle_modal_error.close\": \"Tanca\",\n  \"bundle_modal_error.message\": \"S'ha produït un error en carregar aquest component.\",\n  \"bundle_modal_error.retry\": \"Torna-ho a provar\",\n  \"column.blocks\": \"Usuaris bloquejats\",\n  \"column.community\": \"Línia de temps local\",\n  \"column.direct\": \"Missatges directes\",\n  \"column.domain_blocks\": \"Dominis ocults\",\n  \"column.favourites\": \"Favorits\",\n  \"column.follow_requests\": \"Peticions per seguir-te\",\n  \"column.home\": \"Inici\",\n  \"column.lists\": \"Llistes\",\n  \"column.mutes\": \"Usuaris silenciats\",\n  \"column.notifications\": \"Notificacions\",\n  \"column.pins\": \"Toots fixats\",\n  \"column.public\": \"Línia de temps federada\",\n  \"column_back_button.label\": \"Enrere\",\n  \"column_header.hide_settings\": \"Amaga la configuració\",\n  \"column_header.moveLeft_settings\": \"Mou la columna cap a l'esquerra\",\n  \"column_header.moveRight_settings\": \"Mou la columna cap a la dreta\",\n  \"column_header.pin\": \"Fixa\",\n  \"column_header.show_settings\": \"Mostra la configuració\",\n  \"column_header.unpin\": \"No fixis\",\n  \"column_subheading.settings\": \"Configuració\",\n  \"community.column_settings.media_only\": \"Només multimèdia\",\n  \"compose_form.direct_message_warning\": \"Aquest toot només serà enviat als usuaris esmentats.\",\n  \"compose_form.direct_message_warning_learn_more\": \"Aprèn més\",\n  \"compose_form.hashtag_warning\": \"Aquest toot no es mostrarà en cap etiqueta ja que no està llistat. Només els toots públics poden ser cercats per etiqueta.\",\n  \"compose_form.lock_disclaimer\": \"El teu compte no està bloquejat {locked}. Tothom pot seguir-te i veure els teus missatges a seguidors.\",\n  \"compose_form.lock_disclaimer.lock\": \"bloquejat\",\n  \"compose_form.placeholder\": \"En què penses?\",\n  \"compose_form.poll.add_option\": \"Afegeix una opció\",\n  \"compose_form.poll.duration\": \"Durada de l'enquesta\",\n  \"compose_form.poll.option_placeholder\": \"Opció {number}\",\n  \"compose_form.poll.remove_option\": \"Elimina aquesta opció\",\n  \"compose_form.publish\": \"Toot\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"Marcar mèdia com a sensible\",\n  \"compose_form.sensitive.marked\": \"Mèdia marcat com a sensible\",\n  \"compose_form.sensitive.unmarked\": \"Mèdia no està marcat com a sensible\",\n  \"compose_form.spoiler.marked\": \"Text es ocult sota l'avís\",\n  \"compose_form.spoiler.unmarked\": \"Text no ocult\",\n  \"compose_form.spoiler_placeholder\": \"Escriu l'avís aquí\",\n  \"confirmation_modal.cancel\": \"Cancel·la\",\n  \"confirmations.block.block_and_report\": \"Bloquejar i informar\",\n  \"confirmations.block.confirm\": \"Bloqueja\",\n  \"confirmations.block.message\": \"Estàs segur que vols bloquejar a {name}?\",\n  \"confirmations.delete.confirm\": \"Suprimeix\",\n  \"confirmations.delete.message\": \"Estàs segur que vols suprimir aquest toot?\",\n  \"confirmations.delete_list.confirm\": \"Suprimeix\",\n  \"confirmations.delete_list.message\": \"Estàs segur que vols suprimir permanentment aquesta llista?\",\n  \"confirmations.domain_block.confirm\": \"Amaga tot el domini\",\n  \"confirmations.domain_block.message\": \"Estàs segur, realment segur que vols bloquejar totalment {domain}? En la majoria dels casos bloquejar o silenciar uns pocs objectius és suficient i preferible. No veuràs contingut d’aquest domini en cap de les línies públiques ni en les notificacions. Els teus seguidors d’aquest domini seran eliminats.\",\n  \"confirmations.mute.confirm\": \"Silencia\",\n  \"confirmations.mute.message\": \"Estàs segur que vols silenciar {name}?\",\n  \"confirmations.redraft.confirm\": \"Esborrar i refer\",\n  \"confirmations.redraft.message\": \"Estàs segur que vols esborrar aquest toot i tornar a redactar-lo? Perderàs totes els impulsos i favorits, i les respostes al toot original es quedaran orfes.\",\n  \"confirmations.reply.confirm\": \"Respon\",\n  \"confirmations.reply.message\": \"Responen ara es sobreescriurà el missatge que estàs editant. Estàs segur que vols continuar?\",\n  \"confirmations.unfollow.confirm\": \"Deixa de seguir\",\n  \"confirmations.unfollow.message\": \"Estàs segur que vols deixar de seguir {name}?\",\n  \"embed.instructions\": \"Incrusta aquest toot al lloc web copiant el codi a continuació.\",\n  \"embed.preview\": \"Aquí tenim quin aspecte tindrá:\",\n  \"emoji_button.activity\": \"Activitat\",\n  \"emoji_button.custom\": \"Personalitzat\",\n  \"emoji_button.flags\": \"Banderes\",\n  \"emoji_button.food\": \"Menjar i beure\",\n  \"emoji_button.label\": \"Insereix un emoji\",\n  \"emoji_button.nature\": \"Natura\",\n  \"emoji_button.not_found\": \"Emojis no!! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"Objectes\",\n  \"emoji_button.people\": \"Gent\",\n  \"emoji_button.recent\": \"Usats freqüentment\",\n  \"emoji_button.search\": \"Cerca...\",\n  \"emoji_button.search_results\": \"Resultats de la cerca\",\n  \"emoji_button.symbols\": \"Símbols\",\n  \"emoji_button.travel\": \"Viatges i Llocs\",\n  \"empty_column.account_timeline\": \"No hi ha toots aquí!\",\n  \"empty_column.account_unavailable\": \"Perfil no disponible\",\n  \"empty_column.blocks\": \"Encara no has bloquejat cap usuari.\",\n  \"empty_column.community\": \"La línia de temps local és buida. Escriu alguna cosa públicament per a fer rodar la pilota!\",\n  \"empty_column.direct\": \"Encara no tens missatges directes. Quan enviïs o rebis un, es mostrarà aquí.\",\n  \"empty_column.domain_blocks\": \"Encara no hi ha dominis ocults.\",\n  \"empty_column.favourited_statuses\": \"Encara no tens cap toot favorit. Quan en tinguis, apareixerà aquí.\",\n  \"empty_column.favourites\": \"Encara ningú ha marcat aquest toot com a favorit. Quan algú ho faci, apareixera aquí.\",\n  \"empty_column.follow_requests\": \"Encara no teniu cap petició de seguiment. Quan rebis una, apareixerà aquí.\",\n  \"empty_column.hashtag\": \"Encara no hi ha res en aquesta etiqueta.\",\n  \"empty_column.home\": \"Encara no segueixes ningú. Visita {public} o fes cerca per començar i conèixer altres usuaris.\",\n  \"empty_column.home.public_timeline\": \"la línia de temps pública\",\n  \"empty_column.list\": \"Encara no hi ha res en aquesta llista. Quan els membres d'aquesta llista publiquin nous toots, apareixeran aquí.\",\n  \"empty_column.lists\": \"Encara no tens cap llista. Quan en facis una, apareixerà aquí.\",\n  \"empty_column.mutes\": \"Encara no has silenciat cap usuari.\",\n  \"empty_column.notifications\": \"Encara no tens notificacions. Interactua amb altres per iniciar la conversa.\",\n  \"empty_column.public\": \"No hi ha res aquí! Escriu públicament alguna cosa o manualment segueix usuaris d'altres servidors per omplir-ho\",\n  \"follow_request.authorize\": \"Autoritzar\",\n  \"follow_request.reject\": \"Rebutjar\",\n  \"getting_started.developers\": \"Desenvolupadors\",\n  \"getting_started.directory\": \"Directori de perfils\",\n  \"getting_started.documentation\": \"Documentació\",\n  \"getting_started.heading\": \"Començant\",\n  \"getting_started.invite\": \"Convida gent\",\n  \"getting_started.open_source_notice\": \"Mastodon és un programari de codi obert. Pots contribuir o informar de problemes a GitHub a {github}.\",\n  \"getting_started.security\": \"Seguretat\",\n  \"getting_started.terms\": \"Termes del servei\",\n  \"hashtag.column_header.tag_mode.all\": \"i {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"o {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"sense {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"No s'ha trobat cap suggeriment\",\n  \"hashtag.column_settings.select.placeholder\": \"Introdueix etiquetes…\",\n  \"hashtag.column_settings.tag_mode.all\": \"Tots aquests\",\n  \"hashtag.column_settings.tag_mode.any\": \"Qualsevol d’aquests\",\n  \"hashtag.column_settings.tag_mode.none\": \"Cap d’aquests\",\n  \"hashtag.column_settings.tag_toggle\": \"Inclou etiquetes addicionals per a aquesta columna\",\n  \"home.column_settings.basic\": \"Bàsic\",\n  \"home.column_settings.show_reblogs\": \"Mostrar impulsos\",\n  \"home.column_settings.show_replies\": \"Mostrar respostes\",\n  \"intervals.full.days\": \"{number, plural, one {# dia} other {# dies}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# hora} other {# hores}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minut} other {# minuts}}\",\n  \"introduction.federation.action\": \"Següent\",\n  \"introduction.federation.federated.headline\": \"Federada\",\n  \"introduction.federation.federated.text\": \"Les publicacions públiques d'altres servidors del fedivers apareixeran a la línia de temps federada.\",\n  \"introduction.federation.home.headline\": \"Inici\",\n  \"introduction.federation.home.text\": \"Les publicacions de les persones que segueixes apareixeran a la línia de temps Inici. Pots seguir qualsevol persona de qualsevol servidor!\",\n  \"introduction.federation.local.headline\": \"Local\",\n  \"introduction.federation.local.text\": \"Les publicacions públiques de les persones del teu mateix servidor apareixeran a la línia de temps local.\",\n  \"introduction.interactions.action\": \"Finalitza el tutorial!\",\n  \"introduction.interactions.favourite.headline\": \"Favorit\",\n  \"introduction.interactions.favourite.text\": \"Pots desar un toot per a més tard i deixar que l'autor sàpiga que t'ha agradat, marcant-lo com a favorit.\",\n  \"introduction.interactions.reblog.headline\": \"Impuls\",\n  \"introduction.interactions.reblog.text\": \"Pots compartir amb els teus seguidors els toots d'altres usuaris, impulsant-los.\",\n  \"introduction.interactions.reply.headline\": \"Respondre\",\n  \"introduction.interactions.reply.text\": \"Pots respondre als toots d'altres persones i als teus propis, que els unirà en una conversa.\",\n  \"introduction.welcome.action\": \"Som-hi!\",\n  \"introduction.welcome.headline\": \"Primers passos\",\n  \"introduction.welcome.text\": \"Benvingut al fedivers! En uns moments podràs emetre missatges i conversar amb els teus amics en una gran varietat de servidors. Però aquest servidor, {domain}, és especial: allotja el teu perfil així que recorda el seu nom.\",\n  \"keyboard_shortcuts.back\": \"navegar enrera\",\n  \"keyboard_shortcuts.blocked\": \"per obrir la llista d'usuaris bloquejats\",\n  \"keyboard_shortcuts.boost\": \"impulsar\",\n  \"keyboard_shortcuts.column\": \"per a centrar un toot en una de les columnes\",\n  \"keyboard_shortcuts.compose\": \"per centrar l'area de composició de text\",\n  \"keyboard_shortcuts.description\": \"Descripció\",\n  \"keyboard_shortcuts.direct\": \"per obrir la columna de missatges directes\",\n  \"keyboard_shortcuts.down\": \"per baixar en la llista\",\n  \"keyboard_shortcuts.enter\": \"ampliar el toot\",\n  \"keyboard_shortcuts.favourite\": \"afavorir\",\n  \"keyboard_shortcuts.favourites\": \"per obrir la llista de favorits\",\n  \"keyboard_shortcuts.federated\": \"per obrir la línia de temps federada\",\n  \"keyboard_shortcuts.heading\": \"Dreçeres de teclat\",\n  \"keyboard_shortcuts.home\": \"per a obrir la línia de temps Inici\",\n  \"keyboard_shortcuts.hotkey\": \"Tecla d'accés directe\",\n  \"keyboard_shortcuts.legend\": \"per a mostrar aquesta llegenda\",\n  \"keyboard_shortcuts.local\": \"per a obrir la línia de temps local\",\n  \"keyboard_shortcuts.mention\": \"per a esmentar l'autor\",\n  \"keyboard_shortcuts.muted\": \"per a obrir la llista d'usuaris silenciats\",\n  \"keyboard_shortcuts.my_profile\": \"per a obrir el teu perfil\",\n  \"keyboard_shortcuts.notifications\": \"per a obrir la columna de notificacions\",\n  \"keyboard_shortcuts.pinned\": \"per a obrir la llista de toots fixats\",\n  \"keyboard_shortcuts.profile\": \"per a obrir el perfil de l'autor\",\n  \"keyboard_shortcuts.reply\": \"respondre\",\n  \"keyboard_shortcuts.requests\": \"per a obrir la llista de sol·licituds de seguiment\",\n  \"keyboard_shortcuts.search\": \"per a centrar la cerca\",\n  \"keyboard_shortcuts.start\": \"per a obrir la columna \\\"Començar\\\"\",\n  \"keyboard_shortcuts.toggle_hidden\": \"per a mostrar/amagar text sota CW\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"per a mostrar/amagar mèdia\",\n  \"keyboard_shortcuts.toot\": \"per a començar un toot nou de trinca\",\n  \"keyboard_shortcuts.unfocus\": \"descentrar l'area de composició de text/cerca\",\n  \"keyboard_shortcuts.up\": \"moure amunt en la llista\",\n  \"lightbox.close\": \"Tancar\",\n  \"lightbox.next\": \"Següent\",\n  \"lightbox.previous\": \"Anterior\",\n  \"lightbox.view_context\": \"Veure el context\",\n  \"lists.account.add\": \"Afegir a la llista\",\n  \"lists.account.remove\": \"Treure de la llista\",\n  \"lists.delete\": \"Esborrar llista\",\n  \"lists.edit\": \"Editar llista\",\n  \"lists.edit.submit\": \"Canvi de títol\",\n  \"lists.new.create\": \"Afegir llista\",\n  \"lists.new.title_placeholder\": \"Nova llista\",\n  \"lists.search\": \"Cercar entre les persones que segueixes\",\n  \"lists.subheading\": \"Les teves llistes\",\n  \"loading_indicator.label\": \"Carregant...\",\n  \"media_gallery.toggle_visible\": \"Alternar visibilitat\",\n  \"missing_indicator.label\": \"No trobat\",\n  \"missing_indicator.sublabel\": \"Aquest recurs no pot ser trobat\",\n  \"mute_modal.hide_notifications\": \"Amagar notificacions d'aquest usuari?\",\n  \"navigation_bar.apps\": \"Apps mòbils\",\n  \"navigation_bar.blocks\": \"Usuaris bloquejats\",\n  \"navigation_bar.community_timeline\": \"Línia de temps Local\",\n  \"navigation_bar.compose\": \"Redacta nou toot\",\n  \"navigation_bar.direct\": \"Missatges directes\",\n  \"navigation_bar.discover\": \"Descobreix\",\n  \"navigation_bar.domain_blocks\": \"Dominis ocults\",\n  \"navigation_bar.edit_profile\": \"Editar perfil\",\n  \"navigation_bar.favourites\": \"Favorits\",\n  \"navigation_bar.filters\": \"Paraules silenciades\",\n  \"navigation_bar.follow_requests\": \"Sol·licituds de seguiment\",\n  \"navigation_bar.follows_and_followers\": \"Seguits i seguidors\",\n  \"navigation_bar.info\": \"Sobre aquest servidor\",\n  \"navigation_bar.keyboard_shortcuts\": \"Dreceres de teclat\",\n  \"navigation_bar.lists\": \"Llistes\",\n  \"navigation_bar.logout\": \"Tancar sessió\",\n  \"navigation_bar.mutes\": \"Usuaris silenciats\",\n  \"navigation_bar.personal\": \"Personal\",\n  \"navigation_bar.pins\": \"Toots fixats\",\n  \"navigation_bar.preferences\": \"Preferències\",\n  \"navigation_bar.profile_directory\": \"Directori de perfils\",\n  \"navigation_bar.public_timeline\": \"Línia de temps federada\",\n  \"navigation_bar.security\": \"Seguretat\",\n  \"notification.favourite\": \"{name} ha afavorit el teu estat\",\n  \"notification.follow\": \"{name} et segueix\",\n  \"notification.mention\": \"{name} t'ha esmentat\",\n  \"notification.poll\": \"Ha finalitzat una enquesta en la que has votat\",\n  \"notification.reblog\": \"{name} ha impulsat el teu estat\",\n  \"notifications.clear\": \"Netejar notificacions\",\n  \"notifications.clear_confirmation\": \"Estàs segur que vols esborrar permanenment totes les teves notificacions?\",\n  \"notifications.column_settings.alert\": \"Notificacions d'escriptori\",\n  \"notifications.column_settings.favourite\": \"Favorits:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Mostra totes les categories\",\n  \"notifications.column_settings.filter_bar.category\": \"Barra ràpida de filtres\",\n  \"notifications.column_settings.filter_bar.show\": \"Mostra\",\n  \"notifications.column_settings.follow\": \"Nous seguidors:\",\n  \"notifications.column_settings.mention\": \"Mencions:\",\n  \"notifications.column_settings.poll\": \"Resultats de l’enquesta:\",\n  \"notifications.column_settings.push\": \"Notificacions push\",\n  \"notifications.column_settings.reblog\": \"Impulsos:\",\n  \"notifications.column_settings.show\": \"Mostrar en la columna\",\n  \"notifications.column_settings.sound\": \"Reproduïr so\",\n  \"notifications.filter.all\": \"Tots\",\n  \"notifications.filter.boosts\": \"Impulsos\",\n  \"notifications.filter.favourites\": \"Favorits\",\n  \"notifications.filter.follows\": \"Seguiments\",\n  \"notifications.filter.mentions\": \"Mencions\",\n  \"notifications.filter.polls\": \"Resultats de l'enquesta\",\n  \"notifications.group\": \"{count} notificacions\",\n  \"poll.closed\": \"Finalitzada\",\n  \"poll.refresh\": \"Actualitza\",\n  \"poll.total_votes\": \"{count, plural, one {# vot} other {# vots}}\",\n  \"poll.vote\": \"Vota\",\n  \"poll_button.add_poll\": \"Afegeix una enquesta\",\n  \"poll_button.remove_poll\": \"Elimina l'enquesta\",\n  \"privacy.change\": \"Ajusta l'estat de privacitat\",\n  \"privacy.direct.long\": \"Publicar només per als usuaris esmentats\",\n  \"privacy.direct.short\": \"Directe\",\n  \"privacy.private.long\": \"Publicar només a seguidors\",\n  \"privacy.private.short\": \"Només seguidors\",\n  \"privacy.public.long\": \"Publicar en línies de temps públiques\",\n  \"privacy.public.short\": \"Públic\",\n  \"privacy.unlisted.long\": \"No publicar en línies de temps públiques\",\n  \"privacy.unlisted.short\": \"No llistat\",\n  \"regeneration_indicator.label\": \"Carregant…\",\n  \"regeneration_indicator.sublabel\": \"S'està preparant la línia de temps Inici!\",\n  \"relative_time.days\": \"fa {number} dies\",\n  \"relative_time.hours\": \"fa {number} hores\",\n  \"relative_time.just_now\": \"ara\",\n  \"relative_time.minutes\": \"fa {number} minuts\",\n  \"relative_time.seconds\": \"fa {number} segons\",\n  \"reply_indicator.cancel\": \"Cancel·lar\",\n  \"report.forward\": \"Reenvia a {target}\",\n  \"report.forward_hint\": \"Aquest compte és d'un altre servidor. Enviar-hi també una copia anònima del informe?\",\n  \"report.hint\": \"El informe s'enviarà als moderadors del teu servidor. Pots explicar perquè vols informar d'aquest compte aquí:\",\n  \"report.placeholder\": \"Comentaris addicionals\",\n  \"report.submit\": \"Enviar\",\n  \"report.target\": \"Informes {target}\",\n  \"search.placeholder\": \"Cercar\",\n  \"search_popout.search_format\": \"Format de cerca avançada\",\n  \"search_popout.tips.full_text\": \"Text simple recupera publicacions que has escrit, les marcades com a favorites, les impulsades o en les que has estat esmentat, així com usuaris, noms d'usuari i etiquetes.\",\n  \"search_popout.tips.hashtag\": \"etiqueta\",\n  \"search_popout.tips.status\": \"estat\",\n  \"search_popout.tips.text\": \"El text simple retorna coincidències amb els noms de visualització, els noms d'usuari i les etiquetes\",\n  \"search_popout.tips.user\": \"usuari\",\n  \"search_results.accounts\": \"Gent\",\n  \"search_results.hashtags\": \"Etiquetes\",\n  \"search_results.statuses\": \"Toots\",\n  \"search_results.total\": \"{count, number} {count, plural, one {result} other {results}}\",\n  \"status.admin_account\": \"Obre l'interfície de moderació per a @{name}\",\n  \"status.admin_status\": \"Obre aquest toot a la interfície de moderació\",\n  \"status.block\": \"Bloqueja @{name}\",\n  \"status.cancel_reblog_private\": \"Desfer l'impuls\",\n  \"status.cannot_reblog\": \"Aquesta publicació no pot ser impulsada\",\n  \"status.copy\": \"Copia l'enllaç al toot\",\n  \"status.delete\": \"Esborrar\",\n  \"status.detailed_status\": \"Visualització detallada de la conversa\",\n  \"status.direct\": \"Missatge directe @{name}\",\n  \"status.embed\": \"Incrustar\",\n  \"status.favourite\": \"Favorit\",\n  \"status.filtered\": \"Filtrat\",\n  \"status.load_more\": \"Carrega més\",\n  \"status.media_hidden\": \"Multimèdia amagat\",\n  \"status.mention\": \"Esmentar @{name}\",\n  \"status.more\": \"Més\",\n  \"status.mute\": \"Silenciar @{name}\",\n  \"status.mute_conversation\": \"Silenciar conversació\",\n  \"status.open\": \"Ampliar aquest estat\",\n  \"status.pin\": \"Fixat en el perfil\",\n  \"status.pinned\": \"Toot fixat\",\n  \"status.read_more\": \"Llegir més\",\n  \"status.reblog\": \"Impuls\",\n  \"status.reblog_private\": \"Impulsar a l'audiència original\",\n  \"status.reblogged_by\": \"{name} ha impulsat\",\n  \"status.reblogs.empty\": \"Encara ningú no ha impulsat aquest toot. Quan algú ho faci, apareixeran aquí.\",\n  \"status.redraft\": \"Esborrar i reescriure\",\n  \"status.reply\": \"Respondre\",\n  \"status.replyAll\": \"Respondre al tema\",\n  \"status.report\": \"Informar sobre @{name}\",\n  \"status.sensitive_warning\": \"Contingut sensible\",\n  \"status.share\": \"Compartir\",\n  \"status.show_less\": \"Mostra menys\",\n  \"status.show_less_all\": \"Mostra menys per a tot\",\n  \"status.show_more\": \"Mostra més\",\n  \"status.show_more_all\": \"Mostra més per a tot\",\n  \"status.show_thread\": \"Mostra el fil\",\n  \"status.unmute_conversation\": \"Activar conversació\",\n  \"status.unpin\": \"Deslliga del perfil\",\n  \"suggestions.dismiss\": \"Descartar suggeriment\",\n  \"suggestions.header\": \"És possible que estiguis interessat en…\",\n  \"tabs_bar.federated_timeline\": \"Federada\",\n  \"tabs_bar.home\": \"Inici\",\n  \"tabs_bar.local_timeline\": \"Local\",\n  \"tabs_bar.notifications\": \"Notificacions\",\n  \"tabs_bar.search\": \"Cerca\",\n  \"time_remaining.days\": \"{number, plural, one {# dia} other {# dies}} restants\",\n  \"time_remaining.hours\": \"{number, plural, one {# hora} other {# hores}} restants\",\n  \"time_remaining.minutes\": \"{number, plural, one {# minut} other {# minuts}} restants\",\n  \"time_remaining.moments\": \"Moments restants\",\n  \"time_remaining.seconds\": \"{number, plural, one {# segon} other {# segons}} restants\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {person} other {people}} talking\",\n  \"ui.beforeunload\": \"El teu esborrany es perdrà si surts de Mastodon.\",\n  \"upload_area.title\": \"Arrossega i deixa anar per a carregar\",\n  \"upload_button.label\": \"Afegir multimèdia (JPEG, PNG, GIF, WebM, MP4, MOV)\",\n  \"upload_error.limit\": \"S'ha superat el límit de càrrega d'arxius.\",\n  \"upload_error.poll\": \"No es permet l'enviament de fitxers en les enquestes.\",\n  \"upload_form.description\": \"Descriure els problemes visuals\",\n  \"upload_form.focus\": \"Modificar la previsualització\",\n  \"upload_form.undo\": \"Esborra\",\n  \"upload_progress.label\": \"Pujant...\",\n  \"video.close\": \"Tancar el vídeo\",\n  \"video.exit_fullscreen\": \"Sortir de pantalla completa\",\n  \"video.expand\": \"Ampliar el vídeo\",\n  \"video.fullscreen\": \"Pantalla completa\",\n  \"video.hide\": \"Amaga vídeo\",\n  \"video.mute\": \"Silenciar el so\",\n  \"video.pause\": \"Pausa\",\n  \"video.play\": \"Reproduir\",\n  \"video.unmute\": \"Activar so\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/co.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Aghjustà o toglie da e liste\",\n  \"account.badges.bot\": \"Bot\",\n  \"account.block\": \"Bluccà @{name}\",\n  \"account.block_domain\": \"Piattà tuttu da {domain}\",\n  \"account.blocked\": \"Bluccatu\",\n  \"account.direct\": \"Missaghju direttu @{name}\",\n  \"account.domain_blocked\": \"Duminiu piattatu\",\n  \"account.edit_profile\": \"Mudificà u prufile\",\n  \"account.endorse\": \"Fà figurà nant'à u prufilu\",\n  \"account.follow\": \"Siguità\",\n  \"account.followers\": \"Abbunati\",\n  \"account.followers.empty\": \"Nisunu hè abbunatu à st'utilizatore.\",\n  \"account.follows\": \"Abbunamenti\",\n  \"account.follows.empty\": \"St'utilizatore ùn seguita nisunu.\",\n  \"account.follows_you\": \"Vi seguita\",\n  \"account.hide_reblogs\": \"Piattà spartere da @{name}\",\n  \"account.link_verified_on\": \"A prupietà di stu ligame hè stata verificata u {date}\",\n  \"account.locked_info\": \"U statutu di vita privata di u contu hè chjosu. U pruprietariu esamina manualmente e dumande d'abbunamentu.\",\n  \"account.media\": \"Media\",\n  \"account.mention\": \"Mintuvà @{name}\",\n  \"account.moved_to\": \"{name} hè partutu nant'à:\",\n  \"account.mute\": \"Piattà @{name}\",\n  \"account.mute_notifications\": \"Piattà nutificazione da @{name}\",\n  \"account.muted\": \"Piattatu\",\n  \"account.posts\": \"Statuti\",\n  \"account.posts_with_replies\": \"Statuti è risposte\",\n  \"account.report\": \"Palisà @{name}\",\n  \"account.requested\": \"In attesa d'apprubazione. Cliccate per annullà a dumanda\",\n  \"account.share\": \"Sparte u prufile di @{name}\",\n  \"account.show_reblogs\": \"Vede spartere da @{name}\",\n  \"account.unblock\": \"Sbluccà @{name}\",\n  \"account.unblock_domain\": \"Ùn piattà più {domain}\",\n  \"account.unendorse\": \"Ùn fà figurà nant'à u prufilu\",\n  \"account.unfollow\": \"Ùn siguità più\",\n  \"account.unmute\": \"Ùn piattà più @{name}\",\n  \"account.unmute_notifications\": \"Ùn piattà più nutificazione da @{name}\",\n  \"alert.unexpected.message\": \"Un prublemu inaspettatu hè accadutu.\",\n  \"alert.unexpected.title\": \"Uups!\",\n  \"boost_modal.combo\": \"Pudete appughjà nant'à {combo} per saltà quessa a prussima volta\",\n  \"bundle_column_error.body\": \"C'hè statu un prublemu caricandu st'elementu.\",\n  \"bundle_column_error.retry\": \"Pruvà torna\",\n  \"bundle_column_error.title\": \"Errore di cunnessione\",\n  \"bundle_modal_error.close\": \"Chjudà\",\n  \"bundle_modal_error.message\": \"C'hè statu un prublemu caricandu st'elementu.\",\n  \"bundle_modal_error.retry\": \"Pruvà torna\",\n  \"column.blocks\": \"Utilizatori bluccati\",\n  \"column.community\": \"Linea pubblica lucale\",\n  \"column.direct\": \"Missaghji diretti\",\n  \"column.domain_blocks\": \"Duminii piattati\",\n  \"column.favourites\": \"Favuriti\",\n  \"column.follow_requests\": \"Dumande d'abbunamentu\",\n  \"column.home\": \"Accolta\",\n  \"column.lists\": \"Liste\",\n  \"column.mutes\": \"Utilizatori piattati\",\n  \"column.notifications\": \"Nutificazione\",\n  \"column.pins\": \"Statuti puntarulati\",\n  \"column.public\": \"Linea pubblica glubale\",\n  \"column_back_button.label\": \"Ritornu\",\n  \"column_header.hide_settings\": \"Piattà i parametri\",\n  \"column_header.moveLeft_settings\": \"Spiazzà à manca\",\n  \"column_header.moveRight_settings\": \"Spiazzà à diritta\",\n  \"column_header.pin\": \"Puntarulà\",\n  \"column_header.show_settings\": \"Mustrà i parametri\",\n  \"column_header.unpin\": \"Spuntarulà\",\n  \"column_subheading.settings\": \"Parametri\",\n  \"community.column_settings.media_only\": \"Solu media\",\n  \"compose_form.direct_message_warning\": \"Solu l'utilizatori mintuvati puderenu vede stu statutu.\",\n  \"compose_form.direct_message_warning_learn_more\": \"Amparà di più\",\n  \"compose_form.hashtag_warning\": \"Stu statutu ùn hè \\\"Micca listatu\\\" è ùn sarà micca listatu indè e circate da hashtag. Per esse vistu in quesse, u statutu deve esse \\\"Pubblicu\\\".\",\n  \"compose_form.lock_disclaimer\": \"U vostru contu ùn hè micca {locked}. Tuttu u mondu pò seguitavi è vede i vostri statuti privati.\",\n  \"compose_form.lock_disclaimer.lock\": \"privatu\",\n  \"compose_form.placeholder\": \"À chè pensate?\",\n  \"compose_form.poll.add_option\": \"Aghjustà una scelta\",\n  \"compose_form.poll.duration\": \"Durata di u scandagliu\",\n  \"compose_form.poll.option_placeholder\": \"Scelta {number}\",\n  \"compose_form.poll.remove_option\": \"Toglie sta scelta\",\n  \"compose_form.publish\": \"Toot\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"Indicà u media cum'è sensibile\",\n  \"compose_form.sensitive.marked\": \"Media indicatu cum'è sensibile\",\n  \"compose_form.sensitive.unmarked\": \"Media micca indicatu cum'è sensibile\",\n  \"compose_form.spoiler.marked\": \"Testu piattatu daret'à un'avertimentu\",\n  \"compose_form.spoiler.unmarked\": \"Testu micca piattatu\",\n  \"compose_form.spoiler_placeholder\": \"Scrive u vostr'avertimentu quì\",\n  \"confirmation_modal.cancel\": \"Annullà\",\n  \"confirmations.block.block_and_report\": \"Bluccà è signalà\",\n  \"confirmations.block.confirm\": \"Bluccà\",\n  \"confirmations.block.message\": \"Site sicuru·a che vulete bluccà @{name}?\",\n  \"confirmations.delete.confirm\": \"Toglie\",\n  \"confirmations.delete.message\": \"Site sicuru·a che vulete supprime stu statutu?\",\n  \"confirmations.delete_list.confirm\": \"Toglie\",\n  \"confirmations.delete_list.message\": \"Site sicuru·a che vulete supprime sta lista?\",\n  \"confirmations.domain_block.confirm\": \"Piattà tuttu u duminiu\",\n  \"confirmations.domain_block.message\": \"Site sicuru·a che vulete piattà tuttu à {domain}? Saria forse abbastanza di bluccà ò piattà alcuni conti da quallà. Ùn viderete più nunda da quallà indè e linee pubbliche o e nutificazione. I vostri abbunati da stu duminiu saranu tolti.\",\n  \"confirmations.mute.confirm\": \"Piattà\",\n  \"confirmations.mute.message\": \"Site sicuru·a che vulete piattà @{name}?\",\n  \"confirmations.redraft.confirm\": \"Sguassà è riscrive\",\n  \"confirmations.redraft.message\": \"Site sicuru·a chè vulete sguassà stu statutu è riscrivelu? I favuriti è spartere saranu persi, è e risposte diventeranu orfane.\",\n  \"confirmations.reply.confirm\": \"Risponde\",\n  \"confirmations.reply.message\": \"Risponde avà sguasserà u missaghju chì scrivite. Site sicuru·a chì vulete cuntinuà?\",\n  \"confirmations.unfollow.confirm\": \"Disabbunassi\",\n  \"confirmations.unfollow.message\": \"Site sicuru·a ch'ùn vulete più siguità @{name}?\",\n  \"embed.instructions\": \"Integrà stu statutu à u vostru situ cù u codice quì sottu.\",\n  \"embed.preview\": \"Assumiglierà à qualcosa cusì:\",\n  \"emoji_button.activity\": \"Attività\",\n  \"emoji_button.custom\": \"Persunalizati\",\n  \"emoji_button.flags\": \"Bandere\",\n  \"emoji_button.food\": \"Manghjusca è Bienda\",\n  \"emoji_button.label\": \"Mette un'emoji\",\n  \"emoji_button.nature\": \"Natura\",\n  \"emoji_button.not_found\": \"Ùn c'hè nunda! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"Oggetti\",\n  \"emoji_button.people\": \"Parsunaghji\",\n  \"emoji_button.recent\": \"Assai utilizati\",\n  \"emoji_button.search\": \"Cercà...\",\n  \"emoji_button.search_results\": \"Risultati di a cerca\",\n  \"emoji_button.symbols\": \"Simbuli\",\n  \"emoji_button.travel\": \"Lochi è Viaghju\",\n  \"empty_column.account_timeline\": \"Nisun statutu quì!\",\n  \"empty_column.account_unavailable\": \"Prufile micca dispunibule\",\n  \"empty_column.blocks\": \"Per avà ùn avete bluccatu manc'un utilizatore.\",\n  \"empty_column.community\": \"Ùn c'hè nunda indè a linea lucale. Scrivete puru qualcosa!\",\n  \"empty_column.direct\": \"Ùn avete ancu nisun missaghju direttu. S'è voi mandate o ricevete unu, u vidarete quì.\",\n  \"empty_column.domain_blocks\": \"Ùn c'hè manc'un duminiu bluccatu avà.\",\n  \"empty_column.favourited_statuses\": \"Ùn avete manc'unu statutu favuritu. Quandu aghjusterate unu à i vostri favuriti, sarà mustratu quì.\",\n  \"empty_column.favourites\": \"Nisunu hà aghjustatu stu statutu à i so favuriti. Quandu qualch'unu farà quessa, u so contu sarà mustratu quì.\",\n  \"empty_column.follow_requests\": \"Ùn avete manc'una dumanda d'abbunamentu. Quandu averete una, sarà mustrata quì.\",\n  \"empty_column.hashtag\": \"Ùn c'hè ancu nunda quì.\",\n  \"empty_column.home\": \"A vostr'accolta hè viota! Pudete andà nant'à {public} o pruvà a ricerca per truvà parsone da siguità.\",\n  \"empty_column.home.public_timeline\": \"a linea pubblica\",\n  \"empty_column.list\": \"Ùn c'hè ancu nunda quì. Quandu membri di sta lista manderanu novi statuti, i vidarete quì.\",\n  \"empty_column.lists\": \"Ùn avete manc'una lista. Quandu farete una, sarà mustrata quì.\",\n  \"empty_column.mutes\": \"Per avà ùn avete manc'un utilizatore piattatu.\",\n  \"empty_column.notifications\": \"Ùn avete ancu nisuna nutificazione. Interact with others to start the conversation.\",\n  \"empty_column.public\": \"Ùn c'hè nunda quì! Scrivete qualcosa in pubblicu o seguitate utilizatori d'altri servori per empie a linea pubblica\",\n  \"follow_request.authorize\": \"Auturizà\",\n  \"follow_request.reject\": \"Righjittà\",\n  \"getting_started.developers\": \"Sviluppatori\",\n  \"getting_started.directory\": \"Annuariu di i prufili\",\n  \"getting_started.documentation\": \"Ducumentazione\",\n  \"getting_started.heading\": \"Per principià\",\n  \"getting_started.invite\": \"Invità ghjente\",\n  \"getting_started.open_source_notice\": \"Mastodon ghjè un lugiziale liberu. Pudete cuntribuisce à u codice o a traduzione, o palisà un bug, nant'à GitHub: {github}.\",\n  \"getting_started.security\": \"Sicurità\",\n  \"getting_started.terms\": \"Cundizione di u serviziu\",\n  \"hashtag.column_header.tag_mode.all\": \"è {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"o {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"senza {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"Nisuna sugestione trova\",\n  \"hashtag.column_settings.select.placeholder\": \"Entrà l'hashtag…\",\n  \"hashtag.column_settings.tag_mode.all\": \"Tutti quessi\",\n  \"hashtag.column_settings.tag_mode.any\": \"Unu di quessi\",\n  \"hashtag.column_settings.tag_mode.none\": \"Nisunu di quessi\",\n  \"hashtag.column_settings.tag_toggle\": \"Inchjude tag addiziunali per sta colonna\",\n  \"home.column_settings.basic\": \"Bàsichi\",\n  \"home.column_settings.show_reblogs\": \"Vede e spartere\",\n  \"home.column_settings.show_replies\": \"Vede e risposte\",\n  \"intervals.full.days\": \"{number, plural, one {# ghjornu} other {# ghjorni}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# ora} other {# ore}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minuta} other {# minute}}\",\n  \"introduction.federation.action\": \"Cuntinuà\",\n  \"introduction.federation.federated.headline\": \"Federata\",\n  \"introduction.federation.federated.text\": \"I statuti pubblichi da l'altri servori di u fediverse saranu mustrati nant'à a linea pubblica federata.\",\n  \"introduction.federation.home.headline\": \"Accolta\",\n  \"introduction.federation.home.text\": \"I statuti da a ghjente che vo siguitate saranu affissati nant'à a linea d'accolta. Pudete seguità qualvogliasia nant'à tutti i servori!\",\n  \"introduction.federation.local.headline\": \"Lucale\",\n  \"introduction.federation.local.text\": \"I statuti pubblichi da quelli chì sò nant'a listessu servore chì voi ponu esse visti indè a linea pubblica lucale.\",\n  \"introduction.interactions.action\": \"Finisce u tutoriale!\",\n  \"introduction.interactions.favourite.headline\": \"Favuritu\",\n  \"introduction.interactions.favourite.text\": \"Pudete salvà un statutu per ritruvallu più tardi, è fà sapè à l'autore chì v'hè piaciutu, l'aghustendu à i vostri favuriti.\",\n  \"introduction.interactions.reblog.headline\": \"Sparte\",\n  \"introduction.interactions.reblog.text\": \"Pudete sparte i statuti d'altre persone à i vostri abbunati cù u buttone di spartera.\",\n  \"introduction.interactions.reply.headline\": \"Risponde\",\n  \"introduction.interactions.reply.text\": \"Pudete risponde à d'altre persone o a i vostri propii statuti, cio chì i ligarà indè una cunversazione.\",\n  \"introduction.welcome.action\": \"Andemu!\",\n  \"introduction.welcome.headline\": \"Primi passi\",\n  \"introduction.welcome.text\": \"Benvenutu·a indè u fediverse! In qualchi minuta, puderete diffonde missaghji è parlà à i vostri amichi nant'à una varietà maiò di servori. Mà quess'istanza, {domain}, hè speciale—ghjè induve hè uspitatu u vostru prufile, allora ricurdatevi di u so nome.\",\n  \"keyboard_shortcuts.back\": \"rivultà\",\n  \"keyboard_shortcuts.blocked\": \"per apre una lista d'utilizatori bluccati\",\n  \"keyboard_shortcuts.boost\": \"sparte\",\n  \"keyboard_shortcuts.column\": \"fucalizà un statutu indè una colonna\",\n  \"keyboard_shortcuts.compose\": \"fucalizà nant'à l'area di ridazzione\",\n  \"keyboard_shortcuts.description\": \"Descrizzione\",\n  \"keyboard_shortcuts.direct\": \"per apre una culonna di missaghji diretti\",\n  \"keyboard_shortcuts.down\": \"falà indè a lista\",\n  \"keyboard_shortcuts.enter\": \"apre u statutu\",\n  \"keyboard_shortcuts.favourite\": \"aghjunghje à i favuriti\",\n  \"keyboard_shortcuts.favourites\": \"per apre a lista di i favuriti\",\n  \"keyboard_shortcuts.federated\": \"per apre a linea pubblica federata\",\n  \"keyboard_shortcuts.heading\": \"Accorte cù a tastera\",\n  \"keyboard_shortcuts.home\": \"per apre a linea d'accolta\",\n  \"keyboard_shortcuts.hotkey\": \"Accorta\",\n  \"keyboard_shortcuts.legend\": \"vede a legenda\",\n  \"keyboard_shortcuts.local\": \"per apre a linea pubblica lucale\",\n  \"keyboard_shortcuts.mention\": \"mintuvà l'autore\",\n  \"keyboard_shortcuts.muted\": \"per apre a lista di l'utilizatori piattati\",\n  \"keyboard_shortcuts.my_profile\": \"per apre u vostru prufile\",\n  \"keyboard_shortcuts.notifications\": \"per apre a culonna di nutificazione\",\n  \"keyboard_shortcuts.pinned\": \"per apre a lista di statuti puntarulati\",\n  \"keyboard_shortcuts.profile\": \"per apre u prufile di l'autore\",\n  \"keyboard_shortcuts.reply\": \"risponde\",\n  \"keyboard_shortcuts.requests\": \"per apre a lista di dumande d'abbunamentu\",\n  \"keyboard_shortcuts.search\": \"fucalizà nant'à l'area di circata\",\n  \"keyboard_shortcuts.start\": \"per apre a culonna \\\"per principià\\\"\",\n  \"keyboard_shortcuts.toggle_hidden\": \"vede/piattà u testu daretu à l'avertimentu CW\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"vede/piattà i media\",\n  \"keyboard_shortcuts.toot\": \"scrive un novu statutu\",\n  \"keyboard_shortcuts.unfocus\": \"ùn fucalizà più l'area di testu\",\n  \"keyboard_shortcuts.up\": \"cullà indè a lista\",\n  \"lightbox.close\": \"Chjudà\",\n  \"lightbox.next\": \"Siguente\",\n  \"lightbox.previous\": \"Pricidente\",\n  \"lightbox.view_context\": \"Vede u cuntestu\",\n  \"lists.account.add\": \"Aghjunghje à a lista\",\n  \"lists.account.remove\": \"Toglie di a lista\",\n  \"lists.delete\": \"Supprime a lista\",\n  \"lists.edit\": \"Mudificà a lista\",\n  \"lists.edit.submit\": \"Cambià u titulu\",\n  \"lists.new.create\": \"Aghjustà una lista\",\n  \"lists.new.title_placeholder\": \"Titulu di a lista\",\n  \"lists.search\": \"Circà indè i vostr'abbunamenti\",\n  \"lists.subheading\": \"E vo liste\",\n  \"loading_indicator.label\": \"Caricamentu...\",\n  \"media_gallery.toggle_visible\": \"Cambià a visibilità\",\n  \"missing_indicator.label\": \"Micca trovu\",\n  \"missing_indicator.sublabel\": \"Ùn era micca pussivule di truvà sta risorsa\",\n  \"mute_modal.hide_notifications\": \"Piattà nutificazione da st'utilizatore?\",\n  \"navigation_bar.apps\": \"Applicazione per u telefuninu\",\n  \"navigation_bar.blocks\": \"Utilizatori bluccati\",\n  \"navigation_bar.community_timeline\": \"Linea pubblica lucale\",\n  \"navigation_bar.compose\": \"Scrive un novu statutu\",\n  \"navigation_bar.direct\": \"Missaghji diretti\",\n  \"navigation_bar.discover\": \"Scopre\",\n  \"navigation_bar.domain_blocks\": \"Duminii piattati\",\n  \"navigation_bar.edit_profile\": \"Mudificà u prufile\",\n  \"navigation_bar.favourites\": \"Favuriti\",\n  \"navigation_bar.filters\": \"Parolle silenzate\",\n  \"navigation_bar.follow_requests\": \"Dumande d'abbunamentu\",\n  \"navigation_bar.follows_and_followers\": \"Abbunati è abbunamenti\",\n  \"navigation_bar.info\": \"À prupositu di u servore\",\n  \"navigation_bar.keyboard_shortcuts\": \"Accorte cù a tastera\",\n  \"navigation_bar.lists\": \"Liste\",\n  \"navigation_bar.logout\": \"Scunnettassi\",\n  \"navigation_bar.mutes\": \"Utilizatori piattati\",\n  \"navigation_bar.personal\": \"Persunale\",\n  \"navigation_bar.pins\": \"Statuti puntarulati\",\n  \"navigation_bar.preferences\": \"Preferenze\",\n  \"navigation_bar.profile_directory\": \"Annuariu di i prufili\",\n  \"navigation_bar.public_timeline\": \"Linea pubblica glubale\",\n  \"navigation_bar.security\": \"Sicurità\",\n  \"notification.favourite\": \"{name} hà aghjuntu u vostru statutu à i so favuriti\",\n  \"notification.follow\": \"{name} v'hà seguitatu\",\n  \"notification.mention\": \"{name} v'hà mintuvatu\",\n  \"notification.poll\": \"Un scandagliu induve avete vutatu hè finitu\",\n  \"notification.reblog\": \"{name} hà spartutu u vostru statutu\",\n  \"notifications.clear\": \"Purgà e nutificazione\",\n  \"notifications.clear_confirmation\": \"Site sicuru·a che vulete toglie tutte ste nutificazione?\",\n  \"notifications.column_settings.alert\": \"Nutificazione nant'à l'urdinatore\",\n  \"notifications.column_settings.favourite\": \"Favuriti:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Affissà tutte e categurie\",\n  \"notifications.column_settings.filter_bar.category\": \"Barra di ricerca pronta\",\n  \"notifications.column_settings.filter_bar.show\": \"Mustrà\",\n  \"notifications.column_settings.follow\": \"Abbunati novi:\",\n  \"notifications.column_settings.mention\": \"Minzione:\",\n  \"notifications.column_settings.poll\": \"Risultati:\",\n  \"notifications.column_settings.push\": \"Nutificazione Push\",\n  \"notifications.column_settings.reblog\": \"Spartere:\",\n  \"notifications.column_settings.show\": \"Mustrà indè a colonna\",\n  \"notifications.column_settings.sound\": \"Sunà\",\n  \"notifications.filter.all\": \"Tuttu\",\n  \"notifications.filter.boosts\": \"Spartere\",\n  \"notifications.filter.favourites\": \"Favuriti\",\n  \"notifications.filter.follows\": \"Abbunamenti\",\n  \"notifications.filter.mentions\": \"Minzione\",\n  \"notifications.filter.polls\": \"Risultati di u scandagliu\",\n  \"notifications.group\": \"{count} nutificazione\",\n  \"poll.closed\": \"Chjosu\",\n  \"poll.refresh\": \"Attualizà\",\n  \"poll.total_votes\": \"{count, plural, one {# votu} other {# voti}}\",\n  \"poll.vote\": \"Vutà\",\n  \"poll_button.add_poll\": \"Aghjustà un scandagliu\",\n  \"poll_button.remove_poll\": \"Toglie u scandagliu\",\n  \"privacy.change\": \"Mudificà a cunfidenzialità di u statutu\",\n  \"privacy.direct.long\": \"Mandà solu à quelli chì so mintuvati\",\n  \"privacy.direct.short\": \"Direttu\",\n  \"privacy.private.long\": \"Mustrà solu à l'abbunati\",\n  \"privacy.private.short\": \"Privatu\",\n  \"privacy.public.long\": \"Mustrà à tuttu u mondu nant'a linea pubblica\",\n  \"privacy.public.short\": \"Pubblicu\",\n  \"privacy.unlisted.long\": \"Ùn mette micca nant'a linea pubblica (ma tutt'u mondu pò vede u statutu nant'à u vostru prufile)\",\n  \"privacy.unlisted.short\": \"Micca listatu\",\n  \"regeneration_indicator.label\": \"Caricamentu…\",\n  \"regeneration_indicator.sublabel\": \"Priparazione di a vostra pagina d'accolta!\",\n  \"relative_time.days\": \"{number}ghj\",\n  \"relative_time.hours\": \"{number}o\",\n  \"relative_time.just_now\": \"avà\",\n  \"relative_time.minutes\": \"{number}m\",\n  \"relative_time.seconds\": \"{number}s\",\n  \"reply_indicator.cancel\": \"Annullà\",\n  \"report.forward\": \"Trasferisce à {target}\",\n  \"report.forward_hint\": \"U contu hè nant'à un'altru servore. Vulete ancu mandà una copia anonima di u signalamentu quallà?\",\n  \"report.hint\": \"U signalamentu sarà mandatu à i muderatori di u servore. Pudete spiegà perchè avete palisatu stu contu quì sottu:\",\n  \"report.placeholder\": \"Altri cummenti\",\n  \"report.submit\": \"Mandà\",\n  \"report.target\": \"Signalamentu\",\n  \"search.placeholder\": \"Circà\",\n  \"search_popout.search_format\": \"Ricerca avanzata\",\n  \"search_popout.tips.full_text\": \"I testi simplici rimandanu i statuti ch'avete scritti, aghjunti à i vostri favuriti, spartuti o induve quelli site mintuvatu·a, è ancu i cugnomi, nomi pubblichi è hashtag chì currispondenu.\",\n  \"search_popout.tips.hashtag\": \"hashtag\",\n  \"search_popout.tips.status\": \"statutu\",\n  \"search_popout.tips.text\": \"Un testu simplice rimanda i nomi pubblichi, cugnomi è hashtag\",\n  \"search_popout.tips.user\": \"utilizatore\",\n  \"search_results.accounts\": \"Ghjente\",\n  \"search_results.hashtags\": \"Hashtag\",\n  \"search_results.statuses\": \"Statuti\",\n  \"search_results.total\": \"{count, number} {count, plural, one {risultatu} other {risultati}}\",\n  \"status.admin_account\": \"Apre l'interfaccia di muderazione per @{name}\",\n  \"status.admin_status\": \"Apre stu statutu in l'interfaccia di muderazione\",\n  \"status.block\": \"Bluccà @{name}\",\n  \"status.cancel_reblog_private\": \"Ùn sparte più\",\n  \"status.cannot_reblog\": \"Stu statutu ùn pò micca esse spartutu\",\n  \"status.copy\": \"Cupià ligame indè u statutu\",\n  \"status.delete\": \"Toglie\",\n  \"status.detailed_status\": \"Vista in ditagliu di a cunversazione\",\n  \"status.direct\": \"Mandà un missaghju @{name}\",\n  \"status.embed\": \"Integrà\",\n  \"status.favourite\": \"Aghjunghje à i favuriti\",\n  \"status.filtered\": \"Filtratu\",\n  \"status.load_more\": \"Vede di più\",\n  \"status.media_hidden\": \"Media piattata\",\n  \"status.mention\": \"Mintuvà @{name}\",\n  \"status.more\": \"Più\",\n  \"status.mute\": \"Piattà @{name}\",\n  \"status.mute_conversation\": \"Piattà a cunversazione\",\n  \"status.open\": \"Apre stu statutu\",\n  \"status.pin\": \"Puntarulà à u prufile\",\n  \"status.pinned\": \"Statutu puntarulatu\",\n  \"status.read_more\": \"Leghje di più\",\n  \"status.reblog\": \"Sparte\",\n  \"status.reblog_private\": \"Sparte à l'audienza uriginale\",\n  \"status.reblogged_by\": \"{name} hà spartutu\",\n  \"status.reblogs.empty\": \"Per avà nisunu hà spartutu u statutu. Quandu qualch'unu u sparterà, u so contu sarà mustratu quì.\",\n  \"status.redraft\": \"Sguassà è riscrive\",\n  \"status.reply\": \"Risponde\",\n  \"status.replyAll\": \"Risponde à tutti\",\n  \"status.report\": \"Palisà @{name}\",\n  \"status.sensitive_warning\": \"Cuntinutu sensibile\",\n  \"status.share\": \"Sparte\",\n  \"status.show_less\": \"Ripiegà\",\n  \"status.show_less_all\": \"Ripiegà tuttu\",\n  \"status.show_more\": \"Slibrà\",\n  \"status.show_more_all\": \"Slibrà tuttu\",\n  \"status.show_thread\": \"Vede u filu\",\n  \"status.unmute_conversation\": \"Ùn piattà più a cunversazione\",\n  \"status.unpin\": \"Spuntarulà da u prufile\",\n  \"suggestions.dismiss\": \"Righjittà a pruposta\",\n  \"suggestions.header\": \"Site forse interessatu·a da…\",\n  \"tabs_bar.federated_timeline\": \"Glubale\",\n  \"tabs_bar.home\": \"Accolta\",\n  \"tabs_bar.local_timeline\": \"Lucale\",\n  \"tabs_bar.notifications\": \"Nutificazione\",\n  \"tabs_bar.search\": \"Cercà\",\n  \"time_remaining.days\": \"{number, plural, one {# ghjornu ferma} other {# ghjorni fermanu}}\",\n  \"time_remaining.hours\": \"{number, plural, one {# ora ferma} other {# ore fermanu}}\",\n  \"time_remaining.minutes\": \"{number, plural, one {# minuta ferma} other {# minute fermanu}} left\",\n  \"time_remaining.moments\": \"Ci fermanu qualchi mumentu\",\n  \"time_remaining.seconds\": \"{number, plural, one {# siconda ferma} other {# siconde fermanu}}\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {person} other {people}} parlanu\",\n  \"ui.beforeunload\": \"A bruttacopia sarà persa s'ellu hè chjosu Mastodon.\",\n  \"upload_area.title\": \"Drag & drop per caricà un fugliale\",\n  \"upload_button.label\": \"Aghjunghje un media (JPEG, PNG, GIF, WebM, MP4, MOV)\",\n  \"upload_error.limit\": \"Limita di caricamentu di fugliali trapassata.\",\n  \"upload_error.poll\": \"Ùn si pò micca caricà fugliali cù i scandagli.\",\n  \"upload_form.description\": \"Discrive per i malvistosi\",\n  \"upload_form.focus\": \"Cambià a vista\",\n  \"upload_form.undo\": \"Sguassà\",\n  \"upload_progress.label\": \"Caricamentu...\",\n  \"video.close\": \"Chjudà a video\",\n  \"video.exit_fullscreen\": \"Caccià u pienu screnu\",\n  \"video.expand\": \"Ingrandà a video\",\n  \"video.fullscreen\": \"Pienu screnu\",\n  \"video.hide\": \"Piattà a video\",\n  \"video.mute\": \"Surdina\",\n  \"video.pause\": \"Pausa\",\n  \"video.play\": \"Lettura\",\n  \"video.unmute\": \"Caccià a surdina\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/cs.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Přidat nebo odstranit ze seznamů\",\n  \"account.badges.bot\": \"Robot\",\n  \"account.block\": \"Zablokovat uživatele @{name}\",\n  \"account.block_domain\": \"Skrýt vše z {domain}\",\n  \"account.blocked\": \"Blokován/a\",\n  \"account.direct\": \"Poslat přímou zprávu uživateli @{name}\",\n  \"account.domain_blocked\": \"Doména skryta\",\n  \"account.edit_profile\": \"Upravit profil\",\n  \"account.endorse\": \"Představit na profilu\",\n  \"account.follow\": \"Sledovat\",\n  \"account.followers\": \"Sledující\",\n  \"account.followers.empty\": \"Tohoto uživatele ještě nikdo nesleduje.\",\n  \"account.follows\": \"Sledovaní\",\n  \"account.follows.empty\": \"Tento uživatel ještě nikoho nesleduje.\",\n  \"account.follows_you\": \"Sleduje vás\",\n  \"account.hide_reblogs\": \"Skrýt boosty od uživatele @{name}\",\n  \"account.link_verified_on\": \"Vlastnictví tohoto odkazu bylo zkontrolováno {date}\",\n  \"account.locked_info\": \"Stav soukromí tohoto účtu je nastaven na zamčeno. Jeho vlastník ručně posuzuje, kdo ho může sledovat.\",\n  \"account.media\": \"Média\",\n  \"account.mention\": \"Zmínit uživatele @{name}\",\n  \"account.moved_to\": \"{name} se přesunul/a na:\",\n  \"account.mute\": \"Skrýt uživatele @{name}\",\n  \"account.mute_notifications\": \"Skrýt oznámení od uživatele @{name}\",\n  \"account.muted\": \"Skryt/a\",\n  \"account.posts\": \"Tooty\",\n  \"account.posts_with_replies\": \"Tooty a odpovědi\",\n  \"account.report\": \"Nahlásit uživatele @{name}\",\n  \"account.requested\": \"Čekám na schválení. Kliknutím zrušíte požadavek o sledování\",\n  \"account.share\": \"Sdílet profil uživatele @{name}\",\n  \"account.show_reblogs\": \"Zobrazit boosty od uživatele @{name}\",\n  \"account.unblock\": \"Odblokovat uživatele @{name}\",\n  \"account.unblock_domain\": \"Odkrýt doménu {domain}\",\n  \"account.unendorse\": \"Nepředstavit na profilu\",\n  \"account.unfollow\": \"Přestat sledovat\",\n  \"account.unmute\": \"Odkrýt uživatele @{name}\",\n  \"account.unmute_notifications\": \"Odkrýt oznámení od uživatele @{name}\",\n  \"alert.unexpected.message\": \"Objevila se neočekávaná chyba.\",\n  \"alert.unexpected.title\": \"Jejda!\",\n  \"boost_modal.combo\": \"Příště můžete pro přeskočení kliknout na {combo}\",\n  \"bundle_column_error.body\": \"Při načítání tohoto komponentu se něco pokazilo.\",\n  \"bundle_column_error.retry\": \"Zkuste to znovu\",\n  \"bundle_column_error.title\": \"Chyba sítě\",\n  \"bundle_modal_error.close\": \"Zavřít\",\n  \"bundle_modal_error.message\": \"Při načítání tohoto komponentu se něco pokazilo.\",\n  \"bundle_modal_error.retry\": \"Zkusit znovu\",\n  \"column.blocks\": \"Blokovaní uživatelé\",\n  \"column.community\": \"Místní časová osa\",\n  \"column.direct\": \"Přímé zprávy\",\n  \"column.domain_blocks\": \"Skryté domény\",\n  \"column.favourites\": \"Oblíbené\",\n  \"column.follow_requests\": \"Požadavky o sledování\",\n  \"column.home\": \"Domů\",\n  \"column.lists\": \"Seznamy\",\n  \"column.mutes\": \"Skrytí uživatelé\",\n  \"column.notifications\": \"Oznámení\",\n  \"column.pins\": \"Připnuté tooty\",\n  \"column.public\": \"Federovaná časová osa\",\n  \"column_back_button.label\": \"Zpět\",\n  \"column_header.hide_settings\": \"Skrýt nastavení\",\n  \"column_header.moveLeft_settings\": \"Posunout sloupec doleva\",\n  \"column_header.moveRight_settings\": \"Posunout sloupec doprava\",\n  \"column_header.pin\": \"Připnout\",\n  \"column_header.show_settings\": \"Zobrazit nastavení\",\n  \"column_header.unpin\": \"Odepnout\",\n  \"column_subheading.settings\": \"Nastavení\",\n  \"community.column_settings.media_only\": \"Pouze média\",\n  \"compose_form.direct_message_warning\": \"Tento toot bude odeslán pouze zmíněným uživatelům.\",\n  \"compose_form.direct_message_warning_learn_more\": \"Zjistit více\",\n  \"compose_form.hashtag_warning\": \"Tento toot nebude zobrazen pod žádným hashtagem, neboť je neuvedený. Pouze veřejné tooty mohou být vyhledány podle hashtagu.\",\n  \"compose_form.lock_disclaimer\": \"Váš účet není {locked}. Kdokoliv vás může sledovat a vidět vaše příspěvky pouze pro sledující.\",\n  \"compose_form.lock_disclaimer.lock\": \"uzamčen\",\n  \"compose_form.placeholder\": \"Co se vám honí hlavou?\",\n  \"compose_form.poll.add_option\": \"Přidat volbu\",\n  \"compose_form.poll.duration\": \"Délka ankety\",\n  \"compose_form.poll.option_placeholder\": \"Volba {number}\",\n  \"compose_form.poll.remove_option\": \"Odstranit tuto volbu\",\n  \"compose_form.publish\": \"Tootnout\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"Označit média jako citlivá\",\n  \"compose_form.sensitive.marked\": \"Média jsou označena jako citlivá\",\n  \"compose_form.sensitive.unmarked\": \"Média nejsou označena jako citlivá\",\n  \"compose_form.spoiler.marked\": \"Text je skrytý za varováním\",\n  \"compose_form.spoiler.unmarked\": \"Text není skrytý\",\n  \"compose_form.spoiler_placeholder\": \"Sem napište vaše varování\",\n  \"confirmation_modal.cancel\": \"Zrušit\",\n  \"confirmations.block.block_and_report\": \"Blokovat a nahlásit\",\n  \"confirmations.block.confirm\": \"Blokovat\",\n  \"confirmations.block.message\": \"Jste si jistý/á, že chcete zablokovat uživatele {name}?\",\n  \"confirmations.delete.confirm\": \"Smazat\",\n  \"confirmations.delete.message\": \"Jste si jistý/á, že chcete smazat tento toot?\",\n  \"confirmations.delete_list.confirm\": \"Smazat\",\n  \"confirmations.delete_list.message\": \"Jste si jistý/á, že chcete tento seznam navždy smazat?\",\n  \"confirmations.domain_block.confirm\": \"Skrýt celou doménu\",\n  \"confirmations.domain_block.message\": \"Jste si opravdu, opravdu jistý/á, že chcete blokovat celou doménu {domain}? Ve většině případů stačí zablokovat nebo skrýt pár konkrétních uživatelů, což se doporučuje. Z této domény neuvidíte obsah v žádné veřejné časové ose ani v oznámeních. Vaši sledující z této domény budou odstraněni.\",\n  \"confirmations.mute.confirm\": \"Skrýt\",\n  \"confirmations.mute.message\": \"Jste si jistý/á, že chcete skrýt uživatele {name}?\",\n  \"confirmations.redraft.confirm\": \"Smazat a přepsat\",\n  \"confirmations.redraft.message\": \"Jste si jistý/á, že chcete smazat a přepsat tento toot? Oblíbení a boosty budou ztraceny a odpovědi na původní příspěvek budou opuštěny.\",\n  \"confirmations.reply.confirm\": \"Odpovědět\",\n  \"confirmations.reply.message\": \"Odpovězením nyní přepíšete zprávu, kterou aktuálně píšete. Jste si jistý/á, že chcete pokračovat?\",\n  \"confirmations.unfollow.confirm\": \"Přestat sledovat\",\n  \"confirmations.unfollow.message\": \"jste si jistý/á, že chcete přestat sledovat uživatele {name}?\",\n  \"embed.instructions\": \"Pro přidání tootu na vaši webovou stránku zkopírujte níže uvedený kód.\",\n  \"embed.preview\": \"Takhle to bude vypadat:\",\n  \"emoji_button.activity\": \"Aktivita\",\n  \"emoji_button.custom\": \"Vlastní\",\n  \"emoji_button.flags\": \"Vlajky\",\n  \"emoji_button.food\": \"Jídla a nápoje\",\n  \"emoji_button.label\": \"Vložit emoji\",\n  \"emoji_button.nature\": \"Příroda\",\n  \"emoji_button.not_found\": \"Žádná emoji!! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"Předměty\",\n  \"emoji_button.people\": \"Lidé\",\n  \"emoji_button.recent\": \"Často používaná\",\n  \"emoji_button.search\": \"Hledat…\",\n  \"emoji_button.search_results\": \"Výsledky hledání\",\n  \"emoji_button.symbols\": \"Symboly\",\n  \"emoji_button.travel\": \"Cestování a místa\",\n  \"empty_column.account_timeline\": \"Tady nejsou žádné tooty!\",\n  \"empty_column.account_unavailable\": \"Profil nedostupný\",\n  \"empty_column.blocks\": \"Ještě jste nezablokoval/a žádného uživatele.\",\n  \"empty_column.community\": \"Místní časová osa je prázdná. Napište něco veřejně a rozhýbejte to tu!\",\n  \"empty_column.direct\": \"Ještě nemáte žádné přímé zprávy. Pokud nějakou pošlete nebo dostanete, zobrazí se zde.\",\n  \"empty_column.domain_blocks\": \"Ještě nejsou žádné skryté domény.\",\n  \"empty_column.favourited_statuses\": \"Ještě nemáte žádné oblíbené tooty. Pokud si nějaký oblíbíte, zobrazí se zde.\",\n  \"empty_column.favourites\": \"Tento toot si ještě nikdo neoblíbil. Pokud to někdo udělá, zobrazí se zde.\",\n  \"empty_column.follow_requests\": \"Ještě nemáte žádné požadavky o sledování. Pokud nějaký obdržíte, zobrazí se zde.\",\n  \"empty_column.hashtag\": \"Pod tímto hashtagem ještě nic není.\",\n  \"empty_column.home\": \"Vaše domovská časová osa je prázdná! Začněte navštívením {public} nebo použijte hledání a seznamte se s dalšími uživateli.\",\n  \"empty_column.home.public_timeline\": \"veřejné časové osy\",\n  \"empty_column.list\": \"V tomto seznamu ještě nic není. Pokud budou členové tohoto seznamu psát nové tooty, objeví se zde.\",\n  \"empty_column.lists\": \"Ještě nemáte žádný seznam. Pokud nějaký vytvoříte, zobrazí se zde.\",\n  \"empty_column.mutes\": \"Ještě jste neskryl/a žádné uživatele.\",\n  \"empty_column.notifications\": \"Ještě nemáte žádná oznámení. Začněte konverzaci komunikováním s ostatními.\",\n  \"empty_column.public\": \"Tady nic není! Napište něco veřejně, nebo začněte ručně sledovat uživatele z jiných serverů, aby tu něco přibylo\",\n  \"follow_request.authorize\": \"Autorizovat\",\n  \"follow_request.reject\": \"Odmítnout\",\n  \"getting_started.developers\": \"Vývojáři\",\n  \"getting_started.directory\": \"Adresář profilů\",\n  \"getting_started.documentation\": \"Dokumentace\",\n  \"getting_started.heading\": \"Začínáme\",\n  \"getting_started.invite\": \"Pozvat lidi\",\n  \"getting_started.open_source_notice\": \"Mastodon je otevřený software. Na GitHubu k němu můžete přispět nebo nahlásit chyby: {github}.\",\n  \"getting_started.security\": \"Zabezpečení\",\n  \"getting_started.terms\": \"Podmínky používání\",\n  \"hashtag.column_header.tag_mode.all\": \"a {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"nebo {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"bez {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"Žádné návrhy nenalezeny\",\n  \"hashtag.column_settings.select.placeholder\": \"Zadejte hashtagy…\",\n  \"hashtag.column_settings.tag_mode.all\": \"Všechny z těchto\",\n  \"hashtag.column_settings.tag_mode.any\": \"Jakékoliv z těchto\",\n  \"hashtag.column_settings.tag_mode.none\": \"Žádné z těchto\",\n  \"hashtag.column_settings.tag_toggle\": \"Zahrnout v tomto sloupci dodatečné tagy\",\n  \"home.column_settings.basic\": \"Základní\",\n  \"home.column_settings.show_reblogs\": \"Zobrazit boosty\",\n  \"home.column_settings.show_replies\": \"Zobrazit odpovědi\",\n  \"intervals.full.days\": \"{number, plural, one {# den} few {# dny} many {# dne} other {# dní}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# hodina} few {# hodiny} many {# hodiny} other {# hodin}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minuta} few {# minuty} many {# minuty} other {# minut}}\",\n  \"introduction.federation.action\": \"Další\",\n  \"introduction.federation.federated.headline\": \"Federovaná\",\n  \"introduction.federation.federated.text\": \"Veřejné příspěvky z jiných serverů ve fedivesmíru se zobrazí na federované časové ose.\",\n  \"introduction.federation.home.headline\": \"Domů\",\n  \"introduction.federation.home.text\": \"Příspěvky od lidí, které sledujete, se objeví ve vašem domovském proudu. Můžete sledovat kohokoliv na jakémkoliv serveru!\",\n  \"introduction.federation.local.headline\": \"Místní\",\n  \"introduction.federation.local.text\": \"Veřejné příspěvky od lidí ze stejného serveru jako vy se zobrazí na místní časové ose.\",\n  \"introduction.interactions.action\": \"Dokončit tutoriál!\",\n  \"introduction.interactions.favourite.headline\": \"Oblíbení\",\n  \"introduction.interactions.favourite.text\": \"Oblíbením si můžete uložit toot na později a dát jeho autorovi vědět, že se vám líbí.\",\n  \"introduction.interactions.reblog.headline\": \"Boost\",\n  \"introduction.interactions.reblog.text\": \"Boostnutím můžete sdílet tooty jiných lidí s vašimi sledujícími.\",\n  \"introduction.interactions.reply.headline\": \"Odpověď\",\n  \"introduction.interactions.reply.text\": \"Můžete odpovídat na tooty jiných lidí i vaše vlastní, což je propojí do konverzace.\",\n  \"introduction.welcome.action\": \"Jdeme na to!\",\n  \"introduction.welcome.headline\": \"První kroky\",\n  \"introduction.welcome.text\": \"Vítejte ve fedivesmíru! Za malou chvíli budete moci posílat zprávy a povídat si se svými přátely přes širokou škálu serverů. Tento server, {domain}, je však speciální—je na něm váš profil, proto si zapamatujte jeho jméno.\",\n  \"keyboard_shortcuts.back\": \"k návratu zpět\",\n  \"keyboard_shortcuts.blocked\": \"k otevření seznamu blokovaných uživatelů\",\n  \"keyboard_shortcuts.boost\": \"k boostnutí\",\n  \"keyboard_shortcuts.column\": \"k zaměření na toot v jednom ze sloupců\",\n  \"keyboard_shortcuts.compose\": \"k zaměření na psací prostor\",\n  \"keyboard_shortcuts.description\": \"Popis\",\n  \"keyboard_shortcuts.direct\": \"k otevření sloupce s přímými zprávami\",\n  \"keyboard_shortcuts.down\": \"k posunutí dolů v seznamu\",\n  \"keyboard_shortcuts.enter\": \"k otevření tootu\",\n  \"keyboard_shortcuts.favourite\": \"k oblíbení\",\n  \"keyboard_shortcuts.favourites\": \"k otevření seznamu oblíbených\",\n  \"keyboard_shortcuts.federated\": \"k otevření federované časové osy\",\n  \"keyboard_shortcuts.heading\": \"Klávesové zkratky\",\n  \"keyboard_shortcuts.home\": \"k otevření domovské časové osy\",\n  \"keyboard_shortcuts.hotkey\": \"Klávesová zkratka\",\n  \"keyboard_shortcuts.legend\": \"k zobrazení této legendy\",\n  \"keyboard_shortcuts.local\": \"k otevření místní časové osy\",\n  \"keyboard_shortcuts.mention\": \"ke zmínění autora\",\n  \"keyboard_shortcuts.muted\": \"k otevření seznamu skrytých uživatelů\",\n  \"keyboard_shortcuts.my_profile\": \"k otevření vašeho profilu\",\n  \"keyboard_shortcuts.notifications\": \"k otevření sloupce s oznámeními\",\n  \"keyboard_shortcuts.pinned\": \"k otevření seznamu připnutých tootů\",\n  \"keyboard_shortcuts.profile\": \"k otevření autorova profilu\",\n  \"keyboard_shortcuts.reply\": \"k odpovězení\",\n  \"keyboard_shortcuts.requests\": \"k otevření seznamu požadavků o sledování\",\n  \"keyboard_shortcuts.search\": \"k zaměření na hledání\",\n  \"keyboard_shortcuts.start\": \"k otevření sloupce „začínáme“\",\n  \"keyboard_shortcuts.toggle_hidden\": \"k zobrazení/skrytí textu za varováním o obsahu\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"k zobrazení/skrytí médií\",\n  \"keyboard_shortcuts.toot\": \"k napsání úplně nového tootu\",\n  \"keyboard_shortcuts.unfocus\": \"ke zrušení zaměření na psací prostor/hledání\",\n  \"keyboard_shortcuts.up\": \"k posunutí nahoru v seznamu\",\n  \"lightbox.close\": \"Zavřít\",\n  \"lightbox.next\": \"Další\",\n  \"lightbox.previous\": \"Předchozí\",\n  \"lightbox.view_context\": \"Zobrazit kontext\",\n  \"lists.account.add\": \"Přidat do seznamu\",\n  \"lists.account.remove\": \"Odebrat ze seznamu\",\n  \"lists.delete\": \"Smazat seznam\",\n  \"lists.edit\": \"Upravit seznam\",\n  \"lists.edit.submit\": \"Změnit název\",\n  \"lists.new.create\": \"Přidat seznam\",\n  \"lists.new.title_placeholder\": \"Název nového seznamu\",\n  \"lists.search\": \"Hledejte mezi lidmi, které sledujete\",\n  \"lists.subheading\": \"Vaše seznamy\",\n  \"loading_indicator.label\": \"Načítám…\",\n  \"media_gallery.toggle_visible\": \"Přepínat viditelnost\",\n  \"missing_indicator.label\": \"Nenalezeno\",\n  \"missing_indicator.sublabel\": \"Tento zdroj se nepodařilo najít\",\n  \"mute_modal.hide_notifications\": \"Skrýt oznámení od tohoto uživatele?\",\n  \"navigation_bar.apps\": \"Mobilní aplikace\",\n  \"navigation_bar.blocks\": \"Blokovaní uživatelé\",\n  \"navigation_bar.community_timeline\": \"Místní časová osa\",\n  \"navigation_bar.compose\": \"Vytvořit nový toot\",\n  \"navigation_bar.direct\": \"Přímé zprávy\",\n  \"navigation_bar.discover\": \"Objevujte\",\n  \"navigation_bar.domain_blocks\": \"Skryté domény\",\n  \"navigation_bar.edit_profile\": \"Upravit profil\",\n  \"navigation_bar.favourites\": \"Oblíbené\",\n  \"navigation_bar.filters\": \"Skrytá slova\",\n  \"navigation_bar.follow_requests\": \"Požadavky o sledování\",\n  \"navigation_bar.follows_and_followers\": \"Sledovaní a sledující\",\n  \"navigation_bar.info\": \"O tomto serveru\",\n  \"navigation_bar.keyboard_shortcuts\": \"Klávesové zkratky\",\n  \"navigation_bar.lists\": \"Seznamy\",\n  \"navigation_bar.logout\": \"Odhlásit\",\n  \"navigation_bar.mutes\": \"Skrytí uživatelé\",\n  \"navigation_bar.personal\": \"Osobní\",\n  \"navigation_bar.pins\": \"Připnuté tooty\",\n  \"navigation_bar.preferences\": \"Předvolby\",\n  \"navigation_bar.profile_directory\": \"Adresář profilů\",\n  \"navigation_bar.public_timeline\": \"Federovaná časová osa\",\n  \"navigation_bar.security\": \"Zabezpečení\",\n  \"notification.favourite\": \"{name} si oblíbil/a váš toot\",\n  \"notification.follow\": \"{name} vás začal/a sledovat\",\n  \"notification.mention\": \"{name} vás zmínil/a\",\n  \"notification.poll\": \"Anketa, ve které jste hlasoval/a, skončila\",\n  \"notification.reblog\": \"{name} boostnul/a váš toot\",\n  \"notifications.clear\": \"Vymazat oznámení\",\n  \"notifications.clear_confirmation\": \"Jste si jistý/á, že chcete trvale vymazat všechna vaše oznámení?\",\n  \"notifications.column_settings.alert\": \"Desktopová oznámení\",\n  \"notifications.column_settings.favourite\": \"Oblíbení:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Zobrazit všechny kategorie\",\n  \"notifications.column_settings.filter_bar.category\": \"Panel rychlého filtrování\",\n  \"notifications.column_settings.filter_bar.show\": \"Zobrazit\",\n  \"notifications.column_settings.follow\": \"Noví sledující:\",\n  \"notifications.column_settings.mention\": \"Zmínky:\",\n  \"notifications.column_settings.poll\": \"Výsledky anket:\",\n  \"notifications.column_settings.push\": \"Push oznámení\",\n  \"notifications.column_settings.reblog\": \"Boosty:\",\n  \"notifications.column_settings.show\": \"Zobrazit ve sloupci\",\n  \"notifications.column_settings.sound\": \"Přehrát zvuk\",\n  \"notifications.filter.all\": \"Vše\",\n  \"notifications.filter.boosts\": \"Boosty\",\n  \"notifications.filter.favourites\": \"Oblíbení\",\n  \"notifications.filter.follows\": \"Sledování\",\n  \"notifications.filter.mentions\": \"Zmínky\",\n  \"notifications.filter.polls\": \"Výsledky anket\",\n  \"notifications.group\": \"{count} oznámení\",\n  \"poll.closed\": \"Uzavřena\",\n  \"poll.refresh\": \"Obnovit\",\n  \"poll.total_votes\": \"{count, plural, one {# hlas} few {# hlasy} many {# hlasu} other {# hlasů}}\",\n  \"poll.vote\": \"Hlasovat\",\n  \"poll_button.add_poll\": \"Přidat anketu\",\n  \"poll_button.remove_poll\": \"Odstranit anketu\",\n  \"privacy.change\": \"Změnit soukromí tootu\",\n  \"privacy.direct.long\": \"Odeslat pouze zmíněným uživatelům\",\n  \"privacy.direct.short\": \"Přímý\",\n  \"privacy.private.long\": \"Odeslat pouze sledujícím\",\n  \"privacy.private.short\": \"Pouze pro sledující\",\n  \"privacy.public.long\": \"Odeslat na veřejné časové osy\",\n  \"privacy.public.short\": \"Veřejný\",\n  \"privacy.unlisted.long\": \"Neodeslat na veřejné časové osy\",\n  \"privacy.unlisted.short\": \"Neuvedený\",\n  \"regeneration_indicator.label\": \"Načítám…\",\n  \"regeneration_indicator.sublabel\": \"Váš domovský proud se připravuje!\",\n  \"relative_time.days\": \"{number} d\",\n  \"relative_time.hours\": \"{number} h\",\n  \"relative_time.just_now\": \"teď\",\n  \"relative_time.minutes\": \"{number} m\",\n  \"relative_time.seconds\": \"{number} s\",\n  \"reply_indicator.cancel\": \"Zrušit\",\n  \"report.forward\": \"Přeposlat na {target}\",\n  \"report.forward_hint\": \"Tento účet je z jiného serveru. Chcete na něj také poslat anonymizovanou kopii?\",\n  \"report.hint\": \"Toto nahlášení bude zasláno moderátorům vašeho serveru. Níže můžete uvést, proč tento účet nahlašujete:\",\n  \"report.placeholder\": \"Dodatečné komentáře\",\n  \"report.submit\": \"Odeslat\",\n  \"report.target\": \"Nahlášení uživatele {target}\",\n  \"search.placeholder\": \"Hledat\",\n  \"search_popout.search_format\": \"Pokročilé hledání\",\n  \"search_popout.tips.full_text\": \"Jednoduchý text navrátí tooty, které jste napsal/a, oblíbil/a si, boostnul/a, nebo v nich byl/a zmíněn/a, a také odpovídající přezdívky, zobrazovaná jména a hashtagy.\",\n  \"search_popout.tips.hashtag\": \"hashtag\",\n  \"search_popout.tips.status\": \"toot\",\n  \"search_popout.tips.text\": \"Jednoduchý text navrátí odpovídající zobrazovaná jména, přezdívky a hashtagy\",\n  \"search_popout.tips.user\": \"uživatel\",\n  \"search_results.accounts\": \"Lidé\",\n  \"search_results.hashtags\": \"Hashtagy\",\n  \"search_results.statuses\": \"Tooty\",\n  \"search_results.total\": \"{count, number} {count, plural, one {výsledek} few {výsledky} many {výsledku} other {výsledků}}\",\n  \"status.admin_account\": \"Otevřít moderátorské rozhraní pro uživatele @{name}\",\n  \"status.admin_status\": \"Otevřít tento toot v moderátorském rozhraní\",\n  \"status.block\": \"Zablokovat uživatele @{name}\",\n  \"status.cancel_reblog_private\": \"Zrušit boost\",\n  \"status.cannot_reblog\": \"Tento příspěvek nemůže být boostnutý\",\n  \"status.copy\": \"Kopírovat odkaz k tootu\",\n  \"status.delete\": \"Smazat\",\n  \"status.detailed_status\": \"Detailní zobrazení konverzace\",\n  \"status.direct\": \"Poslat přímou zprávu uživateli @{name}\",\n  \"status.embed\": \"Vložit na web\",\n  \"status.favourite\": \"Oblíbit\",\n  \"status.filtered\": \"Filtrováno\",\n  \"status.load_more\": \"Zobrazit více\",\n  \"status.media_hidden\": \"Média skryta\",\n  \"status.mention\": \"Zmínit uživatele @{name}\",\n  \"status.more\": \"Více\",\n  \"status.mute\": \"Skrýt uživatele @{name}\",\n  \"status.mute_conversation\": \"Skrýt konverzaci\",\n  \"status.open\": \"Otevřít tento toot\",\n  \"status.pin\": \"Připnout na profil\",\n  \"status.pinned\": \"Připnutý toot\",\n  \"status.read_more\": \"Číst více\",\n  \"status.reblog\": \"Boostnout\",\n  \"status.reblog_private\": \"Boostnout původnímu publiku\",\n  \"status.reblogged_by\": \"{name} boostnul/a\",\n  \"status.reblogs.empty\": \"Tento toot ještě nikdo neboostnul. Pokud to někdo udělá, zobrazí se zde.\",\n  \"status.redraft\": \"Smazat a přepsat\",\n  \"status.reply\": \"Odpovědět\",\n  \"status.replyAll\": \"Odpovědět na vlákno\",\n  \"status.report\": \"Nahlásit uživatele @{name}\",\n  \"status.sensitive_warning\": \"Citlivý obsah\",\n  \"status.share\": \"Sdílet\",\n  \"status.show_less\": \"Zobrazit méně\",\n  \"status.show_less_all\": \"Zobrazit méně pro všechny\",\n  \"status.show_more\": \"Zobrazit více\",\n  \"status.show_more_all\": \"Zobrazit více pro všechny\",\n  \"status.show_thread\": \"Zobrazit vlákno\",\n  \"status.unmute_conversation\": \"Odkrýt konverzaci\",\n  \"status.unpin\": \"Odepnout z profilu\",\n  \"suggestions.dismiss\": \"Odmítnout návrh\",\n  \"suggestions.header\": \"Mohli by vás zajímat…\",\n  \"tabs_bar.federated_timeline\": \"Federovaná\",\n  \"tabs_bar.home\": \"Domů\",\n  \"tabs_bar.local_timeline\": \"Místní\",\n  \"tabs_bar.notifications\": \"Oznámení\",\n  \"tabs_bar.search\": \"Hledat\",\n  \"time_remaining.days\": \"{number, plural, one {Zbývá # den} few {Zbývají # dny} many {Zbývá # dne} other {Zbývá # dní}}\",\n  \"time_remaining.hours\": \"{number, plural, one {Zbývá # hodina} few {Zbývají # hodiny} many {Zbývá # hodiny} other {Zbývá # hodin}}\",\n  \"time_remaining.minutes\": \"{number, plural, one {Zbývá # minuta} few {Zbývají # minuty} many {Zbývá # minuty} other {Zbývá # minut}}\",\n  \"time_remaining.moments\": \"Zbývá několik sekund\",\n  \"time_remaining.seconds\": \"{number, plural, one {Zbývá # sekunda} few {Zbývají # sekundy} many {Zbývá # sekundy} other {Zbývá # sekund}}\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {člověk} few {lidé} many {lidí} other {lidí}} hovoří\",\n  \"ui.beforeunload\": \"Váš koncept se ztratí, pokud Mastodon opustíte.\",\n  \"upload_area.title\": \"Přetažením nahrajete\",\n  \"upload_button.label\": \"Přidat média (JPEG, PNG, GIF, WebM, MP4, MOV)\",\n  \"upload_error.limit\": \"Byl překročen limit nahraných souborů.\",\n  \"upload_error.poll\": \"Nahrávání souborů není povoleno u anket.\",\n  \"upload_form.description\": \"Popis pro zrakově postižené\",\n  \"upload_form.focus\": \"Změnit náhled\",\n  \"upload_form.undo\": \"Smazat\",\n  \"upload_progress.label\": \"Nahrávám…\",\n  \"video.close\": \"Zavřít video\",\n  \"video.exit_fullscreen\": \"Ukončit celou obrazovku\",\n  \"video.expand\": \"Otevřít video\",\n  \"video.fullscreen\": \"Celá obrazovka\",\n  \"video.hide\": \"Skrýt video\",\n  \"video.mute\": \"Vypnout zvuk\",\n  \"video.pause\": \"Pauza\",\n  \"video.play\": \"Přehrát\",\n  \"video.unmute\": \"Zapnout zvuk\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/cy.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Ychwanegu neu Dileu o'r rhestrau\",\n  \"account.badges.bot\": \"Bot\",\n  \"account.block\": \"Blocio @{name}\",\n  \"account.block_domain\": \"Cuddio popeth rhag {domain}\",\n  \"account.blocked\": \"Blociwyd\",\n  \"account.direct\": \"Neges breifat @{name}\",\n  \"account.domain_blocked\": \"Parth wedi ei guddio\",\n  \"account.edit_profile\": \"Golygu proffil\",\n  \"account.endorse\": \"Arddangos ar fy mhroffil\",\n  \"account.follow\": \"Dilyn\",\n  \"account.followers\": \"Dilynwyr\",\n  \"account.followers.empty\": \"Nid oes neb yn dilyn y defnyddiwr hwn eto.\",\n  \"account.follows\": \"Yn dilyn\",\n  \"account.follows.empty\": \"Nid yw'r defnyddiwr hwn yn dilyn unrhyw un eto.\",\n  \"account.follows_you\": \"Yn eich dilyn chi\",\n  \"account.hide_reblogs\": \"Cuddio bwstiau o @{name}\",\n  \"account.link_verified_on\": \"Gwiriwyd perchnogaeth y ddolen yma ar {date}\",\n  \"account.locked_info\": \"Mae'r statws preifatrwydd cyfrif hwn wedi'i osod i gloi. Mae'r perchennog yn adolygu'r sawl sy'n gallu eu dilyn.\",\n  \"account.media\": \"Cyfryngau\",\n  \"account.mention\": \"Crybwyll @{name}\",\n  \"account.moved_to\": \"Mae @{name} wedi symud i:\",\n  \"account.mute\": \"Tawelu @{name}\",\n  \"account.mute_notifications\": \"Cuddio hysbysiadau o @{name}\",\n  \"account.muted\": \"Distewyd\",\n  \"account.posts\": \"Tŵtiau\",\n  \"account.posts_with_replies\": \"Tŵtiau ac atebion\",\n  \"account.report\": \"Adrodd @{name}\",\n  \"account.requested\": \"Aros am gymeradwyaeth. Cliciwch er mwyn canslo cais dilyn\",\n  \"account.share\": \"Rhannwch broffil @{name}\",\n  \"account.show_reblogs\": \"Dangos bwstiau o @{name}\",\n  \"account.unblock\": \"Dadflocio @{name}\",\n  \"account.unblock_domain\": \"Dadguddio {domain}\",\n  \"account.unendorse\": \"Peidio a'i arddangos ar fy mhroffil\",\n  \"account.unfollow\": \"Dad-ddilyn\",\n  \"account.unmute\": \"Dad-dawelu @{name}\",\n  \"account.unmute_notifications\": \"Dad-dawelu hysbysiadau o @{name}\",\n  \"alert.unexpected.message\": \"Digwyddodd gwall annisgwyl.\",\n  \"alert.unexpected.title\": \"Wps!\",\n  \"boost_modal.combo\": \"Mae modd gwasgu {combo} er mwyn sgipio hyn tro nesa\",\n  \"bundle_column_error.body\": \"Aeth rhywbeth o'i le tra'n llwytho'r elfen hon.\",\n  \"bundle_column_error.retry\": \"Ceisiwch eto\",\n  \"bundle_column_error.title\": \"Gwall rhwydwaith\",\n  \"bundle_modal_error.close\": \"Cau\",\n  \"bundle_modal_error.message\": \"Aeth rhywbeth o'i le tra'n llwytho'r elfen hon.\",\n  \"bundle_modal_error.retry\": \"Ceiswich eto\",\n  \"column.blocks\": \"Defnyddwyr a flociwyd\",\n  \"column.community\": \"Ffrwd lleol\",\n  \"column.direct\": \"Negeseuon preifat\",\n  \"column.domain_blocks\": \"Parthau cuddiedig\",\n  \"column.favourites\": \"Ffefrynnau\",\n  \"column.follow_requests\": \"Ceisiadau dilyn\",\n  \"column.home\": \"Hafan\",\n  \"column.lists\": \"Rhestrau\",\n  \"column.mutes\": \"Defnyddwyr a ddistewyd\",\n  \"column.notifications\": \"Hysbysiadau\",\n  \"column.pins\": \"Tŵtiau wedi eu pinio\",\n  \"column.public\": \"Ffrwd y ffederasiwn\",\n  \"column_back_button.label\": \"Nôl\",\n  \"column_header.hide_settings\": \"Cuddio dewisiadau\",\n  \"column_header.moveLeft_settings\": \"Symud y golofn i'r chwith\",\n  \"column_header.moveRight_settings\": \"Symud y golofn i'r dde\",\n  \"column_header.pin\": \"Pinio\",\n  \"column_header.show_settings\": \"Dangos gosodiadau\",\n  \"column_header.unpin\": \"Dadbinio\",\n  \"column_subheading.settings\": \"Gosodiadau\",\n  \"community.column_settings.media_only\": \"Cyfryngau yn unig\",\n  \"compose_form.direct_message_warning\": \"Mi fydd y tŵt hwn ond yn cael ei anfon at y defnyddwyr sy'n cael eu crybwyll.\",\n  \"compose_form.direct_message_warning_learn_more\": \"Dysgu mwy\",\n  \"compose_form.hashtag_warning\": \"Ni fydd y tŵt hwn wedi ei restru o dan unrhyw hashnod gan ei fod heb ei restru. Dim ond tŵtiau cyhoeddus gellid chwilota amdanynt drwy hashnod.\",\n  \"compose_form.lock_disclaimer\": \"Nid yw eich cyfri wedi'i {locked}. Gall unrhyw un eich dilyn i weld eich tŵtiau dilynwyr-yn-unig.\",\n  \"compose_form.lock_disclaimer.lock\": \"wedi ei gloi\",\n  \"compose_form.placeholder\": \"Beth sydd ar eich meddwl?\",\n  \"compose_form.poll.add_option\": \"Ychwanegu Dewisiad\",\n  \"compose_form.poll.duration\": \"Cyfnod pleidlais\",\n  \"compose_form.poll.option_placeholder\": \"Dewisiad {number}\",\n  \"compose_form.poll.remove_option\": \"Tynnu'r dewisiad\",\n  \"compose_form.publish\": \"Tŵt\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"Marcio cyfryngau fel eu bod yn sensitif\",\n  \"compose_form.sensitive.marked\": \"Cyfryngau wedi'u marcio'n sensitif\",\n  \"compose_form.sensitive.unmarked\": \"Nid yw'r cyfryngau wedi'u marcio'n sensitif\",\n  \"compose_form.spoiler.marked\": \"Testun wedi ei guddio gan rybudd\",\n  \"compose_form.spoiler.unmarked\": \"Nid yw'r testun wedi ei guddio\",\n  \"compose_form.spoiler_placeholder\": \"Ysgrifenwch eich rhybudd yma\",\n  \"confirmation_modal.cancel\": \"Canslo\",\n  \"confirmations.block.block_and_report\": \"Rhwystro ac Adrodd\",\n  \"confirmations.block.confirm\": \"Blocio\",\n  \"confirmations.block.message\": \"Ydych chi'n sicr eich bod eisiau blocio {name}?\",\n  \"confirmations.delete.confirm\": \"Dileu\",\n  \"confirmations.delete.message\": \"Ydych chi'n sicr eich bod eisiau dileu y tŵt hwn?\",\n  \"confirmations.delete_list.confirm\": \"Dileu\",\n  \"confirmations.delete_list.message\": \"Ydych chi'n sicr eich bod eisiau dileu y rhestr hwn am byth?\",\n  \"confirmations.domain_block.confirm\": \"Cuddio parth cyfan\",\n  \"confirmations.domain_block.message\": \"A ydych yn hollol, hollol sicr eich bod am flocio y {domain} cyfan? Yn y nifer helaeth o achosion mae blocio neu tawelu ambell gyfrif yn ddigonol ac yn well. Ni fyddwch yn gweld cynnwys o'r parth hwnnw mewn unrhyw ffrydiau cyhoeddus na chwaith yn eich hysbysiadau. Bydd hyn yn cael gwared o'ch dilynwyr o'r parth hwnnw.\",\n  \"confirmations.mute.confirm\": \"Tawelu\",\n  \"confirmations.mute.message\": \"Ydych chi'n sicr eich bod am ddistewi {name}?\",\n  \"confirmations.redraft.confirm\": \"Dileu & ailddrafftio\",\n  \"confirmations.redraft.message\": \"Ydych chi'n siwr eich bod eisiau dileu y tŵt hwn a'i ailddrafftio? Bydd ffefrynnau a bwstiau'n cael ei colli, a bydd ymatebion i'r tŵt gwreiddiol yn cael eu hamddifadu.\",\n  \"confirmations.reply.confirm\": \"Ateb\",\n  \"confirmations.reply.message\": \"Bydd ateb nawr yn cymryd lle y neges yr ydych yn cyfansoddi ar hyn o bryd. Ydych chi'n sicr yr ydych am barhau?\",\n  \"confirmations.unfollow.confirm\": \"Dad-ddilynwch\",\n  \"confirmations.unfollow.message\": \"Ydych chi'n sicr eich bod am ddad-ddilyn {name}?\",\n  \"embed.instructions\": \"Mewnblannwch y tŵt hwn ar eich gwefan drwy gopïo'r côd isod.\",\n  \"embed.preview\": \"Dyma sut olwg fydd arno:\",\n  \"emoji_button.activity\": \"Gweithgarwch\",\n  \"emoji_button.custom\": \"Unigryw\",\n  \"emoji_button.flags\": \"Baneri\",\n  \"emoji_button.food\": \"Bwyd a Diod\",\n  \"emoji_button.label\": \"Mewnosodwch emoji\",\n  \"emoji_button.nature\": \"Natur\",\n  \"emoji_button.not_found\": \"Dim emojau!! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"Gwrthrychau\",\n  \"emoji_button.people\": \"Pobl\",\n  \"emoji_button.recent\": \"Defnyddir yn aml\",\n  \"emoji_button.search\": \"Chwilio...\",\n  \"emoji_button.search_results\": \"Canlyniadau chwilio\",\n  \"emoji_button.symbols\": \"Symbolau\",\n  \"emoji_button.travel\": \"Teithio & Llefydd\",\n  \"empty_column.account_timeline\": \"Dim tŵtiau fama!\",\n  \"empty_column.account_unavailable\": \"Proffil ddim ar gael\",\n  \"empty_column.blocks\": \"Nid ydych wedi blocio unrhyw ddefnyddwyr eto.\",\n  \"empty_column.community\": \"Mae'r ffrwd lleol yn wag. Ysgrifenwch rhywbeth yn gyhoeddus i gael dechrau arni!\",\n  \"empty_column.direct\": \"Nid oes gennych unrhyw negeseuon preifat eto. Pan y byddwch yn anfon neu derbyn un, mi fydd yn ymddangos yma.\",\n  \"empty_column.domain_blocks\": \"Nid oes yna unrhyw barthau cuddiedig eto.\",\n  \"empty_column.favourited_statuses\": \"Nid oes gennych unrhyw hoff dwtiau eto. Pan y byddwch yn hoffi un, mi fydd yn ymddangos yma.\",\n  \"empty_column.favourites\": \"Nid oes neb wedi hoffi'r tŵt yma eto. Pan bydd rhywun yn ei hoffi, byddent yn ymddangos yma.\",\n  \"empty_column.follow_requests\": \"Nid oes gennych unrhyw geisiadau dilyn eto. Pan dderbyniwch chi un, byddent yn ymddangos yma.\",\n  \"empty_column.hashtag\": \"Nid oes dim ar yr hashnod hwn eto.\",\n  \"empty_column.home\": \"Mae eich ffrwd gartref yn wag! Ymwelwch a {public} neu defnyddiwch y chwilotwr i ddechrau arni ac i gwrdd a defnyddwyr eraill.\",\n  \"empty_column.home.public_timeline\": \"y ffrwd gyhoeddus\",\n  \"empty_column.list\": \"Nid oes dim yn y rhestr yma eto. Pan y bydd aelodau'r rhestr yn cyhoeddi statws newydd, mi fydd yn ymddangos yma.\",\n  \"empty_column.lists\": \"Nid oes gennych unrhyw restrau eto. Pan grëwch chi un, mi fydd yn ymddangos yma.\",\n  \"empty_column.mutes\": \"Nid ydych wedi tawelu unrhyw ddefnyddwyr eto.\",\n  \"empty_column.notifications\": \"Nid oes gennych unrhyw hysbysiadau eto. Rhyngweithiwch ac eraill i ddechrau'r sgwrs.\",\n  \"empty_column.public\": \"Does dim byd yma! Ysgrifennwch rhywbeth yn gyhoeddus, neu dilynwch ddefnyddwyr o achosion eraill i'w lenwi\",\n  \"follow_request.authorize\": \"Caniatau\",\n  \"follow_request.reject\": \"Gwrthod\",\n  \"getting_started.developers\": \"Datblygwyr\",\n  \"getting_started.directory\": \"Cyfeiriadur proffil\",\n  \"getting_started.documentation\": \"Dogfennaeth\",\n  \"getting_started.heading\": \"Dechrau\",\n  \"getting_started.invite\": \"Gwahodd pobl\",\n  \"getting_started.open_source_notice\": \"Mae Mastodon yn feddalwedd côd agored. Mae modd cyfrannu neu adrodd materion ar GitHUb ar {github}.\",\n  \"getting_started.security\": \"Diogelwch\",\n  \"getting_started.terms\": \"Telerau Gwasanaeth\",\n  \"hashtag.column_header.tag_mode.all\": \"a {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"neu {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"heb {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"Dim awgrymiadau i'w weld\",\n  \"hashtag.column_settings.select.placeholder\": \"Mewnbynnu hashnodau…\",\n  \"hashtag.column_settings.tag_mode.all\": \"Pob un o'r rhain\",\n  \"hashtag.column_settings.tag_mode.any\": \"Unrhyw un o'r rhain\",\n  \"hashtag.column_settings.tag_mode.none\": \"Dim o'r rhain\",\n  \"hashtag.column_settings.tag_toggle\": \"Include additional tags in this column\",\n  \"home.column_settings.basic\": \"Syml\",\n  \"home.column_settings.show_reblogs\": \"Dangos bŵstiau\",\n  \"home.column_settings.show_replies\": \"Dangos ymatebion\",\n  \"intervals.full.days\": \"{number, plural, one {# ddydd} other {# o ddyddiau}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# awr} other {# o oriau}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# funud} other {# o funudau}}\",\n  \"introduction.federation.action\": \"Nesaf\",\n  \"introduction.federation.federated.headline\": \"Ffederasiwn\",\n  \"introduction.federation.federated.text\": \"Bydd pyst cyhoeddus o gweinyddion arall yn y Ffedysawd yn cael ai arddangos yn ffrwd y ffederasiwn.\",\n  \"introduction.federation.home.headline\": \"Hafan\",\n  \"introduction.federation.home.text\": \"Bydd pyst o bobl rydych yn ei ddilyn yn dangos yn eich ffrwd gatref. Gallwch dilyn unrhyw un ar unrhyw gweinydd!\",\n  \"introduction.federation.local.headline\": \"Lleol\",\n  \"introduction.federation.local.text\": \"Bydd pyst gyhoeddus o bobl ar yr un gweinydd a chi yn cael ei arddangos yn y ffrwd lleol.\",\n  \"introduction.interactions.action\": \"Gorffen tiwtorial!\",\n  \"introduction.interactions.favourite.headline\": \"Ffefryn\",\n  \"introduction.interactions.favourite.text\": \"Gallwch cadw tŵt am hwyrach, a gadael i'r awdur gwybod roeddech yn ei hoffi, trwy ei hoffi.\",\n  \"introduction.interactions.reblog.headline\": \"Hwb\",\n  \"introduction.interactions.reblog.text\": \"Gallwch rhannu tŵtiau pobl eraill gyda'ch dilynwyr trwy eu bŵstio.\",\n  \"introduction.interactions.reply.headline\": \"Ateb\",\n  \"introduction.interactions.reply.text\": \"Gallwch ateb i dŵtiau pobl eraill a thŵtiau eich hun, a fydd yn eu cadwyno at ei gilydd mewn sgwrs.\",\n  \"introduction.welcome.action\": \"Awn ni!\",\n  \"introduction.welcome.headline\": \"Camau cyntaf\",\n  \"introduction.welcome.text\": \"Croeso i'r ffedysawd! Mewn ychydig o funudau, byddwch yn gallu darlledu negeseuon a siarad i'ch ffrindiau ar draws amrywiaeth eang o weinyddion. Ond mae'r gweinydd hyn, {domain}, yn arbennig - mae o'n gweinyddu eich proffil, fellu cofiwch ei enw.\",\n  \"keyboard_shortcuts.back\": \"i lywio nôl\",\n  \"keyboard_shortcuts.blocked\": \"i agor rhestr defnyddwyr a flociwyd\",\n  \"keyboard_shortcuts.boost\": \"i fŵstio\",\n  \"keyboard_shortcuts.column\": \"i ffocysu tŵt yn un o'r colofnau\",\n  \"keyboard_shortcuts.compose\": \"i ffocysu yr ardal cyfansoddi testun\",\n  \"keyboard_shortcuts.description\": \"Disgrifiad\",\n  \"keyboard_shortcuts.direct\": \"i agor colofn negeseuon preifat\",\n  \"keyboard_shortcuts.down\": \"i symud lawr yn y rhestr\",\n  \"keyboard_shortcuts.enter\": \"i agor tŵt\",\n  \"keyboard_shortcuts.favourite\": \"i hoffi\",\n  \"keyboard_shortcuts.favourites\": \"i agor rhestr hoffi\",\n  \"keyboard_shortcuts.federated\": \"i agor ffrwd y ffederasiwn\",\n  \"keyboard_shortcuts.heading\": \"Llwybrau byr allweddell\",\n  \"keyboard_shortcuts.home\": \"i agor ffrwd cartref\",\n  \"keyboard_shortcuts.hotkey\": \"Bysell brys\",\n  \"keyboard_shortcuts.legend\": \"i ddangos yr arwr yma\",\n  \"keyboard_shortcuts.local\": \"i agor ffrwd lleol\",\n  \"keyboard_shortcuts.mention\": \"i grybwyll yr awdur\",\n  \"keyboard_shortcuts.muted\": \"i agor rhestr defnyddwyr a dawelwyd\",\n  \"keyboard_shortcuts.my_profile\": \"i agor eich proffil\",\n  \"keyboard_shortcuts.notifications\": \"i agor colofn hysbysiadau\",\n  \"keyboard_shortcuts.pinned\": \"i agor rhestr tŵtiau wedi'i pinio\",\n  \"keyboard_shortcuts.profile\": \"i agor proffil yr awdur\",\n  \"keyboard_shortcuts.reply\": \"i ateb\",\n  \"keyboard_shortcuts.requests\": \"i agor rhestr ceisiadau dilyn\",\n  \"keyboard_shortcuts.search\": \"i ffocysu chwilio\",\n  \"keyboard_shortcuts.start\": \"i agor colofn \\\"dechrau arni\\\"\",\n  \"keyboard_shortcuts.toggle_hidden\": \"i ddangos/cuddio testun tu ôl i CW\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"i ddangos/gyddio cyfryngau\",\n  \"keyboard_shortcuts.toot\": \"i ddechrau tŵt newydd sbon\",\n  \"keyboard_shortcuts.unfocus\": \"i ddad-ffocysu ardal cyfansoddi testun/chwilio\",\n  \"keyboard_shortcuts.up\": \"i symud yn uwch yn y rhestr\",\n  \"lightbox.close\": \"Cau\",\n  \"lightbox.next\": \"Nesaf\",\n  \"lightbox.previous\": \"Blaenorol\",\n  \"lightbox.view_context\": \"Gweld cyd-destyn\",\n  \"lists.account.add\": \"Ychwanegwch at restr\",\n  \"lists.account.remove\": \"Dileu o'r rhestr\",\n  \"lists.delete\": \"Dileu rhestr\",\n  \"lists.edit\": \"Golygwch rhestr\",\n  \"lists.edit.submit\": \"Newid teitl\",\n  \"lists.new.create\": \"Ychwanegu rhestr\",\n  \"lists.new.title_placeholder\": \"Teitl rhestr newydd\",\n  \"lists.search\": \"Chwilio ymysg pobl yr ydych yn ei ddilyn\",\n  \"lists.subheading\": \"Eich rhestrau\",\n  \"loading_indicator.label\": \"Llwytho...\",\n  \"media_gallery.toggle_visible\": \"Toglo gwelededd\",\n  \"missing_indicator.label\": \"Heb ei ganfod\",\n  \"missing_indicator.sublabel\": \"Ni ellid canfod yr adnodd hwn\",\n  \"mute_modal.hide_notifications\": \"Cuddio hysbysiadau rhag y defnyddiwr hwn?\",\n  \"navigation_bar.apps\": \"Apiau symudol\",\n  \"navigation_bar.blocks\": \"Defnyddwyr wedi eu blocio\",\n  \"navigation_bar.community_timeline\": \"Ffrwd leol\",\n  \"navigation_bar.compose\": \"Cyfansoddi tŵt newydd\",\n  \"navigation_bar.direct\": \"Negeseuon preifat\",\n  \"navigation_bar.discover\": \"Darganfod\",\n  \"navigation_bar.domain_blocks\": \"Parthau cuddiedig\",\n  \"navigation_bar.edit_profile\": \"Golygu proffil\",\n  \"navigation_bar.favourites\": \"Ffefrynnau\",\n  \"navigation_bar.filters\": \"Geiriau a dawelwyd\",\n  \"navigation_bar.follow_requests\": \"Ceisiadau dilyn\",\n  \"navigation_bar.follows_and_followers\": \"Dilynion a ddilynwyr\",\n  \"navigation_bar.info\": \"Ynghylch yr achos hwn\",\n  \"navigation_bar.keyboard_shortcuts\": \"Bysellau brys\",\n  \"navigation_bar.lists\": \"Rhestrau\",\n  \"navigation_bar.logout\": \"Allgofnodi\",\n  \"navigation_bar.mutes\": \"Defnyddwyr a dawelwyd\",\n  \"navigation_bar.personal\": \"Personol\",\n  \"navigation_bar.pins\": \"Tŵtiau wedi eu pinio\",\n  \"navigation_bar.preferences\": \"Dewisiadau\",\n  \"navigation_bar.profile_directory\": \"Cyfeiriadur Proffil\",\n  \"navigation_bar.public_timeline\": \"Ffrwd y ffederasiwn\",\n  \"navigation_bar.security\": \"Diogelwch\",\n  \"notification.favourite\": \"hoffodd {name} eich tŵt\",\n  \"notification.follow\": \"dilynodd {name} chi\",\n  \"notification.mention\": \"Soniodd {name} amdanoch chi\",\n  \"notification.poll\": \"Mae pleidlais rydych wedi pleidleisio ynddi wedi dod i ben\",\n  \"notification.reblog\": \"Hysbysebodd {name} eich tŵt\",\n  \"notifications.clear\": \"Clirio hysbysiadau\",\n  \"notifications.clear_confirmation\": \"Ydych chi'n sicr eich bod am glirio'ch holl hysbysiadau am byth?\",\n  \"notifications.column_settings.alert\": \"Hysbysiadau bwrdd gwaith\",\n  \"notifications.column_settings.favourite\": \"Ffefrynnau:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Dangos pob categori\",\n  \"notifications.column_settings.filter_bar.category\": \"Bar hidlo\",\n  \"notifications.column_settings.filter_bar.show\": \"Dangos\",\n  \"notifications.column_settings.follow\": \"Dilynwyr newydd:\",\n  \"notifications.column_settings.mention\": \"Crybwylliadau:\",\n  \"notifications.column_settings.poll\": \"Canlyniadau pleidlais:\",\n  \"notifications.column_settings.push\": \"Hysbysiadau push\",\n  \"notifications.column_settings.reblog\": \"Hybiadau:\",\n  \"notifications.column_settings.show\": \"Dangos yn y golofn\",\n  \"notifications.column_settings.sound\": \"Chwarae sain\",\n  \"notifications.filter.all\": \"Pob\",\n  \"notifications.filter.boosts\": \"Hybiadau\",\n  \"notifications.filter.favourites\": \"Ffefrynnau\",\n  \"notifications.filter.follows\": \"Yn dilyn\",\n  \"notifications.filter.mentions\": \"Crybwylliadau\",\n  \"notifications.filter.polls\": \"Canlyniadau pleidlais\",\n  \"notifications.group\": \"{count} o hysbysiadau\",\n  \"poll.closed\": \"Ar gau\",\n  \"poll.refresh\": \"Adnewyddu\",\n  \"poll.total_votes\": \"{count, plural, one {# bleidlais} other {# o bleidleisiau}}\",\n  \"poll.vote\": \"Pleidleisio\",\n  \"poll_button.add_poll\": \"Ychwanegu pleidlais\",\n  \"poll_button.remove_poll\": \"Tynnu pleidlais\",\n  \"privacy.change\": \"Addasu preifatrwdd y tŵt\",\n  \"privacy.direct.long\": \"Cyhoeddi i'r defnyddwyr sy'n cael eu crybwyll yn unig\",\n  \"privacy.direct.short\": \"Uniongyrchol\",\n  \"privacy.private.long\": \"Cyhoeddi i ddilynwyr yn unig\",\n  \"privacy.private.short\": \"Dilynwyr-yn-unig\",\n  \"privacy.public.long\": \"Cyhoeddi i ffrydiau cyhoeddus\",\n  \"privacy.public.short\": \"Cyhoeddus\",\n  \"privacy.unlisted.long\": \"Peidio a chyhoeddi i ffrydiau cyhoeddus\",\n  \"privacy.unlisted.short\": \"Heb ei restru\",\n  \"regeneration_indicator.label\": \"Llwytho…\",\n  \"regeneration_indicator.sublabel\": \"Mae eich ffrwd cartref yn cael ei baratoi!\",\n  \"relative_time.days\": \"{number}dydd\",\n  \"relative_time.hours\": \"{number}awr\",\n  \"relative_time.just_now\": \"nawr\",\n  \"relative_time.minutes\": \"{number}munud\",\n  \"relative_time.seconds\": \"{number}eiliad\",\n  \"reply_indicator.cancel\": \"Canslo\",\n  \"report.forward\": \"Ymlaen i {target}\",\n  \"report.forward_hint\": \"Mae'r cyfrif o weinydd arall. Anfon copi anhysbys o'r adroddiad yno hefyd?\",\n  \"report.hint\": \"Bydd yr adroddiad yn cael ei anfon i arolygydd eich achos. Mae modd darparu esboniad o pam yr ydych yn cwyno am y cyfrif hwn isod:\",\n  \"report.placeholder\": \"Sylwadau ychwanegol\",\n  \"report.submit\": \"Cyflwyno\",\n  \"report.target\": \"Cwyno am {target}\",\n  \"search.placeholder\": \"Chwilio\",\n  \"search_popout.search_format\": \"Fformat chwilio uwch\",\n  \"search_popout.tips.full_text\": \"Mae testun syml yn dychwelyd tŵtiau yr ydych wedi ysgrifennu, hoffi, wedi'u bŵstio, neu wedi'ch crybwyll ynddynt, ynghyd a chyfateb a enwau defnyddwyr, enwau arddangos ac hashnodau.\",\n  \"search_popout.tips.hashtag\": \"hashnod\",\n  \"search_popout.tips.status\": \"tŵt\",\n  \"search_popout.tips.text\": \"Mae testun syml yn dychwelyd enwau arddangos, enwau defnyddwyr a hashnodau sy'n cyfateb\",\n  \"search_popout.tips.user\": \"defnyddiwr\",\n  \"search_results.accounts\": \"Pobl\",\n  \"search_results.hashtags\": \"Hanshnodau\",\n  \"search_results.statuses\": \"Tŵtiau\",\n  \"search_results.total\": \"{count, number} {count, plural, one {result} other {results}}\",\n  \"status.admin_account\": \"Agor rhyngwyneb goruwchwylio ar gyfer @{name}\",\n  \"status.admin_status\": \"Agor y tŵt yn y rhyngwyneb goruwchwylio\",\n  \"status.block\": \"Blocio @{name}\",\n  \"status.cancel_reblog_private\": \"Dadfŵstio\",\n  \"status.cannot_reblog\": \"Ni ellir sbarduno'r tŵt hwn\",\n  \"status.copy\": \"Copïo cysylltiad i'r tŵt\",\n  \"status.delete\": \"Dileu\",\n  \"status.detailed_status\": \"Golwg manwl o'r sgwrs\",\n  \"status.direct\": \"Neges breifat @{name}\",\n  \"status.embed\": \"Plannu\",\n  \"status.favourite\": \"Hoffi\",\n  \"status.filtered\": \"Wedi'i hidlo\",\n  \"status.load_more\": \"Llwythwch mwy\",\n  \"status.media_hidden\": \"Cyfryngau wedi'u cuddio\",\n  \"status.mention\": \"Crybwyll @{name}\",\n  \"status.more\": \"Mwy\",\n  \"status.mute\": \"Tawelu @{name}\",\n  \"status.mute_conversation\": \"Tawelu sgwrs\",\n  \"status.open\": \"Ehangu'r tŵt hwn\",\n  \"status.pin\": \"Pinio ar y proffil\",\n  \"status.pinned\": \"Pinio tŵt\",\n  \"status.read_more\": \"Darllen mwy\",\n  \"status.reblog\": \"Hybu\",\n  \"status.reblog_private\": \"Hybu i'r gynulleidfa wreiddiol\",\n  \"status.reblogged_by\": \"Bŵstio {name}\",\n  \"status.reblogs.empty\": \"Does neb wedi bŵstio'r tŵt yma eto. Pan y bydd rhywun yn gwneud, byddent yn ymddangos yma.\",\n  \"status.redraft\": \"Dileu & ailddrafftio\",\n  \"status.reply\": \"Ateb\",\n  \"status.replyAll\": \"Ateb i edefyn\",\n  \"status.report\": \"Adrodd @{name}\",\n  \"status.sensitive_warning\": \"Cynnwys sensitif\",\n  \"status.share\": \"Rhannu\",\n  \"status.show_less\": \"Dangos llai\",\n  \"status.show_less_all\": \"Dangos llai i bawb\",\n  \"status.show_more\": \"Dangos mwy\",\n  \"status.show_more_all\": \"Dangos mwy i bawb\",\n  \"status.show_thread\": \"Dangos edefyn\",\n  \"status.unmute_conversation\": \"Dad-dawelu sgwrs\",\n  \"status.unpin\": \"Dadbinio o'r proffil\",\n  \"suggestions.dismiss\": \"Diswyddo\",\n  \"suggestions.header\": \"Efallai y bydd gennych ddiddordeb mewn…\",\n  \"tabs_bar.federated_timeline\": \"Ffederasiwn\",\n  \"tabs_bar.home\": \"Hafan\",\n  \"tabs_bar.local_timeline\": \"Lleol\",\n  \"tabs_bar.notifications\": \"Hysbysiadau\",\n  \"tabs_bar.search\": \"Chwilio\",\n  \"time_remaining.days\": \"{number, plural, one {# ddydd} other {# o ddyddiau}} ar ôl\",\n  \"time_remaining.hours\": \"{number, plural, one {# awr} other {# o oriau}} ar ôl\",\n  \"time_remaining.minutes\": \"{number, plural, one {# funud} other {# o funudau}} ar ôl\",\n  \"time_remaining.moments\": \"Munudau ar ôl\",\n  \"time_remaining.seconds\": \"{number, plural, one {# eiliad} other {# o eiliadau}} ar ôl\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {person} other {people}} yn siarad\",\n  \"ui.beforeunload\": \"Mi fyddwch yn colli eich drafft os gadewch Mastodon.\",\n  \"upload_area.title\": \"Llusgwch & gollwing i uwchlwytho\",\n  \"upload_button.label\": \"Ychwanegwch gyfryngau (JPEG, PNG, GIF, WebM, MP4, MOV)\",\n  \"upload_error.limit\": \"Wedi mynd heibio'r uchafswm terfyn uwchlwytho.\",\n  \"upload_error.poll\": \"Nid oes modd uwchlwytho ffeiliau â phleidleisiau.\",\n  \"upload_form.description\": \"Disgrifio i'r rheini a nam ar ei golwg\",\n  \"upload_form.focus\": \"Newid rhagolwg\",\n  \"upload_form.undo\": \"Dileu\",\n  \"upload_progress.label\": \"Uwchlwytho...\",\n  \"video.close\": \"Cau fideo\",\n  \"video.exit_fullscreen\": \"Gadael sgrîn llawn\",\n  \"video.expand\": \"Ymestyn fideo\",\n  \"video.fullscreen\": \"Sgrîn llawn\",\n  \"video.hide\": \"Cuddio fideo\",\n  \"video.mute\": \"Tawelu sain\",\n  \"video.pause\": \"Oedi\",\n  \"video.play\": \"Chwarae\",\n  \"video.unmute\": \"Dad-dawelu sain\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/da.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Tilføj eller fjern fra lister\",\n  \"account.badges.bot\": \"Robot\",\n  \"account.block\": \"Bloker @{name}\",\n  \"account.block_domain\": \"Skjul alt fra {domain}\",\n  \"account.blocked\": \"Blokeret\",\n  \"account.direct\": \"Send en direkte besked til @{name}\",\n  \"account.domain_blocked\": \"Domænet er blevet skjult\",\n  \"account.edit_profile\": \"Rediger profil\",\n  \"account.endorse\": \"Fremhæv på profil\",\n  \"account.follow\": \"Følg\",\n  \"account.followers\": \"Følgere\",\n  \"account.followers.empty\": \"Der er endnu ingen der følger denne bruger.\",\n  \"account.follows\": \"Følger\",\n  \"account.follows.empty\": \"Denne bruger følger endnu ikke nogen.\",\n  \"account.follows_you\": \"Følger dig\",\n  \"account.hide_reblogs\": \"Skjul fremhævelserne fra @{name}\",\n  \"account.link_verified_on\": \"Ejerskabet af dette link blev tjekket den %{date}\",\n  \"account.locked_info\": \"This account privacy status is set to locked. The owner manually reviews who can follow them.\",\n  \"account.media\": \"Medie\",\n  \"account.mention\": \"Nævn @{name}\",\n  \"account.moved_to\": \"{name} er flyttet til:\",\n  \"account.mute\": \"Dæmp @{name}\",\n  \"account.mute_notifications\": \"Dæmp notifikationer fra @{name}\",\n  \"account.muted\": \"Dæmpet\",\n  \"account.posts\": \"Trut\",\n  \"account.posts_with_replies\": \"Trut og svar\",\n  \"account.report\": \"Rapporter @{name}\",\n  \"account.requested\": \"Afventer godkendelse. Tryk for at annullere følgeanmodning\",\n  \"account.share\": \"Del @{name}s profil\",\n  \"account.show_reblogs\": \"Vis fremhævelserne fra @{name}\",\n  \"account.unblock\": \"Fjern blokeringen af @{name}\",\n  \"account.unblock_domain\": \"Skjul ikke længere {domain}\",\n  \"account.unendorse\": \"Fremhæv ikke på profil\",\n  \"account.unfollow\": \"Følg ikke længere\",\n  \"account.unmute\": \"Fjern dæmpningen af @{name}\",\n  \"account.unmute_notifications\": \"Fjern dæmpningen af notifikationer fra @{name}\",\n  \"alert.unexpected.message\": \"Der opstod en uventet fejl.\",\n  \"alert.unexpected.title\": \"Ups!\",\n  \"boost_modal.combo\": \"Du kan trykke {combo} for at springe dette over næste gang\",\n  \"bundle_column_error.body\": \"Noget gik galt under indlæsningen af dette komponent.\",\n  \"bundle_column_error.retry\": \"Prøv igen\",\n  \"bundle_column_error.title\": \"Netværksfejl\",\n  \"bundle_modal_error.close\": \"Luk\",\n  \"bundle_modal_error.message\": \"Noget gik galt under indlæsningen af dette komponent.\",\n  \"bundle_modal_error.retry\": \"Prøv igen\",\n  \"column.blocks\": \"Blokerede brugere\",\n  \"column.community\": \"Lokal tidslinje\",\n  \"column.direct\": \"Direkte beskeder\",\n  \"column.domain_blocks\": \"Skjulte domæner\",\n  \"column.favourites\": \"Favoritter\",\n  \"column.follow_requests\": \"Anmodning om at følge\",\n  \"column.home\": \"Hjem\",\n  \"column.lists\": \"Lister\",\n  \"column.mutes\": \"Dæmpede brugere\",\n  \"column.notifications\": \"Notifikationer\",\n  \"column.pins\": \"Fastgjorte trut\",\n  \"column.public\": \"Fælles tidslinje\",\n  \"column_back_button.label\": \"Tilbage\",\n  \"column_header.hide_settings\": \"Skjul indstillinger\",\n  \"column_header.moveLeft_settings\": \"Flyt kolonne til venstre\",\n  \"column_header.moveRight_settings\": \"Flyt kolonne til højre\",\n  \"column_header.pin\": \"Fastgør\",\n  \"column_header.show_settings\": \"Vis indstillinger\",\n  \"column_header.unpin\": \"Fastgør ikke længere\",\n  \"column_subheading.settings\": \"Indstillinger\",\n  \"community.column_settings.media_only\": \"Kun medie\",\n  \"compose_form.direct_message_warning\": \"Dette trut vil kun blive sendt til de nævnte brugere.\",\n  \"compose_form.direct_message_warning_learn_more\": \"Lær mere\",\n  \"compose_form.hashtag_warning\": \"Dette trut vil ikke blive vist under noget hashtag da det ikke er listet. Kun offentlige trut kan blive vist under søgninger med hashtags.\",\n  \"compose_form.lock_disclaimer\": \"Din konto er ikke {locked}. Alle kan følge dig for at se dine følger-kun indlæg.\",\n  \"compose_form.lock_disclaimer.lock\": \"låst\",\n  \"compose_form.placeholder\": \"Hvad har du på hjertet?\",\n  \"compose_form.poll.add_option\": \"Add a choice\",\n  \"compose_form.poll.duration\": \"Poll duration\",\n  \"compose_form.poll.option_placeholder\": \"Choice {number}\",\n  \"compose_form.poll.remove_option\": \"Remove this choice\",\n  \"compose_form.publish\": \"Trut\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"Mark media as sensitive\",\n  \"compose_form.sensitive.marked\": \"Medie er markeret som værende følsomt\",\n  \"compose_form.sensitive.unmarked\": \"Mediet er ikke markeret som værende følsomt\",\n  \"compose_form.spoiler.marked\": \"Teksten er skjult bag en advarsel\",\n  \"compose_form.spoiler.unmarked\": \"Teksten er ikke skjult\",\n  \"compose_form.spoiler_placeholder\": \"Skriv din advarsel her\",\n  \"confirmation_modal.cancel\": \"Annuller\",\n  \"confirmations.block.block_and_report\": \"Block & Report\",\n  \"confirmations.block.confirm\": \"Bloker\",\n  \"confirmations.block.message\": \"Er du sikker på, du vil blokere {name}?\",\n  \"confirmations.delete.confirm\": \"Slet\",\n  \"confirmations.delete.message\": \"Er du sikker på, du vil slette denne status?\",\n  \"confirmations.delete_list.confirm\": \"Slet\",\n  \"confirmations.delete_list.message\": \"Er du sikker på, du vil slette denne liste?\",\n  \"confirmations.domain_block.confirm\": \"Skjul helt domæne\",\n  \"confirmations.domain_block.message\": \"Er du helt sikker på du vil blokere hele {domain} domænet? I de fleste tilfælde vil få specifikke blokeringer eller dæmpninger være nok og at fortrække. Du vil ikke se indhold fra det domæne hverken på offentlige tidslinjer eller i dine notifikationer. Dine følgere fra det domæne vil blive fjernet.\",\n  \"confirmations.mute.confirm\": \"Dæmp\",\n  \"confirmations.mute.message\": \"Er du sikker på, du vil dæmpe {name}?\",\n  \"confirmations.redraft.confirm\": \"Slet & omskriv\",\n  \"confirmations.redraft.message\": \"Er du sikker på, du vil slette denne status og omskrive den? Favoritter og fremhævelser vil gå tabt og svar til det oprindelige opslag vil blive forældreløse.\",\n  \"confirmations.reply.confirm\": \"Svar\",\n  \"confirmations.reply.message\": \"Hvis du svarer nu vil du overskrive den besked du er ved at skrive. Er du sikker på, du vil fortsætte?\",\n  \"confirmations.unfollow.confirm\": \"Følg ikke længere\",\n  \"confirmations.unfollow.message\": \"Er du sikker på, du ikke længere vil følge {name}?\",\n  \"embed.instructions\": \"Indlejre denne status på din side ved at kopiere nedenstående kode.\",\n  \"embed.preview\": \"Det kommer til at se således ud:\",\n  \"emoji_button.activity\": \"Aktivitet\",\n  \"emoji_button.custom\": \"Bruger defineret\",\n  \"emoji_button.flags\": \"Flag\",\n  \"emoji_button.food\": \"Mad og drikke\",\n  \"emoji_button.label\": \"Indsæt humørikon\",\n  \"emoji_button.nature\": \"Natur\",\n  \"emoji_button.not_found\": \"Ingen emojos!! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"Objekter\",\n  \"emoji_button.people\": \"Mennesker\",\n  \"emoji_button.recent\": \"Oftest brugt\",\n  \"emoji_button.search\": \"Søg...\",\n  \"emoji_button.search_results\": \"Søgeresultater\",\n  \"emoji_button.symbols\": \"Symboler\",\n  \"emoji_button.travel\": \"Rejser & steder\",\n  \"empty_column.account_timeline\": \"Ingen bidrag her!\",\n  \"empty_column.account_unavailable\": \"Profile unavailable\",\n  \"empty_column.blocks\": \"Du har ikke blokeret nogen endnu.\",\n  \"empty_column.community\": \"Den lokale tidslinje er tom. Skriv noget offentligt for at starte lavinen!\",\n  \"empty_column.direct\": \"Du har endnu ingen direkte beskeder. Når du sender eller modtager en, vil den vises her.\",\n  \"empty_column.domain_blocks\": \"Der er endnu ikke nogle skjulte domæner.\",\n  \"empty_column.favourited_statuses\": \"Du har endnu ikke favoriseret nogen trut. Når du favoriserer et, vil det blive vist her.\",\n  \"empty_column.favourites\": \"Endnu ingen har favoriseret dette trut. Når en anden gør vil det blive vist her.\",\n  \"empty_column.follow_requests\": \"Du har endnu ingen følgeranmodninger. Når du modtager en, vil den komme frem her.\",\n  \"empty_column.hashtag\": \"Dette hashtag indeholder endnu ikke noget.\",\n  \"empty_column.home\": \"Din hjemme tidslinje er tom! Besøg {public} eller brug søgningen for at komme igang og møde andre brugere.\",\n  \"empty_column.home.public_timeline\": \"den offentlige tidslinje\",\n  \"empty_column.list\": \"Der er endnu intet i denne liste. Når medlemmer af denne liste poster nye statusser, vil de vises her.\",\n  \"empty_column.lists\": \"Du har endnu ingen lister. Når du opretter en, vil den blive vist her.\",\n  \"empty_column.mutes\": \"Du har endnu ikke dæmpet nogen som helst bruger.\",\n  \"empty_column.notifications\": \"Du har endnu ingen notifikationer. Tag ud og bland dig med folkemængden for at starte samtalen.\",\n  \"empty_column.public\": \"Der er ikke noget at se her! Skriv noget offentligt eller start ud med manuelt at følge brugere fra andre server for at udfylde tomrummet\",\n  \"follow_request.authorize\": \"Godkend\",\n  \"follow_request.reject\": \"Afvis\",\n  \"getting_started.developers\": \"Udviklere\",\n  \"getting_started.directory\": \"Profile directory\",\n  \"getting_started.documentation\": \"Dokumentation\",\n  \"getting_started.heading\": \"Kom igang\",\n  \"getting_started.invite\": \"Inviter folk\",\n  \"getting_started.open_source_notice\": \"Mastodon er et open source software. Du kan bidrage eller rapporterer fejl på GitHub {github}.\",\n  \"getting_started.security\": \"Sikkerhed\",\n  \"getting_started.terms\": \"Vilkår\",\n  \"hashtag.column_header.tag_mode.all\": \"og {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"eller {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"uden {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"No suggestions found\",\n  \"hashtag.column_settings.select.placeholder\": \"Enter hashtags…\",\n  \"hashtag.column_settings.tag_mode.all\": \"All of these\",\n  \"hashtag.column_settings.tag_mode.any\": \"Any of these\",\n  \"hashtag.column_settings.tag_mode.none\": \"None of these\",\n  \"hashtag.column_settings.tag_toggle\": \"Include additional tags in this column\",\n  \"home.column_settings.basic\": \"Grundlæggende\",\n  \"home.column_settings.show_reblogs\": \"Vis fremhævelser\",\n  \"home.column_settings.show_replies\": \"Vis svar\",\n  \"intervals.full.days\": \"{number, plural, one {# day} other {# days}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# hour} other {# hours}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minute} other {# minutes}}\",\n  \"introduction.federation.action\": \"Næste\",\n  \"introduction.federation.federated.headline\": \"Federated\",\n  \"introduction.federation.federated.text\": \"Offentlige bidrag fra andre servere af fediversen vil komme til syne i den federated timeline.\",\n  \"introduction.federation.home.headline\": \"Home\",\n  \"introduction.federation.home.text\": \"Posts from people you follow will appear in your home feed. You can follow anyone on any server!\",\n  \"introduction.federation.local.headline\": \"Local\",\n  \"introduction.federation.local.text\": \"Public posts from people on the same server as you will appear in the local timeline.\",\n  \"introduction.interactions.action\": \"Slut tutorial!\",\n  \"introduction.interactions.favourite.headline\": \"Favorisere\",\n  \"introduction.interactions.favourite.text\": \"You can save a toot for later, and let the author know that you liked it, by favouriting it.\",\n  \"introduction.interactions.reblog.headline\": \"Boost\",\n  \"introduction.interactions.reblog.text\": \"You can share other people's toots with your followers by boosting them.\",\n  \"introduction.interactions.reply.headline\": \"Svar\",\n  \"introduction.interactions.reply.text\": \"Du kan svare andres og din egen bidrag, hvilke vil kæde dem sammen i en konversation.\",\n  \"introduction.welcome.action\": \"Læd os gå!\",\n  \"introduction.welcome.headline\": \"Første skridt\",\n  \"introduction.welcome.text\": \"Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.\",\n  \"keyboard_shortcuts.back\": \"for at navigere dig tilbage\",\n  \"keyboard_shortcuts.blocked\": \"for at åbne listen over blokerede brugere\",\n  \"keyboard_shortcuts.boost\": \"for at fremhæve\",\n  \"keyboard_shortcuts.column\": \"for at fokusere på en status i en af kolonnerne\",\n  \"keyboard_shortcuts.compose\": \"for at fokusere på skriveområdet\",\n  \"keyboard_shortcuts.description\": \"Beskrivelse\",\n  \"keyboard_shortcuts.direct\": \"for at åbne privat besked kolonnen\",\n  \"keyboard_shortcuts.down\": \"for at rykke ned ad listen\",\n  \"keyboard_shortcuts.enter\": \"for at åbne status\",\n  \"keyboard_shortcuts.favourite\": \"for at favorisere\",\n  \"keyboard_shortcuts.favourites\": \"for at åbne listen over favoritter\",\n  \"keyboard_shortcuts.federated\": \"for at åbne den forenede tidslinje\",\n  \"keyboard_shortcuts.heading\": \"Tastaturgenveje\",\n  \"keyboard_shortcuts.home\": \"for at åbne hjem tidslinjen\",\n  \"keyboard_shortcuts.hotkey\": \"Hurtigtast\",\n  \"keyboard_shortcuts.legend\": \"for at vise denne legende\",\n  \"keyboard_shortcuts.local\": \"for at åbne den lokale tidslinje\",\n  \"keyboard_shortcuts.mention\": \"for at nævne forfatteren\",\n  \"keyboard_shortcuts.muted\": \"for at åbne listen over dæmpede brugere\",\n  \"keyboard_shortcuts.my_profile\": \"for at åbne din profil\",\n  \"keyboard_shortcuts.notifications\": \"for at åbne notifikations kolonnen\",\n  \"keyboard_shortcuts.pinned\": \"for at åbne listen over fastgjorte trut\",\n  \"keyboard_shortcuts.profile\": \"til profil af åben forfatter\",\n  \"keyboard_shortcuts.reply\": \"for at svare\",\n  \"keyboard_shortcuts.requests\": \"for at åbne listen over følgeranmodninger\",\n  \"keyboard_shortcuts.search\": \"for at fokusere søgningen\",\n  \"keyboard_shortcuts.start\": \"for at åbne \\\"kom igen\\\" kolonnen\",\n  \"keyboard_shortcuts.toggle_hidden\": \"for at vise/skjule tekst bag CW\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"to show/hide media\",\n  \"keyboard_shortcuts.toot\": \"for at påbegynde et helt nyt trut\",\n  \"keyboard_shortcuts.unfocus\": \"for at fjerne fokus fra skriveområde/søgning\",\n  \"keyboard_shortcuts.up\": \"for at bevæge dig op ad listen\",\n  \"lightbox.close\": \"Luk\",\n  \"lightbox.next\": \"Næste\",\n  \"lightbox.previous\": \"Forrige\",\n  \"lightbox.view_context\": \"View context\",\n  \"lists.account.add\": \"Tilføj til liste\",\n  \"lists.account.remove\": \"Fjern fra liste\",\n  \"lists.delete\": \"Slet liste\",\n  \"lists.edit\": \"Rediger liste\",\n  \"lists.edit.submit\": \"Change title\",\n  \"lists.new.create\": \"Tilføj liste\",\n  \"lists.new.title_placeholder\": \"Ny liste titel\",\n  \"lists.search\": \"Søg iblandt folk du følger\",\n  \"lists.subheading\": \"Dine lister\",\n  \"loading_indicator.label\": \"Indlæser...\",\n  \"media_gallery.toggle_visible\": \"Ændre synlighed\",\n  \"missing_indicator.label\": \"Ikke fundet\",\n  \"missing_indicator.sublabel\": \"Denne ressource kunne ikke blive fundet\",\n  \"mute_modal.hide_notifications\": \"Skjul notifikationer fra denne bruger?\",\n  \"navigation_bar.apps\": \"Mobil apps\",\n  \"navigation_bar.blocks\": \"Blokerede brugere\",\n  \"navigation_bar.community_timeline\": \"Lokal tidslinje\",\n  \"navigation_bar.compose\": \"Skriv nyt trut\",\n  \"navigation_bar.direct\": \"Direkte beskeder\",\n  \"navigation_bar.discover\": \"Opdag\",\n  \"navigation_bar.domain_blocks\": \"Skjulte domæner\",\n  \"navigation_bar.edit_profile\": \"Rediger profil\",\n  \"navigation_bar.favourites\": \"Favoritter\",\n  \"navigation_bar.filters\": \"Dæmpede ord\",\n  \"navigation_bar.follow_requests\": \"Følgeanmodninger\",\n  \"navigation_bar.follows_and_followers\": \"Follows and followers\",\n  \"navigation_bar.info\": \"Om denne instans\",\n  \"navigation_bar.keyboard_shortcuts\": \"Hurtigtast\",\n  \"navigation_bar.lists\": \"Lister\",\n  \"navigation_bar.logout\": \"Logud\",\n  \"navigation_bar.mutes\": \"Dæmpede brugere\",\n  \"navigation_bar.personal\": \"Personligt\",\n  \"navigation_bar.pins\": \"Fastgjorte trut\",\n  \"navigation_bar.preferences\": \"Præferencer\",\n  \"navigation_bar.profile_directory\": \"Profile directory\",\n  \"navigation_bar.public_timeline\": \"Fælles tidslinje\",\n  \"navigation_bar.security\": \"Sikkerhed\",\n  \"notification.favourite\": \"{name} favoriserede din status\",\n  \"notification.follow\": \"{name} fulgte dig\",\n  \"notification.mention\": \"{name} nævnte dig\",\n  \"notification.poll\": \"A poll you have voted in has ended\",\n  \"notification.reblog\": \"{name} fremhævede din status\",\n  \"notifications.clear\": \"Ryd notifikationer\",\n  \"notifications.clear_confirmation\": \"Er du sikker på, du vil rydde alle dine notifikationer permanent?\",\n  \"notifications.column_settings.alert\": \"Skrivebords notifikationer\",\n  \"notifications.column_settings.favourite\": \"Favoritter:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Display all categories\",\n  \"notifications.column_settings.filter_bar.category\": \"Quick filter bar\",\n  \"notifications.column_settings.filter_bar.show\": \"Show\",\n  \"notifications.column_settings.follow\": \"Nye følgere:\",\n  \"notifications.column_settings.mention\": \"Omtale:\",\n  \"notifications.column_settings.poll\": \"Poll results:\",\n  \"notifications.column_settings.push\": \"Push notifikationer\",\n  \"notifications.column_settings.reblog\": \"Fremhævelser:\",\n  \"notifications.column_settings.show\": \"Vis i kolonne\",\n  \"notifications.column_settings.sound\": \"Afspil lyd\",\n  \"notifications.filter.all\": \"Alle\",\n  \"notifications.filter.boosts\": \"Boosts\",\n  \"notifications.filter.favourites\": \"Favoritter\",\n  \"notifications.filter.follows\": \"Følger\",\n  \"notifications.filter.mentions\": \"Mentions\",\n  \"notifications.filter.polls\": \"Poll results\",\n  \"notifications.group\": \"{count} notifikationer\",\n  \"poll.closed\": \"Closed\",\n  \"poll.refresh\": \"Refresh\",\n  \"poll.total_votes\": \"{count, plural, one {# vote} other {# votes}}\",\n  \"poll.vote\": \"Vote\",\n  \"poll_button.add_poll\": \"Add a poll\",\n  \"poll_button.remove_poll\": \"Remove poll\",\n  \"privacy.change\": \"Ændre status privatliv\",\n  \"privacy.direct.long\": \"Post til kun de nævnte brugere\",\n  \"privacy.direct.short\": \"Direkte\",\n  \"privacy.private.long\": \"Post kun til følgere\",\n  \"privacy.private.short\": \"Kun for følgere\",\n  \"privacy.public.long\": \"Post til offentlige tidslinjer\",\n  \"privacy.public.short\": \"Offentligt\",\n  \"privacy.unlisted.long\": \"Post ikke til offentlige tidslinjer\",\n  \"privacy.unlisted.short\": \"Ikke listet\",\n  \"regeneration_indicator.label\": \"Indlæser…\",\n  \"regeneration_indicator.sublabel\": \"Din startside er ved at blive forberedt!\",\n  \"relative_time.days\": \"{number}d\",\n  \"relative_time.hours\": \"{number}t\",\n  \"relative_time.just_now\": \"nu\",\n  \"relative_time.minutes\": \"{number}m\",\n  \"relative_time.seconds\": \"{number}s\",\n  \"reply_indicator.cancel\": \"Annuller\",\n  \"report.forward\": \"Videresend til {target}\",\n  \"report.forward_hint\": \"Kontoen er fra en anden server. Vil du også sende en anonym kopi af anmeldelsen dertil?\",\n  \"report.hint\": \"Anmeldelsen vil blive sendt til moderatorene af din instans. Du kan give en forklaring for hvorfor du anmelder denne konto nedenfor:\",\n  \"report.placeholder\": \"Yderligere kommentarer\",\n  \"report.submit\": \"Indsend\",\n  \"report.target\": \"Anmelder {target}\",\n  \"search.placeholder\": \"Søg\",\n  \"search_popout.search_format\": \"Avanceret søgeformat\",\n  \"search_popout.tips.full_text\": \"Simpel tekst returnerer statusser du har skrevet, favoriseret, fremhævet, eller er blevet nævnt i, lige så vel som matchende brugernavne, visningsnavne, og hashtags.\",\n  \"search_popout.tips.hashtag\": \"emnetag\",\n  \"search_popout.tips.status\": \"status\",\n  \"search_popout.tips.text\": \"Simpelt tekst returnerer passende visningsnavne, brugernavne og hashtags\",\n  \"search_popout.tips.user\": \"bruger\",\n  \"search_results.accounts\": \"Folk\",\n  \"search_results.hashtags\": \"Emnetags\",\n  \"search_results.statuses\": \"Trut\",\n  \"search_results.total\": \"{count, number} {count, plural, et {result} andre {results}}\",\n  \"status.admin_account\": \"Open moderation interface for @{name}\",\n  \"status.admin_status\": \"Open this status in the moderation interface\",\n  \"status.block\": \"Bloker @{name}\",\n  \"status.cancel_reblog_private\": \"Fremhæv ikke længere\",\n  \"status.cannot_reblog\": \"Denne post kan ikke fremhæves\",\n  \"status.copy\": \"Copy link to status\",\n  \"status.delete\": \"Slet\",\n  \"status.detailed_status\": \"Detaljeret visning af samtale\",\n  \"status.direct\": \"Send direkte besked til @{name}\",\n  \"status.embed\": \"Indlejre\",\n  \"status.favourite\": \"Favorit\",\n  \"status.filtered\": \"Filtreret\",\n  \"status.load_more\": \"Indlæs mere\",\n  \"status.media_hidden\": \"Medie skjult\",\n  \"status.mention\": \"Nævn @{name}\",\n  \"status.more\": \"Mere\",\n  \"status.mute\": \"Dæmp @{name}\",\n  \"status.mute_conversation\": \"Dæmp samtale\",\n  \"status.open\": \"Udvid denne status\",\n  \"status.pin\": \"Fastgør til profil\",\n  \"status.pinned\": \"Fastgjort trut\",\n  \"status.read_more\": \"Læs mere\",\n  \"status.reblog\": \"Fremhæv\",\n  \"status.reblog_private\": \"Fremhæv til oprindeligt publikum\",\n  \"status.reblogged_by\": \"{name} fremhævede\",\n  \"status.reblogs.empty\": \"Der er endnu ingen der har fremhævet dette trut. Når der er nogen der gør, vil det blive vist her.\",\n  \"status.redraft\": \"Slet og omskriv\",\n  \"status.reply\": \"Svar\",\n  \"status.replyAll\": \"Svar samtale\",\n  \"status.report\": \"Anmeld @{name}\",\n  \"status.sensitive_warning\": \"Følsomt indhold\",\n  \"status.share\": \"Del\",\n  \"status.show_less\": \"Vis mindre\",\n  \"status.show_less_all\": \"Vis mindre for alle\",\n  \"status.show_more\": \"Vis mere\",\n  \"status.show_more_all\": \"Vis mere for alle\",\n  \"status.show_thread\": \"Show thread\",\n  \"status.unmute_conversation\": \"Fjern dæmpningen fra samtale\",\n  \"status.unpin\": \"Fjern som fastgjort fra profil\",\n  \"suggestions.dismiss\": \"Dismiss suggestion\",\n  \"suggestions.header\": \"You might be interested in…\",\n  \"tabs_bar.federated_timeline\": \"Fælles\",\n  \"tabs_bar.home\": \"Hjem\",\n  \"tabs_bar.local_timeline\": \"Lokal\",\n  \"tabs_bar.notifications\": \"Notifikationer\",\n  \"tabs_bar.search\": \"Søg\",\n  \"time_remaining.days\": \"{number, plural, one {# day} other {# days}} left\",\n  \"time_remaining.hours\": \"{number, plural, one {# hour} other {# hours}} left\",\n  \"time_remaining.minutes\": \"{number, plural, one {# minute} other {# minutes}} left\",\n  \"time_remaining.moments\": \"Moments remaining\",\n  \"time_remaining.seconds\": \"{number, plural, one {# second} other {# seconds}} left\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {person} other {people}} snakker\",\n  \"ui.beforeunload\": \"Din kladde vil gå tabt hvis du forlader Mastodon.\",\n  \"upload_area.title\": \"Træk og slip for at uploade\",\n  \"upload_button.label\": \"Tilføj medie (JPEG, PNG, GIF, WebM, MP4, MOV)\",\n  \"upload_error.limit\": \"File upload limit exceeded.\",\n  \"upload_error.poll\": \"File upload not allowed with polls.\",\n  \"upload_form.description\": \"Beskriv for de svagtseende\",\n  \"upload_form.focus\": \"Beskær\",\n  \"upload_form.undo\": \"Slet\",\n  \"upload_progress.label\": \"Uploader...\",\n  \"video.close\": \"Luk video\",\n  \"video.exit_fullscreen\": \"Gå ud af fuldskærm\",\n  \"video.expand\": \"Udvid video\",\n  \"video.fullscreen\": \"Fuldskærm\",\n  \"video.hide\": \"Skjul video\",\n  \"video.mute\": \"Dæmp lyd\",\n  \"video.pause\": \"Sæt på pause\",\n  \"video.play\": \"Afspil\",\n  \"video.unmute\": \"Fjern dæmpningen af lyd\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/de.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Hinzufügen oder Entfernen von Listen\",\n  \"account.badges.bot\": \"Bot\",\n  \"account.block\": \"@{name} blockieren\",\n  \"account.block_domain\": \"Alles von {domain} verstecken\",\n  \"account.blocked\": \"Blockiert\",\n  \"account.direct\": \"Direktnachricht an @{name}\",\n  \"account.domain_blocked\": \"Domain versteckt\",\n  \"account.edit_profile\": \"Profil bearbeiten\",\n  \"account.endorse\": \"Auf Profil hervorheben\",\n  \"account.follow\": \"Folgen\",\n  \"account.followers\": \"Folger_innen\",\n  \"account.followers.empty\": \"Diesem Profil folgt noch niemand.\",\n  \"account.follows\": \"Folgt\",\n  \"account.follows.empty\": \"Dieses Profil folgt noch niemandem.\",\n  \"account.follows_you\": \"Folgt dir\",\n  \"account.hide_reblogs\": \"Geteilte Beiträge von @{name} verbergen\",\n  \"account.link_verified_on\": \"Besitz dieses Links wurde geprüft am {date}\",\n  \"account.locked_info\": \"Der Privatsphärenstatus dieses Accounts wurde auf gesperrt gesetzt. Die Person bestimmt manuell wer ihm/ihr folgen darf.\",\n  \"account.media\": \"Medien\",\n  \"account.mention\": \"@{name} erwähnen\",\n  \"account.moved_to\": \"{name} ist umgezogen auf:\",\n  \"account.mute\": \"@{name} stummschalten\",\n  \"account.mute_notifications\": \"Benachrichtigungen von @{name} verbergen\",\n  \"account.muted\": \"Stummgeschaltet\",\n  \"account.posts\": \"Beiträge\",\n  \"account.posts_with_replies\": \"Beiträge und Antworten\",\n  \"account.report\": \"@{name} melden\",\n  \"account.requested\": \"Warte auf Erlaubnis. Klicke zum Abbrechen\",\n  \"account.share\": \"Profil von @{name} teilen\",\n  \"account.show_reblogs\": \"Von @{name} geteilte Beiträge anzeigen\",\n  \"account.unblock\": \"@{name} entblocken\",\n  \"account.unblock_domain\": \"{domain} wieder anzeigen\",\n  \"account.unendorse\": \"Nicht auf Profil hervorheben\",\n  \"account.unfollow\": \"Entfolgen\",\n  \"account.unmute\": \"@{name} nicht mehr stummschalten\",\n  \"account.unmute_notifications\": \"Benachrichtigungen von @{name} einschalten\",\n  \"alert.unexpected.message\": \"Ein unerwarteter Fehler ist aufgetreten.\",\n  \"alert.unexpected.title\": \"Hoppla!\",\n  \"boost_modal.combo\": \"Drücke {combo}, um dieses Fenster zu überspringen\",\n  \"bundle_column_error.body\": \"Etwas ist beim Laden schiefgelaufen.\",\n  \"bundle_column_error.retry\": \"Erneut versuchen\",\n  \"bundle_column_error.title\": \"Netzwerkfehler\",\n  \"bundle_modal_error.close\": \"Schließen\",\n  \"bundle_modal_error.message\": \"Etwas ist beim Laden schiefgelaufen.\",\n  \"bundle_modal_error.retry\": \"Erneut versuchen\",\n  \"column.blocks\": \"Blockierte Profile\",\n  \"column.community\": \"Lokale Zeitleiste\",\n  \"column.direct\": \"Direktnachrichten\",\n  \"column.domain_blocks\": \"Versteckte Domains\",\n  \"column.favourites\": \"Favoriten\",\n  \"column.follow_requests\": \"Folgeanfragen\",\n  \"column.home\": \"Startseite\",\n  \"column.lists\": \"Listen\",\n  \"column.mutes\": \"Stummgeschaltete Profile\",\n  \"column.notifications\": \"Mitteilungen\",\n  \"column.pins\": \"Angeheftete Beiträge\",\n  \"column.public\": \"Föderierte Zeitleiste\",\n  \"column_back_button.label\": \"Zurück\",\n  \"column_header.hide_settings\": \"Einstellungen verbergen\",\n  \"column_header.moveLeft_settings\": \"Spalte nach links verschieben\",\n  \"column_header.moveRight_settings\": \"Spalte nach rechts verschieben\",\n  \"column_header.pin\": \"Anheften\",\n  \"column_header.show_settings\": \"Einstellungen anzeigen\",\n  \"column_header.unpin\": \"Lösen\",\n  \"column_subheading.settings\": \"Einstellungen\",\n  \"community.column_settings.media_only\": \"Nur Medien\",\n  \"compose_form.direct_message_warning\": \"Dieser Beitrag wird nur für die erwähnten Nutzer sichtbar sein.\",\n  \"compose_form.direct_message_warning_learn_more\": \"Mehr erfahren\",\n  \"compose_form.hashtag_warning\": \"Dieser Beitrag wird nicht durch Hashtags entdeckbar sein, weil er ungelistet ist. Nur öffentliche Beiträge tauchen in Hashtag-Zeitleisten auf.\",\n  \"compose_form.lock_disclaimer\": \"Dein Profil ist nicht {locked}. Wer dir folgen will, kann das jederzeit tun und dann auch deine privaten Beiträge sehen.\",\n  \"compose_form.lock_disclaimer.lock\": \"gesperrt\",\n  \"compose_form.placeholder\": \"Was gibt's Neues?\",\n  \"compose_form.poll.add_option\": \"Eine Wahl hinzufügen\",\n  \"compose_form.poll.duration\": \"Umfragedauer\",\n  \"compose_form.poll.option_placeholder\": \"Wahl {number}\",\n  \"compose_form.poll.remove_option\": \"Wahl entfernen\",\n  \"compose_form.publish\": \"Tröt\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"Medien als heikel markieren\",\n  \"compose_form.sensitive.marked\": \"Medien sind als heikel markiert\",\n  \"compose_form.sensitive.unmarked\": \"Medien sind nicht als heikel markiert\",\n  \"compose_form.spoiler.marked\": \"Text ist hinter einer Warnung versteckt\",\n  \"compose_form.spoiler.unmarked\": \"Text ist nicht versteckt\",\n  \"compose_form.spoiler_placeholder\": \"Inhaltswarnung\",\n  \"confirmation_modal.cancel\": \"Abbrechen\",\n  \"confirmations.block.block_and_report\": \"Blockieren und melden\",\n  \"confirmations.block.confirm\": \"Blockieren\",\n  \"confirmations.block.message\": \"Bist du dir sicher, dass du {name} blockieren möchtest?\",\n  \"confirmations.delete.confirm\": \"Löschen\",\n  \"confirmations.delete.message\": \"Bist du dir sicher, dass du diesen Beitrag löschen möchtest?\",\n  \"confirmations.delete_list.confirm\": \"Löschen\",\n  \"confirmations.delete_list.message\": \"Bist du dir sicher, dass du diese Liste permanent löschen möchtest?\",\n  \"confirmations.domain_block.confirm\": \"Die ganze Domain verbergen\",\n  \"confirmations.domain_block.message\": \"Bist du dir wirklich sicher, dass du die ganze Domain {domain} blockieren willst? In den meisten Fällen reichen ein paar gezielte Blockierungen oder Stummschaltungen aus. Nach der Blockierung wirst du nichts mehr von dieser Domain in öffentlichen Zeitleisten oder Benachrichtigungen sehen. Deine Folger_innen von dieser Domain werden auch entfernt.\",\n  \"confirmations.mute.confirm\": \"Stummschalten\",\n  \"confirmations.mute.message\": \"Bist du dir sicher, dass du {name} stummschalten möchtest?\",\n  \"confirmations.redraft.confirm\": \"Löschen und neu erstellen\",\n  \"confirmations.redraft.message\": \"Bist du dir sicher, dass du diesen Beitrag löschen und neu erstellen möchtest? Favorisierungen, geteilte Beiträge und Antworten werden verloren gehen.\",\n  \"confirmations.reply.confirm\": \"Antworten\",\n  \"confirmations.reply.message\": \"Wenn du jetzt antwortest wird es die gesamte Nachricht verwerfen, die du gerade schreibst. Möchtest du wirklich fortfahren?\",\n  \"confirmations.unfollow.confirm\": \"Entfolgen\",\n  \"confirmations.unfollow.message\": \"Bist du dir sicher, dass du {name} entfolgen möchtest?\",\n  \"embed.instructions\": \"Du kannst diesen Beitrag auf deiner Webseite einbetten, indem du den folgenden Code einfügst.\",\n  \"embed.preview\": \"So wird es aussehen:\",\n  \"emoji_button.activity\": \"Aktivitäten\",\n  \"emoji_button.custom\": \"Eigene\",\n  \"emoji_button.flags\": \"Flaggen\",\n  \"emoji_button.food\": \"Essen und Trinken\",\n  \"emoji_button.label\": \"Emoji einfügen\",\n  \"emoji_button.nature\": \"Natur\",\n  \"emoji_button.not_found\": \"Keine Emojis!! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"Gegenstände\",\n  \"emoji_button.people\": \"Personen\",\n  \"emoji_button.recent\": \"Häufig benutzt\",\n  \"emoji_button.search\": \"Suchen…\",\n  \"emoji_button.search_results\": \"Suchergebnisse\",\n  \"emoji_button.symbols\": \"Symbole\",\n  \"emoji_button.travel\": \"Reisen und Orte\",\n  \"empty_column.account_timeline\": \"Keine Beiträge!\",\n  \"empty_column.account_unavailable\": \"Konto nicht verfügbar\",\n  \"empty_column.blocks\": \"Du hast keine Profile blockiert.\",\n  \"empty_column.community\": \"Die lokale Zeitleiste ist leer. Schreibe einen öffentlichen Beitrag, um den Ball ins Rollen zu bringen!\",\n  \"empty_column.direct\": \"Du hast noch keine Direktnachrichten erhalten. Wenn du eine sendest oder empfängst, wird sie hier zu sehen sein.\",\n  \"empty_column.domain_blocks\": \"Es ist noch keine versteckten Domains.\",\n  \"empty_column.favourited_statuses\": \"Du hast noch keine favorisierten Tröts. Wenn du einen favorisierst, wird er hier erscheinen.\",\n  \"empty_column.favourites\": \"Noch niemand hat diesen Beitrag favorisiert. Sobald es jemand tut, wird das hier angezeigt.\",\n  \"empty_column.follow_requests\": \"Du hast noch keine Folge-Anfragen. Sobald du eine erhältst, wird sie hier angezeigt.\",\n  \"empty_column.hashtag\": \"Unter diesem Hashtag gibt es noch nichts.\",\n  \"empty_column.home\": \"Deine Startseite ist leer! Besuche {public} oder nutze die Suche, um loszulegen und andere Leute zu finden.\",\n  \"empty_column.home.public_timeline\": \"die öffentliche Zeitleiste\",\n  \"empty_column.list\": \"Diese Liste ist derzeit leer. Wenn Wesen auf dieser Liste neue Beiträge veröffentlichen werden sie hier erscheinen.\",\n  \"empty_column.lists\": \"Du hast noch keine Listen. Wenn du eine anlegst, wird sie hier angezeigt.\",\n  \"empty_column.mutes\": \"Du hast keine Profile stummgeschaltet.\",\n  \"empty_column.notifications\": \"Du hast noch keine Mitteilungen. Interagiere mit anderen, um ins Gespräch zu kommen.\",\n  \"empty_column.public\": \"Hier ist nichts zu sehen! Schreibe etwas öffentlich oder folge Profilen von anderen Servern, um die Zeitleiste aufzufüllen\",\n  \"follow_request.authorize\": \"Erlauben\",\n  \"follow_request.reject\": \"Ablehnen\",\n  \"getting_started.developers\": \"Entwickler\",\n  \"getting_started.directory\": \"Profilverzeichnis\",\n  \"getting_started.documentation\": \"Dokumentation\",\n  \"getting_started.heading\": \"Erste Schritte\",\n  \"getting_started.invite\": \"Leute einladen\",\n  \"getting_started.open_source_notice\": \"Mastodon ist quelloffene Software. Du kannst auf GitHub unter {github} dazu beitragen oder Probleme melden.\",\n  \"getting_started.security\": \"Sicherheit\",\n  \"getting_started.terms\": \"Nutzungsbedingungen\",\n  \"hashtag.column_header.tag_mode.all\": \"und {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"oder {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"ohne {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"Keine Vorschläge gefunden\",\n  \"hashtag.column_settings.select.placeholder\": \"Hashtags eintragen…\",\n  \"hashtag.column_settings.tag_mode.all\": \"All diese\",\n  \"hashtag.column_settings.tag_mode.any\": \"Eins von diesen\",\n  \"hashtag.column_settings.tag_mode.none\": \"Keins von diesen\",\n  \"hashtag.column_settings.tag_toggle\": \"Zusätzliche Hashtags für diese Spalte einfügen\",\n  \"home.column_settings.basic\": \"Einfach\",\n  \"home.column_settings.show_reblogs\": \"Geteilte Beiträge anzeigen\",\n  \"home.column_settings.show_replies\": \"Antworten anzeigen\",\n  \"intervals.full.days\": \"{number, plural, one {# Tag} other {# Tage}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# Stunde} other {# Stunden}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# Minute} other {# Minuten}}\",\n  \"introduction.federation.action\": \"Weiter\",\n  \"introduction.federation.federated.headline\": \"Föderiert\",\n  \"introduction.federation.federated.text\": \"Öffentliche Beiträge von anderen Servern im Fediversum erscheinen in der föderierten Zeitleiste.\",\n  \"introduction.federation.home.headline\": \"Startseite\",\n  \"introduction.federation.home.text\": \"Beiträge von Leuten, denen du folgst, erscheinen auf deiner Startseite. Du kannst Menschen auf beliebigen Servern folgen!\",\n  \"introduction.federation.local.headline\": \"Lokal\",\n  \"introduction.federation.local.text\": \"Öffentliche Beiträge von Leuten auf demselben Server wie du erscheinen in der lokalen Zeitleiste.\",\n  \"introduction.interactions.action\": \"Tutorial beenden!\",\n  \"introduction.interactions.favourite.headline\": \"Favorisieren\",\n  \"introduction.interactions.favourite.text\": \"Du kannst Beitrage für später speichern und ihre Autor_innen wissen lassen, dass sie dir gefallen haben, indem du sie favorisierst.\",\n  \"introduction.interactions.reblog.headline\": \"Teilen\",\n  \"introduction.interactions.reblog.text\": \"Du kannst Beiträge anderer mit deinen Followern teilen, indem du sie teilst.\",\n  \"introduction.interactions.reply.headline\": \"Antworten\",\n  \"introduction.interactions.reply.text\": \"Du kannst auf die Beiträge anderer antworten. Diese Beiträge werden dann in einer Konversation zusammengefasst.\",\n  \"introduction.welcome.action\": \"Lass uns loslegen!\",\n  \"introduction.welcome.headline\": \"Erste Schritte\",\n  \"introduction.welcome.text\": \"Willkommen im Fediversum! In wenigen Momenten wirst du in der Lage sein Nachrichten zu versenden und mit deinen Freunden von anderen Servern in Kontakt zu treten. Aber dieser Server, {domain}, ist für dich sehr speziell — er hostet dein Profil, also merke dir die Domain.\",\n  \"keyboard_shortcuts.back\": \"zurück navigieren\",\n  \"keyboard_shortcuts.blocked\": \"Liste blockierter Profile öffnen\",\n  \"keyboard_shortcuts.boost\": \"teilen\",\n  \"keyboard_shortcuts.column\": \"einen Beitrag in einer der Spalten fokussieren\",\n  \"keyboard_shortcuts.compose\": \"fokussiere das Eingabefeld\",\n  \"keyboard_shortcuts.description\": \"Beschreibung\",\n  \"keyboard_shortcuts.direct\": \"Direct-Message-Spalte öffnen\",\n  \"keyboard_shortcuts.down\": \"sich in der Liste hinunter bewegen\",\n  \"keyboard_shortcuts.enter\": \"Beitrag öffnen\",\n  \"keyboard_shortcuts.favourite\": \"um zu favorisieren\",\n  \"keyboard_shortcuts.favourites\": \"Favoriten-Liste öffnen\",\n  \"keyboard_shortcuts.federated\": \"Föderierte Zeitleiste öffnen\",\n  \"keyboard_shortcuts.heading\": \"Tastenkombinationen\",\n  \"keyboard_shortcuts.home\": \"Startseite öffnen\",\n  \"keyboard_shortcuts.hotkey\": \"Tastenkürzel\",\n  \"keyboard_shortcuts.legend\": \"diese Übersicht anzeigen\",\n  \"keyboard_shortcuts.local\": \"Lokale Zeitleiste öffnen\",\n  \"keyboard_shortcuts.mention\": \"um Autor_in zu erwähnen\",\n  \"keyboard_shortcuts.muted\": \"Liste stummgeschalteter Profile öffnen\",\n  \"keyboard_shortcuts.my_profile\": \"Dein Profil öffnen\",\n  \"keyboard_shortcuts.notifications\": \"Benachrichtigungsspalte öffnen\",\n  \"keyboard_shortcuts.pinned\": \"Liste angehefteter Beiträge öffnen\",\n  \"keyboard_shortcuts.profile\": \"Profil des Autors öffnen\",\n  \"keyboard_shortcuts.reply\": \"antworten\",\n  \"keyboard_shortcuts.requests\": \"Liste der Folge-Anfragen öffnen\",\n  \"keyboard_shortcuts.search\": \"Suche fokussieren\",\n  \"keyboard_shortcuts.start\": \"\\\"Erste Schritte\\\"-Spalte öffnen\",\n  \"keyboard_shortcuts.toggle_hidden\": \"Text hinter einer Inhaltswarnung verstecken/anzeigen\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"Medien hinter einer Inhaltswarnung verstecken/anzeigen\",\n  \"keyboard_shortcuts.toot\": \"einen neuen Beitrag beginnen\",\n  \"keyboard_shortcuts.unfocus\": \"Textfeld/die Suche nicht mehr fokussieren\",\n  \"keyboard_shortcuts.up\": \"sich in der Liste hinauf bewegen\",\n  \"lightbox.close\": \"Schließen\",\n  \"lightbox.next\": \"Weiter\",\n  \"lightbox.previous\": \"Zurück\",\n  \"lightbox.view_context\": \"Beitrag sehen\",\n  \"lists.account.add\": \"Zur Liste hinzufügen\",\n  \"lists.account.remove\": \"Von der Liste entfernen\",\n  \"lists.delete\": \"Liste löschen\",\n  \"lists.edit\": \"Liste bearbeiten\",\n  \"lists.edit.submit\": \"Titel ändern\",\n  \"lists.new.create\": \"Liste hinzufügen\",\n  \"lists.new.title_placeholder\": \"Neuer Titel der Liste\",\n  \"lists.search\": \"Suche nach Leuten denen du folgst\",\n  \"lists.subheading\": \"Deine Listen\",\n  \"loading_indicator.label\": \"Wird geladen …\",\n  \"media_gallery.toggle_visible\": \"Sichtbarkeit umschalten\",\n  \"missing_indicator.label\": \"Nicht gefunden\",\n  \"missing_indicator.sublabel\": \"Die Ressource konnte nicht gefunden werden\",\n  \"mute_modal.hide_notifications\": \"Benachrichtigungen von diesem Account verbergen?\",\n  \"navigation_bar.apps\": \"Mobile Apps\",\n  \"navigation_bar.blocks\": \"Blockierte Profile\",\n  \"navigation_bar.community_timeline\": \"Lokale Zeitleiste\",\n  \"navigation_bar.compose\": \"Neuen Beitrag verfassen\",\n  \"navigation_bar.direct\": \"Direktnachrichten\",\n  \"navigation_bar.discover\": \"Entdecken\",\n  \"navigation_bar.domain_blocks\": \"Versteckte Domains\",\n  \"navigation_bar.edit_profile\": \"Profil bearbeiten\",\n  \"navigation_bar.favourites\": \"Favoriten\",\n  \"navigation_bar.filters\": \"Stummgeschaltene Wörter\",\n  \"navigation_bar.follow_requests\": \"Folgeanfragen\",\n  \"navigation_bar.follows_and_followers\": \"Folger_innen und Gefolgte\",\n  \"navigation_bar.info\": \"Über diesen Server\",\n  \"navigation_bar.keyboard_shortcuts\": \"Tastenkombinationen\",\n  \"navigation_bar.lists\": \"Listen\",\n  \"navigation_bar.logout\": \"Abmelden\",\n  \"navigation_bar.mutes\": \"Stummgeschaltete Profile\",\n  \"navigation_bar.personal\": \"Persönlich\",\n  \"navigation_bar.pins\": \"Angeheftete Beiträge\",\n  \"navigation_bar.preferences\": \"Einstellungen\",\n  \"navigation_bar.profile_directory\": \"Profilverzeichnis\",\n  \"navigation_bar.public_timeline\": \"Föderierte Zeitleiste\",\n  \"navigation_bar.security\": \"Sicherheit\",\n  \"notification.favourite\": \"{name} hat deinen Beitrag favorisiert\",\n  \"notification.follow\": \"{name} folgt dir\",\n  \"notification.mention\": \"{name} hat dich erwähnt\",\n  \"notification.poll\": \"Eine Umfrage in der du abgestimmt hast ist vorbei\",\n  \"notification.reblog\": \"{name} hat deinen Beitrag geteilt\",\n  \"notifications.clear\": \"Mitteilungen löschen\",\n  \"notifications.clear_confirmation\": \"Bist du dir sicher, dass du alle Mitteilungen löschen möchtest?\",\n  \"notifications.column_settings.alert\": \"Desktop-Benachrichtigungen\",\n  \"notifications.column_settings.favourite\": \"Favorisierungen:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Zeige alle Kategorien an\",\n  \"notifications.column_settings.filter_bar.category\": \"Schnellfilterleiste\",\n  \"notifications.column_settings.filter_bar.show\": \"Anzeigen\",\n  \"notifications.column_settings.follow\": \"Neue Folger_innen:\",\n  \"notifications.column_settings.mention\": \"Erwähnungen:\",\n  \"notifications.column_settings.poll\": \"Ergebnisse von Umfragen:\",\n  \"notifications.column_settings.push\": \"Push-Benachrichtigungen\",\n  \"notifications.column_settings.reblog\": \"Geteilte Beiträge:\",\n  \"notifications.column_settings.show\": \"In der Spalte anzeigen\",\n  \"notifications.column_settings.sound\": \"Ton abspielen\",\n  \"notifications.filter.all\": \"Alle\",\n  \"notifications.filter.boosts\": \"Geteilte Beiträge\",\n  \"notifications.filter.favourites\": \"Favorisierungen\",\n  \"notifications.filter.follows\": \"Folger_innen\",\n  \"notifications.filter.mentions\": \"Erwähnungen\",\n  \"notifications.filter.polls\": \"Ergebnisse der Umfrage\",\n  \"notifications.group\": \"{count} Benachrichtigungen\",\n  \"poll.closed\": \"Geschlossen\",\n  \"poll.refresh\": \"Aktualisieren\",\n  \"poll.total_votes\": \"{count, plural, one {# Stimme} other {# Stimmen}}\",\n  \"poll.vote\": \"Abstimmen\",\n  \"poll_button.add_poll\": \"Eine Umfrage erstellen\",\n  \"poll_button.remove_poll\": \"Umfrage entfernen\",\n  \"privacy.change\": \"Sichtbarkeit des Beitrags anpassen\",\n  \"privacy.direct.long\": \"Wird an erwähnte Profile gesendet\",\n  \"privacy.direct.short\": \"Direktnachricht\",\n  \"privacy.private.long\": \"Wird nur für deine Folger_innen sichtbar sein\",\n  \"privacy.private.short\": \"Nur für Folger_innen\",\n  \"privacy.public.long\": \"Wird in öffentlichen Zeitleisten erscheinen\",\n  \"privacy.public.short\": \"Öffentlich\",\n  \"privacy.unlisted.long\": \"Wird in öffentlichen Zeitleisten nicht gezeigt\",\n  \"privacy.unlisted.short\": \"Nicht gelistet\",\n  \"regeneration_indicator.label\": \"Laden…\",\n  \"regeneration_indicator.sublabel\": \"Deine Startseite wird gerade vorbereitet!\",\n  \"relative_time.days\": \"{number}d\",\n  \"relative_time.hours\": \"{number}h\",\n  \"relative_time.just_now\": \"jetzt\",\n  \"relative_time.minutes\": \"{number}m\",\n  \"relative_time.seconds\": \"{number}s\",\n  \"reply_indicator.cancel\": \"Abbrechen\",\n  \"report.forward\": \"An {target} weiterleiten\",\n  \"report.forward_hint\": \"Dieses Konto ist von einem anderen Server. Soll eine anonymisierte Kopie des Berichts auch dorthin geschickt werden?\",\n  \"report.hint\": \"Der Bericht wird an die Moderatoren des Servers geschickt. Du kannst hier eine Erklärung angeben, warum du dieses Konto meldest:\",\n  \"report.placeholder\": \"Zusätzliche Kommentare\",\n  \"report.submit\": \"Absenden\",\n  \"report.target\": \"{target} melden\",\n  \"search.placeholder\": \"Suche\",\n  \"search_popout.search_format\": \"Fortgeschrittenes Suchformat\",\n  \"search_popout.tips.full_text\": \"Einfache Texteingabe gibt Beiträge, die du geschrieben, favorisiert und geteilt hast zurück. Außerdem auch Beiträge in denen du erwähnt wurdest, aber auch passende Nutzernamen, Anzeigenamen oder Hashtags.\",\n  \"search_popout.tips.hashtag\": \"Hashtag\",\n  \"search_popout.tips.status\": \"Beitrag\",\n  \"search_popout.tips.text\": \"Einfache Texteingabe gibt Anzeigenamen, Benutzernamen und Hashtags zurück\",\n  \"search_popout.tips.user\": \"Nutzer\",\n  \"search_results.accounts\": \"Personen\",\n  \"search_results.hashtags\": \"Hashtags\",\n  \"search_results.statuses\": \"Beiträge\",\n  \"search_results.total\": \"{count, number} {count, plural, one {Ergebnis} other {Ergebnisse}}\",\n  \"status.admin_account\": \"Öffne Moderationsoberfläche für @{name}\",\n  \"status.admin_status\": \"Öffne Beitrag in der Moderationsoberfläche\",\n  \"status.block\": \"Blockiere @{name}\",\n  \"status.cancel_reblog_private\": \"Nicht mehr teilen\",\n  \"status.cannot_reblog\": \"Dieser Beitrag kann nicht geteilt werden\",\n  \"status.copy\": \"Kopiere Link zum Beitrag\",\n  \"status.delete\": \"Löschen\",\n  \"status.detailed_status\": \"Detaillierte Ansicht der Konversation\",\n  \"status.direct\": \"Direktnachricht @{name}\",\n  \"status.embed\": \"Einbetten\",\n  \"status.favourite\": \"Favorisieren\",\n  \"status.filtered\": \"Gefiltert\",\n  \"status.load_more\": \"Weitere laden\",\n  \"status.media_hidden\": \"Medien versteckt\",\n  \"status.mention\": \"@{name} erwähnen\",\n  \"status.more\": \"Mehr\",\n  \"status.mute\": \"@{name} stummschalten\",\n  \"status.mute_conversation\": \"Konversation stummschalten\",\n  \"status.open\": \"Diesen Beitrag öffnen\",\n  \"status.pin\": \"Im Profil anheften\",\n  \"status.pinned\": \"Angehefteter Beitrag\",\n  \"status.read_more\": \"Mehr lesen\",\n  \"status.reblog\": \"Teilen\",\n  \"status.reblog_private\": \"Mit der ursprünglichen Zielgruppe teilen\",\n  \"status.reblogged_by\": \"{name} teilte\",\n  \"status.reblogs.empty\": \"Diesen Beitrag hat noch niemand geteilt. Sobald es jemand tut, wird diese Person hier angezeigt.\",\n  \"status.redraft\": \"Löschen und neu erstellen\",\n  \"status.reply\": \"Antworten\",\n  \"status.replyAll\": \"Allen antworten\",\n  \"status.report\": \"@{name} melden\",\n  \"status.sensitive_warning\": \"Heikle Inhalte\",\n  \"status.share\": \"Teilen\",\n  \"status.show_less\": \"Weniger anzeigen\",\n  \"status.show_less_all\": \"Alle Inhaltswarnungen zuklappen\",\n  \"status.show_more\": \"Mehr anzeigen\",\n  \"status.show_more_all\": \"Alle Inhaltswarnungen aufklappen\",\n  \"status.show_thread\": \"Zeige Konversation\",\n  \"status.unmute_conversation\": \"Stummschaltung von Konversation aufheben\",\n  \"status.unpin\": \"Vom Profil lösen\",\n  \"suggestions.dismiss\": \"Empfehlung ausblenden\",\n  \"suggestions.header\": \"Du bist vielleicht interessiert an…\",\n  \"tabs_bar.federated_timeline\": \"Föderation\",\n  \"tabs_bar.home\": \"Startseite\",\n  \"tabs_bar.local_timeline\": \"Lokal\",\n  \"tabs_bar.notifications\": \"Mitteilungen\",\n  \"tabs_bar.search\": \"Suche\",\n  \"time_remaining.days\": \"{number, plural, one {# Tag} other {# Tage}} verbleibend\",\n  \"time_remaining.hours\": \"{number, plural, one {# Stunde} other {# Stunden}} verbleibend\",\n  \"time_remaining.minutes\": \"{number, plural, one {# Minute} other {# Minuten}} verbleibend\",\n  \"time_remaining.moments\": \"Schließt in Kürze\",\n  \"time_remaining.seconds\": \"{number, plural, one {# Sekunde} other {# Sekunden}} verbleibend\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, eine {Person} other {Personen}} reden darüber\",\n  \"ui.beforeunload\": \"Dein Entwurf geht verloren, wenn du Mastodon verlässt.\",\n  \"upload_area.title\": \"Zum Hochladen hereinziehen\",\n  \"upload_button.label\": \"Mediendatei hinzufügen (JPEG, PNG, GIF, WebM, MP4, MOV)\",\n  \"upload_error.limit\": \"Dateiupload-Limit erreicht.\",\n  \"upload_error.poll\": \"Dateiuploads sind in Kombination mit Umfragen nicht erlaubt.\",\n  \"upload_form.description\": \"Für Menschen mit Sehbehinderung beschreiben\",\n  \"upload_form.focus\": \"Vorschaubild bearbeiten\",\n  \"upload_form.undo\": \"Löschen\",\n  \"upload_progress.label\": \"Wird hochgeladen …\",\n  \"video.close\": \"Video schließen\",\n  \"video.exit_fullscreen\": \"Vollbild verlassen\",\n  \"video.expand\": \"Video vergrößern\",\n  \"video.fullscreen\": \"Vollbild\",\n  \"video.hide\": \"Video verbergen\",\n  \"video.mute\": \"Stummschalten\",\n  \"video.pause\": \"Pausieren\",\n  \"video.play\": \"Abspielen\",\n  \"video.unmute\": \"Ton einschalten\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/defaultMessages.json",
    "content": "[\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Oops!\",\n        \"id\": \"alert.unexpected.title\"\n      },\n      {\n        \"defaultMessage\": \"An unexpected error occurred.\",\n        \"id\": \"alert.unexpected.message\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/actions/alerts.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"File upload limit exceeded.\",\n        \"id\": \"upload_error.limit\"\n      },\n      {\n        \"defaultMessage\": \"File upload not allowed with polls.\",\n        \"id\": \"upload_error.poll\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/actions/compose.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"{name} mentioned you\",\n        \"id\": \"notification.mention\"\n      },\n      {\n        \"defaultMessage\": \"{count} notifications\",\n        \"id\": \"notifications.group\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/actions/notifications.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Follow\",\n        \"id\": \"account.follow\"\n      },\n      {\n        \"defaultMessage\": \"Unfollow\",\n        \"id\": \"account.unfollow\"\n      },\n      {\n        \"defaultMessage\": \"Awaiting approval\",\n        \"id\": \"account.requested\"\n      },\n      {\n        \"defaultMessage\": \"Unblock @{name}\",\n        \"id\": \"account.unblock\"\n      },\n      {\n        \"defaultMessage\": \"Unmute @{name}\",\n        \"id\": \"account.unmute\"\n      },\n      {\n        \"defaultMessage\": \"Mute notifications from @{name}\",\n        \"id\": \"account.mute_notifications\"\n      },\n      {\n        \"defaultMessage\": \"Unmute notifications from @{name}\",\n        \"id\": \"account.unmute_notifications\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/components/account.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Back\",\n        \"id\": \"column_back_button.label\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/components/column_back_button_slim.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Back\",\n        \"id\": \"column_back_button.label\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/components/column_back_button.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Show settings\",\n        \"id\": \"column_header.show_settings\"\n      },\n      {\n        \"defaultMessage\": \"Hide settings\",\n        \"id\": \"column_header.hide_settings\"\n      },\n      {\n        \"defaultMessage\": \"Move column to the left\",\n        \"id\": \"column_header.moveLeft_settings\"\n      },\n      {\n        \"defaultMessage\": \"Move column to the right\",\n        \"id\": \"column_header.moveRight_settings\"\n      },\n      {\n        \"defaultMessage\": \"Unpin\",\n        \"id\": \"column_header.unpin\"\n      },\n      {\n        \"defaultMessage\": \"Pin\",\n        \"id\": \"column_header.pin\"\n      },\n      {\n        \"defaultMessage\": \"Back\",\n        \"id\": \"column_back_button.label\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/components/column_header.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Unhide {domain}\",\n        \"id\": \"account.unblock_domain\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/components/domain.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"{count} {rawCount, plural, one {person} other {people}} talking\",\n        \"id\": \"trends.count_by_accounts\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/components/hashtag.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Load more\",\n        \"id\": \"status.load_more\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/components/load_gap.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Load more\",\n        \"id\": \"status.load_more\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/components/load_more.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Loading...\",\n        \"id\": \"loading_indicator.label\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/components/loading_indicator.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Toggle visibility\",\n        \"id\": \"media_gallery.toggle_visible\"\n      },\n      {\n        \"defaultMessage\": \"Sensitive content\",\n        \"id\": \"status.sensitive_warning\"\n      },\n      {\n        \"defaultMessage\": \"Media hidden\",\n        \"id\": \"status.media_hidden\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/components/media_gallery.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Not found\",\n        \"id\": \"missing_indicator.label\"\n      },\n      {\n        \"defaultMessage\": \"This resource could not be found\",\n        \"id\": \"missing_indicator.sublabel\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/components/missing_indicator.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Closed\",\n        \"id\": \"poll.closed\"\n      },\n      {\n        \"defaultMessage\": \"Vote\",\n        \"id\": \"poll.vote\"\n      },\n      {\n        \"defaultMessage\": \"Refresh\",\n        \"id\": \"poll.refresh\"\n      },\n      {\n        \"defaultMessage\": \"{count, plural, one {# vote} other {# votes}}\",\n        \"id\": \"poll.total_votes\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/components/poll.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"now\",\n        \"id\": \"relative_time.just_now\"\n      },\n      {\n        \"defaultMessage\": \"{number}s\",\n        \"id\": \"relative_time.seconds\"\n      },\n      {\n        \"defaultMessage\": \"{number}m\",\n        \"id\": \"relative_time.minutes\"\n      },\n      {\n        \"defaultMessage\": \"{number}h\",\n        \"id\": \"relative_time.hours\"\n      },\n      {\n        \"defaultMessage\": \"{number}d\",\n        \"id\": \"relative_time.days\"\n      },\n      {\n        \"defaultMessage\": \"Moments remaining\",\n        \"id\": \"time_remaining.moments\"\n      },\n      {\n        \"defaultMessage\": \"{number, plural, one {# second} other {# seconds}} left\",\n        \"id\": \"time_remaining.seconds\"\n      },\n      {\n        \"defaultMessage\": \"{number, plural, one {# minute} other {# minutes}} left\",\n        \"id\": \"time_remaining.minutes\"\n      },\n      {\n        \"defaultMessage\": \"{number, plural, one {# hour} other {# hours}} left\",\n        \"id\": \"time_remaining.hours\"\n      },\n      {\n        \"defaultMessage\": \"{number, plural, one {# day} other {# days}} left\",\n        \"id\": \"time_remaining.days\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/components/relative_timestamp.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Delete\",\n        \"id\": \"status.delete\"\n      },\n      {\n        \"defaultMessage\": \"Delete & re-draft\",\n        \"id\": \"status.redraft\"\n      },\n      {\n        \"defaultMessage\": \"Direct message @{name}\",\n        \"id\": \"status.direct\"\n      },\n      {\n        \"defaultMessage\": \"Mention @{name}\",\n        \"id\": \"status.mention\"\n      },\n      {\n        \"defaultMessage\": \"Mute @{name}\",\n        \"id\": \"account.mute\"\n      },\n      {\n        \"defaultMessage\": \"Block @{name}\",\n        \"id\": \"account.block\"\n      },\n      {\n        \"defaultMessage\": \"Reply\",\n        \"id\": \"status.reply\"\n      },\n      {\n        \"defaultMessage\": \"Share\",\n        \"id\": \"status.share\"\n      },\n      {\n        \"defaultMessage\": \"More\",\n        \"id\": \"status.more\"\n      },\n      {\n        \"defaultMessage\": \"Reply to thread\",\n        \"id\": \"status.replyAll\"\n      },\n      {\n        \"defaultMessage\": \"Boost\",\n        \"id\": \"status.reblog\"\n      },\n      {\n        \"defaultMessage\": \"Boost to original audience\",\n        \"id\": \"status.reblog_private\"\n      },\n      {\n        \"defaultMessage\": \"Unboost\",\n        \"id\": \"status.cancel_reblog_private\"\n      },\n      {\n        \"defaultMessage\": \"This post cannot be boosted\",\n        \"id\": \"status.cannot_reblog\"\n      },\n      {\n        \"defaultMessage\": \"Favourite\",\n        \"id\": \"status.favourite\"\n      },\n      {\n        \"defaultMessage\": \"Expand this status\",\n        \"id\": \"status.open\"\n      },\n      {\n        \"defaultMessage\": \"Report @{name}\",\n        \"id\": \"status.report\"\n      },\n      {\n        \"defaultMessage\": \"Mute conversation\",\n        \"id\": \"status.mute_conversation\"\n      },\n      {\n        \"defaultMessage\": \"Unmute conversation\",\n        \"id\": \"status.unmute_conversation\"\n      },\n      {\n        \"defaultMessage\": \"Pin on profile\",\n        \"id\": \"status.pin\"\n      },\n      {\n        \"defaultMessage\": \"Unpin from profile\",\n        \"id\": \"status.unpin\"\n      },\n      {\n        \"defaultMessage\": \"Embed\",\n        \"id\": \"status.embed\"\n      },\n      {\n        \"defaultMessage\": \"Open moderation interface for @{name}\",\n        \"id\": \"status.admin_account\"\n      },\n      {\n        \"defaultMessage\": \"Open this status in the moderation interface\",\n        \"id\": \"status.admin_status\"\n      },\n      {\n        \"defaultMessage\": \"Copy link to status\",\n        \"id\": \"status.copy\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/components/status_action_bar.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Read more\",\n        \"id\": \"status.read_more\"\n      },\n      {\n        \"defaultMessage\": \"Show more\",\n        \"id\": \"status.show_more\"\n      },\n      {\n        \"defaultMessage\": \"Show less\",\n        \"id\": \"status.show_less\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/components/status_content.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Loading…\",\n        \"id\": \"regeneration_indicator.label\"\n      },\n      {\n        \"defaultMessage\": \"Your home feed is being prepared!\",\n        \"id\": \"regeneration_indicator.sublabel\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/components/status_list.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Filtered\",\n        \"id\": \"status.filtered\"\n      },\n      {\n        \"defaultMessage\": \"Pinned toot\",\n        \"id\": \"status.pinned\"\n      },\n      {\n        \"defaultMessage\": \"{name} boosted\",\n        \"id\": \"status.reblogged_by\"\n      },\n      {\n        \"defaultMessage\": \"Show thread\",\n        \"id\": \"status.show_thread\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/components/status.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Unfollow\",\n        \"id\": \"confirmations.unfollow.confirm\"\n      },\n      {\n        \"defaultMessage\": \"Are you sure you want to unfollow {name}?\",\n        \"id\": \"confirmations.unfollow.message\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/containers/account_container.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Hide entire domain\",\n        \"id\": \"confirmations.domain_block.confirm\"\n      },\n      {\n        \"defaultMessage\": \"Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.\",\n        \"id\": \"confirmations.domain_block.message\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/containers/domain_container.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Delete\",\n        \"id\": \"confirmations.delete.confirm\"\n      },\n      {\n        \"defaultMessage\": \"Are you sure you want to delete this status?\",\n        \"id\": \"confirmations.delete.message\"\n      },\n      {\n        \"defaultMessage\": \"Delete & redraft\",\n        \"id\": \"confirmations.redraft.confirm\"\n      },\n      {\n        \"defaultMessage\": \"Are you sure you want to delete this status and re-draft it? Favourites and boosts will be lost, and replies to the original post will be orphaned.\",\n        \"id\": \"confirmations.redraft.message\"\n      },\n      {\n        \"defaultMessage\": \"Block\",\n        \"id\": \"confirmations.block.confirm\"\n      },\n      {\n        \"defaultMessage\": \"Reply\",\n        \"id\": \"confirmations.reply.confirm\"\n      },\n      {\n        \"defaultMessage\": \"Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?\",\n        \"id\": \"confirmations.reply.message\"\n      },\n      {\n        \"defaultMessage\": \"Block & Report\",\n        \"id\": \"confirmations.block.block_and_report\"\n      },\n      {\n        \"defaultMessage\": \"Are you sure you want to block {name}?\",\n        \"id\": \"confirmations.block.message\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/containers/status_container.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Toots\",\n        \"id\": \"account.posts\"\n      },\n      {\n        \"defaultMessage\": \"Toots and replies\",\n        \"id\": \"account.posts_with_replies\"\n      },\n      {\n        \"defaultMessage\": \"Media\",\n        \"id\": \"account.media\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/account_timeline/components/header.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"{name} has moved to:\",\n        \"id\": \"account.moved_to\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/account_timeline/components/moved_note.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Unfollow\",\n        \"id\": \"confirmations.unfollow.confirm\"\n      },\n      {\n        \"defaultMessage\": \"Block\",\n        \"id\": \"confirmations.block.confirm\"\n      },\n      {\n        \"defaultMessage\": \"Hide entire domain\",\n        \"id\": \"confirmations.domain_block.confirm\"\n      },\n      {\n        \"defaultMessage\": \"Block & Report\",\n        \"id\": \"confirmations.block.block_and_report\"\n      },\n      {\n        \"defaultMessage\": \"Are you sure you want to unfollow {name}?\",\n        \"id\": \"confirmations.unfollow.message\"\n      },\n      {\n        \"defaultMessage\": \"Are you sure you want to block {name}?\",\n        \"id\": \"confirmations.block.message\"\n      },\n      {\n        \"defaultMessage\": \"Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain in any public timelines or your notifications. Your followers from that domain will be removed.\",\n        \"id\": \"confirmations.domain_block.message\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/account_timeline/containers/header_container.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Profile unavailable\",\n        \"id\": \"empty_column.account_unavailable\"\n      },\n      {\n        \"defaultMessage\": \"No toots here!\",\n        \"id\": \"empty_column.account_timeline\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/account_timeline/index.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Unfollow\",\n        \"id\": \"account.unfollow\"\n      },\n      {\n        \"defaultMessage\": \"Follow\",\n        \"id\": \"account.follow\"\n      },\n      {\n        \"defaultMessage\": \"Awaiting approval. Click to cancel follow request\",\n        \"id\": \"account.requested\"\n      },\n      {\n        \"defaultMessage\": \"Unblock @{name}\",\n        \"id\": \"account.unblock\"\n      },\n      {\n        \"defaultMessage\": \"Edit profile\",\n        \"id\": \"account.edit_profile\"\n      },\n      {\n        \"defaultMessage\": \"Ownership of this link was checked on {date}\",\n        \"id\": \"account.link_verified_on\"\n      },\n      {\n        \"defaultMessage\": \"This account privacy status is set to locked. The owner manually reviews who can follow them.\",\n        \"id\": \"account.locked_info\"\n      },\n      {\n        \"defaultMessage\": \"Mention @{name}\",\n        \"id\": \"account.mention\"\n      },\n      {\n        \"defaultMessage\": \"Direct message @{name}\",\n        \"id\": \"account.direct\"\n      },\n      {\n        \"defaultMessage\": \"Unmute @{name}\",\n        \"id\": \"account.unmute\"\n      },\n      {\n        \"defaultMessage\": \"Block @{name}\",\n        \"id\": \"account.block\"\n      },\n      {\n        \"defaultMessage\": \"Mute @{name}\",\n        \"id\": \"account.mute\"\n      },\n      {\n        \"defaultMessage\": \"Report @{name}\",\n        \"id\": \"account.report\"\n      },\n      {\n        \"defaultMessage\": \"Share @{name}'s profile\",\n        \"id\": \"account.share\"\n      },\n      {\n        \"defaultMessage\": \"Media\",\n        \"id\": \"account.media\"\n      },\n      {\n        \"defaultMessage\": \"Hide everything from {domain}\",\n        \"id\": \"account.block_domain\"\n      },\n      {\n        \"defaultMessage\": \"Unhide {domain}\",\n        \"id\": \"account.unblock_domain\"\n      },\n      {\n        \"defaultMessage\": \"Hide boosts from @{name}\",\n        \"id\": \"account.hide_reblogs\"\n      },\n      {\n        \"defaultMessage\": \"Show boosts from @{name}\",\n        \"id\": \"account.show_reblogs\"\n      },\n      {\n        \"defaultMessage\": \"Pinned toots\",\n        \"id\": \"navigation_bar.pins\"\n      },\n      {\n        \"defaultMessage\": \"Preferences\",\n        \"id\": \"navigation_bar.preferences\"\n      },\n      {\n        \"defaultMessage\": \"Follow requests\",\n        \"id\": \"navigation_bar.follow_requests\"\n      },\n      {\n        \"defaultMessage\": \"Favourites\",\n        \"id\": \"navigation_bar.favourites\"\n      },\n      {\n        \"defaultMessage\": \"Lists\",\n        \"id\": \"navigation_bar.lists\"\n      },\n      {\n        \"defaultMessage\": \"Blocked users\",\n        \"id\": \"navigation_bar.blocks\"\n      },\n      {\n        \"defaultMessage\": \"Hidden domains\",\n        \"id\": \"navigation_bar.domain_blocks\"\n      },\n      {\n        \"defaultMessage\": \"Muted users\",\n        \"id\": \"navigation_bar.mutes\"\n      },\n      {\n        \"defaultMessage\": \"Feature on profile\",\n        \"id\": \"account.endorse\"\n      },\n      {\n        \"defaultMessage\": \"Don't feature on profile\",\n        \"id\": \"account.unendorse\"\n      },\n      {\n        \"defaultMessage\": \"Add or Remove from lists\",\n        \"id\": \"account.add_or_remove_from_list\"\n      },\n      {\n        \"defaultMessage\": \"Open moderation interface for @{name}\",\n        \"id\": \"status.admin_account\"\n      },\n      {\n        \"defaultMessage\": \"Follows you\",\n        \"id\": \"account.follows_you\"\n      },\n      {\n        \"defaultMessage\": \"Blocked\",\n        \"id\": \"account.blocked\"\n      },\n      {\n        \"defaultMessage\": \"Muted\",\n        \"id\": \"account.muted\"\n      },\n      {\n        \"defaultMessage\": \"Domain hidden\",\n        \"id\": \"account.domain_blocked\"\n      },\n      {\n        \"defaultMessage\": \"Bot\",\n        \"id\": \"account.badges.bot\"\n      },\n      {\n        \"defaultMessage\": \"Toots\",\n        \"id\": \"account.posts\"\n      },\n      {\n        \"defaultMessage\": \"Follows\",\n        \"id\": \"account.follows\"\n      },\n      {\n        \"defaultMessage\": \"Followers\",\n        \"id\": \"account.followers\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/account/components/header.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Blocked users\",\n        \"id\": \"column.blocks\"\n      },\n      {\n        \"defaultMessage\": \"You haven't blocked any users yet.\",\n        \"id\": \"empty_column.blocks\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/blocks/index.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Media Only\",\n        \"id\": \"community.column_settings.media_only\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/community_timeline/components/column_settings.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Local timeline\",\n        \"id\": \"column.community\"\n      },\n      {\n        \"defaultMessage\": \"The local timeline is empty. Write something publicly to get the ball rolling!\",\n        \"id\": \"empty_column.community\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/community_timeline/index.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Edit profile\",\n        \"id\": \"account.edit_profile\"\n      },\n      {\n        \"defaultMessage\": \"Pinned toots\",\n        \"id\": \"navigation_bar.pins\"\n      },\n      {\n        \"defaultMessage\": \"Preferences\",\n        \"id\": \"navigation_bar.preferences\"\n      },\n      {\n        \"defaultMessage\": \"Follow requests\",\n        \"id\": \"navigation_bar.follow_requests\"\n      },\n      {\n        \"defaultMessage\": \"Favourites\",\n        \"id\": \"navigation_bar.favourites\"\n      },\n      {\n        \"defaultMessage\": \"Lists\",\n        \"id\": \"navigation_bar.lists\"\n      },\n      {\n        \"defaultMessage\": \"Blocked users\",\n        \"id\": \"navigation_bar.blocks\"\n      },\n      {\n        \"defaultMessage\": \"Hidden domains\",\n        \"id\": \"navigation_bar.domain_blocks\"\n      },\n      {\n        \"defaultMessage\": \"Muted users\",\n        \"id\": \"navigation_bar.mutes\"\n      },\n      {\n        \"defaultMessage\": \"Muted words\",\n        \"id\": \"navigation_bar.filters\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/compose/components/action_bar.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"What is on your mind?\",\n        \"id\": \"compose_form.placeholder\"\n      },\n      {\n        \"defaultMessage\": \"Write your warning here\",\n        \"id\": \"compose_form.spoiler_placeholder\"\n      },\n      {\n        \"defaultMessage\": \"Toot\",\n        \"id\": \"compose_form.publish\"\n      },\n      {\n        \"defaultMessage\": \"{publish}!\",\n        \"id\": \"compose_form.publish_loud\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/compose/components/compose_form.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Insert emoji\",\n        \"id\": \"emoji_button.label\"\n      },\n      {\n        \"defaultMessage\": \"Search...\",\n        \"id\": \"emoji_button.search\"\n      },\n      {\n        \"defaultMessage\": \"No emojos!! (╯°□°）╯︵ ┻━┻\",\n        \"id\": \"emoji_button.not_found\"\n      },\n      {\n        \"defaultMessage\": \"Custom\",\n        \"id\": \"emoji_button.custom\"\n      },\n      {\n        \"defaultMessage\": \"Frequently used\",\n        \"id\": \"emoji_button.recent\"\n      },\n      {\n        \"defaultMessage\": \"Search results\",\n        \"id\": \"emoji_button.search_results\"\n      },\n      {\n        \"defaultMessage\": \"People\",\n        \"id\": \"emoji_button.people\"\n      },\n      {\n        \"defaultMessage\": \"Nature\",\n        \"id\": \"emoji_button.nature\"\n      },\n      {\n        \"defaultMessage\": \"Food & Drink\",\n        \"id\": \"emoji_button.food\"\n      },\n      {\n        \"defaultMessage\": \"Activity\",\n        \"id\": \"emoji_button.activity\"\n      },\n      {\n        \"defaultMessage\": \"Travel & Places\",\n        \"id\": \"emoji_button.travel\"\n      },\n      {\n        \"defaultMessage\": \"Objects\",\n        \"id\": \"emoji_button.objects\"\n      },\n      {\n        \"defaultMessage\": \"Symbols\",\n        \"id\": \"emoji_button.symbols\"\n      },\n      {\n        \"defaultMessage\": \"Flags\",\n        \"id\": \"emoji_button.flags\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Edit profile\",\n        \"id\": \"navigation_bar.edit_profile\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/compose/components/navigation_bar.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Add a poll\",\n        \"id\": \"poll_button.add_poll\"\n      },\n      {\n        \"defaultMessage\": \"Remove poll\",\n        \"id\": \"poll_button.remove_poll\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/compose/components/poll_button.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Choice {number}\",\n        \"id\": \"compose_form.poll.option_placeholder\"\n      },\n      {\n        \"defaultMessage\": \"Add a choice\",\n        \"id\": \"compose_form.poll.add_option\"\n      },\n      {\n        \"defaultMessage\": \"Remove this choice\",\n        \"id\": \"compose_form.poll.remove_option\"\n      },\n      {\n        \"defaultMessage\": \"Poll duration\",\n        \"id\": \"compose_form.poll.duration\"\n      },\n      {\n        \"defaultMessage\": \"{number, plural, one {# minute} other {# minutes}}\",\n        \"id\": \"intervals.full.minutes\"\n      },\n      {\n        \"defaultMessage\": \"{number, plural, one {# hour} other {# hours}}\",\n        \"id\": \"intervals.full.hours\"\n      },\n      {\n        \"defaultMessage\": \"{number, plural, one {# day} other {# days}}\",\n        \"id\": \"intervals.full.days\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/compose/components/poll_form.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Public\",\n        \"id\": \"privacy.public.short\"\n      },\n      {\n        \"defaultMessage\": \"Post to public timelines\",\n        \"id\": \"privacy.public.long\"\n      },\n      {\n        \"defaultMessage\": \"Unlisted\",\n        \"id\": \"privacy.unlisted.short\"\n      },\n      {\n        \"defaultMessage\": \"Do not show in public timelines\",\n        \"id\": \"privacy.unlisted.long\"\n      },\n      {\n        \"defaultMessage\": \"Followers-only\",\n        \"id\": \"privacy.private.short\"\n      },\n      {\n        \"defaultMessage\": \"Post to followers only\",\n        \"id\": \"privacy.private.long\"\n      },\n      {\n        \"defaultMessage\": \"Direct\",\n        \"id\": \"privacy.direct.short\"\n      },\n      {\n        \"defaultMessage\": \"Post to mentioned users only\",\n        \"id\": \"privacy.direct.long\"\n      },\n      {\n        \"defaultMessage\": \"Adjust status privacy\",\n        \"id\": \"privacy.change\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/compose/components/privacy_dropdown.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Cancel\",\n        \"id\": \"reply_indicator.cancel\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/compose/components/reply_indicator.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Dismiss suggestion\",\n        \"id\": \"suggestions.dismiss\"\n      },\n      {\n        \"defaultMessage\": \"You might be interested in…\",\n        \"id\": \"suggestions.header\"\n      },\n      {\n        \"defaultMessage\": \"People\",\n        \"id\": \"search_results.accounts\"\n      },\n      {\n        \"defaultMessage\": \"Toots\",\n        \"id\": \"search_results.statuses\"\n      },\n      {\n        \"defaultMessage\": \"Hashtags\",\n        \"id\": \"search_results.hashtags\"\n      },\n      {\n        \"defaultMessage\": \"{count, number} {count, plural, one {result} other {results}}\",\n        \"id\": \"search_results.total\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/compose/components/search_results.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Search\",\n        \"id\": \"search.placeholder\"\n      },\n      {\n        \"defaultMessage\": \"Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.\",\n        \"id\": \"search_popout.tips.full_text\"\n      },\n      {\n        \"defaultMessage\": \"Simple text returns matching display names, usernames and hashtags\",\n        \"id\": \"search_popout.tips.text\"\n      },\n      {\n        \"defaultMessage\": \"Advanced search format\",\n        \"id\": \"search_popout.search_format\"\n      },\n      {\n        \"defaultMessage\": \"hashtag\",\n        \"id\": \"search_popout.tips.hashtag\"\n      },\n      {\n        \"defaultMessage\": \"user\",\n        \"id\": \"search_popout.tips.user\"\n      },\n      {\n        \"defaultMessage\": \"status\",\n        \"id\": \"search_popout.tips.status\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/compose/components/search.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Add media (JPEG, PNG, GIF, WebM, MP4, MOV)\",\n        \"id\": \"upload_button.label\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/compose/components/upload_button.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Uploading...\",\n        \"id\": \"upload_progress.label\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/compose/components/upload_progress.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Describe for the visually impaired\",\n        \"id\": \"upload_form.description\"\n      },\n      {\n        \"defaultMessage\": \"Delete\",\n        \"id\": \"upload_form.undo\"\n      },\n      {\n        \"defaultMessage\": \"Crop\",\n        \"id\": \"upload_form.focus\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/compose/components/upload.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Media is marked as sensitive\",\n        \"id\": \"compose_form.sensitive.marked\"\n      },\n      {\n        \"defaultMessage\": \"Media is not marked as sensitive\",\n        \"id\": \"compose_form.sensitive.unmarked\"\n      },\n      {\n        \"defaultMessage\": \"Mark media as sensitive\",\n        \"id\": \"compose_form.sensitive.hide\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/compose/containers/sensitive_button_container.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Text is hidden behind warning\",\n        \"id\": \"compose_form.spoiler.marked\"\n      },\n      {\n        \"defaultMessage\": \"Text is not hidden\",\n        \"id\": \"compose_form.spoiler.unmarked\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/compose/containers/spoiler_button_container.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Your account is not {locked}. Anyone can follow you to view your follower-only posts.\",\n        \"id\": \"compose_form.lock_disclaimer\"\n      },\n      {\n        \"defaultMessage\": \"locked\",\n        \"id\": \"compose_form.lock_disclaimer.lock\"\n      },\n      {\n        \"defaultMessage\": \"This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.\",\n        \"id\": \"compose_form.hashtag_warning\"\n      },\n      {\n        \"defaultMessage\": \"This toot will only be sent to all the mentioned users.\",\n        \"id\": \"compose_form.direct_message_warning\"\n      },\n      {\n        \"defaultMessage\": \"Learn more\",\n        \"id\": \"compose_form.direct_message_warning_learn_more\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/compose/containers/warning_container.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Getting started\",\n        \"id\": \"getting_started.heading\"\n      },\n      {\n        \"defaultMessage\": \"Home\",\n        \"id\": \"tabs_bar.home\"\n      },\n      {\n        \"defaultMessage\": \"Notifications\",\n        \"id\": \"tabs_bar.notifications\"\n      },\n      {\n        \"defaultMessage\": \"Federated timeline\",\n        \"id\": \"navigation_bar.public_timeline\"\n      },\n      {\n        \"defaultMessage\": \"Local timeline\",\n        \"id\": \"navigation_bar.community_timeline\"\n      },\n      {\n        \"defaultMessage\": \"Preferences\",\n        \"id\": \"navigation_bar.preferences\"\n      },\n      {\n        \"defaultMessage\": \"Logout\",\n        \"id\": \"navigation_bar.logout\"\n      },\n      {\n        \"defaultMessage\": \"Compose new toot\",\n        \"id\": \"navigation_bar.compose\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/compose/index.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Direct messages\",\n        \"id\": \"column.direct\"\n      },\n      {\n        \"defaultMessage\": \"You don't have any direct messages yet. When you send or receive one, it will show up here.\",\n        \"id\": \"empty_column.direct\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/direct_timeline/index.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Hidden domains\",\n        \"id\": \"column.domain_blocks\"\n      },\n      {\n        \"defaultMessage\": \"Unhide {domain}\",\n        \"id\": \"account.unblock_domain\"\n      },\n      {\n        \"defaultMessage\": \"There are no hidden domains yet.\",\n        \"id\": \"empty_column.domain_blocks\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/domain_blocks/index.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Favourites\",\n        \"id\": \"column.favourites\"\n      },\n      {\n        \"defaultMessage\": \"You don't have any favourite toots yet. When you favourite one, it will show up here.\",\n        \"id\": \"empty_column.favourited_statuses\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/favourited_statuses/index.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"No one has favourited this toot yet. When someone does, they will show up here.\",\n        \"id\": \"empty_column.favourites\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/favourites/index.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Authorize\",\n        \"id\": \"follow_request.authorize\"\n      },\n      {\n        \"defaultMessage\": \"Reject\",\n        \"id\": \"follow_request.reject\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/follow_requests/components/account_authorize.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Follow requests\",\n        \"id\": \"column.follow_requests\"\n      },\n      {\n        \"defaultMessage\": \"You don't have any follow requests yet. When you receive one, it will show up here.\",\n        \"id\": \"empty_column.follow_requests\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/follow_requests/index.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Profile unavailable\",\n        \"id\": \"empty_column.account_unavailable\"\n      },\n      {\n        \"defaultMessage\": \"No one follows this user yet.\",\n        \"id\": \"account.followers.empty\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/followers/index.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Profile unavailable\",\n        \"id\": \"empty_column.account_unavailable\"\n      },\n      {\n        \"defaultMessage\": \"This user doesn't follow anyone yet.\",\n        \"id\": \"account.follows.empty\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/following/index.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Home\",\n        \"id\": \"tabs_bar.home\"\n      },\n      {\n        \"defaultMessage\": \"Notifications\",\n        \"id\": \"tabs_bar.notifications\"\n      },\n      {\n        \"defaultMessage\": \"Federated timeline\",\n        \"id\": \"navigation_bar.public_timeline\"\n      },\n      {\n        \"defaultMessage\": \"Settings\",\n        \"id\": \"column_subheading.settings\"\n      },\n      {\n        \"defaultMessage\": \"Local timeline\",\n        \"id\": \"navigation_bar.community_timeline\"\n      },\n      {\n        \"defaultMessage\": \"Direct messages\",\n        \"id\": \"navigation_bar.direct\"\n      },\n      {\n        \"defaultMessage\": \"Preferences\",\n        \"id\": \"navigation_bar.preferences\"\n      },\n      {\n        \"defaultMessage\": \"Follow requests\",\n        \"id\": \"navigation_bar.follow_requests\"\n      },\n      {\n        \"defaultMessage\": \"Favourites\",\n        \"id\": \"navigation_bar.favourites\"\n      },\n      {\n        \"defaultMessage\": \"Blocked users\",\n        \"id\": \"navigation_bar.blocks\"\n      },\n      {\n        \"defaultMessage\": \"Hidden domains\",\n        \"id\": \"navigation_bar.domain_blocks\"\n      },\n      {\n        \"defaultMessage\": \"Muted users\",\n        \"id\": \"navigation_bar.mutes\"\n      },\n      {\n        \"defaultMessage\": \"Pinned toots\",\n        \"id\": \"navigation_bar.pins\"\n      },\n      {\n        \"defaultMessage\": \"Lists\",\n        \"id\": \"navigation_bar.lists\"\n      },\n      {\n        \"defaultMessage\": \"Discover\",\n        \"id\": \"navigation_bar.discover\"\n      },\n      {\n        \"defaultMessage\": \"Personal\",\n        \"id\": \"navigation_bar.personal\"\n      },\n      {\n        \"defaultMessage\": \"Security\",\n        \"id\": \"navigation_bar.security\"\n      },\n      {\n        \"defaultMessage\": \"Getting started\",\n        \"id\": \"getting_started.heading\"\n      },\n      {\n        \"defaultMessage\": \"Profile directory\",\n        \"id\": \"getting_started.directory\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/getting_started/index.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Enter hashtags…\",\n        \"id\": \"hashtag.column_settings.select.placeholder\"\n      },\n      {\n        \"defaultMessage\": \"No suggestions found\",\n        \"id\": \"hashtag.column_settings.select.no_options_message\"\n      },\n      {\n        \"defaultMessage\": \"Any of these\",\n        \"id\": \"hashtag.column_settings.tag_mode.any\"\n      },\n      {\n        \"defaultMessage\": \"All of these\",\n        \"id\": \"hashtag.column_settings.tag_mode.all\"\n      },\n      {\n        \"defaultMessage\": \"None of these\",\n        \"id\": \"hashtag.column_settings.tag_mode.none\"\n      },\n      {\n        \"defaultMessage\": \"Include additional tags in this column\",\n        \"id\": \"hashtag.column_settings.tag_toggle\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/hashtag_timeline/components/column_settings.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"or {additional}\",\n        \"id\": \"hashtag.column_header.tag_mode.any\"\n      },\n      {\n        \"defaultMessage\": \"and {additional}\",\n        \"id\": \"hashtag.column_header.tag_mode.all\"\n      },\n      {\n        \"defaultMessage\": \"without {additional}\",\n        \"id\": \"hashtag.column_header.tag_mode.none\"\n      },\n      {\n        \"defaultMessage\": \"There is nothing in this hashtag yet.\",\n        \"id\": \"empty_column.hashtag\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/hashtag_timeline/index.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Basic\",\n        \"id\": \"home.column_settings.basic\"\n      },\n      {\n        \"defaultMessage\": \"Show boosts\",\n        \"id\": \"home.column_settings.show_reblogs\"\n      },\n      {\n        \"defaultMessage\": \"Show replies\",\n        \"id\": \"home.column_settings.show_replies\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/home_timeline/components/column_settings.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Home\",\n        \"id\": \"column.home\"\n      },\n      {\n        \"defaultMessage\": \"Your home timeline is empty! Visit {public} or use search to get started and meet other users.\",\n        \"id\": \"empty_column.home\"\n      },\n      {\n        \"defaultMessage\": \"the public timeline\",\n        \"id\": \"empty_column.home.public_timeline\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/home_timeline/index.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"First steps\",\n        \"id\": \"introduction.welcome.headline\"\n      },\n      {\n        \"defaultMessage\": \"Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.\",\n        \"id\": \"introduction.welcome.text\"\n      },\n      {\n        \"defaultMessage\": \"Let's go!\",\n        \"id\": \"introduction.welcome.action\"\n      },\n      {\n        \"defaultMessage\": \"Home\",\n        \"id\": \"introduction.federation.home.headline\"\n      },\n      {\n        \"defaultMessage\": \"Posts from people you follow will appear in your home feed. You can follow anyone on any server!\",\n        \"id\": \"introduction.federation.home.text\"\n      },\n      {\n        \"defaultMessage\": \"Local\",\n        \"id\": \"introduction.federation.local.headline\"\n      },\n      {\n        \"defaultMessage\": \"Public posts from people on the same server as you will appear in the local timeline.\",\n        \"id\": \"introduction.federation.local.text\"\n      },\n      {\n        \"defaultMessage\": \"Federated\",\n        \"id\": \"introduction.federation.federated.headline\"\n      },\n      {\n        \"defaultMessage\": \"Public posts from other servers of the fediverse will appear in the federated timeline.\",\n        \"id\": \"introduction.federation.federated.text\"\n      },\n      {\n        \"defaultMessage\": \"Next\",\n        \"id\": \"introduction.federation.action\"\n      },\n      {\n        \"defaultMessage\": \"Reply\",\n        \"id\": \"introduction.interactions.reply.headline\"\n      },\n      {\n        \"defaultMessage\": \"You can reply to other people's and your own toots, which will chain them together in a conversation.\",\n        \"id\": \"introduction.interactions.reply.text\"\n      },\n      {\n        \"defaultMessage\": \"Boost\",\n        \"id\": \"introduction.interactions.reblog.headline\"\n      },\n      {\n        \"defaultMessage\": \"You can share other people's toots with your followers by boosting them.\",\n        \"id\": \"introduction.interactions.reblog.text\"\n      },\n      {\n        \"defaultMessage\": \"Favourite\",\n        \"id\": \"introduction.interactions.favourite.headline\"\n      },\n      {\n        \"defaultMessage\": \"You can save a toot for later, and let the author know that you liked it, by favouriting it.\",\n        \"id\": \"introduction.interactions.favourite.text\"\n      },\n      {\n        \"defaultMessage\": \"Finish toot-orial!\",\n        \"id\": \"introduction.interactions.action\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/introduction/index.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Keyboard Shortcuts\",\n        \"id\": \"keyboard_shortcuts.heading\"\n      },\n      {\n        \"defaultMessage\": \"Hotkey\",\n        \"id\": \"keyboard_shortcuts.hotkey\"\n      },\n      {\n        \"defaultMessage\": \"Description\",\n        \"id\": \"keyboard_shortcuts.description\"\n      },\n      {\n        \"defaultMessage\": \"to reply\",\n        \"id\": \"keyboard_shortcuts.reply\"\n      },\n      {\n        \"defaultMessage\": \"to mention author\",\n        \"id\": \"keyboard_shortcuts.mention\"\n      },\n      {\n        \"defaultMessage\": \"to open author's profile\",\n        \"id\": \"keyboard_shortcuts.profile\"\n      },\n      {\n        \"defaultMessage\": \"to favourite\",\n        \"id\": \"keyboard_shortcuts.favourite\"\n      },\n      {\n        \"defaultMessage\": \"to boost\",\n        \"id\": \"keyboard_shortcuts.boost\"\n      },\n      {\n        \"defaultMessage\": \"to open status\",\n        \"id\": \"keyboard_shortcuts.enter\"\n      },\n      {\n        \"defaultMessage\": \"to show/hide text behind CW\",\n        \"id\": \"keyboard_shortcuts.toggle_hidden\"\n      },\n      {\n        \"defaultMessage\": \"to show/hide media\",\n        \"id\": \"keyboard_shortcuts.toggle_sensitivity\"\n      },\n      {\n        \"defaultMessage\": \"to move up in the list\",\n        \"id\": \"keyboard_shortcuts.up\"\n      },\n      {\n        \"defaultMessage\": \"to move down in the list\",\n        \"id\": \"keyboard_shortcuts.down\"\n      },\n      {\n        \"defaultMessage\": \"to focus a status in one of the columns\",\n        \"id\": \"keyboard_shortcuts.column\"\n      },\n      {\n        \"defaultMessage\": \"to focus the compose textarea\",\n        \"id\": \"keyboard_shortcuts.compose\"\n      },\n      {\n        \"defaultMessage\": \"to start a brand new toot\",\n        \"id\": \"keyboard_shortcuts.toot\"\n      },\n      {\n        \"defaultMessage\": \"to navigate back\",\n        \"id\": \"keyboard_shortcuts.back\"\n      },\n      {\n        \"defaultMessage\": \"to focus search\",\n        \"id\": \"keyboard_shortcuts.search\"\n      },\n      {\n        \"defaultMessage\": \"to un-focus compose textarea/search\",\n        \"id\": \"keyboard_shortcuts.unfocus\"\n      },\n      {\n        \"defaultMessage\": \"to open home timeline\",\n        \"id\": \"keyboard_shortcuts.home\"\n      },\n      {\n        \"defaultMessage\": \"to open notifications column\",\n        \"id\": \"keyboard_shortcuts.notifications\"\n      },\n      {\n        \"defaultMessage\": \"to open local timeline\",\n        \"id\": \"keyboard_shortcuts.local\"\n      },\n      {\n        \"defaultMessage\": \"to open federated timeline\",\n        \"id\": \"keyboard_shortcuts.federated\"\n      },\n      {\n        \"defaultMessage\": \"to open direct messages column\",\n        \"id\": \"keyboard_shortcuts.direct\"\n      },\n      {\n        \"defaultMessage\": \"to open \\\"get started\\\" column\",\n        \"id\": \"keyboard_shortcuts.start\"\n      },\n      {\n        \"defaultMessage\": \"to open favourites list\",\n        \"id\": \"keyboard_shortcuts.favourites\"\n      },\n      {\n        \"defaultMessage\": \"to open pinned toots list\",\n        \"id\": \"keyboard_shortcuts.pinned\"\n      },\n      {\n        \"defaultMessage\": \"to open your profile\",\n        \"id\": \"keyboard_shortcuts.my_profile\"\n      },\n      {\n        \"defaultMessage\": \"to open blocked users list\",\n        \"id\": \"keyboard_shortcuts.blocked\"\n      },\n      {\n        \"defaultMessage\": \"to open muted users list\",\n        \"id\": \"keyboard_shortcuts.muted\"\n      },\n      {\n        \"defaultMessage\": \"to open follow requests list\",\n        \"id\": \"keyboard_shortcuts.requests\"\n      },\n      {\n        \"defaultMessage\": \"to display this legend\",\n        \"id\": \"keyboard_shortcuts.legend\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/keyboard_shortcuts/index.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Remove from list\",\n        \"id\": \"lists.account.remove\"\n      },\n      {\n        \"defaultMessage\": \"Add to list\",\n        \"id\": \"lists.account.add\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/list_adder/components/list.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Remove from list\",\n        \"id\": \"lists.account.remove\"\n      },\n      {\n        \"defaultMessage\": \"Add to list\",\n        \"id\": \"lists.account.add\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/list_editor/components/account.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Change title\",\n        \"id\": \"lists.edit.submit\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/list_editor/components/edit_list_form.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Search among people you follow\",\n        \"id\": \"lists.search\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/list_editor/components/search.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Are you sure you want to permanently delete this list?\",\n        \"id\": \"confirmations.delete_list.message\"\n      },\n      {\n        \"defaultMessage\": \"Delete\",\n        \"id\": \"confirmations.delete_list.confirm\"\n      },\n      {\n        \"defaultMessage\": \"Edit list\",\n        \"id\": \"lists.edit\"\n      },\n      {\n        \"defaultMessage\": \"Delete list\",\n        \"id\": \"lists.delete\"\n      },\n      {\n        \"defaultMessage\": \"There is nothing in this list yet. When members of this list post new statuses, they will appear here.\",\n        \"id\": \"empty_column.list\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/list_timeline/index.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"New list title\",\n        \"id\": \"lists.new.title_placeholder\"\n      },\n      {\n        \"defaultMessage\": \"Add list\",\n        \"id\": \"lists.new.create\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/lists/components/new_list_form.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Lists\",\n        \"id\": \"column.lists\"\n      },\n      {\n        \"defaultMessage\": \"Your lists\",\n        \"id\": \"lists.subheading\"\n      },\n      {\n        \"defaultMessage\": \"You don't have any lists yet. When you create one, it will show up here.\",\n        \"id\": \"empty_column.lists\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/lists/index.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Muted users\",\n        \"id\": \"column.mutes\"\n      },\n      {\n        \"defaultMessage\": \"You haven't muted any users yet.\",\n        \"id\": \"empty_column.mutes\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/mutes/index.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Clear notifications\",\n        \"id\": \"notifications.clear\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/notifications/components/clear_column_button.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Show\",\n        \"id\": \"notifications.column_settings.filter_bar.show\"\n      },\n      {\n        \"defaultMessage\": \"Display all categories\",\n        \"id\": \"notifications.column_settings.filter_bar.advanced\"\n      },\n      {\n        \"defaultMessage\": \"Desktop notifications\",\n        \"id\": \"notifications.column_settings.alert\"\n      },\n      {\n        \"defaultMessage\": \"Show in column\",\n        \"id\": \"notifications.column_settings.show\"\n      },\n      {\n        \"defaultMessage\": \"Play sound\",\n        \"id\": \"notifications.column_settings.sound\"\n      },\n      {\n        \"defaultMessage\": \"Push notifications\",\n        \"id\": \"notifications.column_settings.push\"\n      },\n      {\n        \"defaultMessage\": \"Quick filter bar\",\n        \"id\": \"notifications.column_settings.filter_bar.category\"\n      },\n      {\n        \"defaultMessage\": \"New followers:\",\n        \"id\": \"notifications.column_settings.follow\"\n      },\n      {\n        \"defaultMessage\": \"Favourites:\",\n        \"id\": \"notifications.column_settings.favourite\"\n      },\n      {\n        \"defaultMessage\": \"Mentions:\",\n        \"id\": \"notifications.column_settings.mention\"\n      },\n      {\n        \"defaultMessage\": \"Boosts:\",\n        \"id\": \"notifications.column_settings.reblog\"\n      },\n      {\n        \"defaultMessage\": \"Poll results:\",\n        \"id\": \"notifications.column_settings.poll\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/notifications/components/column_settings.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Mentions\",\n        \"id\": \"notifications.filter.mentions\"\n      },\n      {\n        \"defaultMessage\": \"Favourites\",\n        \"id\": \"notifications.filter.favourites\"\n      },\n      {\n        \"defaultMessage\": \"Boosts\",\n        \"id\": \"notifications.filter.boosts\"\n      },\n      {\n        \"defaultMessage\": \"Poll results\",\n        \"id\": \"notifications.filter.polls\"\n      },\n      {\n        \"defaultMessage\": \"Follows\",\n        \"id\": \"notifications.filter.follows\"\n      },\n      {\n        \"defaultMessage\": \"All\",\n        \"id\": \"notifications.filter.all\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/notifications/components/filter_bar.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"{name} followed you\",\n        \"id\": \"notification.follow\"\n      },\n      {\n        \"defaultMessage\": \"{name} favourited your status\",\n        \"id\": \"notification.favourite\"\n      },\n      {\n        \"defaultMessage\": \"{name} boosted your status\",\n        \"id\": \"notification.reblog\"\n      },\n      {\n        \"defaultMessage\": \"A poll you have voted in has ended\",\n        \"id\": \"notification.poll\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/notifications/components/notification.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Are you sure you want to permanently clear all your notifications?\",\n        \"id\": \"notifications.clear_confirmation\"\n      },\n      {\n        \"defaultMessage\": \"Clear notifications\",\n        \"id\": \"notifications.clear\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/notifications/containers/column_settings_container.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Notifications\",\n        \"id\": \"column.notifications\"\n      },\n      {\n        \"defaultMessage\": \"You don't have any notifications yet. Interact with others to start the conversation.\",\n        \"id\": \"empty_column.notifications\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/notifications/index.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Pinned toot\",\n        \"id\": \"column.pins\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/pinned_statuses/index.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Federated timeline\",\n        \"id\": \"column.public\"\n      },\n      {\n        \"defaultMessage\": \"There is nothing here! Write something publicly, or manually follow users from other servers to fill it up\",\n        \"id\": \"empty_column.public\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/public_timeline/index.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"No one has boosted this toot yet. When someone does, they will show up here.\",\n        \"id\": \"status.reblogs.empty\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/reblogs/index.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Delete\",\n        \"id\": \"status.delete\"\n      },\n      {\n        \"defaultMessage\": \"Delete & re-draft\",\n        \"id\": \"status.redraft\"\n      },\n      {\n        \"defaultMessage\": \"Direct message @{name}\",\n        \"id\": \"status.direct\"\n      },\n      {\n        \"defaultMessage\": \"Mention @{name}\",\n        \"id\": \"status.mention\"\n      },\n      {\n        \"defaultMessage\": \"Reply\",\n        \"id\": \"status.reply\"\n      },\n      {\n        \"defaultMessage\": \"Boost\",\n        \"id\": \"status.reblog\"\n      },\n      {\n        \"defaultMessage\": \"Boost to original audience\",\n        \"id\": \"status.reblog_private\"\n      },\n      {\n        \"defaultMessage\": \"Unboost\",\n        \"id\": \"status.cancel_reblog_private\"\n      },\n      {\n        \"defaultMessage\": \"This post cannot be boosted\",\n        \"id\": \"status.cannot_reblog\"\n      },\n      {\n        \"defaultMessage\": \"Favourite\",\n        \"id\": \"status.favourite\"\n      },\n      {\n        \"defaultMessage\": \"Mute @{name}\",\n        \"id\": \"status.mute\"\n      },\n      {\n        \"defaultMessage\": \"Mute conversation\",\n        \"id\": \"status.mute_conversation\"\n      },\n      {\n        \"defaultMessage\": \"Unmute conversation\",\n        \"id\": \"status.unmute_conversation\"\n      },\n      {\n        \"defaultMessage\": \"Block @{name}\",\n        \"id\": \"status.block\"\n      },\n      {\n        \"defaultMessage\": \"Report @{name}\",\n        \"id\": \"status.report\"\n      },\n      {\n        \"defaultMessage\": \"Share\",\n        \"id\": \"status.share\"\n      },\n      {\n        \"defaultMessage\": \"Pin on profile\",\n        \"id\": \"status.pin\"\n      },\n      {\n        \"defaultMessage\": \"Unpin from profile\",\n        \"id\": \"status.unpin\"\n      },\n      {\n        \"defaultMessage\": \"Embed\",\n        \"id\": \"status.embed\"\n      },\n      {\n        \"defaultMessage\": \"Open moderation interface for @{name}\",\n        \"id\": \"status.admin_account\"\n      },\n      {\n        \"defaultMessage\": \"Open this status in the moderation interface\",\n        \"id\": \"status.admin_status\"\n      },\n      {\n        \"defaultMessage\": \"Copy link to status\",\n        \"id\": \"status.copy\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/status/components/action_bar.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Delete\",\n        \"id\": \"confirmations.delete.confirm\"\n      },\n      {\n        \"defaultMessage\": \"Are you sure you want to delete this status?\",\n        \"id\": \"confirmations.delete.message\"\n      },\n      {\n        \"defaultMessage\": \"Delete & redraft\",\n        \"id\": \"confirmations.redraft.confirm\"\n      },\n      {\n        \"defaultMessage\": \"Are you sure you want to delete this status and re-draft it? Favourites and boosts will be lost, and replies to the original post will be orphaned.\",\n        \"id\": \"confirmations.redraft.message\"\n      },\n      {\n        \"defaultMessage\": \"Block\",\n        \"id\": \"confirmations.block.confirm\"\n      },\n      {\n        \"defaultMessage\": \"Reply\",\n        \"id\": \"confirmations.reply.confirm\"\n      },\n      {\n        \"defaultMessage\": \"Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?\",\n        \"id\": \"confirmations.reply.message\"\n      },\n      {\n        \"defaultMessage\": \"Block & Report\",\n        \"id\": \"confirmations.block.block_and_report\"\n      },\n      {\n        \"defaultMessage\": \"Are you sure you want to block {name}?\",\n        \"id\": \"confirmations.block.message\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/status/containers/detailed_status_container.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Delete\",\n        \"id\": \"confirmations.delete.confirm\"\n      },\n      {\n        \"defaultMessage\": \"Are you sure you want to delete this status?\",\n        \"id\": \"confirmations.delete.message\"\n      },\n      {\n        \"defaultMessage\": \"Delete & redraft\",\n        \"id\": \"confirmations.redraft.confirm\"\n      },\n      {\n        \"defaultMessage\": \"Are you sure you want to delete this status and re-draft it? Favourites and boosts will be lost, and replies to the original post will be orphaned.\",\n        \"id\": \"confirmations.redraft.message\"\n      },\n      {\n        \"defaultMessage\": \"Block\",\n        \"id\": \"confirmations.block.confirm\"\n      },\n      {\n        \"defaultMessage\": \"Show more for all\",\n        \"id\": \"status.show_more_all\"\n      },\n      {\n        \"defaultMessage\": \"Show less for all\",\n        \"id\": \"status.show_less_all\"\n      },\n      {\n        \"defaultMessage\": \"Detailed conversation view\",\n        \"id\": \"status.detailed_status\"\n      },\n      {\n        \"defaultMessage\": \"Reply\",\n        \"id\": \"confirmations.reply.confirm\"\n      },\n      {\n        \"defaultMessage\": \"Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?\",\n        \"id\": \"confirmations.reply.message\"\n      },\n      {\n        \"defaultMessage\": \"Block & Report\",\n        \"id\": \"confirmations.block.block_and_report\"\n      },\n      {\n        \"defaultMessage\": \"Are you sure you want to block {name}?\",\n        \"id\": \"confirmations.block.message\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/status/index.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Unboost\",\n        \"id\": \"status.cancel_reblog_private\"\n      },\n      {\n        \"defaultMessage\": \"Boost\",\n        \"id\": \"status.reblog\"\n      },\n      {\n        \"defaultMessage\": \"You can press {combo} to skip this next time\",\n        \"id\": \"boost_modal.combo\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/ui/components/boost_modal.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Network error\",\n        \"id\": \"bundle_column_error.title\"\n      },\n      {\n        \"defaultMessage\": \"Something went wrong while loading this component.\",\n        \"id\": \"bundle_column_error.body\"\n      },\n      {\n        \"defaultMessage\": \"Try again\",\n        \"id\": \"bundle_column_error.retry\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/ui/components/bundle_column_error.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Something went wrong while loading this component.\",\n        \"id\": \"bundle_modal_error.message\"\n      },\n      {\n        \"defaultMessage\": \"Try again\",\n        \"id\": \"bundle_modal_error.retry\"\n      },\n      {\n        \"defaultMessage\": \"Close\",\n        \"id\": \"bundle_modal_error.close\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/ui/components/bundle_modal_error.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Toot\",\n        \"id\": \"compose_form.publish\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/ui/components/columns_area.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Cancel\",\n        \"id\": \"confirmation_modal.cancel\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/ui/components/confirmation_modal.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Embed\",\n        \"id\": \"status.embed\"\n      },\n      {\n        \"defaultMessage\": \"Embed this status on your website by copying the code below.\",\n        \"id\": \"embed.instructions\"\n      },\n      {\n        \"defaultMessage\": \"Here is what it will look like:\",\n        \"id\": \"embed.preview\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/ui/components/embed_modal.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Follow requests\",\n        \"id\": \"navigation_bar.follow_requests\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/ui/components/follow_requests_nav_link.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Invite people\",\n        \"id\": \"getting_started.invite\"\n      },\n      {\n        \"defaultMessage\": \"Hotkeys\",\n        \"id\": \"navigation_bar.keyboard_shortcuts\"\n      },\n      {\n        \"defaultMessage\": \"Security\",\n        \"id\": \"getting_started.security\"\n      },\n      {\n        \"defaultMessage\": \"About this server\",\n        \"id\": \"navigation_bar.info\"\n      },\n      {\n        \"defaultMessage\": \"Mobile apps\",\n        \"id\": \"navigation_bar.apps\"\n      },\n      {\n        \"defaultMessage\": \"Terms of service\",\n        \"id\": \"getting_started.terms\"\n      },\n      {\n        \"defaultMessage\": \"Developers\",\n        \"id\": \"getting_started.developers\"\n      },\n      {\n        \"defaultMessage\": \"Documentation\",\n        \"id\": \"getting_started.documentation\"\n      },\n      {\n        \"defaultMessage\": \"Logout\",\n        \"id\": \"navigation_bar.logout\"\n      },\n      {\n        \"defaultMessage\": \"Mastodon is open source software. You can contribute or report issues on GitHub at {github}.\",\n        \"id\": \"getting_started.open_source_notice\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/ui/components/link_footer.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Close\",\n        \"id\": \"lightbox.close\"\n      },\n      {\n        \"defaultMessage\": \"Previous\",\n        \"id\": \"lightbox.previous\"\n      },\n      {\n        \"defaultMessage\": \"Next\",\n        \"id\": \"lightbox.next\"\n      },\n      {\n        \"defaultMessage\": \"View context\",\n        \"id\": \"lightbox.view_context\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/ui/components/media_modal.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Are you sure you want to mute {name}?\",\n        \"id\": \"confirmations.mute.message\"\n      },\n      {\n        \"defaultMessage\": \"Hide notifications from this user?\",\n        \"id\": \"mute_modal.hide_notifications\"\n      },\n      {\n        \"defaultMessage\": \"Cancel\",\n        \"id\": \"confirmation_modal.cancel\"\n      },\n      {\n        \"defaultMessage\": \"Mute\",\n        \"id\": \"confirmations.mute.confirm\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/ui/components/mute_modal.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Home\",\n        \"id\": \"tabs_bar.home\"\n      },\n      {\n        \"defaultMessage\": \"Notifications\",\n        \"id\": \"tabs_bar.notifications\"\n      },\n      {\n        \"defaultMessage\": \"Local\",\n        \"id\": \"tabs_bar.local_timeline\"\n      },\n      {\n        \"defaultMessage\": \"Federated\",\n        \"id\": \"tabs_bar.federated_timeline\"\n      },\n      {\n        \"defaultMessage\": \"Direct messages\",\n        \"id\": \"navigation_bar.direct\"\n      },\n      {\n        \"defaultMessage\": \"Favourites\",\n        \"id\": \"navigation_bar.favourites\"\n      },\n      {\n        \"defaultMessage\": \"Lists\",\n        \"id\": \"navigation_bar.lists\"\n      },\n      {\n        \"defaultMessage\": \"Preferences\",\n        \"id\": \"navigation_bar.preferences\"\n      },\n      {\n        \"defaultMessage\": \"Follows and followers\",\n        \"id\": \"navigation_bar.follows_and_followers\"\n      },\n      {\n        \"defaultMessage\": \"Profile directory\",\n        \"id\": \"navigation_bar.profile_directory\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/ui/components/navigation_panel.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Close\",\n        \"id\": \"lightbox.close\"\n      },\n      {\n        \"defaultMessage\": \"Additional comments\",\n        \"id\": \"report.placeholder\"\n      },\n      {\n        \"defaultMessage\": \"Submit\",\n        \"id\": \"report.submit\"\n      },\n      {\n        \"defaultMessage\": \"Report {target}\",\n        \"id\": \"report.target\"\n      },\n      {\n        \"defaultMessage\": \"The report will be sent to your server moderators. You can provide an explanation of why you are reporting this account below:\",\n        \"id\": \"report.hint\"\n      },\n      {\n        \"defaultMessage\": \"The account is from another server. Send an anonymized copy of the report there as well?\",\n        \"id\": \"report.forward_hint\"\n      },\n      {\n        \"defaultMessage\": \"Forward to {target}\",\n        \"id\": \"report.forward\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/ui/components/report_modal.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Home\",\n        \"id\": \"tabs_bar.home\"\n      },\n      {\n        \"defaultMessage\": \"Notifications\",\n        \"id\": \"tabs_bar.notifications\"\n      },\n      {\n        \"defaultMessage\": \"Local\",\n        \"id\": \"tabs_bar.local_timeline\"\n      },\n      {\n        \"defaultMessage\": \"Federated\",\n        \"id\": \"tabs_bar.federated_timeline\"\n      },\n      {\n        \"defaultMessage\": \"Search\",\n        \"id\": \"tabs_bar.search\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/ui/components/tabs_bar.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Drag & drop to upload\",\n        \"id\": \"upload_area.title\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/ui/components/upload_area.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"View context\",\n        \"id\": \"lightbox.view_context\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/ui/components/video_modal.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Your draft will be lost if you leave Mastodon.\",\n        \"id\": \"ui.beforeunload\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/ui/index.json\"\n  },\n  {\n    \"descriptors\": [\n      {\n        \"defaultMessage\": \"Play\",\n        \"id\": \"video.play\"\n      },\n      {\n        \"defaultMessage\": \"Pause\",\n        \"id\": \"video.pause\"\n      },\n      {\n        \"defaultMessage\": \"Mute sound\",\n        \"id\": \"video.mute\"\n      },\n      {\n        \"defaultMessage\": \"Unmute sound\",\n        \"id\": \"video.unmute\"\n      },\n      {\n        \"defaultMessage\": \"Hide video\",\n        \"id\": \"video.hide\"\n      },\n      {\n        \"defaultMessage\": \"Expand video\",\n        \"id\": \"video.expand\"\n      },\n      {\n        \"defaultMessage\": \"Close video\",\n        \"id\": \"video.close\"\n      },\n      {\n        \"defaultMessage\": \"Full screen\",\n        \"id\": \"video.fullscreen\"\n      },\n      {\n        \"defaultMessage\": \"Exit full screen\",\n        \"id\": \"video.exit_fullscreen\"\n      },\n      {\n        \"defaultMessage\": \"Sensitive content\",\n        \"id\": \"status.sensitive_warning\"\n      },\n      {\n        \"defaultMessage\": \"Media hidden\",\n        \"id\": \"status.media_hidden\"\n      }\n    ],\n    \"path\": \"app/javascript/mastodon/features/video/index.json\"\n  }\n]"
  },
  {
    "path": "app/javascript/mastodon/locales/el.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Προσθήκη ή Αφαίρεση από λίστες\",\n  \"account.badges.bot\": \"Μποτ\",\n  \"account.block\": \"Απόκλεισε τον/την @{name}\",\n  \"account.block_domain\": \"Απόκρυψε τα πάντα από το {domain}\",\n  \"account.blocked\": \"Αποκλεισμένος/η\",\n  \"account.direct\": \"Προσωπικό μήνυμα προς @{name}\",\n  \"account.domain_blocked\": \"Κρυμμένος τομέας\",\n  \"account.edit_profile\": \"Επεξεργασία προφίλ\",\n  \"account.endorse\": \"Προβολή στο προφίλ\",\n  \"account.follow\": \"Ακολούθησε\",\n  \"account.followers\": \"Ακόλουθοι\",\n  \"account.followers.empty\": \"Κανείς δεν ακολουθεί αυτό τον χρήστη ακόμα.\",\n  \"account.follows\": \"Ακολουθεί\",\n  \"account.follows.empty\": \"Αυτός ο χρήστης δεν ακολουθεί κανέναν ακόμα.\",\n  \"account.follows_you\": \"Σε ακολουθεί\",\n  \"account.hide_reblogs\": \"Απόκρυψη προωθήσεων από @{name}\",\n  \"account.link_verified_on\": \"Η ιδιοκτησία αυτού του συνδέσμου ελέχθηκε την {date}\",\n  \"account.locked_info\": \"Η κατάσταση απορρήτου αυτού του λογαριασμού είναι κλειδωμένη. Ο ιδιοκτήτης επιβεβαιώνει χειροκίνητα ποιος μπορεί να τον ακολουθήσει.\",\n  \"account.media\": \"Πολυμέσα\",\n  \"account.mention\": \"Ανάφερε @{name}\",\n  \"account.moved_to\": \"{name} μεταφέρθηκε στο:\",\n  \"account.mute\": \"Σώπασε @{name}\",\n  \"account.mute_notifications\": \"Σώπασε τις ειδοποιήσεις από @{name}\",\n  \"account.muted\": \"Αποσιωπημένος/η\",\n  \"account.posts\": \"Τουτ\",\n  \"account.posts_with_replies\": \"Τουτ και απαντήσεις\",\n  \"account.report\": \"Κατάγγειλε @{name}\",\n  \"account.requested\": \"Εκκρεμεί έγκριση. Κάνε κλικ για να ακυρώσεις το αίτημα παρακολούθησης\",\n  \"account.share\": \"Μοιράσου το προφίλ του/της @{name}\",\n  \"account.show_reblogs\": \"Δείξε τις προωθήσεις του/της @{name}\",\n  \"account.unblock\": \"Ξεμπλόκαρε @{name}\",\n  \"account.unblock_domain\": \"Αποκάλυψε το {domain}\",\n  \"account.unendorse\": \"Άνευ προβολής στο προφίλ\",\n  \"account.unfollow\": \"Διακοπή παρακολούθησης\",\n  \"account.unmute\": \"Διακοπή αποσιώπησης του/της @{name}\",\n  \"account.unmute_notifications\": \"Διακοπή αποσιώπησης ειδοποιήσεων του/της @{name}\",\n  \"alert.unexpected.message\": \"Προέκυψε απροσδόκητο σφάλμα.\",\n  \"alert.unexpected.title\": \"Εεπ!\",\n  \"boost_modal.combo\": \"Μπορείς να πατήσεις {combo} για να το προσπεράσεις αυτό την επόμενη φορά\",\n  \"bundle_column_error.body\": \"Κάτι πήγε στραβά ενώ φορτωνόταν αυτό το στοιχείο.\",\n  \"bundle_column_error.retry\": \"Δοκίμασε ξανά\",\n  \"bundle_column_error.title\": \"Σφάλμα δικτύου\",\n  \"bundle_modal_error.close\": \"Κλείσε\",\n  \"bundle_modal_error.message\": \"Κάτι πήγε στραβά ενώ φορτωνόταν αυτό το στοιχείο.\",\n  \"bundle_modal_error.retry\": \"Δοκίμασε ξανά\",\n  \"column.blocks\": \"Αποκλεισμένοι χρήστες\",\n  \"column.community\": \"Τοπική ροή\",\n  \"column.direct\": \"Προσωπικά μηνύματα\",\n  \"column.domain_blocks\": \"Κρυμμένοι τομείς\",\n  \"column.favourites\": \"Αγαπημένα\",\n  \"column.follow_requests\": \"Αιτήματα ακολούθησης\",\n  \"column.home\": \"Αρχική\",\n  \"column.lists\": \"Λίστες\",\n  \"column.mutes\": \"Αποσιωπημένοι χρήστες\",\n  \"column.notifications\": \"Ειδοποιήσεις\",\n  \"column.pins\": \"Καρφιτσωμένα τουτ\",\n  \"column.public\": \"Ομοσπονδιακή ροή\",\n  \"column_back_button.label\": \"Πίσω\",\n  \"column_header.hide_settings\": \"Απόκρυψη ρυθμίσεων\",\n  \"column_header.moveLeft_settings\": \"Μεταφορά κολώνας αριστερά\",\n  \"column_header.moveRight_settings\": \"Μεταφορά κολώνας δεξιά\",\n  \"column_header.pin\": \"Καρφίτσωμα\",\n  \"column_header.show_settings\": \"Εμφάνιση ρυθμίσεων\",\n  \"column_header.unpin\": \"Ξεκαρφίτσωμα\",\n  \"column_subheading.settings\": \"Ρυθμίσεις\",\n  \"community.column_settings.media_only\": \"Μόνο πολυμέσα\",\n  \"compose_form.direct_message_warning\": \"Αυτό το τουτ θα σταλεί μόνο στους αναφερόμενους χρήστες.\",\n  \"compose_form.direct_message_warning_learn_more\": \"Μάθετε περισσότερα\",\n  \"compose_form.hashtag_warning\": \"Αυτό το τουτ δεν θα εμφανίζεται κάτω από κανένα hashtag καθώς είναι αφανές. Μόνο τα δημόσια τουτ μπορούν να αναζητηθούν ανά hashtag.\",\n  \"compose_form.lock_disclaimer\": \"Ο λογαριασμός σου δεν είναι {locked}. Οποιοσδήποτε μπορεί να σε ακολουθήσει για να δει τις δημοσιεύσεις σας προς τους ακολούθους σας.\",\n  \"compose_form.lock_disclaimer.lock\": \"κλειδωμένος\",\n  \"compose_form.placeholder\": \"Τι σκέφτεσαι;\",\n  \"compose_form.poll.add_option\": \"Προσθήκη επιλογής\",\n  \"compose_form.poll.duration\": \"Διάρκεια δημοσκόπησης\",\n  \"compose_form.poll.option_placeholder\": \"Επιλογή {number}\",\n  \"compose_form.poll.remove_option\": \"Αφαίρεση επιλογής\",\n  \"compose_form.publish\": \"Τουτ\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"Σημείωσε τα πολυμέσα ως ευαίσθητα\",\n  \"compose_form.sensitive.marked\": \"Το πολυμέσο έχει σημειωθεί ως ευαίσθητο\",\n  \"compose_form.sensitive.unmarked\": \"Το πολυμέσο δεν έχει σημειωθεί ως ευαίσθητο\",\n  \"compose_form.spoiler.marked\": \"Κείμενο κρυμμένο πίσω από προειδοποίηση\",\n  \"compose_form.spoiler.unmarked\": \"Μη κρυμμένο κείμενο\",\n  \"compose_form.spoiler_placeholder\": \"Γράψε την προειδοποίησή σου εδώ\",\n  \"confirmation_modal.cancel\": \"Άκυρο\",\n  \"confirmations.block.block_and_report\": \"Αποκλεισμός & Καταγγελία\",\n  \"confirmations.block.confirm\": \"Απόκλεισε\",\n  \"confirmations.block.message\": \"Σίγουρα θες να αποκλείσεις {name};\",\n  \"confirmations.delete.confirm\": \"Διέγραψε\",\n  \"confirmations.delete.message\": \"Σίγουρα θες να διαγράψεις αυτή την κατάσταση;\",\n  \"confirmations.delete_list.confirm\": \"Διέγραψε\",\n  \"confirmations.delete_list.message\": \"Σίγουρα θες να διαγράψεις οριστικά αυτή τη λίστα;\",\n  \"confirmations.domain_block.confirm\": \"Απόκρυψη ολόκληρου του τομέα\",\n  \"confirmations.domain_block.message\": \"Σίγουρα θες να μπλοκάρεις ολόκληρο το {domain}; Συνήθως μερικά εστιασμένα μπλοκ ή αποσιωπήσεις επαρκούν και προτιμούνται. Δεν θα βλέπεις περιεχόμενο από αυτό τον κόμβο σε καμία δημόσια ροή, ούτε στις ειδοποιήσεις σου. Όσους ακόλουθους έχεις αυτό αυτό τον κόμβο θα αφαιρεθούν.\",\n  \"confirmations.mute.confirm\": \"Αποσιώπηση\",\n  \"confirmations.mute.message\": \"Σίγουρα θες να αποσιωπήσεις {name};\",\n  \"confirmations.redraft.confirm\": \"Διαγραφή & ξαναγράψιμο\",\n  \"confirmations.redraft.message\": \"Σίγουρα θέλεις να σβήσεις αυτή την κατάσταση και να την ξαναγράψεις; Οι αναφορές και τα αγαπημένα της θα χαθούν ενώ οι απαντήσεις προς αυτή θα μείνουν ορφανές.\",\n  \"confirmations.reply.confirm\": \"Απάντησε\",\n  \"confirmations.reply.message\": \"Απαντώντας τώρα θα αντικαταστήσεις το κείμενο που ήδη γράφεις. Σίγουρα θέλεις να συνεχίσεις;\",\n  \"confirmations.unfollow.confirm\": \"Διακοπή παρακολούθησης\",\n  \"confirmations.unfollow.message\": \"Σίγουρα θες να πάψεις να ακολουθείς τον/την {name};\",\n  \"embed.instructions\": \"Ενσωματώστε αυτή την κατάσταση στην ιστοσελίδα σας αντιγράφοντας τον παρακάτω κώδικα.\",\n  \"embed.preview\": \"Ορίστε πως θα φαίνεται:\",\n  \"emoji_button.activity\": \"Δραστηριότητα\",\n  \"emoji_button.custom\": \"Προσαρμοσμένα\",\n  \"emoji_button.flags\": \"Σημαίες\",\n  \"emoji_button.food\": \"Φαγητά & Ποτά\",\n  \"emoji_button.label\": \"Εισάγετε emoji\",\n  \"emoji_button.nature\": \"Φύση\",\n  \"emoji_button.not_found\": \"Ουδέν emojo!! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"Αντικείμενα\",\n  \"emoji_button.people\": \"Άνθρωποι\",\n  \"emoji_button.recent\": \"Δημοφιλή\",\n  \"emoji_button.search\": \"Αναζήτηση…\",\n  \"emoji_button.search_results\": \"Αποτελέσματα αναζήτησης\",\n  \"emoji_button.symbols\": \"Σύμβολα\",\n  \"emoji_button.travel\": \"Ταξίδια & Τοποθεσίες\",\n  \"empty_column.account_timeline\": \"Δεν έχει τουτ εδώ!\",\n  \"empty_column.account_unavailable\": \"Μη διαθέσιμο προφίλ\",\n  \"empty_column.blocks\": \"Δεν έχεις αποκλείσει κανέναν χρήστη ακόμα.\",\n  \"empty_column.community\": \"Η τοπική ροή είναι κενή. Γράψε κάτι δημόσιο παραμύθι ν' αρχινίσει!\",\n  \"empty_column.direct\": \"Δεν έχεις προσωπικά μηνύματα ακόμα. Όταν στείλεις ή λάβεις κανένα, θα εμφανιστεί εδώ.\",\n  \"empty_column.domain_blocks\": \"Δεν υπάρχουν αποκλεισμένοι τομείς ακόμα.\",\n  \"empty_column.favourited_statuses\": \"Δεν έχεις κανένα αγαπημένο τουτ ακόμα. Μόλις αγαπήσεις κάποιο, θα εμφανιστεί εδώ.\",\n  \"empty_column.favourites\": \"Κανείς δεν έχει αγαπήσει αυτό το τουτ ακόμα. Μόλις το κάνει κάποια, θα εμφανιστούν εδώ.\",\n  \"empty_column.follow_requests\": \"Δεν έχεις κανένα αίτημα παρακολούθησης ακόμα. Μόλις λάβεις κάποιο, θα εμφανιστεί εδώ.\",\n  \"empty_column.hashtag\": \"Δεν υπάρχει ακόμα κάτι για αυτή την ταμπέλα.\",\n  \"empty_column.home\": \"Η τοπική σου ροή είναι κενή! Πήγαινε στο {public} ή κάνε αναζήτηση για να ξεκινήσεις και να γνωρίσεις άλλους χρήστες.\",\n  \"empty_column.home.public_timeline\": \"η δημόσια ροή\",\n  \"empty_column.list\": \"Δεν υπάρχει τίποτα σε αυτή τη λίστα ακόμα. Όταν τα μέλη της δημοσιεύσουν νέες καταστάσεις, θα εμφανιστούν εδώ.\",\n  \"empty_column.lists\": \"Δεν έχεις καμία λίστα ακόμα. Μόλις φτιάξεις μια, θα εμφανιστεί εδώ.\",\n  \"empty_column.mutes\": \"Δεν έχεις αποσιωπήσει κανένα χρήστη ακόμα.\",\n  \"empty_column.notifications\": \"Δεν έχεις ειδοποιήσεις ακόμα. Αλληλεπίδρασε με άλλους χρήστες για να ξεκινήσεις την κουβέντα.\",\n  \"empty_column.public\": \"Δεν υπάρχει τίποτα εδώ! Γράψε κάτι δημόσιο, ή ακολούθησε χειροκίνητα χρήστες από άλλους κόμβους για να τη γεμίσεις\",\n  \"follow_request.authorize\": \"Ενέκρινε\",\n  \"follow_request.reject\": \"Απέρριψε\",\n  \"getting_started.developers\": \"Ανάπτυξη\",\n  \"getting_started.directory\": \"Κατάλογος λογαριασμών\",\n  \"getting_started.documentation\": \"Τεκμηρίωση\",\n  \"getting_started.heading\": \"Αφετηρία\",\n  \"getting_started.invite\": \"Προσκάλεσε κόσμο\",\n  \"getting_started.open_source_notice\": \"Το Mastodon είναι ελεύθερο λογισμικό. Μπορείς να συνεισφέρεις ή να αναφέρεις ζητήματα στο GitHub στο {github}.\",\n  \"getting_started.security\": \"Ασφάλεια\",\n  \"getting_started.terms\": \"Όροι χρήσης\",\n  \"hashtag.column_header.tag_mode.all\": \"και {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"ή {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"χωρίς {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"Δεν βρέθηκαν προτάσεις\",\n  \"hashtag.column_settings.select.placeholder\": \"Γράψε μερικές ταμπέλες…\",\n  \"hashtag.column_settings.tag_mode.all\": \"Όλα αυτα\",\n  \"hashtag.column_settings.tag_mode.any\": \"Οποιοδήποτε από αυτά\",\n  \"hashtag.column_settings.tag_mode.none\": \"Κανένα από αυτά\",\n  \"hashtag.column_settings.tag_toggle\": \"Προσθήκη επιπλέον ταμπελών για την κολώνα\",\n  \"home.column_settings.basic\": \"Βασικά\",\n  \"home.column_settings.show_reblogs\": \"Εμφάνιση προωθήσεων\",\n  \"home.column_settings.show_replies\": \"Εμφάνιση απαντήσεων\",\n  \"intervals.full.days\": \"{number, plural, one {# μέρα} other {# μέρες}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# ώρα} other {# ώρες}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# λεπτό} other {# λεπτά}}\",\n  \"introduction.federation.action\": \"Επόμενο\",\n  \"introduction.federation.federated.headline\": \"Ομοσπονδιακή\",\n  \"introduction.federation.federated.text\": \"Οι δημόσιες αναρτήσεις από άλλους κόμβους του fediverse θα εμφανίζονται στην ομοσπονδιακή ροή.\",\n  \"introduction.federation.home.headline\": \"Αρχική\",\n  \"introduction.federation.home.text\": \"Οι αναρτήσεις όσων ακολουθείς θα εμφανίζονται στην αρχική ροή. Μπορείς να ακολουθήσεις όποιον θέλεις σε οποιονδήποτε κόμβο!\",\n  \"introduction.federation.local.headline\": \"Τοπική\",\n  \"introduction.federation.local.text\": \"Οι δημόσιες αναρτήσεις από άτομα στον ίδιο κόμβο με εσένα θα εμφανίζονται στην τοπική ροή.\",\n  \"introduction.interactions.action\": \"Τέλος μαθήματος!\",\n  \"introduction.interactions.favourite.headline\": \"Αγαπημένο\",\n  \"introduction.interactions.favourite.text\": \"Φύλαξε ένα τουτ για αργότερα και να ειδοποιήσεις τον δημιουργό του ότι σου άρεσε σημειώνοντας το ως αγαπημένο.\",\n  \"introduction.interactions.reblog.headline\": \"Προώθηση\",\n  \"introduction.interactions.reblog.text\": \"Μοιράσου τουτ άλλων χρηστών με όσους σε ακολουθούν προωθώντας τα.\",\n  \"introduction.interactions.reply.headline\": \"Απάντηση\",\n  \"introduction.interactions.reply.text\": \"Μπορείς να απαντήσεις στα τουτ άλλων αλλά ακόμα και στα δικά σου, δένοντας τα όλα μαζί σε μια συζήτηση.\",\n  \"introduction.welcome.action\": \"Ας ξεκινήσουμε!\",\n  \"introduction.welcome.headline\": \"Πρώτα βήματα\",\n  \"introduction.welcome.text\": \"Καλώς ήρθες στο fediverse! Σε πολύ λίγο θα μπορείς να στέλνεις δημοσιεύσεις και να μιλάς με τους φίλους σου σε πολλούς, διαφορετικούς κόμβους. Ο κόμβος {domain} όμως είναι ξεχωριστός — φιλοξενεί τον λογαριασμό σου, για αυτό να θυμάσαι το όνομά του.\",\n  \"keyboard_shortcuts.back\": \"επιστροφή\",\n  \"keyboard_shortcuts.blocked\": \"άνοιγμα λίστας αποκλεισμένων χρηστών\",\n  \"keyboard_shortcuts.boost\": \"προώθηση\",\n  \"keyboard_shortcuts.column\": \"εμφάνιση της κατάστασης σε μια από τις στήλες\",\n  \"keyboard_shortcuts.compose\": \"εστίαση στην περιοχή συγγραφής\",\n  \"keyboard_shortcuts.description\": \"Περιγραφή\",\n  \"keyboard_shortcuts.direct\": \"άνοιγμα στήλης απευθείας μηνυμάτων\",\n  \"keyboard_shortcuts.down\": \"κίνηση προς τα κάτω στη λίστα\",\n  \"keyboard_shortcuts.enter\": \"εμφάνιση κατάστασης\",\n  \"keyboard_shortcuts.favourite\": \"σημείωση ως αγαπημένο\",\n  \"keyboard_shortcuts.favourites\": \"άνοιγμα λίστας αγαπημένων\",\n  \"keyboard_shortcuts.federated\": \"άνοιγμα ομοσπονδιακής ροής\",\n  \"keyboard_shortcuts.heading\": \"Συντομεύσεις\",\n  \"keyboard_shortcuts.home\": \"άνοιγμα αρχικής ροής\",\n  \"keyboard_shortcuts.hotkey\": \"Συντόμευση\",\n  \"keyboard_shortcuts.legend\": \"εμφάνιση αυτού του οδηγού\",\n  \"keyboard_shortcuts.local\": \"άνοιγμα τοπικής ροής\",\n  \"keyboard_shortcuts.mention\": \"αναφορά προς συγγραφέα\",\n  \"keyboard_shortcuts.muted\": \"άνοιγμα λίστας αποσιωπημενων χρηστών\",\n  \"keyboard_shortcuts.my_profile\": \"άνοιγμα του προφίλ σου\",\n  \"keyboard_shortcuts.notifications\": \"άνοιγμα στήλης ειδοποιήσεων\",\n  \"keyboard_shortcuts.pinned\": \"άνοιγμα λίστας καρφιτσωμένων τουτ\",\n  \"keyboard_shortcuts.profile\": \"άνοιγμα προφίλ συγγραφέα\",\n  \"keyboard_shortcuts.reply\": \"απάντηση\",\n  \"keyboard_shortcuts.requests\": \"άνοιγμα λίστας αιτημάτων παρακολούθησης\",\n  \"keyboard_shortcuts.search\": \"εστίαση αναζήτησης\",\n  \"keyboard_shortcuts.start\": \"άνοιγμα κολώνας \\\"Ξεκινώντας\\\"\",\n  \"keyboard_shortcuts.toggle_hidden\": \"εμφάνιση/απόκρυψη κειμένου πίσω από την προειδοποίηση\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"εμφάνιση/απόκρυψη πολυμέσων\",\n  \"keyboard_shortcuts.toot\": \"δημιουργία νέου τουτ\",\n  \"keyboard_shortcuts.unfocus\": \"απο-εστίαση του πεδίου σύνθεσης/αναζήτησης\",\n  \"keyboard_shortcuts.up\": \"κίνηση προς την κορυφή της λίστας\",\n  \"lightbox.close\": \"Κλείσιμο\",\n  \"lightbox.next\": \"Επόμενο\",\n  \"lightbox.previous\": \"Προηγούμενο\",\n  \"lightbox.view_context\": \"Εμφάνιση πλαισίου\",\n  \"lists.account.add\": \"Πρόσθεσε στη λίστα\",\n  \"lists.account.remove\": \"Βγάλε από τη λίστα\",\n  \"lists.delete\": \"Διαγραφή λίστας\",\n  \"lists.edit\": \"Επεξεργασία λίστας\",\n  \"lists.edit.submit\": \"Αλλαγή τίτλου\",\n  \"lists.new.create\": \"Προσθήκη λίστας\",\n  \"lists.new.title_placeholder\": \"Τίτλος νέας λίστα\",\n  \"lists.search\": \"Αναζήτησε μεταξύ των ανθρώπων που ακουλουθείς\",\n  \"lists.subheading\": \"Οι λίστες σου\",\n  \"loading_indicator.label\": \"Φορτώνει...\",\n  \"media_gallery.toggle_visible\": \"Εναλλαγή ορατότητας\",\n  \"missing_indicator.label\": \"Δε βρέθηκε\",\n  \"missing_indicator.sublabel\": \"Αδύνατη η εύρεση αυτού του πόρου\",\n  \"mute_modal.hide_notifications\": \"Απόκρυψη ειδοποιήσεων αυτού του χρήστη;\",\n  \"navigation_bar.apps\": \"Εφαρμογές φορητών συσκευών\",\n  \"navigation_bar.blocks\": \"Αποκλεισμένοι χρήστες\",\n  \"navigation_bar.community_timeline\": \"Τοπική ροή\",\n  \"navigation_bar.compose\": \"Γράψε νέο τουτ\",\n  \"navigation_bar.direct\": \"Προσωπικά μηνύματα\",\n  \"navigation_bar.discover\": \"Ανακάλυψη\",\n  \"navigation_bar.domain_blocks\": \"Κρυμμένοι τομείς\",\n  \"navigation_bar.edit_profile\": \"Επεξεργασία προφίλ\",\n  \"navigation_bar.favourites\": \"Αγαπημένα\",\n  \"navigation_bar.filters\": \"Αποσιωπημένες λέξεις\",\n  \"navigation_bar.follow_requests\": \"Αιτήματα ακολούθησης\",\n  \"navigation_bar.follows_and_followers\": \"Ακολουθεί και ακολουθείται\",\n  \"navigation_bar.info\": \"Πληροφορίες κόμβου\",\n  \"navigation_bar.keyboard_shortcuts\": \"Συντομεύσεις\",\n  \"navigation_bar.lists\": \"Λίστες\",\n  \"navigation_bar.logout\": \"Αποσύνδεση\",\n  \"navigation_bar.mutes\": \"Αποσιωπημένοι χρήστες\",\n  \"navigation_bar.personal\": \"Προσωπικά\",\n  \"navigation_bar.pins\": \"Καρφιτσωμένα τουτ\",\n  \"navigation_bar.preferences\": \"Προτιμήσεις\",\n  \"navigation_bar.profile_directory\": \"Κατάλογος λογαριασμών\",\n  \"navigation_bar.public_timeline\": \"Ομοσπονδιακή ροή\",\n  \"navigation_bar.security\": \"Ασφάλεια\",\n  \"notification.favourite\": \"Ο/Η {name} σημείωσε ως αγαπημένη την κατάστασή σου\",\n  \"notification.follow\": \"Ο/Η {name} σε ακολούθησε\",\n  \"notification.mention\": \"Ο/Η {name} σε ανέφερε\",\n  \"notification.poll\": \"Έλαβε τέλος μια από τις ψηφοφορίες που συμμετείχες\",\n  \"notification.reblog\": \"Ο/Η {name} προώθησε την κατάστασή σου\",\n  \"notifications.clear\": \"Καθαρισμός ειδοποιήσεων\",\n  \"notifications.clear_confirmation\": \"Σίγουρα θέλεις να καθαρίσεις όλες τις ειδοποιήσεις σου;\",\n  \"notifications.column_settings.alert\": \"Ειδοποιήσεις επιφάνειας εργασίας\",\n  \"notifications.column_settings.favourite\": \"Αγαπημένα:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Εμφάνιση όλων των κατηγοριών\",\n  \"notifications.column_settings.filter_bar.category\": \"Μπάρα γρήγορου φίλτρου\",\n  \"notifications.column_settings.filter_bar.show\": \"Εμφάνιση\",\n  \"notifications.column_settings.follow\": \"Νέοι ακόλουθοι:\",\n  \"notifications.column_settings.mention\": \"Αναφορές:\",\n  \"notifications.column_settings.poll\": \"Αποτελέσματα ψηφοφορίας:\",\n  \"notifications.column_settings.push\": \"Άμεσες ειδοποιήσεις\",\n  \"notifications.column_settings.reblog\": \"Προωθήσεις:\",\n  \"notifications.column_settings.show\": \"Εμφάνισε σε στήλη\",\n  \"notifications.column_settings.sound\": \"Ηχητική ειδοποίηση\",\n  \"notifications.filter.all\": \"Όλες\",\n  \"notifications.filter.boosts\": \"Προωθήσεις\",\n  \"notifications.filter.favourites\": \"Αγαπημένα\",\n  \"notifications.filter.follows\": \"Ακόλουθοι\",\n  \"notifications.filter.mentions\": \"Αναφορές\",\n  \"notifications.filter.polls\": \"Αποτελέσματα ψηφοφορίας\",\n  \"notifications.group\": \"{count} ειδοποιήσεις\",\n  \"poll.closed\": \"Κλειστή\",\n  \"poll.refresh\": \"Ανανέωση\",\n  \"poll.total_votes\": \"{count, plural, one {# ψήφος} other {# ψήφοι}}\",\n  \"poll.vote\": \"Ψήφισε\",\n  \"poll_button.add_poll\": \"Προσθήκη δημοσκόπησης\",\n  \"poll_button.remove_poll\": \"Αφαίρεση δημοσκόπησης\",\n  \"privacy.change\": \"Προσαρμογή ιδιωτικότητας δημοσίευσης\",\n  \"privacy.direct.long\": \"Δημοσίευση μόνο σε όσους και όσες αναφέρονται\",\n  \"privacy.direct.short\": \"Προσωπικά\",\n  \"privacy.private.long\": \"Δημοσίευση μόνο στους ακόλουθους\",\n  \"privacy.private.short\": \"Μόνο ακόλουθοι\",\n  \"privacy.public.long\": \"Δημοσίευσε στις δημόσιες ροές\",\n  \"privacy.public.short\": \"Δημόσιο\",\n  \"privacy.unlisted.long\": \"Μην δημοσιεύσεις στις δημόσιες ροές\",\n  \"privacy.unlisted.short\": \"Μη καταχωρημένα\",\n  \"regeneration_indicator.label\": \"Φορτώνει…\",\n  \"regeneration_indicator.sublabel\": \"Η αρχική σου ροή ετοιμάζεται!\",\n  \"relative_time.days\": \"{number}η\",\n  \"relative_time.hours\": \"{number}ω\",\n  \"relative_time.just_now\": \"τώρα\",\n  \"relative_time.minutes\": \"{number}λ\",\n  \"relative_time.seconds\": \"{number}δ\",\n  \"reply_indicator.cancel\": \"Άκυρο\",\n  \"report.forward\": \"Προώθηση προς {target}\",\n  \"report.forward_hint\": \"Ο λογαριασμός είναι από διαφορετικό διακομιστή. Να σταλεί ανώνυμο αντίγραφο της καταγγελίας κι εκεί;\",\n  \"report.hint\": \"Η καταγγελία θα σταλεί στους διαχειριστές του κόμβου σου. Μπορείς να περιγράψεις γιατί καταγγέλεις αυτόν το λογαριασμό παρακάτω:\",\n  \"report.placeholder\": \"Επιπλέον σχόλια\",\n  \"report.submit\": \"Υποβολή\",\n  \"report.target\": \"Καταγγελία {target}\",\n  \"search.placeholder\": \"Αναζήτηση\",\n  \"search_popout.search_format\": \"Προχωρημένη αναζήτηση\",\n  \"search_popout.tips.full_text\": \"Απλό κείμενο που επιστρέφει καταστάσεις που έχεις γράψει, σημειώσει ως αγαπημένες, προωθήσει ή έχεις αναφερθεί σε αυτές, καθώς και όσα ονόματα χρηστών και ταμπέλες ταιριάζουν.\",\n  \"search_popout.tips.hashtag\": \"ταμπέλα\",\n  \"search_popout.tips.status\": \"κατάσταση\",\n  \"search_popout.tips.text\": \"Απλό κείμενο που επιστρέφει ονόματα και ταμπέλες που ταιριάζουν\",\n  \"search_popout.tips.user\": \"χρήστης\",\n  \"search_results.accounts\": \"Άνθρωποι\",\n  \"search_results.hashtags\": \"Ταμπέλες\",\n  \"search_results.statuses\": \"Τουτ\",\n  \"search_results.total\": \"{count, number} {count, plural, zero {αποτελέσματα} one {αποτέλεσμα} other {αποτελέσματα}}\",\n  \"status.admin_account\": \"Άνοιγμα λειτουργίας διαμεσολάβησης για τον/την @{name}\",\n  \"status.admin_status\": \"Άνοιγμα αυτής της δημοσίευσης στη λειτουργία διαμεσολάβησης\",\n  \"status.block\": \"Αποκλεισμός @{name}\",\n  \"status.cancel_reblog_private\": \"Ακύρωσε την προώθηση\",\n  \"status.cannot_reblog\": \"Αυτή η δημοσίευση δεν μπορεί να προωθηθεί\",\n  \"status.copy\": \"Αντιγραφή συνδέσμου της δημοσίευσης\",\n  \"status.delete\": \"Διαγραφή\",\n  \"status.detailed_status\": \"Προβολή λεπτομερειών συζήτησης\",\n  \"status.direct\": \"Προσωπικό μήνυμα προς @{name}\",\n  \"status.embed\": \"Ενσωμάτωσε\",\n  \"status.favourite\": \"Σημείωσε ως αγαπημένο\",\n  \"status.filtered\": \"Φιλτραρισμένα\",\n  \"status.load_more\": \"Φόρτωσε περισσότερα\",\n  \"status.media_hidden\": \"Κρυμμένο πολυμέσο\",\n  \"status.mention\": \"Ανέφερε τον/την @{name}\",\n  \"status.more\": \"Περισσότερα\",\n  \"status.mute\": \"Σώπασε τον/την @{name}\",\n  \"status.mute_conversation\": \"Αποσιώπησε τη συζήτηση\",\n  \"status.open\": \"Διεύρυνε αυτή την κατάσταση\",\n  \"status.pin\": \"Καρφίτσωσε στο προφίλ\",\n  \"status.pinned\": \"Καρφιτσωμένο τουτ\",\n  \"status.read_more\": \"Περισσότερα\",\n  \"status.reblog\": \"Προώθησε\",\n  \"status.reblog_private\": \"Προώθησε στους αρχικούς παραλήπτες\",\n  \"status.reblogged_by\": \"{name} προώθησε\",\n  \"status.reblogs.empty\": \"Κανείς δεν προώθησε αυτό το τουτ ακόμα. Μόλις το κάνει κάποια, θα εμφανιστούν εδώ.\",\n  \"status.redraft\": \"Σβήσε & ξαναγράψε\",\n  \"status.reply\": \"Απάντησε\",\n  \"status.replyAll\": \"Απάντησε στην συζήτηση\",\n  \"status.report\": \"Κατάγγειλε @{name}\",\n  \"status.sensitive_warning\": \"Ευαίσθητο περιεχόμενο\",\n  \"status.share\": \"Μοιράσου\",\n  \"status.show_less\": \"Δείξε λιγότερα\",\n  \"status.show_less_all\": \"Δείξε λιγότερα για όλα\",\n  \"status.show_more\": \"Δείξε περισσότερα\",\n  \"status.show_more_all\": \"Δείξε περισσότερα για όλα\",\n  \"status.show_thread\": \"Εμφάνιση νήματος\",\n  \"status.unmute_conversation\": \"Διέκοψε την αποσιώπηση της συζήτησης\",\n  \"status.unpin\": \"Ξεκαρφίτσωσε από το προφίλ\",\n  \"suggestions.dismiss\": \"Απόρριψη πρότασης\",\n  \"suggestions.header\": \"Ίσως να ενδιαφέρεσαι για…\",\n  \"tabs_bar.federated_timeline\": \"Ομοσπονδιακή\",\n  \"tabs_bar.home\": \"Αρχική\",\n  \"tabs_bar.local_timeline\": \"Τοπικά\",\n  \"tabs_bar.notifications\": \"Ειδοποιήσεις\",\n  \"tabs_bar.search\": \"Αναζήτηση\",\n  \"time_remaining.days\": \"απομένουν {number, plural, one {# ημέρα} other {# ημέρες}}\",\n  \"time_remaining.hours\": \"απομένουν {number, plural, one {# ώρα} other {# ώρες}}\",\n  \"time_remaining.minutes\": \"απομένουν {number, plural, one {# λεπτό} other {# λεπτά}}\",\n  \"time_remaining.moments\": \"Απομένουν στιγμές\",\n  \"time_remaining.seconds\": \"απομένουν {number, plural, one {# δευτερόλεπτο} other {# δευτερόλεπτα}}\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {person} other {people}} μιλάνε\",\n  \"ui.beforeunload\": \"Το προσχέδιό σου θα χαθεί αν φύγεις από το Mastodon.\",\n  \"upload_area.title\": \"Drag & drop για να ανεβάσεις\",\n  \"upload_button.label\": \"Πρόσθεσε πολυμέσα (JPEG, PNG, GIF, WebM, MP4, MOV)\",\n  \"upload_error.limit\": \"Υπέρβαση ορίου μεγέθους ανεβασμένων αρχείων.\",\n  \"upload_error.poll\": \"Στις δημοσκοπήσεις δεν επιτρέπεται η μεταφόρτωση αρχείου.\",\n  \"upload_form.description\": \"Περιέγραψε για όσους & όσες έχουν προβλήματα όρασης\",\n  \"upload_form.focus\": \"Αλλαγή προεπισκόπησης\",\n  \"upload_form.undo\": \"Διαγραφή\",\n  \"upload_progress.label\": \"Ανεβαίνει...\",\n  \"video.close\": \"Κλείσε το βίντεο\",\n  \"video.exit_fullscreen\": \"Έξοδος από πλήρη οθόνη\",\n  \"video.expand\": \"Επέκταση βίντεο\",\n  \"video.fullscreen\": \"Πλήρης οθόνη\",\n  \"video.hide\": \"Κρύψε βίντεο\",\n  \"video.mute\": \"Σίγαση ήχου\",\n  \"video.pause\": \"Παύση\",\n  \"video.play\": \"Αναπαραγωγή\",\n  \"video.unmute\": \"Αναπαραγωγή ήχου\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/en.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Add or Remove from lists\",\n  \"account.badges.bot\": \"Bot\",\n  \"account.block\": \"Block @{name}\",\n  \"account.block_domain\": \"Hide everything from {domain}\",\n  \"account.blocked\": \"Blocked\",\n  \"account.direct\": \"Direct message @{name}\",\n  \"account.domain_blocked\": \"Domain hidden\",\n  \"account.edit_profile\": \"Edit profile\",\n  \"account.endorse\": \"Feature on profile\",\n  \"account.follow\": \"Follow\",\n  \"account.followers\": \"Followers\",\n  \"account.followers.empty\": \"No one follows this user yet.\",\n  \"account.follows\": \"Follows\",\n  \"account.follows.empty\": \"This user doesn't follow anyone yet.\",\n  \"account.follows_you\": \"Follows you\",\n  \"account.hide_reblogs\": \"Hide boosts from @{name}\",\n  \"account.link_verified_on\": \"Ownership of this link was checked on {date}\",\n  \"account.locked_info\": \"This account privacy status is set to locked. The owner manually reviews who can follow them.\",\n  \"account.media\": \"Media\",\n  \"account.mention\": \"Mention @{name}\",\n  \"account.moved_to\": \"{name} has moved to:\",\n  \"account.mute\": \"Mute @{name}\",\n  \"account.mute_notifications\": \"Mute notifications from @{name}\",\n  \"account.muted\": \"Muted\",\n  \"account.posts\": \"Toots\",\n  \"account.posts_with_replies\": \"Toots and replies\",\n  \"account.report\": \"Report @{name}\",\n  \"account.requested\": \"Awaiting approval. Click to cancel follow request\",\n  \"account.share\": \"Share @{name}'s profile\",\n  \"account.show_reblogs\": \"Show boosts from @{name}\",\n  \"account.unblock\": \"Unblock @{name}\",\n  \"account.unblock_domain\": \"Unhide {domain}\",\n  \"account.unendorse\": \"Don't feature on profile\",\n  \"account.unfollow\": \"Unfollow\",\n  \"account.unmute\": \"Unmute @{name}\",\n  \"account.unmute_notifications\": \"Unmute notifications from @{name}\",\n  \"alert.unexpected.message\": \"An unexpected error occurred.\",\n  \"alert.unexpected.title\": \"Oops!\",\n  \"boost_modal.combo\": \"You can press {combo} to skip this next time\",\n  \"bundle_column_error.body\": \"Something went wrong while loading this component.\",\n  \"bundle_column_error.retry\": \"Try again\",\n  \"bundle_column_error.title\": \"Network error\",\n  \"bundle_modal_error.close\": \"Close\",\n  \"bundle_modal_error.message\": \"Something went wrong while loading this component.\",\n  \"bundle_modal_error.retry\": \"Try again\",\n  \"column.blocks\": \"Blocked users\",\n  \"column.community\": \"Local timeline\",\n  \"column.direct\": \"Direct messages\",\n  \"column.domain_blocks\": \"Hidden domains\",\n  \"column.favourites\": \"Favourites\",\n  \"column.follow_requests\": \"Follow requests\",\n  \"column.home\": \"Home\",\n  \"column.lists\": \"Lists\",\n  \"column.mutes\": \"Muted users\",\n  \"column.notifications\": \"Notifications\",\n  \"column.pins\": \"Pinned toots\",\n  \"column.public\": \"Federated timeline\",\n  \"column_back_button.label\": \"Back\",\n  \"column_header.hide_settings\": \"Hide settings\",\n  \"column_header.moveLeft_settings\": \"Move column to the left\",\n  \"column_header.moveRight_settings\": \"Move column to the right\",\n  \"column_header.pin\": \"Pin\",\n  \"column_header.show_settings\": \"Show settings\",\n  \"column_header.unpin\": \"Unpin\",\n  \"column_subheading.settings\": \"Settings\",\n  \"community.column_settings.media_only\": \"Media Only\",\n  \"compose_form.direct_message_warning\": \"This toot will only be sent to the mentioned users.\",\n  \"compose_form.direct_message_warning_learn_more\": \"Learn more\",\n  \"compose_form.hashtag_warning\": \"This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.\",\n  \"compose_form.lock_disclaimer\": \"Your account is not {locked}. Anyone can follow you to view your follower-only posts.\",\n  \"compose_form.lock_disclaimer.lock\": \"locked\",\n  \"compose_form.placeholder\": \"What's on your mind?\",\n  \"compose_form.poll.add_option\": \"Add a choice\",\n  \"compose_form.poll.duration\": \"Poll duration\",\n  \"compose_form.poll.option_placeholder\": \"Choice {number}\",\n  \"compose_form.poll.remove_option\": \"Remove this choice\",\n  \"compose_form.publish\": \"Toot\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"Mark media as sensitive\",\n  \"compose_form.sensitive.marked\": \"Media is marked as sensitive\",\n  \"compose_form.sensitive.unmarked\": \"Media is not marked as sensitive\",\n  \"compose_form.spoiler.marked\": \"Text is hidden behind warning\",\n  \"compose_form.spoiler.unmarked\": \"Text is not hidden\",\n  \"compose_form.spoiler_placeholder\": \"Write your warning here\",\n  \"confirmation_modal.cancel\": \"Cancel\",\n  \"confirmations.block.block_and_report\": \"Block & Report\",\n  \"confirmations.block.confirm\": \"Block\",\n  \"confirmations.block.message\": \"Are you sure you want to block {name}?\",\n  \"confirmations.delete.confirm\": \"Delete\",\n  \"confirmations.delete.message\": \"Are you sure you want to delete this status?\",\n  \"confirmations.delete_list.confirm\": \"Delete\",\n  \"confirmations.delete_list.message\": \"Are you sure you want to permanently delete this list?\",\n  \"confirmations.domain_block.confirm\": \"Hide entire domain\",\n  \"confirmations.domain_block.message\": \"Blocking means you will not see content from {domain} in any public timelines or your notifications. Any followers from {domain} will also be removed.\",\n  \"confirmations.mute.confirm\": \"Mute\",\n  \"confirmations.mute.message\": \"Are you sure you want to mute {name}?\",\n  \"confirmations.redraft.confirm\": \"Delete & redraft\",\n  \"confirmations.redraft.message\": \"Are you sure you want to delete this status and re-draft it? Favourites and boosts will be lost, and replies to the original post will be orphaned.\",\n  \"confirmations.reply.confirm\": \"Reply\",\n  \"confirmations.reply.message\": \"Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?\",\n  \"confirmations.unfollow.confirm\": \"Unfollow\",\n  \"confirmations.unfollow.message\": \"Are you sure you want to unfollow {name}?\",\n  \"embed.instructions\": \"Embed this status on your website by copying the code below.\",\n  \"embed.preview\": \"Here is what it will look like:\",\n  \"emoji_button.activity\": \"Activity\",\n  \"emoji_button.custom\": \"Custom\",\n  \"emoji_button.flags\": \"Flags\",\n  \"emoji_button.food\": \"Food & Drink\",\n  \"emoji_button.label\": \"Insert emoji\",\n  \"emoji_button.nature\": \"Nature\",\n  \"emoji_button.not_found\": \"No emojos!! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"Objects\",\n  \"emoji_button.people\": \"People\",\n  \"emoji_button.recent\": \"Frequently used\",\n  \"emoji_button.search\": \"Search...\",\n  \"emoji_button.search_results\": \"Search results\",\n  \"emoji_button.symbols\": \"Symbols\",\n  \"emoji_button.travel\": \"Travel & Places\",\n  \"empty_column.account_timeline\": \"No toots here!\",\n  \"empty_column.account_unavailable\": \"Profile unavailable\",\n  \"empty_column.blocks\": \"You haven't blocked any users yet.\",\n  \"empty_column.community\": \"The local timeline is empty. Write something publicly to get the ball rolling!\",\n  \"empty_column.direct\": \"You don't have any direct messages yet. When you send or receive one, it will show up here.\",\n  \"empty_column.domain_blocks\": \"There are no hidden domains yet.\",\n  \"empty_column.favourited_statuses\": \"You don't have any favourite toots yet. When you favourite one, it will show up here.\",\n  \"empty_column.favourites\": \"No one has favourited this toot yet. When someone does, they will show up here.\",\n  \"empty_column.follow_requests\": \"You don't have any follow requests yet. When you receive one, it will show up here.\",\n  \"empty_column.hashtag\": \"There is nothing in this hashtag yet.\",\n  \"empty_column.home\": \"Your home timeline is empty! Visit {public} or use search to get started and meet other users.\",\n  \"empty_column.home.public_timeline\": \"the public timeline\",\n  \"empty_column.list\": \"There is nothing in this list yet. When members of this list post new statuses, they will appear here.\",\n  \"empty_column.lists\": \"You don't have any lists yet. When you create one, it will show up here.\",\n  \"empty_column.mutes\": \"You haven't muted any users yet.\",\n  \"empty_column.notifications\": \"You don't have any notifications yet. Interact with others to start the conversation.\",\n  \"empty_column.public\": \"There is nothing here! Write something publicly, or manually follow users from other servers to fill it up\",\n  \"follow_request.authorize\": \"Authorize\",\n  \"follow_request.reject\": \"Reject\",\n  \"getting_started.developers\": \"Developers\",\n  \"getting_started.directory\": \"Profile directory\",\n  \"getting_started.documentation\": \"Documentation\",\n  \"getting_started.heading\": \"Getting started\",\n  \"getting_started.invite\": \"Invite people\",\n  \"getting_started.open_source_notice\": \"Mastodon is open source software. You can contribute or report issues on GitHub at {github}.\",\n  \"getting_started.security\": \"Security\",\n  \"getting_started.terms\": \"Terms of service\",\n  \"hashtag.column_header.tag_mode.all\": \"and {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"or {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"without {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"No suggestions found\",\n  \"hashtag.column_settings.select.placeholder\": \"Enter hashtags…\",\n  \"hashtag.column_settings.tag_mode.all\": \"All of these\",\n  \"hashtag.column_settings.tag_mode.any\": \"Any of these\",\n  \"hashtag.column_settings.tag_mode.none\": \"None of these\",\n  \"hashtag.column_settings.tag_toggle\": \"Include additional tags for this column\",\n  \"home.column_settings.basic\": \"Basic\",\n  \"home.column_settings.show_reblogs\": \"Show boosts\",\n  \"home.column_settings.show_replies\": \"Show replies\",\n  \"intervals.full.days\": \"{number, plural, one {# day} other {# days}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# hour} other {# hours}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minute} other {# minutes}}\",\n  \"introduction.federation.action\": \"Next\",\n  \"introduction.federation.federated.headline\": \"Federated\",\n  \"introduction.federation.federated.text\": \"Public posts from other servers of the fediverse will appear in the federated timeline.\",\n  \"introduction.federation.home.headline\": \"Home\",\n  \"introduction.federation.home.text\": \"Posts from people you follow will appear in your home feed. You can follow anyone on any server!\",\n  \"introduction.federation.local.headline\": \"Local\",\n  \"introduction.federation.local.text\": \"Public posts from people on the same server as you will appear in the local timeline.\",\n  \"introduction.interactions.action\": \"Finish tutorial!\",\n  \"introduction.interactions.favourite.headline\": \"Favourite\",\n  \"introduction.interactions.favourite.text\": \"You can save a toot for later, and let the author know that you liked it, by favouriting it.\",\n  \"introduction.interactions.reblog.headline\": \"Boost\",\n  \"introduction.interactions.reblog.text\": \"You can share other people's toots with your followers by boosting them.\",\n  \"introduction.interactions.reply.headline\": \"Reply\",\n  \"introduction.interactions.reply.text\": \"You can reply to other people's and your own toots, which will chain them together in a conversation.\",\n  \"introduction.welcome.action\": \"Let's go!\",\n  \"introduction.welcome.headline\": \"First steps\",\n  \"introduction.welcome.text\": \"Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.\",\n  \"keyboard_shortcuts.back\": \"to navigate back\",\n  \"keyboard_shortcuts.blocked\": \"to open blocked users list\",\n  \"keyboard_shortcuts.boost\": \"to boost\",\n  \"keyboard_shortcuts.column\": \"to focus a status in one of the columns\",\n  \"keyboard_shortcuts.compose\": \"to focus the compose textarea\",\n  \"keyboard_shortcuts.description\": \"Description\",\n  \"keyboard_shortcuts.direct\": \"to open direct messages column\",\n  \"keyboard_shortcuts.down\": \"to move down in the list\",\n  \"keyboard_shortcuts.enter\": \"to open status\",\n  \"keyboard_shortcuts.favourite\": \"to favourite\",\n  \"keyboard_shortcuts.favourites\": \"to open favourites list\",\n  \"keyboard_shortcuts.federated\": \"to open federated timeline\",\n  \"keyboard_shortcuts.heading\": \"Keyboard shortcuts\",\n  \"keyboard_shortcuts.home\": \"to open home timeline\",\n  \"keyboard_shortcuts.hotkey\": \"Hotkey\",\n  \"keyboard_shortcuts.legend\": \"to display this legend\",\n  \"keyboard_shortcuts.local\": \"to open local timeline\",\n  \"keyboard_shortcuts.mention\": \"to mention author\",\n  \"keyboard_shortcuts.muted\": \"to open muted users list\",\n  \"keyboard_shortcuts.my_profile\": \"to open your profile\",\n  \"keyboard_shortcuts.notifications\": \"to open notifications column\",\n  \"keyboard_shortcuts.pinned\": \"to open pinned toots list\",\n  \"keyboard_shortcuts.profile\": \"to open author's profile\",\n  \"keyboard_shortcuts.reply\": \"to reply\",\n  \"keyboard_shortcuts.requests\": \"to open follow requests list\",\n  \"keyboard_shortcuts.search\": \"to focus search\",\n  \"keyboard_shortcuts.start\": \"to open \\\"get started\\\" column\",\n  \"keyboard_shortcuts.toggle_hidden\": \"to show/hide text behind CW\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"to show/hide media\",\n  \"keyboard_shortcuts.toot\": \"to start a brand new toot\",\n  \"keyboard_shortcuts.unfocus\": \"to un-focus compose textarea/search\",\n  \"keyboard_shortcuts.up\": \"to move up in the list\",\n  \"lightbox.close\": \"Close\",\n  \"lightbox.next\": \"Next\",\n  \"lightbox.previous\": \"Previous\",\n  \"lightbox.view_context\": \"View context\",\n  \"lists.account.add\": \"Add to list\",\n  \"lists.account.remove\": \"Remove from list\",\n  \"lists.delete\": \"Delete list\",\n  \"lists.edit\": \"Edit list\",\n  \"lists.edit.submit\": \"Change title\",\n  \"lists.new.create\": \"Add list\",\n  \"lists.new.title_placeholder\": \"New list title\",\n  \"lists.search\": \"Search among people you follow\",\n  \"lists.subheading\": \"Your lists\",\n  \"loading_indicator.label\": \"Loading...\",\n  \"media_gallery.toggle_visible\": \"Toggle visibility\",\n  \"missing_indicator.label\": \"Not found\",\n  \"missing_indicator.sublabel\": \"This resource could not be found\",\n  \"mute_modal.hide_notifications\": \"Hide notifications from this user?\",\n  \"navigation_bar.apps\": \"Mobile apps\",\n  \"navigation_bar.blocks\": \"Blocked users\",\n  \"navigation_bar.community_timeline\": \"Local timeline\",\n  \"navigation_bar.compose\": \"Compose new toot\",\n  \"navigation_bar.direct\": \"Direct messages\",\n  \"navigation_bar.discover\": \"Discover\",\n  \"navigation_bar.domain_blocks\": \"Hidden domains\",\n  \"navigation_bar.edit_profile\": \"Edit profile\",\n  \"navigation_bar.favourites\": \"Favourites\",\n  \"navigation_bar.filters\": \"Muted words\",\n  \"navigation_bar.follow_requests\": \"Follow requests\",\n  \"navigation_bar.follows_and_followers\": \"Follows and followers\",\n  \"navigation_bar.info\": \"About this server\",\n  \"navigation_bar.keyboard_shortcuts\": \"Hotkeys\",\n  \"navigation_bar.lists\": \"Lists\",\n  \"navigation_bar.logout\": \"Logout\",\n  \"navigation_bar.mutes\": \"Muted users\",\n  \"navigation_bar.personal\": \"Personal\",\n  \"navigation_bar.pins\": \"Pinned toots\",\n  \"navigation_bar.preferences\": \"Preferences\",\n  \"navigation_bar.profile_directory\": \"Profile directory\",\n  \"navigation_bar.public_timeline\": \"Federated timeline\",\n  \"navigation_bar.security\": \"Security\",\n  \"notification.favourite\": \"{name} favourited your status\",\n  \"notification.follow\": \"{name} followed you\",\n  \"notification.mention\": \"{name} mentioned you\",\n  \"notification.poll\": \"A poll you have voted in has ended\",\n  \"notification.reblog\": \"{name} boosted your status\",\n  \"notifications.clear\": \"Clear notifications\",\n  \"notifications.clear_confirmation\": \"Are you sure you want to permanently clear all your notifications?\",\n  \"notifications.column_settings.alert\": \"Desktop notifications\",\n  \"notifications.column_settings.favourite\": \"Favourites:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Display all categories\",\n  \"notifications.column_settings.filter_bar.category\": \"Quick filter bar\",\n  \"notifications.column_settings.filter_bar.show\": \"Show\",\n  \"notifications.column_settings.follow\": \"New followers:\",\n  \"notifications.column_settings.mention\": \"Mentions:\",\n  \"notifications.column_settings.poll\": \"Poll results:\",\n  \"notifications.column_settings.push\": \"Push notifications\",\n  \"notifications.column_settings.reblog\": \"Boosts:\",\n  \"notifications.column_settings.show\": \"Show in column\",\n  \"notifications.column_settings.sound\": \"Play sound\",\n  \"notifications.filter.all\": \"All\",\n  \"notifications.filter.boosts\": \"Boosts\",\n  \"notifications.filter.favourites\": \"Favourites\",\n  \"notifications.filter.follows\": \"Follows\",\n  \"notifications.filter.mentions\": \"Mentions\",\n  \"notifications.filter.polls\": \"Poll results\",\n  \"notifications.group\": \"{count} notifications\",\n  \"poll.closed\": \"Closed\",\n  \"poll.refresh\": \"Refresh\",\n  \"poll.total_votes\": \"{count, plural, one {# vote} other {# votes}}\",\n  \"poll.vote\": \"Vote\",\n  \"poll_button.add_poll\": \"Add a poll\",\n  \"poll_button.remove_poll\": \"Remove poll\",\n  \"privacy.change\": \"Adjust status privacy\",\n  \"privacy.direct.long\": \"Post to mentioned users only\",\n  \"privacy.direct.short\": \"Direct\",\n  \"privacy.private.long\": \"Post to followers only\",\n  \"privacy.private.short\": \"Followers-only\",\n  \"privacy.public.long\": \"Post to public timelines\",\n  \"privacy.public.short\": \"Public\",\n  \"privacy.unlisted.long\": \"Do not post to public timelines\",\n  \"privacy.unlisted.short\": \"Unlisted\",\n  \"regeneration_indicator.label\": \"Loading…\",\n  \"regeneration_indicator.sublabel\": \"Your home feed is being prepared!\",\n  \"relative_time.days\": \"{number}d\",\n  \"relative_time.hours\": \"{number}h\",\n  \"relative_time.just_now\": \"now\",\n  \"relative_time.minutes\": \"{number}m\",\n  \"relative_time.seconds\": \"{number}s\",\n  \"reply_indicator.cancel\": \"Cancel\",\n  \"report.forward\": \"Forward to {target}\",\n  \"report.forward_hint\": \"The account is from another server. Send an anonymized copy of the report there as well?\",\n  \"report.hint\": \"The report will be sent to your server moderators. You can provide an explanation of why you are reporting this account below:\",\n  \"report.placeholder\": \"Additional comments\",\n  \"report.submit\": \"Submit\",\n  \"report.target\": \"Reporting {target}\",\n  \"search.placeholder\": \"Search\",\n  \"search_popout.search_format\": \"Advanced search format\",\n  \"search_popout.tips.full_text\": \"Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.\",\n  \"search_popout.tips.hashtag\": \"hashtag\",\n  \"search_popout.tips.status\": \"status\",\n  \"search_popout.tips.text\": \"Simple text returns matching display names, usernames and hashtags\",\n  \"search_popout.tips.user\": \"user\",\n  \"search_results.accounts\": \"People\",\n  \"search_results.hashtags\": \"Hashtags\",\n  \"search_results.statuses\": \"Toots\",\n  \"search_results.total\": \"{count, number} {count, plural, one {result} other {results}}\",\n  \"status.admin_account\": \"Open moderation interface for @{name}\",\n  \"status.admin_status\": \"Open this status in the moderation interface\",\n  \"status.block\": \"Block @{name}\",\n  \"status.cancel_reblog_private\": \"Unboost\",\n  \"status.cannot_reblog\": \"This post cannot be boosted\",\n  \"status.copy\": \"Copy link to status\",\n  \"status.delete\": \"Delete\",\n  \"status.detailed_status\": \"Detailed conversation view\",\n  \"status.direct\": \"Direct message @{name}\",\n  \"status.embed\": \"Embed\",\n  \"status.favourite\": \"Favourite\",\n  \"status.filtered\": \"Filtered\",\n  \"status.load_more\": \"Load more\",\n  \"status.media_hidden\": \"Media hidden\",\n  \"status.mention\": \"Mention @{name}\",\n  \"status.more\": \"More\",\n  \"status.mute\": \"Mute @{name}\",\n  \"status.mute_conversation\": \"Mute conversation\",\n  \"status.open\": \"Expand this status\",\n  \"status.pin\": \"Pin on profile\",\n  \"status.pinned\": \"Pinned toot\",\n  \"status.read_more\": \"Read more\",\n  \"status.reblog\": \"Boost\",\n  \"status.reblog_private\": \"Boost to original audience\",\n  \"status.reblogged_by\": \"{name} boosted\",\n  \"status.reblogs.empty\": \"No one has boosted this toot yet. When someone does, they will show up here.\",\n  \"status.redraft\": \"Delete & re-draft\",\n  \"status.reply\": \"Reply\",\n  \"status.replyAll\": \"Reply to thread\",\n  \"status.report\": \"Report @{name}\",\n  \"status.sensitive_warning\": \"Sensitive content\",\n  \"status.share\": \"Share\",\n  \"status.show_less\": \"Show less\",\n  \"status.show_less_all\": \"Show less for all\",\n  \"status.show_more\": \"Show more\",\n  \"status.show_more_all\": \"Show more for all\",\n  \"status.show_thread\": \"Show thread\",\n  \"status.unmute_conversation\": \"Unmute conversation\",\n  \"status.unpin\": \"Unpin from profile\",\n  \"suggestions.dismiss\": \"Dismiss suggestion\",\n  \"suggestions.header\": \"You might be interested in…\",\n  \"tabs_bar.federated_timeline\": \"Federated\",\n  \"tabs_bar.home\": \"Home\",\n  \"tabs_bar.local_timeline\": \"Local\",\n  \"tabs_bar.notifications\": \"Notifications\",\n  \"tabs_bar.search\": \"Search\",\n  \"time_remaining.days\": \"{number, plural, one {# day} other {# days}} left\",\n  \"time_remaining.hours\": \"{number, plural, one {# hour} other {# hours}} left\",\n  \"time_remaining.minutes\": \"{number, plural, one {# minute} other {# minutes}} left\",\n  \"time_remaining.moments\": \"Moments remaining\",\n  \"time_remaining.seconds\": \"{number, plural, one {# second} other {# seconds}} left\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {person} other {people}} talking\",\n  \"ui.beforeunload\": \"Your draft will be lost if you leave Mastodon.\",\n  \"upload_area.title\": \"Drag & drop to upload\",\n  \"upload_button.label\": \"Add media (JPEG, PNG, GIF, WebM, MP4, MOV)\",\n  \"upload_error.limit\": \"File upload limit exceeded.\",\n  \"upload_error.poll\": \"File upload not allowed with polls.\",\n  \"upload_form.description\": \"Describe for the visually impaired\",\n  \"upload_form.focus\": \"Change preview\",\n  \"upload_form.undo\": \"Delete\",\n  \"upload_progress.label\": \"Uploading...\",\n  \"video.close\": \"Close video\",\n  \"video.exit_fullscreen\": \"Exit full screen\",\n  \"video.expand\": \"Expand video\",\n  \"video.fullscreen\": \"Full screen\",\n  \"video.hide\": \"Hide video\",\n  \"video.mute\": \"Mute sound\",\n  \"video.pause\": \"Pause\",\n  \"video.play\": \"Play\",\n  \"video.unmute\": \"Unmute sound\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/eo.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Aldoni al aŭ forigi el listoj\",\n  \"account.badges.bot\": \"Roboto\",\n  \"account.block\": \"Bloki @{name}\",\n  \"account.block_domain\": \"Kaŝi ĉion de {domain}\",\n  \"account.blocked\": \"Blokita\",\n  \"account.direct\": \"Rekte mesaĝi @{name}\",\n  \"account.domain_blocked\": \"Domajno kaŝita\",\n  \"account.edit_profile\": \"Redakti profilon\",\n  \"account.endorse\": \"Montri en profilo\",\n  \"account.follow\": \"Sekvi\",\n  \"account.followers\": \"Sekvantoj\",\n  \"account.followers.empty\": \"Ankoraŭ neniu sekvas tiun uzanton.\",\n  \"account.follows\": \"Sekvatoj\",\n  \"account.follows.empty\": \"Tiu uzanto ankoraŭ ne sekvas iun.\",\n  \"account.follows_you\": \"Sekvas vin\",\n  \"account.hide_reblogs\": \"Kaŝi diskonigojn de @{name}\",\n  \"account.link_verified_on\": \"La posedanto de tiu ligilo estis kontrolita je {date}\",\n  \"account.locked_info\": \"La privateco de tiu konto estas elektita kiel fermita. La posedanto povas mane akcepti tiun, kiu povas sekvi rin.\",\n  \"account.media\": \"Aŭdovidaĵoj\",\n  \"account.mention\": \"Mencii @{name}\",\n  \"account.moved_to\": \"{name} moviĝis al:\",\n  \"account.mute\": \"Silentigi @{name}\",\n  \"account.mute_notifications\": \"Silentigi sciigojn el @{name}\",\n  \"account.muted\": \"Silentigita\",\n  \"account.posts\": \"Mesaĝoj\",\n  \"account.posts_with_replies\": \"Kun respondoj\",\n  \"account.report\": \"Signali @{name}\",\n  \"account.requested\": \"Atendo de aprobo. Alklaku por nuligi peton de sekvado\",\n  \"account.share\": \"Diskonigi la profilon de @{name}\",\n  \"account.show_reblogs\": \"Montri diskonigojn de @{name}\",\n  \"account.unblock\": \"Malbloki @{name}\",\n  \"account.unblock_domain\": \"Malkaŝi {domain}\",\n  \"account.unendorse\": \"Ne montri en profilo\",\n  \"account.unfollow\": \"Ne plu sekvi\",\n  \"account.unmute\": \"Malsilentigi @{name}\",\n  \"account.unmute_notifications\": \"Malsilentigi sciigojn de @{name}\",\n  \"alert.unexpected.message\": \"Neatendita eraro okazis.\",\n  \"alert.unexpected.title\": \"Ups!\",\n  \"boost_modal.combo\": \"Vi povas premi {combo} por preterpasi sekvafoje\",\n  \"bundle_column_error.body\": \"Io misfunkciis en la ŝargado de ĉi tiu elemento.\",\n  \"bundle_column_error.retry\": \"Bonvolu reprovi\",\n  \"bundle_column_error.title\": \"Reta eraro\",\n  \"bundle_modal_error.close\": \"Fermi\",\n  \"bundle_modal_error.message\": \"Io misfunkciis en la ŝargado de ĉi tiu elemento.\",\n  \"bundle_modal_error.retry\": \"Bonvolu reprovi\",\n  \"column.blocks\": \"Blokitaj uzantoj\",\n  \"column.community\": \"Loka tempolinio\",\n  \"column.direct\": \"Rektaj mesaĝoj\",\n  \"column.domain_blocks\": \"Kaŝitaj domajnoj\",\n  \"column.favourites\": \"Stelumoj\",\n  \"column.follow_requests\": \"Petoj de sekvado\",\n  \"column.home\": \"Hejmo\",\n  \"column.lists\": \"Listoj\",\n  \"column.mutes\": \"Silentigitaj uzantoj\",\n  \"column.notifications\": \"Sciigoj\",\n  \"column.pins\": \"Alpinglitaj mesaĝoj\",\n  \"column.public\": \"Fratara tempolinio\",\n  \"column_back_button.label\": \"Reveni\",\n  \"column_header.hide_settings\": \"Kaŝi agordojn\",\n  \"column_header.moveLeft_settings\": \"Movi kolumnon maldekstren\",\n  \"column_header.moveRight_settings\": \"Movi kolumnon dekstren\",\n  \"column_header.pin\": \"Alpingli\",\n  \"column_header.show_settings\": \"Montri agordojn\",\n  \"column_header.unpin\": \"Depingli\",\n  \"column_subheading.settings\": \"Agordado\",\n  \"community.column_settings.media_only\": \"Nur aŭdovidaĵoj\",\n  \"compose_form.direct_message_warning\": \"Tiu mesaĝo estos sendita nur al menciitaj uzantoj.\",\n  \"compose_form.direct_message_warning_learn_more\": \"Lerni pli\",\n  \"compose_form.hashtag_warning\": \"Ĉi tiu mesaĝo ne estos listigita per ajna kradvorto. Nur publikaj mesaĝoj estas serĉeblaj per kradvortoj.\",\n  \"compose_form.lock_disclaimer\": \"Via konta ne estas {locked}. Iu ajn povas sekvi vin por vidi viajn mesaĝojn, kiuj estas nur por sekvantoj.\",\n  \"compose_form.lock_disclaimer.lock\": \"ŝlosita\",\n  \"compose_form.placeholder\": \"Pri kio vi pensas?\",\n  \"compose_form.poll.add_option\": \"Aldoni elekto\",\n  \"compose_form.poll.duration\": \"Balotenketo daŭro\",\n  \"compose_form.poll.option_placeholder\": \"elekto {number}\",\n  \"compose_form.poll.remove_option\": \"Forigi ĉi tiu elekton\",\n  \"compose_form.publish\": \"Hup\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"Marki aŭdovidaĵojn kiel tiklaj\",\n  \"compose_form.sensitive.marked\": \"Aŭdovidaĵo markita tikla\",\n  \"compose_form.sensitive.unmarked\": \"Aŭdovidaĵo ne markita tikla\",\n  \"compose_form.spoiler.marked\": \"Teksto kaŝita malantaŭ averto\",\n  \"compose_form.spoiler.unmarked\": \"Teksto ne kaŝita\",\n  \"compose_form.spoiler_placeholder\": \"Skribu vian averton ĉi tie\",\n  \"confirmation_modal.cancel\": \"Nuligi\",\n  \"confirmations.block.block_and_report\": \"Bloki & Signali\",\n  \"confirmations.block.confirm\": \"Bloki\",\n  \"confirmations.block.message\": \"Ĉu vi certas, ke vi volas bloki {name}?\",\n  \"confirmations.delete.confirm\": \"Forigi\",\n  \"confirmations.delete.message\": \"Ĉu vi certas, ke vi volas forigi ĉi tiun mesaĝon?\",\n  \"confirmations.delete_list.confirm\": \"Forigi\",\n  \"confirmations.delete_list.message\": \"Ĉu vi certas, ke vi volas porĉiame forigi ĉi tiun liston?\",\n  \"confirmations.domain_block.confirm\": \"Kaŝi la tutan domajnon\",\n  \"confirmations.domain_block.message\": \"Ĉu vi vere, vere certas, ke vi volas tute bloki {domain}? Plej ofte, trafa blokado kaj silentigado sufiĉas kaj preferindas. Vi ne vidos enhavon de tiu domajno en publika tempolinio aŭ en viaj sciigoj. Viaj sekvantoj de tiu domajno estos forigitaj.\",\n  \"confirmations.mute.confirm\": \"Silentigi\",\n  \"confirmations.mute.message\": \"Ĉu vi certas, ke vi volas silentigi {name}?\",\n  \"confirmations.redraft.confirm\": \"Forigi kaj reskribi\",\n  \"confirmations.redraft.message\": \"Ĉu vi certas ke vi volas forigi tiun mesaĝon kaj reskribi ĝin? Ĉiuj diskonigoj kaj stelumoj estos perditaj, kaj respondoj al la originala mesaĝo estos senparentaj.\",\n  \"confirmations.reply.confirm\": \"Respondi\",\n  \"confirmations.reply.message\": \"Respondi nun anstataŭigos la mesaĝon, kiun vi nun skribas. Ĉu vi certas, ke vi volas daŭrigi?\",\n  \"confirmations.unfollow.confirm\": \"Ne plu sekvi\",\n  \"confirmations.unfollow.message\": \"Ĉu vi certas, ke vi volas ĉesi sekvi {name}?\",\n  \"embed.instructions\": \"Enkorpigu ĉi tiun mesaĝon en vian retejon per kopio de la suba kodo.\",\n  \"embed.preview\": \"Ĝi aperos tiel:\",\n  \"emoji_button.activity\": \"Agadoj\",\n  \"emoji_button.custom\": \"Propraj\",\n  \"emoji_button.flags\": \"Flagoj\",\n  \"emoji_button.food\": \"Manĝi kaj trinki\",\n  \"emoji_button.label\": \"Enmeti emoĝion\",\n  \"emoji_button.nature\": \"Naturo\",\n  \"emoji_button.not_found\": \"Neniu emoĝio!! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"Aĵoj\",\n  \"emoji_button.people\": \"Homoj\",\n  \"emoji_button.recent\": \"Ofte uzataj\",\n  \"emoji_button.search\": \"Serĉo…\",\n  \"emoji_button.search_results\": \"Serĉaj rezultoj\",\n  \"emoji_button.symbols\": \"Simboloj\",\n  \"emoji_button.travel\": \"Vojaĝoj kaj lokoj\",\n  \"empty_column.account_timeline\": \"Neniu mesaĝo ĉi tie!\",\n  \"empty_column.account_unavailable\": \"Profilo ne disponebla\",\n  \"empty_column.blocks\": \"Vi ankoraŭ ne blokis uzanton.\",\n  \"empty_column.community\": \"La loka tempolinio estas malplena. Skribu ion por plenigi ĝin!\",\n  \"empty_column.direct\": \"Vi ankoraŭ ne havas rektan mesaĝon. Kiam vi sendos aŭ ricevos iun, ĝi aperos ĉi tie.\",\n  \"empty_column.domain_blocks\": \"Ankoraŭ neniu domajno estas blokita.\",\n  \"empty_column.favourited_statuses\": \"Vi ankoraŭ ne stelumis mesaĝon. Kiam vi stelumos iun, tiu aperos ĉi tie.\",\n  \"empty_column.favourites\": \"Ankoraŭ neniu stelumis tiun mesaĝon. Kiam iu faros tion, tiu aperos ĉi tie.\",\n  \"empty_column.follow_requests\": \"Vi ne ankoraŭ havas iun peton de sekvado. Kiam vi ricevos unu, ĝi aperos ĉi tie.\",\n  \"empty_column.hashtag\": \"Ankoraŭ estas nenio per ĉi tiu kradvorto.\",\n  \"empty_column.home\": \"Via hejma tempolinio estas malplena! Vizitu {public} aŭ uzu la serĉilon por renkonti aliajn uzantojn.\",\n  \"empty_column.home.public_timeline\": \"la publikan tempolinion\",\n  \"empty_column.list\": \"Ankoraŭ estas nenio en ĉi tiu listo. Kiam membroj de ĉi tiu listo afiŝos novajn mesaĝojn, ili aperos ĉi tie.\",\n  \"empty_column.lists\": \"Vi ankoraŭ ne havas liston. Kiam vi kreos iun, ĝi aperos ĉi tie.\",\n  \"empty_column.mutes\": \"Vi ne ankoraŭ silentigis iun uzanton.\",\n  \"empty_column.notifications\": \"Vi ankoraŭ ne havas sciigojn. Interagu kun aliaj por komenci konversacion.\",\n  \"empty_column.public\": \"Estas nenio ĉi tie! Publike skribu ion, aŭ mane sekvu uzantojn de aliaj serviloj por plenigi la publikan tempolinion\",\n  \"follow_request.authorize\": \"Rajtigi\",\n  \"follow_request.reject\": \"Rifuzi\",\n  \"getting_started.developers\": \"Programistoj\",\n  \"getting_started.directory\": \"Profilujo\",\n  \"getting_started.documentation\": \"Dokumentado\",\n  \"getting_started.heading\": \"Por komenci\",\n  \"getting_started.invite\": \"Inviti homojn\",\n  \"getting_started.open_source_notice\": \"Mastodon estas malfermitkoda programo. Vi povas kontribui aŭ raporti problemojn en GitHub je {github}.\",\n  \"getting_started.security\": \"Sekureco\",\n  \"getting_started.terms\": \"Uzkondiĉoj\",\n  \"hashtag.column_header.tag_mode.all\": \"kaj {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"aŭ {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"sen {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"Neniu sugesto trovita\",\n  \"hashtag.column_settings.select.placeholder\": \"Enmeti kradvortojn…\",\n  \"hashtag.column_settings.tag_mode.all\": \"Ĉiuj\",\n  \"hashtag.column_settings.tag_mode.any\": \"Iu ajn\",\n  \"hashtag.column_settings.tag_mode.none\": \"Neniu\",\n  \"hashtag.column_settings.tag_toggle\": \"Inkluzivi pluajn etikedojn por ĉi tiu kolumno\",\n  \"home.column_settings.basic\": \"Bazaj agordoj\",\n  \"home.column_settings.show_reblogs\": \"Montri diskonigojn\",\n  \"home.column_settings.show_replies\": \"Montri respondojn\",\n  \"intervals.full.days\": \"{number, plural, one {# tago} other {# tagoj}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# horo} other {# horoj}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minuto} other {# minutoj}}\",\n  \"introduction.federation.action\": \"Sekva\",\n  \"introduction.federation.federated.headline\": \"Federacio\",\n  \"introduction.federation.federated.text\": \"Publikaj mesaĝoj el aliaj serviloj de la Fediverse aperos en la fratara tempolinio.\",\n  \"introduction.federation.home.headline\": \"Heimo\",\n  \"introduction.federation.home.text\": \"Mesaĝoj de homoj, kiujn vi sekvas, aperos en via hejma fluo. Vi povas sekvi iun ajn de ajna servilo!\",\n  \"introduction.federation.local.headline\": \"Loka\",\n  \"introduction.federation.local.text\": \"Publikaj mesaĝoj de homoj de via servilo aperos en la loka tempolinio.\",\n  \"introduction.interactions.action\": \"Fini la lernilon!\",\n  \"introduction.interactions.favourite.headline\": \"Stelumi\",\n  \"introduction.interactions.favourite.text\": \"Vi povas konservi mesaĝon por posta uzo, kaj sciigi al ĝia aŭtoro ke vi ŝatis ĝin, per stelumo.\",\n  \"introduction.interactions.reblog.headline\": \"Diskonigi\",\n  \"introduction.interactions.reblog.text\": \"Vi povas diskonigi mesaĝojn al viaj sekvantoj per diskonigo.\",\n  \"introduction.interactions.reply.headline\": \"Respondi\",\n  \"introduction.interactions.reply.text\": \"Vi povas respondi al mesaĝoj aliulaj kaj viaj, kio kreos ĉenon de mesaĝoj nomata konversacio.\",\n  \"introduction.welcome.action\": \"Ek!\",\n  \"introduction.welcome.headline\": \"Unuaj paŝoj\",\n  \"introduction.welcome.text\": \"Bonvenon en Fediverse! Tre baldaŭ, vi povos disdoni mesaĝojn kaj paroli al viaj amikoj tra granda servila diverseco. Sed ĉi tiu servilo, {domain}, estas speciala: ĝi enhavas vian profilon, do memoru ĝian nomon.\",\n  \"keyboard_shortcuts.back\": \"por reveni\",\n  \"keyboard_shortcuts.blocked\": \"por malfermi la liston de blokitaj uzantoj\",\n  \"keyboard_shortcuts.boost\": \"por diskonigi\",\n  \"keyboard_shortcuts.column\": \"por fokusigi mesaĝon en unu el la kolumnoj\",\n  \"keyboard_shortcuts.compose\": \"por fokusigi la tekstujon\",\n  \"keyboard_shortcuts.description\": \"Priskribo\",\n  \"keyboard_shortcuts.direct\": \"por malfermi la kolumnon de rektaj mesaĝoj\",\n  \"keyboard_shortcuts.down\": \"por iri suben en la listo\",\n  \"keyboard_shortcuts.enter\": \"por malfermi mesaĝon\",\n  \"keyboard_shortcuts.favourite\": \"por stelumi\",\n  \"keyboard_shortcuts.favourites\": \"por malfermi la liston de stelumoj\",\n  \"keyboard_shortcuts.federated\": \"por malfermi la frataran tempolinion\",\n  \"keyboard_shortcuts.heading\": \"Klavaraj mallongigoj\",\n  \"keyboard_shortcuts.home\": \"por malfermi la hejman tempolinion\",\n  \"keyboard_shortcuts.hotkey\": \"Rapidklavo\",\n  \"keyboard_shortcuts.legend\": \"por montri ĉi tiun noton\",\n  \"keyboard_shortcuts.local\": \"por malfermi la lokan tempolinion\",\n  \"keyboard_shortcuts.mention\": \"por mencii la aŭtoron\",\n  \"keyboard_shortcuts.muted\": \"por malfermi la liston de silentigitaj uzantoj\",\n  \"keyboard_shortcuts.my_profile\": \"por malfermi vian profilon\",\n  \"keyboard_shortcuts.notifications\": \"por malfermi la kolumnon de sciigoj\",\n  \"keyboard_shortcuts.pinned\": \"por malfermi la liston de alpinglitaj mesaĝoj\",\n  \"keyboard_shortcuts.profile\": \"por malfermi la profilon de la aŭtoro\",\n  \"keyboard_shortcuts.reply\": \"por respondi\",\n  \"keyboard_shortcuts.requests\": \"por malfermi la liston de petoj de sekvado\",\n  \"keyboard_shortcuts.search\": \"por fokusigi la serĉilon\",\n  \"keyboard_shortcuts.start\": \"por malfermi la kolumnon «por komenci»\",\n  \"keyboard_shortcuts.toggle_hidden\": \"por montri/kaŝi tekston malantaŭ enhava averto\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"por montri/kaŝi aŭdovidaĵojn\",\n  \"keyboard_shortcuts.toot\": \"por komenci tute novan mesaĝon\",\n  \"keyboard_shortcuts.unfocus\": \"por malfokusigi la tekstujon aŭ la serĉilon\",\n  \"keyboard_shortcuts.up\": \"por iri supren en la listo\",\n  \"lightbox.close\": \"Fermi\",\n  \"lightbox.next\": \"Sekva\",\n  \"lightbox.previous\": \"Antaŭa\",\n  \"lightbox.view_context\": \"Vidi kontekston\",\n  \"lists.account.add\": \"Aldoni al la listo\",\n  \"lists.account.remove\": \"Forigi de la listo\",\n  \"lists.delete\": \"Forigi la liston\",\n  \"lists.edit\": \"Redakti la liston\",\n  \"lists.edit.submit\": \"Ŝanĝi titolon\",\n  \"lists.new.create\": \"Aldoni liston\",\n  \"lists.new.title_placeholder\": \"Titolo de la nova listo\",\n  \"lists.search\": \"Serĉi inter la homoj, kiujn vi sekvas\",\n  \"lists.subheading\": \"Viaj listoj\",\n  \"loading_indicator.label\": \"Ŝargado…\",\n  \"media_gallery.toggle_visible\": \"Baskuligi videblecon\",\n  \"missing_indicator.label\": \"Ne trovita\",\n  \"missing_indicator.sublabel\": \"Ĉi tiu elemento ne estis trovita\",\n  \"mute_modal.hide_notifications\": \"Ĉu vi volas kaŝi la sciigojn el ĉi tiu uzanto?\",\n  \"navigation_bar.apps\": \"Telefonaj aplikaĵoj\",\n  \"navigation_bar.blocks\": \"Blokitaj uzantoj\",\n  \"navigation_bar.community_timeline\": \"Loka tempolinio\",\n  \"navigation_bar.compose\": \"Skribi novan mesaĝon\",\n  \"navigation_bar.direct\": \"Rektaj mesaĝoj\",\n  \"navigation_bar.discover\": \"Esplori\",\n  \"navigation_bar.domain_blocks\": \"Kaŝitaj domajnoj\",\n  \"navigation_bar.edit_profile\": \"Redakti profilon\",\n  \"navigation_bar.favourites\": \"Stelumoj\",\n  \"navigation_bar.filters\": \"Silentigitaj vortoj\",\n  \"navigation_bar.follow_requests\": \"Petoj de sekvado\",\n  \"navigation_bar.follows_and_followers\": \"Sekvatoj kaj sekvantoj\",\n  \"navigation_bar.info\": \"Pri ĉi tiu servilo\",\n  \"navigation_bar.keyboard_shortcuts\": \"Rapidklavoj\",\n  \"navigation_bar.lists\": \"Listoj\",\n  \"navigation_bar.logout\": \"Elsaluti\",\n  \"navigation_bar.mutes\": \"Silentigitaj uzantoj\",\n  \"navigation_bar.personal\": \"Persone\",\n  \"navigation_bar.pins\": \"Alpinglitaj mesaĝoj\",\n  \"navigation_bar.preferences\": \"Preferoj\",\n  \"navigation_bar.profile_directory\": \"Profilujo\",\n  \"navigation_bar.public_timeline\": \"Fratara tempolinio\",\n  \"navigation_bar.security\": \"Sekureco\",\n  \"notification.favourite\": \"{name} stelumis vian mesaĝon\",\n  \"notification.follow\": \"{name} eksekvis vin\",\n  \"notification.mention\": \"{name} menciis vin\",\n  \"notification.poll\": \"Balotenketo ke vi balotis estas finita\",\n  \"notification.reblog\": \"{name} diskonigis vian mesaĝon\",\n  \"notifications.clear\": \"Forviŝi sciigojn\",\n  \"notifications.clear_confirmation\": \"Ĉu vi certas, ke vi volas porĉiame forviŝi ĉiujn viajn sciigojn?\",\n  \"notifications.column_settings.alert\": \"Retumilaj sciigoj\",\n  \"notifications.column_settings.favourite\": \"Stelumoj:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Montri ĉiujn kategoriojn\",\n  \"notifications.column_settings.filter_bar.category\": \"Rapida filtra breto\",\n  \"notifications.column_settings.filter_bar.show\": \"Montri\",\n  \"notifications.column_settings.follow\": \"Novaj sekvantoj:\",\n  \"notifications.column_settings.mention\": \"Mencioj:\",\n  \"notifications.column_settings.poll\": \"Balotenketo rezulto:\",\n  \"notifications.column_settings.push\": \"Puŝsciigoj\",\n  \"notifications.column_settings.reblog\": \"Diskonigoj:\",\n  \"notifications.column_settings.show\": \"Montri en kolumno\",\n  \"notifications.column_settings.sound\": \"Eligi sonon\",\n  \"notifications.filter.all\": \"Ĉiuj\",\n  \"notifications.filter.boosts\": \"Diskonigoj\",\n  \"notifications.filter.favourites\": \"Stelumoj\",\n  \"notifications.filter.follows\": \"Sekvoj\",\n  \"notifications.filter.mentions\": \"Mencioj\",\n  \"notifications.filter.polls\": \"Balotenketoj rezultoj\",\n  \"notifications.group\": \"{count} sciigoj\",\n  \"poll.closed\": \"Finita\",\n  \"poll.refresh\": \"Aktualigi\",\n  \"poll.total_votes\": \"{count, plural, one {# voĉdono} other {# voĉdonoj}}\",\n  \"poll.vote\": \"Voĉdoni\",\n  \"poll_button.add_poll\": \"Aldoni balotenketon\",\n  \"poll_button.remove_poll\": \"Forigi balotenketon\",\n  \"privacy.change\": \"Agordi mesaĝan privatecon\",\n  \"privacy.direct.long\": \"Afiŝi nur al menciitaj uzantoj\",\n  \"privacy.direct.short\": \"Rekta\",\n  \"privacy.private.long\": \"Afiŝi nur al sekvantoj\",\n  \"privacy.private.short\": \"Nur por sekvantoj\",\n  \"privacy.public.long\": \"Afiŝi en publikaj tempolinioj\",\n  \"privacy.public.short\": \"Publika\",\n  \"privacy.unlisted.long\": \"Ne afiŝi en publikaj tempolinioj\",\n  \"privacy.unlisted.short\": \"Nelistigita\",\n  \"regeneration_indicator.label\": \"Ŝargado…\",\n  \"regeneration_indicator.sublabel\": \"Via hejma fluo pretiĝas!\",\n  \"relative_time.days\": \"{number}t\",\n  \"relative_time.hours\": \"{number}h\",\n  \"relative_time.just_now\": \"nun\",\n  \"relative_time.minutes\": \"{number}m\",\n  \"relative_time.seconds\": \"{number}s\",\n  \"reply_indicator.cancel\": \"Nuligi\",\n  \"report.forward\": \"Plusendi al {target}\",\n  \"report.forward_hint\": \"La konto estas en alia servilo. Ĉu sendi sennomigitan kopion de la signalo ankaŭ tien?\",\n  \"report.hint\": \"La signalo estos sendita al la kontrolantoj de via servilo. Vi povas doni klarigon pri kial vi signalas ĉi tiun konton sube:\",\n  \"report.placeholder\": \"Pliaj komentoj\",\n  \"report.submit\": \"Sendi\",\n  \"report.target\": \"Signali {target}\",\n  \"search.placeholder\": \"Serĉi\",\n  \"search_popout.search_format\": \"Detala serĉo\",\n  \"search_popout.tips.full_text\": \"Simplaj tekstoj montras la mesaĝojn, kiujn vi skribis, stelumis, diskonigis, aŭ en kiuj vi estis menciita, sed ankaŭ kongruajn uzantnomojn, montratajn nomojn, kaj kradvortojn.\",\n  \"search_popout.tips.hashtag\": \"kradvorto\",\n  \"search_popout.tips.status\": \"mesaĝoj\",\n  \"search_popout.tips.text\": \"Simpla teksto montras la kongruajn afiŝitajn nomojn, uzantnomojn kaj kradvortojn\",\n  \"search_popout.tips.user\": \"uzanto\",\n  \"search_results.accounts\": \"Homoj\",\n  \"search_results.hashtags\": \"Kradvortoj\",\n  \"search_results.statuses\": \"Mesaĝoj\",\n  \"search_results.total\": \"{count, number} {count, plural, one {rezulto} other {rezultoj}}\",\n  \"status.admin_account\": \"Malfermi la kontrolan interfacon por @{name}\",\n  \"status.admin_status\": \"Malfermi ĉi tiun mesaĝon en la kontrola interfaco\",\n  \"status.block\": \"Bloki @{name}\",\n  \"status.cancel_reblog_private\": \"Eksdiskonigi\",\n  \"status.cannot_reblog\": \"Ĉi tiu mesaĝo ne diskonigeblas\",\n  \"status.copy\": \"Kopii la ligilon al la mesaĝo\",\n  \"status.delete\": \"Forigi\",\n  \"status.detailed_status\": \"Detala konversacia vido\",\n  \"status.direct\": \"Rekte mesaĝi @{name}\",\n  \"status.embed\": \"Enkorpigi\",\n  \"status.favourite\": \"Stelumi\",\n  \"status.filtered\": \"Filtrita\",\n  \"status.load_more\": \"Ŝargi pli\",\n  \"status.media_hidden\": \"Aŭdovidaĵo kaŝita\",\n  \"status.mention\": \"Mencii @{name}\",\n  \"status.more\": \"Pli\",\n  \"status.mute\": \"Silentigi @{name}\",\n  \"status.mute_conversation\": \"Silentigi konversacion\",\n  \"status.open\": \"Grandigi\",\n  \"status.pin\": \"Alpingli profile\",\n  \"status.pinned\": \"Alpinglita mesaĝo\",\n  \"status.read_more\": \"Legi pli\",\n  \"status.reblog\": \"Diskonigi\",\n  \"status.reblog_private\": \"Diskonigi al la originala atentaro\",\n  \"status.reblogged_by\": \"{name} diskonigis\",\n  \"status.reblogs.empty\": \"Ankoraŭ neniu diskonigis tiun mesaĝon. Kiam iu faros tion, tiu aperos ĉi tie.\",\n  \"status.redraft\": \"Forigi kaj reskribi\",\n  \"status.reply\": \"Respondi\",\n  \"status.replyAll\": \"Respondi al la fadeno\",\n  \"status.report\": \"Signali @{name}\",\n  \"status.sensitive_warning\": \"Tikla enhavo\",\n  \"status.share\": \"Diskonigi\",\n  \"status.show_less\": \"Malgrandigi\",\n  \"status.show_less_all\": \"Malgrandigi ĉiujn\",\n  \"status.show_more\": \"Grandigi\",\n  \"status.show_more_all\": \"Grandigi ĉiujn\",\n  \"status.show_thread\": \"Montri la fadenon\",\n  \"status.unmute_conversation\": \"Malsilentigi la konversacion\",\n  \"status.unpin\": \"Depingli de profilo\",\n  \"suggestions.dismiss\": \"Forigi la proponon\",\n  \"suggestions.header\": \"Vi povus interesiĝi pri…\",\n  \"tabs_bar.federated_timeline\": \"Fratara tempolinio\",\n  \"tabs_bar.home\": \"Hejmo\",\n  \"tabs_bar.local_timeline\": \"Loka tempolinio\",\n  \"tabs_bar.notifications\": \"Sciigoj\",\n  \"tabs_bar.search\": \"Serĉi\",\n  \"time_remaining.days\": \"{number, plural, one {# tago} other {# tagoj}} restanta\",\n  \"time_remaining.hours\": \"{number, plural, one {# horo} other {# horoj}} restanta\",\n  \"time_remaining.minutes\": \"{number, plural, one {# minuto} other {# minutoj}} restanta\",\n  \"time_remaining.moments\": \"Momento restanta\",\n  \"time_remaining.seconds\": \"{number, plural, one {# sekundo} other {# sekundoj}} restanta\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {persono} other {personoj}} parolas\",\n  \"ui.beforeunload\": \"Via malneto perdiĝos se vi eliras de Mastodon.\",\n  \"upload_area.title\": \"Altreni kaj lasi por alŝuti\",\n  \"upload_button.label\": \"Aldoni aŭdovidaĵon (JPEG, PNG, GIF, WebM, MP4, MOV)\",\n  \"upload_error.limit\": \"Limo de dosiera alŝutado transpasita.\",\n  \"upload_error.poll\": \"Alŝuto de dosiero ne permisita kun balotenketo\",\n  \"upload_form.description\": \"Priskribi por misvidantaj homoj\",\n  \"upload_form.focus\": \"Antaŭvido de ŝanĝo\",\n  \"upload_form.undo\": \"Forigi\",\n  \"upload_progress.label\": \"Alŝutado…\",\n  \"video.close\": \"Fermi videon\",\n  \"video.exit_fullscreen\": \"Eksigi plenekrana\",\n  \"video.expand\": \"Grandigi videon\",\n  \"video.fullscreen\": \"Igi plenekrana\",\n  \"video.hide\": \"Kaŝi videon\",\n  \"video.mute\": \"Silentigi\",\n  \"video.pause\": \"Paŭzi\",\n  \"video.play\": \"Ekigi\",\n  \"video.unmute\": \"Malsilentigi\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/es.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Agregar o eliminar de las listas\",\n  \"account.badges.bot\": \"Bot\",\n  \"account.block\": \"Bloquear\",\n  \"account.block_domain\": \"Ocultar todo de {domain}\",\n  \"account.blocked\": \"Bloqueado\",\n  \"account.direct\": \"Direct Message @{name}\",\n  \"account.domain_blocked\": \"Dominio oculto\",\n  \"account.edit_profile\": \"Editar perfil\",\n  \"account.endorse\": \"Mostrar en perfil\",\n  \"account.follow\": \"Seguir\",\n  \"account.followers\": \"Seguidores\",\n  \"account.followers.empty\": \"Nadie sigue a este usuario todavía.\",\n  \"account.follows\": \"Sigue\",\n  \"account.follows.empty\": \"Este usuario todavía no sigue a nadie.\",\n  \"account.follows_you\": \"Te sigue\",\n  \"account.hide_reblogs\": \"Ocultar retoots de @{name}\",\n  \"account.link_verified_on\": \"El proprietario de este link fue verificado el {date}\",\n  \"account.locked_info\": \"El estado de privacidad de esta cuenta està configurado como bloqueado. El proprietario debe revisar manualmente quien puede seguirle.\",\n  \"account.media\": \"Media\",\n  \"account.mention\": \"Mencionar a @{name}\",\n  \"account.moved_to\": \"{name} se ha mudado a:\",\n  \"account.mute\": \"Silenciar a @{name}\",\n  \"account.mute_notifications\": \"Silenciar notificaciones de @{name}\",\n  \"account.muted\": \"Silenciado\",\n  \"account.posts\": \"Toots\",\n  \"account.posts_with_replies\": \"Toots con respuestas\",\n  \"account.report\": \"Reportar a @{name}\",\n  \"account.requested\": \"Esperando aprobación\",\n  \"account.share\": \"Compartir el perfil de @{name}\",\n  \"account.show_reblogs\": \"Mostrar retoots de @{name}\",\n  \"account.unblock\": \"Desbloquear a @{name}\",\n  \"account.unblock_domain\": \"Mostrar a {domain}\",\n  \"account.unendorse\": \"No mostrar en el perfil\",\n  \"account.unfollow\": \"Dejar de seguir\",\n  \"account.unmute\": \"Dejar de silenciar a @{name}\",\n  \"account.unmute_notifications\": \"Dejar de silenciar las notificaciones de @{name}\",\n  \"alert.unexpected.message\": \"Hubo un error inesperado.\",\n  \"alert.unexpected.title\": \"Oops!\",\n  \"boost_modal.combo\": \"Puedes presionar {combo} para saltear este aviso la próxima vez\",\n  \"bundle_column_error.body\": \"Algo salió mal al cargar este componente.\",\n  \"bundle_column_error.retry\": \"Inténtalo de nuevo\",\n  \"bundle_column_error.title\": \"Error de red\",\n  \"bundle_modal_error.close\": \"Cerrar\",\n  \"bundle_modal_error.message\": \"Algo salió mal al cargar este componente.\",\n  \"bundle_modal_error.retry\": \"Inténtalo de nuevo\",\n  \"column.blocks\": \"Usuarios bloqueados\",\n  \"column.community\": \"Línea de tiempo local\",\n  \"column.direct\": \"Mensajes directos\",\n  \"column.domain_blocks\": \"Dominios ocultos\",\n  \"column.favourites\": \"Favoritos\",\n  \"column.follow_requests\": \"Solicitudes de seguimiento\",\n  \"column.home\": \"Inicio\",\n  \"column.lists\": \"Listas\",\n  \"column.mutes\": \"Usuarios silenciados\",\n  \"column.notifications\": \"Notificaciones\",\n  \"column.pins\": \"Toot fijado\",\n  \"column.public\": \"Historia federada\",\n  \"column_back_button.label\": \"Atrás\",\n  \"column_header.hide_settings\": \"Ocultar ajustes\",\n  \"column_header.moveLeft_settings\": \"Mover columna a la izquierda\",\n  \"column_header.moveRight_settings\": \"Mover columna a la derecha\",\n  \"column_header.pin\": \"Fijar\",\n  \"column_header.show_settings\": \"Mostrar ajustes\",\n  \"column_header.unpin\": \"Dejar de fijar\",\n  \"column_subheading.settings\": \"Ajustes\",\n  \"community.column_settings.media_only\": \"Solo media\",\n  \"compose_form.direct_message_warning\": \"Este toot solo será enviado a los usuarios mencionados.\",\n  \"compose_form.direct_message_warning_learn_more\": \"Aprender mas\",\n  \"compose_form.hashtag_warning\": \"Este toot no se mostrará bajo hashtags porque no es público. Sólo los toots públicos se pueden buscar por hashtag.\",\n  \"compose_form.lock_disclaimer\": \"Tu cuenta no está bloqueada. Todos pueden seguirte para ver tus toots solo para seguidores.\",\n  \"compose_form.lock_disclaimer.lock\": \"bloqueado\",\n  \"compose_form.placeholder\": \"¿En qué estás pensando?\",\n  \"compose_form.poll.add_option\": \"Add a choice\",\n  \"compose_form.poll.duration\": \"Poll duration\",\n  \"compose_form.poll.option_placeholder\": \"Choice {number}\",\n  \"compose_form.poll.remove_option\": \"Remove this choice\",\n  \"compose_form.publish\": \"Tootear\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"Mark media as sensitive\",\n  \"compose_form.sensitive.marked\": \"Material marcado como sensible\",\n  \"compose_form.sensitive.unmarked\": \"Material no marcado como sensible\",\n  \"compose_form.spoiler.marked\": \"Texto oculto tras la advertencia\",\n  \"compose_form.spoiler.unmarked\": \"Texto no oculto\",\n  \"compose_form.spoiler_placeholder\": \"Advertencia de contenido\",\n  \"confirmation_modal.cancel\": \"Cancelar\",\n  \"confirmations.block.block_and_report\": \"Block & Report\",\n  \"confirmations.block.confirm\": \"Bloquear\",\n  \"confirmations.block.message\": \"¿Estás seguro de que quieres bloquear a {name}?\",\n  \"confirmations.delete.confirm\": \"Eliminar\",\n  \"confirmations.delete.message\": \"¿Estás seguro de que quieres borrar este toot?\",\n  \"confirmations.delete_list.confirm\": \"Delete\",\n  \"confirmations.delete_list.message\": \"¿Seguro que quieres borrar esta lista permanentemente?\",\n  \"confirmations.domain_block.confirm\": \"Ocultar dominio entero\",\n  \"confirmations.domain_block.message\": \"¿Seguro de que quieres bloquear al dominio {domain} entero? En general unos cuantos bloqueos y silenciados concretos es suficiente y preferible.\",\n  \"confirmations.mute.confirm\": \"Silenciar\",\n  \"confirmations.mute.message\": \"¿Estás seguro de que quieres silenciar a {name}?\",\n  \"confirmations.redraft.confirm\": \"Borrar y volver a borrador\",\n  \"confirmations.redraft.message\": \"Estás seguro de que quieres borrar este estado y volverlo a borrador? Perderás todas las respuestas, impulsos y favoritos asociados a él, y las respuestas a la publicación original quedarán huérfanos.\",\n  \"confirmations.reply.confirm\": \"Reply\",\n  \"confirmations.reply.message\": \"Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?\",\n  \"confirmations.unfollow.confirm\": \"Dejar de seguir\",\n  \"confirmations.unfollow.message\": \"¿Estás seguro de que quieres dejar de seguir a {name}?\",\n  \"embed.instructions\": \"Añade este toot a tu sitio web con el siguiente código.\",\n  \"embed.preview\": \"Así es como se verá:\",\n  \"emoji_button.activity\": \"Actividad\",\n  \"emoji_button.custom\": \"Personalizado\",\n  \"emoji_button.flags\": \"Marcas\",\n  \"emoji_button.food\": \"Comida y bebida\",\n  \"emoji_button.label\": \"Insertar emoji\",\n  \"emoji_button.nature\": \"Naturaleza\",\n  \"emoji_button.not_found\": \"No hay emojos!! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"Objetos\",\n  \"emoji_button.people\": \"Gente\",\n  \"emoji_button.recent\": \"Usados frecuentemente\",\n  \"emoji_button.search\": \"Buscar…\",\n  \"emoji_button.search_results\": \"Resultados de búsqueda\",\n  \"emoji_button.symbols\": \"Símbolos\",\n  \"emoji_button.travel\": \"Viajes y lugares\",\n  \"empty_column.account_timeline\": \"No toots here!\",\n  \"empty_column.account_unavailable\": \"Profile unavailable\",\n  \"empty_column.blocks\": \"Aún no has bloqueado a ningún usuario.\",\n  \"empty_column.community\": \"La línea de tiempo local está vacía. ¡Escribe algo para empezar la fiesta!\",\n  \"empty_column.direct\": \"Aún no tienes ningún mensaje directo. Cuando envíes o recibas uno, se mostrará aquí.\",\n  \"empty_column.domain_blocks\": \"Todavía no hay dominios ocultos.\",\n  \"empty_column.favourited_statuses\": \"Aún no tienes toots preferidos. Cuando marques uno como favorito, aparecerá aquí.\",\n  \"empty_column.favourites\": \"Nadie ha marcado este toot como preferido. Cuando alguien lo haga, aparecerá aquí.\",\n  \"empty_column.follow_requests\": \"No tienes ninguna petición de seguidor. Cuando recibas una, se mostrará aquí.\",\n  \"empty_column.hashtag\": \"No hay nada en este hashtag aún.\",\n  \"empty_column.home\": \"No estás siguiendo a nadie aún. Visita {public} o haz búsquedas para empezar y conocer gente nueva.\",\n  \"empty_column.home.public_timeline\": \"la línea de tiempo pública\",\n  \"empty_column.list\": \"No hay nada en esta lista aún. Cuando miembros de esta lista publiquen nuevos estatus, estos aparecerán qui.\",\n  \"empty_column.lists\": \"No tienes ninguna lista. cuando crees una, se mostrará aquí.\",\n  \"empty_column.mutes\": \"Aún no has silenciado a ningún usuario.\",\n  \"empty_column.notifications\": \"No tienes ninguna notificación aún. Interactúa con otros para empezar una conversación.\",\n  \"empty_column.public\": \"¡No hay nada aquí! Escribe algo públicamente, o sigue usuarios de otras instancias manualmente para llenarlo\",\n  \"follow_request.authorize\": \"Autorizar\",\n  \"follow_request.reject\": \"Rechazar\",\n  \"getting_started.developers\": \"Desarrolladores\",\n  \"getting_started.directory\": \"Profile directory\",\n  \"getting_started.documentation\": \"Documentation\",\n  \"getting_started.heading\": \"Primeros pasos\",\n  \"getting_started.invite\": \"Invitar usuarios\",\n  \"getting_started.open_source_notice\": \"Mastodon es software libre. Puedes contribuir o reportar errores en {github}.\",\n  \"getting_started.security\": \"Seguridad\",\n  \"getting_started.terms\": \"Términos de servicio\",\n  \"hashtag.column_header.tag_mode.all\": \"and {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"or {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"without {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"No suggestions found\",\n  \"hashtag.column_settings.select.placeholder\": \"Enter hashtags…\",\n  \"hashtag.column_settings.tag_mode.all\": \"All of these\",\n  \"hashtag.column_settings.tag_mode.any\": \"Any of these\",\n  \"hashtag.column_settings.tag_mode.none\": \"None of these\",\n  \"hashtag.column_settings.tag_toggle\": \"Include additional tags in this column\",\n  \"home.column_settings.basic\": \"Básico\",\n  \"home.column_settings.show_reblogs\": \"Mostrar retoots\",\n  \"home.column_settings.show_replies\": \"Mostrar respuestas\",\n  \"intervals.full.days\": \"{number, plural, one {# day} other {# days}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# hour} other {# hours}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minute} other {# minutes}}\",\n  \"introduction.federation.action\": \"Next\",\n  \"introduction.federation.federated.headline\": \"Federated\",\n  \"introduction.federation.federated.text\": \"Public posts from other servers of the fediverse will appear in the federated timeline.\",\n  \"introduction.federation.home.headline\": \"Home\",\n  \"introduction.federation.home.text\": \"Posts from people you follow will appear in your home feed. You can follow anyone on any server!\",\n  \"introduction.federation.local.headline\": \"Local\",\n  \"introduction.federation.local.text\": \"Public posts from people on the same server as you will appear in the local timeline.\",\n  \"introduction.interactions.action\": \"Finish toot-orial!\",\n  \"introduction.interactions.favourite.headline\": \"Favourite\",\n  \"introduction.interactions.favourite.text\": \"You can save a toot for later, and let the author know that you liked it, by favouriting it.\",\n  \"introduction.interactions.reblog.headline\": \"Boost\",\n  \"introduction.interactions.reblog.text\": \"You can share other people's toots with your followers by boosting them.\",\n  \"introduction.interactions.reply.headline\": \"Reply\",\n  \"introduction.interactions.reply.text\": \"You can reply to other people's and your own toots, which will chain them together in a conversation.\",\n  \"introduction.welcome.action\": \"Let's go!\",\n  \"introduction.welcome.headline\": \"First steps\",\n  \"introduction.welcome.text\": \"Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.\",\n  \"keyboard_shortcuts.back\": \"volver atrás\",\n  \"keyboard_shortcuts.blocked\": \"abrir una lista de usuarios bloqueados\",\n  \"keyboard_shortcuts.boost\": \"retootear\",\n  \"keyboard_shortcuts.column\": \"enfocar un estado en una de las columnas\",\n  \"keyboard_shortcuts.compose\": \"enfocar el área de texto de redacción\",\n  \"keyboard_shortcuts.description\": \"Description\",\n  \"keyboard_shortcuts.direct\": \"abrir la columna de mensajes directos\",\n  \"keyboard_shortcuts.down\": \"mover hacia abajo en la lista\",\n  \"keyboard_shortcuts.enter\": \"to open status\",\n  \"keyboard_shortcuts.favourite\": \"añadir a favoritos\",\n  \"keyboard_shortcuts.favourites\": \"abrir la lista de favoritos\",\n  \"keyboard_shortcuts.federated\": \"abrir el timeline federado\",\n  \"keyboard_shortcuts.heading\": \"Keyboard Shortcuts\",\n  \"keyboard_shortcuts.home\": \"abrir el timeline propio\",\n  \"keyboard_shortcuts.hotkey\": \"Tecla caliente\",\n  \"keyboard_shortcuts.legend\": \"para mostrar esta leyenda\",\n  \"keyboard_shortcuts.local\": \"abrir el timeline local\",\n  \"keyboard_shortcuts.mention\": \"para mencionar al autor\",\n  \"keyboard_shortcuts.muted\": \"abrir la lista de usuarios silenciados\",\n  \"keyboard_shortcuts.my_profile\": \"abrir tu perfil\",\n  \"keyboard_shortcuts.notifications\": \"abrir la columna de notificaciones\",\n  \"keyboard_shortcuts.pinned\": \"abrir la lista de toots destacados\",\n  \"keyboard_shortcuts.profile\": \"abrir el perfil del autor\",\n  \"keyboard_shortcuts.reply\": \"para responder\",\n  \"keyboard_shortcuts.requests\": \"abrir la lista de peticiones de seguidores\",\n  \"keyboard_shortcuts.search\": \"para poner el foco en la búsqueda\",\n  \"keyboard_shortcuts.start\": \"abrir la columna \\\"comenzar\\\"\",\n  \"keyboard_shortcuts.toggle_hidden\": \"mostrar/ocultar texto tras aviso de contenido (CW)\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"to show/hide media\",\n  \"keyboard_shortcuts.toot\": \"para comenzar un nuevo toot\",\n  \"keyboard_shortcuts.unfocus\": \"para retirar el foco de la caja de redacción/búsqueda\",\n  \"keyboard_shortcuts.up\": \"para ir hacia arriba en la lista\",\n  \"lightbox.close\": \"Cerrar\",\n  \"lightbox.next\": \"Siguiente\",\n  \"lightbox.previous\": \"Anterior\",\n  \"lightbox.view_context\": \"View context\",\n  \"lists.account.add\": \"Añadir a lista\",\n  \"lists.account.remove\": \"Quitar de lista\",\n  \"lists.delete\": \"Delete list\",\n  \"lists.edit\": \"Editar lista\",\n  \"lists.edit.submit\": \"Change title\",\n  \"lists.new.create\": \"Añadir lista\",\n  \"lists.new.title_placeholder\": \"Título de la nueva lista\",\n  \"lists.search\": \"Buscar entre la gente a la que sigues\",\n  \"lists.subheading\": \"Tus listas\",\n  \"loading_indicator.label\": \"Cargando…\",\n  \"media_gallery.toggle_visible\": \"Cambiar visibilidad\",\n  \"missing_indicator.label\": \"No encontrado\",\n  \"missing_indicator.sublabel\": \"No se encontró este recurso\",\n  \"mute_modal.hide_notifications\": \"Ocultar notificaciones de este usuario?\",\n  \"navigation_bar.apps\": \"Aplicaciones móviles\",\n  \"navigation_bar.blocks\": \"Usuarios bloqueados\",\n  \"navigation_bar.community_timeline\": \"Historia local\",\n  \"navigation_bar.compose\": \"Escribir un nuevo toot\",\n  \"navigation_bar.direct\": \"Mensajes directos\",\n  \"navigation_bar.discover\": \"Descubrir\",\n  \"navigation_bar.domain_blocks\": \"Dominios ocultos\",\n  \"navigation_bar.edit_profile\": \"Editar perfil\",\n  \"navigation_bar.favourites\": \"Favoritos\",\n  \"navigation_bar.filters\": \"Palabras silenciadas\",\n  \"navigation_bar.follow_requests\": \"Solicitudes para seguirte\",\n  \"navigation_bar.follows_and_followers\": \"Follows and followers\",\n  \"navigation_bar.info\": \"Información adicional\",\n  \"navigation_bar.keyboard_shortcuts\": \"Atajos\",\n  \"navigation_bar.lists\": \"Listas\",\n  \"navigation_bar.logout\": \"Cerrar sesión\",\n  \"navigation_bar.mutes\": \"Usuarios silenciados\",\n  \"navigation_bar.personal\": \"Personal\",\n  \"navigation_bar.pins\": \"Toots fijados\",\n  \"navigation_bar.preferences\": \"Preferencias\",\n  \"navigation_bar.profile_directory\": \"Profile directory\",\n  \"navigation_bar.public_timeline\": \"Historia federada\",\n  \"navigation_bar.security\": \"Seguridad\",\n  \"notification.favourite\": \"{name} marcó tu estado como favorito\",\n  \"notification.follow\": \"{name} te empezó a seguir\",\n  \"notification.mention\": \"{name} te ha mencionado\",\n  \"notification.poll\": \"A poll you have voted in has ended\",\n  \"notification.reblog\": \"{name} ha retooteado tu estado\",\n  \"notifications.clear\": \"Limpiar notificaciones\",\n  \"notifications.clear_confirmation\": \"¿Seguro que quieres limpiar permanentemente todas tus notificaciones?\",\n  \"notifications.column_settings.alert\": \"Notificaciones de escritorio\",\n  \"notifications.column_settings.favourite\": \"Favoritos:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Display all categories\",\n  \"notifications.column_settings.filter_bar.category\": \"Quick filter bar\",\n  \"notifications.column_settings.filter_bar.show\": \"Show\",\n  \"notifications.column_settings.follow\": \"Nuevos seguidores:\",\n  \"notifications.column_settings.mention\": \"Menciones:\",\n  \"notifications.column_settings.poll\": \"Poll results:\",\n  \"notifications.column_settings.push\": \"Notificaciones push\",\n  \"notifications.column_settings.reblog\": \"Retoots:\",\n  \"notifications.column_settings.show\": \"Mostrar en columna\",\n  \"notifications.column_settings.sound\": \"Reproducir sonido\",\n  \"notifications.filter.all\": \"All\",\n  \"notifications.filter.boosts\": \"Boosts\",\n  \"notifications.filter.favourites\": \"Favourites\",\n  \"notifications.filter.follows\": \"Follows\",\n  \"notifications.filter.mentions\": \"Mentions\",\n  \"notifications.filter.polls\": \"Poll results\",\n  \"notifications.group\": \"{count} notificaciones\",\n  \"poll.closed\": \"Closed\",\n  \"poll.refresh\": \"Refresh\",\n  \"poll.total_votes\": \"{count, plural, one {# vote} other {# votes}}\",\n  \"poll.vote\": \"Vote\",\n  \"poll_button.add_poll\": \"Add a poll\",\n  \"poll_button.remove_poll\": \"Remove poll\",\n  \"privacy.change\": \"Ajustar privacidad\",\n  \"privacy.direct.long\": \"Sólo mostrar a los usuarios mencionados\",\n  \"privacy.direct.short\": \"Directo\",\n  \"privacy.private.long\": \"Sólo mostrar a seguidores\",\n  \"privacy.private.short\": \"Privado\",\n  \"privacy.public.long\": \"Mostrar en la historia federada\",\n  \"privacy.public.short\": \"Público\",\n  \"privacy.unlisted.long\": \"No mostrar en la historia federada\",\n  \"privacy.unlisted.short\": \"Sin federar\",\n  \"regeneration_indicator.label\": \"Cargando…\",\n  \"regeneration_indicator.sublabel\": \"¡Tu historia de inicio se está preparando!\",\n  \"relative_time.days\": \"{number}d\",\n  \"relative_time.hours\": \"{number}h\",\n  \"relative_time.just_now\": \"ahora\",\n  \"relative_time.minutes\": \"{number}m\",\n  \"relative_time.seconds\": \"{number}s\",\n  \"reply_indicator.cancel\": \"Cancelar\",\n  \"report.forward\": \"Reenviar a {target}\",\n  \"report.forward_hint\": \"Esta cuenta es de otro servidor. ¿Enviar una copia anonimizada del informe allí también?\",\n  \"report.hint\": \"El informe se enviará a los moderadores de tu instancia. Puedes proporcionar una explicación de por qué informas sobre esta cuenta a continuación:\",\n  \"report.placeholder\": \"Comentarios adicionales\",\n  \"report.submit\": \"Publicar\",\n  \"report.target\": \"Reportando\",\n  \"search.placeholder\": \"Buscar\",\n  \"search_popout.search_format\": \"Formato de búsqueda avanzada\",\n  \"search_popout.tips.full_text\": \"Búsquedas de texto recuperan posts que has escrito, marcado como favoritos, retooteado o en los que has sido mencionado, así como usuarios, nombres y hashtags.\",\n  \"search_popout.tips.hashtag\": \"etiqueta\",\n  \"search_popout.tips.status\": \"status\",\n  \"search_popout.tips.text\": \"El texto simple devuelve correspondencias de nombre, usuario y hashtag\",\n  \"search_popout.tips.user\": \"usuario\",\n  \"search_results.accounts\": \"Gente\",\n  \"search_results.hashtags\": \"Etiquetas\",\n  \"search_results.statuses\": \"Toots\",\n  \"search_results.total\": \"{count, number} {count, plural, one {resultado} other {resultados}}\",\n  \"status.admin_account\": \"Open moderation interface for @{name}\",\n  \"status.admin_status\": \"Open this status in the moderation interface\",\n  \"status.block\": \"Block @{name}\",\n  \"status.cancel_reblog_private\": \"Des-impulsar\",\n  \"status.cannot_reblog\": \"Este toot no puede retootearse\",\n  \"status.copy\": \"Copy link to status\",\n  \"status.delete\": \"Borrar\",\n  \"status.detailed_status\": \"Vista de conversación detallada\",\n  \"status.direct\": \"Mensaje directo a @{name}\",\n  \"status.embed\": \"Incrustado\",\n  \"status.favourite\": \"Favorito\",\n  \"status.filtered\": \"Filtrado\",\n  \"status.load_more\": \"Cargar más\",\n  \"status.media_hidden\": \"Contenido multimedia oculto\",\n  \"status.mention\": \"Mencionar\",\n  \"status.more\": \"Más\",\n  \"status.mute\": \"Silenciar @{name}\",\n  \"status.mute_conversation\": \"Silenciar conversación\",\n  \"status.open\": \"Expandir estado\",\n  \"status.pin\": \"Fijar\",\n  \"status.pinned\": \"Toot fijado\",\n  \"status.read_more\": \"Read more\",\n  \"status.reblog\": \"Retootear\",\n  \"status.reblog_private\": \"Implusar a la audiencia original\",\n  \"status.reblogged_by\": \"Retooteado por {name}\",\n  \"status.reblogs.empty\": \"Nadie impulsó este toot todavía. Cuando alguien lo haga, aparecerá aqui.\",\n  \"status.redraft\": \"Borrar y volver a borrador\",\n  \"status.reply\": \"Responder\",\n  \"status.replyAll\": \"Responder al hilo\",\n  \"status.report\": \"Reportar\",\n  \"status.sensitive_warning\": \"Contenido sensible\",\n  \"status.share\": \"Compartir\",\n  \"status.show_less\": \"Mostrar menos\",\n  \"status.show_less_all\": \"Mostrar menos para todo\",\n  \"status.show_more\": \"Mostrar más\",\n  \"status.show_more_all\": \"Mostrar más para todo\",\n  \"status.show_thread\": \"Show thread\",\n  \"status.unmute_conversation\": \"Dejar de silenciar conversación\",\n  \"status.unpin\": \"Dejar de fijar\",\n  \"suggestions.dismiss\": \"Dismiss suggestion\",\n  \"suggestions.header\": \"You might be interested in…\",\n  \"tabs_bar.federated_timeline\": \"Federado\",\n  \"tabs_bar.home\": \"Inicio\",\n  \"tabs_bar.local_timeline\": \"Local\",\n  \"tabs_bar.notifications\": \"Notificaciones\",\n  \"tabs_bar.search\": \"Buscar\",\n  \"time_remaining.days\": \"{number, plural, one {# day} other {# days}} left\",\n  \"time_remaining.hours\": \"{number, plural, one {# hour} other {# hours}} left\",\n  \"time_remaining.minutes\": \"{number, plural, one {# minute} other {# minutes}} left\",\n  \"time_remaining.moments\": \"Moments remaining\",\n  \"time_remaining.seconds\": \"{number, plural, one {# second} other {# seconds}} left\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {person} other {people}} talking\",\n  \"ui.beforeunload\": \"Tu borrador se perderá si sales de Mastodon.\",\n  \"upload_area.title\": \"Arrastra y suelta para subir\",\n  \"upload_button.label\": \"Subir multimedia (JPEG, PNG, GIF, WebM, MP4, MOV)\",\n  \"upload_error.limit\": \"File upload limit exceeded.\",\n  \"upload_error.poll\": \"File upload not allowed with polls.\",\n  \"upload_form.description\": \"Describir para los usuarios con dificultad visual\",\n  \"upload_form.focus\": \"Recortar\",\n  \"upload_form.undo\": \"Borrar\",\n  \"upload_progress.label\": \"Subiendo…\",\n  \"video.close\": \"Cerrar video\",\n  \"video.exit_fullscreen\": \"Salir de pantalla completa\",\n  \"video.expand\": \"Expandir vídeo\",\n  \"video.fullscreen\": \"Pantalla completa\",\n  \"video.hide\": \"Ocultar vídeo\",\n  \"video.mute\": \"Silenciar sonido\",\n  \"video.pause\": \"Pausar\",\n  \"video.play\": \"Reproducir\",\n  \"video.unmute\": \"Dejar de silenciar sonido\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/eu.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Gehitu edo kendu zerrendetatik\",\n  \"account.badges.bot\": \"Bot-a\",\n  \"account.block\": \"Blokeatu @{name}\",\n  \"account.block_domain\": \"Ezkutatu {domain} domeinuko guztia\",\n  \"account.blocked\": \"Blokeatuta\",\n  \"account.direct\": \"Mezu zuzena @{name}(r)i\",\n  \"account.domain_blocked\": \"Ezkutatutako domeinua\",\n  \"account.edit_profile\": \"Aldatu profila\",\n  \"account.endorse\": \"Nabarmendu profilean\",\n  \"account.follow\": \"Jarraitu\",\n  \"account.followers\": \"Jarraitzaileak\",\n  \"account.followers.empty\": \"Ez du inork erabiltzaile hau jarraitzen oraindik.\",\n  \"account.follows\": \"Jarraitzen\",\n  \"account.follows.empty\": \"Erabiltzaile honek ez du inor jarraitzen oraindik.\",\n  \"account.follows_you\": \"Jarraitzen dizu\",\n  \"account.hide_reblogs\": \"Ezkutatu @{name}(r)en bultzadak\",\n  \"account.link_verified_on\": \"Esteka honen jabetzaren egiaztaketa data: {date}\",\n  \"account.locked_info\": \"Kontu honen pribatutasun egoera blokeatuta gisa ezarri da. Jabeak eskuz erabakitzen du nork jarraitu diezaioken.\",\n  \"account.media\": \"Multimedia\",\n  \"account.mention\": \"Aipatu @{name}\",\n  \"account.moved_to\": \"{name} hona lekualdatu da:\",\n  \"account.mute\": \"Mututu @{name}\",\n  \"account.mute_notifications\": \"Mututu @{name}(r)en jakinarazpenak\",\n  \"account.muted\": \"Mutututa\",\n  \"account.posts\": \"Tootak\",\n  \"account.posts_with_replies\": \"Toot eta erantzunak\",\n  \"account.report\": \"Salatu @{name}\",\n  \"account.requested\": \"Onarpenaren zain. Klikatu jarraitzeko eskaera ezeztatzeko\",\n  \"account.share\": \"@{name}(e)ren profila elkarbanatu\",\n  \"account.show_reblogs\": \"Erakutsi @{name}(r)en bultzadak\",\n  \"account.unblock\": \"Desblokeatu @{name}\",\n  \"account.unblock_domain\": \"Berriz erakutsi {domain}\",\n  \"account.unendorse\": \"Ez nabarmendu profilean\",\n  \"account.unfollow\": \"Jarraitzeari utzi\",\n  \"account.unmute\": \"Desmututu @{name}\",\n  \"account.unmute_notifications\": \"Desmututu @{name}(r)en jakinarazpenak\",\n  \"alert.unexpected.message\": \"Ustekabeko errore bat gertatu da.\",\n  \"alert.unexpected.title\": \"Ene!\",\n  \"boost_modal.combo\": \"{combo} sakatu dezakezu hurrengoan hau saltatzeko\",\n  \"bundle_column_error.body\": \"Zerbait okerra gertatu da osagai hau kargatzean.\",\n  \"bundle_column_error.retry\": \"Saiatu berriro\",\n  \"bundle_column_error.title\": \"Sareko errorea\",\n  \"bundle_modal_error.close\": \"Itxi\",\n  \"bundle_modal_error.message\": \"Zerbait okerra gertatu da osagai hau kargatzean.\",\n  \"bundle_modal_error.retry\": \"Saiatu berriro\",\n  \"column.blocks\": \"Blokeatutako erabiltzaileak\",\n  \"column.community\": \"Denbora-lerro lokala\",\n  \"column.direct\": \"Mezu zuzenak\",\n  \"column.domain_blocks\": \"Ezkutatutako domeinuak\",\n  \"column.favourites\": \"Gogokoak\",\n  \"column.follow_requests\": \"Jarraitzeko eskariak\",\n  \"column.home\": \"Hasiera\",\n  \"column.lists\": \"Zerrendak\",\n  \"column.mutes\": \"Mutututako erabiltzaileak\",\n  \"column.notifications\": \"Jakinarazpenak\",\n  \"column.pins\": \"Pinned toot\",\n  \"column.public\": \"Federatutako denbora-lerroa\",\n  \"column_back_button.label\": \"Atzera\",\n  \"column_header.hide_settings\": \"Ezkutatu ezarpenak\",\n  \"column_header.moveLeft_settings\": \"Eraman zutabea ezkerrera\",\n  \"column_header.moveRight_settings\": \"Eraman zutabea eskuinera\",\n  \"column_header.pin\": \"Finkatu\",\n  \"column_header.show_settings\": \"Erakutsi ezarpenak\",\n  \"column_header.unpin\": \"Desfinkatu\",\n  \"column_subheading.settings\": \"Ezarpenak\",\n  \"community.column_settings.media_only\": \"Multimedia besterik ez\",\n  \"compose_form.direct_message_warning\": \"Toot hau aipatutako erabiltzaileei besterik ez zaie bidaliko.\",\n  \"compose_form.direct_message_warning_learn_more\": \"Ikasi gehiago\",\n  \"compose_form.hashtag_warning\": \"Toot hau ez da traoletan agertuko zerrendatu gabekoa baita. Traoletan toot publikoak besterik ez dira agertzen.\",\n  \"compose_form.lock_disclaimer\": \"Zure kontua ez dago {locked}. Edonork jarraitu zaitzake zure jarraitzaileentzako soilik diren mezuak ikusteko.\",\n  \"compose_form.lock_disclaimer.lock\": \"giltzapetuta\",\n  \"compose_form.placeholder\": \"Zer duzu buruan?\",\n  \"compose_form.poll.add_option\": \"Gehitu aukera bat\",\n  \"compose_form.poll.duration\": \"Inkestaren iraupena\",\n  \"compose_form.poll.option_placeholder\": \"{number}. aukera\",\n  \"compose_form.poll.remove_option\": \"Kendu aukera hau\",\n  \"compose_form.publish\": \"Toot\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"Markatu multimedia hunkigarri gisa\",\n  \"compose_form.sensitive.marked\": \"Multimedia edukia hunkigarri gisa markatu da\",\n  \"compose_form.sensitive.unmarked\": \"Multimedia edukia ez da hunkigarri gisa markatu\",\n  \"compose_form.spoiler.marked\": \"Testua abisu batek ezkutatzen du\",\n  \"compose_form.spoiler.unmarked\": \"Testua ez dago ezkutatuta\",\n  \"compose_form.spoiler_placeholder\": \"Idatzi zure abisua hemen\",\n  \"confirmation_modal.cancel\": \"Utzi\",\n  \"confirmations.block.block_and_report\": \"Blokeatu eta salatu\",\n  \"confirmations.block.confirm\": \"Blokeatu\",\n  \"confirmations.block.message\": \"Ziur {name} blokeatu nahi duzula?\",\n  \"confirmations.delete.confirm\": \"Ezabatu\",\n  \"confirmations.delete.message\": \"Ziur mezu hau ezabatu nahi duzula?\",\n  \"confirmations.delete_list.confirm\": \"Ezabatu\",\n  \"confirmations.delete_list.message\": \"Ziur behin betiko ezabatu nahi duzula zerrenda hau?\",\n  \"confirmations.domain_block.confirm\": \"Ezkutatu domeinu osoa\",\n  \"confirmations.domain_block.message\": \"Ziur, erabat ziur, {domain} domeinu osoa blokeatu nahi duzula? Gehienetan gutxi batzuk blokeatu edo mututzearekin nahikoa da. Ez duzu domeinu horretako edukirik ikusiko denbora lerroetan edo jakinarazpenetan. Domeinu horretako zure jarraitzaileak kenduko dira ere.\",\n  \"confirmations.mute.confirm\": \"Mututu\",\n  \"confirmations.mute.message\": \"Ziur {name} mututu nahi duzula?\",\n  \"confirmations.redraft.confirm\": \"Ezabatu eta berridatzi\",\n  \"confirmations.redraft.message\": \"Ziur mezu hau ezabatu eta berridatzi nahi duzula? Gogokoak eta bultzadak galduko dira eta jaso dituen erantzunak umezurtz geratuko dira.\",\n  \"confirmations.reply.confirm\": \"Erantzun\",\n  \"confirmations.reply.message\": \"Orain erantzuteak idazten ari zaren mezua gainidatziko du. Ziur jarraitu nahi duzula?\",\n  \"confirmations.unfollow.confirm\": \"Utzi jarraitzeari\",\n  \"confirmations.unfollow.message\": \"Ziur {name} jarraitzeari utzi nahi diozula?\",\n  \"embed.instructions\": \"Txertatu mezu hau zure webgunean beheko kodea kopatuz.\",\n  \"embed.preview\": \"Hau da izango duen itxura:\",\n  \"emoji_button.activity\": \"Jarduera\",\n  \"emoji_button.custom\": \"Pertsonalizatua\",\n  \"emoji_button.flags\": \"Banderak\",\n  \"emoji_button.food\": \"Janari eta edaria\",\n  \"emoji_button.label\": \"Txertatu emoji-a\",\n  \"emoji_button.nature\": \"Natura\",\n  \"emoji_button.not_found\": \"Emojirik ez!! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"Objektuak\",\n  \"emoji_button.people\": \"Jendea\",\n  \"emoji_button.recent\": \"Maiz erabiliak\",\n  \"emoji_button.search\": \"Bilatu...\",\n  \"emoji_button.search_results\": \"Bilaketaren emaitzak\",\n  \"emoji_button.symbols\": \"Sinboloak\",\n  \"emoji_button.travel\": \"Bidaiak eta tokiak\",\n  \"empty_column.account_timeline\": \"Ez dago toot-ik hemen!\",\n  \"empty_column.account_unavailable\": \"Profila ez dago eskuragarri\",\n  \"empty_column.blocks\": \"Ez duzu erabiltzailerik blokeatu oraindik.\",\n  \"empty_column.community\": \"Denbora-lerro lokala hutsik dago. Idatzi zerbait publikoki pilota biraka jartzeko!\",\n  \"empty_column.direct\": \"Ez duzu mezu zuzenik oraindik. Baten bat bidali edo jasotzen duzunean, hemen agertuko da.\",\n  \"empty_column.domain_blocks\": \"Ez dago ezkutatutako domeinurik oraindik.\",\n  \"empty_column.favourited_statuses\": \"Ez duzu gogokorik oraindik. Gogokoren bat duzunean hemen agertuko da.\",\n  \"empty_column.favourites\": \"Ez du inork gogokoetara gehitu toot hau oraindik. Inork egiten duenean, hemen agertuko dira.\",\n  \"empty_column.follow_requests\": \"Ez duzu jarraitzeko eskaririk oraindik. Baten bat jasotzen duzunean, hemen agertuko da.\",\n  \"empty_column.hashtag\": \"Ez dago ezer traola honetan oraindik.\",\n  \"empty_column.home\": \"Zure hasierako denbora-lerroa hutsik dago! Ikusi {public} edo erabili bilaketa lehen urratsak eman eta beste batzuk aurkitzeko.\",\n  \"empty_column.home.public_timeline\": \"denbora-lerro publikoa\",\n  \"empty_column.list\": \"Ez dago ezer zerrenda honetan. Zerrenda honetako kideek mezu berriak argitaratzean, hemen agertuko dira.\",\n  \"empty_column.lists\": \"Ez duzu zerrendarik oraindik. Baten bat sortzen duzunean hemen agertuko da.\",\n  \"empty_column.mutes\": \"Ez duzu erabiltzailerik mututu oraindik.\",\n  \"empty_column.notifications\": \"Ez duzu jakinarazpenik oraindik. Jarri besteekin harremanetan elkarrizketa abiatzeko.\",\n  \"empty_column.public\": \"Ez dago ezer hemen! Idatzi zerbait publikoki edo jarraitu eskuz beste zerbitzari batzuetako erabiltzaileak hau betetzen joateko\",\n  \"follow_request.authorize\": \"Baimendu\",\n  \"follow_request.reject\": \"Ukatu\",\n  \"getting_started.developers\": \"Garatzaileak\",\n  \"getting_started.directory\": \"Profil-direktorioa\",\n  \"getting_started.documentation\": \"Dokumentazioa\",\n  \"getting_started.heading\": \"Menua\",\n  \"getting_started.invite\": \"Gonbidatu jendea\",\n  \"getting_started.open_source_notice\": \"Mastodon software librea da. Ekarpenak egin ditzakezu edo akatsen berri eman GitHub bidez: {github}.\",\n  \"getting_started.security\": \"Segurtasuna\",\n  \"getting_started.terms\": \"Erabilera baldintzak\",\n  \"hashtag.column_header.tag_mode.all\": \"eta {osagarria}\",\n  \"hashtag.column_header.tag_mode.any\": \"edo {osagarria}\",\n  \"hashtag.column_header.tag_mode.none\": \"gabe {osagarria}\",\n  \"hashtag.column_settings.select.no_options_message\": \"Ez da proposamenik aurkitu\",\n  \"hashtag.column_settings.select.placeholder\": \"Sartu traolak…\",\n  \"hashtag.column_settings.tag_mode.all\": \"Hauetako guztiak\",\n  \"hashtag.column_settings.tag_mode.any\": \"Hautako edozein\",\n  \"hashtag.column_settings.tag_mode.none\": \"Hauetako bat ere ez\",\n  \"hashtag.column_settings.tag_toggle\": \"Include additional tags in this column\",\n  \"home.column_settings.basic\": \"Oinarrizkoa\",\n  \"home.column_settings.show_reblogs\": \"Erakutsi bultzadak\",\n  \"home.column_settings.show_replies\": \"Erakutsi erantzunak\",\n  \"intervals.full.days\": \"{number, plural, one {egun #} other {# egun}}\",\n  \"intervals.full.hours\": \"{number, plural, one {ordu #} other {# ordu}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {minutu #} other {# minutu}}\",\n  \"introduction.federation.action\": \"Hurrengoa\",\n  \"introduction.federation.federated.headline\": \"Federatua\",\n  \"introduction.federation.federated.text\": \"Fedibertsoko beste zerbitzarietako bidalketa publikoak federatutako denbora-lerroan agertuko dira.\",\n  \"introduction.federation.home.headline\": \"Hasiera\",\n  \"introduction.federation.home.text\": \"Jarraitzen dituzun horien mezuak zure hasierako jarioan agertuko dira. Edozein zerbitzariko edonor jarraitu dezakezu!\",\n  \"introduction.federation.local.headline\": \"Lokala\",\n  \"introduction.federation.local.text\": \"Zure zerbitzari berean dauden horien mezu publikoak denbora-lerro lokalean agertuko dira.\",\n  \"introduction.interactions.action\": \"Amaitu tutoriala!\",\n  \"introduction.interactions.favourite.headline\": \"Gogokoa\",\n  \"introduction.interactions.favourite.text\": \"Toot bat geroko gorde dezakezu, eta egileari gustukoa duzula jakinarazi, hau gogoko bihurtuz.\",\n  \"introduction.interactions.reblog.headline\": \"Bultzada\",\n  \"introduction.interactions.reblog.text\": \"Beste batzuen mezuak partekatu ditzakezu zure jarraitzaileekin hauei bultzada emanez.\",\n  \"introduction.interactions.reply.headline\": \"Erantzun\",\n  \"introduction.interactions.reply.text\": \"Besteen mezuei eta zure mezuei ere erantzun diezaiekezu, eta elkarrizketa batean lotuta agertuko dira.\",\n  \"introduction.welcome.action\": \"Goazen!\",\n  \"introduction.welcome.headline\": \"Lehen urratsak\",\n  \"introduction.welcome.text\": \"Ongi etorri fedibertsora! Hemendik gutxira hainbat zerbitzarietan zehar mezuak zabaldu eta lagunekin hitz egin ahal izango duzu. Baina zerbitzari hau hainbat zerbitzarietan zehar. berezia da, hau da zure profila ostatatzen duena, ez ahaztu bere izena.\",\n  \"keyboard_shortcuts.back\": \"atzera nabigatzeko\",\n  \"keyboard_shortcuts.blocked\": \"blokeatutako erabiltzaileen zerrenda irekitzeko\",\n  \"keyboard_shortcuts.boost\": \"bultzada ematea\",\n  \"keyboard_shortcuts.column\": \"mezu bat zutabe batean fokatzea\",\n  \"keyboard_shortcuts.compose\": \"testua konposatzeko arean fokatzea\",\n  \"keyboard_shortcuts.description\": \"Deskripzioa\",\n  \"keyboard_shortcuts.direct\": \"mezu zuzenen zutabea irekitzeko\",\n  \"keyboard_shortcuts.down\": \"zerrendan behera mugitzea\",\n  \"keyboard_shortcuts.enter\": \"mezua irekitzeko\",\n  \"keyboard_shortcuts.favourite\": \"gogoko egitea\",\n  \"keyboard_shortcuts.favourites\": \"gogokoen zerrenda irekitzeko\",\n  \"keyboard_shortcuts.federated\": \"federatutako denbora-lerroa irekitzeko\",\n  \"keyboard_shortcuts.heading\": \"Keyboard Shortcuts\",\n  \"keyboard_shortcuts.home\": \"hasierako denbora-lerroa irekitzeko\",\n  \"keyboard_shortcuts.hotkey\": \"Laster-tekla\",\n  \"keyboard_shortcuts.legend\": \"legenda hau bistaratzea\",\n  \"keyboard_shortcuts.local\": \"denbora-lerro lokala irekitzeko\",\n  \"keyboard_shortcuts.mention\": \"egilea aipatzea\",\n  \"keyboard_shortcuts.muted\": \"mutututako erabiltzaileen zerrenda irekitzeko\",\n  \"keyboard_shortcuts.my_profile\": \"zure profila irekitzeko\",\n  \"keyboard_shortcuts.notifications\": \"jakinarazpenen zutabea irekitzeko\",\n  \"keyboard_shortcuts.pinned\": \"finkatutako toot-en zerrenda irekitzeko\",\n  \"keyboard_shortcuts.profile\": \"egilearen profila irekitzeko\",\n  \"keyboard_shortcuts.reply\": \"erantzutea\",\n  \"keyboard_shortcuts.requests\": \"jarraitzeko eskarien zerrenda irekitzeko\",\n  \"keyboard_shortcuts.search\": \"bilaketan fokua jartzea\",\n  \"keyboard_shortcuts.start\": \"\\\"Menua\\\" zutabea irekitzeko\",\n  \"keyboard_shortcuts.toggle_hidden\": \"testua erakustea/ezkutatzea abisu baten atzean\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"multimedia erakutsi/ezkutatzeko\",\n  \"keyboard_shortcuts.toot\": \"toot berria hastea\",\n  \"keyboard_shortcuts.unfocus\": \"testua konposatzeko area / bilaketatik fokua kentzea\",\n  \"keyboard_shortcuts.up\": \"zerrendan gora mugitzea\",\n  \"lightbox.close\": \"Itxi\",\n  \"lightbox.next\": \"Hurrengoa\",\n  \"lightbox.previous\": \"Aurrekoa\",\n  \"lightbox.view_context\": \"Ikusi testuingurua\",\n  \"lists.account.add\": \"Gehitu zerrendara\",\n  \"lists.account.remove\": \"Kendu zerrendatik\",\n  \"lists.delete\": \"Ezabatu zerrenda\",\n  \"lists.edit\": \"Editatu zerrenda\",\n  \"lists.edit.submit\": \"Aldatu izenburua\",\n  \"lists.new.create\": \"Gehitu zerrenda\",\n  \"lists.new.title_placeholder\": \"Zerrenda berriaren izena\",\n  \"lists.search\": \"Bilatu jarraitzen dituzun pertsonen artean\",\n  \"lists.subheading\": \"Zure zerrendak\",\n  \"loading_indicator.label\": \"Kargatzen...\",\n  \"media_gallery.toggle_visible\": \"Txandakatu ikusgaitasuna\",\n  \"missing_indicator.label\": \"Ez aurkitua\",\n  \"missing_indicator.sublabel\": \"Baliabide hau ezin izan da aurkitu\",\n  \"mute_modal.hide_notifications\": \"Ezkutatu erabiltzaile honen jakinarazpenak?\",\n  \"navigation_bar.apps\": \"Mugikorrerako aplikazioak\",\n  \"navigation_bar.blocks\": \"Blokeatutako erabiltzaileak\",\n  \"navigation_bar.community_timeline\": \"Denbora-lerro lokala\",\n  \"navigation_bar.compose\": \"Idatzi toot berria\",\n  \"navigation_bar.direct\": \"Mezu zuzenak\",\n  \"navigation_bar.discover\": \"Aurkitu\",\n  \"navigation_bar.domain_blocks\": \"Ezkutatutako domeinuak\",\n  \"navigation_bar.edit_profile\": \"Aldatu profila\",\n  \"navigation_bar.favourites\": \"Gogokoak\",\n  \"navigation_bar.filters\": \"Mutututako hitzak\",\n  \"navigation_bar.follow_requests\": \"Jarraitzeko eskariak\",\n  \"navigation_bar.follows_and_followers\": \"Jarraitutakoak eta jarraitzaileak\",\n  \"navigation_bar.info\": \"Zerbitzari honi buruz\",\n  \"navigation_bar.keyboard_shortcuts\": \"Laster-teklak\",\n  \"navigation_bar.lists\": \"Zerrendak\",\n  \"navigation_bar.logout\": \"Amaitu saioa\",\n  \"navigation_bar.mutes\": \"Mutututako erabiltzaileak\",\n  \"navigation_bar.personal\": \"Pertsonala\",\n  \"navigation_bar.pins\": \"Finkatutako toot-ak\",\n  \"navigation_bar.preferences\": \"Hobespenak\",\n  \"navigation_bar.profile_directory\": \"Profilen direktorioa\",\n  \"navigation_bar.public_timeline\": \"Federatutako denbora-lerroa\",\n  \"navigation_bar.security\": \"Segurtasuna\",\n  \"notification.favourite\": \"{name}(e)k zure mezua gogoko du\",\n  \"notification.follow\": \"{name}(e)k jarraitzen zaitu\",\n  \"notification.mention\": \"{name}(e)k aipatu zaitu\",\n  \"notification.poll\": \"Zuk erantzun duzun inkesta bat bukatu da\",\n  \"notification.reblog\": \"{name}(e)k bultzada eman dio zure mezuari\",\n  \"notifications.clear\": \"Garbitu jakinarazpenak\",\n  \"notifications.clear_confirmation\": \"Ziur zure jakinarazpen guztiak behin betirako garbitu nahi dituzula?\",\n  \"notifications.column_settings.alert\": \"Mahaigaineko jakinarazpenak\",\n  \"notifications.column_settings.favourite\": \"Gogokoak:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Erakutsi kategoria guztiak\",\n  \"notifications.column_settings.filter_bar.category\": \"Iragazki azkarraren barra\",\n  \"notifications.column_settings.filter_bar.show\": \"Erakutsi\",\n  \"notifications.column_settings.follow\": \"Jarraitzaile berriak:\",\n  \"notifications.column_settings.mention\": \"Aipamenak:\",\n  \"notifications.column_settings.poll\": \"Inkestaren emaitzak:\",\n  \"notifications.column_settings.push\": \"Push jakinarazpenak\",\n  \"notifications.column_settings.reblog\": \"Bultzadak:\",\n  \"notifications.column_settings.show\": \"Erakutsi zutabean\",\n  \"notifications.column_settings.sound\": \"Jo soinua\",\n  \"notifications.filter.all\": \"Denak\",\n  \"notifications.filter.boosts\": \"Bultzadak\",\n  \"notifications.filter.favourites\": \"Gogokoak\",\n  \"notifications.filter.follows\": \"Jarraipenak\",\n  \"notifications.filter.mentions\": \"Aipamenak\",\n  \"notifications.filter.polls\": \"Inkestaren emaitza\",\n  \"notifications.group\": \"{count} jakinarazpen\",\n  \"poll.closed\": \"Itxita\",\n  \"poll.refresh\": \"Berritu\",\n  \"poll.total_votes\": \"{count, plural, one {boto #} other {# boto}}\",\n  \"poll.vote\": \"Bozkatu\",\n  \"poll_button.add_poll\": \"Gehitu inkesta bat\",\n  \"poll_button.remove_poll\": \"Kendu inkesta\",\n  \"privacy.change\": \"Doitu mezuaren pribatutasuna\",\n  \"privacy.direct.long\": \"Bidali aipatutako erabiltzaileei besterik ez\",\n  \"privacy.direct.short\": \"Zuzena\",\n  \"privacy.private.long\": \"Bidali jarraitzaileei besterik ez\",\n  \"privacy.private.short\": \"Jarraitzaileak soilik\",\n  \"privacy.public.long\": \"Bistaratu denbora-lerro publikoetan\",\n  \"privacy.public.short\": \"Publikoa\",\n  \"privacy.unlisted.long\": \"Do not show in public timelines\",\n  \"privacy.unlisted.short\": \"Zerrendatu gabea\",\n  \"regeneration_indicator.label\": \"Kargatzen…\",\n  \"regeneration_indicator.sublabel\": \"Zure hasiera-jarioa prestatzen ari da!\",\n  \"relative_time.days\": \"{number}e\",\n  \"relative_time.hours\": \"{number}o\",\n  \"relative_time.just_now\": \"orain\",\n  \"relative_time.minutes\": \"{number}m\",\n  \"relative_time.seconds\": \"{number}s\",\n  \"reply_indicator.cancel\": \"Utzi\",\n  \"report.forward\": \"Birbidali hona: {target}\",\n  \"report.forward_hint\": \"Kontu hau beste zerbitzari batekoa da. Bidali txostenaren kopia anonimo hara ere?\",\n  \"report.hint\": \"Txostena zure zerbitzariaren moderatzaileei bidaliko zaie. Kontu hau zergatik salatzen duzun behean azaldu dezakezu:\",\n  \"report.placeholder\": \"Iruzkin gehigarriak\",\n  \"report.submit\": \"Bidali\",\n  \"report.target\": \"{target} salatzen\",\n  \"search.placeholder\": \"Bilatu\",\n  \"search_popout.search_format\": \"Bilaketa aurreratuaren formatua\",\n  \"search_popout.tips.full_text\": \"Testu hutsarekin zuk idatzitako mezuak, gogokoak, bultzadak edo aipamenak aurkitu ditzakezu, bat datozen erabiltzaile-izenak, pantaila-izenak, eta traolak.\",\n  \"search_popout.tips.hashtag\": \"traola\",\n  \"search_popout.tips.status\": \"mezua\",\n  \"search_popout.tips.text\": \"Testu hutsak pantaila-izenak, erabiltzaile-izenak eta traolak bilatzen ditu\",\n  \"search_popout.tips.user\": \"erabiltzailea\",\n  \"search_results.accounts\": \"Jendea\",\n  \"search_results.hashtags\": \"Traolak\",\n  \"search_results.statuses\": \"Toot-ak\",\n  \"search_results.total\": \"{count, number} {count, plural, one {emaitza} other {emaitzak}}\",\n  \"status.admin_account\": \"Ireki @{name} erabiltzailearen moderazio interfazea\",\n  \"status.admin_status\": \"Ireki mezu hau moderazio interfazean\",\n  \"status.block\": \"Blokeatu @{name}\",\n  \"status.cancel_reblog_private\": \"Kendu bultzada\",\n  \"status.cannot_reblog\": \"Mezu honi ezin zaio bultzada eman\",\n  \"status.copy\": \"Kopiatu mezuaren esteka\",\n  \"status.delete\": \"Ezabatu\",\n  \"status.detailed_status\": \"Elkarrizketaren ikuspegi xehetsua\",\n  \"status.direct\": \"Mezu zuzena @{name}(r)i\",\n  \"status.embed\": \"Txertatu\",\n  \"status.favourite\": \"Gogokoa\",\n  \"status.filtered\": \"Iragazita\",\n  \"status.load_more\": \"Kargatu gehiago\",\n  \"status.media_hidden\": \"Multimedia ezkutatua\",\n  \"status.mention\": \"Aipatu @{name}\",\n  \"status.more\": \"Gehiago\",\n  \"status.mute\": \"Mututu @{name}\",\n  \"status.mute_conversation\": \"Mututu elkarrizketa\",\n  \"status.open\": \"Hedatu mezu hau\",\n  \"status.pin\": \"Finkatu profilean\",\n  \"status.pinned\": \"Finkatutako toot-a\",\n  \"status.read_more\": \"Irakurri gehiago\",\n  \"status.reblog\": \"Bultzada\",\n  \"status.reblog_private\": \"Bultzada jatorrizko hartzaileei\",\n  \"status.reblogged_by\": \"{name}(r)en bultzada\",\n  \"status.reblogs.empty\": \"Ez dio inork bultzada eman toot honi oraindik. Inork egiten duenean, hemen agertuko dira.\",\n  \"status.redraft\": \"Ezabatu eta berridatzi\",\n  \"status.reply\": \"Erantzun\",\n  \"status.replyAll\": \"Erantzun harian\",\n  \"status.report\": \"Salatu @{name}\",\n  \"status.sensitive_warning\": \"Kontuz: Eduki hunkigarria\",\n  \"status.share\": \"Partekatu\",\n  \"status.show_less\": \"Erakutsi gutxiago\",\n  \"status.show_less_all\": \"Erakutsi denetarik gutxiago\",\n  \"status.show_more\": \"Erakutsi gehiago\",\n  \"status.show_more_all\": \"Erakutsi denetarik gehiago\",\n  \"status.show_thread\": \"Erakutsi haria\",\n  \"status.unmute_conversation\": \"Desmututu elkarrizketa\",\n  \"status.unpin\": \"Desfinkatu profiletik\",\n  \"suggestions.dismiss\": \"Errefusatu proposamena\",\n  \"suggestions.header\": \"Hau interesatu dakizuke…\",\n  \"tabs_bar.federated_timeline\": \"Federatua\",\n  \"tabs_bar.home\": \"Hasiera\",\n  \"tabs_bar.local_timeline\": \"Lokala\",\n  \"tabs_bar.notifications\": \"Jakinarazpenak\",\n  \"tabs_bar.search\": \"Bilatu\",\n  \"time_remaining.days\": \"{number, plural, one {egun #} other {# egun}} amaitzeko\",\n  \"time_remaining.hours\": \"{number, plural, one {ordu #} other {# ordu}} amaitzeko\",\n  \"time_remaining.minutes\": \"{number, plural, one {minutu #} other {# minutu}} amaitzeko\",\n  \"time_remaining.moments\": \"Amaitzekotan\",\n  \"time_remaining.seconds\": \"{number, plural, one {segundo #} other {# segundo}} amaitzeko\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {person} other {people}} hitz egiten\",\n  \"ui.beforeunload\": \"Zure zirriborroa galduko da Mastodon uzten baduzu.\",\n  \"upload_area.title\": \"Arrastatu eta jaregin igotzeko\",\n  \"upload_button.label\": \"Gehitu multimedia  (JPEG, PNG, GIF, WebM, MP4, MOV)\",\n  \"upload_error.limit\": \"Fitxategi igoera muga gaindituta.\",\n  \"upload_error.poll\": \"Ez da inkestetan fitxategiak igotzea onartzen.\",\n  \"upload_form.description\": \"Deskribatu ikusmen arazoak dituztenentzat\",\n  \"upload_form.focus\": \"Aldatu aurrebista\",\n  \"upload_form.undo\": \"Ezabatu\",\n  \"upload_progress.label\": \"Igotzen...\",\n  \"video.close\": \"Itxi bideoa\",\n  \"video.exit_fullscreen\": \"Irten pantaila osotik\",\n  \"video.expand\": \"Hedatu bideoa\",\n  \"video.fullscreen\": \"Pantaila osoa\",\n  \"video.hide\": \"Ezkutatu bideoa\",\n  \"video.mute\": \"Mututu soinua\",\n  \"video.pause\": \"Pausatu\",\n  \"video.play\": \"Jo\",\n  \"video.unmute\": \"Desmututu soinua\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/fa.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"افزودن یا برداشتن از فهرست\",\n  \"account.badges.bot\": \"ربات\",\n  \"account.block\": \"مسدودسازی @{name}\",\n  \"account.block_domain\": \"پنهان‌سازی همه چیز از سرور {domain}\",\n  \"account.blocked\": \"مسدودشده\",\n  \"account.direct\": \"پیغام خصوصی به @{name}\",\n  \"account.domain_blocked\": \"دامین پنهان‌شده\",\n  \"account.edit_profile\": \"ویرایش نمایه\",\n  \"account.endorse\": \"نمایش در نمایه\",\n  \"account.follow\": \"پی بگیرید\",\n  \"account.followers\": \"پیگیران\",\n  \"account.followers.empty\": \"هنوز هیچ کسی پیگیر این کاربر نیست.\",\n  \"account.follows\": \"پی می‌گیرد\",\n  \"account.follows.empty\": \"این کاربر هنوز هیچ کسی را پی نمی‌گیرد.\",\n  \"account.follows_you\": \"پیگیر شماست\",\n  \"account.hide_reblogs\": \"پنهان کردن بازبوق‌های @{name}\",\n  \"account.link_verified_on\": \"مالکیت این نشانی در تایخ {date} بررسی شد\",\n  \"account.locked_info\": \"این حساب خصوصی است. صاحب این حساب تصمیم می‌گیرد که چه کسی می‌تواند پیگیرش باشد.\",\n  \"account.media\": \"عکس و ویدیو\",\n  \"account.mention\": \"نام‌بردن از @{name}\",\n  \"account.moved_to\": \"{name} منتقل شده است به:\",\n  \"account.mute\": \"بی‌صدا کردن @{name}\",\n  \"account.mute_notifications\": \"بی‌صداکردن اعلان‌ها از طرف @{name}\",\n  \"account.muted\": \"بی‌صداشده\",\n  \"account.posts\": \"نوشته‌ها\",\n  \"account.posts_with_replies\": \"نوشته‌ها و پاسخ‌ها\",\n  \"account.report\": \"گزارش @{name}\",\n  \"account.requested\": \"در انتظار پذیرش\",\n  \"account.share\": \"هم‌رسانی نمایهٔ @{name}\",\n  \"account.show_reblogs\": \"نشان‌دادن بازبوق‌های  @{name}\",\n  \"account.unblock\": \"رفع انسداد @{name}\",\n  \"account.unblock_domain\": \"رفع پنهان‌سازی از {domain}\",\n  \"account.unendorse\": \"نهفتن از نمایه\",\n  \"account.unfollow\": \"پایان پیگیری\",\n  \"account.unmute\": \"باصدا کردن @{name}\",\n  \"account.unmute_notifications\": \"باصداکردن اعلان‌ها از طرف @{name}\",\n  \"alert.unexpected.message\": \"خطای پیش‌بینی‌نشده‌ای رخ داد.\",\n  \"alert.unexpected.title\": \"ای وای!\",\n  \"boost_modal.combo\": \"دکمهٔ {combo} را بزنید تا دیگر این را نبینید\",\n  \"bundle_column_error.body\": \"هنگام بازکردن این بخش خطایی رخ داد.\",\n  \"bundle_column_error.retry\": \"تلاش دوباره\",\n  \"bundle_column_error.title\": \"خطای شبکه\",\n  \"bundle_modal_error.close\": \"بستن\",\n  \"bundle_modal_error.message\": \"هنگام بازکردن این بخش خطایی رخ داد.\",\n  \"bundle_modal_error.retry\": \"تلاش دوباره\",\n  \"column.blocks\": \"کاربران مسدودشده\",\n  \"column.community\": \"نوشته‌های محلی\",\n  \"column.direct\": \"پیغام‌های خصوصی\",\n  \"column.domain_blocks\": \"دامین‌های پنهان‌شده\",\n  \"column.favourites\": \"پسندیده‌ها\",\n  \"column.follow_requests\": \"درخواست‌های پیگیری\",\n  \"column.home\": \"خانه\",\n  \"column.lists\": \"فهرست‌ها\",\n  \"column.mutes\": \"کاربران بی‌صداشده\",\n  \"column.notifications\": \"اعلان‌ها\",\n  \"column.pins\": \"نوشته‌های ثابت\",\n  \"column.public\": \"نوشته‌های همه‌جا\",\n  \"column_back_button.label\": \"بازگشت\",\n  \"column_header.hide_settings\": \"نهفتن تنظیمات\",\n  \"column_header.moveLeft_settings\": \"انتقال ستون به راست\",\n  \"column_header.moveRight_settings\": \"انتقال ستون به چپ\",\n  \"column_header.pin\": \"ثابت‌کردن\",\n  \"column_header.show_settings\": \"نمایش تنظیمات\",\n  \"column_header.unpin\": \"رهاکردن\",\n  \"column_subheading.settings\": \"تنظیمات\",\n  \"community.column_settings.media_only\": \"فقط عکس و ویدیو\",\n  \"compose_form.direct_message_warning\": \"این بوق تنها به کاربرانی که از آن‌ها نام برده شده فرستاده خواهد شد.\",\n  \"compose_form.direct_message_warning_learn_more\": \"بیشتر بدانید\",\n  \"compose_form.hashtag_warning\": \"از آن‌جا که این بوق فهرست‌نشده است، در نتایج جستجوی هشتگ‌ها پیدا نخواهد شد. تنها بوق‌های عمومی را می‌توان با جستجوی هشتگ پیدا کرد.\",\n  \"compose_form.lock_disclaimer\": \"حساب شما {locked} نیست. هر کسی می‌تواند پیگیر شما شود و نوشته‌های ویژهٔ پیگیران شما را ببیند.\",\n  \"compose_form.lock_disclaimer.lock\": \"قفل\",\n  \"compose_form.placeholder\": \"تازه چه خبر؟\",\n  \"compose_form.poll.add_option\": \"افزودن گزینه\",\n  \"compose_form.poll.duration\": \"مدت نظرسنجی\",\n  \"compose_form.poll.option_placeholder\": \"گزینهٔ {number}\",\n  \"compose_form.poll.remove_option\": \"حذف این گزینه\",\n  \"compose_form.publish\": \"بوق\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"علامت‌گذاری به عنوان حساس\",\n  \"compose_form.sensitive.marked\": \"این تصویر به عنوان حساس علامت‌گذاری شده\",\n  \"compose_form.sensitive.unmarked\": \"این تصویر به عنوان حساس علامت‌گذاری نشده\",\n  \"compose_form.spoiler.marked\": \"نوشته پشت هشدار محتوا پنهان است\",\n  \"compose_form.spoiler.unmarked\": \"نوشته پنهان نیست\",\n  \"compose_form.spoiler_placeholder\": \"هشدار محتوا\",\n  \"confirmation_modal.cancel\": \"بی‌خیال\",\n  \"confirmations.block.block_and_report\": \"مسدودسازی و گزارش\",\n  \"confirmations.block.confirm\": \"مسدود کن\",\n  \"confirmations.block.message\": \"آیا واقعاً می‌خواهید {name} را مسدود کنید؟\",\n  \"confirmations.delete.confirm\": \"پاک کن\",\n  \"confirmations.delete.message\": \"آیا واقعاً می‌خواهید این نوشته را پاک کنید؟\",\n  \"confirmations.delete_list.confirm\": \"پاک کن\",\n  \"confirmations.delete_list.message\": \"آیا واقعاً می‌خواهید این فهرست را برای همیشه پاک کنید؟\",\n  \"confirmations.domain_block.confirm\": \"پنهان‌سازی کل دامین\",\n  \"confirmations.domain_block.message\": \"آیا جدی جدی می‌خواهید کل دامین {domain} را مسدود کنید؟ بیشتر وقت‌ها مسدودکردن یا بی‌صداکردن چند حساب کاربری خاص کافی است و توصیه می‌شود. پس از این کار شما هیچ نوشته‌ای را از این دامین در فهرست نوشته‌های عمومی یا اعلان‌هایتان نخواهید دید. پیگیران شما از این دامین هم حذف خواهد شد.\",\n  \"confirmations.mute.confirm\": \"بی‌صدا کن\",\n  \"confirmations.mute.message\": \"آیا واقعاً می‌خواهید {name} را بی‌صدا کنید؟\",\n  \"confirmations.redraft.confirm\": \"پاک‌کردن و بازنویسی\",\n  \"confirmations.redraft.message\": \"آیا واقعاً می‌خواهید این نوشته را پاک کنید و آن را از نو بنویسید؟ با این کار بازبوق‌ها و پسندیده‌شدن‌های آن از دست می‌رود و پاسخ‌ها به آن بی‌مرجع می‌شود.\",\n  \"confirmations.reply.confirm\": \"پاسخ\",\n  \"confirmations.reply.message\": \"اگر الان پاسخ دهید، چیزی که در حال نوشتنش بودید پاک خواهد شد. آیا همین را می‌خواهید؟\",\n  \"confirmations.unfollow.confirm\": \"لغو پیگیری\",\n  \"confirmations.unfollow.message\": \"آیا واقعاً می‌خواهید به پیگیری از {name} پایان دهید؟\",\n  \"embed.instructions\": \"برای جاگذاری این نوشته در سایت خودتان، کد زیر را کپی کنید.\",\n  \"embed.preview\": \"نوشتهٔ جاگذاری‌شده این گونه به نظر خواهد رسید:\",\n  \"emoji_button.activity\": \"فعالیت\",\n  \"emoji_button.custom\": \"سفارشی\",\n  \"emoji_button.flags\": \"پرچم‌ها\",\n  \"emoji_button.food\": \"غذا و نوشیدنی\",\n  \"emoji_button.label\": \"افزودن شکلک\",\n  \"emoji_button.nature\": \"طبیعت\",\n  \"emoji_button.not_found\": \"این‌جا شکلکی نیست!! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"اشیا\",\n  \"emoji_button.people\": \"مردم\",\n  \"emoji_button.recent\": \"زیاد به‌کاررفته\",\n  \"emoji_button.search\": \"جستجو...\",\n  \"emoji_button.search_results\": \"نتایج جستجو\",\n  \"emoji_button.symbols\": \"نمادها\",\n  \"emoji_button.travel\": \"سفر و مکان\",\n  \"empty_column.account_timeline\": \"هیچ بوقی این‌جا نیست!\",\n  \"empty_column.account_unavailable\": \"نمایهٔ ناموجود\",\n  \"empty_column.blocks\": \"شما هنوز هیچ کسی را مسدود نکرده‌اید.\",\n  \"empty_column.community\": \"فهرست نوشته‌های محلی خالی است. چیزی بنویسید تا چرخش بچرخد!\",\n  \"empty_column.direct\": \"شما هیچ پیغام مستقیمی ندارید. اگر چنین پیغامی بگیرید یا بفرستید این‌جا نمایش خواهد یافت.\",\n  \"empty_column.domain_blocks\": \"هنوز هیچ دامینی پنهان نشده است.\",\n  \"empty_column.favourited_statuses\": \"شما هنوز هیچ بوقی را نپسندیده‌اید. وقتی بوقی را بپسندید، این‌جا نمایش خواهد یافت.\",\n  \"empty_column.favourites\": \"هنوز هیچ کسی این بوق را نپسندیده است. وقتی کسی آن را بپسندد، نامش این‌جا نمایش خواهد یافت.\",\n  \"empty_column.follow_requests\": \"شما هنوز هیچ درخواست پیگیری‌ای ندارید. وقتی چنین درخواستی بگیرید، این‌جا نمایش خواهد یافت.\",\n  \"empty_column.hashtag\": \"هنوز هیچ چیزی با این هشتگ نیست.\",\n  \"empty_column.home\": \"شما هنوز پیگیر کسی نیستید. {public} را ببینید یا چیزی را جستجو کنید تا کاربران دیگر را ببینید.\",\n  \"empty_column.home.public_timeline\": \"فهرست نوشته‌های همه‌جا\",\n  \"empty_column.list\": \"در این فهرست هنوز چیزی نیست. وقتی اعضای این فهرست چیزی بنویسند، این‌جا ظاهر خواهد شد.\",\n  \"empty_column.lists\": \"شما هنوز هیچ فهرستی ندارید. اگر فهرستی بسازید، این‌جا نمایش خواهد یافت.\",\n  \"empty_column.mutes\": \"شما هنوز هیچ کاربری را بی‌صدا نکرده‌اید.\",\n  \"empty_column.notifications\": \"هنوز هیچ اعلانی ندارید. به نوشته‌های دیگران واکنش نشان دهید تا گفتگو آغاز شود.\",\n  \"empty_column.public\": \"این‌جا هنوز چیزی نیست! خودتان چیزی بنویسید یا کاربران سرورهای دیگر را پی بگیرید تا این‌جا پر شود\",\n  \"follow_request.authorize\": \"اجازه دهید\",\n  \"follow_request.reject\": \"اجازه ندهید\",\n  \"getting_started.developers\": \"برای برنامه‌نویسان\",\n  \"getting_started.directory\": \"فهرست گزیدهٔ کاربران\",\n  \"getting_started.documentation\": \"راهنما\",\n  \"getting_started.heading\": \"آغاز کنید\",\n  \"getting_started.invite\": \"دعوت از دوستان\",\n  \"getting_started.open_source_notice\": \"ماستدون یک نرم‌افزار آزاد است. می‌توانید در ساخت آن مشارکت کنید یا مشکلاتش را در {github} گزارش دهید.\",\n  \"getting_started.security\": \"امنیت\",\n  \"getting_started.terms\": \"شرایط استفاده\",\n  \"hashtag.column_header.tag_mode.all\": \"و {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"یا {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"بدون {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"هیچ پیشنهادی پیدا نشد\",\n  \"hashtag.column_settings.select.placeholder\": \"برچسب‌ها را وارد کنید…\",\n  \"hashtag.column_settings.tag_mode.all\": \"همهٔ این‌ها\",\n  \"hashtag.column_settings.tag_mode.any\": \"هرکدام از این‌ها\",\n  \"hashtag.column_settings.tag_mode.none\": \"هیچ‌کدام از این‌ها\",\n  \"hashtag.column_settings.tag_toggle\": \"برچسب‌های بیشتری به این ستون بیفزایید\",\n  \"home.column_settings.basic\": \"اصلی\",\n  \"home.column_settings.show_reblogs\": \"نمایش بازبوق‌ها\",\n  \"home.column_settings.show_replies\": \"نمایش پاسخ‌ها\",\n  \"intervals.full.days\": \"{number, plural, one {# روز} other {# روز}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# ساعت} other {# ساعت}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# دقیقه} other {# دقیقه}}\",\n  \"introduction.federation.action\": \"بعدی\",\n  \"introduction.federation.federated.headline\": \"فهرست همهٔ سرورها\",\n  \"introduction.federation.federated.text\": \"نوشته‌های عمومی سرورهای دیگر در این فهرست نمایش می‌یابند.\",\n  \"introduction.federation.home.headline\": \"خانه\",\n  \"introduction.federation.home.text\": \"نوشته‌های کسانی که شما آن‌ها را پی می‌گیرید این‌جا نمایش می‌یابند. شما می‌توانید هر کسی را از هر سروری پی بگیرید!\",\n  \"introduction.federation.local.headline\": \"محلی\",\n  \"introduction.federation.local.text\": \"نوشته‌های عمومی کسانی که روی سرور شما هستند در فهرست نوشته‌های محلی نمایش می‌یابند.\",\n  \"introduction.interactions.action\": \"پایان خودآموز!\",\n  \"introduction.interactions.favourite.headline\": \"پسندیدن\",\n  \"introduction.interactions.favourite.text\": \"با پسندیدن یک بوق، شما آن را برای آینده ذخیره می‌کنید و به نویسنده می‌گویید که از بوقش خوشتان آمده.\",\n  \"introduction.interactions.reblog.headline\": \"بازبوقیدن\",\n  \"introduction.interactions.reblog.text\": \"اگر بخواهید نوشته‌ای را با پیگیران خودتان به اشتراک بگذارید، آن را بازمی‌بوقید.\",\n  \"introduction.interactions.reply.headline\": \"پاسخ\",\n  \"introduction.interactions.reply.text\": \"شما می‌توانید به بوق‌های خودتان و دیگران پاسخ دهید، تا همهٔ این بوق‌ها به شکل رشتهٔ به‌هم‌پیوسته‌ای در یک گفتگو درآیند.\",\n  \"introduction.welcome.action\": \"بزن بریم!\",\n  \"introduction.welcome.headline\": \"نخستین گام‌ها\",\n  \"introduction.welcome.text\": \"به دنیای شبکه‌های اجتماعی غیرمتمرکز خوش آمدید! به زودی می‌توانید نوشته‌های خودتان را منتشر کنید و با دوستانتان که روی سرورهای مختلفی هستند حرف بزنید. ولی این سرور، {domain}، با بقیه فرق دارد زیرا حساب شما روی آن ساخته شده است، پس نامش را یادتان نگه دارید.\",\n  \"keyboard_shortcuts.back\": \"برای بازگشت\",\n  \"keyboard_shortcuts.blocked\": \"برای گشودن کاربران بی‌صداشده\",\n  \"keyboard_shortcuts.boost\": \"برای بازبوقیدن\",\n  \"keyboard_shortcuts.column\": \"برای برجسته‌کردن یک نوشته در یکی از ستون‌ها\",\n  \"keyboard_shortcuts.compose\": \"برای فعال‌کردن کادر نوشتهٔ تازه\",\n  \"keyboard_shortcuts.description\": \"توضیح\",\n  \"keyboard_shortcuts.direct\": \"برای گشودن ستون پیغام‌های مستقیم\",\n  \"keyboard_shortcuts.down\": \"برای پایین‌رفتن در فهرست\",\n  \"keyboard_shortcuts.enter\": \"برای گشودن نوشته\",\n  \"keyboard_shortcuts.favourite\": \"برای پسندیدن\",\n  \"keyboard_shortcuts.favourites\": \"برای گشودن پیغام‌های پسندیده‌شده\",\n  \"keyboard_shortcuts.federated\": \"برای گشودن فهرست نوشته‌های همه‌جا\",\n  \"keyboard_shortcuts.heading\": \"میان‌برهای صفحه‌کلید\",\n  \"keyboard_shortcuts.home\": \"برای گشودن ستون اصلی پیگیری‌ها\",\n  \"keyboard_shortcuts.hotkey\": \"میان‌بر\",\n  \"keyboard_shortcuts.legend\": \"برای نمایش این راهنما\",\n  \"keyboard_shortcuts.local\": \"برای گشودن فهرست نوشته‌های محلی\",\n  \"keyboard_shortcuts.mention\": \"برای نام‌بردن از نویسنده\",\n  \"keyboard_shortcuts.muted\": \"برای گشودن فهرست کاربران بی‌صداشده\",\n  \"keyboard_shortcuts.my_profile\": \"برای گشودن صفحهٔ نمایهٔ شما\",\n  \"keyboard_shortcuts.notifications\": \"برای گشودن ستون اعلان‌ها\",\n  \"keyboard_shortcuts.pinned\": \"برای گشودن فهرست نوشته‌‌های ثابت\",\n  \"keyboard_shortcuts.profile\": \"گشودن نمایهٔ نویسنده\",\n  \"keyboard_shortcuts.reply\": \"برای پاسخ‌دادن\",\n  \"keyboard_shortcuts.requests\": \"برای گشودن فهرست درخواست‌های پیگیری\",\n  \"keyboard_shortcuts.search\": \"برای فعال‌کردن جستجو\",\n  \"keyboard_shortcuts.start\": \"برای گشودن ستون «آغاز کنید»\",\n  \"keyboard_shortcuts.toggle_hidden\": \"برای نمایش/نهفتن نوشتهٔ پشت هشدار محتوا\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"برای نمایش/نهفتن عکس و ویدیو\",\n  \"keyboard_shortcuts.toot\": \"برای آغاز یک بوق تازه\",\n  \"keyboard_shortcuts.unfocus\": \"برای برداشتن توجه از نوشتن/جستجو\",\n  \"keyboard_shortcuts.up\": \"برای بالا رفتن در فهرست\",\n  \"lightbox.close\": \"بستن\",\n  \"lightbox.next\": \"بعدی\",\n  \"lightbox.previous\": \"قبلی\",\n  \"lightbox.view_context\": \"نمایش گفتگو\",\n  \"lists.account.add\": \"افزودن به فهرست\",\n  \"lists.account.remove\": \"پاک‌کردن از فهرست\",\n  \"lists.delete\": \"حذف فهرست\",\n  \"lists.edit\": \"ویرایش فهرست\",\n  \"lists.edit.submit\": \"تغییر عنوان\",\n  \"lists.new.create\": \"افزودن فهرست\",\n  \"lists.new.title_placeholder\": \"نام فهرست تازه\",\n  \"lists.search\": \"بین کسانی که پی می‌گیرید بگردید\",\n  \"lists.subheading\": \"فهرست‌های شما\",\n  \"loading_indicator.label\": \"بارگیری...\",\n  \"media_gallery.toggle_visible\": \"تغییر پیدایی\",\n  \"missing_indicator.label\": \"پیدا نشد\",\n  \"missing_indicator.sublabel\": \"این منبع پیدا نشد\",\n  \"mute_modal.hide_notifications\": \"اعلان‌های این کاربر پنهان شود؟\",\n  \"navigation_bar.apps\": \"اپ‌های موبایل\",\n  \"navigation_bar.blocks\": \"کاربران مسدودشده\",\n  \"navigation_bar.community_timeline\": \"نوشته‌های محلی\",\n  \"navigation_bar.compose\": \"نوشتن بوق تازه\",\n  \"navigation_bar.direct\": \"پیغام‌های مستقیم\",\n  \"navigation_bar.discover\": \"گشت و گذار\",\n  \"navigation_bar.domain_blocks\": \"دامین‌های پنهان‌شده\",\n  \"navigation_bar.edit_profile\": \"ویرایش نمایه\",\n  \"navigation_bar.favourites\": \"پسندیده‌ها\",\n  \"navigation_bar.filters\": \"واژگان بی‌صداشده\",\n  \"navigation_bar.follow_requests\": \"درخواست‌های پیگیری\",\n  \"navigation_bar.follows_and_followers\": \"پیگیری‌ها و پیگیران\",\n  \"navigation_bar.info\": \"دربارهٔ این سرور\",\n  \"navigation_bar.keyboard_shortcuts\": \"میان‌برهای صفحه‌کلید\",\n  \"navigation_bar.lists\": \"فهرست‌ها\",\n  \"navigation_bar.logout\": \"خروج\",\n  \"navigation_bar.mutes\": \"کاربران بی‌صداشده\",\n  \"navigation_bar.personal\": \"شخصی\",\n  \"navigation_bar.pins\": \"نوشته‌های ثابت\",\n  \"navigation_bar.preferences\": \"ترجیحات\",\n  \"navigation_bar.profile_directory\": \"فهرست گزیدهٔ کاربران\",\n  \"navigation_bar.public_timeline\": \"نوشته‌های همه‌جا\",\n  \"navigation_bar.security\": \"امنیت\",\n  \"notification.favourite\": \"‫{name}‬ نوشتهٔ شما را پسندید\",\n  \"notification.follow\": \"‫{name}‬ پیگیر شما شد\",\n  \"notification.mention\": \"‫{name}‬ از شما نام برد\",\n  \"notification.poll\": \"نظرسنجی‌ای که در آن رأی دادید به پایان رسیده است\",\n  \"notification.reblog\": \"‫{name}‬ نوشتهٔ شما را بازبوقید\",\n  \"notifications.clear\": \"پاک‌کردن اعلان‌ها\",\n  \"notifications.clear_confirmation\": \"واقعاً می‌خواهید همهٔ اعلان‌هایتان را برای همیشه پاک کنید؟\",\n  \"notifications.column_settings.alert\": \"اعلان در کامپیوتر\",\n  \"notifications.column_settings.favourite\": \"پسندیده‌ها:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"نمایش همهٔ گروه‌ها\",\n  \"notifications.column_settings.filter_bar.category\": \"فیلتر سریع\",\n  \"notifications.column_settings.filter_bar.show\": \"نمایش\",\n  \"notifications.column_settings.follow\": \"پیگیران تازه:\",\n  \"notifications.column_settings.mention\": \"نام‌بردن‌ها:\",\n  \"notifications.column_settings.poll\": \"نتایج نظرسنجی:\",\n  \"notifications.column_settings.push\": \"اعلان‌ها از سمت سرور\",\n  \"notifications.column_settings.reblog\": \"بازبوق‌ها:\",\n  \"notifications.column_settings.show\": \"نمایش در ستون\",\n  \"notifications.column_settings.sound\": \"پخش صدا\",\n  \"notifications.filter.all\": \"همه\",\n  \"notifications.filter.boosts\": \"بازبوق‌ها\",\n  \"notifications.filter.favourites\": \"پسندیده‌ها\",\n  \"notifications.filter.follows\": \"پیگیری‌ها\",\n  \"notifications.filter.mentions\": \"گفتگوها\",\n  \"notifications.filter.polls\": \"نتایج نظرسنجی\",\n  \"notifications.group\": \"{count} اعلان\",\n  \"poll.closed\": \"پایان‌یافته\",\n  \"poll.refresh\": \"به‌روزرسانی\",\n  \"poll.total_votes\": \"{count, plural, one {# رأی} other {# رأی}}\",\n  \"poll.vote\": \"رأی\",\n  \"poll_button.add_poll\": \"افزودن نظرسنجی\",\n  \"poll_button.remove_poll\": \"حذف نظرسنجی\",\n  \"privacy.change\": \"تنظیم حریم خصوصی نوشته‌ها\",\n  \"privacy.direct.long\": \"تنها به کاربران نام‌برده‌شده نشان بده\",\n  \"privacy.direct.short\": \"مستقیم\",\n  \"privacy.private.long\": \"تنها به پیگیران نشان بده\",\n  \"privacy.private.short\": \"خصوصی\",\n  \"privacy.public.long\": \"نمایش در فهرست عمومی\",\n  \"privacy.public.short\": \"عمومی\",\n  \"privacy.unlisted.long\": \"عمومی، ولی فهرست نکن\",\n  \"privacy.unlisted.short\": \"فهرست‌نشده\",\n  \"regeneration_indicator.label\": \"در حال باز شدن…\",\n  \"regeneration_indicator.sublabel\": \"این فهرست دارد آماده می‌شود!\",\n  \"relative_time.days\": \"{number} روز\",\n  \"relative_time.hours\": \"{number} ساعت\",\n  \"relative_time.just_now\": \"الان\",\n  \"relative_time.minutes\": \"{number} دقیقه\",\n  \"relative_time.seconds\": \"{number} ثانیه\",\n  \"reply_indicator.cancel\": \"لغو\",\n  \"report.forward\": \"فرستادن به {target}\",\n  \"report.forward_hint\": \"این حساب در سرور دیگری ثبت شده. آیا می‌خواهید رونوشتی از این گزارش به طور ناشناس به آن‌جا هم فرستاده شود؟\",\n  \"report.hint\": \"این گزارش به مدیران سرور شما فرستاده خواهد شد. می‌توانید دلیل گزارش‌دادن این حساب را در این‌جا بنویسید:\",\n  \"report.placeholder\": \"توضیح اضافه\",\n  \"report.submit\": \"بفرست\",\n  \"report.target\": \"گزارش‌دادن\",\n  \"search.placeholder\": \"جستجو\",\n  \"search_popout.search_format\": \"راهنمای جستجوی پیشرفته\",\n  \"search_popout.tips.full_text\": \"جستجوی متنی ساده می‌تواند بوق‌هایی که شما نوشته‌اید، پسندیده‌اید، بازبوقیده‌اید، یا در آن‌ها از شما نام برده شده است را پیدا کند. همچنین نام‌های کاربری، نام نمایش‌یافته، و هشتگ‌ها را هم شامل می‌شود.\",\n  \"search_popout.tips.hashtag\": \"هشتگ\",\n  \"search_popout.tips.status\": \"نوشته\",\n  \"search_popout.tips.text\": \"جستجوی متنی ساده برای نام‌ها، نام‌های کاربری، و هشتگ‌ها\",\n  \"search_popout.tips.user\": \"کاربر\",\n  \"search_results.accounts\": \"افراد\",\n  \"search_results.hashtags\": \"هشتگ‌ها\",\n  \"search_results.statuses\": \"بوق‌ها\",\n  \"search_results.total\": \"{count, number} {count, plural, one {نتیجه} other {نتیجه}}\",\n  \"status.admin_account\": \"محیط مدیریت مربوط به @{name} را باز کن\",\n  \"status.admin_status\": \"این نوشته را در محیط مدیریت باز کن\",\n  \"status.block\": \"مسدودسازی @{name}\",\n  \"status.cancel_reblog_private\": \"حذف بازبوق\",\n  \"status.cannot_reblog\": \"این نوشته را نمی‌شود بازبوقید\",\n  \"status.copy\": \"رونوشت‌برداری از نشانی این نوشته\",\n  \"status.delete\": \"پاک‌کردن\",\n  \"status.detailed_status\": \"نمایش کامل گفتگو\",\n  \"status.direct\": \"پیغام مستقیم به @{name}\",\n  \"status.embed\": \"جاگذاری\",\n  \"status.favourite\": \"پسندیدن\",\n  \"status.filtered\": \"فیلترشده\",\n  \"status.load_more\": \"بیشتر نشان بده\",\n  \"status.media_hidden\": \"تصویر پنهان شده\",\n  \"status.mention\": \"نام‌بردن از @{name}\",\n  \"status.more\": \"بیشتر\",\n  \"status.mute\": \"بی‌صدا کردن @{name}\",\n  \"status.mute_conversation\": \"بی‌صداکردن گفتگو\",\n  \"status.open\": \"این نوشته را باز کن\",\n  \"status.pin\": \"نوشتهٔ ثابت نمایه\",\n  \"status.pinned\": \"بوق ثابت\",\n  \"status.read_more\": \"بیشتر بخوانید\",\n  \"status.reblog\": \"بازبوقیدن\",\n  \"status.reblog_private\": \"بازبوق به مخاطبان اولیه\",\n  \"status.reblogged_by\": \"‫{name}‬ بازبوقید\",\n  \"status.reblogs.empty\": \"هنوز هیچ کسی این بوق را بازنبوقیده است. وقتی کسی چنین کاری کند، این‌جا نمایش خواهد یافت.\",\n  \"status.redraft\": \"پاک‌کردن و بازنویسی\",\n  \"status.reply\": \"پاسخ\",\n  \"status.replyAll\": \"به نوشته پاسخ دهید\",\n  \"status.report\": \"گزارش دادن @{name}\",\n  \"status.sensitive_warning\": \"محتوای حساس\",\n  \"status.share\": \"هم‌رسانی\",\n  \"status.show_less\": \"نهفتن\",\n  \"status.show_less_all\": \"نمایش کمتر همه\",\n  \"status.show_more\": \"نمایش\",\n  \"status.show_more_all\": \"نمایش بیشتر همه\",\n  \"status.show_thread\": \"نمایش گفتگو\",\n  \"status.unmute_conversation\": \"باصداکردن گفتگو\",\n  \"status.unpin\": \"برداشتن نوشتهٔ ثابت نمایه\",\n  \"suggestions.dismiss\": \"پیشنهاد را نادیده بگیر\",\n  \"suggestions.header\": \"شاید این هم برایتان جالب باشد…\",\n  \"tabs_bar.federated_timeline\": \"همگانی\",\n  \"tabs_bar.home\": \"خانه\",\n  \"tabs_bar.local_timeline\": \"محلی\",\n  \"tabs_bar.notifications\": \"اعلان‌ها\",\n  \"tabs_bar.search\": \"جستجو\",\n  \"time_remaining.days\": \"{number, plural, one {# روز} other {# روز}} باقی مانده\",\n  \"time_remaining.hours\": \"{number, plural, one {# ساعت} other {# ساعت}} باقی مانده\",\n  \"time_remaining.minutes\": \"{number, plural, one {# دقیقه} other {# دقیقه}} باقی مانده\",\n  \"time_remaining.moments\": \"زمان باقی‌مانده\",\n  \"time_remaining.seconds\": \"{number, plural, one {# ثانیه} other {# ثانیه}} باقی مانده\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {نفر نوشته است} other {نفر نوشته‌اند}}\",\n  \"ui.beforeunload\": \"اگر از ماستدون خارج شوید پیش‌نویس شما پاک خواهد شد.\",\n  \"upload_area.title\": \"برای بارگذاری به این‌جا بکشید\",\n  \"upload_button.label\": \"افزودن عکس و ویدیو (JPEG, PNG, GIF, WebM, MP4, MOV)\",\n  \"upload_error.limit\": \"از حد مجاز باگذاری فراتر رفتید.\",\n  \"upload_error.poll\": \"باگذاری پرونده در نظرسنجی‌ها ممکن نیست.\",\n  \"upload_form.description\": \"نوشتهٔ توضیحی برای کم‌بینایان و نابینایان\",\n  \"upload_form.focus\": \"تغییر پیش‌نمایش\",\n  \"upload_form.undo\": \"حذف\",\n  \"upload_progress.label\": \"بارگذاری...\",\n  \"video.close\": \"بستن ویدیو\",\n  \"video.exit_fullscreen\": \"خروج از حالت تمام صفحه\",\n  \"video.expand\": \"بزرگ‌کردن ویدیو\",\n  \"video.fullscreen\": \"تمام صفحه\",\n  \"video.hide\": \"نهفتن ویدیو\",\n  \"video.mute\": \"قطع صدا\",\n  \"video.pause\": \"توقف\",\n  \"video.play\": \"پخش\",\n  \"video.unmute\": \"پخش صدا\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/fi.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Lisää tai poista listoilta\",\n  \"account.badges.bot\": \"Botti\",\n  \"account.block\": \"Estä @{name}\",\n  \"account.block_domain\": \"Piilota kaikki sisältö verkkotunnuksesta {domain}\",\n  \"account.blocked\": \"Estetty\",\n  \"account.direct\": \"Viesti käyttäjälle @{name}\",\n  \"account.domain_blocked\": \"Verkko-osoite piilotettu\",\n  \"account.edit_profile\": \"Muokkaa\",\n  \"account.endorse\": \"Suosittele profiilissasi\",\n  \"account.follow\": \"Seuraa\",\n  \"account.followers\": \"Seuraajia\",\n  \"account.followers.empty\": \"Tällä käyttäjällä ei ole vielä seuraajia.\",\n  \"account.follows\": \"Seuraa\",\n  \"account.follows.empty\": \"Tämä käyttäjä ei vielä seuraa ketään.\",\n  \"account.follows_you\": \"Seuraa sinua\",\n  \"account.hide_reblogs\": \"Piilota buustaukset käyttäjältä @{name}\",\n  \"account.link_verified_on\": \"Tämän linkin omistaja tarkistettiin {date}\",\n  \"account.locked_info\": \"Tämän tili on yksityinen. Käyttäjä vahvistaa itse kuka voi seurata häntä.\",\n  \"account.media\": \"Media\",\n  \"account.mention\": \"Mainitse @{name}\",\n  \"account.moved_to\": \"{name} on muuttanut instanssiin:\",\n  \"account.mute\": \"Mykistä @{name}\",\n  \"account.mute_notifications\": \"Mykistä ilmoitukset käyttäjältä @{name}\",\n  \"account.muted\": \"Mykistetty\",\n  \"account.posts\": \"Tuuttaukset\",\n  \"account.posts_with_replies\": \"Tuuttaukset ja vastaukset\",\n  \"account.report\": \"Raportoi @{name}\",\n  \"account.requested\": \"Odottaa hyväksyntää. Peruuta seuraamispyyntö klikkaamalla\",\n  \"account.share\": \"Jaa käyttäjän @{name} profiili\",\n  \"account.show_reblogs\": \"Näytä buustaukset käyttäjältä @{name}\",\n  \"account.unblock\": \"Salli @{name}\",\n  \"account.unblock_domain\": \"Näytä {domain}\",\n  \"account.unendorse\": \"Poista suosittelu profiilistasi\",\n  \"account.unfollow\": \"Lakkaa seuraamasta\",\n  \"account.unmute\": \"Poista käyttäjän @{name} mykistys\",\n  \"account.unmute_notifications\": \"Poista mykistys käyttäjän @{name} ilmoituksilta\",\n  \"alert.unexpected.message\": \"Tapahtui odottamaton virhe.\",\n  \"alert.unexpected.title\": \"Hups!\",\n  \"boost_modal.combo\": \"Ensi kerralla voit ohittaa tämän painamalla {combo}\",\n  \"bundle_column_error.body\": \"Jokin meni vikaan komponenttia ladattaessa.\",\n  \"bundle_column_error.retry\": \"Yritä uudestaan\",\n  \"bundle_column_error.title\": \"Verkkovirhe\",\n  \"bundle_modal_error.close\": \"Sulje\",\n  \"bundle_modal_error.message\": \"Jokin meni vikaan komponenttia ladattaessa.\",\n  \"bundle_modal_error.retry\": \"Yritä uudestaan\",\n  \"column.blocks\": \"Estetyt käyttäjät\",\n  \"column.community\": \"Paikallinen aikajana\",\n  \"column.direct\": \"Viestit\",\n  \"column.domain_blocks\": \"Piilotetut verkkotunnukset\",\n  \"column.favourites\": \"Suosikit\",\n  \"column.follow_requests\": \"Seuraamispyynnöt\",\n  \"column.home\": \"Koti\",\n  \"column.lists\": \"Listat\",\n  \"column.mutes\": \"Mykistetyt käyttäjät\",\n  \"column.notifications\": \"Ilmoitukset\",\n  \"column.pins\": \"Kiinnitetty tuuttaus\",\n  \"column.public\": \"Yleinen aikajana\",\n  \"column_back_button.label\": \"Takaisin\",\n  \"column_header.hide_settings\": \"Piilota asetukset\",\n  \"column_header.moveLeft_settings\": \"Siirrä saraketta vasemmalle\",\n  \"column_header.moveRight_settings\": \"Siirrä saraketta oikealle\",\n  \"column_header.pin\": \"Kiinnitä\",\n  \"column_header.show_settings\": \"Näytä asetukset\",\n  \"column_header.unpin\": \"Poista kiinnitys\",\n  \"column_subheading.settings\": \"Asetukset\",\n  \"community.column_settings.media_only\": \"Vain media\",\n  \"compose_form.direct_message_warning\": \"Tämä tuuttaus näkyy vain mainituille käyttäjille.\",\n  \"compose_form.direct_message_warning_learn_more\": \"Lisätietoja\",\n  \"compose_form.hashtag_warning\": \"Tämä tuuttaus ei näy hashtag-hauissa, koska se on listaamaton. Hashtagien avulla voi hakea vain julkisia tuuttauksia.\",\n  \"compose_form.lock_disclaimer\": \"Tilisi ei ole {locked}. Kuka tahansa voi seurata tiliäsi ja nähdä vain seuraajille rajaamasi julkaisut.\",\n  \"compose_form.lock_disclaimer.lock\": \"lukittu\",\n  \"compose_form.placeholder\": \"Mitä mietit?\",\n  \"compose_form.poll.add_option\": \"Add a choice\",\n  \"compose_form.poll.duration\": \"Poll duration\",\n  \"compose_form.poll.option_placeholder\": \"Choice {number}\",\n  \"compose_form.poll.remove_option\": \"Remove this choice\",\n  \"compose_form.publish\": \"Tuuttaa\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"Mark media as sensitive\",\n  \"compose_form.sensitive.marked\": \"Media on merkitty arkaluontoiseksi\",\n  \"compose_form.sensitive.unmarked\": \"Mediaa ei ole merkitty arkaluontoiseksi\",\n  \"compose_form.spoiler.marked\": \"Teksti on piilotettu varoituksen taakse\",\n  \"compose_form.spoiler.unmarked\": \"Teksti ei ole piilotettu\",\n  \"compose_form.spoiler_placeholder\": \"Sisältövaroitus\",\n  \"confirmation_modal.cancel\": \"Peruuta\",\n  \"confirmations.block.block_and_report\": \"Block & Report\",\n  \"confirmations.block.confirm\": \"Estä\",\n  \"confirmations.block.message\": \"Haluatko varmasti estää käyttäjän {name}?\",\n  \"confirmations.delete.confirm\": \"Poista\",\n  \"confirmations.delete.message\": \"Haluatko varmasti poistaa tämän tilapäivityksen?\",\n  \"confirmations.delete_list.confirm\": \"Poista\",\n  \"confirmations.delete_list.message\": \"Haluatko varmasti poistaa tämän listan kokonaan?\",\n  \"confirmations.domain_block.confirm\": \"Piilota koko verkko-osoite\",\n  \"confirmations.domain_block.message\": \"Haluatko aivan varmasti estää koko verkko-osoitteen {domain}? Useimmiten jokunen kohdistettu esto ja mykistys riittää, ja se on suositeltavampi tapa toimia.\",\n  \"confirmations.mute.confirm\": \"Mykistä\",\n  \"confirmations.mute.message\": \"Haluatko varmasti mykistää käyttäjän {name}?\",\n  \"confirmations.redraft.confirm\": \"Poista & palauta muokattavaksi\",\n  \"confirmations.redraft.message\": \"Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.\",\n  \"confirmations.reply.confirm\": \"Vastaa\",\n  \"confirmations.reply.message\": \"Jos vastaat nyt, vastaus korvaa tällä hetkellä työstämäsi viestin. Oletko varma, että haluat jatkaa?\",\n  \"confirmations.unfollow.confirm\": \"Lakkaa seuraamasta\",\n  \"confirmations.unfollow.message\": \"Haluatko varmasti lakata seuraamasta käyttäjää {name}?\",\n  \"embed.instructions\": \"Upota statuspäivitys sivullesi kopioimalla alla oleva koodi.\",\n  \"embed.preview\": \"Se tulee näyttämään tältä:\",\n  \"emoji_button.activity\": \"Aktiviteetit\",\n  \"emoji_button.custom\": \"Mukautetut\",\n  \"emoji_button.flags\": \"Liput\",\n  \"emoji_button.food\": \"Ruoka ja juoma\",\n  \"emoji_button.label\": \"Lisää emoji\",\n  \"emoji_button.nature\": \"Luonto\",\n  \"emoji_button.not_found\": \"Ei emojeja!! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"Esineet\",\n  \"emoji_button.people\": \"Ihmiset\",\n  \"emoji_button.recent\": \"Usein käytetyt\",\n  \"emoji_button.search\": \"Etsi...\",\n  \"emoji_button.search_results\": \"Hakutulokset\",\n  \"emoji_button.symbols\": \"Symbolit\",\n  \"emoji_button.travel\": \"Matkailu\",\n  \"empty_column.account_timeline\": \"Ei ole 'toots' täällä!\",\n  \"empty_column.account_unavailable\": \"Profile unavailable\",\n  \"empty_column.blocks\": \"Et ole vielä estänyt yhtään käyttäjää.\",\n  \"empty_column.community\": \"Paikallinen aikajana on tyhjä. Homma lähtee käyntiin, kun kirjoitat jotain julkista!\",\n  \"empty_column.direct\": \"Sinulla ei ole vielä yhtään viestiä yksittäiselle käyttäjälle. Kun lähetät tai vastaanotat sellaisen, se näkyy täällä.\",\n  \"empty_column.domain_blocks\": \"Yhtään verkko-osoitetta ei ole vielä piilotettu.\",\n  \"empty_column.favourited_statuses\": \"Et ole vielä lisännyt tuuttauksia suosikkeihisi. Kun teet niin, tuuttaus näkyy tässä.\",\n  \"empty_column.favourites\": \"Kukaan ei ole vielä lisännyt tätä tuuttausta suosikkeihinsa. Kun joku tekee niin, näkyy kyseinen henkilö tässä.\",\n  \"empty_column.follow_requests\": \"Sinulla ei ole vielä seurauspyyntöjä. Kun saat sellaisen, näkyy se tässä.\",\n  \"empty_column.hashtag\": \"Tällä hashtagilla ei ole vielä mitään.\",\n  \"empty_column.home\": \"Kotiaikajanasi on tyhjä! {public} ja hakutoiminto auttavat alkuun ja kohtaamaan muita käyttäjiä.\",\n  \"empty_column.home.public_timeline\": \"yleinen aikajana\",\n  \"empty_column.list\": \"Lista on vielä tyhjä. Listan jäsenten julkaisemat tilapäivitykset tulevat tähän näkyviin.\",\n  \"empty_column.lists\": \"Sinulla ei ole vielä yhtään listaa. Kun luot sellaisen, näkyy se tässä.\",\n  \"empty_column.mutes\": \"Et ole mykistänyt vielä yhtään käyttäjää.\",\n  \"empty_column.notifications\": \"Sinulle ei ole vielä ilmoituksia. Aloita keskustelu juttelemalla muille.\",\n  \"empty_column.public\": \"Täällä ei ole mitään! Saat sisältöä, kun kirjoitat jotain julkisesti tai käyt seuraamassa muiden instanssien käyttäjiä\",\n  \"follow_request.authorize\": \"Valtuuta\",\n  \"follow_request.reject\": \"Hylkää\",\n  \"getting_started.developers\": \"Kehittäjille\",\n  \"getting_started.directory\": \"Profiili hakemisto\",\n  \"getting_started.documentation\": \"Documentation\",\n  \"getting_started.heading\": \"Aloitus\",\n  \"getting_started.invite\": \"Kutsu ihmisiä\",\n  \"getting_started.open_source_notice\": \"Mastodon on avoimen lähdekoodin ohjelma. Voit avustaa tai raportoida ongelmia GitHubissa: {github}.\",\n  \"getting_started.security\": \"Tunnukset\",\n  \"getting_started.terms\": \"Käyttöehdot\",\n  \"hashtag.column_header.tag_mode.all\": \"ja {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"tai {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"ilman {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"No suggestions found\",\n  \"hashtag.column_settings.select.placeholder\": \"Enter hashtags…\",\n  \"hashtag.column_settings.tag_mode.all\": \"Kaikki\",\n  \"hashtag.column_settings.tag_mode.any\": \"Kaikki\",\n  \"hashtag.column_settings.tag_mode.none\": \"Ei mikään\",\n  \"hashtag.column_settings.tag_toggle\": \"Include additional tags in this column\",\n  \"home.column_settings.basic\": \"Perusasetukset\",\n  \"home.column_settings.show_reblogs\": \"Näytä buustaukset\",\n  \"home.column_settings.show_replies\": \"Näytä vastaukset\",\n  \"intervals.full.days\": \"{number, plural, one {# day} other {# days}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# hour} other {# hours}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minute} other {# minutes}}\",\n  \"introduction.federation.action\": \"Seuraava\",\n  \"introduction.federation.federated.headline\": \"Federated\",\n  \"introduction.federation.federated.text\": \"Public posts from other servers of the fediverse will appear in the federated timeline.\",\n  \"introduction.federation.home.headline\": \"Home\",\n  \"introduction.federation.home.text\": \"Posts from people you follow will appear in your home feed. You can follow anyone on any server!\",\n  \"introduction.federation.local.headline\": \"Local\",\n  \"introduction.federation.local.text\": \"Public posts from people on the same server as you will appear in the local timeline.\",\n  \"introduction.interactions.action\": \"Finish toot-orial!\",\n  \"introduction.interactions.favourite.headline\": \"Favourite\",\n  \"introduction.interactions.favourite.text\": \"You can save a toot for later, and let the author know that you liked it, by favouriting it.\",\n  \"introduction.interactions.reblog.headline\": \"Boost\",\n  \"introduction.interactions.reblog.text\": \"You can share other people's toots with your followers by boosting them.\",\n  \"introduction.interactions.reply.headline\": \"Reply\",\n  \"introduction.interactions.reply.text\": \"You can reply to other people's and your own toots, which will chain them together in a conversation.\",\n  \"introduction.welcome.action\": \"Let's go!\",\n  \"introduction.welcome.headline\": \"First steps\",\n  \"introduction.welcome.text\": \"Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.\",\n  \"keyboard_shortcuts.back\": \"liiku taaksepäin\",\n  \"keyboard_shortcuts.blocked\": \"avaa lista estetyistä käyttäjistä\",\n  \"keyboard_shortcuts.boost\": \"buustaa\",\n  \"keyboard_shortcuts.column\": \"siirrä fokus tietyn sarakkeen tilapäivitykseen\",\n  \"keyboard_shortcuts.compose\": \"siirry tekstinsyöttöön\",\n  \"keyboard_shortcuts.description\": \"Kuvaus\",\n  \"keyboard_shortcuts.direct\": \"avaa pikaviestisarake\",\n  \"keyboard_shortcuts.down\": \"siirry listassa alaspäin\",\n  \"keyboard_shortcuts.enter\": \"avaa tilapäivitys\",\n  \"keyboard_shortcuts.favourite\": \"tykkää\",\n  \"keyboard_shortcuts.favourites\": \"avaa lista suosikeista\",\n  \"keyboard_shortcuts.federated\": \"avaa yleinen aikajana\",\n  \"keyboard_shortcuts.heading\": \"Näppäinkomennot\",\n  \"keyboard_shortcuts.home\": \"avaa kotiaikajana\",\n  \"keyboard_shortcuts.hotkey\": \"Pikanäppäin\",\n  \"keyboard_shortcuts.legend\": \"näytä tämä selite\",\n  \"keyboard_shortcuts.local\": \"avaa paikallinen aikajana\",\n  \"keyboard_shortcuts.mention\": \"mainitse julkaisija\",\n  \"keyboard_shortcuts.muted\": \"avaa lista mykistetyistä käyttäjistä\",\n  \"keyboard_shortcuts.my_profile\": \"avaa profiilisi\",\n  \"keyboard_shortcuts.notifications\": \"avaa ilmoitukset-sarake\",\n  \"keyboard_shortcuts.pinned\": \"avaa lista kiinnitetyistä tuuttauksista\",\n  \"keyboard_shortcuts.profile\": \"avaa kirjoittajan profiili\",\n  \"keyboard_shortcuts.reply\": \"vastaa\",\n  \"keyboard_shortcuts.requests\": \"avaa lista seurauspyynnöistä\",\n  \"keyboard_shortcuts.search\": \"siirry hakukenttään\",\n  \"keyboard_shortcuts.start\": \"avaa \\\"Aloitus\\\" -sarake\",\n  \"keyboard_shortcuts.toggle_hidden\": \"näytä/piilota sisältövaroituksella merkitty teksti\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"to show/hide media\",\n  \"keyboard_shortcuts.toot\": \"ala kirjoittaa uutta tuuttausta\",\n  \"keyboard_shortcuts.unfocus\": \"siirry pois tekstikentästä tai hakukentästä\",\n  \"keyboard_shortcuts.up\": \"siirry listassa ylöspäin\",\n  \"lightbox.close\": \"Sulje\",\n  \"lightbox.next\": \"Seuraava\",\n  \"lightbox.previous\": \"Edellinen\",\n  \"lightbox.view_context\": \"View context\",\n  \"lists.account.add\": \"Lisää listaan\",\n  \"lists.account.remove\": \"Poista listasta\",\n  \"lists.delete\": \"Poista lista\",\n  \"lists.edit\": \"Muokkaa listaa\",\n  \"lists.edit.submit\": \"Change title\",\n  \"lists.new.create\": \"Lisää lista\",\n  \"lists.new.title_placeholder\": \"Uuden listan nimi\",\n  \"lists.search\": \"Etsi seuraamistasi henkilöistä\",\n  \"lists.subheading\": \"Omat listat\",\n  \"loading_indicator.label\": \"Ladataan...\",\n  \"media_gallery.toggle_visible\": \"Säädä näkyvyyttä\",\n  \"missing_indicator.label\": \"Ei löytynyt\",\n  \"missing_indicator.sublabel\": \"Tätä resurssia ei löytynyt\",\n  \"mute_modal.hide_notifications\": \"Piilota tältä käyttäjältä tulevat ilmoitukset?\",\n  \"navigation_bar.apps\": \"Mobiiliapplikaatiot\",\n  \"navigation_bar.blocks\": \"Estetyt käyttäjät\",\n  \"navigation_bar.community_timeline\": \"Paikallinen aikajana\",\n  \"navigation_bar.compose\": \"Kirjoita uusi tuuttaus\",\n  \"navigation_bar.direct\": \"Viestit\",\n  \"navigation_bar.discover\": \"Discover\",\n  \"navigation_bar.domain_blocks\": \"Piilotetut verkkotunnukset\",\n  \"navigation_bar.edit_profile\": \"Muokkaa profiilia\",\n  \"navigation_bar.favourites\": \"Suosikit\",\n  \"navigation_bar.filters\": \"Mykistetyt sanat\",\n  \"navigation_bar.follow_requests\": \"Seuraamispyynnöt\",\n  \"navigation_bar.follows_and_followers\": \"Follows and followers\",\n  \"navigation_bar.info\": \"Tietoa tästä instanssista\",\n  \"navigation_bar.keyboard_shortcuts\": \"Näppäinkomennot\",\n  \"navigation_bar.lists\": \"Listat\",\n  \"navigation_bar.logout\": \"Kirjaudu ulos\",\n  \"navigation_bar.mutes\": \"Mykistetyt käyttäjät\",\n  \"navigation_bar.personal\": \"Personal\",\n  \"navigation_bar.pins\": \"Kiinnitetyt tuuttaukset\",\n  \"navigation_bar.preferences\": \"Asetukset\",\n  \"navigation_bar.profile_directory\": \"Profile directory\",\n  \"navigation_bar.public_timeline\": \"Yleinen aikajana\",\n  \"navigation_bar.security\": \"Tunnukset\",\n  \"notification.favourite\": \"{name} tykkäsi tilastasi\",\n  \"notification.follow\": \"{name} seurasi sinua\",\n  \"notification.mention\": \"{name} mainitsi sinut\",\n  \"notification.poll\": \"A poll you have voted in has ended\",\n  \"notification.reblog\": \"{name} buustasi tilaasi\",\n  \"notifications.clear\": \"Tyhjennä ilmoitukset\",\n  \"notifications.clear_confirmation\": \"Haluatko varmasti poistaa kaikki ilmoitukset pysyvästi?\",\n  \"notifications.column_settings.alert\": \"Työpöytäilmoitukset\",\n  \"notifications.column_settings.favourite\": \"Tykkäykset:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Display all categories\",\n  \"notifications.column_settings.filter_bar.category\": \"Quick filter bar\",\n  \"notifications.column_settings.filter_bar.show\": \"Show\",\n  \"notifications.column_settings.follow\": \"Uudet seuraajat:\",\n  \"notifications.column_settings.mention\": \"Maininnat:\",\n  \"notifications.column_settings.poll\": \"Poll results:\",\n  \"notifications.column_settings.push\": \"Push-ilmoitukset\",\n  \"notifications.column_settings.reblog\": \"Buustit:\",\n  \"notifications.column_settings.show\": \"Näytä sarakkeessa\",\n  \"notifications.column_settings.sound\": \"Äänimerkki\",\n  \"notifications.filter.all\": \"All\",\n  \"notifications.filter.boosts\": \"Boosts\",\n  \"notifications.filter.favourites\": \"Favourites\",\n  \"notifications.filter.follows\": \"Follows\",\n  \"notifications.filter.mentions\": \"Mentions\",\n  \"notifications.filter.polls\": \"Poll results\",\n  \"notifications.group\": \"{count} notifications\",\n  \"poll.closed\": \"Closed\",\n  \"poll.refresh\": \"Refresh\",\n  \"poll.total_votes\": \"{count, plural, one {# vote} other {# votes}}\",\n  \"poll.vote\": \"Vote\",\n  \"poll_button.add_poll\": \"Add a poll\",\n  \"poll_button.remove_poll\": \"Remove poll\",\n  \"privacy.change\": \"Säädä tuuttauksen näkyvyyttä\",\n  \"privacy.direct.long\": \"Julkaise vain mainituille käyttäjille\",\n  \"privacy.direct.short\": \"Suora viesti\",\n  \"privacy.private.long\": \"Julkaise vain seuraajille\",\n  \"privacy.private.short\": \"Vain seuraajat\",\n  \"privacy.public.long\": \"Julkaise julkisille aikajanoille\",\n  \"privacy.public.short\": \"Julkinen\",\n  \"privacy.unlisted.long\": \"Älä julkaise julkisilla aikajanoilla\",\n  \"privacy.unlisted.short\": \"Listaamaton julkinen\",\n  \"regeneration_indicator.label\": \"Ladataan…\",\n  \"regeneration_indicator.sublabel\": \"Kotinäkymääsi valmistellaan!\",\n  \"relative_time.days\": \"{number} pv\",\n  \"relative_time.hours\": \"{number} h\",\n  \"relative_time.just_now\": \"nyt\",\n  \"relative_time.minutes\": \"{number} m\",\n  \"relative_time.seconds\": \"{number} s\",\n  \"reply_indicator.cancel\": \"Peruuta\",\n  \"report.forward\": \"Välitä kohteeseen {target}\",\n  \"report.forward_hint\": \"Tämä tili on toisella palvelimella. Haluatko lähettää nimettömän raportin myös sinne?\",\n  \"report.hint\": \"Raportti lähetetään oman instanssisi moderaattoreille. Seuraavassa voit kertoa, miksi raportoit tästä tilistä:\",\n  \"report.placeholder\": \"Lisäkommentit\",\n  \"report.submit\": \"Lähetä\",\n  \"report.target\": \"Raportoidaan {target}\",\n  \"search.placeholder\": \"Hae\",\n  \"search_popout.search_format\": \"Tarkennettu haku\",\n  \"search_popout.tips.full_text\": \"Tekstihaku palauttaa tilapäivitykset, jotka olet kirjoittanut, lisännyt suosikkeihisi, boostannut tai joissa sinut mainitaan, sekä tekstin sisältävät käyttäjänimet, nimimerkit ja hastagit.\",\n  \"search_popout.tips.hashtag\": \"hashtag\",\n  \"search_popout.tips.status\": \"tila\",\n  \"search_popout.tips.text\": \"Tekstihaku palauttaa hakua vastaavat nimimerkit, käyttäjänimet ja hastagit\",\n  \"search_popout.tips.user\": \"käyttäjä\",\n  \"search_results.accounts\": \"Ihmiset\",\n  \"search_results.hashtags\": \"Hashtagit\",\n  \"search_results.statuses\": \"Tuuttaukset\",\n  \"search_results.total\": \"{count, number} {count, plural, one {result} other {results}}\",\n  \"status.admin_account\": \"Open moderation interface for @{name}\",\n  \"status.admin_status\": \"Open this status in the moderation interface\",\n  \"status.block\": \"Estä @{name}\",\n  \"status.cancel_reblog_private\": \"Peru buustaus\",\n  \"status.cannot_reblog\": \"Tätä julkaisua ei voi buustata\",\n  \"status.copy\": \"Copy link to status\",\n  \"status.delete\": \"Poista\",\n  \"status.detailed_status\": \"Detailed conversation view\",\n  \"status.direct\": \"Viesti käyttäjälle @{name}\",\n  \"status.embed\": \"Upota\",\n  \"status.favourite\": \"Tykkää\",\n  \"status.filtered\": \"Suodatettu\",\n  \"status.load_more\": \"Lataa lisää\",\n  \"status.media_hidden\": \"Media piilotettu\",\n  \"status.mention\": \"Mainitse @{name}\",\n  \"status.more\": \"Lisää\",\n  \"status.mute\": \"Mykistä @{name}\",\n  \"status.mute_conversation\": \"Mykistä keskustelu\",\n  \"status.open\": \"Laajenna tilapäivitys\",\n  \"status.pin\": \"Kiinnitä profiiliin\",\n  \"status.pinned\": \"Kiinnitetty tuuttaus\",\n  \"status.read_more\": \"Näytä enemmän\",\n  \"status.reblog\": \"Buustaa\",\n  \"status.reblog_private\": \"Buustaa alkuperäiselle yleisölle\",\n  \"status.reblogged_by\": \"{name} buustasi\",\n  \"status.reblogs.empty\": \"No one has boosted this toot yet. When someone does, they will show up here.\",\n  \"status.redraft\": \"Poista & palauta muokattavaksi\",\n  \"status.reply\": \"Vastaa\",\n  \"status.replyAll\": \"Vastaa ketjuun\",\n  \"status.report\": \"Raportoi @{name}\",\n  \"status.sensitive_warning\": \"Arkaluontoista sisältöä\",\n  \"status.share\": \"Jaa\",\n  \"status.show_less\": \"Näytä vähemmän\",\n  \"status.show_less_all\": \"Näytä vähemmän kaikista\",\n  \"status.show_more\": \"Näytä lisää\",\n  \"status.show_more_all\": \"Näytä lisää kaikista\",\n  \"status.show_thread\": \"Show thread\",\n  \"status.unmute_conversation\": \"Poista keskustelun mykistys\",\n  \"status.unpin\": \"Irrota profiilista\",\n  \"suggestions.dismiss\": \"Dismiss suggestion\",\n  \"suggestions.header\": \"You might be interested in…\",\n  \"tabs_bar.federated_timeline\": \"Yleinen\",\n  \"tabs_bar.home\": \"Koti\",\n  \"tabs_bar.local_timeline\": \"Paikallinen\",\n  \"tabs_bar.notifications\": \"Ilmoitukset\",\n  \"tabs_bar.search\": \"Hae\",\n  \"time_remaining.days\": \"{number, plural, one {# day} other {# days}} left\",\n  \"time_remaining.hours\": \"{number, plural, one {# hour} other {# hours}} left\",\n  \"time_remaining.minutes\": \"{number, plural, one {# minute} other {# minutes}} left\",\n  \"time_remaining.moments\": \"Moments remaining\",\n  \"time_remaining.seconds\": \"{number, plural, one {# second} other {# seconds}} left\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {person} other {people}} talking\",\n  \"ui.beforeunload\": \"Luonnos häviää, jos poistut Mastodonista.\",\n  \"upload_area.title\": \"Lataa raahaamalla ja pudottamalla tähän\",\n  \"upload_button.label\": \"Lisää mediaa\",\n  \"upload_error.limit\": \"File upload limit exceeded.\",\n  \"upload_error.poll\": \"File upload not allowed with polls.\",\n  \"upload_form.description\": \"Anna kuvaus näkörajoitteisia varten\",\n  \"upload_form.focus\": \"Rajaa\",\n  \"upload_form.undo\": \"Peru\",\n  \"upload_progress.label\": \"Ladataan...\",\n  \"video.close\": \"Sulje video\",\n  \"video.exit_fullscreen\": \"Poistu koko näytön tilasta\",\n  \"video.expand\": \"Laajenna video\",\n  \"video.fullscreen\": \"Koko näyttö\",\n  \"video.hide\": \"Piilota video\",\n  \"video.mute\": \"Mykistä ääni\",\n  \"video.pause\": \"Keskeytä\",\n  \"video.play\": \"Toista\",\n  \"video.unmute\": \"Poista äänen mykistys\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/fr.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Ajouter ou retirer des listes\",\n  \"account.badges.bot\": \"Robot\",\n  \"account.block\": \"Bloquer @{name}\",\n  \"account.block_domain\": \"Tout masquer venant de {domain}\",\n  \"account.blocked\": \"Bloqué\",\n  \"account.direct\": \"Envoyer un message direct à @{name}\",\n  \"account.domain_blocked\": \"Domaine caché\",\n  \"account.edit_profile\": \"Modifier le profil\",\n  \"account.endorse\": \"Figure sur le profil\",\n  \"account.follow\": \"Suivre\",\n  \"account.followers\": \"Abonné⋅e⋅s\",\n  \"account.followers.empty\": \"Personne ne suit cet utilisateur·rice pour l’instant.\",\n  \"account.follows\": \"Abonnements\",\n  \"account.follows.empty\": \"Cet·te utilisateur·rice ne suit personne pour l’instant.\",\n  \"account.follows_you\": \"Vous suit\",\n  \"account.hide_reblogs\": \"Masquer les partages de @{name}\",\n  \"account.link_verified_on\": \"La propriété de ce lien a été vérifiée le {date}\",\n  \"account.locked_info\": \"Ce compte est verrouillé. Son propriétaire approuve manuellement qui peut le ou la suivre.\",\n  \"account.media\": \"Média\",\n  \"account.mention\": \"Mentionner @{name}\",\n  \"account.moved_to\": \"{name} a déménagé vers :\",\n  \"account.mute\": \"Masquer @{name}\",\n  \"account.mute_notifications\": \"Ignorer les notifications de @{name}\",\n  \"account.muted\": \"Silencé\",\n  \"account.posts\": \"Pouets\",\n  \"account.posts_with_replies\": \"Pouets et réponses\",\n  \"account.report\": \"Signaler @{name}\",\n  \"account.requested\": \"En attente d’approbation. Cliquez pour annuler la requête\",\n  \"account.share\": \"Partager le profil de @{name}\",\n  \"account.show_reblogs\": \"Afficher les partages de @{name}\",\n  \"account.unblock\": \"Débloquer @{name}\",\n  \"account.unblock_domain\": \"Ne plus masquer {domain}\",\n  \"account.unendorse\": \"Ne figure pas sur le profil\",\n  \"account.unfollow\": \"Ne plus suivre\",\n  \"account.unmute\": \"Ne plus masquer @{name}\",\n  \"account.unmute_notifications\": \"Réactiver les notifications de @{name}\",\n  \"alert.unexpected.message\": \"Une erreur inattendue s’est produite.\",\n  \"alert.unexpected.title\": \"Oups !\",\n  \"boost_modal.combo\": \"Vous pouvez appuyer sur {combo} pour pouvoir passer ceci, la prochaine fois\",\n  \"bundle_column_error.body\": \"Une erreur s’est produite lors du chargement de ce composant.\",\n  \"bundle_column_error.retry\": \"Réessayer\",\n  \"bundle_column_error.title\": \"Erreur réseau\",\n  \"bundle_modal_error.close\": \"Fermer\",\n  \"bundle_modal_error.message\": \"Une erreur s’est produite lors du chargement de ce composant.\",\n  \"bundle_modal_error.retry\": \"Réessayer\",\n  \"column.blocks\": \"Comptes bloqués\",\n  \"column.community\": \"Fil public local\",\n  \"column.direct\": \"Messages directs\",\n  \"column.domain_blocks\": \"Domaines cachés\",\n  \"column.favourites\": \"Favoris\",\n  \"column.follow_requests\": \"Demandes de suivi\",\n  \"column.home\": \"Accueil\",\n  \"column.lists\": \"Listes\",\n  \"column.mutes\": \"Comptes masqués\",\n  \"column.notifications\": \"Notifications\",\n  \"column.pins\": \"Pouets épinglés\",\n  \"column.public\": \"Fil public global\",\n  \"column_back_button.label\": \"Retour\",\n  \"column_header.hide_settings\": \"Masquer les paramètres\",\n  \"column_header.moveLeft_settings\": \"Déplacer la colonne vers la gauche\",\n  \"column_header.moveRight_settings\": \"Déplacer la colonne vers la droite\",\n  \"column_header.pin\": \"Épingler\",\n  \"column_header.show_settings\": \"Afficher les paramètres\",\n  \"column_header.unpin\": \"Retirer\",\n  \"column_subheading.settings\": \"Paramètres\",\n  \"community.column_settings.media_only\": \"Média uniquement\",\n  \"compose_form.direct_message_warning\": \"Ce pouet sera uniquement envoyé aux personnes mentionnées. Cependant, l’administration de votre instance et des instances réceptrices pourront inspecter ce message.\",\n  \"compose_form.direct_message_warning_learn_more\": \"En savoir plus\",\n  \"compose_form.hashtag_warning\": \"Ce pouet ne sera pas listé dans les recherches par hashtag car sa visibilité est réglée sur \\\"non listé\\\". Seuls les pouets avec une visibilité \\\"publique\\\" peuvent être recherchés par hashtag.\",\n  \"compose_form.lock_disclaimer\": \"Votre compte n’est pas {locked}. Tout le monde peut vous suivre et voir vos pouets privés.\",\n  \"compose_form.lock_disclaimer.lock\": \"verrouillé\",\n  \"compose_form.placeholder\": \"Qu’avez-vous en tête ?\",\n  \"compose_form.poll.add_option\": \"Ajouter un choix\",\n  \"compose_form.poll.duration\": \"Durée du sondage\",\n  \"compose_form.poll.option_placeholder\": \"Choix {number}\",\n  \"compose_form.poll.remove_option\": \"Supprimer ce choix\",\n  \"compose_form.publish\": \"Pouet\",\n  \"compose_form.publish_loud\": \"{publish} !\",\n  \"compose_form.sensitive.hide\": \"Marquer le média comme sensible\",\n  \"compose_form.sensitive.marked\": \"Média marqué comme sensible\",\n  \"compose_form.sensitive.unmarked\": \"Média non marqué comme sensible\",\n  \"compose_form.spoiler.marked\": \"Le texte est caché derrière un avertissement\",\n  \"compose_form.spoiler.unmarked\": \"Le texte n’est pas caché\",\n  \"compose_form.spoiler_placeholder\": \"Écrivez ici votre avertissement\",\n  \"confirmation_modal.cancel\": \"Annuler\",\n  \"confirmations.block.block_and_report\": \"Bloquer et signaler\",\n  \"confirmations.block.confirm\": \"Bloquer\",\n  \"confirmations.block.message\": \"Confirmez-vous le blocage de {name} ?\",\n  \"confirmations.delete.confirm\": \"Supprimer\",\n  \"confirmations.delete.message\": \"Confirmez-vous la suppression de ce pouet ?\",\n  \"confirmations.delete_list.confirm\": \"Supprimer\",\n  \"confirmations.delete_list.message\": \"Êtes-vous sûr·e de vouloir supprimer définitivement cette liste ?\",\n  \"confirmations.domain_block.confirm\": \"Masquer le domaine entier\",\n  \"confirmations.domain_block.message\": \"Êtes-vous vraiment, vraiment sûr⋅e de vouloir bloquer {domain} en entier ? Dans la plupart des cas, quelques blocages ou masquages ciblés sont suffisants et préférables. Vous ne verrez plus de contenu provenant de ce domaine, ni dans fils publics, ni dans vos notifications. Vos abonné·e·s utilisant ce domaine seront retiré·e·s.\",\n  \"confirmations.mute.confirm\": \"Masquer\",\n  \"confirmations.mute.message\": \"Confirmez-vous le masquage de {name} ?\",\n  \"confirmations.redraft.confirm\": \"Effacer et ré-écrire\",\n  \"confirmations.redraft.message\": \"Êtes-vous sûr·e de vouloir effacer ce statut pour le ré-écrire ? Ses partages ainsi que ses mises en favori seront perdu·e·s et ses réponses seront orphelines.\",\n  \"confirmations.reply.confirm\": \"Répondre\",\n  \"confirmations.reply.message\": \"Répondre maintenant écrasera le message que vous êtes en train de composer. Voulez-vous vraiment continuer ?\",\n  \"confirmations.unfollow.confirm\": \"Ne plus suivre\",\n  \"confirmations.unfollow.message\": \"Voulez-vous arrêter de suivre {name} ?\",\n  \"embed.instructions\": \"Intégrez ce statut à votre site en copiant le code ci-dessous.\",\n  \"embed.preview\": \"Il apparaîtra comme cela :\",\n  \"emoji_button.activity\": \"Activités\",\n  \"emoji_button.custom\": \"Personnalisés\",\n  \"emoji_button.flags\": \"Drapeaux\",\n  \"emoji_button.food\": \"Nourriture & Boisson\",\n  \"emoji_button.label\": \"Insérer un émoji\",\n  \"emoji_button.nature\": \"Nature\",\n  \"emoji_button.not_found\": \"Pas d’émoji !! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"Objets\",\n  \"emoji_button.people\": \"Personnages\",\n  \"emoji_button.recent\": \"Fréquemment utilisés\",\n  \"emoji_button.search\": \"Recherche…\",\n  \"emoji_button.search_results\": \"Résultats de la recherche\",\n  \"emoji_button.symbols\": \"Symboles\",\n  \"emoji_button.travel\": \"Lieux & Voyages\",\n  \"empty_column.account_timeline\": \"Aucun pouet ici !\",\n  \"empty_column.account_unavailable\": \"Profil non disponible\",\n  \"empty_column.blocks\": \"Vous n’avez bloqué aucun·e utilisateur·rice pour le moment.\",\n  \"empty_column.community\": \"Le fil public local est vide. Écrivez donc quelque chose pour le remplir !\",\n  \"empty_column.direct\": \"Vous n’avez pas encore de messages directs. Lorsque vous en enverrez ou recevrez un, il s’affichera ici.\",\n  \"empty_column.domain_blocks\": \"Il n’y a aucun domaine caché pour le moment.\",\n  \"empty_column.favourited_statuses\": \"Vous n’avez aucun pouet favoris pour le moment. Lorsque vous en mettrez un en favori, il apparaîtra ici.\",\n  \"empty_column.favourites\": \"Personne n’a encore mis ce pouet en favori. Lorsque quelqu’un le fera, il apparaîtra ici.\",\n  \"empty_column.follow_requests\": \"Vous n’avez pas encore de demande de suivi. Lorsque vous en recevrez une, elle apparaîtra ici.\",\n  \"empty_column.hashtag\": \"Il n’y a encore aucun contenu associé à ce hashtag.\",\n  \"empty_column.home\": \"Vous ne suivez personne. Visitez {public} ou utilisez la recherche pour trouver d’autres personnes à suivre.\",\n  \"empty_column.home.public_timeline\": \"le fil public\",\n  \"empty_column.list\": \"Il n’y a rien dans cette liste pour l’instant. Dès que des personnes de cette liste publieront de nouveaux statuts, ils apparaîtront ici.\",\n  \"empty_column.lists\": \"Vous n’avez pas encore de liste. Lorsque vous en créerez une, elle apparaîtra ici.\",\n  \"empty_column.mutes\": \"Vous n’avez pas encore mis d'utilisateur·rice·s en silence.\",\n  \"empty_column.notifications\": \"Vous n’avez pas encore de notification. Interagissez avec d’autres personnes pour débuter la conversation.\",\n  \"empty_column.public\": \"Il n’y a rien ici ! Écrivez quelque chose publiquement, ou bien suivez manuellement des personnes d’autres instances pour remplir le fil public\",\n  \"follow_request.authorize\": \"Accepter\",\n  \"follow_request.reject\": \"Rejeter\",\n  \"getting_started.developers\": \"Développeur·euse·s\",\n  \"getting_started.directory\": \"Annuaire des profils\",\n  \"getting_started.documentation\": \"Documentation\",\n  \"getting_started.heading\": \"Pour commencer\",\n  \"getting_started.invite\": \"Inviter des gens\",\n  \"getting_started.open_source_notice\": \"Mastodon est un logiciel libre. Vous pouvez contribuer et envoyer vos commentaires et rapports de bogues via {github} sur GitHub.\",\n  \"getting_started.security\": \"Sécurité\",\n  \"getting_started.terms\": \"Conditions d’utilisation\",\n  \"hashtag.column_header.tag_mode.all\": \"et {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"ou {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"sans {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"Aucune suggestion trouvée\",\n  \"hashtag.column_settings.select.placeholder\": \"Ajouter des hashtags…\",\n  \"hashtag.column_settings.tag_mode.all\": \"Tous ces éléments\",\n  \"hashtag.column_settings.tag_mode.any\": \"Au moins un de ces éléments\",\n  \"hashtag.column_settings.tag_mode.none\": \"Aucun de ces éléments\",\n  \"hashtag.column_settings.tag_toggle\": \"Inclure des tags additionnels dans cette colonne\",\n  \"home.column_settings.basic\": \"Basique\",\n  \"home.column_settings.show_reblogs\": \"Afficher les partages\",\n  \"home.column_settings.show_replies\": \"Afficher les réponses\",\n  \"intervals.full.days\": \"{number, plural, one {# jour} other {# jours}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# heure} other {# heures}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minute} other {# minutes}}\",\n  \"introduction.federation.action\": \"Suivant\",\n  \"introduction.federation.federated.headline\": \"Fil public global\",\n  \"introduction.federation.federated.text\": \"Les messages publics provenant d'autres serveurs du fediverse apparaîtront dans le fil public global.\",\n  \"introduction.federation.home.headline\": \"Accueil\",\n  \"introduction.federation.home.text\": \"Les messages des personnes que vous suivez apparaîtront dans votre fil d'accueil. Vous pouvez suivre n'importe qui sur n'importe quel serveur !\",\n  \"introduction.federation.local.headline\": \"Fil public local\",\n  \"introduction.federation.local.text\": \"Les messages publics de personnes se trouvant sur le même serveur que vous apparaîtront sur le fil public local.\",\n  \"introduction.interactions.action\": \"Finir le tutoriel !\",\n  \"introduction.interactions.favourite.headline\": \"Favoris\",\n  \"introduction.interactions.favourite.text\": \"Vous pouvez garder un pouet pour plus tard, et faire savoir à son auteur·ice que vous l'avez aimé, en le favorisant.\",\n  \"introduction.interactions.reblog.headline\": \"Repartager\",\n  \"introduction.interactions.reblog.text\": \"Vous pouvez partager les pouets d'autres personnes avec vos abonné·e·s en les repartageant.\",\n  \"introduction.interactions.reply.headline\": \"Répondre\",\n  \"introduction.interactions.reply.text\": \"Vous pouvez répondre aux pouets d'autres personnes et à vos propres pouets, ce qui les enchaînera dans une conversation.\",\n  \"introduction.welcome.action\": \"Allons-y !\",\n  \"introduction.welcome.headline\": \"Premiers pas\",\n  \"introduction.welcome.text\": \"Bienvenue dans le fediverse ! Dans quelques instants, vous pourrez diffuser des messages et parler à vos amis sur une grande variété de serveurs. Mais ce serveur, {domain}, est spécial - il héberge votre profil, alors souvenez-vous de son nom.\",\n  \"keyboard_shortcuts.back\": \"pour revenir en arrière\",\n  \"keyboard_shortcuts.blocked\": \"pour ouvrir une liste d’utilisateur·rice·s bloqué·e·s\",\n  \"keyboard_shortcuts.boost\": \"pour partager\",\n  \"keyboard_shortcuts.column\": \"pour focaliser un statut dans l’une des colonnes\",\n  \"keyboard_shortcuts.compose\": \"pour centrer la zone de rédaction\",\n  \"keyboard_shortcuts.description\": \"Description\",\n  \"keyboard_shortcuts.direct\": \"pour ouvrir une colonne des messages directs\",\n  \"keyboard_shortcuts.down\": \"pour descendre dans la liste\",\n  \"keyboard_shortcuts.enter\": \"pour ouvrir le statut\",\n  \"keyboard_shortcuts.favourite\": \"pour ajouter aux favoris\",\n  \"keyboard_shortcuts.favourites\": \"pour ouvrir une liste de favoris\",\n  \"keyboard_shortcuts.federated\": \"pour ouvrir le fil public global\",\n  \"keyboard_shortcuts.heading\": \"Raccourcis clavier\",\n  \"keyboard_shortcuts.home\": \"pour ouvrir l’accueil\",\n  \"keyboard_shortcuts.hotkey\": \"Raccourci\",\n  \"keyboard_shortcuts.legend\": \"pour afficher cette légende\",\n  \"keyboard_shortcuts.local\": \"pour ouvrir le fil public local\",\n  \"keyboard_shortcuts.mention\": \"pour mentionner l’auteur·rice\",\n  \"keyboard_shortcuts.muted\": \"pour ouvrir la liste des utilisateur·rice·s rendu·e·s muet·te·s\",\n  \"keyboard_shortcuts.my_profile\": \"pour ouvrir votre profil\",\n  \"keyboard_shortcuts.notifications\": \"pour ouvrir votre colonne de notifications\",\n  \"keyboard_shortcuts.pinned\": \"pour ouvrir une liste des pouets épinglés\",\n  \"keyboard_shortcuts.profile\": \"pour ouvrir le profil de l’auteur·rice\",\n  \"keyboard_shortcuts.reply\": \"pour répondre\",\n  \"keyboard_shortcuts.requests\": \"pour ouvrir la liste de demandes de suivi\",\n  \"keyboard_shortcuts.search\": \"pour cibler la recherche\",\n  \"keyboard_shortcuts.start\": \"pour ouvrir la colonne \\\"pour commencer\\\"\",\n  \"keyboard_shortcuts.toggle_hidden\": \"pour afficher/cacher un texte derrière CW\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"pour afficher/cacher les médias\",\n  \"keyboard_shortcuts.toot\": \"pour démarrer un tout nouveau pouet\",\n  \"keyboard_shortcuts.unfocus\": \"pour quitter la zone de composition/recherche\",\n  \"keyboard_shortcuts.up\": \"pour remonter dans la liste\",\n  \"lightbox.close\": \"Fermer\",\n  \"lightbox.next\": \"Suivant\",\n  \"lightbox.previous\": \"Précédent\",\n  \"lightbox.view_context\": \"Voir le contexte\",\n  \"lists.account.add\": \"Ajouter à la liste\",\n  \"lists.account.remove\": \"Supprimer de la liste\",\n  \"lists.delete\": \"Effacer la liste\",\n  \"lists.edit\": \"Éditer la liste\",\n  \"lists.edit.submit\": \"Changer le titre\",\n  \"lists.new.create\": \"Ajouter une liste\",\n  \"lists.new.title_placeholder\": \"Titre de la nouvelle liste\",\n  \"lists.search\": \"Rechercher parmi les gens que vous suivez\",\n  \"lists.subheading\": \"Vos listes\",\n  \"loading_indicator.label\": \"Chargement…\",\n  \"media_gallery.toggle_visible\": \"Modifier la visibilité\",\n  \"missing_indicator.label\": \"Non trouvé\",\n  \"missing_indicator.sublabel\": \"Ressource introuvable\",\n  \"mute_modal.hide_notifications\": \"Masquer les notifications de cette personne ?\",\n  \"navigation_bar.apps\": \"Applications mobiles\",\n  \"navigation_bar.blocks\": \"Comptes bloqués\",\n  \"navigation_bar.community_timeline\": \"Fil public local\",\n  \"navigation_bar.compose\": \"Rédiger un nouveau toot\",\n  \"navigation_bar.direct\": \"Messages directs\",\n  \"navigation_bar.discover\": \"Découvrir\",\n  \"navigation_bar.domain_blocks\": \"Domaines cachés\",\n  \"navigation_bar.edit_profile\": \"Modifier le profil\",\n  \"navigation_bar.favourites\": \"Favoris\",\n  \"navigation_bar.filters\": \"Mots silenciés\",\n  \"navigation_bar.follow_requests\": \"Demandes de suivi\",\n  \"navigation_bar.follows_and_followers\": \"Abonnements et abonné⋅e·s\",\n  \"navigation_bar.info\": \"Plus d’informations\",\n  \"navigation_bar.keyboard_shortcuts\": \"Raccourcis clavier\",\n  \"navigation_bar.lists\": \"Listes\",\n  \"navigation_bar.logout\": \"Déconnexion\",\n  \"navigation_bar.mutes\": \"Comptes masqués\",\n  \"navigation_bar.personal\": \"Personnel\",\n  \"navigation_bar.pins\": \"Pouets épinglés\",\n  \"navigation_bar.preferences\": \"Préférences\",\n  \"navigation_bar.profile_directory\": \"Annuaire des profils\",\n  \"navigation_bar.public_timeline\": \"Fil public global\",\n  \"navigation_bar.security\": \"Sécurité\",\n  \"notification.favourite\": \"{name} a ajouté à ses favoris :\",\n  \"notification.follow\": \"{name} vous suit\",\n  \"notification.mention\": \"{name} vous a mentionné :\",\n  \"notification.poll\": \"Un sondage auquel vous avez participé vient de se terminer\",\n  \"notification.reblog\": \"{name} a partagé votre statut :\",\n  \"notifications.clear\": \"Nettoyer les notifications\",\n  \"notifications.clear_confirmation\": \"Voulez-vous vraiment supprimer toutes vos notifications ?\",\n  \"notifications.column_settings.alert\": \"Notifications locales\",\n  \"notifications.column_settings.favourite\": \"Favoris :\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Afficher toutes les catégories\",\n  \"notifications.column_settings.filter_bar.category\": \"Barre de filtrage rapide\",\n  \"notifications.column_settings.filter_bar.show\": \"Afficher\",\n  \"notifications.column_settings.follow\": \"Nouveaux⋅elles abonné⋅e·s :\",\n  \"notifications.column_settings.mention\": \"Mentions :\",\n  \"notifications.column_settings.poll\": \"Résultats du sondage :\",\n  \"notifications.column_settings.push\": \"Notifications\",\n  \"notifications.column_settings.reblog\": \"Partages :\",\n  \"notifications.column_settings.show\": \"Afficher dans la colonne\",\n  \"notifications.column_settings.sound\": \"Émettre un son\",\n  \"notifications.filter.all\": \"Tout\",\n  \"notifications.filter.boosts\": \"Repartages\",\n  \"notifications.filter.favourites\": \"Favoris\",\n  \"notifications.filter.follows\": \"Abonné·e·s\",\n  \"notifications.filter.mentions\": \"Mentions\",\n  \"notifications.filter.polls\": \"Résultats des sondages\",\n  \"notifications.group\": \"{count} notifications\",\n  \"poll.closed\": \"Fermé\",\n  \"poll.refresh\": \"Actualiser\",\n  \"poll.total_votes\": \"{count, plural, one {# vote} other {# votes}}\",\n  \"poll.vote\": \"Voter\",\n  \"poll_button.add_poll\": \"Ajouter un sondage\",\n  \"poll_button.remove_poll\": \"Supprimer le sondage\",\n  \"privacy.change\": \"Ajuster la confidentialité du message\",\n  \"privacy.direct.long\": \"N’envoyer qu’aux personnes mentionnées\",\n  \"privacy.direct.short\": \"Direct\",\n  \"privacy.private.long\": \"Seul⋅e⋅s vos abonné⋅e⋅s verront vos statuts\",\n  \"privacy.private.short\": \"Abonné⋅e⋅s uniquement\",\n  \"privacy.public.long\": \"Afficher dans les fils publics\",\n  \"privacy.public.short\": \"Public\",\n  \"privacy.unlisted.long\": \"Ne pas afficher dans les fils publics\",\n  \"privacy.unlisted.short\": \"Non listé\",\n  \"regeneration_indicator.label\": \"Chargement…\",\n  \"regeneration_indicator.sublabel\": \"Le flux de votre page principale est en cours de préparation !\",\n  \"relative_time.days\": \"{number} j\",\n  \"relative_time.hours\": \"{number} h\",\n  \"relative_time.just_now\": \"à l’instant\",\n  \"relative_time.minutes\": \"{number} min\",\n  \"relative_time.seconds\": \"{number} s\",\n  \"reply_indicator.cancel\": \"Annuler\",\n  \"report.forward\": \"Transférer à {target}\",\n  \"report.forward_hint\": \"Le compte provient d’un autre serveur. Envoyez également une copie anonyme du rapport ?\",\n  \"report.hint\": \"Le rapport sera envoyé aux modérateur·rice·s de votre instance. Vous pouvez expliquer pourquoi vous signalez le compte ci-dessous :\",\n  \"report.placeholder\": \"Commentaires additionnels\",\n  \"report.submit\": \"Envoyer\",\n  \"report.target\": \"Signalement\",\n  \"search.placeholder\": \"Rechercher\",\n  \"search_popout.search_format\": \"Recherche avancée\",\n  \"search_popout.tips.full_text\": \"Les textes simples retournent les pouets que vous avez écris, mis en favori, épinglés, ou ayant été mentionnés, ainsi que les identifiants, les noms affichés, et les hashtags des personnes et messages correspondant.\",\n  \"search_popout.tips.hashtag\": \"hashtag\",\n  \"search_popout.tips.status\": \"statuts\",\n  \"search_popout.tips.text\": \"Un texte simple renvoie les noms affichés, les identifiants et les hashtags correspondants\",\n  \"search_popout.tips.user\": \"utilisateur⋅ice\",\n  \"search_results.accounts\": \"Comptes\",\n  \"search_results.hashtags\": \"Hashtags\",\n  \"search_results.statuses\": \"Pouets\",\n  \"search_results.total\": \"{count, number} {count, plural, one {résultat} other {résultats}}\",\n  \"status.admin_account\": \"Ouvrir l'interface de modération pour @{name}\",\n  \"status.admin_status\": \"Ouvrir ce statut dans l'interface de modération\",\n  \"status.block\": \"Bloquer @{name}\",\n  \"status.cancel_reblog_private\": \"Dé-booster\",\n  \"status.cannot_reblog\": \"Cette publication ne peut être boostée\",\n  \"status.copy\": \"Copier le lien vers le pouet\",\n  \"status.delete\": \"Effacer\",\n  \"status.detailed_status\": \"Vue détaillée de la conversation\",\n  \"status.direct\": \"Envoyer un message direct à @{name}\",\n  \"status.embed\": \"Intégrer\",\n  \"status.favourite\": \"Ajouter aux favoris\",\n  \"status.filtered\": \"Filtré\",\n  \"status.load_more\": \"Charger plus\",\n  \"status.media_hidden\": \"Média caché\",\n  \"status.mention\": \"Mentionner @{name}\",\n  \"status.more\": \"Plus\",\n  \"status.mute\": \"Masquer @{name}\",\n  \"status.mute_conversation\": \"Masquer la conversation\",\n  \"status.open\": \"Déplier ce statut\",\n  \"status.pin\": \"Épingler sur le profil\",\n  \"status.pinned\": \"Pouet épinglé\",\n  \"status.read_more\": \"En savoir plus\",\n  \"status.reblog\": \"Partager\",\n  \"status.reblog_private\": \"Booster vers l’audience originale\",\n  \"status.reblogged_by\": \"{name} a partagé :\",\n  \"status.reblogs.empty\": \"Personne n’a encore partagé ce pouet. Lorsque quelqu’un le fera, il apparaîtra ici.\",\n  \"status.redraft\": \"Effacer et ré-écrire\",\n  \"status.reply\": \"Répondre\",\n  \"status.replyAll\": \"Répondre au fil\",\n  \"status.report\": \"Signaler @{name}\",\n  \"status.sensitive_warning\": \"Contenu sensible\",\n  \"status.share\": \"Partager\",\n  \"status.show_less\": \"Replier\",\n  \"status.show_less_all\": \"Tout replier\",\n  \"status.show_more\": \"Déplier\",\n  \"status.show_more_all\": \"Tout déplier\",\n  \"status.show_thread\": \"Lire le fil\",\n  \"status.unmute_conversation\": \"Ne plus masquer la conversation\",\n  \"status.unpin\": \"Retirer du profil\",\n  \"suggestions.dismiss\": \"Rejeter la suggestion\",\n  \"suggestions.header\": \"Vous pourriez être intéressé par…\",\n  \"tabs_bar.federated_timeline\": \"Fil public global\",\n  \"tabs_bar.home\": \"Accueil\",\n  \"tabs_bar.local_timeline\": \"Fil public local\",\n  \"tabs_bar.notifications\": \"Notifications\",\n  \"tabs_bar.search\": \"Chercher\",\n  \"time_remaining.days\": \"{number, plural, one {# day} other {# days}} restants\",\n  \"time_remaining.hours\": \"{number, plural, one {# hour} other {# hours}} restantes\",\n  \"time_remaining.minutes\": \"{number, plural, one {# minute} other {# minutes}} restantes\",\n  \"time_remaining.moments\": \"Encore quelques instants\",\n  \"time_remaining.seconds\": \"{number, plural, one {# second} other {# seconds}} restantes\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {personne} other {personnes}} discutent\",\n  \"ui.beforeunload\": \"Votre brouillon sera perdu si vous quittez Mastodon.\",\n  \"upload_area.title\": \"Glissez et déposez pour envoyer\",\n  \"upload_button.label\": \"Joindre un média (JPEG, PNG, GIF, WebM, MP4, MOV)\",\n  \"upload_error.limit\": \"Taille maximale d'envoi de fichier dépassée.\",\n  \"upload_error.poll\": \"L'envoi de fichiers n'est pas autorisé avec les sondages.\",\n  \"upload_form.description\": \"Décrire pour les malvoyant·e·s\",\n  \"upload_form.focus\": \"Modifier l’aperçu\",\n  \"upload_form.undo\": \"Supprimer\",\n  \"upload_progress.label\": \"Envoi en cours…\",\n  \"video.close\": \"Fermer la vidéo\",\n  \"video.exit_fullscreen\": \"Quitter le plein écran\",\n  \"video.expand\": \"Agrandir la vidéo\",\n  \"video.fullscreen\": \"Plein écran\",\n  \"video.hide\": \"Masquer la vidéo\",\n  \"video.mute\": \"Couper le son\",\n  \"video.pause\": \"Pause\",\n  \"video.play\": \"Lecture\",\n  \"video.unmute\": \"Rétablir le son\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/gl.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Engadir ou Eliminar das listas\",\n  \"account.badges.bot\": \"Bot\",\n  \"account.block\": \"Bloquear @{name}\",\n  \"account.block_domain\": \"Ocultar calquer contido de {domain}\",\n  \"account.blocked\": \"Bloqueada\",\n  \"account.direct\": \"Mensaxe directa @{name}\",\n  \"account.domain_blocked\": \"Dominio agochado\",\n  \"account.edit_profile\": \"Editar perfil\",\n  \"account.endorse\": \"Mostrado no perfil\",\n  \"account.follow\": \"Seguir\",\n  \"account.followers\": \"Seguidoras\",\n  \"account.followers.empty\": \"Ninguén está a seguir esta usuaria por agora.\",\n  \"account.follows\": \"Seguindo\",\n  \"account.follows.empty\": \"Esta usuaria aínda non segue a ninguén.\",\n  \"account.follows_you\": \"Séguete\",\n  \"account.hide_reblogs\": \"Ocultar repeticións de @{name}\",\n  \"account.link_verified_on\": \"A propiedade de esta ligazón foi comprobada en {date}\",\n  \"account.locked_info\": \"O estado da intimidade de esta conta estableceuse en pechado. A persoa dona da conta revisa quen pode seguila.\",\n  \"account.media\": \"Medios\",\n  \"account.mention\": \"Mencionar @{name}\",\n  \"account.moved_to\": \"{name} marchou a:\",\n  \"account.mute\": \"Acalar @{name}\",\n  \"account.mute_notifications\": \"Acalar as notificacións de @{name}\",\n  \"account.muted\": \"Acalada\",\n  \"account.posts\": \"Toots\",\n  \"account.posts_with_replies\": \"Toots e respostas\",\n  \"account.report\": \"Informar sobre @{name}\",\n  \"account.requested\": \"Agardando aceptación. Pulse para cancelar a solicitude de seguimento\",\n  \"account.share\": \"Compartir o perfil de @{name}\",\n  \"account.show_reblogs\": \"Mostrar repeticións de @{name}\",\n  \"account.unblock\": \"Desbloquear @{name}\",\n  \"account.unblock_domain\": \"Non ocultar {domain}\",\n  \"account.unendorse\": \"Non mostrar no perfil\",\n  \"account.unfollow\": \"Non seguir\",\n  \"account.unmute\": \"Non acalar @{name}\",\n  \"account.unmute_notifications\": \"Desbloquear as notificacións de @{name}\",\n  \"alert.unexpected.message\": \"Aconteceu un fallo non agardado.\",\n  \"alert.unexpected.title\": \"Vaia!\",\n  \"boost_modal.combo\": \"Pulse {combo} para saltar esto a próxima vez\",\n  \"bundle_column_error.body\": \"Houbo un fallo mentras se cargaba este compoñente.\",\n  \"bundle_column_error.retry\": \"Inténteo de novo\",\n  \"bundle_column_error.title\": \"Fallo na rede\",\n  \"bundle_modal_error.close\": \"Pechar\",\n  \"bundle_modal_error.message\": \"Algo fallou mentras se cargaba este compoñente.\",\n  \"bundle_modal_error.retry\": \"Inténteo de novo\",\n  \"column.blocks\": \"Usuarias bloqueadas\",\n  \"column.community\": \"Liña temporal local\",\n  \"column.direct\": \"Mensaxes directas\",\n  \"column.domain_blocks\": \"Dominios agochados\",\n  \"column.favourites\": \"Favoritas\",\n  \"column.follow_requests\": \"Peticións de seguimento\",\n  \"column.home\": \"Inicio\",\n  \"column.lists\": \"Listas\",\n  \"column.mutes\": \"Usuarias acaladas\",\n  \"column.notifications\": \"Notificacións\",\n  \"column.pins\": \"Mensaxes fixadas\",\n  \"column.public\": \"Liña temporal federada\",\n  \"column_back_button.label\": \"Atrás\",\n  \"column_header.hide_settings\": \"Agochar axustes\",\n  \"column_header.moveLeft_settings\": \"Mover a columna hacia a esquerda\",\n  \"column_header.moveRight_settings\": \"Mover a columna hacia a dereita\",\n  \"column_header.pin\": \"Fixar\",\n  \"column_header.show_settings\": \"Mostras axustes\",\n  \"column_header.unpin\": \"Soltar\",\n  \"column_subheading.settings\": \"Axustes\",\n  \"community.column_settings.media_only\": \"Só medios\",\n  \"compose_form.direct_message_warning\": \"Este toot enviarase só as usuarias mencionadas. Porén, a súa proveedora de internet e calquera das instancias receptoras poderían examinar esta mensaxe.\",\n  \"compose_form.direct_message_warning_learn_more\": \"Coñecer máis\",\n  \"compose_form.hashtag_warning\": \"Esta mensaxe non será listada baixo ningunha etiqueta xa que está marcada como non listada. Só os toots públicos poden buscarse por etiquetas.\",\n  \"compose_form.lock_disclaimer\": \"A súa conta non está {locked}. Calquera pode seguila para ver as súas mensaxes só-para-seguidoras.\",\n  \"compose_form.lock_disclaimer.lock\": \"bloqueado\",\n  \"compose_form.placeholder\": \"Qué contas?\",\n  \"compose_form.poll.add_option\": \"Engadir unha opción\",\n  \"compose_form.poll.duration\": \"Duración da sondaxe\",\n  \"compose_form.poll.option_placeholder\": \"Opción {number}\",\n  \"compose_form.poll.remove_option\": \"Eliminar esta opción\",\n  \"compose_form.publish\": \"Toot\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"Marcar medios como sensibles\",\n  \"compose_form.sensitive.marked\": \"Medios marcados como sensibles\",\n  \"compose_form.sensitive.unmarked\": \"Os medios non están marcados como sensibles\",\n  \"compose_form.spoiler.marked\": \"O texto está agochado tras un aviso\",\n  \"compose_form.spoiler.unmarked\": \"O texto non está agochado\",\n  \"compose_form.spoiler_placeholder\": \"Escriba o aviso aquí\",\n  \"confirmation_modal.cancel\": \"Cancelar\",\n  \"confirmations.block.block_and_report\": \"Bloquear e Informar\",\n  \"confirmations.block.confirm\": \"Bloquear\",\n  \"confirmations.block.message\": \"Está segura de querer bloquear a {name}?\",\n  \"confirmations.delete.confirm\": \"Borrar\",\n  \"confirmations.delete.message\": \"Está segura de que quere eliminar este estado?\",\n  \"confirmations.delete_list.confirm\": \"Eliminar\",\n  \"confirmations.delete_list.message\": \"Estás seguro de que queres eliminar permanentemente esta lista?\",\n  \"confirmations.domain_block.confirm\": \"Agochar un dominio completo\",\n  \"confirmations.domain_block.message\": \"Realmente está segura de que quere bloquear por completo o dominio {domain}? Normalmente é suficiente, e preferible, bloquear de xeito selectivo varios elementos. Non verá contidos de ese dominio en ningunha liña temporal ou nas notificacións. As súas seguidoras en ese dominio serán eliminadas.\",\n  \"confirmations.mute.confirm\": \"Acalar\",\n  \"confirmations.mute.message\": \"Está segura de que quere acalar a {name}?\",\n  \"confirmations.redraft.confirm\": \"Eliminar e reescribir\",\n  \"confirmations.redraft.message\": \"Está segura de querer eliminar este estado e voltalo a escribir? Perderá réplicas e favoritas, e as respostas ao orixinal quedarán orfas.\",\n  \"confirmations.reply.confirm\": \"Respostar\",\n  \"confirmations.reply.message\": \"Respostando agora sobreescribirá a mensaxe que está a compoñer. Segura de querer proceder?\",\n  \"confirmations.unfollow.confirm\": \"Deixar de seguir\",\n  \"confirmations.unfollow.message\": \"Quere deixar de seguir a {name}?\",\n  \"embed.instructions\": \"Copie o código inferior para incrustar no seu sitio web este estado.\",\n  \"embed.preview\": \"Así será mostrado:\",\n  \"emoji_button.activity\": \"Actividade\",\n  \"emoji_button.custom\": \"Persoalizado\",\n  \"emoji_button.flags\": \"Marcas\",\n  \"emoji_button.food\": \"Comida e Bebida\",\n  \"emoji_button.label\": \"Insertar emoji\",\n  \"emoji_button.nature\": \"Natureza\",\n  \"emoji_button.not_found\": \"Sen emojos!! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"Obxetos\",\n  \"emoji_button.people\": \"Xente\",\n  \"emoji_button.recent\": \"Utilizadas con frecuencia\",\n  \"emoji_button.search\": \"Buscar...\",\n  \"emoji_button.search_results\": \"Resultados da busca\",\n  \"emoji_button.symbols\": \"Símbolos\",\n  \"emoji_button.travel\": \"Viaxes e Lugares\",\n  \"empty_column.account_timeline\": \"Sen toots por aquí!\",\n  \"empty_column.account_unavailable\": \"Perfil non dispoñible\",\n  \"empty_column.blocks\": \"Non bloqueou ningunha usuaria polo de agora.\",\n  \"empty_column.community\": \"A liña temporal local está baldeira. Escriba algo de xeito público para que rule!\",\n  \"empty_column.direct\": \"Aínda non ten mensaxes directas. Cando envíe ou reciba unha, aparecerá aquí.\",\n  \"empty_column.domain_blocks\": \"Aínda non  ocultou ningún dominio.\",\n  \"empty_column.favourited_statuses\": \"Aínda non ten toots favoritos. Cando favoreza algún, aparecerá aquí.\",\n  \"empty_column.favourites\": \"Ninguén favoreceu este toot polo momento. Cando o faga alguén, aparecerán aquí.\",\n  \"empty_column.follow_requests\": \"Non ten peticións de seguimento. Cando reciba unha, mostrarase aquí.\",\n  \"empty_column.hashtag\": \"Aínda non hai nada con esta etiqueta.\",\n  \"empty_column.home\": \"A súa liña temporal de inicio está baldeira! Visite {public} ou utilice a busca para atopar outras usuarias.\",\n  \"empty_column.home.public_timeline\": \"a liña temporal pública\",\n  \"empty_column.list\": \"Aínda non hai nada en esta lista. Cando as usuarias incluídas na lista publiquen mensaxes, aparecerán aquí.\",\n  \"empty_column.lists\": \"Aínda non ten listas. Cando cree unha, mostrarase aquí.\",\n  \"empty_column.mutes\": \"Non acalou ningunha usuaria polo de agora.\",\n  \"empty_column.notifications\": \"Aínda non ten notificacións. Interactúe con outras para iniciar unha conversa.\",\n  \"empty_column.public\": \"Nada por aquí! Escriba algo de xeito público, ou siga manualmente usuarias de outros servidores para ir enchéndoa\",\n  \"follow_request.authorize\": \"Autorizar\",\n  \"follow_request.reject\": \"Rexeitar\",\n  \"getting_started.developers\": \"Desenvolvedoras\",\n  \"getting_started.directory\": \"Directorio do perfil\",\n  \"getting_started.documentation\": \"Documentación\",\n  \"getting_started.heading\": \"Comezando\",\n  \"getting_started.invite\": \"Convide a xente\",\n  \"getting_started.open_source_notice\": \"Mastodon é software de código aberto. Pode contribuír ou informar de fallos en GitHub en {github}.\",\n  \"getting_started.security\": \"Seguridade\",\n  \"getting_started.terms\": \"Termos do servizo\",\n  \"hashtag.column_header.tag_mode.all\": \"e {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"ou {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"sen {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"Non se atopan suxestións\",\n  \"hashtag.column_settings.select.placeholder\": \"Introducir etiquetas…\",\n  \"hashtag.column_settings.tag_mode.all\": \"Todos estos\",\n  \"hashtag.column_settings.tag_mode.any\": \"Calquera de estos\",\n  \"hashtag.column_settings.tag_mode.none\": \"Ningún de estos\",\n  \"hashtag.column_settings.tag_toggle\": \"Incluír etiquetas adicionais para esta columna\",\n  \"home.column_settings.basic\": \"Básico\",\n  \"home.column_settings.show_reblogs\": \"Mostrar repeticións\",\n  \"home.column_settings.show_replies\": \"Mostrar respostas\",\n  \"intervals.full.days\": \"{number, plural,one {# día} other {# días}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# hora} other {# horas}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minuto} other {# minutos}}\",\n  \"introduction.federation.action\": \"Seguinte\",\n  \"introduction.federation.federated.headline\": \"Federado\",\n  \"introduction.federation.federated.text\": \"Publicacións públicas desde outros servidores do fediverso aparecerán na liña temporal federada.\",\n  \"introduction.federation.home.headline\": \"Inicio\",\n  \"introduction.federation.home.text\": \"Publicacións de xente que vostede segue aparecerán no TL de Inicio. Pode seguir a calquera en calquer servidor!\",\n  \"introduction.federation.local.headline\": \"Local\",\n  \"introduction.federation.local.text\": \"Publicacións públicas de xente no seu mesmo servidor aparecerán na liña temporal local.\",\n  \"introduction.interactions.action\": \"Rematar titorial!\",\n  \"introduction.interactions.favourite.headline\": \"Favorito\",\n  \"introduction.interactions.favourite.text\": \"Pode gardar un toot para máis tarde, e facerlle saber a autora que lle gustou, dándolle a Favorito.\",\n  \"introduction.interactions.reblog.headline\": \"Promocionar\",\n  \"introduction.interactions.reblog.text\": \"Pode compartir os toots de outra xente coas súas seguidoras promocionándoos.\",\n  \"introduction.interactions.reply.headline\": \"Respostar\",\n  \"introduction.interactions.reply.text\": \"Pode respostar aos toots de outras persoas e aos seus propios, así quedarán encadeados nunha conversa.\",\n  \"introduction.welcome.action\": \"Imos!\",\n  \"introduction.welcome.headline\": \"Primeiros pasos\",\n  \"introduction.welcome.text\": \"Benvida ao fediverso! Nun intre poderá difundir mensaxes e falar cos seus amigos nun gran número de servidores. Pero este servidor (dominio) é especial—hospeda o seu perfil, así que lémbreo.\",\n  \"keyboard_shortcuts.back\": \"voltar atrás\",\n  \"keyboard_shortcuts.blocked\": \"abrir lista de usuarias bloqueadas\",\n  \"keyboard_shortcuts.boost\": \"promover\",\n  \"keyboard_shortcuts.column\": \"destacar un estado en unha das columnas\",\n  \"keyboard_shortcuts.compose\": \"Foco no área de escritura\",\n  \"keyboard_shortcuts.description\": \"Descrición\",\n  \"keyboard_shortcuts.direct\": \"abrir columna de mensaxes directas\",\n  \"keyboard_shortcuts.down\": \"ir hacia abaixo na lista\",\n  \"keyboard_shortcuts.enter\": \"abrir estado\",\n  \"keyboard_shortcuts.favourite\": \"marcar como favorito\",\n  \"keyboard_shortcuts.favourites\": \"abrir lista de favoritos\",\n  \"keyboard_shortcuts.federated\": \"abrir liña temporal federada\",\n  \"keyboard_shortcuts.heading\": \"Atallos do teclado\",\n  \"keyboard_shortcuts.home\": \"abrir liña temporal de inicio\",\n  \"keyboard_shortcuts.hotkey\": \"Tecla de acceso directo\",\n  \"keyboard_shortcuts.legend\": \"para mostrar esta lenda\",\n  \"keyboard_shortcuts.local\": \"abrir liña temporal local\",\n  \"keyboard_shortcuts.mention\": \"para mencionar o autor\",\n  \"keyboard_shortcuts.muted\": \"abrir lista de usuarias acaladas\",\n  \"keyboard_shortcuts.my_profile\": \"abrir o seu perfil\",\n  \"keyboard_shortcuts.notifications\": \"abrir columna de notificacións\",\n  \"keyboard_shortcuts.pinned\": \"abrir lista de toots fixados\",\n  \"keyboard_shortcuts.profile\": \"abrir perfil da autora\",\n  \"keyboard_shortcuts.reply\": \"para responder\",\n  \"keyboard_shortcuts.requests\": \"abrir lista de peticións de seguimento\",\n  \"keyboard_shortcuts.search\": \"para centrar a busca\",\n  \"keyboard_shortcuts.start\": \"abrir columna \\\"comezando\\\"\",\n  \"keyboard_shortcuts.toggle_hidden\": \"mostrar/agochar un texto detrás do AC\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"mostrar/ocultar medios\",\n  \"keyboard_shortcuts.toot\": \"escribir un toot novo\",\n  \"keyboard_shortcuts.unfocus\": \"quitar o foco do área de escritura/busca\",\n  \"keyboard_shortcuts.up\": \"ir hacia arriba na lista\",\n  \"lightbox.close\": \"Fechar\",\n  \"lightbox.next\": \"Seguinte\",\n  \"lightbox.previous\": \"Anterior\",\n  \"lightbox.view_context\": \"Ver contexto\",\n  \"lists.account.add\": \"Engadir á lista\",\n  \"lists.account.remove\": \"Eliminar da lista\",\n  \"lists.delete\": \"Eliminar lista\",\n  \"lists.edit\": \"Editar lista\",\n  \"lists.edit.submit\": \"Cambiar título\",\n  \"lists.new.create\": \"Engadir lista\",\n  \"lists.new.title_placeholder\": \"Novo título da lista\",\n  \"lists.search\": \"Procurar entre a xente que segues\",\n  \"lists.subheading\": \"As túas listas\",\n  \"loading_indicator.label\": \"Cargando...\",\n  \"media_gallery.toggle_visible\": \"Ocultar\",\n  \"missing_indicator.label\": \"Non atopado\",\n  \"missing_indicator.sublabel\": \"Non se puido atopar o recurso\",\n  \"mute_modal.hide_notifications\": \"Esconder notificacións deste usuario?\",\n  \"navigation_bar.apps\": \"Apps móbiles\",\n  \"navigation_bar.blocks\": \"Usuarias bloqueadas\",\n  \"navigation_bar.community_timeline\": \"Liña temporal local\",\n  \"navigation_bar.compose\": \"Escribir novo toot\",\n  \"navigation_bar.direct\": \"Mensaxes directas\",\n  \"navigation_bar.discover\": \"Descubrir\",\n  \"navigation_bar.domain_blocks\": \"Dominios agochados\",\n  \"navigation_bar.edit_profile\": \"Editar perfil\",\n  \"navigation_bar.favourites\": \"Favoritas\",\n  \"navigation_bar.filters\": \"Palabras acaladas\",\n  \"navigation_bar.follow_requests\": \"Peticións de seguimento\",\n  \"navigation_bar.follows_and_followers\": \"Seguindo e seguidoras\",\n  \"navigation_bar.info\": \"Sobre este servidor\",\n  \"navigation_bar.keyboard_shortcuts\": \"Atallos\",\n  \"navigation_bar.lists\": \"Listas\",\n  \"navigation_bar.logout\": \"Sair\",\n  \"navigation_bar.mutes\": \"Usuarias acaladas\",\n  \"navigation_bar.personal\": \"Persoal\",\n  \"navigation_bar.pins\": \"Mensaxes fixadas\",\n  \"navigation_bar.preferences\": \"Preferencias\",\n  \"navigation_bar.profile_directory\": \"Directorio de perfil\",\n  \"navigation_bar.public_timeline\": \"Liña temporal federada\",\n  \"navigation_bar.security\": \"Seguridade\",\n  \"notification.favourite\": \"{name} marcou como favorito o seu estado\",\n  \"notification.follow\": \"{name} está a seguila\",\n  \"notification.mention\": \"{name} mencionoute\",\n  \"notification.poll\": \"Unha sondaxe na que votou xa rematou\",\n  \"notification.reblog\": \"{name} promoveu o seu estado\",\n  \"notifications.clear\": \"Limpar notificacións\",\n  \"notifications.clear_confirmation\": \"Estás seguro de que queres limpar permanentemente todas as túas notificacións?\",\n  \"notifications.column_settings.alert\": \"Notificacións de escritorio\",\n  \"notifications.column_settings.favourite\": \"Favoritas:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Mostrar todas as categorías\",\n  \"notifications.column_settings.filter_bar.category\": \"Barra de filtrado rápido\",\n  \"notifications.column_settings.filter_bar.show\": \"Mostrar\",\n  \"notifications.column_settings.follow\": \"Novos seguidores:\",\n  \"notifications.column_settings.mention\": \"Mencións:\",\n  \"notifications.column_settings.poll\": \"Resultados da sondaxe:\",\n  \"notifications.column_settings.push\": \"Enviar notificacións\",\n  \"notifications.column_settings.reblog\": \"Promocións:\",\n  \"notifications.column_settings.show\": \"Mostrar en columna\",\n  \"notifications.column_settings.sound\": \"Reproducir son\",\n  \"notifications.filter.all\": \"Todo\",\n  \"notifications.filter.boosts\": \"Promocións\",\n  \"notifications.filter.favourites\": \"Favoritos\",\n  \"notifications.filter.follows\": \"Seguimentos\",\n  \"notifications.filter.mentions\": \"Mencións\",\n  \"notifications.filter.polls\": \"Resultados da sondaxe\",\n  \"notifications.group\": \"{count} notificacións\",\n  \"poll.closed\": \"Pechado\",\n  \"poll.refresh\": \"Actualizar\",\n  \"poll.total_votes\": \"{count, plural, one {# voto} outros {# votos}}\",\n  \"poll.vote\": \"Votar\",\n  \"poll_button.add_poll\": \"Engadir sondaxe\",\n  \"poll_button.remove_poll\": \"Eliminar sondaxe\",\n  \"privacy.change\": \"Axustar a intimidade do estado\",\n  \"privacy.direct.long\": \"Enviar exclusivamente as usuarias mencionadas\",\n  \"privacy.direct.short\": \"Directa\",\n  \"privacy.private.long\": \"Enviar só as seguidoras\",\n  \"privacy.private.short\": \"Só-seguidoras\",\n  \"privacy.public.long\": \"Publicar na liña temporal pública\",\n  \"privacy.public.short\": \"Pública\",\n  \"privacy.unlisted.long\": \"Non publicar en liñas temporais públicas\",\n  \"privacy.unlisted.short\": \"Non listada\",\n  \"regeneration_indicator.label\": \"Cargando…\",\n  \"regeneration_indicator.sublabel\": \"Estase a preparar a súa liña temporal de inicio!\",\n  \"relative_time.days\": \"{number}d\",\n  \"relative_time.hours\": \"{number}h\",\n  \"relative_time.just_now\": \"agora\",\n  \"relative_time.minutes\": \"{number}m\",\n  \"relative_time.seconds\": \"{number}s\",\n  \"reply_indicator.cancel\": \"Cancelar\",\n  \"report.forward\": \"Reenviar a {target}\",\n  \"report.forward_hint\": \"A conta pertence a outro servidor. Enviar unha copia anónima do informe alí tamén?\",\n  \"report.hint\": \"O informe enviarase a moderación do seu servidor. Abaixo pode explicar a razón pola que está a informar:\",\n  \"report.placeholder\": \"Comentarios adicionais\",\n  \"report.submit\": \"Enviar\",\n  \"report.target\": \"Informar {target}\",\n  \"search.placeholder\": \"Buscar\",\n  \"search_popout.search_format\": \"Formato de busca avanzada\",\n  \"search_popout.tips.full_text\": \"Texto simple devolve estados que vostede escribeu, promoveu, marcou favoritos, ou foi mencionada, así como nomes de usuaria coincidentes, nomes públicos e etiquetas.\",\n  \"search_popout.tips.hashtag\": \"etiqueta\",\n  \"search_popout.tips.status\": \"estado\",\n  \"search_popout.tips.text\": \"Texto simple devolve coincidencias con nomes públicos, nomes de usuaria e etiquetas\",\n  \"search_popout.tips.user\": \"usuaria\",\n  \"search_results.accounts\": \"Xente\",\n  \"search_results.hashtags\": \"Etiquetas\",\n  \"search_results.statuses\": \"Toots\",\n  \"search_results.total\": \"{count, number} {count,plural,one {result} outros {results}}\",\n  \"status.admin_account\": \"Abrir interface de moderación para @{name}\",\n  \"status.admin_status\": \"Abrir este estado na interface de moderación\",\n  \"status.block\": \"Bloquear @{name}\",\n  \"status.cancel_reblog_private\": \"Non promover\",\n  \"status.cannot_reblog\": \"Esta mensaxe non pode ser promovida\",\n  \"status.copy\": \"Copiar ligazón ao estado\",\n  \"status.delete\": \"Eliminar\",\n  \"status.detailed_status\": \"Vista detallada da conversa\",\n  \"status.direct\": \"Mensaxe directa @{name}\",\n  \"status.embed\": \"Incrustar\",\n  \"status.favourite\": \"Favorita\",\n  \"status.filtered\": \"Filtrado\",\n  \"status.load_more\": \"Cargar máis\",\n  \"status.media_hidden\": \"Medios ocultos\",\n  \"status.mention\": \"Mencionar @{name}\",\n  \"status.more\": \"Máis\",\n  \"status.mute\": \"Acalar @{name}\",\n  \"status.mute_conversation\": \"Acalar conversa\",\n  \"status.open\": \"Expandir este estado\",\n  \"status.pin\": \"Fixar no perfil\",\n  \"status.pinned\": \"Toot fixado\",\n  \"status.read_more\": \"Lea máis\",\n  \"status.reblog\": \"Promover\",\n  \"status.reblog_private\": \"Promover a audiencia orixinal\",\n  \"status.reblogged_by\": \"{name} promoveu\",\n  \"status.reblogs.empty\": \"Ninguén promoveu este toot polo de agora. Cando alguén o faga, mostraránse aquí.\",\n  \"status.redraft\": \"Eliminar & reescribir\",\n  \"status.reply\": \"Resposta\",\n  \"status.replyAll\": \"Resposta a conversa\",\n  \"status.report\": \"Informar @{name}\",\n  \"status.sensitive_warning\": \"Contido sensible\",\n  \"status.share\": \"Compartir\",\n  \"status.show_less\": \"Mostrar menos\",\n  \"status.show_less_all\": \"Mostrar menos para todas\",\n  \"status.show_more\": \"Mostrar máis\",\n  \"status.show_more_all\": \"Mostrar máis para todas\",\n  \"status.show_thread\": \"Mostrar fío\",\n  \"status.unmute_conversation\": \"Non acalar a conversa\",\n  \"status.unpin\": \"Despegar do perfil\",\n  \"suggestions.dismiss\": \"Rexeitar suxestión\",\n  \"suggestions.header\": \"Podería estar interesada en…\",\n  \"tabs_bar.federated_timeline\": \"Federado\",\n  \"tabs_bar.home\": \"Inicio\",\n  \"tabs_bar.local_timeline\": \"Local\",\n  \"tabs_bar.notifications\": \"Notificacións\",\n  \"tabs_bar.search\": \"Buscar\",\n  \"time_remaining.days\": \"{number, plural, one {# dia} other {# días}} restantes\",\n  \"time_remaining.hours\": \"{number, plural, one {# hora} other {# horas}} restantes\",\n  \"time_remaining.minutes\": \"{number, plural, one {# minuto} other {# minutos}} restantes\",\n  \"time_remaining.moments\": \"Está rematando\",\n  \"time_remaining.seconds\": \"{number, plural, one {# segundo} other {# segundos}} restantes\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {person} outras {people}} conversando\",\n  \"ui.beforeunload\": \"O borrador perderase se sae de Mastodon.\",\n  \"upload_area.title\": \"Arrastre e solte para subir\",\n  \"upload_button.label\": \"Engadir medios (JPEG, PNG, GIF, WebM, MP4, MOV)\",\n  \"upload_error.limit\": \"Excedeu o límite de subida de ficheiros.\",\n  \"upload_error.poll\": \"Non se poden subir ficheiros nas sondaxes.\",\n  \"upload_form.description\": \"Describa para deficientes visuais\",\n  \"upload_form.focus\": \"Cambiar vista previa\",\n  \"upload_form.undo\": \"Eliminar\",\n  \"upload_progress.label\": \"Subindo...\",\n  \"video.close\": \"Pechar video\",\n  \"video.exit_fullscreen\": \"Saír da pantalla completa\",\n  \"video.expand\": \"Expandir vídeo\",\n  \"video.fullscreen\": \"Pantalla completa\",\n  \"video.hide\": \"Agochar vídeo\",\n  \"video.mute\": \"Acalar son\",\n  \"video.pause\": \"Pausar\",\n  \"video.play\": \"Reproducir\",\n  \"video.unmute\": \"Permitir son\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/he.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Add or Remove from lists\",\n  \"account.badges.bot\": \"Bot\",\n  \"account.block\": \"חסימת @{name}\",\n  \"account.block_domain\": \"להסתיר הכל מהקהילה {domain}\",\n  \"account.blocked\": \"Blocked\",\n  \"account.direct\": \"Direct Message @{name}\",\n  \"account.domain_blocked\": \"Domain hidden\",\n  \"account.edit_profile\": \"עריכת פרופיל\",\n  \"account.endorse\": \"Feature on profile\",\n  \"account.follow\": \"מעקב\",\n  \"account.followers\": \"עוקבים\",\n  \"account.followers.empty\": \"No one follows this user yet.\",\n  \"account.follows\": \"נעקבים\",\n  \"account.follows.empty\": \"This user doesn't follow anyone yet.\",\n  \"account.follows_you\": \"במעקב אחריך\",\n  \"account.hide_reblogs\": \"להסתיר הידהודים מאת @{name}\",\n  \"account.link_verified_on\": \"Ownership of this link was checked on {date}\",\n  \"account.locked_info\": \"This account privacy status is set to locked. The owner manually reviews who can follow them.\",\n  \"account.media\": \"מדיה\",\n  \"account.mention\": \"אזכור של @{name}\",\n  \"account.moved_to\": \"החשבון {name} הועבר אל:\",\n  \"account.mute\": \"להשתיק את @{name}\",\n  \"account.mute_notifications\": \"להסתיר התראות מאת @{name}\",\n  \"account.muted\": \"Muted\",\n  \"account.posts\": \"הודעות\",\n  \"account.posts_with_replies\": \"Toots with replies\",\n  \"account.report\": \"לדווח על @{name}\",\n  \"account.requested\": \"בהמתנה לאישור\",\n  \"account.share\": \"לשתף את הפרופיל של @{name}\",\n  \"account.show_reblogs\": \"להראות הדהודים מאת @{name}\",\n  \"account.unblock\": \"הסרת חסימה מעל @{name}\",\n  \"account.unblock_domain\": \"הסר חסימה מקהילת {domain}\",\n  \"account.unendorse\": \"לא להציג בפרופיל\",\n  \"account.unfollow\": \"הפסקת מעקב\",\n  \"account.unmute\": \"הפסקת השתקת @{name}\",\n  \"account.unmute_notifications\": \"להפסיק הסתרת הודעות מעם @{name}\",\n  \"alert.unexpected.message\": \"אירעה שגיאה בלתי צפויה.\",\n  \"alert.unexpected.title\": \"אופס!\",\n  \"boost_modal.combo\": \"ניתן להקיש {combo} כדי לדלג בפעם הבאה\",\n  \"bundle_column_error.body\": \"משהו השתבש בעת הצגת הרכיב הזה.\",\n  \"bundle_column_error.retry\": \"לנסות שוב\",\n  \"bundle_column_error.title\": \"Network error\",\n  \"bundle_modal_error.close\": \"לסגור\",\n  \"bundle_modal_error.message\": \"משהו השתבש בעת טעינת הרכיב הזה.\",\n  \"bundle_modal_error.retry\": \"לנסות שוב\",\n  \"column.blocks\": \"חסימות\",\n  \"column.community\": \"ציר זמן מקומי\",\n  \"column.direct\": \"Direct messages\",\n  \"column.domain_blocks\": \"Hidden domains\",\n  \"column.favourites\": \"חיבובים\",\n  \"column.follow_requests\": \"בקשות מעקב\",\n  \"column.home\": \"בבית\",\n  \"column.lists\": \"Lists\",\n  \"column.mutes\": \"השתקות\",\n  \"column.notifications\": \"התראות\",\n  \"column.pins\": \"Pinned toot\",\n  \"column.public\": \"בפרהסיה\",\n  \"column_back_button.label\": \"חזרה\",\n  \"column_header.hide_settings\": \"הסתרת העדפות\",\n  \"column_header.moveLeft_settings\": \"הזחת טור לשמאל\",\n  \"column_header.moveRight_settings\": \"הזחת טור לימין\",\n  \"column_header.pin\": \"קיבוע\",\n  \"column_header.show_settings\": \"הצגת העדפות\",\n  \"column_header.unpin\": \"שחרור קיבוע\",\n  \"column_subheading.settings\": \"אפשרויות\",\n  \"community.column_settings.media_only\": \"Media Only\",\n  \"compose_form.direct_message_warning\": \"This toot will only be visible to all the mentioned users.\",\n  \"compose_form.direct_message_warning_learn_more\": \"Learn more\",\n  \"compose_form.hashtag_warning\": \"This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.\",\n  \"compose_form.lock_disclaimer\": \"חשבונך אינו {locked}. כל אחד יוכל לעקוב אחריך כדי לקרוא את הודעותיך המיועדות לעוקבים בלבד.\",\n  \"compose_form.lock_disclaimer.lock\": \"נעול\",\n  \"compose_form.placeholder\": \"מה עובר לך בראש?\",\n  \"compose_form.poll.add_option\": \"Add a choice\",\n  \"compose_form.poll.duration\": \"Poll duration\",\n  \"compose_form.poll.option_placeholder\": \"Choice {number}\",\n  \"compose_form.poll.remove_option\": \"Remove this choice\",\n  \"compose_form.publish\": \"ללחוש\",\n  \"compose_form.publish_loud\": \"לחצרץ!\",\n  \"compose_form.sensitive.hide\": \"Mark media as sensitive\",\n  \"compose_form.sensitive.marked\": \"Media is marked as sensitive\",\n  \"compose_form.sensitive.unmarked\": \"Media is not marked as sensitive\",\n  \"compose_form.spoiler.marked\": \"Text is hidden behind warning\",\n  \"compose_form.spoiler.unmarked\": \"Text is not hidden\",\n  \"compose_form.spoiler_placeholder\": \"אזהרת תוכן\",\n  \"confirmation_modal.cancel\": \"ביטול\",\n  \"confirmations.block.block_and_report\": \"Block & Report\",\n  \"confirmations.block.confirm\": \"לחסום\",\n  \"confirmations.block.message\": \"לחסום את {name}?\",\n  \"confirmations.delete.confirm\": \"למחוק\",\n  \"confirmations.delete.message\": \"למחוק את ההודעה?\",\n  \"confirmations.delete_list.confirm\": \"Delete\",\n  \"confirmations.delete_list.message\": \"Are you sure you want to permanently delete this list?\",\n  \"confirmations.domain_block.confirm\": \"הסתר קהילה שלמה\",\n  \"confirmations.domain_block.message\": \"באמת באמת לחסום את כל קהילת {domain}? ברב המקרים השתקות נבחרות של מספר משתמשים מסויימים צריכה להספיק.\",\n  \"confirmations.mute.confirm\": \"להשתיק\",\n  \"confirmations.mute.message\": \"להשתיק את {name}?\",\n  \"confirmations.redraft.confirm\": \"Delete & redraft\",\n  \"confirmations.redraft.message\": \"Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.\",\n  \"confirmations.reply.confirm\": \"Reply\",\n  \"confirmations.reply.message\": \"Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?\",\n  \"confirmations.unfollow.confirm\": \"להפסיק מעקב\",\n  \"confirmations.unfollow.message\": \"להפסיק מעקב אחרי {name}?\",\n  \"embed.instructions\": \"ניתן להטמיע את ההודעה באתרך ע\\\"י העתקת הקוד שלהלן.\",\n  \"embed.preview\": \"דוגמא כיצד זה יראה:\",\n  \"emoji_button.activity\": \"פעילות\",\n  \"emoji_button.custom\": \"מיוחדים\",\n  \"emoji_button.flags\": \"דגלים\",\n  \"emoji_button.food\": \"אוכל ושתיה\",\n  \"emoji_button.label\": \"הוספת אמוג'י\",\n  \"emoji_button.nature\": \"טבע\",\n  \"emoji_button.not_found\": \"רגישון לא נמצא!! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"חפצים\",\n  \"emoji_button.people\": \"אנשים\",\n  \"emoji_button.recent\": \"בשימוש תדיר\",\n  \"emoji_button.search\": \"חיפוש...\",\n  \"emoji_button.search_results\": \"תוצאות חיפוש\",\n  \"emoji_button.symbols\": \"סמלים\",\n  \"emoji_button.travel\": \"טיולים ואתרים\",\n  \"empty_column.account_timeline\": \"No toots here!\",\n  \"empty_column.account_unavailable\": \"Profile unavailable\",\n  \"empty_column.blocks\": \"You haven't blocked any users yet.\",\n  \"empty_column.community\": \"טור הסביבה ריק. יש לפרסם משהו כדי שדברים יתרחילו להתגלגל!\",\n  \"empty_column.direct\": \"You don't have any direct messages yet. When you send or receive one, it will show up here.\",\n  \"empty_column.domain_blocks\": \"There are no hidden domains yet.\",\n  \"empty_column.favourited_statuses\": \"You don't have any favourite toots yet. When you favourite one, it will show up here.\",\n  \"empty_column.favourites\": \"No one has favourited this toot yet. When someone does, they will show up here.\",\n  \"empty_column.follow_requests\": \"You don't have any follow requests yet. When you receive one, it will show up here.\",\n  \"empty_column.hashtag\": \"אין כלום בהאשתג הזה עדיין.\",\n  \"empty_column.home\": \"אף אחד לא במעקב עדיין. אפשר לבקר ב{public} או להשתמש בחיפוש כדי להתחיל ולהכיר חצוצרנים אחרים.\",\n  \"empty_column.home.public_timeline\": \"ציר זמן בין-קהילתי\",\n  \"empty_column.list\": \"אין עדיין מאום ברשימה.\",\n  \"empty_column.lists\": \"You don't have any lists yet. When you create one, it will show up here.\",\n  \"empty_column.mutes\": \"You haven't muted any users yet.\",\n  \"empty_column.notifications\": \"אין התראות עדיין. יאללה, הגיע הזמן להתחיל להתערבב.\",\n  \"empty_column.public\": \"אין פה כלום! כדי למלא את הטור הזה אפשר לכתוב משהו, או להתחיל לעקוב אחרי אנשים מקהילות אחרות\",\n  \"follow_request.authorize\": \"קבלה\",\n  \"follow_request.reject\": \"דחיה\",\n  \"getting_started.developers\": \"Developers\",\n  \"getting_started.directory\": \"Profile directory\",\n  \"getting_started.documentation\": \"Documentation\",\n  \"getting_started.heading\": \"בואו נתחיל\",\n  \"getting_started.invite\": \"Invite people\",\n  \"getting_started.open_source_notice\": \"מסטודון היא תוכנה חופשית (בקוד פתוח). ניתן לתרום או לדווח על בעיות בגיטהאב: {github}.\",\n  \"getting_started.security\": \"Security\",\n  \"getting_started.terms\": \"Terms of service\",\n  \"hashtag.column_header.tag_mode.all\": \"and {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"or {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"without {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"No suggestions found\",\n  \"hashtag.column_settings.select.placeholder\": \"Enter hashtags…\",\n  \"hashtag.column_settings.tag_mode.all\": \"All of these\",\n  \"hashtag.column_settings.tag_mode.any\": \"Any of these\",\n  \"hashtag.column_settings.tag_mode.none\": \"None of these\",\n  \"hashtag.column_settings.tag_toggle\": \"Include additional tags in this column\",\n  \"home.column_settings.basic\": \"למתחילים\",\n  \"home.column_settings.show_reblogs\": \"הצגת הדהודים\",\n  \"home.column_settings.show_replies\": \"הצגת תגובות\",\n  \"intervals.full.days\": \"{number, plural, one {# day} other {# days}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# hour} other {# hours}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minute} other {# minutes}}\",\n  \"introduction.federation.action\": \"Next\",\n  \"introduction.federation.federated.headline\": \"Federated\",\n  \"introduction.federation.federated.text\": \"Public posts from other servers of the fediverse will appear in the federated timeline.\",\n  \"introduction.federation.home.headline\": \"Home\",\n  \"introduction.federation.home.text\": \"Posts from people you follow will appear in your home feed. You can follow anyone on any server!\",\n  \"introduction.federation.local.headline\": \"Local\",\n  \"introduction.federation.local.text\": \"Public posts from people on the same server as you will appear in the local timeline.\",\n  \"introduction.interactions.action\": \"Finish toot-orial!\",\n  \"introduction.interactions.favourite.headline\": \"Favourite\",\n  \"introduction.interactions.favourite.text\": \"You can save a toot for later, and let the author know that you liked it, by favouriting it.\",\n  \"introduction.interactions.reblog.headline\": \"Boost\",\n  \"introduction.interactions.reblog.text\": \"You can share other people's toots with your followers by boosting them.\",\n  \"introduction.interactions.reply.headline\": \"Reply\",\n  \"introduction.interactions.reply.text\": \"You can reply to other people's and your own toots, which will chain them together in a conversation.\",\n  \"introduction.welcome.action\": \"Let's go!\",\n  \"introduction.welcome.headline\": \"First steps\",\n  \"introduction.welcome.text\": \"Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.\",\n  \"keyboard_shortcuts.back\": \"ניווט חזרה\",\n  \"keyboard_shortcuts.blocked\": \"to open blocked users list\",\n  \"keyboard_shortcuts.boost\": \"להדהד\",\n  \"keyboard_shortcuts.column\": \"להתמקד בהודעה באחד מהטורים\",\n  \"keyboard_shortcuts.compose\": \"להתמקד בתיבת חיבור ההודעות\",\n  \"keyboard_shortcuts.description\": \"Description\",\n  \"keyboard_shortcuts.direct\": \"to open direct messages column\",\n  \"keyboard_shortcuts.down\": \"לנוע במורד הרשימה\",\n  \"keyboard_shortcuts.enter\": \"to open status\",\n  \"keyboard_shortcuts.favourite\": \"לחבב\",\n  \"keyboard_shortcuts.favourites\": \"to open favourites list\",\n  \"keyboard_shortcuts.federated\": \"to open federated timeline\",\n  \"keyboard_shortcuts.heading\": \"Keyboard Shortcuts\",\n  \"keyboard_shortcuts.home\": \"to open home timeline\",\n  \"keyboard_shortcuts.hotkey\": \"מקש קיצור\",\n  \"keyboard_shortcuts.legend\": \"להציג את הפירוש\",\n  \"keyboard_shortcuts.local\": \"to open local timeline\",\n  \"keyboard_shortcuts.mention\": \"לאזכר את המחבר(ת)\",\n  \"keyboard_shortcuts.muted\": \"to open muted users list\",\n  \"keyboard_shortcuts.my_profile\": \"to open your profile\",\n  \"keyboard_shortcuts.notifications\": \"to open notifications column\",\n  \"keyboard_shortcuts.pinned\": \"to open pinned toots list\",\n  \"keyboard_shortcuts.profile\": \"to open author's profile\",\n  \"keyboard_shortcuts.reply\": \"לענות\",\n  \"keyboard_shortcuts.requests\": \"to open follow requests list\",\n  \"keyboard_shortcuts.search\": \"להתמקד בחלון החיפוש\",\n  \"keyboard_shortcuts.start\": \"to open \\\"get started\\\" column\",\n  \"keyboard_shortcuts.toggle_hidden\": \"to show/hide text behind CW\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"to show/hide media\",\n  \"keyboard_shortcuts.toot\": \"להתחיל חיצרוץ חדש\",\n  \"keyboard_shortcuts.unfocus\": \"לצאת מתיבת חיבור/חיפוש\",\n  \"keyboard_shortcuts.up\": \"לנוע במעלה הרשימה\",\n  \"lightbox.close\": \"סגירה\",\n  \"lightbox.next\": \"הלאה\",\n  \"lightbox.previous\": \"הקודם\",\n  \"lightbox.view_context\": \"View context\",\n  \"lists.account.add\": \"Add to list\",\n  \"lists.account.remove\": \"Remove from list\",\n  \"lists.delete\": \"Delete list\",\n  \"lists.edit\": \"Edit list\",\n  \"lists.edit.submit\": \"Change title\",\n  \"lists.new.create\": \"Add list\",\n  \"lists.new.title_placeholder\": \"New list title\",\n  \"lists.search\": \"Search among people you follow\",\n  \"lists.subheading\": \"Your lists\",\n  \"loading_indicator.label\": \"טוען...\",\n  \"media_gallery.toggle_visible\": \"נראה\\\\בלתי נראה\",\n  \"missing_indicator.label\": \"לא נמצא\",\n  \"missing_indicator.sublabel\": \"This resource could not be found\",\n  \"mute_modal.hide_notifications\": \"להסתיר הודעות מחשבון זה?\",\n  \"navigation_bar.apps\": \"Mobile apps\",\n  \"navigation_bar.blocks\": \"חסימות\",\n  \"navigation_bar.community_timeline\": \"ציר זמן מקומי\",\n  \"navigation_bar.compose\": \"Compose new toot\",\n  \"navigation_bar.direct\": \"Direct messages\",\n  \"navigation_bar.discover\": \"Discover\",\n  \"navigation_bar.domain_blocks\": \"Hidden domains\",\n  \"navigation_bar.edit_profile\": \"עריכת פרופיל\",\n  \"navigation_bar.favourites\": \"חיבובים\",\n  \"navigation_bar.filters\": \"Muted words\",\n  \"navigation_bar.follow_requests\": \"בקשות מעקב\",\n  \"navigation_bar.follows_and_followers\": \"Follows and followers\",\n  \"navigation_bar.info\": \"מידע נוסף\",\n  \"navigation_bar.keyboard_shortcuts\": \"קיצורי מקלדת\",\n  \"navigation_bar.lists\": \"Lists\",\n  \"navigation_bar.logout\": \"יציאה\",\n  \"navigation_bar.mutes\": \"השתקות\",\n  \"navigation_bar.personal\": \"Personal\",\n  \"navigation_bar.pins\": \"חיצרוצים מקובעים\",\n  \"navigation_bar.preferences\": \"העדפות\",\n  \"navigation_bar.profile_directory\": \"Profile directory\",\n  \"navigation_bar.public_timeline\": \"ציר זמן בין-קהילתי\",\n  \"navigation_bar.security\": \"Security\",\n  \"notification.favourite\": \"חצרוצך חובב על ידי {name}\",\n  \"notification.follow\": \"{name} במעקב אחרייך\",\n  \"notification.mention\": \"אוזכרת על ידי {name}\",\n  \"notification.poll\": \"A poll you have voted in has ended\",\n  \"notification.reblog\": \"חצרוצך הודהד על ידי {name}\",\n  \"notifications.clear\": \"הסרת התראות\",\n  \"notifications.clear_confirmation\": \"להסיר את כל ההתראות? בטוח?\",\n  \"notifications.column_settings.alert\": \"התראות לשולחן העבודה\",\n  \"notifications.column_settings.favourite\": \"מחובבים:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Display all categories\",\n  \"notifications.column_settings.filter_bar.category\": \"Quick filter bar\",\n  \"notifications.column_settings.filter_bar.show\": \"Show\",\n  \"notifications.column_settings.follow\": \"עוקבים חדשים:\",\n  \"notifications.column_settings.mention\": \"פניות:\",\n  \"notifications.column_settings.poll\": \"Poll results:\",\n  \"notifications.column_settings.push\": \"הודעות בדחיפה\",\n  \"notifications.column_settings.reblog\": \"הדהודים:\",\n  \"notifications.column_settings.show\": \"הצגה בטור\",\n  \"notifications.column_settings.sound\": \"שמע מופעל\",\n  \"notifications.filter.all\": \"All\",\n  \"notifications.filter.boosts\": \"Boosts\",\n  \"notifications.filter.favourites\": \"Favourites\",\n  \"notifications.filter.follows\": \"Follows\",\n  \"notifications.filter.mentions\": \"Mentions\",\n  \"notifications.filter.polls\": \"Poll results\",\n  \"notifications.group\": \"{count} notifications\",\n  \"poll.closed\": \"Closed\",\n  \"poll.refresh\": \"Refresh\",\n  \"poll.total_votes\": \"{count, plural, one {# vote} other {# votes}}\",\n  \"poll.vote\": \"Vote\",\n  \"poll_button.add_poll\": \"Add a poll\",\n  \"poll_button.remove_poll\": \"Remove poll\",\n  \"privacy.change\": \"שינוי פרטיות ההודעה\",\n  \"privacy.direct.long\": \"הצג רק למי שהודעה זו פונה אליו\",\n  \"privacy.direct.short\": \"הודעה ישירה\",\n  \"privacy.private.long\": \"הצג לעוקבים בלבד\",\n  \"privacy.private.short\": \"לעוקבים בלבד\",\n  \"privacy.public.long\": \"פרסם בפומבי\",\n  \"privacy.public.short\": \"פומבי\",\n  \"privacy.unlisted.long\": \"לא יופיע בפידים הציבוריים המשותפים\",\n  \"privacy.unlisted.short\": \"לא לפיד הכללי\",\n  \"regeneration_indicator.label\": \"Loading…\",\n  \"regeneration_indicator.sublabel\": \"Your home feed is being prepared!\",\n  \"relative_time.days\": \"{number}d\",\n  \"relative_time.hours\": \"{number}h\",\n  \"relative_time.just_now\": \"כרגע\",\n  \"relative_time.minutes\": \"{number}m\",\n  \"relative_time.seconds\": \"{number}s\",\n  \"reply_indicator.cancel\": \"ביטול\",\n  \"report.forward\": \"Forward to {target}\",\n  \"report.forward_hint\": \"The account is from another server. Send an anonymized copy of the report there as well?\",\n  \"report.hint\": \"The report will be sent to your instance moderators. You can provide an explanation of why you are reporting this account below:\",\n  \"report.placeholder\": \"הערות נוספות\",\n  \"report.submit\": \"שליחה\",\n  \"report.target\": \"דיווח\",\n  \"search.placeholder\": \"חיפוש\",\n  \"search_popout.search_format\": \"מבנה חיפוש מתקדם\",\n  \"search_popout.tips.full_text\": \"Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.\",\n  \"search_popout.tips.hashtag\": \"האשתג\",\n  \"search_popout.tips.status\": \"status\",\n  \"search_popout.tips.text\": \"טקסט פשוט מחזיר כינויים, שמות משתמש והאשתגים\",\n  \"search_popout.tips.user\": \"משתמש(ת)\",\n  \"search_results.accounts\": \"People\",\n  \"search_results.hashtags\": \"Hashtags\",\n  \"search_results.statuses\": \"Toots\",\n  \"search_results.total\": \"{count, number} {count, plural, one {תוצאה} other {תוצאות}}\",\n  \"status.admin_account\": \"Open moderation interface for @{name}\",\n  \"status.admin_status\": \"Open this status in the moderation interface\",\n  \"status.block\": \"Block @{name}\",\n  \"status.cancel_reblog_private\": \"Unboost\",\n  \"status.cannot_reblog\": \"לא ניתן להדהד הודעה זו\",\n  \"status.copy\": \"Copy link to status\",\n  \"status.delete\": \"מחיקה\",\n  \"status.detailed_status\": \"Detailed conversation view\",\n  \"status.direct\": \"Direct message @{name}\",\n  \"status.embed\": \"הטמעה\",\n  \"status.favourite\": \"חיבוב\",\n  \"status.filtered\": \"Filtered\",\n  \"status.load_more\": \"עוד\",\n  \"status.media_hidden\": \"מדיה מוסתרת\",\n  \"status.mention\": \"פניה אל @{name}\",\n  \"status.more\": \"עוד\",\n  \"status.mute\": \"Mute @{name}\",\n  \"status.mute_conversation\": \"השתקת שיחה\",\n  \"status.open\": \"הרחבת הודעה\",\n  \"status.pin\": \"לקבע באודות\",\n  \"status.pinned\": \"Pinned toot\",\n  \"status.read_more\": \"Read more\",\n  \"status.reblog\": \"הדהוד\",\n  \"status.reblog_private\": \"Boost to original audience\",\n  \"status.reblogged_by\": \"הודהד על ידי {name}\",\n  \"status.reblogs.empty\": \"No one has boosted this toot yet. When someone does, they will show up here.\",\n  \"status.redraft\": \"Delete & re-draft\",\n  \"status.reply\": \"תגובה\",\n  \"status.replyAll\": \"תגובה לכולם\",\n  \"status.report\": \"דיווח על @{name}\",\n  \"status.sensitive_warning\": \"תוכן רגיש\",\n  \"status.share\": \"שיתוף\",\n  \"status.show_less\": \"הראה פחות\",\n  \"status.show_less_all\": \"Show less for all\",\n  \"status.show_more\": \"הראה יותר\",\n  \"status.show_more_all\": \"Show more for all\",\n  \"status.show_thread\": \"Show thread\",\n  \"status.unmute_conversation\": \"הסרת השתקת שיחה\",\n  \"status.unpin\": \"לשחרר מקיבוע באודות\",\n  \"suggestions.dismiss\": \"Dismiss suggestion\",\n  \"suggestions.header\": \"You might be interested in…\",\n  \"tabs_bar.federated_timeline\": \"ציר זמן בין-קהילתי\",\n  \"tabs_bar.home\": \"בבית\",\n  \"tabs_bar.local_timeline\": \"ציר זמן מקומי\",\n  \"tabs_bar.notifications\": \"התראות\",\n  \"tabs_bar.search\": \"Search\",\n  \"time_remaining.days\": \"{number, plural, one {# day} other {# days}} left\",\n  \"time_remaining.hours\": \"{number, plural, one {# hour} other {# hours}} left\",\n  \"time_remaining.minutes\": \"{number, plural, one {# minute} other {# minutes}} left\",\n  \"time_remaining.moments\": \"Moments remaining\",\n  \"time_remaining.seconds\": \"{number, plural, one {# second} other {# seconds}} left\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {person} other {people}} talking\",\n  \"ui.beforeunload\": \"הטיוטא תאבד אם תעזבו את מסטודון.\",\n  \"upload_area.title\": \"ניתן להעלות על ידי Drag & drop\",\n  \"upload_button.label\": \"הוספת מדיה\",\n  \"upload_error.limit\": \"File upload limit exceeded.\",\n  \"upload_error.poll\": \"File upload not allowed with polls.\",\n  \"upload_form.description\": \"תיאור לכבדי ראיה\",\n  \"upload_form.focus\": \"Crop\",\n  \"upload_form.undo\": \"ביטול\",\n  \"upload_progress.label\": \"עולה...\",\n  \"video.close\": \"סגירת וידאו\",\n  \"video.exit_fullscreen\": \"יציאה ממסך מלא\",\n  \"video.expand\": \"להרחיב וידאו\",\n  \"video.fullscreen\": \"Full screen\",\n  \"video.hide\": \"להסתיר וידאו\",\n  \"video.mute\": \"השתקת צליל\",\n  \"video.pause\": \"Pause\",\n  \"video.play\": \"ניגון\",\n  \"video.unmute\": \"החזרת צליל\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/hi.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Add or Remove from lists\",\n  \"account.badges.bot\": \"Bot\",\n  \"account.block\": \"Block @{name}\",\n  \"account.block_domain\": \"Hide everything from {domain}\",\n  \"account.blocked\": \"Blocked\",\n  \"account.direct\": \"Direct message @{name}\",\n  \"account.domain_blocked\": \"Domain hidden\",\n  \"account.edit_profile\": \"Edit profile\",\n  \"account.endorse\": \"Feature on profile\",\n  \"account.follow\": \"Follow\",\n  \"account.followers\": \"Followers\",\n  \"account.followers.empty\": \"No one follows this user yet.\",\n  \"account.follows\": \"Follows\",\n  \"account.follows.empty\": \"This user doesn't follow anyone yet.\",\n  \"account.follows_you\": \"Follows you\",\n  \"account.hide_reblogs\": \"Hide boosts from @{name}\",\n  \"account.link_verified_on\": \"Ownership of this link was checked on {date}\",\n  \"account.locked_info\": \"This account privacy status is set to locked. The owner manually reviews who can follow them.\",\n  \"account.media\": \"Media\",\n  \"account.mention\": \"Mention @{name}\",\n  \"account.moved_to\": \"{name} has moved to:\",\n  \"account.mute\": \"Mute @{name}\",\n  \"account.mute_notifications\": \"Mute notifications from @{name}\",\n  \"account.muted\": \"Muted\",\n  \"account.posts\": \"Toots\",\n  \"account.posts_with_replies\": \"Toots and replies\",\n  \"account.report\": \"Report @{name}\",\n  \"account.requested\": \"Awaiting approval. Click to cancel follow request\",\n  \"account.share\": \"Share @{name}'s profile\",\n  \"account.show_reblogs\": \"Show boosts from @{name}\",\n  \"account.unblock\": \"Unblock @{name}\",\n  \"account.unblock_domain\": \"Unhide {domain}\",\n  \"account.unendorse\": \"Don't feature on profile\",\n  \"account.unfollow\": \"Unfollow\",\n  \"account.unmute\": \"Unmute @{name}\",\n  \"account.unmute_notifications\": \"Unmute notifications from @{name}\",\n  \"alert.unexpected.message\": \"An unexpected error occurred.\",\n  \"alert.unexpected.title\": \"Oops!\",\n  \"boost_modal.combo\": \"You can press {combo} to skip this next time\",\n  \"bundle_column_error.body\": \"Something went wrong while loading this component.\",\n  \"bundle_column_error.retry\": \"Try again\",\n  \"bundle_column_error.title\": \"Network error\",\n  \"bundle_modal_error.close\": \"Close\",\n  \"bundle_modal_error.message\": \"Something went wrong while loading this component.\",\n  \"bundle_modal_error.retry\": \"Try again\",\n  \"column.blocks\": \"Blocked users\",\n  \"column.community\": \"Local timeline\",\n  \"column.direct\": \"Direct messages\",\n  \"column.domain_blocks\": \"Hidden domains\",\n  \"column.favourites\": \"Favourites\",\n  \"column.follow_requests\": \"Follow requests\",\n  \"column.home\": \"Home\",\n  \"column.lists\": \"Lists\",\n  \"column.mutes\": \"Muted users\",\n  \"column.notifications\": \"Notifications\",\n  \"column.pins\": \"Pinned toot\",\n  \"column.public\": \"Federated timeline\",\n  \"column_back_button.label\": \"Back\",\n  \"column_header.hide_settings\": \"Hide settings\",\n  \"column_header.moveLeft_settings\": \"Move column to the left\",\n  \"column_header.moveRight_settings\": \"Move column to the right\",\n  \"column_header.pin\": \"Pin\",\n  \"column_header.show_settings\": \"Show settings\",\n  \"column_header.unpin\": \"Unpin\",\n  \"column_subheading.settings\": \"Settings\",\n  \"community.column_settings.media_only\": \"Media Only\",\n  \"compose_form.direct_message_warning\": \"This toot will only be sent to all the mentioned users.\",\n  \"compose_form.direct_message_warning_learn_more\": \"Learn more\",\n  \"compose_form.hashtag_warning\": \"This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.\",\n  \"compose_form.lock_disclaimer\": \"Your account is not {locked}. Anyone can follow you to view your follower-only posts.\",\n  \"compose_form.lock_disclaimer.lock\": \"locked\",\n  \"compose_form.placeholder\": \"What is on your mind?\",\n  \"compose_form.poll.add_option\": \"Add a choice\",\n  \"compose_form.poll.duration\": \"Poll duration\",\n  \"compose_form.poll.option_placeholder\": \"Choice {number}\",\n  \"compose_form.poll.remove_option\": \"Remove this choice\",\n  \"compose_form.publish\": \"Toot\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"Mark media as sensitive\",\n  \"compose_form.sensitive.marked\": \"Media is marked as sensitive\",\n  \"compose_form.sensitive.unmarked\": \"Media is not marked as sensitive\",\n  \"compose_form.spoiler.marked\": \"Text is hidden behind warning\",\n  \"compose_form.spoiler.unmarked\": \"Text is not hidden\",\n  \"compose_form.spoiler_placeholder\": \"Write your warning here\",\n  \"confirmation_modal.cancel\": \"Cancel\",\n  \"confirmations.block.block_and_report\": \"Block & Report\",\n  \"confirmations.block.confirm\": \"Block\",\n  \"confirmations.block.message\": \"Are you sure you want to block {name}?\",\n  \"confirmations.delete.confirm\": \"Delete\",\n  \"confirmations.delete.message\": \"Are you sure you want to delete this status?\",\n  \"confirmations.delete_list.confirm\": \"Delete\",\n  \"confirmations.delete_list.message\": \"Are you sure you want to permanently delete this list?\",\n  \"confirmations.domain_block.confirm\": \"Hide entire domain\",\n  \"confirmations.domain_block.message\": \"Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain in any public timelines or your notifications. Your followers from that domain will be removed.\",\n  \"confirmations.mute.confirm\": \"Mute\",\n  \"confirmations.mute.message\": \"Are you sure you want to mute {name}?\",\n  \"confirmations.redraft.confirm\": \"Delete & redraft\",\n  \"confirmations.redraft.message\": \"Are you sure you want to delete this status and re-draft it? Favourites and boosts will be lost, and replies to the original post will be orphaned.\",\n  \"confirmations.reply.confirm\": \"Reply\",\n  \"confirmations.reply.message\": \"Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?\",\n  \"confirmations.unfollow.confirm\": \"Unfollow\",\n  \"confirmations.unfollow.message\": \"Are you sure you want to unfollow {name}?\",\n  \"embed.instructions\": \"Embed this status on your website by copying the code below.\",\n  \"embed.preview\": \"Here is what it will look like:\",\n  \"emoji_button.activity\": \"Activity\",\n  \"emoji_button.custom\": \"Custom\",\n  \"emoji_button.flags\": \"Flags\",\n  \"emoji_button.food\": \"Food & Drink\",\n  \"emoji_button.label\": \"Insert emoji\",\n  \"emoji_button.nature\": \"Nature\",\n  \"emoji_button.not_found\": \"No emojos!! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"Objects\",\n  \"emoji_button.people\": \"People\",\n  \"emoji_button.recent\": \"Frequently used\",\n  \"emoji_button.search\": \"Search...\",\n  \"emoji_button.search_results\": \"Search results\",\n  \"emoji_button.symbols\": \"Symbols\",\n  \"emoji_button.travel\": \"Travel & Places\",\n  \"empty_column.account_timeline\": \"No toots here!\",\n  \"empty_column.account_unavailable\": \"Profile unavailable\",\n  \"empty_column.blocks\": \"You haven't blocked any users yet.\",\n  \"empty_column.community\": \"The local timeline is empty. Write something publicly to get the ball rolling!\",\n  \"empty_column.direct\": \"You don't have any direct messages yet. When you send or receive one, it will show up here.\",\n  \"empty_column.domain_blocks\": \"There are no hidden domains yet.\",\n  \"empty_column.favourited_statuses\": \"You don't have any favourite toots yet. When you favourite one, it will show up here.\",\n  \"empty_column.favourites\": \"No one has favourited this toot yet. When someone does, they will show up here.\",\n  \"empty_column.follow_requests\": \"You don't have any follow requests yet. When you receive one, it will show up here.\",\n  \"empty_column.hashtag\": \"There is nothing in this hashtag yet.\",\n  \"empty_column.home\": \"Your home timeline is empty! Visit {public} or use search to get started and meet other users.\",\n  \"empty_column.home.public_timeline\": \"the public timeline\",\n  \"empty_column.list\": \"There is nothing in this list yet. When members of this list post new statuses, they will appear here.\",\n  \"empty_column.lists\": \"You don't have any lists yet. When you create one, it will show up here.\",\n  \"empty_column.mutes\": \"You haven't muted any users yet.\",\n  \"empty_column.notifications\": \"You don't have any notifications yet. Interact with others to start the conversation.\",\n  \"empty_column.public\": \"There is nothing here! Write something publicly, or manually follow users from other servers to fill it up\",\n  \"follow_request.authorize\": \"Authorize\",\n  \"follow_request.reject\": \"Reject\",\n  \"getting_started.developers\": \"Developers\",\n  \"getting_started.directory\": \"Profile directory\",\n  \"getting_started.documentation\": \"Documentation\",\n  \"getting_started.heading\": \"Getting started\",\n  \"getting_started.invite\": \"Invite people\",\n  \"getting_started.open_source_notice\": \"Mastodon is open source software. You can contribute or report issues on GitHub at {github}.\",\n  \"getting_started.security\": \"Security\",\n  \"getting_started.terms\": \"Terms of service\",\n  \"hashtag.column_header.tag_mode.all\": \"and {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"or {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"without {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"No suggestions found\",\n  \"hashtag.column_settings.select.placeholder\": \"Enter hashtags…\",\n  \"hashtag.column_settings.tag_mode.all\": \"All of these\",\n  \"hashtag.column_settings.tag_mode.any\": \"Any of these\",\n  \"hashtag.column_settings.tag_mode.none\": \"None of these\",\n  \"hashtag.column_settings.tag_toggle\": \"Include additional tags in this column\",\n  \"home.column_settings.basic\": \"Basic\",\n  \"home.column_settings.show_reblogs\": \"Show boosts\",\n  \"home.column_settings.show_replies\": \"Show replies\",\n  \"intervals.full.days\": \"{number, plural, one {# day} other {# days}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# hour} other {# hours}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minute} other {# minutes}}\",\n  \"introduction.federation.action\": \"Next\",\n  \"introduction.federation.federated.headline\": \"Federated\",\n  \"introduction.federation.federated.text\": \"Public posts from other servers of the fediverse will appear in the federated timeline.\",\n  \"introduction.federation.home.headline\": \"Home\",\n  \"introduction.federation.home.text\": \"Posts from people you follow will appear in your home feed. You can follow anyone on any server!\",\n  \"introduction.federation.local.headline\": \"Local\",\n  \"introduction.federation.local.text\": \"Public posts from people on the same server as you will appear in the local timeline.\",\n  \"introduction.interactions.action\": \"Finish toot-orial!\",\n  \"introduction.interactions.favourite.headline\": \"Favourite\",\n  \"introduction.interactions.favourite.text\": \"You can save a toot for later, and let the author know that you liked it, by favouriting it.\",\n  \"introduction.interactions.reblog.headline\": \"Boost\",\n  \"introduction.interactions.reblog.text\": \"You can share other people's toots with your followers by boosting them.\",\n  \"introduction.interactions.reply.headline\": \"Reply\",\n  \"introduction.interactions.reply.text\": \"You can reply to other people's and your own toots, which will chain them together in a conversation.\",\n  \"introduction.welcome.action\": \"Let's go!\",\n  \"introduction.welcome.headline\": \"First steps\",\n  \"introduction.welcome.text\": \"Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.\",\n  \"keyboard_shortcuts.back\": \"to navigate back\",\n  \"keyboard_shortcuts.blocked\": \"to open blocked users list\",\n  \"keyboard_shortcuts.boost\": \"to boost\",\n  \"keyboard_shortcuts.column\": \"to focus a status in one of the columns\",\n  \"keyboard_shortcuts.compose\": \"to focus the compose textarea\",\n  \"keyboard_shortcuts.description\": \"Description\",\n  \"keyboard_shortcuts.direct\": \"to open direct messages column\",\n  \"keyboard_shortcuts.down\": \"to move down in the list\",\n  \"keyboard_shortcuts.enter\": \"to open status\",\n  \"keyboard_shortcuts.favourite\": \"to favourite\",\n  \"keyboard_shortcuts.favourites\": \"to open favourites list\",\n  \"keyboard_shortcuts.federated\": \"to open federated timeline\",\n  \"keyboard_shortcuts.heading\": \"Keyboard Shortcuts\",\n  \"keyboard_shortcuts.home\": \"to open home timeline\",\n  \"keyboard_shortcuts.hotkey\": \"Hotkey\",\n  \"keyboard_shortcuts.legend\": \"to display this legend\",\n  \"keyboard_shortcuts.local\": \"to open local timeline\",\n  \"keyboard_shortcuts.mention\": \"to mention author\",\n  \"keyboard_shortcuts.muted\": \"to open muted users list\",\n  \"keyboard_shortcuts.my_profile\": \"to open your profile\",\n  \"keyboard_shortcuts.notifications\": \"to open notifications column\",\n  \"keyboard_shortcuts.pinned\": \"to open pinned toots list\",\n  \"keyboard_shortcuts.profile\": \"to open author's profile\",\n  \"keyboard_shortcuts.reply\": \"to reply\",\n  \"keyboard_shortcuts.requests\": \"to open follow requests list\",\n  \"keyboard_shortcuts.search\": \"to focus search\",\n  \"keyboard_shortcuts.start\": \"to open \\\"get started\\\" column\",\n  \"keyboard_shortcuts.toggle_hidden\": \"to show/hide text behind CW\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"to show/hide media\",\n  \"keyboard_shortcuts.toot\": \"to start a brand new toot\",\n  \"keyboard_shortcuts.unfocus\": \"to un-focus compose textarea/search\",\n  \"keyboard_shortcuts.up\": \"to move up in the list\",\n  \"lightbox.close\": \"Close\",\n  \"lightbox.next\": \"Next\",\n  \"lightbox.previous\": \"Previous\",\n  \"lightbox.view_context\": \"View context\",\n  \"lists.account.add\": \"Add to list\",\n  \"lists.account.remove\": \"Remove from list\",\n  \"lists.delete\": \"Delete list\",\n  \"lists.edit\": \"Edit list\",\n  \"lists.edit.submit\": \"Change title\",\n  \"lists.new.create\": \"Add list\",\n  \"lists.new.title_placeholder\": \"New list title\",\n  \"lists.search\": \"Search among people you follow\",\n  \"lists.subheading\": \"Your lists\",\n  \"loading_indicator.label\": \"Loading...\",\n  \"media_gallery.toggle_visible\": \"Toggle visibility\",\n  \"missing_indicator.label\": \"Not found\",\n  \"missing_indicator.sublabel\": \"This resource could not be found\",\n  \"mute_modal.hide_notifications\": \"Hide notifications from this user?\",\n  \"navigation_bar.apps\": \"Mobile apps\",\n  \"navigation_bar.blocks\": \"Blocked users\",\n  \"navigation_bar.community_timeline\": \"Local timeline\",\n  \"navigation_bar.compose\": \"Compose new toot\",\n  \"navigation_bar.direct\": \"Direct messages\",\n  \"navigation_bar.discover\": \"Discover\",\n  \"navigation_bar.domain_blocks\": \"Hidden domains\",\n  \"navigation_bar.edit_profile\": \"Edit profile\",\n  \"navigation_bar.favourites\": \"Favourites\",\n  \"navigation_bar.filters\": \"Muted words\",\n  \"navigation_bar.follow_requests\": \"Follow requests\",\n  \"navigation_bar.follows_and_followers\": \"Follows and followers\",\n  \"navigation_bar.info\": \"About this server\",\n  \"navigation_bar.keyboard_shortcuts\": \"Hotkeys\",\n  \"navigation_bar.lists\": \"Lists\",\n  \"navigation_bar.logout\": \"Logout\",\n  \"navigation_bar.mutes\": \"Muted users\",\n  \"navigation_bar.personal\": \"Personal\",\n  \"navigation_bar.pins\": \"Pinned toots\",\n  \"navigation_bar.preferences\": \"Preferences\",\n  \"navigation_bar.profile_directory\": \"Profile directory\",\n  \"navigation_bar.public_timeline\": \"Federated timeline\",\n  \"navigation_bar.security\": \"Security\",\n  \"notification.favourite\": \"{name} favourited your status\",\n  \"notification.follow\": \"{name} followed you\",\n  \"notification.mention\": \"{name} mentioned you\",\n  \"notification.poll\": \"A poll you have voted in has ended\",\n  \"notification.reblog\": \"{name} boosted your status\",\n  \"notifications.clear\": \"Clear notifications\",\n  \"notifications.clear_confirmation\": \"Are you sure you want to permanently clear all your notifications?\",\n  \"notifications.column_settings.alert\": \"Desktop notifications\",\n  \"notifications.column_settings.favourite\": \"Favourites:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Display all categories\",\n  \"notifications.column_settings.filter_bar.category\": \"Quick filter bar\",\n  \"notifications.column_settings.filter_bar.show\": \"Show\",\n  \"notifications.column_settings.follow\": \"New followers:\",\n  \"notifications.column_settings.mention\": \"Mentions:\",\n  \"notifications.column_settings.poll\": \"Poll results:\",\n  \"notifications.column_settings.push\": \"Push notifications\",\n  \"notifications.column_settings.reblog\": \"Boosts:\",\n  \"notifications.column_settings.show\": \"Show in column\",\n  \"notifications.column_settings.sound\": \"Play sound\",\n  \"notifications.filter.all\": \"All\",\n  \"notifications.filter.boosts\": \"Boosts\",\n  \"notifications.filter.favourites\": \"Favourites\",\n  \"notifications.filter.follows\": \"Follows\",\n  \"notifications.filter.mentions\": \"Mentions\",\n  \"notifications.filter.polls\": \"Poll results\",\n  \"notifications.group\": \"{count} notifications\",\n  \"poll.closed\": \"Closed\",\n  \"poll.refresh\": \"Refresh\",\n  \"poll.total_votes\": \"{count, plural, one {# vote} other {# votes}}\",\n  \"poll.vote\": \"Vote\",\n  \"poll_button.add_poll\": \"Add a poll\",\n  \"poll_button.remove_poll\": \"Remove poll\",\n  \"privacy.change\": \"Adjust status privacy\",\n  \"privacy.direct.long\": \"Post to mentioned users only\",\n  \"privacy.direct.short\": \"Direct\",\n  \"privacy.private.long\": \"Post to followers only\",\n  \"privacy.private.short\": \"Followers-only\",\n  \"privacy.public.long\": \"Post to public timelines\",\n  \"privacy.public.short\": \"Public\",\n  \"privacy.unlisted.long\": \"Do not show in public timelines\",\n  \"privacy.unlisted.short\": \"Unlisted\",\n  \"regeneration_indicator.label\": \"Loading…\",\n  \"regeneration_indicator.sublabel\": \"Your home feed is being prepared!\",\n  \"relative_time.days\": \"{number}d\",\n  \"relative_time.hours\": \"{number}h\",\n  \"relative_time.just_now\": \"now\",\n  \"relative_time.minutes\": \"{number}m\",\n  \"relative_time.seconds\": \"{number}s\",\n  \"reply_indicator.cancel\": \"Cancel\",\n  \"report.forward\": \"Forward to {target}\",\n  \"report.forward_hint\": \"The account is from another server. Send an anonymized copy of the report there as well?\",\n  \"report.hint\": \"The report will be sent to your server moderators. You can provide an explanation of why you are reporting this account below:\",\n  \"report.placeholder\": \"Additional comments\",\n  \"report.submit\": \"Submit\",\n  \"report.target\": \"Report {target}\",\n  \"search.placeholder\": \"Search\",\n  \"search_popout.search_format\": \"Advanced search format\",\n  \"search_popout.tips.full_text\": \"Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.\",\n  \"search_popout.tips.hashtag\": \"hashtag\",\n  \"search_popout.tips.status\": \"status\",\n  \"search_popout.tips.text\": \"Simple text returns matching display names, usernames and hashtags\",\n  \"search_popout.tips.user\": \"user\",\n  \"search_results.accounts\": \"People\",\n  \"search_results.hashtags\": \"Hashtags\",\n  \"search_results.statuses\": \"Toots\",\n  \"search_results.total\": \"{count, number} {count, plural, one {result} other {results}}\",\n  \"status.admin_account\": \"Open moderation interface for @{name}\",\n  \"status.admin_status\": \"Open this status in the moderation interface\",\n  \"status.block\": \"Block @{name}\",\n  \"status.cancel_reblog_private\": \"Unboost\",\n  \"status.cannot_reblog\": \"This post cannot be boosted\",\n  \"status.copy\": \"Copy link to status\",\n  \"status.delete\": \"Delete\",\n  \"status.detailed_status\": \"Detailed conversation view\",\n  \"status.direct\": \"Direct message @{name}\",\n  \"status.embed\": \"Embed\",\n  \"status.favourite\": \"Favourite\",\n  \"status.filtered\": \"Filtered\",\n  \"status.load_more\": \"Load more\",\n  \"status.media_hidden\": \"Media hidden\",\n  \"status.mention\": \"Mention @{name}\",\n  \"status.more\": \"More\",\n  \"status.mute\": \"Mute @{name}\",\n  \"status.mute_conversation\": \"Mute conversation\",\n  \"status.open\": \"Expand this status\",\n  \"status.pin\": \"Pin on profile\",\n  \"status.pinned\": \"Pinned toot\",\n  \"status.read_more\": \"Read more\",\n  \"status.reblog\": \"Boost\",\n  \"status.reblog_private\": \"Boost to original audience\",\n  \"status.reblogged_by\": \"{name} boosted\",\n  \"status.reblogs.empty\": \"No one has boosted this toot yet. When someone does, they will show up here.\",\n  \"status.redraft\": \"Delete & re-draft\",\n  \"status.reply\": \"Reply\",\n  \"status.replyAll\": \"Reply to thread\",\n  \"status.report\": \"Report @{name}\",\n  \"status.sensitive_warning\": \"Sensitive content\",\n  \"status.share\": \"Share\",\n  \"status.show_less\": \"Show less\",\n  \"status.show_less_all\": \"Show less for all\",\n  \"status.show_more\": \"Show more\",\n  \"status.show_more_all\": \"Show more for all\",\n  \"status.show_thread\": \"Show thread\",\n  \"status.unmute_conversation\": \"Unmute conversation\",\n  \"status.unpin\": \"Unpin from profile\",\n  \"suggestions.dismiss\": \"Dismiss suggestion\",\n  \"suggestions.header\": \"You might be interested in…\",\n  \"tabs_bar.federated_timeline\": \"Federated\",\n  \"tabs_bar.home\": \"Home\",\n  \"tabs_bar.local_timeline\": \"Local\",\n  \"tabs_bar.notifications\": \"Notifications\",\n  \"tabs_bar.search\": \"Search\",\n  \"time_remaining.days\": \"{number, plural, one {# day} other {# days}} left\",\n  \"time_remaining.hours\": \"{number, plural, one {# hour} other {# hours}} left\",\n  \"time_remaining.minutes\": \"{number, plural, one {# minute} other {# minutes}} left\",\n  \"time_remaining.moments\": \"Moments remaining\",\n  \"time_remaining.seconds\": \"{number, plural, one {# second} other {# seconds}} left\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {person} other {people}} talking\",\n  \"ui.beforeunload\": \"Your draft will be lost if you leave Mastodon.\",\n  \"upload_area.title\": \"Drag & drop to upload\",\n  \"upload_button.label\": \"Add media (JPEG, PNG, GIF, WebM, MP4, MOV)\",\n  \"upload_error.limit\": \"File upload limit exceeded.\",\n  \"upload_error.poll\": \"File upload not allowed with polls.\",\n  \"upload_form.description\": \"Describe for the visually impaired\",\n  \"upload_form.focus\": \"Crop\",\n  \"upload_form.undo\": \"Delete\",\n  \"upload_progress.label\": \"Uploading...\",\n  \"video.close\": \"Close video\",\n  \"video.exit_fullscreen\": \"Exit full screen\",\n  \"video.expand\": \"Expand video\",\n  \"video.fullscreen\": \"Full screen\",\n  \"video.hide\": \"Hide video\",\n  \"video.mute\": \"Mute sound\",\n  \"video.pause\": \"Pause\",\n  \"video.play\": \"Play\",\n  \"video.unmute\": \"Unmute sound\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/hr.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Add or Remove from lists\",\n  \"account.badges.bot\": \"Bot\",\n  \"account.block\": \"Blokiraj @{name}\",\n  \"account.block_domain\": \"Sakrij sve sa {domain}\",\n  \"account.blocked\": \"Blocked\",\n  \"account.direct\": \"Direct Message @{name}\",\n  \"account.domain_blocked\": \"Domain hidden\",\n  \"account.edit_profile\": \"Uredi profil\",\n  \"account.endorse\": \"Feature on profile\",\n  \"account.follow\": \"Slijedi\",\n  \"account.followers\": \"Sljedbenici\",\n  \"account.followers.empty\": \"No one follows this user yet.\",\n  \"account.follows\": \"Slijedi\",\n  \"account.follows.empty\": \"This user doesn't follow anyone yet.\",\n  \"account.follows_you\": \"te slijedi\",\n  \"account.hide_reblogs\": \"Hide boosts from @{name}\",\n  \"account.link_verified_on\": \"Ownership of this link was checked on {date}\",\n  \"account.locked_info\": \"This account privacy status is set to locked. The owner manually reviews who can follow them.\",\n  \"account.media\": \"Media\",\n  \"account.mention\": \"Spomeni @{name}\",\n  \"account.moved_to\": \"{name} has moved to:\",\n  \"account.mute\": \"Utišaj @{name}\",\n  \"account.mute_notifications\": \"Mute notifications from @{name}\",\n  \"account.muted\": \"Muted\",\n  \"account.posts\": \"Postovi\",\n  \"account.posts_with_replies\": \"Toots with replies\",\n  \"account.report\": \"Prijavi @{name}\",\n  \"account.requested\": \"Čeka pristanak\",\n  \"account.share\": \"Share @{name}'s profile\",\n  \"account.show_reblogs\": \"Show boosts from @{name}\",\n  \"account.unblock\": \"Deblokiraj @{name}\",\n  \"account.unblock_domain\": \"Poništi sakrivanje {domain}\",\n  \"account.unendorse\": \"Don't feature on profile\",\n  \"account.unfollow\": \"Prestani slijediti\",\n  \"account.unmute\": \"Poništi utišavanje @{name}\",\n  \"account.unmute_notifications\": \"Unmute notifications from @{name}\",\n  \"alert.unexpected.message\": \"An unexpected error occurred.\",\n  \"alert.unexpected.title\": \"Oops!\",\n  \"boost_modal.combo\": \"Možeš pritisnuti {combo} kako bi ovo preskočio sljedeći put\",\n  \"bundle_column_error.body\": \"Something went wrong while loading this component.\",\n  \"bundle_column_error.retry\": \"Try again\",\n  \"bundle_column_error.title\": \"Network error\",\n  \"bundle_modal_error.close\": \"Close\",\n  \"bundle_modal_error.message\": \"Something went wrong while loading this component.\",\n  \"bundle_modal_error.retry\": \"Try again\",\n  \"column.blocks\": \"Blokirani korisnici\",\n  \"column.community\": \"Lokalni timeline\",\n  \"column.direct\": \"Direct messages\",\n  \"column.domain_blocks\": \"Hidden domains\",\n  \"column.favourites\": \"Favoriti\",\n  \"column.follow_requests\": \"Zahtjevi za slijeđenje\",\n  \"column.home\": \"Dom\",\n  \"column.lists\": \"Lists\",\n  \"column.mutes\": \"Utišani korisnici\",\n  \"column.notifications\": \"Notifikacije\",\n  \"column.pins\": \"Pinned toot\",\n  \"column.public\": \"Federalni timeline\",\n  \"column_back_button.label\": \"Natrag\",\n  \"column_header.hide_settings\": \"Hide settings\",\n  \"column_header.moveLeft_settings\": \"Move column to the left\",\n  \"column_header.moveRight_settings\": \"Move column to the right\",\n  \"column_header.pin\": \"Pin\",\n  \"column_header.show_settings\": \"Show settings\",\n  \"column_header.unpin\": \"Unpin\",\n  \"column_subheading.settings\": \"Postavke\",\n  \"community.column_settings.media_only\": \"Media Only\",\n  \"compose_form.direct_message_warning\": \"This toot will only be visible to all the mentioned users.\",\n  \"compose_form.direct_message_warning_learn_more\": \"Learn more\",\n  \"compose_form.hashtag_warning\": \"This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.\",\n  \"compose_form.lock_disclaimer\": \"Tvoj račun nije {locked}. Svatko te može slijediti kako bi vidio postove namijenjene samo tvojim sljedbenicima.\",\n  \"compose_form.lock_disclaimer.lock\": \"zaključan\",\n  \"compose_form.placeholder\": \"Što ti je na umu?\",\n  \"compose_form.poll.add_option\": \"Add a choice\",\n  \"compose_form.poll.duration\": \"Poll duration\",\n  \"compose_form.poll.option_placeholder\": \"Choice {number}\",\n  \"compose_form.poll.remove_option\": \"Remove this choice\",\n  \"compose_form.publish\": \"Toot\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"Mark media as sensitive\",\n  \"compose_form.sensitive.marked\": \"Media is marked as sensitive\",\n  \"compose_form.sensitive.unmarked\": \"Media is not marked as sensitive\",\n  \"compose_form.spoiler.marked\": \"Text is hidden behind warning\",\n  \"compose_form.spoiler.unmarked\": \"Text is not hidden\",\n  \"compose_form.spoiler_placeholder\": \"Upozorenje o sadržaju\",\n  \"confirmation_modal.cancel\": \"Otkaži\",\n  \"confirmations.block.block_and_report\": \"Block & Report\",\n  \"confirmations.block.confirm\": \"Blokiraj\",\n  \"confirmations.block.message\": \"Želiš li sigurno blokirati {name}?\",\n  \"confirmations.delete.confirm\": \"Obriši\",\n  \"confirmations.delete.message\": \"Želiš li stvarno obrisati ovaj status?\",\n  \"confirmations.delete_list.confirm\": \"Delete\",\n  \"confirmations.delete_list.message\": \"Are you sure you want to permanently delete this list?\",\n  \"confirmations.domain_block.confirm\": \"Sakrij cijelu domenu\",\n  \"confirmations.domain_block.message\": \"Jesi li zaista, zaista siguran da želiš potpuno blokirati {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.\",\n  \"confirmations.mute.confirm\": \"Utišaj\",\n  \"confirmations.mute.message\": \"Jesi li siguran da želiš utišati {name}?\",\n  \"confirmations.redraft.confirm\": \"Delete & redraft\",\n  \"confirmations.redraft.message\": \"Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.\",\n  \"confirmations.reply.confirm\": \"Reply\",\n  \"confirmations.reply.message\": \"Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?\",\n  \"confirmations.unfollow.confirm\": \"Unfollow\",\n  \"confirmations.unfollow.message\": \"Are you sure you want to unfollow {name}?\",\n  \"embed.instructions\": \"Embed this status on your website by copying the code below.\",\n  \"embed.preview\": \"Here is what it will look like:\",\n  \"emoji_button.activity\": \"Aktivnost\",\n  \"emoji_button.custom\": \"Custom\",\n  \"emoji_button.flags\": \"Zastave\",\n  \"emoji_button.food\": \"Hrana & Piće\",\n  \"emoji_button.label\": \"Umetni smajlije\",\n  \"emoji_button.nature\": \"Priroda\",\n  \"emoji_button.not_found\": \"No emojos!! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"Objekti\",\n  \"emoji_button.people\": \"Ljudi\",\n  \"emoji_button.recent\": \"Frequently used\",\n  \"emoji_button.search\": \"Traži...\",\n  \"emoji_button.search_results\": \"Search results\",\n  \"emoji_button.symbols\": \"Simboli\",\n  \"emoji_button.travel\": \"Putovanja & Mjesta\",\n  \"empty_column.account_timeline\": \"No toots here!\",\n  \"empty_column.account_unavailable\": \"Profile unavailable\",\n  \"empty_column.blocks\": \"You haven't blocked any users yet.\",\n  \"empty_column.community\": \"Lokalni timeline je prazan. Napiši nešto javno kako bi pokrenuo stvari!\",\n  \"empty_column.direct\": \"You don't have any direct messages yet. When you send or receive one, it will show up here.\",\n  \"empty_column.domain_blocks\": \"There are no hidden domains yet.\",\n  \"empty_column.favourited_statuses\": \"You don't have any favourite toots yet. When you favourite one, it will show up here.\",\n  \"empty_column.favourites\": \"No one has favourited this toot yet. When someone does, they will show up here.\",\n  \"empty_column.follow_requests\": \"You don't have any follow requests yet. When you receive one, it will show up here.\",\n  \"empty_column.hashtag\": \"Još ne postoji ništa s ovim hashtagom.\",\n  \"empty_column.home\": \"Još ne slijediš nikoga. Posjeti {public} ili koristi tražilicu kako bi počeo i upoznao druge korisnike.\",\n  \"empty_column.home.public_timeline\": \"javni timeline\",\n  \"empty_column.list\": \"There is nothing in this list yet.\",\n  \"empty_column.lists\": \"You don't have any lists yet. When you create one, it will show up here.\",\n  \"empty_column.mutes\": \"You haven't muted any users yet.\",\n  \"empty_column.notifications\": \"Još nemaš notifikacija. Komuniciraj sa drugima kako bi započeo razgovor.\",\n  \"empty_column.public\": \"Ovdje nema ništa! Napiši nešto javno, ili ručno slijedi korisnike sa drugih instanci kako bi popunio\",\n  \"follow_request.authorize\": \"Autoriziraj\",\n  \"follow_request.reject\": \"Odbij\",\n  \"getting_started.developers\": \"Developers\",\n  \"getting_started.directory\": \"Profile directory\",\n  \"getting_started.documentation\": \"Documentation\",\n  \"getting_started.heading\": \"Počnimo\",\n  \"getting_started.invite\": \"Invite people\",\n  \"getting_started.open_source_notice\": \"Mastodon je softver otvorenog koda. Možeš pridonijeti ili prijaviti probleme na GitHubu  {github}.\",\n  \"getting_started.security\": \"Security\",\n  \"getting_started.terms\": \"Terms of service\",\n  \"hashtag.column_header.tag_mode.all\": \"and {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"or {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"without {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"No suggestions found\",\n  \"hashtag.column_settings.select.placeholder\": \"Enter hashtags…\",\n  \"hashtag.column_settings.tag_mode.all\": \"All of these\",\n  \"hashtag.column_settings.tag_mode.any\": \"Any of these\",\n  \"hashtag.column_settings.tag_mode.none\": \"None of these\",\n  \"hashtag.column_settings.tag_toggle\": \"Include additional tags in this column\",\n  \"home.column_settings.basic\": \"Osnovno\",\n  \"home.column_settings.show_reblogs\": \"Pokaži boostove\",\n  \"home.column_settings.show_replies\": \"Pokaži odgovore\",\n  \"intervals.full.days\": \"{number, plural, one {# day} other {# days}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# hour} other {# hours}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minute} other {# minutes}}\",\n  \"introduction.federation.action\": \"Next\",\n  \"introduction.federation.federated.headline\": \"Federated\",\n  \"introduction.federation.federated.text\": \"Public posts from other servers of the fediverse will appear in the federated timeline.\",\n  \"introduction.federation.home.headline\": \"Home\",\n  \"introduction.federation.home.text\": \"Posts from people you follow will appear in your home feed. You can follow anyone on any server!\",\n  \"introduction.federation.local.headline\": \"Local\",\n  \"introduction.federation.local.text\": \"Public posts from people on the same server as you will appear in the local timeline.\",\n  \"introduction.interactions.action\": \"Finish toot-orial!\",\n  \"introduction.interactions.favourite.headline\": \"Favourite\",\n  \"introduction.interactions.favourite.text\": \"You can save a toot for later, and let the author know that you liked it, by favouriting it.\",\n  \"introduction.interactions.reblog.headline\": \"Boost\",\n  \"introduction.interactions.reblog.text\": \"You can share other people's toots with your followers by boosting them.\",\n  \"introduction.interactions.reply.headline\": \"Reply\",\n  \"introduction.interactions.reply.text\": \"You can reply to other people's and your own toots, which will chain them together in a conversation.\",\n  \"introduction.welcome.action\": \"Let's go!\",\n  \"introduction.welcome.headline\": \"First steps\",\n  \"introduction.welcome.text\": \"Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.\",\n  \"keyboard_shortcuts.back\": \"to navigate back\",\n  \"keyboard_shortcuts.blocked\": \"to open blocked users list\",\n  \"keyboard_shortcuts.boost\": \"to boost\",\n  \"keyboard_shortcuts.column\": \"to focus a status in one of the columns\",\n  \"keyboard_shortcuts.compose\": \"to focus the compose textarea\",\n  \"keyboard_shortcuts.description\": \"Description\",\n  \"keyboard_shortcuts.direct\": \"to open direct messages column\",\n  \"keyboard_shortcuts.down\": \"to move down in the list\",\n  \"keyboard_shortcuts.enter\": \"to open status\",\n  \"keyboard_shortcuts.favourite\": \"to favourite\",\n  \"keyboard_shortcuts.favourites\": \"to open favourites list\",\n  \"keyboard_shortcuts.federated\": \"to open federated timeline\",\n  \"keyboard_shortcuts.heading\": \"Keyboard Shortcuts\",\n  \"keyboard_shortcuts.home\": \"to open home timeline\",\n  \"keyboard_shortcuts.hotkey\": \"Hotkey\",\n  \"keyboard_shortcuts.legend\": \"to display this legend\",\n  \"keyboard_shortcuts.local\": \"to open local timeline\",\n  \"keyboard_shortcuts.mention\": \"to mention author\",\n  \"keyboard_shortcuts.muted\": \"to open muted users list\",\n  \"keyboard_shortcuts.my_profile\": \"to open your profile\",\n  \"keyboard_shortcuts.notifications\": \"to open notifications column\",\n  \"keyboard_shortcuts.pinned\": \"to open pinned toots list\",\n  \"keyboard_shortcuts.profile\": \"to open author's profile\",\n  \"keyboard_shortcuts.reply\": \"to reply\",\n  \"keyboard_shortcuts.requests\": \"to open follow requests list\",\n  \"keyboard_shortcuts.search\": \"to focus search\",\n  \"keyboard_shortcuts.start\": \"to open \\\"get started\\\" column\",\n  \"keyboard_shortcuts.toggle_hidden\": \"to show/hide text behind CW\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"to show/hide media\",\n  \"keyboard_shortcuts.toot\": \"to start a brand new toot\",\n  \"keyboard_shortcuts.unfocus\": \"to un-focus compose textarea/search\",\n  \"keyboard_shortcuts.up\": \"to move up in the list\",\n  \"lightbox.close\": \"Zatvori\",\n  \"lightbox.next\": \"Next\",\n  \"lightbox.previous\": \"Previous\",\n  \"lightbox.view_context\": \"View context\",\n  \"lists.account.add\": \"Add to list\",\n  \"lists.account.remove\": \"Remove from list\",\n  \"lists.delete\": \"Delete list\",\n  \"lists.edit\": \"Edit list\",\n  \"lists.edit.submit\": \"Change title\",\n  \"lists.new.create\": \"Add list\",\n  \"lists.new.title_placeholder\": \"New list title\",\n  \"lists.search\": \"Search among people you follow\",\n  \"lists.subheading\": \"Your lists\",\n  \"loading_indicator.label\": \"Učitavam...\",\n  \"media_gallery.toggle_visible\": \"Preklopi vidljivost\",\n  \"missing_indicator.label\": \"Nije nađen\",\n  \"missing_indicator.sublabel\": \"This resource could not be found\",\n  \"mute_modal.hide_notifications\": \"Hide notifications from this user?\",\n  \"navigation_bar.apps\": \"Mobile apps\",\n  \"navigation_bar.blocks\": \"Blokirani korisnici\",\n  \"navigation_bar.community_timeline\": \"Lokalni timeline\",\n  \"navigation_bar.compose\": \"Compose new toot\",\n  \"navigation_bar.direct\": \"Direct messages\",\n  \"navigation_bar.discover\": \"Discover\",\n  \"navigation_bar.domain_blocks\": \"Hidden domains\",\n  \"navigation_bar.edit_profile\": \"Uredi profil\",\n  \"navigation_bar.favourites\": \"Favoriti\",\n  \"navigation_bar.filters\": \"Muted words\",\n  \"navigation_bar.follow_requests\": \"Zahtjevi za slijeđenje\",\n  \"navigation_bar.follows_and_followers\": \"Follows and followers\",\n  \"navigation_bar.info\": \"Više informacija\",\n  \"navigation_bar.keyboard_shortcuts\": \"Keyboard shortcuts\",\n  \"navigation_bar.lists\": \"Lists\",\n  \"navigation_bar.logout\": \"Odjavi se\",\n  \"navigation_bar.mutes\": \"Utišani korisnici\",\n  \"navigation_bar.personal\": \"Personal\",\n  \"navigation_bar.pins\": \"Pinned toots\",\n  \"navigation_bar.preferences\": \"Postavke\",\n  \"navigation_bar.profile_directory\": \"Profile directory\",\n  \"navigation_bar.public_timeline\": \"Federalni timeline\",\n  \"navigation_bar.security\": \"Security\",\n  \"notification.favourite\": \"{name} je lajkao tvoj status\",\n  \"notification.follow\": \"{name} te sada slijedi\",\n  \"notification.mention\": \"{name} te je spomenuo\",\n  \"notification.poll\": \"A poll you have voted in has ended\",\n  \"notification.reblog\": \"{name} je podigao tvoj status\",\n  \"notifications.clear\": \"Očisti notifikacije\",\n  \"notifications.clear_confirmation\": \"Želiš li zaista obrisati sve svoje notifikacije?\",\n  \"notifications.column_settings.alert\": \"Desktop notifikacije\",\n  \"notifications.column_settings.favourite\": \"Favoriti:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Display all categories\",\n  \"notifications.column_settings.filter_bar.category\": \"Quick filter bar\",\n  \"notifications.column_settings.filter_bar.show\": \"Show\",\n  \"notifications.column_settings.follow\": \"Novi sljedbenici:\",\n  \"notifications.column_settings.mention\": \"Spominjanja:\",\n  \"notifications.column_settings.poll\": \"Poll results:\",\n  \"notifications.column_settings.push\": \"Push notifications\",\n  \"notifications.column_settings.reblog\": \"Boostovi:\",\n  \"notifications.column_settings.show\": \"Prikaži u stupcu\",\n  \"notifications.column_settings.sound\": \"Sviraj zvuk\",\n  \"notifications.filter.all\": \"All\",\n  \"notifications.filter.boosts\": \"Boosts\",\n  \"notifications.filter.favourites\": \"Favourites\",\n  \"notifications.filter.follows\": \"Follows\",\n  \"notifications.filter.mentions\": \"Mentions\",\n  \"notifications.filter.polls\": \"Poll results\",\n  \"notifications.group\": \"{count} notifications\",\n  \"poll.closed\": \"Closed\",\n  \"poll.refresh\": \"Refresh\",\n  \"poll.total_votes\": \"{count, plural, one {# vote} other {# votes}}\",\n  \"poll.vote\": \"Vote\",\n  \"poll_button.add_poll\": \"Add a poll\",\n  \"poll_button.remove_poll\": \"Remove poll\",\n  \"privacy.change\": \"Podesi status privatnosti\",\n  \"privacy.direct.long\": \"Prikaži samo spomenutim korisnicima\",\n  \"privacy.direct.short\": \"Direktno\",\n  \"privacy.private.long\": \"Prikaži samo sljedbenicima\",\n  \"privacy.private.short\": \"Privatno\",\n  \"privacy.public.long\": \"Postaj na javne timeline\",\n  \"privacy.public.short\": \"Javno\",\n  \"privacy.unlisted.long\": \"Ne prikazuj u javnim timelineovima\",\n  \"privacy.unlisted.short\": \"Unlisted\",\n  \"regeneration_indicator.label\": \"Loading…\",\n  \"regeneration_indicator.sublabel\": \"Your home feed is being prepared!\",\n  \"relative_time.days\": \"{number}d\",\n  \"relative_time.hours\": \"{number}h\",\n  \"relative_time.just_now\": \"now\",\n  \"relative_time.minutes\": \"{number}m\",\n  \"relative_time.seconds\": \"{number}s\",\n  \"reply_indicator.cancel\": \"Otkaži\",\n  \"report.forward\": \"Forward to {target}\",\n  \"report.forward_hint\": \"The account is from another server. Send an anonymized copy of the report there as well?\",\n  \"report.hint\": \"The report will be sent to your instance moderators. You can provide an explanation of why you are reporting this account below:\",\n  \"report.placeholder\": \"Dodatni komentari\",\n  \"report.submit\": \"Pošalji\",\n  \"report.target\": \"Prijavljivanje\",\n  \"search.placeholder\": \"Traži\",\n  \"search_popout.search_format\": \"Advanced search format\",\n  \"search_popout.tips.full_text\": \"Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.\",\n  \"search_popout.tips.hashtag\": \"hashtag\",\n  \"search_popout.tips.status\": \"status\",\n  \"search_popout.tips.text\": \"Simple text returns matching display names, usernames and hashtags\",\n  \"search_popout.tips.user\": \"user\",\n  \"search_results.accounts\": \"People\",\n  \"search_results.hashtags\": \"Hashtags\",\n  \"search_results.statuses\": \"Toots\",\n  \"search_results.total\": \"{count, number} {count, plural, one {result} other {results}}\",\n  \"status.admin_account\": \"Open moderation interface for @{name}\",\n  \"status.admin_status\": \"Open this status in the moderation interface\",\n  \"status.block\": \"Block @{name}\",\n  \"status.cancel_reblog_private\": \"Unboost\",\n  \"status.cannot_reblog\": \"Ovaj post ne može biti boostan\",\n  \"status.copy\": \"Copy link to status\",\n  \"status.delete\": \"Obriši\",\n  \"status.detailed_status\": \"Detailed conversation view\",\n  \"status.direct\": \"Direct message @{name}\",\n  \"status.embed\": \"Embed\",\n  \"status.favourite\": \"Označi omiljenim\",\n  \"status.filtered\": \"Filtered\",\n  \"status.load_more\": \"Učitaj više\",\n  \"status.media_hidden\": \"Sakriven media sadržaj\",\n  \"status.mention\": \"Spomeni @{name}\",\n  \"status.more\": \"More\",\n  \"status.mute\": \"Mute @{name}\",\n  \"status.mute_conversation\": \"Utišaj razgovor\",\n  \"status.open\": \"Proširi ovaj status\",\n  \"status.pin\": \"Pin on profile\",\n  \"status.pinned\": \"Pinned toot\",\n  \"status.read_more\": \"Read more\",\n  \"status.reblog\": \"Podigni\",\n  \"status.reblog_private\": \"Boost to original audience\",\n  \"status.reblogged_by\": \"{name} je podigao\",\n  \"status.reblogs.empty\": \"No one has boosted this toot yet. When someone does, they will show up here.\",\n  \"status.redraft\": \"Delete & re-draft\",\n  \"status.reply\": \"Odgovori\",\n  \"status.replyAll\": \"Odgovori na temu\",\n  \"status.report\": \"Prijavi @{name}\",\n  \"status.sensitive_warning\": \"Osjetljiv sadržaj\",\n  \"status.share\": \"Share\",\n  \"status.show_less\": \"Pokaži manje\",\n  \"status.show_less_all\": \"Show less for all\",\n  \"status.show_more\": \"Pokaži više\",\n  \"status.show_more_all\": \"Show more for all\",\n  \"status.show_thread\": \"Show thread\",\n  \"status.unmute_conversation\": \"Poništi utišavanje razgovora\",\n  \"status.unpin\": \"Unpin from profile\",\n  \"suggestions.dismiss\": \"Dismiss suggestion\",\n  \"suggestions.header\": \"You might be interested in…\",\n  \"tabs_bar.federated_timeline\": \"Federalni\",\n  \"tabs_bar.home\": \"Dom\",\n  \"tabs_bar.local_timeline\": \"Lokalno\",\n  \"tabs_bar.notifications\": \"Notifikacije\",\n  \"tabs_bar.search\": \"Search\",\n  \"time_remaining.days\": \"{number, plural, one {# day} other {# days}} left\",\n  \"time_remaining.hours\": \"{number, plural, one {# hour} other {# hours}} left\",\n  \"time_remaining.minutes\": \"{number, plural, one {# minute} other {# minutes}} left\",\n  \"time_remaining.moments\": \"Moments remaining\",\n  \"time_remaining.seconds\": \"{number, plural, one {# second} other {# seconds}} left\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {person} other {people}} talking\",\n  \"ui.beforeunload\": \"Your draft will be lost if you leave Mastodon.\",\n  \"upload_area.title\": \"Povuci i spusti kako bi uploadao\",\n  \"upload_button.label\": \"Dodaj media\",\n  \"upload_error.limit\": \"File upload limit exceeded.\",\n  \"upload_error.poll\": \"File upload not allowed with polls.\",\n  \"upload_form.description\": \"Describe for the visually impaired\",\n  \"upload_form.focus\": \"Crop\",\n  \"upload_form.undo\": \"Poništi\",\n  \"upload_progress.label\": \"Uploadam...\",\n  \"video.close\": \"Close video\",\n  \"video.exit_fullscreen\": \"Exit full screen\",\n  \"video.expand\": \"Expand video\",\n  \"video.fullscreen\": \"Full screen\",\n  \"video.hide\": \"Hide video\",\n  \"video.mute\": \"Mute sound\",\n  \"video.pause\": \"Pause\",\n  \"video.play\": \"Play\",\n  \"video.unmute\": \"Unmute sound\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/hu.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Add or Remove from lists\",\n  \"account.badges.bot\": \"Bot\",\n  \"account.block\": \"@{name} letiltása\",\n  \"account.block_domain\": \"Minden elrejtése innen: {domain}\",\n  \"account.blocked\": \"Blocked\",\n  \"account.direct\": \"Direct Message @{name}\",\n  \"account.domain_blocked\": \"Domain hidden\",\n  \"account.edit_profile\": \"Profil szerkesztése\",\n  \"account.endorse\": \"Feature on profile\",\n  \"account.follow\": \"Követés\",\n  \"account.followers\": \"Követők\",\n  \"account.followers.empty\": \"No one follows this user yet.\",\n  \"account.follows\": \"Követve\",\n  \"account.follows.empty\": \"This user doesn't follow anyone yet.\",\n  \"account.follows_you\": \"Követnek téged\",\n  \"account.hide_reblogs\": \"Rejtsd el a tülkölést @{name}-tól/től\",\n  \"account.link_verified_on\": \"Ownership of this link was checked on {date}\",\n  \"account.locked_info\": \"This account privacy status is set to locked. The owner manually reviews who can follow them.\",\n  \"account.media\": \"Média\",\n  \"account.mention\": \"@{name} említése\",\n  \"account.moved_to\": \"{name} átköltözött:\",\n  \"account.mute\": \"@{name} némítása\",\n  \"account.mute_notifications\": \"@{name} értesítések némítása\",\n  \"account.muted\": \"Muted\",\n  \"account.posts\": \"Státuszok\",\n  \"account.posts_with_replies\": \"Toots with replies\",\n  \"account.report\": \"@{name} jelentése\",\n  \"account.requested\": \"Engedélyre vár. Kattintson a követési kérés visszavonására\",\n  \"account.share\": \"@{name} profiljának megosztása\",\n  \"account.show_reblogs\": \"@{name} kedvenceinek mutatása\",\n  \"account.unblock\": \"@{name} kiblokkolása\",\n  \"account.unblock_domain\": \"{domain} mutatása\",\n  \"account.unendorse\": \"Don't feature on profile\",\n  \"account.unfollow\": \"Követés abbahagyása\",\n  \"account.unmute\": \"@{name} kinémítása\",\n  \"account.unmute_notifications\": \"@{name} értesítéseinek kinémítása\",\n  \"alert.unexpected.message\": \"An unexpected error occurred.\",\n  \"alert.unexpected.title\": \"Oops!\",\n  \"boost_modal.combo\": \"Megnyomhatod {combo}, hogy átugord következő alkalommal\",\n  \"bundle_column_error.body\": \"Hiba történt a komponens betöltése közben.\",\n  \"bundle_column_error.retry\": \"Próbálja újra\",\n  \"bundle_column_error.title\": \"Hálózati hiba\",\n  \"bundle_modal_error.close\": \"Bezár\",\n  \"bundle_modal_error.message\": \"Hiba történt a komponens betöltésekor.\",\n  \"bundle_modal_error.retry\": \"Próbálja újra\",\n  \"column.blocks\": \"Letiltott felhasználók\",\n  \"column.community\": \"Helyi idővonal\",\n  \"column.direct\": \"Direct messages\",\n  \"column.domain_blocks\": \"Hidden domains\",\n  \"column.favourites\": \"Kedvencek\",\n  \"column.follow_requests\": \"Követési kérések\",\n  \"column.home\": \"Kezdőlap\",\n  \"column.lists\": \"Listák\",\n  \"column.mutes\": \"Némított felhasználók\",\n  \"column.notifications\": \"Értesítések\",\n  \"column.pins\": \"Kitűzött tülkölések\",\n  \"column.public\": \"Nyilvános idővonal\",\n  \"column_back_button.label\": \"Vissza\",\n  \"column_header.hide_settings\": \"Beállítások elrejtése\",\n  \"column_header.moveLeft_settings\": \"Oszlop elmozdítása balra\",\n  \"column_header.moveRight_settings\": \"oszlop elmozdítása jobbra\",\n  \"column_header.pin\": \"Kitűz\",\n  \"column_header.show_settings\": \"Beállítások mutatása\",\n  \"column_header.unpin\": \"Kitűzés eltávolítása\",\n  \"column_subheading.settings\": \"Beállítások\",\n  \"community.column_settings.media_only\": \"Media Only\",\n  \"compose_form.direct_message_warning\": \"This toot will only be visible to all the mentioned users.\",\n  \"compose_form.direct_message_warning_learn_more\": \"Learn more\",\n  \"compose_form.hashtag_warning\": \"Ezen tülkölés nem fog megjelenni semmilyen hashtag alatt mivel listázatlan. Csak a publikus tülkölések kereshetőek hashtag-el.\",\n  \"compose_form.lock_disclaimer\": \"Az ön fiókja nincs {locked}. Bárki követni tud, hogy megtekintse a kizárt követőknek szánt üzeneteid.\",\n  \"compose_form.lock_disclaimer.lock\": \"lezárva\",\n  \"compose_form.placeholder\": \"Mire gondolsz?\",\n  \"compose_form.poll.add_option\": \"Add a choice\",\n  \"compose_form.poll.duration\": \"Poll duration\",\n  \"compose_form.poll.option_placeholder\": \"Choice {number}\",\n  \"compose_form.poll.remove_option\": \"Remove this choice\",\n  \"compose_form.publish\": \"Tülk\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"Mark media as sensitive\",\n  \"compose_form.sensitive.marked\": \"Media is marked as sensitive\",\n  \"compose_form.sensitive.unmarked\": \"Media is not marked as sensitive\",\n  \"compose_form.spoiler.marked\": \"Text is hidden behind warning\",\n  \"compose_form.spoiler.unmarked\": \"Text is not hidden\",\n  \"compose_form.spoiler_placeholder\": \"Figyelmeztetését írja ide\",\n  \"confirmation_modal.cancel\": \"Bezár\",\n  \"confirmations.block.block_and_report\": \"Block & Report\",\n  \"confirmations.block.confirm\": \"Letilt\",\n  \"confirmations.block.message\": \"Biztos benne, hogy le szeretné tiltani {name}?\",\n  \"confirmations.delete.confirm\": \"Töröl\",\n  \"confirmations.delete.message\": \"Biztos benne, hogy törölni szeretné ezt a státuszt?\",\n  \"confirmations.delete_list.confirm\": \"Töröl\",\n  \"confirmations.delete_list.message\": \"Biztos benne, hogy véglegesen törölni szeretné ezt a listát?\",\n  \"confirmations.domain_block.confirm\": \"Egész domain elrejtése\",\n  \"confirmations.domain_block.message\": \"Nagyon biztos abban, hogy le szeretné tiltani az egész {domain}-t? A legtöbb esetben néhány célszerű tiltás vagy némítás elegendő és kívánatosabb megoldás.\",\n  \"confirmations.mute.confirm\": \"Némít\",\n  \"confirmations.mute.message\": \"Biztos benne, hogy némítani szeretné {name}?\",\n  \"confirmations.redraft.confirm\": \"Delete & redraft\",\n  \"confirmations.redraft.message\": \"Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.\",\n  \"confirmations.reply.confirm\": \"Reply\",\n  \"confirmations.reply.message\": \"Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?\",\n  \"confirmations.unfollow.confirm\": \"Követés visszavonása\",\n  \"confirmations.unfollow.message\": \"Biztos benne, hogy vissza szeretné vonni {name} követését?\",\n  \"embed.instructions\": \"Ágyazza be ezen státuszt weboldalába az alábbi kód másolásával.\",\n  \"embed.preview\": \"Így fog kinézni:\",\n  \"emoji_button.activity\": \"Aktivitás\",\n  \"emoji_button.custom\": \"Egyéni\",\n  \"emoji_button.flags\": \"Zászlók\",\n  \"emoji_button.food\": \"Étel és Ital\",\n  \"emoji_button.label\": \"Emoji beszúrása\",\n  \"emoji_button.nature\": \"Természet\",\n  \"emoji_button.not_found\": \"Nincsenek emojok!! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"Tárgyak\",\n  \"emoji_button.people\": \"Emberek\",\n  \"emoji_button.recent\": \"Gyakran használt\",\n  \"emoji_button.search\": \"Keresés...\",\n  \"emoji_button.search_results\": \"Keresési találatok\",\n  \"emoji_button.symbols\": \"Szimbólumok\",\n  \"emoji_button.travel\": \"Utazás és Helyek\",\n  \"empty_column.account_timeline\": \"No toots here!\",\n  \"empty_column.account_unavailable\": \"Profile unavailable\",\n  \"empty_column.blocks\": \"You haven't blocked any users yet.\",\n  \"empty_column.community\": \"A helyi idővonal üres. Írj egy publikus stástuszt, hogy elindítsd a labdát!\",\n  \"empty_column.direct\": \"You don't have any direct messages yet. When you send or receive one, it will show up here.\",\n  \"empty_column.domain_blocks\": \"There are no hidden domains yet.\",\n  \"empty_column.favourited_statuses\": \"You don't have any favourite toots yet. When you favourite one, it will show up here.\",\n  \"empty_column.favourites\": \"No one has favourited this toot yet. When someone does, they will show up here.\",\n  \"empty_column.follow_requests\": \"You don't have any follow requests yet. When you receive one, it will show up here.\",\n  \"empty_column.hashtag\": \"Jelenleg nem található semmi ezen hashtaggel.\",\n  \"empty_column.home\": \"A hazai idővonala üres! Látogasd meg a {public} vagy használd a keresőt, hogy ismerj meg más felhasználókat.\",\n  \"empty_column.home.public_timeline\": \"publikus idővonal\",\n  \"empty_column.list\": \"A lista jelenleg üres. Mikor a listatagok új státuszt posztolnak itt meg fognak jelenni.\",\n  \"empty_column.lists\": \"You don't have any lists yet. When you create one, it will show up here.\",\n  \"empty_column.mutes\": \"You haven't muted any users yet.\",\n  \"empty_column.notifications\": \"Jelenleg nincsenek értesítései. Lépj kapcsolatba másokkal, hogy indítsd el a beszélgetést.\",\n  \"empty_column.public\": \"Jelenleg semmi nincs itt! Írj valamit publikusan vagy kövess más szervereken levő felhasználókat, hogy megtöltsd\",\n  \"follow_request.authorize\": \"Engedélyez\",\n  \"follow_request.reject\": \"Visszautasít\",\n  \"getting_started.developers\": \"Developers\",\n  \"getting_started.directory\": \"Profile directory\",\n  \"getting_started.documentation\": \"Documentation\",\n  \"getting_started.heading\": \"Első lépések\",\n  \"getting_started.invite\": \"Invite people\",\n  \"getting_started.open_source_notice\": \"Mastodon egy nyílt forráskódú szoftver. Hozzájárulás vagy problémák jelentése a GitHub-on {github}.\",\n  \"getting_started.security\": \"Security\",\n  \"getting_started.terms\": \"Terms of service\",\n  \"hashtag.column_header.tag_mode.all\": \"and {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"or {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"without {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"No suggestions found\",\n  \"hashtag.column_settings.select.placeholder\": \"Enter hashtags…\",\n  \"hashtag.column_settings.tag_mode.all\": \"All of these\",\n  \"hashtag.column_settings.tag_mode.any\": \"Any of these\",\n  \"hashtag.column_settings.tag_mode.none\": \"None of these\",\n  \"hashtag.column_settings.tag_toggle\": \"Include additional tags in this column\",\n  \"home.column_settings.basic\": \"Alap\",\n  \"home.column_settings.show_reblogs\": \"Ismétlések mutatása\",\n  \"home.column_settings.show_replies\": \"Válaszok mutatása\",\n  \"intervals.full.days\": \"{number, plural, one {# day} other {# days}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# hour} other {# hours}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minute} other {# minutes}}\",\n  \"introduction.federation.action\": \"Next\",\n  \"introduction.federation.federated.headline\": \"Federated\",\n  \"introduction.federation.federated.text\": \"Public posts from other servers of the fediverse will appear in the federated timeline.\",\n  \"introduction.federation.home.headline\": \"Home\",\n  \"introduction.federation.home.text\": \"Posts from people you follow will appear in your home feed. You can follow anyone on any server!\",\n  \"introduction.federation.local.headline\": \"Local\",\n  \"introduction.federation.local.text\": \"Public posts from people on the same server as you will appear in the local timeline.\",\n  \"introduction.interactions.action\": \"Finish toot-orial!\",\n  \"introduction.interactions.favourite.headline\": \"Favourite\",\n  \"introduction.interactions.favourite.text\": \"You can save a toot for later, and let the author know that you liked it, by favouriting it.\",\n  \"introduction.interactions.reblog.headline\": \"Boost\",\n  \"introduction.interactions.reblog.text\": \"You can share other people's toots with your followers by boosting them.\",\n  \"introduction.interactions.reply.headline\": \"Reply\",\n  \"introduction.interactions.reply.text\": \"You can reply to other people's and your own toots, which will chain them together in a conversation.\",\n  \"introduction.welcome.action\": \"Let's go!\",\n  \"introduction.welcome.headline\": \"First steps\",\n  \"introduction.welcome.text\": \"Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.\",\n  \"keyboard_shortcuts.back\": \"vissza navigálás\",\n  \"keyboard_shortcuts.blocked\": \"to open blocked users list\",\n  \"keyboard_shortcuts.boost\": \"ismétlés\",\n  \"keyboard_shortcuts.column\": \"összpontosítson egy státuszra az egyik oszlopban\",\n  \"keyboard_shortcuts.compose\": \"fókuszálja a szerkesztési szövegdobozt\",\n  \"keyboard_shortcuts.description\": \"Leírás\",\n  \"keyboard_shortcuts.direct\": \"to open direct messages column\",\n  \"keyboard_shortcuts.down\": \"lefele navigálás a listában\",\n  \"keyboard_shortcuts.enter\": \"státusz megnyitása\",\n  \"keyboard_shortcuts.favourite\": \"kedvenccé tétel\",\n  \"keyboard_shortcuts.favourites\": \"to open favourites list\",\n  \"keyboard_shortcuts.federated\": \"to open federated timeline\",\n  \"keyboard_shortcuts.heading\": \"Billentyű rövidítések\",\n  \"keyboard_shortcuts.home\": \"to open home timeline\",\n  \"keyboard_shortcuts.hotkey\": \"Gyorsbillentyű\",\n  \"keyboard_shortcuts.legend\": \"jelmagyarázat megjelenítése\",\n  \"keyboard_shortcuts.local\": \"to open local timeline\",\n  \"keyboard_shortcuts.mention\": \"szerző megjelenítése\",\n  \"keyboard_shortcuts.muted\": \"to open muted users list\",\n  \"keyboard_shortcuts.my_profile\": \"to open your profile\",\n  \"keyboard_shortcuts.notifications\": \"to open notifications column\",\n  \"keyboard_shortcuts.pinned\": \"to open pinned toots list\",\n  \"keyboard_shortcuts.profile\": \"to open author's profile\",\n  \"keyboard_shortcuts.reply\": \"válaszolás\",\n  \"keyboard_shortcuts.requests\": \"to open follow requests list\",\n  \"keyboard_shortcuts.search\": \"kereső kiemelése\",\n  \"keyboard_shortcuts.start\": \"to open \\\"get started\\\" column\",\n  \"keyboard_shortcuts.toggle_hidden\": \"to show/hide text behind CW\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"to show/hide media\",\n  \"keyboard_shortcuts.toot\": \"új tülk megkezdése\",\n  \"keyboard_shortcuts.unfocus\": \"tülk szerkesztés/keresés fókuszpontból való kivétele\",\n  \"keyboard_shortcuts.up\": \"fennebb helyezés a listában\",\n  \"lightbox.close\": \"Bezárás\",\n  \"lightbox.next\": \"Következő\",\n  \"lightbox.previous\": \"Előző\",\n  \"lightbox.view_context\": \"View context\",\n  \"lists.account.add\": \"Hozzáadás a listához\",\n  \"lists.account.remove\": \"Eltávolít a listából\",\n  \"lists.delete\": \"Lista törlése\",\n  \"lists.edit\": \"Lista szerkesztése\",\n  \"lists.edit.submit\": \"Change title\",\n  \"lists.new.create\": \"Lista hozzáadása\",\n  \"lists.new.title_placeholder\": \"Új lista cím\",\n  \"lists.search\": \"Keresés a követtett személyek között\",\n  \"lists.subheading\": \"Listáid\",\n  \"loading_indicator.label\": \"Betöltés...\",\n  \"media_gallery.toggle_visible\": \"Láthatóság váltása\",\n  \"missing_indicator.label\": \"Nincs találat\",\n  \"missing_indicator.sublabel\": \"Ezen forrás nem található\",\n  \"mute_modal.hide_notifications\": \"Értesítések elrejtése ezen felhasználótól?\",\n  \"navigation_bar.apps\": \"Mobile apps\",\n  \"navigation_bar.blocks\": \"Tiltott felhasználók\",\n  \"navigation_bar.community_timeline\": \"Helyi idővonal\",\n  \"navigation_bar.compose\": \"Compose new toot\",\n  \"navigation_bar.direct\": \"Direct messages\",\n  \"navigation_bar.discover\": \"Discover\",\n  \"navigation_bar.domain_blocks\": \"Hidden domains\",\n  \"navigation_bar.edit_profile\": \"Profil szerkesztése\",\n  \"navigation_bar.favourites\": \"Kedvencek\",\n  \"navigation_bar.filters\": \"Muted words\",\n  \"navigation_bar.follow_requests\": \"Követési kérések\",\n  \"navigation_bar.follows_and_followers\": \"Follows and followers\",\n  \"navigation_bar.info\": \"Ezen szerverről\",\n  \"navigation_bar.keyboard_shortcuts\": \"Gyorsbillentyűk\",\n  \"navigation_bar.lists\": \"Listák\",\n  \"navigation_bar.logout\": \"Kijelentkezés\",\n  \"navigation_bar.mutes\": \"Némított felhasználók\",\n  \"navigation_bar.personal\": \"Personal\",\n  \"navigation_bar.pins\": \"Kitűzött tülkök\",\n  \"navigation_bar.preferences\": \"Beállítások\",\n  \"navigation_bar.profile_directory\": \"Profile directory\",\n  \"navigation_bar.public_timeline\": \"Nyilvános időfolyam\",\n  \"navigation_bar.security\": \"Security\",\n  \"notification.favourite\": \"{name} kedvencnek jelölte az állapotod\",\n  \"notification.follow\": \"{name} követ téged\",\n  \"notification.mention\": \"{name} megemlített\",\n  \"notification.poll\": \"A poll you have voted in has ended\",\n  \"notification.reblog\": \"{name} rebloggolta az állapotod\",\n  \"notifications.clear\": \"Értesítések törlése\",\n  \"notifications.clear_confirmation\": \"Biztos benne, hogy véglegesen törölni akarja az összes értesítését?\",\n  \"notifications.column_settings.alert\": \"Asztali gépi értesítések\",\n  \"notifications.column_settings.favourite\": \"Kedvencek:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Display all categories\",\n  \"notifications.column_settings.filter_bar.category\": \"Quick filter bar\",\n  \"notifications.column_settings.filter_bar.show\": \"Show\",\n  \"notifications.column_settings.follow\": \"Új követők:\",\n  \"notifications.column_settings.mention\": \"Megemítéseim:\",\n  \"notifications.column_settings.poll\": \"Poll results:\",\n  \"notifications.column_settings.push\": \"Push értesítések\",\n  \"notifications.column_settings.reblog\": \"Rebloggolások:\",\n  \"notifications.column_settings.show\": \"Oszlopban mutatás\",\n  \"notifications.column_settings.sound\": \"Hang lejátszása\",\n  \"notifications.filter.all\": \"All\",\n  \"notifications.filter.boosts\": \"Boosts\",\n  \"notifications.filter.favourites\": \"Favourites\",\n  \"notifications.filter.follows\": \"Follows\",\n  \"notifications.filter.mentions\": \"Mentions\",\n  \"notifications.filter.polls\": \"Poll results\",\n  \"notifications.group\": \"{count} notifications\",\n  \"poll.closed\": \"Closed\",\n  \"poll.refresh\": \"Refresh\",\n  \"poll.total_votes\": \"{count, plural, one {# vote} other {# votes}}\",\n  \"poll.vote\": \"Vote\",\n  \"poll_button.add_poll\": \"Add a poll\",\n  \"poll_button.remove_poll\": \"Remove poll\",\n  \"privacy.change\": \"Státusz láthatóságának módosítása\",\n  \"privacy.direct.long\": \"Posztolás csak az említett felhasználóknak\",\n  \"privacy.direct.short\": \"Egyenesen\",\n  \"privacy.private.long\": \"Posztolás csak követőknek\",\n  \"privacy.private.short\": \"Csak követőknek\",\n  \"privacy.public.long\": \"Posztolás a publikus idővonalakra\",\n  \"privacy.public.short\": \"Publikus\",\n  \"privacy.unlisted.long\": \"Do not show in public timelines\",\n  \"privacy.unlisted.short\": \"Listázatlan\",\n  \"regeneration_indicator.label\": \"Töltődik…\",\n  \"regeneration_indicator.sublabel\": \"Your home feed is being prepared!\",\n  \"relative_time.days\": \"{number}d\",\n  \"relative_time.hours\": \"{number}h\",\n  \"relative_time.just_now\": \"most\",\n  \"relative_time.minutes\": \"{number}m\",\n  \"relative_time.seconds\": \"{number}s\",\n  \"reply_indicator.cancel\": \"Mégsem\",\n  \"report.forward\": \"Forward to {target}\",\n  \"report.forward_hint\": \"The account is from another server. Send an anonymized copy of the report there as well?\",\n  \"report.hint\": \"The report will be sent to your instance moderators. You can provide an explanation of why you are reporting this account below:\",\n  \"report.placeholder\": \"További kommentek\",\n  \"report.submit\": \"Submit\",\n  \"report.target\": \"Reporting\",\n  \"search.placeholder\": \"Keresés\",\n  \"search_popout.search_format\": \"Fejlett keresés\",\n  \"search_popout.tips.full_text\": \"Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.\",\n  \"search_popout.tips.hashtag\": \"hashtag\",\n  \"search_popout.tips.status\": \"status\",\n  \"search_popout.tips.text\": \"Simple text returns matching display names, usernames and hashtags\",\n  \"search_popout.tips.user\": \"felhasználó\",\n  \"search_results.accounts\": \"People\",\n  \"search_results.hashtags\": \"Hashtags\",\n  \"search_results.statuses\": \"Toots\",\n  \"search_results.total\": \"{count, number} {count, plural, one {result} other {results}}\",\n  \"status.admin_account\": \"Open moderation interface for @{name}\",\n  \"status.admin_status\": \"Open this status in the moderation interface\",\n  \"status.block\": \"Block @{name}\",\n  \"status.cancel_reblog_private\": \"Unboost\",\n  \"status.cannot_reblog\": \"Ezen státusz nem rebloggolható\",\n  \"status.copy\": \"Copy link to status\",\n  \"status.delete\": \"Törlés\",\n  \"status.detailed_status\": \"Detailed conversation view\",\n  \"status.direct\": \"Direct message @{name}\",\n  \"status.embed\": \"Beágyaz\",\n  \"status.favourite\": \"Kedvenc\",\n  \"status.filtered\": \"Filtered\",\n  \"status.load_more\": \"Többet\",\n  \"status.media_hidden\": \"Média elrejtve\",\n  \"status.mention\": \"Említés\",\n  \"status.more\": \"Többet\",\n  \"status.mute\": \"@{name} némítása\",\n  \"status.mute_conversation\": \"Beszélgetés némítása\",\n  \"status.open\": \"Státusz kinagyítása\",\n  \"status.pin\": \"Kitűzés a profilra\",\n  \"status.pinned\": \"Pinned toot\",\n  \"status.read_more\": \"Read more\",\n  \"status.reblog\": \"Reblog\",\n  \"status.reblog_private\": \"Boost to original audience\",\n  \"status.reblogged_by\": \"{name} reblogolta\",\n  \"status.reblogs.empty\": \"No one has boosted this toot yet. When someone does, they will show up here.\",\n  \"status.redraft\": \"Delete & re-draft\",\n  \"status.reply\": \"Válasz\",\n  \"status.replyAll\": \"Válaszolj a beszélgetésre\",\n  \"status.report\": \"Report @{name}\",\n  \"status.sensitive_warning\": \"Érzékeny tartalom\",\n  \"status.share\": \"Megosztás\",\n  \"status.show_less\": \"Kevesebb\",\n  \"status.show_less_all\": \"Show less for all\",\n  \"status.show_more\": \"Többet\",\n  \"status.show_more_all\": \"Show more for all\",\n  \"status.show_thread\": \"Show thread\",\n  \"status.unmute_conversation\": \"Beszélgetés némításának elvonása\",\n  \"status.unpin\": \"Kitűzés eltávolítása a profilról\",\n  \"suggestions.dismiss\": \"Dismiss suggestion\",\n  \"suggestions.header\": \"You might be interested in…\",\n  \"tabs_bar.federated_timeline\": \"Federált\",\n  \"tabs_bar.home\": \"Kezdőlap\",\n  \"tabs_bar.local_timeline\": \"Local\",\n  \"tabs_bar.notifications\": \"Értesítések\",\n  \"tabs_bar.search\": \"Search\",\n  \"time_remaining.days\": \"{number, plural, one {# day} other {# days}} left\",\n  \"time_remaining.hours\": \"{number, plural, one {# hour} other {# hours}} left\",\n  \"time_remaining.minutes\": \"{number, plural, one {# minute} other {# minutes}} left\",\n  \"time_remaining.moments\": \"Moments remaining\",\n  \"time_remaining.seconds\": \"{number, plural, one {# second} other {# seconds}} left\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {person} other {people}} talking\",\n  \"ui.beforeunload\": \"A piszkozata el fog vesztődni ha elhagyja Mastodon-t.\",\n  \"upload_area.title\": \"Húzza ide a feltöltéshez\",\n  \"upload_button.label\": \"Média hozzáadása\",\n  \"upload_error.limit\": \"File upload limit exceeded.\",\n  \"upload_error.poll\": \"File upload not allowed with polls.\",\n  \"upload_form.description\": \"Describe for the visually impaired\",\n  \"upload_form.focus\": \"Crop\",\n  \"upload_form.undo\": \"Mégsem\",\n  \"upload_progress.label\": \"Uploading...\",\n  \"video.close\": \"Close video\",\n  \"video.exit_fullscreen\": \"Exit full screen\",\n  \"video.expand\": \"Expand video\",\n  \"video.fullscreen\": \"Full screen\",\n  \"video.hide\": \"Hide video\",\n  \"video.mute\": \"Mute sound\",\n  \"video.pause\": \"Szünet\",\n  \"video.play\": \"Lejátszás\",\n  \"video.unmute\": \"Hang kinémítása\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/hy.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Add or Remove from lists\",\n  \"account.badges.bot\": \"Bot\",\n  \"account.block\": \"Արգելափակել @{name}֊ին\",\n  \"account.block_domain\": \"Թաքցնել ամենը հետեւյալ տիրույթից՝ {domain}\",\n  \"account.blocked\": \"Blocked\",\n  \"account.direct\": \"Direct Message @{name}\",\n  \"account.domain_blocked\": \"Domain hidden\",\n  \"account.edit_profile\": \"Խմբագրել անձնական էջը\",\n  \"account.endorse\": \"Feature on profile\",\n  \"account.follow\": \"Հետեւել\",\n  \"account.followers\": \"Հետեւվողներ\",\n  \"account.followers.empty\": \"No one follows this user yet.\",\n  \"account.follows\": \"Հետեւում է\",\n  \"account.follows.empty\": \"This user doesn't follow anyone yet.\",\n  \"account.follows_you\": \"Հետեւում է քեզ\",\n  \"account.hide_reblogs\": \"Թաքցնել @{name}֊ի տարածածները\",\n  \"account.link_verified_on\": \"Ownership of this link was checked on {date}\",\n  \"account.locked_info\": \"This account privacy status is set to locked. The owner manually reviews who can follow them.\",\n  \"account.media\": \"Մեդիա\",\n  \"account.mention\": \"Նշել @{name}֊ին\",\n  \"account.moved_to\": \"{name}֊ը տեղափոխվել է՝\",\n  \"account.mute\": \"Լռեցնել @{name}֊ին\",\n  \"account.mute_notifications\": \"Անջատել ծանուցումները @{name}֊ից\",\n  \"account.muted\": \"Muted\",\n  \"account.posts\": \"Գրառումներ\",\n  \"account.posts_with_replies\": \"Toots with replies\",\n  \"account.report\": \"Բողոքել @{name}֊ից\",\n  \"account.requested\": \"Հաստատման կարիք ունի։ Սեղմիր՝ հետեւելու հայցը չեղարկելու համար։\",\n  \"account.share\": \"Կիսվել @{name}֊ի էջով\",\n  \"account.show_reblogs\": \"Ցուցադրել @{name}֊ի տարածածները\",\n  \"account.unblock\": \"Ապաարգելափակել @{name}֊ին\",\n  \"account.unblock_domain\": \"Ցուցադրել {domain} թաքցված տիրույթի գրառումները\",\n  \"account.unendorse\": \"Don't feature on profile\",\n  \"account.unfollow\": \"Չհետեւել\",\n  \"account.unmute\": \"Ապալռեցնել @{name}֊ին\",\n  \"account.unmute_notifications\": \"Միացնել ծանուցումները @{name}֊ից\",\n  \"alert.unexpected.message\": \"An unexpected error occurred.\",\n  \"alert.unexpected.title\": \"Oops!\",\n  \"boost_modal.combo\": \"Կարող ես սեղմել {combo}՝ սա հաջորդ անգամ բաց թողնելու համար\",\n  \"bundle_column_error.body\": \"Այս բաղադրիչը բեռնելու ընթացքում ինչ֊որ բան խափանվեց։\",\n  \"bundle_column_error.retry\": \"Կրկին փորձել\",\n  \"bundle_column_error.title\": \"Ցանցային սխալ\",\n  \"bundle_modal_error.close\": \"Փակել\",\n  \"bundle_modal_error.message\": \"Այս բաղադրիչը բեռնելու ընթացքում ինչ֊որ բան խափանվեց։\",\n  \"bundle_modal_error.retry\": \"Կրկին փորձել\",\n  \"column.blocks\": \"Արգելափակված օգտատերեր\",\n  \"column.community\": \"Տեղական հոսք\",\n  \"column.direct\": \"Direct messages\",\n  \"column.domain_blocks\": \"Hidden domains\",\n  \"column.favourites\": \"Հավանածներ\",\n  \"column.follow_requests\": \"Հետեւելու հայցեր\",\n  \"column.home\": \"Հիմնական\",\n  \"column.lists\": \"Ցանկեր\",\n  \"column.mutes\": \"Լռեցրած օգտատերեր\",\n  \"column.notifications\": \"Ծանուցումներ\",\n  \"column.pins\": \"Ամրացված թթեր\",\n  \"column.public\": \"Դաշնային հոսք\",\n  \"column_back_button.label\": \"Ետ\",\n  \"column_header.hide_settings\": \"Թաքցնել կարգավորումները\",\n  \"column_header.moveLeft_settings\": \"Տեղաշարժել սյունը ձախ\",\n  \"column_header.moveRight_settings\": \"Տեղաշարժել սյունը աջ\",\n  \"column_header.pin\": \"Ամրացնել\",\n  \"column_header.show_settings\": \"Ցուցադրել կարգավորումները\",\n  \"column_header.unpin\": \"Հանել\",\n  \"column_subheading.settings\": \"Կարգավորումներ\",\n  \"community.column_settings.media_only\": \"Media Only\",\n  \"compose_form.direct_message_warning\": \"This toot will only be visible to all the mentioned users.\",\n  \"compose_form.direct_message_warning_learn_more\": \"Learn more\",\n  \"compose_form.hashtag_warning\": \"Այս թութը չի հաշվառվի որեւէ պիտակի տակ, քանզի այն ծածուկ է։ Միայն հրապարակային թթերը հնարավոր է որոնել պիտակներով։\",\n  \"compose_form.lock_disclaimer\": \"Քո հաշիվը {locked} չէ։ Յուրաքանչյուր ոք կարող է հետեւել քեզ եւ տեսնել միայն հետեւողների համար նախատեսված գրառումները։\",\n  \"compose_form.lock_disclaimer.lock\": \"փակ\",\n  \"compose_form.placeholder\": \"Ի՞նչ կա մտքիդ\",\n  \"compose_form.poll.add_option\": \"Add a choice\",\n  \"compose_form.poll.duration\": \"Poll duration\",\n  \"compose_form.poll.option_placeholder\": \"Choice {number}\",\n  \"compose_form.poll.remove_option\": \"Remove this choice\",\n  \"compose_form.publish\": \"Թթել\",\n  \"compose_form.publish_loud\": \"Թթե՜լ\",\n  \"compose_form.sensitive.hide\": \"Mark media as sensitive\",\n  \"compose_form.sensitive.marked\": \"Media is marked as sensitive\",\n  \"compose_form.sensitive.unmarked\": \"Media is not marked as sensitive\",\n  \"compose_form.spoiler.marked\": \"Text is hidden behind warning\",\n  \"compose_form.spoiler.unmarked\": \"Text is not hidden\",\n  \"compose_form.spoiler_placeholder\": \"Գրիր նախազգուշացումդ այստեղ\",\n  \"confirmation_modal.cancel\": \"Չեղարկել\",\n  \"confirmations.block.block_and_report\": \"Block & Report\",\n  \"confirmations.block.confirm\": \"Արգելափակել\",\n  \"confirmations.block.message\": \"Վստա՞հ ես, որ ուզում ես արգելափակել {name}֊ին։\",\n  \"confirmations.delete.confirm\": \"Ջնջել\",\n  \"confirmations.delete.message\": \"Վստա՞հ ես, որ ուզում ես ջնջել այս թութը։\",\n  \"confirmations.delete_list.confirm\": \"Ջնջել\",\n  \"confirmations.delete_list.message\": \"Վստա՞հ ես, որ ուզում ես մշտապես ջնջել այս ցանկը։\",\n  \"confirmations.domain_block.confirm\": \"Թաքցնել ամբողջ տիրույթը\",\n  \"confirmations.domain_block.message\": \"Հաստատ֊հաստա՞տ վստահ ես, որ ուզում ես արգելափակել ամբողջ {domain} տիրույթը։ Սովորաբար մի երկու թիրախավորված արգելափակում կամ լռեցում բավական է ու նախընտրելի։\",\n  \"confirmations.mute.confirm\": \"Լռեցնել\",\n  \"confirmations.mute.message\": \"Վստա՞հ ես, որ ուզում ես {name}֊ին լռեցնել։\",\n  \"confirmations.redraft.confirm\": \"Delete & redraft\",\n  \"confirmations.redraft.message\": \"Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.\",\n  \"confirmations.reply.confirm\": \"Reply\",\n  \"confirmations.reply.message\": \"Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?\",\n  \"confirmations.unfollow.confirm\": \"Ապահետեւել\",\n  \"confirmations.unfollow.message\": \"Վստա՞հ ես, որ ուզում ես այլեւս չհետեւել {name}֊ին։\",\n  \"embed.instructions\": \"Այս թութը քո կայքում ներդնելու համար կարող ես պատճենել ներքոհիշյալ կոդը։\",\n  \"embed.preview\": \"Ահա, թե ինչ տեսք կունենա այն՝\",\n  \"emoji_button.activity\": \"Զբաղմունքներ\",\n  \"emoji_button.custom\": \"Հատուկ\",\n  \"emoji_button.flags\": \"Դրոշներ\",\n  \"emoji_button.food\": \"Կերուխում\",\n  \"emoji_button.label\": \"Էմոջի ավելացնել\",\n  \"emoji_button.nature\": \"Բնություն\",\n  \"emoji_button.not_found\": \"Նման էմոջիներ դեռ չեն հայտնաբերվել։ (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"Առարկաներ\",\n  \"emoji_button.people\": \"Մարդիկ\",\n  \"emoji_button.recent\": \"Հաճախ օգտագործվող\",\n  \"emoji_button.search\": \"Որոնել…\",\n  \"emoji_button.search_results\": \"Որոնման արդյունքներ\",\n  \"emoji_button.symbols\": \"Նշաններ\",\n  \"emoji_button.travel\": \"Ուղեւորություն եւ տեղանքներ\",\n  \"empty_column.account_timeline\": \"No toots here!\",\n  \"empty_column.account_unavailable\": \"Profile unavailable\",\n  \"empty_column.blocks\": \"You haven't blocked any users yet.\",\n  \"empty_column.community\": \"Տեղական հոսքը դատա՛րկ է։ Հրապարակային մի բան գրիր շարժիչը խոդ տալու համար։\",\n  \"empty_column.direct\": \"You don't have any direct messages yet. When you send or receive one, it will show up here.\",\n  \"empty_column.domain_blocks\": \"There are no hidden domains yet.\",\n  \"empty_column.favourited_statuses\": \"You don't have any favourite toots yet. When you favourite one, it will show up here.\",\n  \"empty_column.favourites\": \"No one has favourited this toot yet. When someone does, they will show up here.\",\n  \"empty_column.follow_requests\": \"You don't have any follow requests yet. When you receive one, it will show up here.\",\n  \"empty_column.hashtag\": \"Այս պիտակով դեռ ոչինչ չկա։\",\n  \"empty_column.home\": \"Քո հիմնական հոսքը դատա՛րկ է։ Այցելի՛ր {public}ը կամ օգտվիր որոնումից՝ այլ մարդկանց հանդիպելու համար։\",\n  \"empty_column.home.public_timeline\": \"հրապարակային հոսք\",\n  \"empty_column.list\": \"Այս ցանկում դեռ ոչինչ չկա։ Երբ ցանկի անդամներից որեւէ մեկը նոր թութ գրի, այն կհայտնվի այստեղ։\",\n  \"empty_column.lists\": \"You don't have any lists yet. When you create one, it will show up here.\",\n  \"empty_column.mutes\": \"You haven't muted any users yet.\",\n  \"empty_column.notifications\": \"Ոչ մի ծանուցում դեռ չունես։ Բզիր մյուսներին՝ խոսակցությունը սկսելու համար։\",\n  \"empty_column.public\": \"Այստեղ բան չկա՛։ Հրապարակային մի բան գրիր կամ հետեւիր այլ հանգույցներից էակների՝ այն լցնելու համար։\",\n  \"follow_request.authorize\": \"Վավերացնել\",\n  \"follow_request.reject\": \"Մերժել\",\n  \"getting_started.developers\": \"Developers\",\n  \"getting_started.directory\": \"Profile directory\",\n  \"getting_started.documentation\": \"Documentation\",\n  \"getting_started.heading\": \"Ինչպես սկսել\",\n  \"getting_started.invite\": \"Invite people\",\n  \"getting_started.open_source_notice\": \"Մաստոդոնը բաց ելատեքստով ծրագրակազմ է։ Կարող ես ներդրում անել կամ վրեպներ զեկուցել ԳիթՀաբում՝ {github}։\",\n  \"getting_started.security\": \"Security\",\n  \"getting_started.terms\": \"Terms of service\",\n  \"hashtag.column_header.tag_mode.all\": \"and {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"or {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"without {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"No suggestions found\",\n  \"hashtag.column_settings.select.placeholder\": \"Enter hashtags…\",\n  \"hashtag.column_settings.tag_mode.all\": \"All of these\",\n  \"hashtag.column_settings.tag_mode.any\": \"Any of these\",\n  \"hashtag.column_settings.tag_mode.none\": \"None of these\",\n  \"hashtag.column_settings.tag_toggle\": \"Include additional tags in this column\",\n  \"home.column_settings.basic\": \"Հիմնական\",\n  \"home.column_settings.show_reblogs\": \"Ցուցադրել տարածածները\",\n  \"home.column_settings.show_replies\": \"Ցուցադրել պատասխանները\",\n  \"intervals.full.days\": \"{number, plural, one {# day} other {# days}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# hour} other {# hours}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minute} other {# minutes}}\",\n  \"introduction.federation.action\": \"Next\",\n  \"introduction.federation.federated.headline\": \"Federated\",\n  \"introduction.federation.federated.text\": \"Public posts from other servers of the fediverse will appear in the federated timeline.\",\n  \"introduction.federation.home.headline\": \"Home\",\n  \"introduction.federation.home.text\": \"Posts from people you follow will appear in your home feed. You can follow anyone on any server!\",\n  \"introduction.federation.local.headline\": \"Local\",\n  \"introduction.federation.local.text\": \"Public posts from people on the same server as you will appear in the local timeline.\",\n  \"introduction.interactions.action\": \"Finish toot-orial!\",\n  \"introduction.interactions.favourite.headline\": \"Favourite\",\n  \"introduction.interactions.favourite.text\": \"You can save a toot for later, and let the author know that you liked it, by favouriting it.\",\n  \"introduction.interactions.reblog.headline\": \"Boost\",\n  \"introduction.interactions.reblog.text\": \"You can share other people's toots with your followers by boosting them.\",\n  \"introduction.interactions.reply.headline\": \"Reply\",\n  \"introduction.interactions.reply.text\": \"You can reply to other people's and your own toots, which will chain them together in a conversation.\",\n  \"introduction.welcome.action\": \"Let's go!\",\n  \"introduction.welcome.headline\": \"First steps\",\n  \"introduction.welcome.text\": \"Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.\",\n  \"keyboard_shortcuts.back\": \"ետ նավարկելու համար\",\n  \"keyboard_shortcuts.blocked\": \"to open blocked users list\",\n  \"keyboard_shortcuts.boost\": \"տարածելու համար\",\n  \"keyboard_shortcuts.column\": \"սյուներից մեկի վրա սեւեռվելու համար\",\n  \"keyboard_shortcuts.compose\": \"շարադրման տիրույթին սեւեռվելու համար\",\n  \"keyboard_shortcuts.description\": \"Նկարագրություն\",\n  \"keyboard_shortcuts.direct\": \"to open direct messages column\",\n  \"keyboard_shortcuts.down\": \"ցանկով ներքեւ շարժվելու համար\",\n  \"keyboard_shortcuts.enter\": \"թութը բացելու համար\",\n  \"keyboard_shortcuts.favourite\": \"հավանելու համար\",\n  \"keyboard_shortcuts.favourites\": \"to open favourites list\",\n  \"keyboard_shortcuts.federated\": \"to open federated timeline\",\n  \"keyboard_shortcuts.heading\": \"Ստեղնաշարի կարճատներ\",\n  \"keyboard_shortcuts.home\": \"to open home timeline\",\n  \"keyboard_shortcuts.hotkey\": \"Հատուկ ստեղն\",\n  \"keyboard_shortcuts.legend\": \"այս ձեռնարկը ցուցադրելու համար\",\n  \"keyboard_shortcuts.local\": \"to open local timeline\",\n  \"keyboard_shortcuts.mention\": \"հեղինակին նշելու համար\",\n  \"keyboard_shortcuts.muted\": \"to open muted users list\",\n  \"keyboard_shortcuts.my_profile\": \"to open your profile\",\n  \"keyboard_shortcuts.notifications\": \"to open notifications column\",\n  \"keyboard_shortcuts.pinned\": \"to open pinned toots list\",\n  \"keyboard_shortcuts.profile\": \"to open author's profile\",\n  \"keyboard_shortcuts.reply\": \"պատասխանելու համար\",\n  \"keyboard_shortcuts.requests\": \"to open follow requests list\",\n  \"keyboard_shortcuts.search\": \"որոնման դաշտին սեւեռվելու համար\",\n  \"keyboard_shortcuts.start\": \"to open \\\"get started\\\" column\",\n  \"keyboard_shortcuts.toggle_hidden\": \"to show/hide text behind CW\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"to show/hide media\",\n  \"keyboard_shortcuts.toot\": \"թարմ թութ սկսելու համար\",\n  \"keyboard_shortcuts.unfocus\": \"տեքստի/որոնման տիրույթից ապասեւեռվելու համար\",\n  \"keyboard_shortcuts.up\": \"ցանկով վերեւ շարժվելու համար\",\n  \"lightbox.close\": \"Փակել\",\n  \"lightbox.next\": \"Հաջորդ\",\n  \"lightbox.previous\": \"Նախորդ\",\n  \"lightbox.view_context\": \"View context\",\n  \"lists.account.add\": \"Ավելացնել ցանկին\",\n  \"lists.account.remove\": \"Հանել ցանկից\",\n  \"lists.delete\": \"Ջնջել ցանկը\",\n  \"lists.edit\": \"Փոփոխել ցանկը\",\n  \"lists.edit.submit\": \"Change title\",\n  \"lists.new.create\": \"Ավելացնել ցանկ\",\n  \"lists.new.title_placeholder\": \"Նոր ցանկի վերնագիր\",\n  \"lists.search\": \"Փնտրել քո հետեւած մարդկանց մեջ\",\n  \"lists.subheading\": \"Քո ցանկերը\",\n  \"loading_indicator.label\": \"Բեռնվում է…\",\n  \"media_gallery.toggle_visible\": \"Ցուցադրել/թաքցնել\",\n  \"missing_indicator.label\": \"Չգտնվեց\",\n  \"missing_indicator.sublabel\": \"This resource could not be found\",\n  \"mute_modal.hide_notifications\": \"Թաքցնե՞լ ցանուցումներն այս օգտատիրոջից։\",\n  \"navigation_bar.apps\": \"Mobile apps\",\n  \"navigation_bar.blocks\": \"Արգելափակված օգտատերեր\",\n  \"navigation_bar.community_timeline\": \"Տեղական հոսք\",\n  \"navigation_bar.compose\": \"Compose new toot\",\n  \"navigation_bar.direct\": \"Direct messages\",\n  \"navigation_bar.discover\": \"Discover\",\n  \"navigation_bar.domain_blocks\": \"Hidden domains\",\n  \"navigation_bar.edit_profile\": \"Խմբագրել անձնական էջը\",\n  \"navigation_bar.favourites\": \"Հավանածներ\",\n  \"navigation_bar.filters\": \"Muted words\",\n  \"navigation_bar.follow_requests\": \"Հետեւելու հայցեր\",\n  \"navigation_bar.follows_and_followers\": \"Follows and followers\",\n  \"navigation_bar.info\": \"Այս հանգույցի մասին\",\n  \"navigation_bar.keyboard_shortcuts\": \"Ստեղնաշարի կարճատներ\",\n  \"navigation_bar.lists\": \"Ցանկեր\",\n  \"navigation_bar.logout\": \"Դուրս գալ\",\n  \"navigation_bar.mutes\": \"Լռեցրած օգտատերեր\",\n  \"navigation_bar.personal\": \"Անձնական\",\n  \"navigation_bar.pins\": \"Ամրացված թթեր\",\n  \"navigation_bar.preferences\": \"Նախապատվություններ\",\n  \"navigation_bar.profile_directory\": \"Profile directory\",\n  \"navigation_bar.public_timeline\": \"Դաշնային հոսք\",\n  \"navigation_bar.security\": \"Անվտանգություն\",\n  \"notification.favourite\": \"{name} հավանեց թութդ\",\n  \"notification.follow\": \"{name} սկսեց հետեւել քեզ\",\n  \"notification.mention\": \"{name} նշեց քեզ\",\n  \"notification.poll\": \"A poll you have voted in has ended\",\n  \"notification.reblog\": \"{name} տարածեց թութդ\",\n  \"notifications.clear\": \"Մաքրել ծանուցումները\",\n  \"notifications.clear_confirmation\": \"Վստա՞հ ես, որ ուզում ես մշտապես մաքրել քո բոլոր ծանուցումները։\",\n  \"notifications.column_settings.alert\": \"Աշխատատիրույթի ծանուցումներ\",\n  \"notifications.column_settings.favourite\": \"Հավանածներից՝\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Display all categories\",\n  \"notifications.column_settings.filter_bar.category\": \"Quick filter bar\",\n  \"notifications.column_settings.filter_bar.show\": \"Show\",\n  \"notifications.column_settings.follow\": \"Նոր հետեւողներ՝\",\n  \"notifications.column_settings.mention\": \"Նշումներ՝\",\n  \"notifications.column_settings.poll\": \"Poll results:\",\n  \"notifications.column_settings.push\": \"Հրելու ծանուցումներ\",\n  \"notifications.column_settings.reblog\": \"Տարածածներից՝\",\n  \"notifications.column_settings.show\": \"Ցուցադրել սյունում\",\n  \"notifications.column_settings.sound\": \"Ձայն հանել\",\n  \"notifications.filter.all\": \"All\",\n  \"notifications.filter.boosts\": \"Boosts\",\n  \"notifications.filter.favourites\": \"Favourites\",\n  \"notifications.filter.follows\": \"Follows\",\n  \"notifications.filter.mentions\": \"Mentions\",\n  \"notifications.filter.polls\": \"Poll results\",\n  \"notifications.group\": \"{count} notifications\",\n  \"poll.closed\": \"Closed\",\n  \"poll.refresh\": \"Refresh\",\n  \"poll.total_votes\": \"{count, plural, one {# vote} other {# votes}}\",\n  \"poll.vote\": \"Vote\",\n  \"poll_button.add_poll\": \"Add a poll\",\n  \"poll_button.remove_poll\": \"Remove poll\",\n  \"privacy.change\": \"Կարգավորել թթի գաղտնիությունը\",\n  \"privacy.direct.long\": \"Թթել միայն նշված օգտատերերի համար\",\n  \"privacy.direct.short\": \"Հասցեագրված\",\n  \"privacy.private.long\": \"Թթել միայն հետեւողների համար\",\n  \"privacy.private.short\": \"Միայն հետեւողներին\",\n  \"privacy.public.long\": \"Թթել հրապարակային հոսքերում\",\n  \"privacy.public.short\": \"Հրապարակային\",\n  \"privacy.unlisted.long\": \"Չթթել հրապարակային հոսքերում\",\n  \"privacy.unlisted.short\": \"Ծածուկ\",\n  \"regeneration_indicator.label\": \"Loading…\",\n  \"regeneration_indicator.sublabel\": \"Your home feed is being prepared!\",\n  \"relative_time.days\": \"{number}օր\",\n  \"relative_time.hours\": \"{number}ժ\",\n  \"relative_time.just_now\": \"նոր\",\n  \"relative_time.minutes\": \"{number}ր\",\n  \"relative_time.seconds\": \"{number}վ\",\n  \"reply_indicator.cancel\": \"Չեղարկել\",\n  \"report.forward\": \"Forward to {target}\",\n  \"report.forward_hint\": \"The account is from another server. Send an anonymized copy of the report there as well?\",\n  \"report.hint\": \"The report will be sent to your instance moderators. You can provide an explanation of why you are reporting this account below:\",\n  \"report.placeholder\": \"Լրացուցիչ մեկնաբանություններ\",\n  \"report.submit\": \"Ուղարկել\",\n  \"report.target\": \"Բողոքել {target}֊ի մասին\",\n  \"search.placeholder\": \"Փնտրել\",\n  \"search_popout.search_format\": \"Փնտրելու առաջադեմ ձեւ\",\n  \"search_popout.tips.full_text\": \"Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.\",\n  \"search_popout.tips.hashtag\": \"պիտակ\",\n  \"search_popout.tips.status\": \"թութ\",\n  \"search_popout.tips.text\": \"Հասարակ տեքստը կվերադարձնի համընկնող անուններ, օգտանուններ ու պիտակներ\",\n  \"search_popout.tips.user\": \"օգտատեր\",\n  \"search_results.accounts\": \"People\",\n  \"search_results.hashtags\": \"Hashtags\",\n  \"search_results.statuses\": \"Toots\",\n  \"search_results.total\": \"{count, number} {count, plural, one {արդյունք} other {արդյունք}}\",\n  \"status.admin_account\": \"Open moderation interface for @{name}\",\n  \"status.admin_status\": \"Open this status in the moderation interface\",\n  \"status.block\": \"Արգելափակել @{name}֊ին\",\n  \"status.cancel_reblog_private\": \"Unboost\",\n  \"status.cannot_reblog\": \"Այս թութը չի կարող տարածվել\",\n  \"status.copy\": \"Copy link to status\",\n  \"status.delete\": \"Ջնջել\",\n  \"status.detailed_status\": \"Detailed conversation view\",\n  \"status.direct\": \"Direct message @{name}\",\n  \"status.embed\": \"Ներդնել\",\n  \"status.favourite\": \"Հավանել\",\n  \"status.filtered\": \"Filtered\",\n  \"status.load_more\": \"Բեռնել ավելին\",\n  \"status.media_hidden\": \"մեդիաբովանդակությունը թաքցված է\",\n  \"status.mention\": \"Նշել @{name}֊ին\",\n  \"status.more\": \"Ավելին\",\n  \"status.mute\": \"Լռեցնել @{name}֊ին\",\n  \"status.mute_conversation\": \"Լռեցնել խոսակցությունը\",\n  \"status.open\": \"Ընդարձակել այս թութը\",\n  \"status.pin\": \"Ամրացնել անձնական էջում\",\n  \"status.pinned\": \"Pinned toot\",\n  \"status.read_more\": \"Read more\",\n  \"status.reblog\": \"Տարածել\",\n  \"status.reblog_private\": \"Boost to original audience\",\n  \"status.reblogged_by\": \"{name} տարածել է\",\n  \"status.reblogs.empty\": \"No one has boosted this toot yet. When someone does, they will show up here.\",\n  \"status.redraft\": \"Delete & re-draft\",\n  \"status.reply\": \"Պատասխանել\",\n  \"status.replyAll\": \"Պատասխանել թելին\",\n  \"status.report\": \"Բողոքել @{name}֊ից\",\n  \"status.sensitive_warning\": \"Կասկածելի բովանդակություն\",\n  \"status.share\": \"Կիսվել\",\n  \"status.show_less\": \"Պակաս\",\n  \"status.show_less_all\": \"Show less for all\",\n  \"status.show_more\": \"Ավելին\",\n  \"status.show_more_all\": \"Show more for all\",\n  \"status.show_thread\": \"Show thread\",\n  \"status.unmute_conversation\": \"Ապալռեցնել խոսակցությունը\",\n  \"status.unpin\": \"Հանել անձնական էջից\",\n  \"suggestions.dismiss\": \"Dismiss suggestion\",\n  \"suggestions.header\": \"You might be interested in…\",\n  \"tabs_bar.federated_timeline\": \"Դաշնային\",\n  \"tabs_bar.home\": \"Հիմնական\",\n  \"tabs_bar.local_timeline\": \"Տեղական\",\n  \"tabs_bar.notifications\": \"Ծանուցումներ\",\n  \"tabs_bar.search\": \"Search\",\n  \"time_remaining.days\": \"{number, plural, one {# day} other {# days}} left\",\n  \"time_remaining.hours\": \"{number, plural, one {# hour} other {# hours}} left\",\n  \"time_remaining.minutes\": \"{number, plural, one {# minute} other {# minutes}} left\",\n  \"time_remaining.moments\": \"Moments remaining\",\n  \"time_remaining.seconds\": \"{number, plural, one {# second} other {# seconds}} left\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {person} other {people}} talking\",\n  \"ui.beforeunload\": \"Քո սեւագիրը կկորի, եթե լքես Մաստոդոնը։\",\n  \"upload_area.title\": \"Քաշիր ու նետիր՝ վերբեռնելու համար\",\n  \"upload_button.label\": \"Ավելացնել մեդիա\",\n  \"upload_error.limit\": \"File upload limit exceeded.\",\n  \"upload_error.poll\": \"File upload not allowed with polls.\",\n  \"upload_form.description\": \"Նկարագրություն ավելացրու տեսողական խնդիրներ ունեցողների համար\",\n  \"upload_form.focus\": \"Crop\",\n  \"upload_form.undo\": \"Հետարկել\",\n  \"upload_progress.label\": \"Վերբեռնվում է…\",\n  \"video.close\": \"Փակել  տեսագրությունը\",\n  \"video.exit_fullscreen\": \"Անջատել լիաէկրան դիտումը\",\n  \"video.expand\": \"Ընդարձակել տեսագրությունը\",\n  \"video.fullscreen\": \"Լիաէկրան\",\n  \"video.hide\": \"Թաքցնել տեսագրությունը\",\n  \"video.mute\": \"Լռեցնել ձայնը\",\n  \"video.pause\": \"Դադար տալ\",\n  \"video.play\": \"Նվագել\",\n  \"video.unmute\": \"Միացնել ձայնը\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/id.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Add or Remove from lists\",\n  \"account.badges.bot\": \"Bot\",\n  \"account.block\": \"Blokir @{name}\",\n  \"account.block_domain\": \"Sembunyikan segalanya dari {domain}\",\n  \"account.blocked\": \"Terblokir\",\n  \"account.direct\": \"Direct Message @{name}\",\n  \"account.domain_blocked\": \"Domain disembunyikan\",\n  \"account.edit_profile\": \"Ubah profil\",\n  \"account.endorse\": \"Feature on profile\",\n  \"account.follow\": \"Ikuti\",\n  \"account.followers\": \"Pengikut\",\n  \"account.followers.empty\": \"No one follows this user yet.\",\n  \"account.follows\": \"Mengikuti\",\n  \"account.follows.empty\": \"This user doesn't follow anyone yet.\",\n  \"account.follows_you\": \"Mengikuti anda\",\n  \"account.hide_reblogs\": \"Sembunyikan boosts dari @{name}\",\n  \"account.link_verified_on\": \"Ownership of this link was checked on {date}\",\n  \"account.locked_info\": \"This account privacy status is set to locked. The owner manually reviews who can follow them.\",\n  \"account.media\": \"Media\",\n  \"account.mention\": \"Balasan @{name}\",\n  \"account.moved_to\": \"{name} telah pindah ke:\",\n  \"account.mute\": \"Bisukan @{name}\",\n  \"account.mute_notifications\": \"Sembunyikan notifikasi dari @{name}\",\n  \"account.muted\": \"Dibisukan\",\n  \"account.posts\": \"Toots\",\n  \"account.posts_with_replies\": \"Postingan dengan balasan\",\n  \"account.report\": \"Laporkan @{name}\",\n  \"account.requested\": \"Menunggu persetujuan. Klik untuk membatalkan permintaan\",\n  \"account.share\": \"Bagikan profil @{name}\",\n  \"account.show_reblogs\": \"Tampilkan boost dari @{name}\",\n  \"account.unblock\": \"Hapus blokir @{name}\",\n  \"account.unblock_domain\": \"Tampilkan {domain}\",\n  \"account.unendorse\": \"Don't feature on profile\",\n  \"account.unfollow\": \"Berhenti mengikuti\",\n  \"account.unmute\": \"Berhenti membisukan @{name}\",\n  \"account.unmute_notifications\": \"Munculkan notifikasi dari @{name}\",\n  \"alert.unexpected.message\": \"An unexpected error occurred.\",\n  \"alert.unexpected.title\": \"Oops!\",\n  \"boost_modal.combo\": \"Anda dapat menekan {combo} untuk melewati ini\",\n  \"bundle_column_error.body\": \"Kesalahan terjadi saat memuat komponen ini.\",\n  \"bundle_column_error.retry\": \"Coba lagi\",\n  \"bundle_column_error.title\": \"Network error\",\n  \"bundle_modal_error.close\": \"Tutup\",\n  \"bundle_modal_error.message\": \"Kesalahan terjadi saat memuat komponen ini.\",\n  \"bundle_modal_error.retry\": \"Coba lagi\",\n  \"column.blocks\": \"Pengguna diblokir\",\n  \"column.community\": \"Linimasa Lokal\",\n  \"column.direct\": \"Direct messages\",\n  \"column.domain_blocks\": \"Hidden domains\",\n  \"column.favourites\": \"Favorit\",\n  \"column.follow_requests\": \"Permintaan mengikuti\",\n  \"column.home\": \"Beranda\",\n  \"column.lists\": \"List\",\n  \"column.mutes\": \"Pengguna yang dibisukan\",\n  \"column.notifications\": \"Notifikasi\",\n  \"column.pins\": \"Pinned toot\",\n  \"column.public\": \"Linimasa gabungan\",\n  \"column_back_button.label\": \"Kembali\",\n  \"column_header.hide_settings\": \"Sembunyikan pengaturan\",\n  \"column_header.moveLeft_settings\": \"Pindahkan kolom ke kiri\",\n  \"column_header.moveRight_settings\": \"Pindahkan kolom ke kanan\",\n  \"column_header.pin\": \"Sematkan\",\n  \"column_header.show_settings\": \"Tampilkan pengaturan\",\n  \"column_header.unpin\": \"Lepaskan\",\n  \"column_subheading.settings\": \"Pengaturan\",\n  \"community.column_settings.media_only\": \"Media Only\",\n  \"compose_form.direct_message_warning\": \"This toot will only be visible to all the mentioned users.\",\n  \"compose_form.direct_message_warning_learn_more\": \"Learn more\",\n  \"compose_form.hashtag_warning\": \"Toot ini tidak akan ada dalam daftar tagar manapun karena telah di set sebagai tidak terdaftar. Hanya postingan publik yang bisa dicari dengan tagar.\",\n  \"compose_form.lock_disclaimer\": \"Akun anda tidak {locked}. Semua orang dapat mengikuti anda untuk melihat postingan khusus untuk pengikut anda.\",\n  \"compose_form.lock_disclaimer.lock\": \"terkunci\",\n  \"compose_form.placeholder\": \"Apa yang ada di pikiran anda?\",\n  \"compose_form.poll.add_option\": \"Add a choice\",\n  \"compose_form.poll.duration\": \"Poll duration\",\n  \"compose_form.poll.option_placeholder\": \"Choice {number}\",\n  \"compose_form.poll.remove_option\": \"Remove this choice\",\n  \"compose_form.publish\": \"Toot\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"Mark media as sensitive\",\n  \"compose_form.sensitive.marked\": \"Sumber ini telah ditandai sebagai sumber sensitif.\",\n  \"compose_form.sensitive.unmarked\": \"Sumber ini tidak ditandai sebagai sumber sensitif\",\n  \"compose_form.spoiler.marked\": \"Teks disembunyikan dibalik peringatan\",\n  \"compose_form.spoiler.unmarked\": \"Teks tidak tersembunyi\",\n  \"compose_form.spoiler_placeholder\": \"Peringatan konten\",\n  \"confirmation_modal.cancel\": \"Batal\",\n  \"confirmations.block.block_and_report\": \"Block & Report\",\n  \"confirmations.block.confirm\": \"Blokir\",\n  \"confirmations.block.message\": \"Apa anda yakin ingin memblokir {name}?\",\n  \"confirmations.delete.confirm\": \"Hapus\",\n  \"confirmations.delete.message\": \"Apa anda yakin untuk menghapus status ini?\",\n  \"confirmations.delete_list.confirm\": \"Delete\",\n  \"confirmations.delete_list.message\": \"Apakah anda yakin untuk menghapus daftar ini secara permanen?\",\n  \"confirmations.domain_block.confirm\": \"Sembunyikan keseluruhan domain\",\n  \"confirmations.domain_block.message\": \"Apakah anda benar benar yakin untuk memblokir keseluruhan {domain}? Dalam kasus tertentu beberapa pemblokiran atau penyembunyian lebih baik.\",\n  \"confirmations.mute.confirm\": \"Bisukan\",\n  \"confirmations.mute.message\": \"Apa anda yakin ingin membisukan {name}?\",\n  \"confirmations.redraft.confirm\": \"Delete & redraft\",\n  \"confirmations.redraft.message\": \"Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.\",\n  \"confirmations.reply.confirm\": \"Reply\",\n  \"confirmations.reply.message\": \"Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?\",\n  \"confirmations.unfollow.confirm\": \"Berhenti mengikuti\",\n  \"confirmations.unfollow.message\": \"Apakah anda ingin berhenti mengikuti {name}?\",\n  \"embed.instructions\": \"Sematkan status ini di website anda dengan menyalin kode di bawah ini.\",\n  \"embed.preview\": \"Seperti ini nantinya:\",\n  \"emoji_button.activity\": \"Aktivitas\",\n  \"emoji_button.custom\": \"Kustom\",\n  \"emoji_button.flags\": \"Bendera\",\n  \"emoji_button.food\": \"Makanan & Minuman\",\n  \"emoji_button.label\": \"Tambahkan emoji\",\n  \"emoji_button.nature\": \"Alam\",\n  \"emoji_button.not_found\": \"Katakan tidak pada emoji!! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"Benda-benda\",\n  \"emoji_button.people\": \"Orang\",\n  \"emoji_button.recent\": \"Yang sering digunakan\",\n  \"emoji_button.search\": \"Cari...\",\n  \"emoji_button.search_results\": \"Hasil pencarian\",\n  \"emoji_button.symbols\": \"Simbol\",\n  \"emoji_button.travel\": \"Tempat Wisata\",\n  \"empty_column.account_timeline\": \"No toots here!\",\n  \"empty_column.account_unavailable\": \"Profile unavailable\",\n  \"empty_column.blocks\": \"You haven't blocked any users yet.\",\n  \"empty_column.community\": \"Linimasa lokal masih kosong. Tulis sesuatu secara publik dan buat roda berputar!\",\n  \"empty_column.direct\": \"You don't have any direct messages yet. When you send or receive one, it will show up here.\",\n  \"empty_column.domain_blocks\": \"There are no hidden domains yet.\",\n  \"empty_column.favourited_statuses\": \"You don't have any favourite toots yet. When you favourite one, it will show up here.\",\n  \"empty_column.favourites\": \"No one has favourited this toot yet. When someone does, they will show up here.\",\n  \"empty_column.follow_requests\": \"You don't have any follow requests yet. When you receive one, it will show up here.\",\n  \"empty_column.hashtag\": \"Tidak ada apapun dalam hashtag ini.\",\n  \"empty_column.home\": \"Linimasa anda kosong! Kunjungi {public} atau gunakan pencarian untuk memulai dan bertemu pengguna lain.\",\n  \"empty_column.home.public_timeline\": \"linimasa publik\",\n  \"empty_column.list\": \"Tidak ada postingan di list ini. Ketika anggota dari list ini memposting status baru, status tersebut akan tampil disini.\",\n  \"empty_column.lists\": \"You don't have any lists yet. When you create one, it will show up here.\",\n  \"empty_column.mutes\": \"You haven't muted any users yet.\",\n  \"empty_column.notifications\": \"Anda tidak memiliki notifikasi apapun. Berinteraksi dengan orang lain untuk memulai percakapan.\",\n  \"empty_column.public\": \"Tidak ada apapun disini! Tulis sesuatu, atau ikuti pengguna lain dari server lain untuk mengisi ini\",\n  \"follow_request.authorize\": \"Izinkan\",\n  \"follow_request.reject\": \"Tolak\",\n  \"getting_started.developers\": \"Developers\",\n  \"getting_started.directory\": \"Profile directory\",\n  \"getting_started.documentation\": \"Documentation\",\n  \"getting_started.heading\": \"Mulai\",\n  \"getting_started.invite\": \"Invite people\",\n  \"getting_started.open_source_notice\": \"Mastodon adalah perangkat lunak yang bersifat terbuka. Anda dapat berkontribusi atau melaporkan permasalahan/bug di Github {github}.\",\n  \"getting_started.security\": \"Security\",\n  \"getting_started.terms\": \"Terms of service\",\n  \"hashtag.column_header.tag_mode.all\": \"and {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"or {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"without {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"No suggestions found\",\n  \"hashtag.column_settings.select.placeholder\": \"Enter hashtags…\",\n  \"hashtag.column_settings.tag_mode.all\": \"All of these\",\n  \"hashtag.column_settings.tag_mode.any\": \"Any of these\",\n  \"hashtag.column_settings.tag_mode.none\": \"None of these\",\n  \"hashtag.column_settings.tag_toggle\": \"Include additional tags in this column\",\n  \"home.column_settings.basic\": \"Dasar\",\n  \"home.column_settings.show_reblogs\": \"Tampilkan boost\",\n  \"home.column_settings.show_replies\": \"Tampilkan balasan\",\n  \"intervals.full.days\": \"{number, plural, one {# day} other {# days}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# hour} other {# hours}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minute} other {# minutes}}\",\n  \"introduction.federation.action\": \"Next\",\n  \"introduction.federation.federated.headline\": \"Federated\",\n  \"introduction.federation.federated.text\": \"Public posts from other servers of the fediverse will appear in the federated timeline.\",\n  \"introduction.federation.home.headline\": \"Home\",\n  \"introduction.federation.home.text\": \"Posts from people you follow will appear in your home feed. You can follow anyone on any server!\",\n  \"introduction.federation.local.headline\": \"Local\",\n  \"introduction.federation.local.text\": \"Public posts from people on the same server as you will appear in the local timeline.\",\n  \"introduction.interactions.action\": \"Finish toot-orial!\",\n  \"introduction.interactions.favourite.headline\": \"Favourite\",\n  \"introduction.interactions.favourite.text\": \"You can save a toot for later, and let the author know that you liked it, by favouriting it.\",\n  \"introduction.interactions.reblog.headline\": \"Boost\",\n  \"introduction.interactions.reblog.text\": \"You can share other people's toots with your followers by boosting them.\",\n  \"introduction.interactions.reply.headline\": \"Reply\",\n  \"introduction.interactions.reply.text\": \"You can reply to other people's and your own toots, which will chain them together in a conversation.\",\n  \"introduction.welcome.action\": \"Let's go!\",\n  \"introduction.welcome.headline\": \"First steps\",\n  \"introduction.welcome.text\": \"Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.\",\n  \"keyboard_shortcuts.back\": \"untuk kembali\",\n  \"keyboard_shortcuts.blocked\": \"to open blocked users list\",\n  \"keyboard_shortcuts.boost\": \"untuk menyebarkan\",\n  \"keyboard_shortcuts.column\": \"untuk fokus kepada sebuah status di sebuah kolom\",\n  \"keyboard_shortcuts.compose\": \"untuk fokus ke area penulisan\",\n  \"keyboard_shortcuts.description\": \"Deskripsi\",\n  \"keyboard_shortcuts.direct\": \"to open direct messages column\",\n  \"keyboard_shortcuts.down\": \"untuk pindah ke bawah dalam sebuah daftar\",\n  \"keyboard_shortcuts.enter\": \"untuk membuka status\",\n  \"keyboard_shortcuts.favourite\": \"untuk memfavoritkan\",\n  \"keyboard_shortcuts.favourites\": \"to open favourites list\",\n  \"keyboard_shortcuts.federated\": \"to open federated timeline\",\n  \"keyboard_shortcuts.heading\": \"Pintasan keyboard\",\n  \"keyboard_shortcuts.home\": \"to open home timeline\",\n  \"keyboard_shortcuts.hotkey\": \"Hotkey\",\n  \"keyboard_shortcuts.legend\": \"to display this legend\",\n  \"keyboard_shortcuts.local\": \"to open local timeline\",\n  \"keyboard_shortcuts.mention\": \"to mention author\",\n  \"keyboard_shortcuts.muted\": \"to open muted users list\",\n  \"keyboard_shortcuts.my_profile\": \"to open your profile\",\n  \"keyboard_shortcuts.notifications\": \"to open notifications column\",\n  \"keyboard_shortcuts.pinned\": \"to open pinned toots list\",\n  \"keyboard_shortcuts.profile\": \"to open author's profile\",\n  \"keyboard_shortcuts.reply\": \"to reply\",\n  \"keyboard_shortcuts.requests\": \"to open follow requests list\",\n  \"keyboard_shortcuts.search\": \"untuk fokus mencari\",\n  \"keyboard_shortcuts.start\": \"to open \\\"get started\\\" column\",\n  \"keyboard_shortcuts.toggle_hidden\": \"to show/hide text behind CW\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"to show/hide media\",\n  \"keyboard_shortcuts.toot\": \"to start a brand new toot\",\n  \"keyboard_shortcuts.unfocus\": \"to un-focus compose textarea/search\",\n  \"keyboard_shortcuts.up\": \"to move up in the list\",\n  \"lightbox.close\": \"Tutup\",\n  \"lightbox.next\": \"Next\",\n  \"lightbox.previous\": \"Previous\",\n  \"lightbox.view_context\": \"View context\",\n  \"lists.account.add\": \"Add to list\",\n  \"lists.account.remove\": \"Remove from list\",\n  \"lists.delete\": \"Delete list\",\n  \"lists.edit\": \"Edit list\",\n  \"lists.edit.submit\": \"Change title\",\n  \"lists.new.create\": \"Add list\",\n  \"lists.new.title_placeholder\": \"New list title\",\n  \"lists.search\": \"Search among people you follow\",\n  \"lists.subheading\": \"Your lists\",\n  \"loading_indicator.label\": \"Tunggu sebentar...\",\n  \"media_gallery.toggle_visible\": \"Tampil/Sembunyikan\",\n  \"missing_indicator.label\": \"Tidak ditemukan\",\n  \"missing_indicator.sublabel\": \"This resource could not be found\",\n  \"mute_modal.hide_notifications\": \"Hide notifications from this user?\",\n  \"navigation_bar.apps\": \"Mobile apps\",\n  \"navigation_bar.blocks\": \"Pengguna diblokir\",\n  \"navigation_bar.community_timeline\": \"Linimasa lokal\",\n  \"navigation_bar.compose\": \"Compose new toot\",\n  \"navigation_bar.direct\": \"Direct messages\",\n  \"navigation_bar.discover\": \"Discover\",\n  \"navigation_bar.domain_blocks\": \"Hidden domains\",\n  \"navigation_bar.edit_profile\": \"Ubah profil\",\n  \"navigation_bar.favourites\": \"Favorit\",\n  \"navigation_bar.filters\": \"Muted words\",\n  \"navigation_bar.follow_requests\": \"Permintaan mengikuti\",\n  \"navigation_bar.follows_and_followers\": \"Follows and followers\",\n  \"navigation_bar.info\": \"Informasi selengkapnya\",\n  \"navigation_bar.keyboard_shortcuts\": \"Keyboard shortcuts\",\n  \"navigation_bar.lists\": \"Lists\",\n  \"navigation_bar.logout\": \"Keluar\",\n  \"navigation_bar.mutes\": \"Pengguna dibisukan\",\n  \"navigation_bar.personal\": \"Personal\",\n  \"navigation_bar.pins\": \"Pinned toots\",\n  \"navigation_bar.preferences\": \"Pengaturan\",\n  \"navigation_bar.profile_directory\": \"Profile directory\",\n  \"navigation_bar.public_timeline\": \"Linimasa gabungan\",\n  \"navigation_bar.security\": \"Security\",\n  \"notification.favourite\": \"{name} menyukai status anda\",\n  \"notification.follow\": \"{name} mengikuti anda\",\n  \"notification.mention\": \"{name} mentioned you\",\n  \"notification.poll\": \"A poll you have voted in has ended\",\n  \"notification.reblog\": \"{name} mem-boost status anda\",\n  \"notifications.clear\": \"Hapus notifikasi\",\n  \"notifications.clear_confirmation\": \"Apa anda yakin hendak menghapus semua notifikasi anda?\",\n  \"notifications.column_settings.alert\": \"Notifikasi desktop\",\n  \"notifications.column_settings.favourite\": \"Favorit:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Display all categories\",\n  \"notifications.column_settings.filter_bar.category\": \"Quick filter bar\",\n  \"notifications.column_settings.filter_bar.show\": \"Show\",\n  \"notifications.column_settings.follow\": \"Pengikut baru:\",\n  \"notifications.column_settings.mention\": \"Balasan:\",\n  \"notifications.column_settings.poll\": \"Poll results:\",\n  \"notifications.column_settings.push\": \"Push notifications\",\n  \"notifications.column_settings.reblog\": \"Boost:\",\n  \"notifications.column_settings.show\": \"Tampilkan dalam kolom\",\n  \"notifications.column_settings.sound\": \"Mainkan suara\",\n  \"notifications.filter.all\": \"All\",\n  \"notifications.filter.boosts\": \"Boosts\",\n  \"notifications.filter.favourites\": \"Favourites\",\n  \"notifications.filter.follows\": \"Follows\",\n  \"notifications.filter.mentions\": \"Mentions\",\n  \"notifications.filter.polls\": \"Poll results\",\n  \"notifications.group\": \"{count} notifications\",\n  \"poll.closed\": \"Closed\",\n  \"poll.refresh\": \"Refresh\",\n  \"poll.total_votes\": \"{count, plural, one {# vote} other {# votes}}\",\n  \"poll.vote\": \"Vote\",\n  \"poll_button.add_poll\": \"Add a poll\",\n  \"poll_button.remove_poll\": \"Remove poll\",\n  \"privacy.change\": \"Tentukan privasi status\",\n  \"privacy.direct.long\": \"Kirim hanya ke pengguna yang disebut\",\n  \"privacy.direct.short\": \"Langsung\",\n  \"privacy.private.long\": \"Kirim postingan hanya kepada pengikut\",\n  \"privacy.private.short\": \"Pribadi\",\n  \"privacy.public.long\": \"Kirim ke linimasa publik\",\n  \"privacy.public.short\": \"Publik\",\n  \"privacy.unlisted.long\": \"Tidak ditampilkan di linimasa publik\",\n  \"privacy.unlisted.short\": \"Tak Terdaftar\",\n  \"regeneration_indicator.label\": \"Loading…\",\n  \"regeneration_indicator.sublabel\": \"Linimasa anda sedang disiapkan!\",\n  \"relative_time.days\": \"{number}d\",\n  \"relative_time.hours\": \"{number}h\",\n  \"relative_time.just_now\": \"now\",\n  \"relative_time.minutes\": \"{number}m\",\n  \"relative_time.seconds\": \"{number}s\",\n  \"reply_indicator.cancel\": \"Batal\",\n  \"report.forward\": \"Forward to {target}\",\n  \"report.forward_hint\": \"The account is from another server. Send an anonymized copy of the report there as well?\",\n  \"report.hint\": \"The report will be sent to your instance moderators. You can provide an explanation of why you are reporting this account below:\",\n  \"report.placeholder\": \"Komentar tambahan\",\n  \"report.submit\": \"Kirim\",\n  \"report.target\": \"Melaporkan\",\n  \"search.placeholder\": \"Pencarian\",\n  \"search_popout.search_format\": \"Advanced search format\",\n  \"search_popout.tips.full_text\": \"Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.\",\n  \"search_popout.tips.hashtag\": \"tagar\",\n  \"search_popout.tips.status\": \"status\",\n  \"search_popout.tips.text\": \"Simple text returns matching display names, usernames and hashtags\",\n  \"search_popout.tips.user\": \"user\",\n  \"search_results.accounts\": \"People\",\n  \"search_results.hashtags\": \"Hashtags\",\n  \"search_results.statuses\": \"Toots\",\n  \"search_results.total\": \"{count, number} {count, plural, one {hasil} other {hasil}}\",\n  \"status.admin_account\": \"Open moderation interface for @{name}\",\n  \"status.admin_status\": \"Open this status in the moderation interface\",\n  \"status.block\": \"Block @{name}\",\n  \"status.cancel_reblog_private\": \"Unboost\",\n  \"status.cannot_reblog\": \"This post cannot be boosted\",\n  \"status.copy\": \"Copy link to status\",\n  \"status.delete\": \"Hapus\",\n  \"status.detailed_status\": \"Detailed conversation view\",\n  \"status.direct\": \"Direct message @{name}\",\n  \"status.embed\": \"Embed\",\n  \"status.favourite\": \"Difavoritkan\",\n  \"status.filtered\": \"Filtered\",\n  \"status.load_more\": \"Tampilkan semua\",\n  \"status.media_hidden\": \"Media disembunyikan\",\n  \"status.mention\": \"Balasan @{name}\",\n  \"status.more\": \"More\",\n  \"status.mute\": \"Mute @{name}\",\n  \"status.mute_conversation\": \"Mute conversation\",\n  \"status.open\": \"Tampilkan status ini\",\n  \"status.pin\": \"Pin on profile\",\n  \"status.pinned\": \"Pinned toot\",\n  \"status.read_more\": \"Read more\",\n  \"status.reblog\": \"Boost\",\n  \"status.reblog_private\": \"Boost to original audience\",\n  \"status.reblogged_by\": \"di-boost {name}\",\n  \"status.reblogs.empty\": \"No one has boosted this toot yet. When someone does, they will show up here.\",\n  \"status.redraft\": \"Delete & re-draft\",\n  \"status.reply\": \"Balas\",\n  \"status.replyAll\": \"Balas ke semua\",\n  \"status.report\": \"Laporkan @{name}\",\n  \"status.sensitive_warning\": \"Konten sensitif\",\n  \"status.share\": \"Share\",\n  \"status.show_less\": \"Tampilkan lebih sedikit\",\n  \"status.show_less_all\": \"Show less for all\",\n  \"status.show_more\": \"Tampilkan semua\",\n  \"status.show_more_all\": \"Show more for all\",\n  \"status.show_thread\": \"Show thread\",\n  \"status.unmute_conversation\": \"Unmute conversation\",\n  \"status.unpin\": \"Unpin from profile\",\n  \"suggestions.dismiss\": \"Dismiss suggestion\",\n  \"suggestions.header\": \"You might be interested in…\",\n  \"tabs_bar.federated_timeline\": \"Gabungan\",\n  \"tabs_bar.home\": \"Beranda\",\n  \"tabs_bar.local_timeline\": \"Lokal\",\n  \"tabs_bar.notifications\": \"Notifikasi\",\n  \"tabs_bar.search\": \"Search\",\n  \"time_remaining.days\": \"{number, plural, one {# day} other {# days}} left\",\n  \"time_remaining.hours\": \"{number, plural, one {# hour} other {# hours}} left\",\n  \"time_remaining.minutes\": \"{number, plural, one {# minute} other {# minutes}} left\",\n  \"time_remaining.moments\": \"Moments remaining\",\n  \"time_remaining.seconds\": \"{number, plural, one {# second} other {# seconds}} left\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {person} other {people}} talking\",\n  \"ui.beforeunload\": \"Naskah anda akan hilang jika anda keluar dari Mastodon.\",\n  \"upload_area.title\": \"Seret & lepaskan untuk mengunggah\",\n  \"upload_button.label\": \"Tambahkan media\",\n  \"upload_error.limit\": \"File upload limit exceeded.\",\n  \"upload_error.poll\": \"File upload not allowed with polls.\",\n  \"upload_form.description\": \"Deskripsikan untuk mereka yang tidak bisa melihat dengan jelas\",\n  \"upload_form.focus\": \"Potong\",\n  \"upload_form.undo\": \"Undo\",\n  \"upload_progress.label\": \"Mengunggah...\",\n  \"video.close\": \"Close video\",\n  \"video.exit_fullscreen\": \"Keluar dari layar penuh\",\n  \"video.expand\": \"Perbesar video\",\n  \"video.fullscreen\": \"Full screen\",\n  \"video.hide\": \"Hide video\",\n  \"video.mute\": \"Mute sound\",\n  \"video.pause\": \"Pause\",\n  \"video.play\": \"Play\",\n  \"video.unmute\": \"Unmute sound\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/index.js",
    "content": "let theLocale;\n\nexport function setLocale(locale) {\n  theLocale = locale;\n}\n\nexport function getLocale() {\n  return theLocale;\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/io.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Add or Remove from lists\",\n  \"account.badges.bot\": \"Bot\",\n  \"account.block\": \"Blokusar @{name}\",\n  \"account.block_domain\": \"Hide everything from {domain}\",\n  \"account.blocked\": \"Blocked\",\n  \"account.direct\": \"Direct Message @{name}\",\n  \"account.domain_blocked\": \"Domain hidden\",\n  \"account.edit_profile\": \"Modifikar profilo\",\n  \"account.endorse\": \"Feature on profile\",\n  \"account.follow\": \"Sequar\",\n  \"account.followers\": \"Sequanti\",\n  \"account.followers.empty\": \"No one follows this user yet.\",\n  \"account.follows\": \"Sequas\",\n  \"account.follows.empty\": \"This user doesn't follow anyone yet.\",\n  \"account.follows_you\": \"Sequas tu\",\n  \"account.hide_reblogs\": \"Hide boosts from @{name}\",\n  \"account.link_verified_on\": \"Ownership of this link was checked on {date}\",\n  \"account.locked_info\": \"This account privacy status is set to locked. The owner manually reviews who can follow them.\",\n  \"account.media\": \"Media\",\n  \"account.mention\": \"Mencionar @{name}\",\n  \"account.moved_to\": \"{name} has moved to:\",\n  \"account.mute\": \"Celar @{name}\",\n  \"account.mute_notifications\": \"Mute notifications from @{name}\",\n  \"account.muted\": \"Muted\",\n  \"account.posts\": \"Mesaji\",\n  \"account.posts_with_replies\": \"Toots with replies\",\n  \"account.report\": \"Denuncar @{name}\",\n  \"account.requested\": \"Vartante aprobo\",\n  \"account.share\": \"Share @{name}'s profile\",\n  \"account.show_reblogs\": \"Show boosts from @{name}\",\n  \"account.unblock\": \"Desblokusar @{name}\",\n  \"account.unblock_domain\": \"Unhide {domain}\",\n  \"account.unendorse\": \"Don't feature on profile\",\n  \"account.unfollow\": \"Ne plus sequar\",\n  \"account.unmute\": \"Ne plus celar @{name}\",\n  \"account.unmute_notifications\": \"Unmute notifications from @{name}\",\n  \"alert.unexpected.message\": \"An unexpected error occurred.\",\n  \"alert.unexpected.title\": \"Oops!\",\n  \"boost_modal.combo\": \"Tu povas presar sur {combo} por omisar co en la venonta foyo\",\n  \"bundle_column_error.body\": \"Something went wrong while loading this component.\",\n  \"bundle_column_error.retry\": \"Try again\",\n  \"bundle_column_error.title\": \"Network error\",\n  \"bundle_modal_error.close\": \"Close\",\n  \"bundle_modal_error.message\": \"Something went wrong while loading this component.\",\n  \"bundle_modal_error.retry\": \"Try again\",\n  \"column.blocks\": \"Blokusita uzeri\",\n  \"column.community\": \"Lokala tempolineo\",\n  \"column.direct\": \"Direct messages\",\n  \"column.domain_blocks\": \"Hidden domains\",\n  \"column.favourites\": \"Favorati\",\n  \"column.follow_requests\": \"Demandi di sequado\",\n  \"column.home\": \"Hemo\",\n  \"column.lists\": \"Lists\",\n  \"column.mutes\": \"Celita uzeri\",\n  \"column.notifications\": \"Savigi\",\n  \"column.pins\": \"Pinned toot\",\n  \"column.public\": \"Federata tempolineo\",\n  \"column_back_button.label\": \"Retro\",\n  \"column_header.hide_settings\": \"Hide settings\",\n  \"column_header.moveLeft_settings\": \"Move column to the left\",\n  \"column_header.moveRight_settings\": \"Move column to the right\",\n  \"column_header.pin\": \"Pin\",\n  \"column_header.show_settings\": \"Show settings\",\n  \"column_header.unpin\": \"Unpin\",\n  \"column_subheading.settings\": \"Settings\",\n  \"community.column_settings.media_only\": \"Media Only\",\n  \"compose_form.direct_message_warning\": \"This toot will only be visible to all the mentioned users.\",\n  \"compose_form.direct_message_warning_learn_more\": \"Learn more\",\n  \"compose_form.hashtag_warning\": \"This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.\",\n  \"compose_form.lock_disclaimer\": \"Your account is not {locked}. Anyone can follow you to view your follower-only posts.\",\n  \"compose_form.lock_disclaimer.lock\": \"locked\",\n  \"compose_form.placeholder\": \"Quo esas en tua spirito?\",\n  \"compose_form.poll.add_option\": \"Add a choice\",\n  \"compose_form.poll.duration\": \"Poll duration\",\n  \"compose_form.poll.option_placeholder\": \"Choice {number}\",\n  \"compose_form.poll.remove_option\": \"Remove this choice\",\n  \"compose_form.publish\": \"Siflar\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"Mark media as sensitive\",\n  \"compose_form.sensitive.marked\": \"Media is marked as sensitive\",\n  \"compose_form.sensitive.unmarked\": \"Media is not marked as sensitive\",\n  \"compose_form.spoiler.marked\": \"Text is hidden behind warning\",\n  \"compose_form.spoiler.unmarked\": \"Text is not hidden\",\n  \"compose_form.spoiler_placeholder\": \"Averto di kontenajo\",\n  \"confirmation_modal.cancel\": \"Cancel\",\n  \"confirmations.block.block_and_report\": \"Block & Report\",\n  \"confirmations.block.confirm\": \"Block\",\n  \"confirmations.block.message\": \"Are you sure you want to block {name}?\",\n  \"confirmations.delete.confirm\": \"Delete\",\n  \"confirmations.delete.message\": \"Are you sure you want to delete this status?\",\n  \"confirmations.delete_list.confirm\": \"Delete\",\n  \"confirmations.delete_list.message\": \"Are you sure you want to permanently delete this list?\",\n  \"confirmations.domain_block.confirm\": \"Hide entire domain\",\n  \"confirmations.domain_block.message\": \"Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.\",\n  \"confirmations.mute.confirm\": \"Mute\",\n  \"confirmations.mute.message\": \"Are you sure you want to mute {name}?\",\n  \"confirmations.redraft.confirm\": \"Delete & redraft\",\n  \"confirmations.redraft.message\": \"Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.\",\n  \"confirmations.reply.confirm\": \"Reply\",\n  \"confirmations.reply.message\": \"Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?\",\n  \"confirmations.unfollow.confirm\": \"Unfollow\",\n  \"confirmations.unfollow.message\": \"Are you sure you want to unfollow {name}?\",\n  \"embed.instructions\": \"Embed this status on your website by copying the code below.\",\n  \"embed.preview\": \"Here is what it will look like:\",\n  \"emoji_button.activity\": \"Activity\",\n  \"emoji_button.custom\": \"Custom\",\n  \"emoji_button.flags\": \"Flags\",\n  \"emoji_button.food\": \"Food & Drink\",\n  \"emoji_button.label\": \"Insertar emoji\",\n  \"emoji_button.nature\": \"Nature\",\n  \"emoji_button.not_found\": \"No emojos!! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"Objects\",\n  \"emoji_button.people\": \"People\",\n  \"emoji_button.recent\": \"Frequently used\",\n  \"emoji_button.search\": \"Search...\",\n  \"emoji_button.search_results\": \"Search results\",\n  \"emoji_button.symbols\": \"Symbols\",\n  \"emoji_button.travel\": \"Travel & Places\",\n  \"empty_column.account_timeline\": \"No toots here!\",\n  \"empty_column.account_unavailable\": \"Profile unavailable\",\n  \"empty_column.blocks\": \"You haven't blocked any users yet.\",\n  \"empty_column.community\": \"La lokala tempolineo esas vakua. Skribez ulo publike por iniciar la agiveso!\",\n  \"empty_column.direct\": \"You don't have any direct messages yet. When you send or receive one, it will show up here.\",\n  \"empty_column.domain_blocks\": \"There are no hidden domains yet.\",\n  \"empty_column.favourited_statuses\": \"You don't have any favourite toots yet. When you favourite one, it will show up here.\",\n  \"empty_column.favourites\": \"No one has favourited this toot yet. When someone does, they will show up here.\",\n  \"empty_column.follow_requests\": \"You don't have any follow requests yet. When you receive one, it will show up here.\",\n  \"empty_column.hashtag\": \"Esas ankore nulo en ta gretovorto.\",\n  \"empty_column.home\": \"Tu sequas ankore nulu. Vizitez {public} od uzez la serchilo por komencar e renkontrar altra uzeri.\",\n  \"empty_column.home.public_timeline\": \"la publika tempolineo\",\n  \"empty_column.list\": \"There is nothing in this list yet.\",\n  \"empty_column.lists\": \"You don't have any lists yet. When you create one, it will show up here.\",\n  \"empty_column.mutes\": \"You haven't muted any users yet.\",\n  \"empty_column.notifications\": \"Tu havas ankore nula savigo. Komunikez kun altri por debutar la konverso.\",\n  \"empty_column.public\": \"Esas nulo hike! Skribez ulo publike, o manuale sequez uzeri de altra instaluri por plenigar ol.\",\n  \"follow_request.authorize\": \"Yurizar\",\n  \"follow_request.reject\": \"Refuzar\",\n  \"getting_started.developers\": \"Developers\",\n  \"getting_started.directory\": \"Profile directory\",\n  \"getting_started.documentation\": \"Documentation\",\n  \"getting_started.heading\": \"Debuto\",\n  \"getting_started.invite\": \"Invite people\",\n  \"getting_started.open_source_notice\": \"Mastodon esas programaro kun apertita kodexo. Tu povas kontributar o signalar problemi en GitHub ye {github}.\",\n  \"getting_started.security\": \"Security\",\n  \"getting_started.terms\": \"Terms of service\",\n  \"hashtag.column_header.tag_mode.all\": \"and {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"or {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"without {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"No suggestions found\",\n  \"hashtag.column_settings.select.placeholder\": \"Enter hashtags…\",\n  \"hashtag.column_settings.tag_mode.all\": \"All of these\",\n  \"hashtag.column_settings.tag_mode.any\": \"Any of these\",\n  \"hashtag.column_settings.tag_mode.none\": \"None of these\",\n  \"hashtag.column_settings.tag_toggle\": \"Include additional tags in this column\",\n  \"home.column_settings.basic\": \"Simpla\",\n  \"home.column_settings.show_reblogs\": \"Montrar repeti\",\n  \"home.column_settings.show_replies\": \"Montrar respondi\",\n  \"intervals.full.days\": \"{number, plural, one {# day} other {# days}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# hour} other {# hours}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minute} other {# minutes}}\",\n  \"introduction.federation.action\": \"Next\",\n  \"introduction.federation.federated.headline\": \"Federated\",\n  \"introduction.federation.federated.text\": \"Public posts from other servers of the fediverse will appear in the federated timeline.\",\n  \"introduction.federation.home.headline\": \"Home\",\n  \"introduction.federation.home.text\": \"Posts from people you follow will appear in your home feed. You can follow anyone on any server!\",\n  \"introduction.federation.local.headline\": \"Local\",\n  \"introduction.federation.local.text\": \"Public posts from people on the same server as you will appear in the local timeline.\",\n  \"introduction.interactions.action\": \"Finish toot-orial!\",\n  \"introduction.interactions.favourite.headline\": \"Favourite\",\n  \"introduction.interactions.favourite.text\": \"You can save a toot for later, and let the author know that you liked it, by favouriting it.\",\n  \"introduction.interactions.reblog.headline\": \"Boost\",\n  \"introduction.interactions.reblog.text\": \"You can share other people's toots with your followers by boosting them.\",\n  \"introduction.interactions.reply.headline\": \"Reply\",\n  \"introduction.interactions.reply.text\": \"You can reply to other people's and your own toots, which will chain them together in a conversation.\",\n  \"introduction.welcome.action\": \"Let's go!\",\n  \"introduction.welcome.headline\": \"First steps\",\n  \"introduction.welcome.text\": \"Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.\",\n  \"keyboard_shortcuts.back\": \"to navigate back\",\n  \"keyboard_shortcuts.blocked\": \"to open blocked users list\",\n  \"keyboard_shortcuts.boost\": \"to boost\",\n  \"keyboard_shortcuts.column\": \"to focus a status in one of the columns\",\n  \"keyboard_shortcuts.compose\": \"to focus the compose textarea\",\n  \"keyboard_shortcuts.description\": \"Description\",\n  \"keyboard_shortcuts.direct\": \"to open direct messages column\",\n  \"keyboard_shortcuts.down\": \"to move down in the list\",\n  \"keyboard_shortcuts.enter\": \"to open status\",\n  \"keyboard_shortcuts.favourite\": \"to favourite\",\n  \"keyboard_shortcuts.favourites\": \"to open favourites list\",\n  \"keyboard_shortcuts.federated\": \"to open federated timeline\",\n  \"keyboard_shortcuts.heading\": \"Keyboard Shortcuts\",\n  \"keyboard_shortcuts.home\": \"to open home timeline\",\n  \"keyboard_shortcuts.hotkey\": \"Hotkey\",\n  \"keyboard_shortcuts.legend\": \"to display this legend\",\n  \"keyboard_shortcuts.local\": \"to open local timeline\",\n  \"keyboard_shortcuts.mention\": \"to mention author\",\n  \"keyboard_shortcuts.muted\": \"to open muted users list\",\n  \"keyboard_shortcuts.my_profile\": \"to open your profile\",\n  \"keyboard_shortcuts.notifications\": \"to open notifications column\",\n  \"keyboard_shortcuts.pinned\": \"to open pinned toots list\",\n  \"keyboard_shortcuts.profile\": \"to open author's profile\",\n  \"keyboard_shortcuts.reply\": \"to reply\",\n  \"keyboard_shortcuts.requests\": \"to open follow requests list\",\n  \"keyboard_shortcuts.search\": \"to focus search\",\n  \"keyboard_shortcuts.start\": \"to open \\\"get started\\\" column\",\n  \"keyboard_shortcuts.toggle_hidden\": \"to show/hide text behind CW\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"to show/hide media\",\n  \"keyboard_shortcuts.toot\": \"to start a brand new toot\",\n  \"keyboard_shortcuts.unfocus\": \"to un-focus compose textarea/search\",\n  \"keyboard_shortcuts.up\": \"to move up in the list\",\n  \"lightbox.close\": \"Klozar\",\n  \"lightbox.next\": \"Next\",\n  \"lightbox.previous\": \"Previous\",\n  \"lightbox.view_context\": \"View context\",\n  \"lists.account.add\": \"Add to list\",\n  \"lists.account.remove\": \"Remove from list\",\n  \"lists.delete\": \"Delete list\",\n  \"lists.edit\": \"Edit list\",\n  \"lists.edit.submit\": \"Change title\",\n  \"lists.new.create\": \"Add list\",\n  \"lists.new.title_placeholder\": \"New list title\",\n  \"lists.search\": \"Search among people you follow\",\n  \"lists.subheading\": \"Your lists\",\n  \"loading_indicator.label\": \"Kargante...\",\n  \"media_gallery.toggle_visible\": \"Chanjar videbleso\",\n  \"missing_indicator.label\": \"Ne trovita\",\n  \"missing_indicator.sublabel\": \"This resource could not be found\",\n  \"mute_modal.hide_notifications\": \"Hide notifications from this user?\",\n  \"navigation_bar.apps\": \"Mobile apps\",\n  \"navigation_bar.blocks\": \"Blokusita uzeri\",\n  \"navigation_bar.community_timeline\": \"Lokala tempolineo\",\n  \"navigation_bar.compose\": \"Compose new toot\",\n  \"navigation_bar.direct\": \"Direct messages\",\n  \"navigation_bar.discover\": \"Discover\",\n  \"navigation_bar.domain_blocks\": \"Hidden domains\",\n  \"navigation_bar.edit_profile\": \"Modifikar profilo\",\n  \"navigation_bar.favourites\": \"Favorati\",\n  \"navigation_bar.filters\": \"Muted words\",\n  \"navigation_bar.follow_requests\": \"Demandi di sequado\",\n  \"navigation_bar.follows_and_followers\": \"Follows and followers\",\n  \"navigation_bar.info\": \"Detaloza informi\",\n  \"navigation_bar.keyboard_shortcuts\": \"Keyboard shortcuts\",\n  \"navigation_bar.lists\": \"Lists\",\n  \"navigation_bar.logout\": \"Ekirar\",\n  \"navigation_bar.mutes\": \"Celita uzeri\",\n  \"navigation_bar.personal\": \"Personal\",\n  \"navigation_bar.pins\": \"Pinned toots\",\n  \"navigation_bar.preferences\": \"Preferi\",\n  \"navigation_bar.profile_directory\": \"Profile directory\",\n  \"navigation_bar.public_timeline\": \"Federata tempolineo\",\n  \"navigation_bar.security\": \"Security\",\n  \"notification.favourite\": \"{name} favorizis tua mesajo\",\n  \"notification.follow\": \"{name} sequeskis tu\",\n  \"notification.mention\": \"{name} mencionis tu\",\n  \"notification.poll\": \"A poll you have voted in has ended\",\n  \"notification.reblog\": \"{name} repetis tua mesajo\",\n  \"notifications.clear\": \"Efacar savigi\",\n  \"notifications.clear_confirmation\": \"Ka tu esas certa, ke tu volas efacar omna tua savigi?\",\n  \"notifications.column_settings.alert\": \"Surtabla savigi\",\n  \"notifications.column_settings.favourite\": \"Favorati:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Display all categories\",\n  \"notifications.column_settings.filter_bar.category\": \"Quick filter bar\",\n  \"notifications.column_settings.filter_bar.show\": \"Show\",\n  \"notifications.column_settings.follow\": \"Nova sequanti:\",\n  \"notifications.column_settings.mention\": \"Mencioni:\",\n  \"notifications.column_settings.poll\": \"Poll results:\",\n  \"notifications.column_settings.push\": \"Push notifications\",\n  \"notifications.column_settings.reblog\": \"Repeti:\",\n  \"notifications.column_settings.show\": \"Montrar en kolumno\",\n  \"notifications.column_settings.sound\": \"Plear sono\",\n  \"notifications.filter.all\": \"All\",\n  \"notifications.filter.boosts\": \"Boosts\",\n  \"notifications.filter.favourites\": \"Favourites\",\n  \"notifications.filter.follows\": \"Follows\",\n  \"notifications.filter.mentions\": \"Mentions\",\n  \"notifications.filter.polls\": \"Poll results\",\n  \"notifications.group\": \"{count} notifications\",\n  \"poll.closed\": \"Closed\",\n  \"poll.refresh\": \"Refresh\",\n  \"poll.total_votes\": \"{count, plural, one {# vote} other {# votes}}\",\n  \"poll.vote\": \"Vote\",\n  \"poll_button.add_poll\": \"Add a poll\",\n  \"poll_button.remove_poll\": \"Remove poll\",\n  \"privacy.change\": \"Aranjar privateso di mesaji\",\n  \"privacy.direct.long\": \"Sendar nur a mencionata uzeri\",\n  \"privacy.direct.short\": \"Direte\",\n  \"privacy.private.long\": \"Sendar nur a sequanti\",\n  \"privacy.private.short\": \"Private\",\n  \"privacy.public.long\": \"Sendar a publika tempolinei\",\n  \"privacy.public.short\": \"Publike\",\n  \"privacy.unlisted.long\": \"Ne montrar en publika tempolinei\",\n  \"privacy.unlisted.short\": \"Ne enlistigota\",\n  \"regeneration_indicator.label\": \"Loading…\",\n  \"regeneration_indicator.sublabel\": \"Your home feed is being prepared!\",\n  \"relative_time.days\": \"{number}d\",\n  \"relative_time.hours\": \"{number}h\",\n  \"relative_time.just_now\": \"now\",\n  \"relative_time.minutes\": \"{number}m\",\n  \"relative_time.seconds\": \"{number}s\",\n  \"reply_indicator.cancel\": \"Nihiligar\",\n  \"report.forward\": \"Forward to {target}\",\n  \"report.forward_hint\": \"The account is from another server. Send an anonymized copy of the report there as well?\",\n  \"report.hint\": \"The report will be sent to your instance moderators. You can provide an explanation of why you are reporting this account below:\",\n  \"report.placeholder\": \"Plusa komenti\",\n  \"report.submit\": \"Sendar\",\n  \"report.target\": \"Denuncante\",\n  \"search.placeholder\": \"Serchez\",\n  \"search_popout.search_format\": \"Advanced search format\",\n  \"search_popout.tips.full_text\": \"Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.\",\n  \"search_popout.tips.hashtag\": \"hashtag\",\n  \"search_popout.tips.status\": \"status\",\n  \"search_popout.tips.text\": \"Simple text returns matching display names, usernames and hashtags\",\n  \"search_popout.tips.user\": \"user\",\n  \"search_results.accounts\": \"People\",\n  \"search_results.hashtags\": \"Hashtags\",\n  \"search_results.statuses\": \"Toots\",\n  \"search_results.total\": \"{count, number} {count, plural, one {rezulto} other {rezulti}}\",\n  \"status.admin_account\": \"Open moderation interface for @{name}\",\n  \"status.admin_status\": \"Open this status in the moderation interface\",\n  \"status.block\": \"Block @{name}\",\n  \"status.cancel_reblog_private\": \"Unboost\",\n  \"status.cannot_reblog\": \"This post cannot be boosted\",\n  \"status.copy\": \"Copy link to status\",\n  \"status.delete\": \"Efacar\",\n  \"status.detailed_status\": \"Detailed conversation view\",\n  \"status.direct\": \"Direct message @{name}\",\n  \"status.embed\": \"Embed\",\n  \"status.favourite\": \"Favorizar\",\n  \"status.filtered\": \"Filtered\",\n  \"status.load_more\": \"Kargar pluse\",\n  \"status.media_hidden\": \"Kontenajo celita\",\n  \"status.mention\": \"Mencionar @{name}\",\n  \"status.more\": \"More\",\n  \"status.mute\": \"Mute @{name}\",\n  \"status.mute_conversation\": \"Mute conversation\",\n  \"status.open\": \"Detaligar ca mesajo\",\n  \"status.pin\": \"Pin on profile\",\n  \"status.pinned\": \"Pinned toot\",\n  \"status.read_more\": \"Read more\",\n  \"status.reblog\": \"Repetar\",\n  \"status.reblog_private\": \"Boost to original audience\",\n  \"status.reblogged_by\": \"{name} repetita\",\n  \"status.reblogs.empty\": \"No one has boosted this toot yet. When someone does, they will show up here.\",\n  \"status.redraft\": \"Delete & re-draft\",\n  \"status.reply\": \"Respondar\",\n  \"status.replyAll\": \"Respondar a filo\",\n  \"status.report\": \"Denuncar @{name}\",\n  \"status.sensitive_warning\": \"Trubliva kontenajo\",\n  \"status.share\": \"Share\",\n  \"status.show_less\": \"Montrar mine\",\n  \"status.show_less_all\": \"Show less for all\",\n  \"status.show_more\": \"Montrar plue\",\n  \"status.show_more_all\": \"Show more for all\",\n  \"status.show_thread\": \"Show thread\",\n  \"status.unmute_conversation\": \"Unmute conversation\",\n  \"status.unpin\": \"Unpin from profile\",\n  \"suggestions.dismiss\": \"Dismiss suggestion\",\n  \"suggestions.header\": \"You might be interested in…\",\n  \"tabs_bar.federated_timeline\": \"Federata\",\n  \"tabs_bar.home\": \"Hemo\",\n  \"tabs_bar.local_timeline\": \"Lokala\",\n  \"tabs_bar.notifications\": \"Savigi\",\n  \"tabs_bar.search\": \"Search\",\n  \"time_remaining.days\": \"{number, plural, one {# day} other {# days}} left\",\n  \"time_remaining.hours\": \"{number, plural, one {# hour} other {# hours}} left\",\n  \"time_remaining.minutes\": \"{number, plural, one {# minute} other {# minutes}} left\",\n  \"time_remaining.moments\": \"Moments remaining\",\n  \"time_remaining.seconds\": \"{number, plural, one {# second} other {# seconds}} left\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {person} other {people}} talking\",\n  \"ui.beforeunload\": \"Your draft will be lost if you leave Mastodon.\",\n  \"upload_area.title\": \"Tranar faligar por kargar\",\n  \"upload_button.label\": \"Adjuntar kontenajo\",\n  \"upload_error.limit\": \"File upload limit exceeded.\",\n  \"upload_error.poll\": \"File upload not allowed with polls.\",\n  \"upload_form.description\": \"Describe for the visually impaired\",\n  \"upload_form.focus\": \"Crop\",\n  \"upload_form.undo\": \"Desfacar\",\n  \"upload_progress.label\": \"Kargante...\",\n  \"video.close\": \"Close video\",\n  \"video.exit_fullscreen\": \"Exit full screen\",\n  \"video.expand\": \"Expand video\",\n  \"video.fullscreen\": \"Full screen\",\n  \"video.hide\": \"Hide video\",\n  \"video.mute\": \"Mute sound\",\n  \"video.pause\": \"Pause\",\n  \"video.play\": \"Play\",\n  \"video.unmute\": \"Unmute sound\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/it.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Aggiungi o togli dalle liste\",\n  \"account.badges.bot\": \"Bot\",\n  \"account.block\": \"Blocca @{name}\",\n  \"account.block_domain\": \"Nascondi tutto da {domain}\",\n  \"account.blocked\": \"Bloccato\",\n  \"account.direct\": \"Invia messaggio diretto a @{name}\",\n  \"account.domain_blocked\": \"Dominio nascosto\",\n  \"account.edit_profile\": \"Modifica profilo\",\n  \"account.endorse\": \"Metti in evidenza sul profilo\",\n  \"account.follow\": \"Segui\",\n  \"account.followers\": \"Seguaci\",\n  \"account.followers.empty\": \"Ancora nessuno segue questo utente.\",\n  \"account.follows\": \"Segue\",\n  \"account.follows.empty\": \"Questo utente non segue ancora nessuno.\",\n  \"account.follows_you\": \"Ti segue\",\n  \"account.hide_reblogs\": \"Nascondi condivisioni da @{name}\",\n  \"account.link_verified_on\": \"La proprietà di questo link è stata controllata il {date}\",\n  \"account.locked_info\": \"Il livello di privacy di questo account è impostato a \\\"bloccato\\\". Il proprietario esamina manualmente le richieste di seguirlo.\",\n  \"account.media\": \"Media\",\n  \"account.mention\": \"Menziona @{name}\",\n  \"account.moved_to\": \"{name} si è trasferito su:\",\n  \"account.mute\": \"Silenzia @{name}\",\n  \"account.mute_notifications\": \"Silenzia notifiche da @{name}\",\n  \"account.muted\": \"Silenziato\",\n  \"account.posts\": \"Toot\",\n  \"account.posts_with_replies\": \"Toot e risposte\",\n  \"account.report\": \"Segnala @{name}\",\n  \"account.requested\": \"In attesa di approvazione\",\n  \"account.share\": \"Condividi il profilo di @{name}\",\n  \"account.show_reblogs\": \"Mostra condivisioni da @{name}\",\n  \"account.unblock\": \"Sblocca @{name}\",\n  \"account.unblock_domain\": \"Non nascondere {domain}\",\n  \"account.unendorse\": \"Non mettere in evidenza sul profilo\",\n  \"account.unfollow\": \"Non seguire\",\n  \"account.unmute\": \"Non silenziare @{name}\",\n  \"account.unmute_notifications\": \"Non silenziare più le notifiche da @{name}\",\n  \"alert.unexpected.message\": \"Si è verificato un errore inatteso.\",\n  \"alert.unexpected.title\": \"Oops!\",\n  \"boost_modal.combo\": \"Puoi premere {combo} per saltare questo passaggio la prossima volta\",\n  \"bundle_column_error.body\": \"E' avvenuto un errore durante il caricamento di questo componente.\",\n  \"bundle_column_error.retry\": \"Riprova\",\n  \"bundle_column_error.title\": \"Network error\",\n  \"bundle_modal_error.close\": \"Chiudi\",\n  \"bundle_modal_error.message\": \"C'è stato un errore mentre questo componente veniva caricato.\",\n  \"bundle_modal_error.retry\": \"Riprova\",\n  \"column.blocks\": \"Utenti bloccati\",\n  \"column.community\": \"Timeline locale\",\n  \"column.direct\": \"Messaggi diretti\",\n  \"column.domain_blocks\": \"Domini nascosti\",\n  \"column.favourites\": \"Apprezzati\",\n  \"column.follow_requests\": \"Richieste di amicizia\",\n  \"column.home\": \"Home\",\n  \"column.lists\": \"Liste\",\n  \"column.mutes\": \"Utenti silenziati\",\n  \"column.notifications\": \"Notifiche\",\n  \"column.pins\": \"Toot fissati in cima\",\n  \"column.public\": \"Timeline federata\",\n  \"column_back_button.label\": \"Indietro\",\n  \"column_header.hide_settings\": \"Nascondi impostazioni\",\n  \"column_header.moveLeft_settings\": \"Sposta colonna a sinistra\",\n  \"column_header.moveRight_settings\": \"Sposta colonna a destra\",\n  \"column_header.pin\": \"Fissa in cima\",\n  \"column_header.show_settings\": \"Mostra impostazioni\",\n  \"column_header.unpin\": \"Non fissare in cima\",\n  \"column_subheading.settings\": \"Impostazioni\",\n  \"community.column_settings.media_only\": \"Solo media\",\n  \"compose_form.direct_message_warning\": \"Questo toot sarà mandato solo a tutti gli utenti menzionati.\",\n  \"compose_form.direct_message_warning_learn_more\": \"Per saperne di piu'\",\n  \"compose_form.hashtag_warning\": \"Questo toot non è listato, quindi non sarà trovato nelle ricerche per hashtag. Solo i toot pubblici possono essere cercati per hashtag.\",\n  \"compose_form.lock_disclaimer\": \"Il tuo account non è {bloccato}. Chiunque può decidere di seguirti per vedere i tuoi post per soli seguaci.\",\n  \"compose_form.lock_disclaimer.lock\": \"bloccato\",\n  \"compose_form.placeholder\": \"A cosa stai pensando?\",\n  \"compose_form.poll.add_option\": \"Add a choice\",\n  \"compose_form.poll.duration\": \"Poll duration\",\n  \"compose_form.poll.option_placeholder\": \"Choice {number}\",\n  \"compose_form.poll.remove_option\": \"Remove this choice\",\n  \"compose_form.publish\": \"Toot\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"Mark media as sensitive\",\n  \"compose_form.sensitive.marked\": \"Questo media è contrassegnato come sensibile\",\n  \"compose_form.sensitive.unmarked\": \"Questo media non è contrassegnato come sensibile\",\n  \"compose_form.spoiler.marked\": \"Il testo è nascosto dall'avviso\",\n  \"compose_form.spoiler.unmarked\": \"Il testo non è nascosto\",\n  \"compose_form.spoiler_placeholder\": \"Content warning\",\n  \"confirmation_modal.cancel\": \"Annulla\",\n  \"confirmations.block.block_and_report\": \"Block & Report\",\n  \"confirmations.block.confirm\": \"Blocca\",\n  \"confirmations.block.message\": \"Sei sicuro di voler bloccare {name}?\",\n  \"confirmations.delete.confirm\": \"Cancella\",\n  \"confirmations.delete.message\": \"Sei sicuro di voler cancellare questo status?\",\n  \"confirmations.delete_list.confirm\": \"Cancella\",\n  \"confirmations.delete_list.message\": \"Sei sicuro di voler cancellare definitivamente questa lista?\",\n  \"confirmations.domain_block.confirm\": \"Nascondi intero dominio\",\n  \"confirmations.domain_block.message\": \"Sei davvero sicuro che vuoi bloccare l'intero {domain}? Nella maggior parte dei casi, pochi blocchi o silenziamenti mirati sono sufficienti e preferibili. Non vedrai nessun contenuto di quel dominio né nelle timeline pubbliche né nelle notifiche. I tuoi seguaci di quel dominio saranno eliminati.\",\n  \"confirmations.mute.confirm\": \"Silenzia\",\n  \"confirmations.mute.message\": \"Sei sicuro di voler silenziare {name}?\",\n  \"confirmations.redraft.confirm\": \"Cancella e riscrivi\",\n  \"confirmations.redraft.message\": \"Sei sicuro di voler cancellare questo stato e riscriverlo? Perderai tutte le risposte, condivisioni e preferiti.\",\n  \"confirmations.reply.confirm\": \"Rispondi\",\n  \"confirmations.reply.message\": \"Se rispondi ora, il messaggio che stai componendo sarà sovrascritto. Sei sicuro di voler continuare?\",\n  \"confirmations.unfollow.confirm\": \"Smetti di seguire\",\n  \"confirmations.unfollow.message\": \"Sei sicuro che non vuoi più seguire {name}?\",\n  \"embed.instructions\": \"Inserisci questo status nel tuo sito copiando il codice qui sotto.\",\n  \"embed.preview\": \"Ecco come apparirà:\",\n  \"emoji_button.activity\": \"Attività\",\n  \"emoji_button.custom\": \"Personalizzato\",\n  \"emoji_button.flags\": \"Bandiere\",\n  \"emoji_button.food\": \"Cibo e bevande\",\n  \"emoji_button.label\": \"Inserisci emoji\",\n  \"emoji_button.nature\": \"Natura\",\n  \"emoji_button.not_found\": \"Nessun emojos!! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"Oggetti\",\n  \"emoji_button.people\": \"Persone\",\n  \"emoji_button.recent\": \"Usati di frequente\",\n  \"emoji_button.search\": \"Cerca...\",\n  \"emoji_button.search_results\": \"Risultati della ricerca\",\n  \"emoji_button.symbols\": \"Simboli\",\n  \"emoji_button.travel\": \"Viaggi e luoghi\",\n  \"empty_column.account_timeline\": \"Non ci sono toot qui!\",\n  \"empty_column.account_unavailable\": \"Profile unavailable\",\n  \"empty_column.blocks\": \"Non hai ancora bloccato nessun utente.\",\n  \"empty_column.community\": \"La timeline locale è vuota. Condividi qualcosa pubblicamente per dare inizio alla festa!\",\n  \"empty_column.direct\": \"Non hai ancora nessun messaggio diretto. Quando ne manderai o riceverai qualcuno, apparirà qui.\",\n  \"empty_column.domain_blocks\": \"Non vi sono domini nascosti.\",\n  \"empty_column.favourited_statuses\": \"Non hai ancora segnato nessun toot come apprezzato. Quando lo farai, comparirà qui.\",\n  \"empty_column.favourites\": \"Nessuno ha ancora segnato questo toot come apprezzato. Quando qualcuno lo farà, apparirà qui.\",\n  \"empty_column.follow_requests\": \"Non hai ancora ricevuto nessuna richiesta di seguirti. Quando ne arriveranno, saranno mostrate qui.\",\n  \"empty_column.hashtag\": \"Non c'è ancora nessun post con questo hashtag.\",\n  \"empty_column.home\": \"Non stai ancora seguendo nessuno. Visita {public} o usa la ricerca per incontrare nuove persone.\",\n  \"empty_column.home.public_timeline\": \"la timeline pubblica\",\n  \"empty_column.list\": \"Non c'è ancora niente in questa lista. Quando i membri di questa lista pubblicheranno nuovi stati, appariranno qui.\",\n  \"empty_column.lists\": \"Non hai ancora nessuna lista. Quando ne creerai qualcuna, comparirà qui.\",\n  \"empty_column.mutes\": \"Non hai ancora silenziato nessun utente.\",\n  \"empty_column.notifications\": \"Non hai ancora nessuna notifica. Interagisci con altri per iniziare conversazioni.\",\n  \"empty_column.public\": \"Qui non c'è nulla! Scrivi qualcosa pubblicamente, o aggiungi utenti da altri server per riempire questo spazio\",\n  \"follow_request.authorize\": \"Autorizza\",\n  \"follow_request.reject\": \"Rifiuta\",\n  \"getting_started.developers\": \"Sviluppatori\",\n  \"getting_started.directory\": \"Directory del profilo\",\n  \"getting_started.documentation\": \"Documentazione\",\n  \"getting_started.heading\": \"Come iniziare\",\n  \"getting_started.invite\": \"Invita qualcuno\",\n  \"getting_started.open_source_notice\": \"Mastodon è un software open source. Puoi contribuire o segnalare errori su GitHub all'indirizzo {github}.\",\n  \"getting_started.security\": \"Sicurezza\",\n  \"getting_started.terms\": \"Condizioni del servizio\",\n  \"hashtag.column_header.tag_mode.all\": \"e {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"o {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"senza {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"Nessun suggerimento trovato\",\n  \"hashtag.column_settings.select.placeholder\": \"Inserisci hashtag…\",\n  \"hashtag.column_settings.tag_mode.all\": \"Tutti questi\",\n  \"hashtag.column_settings.tag_mode.any\": \"Uno o più di questi\",\n  \"hashtag.column_settings.tag_mode.none\": \"Nessuno di questi\",\n  \"hashtag.column_settings.tag_toggle\": \"Include additional tags in this column\",\n  \"home.column_settings.basic\": \"Semplice\",\n  \"home.column_settings.show_reblogs\": \"Mostra post condivisi\",\n  \"home.column_settings.show_replies\": \"Mostra risposte\",\n  \"intervals.full.days\": \"{number, plural, one {# day} other {# days}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# hour} other {# hours}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minute} other {# minutes}}\",\n  \"introduction.federation.action\": \"Avanti\",\n  \"introduction.federation.federated.headline\": \"Federated\",\n  \"introduction.federation.federated.text\": \"I post pubblici provenienti da altri server del fediverse saranno mostrati nella timeline federata.\",\n  \"introduction.federation.home.headline\": \"Home\",\n  \"introduction.federation.home.text\": \"I post scritti da persone che segui saranno mostrati nella timeline home. Puoi seguire chiunque su qualunque server!\",\n  \"introduction.federation.local.headline\": \"Local\",\n  \"introduction.federation.local.text\": \"I post pubblici scritti da persone sul tuo stesso server saranno mostrati nella timeline locale.\",\n  \"introduction.interactions.action\": \"Finisci il tutorial!\",\n  \"introduction.interactions.favourite.headline\": \"Apprezza\",\n  \"introduction.interactions.favourite.text\": \"Puoi salvare un toot e tenerlo per dopo, e far sapere all'autore che ti è piaciuto, segnandolo come apprezzato.\",\n  \"introduction.interactions.reblog.headline\": \"Condividi\",\n  \"introduction.interactions.reblog.text\": \"Con la condivisione puoi segnalare i toot di altre persone ai tuoi seguaci .\",\n  \"introduction.interactions.reply.headline\": \"Rispondi\",\n  \"introduction.interactions.reply.text\": \"Puoi rispondere ai toot, sia a quelli di altri sia ai tuoi, e i toot saranno collegati a formare una conversazione.\",\n  \"introduction.welcome.action\": \"Andiamo!\",\n  \"introduction.welcome.headline\": \"Primi passi\",\n  \"introduction.welcome.text\": \"Benvenuto/a nel fediverse! Tra poco potrai inviare messaggi e parlare con i tuoi amici su una grande varietà di server. Ma questo server, {domain}, è speciale: ospita il tuo profilo, quindi ricordati il suo nome.\",\n  \"keyboard_shortcuts.back\": \"per tornare indietro\",\n  \"keyboard_shortcuts.blocked\": \"per aprire l'elenco degli utenti bloccati\",\n  \"keyboard_shortcuts.boost\": \"per condividere\",\n  \"keyboard_shortcuts.column\": \"per portare il focus su uno status in una delle colonne\",\n  \"keyboard_shortcuts.compose\": \"per portare il focus nell'area di composizione\",\n  \"keyboard_shortcuts.description\": \"Descrizione\",\n  \"keyboard_shortcuts.direct\": \"per aprire la colonna dei messaggi diretti\",\n  \"keyboard_shortcuts.down\": \"per spostarsi in basso nella lista\",\n  \"keyboard_shortcuts.enter\": \"per aprire lo status\",\n  \"keyboard_shortcuts.favourite\": \"per segnare come apprezzato\",\n  \"keyboard_shortcuts.favourites\": \"per aprire l'elenco dei toot apprezzati\",\n  \"keyboard_shortcuts.federated\": \"per aprire la timeline federata\",\n  \"keyboard_shortcuts.heading\": \"Tasti di scelta rapida\",\n  \"keyboard_shortcuts.home\": \"per aprire la timeline home\",\n  \"keyboard_shortcuts.hotkey\": \"Tasto di scelta rapida\",\n  \"keyboard_shortcuts.legend\": \"per mostrare questa spiegazione\",\n  \"keyboard_shortcuts.local\": \"per aprire la timeline locale\",\n  \"keyboard_shortcuts.mention\": \"per menzionare l'autore\",\n  \"keyboard_shortcuts.muted\": \"per aprire l'elenco degli utenti silenziati\",\n  \"keyboard_shortcuts.my_profile\": \"per aprire il tuo profilo\",\n  \"keyboard_shortcuts.notifications\": \"per aprire la colonna delle notifiche\",\n  \"keyboard_shortcuts.pinned\": \"per aprire l'elenco dei toot fissati in cima\",\n  \"keyboard_shortcuts.profile\": \"per aprire il profilo dell'autore\",\n  \"keyboard_shortcuts.reply\": \"per rispondere\",\n  \"keyboard_shortcuts.requests\": \"per aprire l'elenco delle richieste di seguirti\",\n  \"keyboard_shortcuts.search\": \"per spostare il focus sulla ricerca\",\n  \"keyboard_shortcuts.start\": \"per aprire la colonna \\\"Come iniziare\\\"\",\n  \"keyboard_shortcuts.toggle_hidden\": \"per mostrare/nascondere il testo dei CW\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"to show/hide media\",\n  \"keyboard_shortcuts.toot\": \"per iniziare a scrivere un toot completamente nuovo\",\n  \"keyboard_shortcuts.unfocus\": \"per uscire dall'area di composizione o dalla ricerca\",\n  \"keyboard_shortcuts.up\": \"per spostarsi in alto nella lista\",\n  \"lightbox.close\": \"Chiudi\",\n  \"lightbox.next\": \"Successivo\",\n  \"lightbox.previous\": \"Precedente\",\n  \"lightbox.view_context\": \"View context\",\n  \"lists.account.add\": \"Aggiungi alla lista\",\n  \"lists.account.remove\": \"Togli dalla lista\",\n  \"lists.delete\": \"Delete list\",\n  \"lists.edit\": \"Modifica lista\",\n  \"lists.edit.submit\": \"Cambia titolo\",\n  \"lists.new.create\": \"Aggiungi lista\",\n  \"lists.new.title_placeholder\": \"Titolo della nuova lista\",\n  \"lists.search\": \"Cerca tra le persone che segui\",\n  \"lists.subheading\": \"Le tue liste\",\n  \"loading_indicator.label\": \"Caricamento...\",\n  \"media_gallery.toggle_visible\": \"Imposta visibilità\",\n  \"missing_indicator.label\": \"Non trovato\",\n  \"missing_indicator.sublabel\": \"Risorsa non trovata\",\n  \"mute_modal.hide_notifications\": \"Nascondere le notifiche da quest'utente?\",\n  \"navigation_bar.apps\": \"App per dispositivi mobili\",\n  \"navigation_bar.blocks\": \"Utenti bloccati\",\n  \"navigation_bar.community_timeline\": \"Timeline locale\",\n  \"navigation_bar.compose\": \"Componi nuovo toot\",\n  \"navigation_bar.direct\": \"Messaggi diretti\",\n  \"navigation_bar.discover\": \"Scopri\",\n  \"navigation_bar.domain_blocks\": \"Domini nascosti\",\n  \"navigation_bar.edit_profile\": \"Modifica profilo\",\n  \"navigation_bar.favourites\": \"Apprezzati\",\n  \"navigation_bar.filters\": \"Parole silenziate\",\n  \"navigation_bar.follow_requests\": \"Richieste di amicizia\",\n  \"navigation_bar.follows_and_followers\": \"Follows and followers\",\n  \"navigation_bar.info\": \"Informazioni su questo server\",\n  \"navigation_bar.keyboard_shortcuts\": \"Tasti di scelta rapida\",\n  \"navigation_bar.lists\": \"Liste\",\n  \"navigation_bar.logout\": \"Esci\",\n  \"navigation_bar.mutes\": \"Utenti silenziati\",\n  \"navigation_bar.personal\": \"Personal\",\n  \"navigation_bar.pins\": \"Toot fissati in cima\",\n  \"navigation_bar.preferences\": \"Impostazioni\",\n  \"navigation_bar.profile_directory\": \"Profile directory\",\n  \"navigation_bar.public_timeline\": \"Timeline federata\",\n  \"navigation_bar.security\": \"Sicurezza\",\n  \"notification.favourite\": \"{name} ha apprezzato il tuo post\",\n  \"notification.follow\": \"{name} ha iniziato a seguirti\",\n  \"notification.mention\": \"{name} ti ha menzionato\",\n  \"notification.poll\": \"A poll you have voted in has ended\",\n  \"notification.reblog\": \"{name} ha condiviso il tuo post\",\n  \"notifications.clear\": \"Cancella notifiche\",\n  \"notifications.clear_confirmation\": \"Vuoi davvero cancellare tutte le notifiche?\",\n  \"notifications.column_settings.alert\": \"Notifiche desktop\",\n  \"notifications.column_settings.favourite\": \"Apprezzati:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Mostra tutte le categorie\",\n  \"notifications.column_settings.filter_bar.category\": \"Filtro rapido\",\n  \"notifications.column_settings.filter_bar.show\": \"Mostra\",\n  \"notifications.column_settings.follow\": \"Nuovi seguaci:\",\n  \"notifications.column_settings.mention\": \"Menzioni:\",\n  \"notifications.column_settings.poll\": \"Poll results:\",\n  \"notifications.column_settings.push\": \"Notifiche push\",\n  \"notifications.column_settings.reblog\": \"Post condivisi:\",\n  \"notifications.column_settings.show\": \"Mostra in colonna\",\n  \"notifications.column_settings.sound\": \"Riproduci suono\",\n  \"notifications.filter.all\": \"Tutti\",\n  \"notifications.filter.boosts\": \"Condivisioni\",\n  \"notifications.filter.favourites\": \"Apprezzati\",\n  \"notifications.filter.follows\": \"Seguaci\",\n  \"notifications.filter.mentions\": \"Menzioni\",\n  \"notifications.filter.polls\": \"Poll results\",\n  \"notifications.group\": \"{count} notifiche\",\n  \"poll.closed\": \"Chiuso\",\n  \"poll.refresh\": \"Aggiorna\",\n  \"poll.total_votes\": \"{count, plural, one {# voto} other {# voti}}\",\n  \"poll.vote\": \"Vota\",\n  \"poll_button.add_poll\": \"Add a poll\",\n  \"poll_button.remove_poll\": \"Remove poll\",\n  \"privacy.change\": \"Modifica privacy del post\",\n  \"privacy.direct.long\": \"Invia solo a utenti menzionati\",\n  \"privacy.direct.short\": \"Diretto\",\n  \"privacy.private.long\": \"Invia solo ai seguaci\",\n  \"privacy.private.short\": \"Privato\",\n  \"privacy.public.long\": \"Invia alla timeline pubblica\",\n  \"privacy.public.short\": \"Pubblico\",\n  \"privacy.unlisted.long\": \"Non mostrare sulla timeline pubblica\",\n  \"privacy.unlisted.short\": \"Non elencato\",\n  \"regeneration_indicator.label\": \"Caricamento in corso…\",\n  \"regeneration_indicator.sublabel\": \"Stiamo preparando il tuo home feed!\",\n  \"relative_time.days\": \"{number}d\",\n  \"relative_time.hours\": \"{number}h\",\n  \"relative_time.just_now\": \"ora\",\n  \"relative_time.minutes\": \"{number}m\",\n  \"relative_time.seconds\": \"{number}s\",\n  \"reply_indicator.cancel\": \"Annulla\",\n  \"report.forward\": \"Inoltra a {target}\",\n  \"report.forward_hint\": \"Questo account appartiene a un altro server. Mandare anche là una copia anonima del rapporto?\",\n  \"report.hint\": \"La segnalazione sarà inviata ai moderatori del tuo server. Di seguito, puoi fornire il motivo per il quale stai segnalando questo account:\",\n  \"report.placeholder\": \"Commenti aggiuntivi\",\n  \"report.submit\": \"Invia\",\n  \"report.target\": \"Invio la segnalazione {target}\",\n  \"search.placeholder\": \"Cerca\",\n  \"search_popout.search_format\": \"Formato di ricerca avanzato\",\n  \"search_popout.tips.full_text\": \"Testo semplice per trovare gli status che hai scritto, segnato come apprezzati, condiviso o in cui sei stato citato, e inoltre i nomi utente, nomi visualizzati e hashtag che lo contengono.\",\n  \"search_popout.tips.hashtag\": \"hashtag\",\n  \"search_popout.tips.status\": \"status\",\n  \"search_popout.tips.text\": \"Testo semplice per trovare nomi visualizzati, nomi utente e hashtag che lo contengono\",\n  \"search_popout.tips.user\": \"utente\",\n  \"search_results.accounts\": \"Gente\",\n  \"search_results.hashtags\": \"Hashtag\",\n  \"search_results.statuses\": \"Toot\",\n  \"search_results.total\": \"{count} {count, plural, one {risultato} other {risultati}}\",\n  \"status.admin_account\": \"Apri interfaccia di moderazione per @{name}\",\n  \"status.admin_status\": \"Apri questo status nell'interfaccia di moderazione\",\n  \"status.block\": \"Blocca @{name}\",\n  \"status.cancel_reblog_private\": \"Annulla condivisione\",\n  \"status.cannot_reblog\": \"Questo post non può essere condiviso\",\n  \"status.copy\": \"Copia link allo status\",\n  \"status.delete\": \"Elimina\",\n  \"status.detailed_status\": \"Vista conversazione dettagliata\",\n  \"status.direct\": \"Messaggio diretto @{name}\",\n  \"status.embed\": \"Incorpora\",\n  \"status.favourite\": \"Apprezzato\",\n  \"status.filtered\": \"Filtrato\",\n  \"status.load_more\": \"Mostra di più\",\n  \"status.media_hidden\": \"Allegato nascosto\",\n  \"status.mention\": \"Nomina @{name}\",\n  \"status.more\": \"Altro\",\n  \"status.mute\": \"Silenzia @{name}\",\n  \"status.mute_conversation\": \"Silenzia conversazione\",\n  \"status.open\": \"Espandi questo post\",\n  \"status.pin\": \"Fissa in cima sul profilo\",\n  \"status.pinned\": \"Toot fissato in cima\",\n  \"status.read_more\": \"Leggi altro\",\n  \"status.reblog\": \"Condividi\",\n  \"status.reblog_private\": \"Condividi con i destinatari iniziali\",\n  \"status.reblogged_by\": \"{name} ha condiviso\",\n  \"status.reblogs.empty\": \"Nessuno ha ancora condiviso questo toot. Quando qualcuno lo farà, comparirà qui.\",\n  \"status.redraft\": \"Cancella e riscrivi\",\n  \"status.reply\": \"Rispondi\",\n  \"status.replyAll\": \"Rispondi alla conversazione\",\n  \"status.report\": \"Segnala @{name}\",\n  \"status.sensitive_warning\": \"Materiale sensibile\",\n  \"status.share\": \"Condividi\",\n  \"status.show_less\": \"Mostra meno\",\n  \"status.show_less_all\": \"Mostra meno per tutti\",\n  \"status.show_more\": \"Mostra di più\",\n  \"status.show_more_all\": \"Mostra di più per tutti\",\n  \"status.show_thread\": \"Mostra thread\",\n  \"status.unmute_conversation\": \"Annulla silenzia conversazione\",\n  \"status.unpin\": \"Non fissare in cima al profilo\",\n  \"suggestions.dismiss\": \"Elimina suggerimento\",\n  \"suggestions.header\": \"Ti potrebbe interessare…\",\n  \"tabs_bar.federated_timeline\": \"Federazione\",\n  \"tabs_bar.home\": \"Home\",\n  \"tabs_bar.local_timeline\": \"Locale\",\n  \"tabs_bar.notifications\": \"Notifiche\",\n  \"tabs_bar.search\": \"Cerca\",\n  \"time_remaining.days\": \"{number, plural, one {# giorno} other {# giorni}} left\",\n  \"time_remaining.hours\": \"{number, plural, one {# ora} other {# ore}} left\",\n  \"time_remaining.minutes\": \"{number, plural, one {# minuto} other {# minuti}} left\",\n  \"time_remaining.moments\": \"Restano pochi istanti\",\n  \"time_remaining.seconds\": \"{number, plural, one {# secondo} other {# secondi}} left\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {persona ne sta} other {persone ne stanno}} parlando\",\n  \"ui.beforeunload\": \"La bozza andrà persa se esci da Mastodon.\",\n  \"upload_area.title\": \"Trascina per caricare\",\n  \"upload_button.label\": \"Aggiungi file multimediale\",\n  \"upload_error.limit\": \"Limite al caricamento di file superato.\",\n  \"upload_error.poll\": \"File upload not allowed with polls.\",\n  \"upload_form.description\": \"Descrizione per utenti con disabilità visive\",\n  \"upload_form.focus\": \"Modifica anteprima\",\n  \"upload_form.undo\": \"Cancella\",\n  \"upload_progress.label\": \"Sto caricando...\",\n  \"video.close\": \"Chiudi video\",\n  \"video.exit_fullscreen\": \"Esci da modalità a schermo intero\",\n  \"video.expand\": \"Espandi video\",\n  \"video.fullscreen\": \"Schermo intero\",\n  \"video.hide\": \"Nascondi video\",\n  \"video.mute\": \"Silenzia suono\",\n  \"video.pause\": \"Pausa\",\n  \"video.play\": \"Avvia\",\n  \"video.unmute\": \"Riattiva suono\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/ja.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"リストから追加または外す\",\n  \"account.badges.bot\": \"Bot\",\n  \"account.block\": \"@{name}さんをブロック\",\n  \"account.block_domain\": \"{domain}全体を非表示\",\n  \"account.blocked\": \"ブロック済み\",\n  \"account.direct\": \"@{name}さんにダイレクトメッセージ\",\n  \"account.domain_blocked\": \"ドメイン非表示中\",\n  \"account.edit_profile\": \"プロフィール編集\",\n  \"account.endorse\": \"プロフィールで紹介する\",\n  \"account.follow\": \"フォロー\",\n  \"account.followers\": \"フォロワー\",\n  \"account.followers.empty\": \"まだ誰もフォローしていません。\",\n  \"account.follows\": \"フォロー\",\n  \"account.follows.empty\": \"まだ誰もフォローしていません。\",\n  \"account.follows_you\": \"フォローされています\",\n  \"account.hide_reblogs\": \"@{name}さんからのブーストを非表示\",\n  \"account.link_verified_on\": \"このリンクの所有権は{date}に確認されました\",\n  \"account.locked_info\": \"このアカウントは承認制アカウントです。相手が承認するまでフォローは完了しません。\",\n  \"account.media\": \"メディア\",\n  \"account.mention\": \"@{name}さんにトゥート\",\n  \"account.moved_to\": \"{name}さんは引っ越しました:\",\n  \"account.mute\": \"@{name}さんをミュート\",\n  \"account.mute_notifications\": \"@{name}さんからの通知を受け取らない\",\n  \"account.muted\": \"ミュート済み\",\n  \"account.posts\": \"投稿\",\n  \"account.posts_with_replies\": \"投稿と返信\",\n  \"account.report\": \"@{name}さんを通報\",\n  \"account.requested\": \"フォロー承認待ちです。クリックしてキャンセル\",\n  \"account.share\": \"@{name}さんのプロフィールを共有する\",\n  \"account.show_reblogs\": \"@{name}さんからのブーストを表示\",\n  \"account.unblock\": \"@{name}さんのブロックを解除\",\n  \"account.unblock_domain\": \"{domain}の非表示を解除\",\n  \"account.unendorse\": \"プロフィールから外す\",\n  \"account.unfollow\": \"フォロー解除\",\n  \"account.unmute\": \"@{name}さんのミュートを解除\",\n  \"account.unmute_notifications\": \"@{name}さんからの通知を受け取るようにする\",\n  \"alert.unexpected.message\": \"不明なエラーが発生しました。\",\n  \"alert.unexpected.title\": \"エラー！\",\n  \"boost_modal.combo\": \"次からは{combo}を押せばスキップできます\",\n  \"bundle_column_error.body\": \"コンポーネントの読み込み中に問題が発生しました。\",\n  \"bundle_column_error.retry\": \"再試行\",\n  \"bundle_column_error.title\": \"ネットワークエラー\",\n  \"bundle_modal_error.close\": \"閉じる\",\n  \"bundle_modal_error.message\": \"コンポーネントの読み込み中に問題が発生しました。\",\n  \"bundle_modal_error.retry\": \"再試行\",\n  \"column.blocks\": \"ブロックしたユーザー\",\n  \"column.community\": \"ローカルタイムライン\",\n  \"column.direct\": \"ダイレクトメッセージ\",\n  \"column.domain_blocks\": \"非表示にしたドメイン\",\n  \"column.favourites\": \"お気に入り\",\n  \"column.follow_requests\": \"フォローリクエスト\",\n  \"column.home\": \"ホーム\",\n  \"column.lists\": \"リスト\",\n  \"column.mutes\": \"ミュートしたユーザー\",\n  \"column.notifications\": \"通知\",\n  \"column.pins\": \"固定されたトゥート\",\n  \"column.public\": \"連合タイムライン\",\n  \"column_back_button.label\": \"戻る\",\n  \"column_header.hide_settings\": \"設定を隠す\",\n  \"column_header.moveLeft_settings\": \"カラムを左に移動する\",\n  \"column_header.moveRight_settings\": \"カラムを右に移動する\",\n  \"column_header.pin\": \"ピン留めする\",\n  \"column_header.show_settings\": \"設定を表示\",\n  \"column_header.unpin\": \"ピン留めを外す\",\n  \"column_subheading.settings\": \"設定\",\n  \"community.column_settings.media_only\": \"メディアのみ表示\",\n  \"compose_form.direct_message_warning\": \"このトゥートはメンションされた人にのみ送信されます。\",\n  \"compose_form.direct_message_warning_learn_more\": \"もっと詳しく\",\n  \"compose_form.hashtag_warning\": \"このトゥートは公開設定ではないのでハッシュタグの一覧に表示されません。公開トゥートだけがハッシュタグで検索できます。\",\n  \"compose_form.lock_disclaimer\": \"あなたのアカウントは{locked}になっていません。誰でもあなたをフォローすることができ、フォロワー限定の投稿を見ることができます。\",\n  \"compose_form.lock_disclaimer.lock\": \"承認制\",\n  \"compose_form.placeholder\": \"今なにしてる？\",\n  \"compose_form.poll.add_option\": \"追加\",\n  \"compose_form.poll.duration\": \"アンケート期間\",\n  \"compose_form.poll.option_placeholder\": \"項目 {number}\",\n  \"compose_form.poll.remove_option\": \"この項目を削除\",\n  \"compose_form.publish\": \"トゥート\",\n  \"compose_form.publish_loud\": \"{publish}！\",\n  \"compose_form.sensitive.hide\": \"メディアを閲覧注意にする\",\n  \"compose_form.sensitive.marked\": \"メディアに閲覧注意が設定されています\",\n  \"compose_form.sensitive.unmarked\": \"メディアに閲覧注意が設定されていません\",\n  \"compose_form.spoiler.marked\": \"閲覧注意が設定されています\",\n  \"compose_form.spoiler.unmarked\": \"閲覧注意が設定されていません\",\n  \"compose_form.spoiler_placeholder\": \"ここに警告を書いてください\",\n  \"confirmation_modal.cancel\": \"キャンセル\",\n  \"confirmations.block.block_and_report\": \"ブロックし通報\",\n  \"confirmations.block.confirm\": \"ブロック\",\n  \"confirmations.block.message\": \"本当に{name}さんをブロックしますか？\",\n  \"confirmations.delete.confirm\": \"削除\",\n  \"confirmations.delete.message\": \"本当に削除しますか？\",\n  \"confirmations.delete_list.confirm\": \"削除\",\n  \"confirmations.delete_list.message\": \"本当にこのリストを完全に削除しますか？\",\n  \"confirmations.domain_block.confirm\": \"ドメイン全体を非表示\",\n  \"confirmations.domain_block.message\": \"本当に{domain}全体を非表示にしますか？ 多くの場合は個別にブロックやミュートするだけで充分であり、また好ましいです。公開タイムラインにそのドメインのコンテンツが表示されなくなり、通知も届かなくなります。そのドメインのフォロワーはアンフォローされます。\",\n  \"confirmations.mute.confirm\": \"ミュート\",\n  \"confirmations.mute.message\": \"本当に{name}さんをミュートしますか？\",\n  \"confirmations.redraft.confirm\": \"削除して下書きに戻す\",\n  \"confirmations.redraft.message\": \"本当にこのトゥートを削除して下書きに戻しますか？ このトゥートへのお気に入り登録やブーストは失われ、返信は孤立することになります。\",\n  \"confirmations.reply.confirm\": \"返信\",\n  \"confirmations.reply.message\": \"今返信すると現在作成中のメッセージが上書きされます。本当に実行しますか？\",\n  \"confirmations.unfollow.confirm\": \"フォロー解除\",\n  \"confirmations.unfollow.message\": \"本当に{name}さんのフォローを解除しますか？\",\n  \"embed.instructions\": \"下記のコードをコピーしてウェブサイトに埋め込みます。\",\n  \"embed.preview\": \"表示例:\",\n  \"emoji_button.activity\": \"活動\",\n  \"emoji_button.custom\": \"カスタム絵文字\",\n  \"emoji_button.flags\": \"国旗\",\n  \"emoji_button.food\": \"食べ物\",\n  \"emoji_button.label\": \"絵文字を追加\",\n  \"emoji_button.nature\": \"自然\",\n  \"emoji_button.not_found\": \"絵文字がなーい！！ (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"物\",\n  \"emoji_button.people\": \"人々\",\n  \"emoji_button.recent\": \"よく使う絵文字\",\n  \"emoji_button.search\": \"検索...\",\n  \"emoji_button.search_results\": \"検索結果\",\n  \"emoji_button.symbols\": \"記号\",\n  \"emoji_button.travel\": \"旅行と場所\",\n  \"empty_column.account_timeline\": \"トゥートがありません！\",\n  \"empty_column.account_unavailable\": \"プロフィールは利用できません\",\n  \"empty_column.blocks\": \"まだ誰もブロックしていません。\",\n  \"empty_column.community\": \"ローカルタイムラインはまだ使われていません。何か書いてみましょう！\",\n  \"empty_column.direct\": \"ダイレクトメッセージはまだありません。ダイレクトメッセージをやりとりすると、ここに表示されます。\",\n  \"empty_column.domain_blocks\": \"非表示にしているドメインはありません。\",\n  \"empty_column.favourited_statuses\": \"まだ何もお気に入り登録していません。お気に入り登録するとここに表示されます。\",\n  \"empty_column.favourites\": \"まだ誰もお気に入り登録していません。お気に入り登録されるとここに表示されます。\",\n  \"empty_column.follow_requests\": \"まだフォローリクエストを受けていません。フォローリクエストを受けるとここに表示されます。\",\n  \"empty_column.hashtag\": \"このハッシュタグはまだ使われていません。\",\n  \"empty_column.home\": \"まだ誰もフォローしていません。{public}を見に行くか、検索を使って他のユーザーを見つけましょう。\",\n  \"empty_column.home.public_timeline\": \"連合タイムライン\",\n  \"empty_column.list\": \"このリストにはまだなにもありません。このリストのメンバーが新しいトゥートをするとここに表示されます。\",\n  \"empty_column.lists\": \"まだリストがありません。リストを作るとここに表示されます。\",\n  \"empty_column.mutes\": \"まだ誰もミュートしていません。\",\n  \"empty_column.notifications\": \"まだ通知がありません。他の人とふれ合って会話を始めましょう。\",\n  \"empty_column.public\": \"ここにはまだ何もありません！ 公開で何かを投稿したり、他のサーバーのユーザーをフォローしたりしていっぱいにしましょう\",\n  \"follow_request.authorize\": \"許可\",\n  \"follow_request.reject\": \"拒否\",\n  \"getting_started.developers\": \"開発\",\n  \"getting_started.directory\": \"ディレクトリ\",\n  \"getting_started.documentation\": \"ドキュメント\",\n  \"getting_started.heading\": \"スタート\",\n  \"getting_started.invite\": \"招待\",\n  \"getting_started.open_source_notice\": \"Mastodonはオープンソースソフトウェアです。誰でもGitHub ( {github} ) から開発に参加したり、問題を報告したりできます。\",\n  \"getting_started.security\": \"セキュリティ\",\n  \"getting_started.terms\": \"プライバシーポリシー\",\n  \"hashtag.column_header.tag_mode.all\": \"と {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"か {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"({additional} を除く)\",\n  \"hashtag.column_settings.select.no_options_message\": \"提案はありません\",\n  \"hashtag.column_settings.select.placeholder\": \"ハッシュタグを入力してください…\",\n  \"hashtag.column_settings.tag_mode.all\": \"すべてを含む\",\n  \"hashtag.column_settings.tag_mode.any\": \"いずれかを含む\",\n  \"hashtag.column_settings.tag_mode.none\": \"これらを除く\",\n  \"hashtag.column_settings.tag_toggle\": \"このカラムに追加のタグを含める\",\n  \"home.column_settings.basic\": \"基本設定\",\n  \"home.column_settings.show_reblogs\": \"ブースト表示\",\n  \"home.column_settings.show_replies\": \"返信表示\",\n  \"intervals.full.days\": \"{number}日\",\n  \"intervals.full.hours\": \"{number}時間\",\n  \"intervals.full.minutes\": \"{number}分\",\n  \"introduction.federation.action\": \"次へ\",\n  \"introduction.federation.federated.headline\": \"連合タイムライン\",\n  \"introduction.federation.federated.text\": \"Fediverseの他のサーバーからの公開投稿は連合タイムラインに表示されます。\",\n  \"introduction.federation.home.headline\": \"ホームタイムライン\",\n  \"introduction.federation.home.text\": \"フォローしている人々の投稿はホームタイムラインに表示されます。どこのサーバーの誰でもフォローできます！\",\n  \"introduction.federation.local.headline\": \"ローカルタイムライン\",\n  \"introduction.federation.local.text\": \"同じサーバーにいる人々の公開投稿はローカルタイムラインに表示されます。\",\n  \"introduction.interactions.action\": \"はじめよう！\",\n  \"introduction.interactions.favourite.headline\": \"お気に入り\",\n  \"introduction.interactions.favourite.text\": \"お気に入り登録することで後から見られるよう保存したり、「好き」を相手に伝えたりできます。\",\n  \"introduction.interactions.reblog.headline\": \"ブースト\",\n  \"introduction.interactions.reblog.text\": \"ブーストすることでフォロワーにそのトゥートを共有できます。\",\n  \"introduction.interactions.reply.headline\": \"返信\",\n  \"introduction.interactions.reply.text\": \"自身や人々のトゥートに返信することで、一連の会話に繋げることができます。\",\n  \"introduction.welcome.action\": \"はじめる！\",\n  \"introduction.welcome.headline\": \"はじめに\",\n  \"introduction.welcome.text\": \"Fediverseの世界へようこそ！あと少しでメッセージを配信したり、さまざまなサーバーを越えた友達と話せるようになります。ところで、ここ{domain}は特別なサーバーです…あなたのプロフィールを持つ主体のサーバーですので、名前を覚えておきましょう。\",\n  \"keyboard_shortcuts.back\": \"戻る\",\n  \"keyboard_shortcuts.blocked\": \"ブロックしたユーザーのリストを開く\",\n  \"keyboard_shortcuts.boost\": \"ブースト\",\n  \"keyboard_shortcuts.column\": \"左からn番目のカラム内最新トゥートに移動\",\n  \"keyboard_shortcuts.compose\": \"トゥート入力欄に移動\",\n  \"keyboard_shortcuts.description\": \"説明\",\n  \"keyboard_shortcuts.direct\": \"ダイレクトメッセージのカラムを開く\",\n  \"keyboard_shortcuts.down\": \"カラム内一つ下に移動\",\n  \"keyboard_shortcuts.enter\": \"トゥートの詳細を表示\",\n  \"keyboard_shortcuts.favourite\": \"お気に入り\",\n  \"keyboard_shortcuts.favourites\": \"お気に入り登録のリストを開く\",\n  \"keyboard_shortcuts.federated\": \"連合タイムラインを開く\",\n  \"keyboard_shortcuts.heading\": \"キーボードショートカット\",\n  \"keyboard_shortcuts.home\": \"ホームタイムラインを開く\",\n  \"keyboard_shortcuts.hotkey\": \"ホットキー\",\n  \"keyboard_shortcuts.legend\": \"この一覧を表示\",\n  \"keyboard_shortcuts.local\": \"ローカルタイムラインを開く\",\n  \"keyboard_shortcuts.mention\": \"メンション\",\n  \"keyboard_shortcuts.muted\": \"ミュートしたユーザーのリストを開く\",\n  \"keyboard_shortcuts.my_profile\": \"自分のプロフィールを開く\",\n  \"keyboard_shortcuts.notifications\": \"通知カラムを開く\",\n  \"keyboard_shortcuts.pinned\": \"固定したトゥートのリストを開く\",\n  \"keyboard_shortcuts.profile\": \"プロフィールを開く\",\n  \"keyboard_shortcuts.reply\": \"返信\",\n  \"keyboard_shortcuts.requests\": \"フォローリクエストのリストを開く\",\n  \"keyboard_shortcuts.search\": \"検索欄に移動\",\n  \"keyboard_shortcuts.start\": \"\\\"スタート\\\" カラムを開く\",\n  \"keyboard_shortcuts.toggle_hidden\": \"CWで隠れた文を見る/隠す\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"非表示のメディアを見る/隠す\",\n  \"keyboard_shortcuts.toot\": \"新規トゥート\",\n  \"keyboard_shortcuts.unfocus\": \"トゥート入力欄・検索欄から離れる\",\n  \"keyboard_shortcuts.up\": \"カラム内一つ上に移動\",\n  \"lightbox.close\": \"閉じる\",\n  \"lightbox.next\": \"次\",\n  \"lightbox.previous\": \"前\",\n  \"lightbox.view_context\": \"トゥートを表示\",\n  \"lists.account.add\": \"リストに追加\",\n  \"lists.account.remove\": \"リストから外す\",\n  \"lists.delete\": \"リストを削除\",\n  \"lists.edit\": \"リストを編集\",\n  \"lists.edit.submit\": \"タイトルを変更\",\n  \"lists.new.create\": \"リストを作成\",\n  \"lists.new.title_placeholder\": \"新規リスト名\",\n  \"lists.search\": \"フォローしている人の中から検索\",\n  \"lists.subheading\": \"あなたのリスト\",\n  \"loading_indicator.label\": \"読み込み中...\",\n  \"media_gallery.toggle_visible\": \"表示切り替え\",\n  \"missing_indicator.label\": \"見つかりません\",\n  \"missing_indicator.sublabel\": \"見つかりませんでした\",\n  \"mute_modal.hide_notifications\": \"このユーザーからの通知を隠しますか？\",\n  \"navigation_bar.apps\": \"アプリ\",\n  \"navigation_bar.blocks\": \"ブロックしたユーザー\",\n  \"navigation_bar.community_timeline\": \"ローカルタイムライン\",\n  \"navigation_bar.compose\": \"トゥートの新規作成\",\n  \"navigation_bar.direct\": \"ダイレクトメッセージ\",\n  \"navigation_bar.discover\": \"見つける\",\n  \"navigation_bar.domain_blocks\": \"非表示にしたドメイン\",\n  \"navigation_bar.edit_profile\": \"プロフィールを編集\",\n  \"navigation_bar.favourites\": \"お気に入り\",\n  \"navigation_bar.filters\": \"フィルター設定\",\n  \"navigation_bar.follow_requests\": \"フォローリクエスト\",\n  \"navigation_bar.follows_and_followers\": \"フォロー・フォロワー\",\n  \"navigation_bar.info\": \"このサーバーについて\",\n  \"navigation_bar.keyboard_shortcuts\": \"ホットキー\",\n  \"navigation_bar.lists\": \"リスト\",\n  \"navigation_bar.logout\": \"ログアウト\",\n  \"navigation_bar.mutes\": \"ミュートしたユーザー\",\n  \"navigation_bar.personal\": \"個人用\",\n  \"navigation_bar.pins\": \"固定したトゥート\",\n  \"navigation_bar.preferences\": \"ユーザー設定\",\n  \"navigation_bar.profile_directory\": \"ディレクトリ\",\n  \"navigation_bar.public_timeline\": \"連合タイムライン\",\n  \"navigation_bar.security\": \"セキュリティ\",\n  \"notification.favourite\": \"{name}さんがあなたのトゥートをお気に入りに登録しました\",\n  \"notification.follow\": \"{name}さんにフォローされました\",\n  \"notification.mention\": \"{name}さんがあなたに返信しました\",\n  \"notification.poll\": \"アンケートが終了しました\",\n  \"notification.reblog\": \"{name}さんがあなたのトゥートをブーストしました\",\n  \"notifications.clear\": \"通知を消去\",\n  \"notifications.clear_confirmation\": \"本当に通知を消去しますか？\",\n  \"notifications.column_settings.alert\": \"デスクトップ通知\",\n  \"notifications.column_settings.favourite\": \"お気に入り:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"すべてのカテゴリを表示\",\n  \"notifications.column_settings.filter_bar.category\": \"クイックフィルターバー\",\n  \"notifications.column_settings.filter_bar.show\": \"表示\",\n  \"notifications.column_settings.follow\": \"新しいフォロワー:\",\n  \"notifications.column_settings.mention\": \"返信:\",\n  \"notifications.column_settings.poll\": \"アンケート結果:\",\n  \"notifications.column_settings.push\": \"プッシュ通知\",\n  \"notifications.column_settings.reblog\": \"ブースト:\",\n  \"notifications.column_settings.show\": \"カラムに表示\",\n  \"notifications.column_settings.sound\": \"通知音を再生\",\n  \"notifications.filter.all\": \"すべて\",\n  \"notifications.filter.boosts\": \"ブースト\",\n  \"notifications.filter.favourites\": \"お気に入り\",\n  \"notifications.filter.follows\": \"フォロー\",\n  \"notifications.filter.mentions\": \"返信\",\n  \"notifications.filter.polls\": \"アンケート結果\",\n  \"notifications.group\": \"{count} 件の通知\",\n  \"poll.closed\": \"終了\",\n  \"poll.refresh\": \"更新\",\n  \"poll.total_votes\": \"{count}票\",\n  \"poll.vote\": \"投票\",\n  \"poll_button.add_poll\": \"アンケートを追加\",\n  \"poll_button.remove_poll\": \"アンケートを削除\",\n  \"privacy.change\": \"公開範囲を変更\",\n  \"privacy.direct.long\": \"メンションしたユーザーだけに公開\",\n  \"privacy.direct.short\": \"ダイレクト\",\n  \"privacy.private.long\": \"フォロワーだけに公開\",\n  \"privacy.private.short\": \"フォロワー限定\",\n  \"privacy.public.long\": \"公開TLに投稿する\",\n  \"privacy.public.short\": \"公開\",\n  \"privacy.unlisted.long\": \"公開TLで表示しない\",\n  \"privacy.unlisted.short\": \"未収載\",\n  \"regeneration_indicator.label\": \"読み込み中…\",\n  \"regeneration_indicator.sublabel\": \"ホームタイムラインは準備中です！\",\n  \"relative_time.days\": \"{number}日前\",\n  \"relative_time.hours\": \"{number}時間前\",\n  \"relative_time.just_now\": \"今\",\n  \"relative_time.minutes\": \"{number}分前\",\n  \"relative_time.seconds\": \"{number}秒前\",\n  \"reply_indicator.cancel\": \"キャンセル\",\n  \"report.forward\": \"{target} に転送する\",\n  \"report.forward_hint\": \"このアカウントは別のサーバーに所属しています。通報内容を匿名で転送しますか？\",\n  \"report.hint\": \"通報内容はあなたのサーバーのモデレーターへ送信されます。通報理由を入力してください。:\",\n  \"report.placeholder\": \"追加コメント\",\n  \"report.submit\": \"通報する\",\n  \"report.target\": \"{target}さんを通報する\",\n  \"search.placeholder\": \"検索\",\n  \"search_popout.search_format\": \"高度な検索フォーマット\",\n  \"search_popout.tips.full_text\": \"表示名やユーザー名、ハッシュタグのほか、あなたのトゥートやお気に入り、ブーストしたトゥート、返信に一致する単純なテキスト。\",\n  \"search_popout.tips.hashtag\": \"ハッシュタグ\",\n  \"search_popout.tips.status\": \"トゥート\",\n  \"search_popout.tips.text\": \"表示名やユーザー名、ハッシュタグに一致する単純なテキスト\",\n  \"search_popout.tips.user\": \"ユーザー\",\n  \"search_results.accounts\": \"人々\",\n  \"search_results.hashtags\": \"ハッシュタグ\",\n  \"search_results.statuses\": \"トゥート\",\n  \"search_results.total\": \"{count, number}件の結果\",\n  \"status.admin_account\": \"@{name} のモデレーション画面を開く\",\n  \"status.admin_status\": \"このトゥートをモデレーション画面で開く\",\n  \"status.block\": \"@{name}さんをブロック\",\n  \"status.cancel_reblog_private\": \"ブースト解除\",\n  \"status.cannot_reblog\": \"この投稿はブーストできません\",\n  \"status.copy\": \"トゥートへのリンクをコピー\",\n  \"status.delete\": \"削除\",\n  \"status.detailed_status\": \"詳細な会話ビュー\",\n  \"status.direct\": \"@{name}さんにダイレクトメッセージ\",\n  \"status.embed\": \"埋め込み\",\n  \"status.favourite\": \"お気に入り\",\n  \"status.filtered\": \"フィルターされました\",\n  \"status.load_more\": \"もっと見る\",\n  \"status.media_hidden\": \"非表示のメディア\",\n  \"status.mention\": \"@{name}さんにトゥート\",\n  \"status.more\": \"もっと見る\",\n  \"status.mute\": \"@{name}さんをミュート\",\n  \"status.mute_conversation\": \"会話をミュート\",\n  \"status.open\": \"詳細を表示\",\n  \"status.pin\": \"プロフィールに固定表示\",\n  \"status.pinned\": \"固定されたトゥート\",\n  \"status.read_more\": \"もっと見る\",\n  \"status.reblog\": \"ブースト\",\n  \"status.reblog_private\": \"ブースト\",\n  \"status.reblogged_by\": \"{name}さんがブースト\",\n  \"status.reblogs.empty\": \"まだ誰もブーストしていません。ブーストされるとここに表示されます。\",\n  \"status.redraft\": \"削除して下書きに戻す\",\n  \"status.reply\": \"返信\",\n  \"status.replyAll\": \"全員に返信\",\n  \"status.report\": \"@{name}さんを通報\",\n  \"status.sensitive_warning\": \"閲覧注意\",\n  \"status.share\": \"共有\",\n  \"status.show_less\": \"隠す\",\n  \"status.show_less_all\": \"全て隠す\",\n  \"status.show_more\": \"もっと見る\",\n  \"status.show_more_all\": \"全て見る\",\n  \"status.show_thread\": \"スレッドを表示\",\n  \"status.unmute_conversation\": \"会話のミュートを解除\",\n  \"status.unpin\": \"プロフィールへの固定を解除\",\n  \"suggestions.dismiss\": \"隠す\",\n  \"suggestions.header\": \"興味あるかもしれません…\",\n  \"tabs_bar.federated_timeline\": \"連合\",\n  \"tabs_bar.home\": \"ホーム\",\n  \"tabs_bar.local_timeline\": \"ローカル\",\n  \"tabs_bar.notifications\": \"通知\",\n  \"tabs_bar.search\": \"検索\",\n  \"time_remaining.days\": \"残り{number}日\",\n  \"time_remaining.hours\": \"残り{number}時間\",\n  \"time_remaining.minutes\": \"残り{number}分\",\n  \"time_remaining.moments\": \"まもなく終了\",\n  \"time_remaining.seconds\": \"残り{number}秒\",\n  \"trends.count_by_accounts\": \"{count}人がトゥート\",\n  \"ui.beforeunload\": \"Mastodonから離れると送信前の投稿は失われます。\",\n  \"upload_area.title\": \"ドラッグ＆ドロップでアップロード\",\n  \"upload_button.label\": \"メディアを追加 (JPEG, PNG, GIF, WebM, MP4, MOV)\",\n  \"upload_error.limit\": \"アップロードできる上限を超えています。\",\n  \"upload_error.poll\": \"アンケートではファイルをアップロードできません。\",\n  \"upload_form.description\": \"視覚障害者のための説明\",\n  \"upload_form.focus\": \"プレビューを変更\",\n  \"upload_form.undo\": \"削除\",\n  \"upload_progress.label\": \"アップロード中...\",\n  \"video.close\": \"動画を閉じる\",\n  \"video.exit_fullscreen\": \"全画面を終了する\",\n  \"video.expand\": \"動画を拡大する\",\n  \"video.fullscreen\": \"全画面\",\n  \"video.hide\": \"動画を閉じる\",\n  \"video.mute\": \"ミュート\",\n  \"video.pause\": \"一時停止\",\n  \"video.play\": \"再生\",\n  \"video.unmute\": \"ミュートを解除する\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/ka.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Add or Remove from lists\",\n  \"account.badges.bot\": \"ბოტი\",\n  \"account.block\": \"დაბლოკე @{name}\",\n  \"account.block_domain\": \"დაიმალოს ყველაფერი დომენიდან {domain}\",\n  \"account.blocked\": \"დაიბლოკა\",\n  \"account.direct\": \"პირდაპირი წერილი @{name}-ს\",\n  \"account.domain_blocked\": \"დომენი დამალულია\",\n  \"account.edit_profile\": \"პროფილის ცვლილება\",\n  \"account.endorse\": \"გამორჩევა პროფილზე\",\n  \"account.follow\": \"გაყოლა\",\n  \"account.followers\": \"მიმდევრები\",\n  \"account.followers.empty\": \"No one follows this user yet.\",\n  \"account.follows\": \"მიდევნებები\",\n  \"account.follows.empty\": \"This user doesn't follow anyone yet.\",\n  \"account.follows_you\": \"მოგყვებათ\",\n  \"account.hide_reblogs\": \"დაიმალოს ბუსტები @{name}-სგან\",\n  \"account.link_verified_on\": \"Ownership of this link was checked on {date}\",\n  \"account.locked_info\": \"This account privacy status is set to locked. The owner manually reviews who can follow them.\",\n  \"account.media\": \"მედია\",\n  \"account.mention\": \"ასახელეთ @{name}\",\n  \"account.moved_to\": \"{name} გადავიდა:\",\n  \"account.mute\": \"გააჩუმე @{name}\",\n  \"account.mute_notifications\": \"გააჩუმე შეტყობინებები @{name}-სგან\",\n  \"account.muted\": \"გაჩუმებული\",\n  \"account.posts\": \"ტუტები\",\n  \"account.posts_with_replies\": \"ტუტები და პასუხები\",\n  \"account.report\": \"დაარეპორტე @{name}\",\n  \"account.requested\": \"დამტკიცების მოლოდინში. დააწკაპუნეთ რომ უარყოთ დადევნების მოთხონვა\",\n  \"account.share\": \"გააზიარე @{name}-ის პროფილი\",\n  \"account.show_reblogs\": \"აჩვენე ბუსტები @{name}-სგან\",\n  \"account.unblock\": \"განბლოკე @{name}\",\n  \"account.unblock_domain\": \"გამოაჩინე {domain}\",\n  \"account.unendorse\": \"არ გამოირჩეს პროფილზე\",\n  \"account.unfollow\": \"ნუღარ მიჰყვები\",\n  \"account.unmute\": \"ნუღარ აჩუმებ @{name}-ს\",\n  \"account.unmute_notifications\": \"ნუღარ აჩუმებ შეტყობინებებს @{name}-სგან\",\n  \"alert.unexpected.message\": \"წარმოიშვა მოულოდნელი შეცდომა.\",\n  \"alert.unexpected.title\": \"უპს!\",\n  \"boost_modal.combo\": \"შეგიძლიათ დააჭიროთ {combo}-ს რათა შემდეგ ჯერზე გამოტოვოთ ეს\",\n  \"bundle_column_error.body\": \"ამ კომპონენტის ჩატვირთვისას რაღაც აირია.\",\n  \"bundle_column_error.retry\": \"სცადეთ კიდევ ერთხელ\",\n  \"bundle_column_error.title\": \"ქსელის შეცდომა\",\n  \"bundle_modal_error.close\": \"დახურვა\",\n  \"bundle_modal_error.message\": \"ამ კომპონენტის ჩატვირთვისას რაღაც აირია.\",\n  \"bundle_modal_error.retry\": \"სცადეთ კიდევ ერთხელ\",\n  \"column.blocks\": \"დაბლოკილი მომხმარებლები\",\n  \"column.community\": \"ლოკალური თაიმლაინი\",\n  \"column.direct\": \"პირდაპირი წერილები\",\n  \"column.domain_blocks\": \"დამალული დომენები\",\n  \"column.favourites\": \"ფავორიტები\",\n  \"column.follow_requests\": \"დადევნების მოთხოვნები\",\n  \"column.home\": \"სახლი\",\n  \"column.lists\": \"სიები\",\n  \"column.mutes\": \"გაჩუმებული მომხმარებლები\",\n  \"column.notifications\": \"შეტყობინებები\",\n  \"column.pins\": \"აპინული ტუტები\",\n  \"column.public\": \"ფედერალური თაიმლაინი\",\n  \"column_back_button.label\": \"უკან\",\n  \"column_header.hide_settings\": \"პარამეტრების დამალვა\",\n  \"column_header.moveLeft_settings\": \"სვეტის მარცხნივ გადატანა\",\n  \"column_header.moveRight_settings\": \"სვეტის მარჯვნივ გადატანა\",\n  \"column_header.pin\": \"აპინვა\",\n  \"column_header.show_settings\": \"პარამეტრების ჩვენება\",\n  \"column_header.unpin\": \"პინის მოხსნა\",\n  \"column_subheading.settings\": \"პარამეტრები\",\n  \"community.column_settings.media_only\": \"მხოლოდ მედია\",\n  \"compose_form.direct_message_warning\": \"ეს ტუტი გაეგზავნება მხოლოდ ნახსენებ მომხმარებლებს.\",\n  \"compose_form.direct_message_warning_learn_more\": \"გაიგე მეტი\",\n  \"compose_form.hashtag_warning\": \"ეს ტუტი არ მოექცევა ჰეშტეგების ქვეს, რამეთუ ის არაა მითითებული. მხოლოდ ღია ტუტები მოიძებნება ჰეშტეგით.\",\n  \"compose_form.lock_disclaimer\": \"თქვენი ანგარიში არაა {locked}. ნებისმიერს შეიძლია გამოგყვეთ, რომ იხილოს თქვენი მიმდევრებზე გათვლილი პოსტები.\",\n  \"compose_form.lock_disclaimer.lock\": \"ჩაკეტილი\",\n  \"compose_form.placeholder\": \"რაზე ფიქრობ?\",\n  \"compose_form.poll.add_option\": \"Add a choice\",\n  \"compose_form.poll.duration\": \"Poll duration\",\n  \"compose_form.poll.option_placeholder\": \"Choice {number}\",\n  \"compose_form.poll.remove_option\": \"Remove this choice\",\n  \"compose_form.publish\": \"ტუტი\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"Mark media as sensitive\",\n  \"compose_form.sensitive.marked\": \"მედია მონიშნულია მგრძნობიარედ\",\n  \"compose_form.sensitive.unmarked\": \"მედია არაა მონიშნული მგრძნობიარედ\",\n  \"compose_form.spoiler.marked\": \"გაფრთხილების უკან ტექსტი დამალულია\",\n  \"compose_form.spoiler.unmarked\": \"ტექსტი არაა დამალული\",\n  \"compose_form.spoiler_placeholder\": \"თქვენი გაფრთხილება დაწერეთ აქ\",\n  \"confirmation_modal.cancel\": \"უარყოფა\",\n  \"confirmations.block.block_and_report\": \"Block & Report\",\n  \"confirmations.block.confirm\": \"ბლოკი\",\n  \"confirmations.block.message\": \"დარწმუნებული ხართ, გსურთ დაბლოკოთ {name}?\",\n  \"confirmations.delete.confirm\": \"გაუქმება\",\n  \"confirmations.delete.message\": \"დარწმუნებული ხართ, გსურთ გააუქმოთ ეს სტატუსი?\",\n  \"confirmations.delete_list.confirm\": \"გაუქმება\",\n  \"confirmations.delete_list.message\": \"დარწმუნებული ხართ, გსურთ სამუდამოდ გააუქმოთ ეს სია?\",\n  \"confirmations.domain_block.confirm\": \"მთელი დომენის დამალვა\",\n  \"confirmations.domain_block.message\": \"ნაღდად, ნაღდად, დარწმუნებული ხართ, გსურთ დაბლოკოთ მთელი {domain}? უმეტეს შემთხვევაში რამდენიმე გამიზნული ბლოკი ან გაჩუმება საკმარისი და უკეთესია. კონტენტს ამ დომენიდან ვერ იხილავთ ვერც ერთ ღია თაიმლაინზე ან თქვენს შეტყობინებებში. ამ დომენიდან არსებული მიმდევრები ამოიშლება.\",\n  \"confirmations.mute.confirm\": \"გაჩუმება\",\n  \"confirmations.mute.message\": \"დარწმუნებული ხართ, გსურთ გააჩუმოთ {name}?\",\n  \"confirmations.redraft.confirm\": \"გაუქმება და გადანაწილება\",\n  \"confirmations.redraft.message\": \"დარწმუნებული ხართ, გსურთ გააუქმოთ ეს სტატუსი და გადაანაწილოთ? დაკარგავთ ყველა პასუხს, ბუსტს და მასზედ არსებულ ფავორიტს.\",\n  \"confirmations.reply.confirm\": \"Reply\",\n  \"confirmations.reply.message\": \"Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?\",\n  \"confirmations.unfollow.confirm\": \"ნუღარ მიჰყვები\",\n  \"confirmations.unfollow.message\": \"დარწმუნებული ხართ, აღარ გსურთ მიჰყვებოდეთ {name}-ს?\",\n  \"embed.instructions\": \"ეს სტატუსი ჩასვით თქვენს ვებ-საიტზე შემდეგი კოდის კოპირებით.\",\n  \"embed.preview\": \"ესაა თუ როგორც გამოჩნდება:\",\n  \"emoji_button.activity\": \"აქტივობა\",\n  \"emoji_button.custom\": \"პერსონალიზირებული\",\n  \"emoji_button.flags\": \"დროშები\",\n  \"emoji_button.food\": \"საჭმელი და სასლმელი\",\n  \"emoji_button.label\": \"ემოჯის ჩასმა\",\n  \"emoji_button.nature\": \"ბუმება\",\n  \"emoji_button.not_found\": \"არაა ემოჯი!! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"ობიექტები\",\n  \"emoji_button.people\": \"ხალხი\",\n  \"emoji_button.recent\": \"ხშირად გამოყენებული\",\n  \"emoji_button.search\": \"ძებნა...\",\n  \"emoji_button.search_results\": \"ძებნის შედეგები\",\n  \"emoji_button.symbols\": \"სიმბოლოები\",\n  \"emoji_button.travel\": \"მოგზაურობა და ადგილები\",\n  \"empty_column.account_timeline\": \"No toots here!\",\n  \"empty_column.account_unavailable\": \"Profile unavailable\",\n  \"empty_column.blocks\": \"You haven't blocked any users yet.\",\n  \"empty_column.community\": \"ლოკალური თაიმლაინი ცარიელია. დაწერეთ რაიმე ღიად ან ქენით რაიმე სხვა!\",\n  \"empty_column.direct\": \"ჯერ პირდაპირი წერილები არ გაქვთ. როდესაც მიიღებთ ან გააგზავნით, გამოჩნდება აქ.\",\n  \"empty_column.domain_blocks\": \"There are no hidden domains yet.\",\n  \"empty_column.favourited_statuses\": \"You don't have any favourite toots yet. When you favourite one, it will show up here.\",\n  \"empty_column.favourites\": \"No one has favourited this toot yet. When someone does, they will show up here.\",\n  \"empty_column.follow_requests\": \"You don't have any follow requests yet. When you receive one, it will show up here.\",\n  \"empty_column.hashtag\": \"ამ ჰეშტეგში ჯერ არაფერია.\",\n  \"empty_column.home\": \"თქვენი სახლის თაიმლაინი ცარიელია! ესტუმრეთ {public}-ს ან დასაწყისისთვის გამოიყენეთ ძებნა, რომ შეხვდეთ სხვა მომხმარებლებს.\",\n  \"empty_column.home.public_timeline\": \"ღია თაიმლაინი\",\n  \"empty_column.list\": \"ამ სიაში ჯერ არაფერია. როდესაც სიის წევრები დაპოსტავენ ახალ სტატუსებს, ისინი გამოჩნდებიან აქ.\",\n  \"empty_column.lists\": \"You don't have any lists yet. When you create one, it will show up here.\",\n  \"empty_column.mutes\": \"You haven't muted any users yet.\",\n  \"empty_column.notifications\": \"ჯერ შეტყობინებები არ გაქვთ. საუბრის დასაწყებად იურთიერთქმედეთ სხვებთან.\",\n  \"empty_column.public\": \"აქ არაფერია! შესავსებად, დაწერეთ რაიმე ღიად ან ხელით გაჰყევით მომხმარებლებს სხვა ინსტანციებისგან\",\n  \"follow_request.authorize\": \"ავტორიზაცია\",\n  \"follow_request.reject\": \"უარყოფა\",\n  \"getting_started.developers\": \"დეველოპერები\",\n  \"getting_started.directory\": \"Profile directory\",\n  \"getting_started.documentation\": \"დოკუმენტაცია\",\n  \"getting_started.heading\": \"დაწყება\",\n  \"getting_started.invite\": \"ხალხის მოწვევა\",\n  \"getting_started.open_source_notice\": \"მასტოდონი ღია პროგრამაა. შეგიძლიათ შეუწყოთ ხელი ან შექმნათ პრობემის რეპორტი {github}-ზე.\",\n  \"getting_started.security\": \"უსაფრთხოება\",\n  \"getting_started.terms\": \"მომსახურების პირობები\",\n  \"hashtag.column_header.tag_mode.all\": \"and {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"or {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"without {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"No suggestions found\",\n  \"hashtag.column_settings.select.placeholder\": \"Enter hashtags…\",\n  \"hashtag.column_settings.tag_mode.all\": \"All of these\",\n  \"hashtag.column_settings.tag_mode.any\": \"Any of these\",\n  \"hashtag.column_settings.tag_mode.none\": \"None of these\",\n  \"hashtag.column_settings.tag_toggle\": \"Include additional tags in this column\",\n  \"home.column_settings.basic\": \"ძირითადი\",\n  \"home.column_settings.show_reblogs\": \"ბუსტების ჩვენება\",\n  \"home.column_settings.show_replies\": \"პასუხების ჩვენება\",\n  \"intervals.full.days\": \"{number, plural, one {# day} other {# days}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# hour} other {# hours}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minute} other {# minutes}}\",\n  \"introduction.federation.action\": \"Next\",\n  \"introduction.federation.federated.headline\": \"Federated\",\n  \"introduction.federation.federated.text\": \"Public posts from other servers of the fediverse will appear in the federated timeline.\",\n  \"introduction.federation.home.headline\": \"Home\",\n  \"introduction.federation.home.text\": \"Posts from people you follow will appear in your home feed. You can follow anyone on any server!\",\n  \"introduction.federation.local.headline\": \"Local\",\n  \"introduction.federation.local.text\": \"Public posts from people on the same server as you will appear in the local timeline.\",\n  \"introduction.interactions.action\": \"Finish toot-orial!\",\n  \"introduction.interactions.favourite.headline\": \"Favourite\",\n  \"introduction.interactions.favourite.text\": \"You can save a toot for later, and let the author know that you liked it, by favouriting it.\",\n  \"introduction.interactions.reblog.headline\": \"Boost\",\n  \"introduction.interactions.reblog.text\": \"You can share other people's toots with your followers by boosting them.\",\n  \"introduction.interactions.reply.headline\": \"Reply\",\n  \"introduction.interactions.reply.text\": \"You can reply to other people's and your own toots, which will chain them together in a conversation.\",\n  \"introduction.welcome.action\": \"Let's go!\",\n  \"introduction.welcome.headline\": \"First steps\",\n  \"introduction.welcome.text\": \"Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.\",\n  \"keyboard_shortcuts.back\": \"უკან გადასასვლელად\",\n  \"keyboard_shortcuts.blocked\": \"to open blocked users list\",\n  \"keyboard_shortcuts.boost\": \"დასაბუსტად\",\n  \"keyboard_shortcuts.column\": \"ერთ-ერთი სვეტში სტატუსზე ფოკუსირებისთვის\",\n  \"keyboard_shortcuts.compose\": \"შედგენის ტექსტ-არეაზე ფოკუსირებისთვის\",\n  \"keyboard_shortcuts.description\": \"აღწერილობა\",\n  \"keyboard_shortcuts.direct\": \"to open direct messages column\",\n  \"keyboard_shortcuts.down\": \"სიაში ქვემოთ გადასაადგილებლად\",\n  \"keyboard_shortcuts.enter\": \"სტატუსის გასახსნელად\",\n  \"keyboard_shortcuts.favourite\": \"ფავორიტად ქცევისთვის\",\n  \"keyboard_shortcuts.favourites\": \"to open favourites list\",\n  \"keyboard_shortcuts.federated\": \"to open federated timeline\",\n  \"keyboard_shortcuts.heading\": \"კლავიატურის სწრაფი ბმულები\",\n  \"keyboard_shortcuts.home\": \"to open home timeline\",\n  \"keyboard_shortcuts.hotkey\": \"ცხელი კლავიში\",\n  \"keyboard_shortcuts.legend\": \"ამ ლეგენდის გამოსაჩენად\",\n  \"keyboard_shortcuts.local\": \"to open local timeline\",\n  \"keyboard_shortcuts.mention\": \"ავტორის დასახელებლად\",\n  \"keyboard_shortcuts.muted\": \"to open muted users list\",\n  \"keyboard_shortcuts.my_profile\": \"to open your profile\",\n  \"keyboard_shortcuts.notifications\": \"to open notifications column\",\n  \"keyboard_shortcuts.pinned\": \"to open pinned toots list\",\n  \"keyboard_shortcuts.profile\": \"ავტორის პროფილის გასახსნელად\",\n  \"keyboard_shortcuts.reply\": \"პასუხისთვის\",\n  \"keyboard_shortcuts.requests\": \"to open follow requests list\",\n  \"keyboard_shortcuts.search\": \"ძიებაზე ფოკუსირებისთვის\",\n  \"keyboard_shortcuts.start\": \"to open \\\"get started\\\" column\",\n  \"keyboard_shortcuts.toggle_hidden\": \"გაფრთხილების უკან ტექსტის გამოსაჩენად/დასამალვად\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"to show/hide media\",\n  \"keyboard_shortcuts.toot\": \"ახალი ტუტის დასაწყებად\",\n  \"keyboard_shortcuts.unfocus\": \"შედგენის ტექსტ-არეაზე ფოკუსის მოსაშორებლად\",\n  \"keyboard_shortcuts.up\": \"სიაში ზემოთ გადასაადგილებლად\",\n  \"lightbox.close\": \"დახურვა\",\n  \"lightbox.next\": \"შემდეგი\",\n  \"lightbox.previous\": \"წინა\",\n  \"lightbox.view_context\": \"View context\",\n  \"lists.account.add\": \"სიაში დამატება\",\n  \"lists.account.remove\": \"სიიდან ამოშლა\",\n  \"lists.delete\": \"სიის წაშლა\",\n  \"lists.edit\": \"სიის შეცვლა\",\n  \"lists.edit.submit\": \"Change title\",\n  \"lists.new.create\": \"სიის დამატება\",\n  \"lists.new.title_placeholder\": \"ახალი სიის სათაური\",\n  \"lists.search\": \"ძებნა ადამიანებს შორის რომელთაც მიჰყვებით\",\n  \"lists.subheading\": \"თქვენი სიები\",\n  \"loading_indicator.label\": \"იტვირთება...\",\n  \"media_gallery.toggle_visible\": \"ხილვადობის ჩართვა\",\n  \"missing_indicator.label\": \"არაა ნაპოვნი\",\n  \"missing_indicator.sublabel\": \"ამ რესურსის პოვნა ვერ მოხერხდა\",\n  \"mute_modal.hide_notifications\": \"დავმალოთ შეტყობინებები ამ მომხმარებლისგან?\",\n  \"navigation_bar.apps\": \"Mobile apps\",\n  \"navigation_bar.blocks\": \"დაბლოკილი მომხმარებლები\",\n  \"navigation_bar.community_timeline\": \"ლოკალური თაიმლაინი\",\n  \"navigation_bar.compose\": \"Compose new toot\",\n  \"navigation_bar.direct\": \"პირდაპირი წერილები\",\n  \"navigation_bar.discover\": \"აღმოაჩინე\",\n  \"navigation_bar.domain_blocks\": \"დამალული დომენები\",\n  \"navigation_bar.edit_profile\": \"შეცვალე პროფილი\",\n  \"navigation_bar.favourites\": \"ფავორიტები\",\n  \"navigation_bar.filters\": \"გაჩუმებული სიტყვები\",\n  \"navigation_bar.follow_requests\": \"დადევნების მოთხოვნები\",\n  \"navigation_bar.follows_and_followers\": \"Follows and followers\",\n  \"navigation_bar.info\": \"ამ ინსტანციის შესახებ\",\n  \"navigation_bar.keyboard_shortcuts\": \"ცხელი კლავიშები\",\n  \"navigation_bar.lists\": \"სიები\",\n  \"navigation_bar.logout\": \"გასვლა\",\n  \"navigation_bar.mutes\": \"გაჩუმებული მომხმარებლები\",\n  \"navigation_bar.personal\": \"პირადი\",\n  \"navigation_bar.pins\": \"აპინული ტუტები\",\n  \"navigation_bar.preferences\": \"პრეფერენსიები\",\n  \"navigation_bar.profile_directory\": \"Profile directory\",\n  \"navigation_bar.public_timeline\": \"ფედერალური თაიმლაინი\",\n  \"navigation_bar.security\": \"უსაფრთხოება\",\n  \"notification.favourite\": \"{name}-მა თქვენი სტატუსი აქცია ფავორიტად\",\n  \"notification.follow\": \"{name} გამოგყვათ\",\n  \"notification.mention\": \"{name}-მა გასახელათ\",\n  \"notification.poll\": \"A poll you have voted in has ended\",\n  \"notification.reblog\": \"{name}-მა დაბუსტა თქვენი სტატუსი\",\n  \"notifications.clear\": \"შეტყობინებების გასუფთავება\",\n  \"notifications.clear_confirmation\": \"დარწმუნებული ხართ, გსურთ სამუდამოდ წაშალოთ ყველა თქვენი შეტყობინება?\",\n  \"notifications.column_settings.alert\": \"დესკტოპ შეტყობინებები\",\n  \"notifications.column_settings.favourite\": \"ფავორიტები:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Display all categories\",\n  \"notifications.column_settings.filter_bar.category\": \"Quick filter bar\",\n  \"notifications.column_settings.filter_bar.show\": \"Show\",\n  \"notifications.column_settings.follow\": \"ახალი მიმდევრები:\",\n  \"notifications.column_settings.mention\": \"ხსენებები:\",\n  \"notifications.column_settings.poll\": \"Poll results:\",\n  \"notifications.column_settings.push\": \"ფუშ შეტყობინებები\",\n  \"notifications.column_settings.reblog\": \"ბუსტები:\",\n  \"notifications.column_settings.show\": \"გამოჩნდეს სვეტში\",\n  \"notifications.column_settings.sound\": \"ხმის დაკვრა\",\n  \"notifications.filter.all\": \"All\",\n  \"notifications.filter.boosts\": \"Boosts\",\n  \"notifications.filter.favourites\": \"Favourites\",\n  \"notifications.filter.follows\": \"Follows\",\n  \"notifications.filter.mentions\": \"Mentions\",\n  \"notifications.filter.polls\": \"Poll results\",\n  \"notifications.group\": \"{count} შეტყობინება\",\n  \"poll.closed\": \"Closed\",\n  \"poll.refresh\": \"Refresh\",\n  \"poll.total_votes\": \"{count, plural, one {# vote} other {# votes}}\",\n  \"poll.vote\": \"Vote\",\n  \"poll_button.add_poll\": \"Add a poll\",\n  \"poll_button.remove_poll\": \"Remove poll\",\n  \"privacy.change\": \"სტატუსის კონფიდენციალურობის მითითება\",\n  \"privacy.direct.long\": \"დაიპოსტოს მხოლოდ დასახელებულ მომხმარებლებთან\",\n  \"privacy.direct.short\": \"პირდაპირი\",\n  \"privacy.private.long\": \"დაიპოსტოს მხოლოდ მიმდევრებთან\",\n  \"privacy.private.short\": \"მხოლოდ-მიმდევრებისთვის\",\n  \"privacy.public.long\": \"დაიპოსტოს საჯარო თაიმლაინებზე\",\n  \"privacy.public.short\": \"საჯარო\",\n  \"privacy.unlisted.long\": \"არ დაიპოსტოს საჯარო თაიმლაინებზე\",\n  \"privacy.unlisted.short\": \"ჩამოუთვლელი\",\n  \"regeneration_indicator.label\": \"იტვირთება…\",\n  \"regeneration_indicator.sublabel\": \"თქვენი სახლის ლენტა მზადდება!\",\n  \"relative_time.days\": \"{number}დღ\",\n  \"relative_time.hours\": \"{number}სთ\",\n  \"relative_time.just_now\": \"ახლა\",\n  \"relative_time.minutes\": \"{number}წთ\",\n  \"relative_time.seconds\": \"{number}წმ\",\n  \"reply_indicator.cancel\": \"უარყოფა\",\n  \"report.forward\": \"ფორვარდი {target}-ს\",\n  \"report.forward_hint\": \"ანგარიში სხვა სერვერიდანაა. გავაგზავნოთ რეპორტის ანონიმური ასლიც?\",\n  \"report.hint\": \"რეპორტი გაეგზავნება თქვენი ინსტანციის მოდერატორებს. ქვემოთ შეგიძლიათ დაამატოთ მიზეზი თუ რატომ არეპორტებთ ამ ანგარიშს:\",\n  \"report.placeholder\": \"დამატებითი კომენტარები\",\n  \"report.submit\": \"დასრულება\",\n  \"report.target\": \"არეპორტებთ {target}\",\n  \"search.placeholder\": \"ძებნა\",\n  \"search_popout.search_format\": \"დეტალური ძებნის ფორმა\",\n  \"search_popout.tips.full_text\": \"მარტივი ტექსტი აბრუნებს სტატუსებს რომლებიც შექმენით, აქციეთ ფავორიტად, დაბუსტეთ, ან რაშიც ასახელეთ, ასევე ემთხვევა მომხმარებლის სახელებს, დისპლეი სახელებს, და ჰეშტეგებს.\",\n  \"search_popout.tips.hashtag\": \"ჰეშტეგი\",\n  \"search_popout.tips.status\": \"სტატუსი\",\n  \"search_popout.tips.text\": \"მარტივი ტექსტი აბრუნებს დამთხვეულ დისპლეი სახელებს, მომხმარებლის სახელებს და ჰეშტეგებს\",\n  \"search_popout.tips.user\": \"მომხმარებელი\",\n  \"search_results.accounts\": \"ხალხი\",\n  \"search_results.hashtags\": \"ჰეშტეგები\",\n  \"search_results.statuses\": \"ტუტები\",\n  \"search_results.total\": \"{count, number} {count, plural, one {result} other {results}}\",\n  \"status.admin_account\": \"Open moderation interface for @{name}\",\n  \"status.admin_status\": \"Open this status in the moderation interface\",\n  \"status.block\": \"დაბლოკე @{name}\",\n  \"status.cancel_reblog_private\": \"ბუსტის მოშორება\",\n  \"status.cannot_reblog\": \"ეს პოსტი ვერ დაიბუსტება\",\n  \"status.copy\": \"Copy link to status\",\n  \"status.delete\": \"წაშლა\",\n  \"status.detailed_status\": \"Detailed conversation view\",\n  \"status.direct\": \"პირდაპირი წერილი @{name}-ს\",\n  \"status.embed\": \"ჩართვა\",\n  \"status.favourite\": \"ფავორიტი\",\n  \"status.filtered\": \"ფილტრირებული\",\n  \"status.load_more\": \"მეტის ჩატვირთვა\",\n  \"status.media_hidden\": \"მედია დამალულია\",\n  \"status.mention\": \"ასახელე @{name}\",\n  \"status.more\": \"მეტი\",\n  \"status.mute\": \"გააჩუმე @{name}\",\n  \"status.mute_conversation\": \"გააჩუმე საუბარი\",\n  \"status.open\": \"ამ სტატუსის გაფართოება\",\n  \"status.pin\": \"აპინე პროფილზე\",\n  \"status.pinned\": \"აპინული ტუტი\",\n  \"status.read_more\": \"Read more\",\n  \"status.reblog\": \"ბუსტი\",\n  \"status.reblog_private\": \"დაიბუსტოს საწყის აუდიტორიაზე\",\n  \"status.reblogged_by\": \"{name} დაიბუსტა\",\n  \"status.reblogs.empty\": \"No one has boosted this toot yet. When someone does, they will show up here.\",\n  \"status.redraft\": \"გაუქმდეს და გადანაწილდეს\",\n  \"status.reply\": \"პასუხი\",\n  \"status.replyAll\": \"უპასუხე თემას\",\n  \"status.report\": \"დაარეპორტე @{name}\",\n  \"status.sensitive_warning\": \"მგრძნობიარე კონტენტი\",\n  \"status.share\": \"გაზიარება\",\n  \"status.show_less\": \"აჩვენე ნაკლები\",\n  \"status.show_less_all\": \"აჩვენე ნაკლები ყველაზე\",\n  \"status.show_more\": \"აჩვენე მეტი\",\n  \"status.show_more_all\": \"აჩვენე მეტი ყველაზე\",\n  \"status.show_thread\": \"Show thread\",\n  \"status.unmute_conversation\": \"საუბარზე გაჩუმების მოშორება\",\n  \"status.unpin\": \"პროფილიდან პინის მოშორება\",\n  \"suggestions.dismiss\": \"Dismiss suggestion\",\n  \"suggestions.header\": \"You might be interested in…\",\n  \"tabs_bar.federated_timeline\": \"ფედერალური\",\n  \"tabs_bar.home\": \"სახლი\",\n  \"tabs_bar.local_timeline\": \"ლოკალური\",\n  \"tabs_bar.notifications\": \"შეტყობინებები\",\n  \"tabs_bar.search\": \"ძებნა\",\n  \"time_remaining.days\": \"{number, plural, one {# day} other {# days}} left\",\n  \"time_remaining.hours\": \"{number, plural, one {# hour} other {# hours}} left\",\n  \"time_remaining.minutes\": \"{number, plural, one {# minute} other {# minutes}} left\",\n  \"time_remaining.moments\": \"Moments remaining\",\n  \"time_remaining.seconds\": \"{number, plural, one {# second} other {# seconds}} left\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {person} other {people}} საუბრობს\",\n  \"ui.beforeunload\": \"თქვენი დრაფტი გაუქმდება თუ დატოვებთ მასტოდონს.\",\n  \"upload_area.title\": \"გადმოწიეთ და ჩააგდეთ ასატვირთათ\",\n  \"upload_button.label\": \"მედიის დამატება\",\n  \"upload_error.limit\": \"File upload limit exceeded.\",\n  \"upload_error.poll\": \"File upload not allowed with polls.\",\n  \"upload_form.description\": \"აღწერილობა ვიზუალურად უფასურისთვის\",\n  \"upload_form.focus\": \"კროპი\",\n  \"upload_form.undo\": \"გაუქმება\",\n  \"upload_progress.label\": \"იტვირთება...\",\n  \"video.close\": \"ვიდეოს დახურვა\",\n  \"video.exit_fullscreen\": \"სრულ ეკრანზე ჩვენების გათიშვა\",\n  \"video.expand\": \"ვიდეოს გაფართოება\",\n  \"video.fullscreen\": \"ჩვენება სრულ ეკრანზე\",\n  \"video.hide\": \"ვიდეოს დამალვა\",\n  \"video.mute\": \"ხმის გაჩუმება\",\n  \"video.pause\": \"პაუზა\",\n  \"video.play\": \"დაკვრა\",\n  \"video.unmute\": \"ხმის გაჩუმების მოშორება\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/kk.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Тізімге қосу немесе жою\",\n  \"account.badges.bot\": \"Бот\",\n  \"account.block\": \"Бұғаттау @{name}\",\n  \"account.block_domain\": \"Домендегі барлығын бұғатта {domain}\",\n  \"account.blocked\": \"Бұғатталды\",\n  \"account.direct\": \"Жеке хат @{name}\",\n  \"account.domain_blocked\": \"Домен жабық\",\n  \"account.edit_profile\": \"Профильді өңдеу\",\n  \"account.endorse\": \"Профильде рекомендеу\",\n  \"account.follow\": \"Жазылу\",\n  \"account.followers\": \"Оқырмандар\",\n  \"account.followers.empty\": \"Әлі ешкім жазылмаған.\",\n  \"account.follows\": \"Жазылғандары\",\n  \"account.follows.empty\": \"Ешкімге жазылмапты.\",\n  \"account.follows_you\": \"Сізге жазылыпты\",\n  \"account.hide_reblogs\": \"@{name} атты қолданушының әрекеттерін жасыру\",\n  \"account.link_verified_on\": \"Сілтеме меншігі расталған күн {date}\",\n  \"account.locked_info\": \"Бұл қолданушы өзі туралы мәліметтерді жасырған. Тек жазылғандар ғана көре алады.\",\n  \"account.media\": \"Медиа\",\n  \"account.mention\": \"Аталым @{name}\",\n  \"account.moved_to\": \"{name} көшіп кетті:\",\n  \"account.mute\": \"Үнсіз қылу @{name}\",\n  \"account.mute_notifications\": \"@{name} туралы ескертпелерді жасыру\",\n  \"account.muted\": \"Үнсіз\",\n  \"account.posts\": \"Жазбалар\",\n  \"account.posts_with_replies\": \"Жазбалар мен жауаптар\",\n  \"account.report\": \"Шағымдану @{name}\",\n  \"account.requested\": \"Растауын күтіңіз. Жазылудан бас тарту үшін басыңыз\",\n  \"account.share\": \"@{name} профилін бөлісу\\\"\",\n  \"account.show_reblogs\": \"@{name} бөліскендерін көрсету\",\n  \"account.unblock\": \"Бұғаттан шығару @{name}\",\n  \"account.unblock_domain\": \"Бұғаттан шығару {domain}\",\n  \"account.unendorse\": \"Профильде рекомендемеу\",\n  \"account.unfollow\": \"Оқымау\",\n  \"account.unmute\": \"@{name} ескертпелерін қосу\",\n  \"account.unmute_notifications\": \"@{name} ескертпелерін көрсету\",\n  \"alert.unexpected.message\": \"Бір нәрсе дұрыс болмады.\",\n  \"alert.unexpected.title\": \"Өй!\",\n  \"boost_modal.combo\": \"Келесіде өткізіп жіберу үшін басыңыз {combo}\",\n  \"bundle_column_error.body\": \"Бұл компонентті жүктеген кезде бір қате пайда болды.\",\n  \"bundle_column_error.retry\": \"Қайтадан көріңіз\",\n  \"bundle_column_error.title\": \"Желі қатесі\",\n  \"bundle_modal_error.close\": \"Жабу\",\n  \"bundle_modal_error.message\": \"Бұл компонентті жүктеген кезде бір қате пайда болды.\",\n  \"bundle_modal_error.retry\": \"Қайтадан көріңіз\",\n  \"column.blocks\": \"Бұғатталғандар\",\n  \"column.community\": \"Жергілікті желі\",\n  \"column.direct\": \"Жеке хаттар\",\n  \"column.domain_blocks\": \"Жасырылған домендер\",\n  \"column.favourites\": \"Таңдаулылар\",\n  \"column.follow_requests\": \"Жазылу сұранымдары\",\n  \"column.home\": \"Басты бет\",\n  \"column.lists\": \"Тізімдер\",\n  \"column.mutes\": \"Үнсіз қолданушылар\",\n  \"column.notifications\": \"Ескертпелер\",\n  \"column.pins\": \"Жабыстырылған жазбалар\",\n  \"column.public\": \"Жаһандық желі\",\n  \"column_back_button.label\": \"Артқа\",\n  \"column_header.hide_settings\": \"Баптауларды жасыр\",\n  \"column_header.moveLeft_settings\": \"Бағананы солға жылжыту\",\n  \"column_header.moveRight_settings\": \"Бағананы оңға жылжыту\",\n  \"column_header.pin\": \"Жабыстыру\",\n  \"column_header.show_settings\": \"Баптауларды көрсет\",\n  \"column_header.unpin\": \"Алып тастау\",\n  \"column_subheading.settings\": \"Баптаулар\",\n  \"community.column_settings.media_only\": \"Тек медиа\",\n  \"compose_form.direct_message_warning\": \"Тек аталған қолданушыларға.\",\n  \"compose_form.direct_message_warning_learn_more\": \"Көбірек білу\",\n  \"compose_form.hashtag_warning\": \"Бұл пост іздеуде хэштегпен шықпайды, өйткені ол бәріне ашық емес. Тек ашық жазбаларды ғана хэштег арқылы іздеп табуға болады.\",\n  \"compose_form.lock_disclaimer\": \"Аккаунтыңыз {locked} емес. Кез келген адам жазылып, сізді оқи алады.\",\n  \"compose_form.lock_disclaimer.lock\": \"жабық\",\n  \"compose_form.placeholder\": \"Не бөліскіңіз келеді?\",\n  \"compose_form.poll.add_option\": \"Жауап қос\",\n  \"compose_form.poll.duration\": \"Сауалнама мерзімі\",\n  \"compose_form.poll.option_placeholder\": \"Жауап {number}\",\n  \"compose_form.poll.remove_option\": \"Бұл жауапты өшір\",\n  \"compose_form.publish\": \"Түрт\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"Mark media as sensitive\",\n  \"compose_form.sensitive.marked\": \"Медиа нәзік деп белгіленген\",\n  \"compose_form.sensitive.unmarked\": \"Медиа нәзік деп белгіленбеген\",\n  \"compose_form.spoiler.marked\": \"Мәтін ескертумен жасырылған\",\n  \"compose_form.spoiler.unmarked\": \"Мәтін жасырылмаған\",\n  \"compose_form.spoiler_placeholder\": \"Ескертуіңізді осында жазыңыз\",\n  \"confirmation_modal.cancel\": \"Қайтып алу\",\n  \"confirmations.block.block_and_report\": \"Block & Report\",\n  \"confirmations.block.confirm\": \"Бұғаттау\",\n  \"confirmations.block.message\": \"{name} атты қолданушыны бұғаттайтыныңызға сенімдісіз бе?\",\n  \"confirmations.delete.confirm\": \"Өшіру\",\n  \"confirmations.delete.message\": \"Бұл жазбаны өшіресіз бе?\",\n  \"confirmations.delete_list.confirm\": \"Өшіру\",\n  \"confirmations.delete_list.message\": \"Бұл тізімді жоясыз ба шынымен?\",\n  \"confirmations.domain_block.confirm\": \"Бұл доменді бұғатта\",\n  \"confirmations.domain_block.message\": \"Бұл домендегі {domain} жазбаларды шынымен бұғаттайсыз ба? Кейде үнсіз қылып тастау да жеткілікті.\",\n  \"confirmations.mute.confirm\": \"Үнсіз қылу\",\n  \"confirmations.mute.message\": \"{name} атты қолданушы үнсіз болсын ба?\",\n  \"confirmations.redraft.confirm\": \"Өшіруді құптау\",\n  \"confirmations.redraft.message\": \"Бұл жазбаны өшіріп, нобайларға жібереміз бе? Барлық жауаптар мен лайктарды жоғалтасыз.\",\n  \"confirmations.reply.confirm\": \"Жауап\",\n  \"confirmations.reply.message\": \"Жауабыңыз жазып жатқан жазбаңыздың үстіне кетеді. Жалғастырамыз ба?\",\n  \"confirmations.unfollow.confirm\": \"Оқымау\",\n  \"confirmations.unfollow.message\": \"\\\"{name} атты қолданушыға енді жазылғыңыз келмей ме?\",\n  \"embed.instructions\": \"Төмендегі кодты көшіріп алу арқылы жазбаны басқа сайттарға да орналастыра аласыз.\",\n  \"embed.preview\": \"Былай көрінетін болады:\",\n  \"emoji_button.activity\": \"Белсенділік\",\n  \"emoji_button.custom\": \"Жеке\",\n  \"emoji_button.flags\": \"Тулар\",\n  \"emoji_button.food\": \"Тамақ\",\n  \"emoji_button.label\": \"Эмодзи қосу\",\n  \"emoji_button.nature\": \"Табиғат\",\n  \"emoji_button.not_found\": \"Эмодзи жоқ!! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"Заттар\",\n  \"emoji_button.people\": \"Адамдар\",\n  \"emoji_button.recent\": \"Соңғы\",\n  \"emoji_button.search\": \"Іздеу...\",\n  \"emoji_button.search_results\": \"Іздеу нәтижелері\",\n  \"emoji_button.symbols\": \"Таңбалар\",\n  \"emoji_button.travel\": \"Саяхат\",\n  \"empty_column.account_timeline\": \"Жазба жоқ ешқандай!\",\n  \"empty_column.account_unavailable\": \"Profile unavailable\",\n  \"empty_column.blocks\": \"Ешкімді бұғаттамағансыз.\",\n  \"empty_column.community\": \"Жергілікті желі бос. Сіз бастап жазыңыз!\",\n  \"empty_column.direct\": \"Әзірше дым хат жоқ. Өзіңіз жазып көріңіз алдымен.\",\n  \"empty_column.domain_blocks\": \"Бұғатталған домен жоқ.\",\n  \"empty_column.favourited_statuses\": \"Ешқандай жазба 'Таңдаулылар' тізіміне қосылмапты. Қосылғаннан кейін осында жинала бастайды.\",\n  \"empty_column.favourites\": \"Бұл постты әлі ешкім 'Таңдаулылар' тізіміне қоспапты. Біреу бастағаннан кейін осында көрінетін болады.\",\n  \"empty_column.follow_requests\": \"Әлі ешқандай жазылуға сұранымдар келмеді. Жаңа сұранымдар осында көрінетін болады.\",\n  \"empty_column.hashtag\": \"Бұндай хэштегпен әлі ешкім жазбапты.\",\n  \"empty_column.home\": \"Әлі ешкімге жазылмапсыз. Бәлкім {public} жазбаларын қарап немесе іздеуді қолданып көрерсіз.\",\n  \"empty_column.home.public_timeline\": \"ашық желі\",\n  \"empty_column.list\": \"Бұл тізімде ештеңе жоқ.\",\n  \"empty_column.lists\": \"Әзірше ешқандай тізіміңіз жоқ. Біреуін құрғаннан кейін осы жерде көрінетін болады.\",\n  \"empty_column.mutes\": \"Әзірше ешқандай үнсізге қойылған қолданушы жоқ.\",\n  \"empty_column.notifications\": \"Әзірше ешқандай ескертпе жоқ. Басқалармен араласуды бастаңыз және пікірталастарға қатысыңыз.\",\n  \"empty_column.public\": \"Ештеңе жоқ бұл жерде! Өзіңіз бастап жазып көріңіз немесе басқаларға жазылыңыз\",\n  \"follow_request.authorize\": \"Авторизация\",\n  \"follow_request.reject\": \"Қабылдамау\",\n  \"getting_started.developers\": \"Жасаушылар тобы\",\n  \"getting_started.directory\": \"Профильдер каталогы\",\n  \"getting_started.documentation\": \"Құжаттама\",\n  \"getting_started.heading\": \"Желіде\",\n  \"getting_started.invite\": \"Адам шақыру\",\n  \"getting_started.open_source_notice\": \"Mastodon - ашық кодты құрылым. Түзету енгізу немесе ұсыныстарды GitHub арқылы жасаңыз {github}.\",\n  \"getting_started.security\": \"Қауіпсіздік\",\n  \"getting_started.terms\": \"Қызмет көрсету шарттары\",\n  \"hashtag.column_header.tag_mode.all\": \"және {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"немесе {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"{additional} болмай\",\n  \"hashtag.column_settings.select.no_options_message\": \"Ұсыныстар табылмады\",\n  \"hashtag.column_settings.select.placeholder\": \"Хэштег жазыңыз…\",\n  \"hashtag.column_settings.tag_mode.all\": \"Осының барлығын\",\n  \"hashtag.column_settings.tag_mode.any\": \"Осылардың біреуін\",\n  \"hashtag.column_settings.tag_mode.none\": \"Бұлардың ешқайсысын\",\n  \"hashtag.column_settings.tag_toggle\": \"Осы бағанға қосымша тегтерді қосыңыз\",\n  \"home.column_settings.basic\": \"Негізгі\",\n  \"home.column_settings.show_reblogs\": \"Бөлісулерді көрсету\",\n  \"home.column_settings.show_replies\": \"Жауаптарды көрсету\",\n  \"intervals.full.days\": \"{number, plural, one {# күн} other {# күн}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# сағат} other {# сағат}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minute} other {# minutes}}\",\n  \"introduction.federation.action\": \"Келесі\",\n  \"introduction.federation.federated.headline\": \"Жаһандық\",\n  \"introduction.federation.federated.text\": \"Жаһандық желідегі жазбалар осында көрінетін болады.\",\n  \"introduction.federation.home.headline\": \"Басты бет\",\n  \"introduction.federation.home.text\": \"Жазылған адамдарыңыздың жазбалары осында шығады. Кез келген серверден жазылуыңызға болады!\",\n  \"introduction.federation.local.headline\": \"Жергілікті\",\n  \"introduction.federation.local.text\": \"Жергілікті желіде жазылған жазбалар осында шығатын болады.\",\n  \"introduction.interactions.action\": \"Оқулық аяқталды!\",\n  \"introduction.interactions.favourite.headline\": \"Таңдаулы\",\n  \"introduction.interactions.favourite.text\": \"Жазбаларды таңдаулыға сақтауға болады, осылайша авторына ұнағанын білдіре аласыз.\",\n  \"introduction.interactions.reblog.headline\": \"Бөлісу\",\n  \"introduction.interactions.reblog.text\": \"Ұнаған жазбаларды өз оқырмандарыңызбен бөлісе аласыз.\",\n  \"introduction.interactions.reply.headline\": \"Жауап\",\n  \"introduction.interactions.reply.text\": \"Жазбаларға жауап жаза аласыз, осылайша пікірталас өрбітуіңізге болады.\",\n  \"introduction.welcome.action\": \"Кеттік!\",\n  \"introduction.welcome.headline\": \"Алғашқы қадамдар\",\n  \"introduction.welcome.text\": \"Желіге қош келдіңіз! Бірнеше минуттан кейін желіде жазба қалдырып, медиа бөлісіп, басқалармен пікірталасқа қатысып ортаға қосыла аласыз. . Бірақ бұл сервер {domain} - бұл ерекше, ол сіздің профиліңізді қояды, сондықтан оның есімін есіңізде сақтаңыз.\",\n  \"keyboard_shortcuts.back\": \"артқа қайту\",\n  \"keyboard_shortcuts.blocked\": \"бұғатталғандар тізімін ашу\",\n  \"keyboard_shortcuts.boost\": \"жазба бөлісу\",\n  \"keyboard_shortcuts.column\": \"бағандардағы жазбаны оқу\",\n  \"keyboard_shortcuts.compose\": \"пост жазу\",\n  \"keyboard_shortcuts.description\": \"Сипаттама\",\n  \"keyboard_shortcuts.direct\": \"жеке хаттар бағаны\",\n  \"keyboard_shortcuts.down\": \"тізімде төмен түсу\",\n  \"keyboard_shortcuts.enter\": \"жазбаны ашу\",\n  \"keyboard_shortcuts.favourite\": \"таңдаулыға қосу\",\n  \"keyboard_shortcuts.favourites\": \"таңдаулылар тізімін ашу\",\n  \"keyboard_shortcuts.federated\": \"жаңандық желіні ашу\",\n  \"keyboard_shortcuts.heading\": \"Қысқа кодтар тақтасы\",\n  \"keyboard_shortcuts.home\": \"жергілікті жазбаларды қарау\",\n  \"keyboard_shortcuts.hotkey\": \"Ыстық пернелер\",\n  \"keyboard_shortcuts.legend\": \"осы мазмұнды көрсету\",\n  \"keyboard_shortcuts.local\": \"жергілікті желіні ашу\",\n  \"keyboard_shortcuts.mention\": \"авторды атап өту\",\n  \"keyboard_shortcuts.muted\": \"үнсіздер тізімін ашу\",\n  \"keyboard_shortcuts.my_profile\": \"профиліңізді ашу\",\n  \"keyboard_shortcuts.notifications\": \"ескертпелер бағанын ашу\",\n  \"keyboard_shortcuts.pinned\": \"жабыстырылған жазбаларды көру\",\n  \"keyboard_shortcuts.profile\": \"автор профилін қарау\",\n  \"keyboard_shortcuts.reply\": \"жауап жазу\",\n  \"keyboard_shortcuts.requests\": \"жазылу сұранымдарын қарау\",\n  \"keyboard_shortcuts.search\": \"іздеу\",\n  \"keyboard_shortcuts.start\": \"бастапқы бағанға бару\",\n  \"keyboard_shortcuts.toggle_hidden\": \"жабық мәтінді CW ашу/жабу\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"to show/hide media\",\n  \"keyboard_shortcuts.toot\": \"жаңа жазба бастау\",\n  \"keyboard_shortcuts.unfocus\": \"жазба қалдыру алаңынан шығу\",\n  \"keyboard_shortcuts.up\": \"тізімде жоғары шығу\",\n  \"lightbox.close\": \"Жабу\",\n  \"lightbox.next\": \"Келесі\",\n  \"lightbox.previous\": \"Алдыңғы\",\n  \"lightbox.view_context\": \"View context\",\n  \"lists.account.add\": \"Тізімге қосу\",\n  \"lists.account.remove\": \"Тізімнен шығару\",\n  \"lists.delete\": \"Тізімді өшіру\",\n  \"lists.edit\": \"Тізімді өңдеу\",\n  \"lists.edit.submit\": \"Тақырыбын өзгерту\",\n  \"lists.new.create\": \"Тізім құру\",\n  \"lists.new.title_placeholder\": \"Жаңа тізім аты\",\n  \"lists.search\": \"Сіз іздеген адамдар арасында іздеу\",\n  \"lists.subheading\": \"Тізімдеріңіз\",\n  \"loading_indicator.label\": \"Жүктеу...\",\n  \"media_gallery.toggle_visible\": \"Көрінуді қосу\",\n  \"missing_indicator.label\": \"Табылмады\",\n  \"missing_indicator.sublabel\": \"Бұл ресурс табылмады\",\n  \"mute_modal.hide_notifications\": \"Бұл қолданушы ескертпелерін жасырамыз ба?\",\n  \"navigation_bar.apps\": \"Мобиль қосымшалар\",\n  \"navigation_bar.blocks\": \"Бұғатталғандар\",\n  \"navigation_bar.community_timeline\": \"Жергілікті желі\",\n  \"navigation_bar.compose\": \"Жаңа жазба бастау\",\n  \"navigation_bar.direct\": \"Жеке хаттар\",\n  \"navigation_bar.discover\": \"шарлау\",\n  \"navigation_bar.domain_blocks\": \"Жабық домендер\",\n  \"navigation_bar.edit_profile\": \"Профиль түзету\",\n  \"navigation_bar.favourites\": \"Таңдаулылар\",\n  \"navigation_bar.filters\": \"Үнсіз сөздер\",\n  \"navigation_bar.follow_requests\": \"Жазылуға сұранғандар\",\n  \"navigation_bar.follows_and_followers\": \"Follows and followers\",\n  \"navigation_bar.info\": \"Сервер туралы\",\n  \"navigation_bar.keyboard_shortcuts\": \"Ыстық пернелер\",\n  \"navigation_bar.lists\": \"Тізімдер\",\n  \"navigation_bar.logout\": \"Шығу\",\n  \"navigation_bar.mutes\": \"Үнсіз қолданушылар\",\n  \"navigation_bar.personal\": \"Жеке\",\n  \"navigation_bar.pins\": \"Жабыстырылғандар\",\n  \"navigation_bar.preferences\": \"Басымдықтар\",\n  \"navigation_bar.profile_directory\": \"Profile directory\",\n  \"navigation_bar.public_timeline\": \"Жаһандық желі\",\n  \"navigation_bar.security\": \"Қауіпсіздік\",\n  \"notification.favourite\": \"{name} жазбаңызды таңдаулыға қосты\",\n  \"notification.follow\": \"{name} сізге жазылды\",\n  \"notification.mention\": \"{name} сізді атап өтті\",\n  \"notification.poll\": \"Бұл сауалнаманың мерзімі аяқталыпты\",\n  \"notification.reblog\": \"{name} жазбаңызды бөлісті\",\n  \"notifications.clear\": \"Ескертпелерді тазарт\",\n  \"notifications.clear_confirmation\": \"Шынымен барлық ескертпелерді өшіресіз бе?\",\n  \"notifications.column_settings.alert\": \"Үстел ескертпелері\",\n  \"notifications.column_settings.favourite\": \"Таңдаулылар:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Барлық категорияны көрсет\",\n  \"notifications.column_settings.filter_bar.category\": \"Жедел сүзгі\",\n  \"notifications.column_settings.filter_bar.show\": \"Көрсету\",\n  \"notifications.column_settings.follow\": \"Жаңа оқырмандар:\",\n  \"notifications.column_settings.mention\": \"Аталымдар:\",\n  \"notifications.column_settings.poll\": \"Нәтижелері:\",\n  \"notifications.column_settings.push\": \"Push ескертпелер\",\n  \"notifications.column_settings.reblog\": \"Бөлісулер:\",\n  \"notifications.column_settings.show\": \"Бағанда көрсет\",\n  \"notifications.column_settings.sound\": \"Дыбысын қос\",\n  \"notifications.filter.all\": \"Барлығы\",\n  \"notifications.filter.boosts\": \"Бөлісулер\",\n  \"notifications.filter.favourites\": \"Таңдаулылар\",\n  \"notifications.filter.follows\": \"Жазылулар\",\n  \"notifications.filter.mentions\": \"Аталымдар\",\n  \"notifications.filter.polls\": \"Сауалнама нәтижелері\",\n  \"notifications.group\": \"{count} ескертпе\",\n  \"poll.closed\": \"Жабық\",\n  \"poll.refresh\": \"Жаңарту\",\n  \"poll.total_votes\": \"{count, plural, one {# дауыс} other {# дауыс}}\",\n  \"poll.vote\": \"Дауыс беру\",\n  \"poll_button.add_poll\": \"Сауалнама қосу\",\n  \"poll_button.remove_poll\": \"Сауалнаманы өшіру\",\n  \"privacy.change\": \"Құпиялылықты реттеу\",\n  \"privacy.direct.long\": \"Аталған адамдарға ғана көрінетін жазба\",\n  \"privacy.direct.short\": \"Тікелей\",\n  \"privacy.private.long\": \"Тек оқырмандарға арналған жазба\",\n  \"privacy.private.short\": \"Оқырмандарға ғана\",\n  \"privacy.public.long\": \"Ашық желіге жібер\",\n  \"privacy.public.short\": \"Ашық\",\n  \"privacy.unlisted.long\": \"Do not show in public timelines\",\n  \"privacy.unlisted.short\": \"Тізімсіз\",\n  \"regeneration_indicator.label\": \"Жүктеу…\",\n  \"regeneration_indicator.sublabel\": \"Жергілікті желі құрылуда!\",\n  \"relative_time.days\": \"{number}күн\",\n  \"relative_time.hours\": \"{number}сағ\",\n  \"relative_time.just_now\": \"жаңа\",\n  \"relative_time.minutes\": \"{number}мин\",\n  \"relative_time.seconds\": \"{number}s\",\n  \"reply_indicator.cancel\": \"Қайтып алу\",\n  \"report.forward\": \"Жіберу {target}\",\n  \"report.forward_hint\": \"Бұл аккаунт басқа серверден. Аноним шағым жібересіз бе?\",\n  \"report.hint\": \"Шағым сіздің модераторларға жіберіледі. Шағымның себептерін мына жерге жазуыңызға болады:\",\n  \"report.placeholder\": \"Қосымша пікірлер\",\n  \"report.submit\": \"Жіберу\",\n  \"report.target\": \"Шағымдану {target}\",\n  \"search.placeholder\": \"Іздеу\",\n  \"search_popout.search_format\": \"Кеңейтілген іздеу форматы\",\n  \"search_popout.tips.full_text\": \"Simple text returns statuses you have written, favourited, bоosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.\",\n  \"search_popout.tips.hashtag\": \"хэштег\",\n  \"search_popout.tips.status\": \"статус\",\n  \"search_popout.tips.text\": \"Simple text returns matching display names, usernames аnd hashtags\",\n  \"search_popout.tips.user\": \"қолданушы\",\n  \"search_results.accounts\": \"Адамдар\",\n  \"search_results.hashtags\": \"Хэштегтер\",\n  \"search_results.statuses\": \"Жазбалар\",\n  \"search_results.total\": \"{count, number} {count, plural, one {result} other {results}}\",\n  \"status.admin_account\": \"@{name} үшін модерация интерфейсін аш\",\n  \"status.admin_status\": \"Бұл жазбаны модерация интерфейсінде аш\",\n  \"status.block\": \"Бұғаттау @{name}\",\n  \"status.cancel_reblog_private\": \"Бөліспеу\",\n  \"status.cannot_reblog\": \"Бұл жазба бөлісілмейді\",\n  \"status.copy\": \"Жазба сілтемесін көшір\",\n  \"status.delete\": \"Өшіру\",\n  \"status.detailed_status\": \"Толық пікірталас көрінісі\",\n  \"status.direct\": \"Хат жіберу @{name}\",\n  \"status.embed\": \"Embеd\",\n  \"status.favourite\": \"Таңдаулы\",\n  \"status.filtered\": \"Фильтрленген\",\n  \"status.load_more\": \"Тағы әкел\",\n  \"status.media_hidden\": \"Жабық медиа\",\n  \"status.mention\": \"Аталым @{name}\",\n  \"status.more\": \"Тағы\",\n  \"status.mute\": \"Үнсіз @{name}\",\n  \"status.mute_conversation\": \"Пікірталасты үнсіз қылу\",\n  \"status.open\": \"Жазбаны ашу\",\n  \"status.pin\": \"Профильде жабыстыру\",\n  \"status.pinned\": \"Жабыстырылған жазба\",\n  \"status.read_more\": \"Әрі қарай\",\n  \"status.reblog\": \"Бөлісу\",\n  \"status.reblog_private\": \"Негізгі аудиторияға бөлісу\",\n  \"status.reblogged_by\": \"{name} бөлісті\",\n  \"status.reblogs.empty\": \"Бұл жазбаны әлі ешкім бөліспеді. Біреу бөліскен кезде осында көрінеді.\",\n  \"status.redraft\": \"Өшіру & қайта қарастыру\",\n  \"status.reply\": \"Жауап\",\n  \"status.replyAll\": \"Тақырыпқа жауап\",\n  \"status.report\": \"Шағым @{name}\",\n  \"status.sensitive_warning\": \"Нәзік контент\",\n  \"status.share\": \"Бөлісу\",\n  \"status.show_less\": \"Аздап көрсет\",\n  \"status.show_less_all\": \"Бәрін аздап көрсет\",\n  \"status.show_more\": \"Толығырақ\",\n  \"status.show_more_all\": \"Бәрін толығымен\",\n  \"status.show_thread\": \"Желіні көрсет\",\n  \"status.unmute_conversation\": \"Пікірталасты үнсіз қылмау\",\n  \"status.unpin\": \"Профильден алып тастау\",\n  \"suggestions.dismiss\": \"Өткізіп жіберу\",\n  \"suggestions.header\": \"Қызығуыңыз мүмкін…\",\n  \"tabs_bar.federated_timeline\": \"Жаһандық\",\n  \"tabs_bar.home\": \"Басты бет\",\n  \"tabs_bar.local_timeline\": \"Жергілікті\",\n  \"tabs_bar.notifications\": \"Ескертпелер\",\n  \"tabs_bar.search\": \"Іздеу\",\n  \"time_remaining.days\": \"{number, plural, one {# күн} other {# күн}}\",\n  \"time_remaining.hours\": \"{number, plural, one {# сағат} other {# сағат}}\",\n  \"time_remaining.minutes\": \"{number, plural, one {# минут} other {# минут}}\",\n  \"time_remaining.moments\": \"Қалған уақыт\",\n  \"time_remaining.seconds\": \"{number, plural, one {# секунд} other {# секунд}}\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {person} other {people}} жазған екен\",\n  \"ui.beforeunload\": \"Mastodon желісінен шықсаңыз, нобайыңыз сақталмайды.\",\n  \"upload_area.title\": \"Жүктеу үшін сүйреп әкеліңіз\",\n  \"upload_button.label\": \"Медиа қосу (JPEG, PNG, GIF, WebM, MP4, MOV)\",\n  \"upload_error.limit\": \"Файл жүктеу лимитінен асып кеттіңіз.\",\n  \"upload_error.poll\": \"Сауалнамамен бірге файл жүктеуге болмайды.\",\n  \"upload_form.description\": \"Көру қабілеті нашар адамдар үшін сипаттаңыз\",\n  \"upload_form.focus\": \"Превьюді өзгерту\",\n  \"upload_form.undo\": \"Өшіру\",\n  \"upload_progress.label\": \"Жүктеп жатыр...\",\n  \"video.close\": \"Видеоны жабу\",\n  \"video.exit_fullscreen\": \"Толық экраннан шық\",\n  \"video.expand\": \"Видеоны аш\",\n  \"video.fullscreen\": \"Толық экран\",\n  \"video.hide\": \"Видеоны жасыр\",\n  \"video.mute\": \"Дыбысын бас\",\n  \"video.pause\": \"Пауза\",\n  \"video.play\": \"Қосу\",\n  \"video.unmute\": \"Дауысын аш\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/ko.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"리스트에 추가 혹은 삭제\",\n  \"account.badges.bot\": \"봇\",\n  \"account.block\": \"@{name}을 차단\",\n  \"account.block_domain\": \"{domain} 전체를 숨김\",\n  \"account.blocked\": \"차단 됨\",\n  \"account.direct\": \"@{name}으로부터의 다이렉트 메시지\",\n  \"account.domain_blocked\": \"도메인 숨겨짐\",\n  \"account.edit_profile\": \"프로필 편집\",\n  \"account.endorse\": \"프로필에 나타내기\",\n  \"account.follow\": \"팔로우\",\n  \"account.followers\": \"팔로워\",\n  \"account.followers.empty\": \"아직 아무도 이 유저를 팔로우 하고 있지 않습니다.\",\n  \"account.follows\": \"팔로우\",\n  \"account.follows.empty\": \"이 유저는 아직 아무도 팔로우 하고 있지 않습니다.\",\n  \"account.follows_you\": \"날 팔로우합니다\",\n  \"account.hide_reblogs\": \"@{name}의 부스트를 숨기기\",\n  \"account.link_verified_on\": \"{date}에 이 링크의 소유권이 확인 됨\",\n  \"account.locked_info\": \"이 계정의 프라이버시 설정은 잠금으로 설정되어 있습니다. 계정 소유자가 수동으로 팔로어를 승인합니다.\",\n  \"account.media\": \"미디어\",\n  \"account.mention\": \"@{name}에게 글쓰기\",\n  \"account.moved_to\": \"{name}는 계정을 이동했습니다:\",\n  \"account.mute\": \"@{name} 뮤트\",\n  \"account.mute_notifications\": \"@{name}의 알림을 뮤트\",\n  \"account.muted\": \"뮤트 됨\",\n  \"account.posts\": \"툿\",\n  \"account.posts_with_replies\": \"툿과 답장\",\n  \"account.report\": \"@{name} 신고\",\n  \"account.requested\": \"승인 대기 중. 클릭해서 취소하기\",\n  \"account.share\": \"@{name}의 프로파일 공유\",\n  \"account.show_reblogs\": \"@{name}의 부스트 보기\",\n  \"account.unblock\": \"차단 해제\",\n  \"account.unblock_domain\": \"{domain} 숨김 해제\",\n  \"account.unendorse\": \"프로필에 나타내지 않기\",\n  \"account.unfollow\": \"팔로우 해제\",\n  \"account.unmute\": \"뮤트 해제\",\n  \"account.unmute_notifications\": \"@{name}의 알림 뮤트 해제\",\n  \"alert.unexpected.message\": \"예측하지 못한 에러가 발생했습니다.\",\n  \"alert.unexpected.title\": \"앗!\",\n  \"boost_modal.combo\": \"{combo}를 누르면 다음부터 이 과정을 건너뛸 수 있습니다\",\n  \"bundle_column_error.body\": \"컴포넌트를 불러오는 과정에서 문제가 발생했습니다.\",\n  \"bundle_column_error.retry\": \"다시 시도\",\n  \"bundle_column_error.title\": \"네트워크 에러\",\n  \"bundle_modal_error.close\": \"닫기\",\n  \"bundle_modal_error.message\": \"컴포넌트를 불러오는 과정에서 문제가 발생했습니다.\",\n  \"bundle_modal_error.retry\": \"다시 시도\",\n  \"column.blocks\": \"차단 중인 사용자\",\n  \"column.community\": \"로컬 타임라인\",\n  \"column.direct\": \"다이렉트 메시지\",\n  \"column.domain_blocks\": \"숨겨진 도메인\",\n  \"column.favourites\": \"즐겨찾기\",\n  \"column.follow_requests\": \"팔로우 요청\",\n  \"column.home\": \"홈\",\n  \"column.lists\": \"리스트\",\n  \"column.mutes\": \"뮤트 중인 사용자\",\n  \"column.notifications\": \"알림\",\n  \"column.pins\": \"고정된 툿\",\n  \"column.public\": \"연합 타임라인\",\n  \"column_back_button.label\": \"돌아가기\",\n  \"column_header.hide_settings\": \"설정 숨기기\",\n  \"column_header.moveLeft_settings\": \"왼쪽으로 이동\",\n  \"column_header.moveRight_settings\": \"오른쪽으로 이동\",\n  \"column_header.pin\": \"고정하기\",\n  \"column_header.show_settings\": \"설정 보이기\",\n  \"column_header.unpin\": \"고정 해제\",\n  \"column_subheading.settings\": \"설정\",\n  \"community.column_settings.media_only\": \"미디어만\",\n  \"compose_form.direct_message_warning\": \"이 툿은 멘션 된 유저들에게만 보여집니다.\",\n  \"compose_form.direct_message_warning_learn_more\": \"더 알아보기\",\n  \"compose_form.hashtag_warning\": \"이 툿은 어떤 해시태그로도 검색 되지 않습니다. 전체공개로 게시 된 툿만이 해시태그로 검색 될 수 있습니다.\",\n  \"compose_form.lock_disclaimer\": \"이 계정은 {locked}로 설정 되어 있지 않습니다. 누구나 이 계정을 팔로우 할 수 있으며, 팔로워 공개의 포스팅을 볼 수 있습니다.\",\n  \"compose_form.lock_disclaimer.lock\": \"비공개\",\n  \"compose_form.placeholder\": \"지금 무엇을 하고 있나요?\",\n  \"compose_form.poll.add_option\": \"항목 추가\",\n  \"compose_form.poll.duration\": \"투표 기간\",\n  \"compose_form.poll.option_placeholder\": \"{number}번 항목\",\n  \"compose_form.poll.remove_option\": \"이 항목 삭제\",\n  \"compose_form.publish\": \"툿\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"미디어를 민감함으로 설정하기\",\n  \"compose_form.sensitive.marked\": \"미디어가 열람주의로 설정되어 있습니다\",\n  \"compose_form.sensitive.unmarked\": \"미디어가 열람주의로 설정 되어 있지 않습니다\",\n  \"compose_form.spoiler.marked\": \"열람주의가 설정되어 있습니다\",\n  \"compose_form.spoiler.unmarked\": \"열람주의가 설정 되어 있지 않습니다\",\n  \"compose_form.spoiler_placeholder\": \"경고\",\n  \"confirmation_modal.cancel\": \"취소\",\n  \"confirmations.block.block_and_report\": \"차단하고 신고하기\",\n  \"confirmations.block.confirm\": \"차단\",\n  \"confirmations.block.message\": \"정말로 {name}를 차단하시겠습니까?\",\n  \"confirmations.delete.confirm\": \"삭제\",\n  \"confirmations.delete.message\": \"정말로 삭제하시겠습니까?\",\n  \"confirmations.delete_list.confirm\": \"삭제\",\n  \"confirmations.delete_list.message\": \"정말로 이 리스트를 삭제하시겠습니까?\",\n  \"confirmations.domain_block.confirm\": \"도메인 전체를 숨김\",\n  \"confirmations.domain_block.message\": \"정말로 {domain} 전체를 숨기시겠습니까? 대부분의 경우 개별 차단이나 뮤트로 충분합니다. 모든 공개 타임라인과 알림에서 해당 도메인에서 작성된 컨텐츠를 보지 못합니다. 해당 도메인 팔로워와의 관계가 사라집니다.\",\n  \"confirmations.mute.confirm\": \"뮤트\",\n  \"confirmations.mute.message\": \"정말로 {name}를 뮤트하시겠습니까?\",\n  \"confirmations.redraft.confirm\": \"삭제하고 다시 쓰기\",\n  \"confirmations.redraft.message\": \"정말로 이 포스트를 삭제하고 다시 쓰시겠습니까? 해당 포스트에 대한 부스트와 즐겨찾기를 잃게 되고 원본에 대한 답장은 연결 되지 않습니다.\",\n  \"confirmations.reply.confirm\": \"답글\",\n  \"confirmations.reply.message\": \"답글을 달기 위해 현재 작성 중인 메시지가 덮어 씌워집니다. 진행하시겠습니까?\",\n  \"confirmations.unfollow.confirm\": \"언팔로우\",\n  \"confirmations.unfollow.message\": \"정말로 {name}를 언팔로우하시겠습니까?\",\n  \"embed.instructions\": \"아래의 코드를 복사하여 대화를 원하는 곳으로 공유하세요.\",\n  \"embed.preview\": \"다음과 같이 표시됩니다:\",\n  \"emoji_button.activity\": \"활동\",\n  \"emoji_button.custom\": \"커스텀\",\n  \"emoji_button.flags\": \"국기\",\n  \"emoji_button.food\": \"음식\",\n  \"emoji_button.label\": \"에모지를 추가\",\n  \"emoji_button.nature\": \"자연\",\n  \"emoji_button.not_found\": \"없어!! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"물건\",\n  \"emoji_button.people\": \"사람들\",\n  \"emoji_button.recent\": \"자주 사용 됨\",\n  \"emoji_button.search\": \"검색...\",\n  \"emoji_button.search_results\": \"검색 결과\",\n  \"emoji_button.symbols\": \"기호\",\n  \"emoji_button.travel\": \"여행과 장소\",\n  \"empty_column.account_timeline\": \"여긴 툿이 없어요!\",\n  \"empty_column.account_unavailable\": \"프로필 사용 불가\",\n  \"empty_column.blocks\": \"아직 아무도 차단하지 않았습니다.\",\n  \"empty_column.community\": \"로컬 타임라인에 아무 것도 없습니다. 아무거나 적어 보세요!\",\n  \"empty_column.direct\": \"아직 다이렉트 메시지가 없습니다. 다이렉트 메시지를 보내거나 받은 경우, 여기에 표시 됩니다.\",\n  \"empty_column.domain_blocks\": \"아직 숨겨진 도메인이 없습니다.\",\n  \"empty_column.favourited_statuses\": \"아직 즐겨찾기 한 툿이 없습니다. 툿을 즐겨찾기 하면 여기에 나타납니다.\",\n  \"empty_column.favourites\": \"아직 아무도 이 툿을 즐겨찾기 하지 않았습니다. 누군가 즐겨찾기를 하면 여기에 그들이 나타납니다.\",\n  \"empty_column.follow_requests\": \"아직 팔로우 요청이 없습니다. 요청을 받았을 때 여기에 나타납니다.\",\n  \"empty_column.hashtag\": \"이 해시태그는 아직 사용되지 않았습니다.\",\n  \"empty_column.home\": \"아직 아무도 팔로우 하고 있지 않습니다. {public}를 보러 가거나, 검색하여 다른 사용자를 찾아 보세요.\",\n  \"empty_column.home.public_timeline\": \"연합 타임라인\",\n  \"empty_column.list\": \"리스트에 아직 아무 것도 없습니다.\",\n  \"empty_column.lists\": \"아직 리스트가 없습니다. 리스트를 만들면 여기에 나타납니다.\",\n  \"empty_column.mutes\": \"아직 아무도 뮤트하지 않았습니다.\",\n  \"empty_column.notifications\": \"아직 알림이 없습니다. 다른 사람과 대화를 시작해 보세요.\",\n  \"empty_column.public\": \"여기엔 아직 아무 것도 없습니다! 공개적으로 무언가 포스팅하거나, 다른 서버의 유저를 팔로우 해서 채워보세요\",\n  \"follow_request.authorize\": \"허가\",\n  \"follow_request.reject\": \"거부\",\n  \"getting_started.developers\": \"개발자\",\n  \"getting_started.directory\": \"프로필 디렉터리\",\n  \"getting_started.documentation\": \"문서\",\n  \"getting_started.heading\": \"시작\",\n  \"getting_started.invite\": \"초대\",\n  \"getting_started.open_source_notice\": \"Mastodon은 오픈 소스 소프트웨어입니다. 누구나 GitHub({github})에서 개발에 참여하거나, 문제를 보고할 수 있습니다.\",\n  \"getting_started.security\": \"보안\",\n  \"getting_started.terms\": \"이용 약관\",\n  \"hashtag.column_header.tag_mode.all\": \"그리고 {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"또는 {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"({additional}를 제외)\",\n  \"hashtag.column_settings.select.no_options_message\": \"추천 할 내용이 없습니다\",\n  \"hashtag.column_settings.select.placeholder\": \"해시태그를 입력하세요…\",\n  \"hashtag.column_settings.tag_mode.all\": \"모두\",\n  \"hashtag.column_settings.tag_mode.any\": \"아무것이든\",\n  \"hashtag.column_settings.tag_mode.none\": \"이것들을 제외하고\",\n  \"hashtag.column_settings.tag_toggle\": \"추가 해시태그를 이 컬럼에 추가합니다\",\n  \"home.column_settings.basic\": \"기본 설정\",\n  \"home.column_settings.show_reblogs\": \"부스트 표시\",\n  \"home.column_settings.show_replies\": \"답글 표시\",\n  \"intervals.full.days\": \"{number} 일\",\n  \"intervals.full.hours\": \"{number} 시간\",\n  \"intervals.full.minutes\": \"{number} 분\",\n  \"introduction.federation.action\": \"다음\",\n  \"introduction.federation.federated.headline\": \"연합\",\n  \"introduction.federation.federated.text\": \"페디버스의 다른 서버의 공개 게시물이 연합 타임라인에 나타납니다.\",\n  \"introduction.federation.home.headline\": \"홈\",\n  \"introduction.federation.home.text\": \"당신이 팔로우 하고 있는 사람의 게시물이 홈 타임라인에 나타납니다. 어느 서버에 있는 사람이라도 팔로우가 가능합니다!\",\n  \"introduction.federation.local.headline\": \"로컬\",\n  \"introduction.federation.local.text\": \"같은 서버에 있는 공개 게시물은 로컬 타임라인에 나타납니다.\",\n  \"introduction.interactions.action\": \"튜토리얼 마치기!\",\n  \"introduction.interactions.favourite.headline\": \"즐겨찾기\",\n  \"introduction.interactions.favourite.text\": \"나중을 위해 툿을 저장할 수 있습니다, 그리고 작성자에게 당신이 이 글을 마음에 들어한다는 걸 알립니다.\",\n  \"introduction.interactions.reblog.headline\": \"부스트\",\n  \"introduction.interactions.reblog.text\": \"부스트를 통해 다른 사람의 툿을 당신의 팔로워들에게 공유할 수 있습니다.\",\n  \"introduction.interactions.reply.headline\": \"답글\",\n  \"introduction.interactions.reply.text\": \"다른 사람이나 나의 툿에 답글을 달 수 있습니다, 이 답글은 하나의 타래글로 이어집니다.\",\n  \"introduction.welcome.action\": \"출발!\",\n  \"introduction.welcome.headline\": \"첫걸음\",\n  \"introduction.welcome.text\": \"페디버스에 오신 것을 환영합니다! 잠시 후, 당신은 수 많은 다양한 서버들에 존재하는 친구들에게 메시지를 보내고 대화 할 수 있게 됩니다. 하지만 이 서버, {domain}은 특별합니다. 이 서버는 당신의 프로필을 제공하니 이름을 기억하세요.\",\n  \"keyboard_shortcuts.back\": \"뒤로가기\",\n  \"keyboard_shortcuts.blocked\": \"차단한 유저 리스트 열기\",\n  \"keyboard_shortcuts.boost\": \"부스트\",\n  \"keyboard_shortcuts.column\": \"해당 열에 포커스\",\n  \"keyboard_shortcuts.compose\": \"작성창으로 포커스\",\n  \"keyboard_shortcuts.description\": \"설명\",\n  \"keyboard_shortcuts.direct\": \"다이렉트 메시지 컬럼 열기\",\n  \"keyboard_shortcuts.down\": \"리스트에서 아래로 이동\",\n  \"keyboard_shortcuts.enter\": \"열기\",\n  \"keyboard_shortcuts.favourite\": \"관심글 지정\",\n  \"keyboard_shortcuts.favourites\": \"즐겨찾기 리스트 열기\",\n  \"keyboard_shortcuts.federated\": \"연합 타임라인 열기\",\n  \"keyboard_shortcuts.heading\": \"키보드 단축키\",\n  \"keyboard_shortcuts.home\": \"홈 타임라인 열기\",\n  \"keyboard_shortcuts.hotkey\": \"핫키\",\n  \"keyboard_shortcuts.legend\": \"이 도움말 표시\",\n  \"keyboard_shortcuts.local\": \"로컬 타임라인 열기\",\n  \"keyboard_shortcuts.mention\": \"멘션\",\n  \"keyboard_shortcuts.muted\": \"뮤트 된 유저 리스트 열기\",\n  \"keyboard_shortcuts.my_profile\": \"내 프로필 열기\",\n  \"keyboard_shortcuts.notifications\": \"알림 컬럼 열기\",\n  \"keyboard_shortcuts.pinned\": \"고정 툿 리스트 열기\",\n  \"keyboard_shortcuts.profile\": \"프로필 열기\",\n  \"keyboard_shortcuts.reply\": \"답장\",\n  \"keyboard_shortcuts.requests\": \"팔로우 요청 리스트 열기\",\n  \"keyboard_shortcuts.search\": \"검색창에 포커스\",\n  \"keyboard_shortcuts.start\": \"\\\"시작하기\\\" 컬럼 열기\",\n  \"keyboard_shortcuts.toggle_hidden\": \"CW로 가려진 텍스트를 표시/비표시\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"이미지 보이기/숨기기\",\n  \"keyboard_shortcuts.toot\": \"새 툿 작성\",\n  \"keyboard_shortcuts.unfocus\": \"작성창에서 포커스 해제\",\n  \"keyboard_shortcuts.up\": \"리스트에서 위로 이동\",\n  \"lightbox.close\": \"닫기\",\n  \"lightbox.next\": \"다음\",\n  \"lightbox.previous\": \"이전\",\n  \"lightbox.view_context\": \"게시물 보기\",\n  \"lists.account.add\": \"리스트에 추가\",\n  \"lists.account.remove\": \"리스트에서 제거\",\n  \"lists.delete\": \"리스트 삭제\",\n  \"lists.edit\": \"리스트 편집\",\n  \"lists.edit.submit\": \"제목 수정\",\n  \"lists.new.create\": \"리스트 추가\",\n  \"lists.new.title_placeholder\": \"새 리스트의 이름\",\n  \"lists.search\": \"팔로우 중인 사람들 중에서 찾기\",\n  \"lists.subheading\": \"당신의 리스트\",\n  \"loading_indicator.label\": \"불러오는 중...\",\n  \"media_gallery.toggle_visible\": \"표시 전환\",\n  \"missing_indicator.label\": \"찾을 수 없습니다\",\n  \"missing_indicator.sublabel\": \"이 리소스를 찾을 수 없었습니다\",\n  \"mute_modal.hide_notifications\": \"이 사용자로부터의 알림을 뮤트하시겠습니까?\",\n  \"navigation_bar.apps\": \"모바일 앱\",\n  \"navigation_bar.blocks\": \"차단한 사용자\",\n  \"navigation_bar.community_timeline\": \"로컬 타임라인\",\n  \"navigation_bar.compose\": \"새 툿 작성\",\n  \"navigation_bar.direct\": \"다이렉트 메시지\",\n  \"navigation_bar.discover\": \"발견하기\",\n  \"navigation_bar.domain_blocks\": \"숨겨진 도메인\",\n  \"navigation_bar.edit_profile\": \"프로필 편집\",\n  \"navigation_bar.favourites\": \"즐겨찾기\",\n  \"navigation_bar.filters\": \"뮤트\",\n  \"navigation_bar.follow_requests\": \"팔로우 요청\",\n  \"navigation_bar.follows_and_followers\": \"팔로우와 팔로워\",\n  \"navigation_bar.info\": \"이 서버에 대해서\",\n  \"navigation_bar.keyboard_shortcuts\": \"단축키\",\n  \"navigation_bar.lists\": \"리스트\",\n  \"navigation_bar.logout\": \"로그아웃\",\n  \"navigation_bar.mutes\": \"뮤트 중인 사용자\",\n  \"navigation_bar.personal\": \"개인용\",\n  \"navigation_bar.pins\": \"고정된 툿\",\n  \"navigation_bar.preferences\": \"사용자 설정\",\n  \"navigation_bar.profile_directory\": \"프로필 디렉토리\",\n  \"navigation_bar.public_timeline\": \"연합 타임라인\",\n  \"navigation_bar.security\": \"보안\",\n  \"notification.favourite\": \"{name}님이 즐겨찾기 했습니다\",\n  \"notification.follow\": \"{name}님이 나를 팔로우 했습니다\",\n  \"notification.mention\": \"{name}님이 답글을 보냈습니다\",\n  \"notification.poll\": \"당신이 참여 한 투표가 종료되었습니다\",\n  \"notification.reblog\": \"{name}님이 부스트 했습니다\",\n  \"notifications.clear\": \"알림 지우기\",\n  \"notifications.clear_confirmation\": \"정말로 알림을 삭제하시겠습니까?\",\n  \"notifications.column_settings.alert\": \"데스크탑 알림\",\n  \"notifications.column_settings.favourite\": \"즐겨찾기:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"카테고리의 모든 종류를 표시\",\n  \"notifications.column_settings.filter_bar.category\": \"퀵 필터 바\",\n  \"notifications.column_settings.filter_bar.show\": \"표시\",\n  \"notifications.column_settings.follow\": \"새 팔로워:\",\n  \"notifications.column_settings.mention\": \"답글:\",\n  \"notifications.column_settings.poll\": \"투표 결과:\",\n  \"notifications.column_settings.push\": \"푸시 알림\",\n  \"notifications.column_settings.reblog\": \"부스트:\",\n  \"notifications.column_settings.show\": \"컬럼에 표시\",\n  \"notifications.column_settings.sound\": \"효과음 재생\",\n  \"notifications.filter.all\": \"모두\",\n  \"notifications.filter.boosts\": \"부스트\",\n  \"notifications.filter.favourites\": \"즐겨찾기\",\n  \"notifications.filter.follows\": \"팔로우\",\n  \"notifications.filter.mentions\": \"멘션\",\n  \"notifications.filter.polls\": \"투표 결과\",\n  \"notifications.group\": \"{count} 개의 알림\",\n  \"poll.closed\": \"마감됨\",\n  \"poll.refresh\": \"새로고침\",\n  \"poll.total_votes\": \"{count} 명 참여\",\n  \"poll.vote\": \"투표\",\n  \"poll_button.add_poll\": \"투표 추가\",\n  \"poll_button.remove_poll\": \"투표 삭제\",\n  \"privacy.change\": \"포스트의 프라이버시 설정을 변경\",\n  \"privacy.direct.long\": \"멘션한 사용자에게만 공개\",\n  \"privacy.direct.short\": \"다이렉트\",\n  \"privacy.private.long\": \"팔로워에게만 공개\",\n  \"privacy.private.short\": \"비공개\",\n  \"privacy.public.long\": \"공개 타임라인에 표시\",\n  \"privacy.public.short\": \"공개\",\n  \"privacy.unlisted.long\": \"공개 타임라인에 표시하지 않음\",\n  \"privacy.unlisted.short\": \"타임라인에 비표시\",\n  \"regeneration_indicator.label\": \"불러오는 중…\",\n  \"regeneration_indicator.sublabel\": \"당신의 홈 피드가 준비되는 중입니다!\",\n  \"relative_time.days\": \"{number}일 전\",\n  \"relative_time.hours\": \"{number}시간 전\",\n  \"relative_time.just_now\": \"방금\",\n  \"relative_time.minutes\": \"{number}분 전\",\n  \"relative_time.seconds\": \"{number}초 전\",\n  \"reply_indicator.cancel\": \"취소\",\n  \"report.forward\": \"{target}에 포워드 됨\",\n  \"report.forward_hint\": \"이 계정은 다른 서버에 있습니다. 익명화 된 사본을 해당 서버에도 전송할까요?\",\n  \"report.hint\": \"신고는 당신의 서버 스태프에게 전송 됩니다. 왜 이 계정을 신고하는 지에 대한 설명을 아래에 작성할 수 있습니다:\",\n  \"report.placeholder\": \"코멘트\",\n  \"report.submit\": \"신고하기\",\n  \"report.target\": \"문제가 된 사용자\",\n  \"search.placeholder\": \"검색\",\n  \"search_popout.search_format\": \"고급 검색 방법\",\n  \"search_popout.tips.full_text\": \"단순한 텍스트 검색은 당신이 작성했거나, 관심글로 지정했거나, 부스트했거나, 멘션을 받은 게시글, 그리고 유저네임, 디스플레이네임, 해시태그를 반환합니다.\",\n  \"search_popout.tips.hashtag\": \"해시태그\",\n  \"search_popout.tips.status\": \"툿\",\n  \"search_popout.tips.text\": \"단순한 텍스트 검색은 관계된 프로필 이름, 유저 이름 그리고 해시태그를 표시합니다\",\n  \"search_popout.tips.user\": \"유저\",\n  \"search_results.accounts\": \"사람\",\n  \"search_results.hashtags\": \"해시태그\",\n  \"search_results.statuses\": \"툿\",\n  \"search_results.total\": \"{count, number}건의 결과\",\n  \"status.admin_account\": \"@{name}에 대한 모더레이션 인터페이스 열기\",\n  \"status.admin_status\": \"모더레이션 인터페이스에서 이 게시물 열기\",\n  \"status.block\": \"@{name} 차단\",\n  \"status.cancel_reblog_private\": \"부스트 취소\",\n  \"status.cannot_reblog\": \"이 포스트는 부스트 할 수 없습니다\",\n  \"status.copy\": \"게시물 링크 복사\",\n  \"status.delete\": \"삭제\",\n  \"status.detailed_status\": \"대화 자세히 보기\",\n  \"status.direct\": \"@{name}에게 다이렉트 메시지\",\n  \"status.embed\": \"공유하기\",\n  \"status.favourite\": \"즐겨찾기\",\n  \"status.filtered\": \"필터링 됨\",\n  \"status.load_more\": \"더 보기\",\n  \"status.media_hidden\": \"미디어 숨겨짐\",\n  \"status.mention\": \"답장\",\n  \"status.more\": \"자세히\",\n  \"status.mute\": \"@{name} 뮤트\",\n  \"status.mute_conversation\": \"이 대화를 뮤트\",\n  \"status.open\": \"상세 정보 표시\",\n  \"status.pin\": \"고정\",\n  \"status.pinned\": \"고정 된 툿\",\n  \"status.read_more\": \"더 보기\",\n  \"status.reblog\": \"부스트\",\n  \"status.reblog_private\": \"원래의 수신자들에게 부스트\",\n  \"status.reblogged_by\": \"{name}님이 부스트 했습니다\",\n  \"status.reblogs.empty\": \"아직 아무도 이 툿을 부스트하지 않았습니다. 부스트 한 사람들이 여기에 표시 됩니다.\",\n  \"status.redraft\": \"지우고 다시 쓰기\",\n  \"status.reply\": \"답장\",\n  \"status.replyAll\": \"전원에게 답장\",\n  \"status.report\": \"신고\",\n  \"status.sensitive_warning\": \"민감한 미디어\",\n  \"status.share\": \"공유\",\n  \"status.show_less\": \"숨기기\",\n  \"status.show_less_all\": \"모두 접기\",\n  \"status.show_more\": \"더 보기\",\n  \"status.show_more_all\": \"모두 펼치기\",\n  \"status.show_thread\": \"글타래 보기\",\n  \"status.unmute_conversation\": \"이 대화의 뮤트 해제하기\",\n  \"status.unpin\": \"고정 해제\",\n  \"suggestions.dismiss\": \"추천 지우기\",\n  \"suggestions.header\": \"이것에 관심이 있을 것 같습니다…\",\n  \"tabs_bar.federated_timeline\": \"연합\",\n  \"tabs_bar.home\": \"홈\",\n  \"tabs_bar.local_timeline\": \"로컬\",\n  \"tabs_bar.notifications\": \"알림\",\n  \"tabs_bar.search\": \"검색\",\n  \"time_remaining.days\": \"{number} 일 남음\",\n  \"time_remaining.hours\": \"{number} 시간 남음\",\n  \"time_remaining.minutes\": \"{number} 분 남음\",\n  \"time_remaining.moments\": \"남은 시간\",\n  \"time_remaining.seconds\": \"{number} 초 남음\",\n  \"trends.count_by_accounts\": \"{count} 명의 사람들이 말하고 있습니다\",\n  \"ui.beforeunload\": \"지금 나가면 저장되지 않은 항목을 잃게 됩니다.\",\n  \"upload_area.title\": \"드래그 & 드롭으로 업로드\",\n  \"upload_button.label\": \"미디어 추가 (JPEG, PNG, GIF, WebM, MP4, MOV)\",\n  \"upload_error.limit\": \"파일 업로드 제한에 도달했습니다.\",\n  \"upload_error.poll\": \"파일 업로드는 투표와 함께 첨부할 수 없습니다.\",\n  \"upload_form.description\": \"시각장애인을 위한 설명\",\n  \"upload_form.focus\": \"미리보기 변경\",\n  \"upload_form.undo\": \"삭제\",\n  \"upload_progress.label\": \"업로드 중...\",\n  \"video.close\": \"동영상 닫기\",\n  \"video.exit_fullscreen\": \"전체화면 나가기\",\n  \"video.expand\": \"동영상 확장\",\n  \"video.fullscreen\": \"전체화면\",\n  \"video.hide\": \"동영상 숨기기\",\n  \"video.mute\": \"음소거\",\n  \"video.pause\": \"일시정지\",\n  \"video.play\": \"재생\",\n  \"video.unmute\": \"음소거 해제\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/locale-data/README.md",
    "content": "# Custom Locale Data\n\nThis folder is used to store custom locale data. These custom locale data are\nnot yet provided by [Unicode Common Locale Data Repository](http://cldr.unicode.org/development/new-cldr-developers)\nand hence not provided in [react-intl/locale-data/*](https://github.com/yahoo/react-intl).\n\nThe locale data should support [Locale Data APIs](https://github.com/yahoo/react-intl/wiki/API#locale-data-apis)\nof the react-intl library.\n\nIt is recommended to start your custom locale data from this sample English\nlocale data ([*](#plural-rules)):\n\n```javascript\n/*eslint eqeqeq: \"off\"*/\n/*eslint no-nested-ternary: \"off\"*/\n\nexport default [\n  {\n    locale: \"en\",\n    pluralRuleFunction: function(e, a) {\n      var n = String(e).split(\".\"),\n        l = !n[1],\n        o = Number(n[0]) == e,\n        t = o && n[0].slice(-1),\n        r = o && n[0].slice(-2);\n      return a ? 1 == t && 11 != r ? \"one\" : 2 == t && 12 != r ? \"two\" : 3 == t && 13 != r ? \"few\" : \"other\" : 1 == e && l ? \"one\" : \"other\"\n    },\n    fields: {\n      year: {\n        displayName: \"year\",\n        relative: {\n          0: \"this year\",\n          1: \"next year\",\n          \"-1\": \"last year\"\n        },\n        relativeTime: {\n          future: {\n            one: \"in {0} year\",\n            other: \"in {0} years\"\n          },\n          past: {\n            one: \"{0} year ago\",\n            other: \"{0} years ago\"\n          }\n        }\n      },\n      month: {\n        displayName: \"month\",\n        relative: {\n          0: \"this month\",\n          1: \"next month\",\n          \"-1\": \"last month\"\n        },\n        relativeTime: {\n          future: {\n            one: \"in {0} month\",\n            other: \"in {0} months\"\n          },\n          past: {\n            one: \"{0} month ago\",\n            other: \"{0} months ago\"\n          }\n        }\n      },\n      day: {\n        displayName: \"day\",\n        relative: {\n          0: \"today\",\n          1: \"tomorrow\",\n          \"-1\": \"yesterday\"\n        },\n        relativeTime: {\n          future: {\n            one: \"in {0} day\",\n            other: \"in {0} days\"\n          },\n          past: {\n            one: \"{0} day ago\",\n            other: \"{0} days ago\"\n          }\n        }\n      },\n      hour: {\n        displayName: \"hour\",\n        relativeTime: {\n          future: {\n            one: \"in {0} hour\",\n            other: \"in {0} hours\"\n          },\n          past: {\n            one: \"{0} hour ago\",\n            other: \"{0} hours ago\"\n          }\n        }\n      },\n      minute: {\n        displayName: \"minute\",\n        relativeTime: {\n          future: {\n            one: \"in {0} minute\",\n            other: \"in {0} minutes\"\n          },\n          past: {\n            one: \"{0} minute ago\",\n            other: \"{0} minutes ago\"\n          }\n        }\n      },\n      second: {\n        displayName: \"second\",\n        relative: {\n          0: \"now\"\n        },\n        relativeTime: {\n          future: {\n            one: \"in {0} second\",\n            other: \"in {0} seconds\"\n          },\n          past: {\n            one: \"{0} second ago\",\n            other: \"{0} seconds ago\"\n          }\n        }\n      }\n    }\n  }\n]\n\n```\n\n## Notes\n\n### Plural Rules\n\nThe function `pluralRuleFunction()` should return the key to proper string of\na plural form(s). The purpose of the function is to provide key of translate\nstrings of correct plural form according. The different forms are described in\n[CLDR's Plural Rules][cldr-plural-rules],\n\n[cldr-plural-rules]: http://cldr.unicode.org/index/cldr-spec/plural-rules\n\n#### Quick Overview on CLDR Rules\n\nLet's take English as an example.\n\nWhen you describe a number, you can be either describe it as:\n* Cardinals: 1st, 2nd, 3rd ... 11th, 12th ... 21st, 22nd, 23nd ....\n* Ordinals: 1, 2, 3 ...\n\nIn any of these cases, the nouns will reflect the number with singular or plural\nform. For example:\n* in 0 days\n* in 1 day\n* in 2 days\n\nThe `pluralRuleFunction` receives 2 parameters:\n* `e`: a string representation of the number. Such as, \"`1`\", \"`2`\", \"`2.1`\".\n* `a`: `true` if this is \"cardinal\" type of description. `false` for ordinal and other case.\n\n#### How you should write `pluralRuleFunction`\n\nThe first rule to write pluralRuleFunction is never translate the output string\ninto your language. [Plural Rules][cldr-plural-rules] specified you should use\nthese as the return values:\n\n  * \"`zero`\"\n  * \"`one`\" (singular)\n  * \"`two`\" (dual)\n  * \"`few`\" (paucal)\n  * \"`many`\" (also used for fractions if they have a separate class)\n  * \"`other`\" (required—general plural form—also used if the language only has a single form)\n\nAgain, we'll use English as the example here.\n\nLet's read the `return` statement in the pluralRuleFunction above:\n```javascript\n  return a ? 1 == t && 11 != r ? \"one\" : 2 == t && 12 != r ? \"two\" : 3 == t && 13 != r ? \"few\" : \"other\" : 1 == e && l ? \"one\" : \"other\"\n```\n\nThis nested ternary is hard to read. It basically means:\n```javascript\n// e: the number variable to examine\n// a: \"true\" if cardinals\n// l: \"true\" if the variable e has nothin after decimal mark (e.g. \"1.0\" would be false)\n// o: \"true\" if the variable e is an integer\n// t: the \"ones\" of the number. e.g. \"3\" for number \"9123\"\n// r: the \"ones\" and \"tens\" of the number. e.g. \"23\" for number \"9123\"\nif (a == true) {\n  if (t == 1 && r != 11) {\n    return \"one\"; // i.e. 1st, 21st, 101st, 121st ...\n  } else if (t == 2 && r != 12) {\n    return \"two\"; // i.e. 2nd, 22nd, 102nd, 122nd ...\n  } else if (t == 3 && r != 13) {\n    return \"few\"; // i.e. 3rd, 23rd, 103rd, 123rd ...\n  } else {\n    return \"other\"; // i.e. 4th, 11th, 12th, 24th ...\n  }\n} else {\n  if (e == 1 && l) {\n    return \"one\"; // i.e. 1 day\n  } else {\n    return \"other\"; // i.e. 0 days, 2 days, 3 days\n  }\n}\n```\n\nIf your language, like French, do not have complicated cardinal rules, you may\nuse the French's version of it:\n```javascript\nfunction (e, a) {\n  return a ? 1 == e ? \"one\" : \"other\" : e >= 0 && e < 2 ? \"one\" : \"other\";\n}\n```\n\nIf your language, like Chinese, do not have any pluralization rule at all you\nmay use the Chinese's version of it:\n```javascript\nfunction (e, a) {\n  return \"other\";\n}\n```\n"
  },
  {
    "path": "app/javascript/mastodon/locales/locale-data/co.js",
    "content": "/*eslint eqeqeq: \"off\"*/\n/*eslint no-nested-ternary: \"off\"*/\n/*eslint quotes: \"off\"*/\n\nexport default [{\n  locale: \"co\",\n  pluralRuleFunction: function (e, a) {\n    return a ? 1 == e ? \"one\" : \"other\" : e >= 0 && e < 2 ? \"one\" : \"other\";\n  },\n  fields: {\n    year: {\n      displayName: \"annu\",\n      relative: {\n        0: \"quist'annu\",\n        1: \"l'annu chì vene\",\n        \"-1\": \"l'annu passatu\",\n      },\n      relativeTime: {\n        future: {\n          one: \"in {0} annu\",\n          other: \"in {0} anni\",\n        },\n        past: {\n          one: \"{0} annu fà\",\n          other: \"{0} anni fà\",\n        },\n      },\n    },\n    month: {\n      displayName: \"mese\",\n      relative: {\n        0: \"Questu mese\",\n        1: \"u mese chì vene\",\n        \"-1\": \"u mese passatu\",\n      },\n      relativeTime: {\n        future: {\n          one: \"in {0} mese\",\n          other: \"in {0} mesi\",\n        },\n        past: {\n          one: \"{0} mese fà\",\n          other: \"{0} mesi fà\",\n        },\n      },\n    },\n    day: {\n      displayName: \"ghjornu\",\n      relative: {\n        0: \"oghje\",\n        1: \"dumane\",\n        \"-1\": \"eri\",\n      },\n      relativeTime: {\n        future: {\n          one: \"in {0} ghjornu\",\n          other: \"in {0} ghjornu\",\n        },\n        past: {\n          one: \"{0} ghjornu fà\",\n          other: \"{0} ghjorni fà\",\n        },\n      },\n    },\n    hour: {\n      displayName: \"ora\",\n      relativeTime: {\n        future: {\n          one: \"in {0} ora\",\n          other: \"in {0} ore\",\n        },\n        past: {\n          one: \"{0} ora fà\",\n          other: \"{0} ore fà\",\n        },\n      },\n    },\n    minute: {\n      displayName: \"minuta\",\n      relativeTime: {\n        future: {\n          one: \"in {0} minuta\",\n          other: \"in {0} minute\",\n        },\n        past: {\n          one: \"{0} minuta fà\",\n          other: \"{0} minute fà\",\n        },\n      },\n    },\n    second: {\n      displayName: \"siconda\",\n      relative: {\n        0: \"avà\",\n      },\n      relativeTime: {\n        future: {\n          one: \"in {0} siconda\",\n          other: \"in {0} siconde\",\n        },\n        past: {\n          one: \"{0} siconda fà\",\n          other: \"{0} siconde fà\",\n        },\n      },\n    },\n  },\n}];\n"
  },
  {
    "path": "app/javascript/mastodon/locales/locale-data/oc.js",
    "content": "/*eslint eqeqeq: \"off\"*/\n/*eslint no-nested-ternary: \"off\"*/\n/*eslint quotes: \"off\"*/\n\nexport default [{\n  locale: \"oc\",\n  pluralRuleFunction: function (e, a) {\n    return a ? 1 == e ? \"one\" : \"other\" : e >= 0 && e < 2 ? \"one\" : \"other\";\n  },\n  fields: {\n    year: {\n      displayName: \"an\",\n      relative: {\n        0: \"ongan\",\n        1: \"l'an que ven\",\n        \"-1\": \"l'an passat\",\n      },\n      relativeTime: {\n        future: {\n          one: \"d’aquí {0} an\",\n          other: \"d’aquí {0} ans\",\n        },\n        past: {\n          one: \"fa {0} an\",\n          other: \"fa {0} ans\",\n        },\n      },\n    },\n    month: {\n      displayName: \"mes\",\n      relative: {\n        0: \"aqueste mes\",\n        1: \"lo mes que ven\",\n        \"-1\": \"lo mes passat\",\n      },\n      relativeTime: {\n        future: {\n          one: \"d’aquí {0} mes\",\n          other: \"d’aquí {0} meses\",\n        },\n        past: {\n          one: \"fa {0} mes\",\n          other: \"fa {0} meses\",\n        },\n      },\n    },\n    day: {\n      displayName: \"jorn\",\n      relative: {\n        0: \"uèi\",\n        1: \"deman\",\n        \"-1\": \"ièr\",\n      },\n      relativeTime: {\n        future: {\n          one: \"d’aquí {0} jorn\",\n          other: \"d’aquí {0} jorns\",\n        },\n        past: {\n          one: \"fa {0} jorn\",\n          other: \"fa {0} jorns\",\n        },\n      },\n    },\n    hour: {\n      displayName: \"ora\",\n      relativeTime: {\n        future: {\n          one: \"d’aquí {0} ora\",\n          other: \"d’aquí {0} oras\",\n        },\n        past: {\n          one: \"fa {0} ora\",\n          other: \"fa {0} oras\",\n        },\n      },\n    },\n    minute: {\n      displayName: \"minuta\",\n      relativeTime: {\n        future: {\n          one: \"d’aquí {0} minuta\",\n          other: \"d’aquí {0} minutas\",\n        },\n        past: {\n          one: \"fa {0} minuta\",\n          other: \"fa {0} minutas\",\n        },\n      },\n    },\n    second: {\n      displayName: \"segonda\",\n      relative: {\n        0: \"ara\",\n      },\n      relativeTime: {\n        future: {\n          one: \"d’aquí {0} segonda\",\n          other: \"d’aquí {0} segondas\",\n        },\n        past: {\n          one: \"fa {0} segonda\",\n          other: \"fa {0} segondas\",\n        },\n      },\n    },\n  },\n}];\n"
  },
  {
    "path": "app/javascript/mastodon/locales/lt.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Add or Remove from lists\",\n  \"account.badges.bot\": \"Bot\",\n  \"account.block\": \"Block @{name}\",\n  \"account.block_domain\": \"Hide everything from {domain}\",\n  \"account.blocked\": \"Blocked\",\n  \"account.direct\": \"Direct message @{name}\",\n  \"account.domain_blocked\": \"Domain hidden\",\n  \"account.edit_profile\": \"Edit profile\",\n  \"account.endorse\": \"Feature on profile\",\n  \"account.follow\": \"Follow\",\n  \"account.followers\": \"Followers\",\n  \"account.followers.empty\": \"No one follows this user yet.\",\n  \"account.follows\": \"Follows\",\n  \"account.follows.empty\": \"This user doesn't follow anyone yet.\",\n  \"account.follows_you\": \"Follows you\",\n  \"account.hide_reblogs\": \"Hide boosts from @{name}\",\n  \"account.link_verified_on\": \"Ownership of this link was checked on {date}\",\n  \"account.locked_info\": \"This account privacy status is set to locked. The owner manually reviews who can follow them.\",\n  \"account.media\": \"Media\",\n  \"account.mention\": \"Mention @{name}\",\n  \"account.moved_to\": \"{name} has moved to:\",\n  \"account.mute\": \"Mute @{name}\",\n  \"account.mute_notifications\": \"Mute notifications from @{name}\",\n  \"account.muted\": \"Muted\",\n  \"account.posts\": \"Toots\",\n  \"account.posts_with_replies\": \"Toots and replies\",\n  \"account.report\": \"Report @{name}\",\n  \"account.requested\": \"Awaiting approval. Click to cancel follow request\",\n  \"account.share\": \"Share @{name}'s profile\",\n  \"account.show_reblogs\": \"Show boosts from @{name}\",\n  \"account.unblock\": \"Unblock @{name}\",\n  \"account.unblock_domain\": \"Unhide {domain}\",\n  \"account.unendorse\": \"Don't feature on profile\",\n  \"account.unfollow\": \"Unfollow\",\n  \"account.unmute\": \"Unmute @{name}\",\n  \"account.unmute_notifications\": \"Unmute notifications from @{name}\",\n  \"alert.unexpected.message\": \"An unexpected error occurred.\",\n  \"alert.unexpected.title\": \"Oops!\",\n  \"boost_modal.combo\": \"You can press {combo} to skip this next time\",\n  \"bundle_column_error.body\": \"Something went wrong while loading this component.\",\n  \"bundle_column_error.retry\": \"Try again\",\n  \"bundle_column_error.title\": \"Network error\",\n  \"bundle_modal_error.close\": \"Close\",\n  \"bundle_modal_error.message\": \"Something went wrong while loading this component.\",\n  \"bundle_modal_error.retry\": \"Try again\",\n  \"column.blocks\": \"Blocked users\",\n  \"column.community\": \"Local timeline\",\n  \"column.direct\": \"Direct messages\",\n  \"column.domain_blocks\": \"Hidden domains\",\n  \"column.favourites\": \"Favourites\",\n  \"column.follow_requests\": \"Follow requests\",\n  \"column.home\": \"Home\",\n  \"column.lists\": \"Lists\",\n  \"column.mutes\": \"Muted users\",\n  \"column.notifications\": \"Notifications\",\n  \"column.pins\": \"Pinned toot\",\n  \"column.public\": \"Federated timeline\",\n  \"column_back_button.label\": \"Back\",\n  \"column_header.hide_settings\": \"Hide settings\",\n  \"column_header.moveLeft_settings\": \"Move column to the left\",\n  \"column_header.moveRight_settings\": \"Move column to the right\",\n  \"column_header.pin\": \"Pin\",\n  \"column_header.show_settings\": \"Show settings\",\n  \"column_header.unpin\": \"Unpin\",\n  \"column_subheading.settings\": \"Settings\",\n  \"community.column_settings.media_only\": \"Media Only\",\n  \"compose_form.direct_message_warning\": \"This toot will only be sent to all the mentioned users.\",\n  \"compose_form.direct_message_warning_learn_more\": \"Learn more\",\n  \"compose_form.hashtag_warning\": \"This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.\",\n  \"compose_form.lock_disclaimer\": \"Your account is not {locked}. Anyone can follow you to view your follower-only posts.\",\n  \"compose_form.lock_disclaimer.lock\": \"locked\",\n  \"compose_form.placeholder\": \"What is on your mind?\",\n  \"compose_form.poll.add_option\": \"Add a choice\",\n  \"compose_form.poll.duration\": \"Poll duration\",\n  \"compose_form.poll.option_placeholder\": \"Choice {number}\",\n  \"compose_form.poll.remove_option\": \"Remove this choice\",\n  \"compose_form.publish\": \"Toot\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"Mark media as sensitive\",\n  \"compose_form.sensitive.marked\": \"Media is marked as sensitive\",\n  \"compose_form.sensitive.unmarked\": \"Media is not marked as sensitive\",\n  \"compose_form.spoiler.marked\": \"Text is hidden behind warning\",\n  \"compose_form.spoiler.unmarked\": \"Text is not hidden\",\n  \"compose_form.spoiler_placeholder\": \"Write your warning here\",\n  \"confirmation_modal.cancel\": \"Cancel\",\n  \"confirmations.block.block_and_report\": \"Block & Report\",\n  \"confirmations.block.confirm\": \"Block\",\n  \"confirmations.block.message\": \"Are you sure you want to block {name}?\",\n  \"confirmations.delete.confirm\": \"Delete\",\n  \"confirmations.delete.message\": \"Are you sure you want to delete this status?\",\n  \"confirmations.delete_list.confirm\": \"Delete\",\n  \"confirmations.delete_list.message\": \"Are you sure you want to permanently delete this list?\",\n  \"confirmations.domain_block.confirm\": \"Hide entire domain\",\n  \"confirmations.domain_block.message\": \"Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain in any public timelines or your notifications. Your followers from that domain will be removed.\",\n  \"confirmations.mute.confirm\": \"Mute\",\n  \"confirmations.mute.message\": \"Are you sure you want to mute {name}?\",\n  \"confirmations.redraft.confirm\": \"Delete & redraft\",\n  \"confirmations.redraft.message\": \"Are you sure you want to delete this status and re-draft it? Favourites and boosts will be lost, and replies to the original post will be orphaned.\",\n  \"confirmations.reply.confirm\": \"Reply\",\n  \"confirmations.reply.message\": \"Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?\",\n  \"confirmations.unfollow.confirm\": \"Unfollow\",\n  \"confirmations.unfollow.message\": \"Are you sure you want to unfollow {name}?\",\n  \"embed.instructions\": \"Embed this status on your website by copying the code below.\",\n  \"embed.preview\": \"Here is what it will look like:\",\n  \"emoji_button.activity\": \"Activity\",\n  \"emoji_button.custom\": \"Custom\",\n  \"emoji_button.flags\": \"Flags\",\n  \"emoji_button.food\": \"Food & Drink\",\n  \"emoji_button.label\": \"Insert emoji\",\n  \"emoji_button.nature\": \"Nature\",\n  \"emoji_button.not_found\": \"No emojos!! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"Objects\",\n  \"emoji_button.people\": \"People\",\n  \"emoji_button.recent\": \"Frequently used\",\n  \"emoji_button.search\": \"Search...\",\n  \"emoji_button.search_results\": \"Search results\",\n  \"emoji_button.symbols\": \"Symbols\",\n  \"emoji_button.travel\": \"Travel & Places\",\n  \"empty_column.account_timeline\": \"No toots here!\",\n  \"empty_column.account_unavailable\": \"Profile unavailable\",\n  \"empty_column.blocks\": \"You haven't blocked any users yet.\",\n  \"empty_column.community\": \"The local timeline is empty. Write something publicly to get the ball rolling!\",\n  \"empty_column.direct\": \"You don't have any direct messages yet. When you send or receive one, it will show up here.\",\n  \"empty_column.domain_blocks\": \"There are no hidden domains yet.\",\n  \"empty_column.favourited_statuses\": \"You don't have any favourite toots yet. When you favourite one, it will show up here.\",\n  \"empty_column.favourites\": \"No one has favourited this toot yet. When someone does, they will show up here.\",\n  \"empty_column.follow_requests\": \"You don't have any follow requests yet. When you receive one, it will show up here.\",\n  \"empty_column.hashtag\": \"There is nothing in this hashtag yet.\",\n  \"empty_column.home\": \"Your home timeline is empty! Visit {public} or use search to get started and meet other users.\",\n  \"empty_column.home.public_timeline\": \"the public timeline\",\n  \"empty_column.list\": \"There is nothing in this list yet. When members of this list post new statuses, they will appear here.\",\n  \"empty_column.lists\": \"You don't have any lists yet. When you create one, it will show up here.\",\n  \"empty_column.mutes\": \"You haven't muted any users yet.\",\n  \"empty_column.notifications\": \"You don't have any notifications yet. Interact with others to start the conversation.\",\n  \"empty_column.public\": \"There is nothing here! Write something publicly, or manually follow users from other servers to fill it up\",\n  \"follow_request.authorize\": \"Authorize\",\n  \"follow_request.reject\": \"Reject\",\n  \"getting_started.developers\": \"Developers\",\n  \"getting_started.directory\": \"Profile directory\",\n  \"getting_started.documentation\": \"Documentation\",\n  \"getting_started.heading\": \"Getting started\",\n  \"getting_started.invite\": \"Invite people\",\n  \"getting_started.open_source_notice\": \"Mastodon is open source software. You can contribute or report issues on GitHub at {github}.\",\n  \"getting_started.security\": \"Security\",\n  \"getting_started.terms\": \"Terms of service\",\n  \"hashtag.column_header.tag_mode.all\": \"and {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"or {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"without {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"No suggestions found\",\n  \"hashtag.column_settings.select.placeholder\": \"Enter hashtags…\",\n  \"hashtag.column_settings.tag_mode.all\": \"All of these\",\n  \"hashtag.column_settings.tag_mode.any\": \"Any of these\",\n  \"hashtag.column_settings.tag_mode.none\": \"None of these\",\n  \"hashtag.column_settings.tag_toggle\": \"Include additional tags in this column\",\n  \"home.column_settings.basic\": \"Basic\",\n  \"home.column_settings.show_reblogs\": \"Show boosts\",\n  \"home.column_settings.show_replies\": \"Show replies\",\n  \"intervals.full.days\": \"{number, plural, one {# day} other {# days}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# hour} other {# hours}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minute} other {# minutes}}\",\n  \"introduction.federation.action\": \"Next\",\n  \"introduction.federation.federated.headline\": \"Federated\",\n  \"introduction.federation.federated.text\": \"Public posts from other servers of the fediverse will appear in the federated timeline.\",\n  \"introduction.federation.home.headline\": \"Home\",\n  \"introduction.federation.home.text\": \"Posts from people you follow will appear in your home feed. You can follow anyone on any server!\",\n  \"introduction.federation.local.headline\": \"Local\",\n  \"introduction.federation.local.text\": \"Public posts from people on the same server as you will appear in the local timeline.\",\n  \"introduction.interactions.action\": \"Finish toot-orial!\",\n  \"introduction.interactions.favourite.headline\": \"Favourite\",\n  \"introduction.interactions.favourite.text\": \"You can save a toot for later, and let the author know that you liked it, by favouriting it.\",\n  \"introduction.interactions.reblog.headline\": \"Boost\",\n  \"introduction.interactions.reblog.text\": \"You can share other people's toots with your followers by boosting them.\",\n  \"introduction.interactions.reply.headline\": \"Reply\",\n  \"introduction.interactions.reply.text\": \"You can reply to other people's and your own toots, which will chain them together in a conversation.\",\n  \"introduction.welcome.action\": \"Let's go!\",\n  \"introduction.welcome.headline\": \"First steps\",\n  \"introduction.welcome.text\": \"Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.\",\n  \"keyboard_shortcuts.back\": \"to navigate back\",\n  \"keyboard_shortcuts.blocked\": \"to open blocked users list\",\n  \"keyboard_shortcuts.boost\": \"to boost\",\n  \"keyboard_shortcuts.column\": \"to focus a status in one of the columns\",\n  \"keyboard_shortcuts.compose\": \"to focus the compose textarea\",\n  \"keyboard_shortcuts.description\": \"Description\",\n  \"keyboard_shortcuts.direct\": \"to open direct messages column\",\n  \"keyboard_shortcuts.down\": \"to move down in the list\",\n  \"keyboard_shortcuts.enter\": \"to open status\",\n  \"keyboard_shortcuts.favourite\": \"to favourite\",\n  \"keyboard_shortcuts.favourites\": \"to open favourites list\",\n  \"keyboard_shortcuts.federated\": \"to open federated timeline\",\n  \"keyboard_shortcuts.heading\": \"Keyboard Shortcuts\",\n  \"keyboard_shortcuts.home\": \"to open home timeline\",\n  \"keyboard_shortcuts.hotkey\": \"Hotkey\",\n  \"keyboard_shortcuts.legend\": \"to display this legend\",\n  \"keyboard_shortcuts.local\": \"to open local timeline\",\n  \"keyboard_shortcuts.mention\": \"to mention author\",\n  \"keyboard_shortcuts.muted\": \"to open muted users list\",\n  \"keyboard_shortcuts.my_profile\": \"to open your profile\",\n  \"keyboard_shortcuts.notifications\": \"to open notifications column\",\n  \"keyboard_shortcuts.pinned\": \"to open pinned toots list\",\n  \"keyboard_shortcuts.profile\": \"to open author's profile\",\n  \"keyboard_shortcuts.reply\": \"to reply\",\n  \"keyboard_shortcuts.requests\": \"to open follow requests list\",\n  \"keyboard_shortcuts.search\": \"to focus search\",\n  \"keyboard_shortcuts.start\": \"to open \\\"get started\\\" column\",\n  \"keyboard_shortcuts.toggle_hidden\": \"to show/hide text behind CW\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"to show/hide media\",\n  \"keyboard_shortcuts.toot\": \"to start a brand new toot\",\n  \"keyboard_shortcuts.unfocus\": \"to un-focus compose textarea/search\",\n  \"keyboard_shortcuts.up\": \"to move up in the list\",\n  \"lightbox.close\": \"Close\",\n  \"lightbox.next\": \"Next\",\n  \"lightbox.previous\": \"Previous\",\n  \"lightbox.view_context\": \"View context\",\n  \"lists.account.add\": \"Add to list\",\n  \"lists.account.remove\": \"Remove from list\",\n  \"lists.delete\": \"Delete list\",\n  \"lists.edit\": \"Edit list\",\n  \"lists.edit.submit\": \"Change title\",\n  \"lists.new.create\": \"Add list\",\n  \"lists.new.title_placeholder\": \"New list title\",\n  \"lists.search\": \"Search among people you follow\",\n  \"lists.subheading\": \"Your lists\",\n  \"loading_indicator.label\": \"Loading...\",\n  \"media_gallery.toggle_visible\": \"Toggle visibility\",\n  \"missing_indicator.label\": \"Not found\",\n  \"missing_indicator.sublabel\": \"This resource could not be found\",\n  \"mute_modal.hide_notifications\": \"Hide notifications from this user?\",\n  \"navigation_bar.apps\": \"Mobile apps\",\n  \"navigation_bar.blocks\": \"Blocked users\",\n  \"navigation_bar.community_timeline\": \"Local timeline\",\n  \"navigation_bar.compose\": \"Compose new toot\",\n  \"navigation_bar.direct\": \"Direct messages\",\n  \"navigation_bar.discover\": \"Discover\",\n  \"navigation_bar.domain_blocks\": \"Hidden domains\",\n  \"navigation_bar.edit_profile\": \"Edit profile\",\n  \"navigation_bar.favourites\": \"Favourites\",\n  \"navigation_bar.filters\": \"Muted words\",\n  \"navigation_bar.follow_requests\": \"Follow requests\",\n  \"navigation_bar.follows_and_followers\": \"Follows and followers\",\n  \"navigation_bar.info\": \"About this server\",\n  \"navigation_bar.keyboard_shortcuts\": \"Hotkeys\",\n  \"navigation_bar.lists\": \"Lists\",\n  \"navigation_bar.logout\": \"Logout\",\n  \"navigation_bar.mutes\": \"Muted users\",\n  \"navigation_bar.personal\": \"Personal\",\n  \"navigation_bar.pins\": \"Pinned toots\",\n  \"navigation_bar.preferences\": \"Preferences\",\n  \"navigation_bar.profile_directory\": \"Profile directory\",\n  \"navigation_bar.public_timeline\": \"Federated timeline\",\n  \"navigation_bar.security\": \"Security\",\n  \"notification.favourite\": \"{name} favourited your status\",\n  \"notification.follow\": \"{name} followed you\",\n  \"notification.mention\": \"{name} mentioned you\",\n  \"notification.poll\": \"A poll you have voted in has ended\",\n  \"notification.reblog\": \"{name} boosted your status\",\n  \"notifications.clear\": \"Clear notifications\",\n  \"notifications.clear_confirmation\": \"Are you sure you want to permanently clear all your notifications?\",\n  \"notifications.column_settings.alert\": \"Desktop notifications\",\n  \"notifications.column_settings.favourite\": \"Favourites:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Display all categories\",\n  \"notifications.column_settings.filter_bar.category\": \"Quick filter bar\",\n  \"notifications.column_settings.filter_bar.show\": \"Show\",\n  \"notifications.column_settings.follow\": \"New followers:\",\n  \"notifications.column_settings.mention\": \"Mentions:\",\n  \"notifications.column_settings.poll\": \"Poll results:\",\n  \"notifications.column_settings.push\": \"Push notifications\",\n  \"notifications.column_settings.reblog\": \"Boosts:\",\n  \"notifications.column_settings.show\": \"Show in column\",\n  \"notifications.column_settings.sound\": \"Play sound\",\n  \"notifications.filter.all\": \"All\",\n  \"notifications.filter.boosts\": \"Boosts\",\n  \"notifications.filter.favourites\": \"Favourites\",\n  \"notifications.filter.follows\": \"Follows\",\n  \"notifications.filter.mentions\": \"Mentions\",\n  \"notifications.filter.polls\": \"Poll results\",\n  \"notifications.group\": \"{count} notifications\",\n  \"poll.closed\": \"Closed\",\n  \"poll.refresh\": \"Refresh\",\n  \"poll.total_votes\": \"{count, plural, one {# vote} other {# votes}}\",\n  \"poll.vote\": \"Vote\",\n  \"poll_button.add_poll\": \"Add a poll\",\n  \"poll_button.remove_poll\": \"Remove poll\",\n  \"privacy.change\": \"Adjust status privacy\",\n  \"privacy.direct.long\": \"Post to mentioned users only\",\n  \"privacy.direct.short\": \"Direct\",\n  \"privacy.private.long\": \"Post to followers only\",\n  \"privacy.private.short\": \"Followers-only\",\n  \"privacy.public.long\": \"Post to public timelines\",\n  \"privacy.public.short\": \"Public\",\n  \"privacy.unlisted.long\": \"Do not show in public timelines\",\n  \"privacy.unlisted.short\": \"Unlisted\",\n  \"regeneration_indicator.label\": \"Loading…\",\n  \"regeneration_indicator.sublabel\": \"Your home feed is being prepared!\",\n  \"relative_time.days\": \"{number}d\",\n  \"relative_time.hours\": \"{number}h\",\n  \"relative_time.just_now\": \"now\",\n  \"relative_time.minutes\": \"{number}m\",\n  \"relative_time.seconds\": \"{number}s\",\n  \"reply_indicator.cancel\": \"Cancel\",\n  \"report.forward\": \"Forward to {target}\",\n  \"report.forward_hint\": \"The account is from another server. Send an anonymized copy of the report there as well?\",\n  \"report.hint\": \"The report will be sent to your server moderators. You can provide an explanation of why you are reporting this account below:\",\n  \"report.placeholder\": \"Additional comments\",\n  \"report.submit\": \"Submit\",\n  \"report.target\": \"Report {target}\",\n  \"search.placeholder\": \"Search\",\n  \"search_popout.search_format\": \"Advanced search format\",\n  \"search_popout.tips.full_text\": \"Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.\",\n  \"search_popout.tips.hashtag\": \"hashtag\",\n  \"search_popout.tips.status\": \"status\",\n  \"search_popout.tips.text\": \"Simple text returns matching display names, usernames and hashtags\",\n  \"search_popout.tips.user\": \"user\",\n  \"search_results.accounts\": \"People\",\n  \"search_results.hashtags\": \"Hashtags\",\n  \"search_results.statuses\": \"Toots\",\n  \"search_results.total\": \"{count, number} {count, plural, one {result} other {results}}\",\n  \"status.admin_account\": \"Open moderation interface for @{name}\",\n  \"status.admin_status\": \"Open this status in the moderation interface\",\n  \"status.block\": \"Block @{name}\",\n  \"status.cancel_reblog_private\": \"Unboost\",\n  \"status.cannot_reblog\": \"This post cannot be boosted\",\n  \"status.copy\": \"Copy link to status\",\n  \"status.delete\": \"Delete\",\n  \"status.detailed_status\": \"Detailed conversation view\",\n  \"status.direct\": \"Direct message @{name}\",\n  \"status.embed\": \"Embed\",\n  \"status.favourite\": \"Favourite\",\n  \"status.filtered\": \"Filtered\",\n  \"status.load_more\": \"Load more\",\n  \"status.media_hidden\": \"Media hidden\",\n  \"status.mention\": \"Mention @{name}\",\n  \"status.more\": \"More\",\n  \"status.mute\": \"Mute @{name}\",\n  \"status.mute_conversation\": \"Mute conversation\",\n  \"status.open\": \"Expand this status\",\n  \"status.pin\": \"Pin on profile\",\n  \"status.pinned\": \"Pinned toot\",\n  \"status.read_more\": \"Read more\",\n  \"status.reblog\": \"Boost\",\n  \"status.reblog_private\": \"Boost to original audience\",\n  \"status.reblogged_by\": \"{name} boosted\",\n  \"status.reblogs.empty\": \"No one has boosted this toot yet. When someone does, they will show up here.\",\n  \"status.redraft\": \"Delete & re-draft\",\n  \"status.reply\": \"Reply\",\n  \"status.replyAll\": \"Reply to thread\",\n  \"status.report\": \"Report @{name}\",\n  \"status.sensitive_warning\": \"Sensitive content\",\n  \"status.share\": \"Share\",\n  \"status.show_less\": \"Show less\",\n  \"status.show_less_all\": \"Show less for all\",\n  \"status.show_more\": \"Show more\",\n  \"status.show_more_all\": \"Show more for all\",\n  \"status.show_thread\": \"Show thread\",\n  \"status.unmute_conversation\": \"Unmute conversation\",\n  \"status.unpin\": \"Unpin from profile\",\n  \"suggestions.dismiss\": \"Dismiss suggestion\",\n  \"suggestions.header\": \"You might be interested in…\",\n  \"tabs_bar.federated_timeline\": \"Federated\",\n  \"tabs_bar.home\": \"Home\",\n  \"tabs_bar.local_timeline\": \"Local\",\n  \"tabs_bar.notifications\": \"Notifications\",\n  \"tabs_bar.search\": \"Search\",\n  \"time_remaining.days\": \"{number, plural, one {# day} other {# days}} left\",\n  \"time_remaining.hours\": \"{number, plural, one {# hour} other {# hours}} left\",\n  \"time_remaining.minutes\": \"{number, plural, one {# minute} other {# minutes}} left\",\n  \"time_remaining.moments\": \"Moments remaining\",\n  \"time_remaining.seconds\": \"{number, plural, one {# second} other {# seconds}} left\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {person} other {people}} talking\",\n  \"ui.beforeunload\": \"Your draft will be lost if you leave Mastodon.\",\n  \"upload_area.title\": \"Drag & drop to upload\",\n  \"upload_button.label\": \"Add media (JPEG, PNG, GIF, WebM, MP4, MOV)\",\n  \"upload_error.limit\": \"File upload limit exceeded.\",\n  \"upload_error.poll\": \"File upload not allowed with polls.\",\n  \"upload_form.description\": \"Describe for the visually impaired\",\n  \"upload_form.focus\": \"Crop\",\n  \"upload_form.undo\": \"Delete\",\n  \"upload_progress.label\": \"Uploading...\",\n  \"video.close\": \"Close video\",\n  \"video.exit_fullscreen\": \"Exit full screen\",\n  \"video.expand\": \"Expand video\",\n  \"video.fullscreen\": \"Full screen\",\n  \"video.hide\": \"Hide video\",\n  \"video.mute\": \"Mute sound\",\n  \"video.pause\": \"Pause\",\n  \"video.play\": \"Play\",\n  \"video.unmute\": \"Unmute sound\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/lv.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Pievienot vai noņemt no saraksta\",\n  \"account.badges.bot\": \"Bots\",\n  \"account.block\": \"Bloķēt @{name}\",\n  \"account.block_domain\": \"Slēpt visu no {domain}\",\n  \"account.blocked\": \"Bloķēts\",\n  \"account.direct\": \"Privātā ziņa @{name}\",\n  \"account.domain_blocked\": \"Domēns ir paslēpts\",\n  \"account.edit_profile\": \"Labot profilu\",\n  \"account.endorse\": \"Izcelts profilā\",\n  \"account.follow\": \"Sekot\",\n  \"account.followers\": \"Sekotāji\",\n  \"account.followers.empty\": \"Šim lietotājam nav sekotāju.\",\n  \"account.follows\": \"Seko\",\n  \"account.follows.empty\": \"Šis lietotājs pagaidām nevienam neseko.\",\n  \"account.follows_you\": \"Seko tev\",\n  \"account.hide_reblogs\": \"Paslēpt paceltos ierakstus no lietotāja @{name}\",\n  \"account.link_verified_on\": \"Šīs saites piederība ir pārbaudīta {date}\",\n  \"account.locked_info\": \"Šī konta privātuma status ir iestatīts slēgts. Īpašnieks izskatīs un izvēlēsies kas viņam drīkst sekot.\",\n  \"account.media\": \"Mēdiji\",\n  \"account.mention\": \"Piemin @{name}\",\n  \"account.moved_to\": \"{name} ir pārvācies uz:\",\n  \"account.mute\": \"Apklusināt @{name}\",\n  \"account.mute_notifications\": \"Nerādīt paziņojumus no @{name}\",\n  \"account.muted\": \"Apklusināts\",\n  \"account.posts\": \"Ieraksti\",\n  \"account.posts_with_replies\": \"Ieraksti un atbildes\",\n  \"account.report\": \"Ziņot par lietotāju @{name}\",\n  \"account.requested\": \"Gaidām apstiprinājumu. Nospied lai atceltu sekošanas pieparasījumu\",\n  \"account.share\": \"Dalīties ar lietotāja @{name}'s profilu\",\n  \"account.show_reblogs\": \"Parādīt lietotāja @{name} paceltos ierakstus\",\n  \"account.unblock\": \"Atbloķēt lietotāju @{name}\",\n  \"account.unblock_domain\": \"Atbloķēt domēnu {domain}\",\n  \"account.unendorse\": \"Neizcelt profilā\",\n  \"account.unfollow\": \"Nesekot\",\n  \"account.unmute\": \"Noņemt apklusinājumu no lietotāja @{name}\",\n  \"account.unmute_notifications\": \"Rādīt paziņojumus no lietotāja @{name}\",\n  \"alert.unexpected.message\": \"Negaidīta kļūda.\",\n  \"alert.unexpected.title\": \"Ups!\",\n  \"boost_modal.combo\": \"Nospied {combo} lai izlaistu šo nākamreiz\",\n  \"bundle_column_error.body\": \"Kaut kas nogāja greizi ielādējot šo komponenti.\",\n  \"bundle_column_error.retry\": \"Mēģini vēlreiz\",\n  \"bundle_column_error.title\": \"Tīkla kļūda\",\n  \"bundle_modal_error.close\": \"Aizvērt\",\n  \"bundle_modal_error.message\": \"Kaut kas nogāja greizi ielādējot šo komponenti.\",\n  \"bundle_modal_error.retry\": \"Mēģini vēlreiz\",\n  \"column.blocks\": \"Bloķētie lietotāji\",\n  \"column.community\": \"Lokālā laika līnija\",\n  \"column.direct\": \"Privātās ziņas\",\n  \"column.domain_blocks\": \"Paslēptie domēni\",\n  \"column.favourites\": \"Favorīti\",\n  \"column.follow_requests\": \"Sekotāju pieprasījumi\",\n  \"column.home\": \"Sākums\",\n  \"column.lists\": \"Saraksti\",\n  \"column.mutes\": \"Apklusinātie lietotāji\",\n  \"column.notifications\": \"Paziņojumi\",\n  \"column.pins\": \"Piespraustie ziņojumi\",\n  \"column.public\": \"Federatīvā laika līnija\",\n  \"column_back_button.label\": \"Atpakaļ\",\n  \"column_header.hide_settings\": \"Paslēpt iestatījumus\",\n  \"column_header.moveLeft_settings\": \"Pārvietot kolonu pa kreisi\",\n  \"column_header.moveRight_settings\": \"Pārvietot kolonu pa labi\",\n  \"column_header.pin\": \"Piespraust\",\n  \"column_header.show_settings\": \"Rādīt iestatījumus\",\n  \"column_header.unpin\": \"Atspraust\",\n  \"column_subheading.settings\": \"Iestatījumi\",\n  \"community.column_settings.media_only\": \"Tikai mēdiji\",\n  \"compose_form.direct_message_warning\": \"Šis ziņojums tiks nosūtīts tikai pieminētajiem lietotājiem.\",\n  \"compose_form.direct_message_warning_learn_more\": \"Papildus informācija\",\n  \"compose_form.hashtag_warning\": \"Ziņojumu nebūs iespējams atrast zem haštagiem jo tas nav publisks. Tikai publiskos ziņojumus ir iespējams meklēt pēc tiem.\",\n  \"compose_form.lock_disclaimer\": \"Tavs konts nav {locked}. Ikviens var Tev sekot lai apskatītu tikai sekotājiem paredzētos ziņojumus.\",\n  \"compose_form.lock_disclaimer.lock\": \"slēgts\",\n  \"compose_form.placeholder\": \"Ko vēlies publicēt?\",\n  \"compose_form.poll.add_option\": \"Add a choice\",\n  \"compose_form.poll.duration\": \"Poll duration\",\n  \"compose_form.poll.option_placeholder\": \"Choice {number}\",\n  \"compose_form.poll.remove_option\": \"Remove this choice\",\n  \"compose_form.publish\": \"Publicēt\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"Mark media as sensitive\",\n  \"compose_form.sensitive.marked\": \"Mēdijs ir atzīmēts kā sensitīvs\",\n  \"compose_form.sensitive.unmarked\": \"Mēdijs nav atzīmēts kā sensitīvs\",\n  \"compose_form.spoiler.marked\": \"Teksts ir paslēpts aiz brīdinājuma\",\n  \"compose_form.spoiler.unmarked\": \"Teksts nav paslēpts\",\n  \"compose_form.spoiler_placeholder\": \"Ieraksti Savu brīdinājuma tekstu šeit\",\n  \"confirmation_modal.cancel\": \"Atcelt\",\n  \"confirmations.block.block_and_report\": \"Block & Report\",\n  \"confirmations.block.confirm\": \"Bloķēt\",\n  \"confirmations.block.message\": \"Vai tiešām vēlies bloķēt lietotāju {name}?\",\n  \"confirmations.delete.confirm\": \"Dzēst\",\n  \"confirmations.delete.message\": \"Vai tiešām vēlies dzēst šo ierakstu?\",\n  \"confirmations.delete_list.confirm\": \"Dzēst\",\n  \"confirmations.delete_list.message\": \"Vai tiešam vēlies neatgriezeniski dzēst šo sarakstu?\",\n  \"confirmations.domain_block.confirm\": \"Paslēpt visu domēnu\",\n  \"confirmations.domain_block.message\": \"Vai tu tiešām, tiešam vēlies bloķēt visu domēnu {domain}? Lielākajā daļā gadījumu pietiek ja nobloķē vai apklusini kādu. Tu neredzēsi saturu vai paziņojumus no šī domēna nevienā laika līnijā. Tavi sekotāji no šī domēna tiks noņemti.\",\n  \"confirmations.mute.confirm\": \"Apklusināt\",\n  \"confirmations.mute.message\": \"Vai Tu tiešām velies apklusināt {name}?\",\n  \"confirmations.redraft.confirm\": \"Dzēst un pārrakstīt\",\n  \"confirmations.redraft.message\": \"Vai tiešām vēlies dzēst un pārrakstīt šo ierakstu? Favorīti un paceltie ieraksti tiks dzēsti, kā arī atbildes tiks atsaistītas no šī ieraksta.\",\n  \"confirmations.reply.confirm\": \"Atbildēt\",\n  \"confirmations.reply.message\": \"Atbildot tagad tava ziņa ko šobrīd raksti tiks pārrakstīta. Vai tiešām vēlies turpināt?\",\n  \"confirmations.unfollow.confirm\": \"Nesekot\",\n  \"confirmations.unfollow.message\": \"Vai tiešam vairs nevēlies sekot lietotājam {name}?\",\n  \"embed.instructions\": \"Iegul šo ziņojumu savā mājaslapā kopējot kodu zemāk.\",\n  \"embed.preview\": \"Tas izskatīsies šādi:\",\n  \"emoji_button.activity\": \"Aktivitāte\",\n  \"emoji_button.custom\": \"Pielāgots\",\n  \"emoji_button.flags\": \"Karogi\",\n  \"emoji_button.food\": \"Ēdieni un dzērieni\",\n  \"emoji_button.label\": \"Ielikt emoji smaidiņu\",\n  \"emoji_button.nature\": \"Daba\",\n  \"emoji_button.not_found\": \"Nekādu emodžīšu!! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"Objekti\",\n  \"emoji_button.people\": \"Cilvēki\",\n  \"emoji_button.recent\": \"Biežāk lietotie\",\n  \"emoji_button.search\": \"Meklēt...\",\n  \"emoji_button.search_results\": \"Meklēšanas rezultāti\",\n  \"emoji_button.symbols\": \"Simboli\",\n  \"emoji_button.travel\": \"Ceļošana & Vietas\",\n  \"empty_column.account_timeline\": \"Šeit ziņojumu nav!\",\n  \"empty_column.account_unavailable\": \"Profile unavailable\",\n  \"empty_column.blocks\": \"Tu neesi vēl nevienu bloķējis.\",\n  \"empty_column.community\": \"Lokālā laika līnija ir tukša. :/ Ieraksti kaut ko lai sākas rosība!\",\n  \"empty_column.direct\": \"Tev nav privāto ziņu. Tiklīdz saņemsi tās šeit parādīsies.\",\n  \"empty_column.domain_blocks\": \"Slēpto domēnu vēl nav.\",\n  \"empty_column.favourited_statuses\": \"Tev vēl nav iemīļoto ziņojumu. Kad Tev tādu būs tie šeit parādīsies.\",\n  \"empty_column.favourites\": \"Neviens šo ziņojumu nav pievienojis favorītiem. Kad tādu būs tie šeit parādīsies.\",\n  \"empty_column.follow_requests\": \"Šobrīd neviens nav pieteicies tev sekot. Kad kāds pieteiksies tas parādīsies šeit.\",\n  \"empty_column.hashtag\": \"Ar šo haštagu nekas nav atrodams.\",\n  \"empty_column.home\": \"Tava laika līnija ir tukša! Apmeklē federatīvo laika līniju vai uzmeklē kādu meklētājā lai satiktu citus.\",\n  \"empty_column.home.public_timeline\": \"publiskā laika līnija\",\n  \"empty_column.list\": \"Šis saraksts ir tukšs. Kad šī saraksta dalībnieki atjaunos statusu tas parādīsies šeit.\",\n  \"empty_column.lists\": \"Tev nav neviena saraksta. Kad tādu būs tie parādīsies šeit.\",\n  \"empty_column.mutes\": \"Tu neesi nevienu apklusinājis.\",\n  \"empty_column.notifications\": \"Tev nav paziņojumu. Iesaisties sarunās ar citiem.\",\n  \"empty_column.public\": \"Šeit nekā nav, tukšums! Ieraksti kaut ko publiski, vai uzmeklē un seko kādam no citas instances\",\n  \"follow_request.authorize\": \"Autorizēt\",\n  \"follow_request.reject\": \"Noraidīt\",\n  \"getting_started.developers\": \"Developers\",\n  \"getting_started.directory\": \"Profile directory\",\n  \"getting_started.documentation\": \"Documentation\",\n  \"getting_started.heading\": \"Getting started\",\n  \"getting_started.invite\": \"Invite people\",\n  \"getting_started.open_source_notice\": \"Mastodon is open source software. You can contribute or report issues on GitHub at {github}.\",\n  \"getting_started.security\": \"Security\",\n  \"getting_started.terms\": \"Terms of service\",\n  \"hashtag.column_header.tag_mode.all\": \"and {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"or {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"without {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"No suggestions found\",\n  \"hashtag.column_settings.select.placeholder\": \"Enter hashtags…\",\n  \"hashtag.column_settings.tag_mode.all\": \"All of these\",\n  \"hashtag.column_settings.tag_mode.any\": \"Any of these\",\n  \"hashtag.column_settings.tag_mode.none\": \"None of these\",\n  \"hashtag.column_settings.tag_toggle\": \"Include additional tags in this column\",\n  \"home.column_settings.basic\": \"Basic\",\n  \"home.column_settings.show_reblogs\": \"Show boosts\",\n  \"home.column_settings.show_replies\": \"Show replies\",\n  \"intervals.full.days\": \"{number, plural, one {# day} other {# days}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# hour} other {# hours}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minute} other {# minutes}}\",\n  \"introduction.federation.action\": \"Next\",\n  \"introduction.federation.federated.headline\": \"Federated\",\n  \"introduction.federation.federated.text\": \"Public posts from other servers of the fediverse will appear in the federated timeline.\",\n  \"introduction.federation.home.headline\": \"Home\",\n  \"introduction.federation.home.text\": \"Posts from people you follow will appear in your home feed. You can follow anyone on any server!\",\n  \"introduction.federation.local.headline\": \"Local\",\n  \"introduction.federation.local.text\": \"Public posts from people on the same server as you will appear in the local timeline.\",\n  \"introduction.interactions.action\": \"Finish toot-orial!\",\n  \"introduction.interactions.favourite.headline\": \"Favourite\",\n  \"introduction.interactions.favourite.text\": \"You can save a toot for later, and let the author know that you liked it, by favouriting it.\",\n  \"introduction.interactions.reblog.headline\": \"Boost\",\n  \"introduction.interactions.reblog.text\": \"You can share other people's toots with your followers by boosting them.\",\n  \"introduction.interactions.reply.headline\": \"Reply\",\n  \"introduction.interactions.reply.text\": \"You can reply to other people's and your own toots, which will chain them together in a conversation.\",\n  \"introduction.welcome.action\": \"Let's go!\",\n  \"introduction.welcome.headline\": \"First steps\",\n  \"introduction.welcome.text\": \"Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.\",\n  \"keyboard_shortcuts.back\": \"to navigate back\",\n  \"keyboard_shortcuts.blocked\": \"to open blocked users list\",\n  \"keyboard_shortcuts.boost\": \"to boost\",\n  \"keyboard_shortcuts.column\": \"to focus a status in one of the columns\",\n  \"keyboard_shortcuts.compose\": \"to focus the compose textarea\",\n  \"keyboard_shortcuts.description\": \"Description\",\n  \"keyboard_shortcuts.direct\": \"to open direct messages column\",\n  \"keyboard_shortcuts.down\": \"to move down in the list\",\n  \"keyboard_shortcuts.enter\": \"to open status\",\n  \"keyboard_shortcuts.favourite\": \"to favourite\",\n  \"keyboard_shortcuts.favourites\": \"to open favourites list\",\n  \"keyboard_shortcuts.federated\": \"to open federated timeline\",\n  \"keyboard_shortcuts.heading\": \"Keyboard Shortcuts\",\n  \"keyboard_shortcuts.home\": \"to open home timeline\",\n  \"keyboard_shortcuts.hotkey\": \"Hotkey\",\n  \"keyboard_shortcuts.legend\": \"to display this legend\",\n  \"keyboard_shortcuts.local\": \"to open local timeline\",\n  \"keyboard_shortcuts.mention\": \"to mention author\",\n  \"keyboard_shortcuts.muted\": \"to open muted users list\",\n  \"keyboard_shortcuts.my_profile\": \"to open your profile\",\n  \"keyboard_shortcuts.notifications\": \"to open notifications column\",\n  \"keyboard_shortcuts.pinned\": \"to open pinned toots list\",\n  \"keyboard_shortcuts.profile\": \"to open author's profile\",\n  \"keyboard_shortcuts.reply\": \"to reply\",\n  \"keyboard_shortcuts.requests\": \"to open follow requests list\",\n  \"keyboard_shortcuts.search\": \"to focus search\",\n  \"keyboard_shortcuts.start\": \"to open \\\"get started\\\" column\",\n  \"keyboard_shortcuts.toggle_hidden\": \"to show/hide text behind CW\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"to show/hide media\",\n  \"keyboard_shortcuts.toot\": \"to start a brand new toot\",\n  \"keyboard_shortcuts.unfocus\": \"to un-focus compose textarea/search\",\n  \"keyboard_shortcuts.up\": \"to move up in the list\",\n  \"lightbox.close\": \"Close\",\n  \"lightbox.next\": \"Next\",\n  \"lightbox.previous\": \"Previous\",\n  \"lightbox.view_context\": \"View context\",\n  \"lists.account.add\": \"Add to list\",\n  \"lists.account.remove\": \"Remove from list\",\n  \"lists.delete\": \"Delete list\",\n  \"lists.edit\": \"Edit list\",\n  \"lists.edit.submit\": \"Change title\",\n  \"lists.new.create\": \"Add list\",\n  \"lists.new.title_placeholder\": \"New list title\",\n  \"lists.search\": \"Search among people you follow\",\n  \"lists.subheading\": \"Your lists\",\n  \"loading_indicator.label\": \"Loading...\",\n  \"media_gallery.toggle_visible\": \"Toggle visibility\",\n  \"missing_indicator.label\": \"Not found\",\n  \"missing_indicator.sublabel\": \"This resource could not be found\",\n  \"mute_modal.hide_notifications\": \"Hide notifications from this user?\",\n  \"navigation_bar.apps\": \"Mobile apps\",\n  \"navigation_bar.blocks\": \"Blocked users\",\n  \"navigation_bar.community_timeline\": \"Local timeline\",\n  \"navigation_bar.compose\": \"Compose new toot\",\n  \"navigation_bar.direct\": \"Direct messages\",\n  \"navigation_bar.discover\": \"Discover\",\n  \"navigation_bar.domain_blocks\": \"Hidden domains\",\n  \"navigation_bar.edit_profile\": \"Edit profile\",\n  \"navigation_bar.favourites\": \"Favourites\",\n  \"navigation_bar.filters\": \"Muted words\",\n  \"navigation_bar.follow_requests\": \"Follow requests\",\n  \"navigation_bar.follows_and_followers\": \"Follows and followers\",\n  \"navigation_bar.info\": \"About this instance\",\n  \"navigation_bar.keyboard_shortcuts\": \"Hotkeys\",\n  \"navigation_bar.lists\": \"Lists\",\n  \"navigation_bar.logout\": \"Logout\",\n  \"navigation_bar.mutes\": \"Muted users\",\n  \"navigation_bar.personal\": \"Personal\",\n  \"navigation_bar.pins\": \"Pinned toots\",\n  \"navigation_bar.preferences\": \"Preferences\",\n  \"navigation_bar.profile_directory\": \"Profile directory\",\n  \"navigation_bar.public_timeline\": \"Federated timeline\",\n  \"navigation_bar.security\": \"Security\",\n  \"notification.favourite\": \"{name} favourited your status\",\n  \"notification.follow\": \"{name} followed you\",\n  \"notification.mention\": \"{name} mentioned you\",\n  \"notification.poll\": \"A poll you have voted in has ended\",\n  \"notification.reblog\": \"{name} boosted your status\",\n  \"notifications.clear\": \"Clear notifications\",\n  \"notifications.clear_confirmation\": \"Are you sure you want to permanently clear all your notifications?\",\n  \"notifications.column_settings.alert\": \"Desktop notifications\",\n  \"notifications.column_settings.favourite\": \"Favourites:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Display all categories\",\n  \"notifications.column_settings.filter_bar.category\": \"Quick filter bar\",\n  \"notifications.column_settings.filter_bar.show\": \"Show\",\n  \"notifications.column_settings.follow\": \"New followers:\",\n  \"notifications.column_settings.mention\": \"Mentions:\",\n  \"notifications.column_settings.poll\": \"Poll results:\",\n  \"notifications.column_settings.push\": \"Push notifications\",\n  \"notifications.column_settings.reblog\": \"Boosts:\",\n  \"notifications.column_settings.show\": \"Show in column\",\n  \"notifications.column_settings.sound\": \"Play sound\",\n  \"notifications.filter.all\": \"All\",\n  \"notifications.filter.boosts\": \"Boosts\",\n  \"notifications.filter.favourites\": \"Favourites\",\n  \"notifications.filter.follows\": \"Follows\",\n  \"notifications.filter.mentions\": \"Mentions\",\n  \"notifications.filter.polls\": \"Poll results\",\n  \"notifications.group\": \"{count} notifications\",\n  \"poll.closed\": \"Closed\",\n  \"poll.refresh\": \"Refresh\",\n  \"poll.total_votes\": \"{count, plural, one {# vote} other {# votes}}\",\n  \"poll.vote\": \"Vote\",\n  \"poll_button.add_poll\": \"Add a poll\",\n  \"poll_button.remove_poll\": \"Remove poll\",\n  \"privacy.change\": \"Adjust status privacy\",\n  \"privacy.direct.long\": \"Post to mentioned users only\",\n  \"privacy.direct.short\": \"Direct\",\n  \"privacy.private.long\": \"Post to followers only\",\n  \"privacy.private.short\": \"Followers-only\",\n  \"privacy.public.long\": \"Post to public timelines\",\n  \"privacy.public.short\": \"Public\",\n  \"privacy.unlisted.long\": \"Do not show in public timelines\",\n  \"privacy.unlisted.short\": \"Unlisted\",\n  \"regeneration_indicator.label\": \"Loading…\",\n  \"regeneration_indicator.sublabel\": \"Your home feed is being prepared!\",\n  \"relative_time.days\": \"{number}d\",\n  \"relative_time.hours\": \"{number}h\",\n  \"relative_time.just_now\": \"now\",\n  \"relative_time.minutes\": \"{number}m\",\n  \"relative_time.seconds\": \"{number}s\",\n  \"reply_indicator.cancel\": \"Cancel\",\n  \"report.forward\": \"Forward to {target}\",\n  \"report.forward_hint\": \"The account is from another server. Send an anonymized copy of the report there as well?\",\n  \"report.hint\": \"The report will be sent to your instance moderators. You can provide an explanation of why you are reporting this account below:\",\n  \"report.placeholder\": \"Additional comments\",\n  \"report.submit\": \"Submit\",\n  \"report.target\": \"Report {target}\",\n  \"search.placeholder\": \"Search\",\n  \"search_popout.search_format\": \"Advanced search format\",\n  \"search_popout.tips.full_text\": \"Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.\",\n  \"search_popout.tips.hashtag\": \"hashtag\",\n  \"search_popout.tips.status\": \"status\",\n  \"search_popout.tips.text\": \"Simple text returns matching display names, usernames and hashtags\",\n  \"search_popout.tips.user\": \"user\",\n  \"search_results.accounts\": \"People\",\n  \"search_results.hashtags\": \"Hashtags\",\n  \"search_results.statuses\": \"Toots\",\n  \"search_results.total\": \"{count, number} {count, plural, one {result} other {results}}\",\n  \"status.admin_account\": \"Open moderation interface for @{name}\",\n  \"status.admin_status\": \"Open this status in the moderation interface\",\n  \"status.block\": \"Block @{name}\",\n  \"status.cancel_reblog_private\": \"Unboost\",\n  \"status.cannot_reblog\": \"This post cannot be boosted\",\n  \"status.copy\": \"Copy link to status\",\n  \"status.delete\": \"Delete\",\n  \"status.detailed_status\": \"Detailed conversation view\",\n  \"status.direct\": \"Direct message @{name}\",\n  \"status.embed\": \"Embed\",\n  \"status.favourite\": \"Favourite\",\n  \"status.filtered\": \"Filtered\",\n  \"status.load_more\": \"Load more\",\n  \"status.media_hidden\": \"Media hidden\",\n  \"status.mention\": \"Mention @{name}\",\n  \"status.more\": \"More\",\n  \"status.mute\": \"Mute @{name}\",\n  \"status.mute_conversation\": \"Mute conversation\",\n  \"status.open\": \"Expand this status\",\n  \"status.pin\": \"Pin on profile\",\n  \"status.pinned\": \"Pinned toot\",\n  \"status.read_more\": \"Read more\",\n  \"status.reblog\": \"Boost\",\n  \"status.reblog_private\": \"Boost to original audience\",\n  \"status.reblogged_by\": \"{name} boosted\",\n  \"status.reblogs.empty\": \"No one has boosted this toot yet. When someone does, they will show up here.\",\n  \"status.redraft\": \"Delete & re-draft\",\n  \"status.reply\": \"Reply\",\n  \"status.replyAll\": \"Reply to thread\",\n  \"status.report\": \"Report @{name}\",\n  \"status.sensitive_warning\": \"Sensitive content\",\n  \"status.share\": \"Share\",\n  \"status.show_less\": \"Show less\",\n  \"status.show_less_all\": \"Show less for all\",\n  \"status.show_more\": \"Show more\",\n  \"status.show_more_all\": \"Show more for all\",\n  \"status.show_thread\": \"Show thread\",\n  \"status.unmute_conversation\": \"Unmute conversation\",\n  \"status.unpin\": \"Unpin from profile\",\n  \"suggestions.dismiss\": \"Dismiss suggestion\",\n  \"suggestions.header\": \"You might be interested in…\",\n  \"tabs_bar.federated_timeline\": \"Federated\",\n  \"tabs_bar.home\": \"Home\",\n  \"tabs_bar.local_timeline\": \"Local\",\n  \"tabs_bar.notifications\": \"Notifications\",\n  \"tabs_bar.search\": \"Search\",\n  \"time_remaining.days\": \"{number, plural, one {# day} other {# days}} left\",\n  \"time_remaining.hours\": \"{number, plural, one {# hour} other {# hours}} left\",\n  \"time_remaining.minutes\": \"{number, plural, one {# minute} other {# minutes}} left\",\n  \"time_remaining.moments\": \"Moments remaining\",\n  \"time_remaining.seconds\": \"{number, plural, one {# second} other {# seconds}} left\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {person} other {people}} talking\",\n  \"ui.beforeunload\": \"Your draft will be lost if you leave Mastodon.\",\n  \"upload_area.title\": \"Drag & drop to upload\",\n  \"upload_button.label\": \"Add media (JPEG, PNG, GIF, WebM, MP4, MOV)\",\n  \"upload_error.limit\": \"File upload limit exceeded.\",\n  \"upload_error.poll\": \"File upload not allowed with polls.\",\n  \"upload_form.description\": \"Describe for the visually impaired\",\n  \"upload_form.focus\": \"Crop\",\n  \"upload_form.undo\": \"Delete\",\n  \"upload_progress.label\": \"Uploading...\",\n  \"video.close\": \"Close video\",\n  \"video.exit_fullscreen\": \"Exit full screen\",\n  \"video.expand\": \"Expand video\",\n  \"video.fullscreen\": \"Full screen\",\n  \"video.hide\": \"Hide video\",\n  \"video.mute\": \"Mute sound\",\n  \"video.pause\": \"Pause\",\n  \"video.play\": \"Play\",\n  \"video.unmute\": \"Unmute sound\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/ms.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Add or Remove from lists\",\n  \"account.badges.bot\": \"Bot\",\n  \"account.block\": \"Block @{name}\",\n  \"account.block_domain\": \"Hide everything from {domain}\",\n  \"account.blocked\": \"Blocked\",\n  \"account.direct\": \"Direct message @{name}\",\n  \"account.domain_blocked\": \"Domain hidden\",\n  \"account.edit_profile\": \"Edit profile\",\n  \"account.endorse\": \"Feature on profile\",\n  \"account.follow\": \"Follow\",\n  \"account.followers\": \"Followers\",\n  \"account.followers.empty\": \"No one follows this user yet.\",\n  \"account.follows\": \"Follows\",\n  \"account.follows.empty\": \"This user doesn't follow anyone yet.\",\n  \"account.follows_you\": \"Follows you\",\n  \"account.hide_reblogs\": \"Hide boosts from @{name}\",\n  \"account.link_verified_on\": \"Ownership of this link was checked on {date}\",\n  \"account.locked_info\": \"This account privacy status is set to locked. The owner manually reviews who can follow them.\",\n  \"account.media\": \"Media\",\n  \"account.mention\": \"Mention @{name}\",\n  \"account.moved_to\": \"{name} has moved to:\",\n  \"account.mute\": \"Mute @{name}\",\n  \"account.mute_notifications\": \"Mute notifications from @{name}\",\n  \"account.muted\": \"Muted\",\n  \"account.posts\": \"Toots\",\n  \"account.posts_with_replies\": \"Toots and replies\",\n  \"account.report\": \"Report @{name}\",\n  \"account.requested\": \"Awaiting approval. Click to cancel follow request\",\n  \"account.share\": \"Share @{name}'s profile\",\n  \"account.show_reblogs\": \"Show boosts from @{name}\",\n  \"account.unblock\": \"Unblock @{name}\",\n  \"account.unblock_domain\": \"Unhide {domain}\",\n  \"account.unendorse\": \"Don't feature on profile\",\n  \"account.unfollow\": \"Unfollow\",\n  \"account.unmute\": \"Unmute @{name}\",\n  \"account.unmute_notifications\": \"Unmute notifications from @{name}\",\n  \"alert.unexpected.message\": \"An unexpected error occurred.\",\n  \"alert.unexpected.title\": \"Oops!\",\n  \"boost_modal.combo\": \"You can press {combo} to skip this next time\",\n  \"bundle_column_error.body\": \"Something went wrong while loading this component.\",\n  \"bundle_column_error.retry\": \"Try again\",\n  \"bundle_column_error.title\": \"Network error\",\n  \"bundle_modal_error.close\": \"Close\",\n  \"bundle_modal_error.message\": \"Something went wrong while loading this component.\",\n  \"bundle_modal_error.retry\": \"Try again\",\n  \"column.blocks\": \"Blocked users\",\n  \"column.community\": \"Local timeline\",\n  \"column.direct\": \"Direct messages\",\n  \"column.domain_blocks\": \"Hidden domains\",\n  \"column.favourites\": \"Favourites\",\n  \"column.follow_requests\": \"Follow requests\",\n  \"column.home\": \"Home\",\n  \"column.lists\": \"Lists\",\n  \"column.mutes\": \"Muted users\",\n  \"column.notifications\": \"Notifications\",\n  \"column.pins\": \"Pinned toot\",\n  \"column.public\": \"Federated timeline\",\n  \"column_back_button.label\": \"Back\",\n  \"column_header.hide_settings\": \"Hide settings\",\n  \"column_header.moveLeft_settings\": \"Move column to the left\",\n  \"column_header.moveRight_settings\": \"Move column to the right\",\n  \"column_header.pin\": \"Pin\",\n  \"column_header.show_settings\": \"Show settings\",\n  \"column_header.unpin\": \"Unpin\",\n  \"column_subheading.settings\": \"Settings\",\n  \"community.column_settings.media_only\": \"Media Only\",\n  \"compose_form.direct_message_warning\": \"This toot will only be sent to all the mentioned users.\",\n  \"compose_form.direct_message_warning_learn_more\": \"Learn more\",\n  \"compose_form.hashtag_warning\": \"This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.\",\n  \"compose_form.lock_disclaimer\": \"Your account is not {locked}. Anyone can follow you to view your follower-only posts.\",\n  \"compose_form.lock_disclaimer.lock\": \"locked\",\n  \"compose_form.placeholder\": \"What is on your mind?\",\n  \"compose_form.poll.add_option\": \"Add a choice\",\n  \"compose_form.poll.duration\": \"Poll duration\",\n  \"compose_form.poll.option_placeholder\": \"Choice {number}\",\n  \"compose_form.poll.remove_option\": \"Remove this choice\",\n  \"compose_form.publish\": \"Toot\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"Mark media as sensitive\",\n  \"compose_form.sensitive.marked\": \"Media is marked as sensitive\",\n  \"compose_form.sensitive.unmarked\": \"Media is not marked as sensitive\",\n  \"compose_form.spoiler.marked\": \"Text is hidden behind warning\",\n  \"compose_form.spoiler.unmarked\": \"Text is not hidden\",\n  \"compose_form.spoiler_placeholder\": \"Write your warning here\",\n  \"confirmation_modal.cancel\": \"Cancel\",\n  \"confirmations.block.block_and_report\": \"Block & Report\",\n  \"confirmations.block.confirm\": \"Block\",\n  \"confirmations.block.message\": \"Are you sure you want to block {name}?\",\n  \"confirmations.delete.confirm\": \"Delete\",\n  \"confirmations.delete.message\": \"Are you sure you want to delete this status?\",\n  \"confirmations.delete_list.confirm\": \"Delete\",\n  \"confirmations.delete_list.message\": \"Are you sure you want to permanently delete this list?\",\n  \"confirmations.domain_block.confirm\": \"Hide entire domain\",\n  \"confirmations.domain_block.message\": \"Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain in any public timelines or your notifications. Your followers from that domain will be removed.\",\n  \"confirmations.mute.confirm\": \"Mute\",\n  \"confirmations.mute.message\": \"Are you sure you want to mute {name}?\",\n  \"confirmations.redraft.confirm\": \"Delete & redraft\",\n  \"confirmations.redraft.message\": \"Are you sure you want to delete this status and re-draft it? Favourites and boosts will be lost, and replies to the original post will be orphaned.\",\n  \"confirmations.reply.confirm\": \"Reply\",\n  \"confirmations.reply.message\": \"Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?\",\n  \"confirmations.unfollow.confirm\": \"Unfollow\",\n  \"confirmations.unfollow.message\": \"Are you sure you want to unfollow {name}?\",\n  \"embed.instructions\": \"Embed this status on your website by copying the code below.\",\n  \"embed.preview\": \"Here is what it will look like:\",\n  \"emoji_button.activity\": \"Activity\",\n  \"emoji_button.custom\": \"Custom\",\n  \"emoji_button.flags\": \"Flags\",\n  \"emoji_button.food\": \"Food & Drink\",\n  \"emoji_button.label\": \"Insert emoji\",\n  \"emoji_button.nature\": \"Nature\",\n  \"emoji_button.not_found\": \"No emojos!! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"Objects\",\n  \"emoji_button.people\": \"People\",\n  \"emoji_button.recent\": \"Frequently used\",\n  \"emoji_button.search\": \"Search...\",\n  \"emoji_button.search_results\": \"Search results\",\n  \"emoji_button.symbols\": \"Symbols\",\n  \"emoji_button.travel\": \"Travel & Places\",\n  \"empty_column.account_timeline\": \"No toots here!\",\n  \"empty_column.account_unavailable\": \"Profile unavailable\",\n  \"empty_column.blocks\": \"You haven't blocked any users yet.\",\n  \"empty_column.community\": \"The local timeline is empty. Write something publicly to get the ball rolling!\",\n  \"empty_column.direct\": \"You don't have any direct messages yet. When you send or receive one, it will show up here.\",\n  \"empty_column.domain_blocks\": \"There are no hidden domains yet.\",\n  \"empty_column.favourited_statuses\": \"You don't have any favourite toots yet. When you favourite one, it will show up here.\",\n  \"empty_column.favourites\": \"No one has favourited this toot yet. When someone does, they will show up here.\",\n  \"empty_column.follow_requests\": \"You don't have any follow requests yet. When you receive one, it will show up here.\",\n  \"empty_column.hashtag\": \"There is nothing in this hashtag yet.\",\n  \"empty_column.home\": \"Your home timeline is empty! Visit {public} or use search to get started and meet other users.\",\n  \"empty_column.home.public_timeline\": \"the public timeline\",\n  \"empty_column.list\": \"There is nothing in this list yet. When members of this list post new statuses, they will appear here.\",\n  \"empty_column.lists\": \"You don't have any lists yet. When you create one, it will show up here.\",\n  \"empty_column.mutes\": \"You haven't muted any users yet.\",\n  \"empty_column.notifications\": \"You don't have any notifications yet. Interact with others to start the conversation.\",\n  \"empty_column.public\": \"There is nothing here! Write something publicly, or manually follow users from other instances to fill it up\",\n  \"follow_request.authorize\": \"Authorize\",\n  \"follow_request.reject\": \"Reject\",\n  \"getting_started.developers\": \"Developers\",\n  \"getting_started.directory\": \"Profile directory\",\n  \"getting_started.documentation\": \"Documentation\",\n  \"getting_started.heading\": \"Getting started\",\n  \"getting_started.invite\": \"Invite people\",\n  \"getting_started.open_source_notice\": \"Mastodon is open source software. You can contribute or report issues on GitHub at {github}.\",\n  \"getting_started.security\": \"Security\",\n  \"getting_started.terms\": \"Terms of service\",\n  \"hashtag.column_header.tag_mode.all\": \"and {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"or {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"without {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"No suggestions found\",\n  \"hashtag.column_settings.select.placeholder\": \"Enter hashtags…\",\n  \"hashtag.column_settings.tag_mode.all\": \"All of these\",\n  \"hashtag.column_settings.tag_mode.any\": \"Any of these\",\n  \"hashtag.column_settings.tag_mode.none\": \"None of these\",\n  \"hashtag.column_settings.tag_toggle\": \"Include additional tags in this column\",\n  \"home.column_settings.basic\": \"Basic\",\n  \"home.column_settings.show_reblogs\": \"Show boosts\",\n  \"home.column_settings.show_replies\": \"Show replies\",\n  \"intervals.full.days\": \"{number, plural, one {# day} other {# days}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# hour} other {# hours}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minute} other {# minutes}}\",\n  \"introduction.federation.action\": \"Next\",\n  \"introduction.federation.federated.headline\": \"Federated\",\n  \"introduction.federation.federated.text\": \"Public posts from other servers of the fediverse will appear in the federated timeline.\",\n  \"introduction.federation.home.headline\": \"Home\",\n  \"introduction.federation.home.text\": \"Posts from people you follow will appear in your home feed. You can follow anyone on any server!\",\n  \"introduction.federation.local.headline\": \"Local\",\n  \"introduction.federation.local.text\": \"Public posts from people on the same server as you will appear in the local timeline.\",\n  \"introduction.interactions.action\": \"Finish toot-orial!\",\n  \"introduction.interactions.favourite.headline\": \"Favourite\",\n  \"introduction.interactions.favourite.text\": \"You can save a toot for later, and let the author know that you liked it, by favouriting it.\",\n  \"introduction.interactions.reblog.headline\": \"Boost\",\n  \"introduction.interactions.reblog.text\": \"You can share other people's toots with your followers by boosting them.\",\n  \"introduction.interactions.reply.headline\": \"Reply\",\n  \"introduction.interactions.reply.text\": \"You can reply to other people's and your own toots, which will chain them together in a conversation.\",\n  \"introduction.welcome.action\": \"Let's go!\",\n  \"introduction.welcome.headline\": \"First steps\",\n  \"introduction.welcome.text\": \"Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.\",\n  \"keyboard_shortcuts.back\": \"to navigate back\",\n  \"keyboard_shortcuts.blocked\": \"to open blocked users list\",\n  \"keyboard_shortcuts.boost\": \"to boost\",\n  \"keyboard_shortcuts.column\": \"to focus a status in one of the columns\",\n  \"keyboard_shortcuts.compose\": \"to focus the compose textarea\",\n  \"keyboard_shortcuts.description\": \"Description\",\n  \"keyboard_shortcuts.direct\": \"to open direct messages column\",\n  \"keyboard_shortcuts.down\": \"to move down in the list\",\n  \"keyboard_shortcuts.enter\": \"to open status\",\n  \"keyboard_shortcuts.favourite\": \"to favourite\",\n  \"keyboard_shortcuts.favourites\": \"to open favourites list\",\n  \"keyboard_shortcuts.federated\": \"to open federated timeline\",\n  \"keyboard_shortcuts.heading\": \"Keyboard Shortcuts\",\n  \"keyboard_shortcuts.home\": \"to open home timeline\",\n  \"keyboard_shortcuts.hotkey\": \"Hotkey\",\n  \"keyboard_shortcuts.legend\": \"to display this legend\",\n  \"keyboard_shortcuts.local\": \"to open local timeline\",\n  \"keyboard_shortcuts.mention\": \"to mention author\",\n  \"keyboard_shortcuts.muted\": \"to open muted users list\",\n  \"keyboard_shortcuts.my_profile\": \"to open your profile\",\n  \"keyboard_shortcuts.notifications\": \"to open notifications column\",\n  \"keyboard_shortcuts.pinned\": \"to open pinned toots list\",\n  \"keyboard_shortcuts.profile\": \"to open author's profile\",\n  \"keyboard_shortcuts.reply\": \"to reply\",\n  \"keyboard_shortcuts.requests\": \"to open follow requests list\",\n  \"keyboard_shortcuts.search\": \"to focus search\",\n  \"keyboard_shortcuts.start\": \"to open \\\"get started\\\" column\",\n  \"keyboard_shortcuts.toggle_hidden\": \"to show/hide text behind CW\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"to show/hide media\",\n  \"keyboard_shortcuts.toot\": \"to start a brand new toot\",\n  \"keyboard_shortcuts.unfocus\": \"to un-focus compose textarea/search\",\n  \"keyboard_shortcuts.up\": \"to move up in the list\",\n  \"lightbox.close\": \"Close\",\n  \"lightbox.next\": \"Next\",\n  \"lightbox.previous\": \"Previous\",\n  \"lightbox.view_context\": \"View context\",\n  \"lists.account.add\": \"Add to list\",\n  \"lists.account.remove\": \"Remove from list\",\n  \"lists.delete\": \"Delete list\",\n  \"lists.edit\": \"Edit list\",\n  \"lists.edit.submit\": \"Change title\",\n  \"lists.new.create\": \"Add list\",\n  \"lists.new.title_placeholder\": \"New list title\",\n  \"lists.search\": \"Search among people you follow\",\n  \"lists.subheading\": \"Your lists\",\n  \"loading_indicator.label\": \"Loading...\",\n  \"media_gallery.toggle_visible\": \"Toggle visibility\",\n  \"missing_indicator.label\": \"Not found\",\n  \"missing_indicator.sublabel\": \"This resource could not be found\",\n  \"mute_modal.hide_notifications\": \"Hide notifications from this user?\",\n  \"navigation_bar.apps\": \"Mobile apps\",\n  \"navigation_bar.blocks\": \"Blocked users\",\n  \"navigation_bar.community_timeline\": \"Local timeline\",\n  \"navigation_bar.compose\": \"Compose new toot\",\n  \"navigation_bar.direct\": \"Direct messages\",\n  \"navigation_bar.discover\": \"Discover\",\n  \"navigation_bar.domain_blocks\": \"Hidden domains\",\n  \"navigation_bar.edit_profile\": \"Edit profile\",\n  \"navigation_bar.favourites\": \"Favourites\",\n  \"navigation_bar.filters\": \"Muted words\",\n  \"navigation_bar.follow_requests\": \"Follow requests\",\n  \"navigation_bar.follows_and_followers\": \"Follows and followers\",\n  \"navigation_bar.info\": \"About this instance\",\n  \"navigation_bar.keyboard_shortcuts\": \"Hotkeys\",\n  \"navigation_bar.lists\": \"Lists\",\n  \"navigation_bar.logout\": \"Logout\",\n  \"navigation_bar.mutes\": \"Muted users\",\n  \"navigation_bar.personal\": \"Personal\",\n  \"navigation_bar.pins\": \"Pinned toots\",\n  \"navigation_bar.preferences\": \"Preferences\",\n  \"navigation_bar.profile_directory\": \"Profile directory\",\n  \"navigation_bar.public_timeline\": \"Federated timeline\",\n  \"navigation_bar.security\": \"Security\",\n  \"notification.favourite\": \"{name} favourited your status\",\n  \"notification.follow\": \"{name} followed you\",\n  \"notification.mention\": \"{name} mentioned you\",\n  \"notification.poll\": \"A poll you have voted in has ended\",\n  \"notification.reblog\": \"{name} boosted your status\",\n  \"notifications.clear\": \"Clear notifications\",\n  \"notifications.clear_confirmation\": \"Are you sure you want to permanently clear all your notifications?\",\n  \"notifications.column_settings.alert\": \"Desktop notifications\",\n  \"notifications.column_settings.favourite\": \"Favourites:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Display all categories\",\n  \"notifications.column_settings.filter_bar.category\": \"Quick filter bar\",\n  \"notifications.column_settings.filter_bar.show\": \"Show\",\n  \"notifications.column_settings.follow\": \"New followers:\",\n  \"notifications.column_settings.mention\": \"Mentions:\",\n  \"notifications.column_settings.poll\": \"Poll results:\",\n  \"notifications.column_settings.push\": \"Push notifications\",\n  \"notifications.column_settings.reblog\": \"Boosts:\",\n  \"notifications.column_settings.show\": \"Show in column\",\n  \"notifications.column_settings.sound\": \"Play sound\",\n  \"notifications.filter.all\": \"All\",\n  \"notifications.filter.boosts\": \"Boosts\",\n  \"notifications.filter.favourites\": \"Favourites\",\n  \"notifications.filter.follows\": \"Follows\",\n  \"notifications.filter.mentions\": \"Mentions\",\n  \"notifications.filter.polls\": \"Poll results\",\n  \"notifications.group\": \"{count} notifications\",\n  \"poll.closed\": \"Closed\",\n  \"poll.refresh\": \"Refresh\",\n  \"poll.total_votes\": \"{count, plural, one {# vote} other {# votes}}\",\n  \"poll.vote\": \"Vote\",\n  \"poll_button.add_poll\": \"Add a poll\",\n  \"poll_button.remove_poll\": \"Remove poll\",\n  \"privacy.change\": \"Adjust status privacy\",\n  \"privacy.direct.long\": \"Post to mentioned users only\",\n  \"privacy.direct.short\": \"Direct\",\n  \"privacy.private.long\": \"Post to followers only\",\n  \"privacy.private.short\": \"Followers-only\",\n  \"privacy.public.long\": \"Post to public timelines\",\n  \"privacy.public.short\": \"Public\",\n  \"privacy.unlisted.long\": \"Do not show in public timelines\",\n  \"privacy.unlisted.short\": \"Unlisted\",\n  \"regeneration_indicator.label\": \"Loading…\",\n  \"regeneration_indicator.sublabel\": \"Your home feed is being prepared!\",\n  \"relative_time.days\": \"{number}d\",\n  \"relative_time.hours\": \"{number}h\",\n  \"relative_time.just_now\": \"now\",\n  \"relative_time.minutes\": \"{number}m\",\n  \"relative_time.seconds\": \"{number}s\",\n  \"reply_indicator.cancel\": \"Cancel\",\n  \"report.forward\": \"Forward to {target}\",\n  \"report.forward_hint\": \"The account is from another server. Send an anonymized copy of the report there as well?\",\n  \"report.hint\": \"The report will be sent to your instance moderators. You can provide an explanation of why you are reporting this account below:\",\n  \"report.placeholder\": \"Additional comments\",\n  \"report.submit\": \"Submit\",\n  \"report.target\": \"Report {target}\",\n  \"search.placeholder\": \"Search\",\n  \"search_popout.search_format\": \"Advanced search format\",\n  \"search_popout.tips.full_text\": \"Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.\",\n  \"search_popout.tips.hashtag\": \"hashtag\",\n  \"search_popout.tips.status\": \"status\",\n  \"search_popout.tips.text\": \"Simple text returns matching display names, usernames and hashtags\",\n  \"search_popout.tips.user\": \"user\",\n  \"search_results.accounts\": \"People\",\n  \"search_results.hashtags\": \"Hashtags\",\n  \"search_results.statuses\": \"Toots\",\n  \"search_results.total\": \"{count, number} {count, plural, one {result} other {results}}\",\n  \"status.admin_account\": \"Open moderation interface for @{name}\",\n  \"status.admin_status\": \"Open this status in the moderation interface\",\n  \"status.block\": \"Block @{name}\",\n  \"status.cancel_reblog_private\": \"Unboost\",\n  \"status.cannot_reblog\": \"This post cannot be boosted\",\n  \"status.copy\": \"Copy link to status\",\n  \"status.delete\": \"Delete\",\n  \"status.detailed_status\": \"Detailed conversation view\",\n  \"status.direct\": \"Direct message @{name}\",\n  \"status.embed\": \"Embed\",\n  \"status.favourite\": \"Favourite\",\n  \"status.filtered\": \"Filtered\",\n  \"status.load_more\": \"Load more\",\n  \"status.media_hidden\": \"Media hidden\",\n  \"status.mention\": \"Mention @{name}\",\n  \"status.more\": \"More\",\n  \"status.mute\": \"Mute @{name}\",\n  \"status.mute_conversation\": \"Mute conversation\",\n  \"status.open\": \"Expand this status\",\n  \"status.pin\": \"Pin on profile\",\n  \"status.pinned\": \"Pinned toot\",\n  \"status.read_more\": \"Read more\",\n  \"status.reblog\": \"Boost\",\n  \"status.reblog_private\": \"Boost to original audience\",\n  \"status.reblogged_by\": \"{name} boosted\",\n  \"status.reblogs.empty\": \"No one has boosted this toot yet. When someone does, they will show up here.\",\n  \"status.redraft\": \"Delete & re-draft\",\n  \"status.reply\": \"Reply\",\n  \"status.replyAll\": \"Reply to thread\",\n  \"status.report\": \"Report @{name}\",\n  \"status.sensitive_warning\": \"Sensitive content\",\n  \"status.share\": \"Share\",\n  \"status.show_less\": \"Show less\",\n  \"status.show_less_all\": \"Show less for all\",\n  \"status.show_more\": \"Show more\",\n  \"status.show_more_all\": \"Show more for all\",\n  \"status.show_thread\": \"Show thread\",\n  \"status.unmute_conversation\": \"Unmute conversation\",\n  \"status.unpin\": \"Unpin from profile\",\n  \"suggestions.dismiss\": \"Dismiss suggestion\",\n  \"suggestions.header\": \"You might be interested in…\",\n  \"tabs_bar.federated_timeline\": \"Federated\",\n  \"tabs_bar.home\": \"Home\",\n  \"tabs_bar.local_timeline\": \"Local\",\n  \"tabs_bar.notifications\": \"Notifications\",\n  \"tabs_bar.search\": \"Search\",\n  \"time_remaining.days\": \"{number, plural, one {# day} other {# days}} left\",\n  \"time_remaining.hours\": \"{number, plural, one {# hour} other {# hours}} left\",\n  \"time_remaining.minutes\": \"{number, plural, one {# minute} other {# minutes}} left\",\n  \"time_remaining.moments\": \"Moments remaining\",\n  \"time_remaining.seconds\": \"{number, plural, one {# second} other {# seconds}} left\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {person} other {people}} talking\",\n  \"ui.beforeunload\": \"Your draft will be lost if you leave Mastodon.\",\n  \"upload_area.title\": \"Drag & drop to upload\",\n  \"upload_button.label\": \"Add media (JPEG, PNG, GIF, WebM, MP4, MOV)\",\n  \"upload_error.limit\": \"File upload limit exceeded.\",\n  \"upload_error.poll\": \"File upload not allowed with polls.\",\n  \"upload_form.description\": \"Describe for the visually impaired\",\n  \"upload_form.focus\": \"Crop\",\n  \"upload_form.undo\": \"Delete\",\n  \"upload_progress.label\": \"Uploading...\",\n  \"video.close\": \"Close video\",\n  \"video.exit_fullscreen\": \"Exit full screen\",\n  \"video.expand\": \"Expand video\",\n  \"video.fullscreen\": \"Full screen\",\n  \"video.hide\": \"Hide video\",\n  \"video.mute\": \"Mute sound\",\n  \"video.pause\": \"Pause\",\n  \"video.play\": \"Play\",\n  \"video.unmute\": \"Unmute sound\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/nl.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Toevoegen of verwijderen vanuit lijsten\",\n  \"account.badges.bot\": \"Bot\",\n  \"account.block\": \"Blokkeer @{name}\",\n  \"account.block_domain\": \"Verberg alles van {domain}\",\n  \"account.blocked\": \"Geblokkeerd\",\n  \"account.direct\": \"Direct Message @{name}\",\n  \"account.domain_blocked\": \"Domein verborgen\",\n  \"account.edit_profile\": \"Profiel bewerken\",\n  \"account.endorse\": \"Op profiel weergeven\",\n  \"account.follow\": \"Volgen\",\n  \"account.followers\": \"Volgers\",\n  \"account.followers.empty\": \"Niemand volgt nog deze gebruiker.\",\n  \"account.follows\": \"Volgend\",\n  \"account.follows.empty\": \"Deze gebruiker volgt nog niemand.\",\n  \"account.follows_you\": \"Volgt jou\",\n  \"account.hide_reblogs\": \"Verberg boosts van @{name}\",\n  \"account.link_verified_on\": \"Eigendom van deze link is gecontroleerd op {date}\",\n  \"account.locked_info\": \"De privacystatus van dit account is op besloten gezet. De eigenaar bepaalt handmatig wie hen kan volgen.\",\n  \"account.media\": \"Media\",\n  \"account.mention\": \"Vermeld @{name}\",\n  \"account.moved_to\": \"{name} is verhuisd naar:\",\n  \"account.mute\": \"Negeer @{name}\",\n  \"account.mute_notifications\": \"Negeer meldingen van @{name}\",\n  \"account.muted\": \"Genegeerd\",\n  \"account.posts\": \"Toots\",\n  \"account.posts_with_replies\": \"Toots en reacties\",\n  \"account.report\": \"Rapporteer @{name}\",\n  \"account.requested\": \"Wacht op goedkeuring. Klik om het volgverzoek te annuleren\",\n  \"account.share\": \"Profiel van @{name} delen\",\n  \"account.show_reblogs\": \"Toon boosts van @{name}\",\n  \"account.unblock\": \"Deblokkeer @{name}\",\n  \"account.unblock_domain\": \"{domain} niet langer verbergen\",\n  \"account.unendorse\": \"Niet op profiel weergeven\",\n  \"account.unfollow\": \"Ontvolgen\",\n  \"account.unmute\": \"@{name} niet langer negeren\",\n  \"account.unmute_notifications\": \"@{name} meldingen niet langer negeren\",\n  \"alert.unexpected.message\": \"Er deed zich een onverwachte fout voor\",\n  \"alert.unexpected.title\": \"Oeps!\",\n  \"boost_modal.combo\": \"Je kunt {combo} klikken om dit de volgende keer over te slaan\",\n  \"bundle_column_error.body\": \"Tijdens het laden van dit onderdeel is er iets fout gegaan.\",\n  \"bundle_column_error.retry\": \"Opnieuw proberen\",\n  \"bundle_column_error.title\": \"Netwerkfout\",\n  \"bundle_modal_error.close\": \"Sluiten\",\n  \"bundle_modal_error.message\": \"Tijdens het laden van dit onderdeel is er iets fout gegaan.\",\n  \"bundle_modal_error.retry\": \"Opnieuw proberen\",\n  \"column.blocks\": \"Geblokkeerde gebruikers\",\n  \"column.community\": \"Lokale tijdlijn\",\n  \"column.direct\": \"Directe berichten\",\n  \"column.domain_blocks\": \"Genegeerde servers\",\n  \"column.favourites\": \"Favorieten\",\n  \"column.follow_requests\": \"Volgverzoeken\",\n  \"column.home\": \"Start\",\n  \"column.lists\": \"Lijsten\",\n  \"column.mutes\": \"Genegeerde gebruikers\",\n  \"column.notifications\": \"Meldingen\",\n  \"column.pins\": \"Vastgezette toots\",\n  \"column.public\": \"Globale tijdlijn\",\n  \"column_back_button.label\": \"Terug\",\n  \"column_header.hide_settings\": \"Instellingen verbergen\",\n  \"column_header.moveLeft_settings\": \"Kolom naar links verplaatsen\",\n  \"column_header.moveRight_settings\": \"Kolom naar rechts verplaatsen\",\n  \"column_header.pin\": \"Vastmaken\",\n  \"column_header.show_settings\": \"Instellingen tonen\",\n  \"column_header.unpin\": \"Losmaken\",\n  \"column_subheading.settings\": \"Instellingen\",\n  \"community.column_settings.media_only\": \"Alleen media\",\n  \"compose_form.direct_message_warning\": \"Deze toot wordt alleen naar vermelde gebruikers verstuurd. Echter, de beheerders en moderatoren van jouw en de ontvangende Mastodonserver(s) kunnen dit bericht mogelijk wel bekijken.\",\n  \"compose_form.direct_message_warning_learn_more\": \"Meer leren\",\n  \"compose_form.hashtag_warning\": \"Deze toot valt niet onder een hashtag te bekijken, omdat deze niet op openbare tijdlijnen wordt getoond. Alleen openbare toots kunnen via hashtags gevonden worden.\",\n  \"compose_form.lock_disclaimer\": \"Jouw account is niet {locked}. Iedereen kan jou volgen en kan de toots zien die je alleen aan jouw volgers hebt gericht.\",\n  \"compose_form.lock_disclaimer.lock\": \"besloten\",\n  \"compose_form.placeholder\": \"Wat wil je kwijt?\",\n  \"compose_form.poll.add_option\": \"Keuze toevoegen\",\n  \"compose_form.poll.duration\": \"Duur van de poll\",\n  \"compose_form.poll.option_placeholder\": \"Keuze {number}\",\n  \"compose_form.poll.remove_option\": \"Deze keuze verwijderen\",\n  \"compose_form.publish\": \"Toot\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"Media als gevoelig markeren\",\n  \"compose_form.sensitive.marked\": \"Media is als gevoelig gemarkeerd\",\n  \"compose_form.sensitive.unmarked\": \"Media is niet als gevoelig gemarkeerd\",\n  \"compose_form.spoiler.marked\": \"Tekst is achter een waarschuwing verborgen\",\n  \"compose_form.spoiler.unmarked\": \"Tekst is niet verborgen\",\n  \"compose_form.spoiler_placeholder\": \"Waarschuwingstekst\",\n  \"confirmation_modal.cancel\": \"Annuleren\",\n  \"confirmations.block.block_and_report\": \"Blokkeren en rapporteren\",\n  \"confirmations.block.confirm\": \"Blokkeren\",\n  \"confirmations.block.message\": \"Weet je het zeker dat je {name} wilt blokkeren?\",\n  \"confirmations.delete.confirm\": \"Verwijderen\",\n  \"confirmations.delete.message\": \"Weet je het zeker dat je deze toot wilt verwijderen?\",\n  \"confirmations.delete_list.confirm\": \"Verwijderen\",\n  \"confirmations.delete_list.message\": \"Weet je zeker dat je deze lijst definitief wilt verwijderen?\",\n  \"confirmations.domain_block.confirm\": \"Verberg alles van deze server\",\n  \"confirmations.domain_block.message\": \"Weet je het echt heel erg zeker dat je alles van {domain} wilt negeren? In de meeste gevallen is het blokkeren of negeren van een paar specifieke personen voldoende en beter. Je zult geen toots van deze server op openbare tijdlijnen zien of in jouw meldingen. Jouw volgers van deze server worden verwijderd.\",\n  \"confirmations.mute.confirm\": \"Negeren\",\n  \"confirmations.mute.message\": \"Weet je het zeker dat je {name} wilt negeren?\",\n  \"confirmations.redraft.confirm\": \"Verwijderen en herschrijven\",\n  \"confirmations.redraft.message\": \"Weet je zeker dat je deze toot wilt verwijderen en herschrijven? Je verliest wel de boosts en favorieten, en reacties op de originele toot zitten niet meer aan de nieuwe toot vast.\",\n  \"confirmations.reply.confirm\": \"Reageren\",\n  \"confirmations.reply.message\": \"Door nu te reageren overschrijf je de toot die je op dit moment aan het schrijven bent. Weet je zeker dat je verder wil gaan?\",\n  \"confirmations.unfollow.confirm\": \"Ontvolgen\",\n  \"confirmations.unfollow.message\": \"Weet je het zeker dat je {name} wilt ontvolgen?\",\n  \"embed.instructions\": \"Embed deze toot op jouw website, door de onderstaande code te kopiëren.\",\n  \"embed.preview\": \"Zo komt het eruit te zien:\",\n  \"emoji_button.activity\": \"Activiteiten\",\n  \"emoji_button.custom\": \"Lokale emoji’s\",\n  \"emoji_button.flags\": \"Vlaggen\",\n  \"emoji_button.food\": \"Eten en drinken\",\n  \"emoji_button.label\": \"Emoji toevoegen\",\n  \"emoji_button.nature\": \"Natuur\",\n  \"emoji_button.not_found\": \"Geen emoji’s!! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"Voorwerpen\",\n  \"emoji_button.people\": \"Mensen\",\n  \"emoji_button.recent\": \"Vaak gebruikt\",\n  \"emoji_button.search\": \"Zoeken...\",\n  \"emoji_button.search_results\": \"Zoekresultaten\",\n  \"emoji_button.symbols\": \"Symbolen\",\n  \"emoji_button.travel\": \"Reizen en plekken\",\n  \"empty_column.account_timeline\": \"Hier zijn geen toots!\",\n  \"empty_column.account_unavailable\": \"Profiel is niet beschikbaar\",\n  \"empty_column.blocks\": \"Jij hebt nog geen enkele gebruiker geblokkeerd.\",\n  \"empty_column.community\": \"De lokale tijdlijn is nog leeg. Toot iets in het openbaar om de bal aan het rollen te krijgen!\",\n  \"empty_column.direct\": \"Je hebt nog geen directe berichten. Wanneer je er een verzend of ontvangt, zijn deze hier te zien.\",\n  \"empty_column.domain_blocks\": \"Er zijn nog geen genegeerde servers.\",\n  \"empty_column.favourited_statuses\": \"Jij hebt nog geen favoriete toots. Wanneer je er een aan jouw favorieten toevoegt, valt deze hier te zien.\",\n  \"empty_column.favourites\": \"Niemand heeft deze toot nog aan hun favorieten toegevoegd. Wanneer iemand dit doet, valt dat hier te zien.\",\n  \"empty_column.follow_requests\": \"Jij hebt nog enkel volgverzoek ontvangen. Wanneer je er eentje ontvangt, valt dat hier te zien.\",\n  \"empty_column.hashtag\": \"Er is nog niks te vinden onder deze hashtag.\",\n  \"empty_column.home\": \"Jij volgt nog niemand. Bezoek {public} of gebruik het zoekvenster om andere mensen te ontmoeten.\",\n  \"empty_column.home.public_timeline\": \"de globale tijdlijn\",\n  \"empty_column.list\": \"Er is nog niks in deze lijst. Wanneer lijstleden nieuwe toots publiceren, zijn deze hier te zien.\",\n  \"empty_column.lists\": \"Jij hebt nog enkele lijst. Wanneer je er eentje hebt aangemaakt, valt deze hier te zien.\",\n  \"empty_column.mutes\": \"Jij hebt nog geen gebruikers genegeerd.\",\n  \"empty_column.notifications\": \"Je hebt nog geen meldingen. Begin met iemand een gesprek.\",\n  \"empty_column.public\": \"Er is hier helemaal niks! Toot iets in het openbaar of volg mensen van andere servers om het te vullen\",\n  \"follow_request.authorize\": \"Goedkeuren\",\n  \"follow_request.reject\": \"Afkeuren\",\n  \"getting_started.developers\": \"Ontwikkelaars\",\n  \"getting_started.directory\": \"Gebruikersgids\",\n  \"getting_started.documentation\": \"Documentatie\",\n  \"getting_started.heading\": \"Aan de slag\",\n  \"getting_started.invite\": \"Mensen uitnodigen\",\n  \"getting_started.open_source_notice\": \"Mastodon is vrije software. Je kunt bijdragen of problemen melden op GitHub via {github}.\",\n  \"getting_started.security\": \"Beveiliging\",\n  \"getting_started.terms\": \"Voorwaarden\",\n  \"hashtag.column_header.tag_mode.all\": \"en {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"of {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"zonder {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"Geen voorstellen gevonden\",\n  \"hashtag.column_settings.select.placeholder\": \"Vul hashtags in…\",\n  \"hashtag.column_settings.tag_mode.all\": \"Allemaal\",\n  \"hashtag.column_settings.tag_mode.any\": \"Een van deze\",\n  \"hashtag.column_settings.tag_mode.none\": \"Geen van deze\",\n  \"hashtag.column_settings.tag_toggle\": \"Additionele tags aan deze kolom toevoegen\",\n  \"home.column_settings.basic\": \"Algemeen\",\n  \"home.column_settings.show_reblogs\": \"Boosts tonen\",\n  \"home.column_settings.show_replies\": \"Reacties tonen\",\n  \"intervals.full.days\": \"{number, plural, one {# dag} other {# dagen}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# uur} other {# uur}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minuut} other {# minuten}}\",\n  \"introduction.federation.action\": \"Volgende\",\n  \"introduction.federation.federated.headline\": \"Globaal\",\n  \"introduction.federation.federated.text\": \"Openbare toots van mensen op andere servers in de fediverse verschijnen op de globale tijdlijn.\",\n  \"introduction.federation.home.headline\": \"Start\",\n  \"introduction.federation.home.text\": \"Toots van mensen die jij volgt verschijnen onder start. Je kunt iedereen op elke server volgen!\",\n  \"introduction.federation.local.headline\": \"Lokaal\",\n  \"introduction.federation.local.text\": \"Openbare toots van mensen die ook op jouw server zitten verschijnen op de lokale tijdlijn.\",\n  \"introduction.interactions.action\": \"Introductie beëindigen!\",\n  \"introduction.interactions.favourite.headline\": \"Favorieten\",\n  \"introduction.interactions.favourite.text\": \"Je kunt door een toot aan jouw favorieten toe te voegen, deze voor later bewaren en de auteur laten weten dat je de toot leuk vind.\",\n  \"introduction.interactions.reblog.headline\": \"Boosten\",\n  \"introduction.interactions.reblog.text\": \"Je kunt toots van andere mensen met jouw volgers delen door deze te boosten.\",\n  \"introduction.interactions.reply.headline\": \"Reageren\",\n  \"introduction.interactions.reply.text\": \"Je kunt op toots van andere mensen en op die van jezelf reageren, waardoor er een gesprek ontstaat.\",\n  \"introduction.welcome.action\": \"Laten we beginnen!\",\n  \"introduction.welcome.headline\": \"Eerste stappen\",\n  \"introduction.welcome.text\": \"Welkom in de fediverse! Binnen enkele ogenblikken kun jij berichten (toots) versturen en met vrienden op veel verschillende servers praten. Maar deze server, {domain}, is speciaal—het herbergt jouw profiel, onthou dus de naam.\",\n  \"keyboard_shortcuts.back\": \"om terug te gaan\",\n  \"keyboard_shortcuts.blocked\": \"om de door jou geblokkeerde gebruikers te tonen\",\n  \"keyboard_shortcuts.boost\": \"om te boosten\",\n  \"keyboard_shortcuts.column\": \"om op een toot te focussen in één van de kolommen\",\n  \"keyboard_shortcuts.compose\": \"om het tekstvak voor toots te focussen\",\n  \"keyboard_shortcuts.description\": \"Omschrijving\",\n  \"keyboard_shortcuts.direct\": \"om jouw directe berichten te tonen\",\n  \"keyboard_shortcuts.down\": \"om naar beneden door de lijst te bewegen\",\n  \"keyboard_shortcuts.enter\": \"om toot volledig te tonen\",\n  \"keyboard_shortcuts.favourite\": \"om aan jouw favorieten toe te voegen\",\n  \"keyboard_shortcuts.favourites\": \"om jouw lijst met favorieten te tonen\",\n  \"keyboard_shortcuts.federated\": \"om de globale tijdlijn te tonen\",\n  \"keyboard_shortcuts.heading\": \"Sneltoetsen\",\n  \"keyboard_shortcuts.home\": \"om jouw starttijdlijn te tonen\",\n  \"keyboard_shortcuts.hotkey\": \"Sneltoets\",\n  \"keyboard_shortcuts.legend\": \"om deze legenda te tonen\",\n  \"keyboard_shortcuts.local\": \"om de lokale tijdlijn te tonen\",\n  \"keyboard_shortcuts.mention\": \"om de auteur te vermelden\",\n  \"keyboard_shortcuts.muted\": \"om de door jou genegeerde gebruikers te tonen\",\n  \"keyboard_shortcuts.my_profile\": \"om jouw profiel te tonen\",\n  \"keyboard_shortcuts.notifications\": \"om jouw meldingen te tonen\",\n  \"keyboard_shortcuts.pinned\": \"om jouw vastgezette toots te tonen\",\n  \"keyboard_shortcuts.profile\": \"om het gebruikersprofiel te openen\",\n  \"keyboard_shortcuts.reply\": \"om te reageren\",\n  \"keyboard_shortcuts.requests\": \"om jouw volgverzoeken te tonen\",\n  \"keyboard_shortcuts.search\": \"om het zoekvak te focussen\",\n  \"keyboard_shortcuts.start\": \"om de \\\"Aan de slag\\\"-kolom te tonen\",\n  \"keyboard_shortcuts.toggle_hidden\": \"om tekst achter een waarschuwing (CW) te tonen/verbergen\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"om media te tonen/verbergen\",\n  \"keyboard_shortcuts.toot\": \"om een nieuwe toot te starten\",\n  \"keyboard_shortcuts.unfocus\": \"om het tekst- en zoekvak te ontfocussen\",\n  \"keyboard_shortcuts.up\": \"om omhoog te bewegen in de lijst\",\n  \"lightbox.close\": \"Sluiten\",\n  \"lightbox.next\": \"Volgende\",\n  \"lightbox.previous\": \"Vorige\",\n  \"lightbox.view_context\": \"Context tonen\",\n  \"lists.account.add\": \"Aan lijst toevoegen\",\n  \"lists.account.remove\": \"Uit lijst verwijderen\",\n  \"lists.delete\": \"Lijst verwijderen\",\n  \"lists.edit\": \"Lijst bewerken\",\n  \"lists.edit.submit\": \"Titel veranderen\",\n  \"lists.new.create\": \"Lijst toevoegen\",\n  \"lists.new.title_placeholder\": \"Naam nieuwe lijst\",\n  \"lists.search\": \"Zoek naar mensen die je volgt\",\n  \"lists.subheading\": \"Jouw lijsten\",\n  \"loading_indicator.label\": \"Laden…\",\n  \"media_gallery.toggle_visible\": \"Media wel/niet tonen\",\n  \"missing_indicator.label\": \"Niet gevonden\",\n  \"missing_indicator.sublabel\": \"Deze hulpbron kan niet gevonden worden\",\n  \"mute_modal.hide_notifications\": \"Verberg meldingen van deze persoon?\",\n  \"navigation_bar.apps\": \"Mobiele apps\",\n  \"navigation_bar.blocks\": \"Geblokkeerde gebruikers\",\n  \"navigation_bar.community_timeline\": \"Lokale tijdlijn\",\n  \"navigation_bar.compose\": \"Nieuw toot schrijven\",\n  \"navigation_bar.direct\": \"Directe berichten\",\n  \"navigation_bar.discover\": \"Ontdekken\",\n  \"navigation_bar.domain_blocks\": \"Genegeerde servers\",\n  \"navigation_bar.edit_profile\": \"Profiel bewerken\",\n  \"navigation_bar.favourites\": \"Favorieten\",\n  \"navigation_bar.filters\": \"Filters\",\n  \"navigation_bar.follow_requests\": \"Volgverzoeken\",\n  \"navigation_bar.follows_and_followers\": \"Volgers en gevolgden\",\n  \"navigation_bar.info\": \"Over deze server\",\n  \"navigation_bar.keyboard_shortcuts\": \"Sneltoetsen\",\n  \"navigation_bar.lists\": \"Lijsten\",\n  \"navigation_bar.logout\": \"Uitloggen\",\n  \"navigation_bar.mutes\": \"Genegeerde gebruikers\",\n  \"navigation_bar.personal\": \"Persoonlijk\",\n  \"navigation_bar.pins\": \"Vastgezette toots\",\n  \"navigation_bar.preferences\": \"Instellingen\",\n  \"navigation_bar.profile_directory\": \"Gebruikersgids\",\n  \"navigation_bar.public_timeline\": \"Globale tijdlijn\",\n  \"navigation_bar.security\": \"Beveiliging\",\n  \"notification.favourite\": \"{name} voegde jouw toot als favoriet toe\",\n  \"notification.follow\": \"{name} volgt jou nu\",\n  \"notification.mention\": \"{name} vermeldde jou\",\n  \"notification.poll\": \"Een poll waaraan jij hebt meegedaan is beëindigd\",\n  \"notification.reblog\": \"{name} boostte jouw toot\",\n  \"notifications.clear\": \"Meldingen verwijderen\",\n  \"notifications.clear_confirmation\": \"Weet je het zeker dat je al jouw meldingen wilt verwijderen?\",\n  \"notifications.column_settings.alert\": \"Desktopmeldingen\",\n  \"notifications.column_settings.favourite\": \"Favorieten:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Alle categorieën tonen\",\n  \"notifications.column_settings.filter_bar.category\": \"Snelle filterbalk\",\n  \"notifications.column_settings.filter_bar.show\": \"Tonen\",\n  \"notifications.column_settings.follow\": \"Nieuwe volgers:\",\n  \"notifications.column_settings.mention\": \"Vermeldingen:\",\n  \"notifications.column_settings.poll\": \"Pollresultaten:\",\n  \"notifications.column_settings.push\": \"Pushmeldingen\",\n  \"notifications.column_settings.reblog\": \"Boosts:\",\n  \"notifications.column_settings.show\": \"In kolom tonen\",\n  \"notifications.column_settings.sound\": \"Geluid afspelen\",\n  \"notifications.filter.all\": \"Alles\",\n  \"notifications.filter.boosts\": \"Boosts\",\n  \"notifications.filter.favourites\": \"Favorieten\",\n  \"notifications.filter.follows\": \"Die jij volgt\",\n  \"notifications.filter.mentions\": \"Vermeldingen\",\n  \"notifications.filter.polls\": \"Pollresultaten\",\n  \"notifications.group\": \"{count} meldingen\",\n  \"poll.closed\": \"Gesloten\",\n  \"poll.refresh\": \"Vernieuwen\",\n  \"poll.total_votes\": \"{count, plural, one {# stem} other {# stemmen}}\",\n  \"poll.vote\": \"Stemmen\",\n  \"poll_button.add_poll\": \"Poll toevoegen\",\n  \"poll_button.remove_poll\": \"Poll verwijderen\",\n  \"privacy.change\": \"Zichtbaarheid toot aanpassen\",\n  \"privacy.direct.long\": \"Alleen aan vermelde gebruikers tonen\",\n  \"privacy.direct.short\": \"Direct\",\n  \"privacy.private.long\": \"Alleen aan volgers tonen\",\n  \"privacy.private.short\": \"Alleen volgers\",\n  \"privacy.public.long\": \"Op openbare tijdlijnen tonen\",\n  \"privacy.public.short\": \"Openbaar\",\n  \"privacy.unlisted.long\": \"Niet op openbare tijdlijnen tonen\",\n  \"privacy.unlisted.short\": \"Minder openbaar\",\n  \"regeneration_indicator.label\": \"Aan het laden…\",\n  \"regeneration_indicator.sublabel\": \"Jouw tijdlijn wordt aangemaakt!\",\n  \"relative_time.days\": \"{number}d\",\n  \"relative_time.hours\": \"{number}u\",\n  \"relative_time.just_now\": \"nu\",\n  \"relative_time.minutes\": \"{number}m\",\n  \"relative_time.seconds\": \"{number}s\",\n  \"reply_indicator.cancel\": \"Annuleren\",\n  \"report.forward\": \"Doorsturen naar {target}\",\n  \"report.forward_hint\": \"Het account bevindt zich op een andere server. Stuur daar eveneens een geanonimiseerde kopie van de rapportage naartoe?\",\n  \"report.hint\": \"De rapportage wordt naar de moderatoren van jouw server gestuurd. Je kunt hieronder een uitleg geven waarom je dit account rapporteert:\",\n  \"report.placeholder\": \"Extra opmerkingen\",\n  \"report.submit\": \"Verzenden\",\n  \"report.target\": \"Rapporteer {target}\",\n  \"search.placeholder\": \"Zoeken\",\n  \"search_popout.search_format\": \"Geavanceerd zoeken\",\n  \"search_popout.tips.full_text\": \"Gebruik gewone tekst om te zoeken in jouw toots, gebooste toots, favorieten en in toots waarin jij bent vermeldt, en tevens naar gebruikersnamen, weergavenamen en hashtags.\",\n  \"search_popout.tips.hashtag\": \"hashtag\",\n  \"search_popout.tips.status\": \"toot\",\n  \"search_popout.tips.text\": \"Gebruik gewone tekst om te zoeken op weergavenamen, gebruikersnamen en hashtags\",\n  \"search_popout.tips.user\": \"gebruiker\",\n  \"search_results.accounts\": \"Gebruikers\",\n  \"search_results.hashtags\": \"Hashtags\",\n  \"search_results.statuses\": \"Toots\",\n  \"search_results.total\": \"{count, number} {count, plural, one {resultaat} other {resultaten}}\",\n  \"status.admin_account\": \"Moderatie-omgeving van @{name} openen\",\n  \"status.admin_status\": \"Deze toot in de moderatie-omgeving openen\",\n  \"status.block\": \"Blokkeer @{name}\",\n  \"status.cancel_reblog_private\": \"Niet langer boosten\",\n  \"status.cannot_reblog\": \"Deze toot kan niet geboost worden\",\n  \"status.copy\": \"Link naar toot kopiëren\",\n  \"status.delete\": \"Verwijderen\",\n  \"status.detailed_status\": \"Uitgebreide gespreksweergave\",\n  \"status.direct\": \"Directe toot @{name}\",\n  \"status.embed\": \"Insluiten\",\n  \"status.favourite\": \"Favoriet\",\n  \"status.filtered\": \"Gefilterd\",\n  \"status.load_more\": \"Meer laden\",\n  \"status.media_hidden\": \"Media verborgen\",\n  \"status.mention\": \"Vermeld @{name}\",\n  \"status.more\": \"Meer\",\n  \"status.mute\": \"Negeer @{name}\",\n  \"status.mute_conversation\": \"Negeer gesprek\",\n  \"status.open\": \"Toot volledig tonen\",\n  \"status.pin\": \"Aan profielpagina vastmaken\",\n  \"status.pinned\": \"Vastgemaakte toot\",\n  \"status.read_more\": \"Meer lezen\",\n  \"status.reblog\": \"Boosten\",\n  \"status.reblog_private\": \"Boost naar oorspronkelijke ontvangers\",\n  \"status.reblogged_by\": \"{name} boostte\",\n  \"status.reblogs.empty\": \"Niemand heeft deze toot nog geboost. Wanneer iemand dit doet, valt dat hier te zien.\",\n  \"status.redraft\": \"Verwijderen en herschrijven\",\n  \"status.reply\": \"Reageren\",\n  \"status.replyAll\": \"Reageer op iedereen\",\n  \"status.report\": \"Rapporteer @{name}\",\n  \"status.sensitive_warning\": \"Gevoelige inhoud\",\n  \"status.share\": \"Delen\",\n  \"status.show_less\": \"Minder tonen\",\n  \"status.show_less_all\": \"Alles minder tonen\",\n  \"status.show_more\": \"Meer tonen\",\n  \"status.show_more_all\": \"Alles meer tonen\",\n  \"status.show_thread\": \"Gesprek tonen\",\n  \"status.unmute_conversation\": \"Gesprek niet langer negeren\",\n  \"status.unpin\": \"Van profielpagina losmaken\",\n  \"suggestions.dismiss\": \"Voorstel verwerpen\",\n  \"suggestions.header\": \"Je bent waarschijnlijk ook geïnteresseerd in…\",\n  \"tabs_bar.federated_timeline\": \"Globaal\",\n  \"tabs_bar.home\": \"Start\",\n  \"tabs_bar.local_timeline\": \"Lokaal\",\n  \"tabs_bar.notifications\": \"Meldingen\",\n  \"tabs_bar.search\": \"Zoeken\",\n  \"time_remaining.days\": \"{number, plural, one {# dag} other {# dagen}} left\",\n  \"time_remaining.hours\": \"{number, plural, one {# uur} other {# uur}} left\",\n  \"time_remaining.minutes\": \"{number, plural, one {# minuut} other {# minuten}} left\",\n  \"time_remaining.moments\": \"Nog enkele ogenblikken resterend\",\n  \"time_remaining.seconds\": \"{number, plural, one {# seconde} other {# seconden}} left\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {persoon praat} other {mensen praten}} hierover\",\n  \"ui.beforeunload\": \"Je concept zal verloren gaan als je Mastodon verlaat.\",\n  \"upload_area.title\": \"Hierin slepen om te uploaden\",\n  \"upload_button.label\": \"Media toevoegen (JPEG, PNG, GIF, WebM, MP4, MOV)\",\n  \"upload_error.limit\": \"Uploadlimiet van bestand overschreden.\",\n  \"upload_error.poll\": \"Het uploaden van bestanden is in polls niet toegestaan.\",\n  \"upload_form.description\": \"Omschrijf dit voor mensen met een visuele beperking\",\n  \"upload_form.focus\": \"Voorvertoning aanpassen\",\n  \"upload_form.undo\": \"Verwijderen\",\n  \"upload_progress.label\": \"Uploaden...\",\n  \"video.close\": \"Video sluiten\",\n  \"video.exit_fullscreen\": \"Volledig scherm sluiten\",\n  \"video.expand\": \"Video groter maken\",\n  \"video.fullscreen\": \"Volledig scherm\",\n  \"video.hide\": \"Video verbergen\",\n  \"video.mute\": \"Geluid uitschakelen\",\n  \"video.pause\": \"Pauze\",\n  \"video.play\": \"Afspelen\",\n  \"video.unmute\": \"Geluid inschakelen\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/no.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Add or Remove from lists\",\n  \"account.badges.bot\": \"Bot\",\n  \"account.block\": \"Blokkér @{name}\",\n  \"account.block_domain\": \"Skjul alt fra {domain}\",\n  \"account.blocked\": \"Blocked\",\n  \"account.direct\": \"Direct Message @{name}\",\n  \"account.domain_blocked\": \"Domain hidden\",\n  \"account.edit_profile\": \"Rediger profil\",\n  \"account.endorse\": \"Feature on profile\",\n  \"account.follow\": \"Følg\",\n  \"account.followers\": \"Følgere\",\n  \"account.followers.empty\": \"No one follows this user yet.\",\n  \"account.follows\": \"Følger\",\n  \"account.follows.empty\": \"This user doesn't follow anyone yet.\",\n  \"account.follows_you\": \"Følger deg\",\n  \"account.hide_reblogs\": \"Skjul fremhevinger fra @{name}\",\n  \"account.link_verified_on\": \"Ownership of this link was checked on {date}\",\n  \"account.locked_info\": \"This account privacy status is set to locked. The owner manually reviews who can follow them.\",\n  \"account.media\": \"Media\",\n  \"account.mention\": \"Nevn @{name}\",\n  \"account.moved_to\": \"{name} har flyttet til:\",\n  \"account.mute\": \"Demp @{name}\",\n  \"account.mute_notifications\": \"Ignorer varsler fra @{name}\",\n  \"account.muted\": \"Muted\",\n  \"account.posts\": \"Innlegg\",\n  \"account.posts_with_replies\": \"Toots with replies\",\n  \"account.report\": \"Rapportér @{name}\",\n  \"account.requested\": \"Venter på godkjennelse\",\n  \"account.share\": \"Del @{name}s profil\",\n  \"account.show_reblogs\": \"Vis boosts fra @{name}\",\n  \"account.unblock\": \"Avblokker @{name}\",\n  \"account.unblock_domain\": \"Vis {domain}\",\n  \"account.unendorse\": \"Don't feature on profile\",\n  \"account.unfollow\": \"Avfølg\",\n  \"account.unmute\": \"Avdemp @{name}\",\n  \"account.unmute_notifications\": \"Vis varsler fra @{name}\",\n  \"alert.unexpected.message\": \"An unexpected error occurred.\",\n  \"alert.unexpected.title\": \"Oops!\",\n  \"boost_modal.combo\": \"You kan trykke {combo} for å hoppe over dette neste gang\",\n  \"bundle_column_error.body\": \"Noe gikk galt mens denne komponenten lastet.\",\n  \"bundle_column_error.retry\": \"Prøv igjen\",\n  \"bundle_column_error.title\": \"Network error\",\n  \"bundle_modal_error.close\": \"Lukk\",\n  \"bundle_modal_error.message\": \"Noe gikk galt da denne komponenten lastet.\",\n  \"bundle_modal_error.retry\": \"Prøv igjen\",\n  \"column.blocks\": \"Blokkerte brukere\",\n  \"column.community\": \"Lokal tidslinje\",\n  \"column.direct\": \"Direct messages\",\n  \"column.domain_blocks\": \"Hidden domains\",\n  \"column.favourites\": \"Likt\",\n  \"column.follow_requests\": \"Følgeforespørsler\",\n  \"column.home\": \"Hjem\",\n  \"column.lists\": \"Lister\",\n  \"column.mutes\": \"Dempede brukere\",\n  \"column.notifications\": \"Varsler\",\n  \"column.pins\": \"Pinned toot\",\n  \"column.public\": \"Felles tidslinje\",\n  \"column_back_button.label\": \"Tilbake\",\n  \"column_header.hide_settings\": \"Gjem  innstillinger\",\n  \"column_header.moveLeft_settings\": \"Flytt feltet til venstre\",\n  \"column_header.moveRight_settings\": \"Flytt feltet til høyre\",\n  \"column_header.pin\": \"Fest\",\n  \"column_header.show_settings\": \"Vis innstillinger\",\n  \"column_header.unpin\": \"Løsne\",\n  \"column_subheading.settings\": \"Innstillinger\",\n  \"community.column_settings.media_only\": \"Media Only\",\n  \"compose_form.direct_message_warning\": \"This toot will only be visible to all the mentioned users.\",\n  \"compose_form.direct_message_warning_learn_more\": \"Learn more\",\n  \"compose_form.hashtag_warning\": \"Denne tuten blir ikke listet under noen emneknagger da den er ulistet. Kun offentlige tuter kan søktes etter med emneknagg.\",\n  \"compose_form.lock_disclaimer\": \"Din konto er ikke {locked}. Hvem som helst kan følge deg og se dine private poster.\",\n  \"compose_form.lock_disclaimer.lock\": \"låst\",\n  \"compose_form.placeholder\": \"Hva har du på hjertet?\",\n  \"compose_form.poll.add_option\": \"Add a choice\",\n  \"compose_form.poll.duration\": \"Poll duration\",\n  \"compose_form.poll.option_placeholder\": \"Choice {number}\",\n  \"compose_form.poll.remove_option\": \"Remove this choice\",\n  \"compose_form.publish\": \"Tut\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"Mark media as sensitive\",\n  \"compose_form.sensitive.marked\": \"Media is marked as sensitive\",\n  \"compose_form.sensitive.unmarked\": \"Media is not marked as sensitive\",\n  \"compose_form.spoiler.marked\": \"Text is hidden behind warning\",\n  \"compose_form.spoiler.unmarked\": \"Text is not hidden\",\n  \"compose_form.spoiler_placeholder\": \"Innholdsadvarsel\",\n  \"confirmation_modal.cancel\": \"Avbryt\",\n  \"confirmations.block.block_and_report\": \"Block & Report\",\n  \"confirmations.block.confirm\": \"Blokkèr\",\n  \"confirmations.block.message\": \"Er du sikker på at du vil blokkere {name}?\",\n  \"confirmations.delete.confirm\": \"Slett\",\n  \"confirmations.delete.message\": \"Er du sikker på at du vil slette denne statusen?\",\n  \"confirmations.delete_list.confirm\": \"Delete\",\n  \"confirmations.delete_list.message\": \"Er du sikker på at du vil slette denne listen permanent?\",\n  \"confirmations.domain_block.confirm\": \"Skjul alt fra domenet\",\n  \"confirmations.domain_block.message\": \"Er du sikker på at du vil skjule hele domenet {domain}? I de fleste tilfeller er det bedre med målrettet blokkering eller demping.\",\n  \"confirmations.mute.confirm\": \"Demp\",\n  \"confirmations.mute.message\": \"Er du sikker på at du vil dempe {name}?\",\n  \"confirmations.redraft.confirm\": \"Delete & redraft\",\n  \"confirmations.redraft.message\": \"Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.\",\n  \"confirmations.reply.confirm\": \"Reply\",\n  \"confirmations.reply.message\": \"Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?\",\n  \"confirmations.unfollow.confirm\": \"Slutt å følge\",\n  \"confirmations.unfollow.message\": \"Er du sikker på at du vil slutte å følge {name}?\",\n  \"embed.instructions\": \"Kopier koden under for å bygge inn denne statusen på hjemmesiden din.\",\n  \"embed.preview\": \"Slik kommer det til å se ut:\",\n  \"emoji_button.activity\": \"Aktivitet\",\n  \"emoji_button.custom\": \"Tilpasset\",\n  \"emoji_button.flags\": \"Flagg\",\n  \"emoji_button.food\": \"Mat og drikke\",\n  \"emoji_button.label\": \"Sett inn emoji\",\n  \"emoji_button.nature\": \"Natur\",\n  \"emoji_button.not_found\": \"Ingen emojojoer!! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"Objekter\",\n  \"emoji_button.people\": \"Mennesker\",\n  \"emoji_button.recent\": \"Hyppig brukt\",\n  \"emoji_button.search\": \"Søk...\",\n  \"emoji_button.search_results\": \"Søkeresultat\",\n  \"emoji_button.symbols\": \"Symboler\",\n  \"emoji_button.travel\": \"Reise & steder\",\n  \"empty_column.account_timeline\": \"No toots here!\",\n  \"empty_column.account_unavailable\": \"Profile unavailable\",\n  \"empty_column.blocks\": \"You haven't blocked any users yet.\",\n  \"empty_column.community\": \"Den lokale tidslinjen er tom. Skriv noe offentlig for å få snøballen til å rulle!\",\n  \"empty_column.direct\": \"You don't have any direct messages yet. When you send or receive one, it will show up here.\",\n  \"empty_column.domain_blocks\": \"There are no hidden domains yet.\",\n  \"empty_column.favourited_statuses\": \"You don't have any favourite toots yet. When you favourite one, it will show up here.\",\n  \"empty_column.favourites\": \"No one has favourited this toot yet. When someone does, they will show up here.\",\n  \"empty_column.follow_requests\": \"You don't have any follow requests yet. When you receive one, it will show up here.\",\n  \"empty_column.hashtag\": \"Det er ingenting i denne hashtagen ennå.\",\n  \"empty_column.home\": \"Du har ikke fulgt noen ennå. Besøk {publlic} eller bruk søk for å komme i gang og møte andre brukere.\",\n  \"empty_column.home.public_timeline\": \"en offentlig tidslinje\",\n  \"empty_column.list\": \"Det er ingenting i denne listen ennå. Når medlemmene av denne listen legger ut nye statuser vil de dukke opp her.\",\n  \"empty_column.lists\": \"You don't have any lists yet. When you create one, it will show up here.\",\n  \"empty_column.mutes\": \"You haven't muted any users yet.\",\n  \"empty_column.notifications\": \"Du har ingen varsler ennå. Kommuniser med andre for å begynne samtalen.\",\n  \"empty_column.public\": \"Det er ingenting her! Skriv noe offentlig, eller følg brukere manuelt fra andre instanser for å fylle den opp\",\n  \"follow_request.authorize\": \"Autorisér\",\n  \"follow_request.reject\": \"Avvis\",\n  \"getting_started.developers\": \"Developers\",\n  \"getting_started.directory\": \"Profile directory\",\n  \"getting_started.documentation\": \"Documentation\",\n  \"getting_started.heading\": \"Kom i gang\",\n  \"getting_started.invite\": \"Invite people\",\n  \"getting_started.open_source_notice\": \"Mastodon er fri programvare. Du kan bidra eller rapportere problemer på GitHub på {github}.\",\n  \"getting_started.security\": \"Security\",\n  \"getting_started.terms\": \"Terms of service\",\n  \"hashtag.column_header.tag_mode.all\": \"and {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"or {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"without {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"No suggestions found\",\n  \"hashtag.column_settings.select.placeholder\": \"Enter hashtags…\",\n  \"hashtag.column_settings.tag_mode.all\": \"All of these\",\n  \"hashtag.column_settings.tag_mode.any\": \"Any of these\",\n  \"hashtag.column_settings.tag_mode.none\": \"None of these\",\n  \"hashtag.column_settings.tag_toggle\": \"Include additional tags in this column\",\n  \"home.column_settings.basic\": \"Enkel\",\n  \"home.column_settings.show_reblogs\": \"Vis fremhevinger\",\n  \"home.column_settings.show_replies\": \"Vis svar\",\n  \"intervals.full.days\": \"{number, plural, one {# day} other {# days}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# hour} other {# hours}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minute} other {# minutes}}\",\n  \"introduction.federation.action\": \"Next\",\n  \"introduction.federation.federated.headline\": \"Federated\",\n  \"introduction.federation.federated.text\": \"Public posts from other servers of the fediverse will appear in the federated timeline.\",\n  \"introduction.federation.home.headline\": \"Home\",\n  \"introduction.federation.home.text\": \"Posts from people you follow will appear in your home feed. You can follow anyone on any server!\",\n  \"introduction.federation.local.headline\": \"Local\",\n  \"introduction.federation.local.text\": \"Public posts from people on the same server as you will appear in the local timeline.\",\n  \"introduction.interactions.action\": \"Finish toot-orial!\",\n  \"introduction.interactions.favourite.headline\": \"Favourite\",\n  \"introduction.interactions.favourite.text\": \"You can save a toot for later, and let the author know that you liked it, by favouriting it.\",\n  \"introduction.interactions.reblog.headline\": \"Boost\",\n  \"introduction.interactions.reblog.text\": \"You can share other people's toots with your followers by boosting them.\",\n  \"introduction.interactions.reply.headline\": \"Reply\",\n  \"introduction.interactions.reply.text\": \"You can reply to other people's and your own toots, which will chain them together in a conversation.\",\n  \"introduction.welcome.action\": \"Let's go!\",\n  \"introduction.welcome.headline\": \"First steps\",\n  \"introduction.welcome.text\": \"Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.\",\n  \"keyboard_shortcuts.back\": \"for å navigere tilbake\",\n  \"keyboard_shortcuts.blocked\": \"to open blocked users list\",\n  \"keyboard_shortcuts.boost\": \"å fremheve\",\n  \"keyboard_shortcuts.column\": \"å fokusere en status i en av kolonnene\",\n  \"keyboard_shortcuts.compose\": \"å fokusere komponeringsfeltet\",\n  \"keyboard_shortcuts.description\": \"Description\",\n  \"keyboard_shortcuts.direct\": \"to open direct messages column\",\n  \"keyboard_shortcuts.down\": \"for å flytte ned i listen\",\n  \"keyboard_shortcuts.enter\": \"to open status\",\n  \"keyboard_shortcuts.favourite\": \"for å favorittmarkere\",\n  \"keyboard_shortcuts.favourites\": \"to open favourites list\",\n  \"keyboard_shortcuts.federated\": \"to open federated timeline\",\n  \"keyboard_shortcuts.heading\": \"Keyboard Shortcuts\",\n  \"keyboard_shortcuts.home\": \"to open home timeline\",\n  \"keyboard_shortcuts.hotkey\": \"Lyntast\",\n  \"keyboard_shortcuts.legend\": \"å vise denne forklaringen\",\n  \"keyboard_shortcuts.local\": \"to open local timeline\",\n  \"keyboard_shortcuts.mention\": \"å nevne forfatter\",\n  \"keyboard_shortcuts.muted\": \"to open muted users list\",\n  \"keyboard_shortcuts.my_profile\": \"to open your profile\",\n  \"keyboard_shortcuts.notifications\": \"to open notifications column\",\n  \"keyboard_shortcuts.pinned\": \"to open pinned toots list\",\n  \"keyboard_shortcuts.profile\": \"to open author's profile\",\n  \"keyboard_shortcuts.reply\": \"for å svare\",\n  \"keyboard_shortcuts.requests\": \"to open follow requests list\",\n  \"keyboard_shortcuts.search\": \"å fokusere søk\",\n  \"keyboard_shortcuts.start\": \"to open \\\"get started\\\" column\",\n  \"keyboard_shortcuts.toggle_hidden\": \"to show/hide text behind CW\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"to show/hide media\",\n  \"keyboard_shortcuts.toot\": \"å starte en helt ny tut\",\n  \"keyboard_shortcuts.unfocus\": \"å ufokusere komponerings-/søkefeltet\",\n  \"keyboard_shortcuts.up\": \"å flytte opp i listen\",\n  \"lightbox.close\": \"Lukk\",\n  \"lightbox.next\": \"Neste\",\n  \"lightbox.previous\": \"Forrige\",\n  \"lightbox.view_context\": \"View context\",\n  \"lists.account.add\": \"Legg til i listen\",\n  \"lists.account.remove\": \"Fjern fra listen\",\n  \"lists.delete\": \"Slett listen\",\n  \"lists.edit\": \"Rediger listen\",\n  \"lists.edit.submit\": \"Change title\",\n  \"lists.new.create\": \"Ligg til liste\",\n  \"lists.new.title_placeholder\": \"Ny listetittel\",\n  \"lists.search\": \"Søk blant personer du følger\",\n  \"lists.subheading\": \"Dine lister\",\n  \"loading_indicator.label\": \"Laster...\",\n  \"media_gallery.toggle_visible\": \"Veksle synlighet\",\n  \"missing_indicator.label\": \"Ikke funnet\",\n  \"missing_indicator.sublabel\": \"Denne ressursen ble ikke funnet\",\n  \"mute_modal.hide_notifications\": \"Skjul varslinger fra denne brukeren?\",\n  \"navigation_bar.apps\": \"Mobile apps\",\n  \"navigation_bar.blocks\": \"Blokkerte brukere\",\n  \"navigation_bar.community_timeline\": \"Lokal tidslinje\",\n  \"navigation_bar.compose\": \"Compose new toot\",\n  \"navigation_bar.direct\": \"Direct messages\",\n  \"navigation_bar.discover\": \"Discover\",\n  \"navigation_bar.domain_blocks\": \"Hidden domains\",\n  \"navigation_bar.edit_profile\": \"Rediger profil\",\n  \"navigation_bar.favourites\": \"Favoritter\",\n  \"navigation_bar.filters\": \"Muted words\",\n  \"navigation_bar.follow_requests\": \"Følgeforespørsler\",\n  \"navigation_bar.follows_and_followers\": \"Follows and followers\",\n  \"navigation_bar.info\": \"Utvidet informasjon\",\n  \"navigation_bar.keyboard_shortcuts\": \"Tastatursnarveier\",\n  \"navigation_bar.lists\": \"Lister\",\n  \"navigation_bar.logout\": \"Logg ut\",\n  \"navigation_bar.mutes\": \"Dempede brukere\",\n  \"navigation_bar.personal\": \"Personal\",\n  \"navigation_bar.pins\": \"Festa tuter\",\n  \"navigation_bar.preferences\": \"Preferanser\",\n  \"navigation_bar.profile_directory\": \"Profile directory\",\n  \"navigation_bar.public_timeline\": \"Felles tidslinje\",\n  \"navigation_bar.security\": \"Security\",\n  \"notification.favourite\": \"{name} likte din status\",\n  \"notification.follow\": \"{name} fulgte deg\",\n  \"notification.mention\": \"{name} nevnte deg\",\n  \"notification.poll\": \"A poll you have voted in has ended\",\n  \"notification.reblog\": \"{name} fremhevde din status\",\n  \"notifications.clear\": \"Fjern varsler\",\n  \"notifications.clear_confirmation\": \"Er du sikker på at du vil fjerne alle dine varsler permanent?\",\n  \"notifications.column_settings.alert\": \"Skrivebordsvarslinger\",\n  \"notifications.column_settings.favourite\": \"Likt:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Display all categories\",\n  \"notifications.column_settings.filter_bar.category\": \"Quick filter bar\",\n  \"notifications.column_settings.filter_bar.show\": \"Show\",\n  \"notifications.column_settings.follow\": \"Nye følgere:\",\n  \"notifications.column_settings.mention\": \"Nevnt:\",\n  \"notifications.column_settings.poll\": \"Poll results:\",\n  \"notifications.column_settings.push\": \"Push varsler\",\n  \"notifications.column_settings.reblog\": \"Fremhevet:\",\n  \"notifications.column_settings.show\": \"Vis i kolonne\",\n  \"notifications.column_settings.sound\": \"Spill lyd\",\n  \"notifications.filter.all\": \"All\",\n  \"notifications.filter.boosts\": \"Boosts\",\n  \"notifications.filter.favourites\": \"Favourites\",\n  \"notifications.filter.follows\": \"Follows\",\n  \"notifications.filter.mentions\": \"Mentions\",\n  \"notifications.filter.polls\": \"Poll results\",\n  \"notifications.group\": \"{count} notifications\",\n  \"poll.closed\": \"Closed\",\n  \"poll.refresh\": \"Refresh\",\n  \"poll.total_votes\": \"{count, plural, one {# vote} other {# votes}}\",\n  \"poll.vote\": \"Vote\",\n  \"poll_button.add_poll\": \"Add a poll\",\n  \"poll_button.remove_poll\": \"Remove poll\",\n  \"privacy.change\": \"Justér synlighet\",\n  \"privacy.direct.long\": \"Post kun til nevnte brukere\",\n  \"privacy.direct.short\": \"Direkte\",\n  \"privacy.private.long\": \"Post kun til følgere\",\n  \"privacy.private.short\": \"Privat\",\n  \"privacy.public.long\": \"Post kun til offentlige tidslinjer\",\n  \"privacy.public.short\": \"Offentlig\",\n  \"privacy.unlisted.long\": \"Ikke vis i offentlige tidslinjer\",\n  \"privacy.unlisted.short\": \"Uoppført\",\n  \"regeneration_indicator.label\": \"Laster…\",\n  \"regeneration_indicator.sublabel\": \"Dine startside forberedes!\",\n  \"relative_time.days\": \"{number}d\",\n  \"relative_time.hours\": \"{number}h\",\n  \"relative_time.just_now\": \"nå\",\n  \"relative_time.minutes\": \"{number}m\",\n  \"relative_time.seconds\": \"{number}s\",\n  \"reply_indicator.cancel\": \"Avbryt\",\n  \"report.forward\": \"Forward to {target}\",\n  \"report.forward_hint\": \"The account is from another server. Send an anonymized copy of the report there as well?\",\n  \"report.hint\": \"The report will be sent to your instance moderators. You can provide an explanation of why you are reporting this account below:\",\n  \"report.placeholder\": \"Tilleggskommentarer\",\n  \"report.submit\": \"Send inn\",\n  \"report.target\": \"Rapporterer\",\n  \"search.placeholder\": \"Søk\",\n  \"search_popout.search_format\": \"Avansert søkeformat\",\n  \"search_popout.tips.full_text\": \"Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.\",\n  \"search_popout.tips.hashtag\": \"emneknagg\",\n  \"search_popout.tips.status\": \"status\",\n  \"search_popout.tips.text\": \"Enkel tekst returnerer matchende visningsnavn, brukernavn og emneknagger\",\n  \"search_popout.tips.user\": \"bruker\",\n  \"search_results.accounts\": \"People\",\n  \"search_results.hashtags\": \"Hashtags\",\n  \"search_results.statuses\": \"Toots\",\n  \"search_results.total\": \"{count, number} {count, plural, one {resultat} other {resultater}}\",\n  \"status.admin_account\": \"Open moderation interface for @{name}\",\n  \"status.admin_status\": \"Open this status in the moderation interface\",\n  \"status.block\": \"Block @{name}\",\n  \"status.cancel_reblog_private\": \"Unboost\",\n  \"status.cannot_reblog\": \"Denne posten kan ikke fremheves\",\n  \"status.copy\": \"Copy link to status\",\n  \"status.delete\": \"Slett\",\n  \"status.detailed_status\": \"Detailed conversation view\",\n  \"status.direct\": \"Direct message @{name}\",\n  \"status.embed\": \"Bygge inn\",\n  \"status.favourite\": \"Lik\",\n  \"status.filtered\": \"Filtered\",\n  \"status.load_more\": \"Last mer\",\n  \"status.media_hidden\": \"Media skjult\",\n  \"status.mention\": \"Nevn @{name}\",\n  \"status.more\": \"Mer\",\n  \"status.mute\": \"Demp @{name}\",\n  \"status.mute_conversation\": \"Demp samtale\",\n  \"status.open\": \"Utvid denne statusen\",\n  \"status.pin\": \"Fest på profilen\",\n  \"status.pinned\": \"Pinned toot\",\n  \"status.read_more\": \"Read more\",\n  \"status.reblog\": \"Fremhev\",\n  \"status.reblog_private\": \"Boost to original audience\",\n  \"status.reblogged_by\": \"Fremhevd av {name}\",\n  \"status.reblogs.empty\": \"No one has boosted this toot yet. When someone does, they will show up here.\",\n  \"status.redraft\": \"Delete & re-draft\",\n  \"status.reply\": \"Svar\",\n  \"status.replyAll\": \"Svar til samtale\",\n  \"status.report\": \"Rapporter @{name}\",\n  \"status.sensitive_warning\": \"Følsomt innhold\",\n  \"status.share\": \"Del\",\n  \"status.show_less\": \"Vis mindre\",\n  \"status.show_less_all\": \"Show less for all\",\n  \"status.show_more\": \"Vis mer\",\n  \"status.show_more_all\": \"Show more for all\",\n  \"status.show_thread\": \"Show thread\",\n  \"status.unmute_conversation\": \"Ikke demp samtale\",\n  \"status.unpin\": \"Angre festing på profilen\",\n  \"suggestions.dismiss\": \"Dismiss suggestion\",\n  \"suggestions.header\": \"You might be interested in…\",\n  \"tabs_bar.federated_timeline\": \"Felles\",\n  \"tabs_bar.home\": \"Hjem\",\n  \"tabs_bar.local_timeline\": \"Lokal\",\n  \"tabs_bar.notifications\": \"Varslinger\",\n  \"tabs_bar.search\": \"Search\",\n  \"time_remaining.days\": \"{number, plural, one {# day} other {# days}} left\",\n  \"time_remaining.hours\": \"{number, plural, one {# hour} other {# hours}} left\",\n  \"time_remaining.minutes\": \"{number, plural, one {# minute} other {# minutes}} left\",\n  \"time_remaining.moments\": \"Moments remaining\",\n  \"time_remaining.seconds\": \"{number, plural, one {# second} other {# seconds}} left\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {person} other {people}} talking\",\n  \"ui.beforeunload\": \"Din kladd vil bli forkastet om du forlater Mastodon.\",\n  \"upload_area.title\": \"Dra og slipp for å laste opp\",\n  \"upload_button.label\": \"Legg til media\",\n  \"upload_error.limit\": \"File upload limit exceeded.\",\n  \"upload_error.poll\": \"File upload not allowed with polls.\",\n  \"upload_form.description\": \"Beskriv for synshemmede\",\n  \"upload_form.focus\": \"Crop\",\n  \"upload_form.undo\": \"Angre\",\n  \"upload_progress.label\": \"Laster opp...\",\n  \"video.close\": \"Lukk video\",\n  \"video.exit_fullscreen\": \"Lukk fullskjerm\",\n  \"video.expand\": \"Utvid video\",\n  \"video.fullscreen\": \"Full screen\",\n  \"video.hide\": \"Skjul video\",\n  \"video.mute\": \"Skru av lyd\",\n  \"video.pause\": \"Pause\",\n  \"video.play\": \"Spill av\",\n  \"video.unmute\": \"Skru på lyd\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/oc.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Ajustar o tirar de las listas\",\n  \"account.badges.bot\": \"Robòt\",\n  \"account.block\": \"Blocar @{name}\",\n  \"account.block_domain\": \"Tot amagar del domeni {domain}\",\n  \"account.blocked\": \"Blocat\",\n  \"account.direct\": \"Escriure un MP a @{name}\",\n  \"account.domain_blocked\": \"Domeni amagat\",\n  \"account.edit_profile\": \"Modificar lo perfil\",\n  \"account.endorse\": \"Mostrar pel perfil\",\n  \"account.follow\": \"Sègre\",\n  \"account.followers\": \"Seguidors\",\n  \"account.followers.empty\": \"Degun sèc pas aqueste utilizaire pel moment.\",\n  \"account.follows\": \"Abonaments\",\n  \"account.follows.empty\": \"Aqueste utilizaire sèc pas degun pel moment.\",\n  \"account.follows_you\": \"Vos sèc\",\n  \"account.hide_reblogs\": \"Rescondre los partatges de @{name}\",\n  \"account.link_verified_on\": \"La proprietat d’aqueste ligam foguèt verificada lo {date}\",\n  \"account.locked_info\": \"L’estatut de privacitat del compte es configurat sus clavat. Lo proprietari causís qual pòt sègre son compte.\",\n  \"account.media\": \"Mèdias\",\n  \"account.mention\": \"Mencionar @{name}\",\n  \"account.moved_to\": \"{name} a mudat los catons a :\",\n  \"account.mute\": \"Rescondre @{name}\",\n  \"account.mute_notifications\": \"Rescondre las notificacions de @{name}\",\n  \"account.muted\": \"Mes en silenci\",\n  \"account.posts\": \"Tuts\",\n  \"account.posts_with_replies\": \"Tuts e responsas\",\n  \"account.report\": \"Senhalar @{name}\",\n  \"account.requested\": \"Invitacion mandada. Clicatz per anullar\",\n  \"account.share\": \"Partejar lo perfil a @{name}\",\n  \"account.show_reblogs\": \"Mostrar los partatges de @{name}\",\n  \"account.unblock\": \"Desblocar @{name}\",\n  \"account.unblock_domain\": \"Desblocar {domain}\",\n  \"account.unendorse\": \"Mostrar pas pel perfil\",\n  \"account.unfollow\": \"Quitar de sègre\",\n  \"account.unmute\": \"Quitar de rescondre @{name}\",\n  \"account.unmute_notifications\": \"Mostrar las notificacions de @{name}\",\n  \"alert.unexpected.message\": \"Una error s’es producha.\",\n  \"alert.unexpected.title\": \"Ops !\",\n  \"boost_modal.combo\": \"Podètz botar {combo} per passar aquò lo còp que ven\",\n  \"bundle_column_error.body\": \"Quicòm a fach mèuca pendent lo cargament d’aqueste compausant.\",\n  \"bundle_column_error.retry\": \"Tornar ensajar\",\n  \"bundle_column_error.title\": \"Error de ret\",\n  \"bundle_modal_error.close\": \"Tampar\",\n  \"bundle_modal_error.message\": \"Quicòm a fach mèuca pendent lo cargament d’aqueste compausant.\",\n  \"bundle_modal_error.retry\": \"Tornar ensajar\",\n  \"column.blocks\": \"Personas blocadas\",\n  \"column.community\": \"Flux public local\",\n  \"column.direct\": \"Messatges dirèctes\",\n  \"column.domain_blocks\": \"Domenis resconduts\",\n  \"column.favourites\": \"Favorits\",\n  \"column.follow_requests\": \"Demandas d’abonament\",\n  \"column.home\": \"Acuèlh\",\n  \"column.lists\": \"Listas\",\n  \"column.mutes\": \"Personas rescondudas\",\n  \"column.notifications\": \"Notificacions\",\n  \"column.pins\": \"Tuts penjats\",\n  \"column.public\": \"Flux public global\",\n  \"column_back_button.label\": \"Tornar\",\n  \"column_header.hide_settings\": \"Amagar los paramètres\",\n  \"column_header.moveLeft_settings\": \"Desplaçar la colomna a man drecha\",\n  \"column_header.moveRight_settings\": \"Desplaçar la colomna a man esquèrra\",\n  \"column_header.pin\": \"Penjar\",\n  \"column_header.show_settings\": \"Mostrar los paramètres\",\n  \"column_header.unpin\": \"Despenjar\",\n  \"column_subheading.settings\": \"Paramètres\",\n  \"community.column_settings.media_only\": \"Solament los mèdias\",\n  \"compose_form.direct_message_warning\": \"Sols los mencionats poiràn veire aqueste tut.\",\n  \"compose_form.direct_message_warning_learn_more\": \"Ne saber mai\",\n  \"compose_form.hashtag_warning\": \"Aqueste tut serà pas ligat a cap d’etiqueta estant qu’es pas listat. Òm pòt pas cercar que los tuts publics per etiqueta.\",\n  \"compose_form.lock_disclaimer\": \"Vòstre compte es pas {locked}. Tot lo monde pòt vos sègre e veire los estatuts reservats als seguidors.\",\n  \"compose_form.lock_disclaimer.lock\": \"clavat\",\n  \"compose_form.placeholder\": \"A de qué pensatz ?\",\n  \"compose_form.poll.add_option\": \"Ajustar una causida\",\n  \"compose_form.poll.duration\": \"Durada del sondatge\",\n  \"compose_form.poll.option_placeholder\": \"Opcion {number}\",\n  \"compose_form.poll.remove_option\": \"Levar aquesta opcion\",\n  \"compose_form.publish\": \"Tut\",\n  \"compose_form.publish_loud\": \"{publish} !\",\n  \"compose_form.sensitive.hide\": \"Mark media as sensitive\",\n  \"compose_form.sensitive.marked\": \"Lo mèdia es marcat coma sensible\",\n  \"compose_form.sensitive.unmarked\": \"Lo mèdia es pas marcat coma sensible\",\n  \"compose_form.spoiler.marked\": \"Lo tèxte es rescondut jos l’avertiment\",\n  \"compose_form.spoiler.unmarked\": \"Lo tèxte es pas rescondut\",\n  \"compose_form.spoiler_placeholder\": \"Escrivètz l’avertiment aquí\",\n  \"confirmation_modal.cancel\": \"Anullar\",\n  \"confirmations.block.block_and_report\": \"Blocar e senhalar\",\n  \"confirmations.block.confirm\": \"Blocar\",\n  \"confirmations.block.message\": \"Volètz vertadièrament blocar {name} ?\",\n  \"confirmations.delete.confirm\": \"Escafar\",\n  \"confirmations.delete.message\": \"Volètz vertadièrament escafar l’estatut ?\",\n  \"confirmations.delete_list.confirm\": \"Suprimir\",\n  \"confirmations.delete_list.message\": \"Volètz vertadièrament suprimir aquesta lista per totjorn ?\",\n  \"confirmations.domain_block.confirm\": \"Amagar tot lo domeni\",\n  \"confirmations.domain_block.message\": \"Volètz vertadièrament blocar complètament {domain} ? De còps cal pas que blocar o rescondre unas personas solament.\\nVeiretz pas cap de contengut d’aquel domeni dins cap de flux public o dins vòstras notificacions. Vòstres seguidors d’aquel domeni seràn levats.\",\n  \"confirmations.mute.confirm\": \"Rescondre\",\n  \"confirmations.mute.message\": \"Volètz vertadièrament rescondre {name} ?\",\n  \"confirmations.redraft.confirm\": \"Escafar & tornar formular\",\n  \"confirmations.redraft.message\": \"Volètz vertadièrament escafar aqueste estatut e lo reformular ? Totes sos partiments e favorits seràn perduts, e sas responsas seràn orfanèlas.\",\n  \"confirmations.reply.confirm\": \"Respondre\",\n  \"confirmations.reply.message\": \"Respondre remplaçarà lo messatge que sètz a escriure. Volètz vertadièrament contunhar ?\",\n  \"confirmations.unfollow.confirm\": \"Quitar de sègre\",\n  \"confirmations.unfollow.message\": \"Volètz vertadièrament quitar de sègre {name} ?\",\n  \"embed.instructions\": \"Embarcar aqueste estatut per lo far veire sus un site Internet en copiar lo còdi çai-jos.\",\n  \"embed.preview\": \"Semblarà aquò :\",\n  \"emoji_button.activity\": \"Activitats\",\n  \"emoji_button.custom\": \"Personalizats\",\n  \"emoji_button.flags\": \"Drapèus\",\n  \"emoji_button.food\": \"Beure e manjar\",\n  \"emoji_button.label\": \"Inserir un emoji\",\n  \"emoji_button.nature\": \"Natura\",\n  \"emoji_button.not_found\": \"Cap d’emoji ! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"Objèctes\",\n  \"emoji_button.people\": \"Gents\",\n  \"emoji_button.recent\": \"Sovent utilizats\",\n  \"emoji_button.search\": \"Cercar…\",\n  \"emoji_button.search_results\": \"Resultats de recèrca\",\n  \"emoji_button.symbols\": \"Simbòls\",\n  \"emoji_button.travel\": \"Viatges & lòcs\",\n  \"empty_column.account_timeline\": \"Cap de tuts aquí !\",\n  \"empty_column.account_unavailable\": \"Perfil pas disponible\",\n  \"empty_column.blocks\": \"Avètz pas blocat degun pel moment.\",\n  \"empty_column.community\": \"Lo flux public local es void. Escrivètz quicòm per lo garnir !\",\n  \"empty_column.direct\": \"Avètz pas encara cap de messatges. Quand ne mandatz un o que ne recebètz un, serà mostrat aquí.\",\n  \"empty_column.domain_blocks\": \"I a pas encara cap de domeni amagat.\",\n  \"empty_column.favourited_statuses\": \"Avètz pas encara cap de tut favorit. Quand n’auretz un, apareisserà aquí.\",\n  \"empty_column.favourites\": \"Degun a pas encara mes en favorit aqueste tut. Quand qualqu’un o farà, apareisserà aquí.\",\n  \"empty_column.follow_requests\": \"Avètz pas encara de demanda d’abonament. Quand n’auretz una apareisserà aquí.\",\n  \"empty_column.hashtag\": \"I a pas encara de contengut ligat a aquesta etiqueta.\",\n  \"empty_column.home\": \"Vòstre flux d’acuèlh es void. Visitatz {public} o utilizatz la recèrca per vos connectar a d’autras personas.\",\n  \"empty_column.home.public_timeline\": \"lo flux public\",\n  \"empty_column.list\": \"I a pas res dins la lista pel moment. Quand de membres d’aquesta lista publiquen de novèls estatuts los veiretz aquí.\",\n  \"empty_column.lists\": \"Encara avètz pas cap de lista. Quand ne creetz una, apareisserà aquí.\",\n  \"empty_column.mutes\": \"Encara avètz pas mes en silenci degun.\",\n  \"empty_column.notifications\": \"Avètz pas encara de notificacions. Respondètz a qualqu’un per començar una conversacion.\",\n  \"empty_column.public\": \"I a pas res aquí ! Escrivètz quicòm de public, o seguètz de personas d’autres servidors per garnir lo flux public\",\n  \"follow_request.authorize\": \"Acceptar\",\n  \"follow_request.reject\": \"Regetar\",\n  \"getting_started.developers\": \"Desvelopaires\",\n  \"getting_started.directory\": \"Annuari de perfils\",\n  \"getting_started.documentation\": \"Documentacion\",\n  \"getting_started.heading\": \"Per començar\",\n  \"getting_started.invite\": \"Convidar de monde\",\n  \"getting_started.open_source_notice\": \"Mastodon es un logicial liure. Podètz contribuir e mandar vòstres comentaris e rapòrt de bug via {github} sus GitHub.\",\n  \"getting_started.security\": \"Seguretat\",\n  \"getting_started.terms\": \"Condicions d’utilizacion\",\n  \"hashtag.column_header.tag_mode.all\": \"e {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"o {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"sens {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"Cap de suggestion pas trobada\",\n  \"hashtag.column_settings.select.placeholder\": \"Picatz d’etiquetas…\",\n  \"hashtag.column_settings.tag_mode.all\": \"Totes aquestes\",\n  \"hashtag.column_settings.tag_mode.any\": \"Un d’aquestes\",\n  \"hashtag.column_settings.tag_mode.none\": \"Cap d’aquestes\",\n  \"hashtag.column_settings.tag_toggle\": \"Inclure las etiquetas suplementàrias dins aquesta colomna\",\n  \"home.column_settings.basic\": \"Basic\",\n  \"home.column_settings.show_reblogs\": \"Mostrar los partatges\",\n  \"home.column_settings.show_replies\": \"Mostrar las responsas\",\n  \"intervals.full.days\": \"{number, plural, one {# jorn} other {# jorns}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# ora} other {# oras}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minuta} other {# minutas}}\",\n  \"introduction.federation.action\": \"Seguent\",\n  \"introduction.federation.federated.headline\": \"Federat\",\n  \"introduction.federation.federated.text\": \"Los tuts publics d’autres servidors del fediverse apareisseràn dins lo flux d’actualitats.\",\n  \"introduction.federation.home.headline\": \"Acuèlh\",\n  \"introduction.federation.home.text\": \"Los tuts del monde que seguètz apareisseràn dins vòstre flux d’acuèlh. Podètz sègre de monde ont que siasquen !\",\n  \"introduction.federation.local.headline\": \"Local\",\n  \"introduction.federation.local.text\": \"Los tuts publics del monde del meteis servidor que vosautres apareisseràn dins lo flux local.\",\n  \"introduction.interactions.action\": \"Acabar la leiçon !\",\n  \"introduction.interactions.favourite.headline\": \"Favorit\",\n  \"introduction.interactions.favourite.text\": \"Podètz enregistrar un tut per mai tard, e avisar l’autor que l’avètz aimat, en l’ajustant als favorits.\",\n  \"introduction.interactions.reblog.headline\": \"Partejar\",\n  \"introduction.interactions.reblog.text\": \"Podètz partejar los tuts dels autres amb vòstres seguidors en los partejant.\",\n  \"introduction.interactions.reply.headline\": \"Respondre\",\n  \"introduction.interactions.reply.text\": \"Podètz respondre als tuts dels autres e a vòstres tuts, seràn amassats en una conversacion.\",\n  \"introduction.welcome.action\": \"Anem-i !\",\n  \"introduction.welcome.headline\": \"Primièrs passes\",\n  \"introduction.welcome.text\": \"La benvenguda al fediverse ! D’aquí un momenton, poiretz enviar de messatges e charrar amd d’amics via mantuns servidors. Mas aqueste servidor, {domain}, es especial perque alberga vòstre perfil, doncas oblidatz pas son nom.\",\n  \"keyboard_shortcuts.back\": \"anar enrèire\",\n  \"keyboard_shortcuts.blocked\": \"dobrir la lista d’utilizaires blocats\",\n  \"keyboard_shortcuts.boost\": \"partejar\",\n  \"keyboard_shortcuts.column\": \"centrar un estatut a una colomna\",\n  \"keyboard_shortcuts.compose\": \"anar al camp tèxte\",\n  \"keyboard_shortcuts.description\": \"descripcion\",\n  \"keyboard_shortcuts.direct\": \"dobrir la colomna de messatges dirèctes\",\n  \"keyboard_shortcuts.down\": \"far davalar dins la lista\",\n  \"keyboard_shortcuts.enter\": \"dobrir los estatuts\",\n  \"keyboard_shortcuts.favourite\": \"apondre als favorits\",\n  \"keyboard_shortcuts.favourites\": \"dobrir la lista de favorits\",\n  \"keyboard_shortcuts.federated\": \"dobrir lo flux public global\",\n  \"keyboard_shortcuts.heading\": \"Acorchis clavièr\",\n  \"keyboard_shortcuts.home\": \"dobrir lo flux public local\",\n  \"keyboard_shortcuts.hotkey\": \"Acorchis\",\n  \"keyboard_shortcuts.legend\": \"mostrar aquesta legenda\",\n  \"keyboard_shortcuts.local\": \"dobrir lo flux public local\",\n  \"keyboard_shortcuts.mention\": \"mencionar l’autor\",\n  \"keyboard_shortcuts.muted\": \"dobrir la lista dels utilizaires silenciats\",\n  \"keyboard_shortcuts.my_profile\": \"dobrir vòstre perfil\",\n  \"keyboard_shortcuts.notifications\": \"dobrir la colomna de notificacions\",\n  \"keyboard_shortcuts.pinned\": \"dobrir la lista dels tuts penjats\",\n  \"keyboard_shortcuts.profile\": \"dobrir lo perfil de l’autor\",\n  \"keyboard_shortcuts.reply\": \"respondre\",\n  \"keyboard_shortcuts.requests\": \"dorbir la lista de demanda d’abonament\",\n  \"keyboard_shortcuts.search\": \"anar a la recèrca\",\n  \"keyboard_shortcuts.start\": \"dobrir la colomna « Per començar »\",\n  \"keyboard_shortcuts.toggle_hidden\": \"mostrar/amagar lo tèxte dels avertiments\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"to show/hide media\",\n  \"keyboard_shortcuts.toot\": \"començar un estatut tot novèl\",\n  \"keyboard_shortcuts.unfocus\": \"quitar lo camp tèxte/de recèrca\",\n  \"keyboard_shortcuts.up\": \"far montar dins la lista\",\n  \"lightbox.close\": \"Tampar\",\n  \"lightbox.next\": \"Seguent\",\n  \"lightbox.previous\": \"Precedent\",\n  \"lightbox.view_context\": \"View context\",\n  \"lists.account.add\": \"Ajustar a la lista\",\n  \"lists.account.remove\": \"Levar de la lista\",\n  \"lists.delete\": \"Suprimir la lista\",\n  \"lists.edit\": \"Modificar la lista\",\n  \"lists.edit.submit\": \"Cambiar lo títol\",\n  \"lists.new.create\": \"Ajustar una lista\",\n  \"lists.new.title_placeholder\": \"Títol de la nòva lista\",\n  \"lists.search\": \"Cercar demest lo monde que seguètz\",\n  \"lists.subheading\": \"Vòstras listas\",\n  \"loading_indicator.label\": \"Cargament…\",\n  \"media_gallery.toggle_visible\": \"Modificar la visibilitat\",\n  \"missing_indicator.label\": \"Pas trobat\",\n  \"missing_indicator.sublabel\": \"Aquesta ressorsa es pas estada trobada\",\n  \"mute_modal.hide_notifications\": \"Rescondre las notificacions d’aquesta persona ?\",\n  \"navigation_bar.apps\": \"Aplicacions mobil\",\n  \"navigation_bar.blocks\": \"Personas blocadas\",\n  \"navigation_bar.community_timeline\": \"Flux public local\",\n  \"navigation_bar.compose\": \"Escriure un nòu tut\",\n  \"navigation_bar.direct\": \"Messatges dirèctes\",\n  \"navigation_bar.discover\": \"Trobar\",\n  \"navigation_bar.domain_blocks\": \"Domenis resconduts\",\n  \"navigation_bar.edit_profile\": \"Modificar lo perfil\",\n  \"navigation_bar.favourites\": \"Favorits\",\n  \"navigation_bar.filters\": \"Mots ignorats\",\n  \"navigation_bar.follow_requests\": \"Demandas d’abonament\",\n  \"navigation_bar.follows_and_followers\": \"Follows and followers\",\n  \"navigation_bar.info\": \"Tocant aqueste servidor\",\n  \"navigation_bar.keyboard_shortcuts\": \"Acorchis clavièr\",\n  \"navigation_bar.lists\": \"Listas\",\n  \"navigation_bar.logout\": \"Desconnexion\",\n  \"navigation_bar.mutes\": \"Personas rescondudas\",\n  \"navigation_bar.personal\": \"Personal\",\n  \"navigation_bar.pins\": \"Tuts penjats\",\n  \"navigation_bar.preferences\": \"Preferéncias\",\n  \"navigation_bar.profile_directory\": \"Profile directory\",\n  \"navigation_bar.public_timeline\": \"Flux public global\",\n  \"navigation_bar.security\": \"Seguretat\",\n  \"notification.favourite\": \"{name} a ajustat a sos favorits\",\n  \"notification.follow\": \"{name} vos sèc\",\n  \"notification.mention\": \"{name} vos a mencionat\",\n  \"notification.poll\": \"Avètz participat a un sondatge que ven de s’acabar\",\n  \"notification.reblog\": \"{name} a partejat vòstre estatut\",\n  \"notifications.clear\": \"Escafar\",\n  \"notifications.clear_confirmation\": \"Volètz vertadièrament escafar totas vòstras las notificacions ?\",\n  \"notifications.column_settings.alert\": \"Notificacions localas\",\n  \"notifications.column_settings.favourite\": \"Favorits :\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Mostrar totas las categorias\",\n  \"notifications.column_settings.filter_bar.category\": \"Barra de recèrca rapida\",\n  \"notifications.column_settings.filter_bar.show\": \"Mostrar\",\n  \"notifications.column_settings.follow\": \"Nòus seguidors :\",\n  \"notifications.column_settings.mention\": \"Mencions :\",\n  \"notifications.column_settings.poll\": \"Resultats del sondatge :\",\n  \"notifications.column_settings.push\": \"Notificacions\",\n  \"notifications.column_settings.reblog\": \"Partatges :\",\n  \"notifications.column_settings.show\": \"Mostrar dins la colomna\",\n  \"notifications.column_settings.sound\": \"Emetre un son\",\n  \"notifications.filter.all\": \"Totas\",\n  \"notifications.filter.boosts\": \"Partages\",\n  \"notifications.filter.favourites\": \"Favorits\",\n  \"notifications.filter.follows\": \"Seguiments\",\n  \"notifications.filter.mentions\": \"Mencions\",\n  \"notifications.filter.polls\": \"Resultats del sondatge\",\n  \"notifications.group\": \"{count} notificacions\",\n  \"poll.closed\": \"Tampat\",\n  \"poll.refresh\": \"Actualizar\",\n  \"poll.total_votes\": \"{count, plural, one {# vòte} other {# vòtes}}\",\n  \"poll.vote\": \"Votar\",\n  \"poll_button.add_poll\": \"Ajustar un sondatge\",\n  \"poll_button.remove_poll\": \"Levar lo sondatge\",\n  \"privacy.change\": \"Ajustar la confidencialitat del messatge\",\n  \"privacy.direct.long\": \"Mostrar pas qu’a las personas mencionadas\",\n  \"privacy.direct.short\": \"Dirècte\",\n  \"privacy.private.long\": \"Mostrar pas qu’a vòstres seguidors\",\n  \"privacy.private.short\": \"Privat\",\n  \"privacy.public.long\": \"Mostrar dins los fluxes publics\",\n  \"privacy.public.short\": \"Public\",\n  \"privacy.unlisted.long\": \"Mostrar pas dins los fluxes publics\",\n  \"privacy.unlisted.short\": \"Pas-listat\",\n  \"regeneration_indicator.label\": \"Cargament…\",\n  \"regeneration_indicator.sublabel\": \"Sèm a preparar vòstre flux d’acuèlh !\",\n  \"relative_time.days\": \"fa {number}d\",\n  \"relative_time.hours\": \"fa {number}h\",\n  \"relative_time.just_now\": \"ara\",\n  \"relative_time.minutes\": \"fa {number} min\",\n  \"relative_time.seconds\": \"fa {number}s\",\n  \"reply_indicator.cancel\": \"Anullar\",\n  \"report.forward\": \"Far sègre a {target}\",\n  \"report.forward_hint\": \"Lo compte ven d’un autre servidor. Volètz mandar una còpia anonima del rapòrt enlai tanben ?\",\n  \"report.hint\": \"Lo moderator del servidor aurà lo rapòrt. Podètz fornir una explicacion de vòstre senhalament aquí dejós  :\",\n  \"report.placeholder\": \"Comentaris addicionals\",\n  \"report.submit\": \"Mandar\",\n  \"report.target\": \"Senhalar {target}\",\n  \"search.placeholder\": \"Recercar\",\n  \"search_popout.search_format\": \"Format recèrca avançada\",\n  \"search_popout.tips.full_text\": \"Un tèxte simple que tòrna los estatuts qu’avètz escriches, mes en favorits, partejats, o ont sètz mencionat, e tanben los noms d’utilizaires, escais-noms e etiquetas que correspondonas.\",\n  \"search_popout.tips.hashtag\": \"etiqueta\",\n  \"search_popout.tips.status\": \"estatut\",\n  \"search_popout.tips.text\": \"Lo tèxte brut tòrna escais, noms d’utilizaire e etiquetas correspondents\",\n  \"search_popout.tips.user\": \"utilizaire\",\n  \"search_results.accounts\": \"Gents\",\n  \"search_results.hashtags\": \"Etiquetas\",\n  \"search_results.statuses\": \"Tuts\",\n  \"search_results.total\": \"{count, number} {count, plural, one {resultat} other {resultats}}\",\n  \"status.admin_account\": \"Dobrir l’interfàcia de moderacion per @{name}\",\n  \"status.admin_status\": \"Dobrir aqueste estatut dins l’interfàcia de moderacion\",\n  \"status.block\": \"Blocar @{name}\",\n  \"status.cancel_reblog_private\": \"Quitar de partejar\",\n  \"status.cannot_reblog\": \"Aqueste estatut pòt pas èsser partejat\",\n  \"status.copy\": \"Copiar lo ligam de l’estatut\",\n  \"status.delete\": \"Escafar\",\n  \"status.detailed_status\": \"Vista detalhada de la convèrsa\",\n  \"status.direct\": \"Messatge per @{name}\",\n  \"status.embed\": \"Embarcar\",\n  \"status.favourite\": \"Apondre als favorits\",\n  \"status.filtered\": \"Filtrat\",\n  \"status.load_more\": \"Cargar mai\",\n  \"status.media_hidden\": \"Mèdia rescondut\",\n  \"status.mention\": \"Mencionar\",\n  \"status.more\": \"Mai\",\n  \"status.mute\": \"Rescondre @{name}\",\n  \"status.mute_conversation\": \"Rescondre la conversacion\",\n  \"status.open\": \"Desplegar aqueste estatut\",\n  \"status.pin\": \"Penjar al perfil\",\n  \"status.pinned\": \"Tut penjat\",\n  \"status.read_more\": \"Ne legir mai\",\n  \"status.reblog\": \"Partejar\",\n  \"status.reblog_private\": \"Partejar a l’audiéncia d’origina\",\n  \"status.reblogged_by\": \"{name} a partejat\",\n  \"status.reblogs.empty\": \"Degun a pas encara partejat aqueste tut. Quand qualqu’un o farà, apareisserà aquí.\",\n  \"status.redraft\": \"Escafar e tornar formular\",\n  \"status.reply\": \"Respondre\",\n  \"status.replyAll\": \"Respondre a la conversacion\",\n  \"status.report\": \"Senhalar @{name}\",\n  \"status.sensitive_warning\": \"Contengut sensible\",\n  \"status.share\": \"Partejar\",\n  \"status.show_less\": \"Tornar plegar\",\n  \"status.show_less_all\": \"Los tornar plegar totes\",\n  \"status.show_more\": \"Desplegar\",\n  \"status.show_more_all\": \"Los desplegar totes\",\n  \"status.show_thread\": \"Mostrar lo fil\",\n  \"status.unmute_conversation\": \"Tornar mostrar la conversacion\",\n  \"status.unpin\": \"Tirar del perfil\",\n  \"suggestions.dismiss\": \"Regetar la suggestion\",\n  \"suggestions.header\": \"Vos poiriá interessar…\",\n  \"tabs_bar.federated_timeline\": \"Flux public global\",\n  \"tabs_bar.home\": \"Acuèlh\",\n  \"tabs_bar.local_timeline\": \"Flux public local\",\n  \"tabs_bar.notifications\": \"Notificacions\",\n  \"tabs_bar.search\": \"Recèrcas\",\n  \"time_remaining.days\": \"demòra{number, plural, one  { # jorn} other {n # jorns}}\",\n  \"time_remaining.hours\": \"demòra{number, plural, one { # ora} other {n # oras}}\",\n  \"time_remaining.minutes\": \"demòra{number, plural, one { # minuta} other {n # minutas}}\",\n  \"time_remaining.moments\": \"Moments restants\",\n  \"time_remaining.seconds\": \"demòra{number, plural, one { # segonda} other {n # segondas}}\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {person} ne charra other {people}} ne charran\",\n  \"ui.beforeunload\": \"Vòstre brolhon serà perdut se quitatz Mastodon.\",\n  \"upload_area.title\": \"Lisatz e depausatz per mandar\",\n  \"upload_button.label\": \"Ajustar un mèdia (JPEG, PNG, GIF, WebM, MP4, MOV)\",\n  \"upload_error.limit\": \"Talha maximum pels mandadís subrepassada.\",\n  \"upload_error.poll\": \"Lo mandadís de fichièr es pas autorizat pels sondatges.\",\n  \"upload_form.description\": \"Descripcion pels mal vesents\",\n  \"upload_form.focus\": \"Modificar l’apercebut\",\n  \"upload_form.undo\": \"Suprimir\",\n  \"upload_progress.label\": \"Mandadís…\",\n  \"video.close\": \"Tampar la vidèo\",\n  \"video.exit_fullscreen\": \"Sortir plen ecran\",\n  \"video.expand\": \"Agrandir la vidèo\",\n  \"video.fullscreen\": \"Ecran complèt\",\n  \"video.hide\": \"Amagar la vidèo\",\n  \"video.mute\": \"Copar lo son\",\n  \"video.pause\": \"Pausa\",\n  \"video.play\": \"Lectura\",\n  \"video.unmute\": \"Restablir lo son\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/pl.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Dodaj lub usuń z list\",\n  \"account.badges.bot\": \"Bot\",\n  \"account.block\": \"Blokuj @{name}\",\n  \"account.block_domain\": \"Blokuj wszystko z {domain}\",\n  \"account.blocked\": \"Zablokowany(-a)\",\n  \"account.direct\": \"Wyślij wiadomość bezpośrednią do @{name}\",\n  \"account.domain_blocked\": \"Ukryto domenę\",\n  \"account.edit_profile\": \"Edytuj profil\",\n  \"account.endorse\": \"Polecaj na profilu\",\n  \"account.follow\": \"Śledź\",\n  \"account.followers\": \"Śledzący\",\n  \"account.followers.empty\": \"Nikt jeszcze nie śledzi tego użytkownika.\",\n  \"account.follows\": \"Śledzeni\",\n  \"account.follows.empty\": \"Ten użytkownik nie śledzi jeszcze nikogo.\",\n  \"account.follows_you\": \"Śledzi Cię\",\n  \"account.hide_reblogs\": \"Ukryj podbicia od @{name}\",\n  \"account.link_verified_on\": \"Własność tego odnośnika została potwierdzona {date}\",\n  \"account.locked_info\": \"To konto jest prywatne. Właściciel ręcznie wybiera kto może go śledzić.\",\n  \"account.media\": \"Zawartość multimedialna\",\n  \"account.mention\": \"Wspomnij o @{name}\",\n  \"account.moved_to\": \"{name} przeniósł(-osła) się do:\",\n  \"account.mute\": \"Wycisz @{name}\",\n  \"account.mute_notifications\": \"Wycisz powiadomienia o @{name}\",\n  \"account.muted\": \"Wyciszony\",\n  \"account.posts\": \"Wpisy\",\n  \"account.posts_with_replies\": \"Wpisy i odpowiedzi\",\n  \"account.report\": \"Zgłoś @{name}\",\n  \"account.requested\": \"Oczekująca prośba, kliknij aby anulować\",\n  \"account.share\": \"Udostępnij profil @{name}\",\n  \"account.show_reblogs\": \"Pokazuj podbicia od @{name}\",\n  \"account.unblock\": \"Odblokuj @{name}\",\n  \"account.unblock_domain\": \"Odblokuj domenę {domain}\",\n  \"account.unendorse\": \"Przestań polecać\",\n  \"account.unfollow\": \"Przestań śledzić\",\n  \"account.unmute\": \"Cofnij wyciszenie @{name}\",\n  \"account.unmute_notifications\": \"Cofnij wyciszenie powiadomień od @{name}\",\n  \"alert.unexpected.message\": \"Wystąpił nieoczekiwany błąd.\",\n  \"alert.unexpected.title\": \"O nie!\",\n  \"boost_modal.combo\": \"Naciśnij {combo}, aby pominąć to następnym razem\",\n  \"bundle_column_error.body\": \"Coś poszło nie tak podczas ładowania tego składnika.\",\n  \"bundle_column_error.retry\": \"Spróbuj ponownie\",\n  \"bundle_column_error.title\": \"Błąd sieci\",\n  \"bundle_modal_error.close\": \"Zamknij\",\n  \"bundle_modal_error.message\": \"Coś poszło nie tak podczas ładowania tego składnika.\",\n  \"bundle_modal_error.retry\": \"Spróbuj ponownie\",\n  \"column.blocks\": \"Zablokowani użytkownicy\",\n  \"column.community\": \"Lokalna oś czasu\",\n  \"column.direct\": \"Wiadomości bezpośrednie\",\n  \"column.domain_blocks\": \"Ukryte domeny\",\n  \"column.favourites\": \"Ulubione\",\n  \"column.follow_requests\": \"Prośby o śledzenie\",\n  \"column.home\": \"Strona główna\",\n  \"column.lists\": \"Listy\",\n  \"column.mutes\": \"Wyciszeni użytkownicy\",\n  \"column.notifications\": \"Powiadomienia\",\n  \"column.pins\": \"Przypięte wpisy\",\n  \"column.public\": \"Globalna oś czasu\",\n  \"column_back_button.label\": \"Wróć\",\n  \"column_header.hide_settings\": \"Ukryj ustawienia\",\n  \"column_header.moveLeft_settings\": \"Przesuń kolumnę w lewo\",\n  \"column_header.moveRight_settings\": \"Przesuń kolumnę w prawo\",\n  \"column_header.pin\": \"Przypnij\",\n  \"column_header.show_settings\": \"Pokaż ustawienia\",\n  \"column_header.unpin\": \"Cofnij przypięcie\",\n  \"column_subheading.settings\": \"Ustawienia\",\n  \"community.column_settings.media_only\": \"Tylko zawartość multimedialna\",\n  \"compose_form.direct_message_warning\": \"Ten wpis będzie widoczny tylko dla wszystkich wspomnianych użytkowników.\",\n  \"compose_form.direct_message_warning_learn_more\": \"Dowiedz się więcej\",\n  \"compose_form.hashtag_warning\": \"Ten wpis nie będzie widoczny pod podanymi hashtagami, ponieważ jest oznaczony jako niewidoczny. Tylko publiczne wpisy mogą zostać znalezione z użyciem hashtagów.\",\n  \"compose_form.lock_disclaimer\": \"Twoje konto nie jest {locked}. Każdy, kto Cię śledzi, może wyświetlać Twoje wpisy przeznaczone tylko dla śledzących.\",\n  \"compose_form.lock_disclaimer.lock\": \"zablokowane\",\n  \"compose_form.placeholder\": \"Co Ci chodzi po głowie?\",\n  \"compose_form.poll.add_option\": \"Dodaj opcję\",\n  \"compose_form.poll.duration\": \"Czas trwania głosowania\",\n  \"compose_form.poll.option_placeholder\": \"Opcja {number}\",\n  \"compose_form.poll.remove_option\": \"Usuń tę opcję\",\n  \"compose_form.publish\": \"Wyślij\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"Oznacz multimedia jako wrażliwe\",\n  \"compose_form.sensitive.marked\": \"Zawartość multimedia jest oznaczona jako wrażliwa\",\n  \"compose_form.sensitive.unmarked\": \"Zawartość multimedialna nie jest oznaczona jako wrażliwa\",\n  \"compose_form.spoiler.marked\": \"Tekst jest ukryty za ostrzeżeniem\",\n  \"compose_form.spoiler.unmarked\": \"Tekst nie jest ukryty\",\n  \"compose_form.spoiler_placeholder\": \"Wprowadź swoje ostrzeżenie o zawartości\",\n  \"confirmation_modal.cancel\": \"Anuluj\",\n  \"confirmations.block.block_and_report\": \"Zablokuj i zgłoś\",\n  \"confirmations.block.confirm\": \"Zablokuj\",\n  \"confirmations.block.message\": \"Czy na pewno chcesz zablokować {name}?\",\n  \"confirmations.delete.confirm\": \"Usuń\",\n  \"confirmations.delete.message\": \"Czy na pewno chcesz usunąć ten wpis?\",\n  \"confirmations.delete_list.confirm\": \"Usuń\",\n  \"confirmations.delete_list.message\": \"Czy na pewno chcesz bezpowrotnie usunąć tą listę?\",\n  \"confirmations.domain_block.confirm\": \"Ukryj wszysyko z domeny\",\n  \"confirmations.domain_block.message\": \"Czy na pewno chcesz zablokować całą domenę {domain}? Zwykle lepszym rozwiązaniem jest blokada lub wyciszenie kilku użytkowników.\",\n  \"confirmations.mute.confirm\": \"Wycisz\",\n  \"confirmations.mute.message\": \"Czy na pewno chcesz wyciszyć {name}?\",\n  \"confirmations.redraft.confirm\": \"Usuń i przeredaguj\",\n  \"confirmations.redraft.message\": \"Czy na pewno chcesz usunąć i przeredagować ten wpis? Polubienia i podbicia zostaną utracone, a odpowiedzi do oryginalnego wpisu zostaną osierocone.\",\n  \"confirmations.reply.confirm\": \"Odpowiedz\",\n  \"confirmations.reply.message\": \"W ten sposób utracisz wpis który obecnie tworzysz. Czy na pewno chcesz to zrobić?\",\n  \"confirmations.unfollow.confirm\": \"Przestań śledzić\",\n  \"confirmations.unfollow.message\": \"Czy na pewno zamierzasz przestać śledzić {name}?\",\n  \"embed.instructions\": \"Osadź ten wpis na swojej stronie wklejając poniższy kod.\",\n  \"embed.preview\": \"Tak będzie to wyglądać:\",\n  \"emoji_button.activity\": \"Aktywność\",\n  \"emoji_button.custom\": \"Niestandardowe\",\n  \"emoji_button.flags\": \"Flagi\",\n  \"emoji_button.food\": \"Żywność i napoje\",\n  \"emoji_button.label\": \"Wstaw emoji\",\n  \"emoji_button.nature\": \"Natura\",\n  \"emoji_button.not_found\": \"Brak emoji!! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"Objekty\",\n  \"emoji_button.people\": \"Ludzie\",\n  \"emoji_button.recent\": \"Najczęściej używane\",\n  \"emoji_button.search\": \"Szukaj…\",\n  \"emoji_button.search_results\": \"Wyniki wyszukiwania\",\n  \"emoji_button.symbols\": \"Symbole\",\n  \"emoji_button.travel\": \"Podróże i miejsca\",\n  \"empty_column.account_timeline\": \"Brak wpisów tutaj!\",\n  \"empty_column.account_unavailable\": \"Profil niedostępny\",\n  \"empty_column.blocks\": \"Nie zablokowałeś(-aś) jeszcze żadnego użytkownika.\",\n  \"empty_column.community\": \"Lokalna oś czasu jest pusta. Napisz coś publicznie, aby zagaić!\",\n  \"empty_column.direct\": \"Nie masz żadnych wiadomości bezpośrednich. Kiedy dostaniesz lub wyślesz jakąś, pojawi się ona tutaj.\",\n  \"empty_column.domain_blocks\": \"Brak ukrytych domen.\",\n  \"empty_column.favourited_statuses\": \"Nie dodałeś(-aś) żadnego wpisu do ulubionych. Kiedy to zrobisz, pojawi się on tutaj.\",\n  \"empty_column.favourites\": \"Nikt nie dodał tego wpisu do ulubionych. Gdy ktoś to zrobi, pojawi się tutaj.\",\n  \"empty_column.follow_requests\": \"Nie masz żadnych próśb o możliwość śledzenia. Kiedy ktoś utworzy ją, pojawi się tutaj.\",\n  \"empty_column.hashtag\": \"Nie ma wpisów oznaczonych tym hashtagiem. Możesz napisać pierwszy(-a)!\",\n  \"empty_column.home\": \"Nie śledzisz nikogo. Odwiedź globalną oś czasu lub użyj wyszukiwarki, aby znaleźć interesujące Cię profile.\",\n  \"empty_column.home.public_timeline\": \"globalna oś czasu\",\n  \"empty_column.list\": \"Nie ma nic na tej liście. Kiedy członkowie listy dodadzą nowe wpisy, pojawia się one tutaj.\",\n  \"empty_column.lists\": \"Nie masz żadnych list. Kiedy utworzysz jedną, pojawi się tutaj.\",\n  \"empty_column.mutes\": \"Nie wyciszyłeś(-aś) jeszcze żadnego użytkownika.\",\n  \"empty_column.notifications\": \"Nie masz żadnych powiadomień. Rozpocznij interakcje z innymi użytkownikami.\",\n  \"empty_column.public\": \"Tu nic nie ma! Napisz coś publicznie, lub dodaj ludzi z innych serwerów, aby to wyświetlić\",\n  \"follow_request.authorize\": \"Autoryzuj\",\n  \"follow_request.reject\": \"Odrzuć\",\n  \"getting_started.developers\": \"Dla programistów\",\n  \"getting_started.directory\": \"Katalog profilów\",\n  \"getting_started.documentation\": \"Dokumentacja\",\n  \"getting_started.heading\": \"Rozpocznij\",\n  \"getting_started.invite\": \"Zaproś znajomych\",\n  \"getting_started.open_source_notice\": \"Mastodon jest oprogramowaniem o otwartym źródle. Możesz pomóc w rozwoju lub zgłaszać błędy na GitHubie tutaj: {github}.\",\n  \"getting_started.security\": \"Bezpieczeństwo\",\n  \"getting_started.terms\": \"Zasady użytkowania\",\n  \"hashtag.column_header.tag_mode.all\": \"i {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"lub {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"bez {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"Nie odnaleziono sugestii\",\n  \"hashtag.column_settings.select.placeholder\": \"Wprowadź hashtagi…\",\n  \"hashtag.column_settings.tag_mode.all\": \"Wszystkie\",\n  \"hashtag.column_settings.tag_mode.any\": \"Dowolne\",\n  \"hashtag.column_settings.tag_mode.none\": \"Żadne\",\n  \"hashtag.column_settings.tag_toggle\": \"Include additional tags in this column\",\n  \"home.column_settings.basic\": \"Podstawowe\",\n  \"home.column_settings.show_reblogs\": \"Pokazuj podbicia\",\n  \"home.column_settings.show_replies\": \"Pokazuj odpowiedzi\",\n  \"intervals.full.days\": \"{number, plural, one {# dzień} few {# dni} many {# dni} other {# dni}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# godzina} few {# godziny} many {# godzin} other {# godzin}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minuta} few {# minuty} many {# minut} other {# minut}}\",\n  \"introduction.federation.action\": \"Dalej\",\n  \"introduction.federation.federated.headline\": \"Oś czasu federacji\",\n  \"introduction.federation.federated.text\": \"Publiczne wpisy osób z tego całego Fediwersum pojawiają się na lokalnej osi czasu.\",\n  \"introduction.federation.home.headline\": \"Strona główna\",\n  \"introduction.federation.home.text\": \"Wpisy osób które śledzisz pojawią się na stronie głównej. Możesz zacząć śledzić użytkowników dowolnego serwera!\",\n  \"introduction.federation.local.headline\": \"Lokalna oś czasu\",\n  \"introduction.federation.local.text\": \"Publiczne wpisy osób z tego samego serwera pojawiają się na lokalnej osi czasu.\",\n  \"introduction.interactions.action\": \"Zakończ poradnik!\",\n  \"introduction.interactions.favourite.headline\": \"Ulubione\",\n  \"introduction.interactions.favourite.text\": \"Możesz zapisać wpis na później i pokazać autorowi, że Ci się spodobał, jeżeli dodasz go .\",\n  \"introduction.interactions.reblog.headline\": \"Podbicia\",\n  \"introduction.interactions.reblog.text\": \"Możesz podzielić się wpisem innego użytkownikami z osobami które Cię śledzą podbijając go.\",\n  \"introduction.interactions.reply.headline\": \"Odpowiedzi\",\n  \"introduction.interactions.reply.text\": \"Możesz odpowiadać na wpisy swoje i innych, tworząc konwersację.\",\n  \"introduction.welcome.action\": \"Rozpocznij!\",\n  \"introduction.welcome.headline\": \"Pierwsze kroki\",\n  \"introduction.welcome.text\": \"Witmay w Fediwersum! Za chwilę dowiesz się, jak przekazywać wiadomości i rozmawiać ze znajomymi pomiędzy różnymi serwerami. Ale ten serwer – {domain} jest wyjątkowy, ponieważ zawiera Twój profil – zapamiętaj więc jego nazwę.\",\n  \"keyboard_shortcuts.back\": \"aby cofnąć się\",\n  \"keyboard_shortcuts.blocked\": \"aby przejść do listy zablokowanych użytkowników\",\n  \"keyboard_shortcuts.boost\": \"aby podbić wpis\",\n  \"keyboard_shortcuts.column\": \"aby przejść do wpisu z jednej z kolumn\",\n  \"keyboard_shortcuts.compose\": \"aby przejść do pola tworzenia wpisu\",\n  \"keyboard_shortcuts.description\": \"Opis\",\n  \"keyboard_shortcuts.direct\": \"aby otworzyć kolumnę wiadomości bezpośrednich\",\n  \"keyboard_shortcuts.down\": \"aby przejść na dół listy\",\n  \"keyboard_shortcuts.enter\": \"aby otworzyć wpis\",\n  \"keyboard_shortcuts.favourite\": \"aby dodać do ulubionych\",\n  \"keyboard_shortcuts.favourites\": \"aby przejść do listy ulubionych wpisów\",\n  \"keyboard_shortcuts.federated\": \"aby otworzyć oś czasu federacji\",\n  \"keyboard_shortcuts.heading\": \"Skróty klawiszowe\",\n  \"keyboard_shortcuts.home\": \"aby otworzyć stronę główną\",\n  \"keyboard_shortcuts.hotkey\": \"Klawisz\",\n  \"keyboard_shortcuts.legend\": \"aby wyświetlić tę legendę\",\n  \"keyboard_shortcuts.local\": \"aby otworzyć lokalną oś czasu\",\n  \"keyboard_shortcuts.mention\": \"aby wspomnieć o autorze\",\n  \"keyboard_shortcuts.muted\": \"aby przejść do listy wyciszonych użytkowników\",\n  \"keyboard_shortcuts.my_profile\": \"aby otworzyć własny profil\",\n  \"keyboard_shortcuts.notifications\": \"aby otworzyć kolumnę powiadomień\",\n  \"keyboard_shortcuts.pinned\": \"aby przejść do listy przypiętych wpisów\",\n  \"keyboard_shortcuts.profile\": \"aby przejść do profilu autora wpisu\",\n  \"keyboard_shortcuts.reply\": \"aby odpowiedzieć\",\n  \"keyboard_shortcuts.requests\": \"aby przejść do listy próśb o możliwość śledzenia\",\n  \"keyboard_shortcuts.search\": \"aby przejść do pola wyszukiwania\",\n  \"keyboard_shortcuts.start\": \"aby otworzyć kolumnę „Rozpocznij”\",\n  \"keyboard_shortcuts.toggle_hidden\": \"aby wyświetlić lub ukryć wpis spod CW\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"by pokazać/ukryć multimedia\",\n  \"keyboard_shortcuts.toot\": \"aby utworzyć nowy wpis\",\n  \"keyboard_shortcuts.unfocus\": \"aby opuścić pole wyszukiwania/pisania\",\n  \"keyboard_shortcuts.up\": \"aby przejść na górę listy\",\n  \"lightbox.close\": \"Zamknij\",\n  \"lightbox.next\": \"Następne\",\n  \"lightbox.previous\": \"Poprzednie\",\n  \"lightbox.view_context\": \"Pokaż kontekst\",\n  \"lists.account.add\": \"Dodaj do listy\",\n  \"lists.account.remove\": \"Usunąć z listy\",\n  \"lists.delete\": \"Usuń listę\",\n  \"lists.edit\": \"Edytuj listę\",\n  \"lists.edit.submit\": \"Zmień tytuł\",\n  \"lists.new.create\": \"Utwórz listę\",\n  \"lists.new.title_placeholder\": \"Wprowadź tytuł listy\",\n  \"lists.search\": \"Szukaj wśród osób które śledzisz\",\n  \"lists.subheading\": \"Twoje listy\",\n  \"loading_indicator.label\": \"Ładowanie…\",\n  \"media_gallery.toggle_visible\": \"Przełącz widoczność\",\n  \"missing_indicator.label\": \"Nie znaleziono\",\n  \"missing_indicator.sublabel\": \"Nie można odnaleźć tego zasobu\",\n  \"mute_modal.hide_notifications\": \"Chcesz ukryć powiadomienia od tego użytkownika?\",\n  \"navigation_bar.apps\": \"Aplikacje mobilne\",\n  \"navigation_bar.blocks\": \"Zablokowani użytkownicy\",\n  \"navigation_bar.community_timeline\": \"Lokalna oś czasu\",\n  \"navigation_bar.compose\": \"Utwórz nowy wpis\",\n  \"navigation_bar.direct\": \"Wiadomości bezpośrednie\",\n  \"navigation_bar.discover\": \"Odkrywaj\",\n  \"navigation_bar.domain_blocks\": \"Ukryte domeny\",\n  \"navigation_bar.edit_profile\": \"Edytuj profil\",\n  \"navigation_bar.favourites\": \"Ulubione\",\n  \"navigation_bar.filters\": \"Wyciszone słowa\",\n  \"navigation_bar.follow_requests\": \"Prośby o śledzenie\",\n  \"navigation_bar.follows_and_followers\": \"Śledzeni i śledzący\",\n  \"navigation_bar.info\": \"Szczegółowe informacje\",\n  \"navigation_bar.keyboard_shortcuts\": \"Skróty klawiszowe\",\n  \"navigation_bar.lists\": \"Listy\",\n  \"navigation_bar.logout\": \"Wyloguj\",\n  \"navigation_bar.mutes\": \"Wyciszeni użytkownicy\",\n  \"navigation_bar.personal\": \"Osobiste\",\n  \"navigation_bar.pins\": \"Przypięte wpisy\",\n  \"navigation_bar.preferences\": \"Preferencje\",\n  \"navigation_bar.profile_directory\": \"Katalog profilów\",\n  \"navigation_bar.public_timeline\": \"Globalna oś czasu\",\n  \"navigation_bar.security\": \"Bezpieczeństwo\",\n  \"notification.favourite\": \"{name} dodał(a) Twój wpis do ulubionych\",\n  \"notification.follow\": \"{name} zaczął(-ęła) Cię śledzić\",\n  \"notification.mention\": \"{name} wspomniał(a) o tobie\",\n  \"notification.poll\": \"Głosowanie w którym brałeś(-aś) udział zakończyła się\",\n  \"notification.reblog\": \"{name} podbił(a) Twój wpis\",\n  \"notifications.clear\": \"Wyczyść powiadomienia\",\n  \"notifications.clear_confirmation\": \"Czy na pewno chcesz bezpowrotnie usunąć wszystkie powiadomienia?\",\n  \"notifications.column_settings.alert\": \"Powiadomienia na pulpicie\",\n  \"notifications.column_settings.favourite\": \"Dodanie do ulubionych:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Wyświetl wszystkie kategorie\",\n  \"notifications.column_settings.filter_bar.category\": \"Szybkie filtrowanie\",\n  \"notifications.column_settings.filter_bar.show\": \"Pokaż\",\n  \"notifications.column_settings.follow\": \"Nowi śledzący:\",\n  \"notifications.column_settings.mention\": \"Wspomnienia:\",\n  \"notifications.column_settings.poll\": \"Wyniki głosowania:\",\n  \"notifications.column_settings.push\": \"Powiadomienia push\",\n  \"notifications.column_settings.reblog\": \"Podbicia:\",\n  \"notifications.column_settings.show\": \"Pokaż w kolumnie\",\n  \"notifications.column_settings.sound\": \"Odtwarzaj dźwięk\",\n  \"notifications.filter.all\": \"Wszystkie\",\n  \"notifications.filter.boosts\": \"Podbicia\",\n  \"notifications.filter.favourites\": \"Ulubione\",\n  \"notifications.filter.follows\": \"Śledzenia\",\n  \"notifications.filter.mentions\": \"Wspomienia\",\n  \"notifications.filter.polls\": \"Wyniki głosowania\",\n  \"notifications.group\": \"{count, number} {count, plural, one {powiadomienie} few {powiadomienia} many {powiadomień} more {powiadomień}}\",\n  \"poll.closed\": \"Zamknięte\",\n  \"poll.refresh\": \"Odśwież\",\n  \"poll.total_votes\": \"{count, plural, one {# głos} few {# głosy} many {# głosów} other {# głosów}}\",\n  \"poll.vote\": \"Zagłosuj\",\n  \"poll_button.add_poll\": \"Dodaj głosowanie\",\n  \"poll_button.remove_poll\": \"Usuń głosowanie\",\n  \"privacy.change\": \"Dostosuj widoczność wpisów\",\n  \"privacy.direct.long\": \"Widoczny tylko dla wspomnianych\",\n  \"privacy.direct.short\": \"Bezpośrednio\",\n  \"privacy.private.long\": \"Widoczny tylko dla osób, które Cię śledzą\",\n  \"privacy.private.short\": \"Tylko dla śledzących\",\n  \"privacy.public.long\": \"Widoczny na publicznych osiach czasu\",\n  \"privacy.public.short\": \"Publiczny\",\n  \"privacy.unlisted.long\": \"Niewidoczny na publicznych osiach czasu\",\n  \"privacy.unlisted.short\": \"Niewidoczny\",\n  \"regeneration_indicator.label\": \"Ładuję…\",\n  \"regeneration_indicator.sublabel\": \"Twoja oś czasu jest przygotowywana!\",\n  \"relative_time.days\": \"{number} dni\",\n  \"relative_time.hours\": \"{number} godz.\",\n  \"relative_time.just_now\": \"teraz\",\n  \"relative_time.minutes\": \"{number} min.\",\n  \"relative_time.seconds\": \"{number} s.\",\n  \"reply_indicator.cancel\": \"Anuluj\",\n  \"report.forward\": \"Przekaż na {target}\",\n  \"report.forward_hint\": \"To konto znajduje się na innej instancji. Czy chcesz wysłać anonimową kopię zgłoszenia rnież na nią?\",\n  \"report.hint\": \"Zgłoszenie zostanie wysłane moderatorom Twojego serwera. Poniżej możesz też umieścić wyjaśnienie dlaczego zgłaszasz to konto:\",\n  \"report.placeholder\": \"Dodatkowe komentarze\",\n  \"report.submit\": \"Wyślij\",\n  \"report.target\": \"Zgłaszanie {target}\",\n  \"search.placeholder\": \"Szukaj\",\n  \"search_popout.search_format\": \"Zaawansowane wyszukiwanie\",\n  \"search_popout.tips.full_text\": \"Pozwala na wyszukiwanie wpisów które napisałeś(-aś), dodałeś(-aś) do ulubionych lub podbiłeś(-aś), w których o Tobie wspomniano, oraz pasujące nazwy użytkowników, pełne nazwy i hashtagi.\",\n  \"search_popout.tips.hashtag\": \"hasztag\",\n  \"search_popout.tips.status\": \"wpis\",\n  \"search_popout.tips.text\": \"Proste wyszukiwanie pasujących pseudonimów, nazw użytkowników i hashtagów\",\n  \"search_popout.tips.user\": \"użytkownik\",\n  \"search_results.accounts\": \"Ludzie\",\n  \"search_results.hashtags\": \"Hashtagi\",\n  \"search_results.statuses\": \"Wpisy\",\n  \"search_results.total\": \"{count, number} {count, plural, one {wynik} few {wyniki} many {wyników} more {wyników}}\",\n  \"status.admin_account\": \"Otwórz interfejs moderacyjny dla @{name}\",\n  \"status.admin_status\": \"Otwórz ten wpis w interfejsie moderacyjnym\",\n  \"status.block\": \"Zablokuj @{name}\",\n  \"status.cancel_reblog_private\": \"Cofnij podbicie\",\n  \"status.cannot_reblog\": \"Ten wpis nie może zostać podbity\",\n  \"status.copy\": \"Skopiuj odnośnik do wpisu\",\n  \"status.delete\": \"Usuń\",\n  \"status.detailed_status\": \"Szczegółowy widok konwersacji\",\n  \"status.direct\": \"Wyślij wiadomość bezpośrednią do @{name}\",\n  \"status.embed\": \"Osadź\",\n  \"status.favourite\": \"Dodaj do ulubionych\",\n  \"status.filtered\": \"Filtrowany(-a)\",\n  \"status.load_more\": \"Załaduj więcej\",\n  \"status.media_hidden\": \"Zawartość multimedialna ukryta\",\n  \"status.mention\": \"Wspomnij o @{name}\",\n  \"status.more\": \"Więcej\",\n  \"status.mute\": \"Wycisz @{name}\",\n  \"status.mute_conversation\": \"Wycisz konwersację\",\n  \"status.open\": \"Rozszerz ten wpis\",\n  \"status.pin\": \"Przypnij do profilu\",\n  \"status.pinned\": \"Przypięty wpis\",\n  \"status.read_more\": \"Czytaj dalej\",\n  \"status.reblog\": \"Podbij\",\n  \"status.reblog_private\": \"Podbij dla odbiorców oryginalnego wpisu\",\n  \"status.reblogged_by\": \"{name} podbił(a)\",\n  \"status.reblogs.empty\": \"Nikt nie podbił jeszcze tego wpisu. Gdy ktoś to zrobi, pojawi się tutaj.\",\n  \"status.redraft\": \"Usuń i przeredaguj\",\n  \"status.reply\": \"Odpowiedz\",\n  \"status.replyAll\": \"Odpowiedz na wątek\",\n  \"status.report\": \"Zgłoś @{name}\",\n  \"status.sensitive_warning\": \"Wrażliwa zawartość\",\n  \"status.share\": \"Udostępnij\",\n  \"status.show_less\": \"Zwiń\",\n  \"status.show_less_all\": \"Zwiń wszystkie\",\n  \"status.show_more\": \"Rozwiń\",\n  \"status.show_more_all\": \"Rozwiń wszystkie\",\n  \"status.show_thread\": \"Pokaż wątek\",\n  \"status.unmute_conversation\": \"Cofnij wyciszenie konwersacji\",\n  \"status.unpin\": \"Odepnij z profilu\",\n  \"suggestions.dismiss\": \"Odrzuć sugestię\",\n  \"suggestions.header\": \"Może Cię zainteresować…\",\n  \"tabs_bar.federated_timeline\": \"Globalne\",\n  \"tabs_bar.home\": \"Strona główna\",\n  \"tabs_bar.local_timeline\": \"Lokalne\",\n  \"tabs_bar.notifications\": \"Powiadomienia\",\n  \"tabs_bar.search\": \"Szukaj\",\n  \"time_remaining.days\": \"{number, plural, one {Pozostał # dzień} few {Pozostały # dni} many {Pozostało # dni} other {Pozostało # dni}}\",\n  \"time_remaining.hours\": \"{number, plural, one {Pozostała # godzina} few {Pozostały # godziny} many {Pozostało # godzin} other {Pozostało # godzin}}\",\n  \"time_remaining.minutes\": \"{number, plural, one {Pozostała # minuta} few {Pozostały # minuty} many {Pozostało # minut} other {Pozostało # minut}}\",\n  \"time_remaining.moments\": \"Pozostała chwila\",\n  \"time_remaining.seconds\": \"{number, plural, one {Pozostała # sekunda} few {Pozostały # sekundy} many {Pozostało # sekund} other {Pozostało # sekund}}\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {osoba rozmawia} few {osoby rozmawiają} other {osób rozmawia}} o tym\",\n  \"ui.beforeunload\": \"Utracisz tworzony wpis, jeżeli opuścisz Mastodona.\",\n  \"upload_area.title\": \"Przeciągnij i upuść aby wysłać\",\n  \"upload_button.label\": \"Dodaj zawartość multimedialną (JPEG, PNG, GIF, WebM, MP4, MOV)\",\n  \"upload_error.limit\": \"Przekroczono limit plików do wysłania.\",\n  \"upload_error.poll\": \"Dołączanie plików nie dozwolone z głosowaniami.\",\n  \"upload_form.description\": \"Wprowadź opis dla niewidomych i niedowidzących\",\n  \"upload_form.focus\": \"Dopasuj podgląd\",\n  \"upload_form.undo\": \"Usuń\",\n  \"upload_progress.label\": \"Wysyłanie…\",\n  \"video.close\": \"Zamknij film\",\n  \"video.exit_fullscreen\": \"Opuść tryb pełnoekranowy\",\n  \"video.expand\": \"Rozszerz film\",\n  \"video.fullscreen\": \"Pełny ekran\",\n  \"video.hide\": \"Ukryj film\",\n  \"video.mute\": \"Wycisz\",\n  \"video.pause\": \"Pauzuj\",\n  \"video.play\": \"Odtwórz\",\n  \"video.unmute\": \"Cofnij wyciszenie\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/pt-BR.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Adicionar ou remover de listas\",\n  \"account.badges.bot\": \"Robô\",\n  \"account.block\": \"Bloquear @{name}\",\n  \"account.block_domain\": \"Esconder tudo de {domain}\",\n  \"account.blocked\": \"Bloqueado\",\n  \"account.direct\": \"Direct Message @{name}\",\n  \"account.domain_blocked\": \"Domínio escondido\",\n  \"account.edit_profile\": \"Editar perfil\",\n  \"account.endorse\": \"Destacar no perfil\",\n  \"account.follow\": \"Seguir\",\n  \"account.followers\": \"Seguidores\",\n  \"account.followers.empty\": \"Ninguém segue esse usuário no momento.\",\n  \"account.follows\": \"Segue\",\n  \"account.follows.empty\": \"Esse usuário não segue ninguém no momento.\",\n  \"account.follows_you\": \"Segue você\",\n  \"account.hide_reblogs\": \"Esconder compartilhamentos de @{name}\",\n  \"account.link_verified_on\": \"A posse desse link foi verificada em {date}\",\n  \"account.locked_info\": \"Essa conta está trancada. Se você a seguir sua solicitação será revisada manualmente.\",\n  \"account.media\": \"Mídia\",\n  \"account.mention\": \"Mencionar @{name}\",\n  \"account.moved_to\": \"{name} se mudou para:\",\n  \"account.mute\": \"Silenciar @{name}\",\n  \"account.mute_notifications\": \"Silenciar notificações de @{name}\",\n  \"account.muted\": \"Silenciado\",\n  \"account.posts\": \"Toots\",\n  \"account.posts_with_replies\": \"Toots e respostas\",\n  \"account.report\": \"Denunciar @{name}\",\n  \"account.requested\": \"Aguardando aprovação. Clique para cancelar a solicitação\",\n  \"account.share\": \"Compartilhar perfil de @{name}\",\n  \"account.show_reblogs\": \"Mostra compartilhamentos de @{name}\",\n  \"account.unblock\": \"Desbloquear @{name}\",\n  \"account.unblock_domain\": \"Desbloquear {domain}\",\n  \"account.unendorse\": \"Não destacar no perfil\",\n  \"account.unfollow\": \"Deixar de seguir\",\n  \"account.unmute\": \"Não silenciar @{name}\",\n  \"account.unmute_notifications\": \"Retirar silêncio das notificações vindas de @{name}\",\n  \"alert.unexpected.message\": \"Um erro inesperado ocorreu.\",\n  \"alert.unexpected.title\": \"Oops!\",\n  \"boost_modal.combo\": \"Você pode pressionar {combo} para ignorar este diálogo na próxima vez\",\n  \"bundle_column_error.body\": \"Algo de errado aconteceu enquanto este componente era carregado.\",\n  \"bundle_column_error.retry\": \"Tente novamente\",\n  \"bundle_column_error.title\": \"Erro de rede\",\n  \"bundle_modal_error.close\": \"Fechar\",\n  \"bundle_modal_error.message\": \"Algo de errado aconteceu enquanto este componente era carregado.\",\n  \"bundle_modal_error.retry\": \"Tente novamente\",\n  \"column.blocks\": \"Usuários bloqueados\",\n  \"column.community\": \"Local\",\n  \"column.direct\": \"Mensagens diretas\",\n  \"column.domain_blocks\": \"Domínios escondidos\",\n  \"column.favourites\": \"Favoritos\",\n  \"column.follow_requests\": \"Seguidores pendentes\",\n  \"column.home\": \"Página inicial\",\n  \"column.lists\": \"Listas\",\n  \"column.mutes\": \"Usuários silenciados\",\n  \"column.notifications\": \"Notificações\",\n  \"column.pins\": \"Postagens fixadas\",\n  \"column.public\": \"Global\",\n  \"column_back_button.label\": \"Voltar\",\n  \"column_header.hide_settings\": \"Esconder configurações\",\n  \"column_header.moveLeft_settings\": \"Mover coluna para a esquerda\",\n  \"column_header.moveRight_settings\": \"Mover coluna para a direita\",\n  \"column_header.pin\": \"Fixar\",\n  \"column_header.show_settings\": \"Mostrar configurações\",\n  \"column_header.unpin\": \"Desafixar\",\n  \"column_subheading.settings\": \"Configurações\",\n  \"community.column_settings.media_only\": \"Apenas mídia\",\n  \"compose_form.direct_message_warning\": \"Este toot só será enviado aos usuários mencionados.\",\n  \"compose_form.direct_message_warning_learn_more\": \"Saber mais\",\n  \"compose_form.hashtag_warning\": \"Esse toot não será listado em nenhuma hashtag por ser não listado. Somente toots públicos podem ser pesquisados por hashtag.\",\n  \"compose_form.lock_disclaimer\": \"A sua conta não está {locked}. Qualquer pessoa pode te seguir e visualizar postagens direcionadas a apenas seguidores.\",\n  \"compose_form.lock_disclaimer.lock\": \"trancada\",\n  \"compose_form.placeholder\": \"No que você está pensando?\",\n  \"compose_form.poll.add_option\": \"Adicionar uma opção\",\n  \"compose_form.poll.duration\": \"Duração da enquete\",\n  \"compose_form.poll.option_placeholder\": \"Opção {number}\",\n  \"compose_form.poll.remove_option\": \"Remover essa opção\",\n  \"compose_form.publish\": \"Publicar\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"Mark media as sensitive\",\n  \"compose_form.sensitive.marked\": \"Mídia está marcada como sensível\",\n  \"compose_form.sensitive.unmarked\": \"Mídia não está marcada como sensível\",\n  \"compose_form.spoiler.marked\": \"O texto está escondido por um aviso de conteúdo\",\n  \"compose_form.spoiler.unmarked\": \"O texto não está escondido\",\n  \"compose_form.spoiler_placeholder\": \"Aviso de conteúdo\",\n  \"confirmation_modal.cancel\": \"Cancelar\",\n  \"confirmations.block.block_and_report\": \"Bloquear e denunciar\",\n  \"confirmations.block.confirm\": \"Bloquear\",\n  \"confirmations.block.message\": \"Você tem certeza de que quer bloquear {name}?\",\n  \"confirmations.delete.confirm\": \"Excluir\",\n  \"confirmations.delete.message\": \"Você tem certeza de que quer excluir esta postagem?\",\n  \"confirmations.delete_list.confirm\": \"Delete\",\n  \"confirmations.delete_list.message\": \"Você tem certeza que quer deletar permanentemente a lista?\",\n  \"confirmations.domain_block.confirm\": \"Esconder o domínio inteiro\",\n  \"confirmations.domain_block.message\": \"Você quer mesmo bloquear {domain} inteiro? Na maioria dos casos, silenciar ou bloquear alguns usuários é o suficiente e o recomendado. Você não vai ver conteúdo desse domínio em nenhuma das timelines públicas ou nas suas notificações. Seus seguidores desse domínio serão removidos.\",\n  \"confirmations.mute.confirm\": \"Silenciar\",\n  \"confirmations.mute.message\": \"Você tem certeza de que quer silenciar {name}?\",\n  \"confirmations.redraft.confirm\": \"Apagar & usar como rascunho\",\n  \"confirmations.redraft.message\": \"Você tem certeza que deseja apagar esse status e usá-lo como rascunho? Seus compartilhamentos e favoritos serão perdidos e as respostas ao toot original ficarão desconectadas.\",\n  \"confirmations.reply.confirm\": \"Responder\",\n  \"confirmations.reply.message\": \"Responder agora vai sobrescrever a mensagem que você está compondo. Você tem certeza que quer continuar?\",\n  \"confirmations.unfollow.confirm\": \"Deixar de seguir\",\n  \"confirmations.unfollow.message\": \"Você tem certeza de que quer deixar de seguir {name}?\",\n  \"embed.instructions\": \"Incorpore esta postagem em seu site copiando o código abaixo.\",\n  \"embed.preview\": \"Aqui está uma previsão de como ficará:\",\n  \"emoji_button.activity\": \"Atividades\",\n  \"emoji_button.custom\": \"Customizados\",\n  \"emoji_button.flags\": \"Bandeiras\",\n  \"emoji_button.food\": \"Comidas & Bebidas\",\n  \"emoji_button.label\": \"Inserir Emoji\",\n  \"emoji_button.nature\": \"Natureza\",\n  \"emoji_button.not_found\": \"Não tem emojos! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"Objetos\",\n  \"emoji_button.people\": \"Pessoas\",\n  \"emoji_button.recent\": \"Usados frequentemente\",\n  \"emoji_button.search\": \"Buscar...\",\n  \"emoji_button.search_results\": \"Resultados da busca\",\n  \"emoji_button.symbols\": \"Símbolos\",\n  \"emoji_button.travel\": \"Viagens & Lugares\",\n  \"empty_column.account_timeline\": \"Não há toots aqui!\",\n  \"empty_column.account_unavailable\": \"Perfil indisponível\",\n  \"empty_column.blocks\": \"Você ainda não bloqueou nenhum usuário.\",\n  \"empty_column.community\": \"A timeline local está vazia. Escreva algo publicamente para começar!\",\n  \"empty_column.direct\": \"Você não tem nenhuma mensagem direta ainda. Quando você enviar ou receber uma, as mensagens aparecerão por aqui.\",\n  \"empty_column.domain_blocks\": \"Ainda não há nenhum domínio escondido.\",\n  \"empty_column.favourited_statuses\": \"Você ainda não tem nenhum toot favorito. Quando você favoritar um toot, ele aparecerá aqui.\",\n  \"empty_column.favourites\": \"Ninguém favoritou esse toot até agora. Quando alguém favoritar, a pessoa aparecerá aqui.\",\n  \"empty_column.follow_requests\": \"Você não tem nenhum pedido de seguir por agora. Quando você receber um, ele aparecerá aqui.\",\n  \"empty_column.hashtag\": \"Ainda não há qualquer conteúdo com essa hashtag.\",\n  \"empty_column.home\": \"Você ainda não segue usuário algum. Visite a timeline {public} ou use o buscador para procurar e conhecer outros usuários.\",\n  \"empty_column.home.public_timeline\": \"global\",\n  \"empty_column.list\": \"Ainda não há nada nesta lista. Quando membros dessa lista fizerem novas postagens, elas aparecerão aqui.\",\n  \"empty_column.lists\": \"Você ainda não tem nenhuma lista. Quando você criar uma, ela aparecerá aqui.\",\n  \"empty_column.mutes\": \"Você ainda não silenciou nenhum usuário.\",\n  \"empty_column.notifications\": \"Você ainda não possui notificações. Interaja com outros usuários para começar a conversar.\",\n  \"empty_column.public\": \"Não há nada aqui! Escreva algo publicamente ou siga manualmente usuários de outras instâncias\",\n  \"follow_request.authorize\": \"Autorizar\",\n  \"follow_request.reject\": \"Rejeitar\",\n  \"getting_started.developers\": \"Desenvolvedores\",\n  \"getting_started.directory\": \"Diretório de perfis\",\n  \"getting_started.documentation\": \"Documentação\",\n  \"getting_started.heading\": \"Primeiros passos\",\n  \"getting_started.invite\": \"Convide pessoas\",\n  \"getting_started.open_source_notice\": \"Mastodon é um software de código aberto. Você pode contribuir ou reportar problemas na página do GitHub do projeto: {github}.\",\n  \"getting_started.security\": \"Segurança\",\n  \"getting_started.terms\": \"Termos de serviço\",\n  \"hashtag.column_header.tag_mode.all\": \"e {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"ou {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"sem {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"Nenhuma sugestão encontrada\",\n  \"hashtag.column_settings.select.placeholder\": \"Adicione as hashtags…\",\n  \"hashtag.column_settings.tag_mode.all\": \"Todas essas\",\n  \"hashtag.column_settings.tag_mode.any\": \"Qualquer uma dessas\",\n  \"hashtag.column_settings.tag_mode.none\": \"Nenhuma dessas\",\n  \"hashtag.column_settings.tag_toggle\": \"Incluir outras hashtags nessa coluna\",\n  \"home.column_settings.basic\": \"Básico\",\n  \"home.column_settings.show_reblogs\": \"Mostrar compartilhamentos\",\n  \"home.column_settings.show_replies\": \"Mostrar as respostas\",\n  \"intervals.full.days\": \"{number, plural, one {# dia} other {# dias}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# hora} other {# horas}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minute} other {# minutes}}\",\n  \"introduction.federation.action\": \"Próximo\",\n  \"introduction.federation.federated.headline\": \"Federated\",\n  \"introduction.federation.federated.text\": \"Posts públicos de outros servidores do fediverso vão aparecer na timeline global.\",\n  \"introduction.federation.home.headline\": \"Home\",\n  \"introduction.federation.home.text\": \"Posts de pessoas que você segue vão aparecer na sua página inicial. Você pode seguir pessoas de qualquer servidor!\",\n  \"introduction.federation.local.headline\": \"Local\",\n  \"introduction.federation.local.text\": \"Posts públicos de pessoas no mesmo servidor que você vão aparecer na timeline local.\",\n  \"introduction.interactions.action\": \"Finalizar o tutorial!\",\n  \"introduction.interactions.favourite.headline\": \"Favoritos\",\n  \"introduction.interactions.favourite.text\": \"Você pode salvar um toot pra mais tarde, e deixar a pessoa que postou saber que você gostou, favoritando-o.\",\n  \"introduction.interactions.reblog.headline\": \"Compartilhamento\",\n  \"introduction.interactions.reblog.text\": \"Você pode mostrar toots de outras pessoas aos seus seguidores compartilhando.\",\n  \"introduction.interactions.reply.headline\": \"Responder\",\n  \"introduction.interactions.reply.text\": \"Você pode responder a toots de outras pessoas e aos seus, e isso vai uni-los em uma conversa.\",\n  \"introduction.welcome.action\": \"Vamos!\",\n  \"introduction.welcome.headline\": \"Primeiros passos\",\n  \"introduction.welcome.text\": \"Boas vindas ao fediverso! Em alguns momentos, você vai poder transmitir mensagens e falar com pessoas amigas através de uma variedade de servidores. Mas esse servidor, {domain}, é especial—é onde o seu perfil está hospedado, então lembre do nome.\",\n  \"keyboard_shortcuts.back\": \"para navegar de volta\",\n  \"keyboard_shortcuts.blocked\": \"para abrir a lista de usuários bloqueados\",\n  \"keyboard_shortcuts.boost\": \"para compartilhar\",\n  \"keyboard_shortcuts.column\": \"Focar um status em uma das colunas\",\n  \"keyboard_shortcuts.compose\": \"para focar a área de redação\",\n  \"keyboard_shortcuts.description\": \"Descrição\",\n  \"keyboard_shortcuts.direct\": \"para abrir a coluna de mensagens diretas\",\n  \"keyboard_shortcuts.down\": \"para mover para baixo na lista\",\n  \"keyboard_shortcuts.enter\": \"para expandir um status\",\n  \"keyboard_shortcuts.favourite\": \"para adicionar aos favoritos\",\n  \"keyboard_shortcuts.favourites\": \"para abrir a lista de favoritos\",\n  \"keyboard_shortcuts.federated\": \"para abrir a timeline global\",\n  \"keyboard_shortcuts.heading\": \"Atalhos de teclado\",\n  \"keyboard_shortcuts.home\": \"para abrir a página inicial\",\n  \"keyboard_shortcuts.hotkey\": \"Atalho\",\n  \"keyboard_shortcuts.legend\": \"para mostrar essa legenda\",\n  \"keyboard_shortcuts.local\": \"para abrir a timeline local\",\n  \"keyboard_shortcuts.mention\": \"para mencionar o autor\",\n  \"keyboard_shortcuts.muted\": \"para abrir a lista de usuários silenciados\",\n  \"keyboard_shortcuts.my_profile\": \"para abrir o seu perfil\",\n  \"keyboard_shortcuts.notifications\": \"para abrir a coluna de notificações\",\n  \"keyboard_shortcuts.pinned\": \"para abrir a lista de toots fixados\",\n  \"keyboard_shortcuts.profile\": \"para abrir o perfil do autor\",\n  \"keyboard_shortcuts.reply\": \"para responder\",\n  \"keyboard_shortcuts.requests\": \"para abrir a lista de seguidores pendentes\",\n  \"keyboard_shortcuts.search\": \"para focar a pesquisa\",\n  \"keyboard_shortcuts.start\": \"para abrir a coluna \\\"primeiros passos\\\"\",\n  \"keyboard_shortcuts.toggle_hidden\": \"mostrar/esconder o texto com aviso de conteúdo\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"to show/hide media\",\n  \"keyboard_shortcuts.toot\": \"para compor um novo toot\",\n  \"keyboard_shortcuts.unfocus\": \"para remover o foco da área de composição/pesquisa\",\n  \"keyboard_shortcuts.up\": \"para mover para cima na lista\",\n  \"lightbox.close\": \"Fechar\",\n  \"lightbox.next\": \"Próximo\",\n  \"lightbox.previous\": \"Anterior\",\n  \"lightbox.view_context\": \"View context\",\n  \"lists.account.add\": \"Adicionar a listas\",\n  \"lists.account.remove\": \"Remover da lista\",\n  \"lists.delete\": \"Delete list\",\n  \"lists.edit\": \"Editar lista\",\n  \"lists.edit.submit\": \"Mudar o título\",\n  \"lists.new.create\": \"Adicionar lista\",\n  \"lists.new.title_placeholder\": \"Novo título da lista\",\n  \"lists.search\": \"Procurar entre as pessoas que você segue\",\n  \"lists.subheading\": \"Suas listas\",\n  \"loading_indicator.label\": \"Carregando...\",\n  \"media_gallery.toggle_visible\": \"Esconder/Mostrar\",\n  \"missing_indicator.label\": \"Não encontrado\",\n  \"missing_indicator.sublabel\": \"Esse recurso não pôde ser encontrado\",\n  \"mute_modal.hide_notifications\": \"Esconder notificações deste usuário?\",\n  \"navigation_bar.apps\": \"Apps\",\n  \"navigation_bar.blocks\": \"Usuários bloqueados\",\n  \"navigation_bar.community_timeline\": \"Local\",\n  \"navigation_bar.compose\": \"Compor um novo toot\",\n  \"navigation_bar.direct\": \"Mensagens diretas\",\n  \"navigation_bar.discover\": \"Descobrir\",\n  \"navigation_bar.domain_blocks\": \"Domínios escondidos\",\n  \"navigation_bar.edit_profile\": \"Editar perfil\",\n  \"navigation_bar.favourites\": \"Favoritos\",\n  \"navigation_bar.filters\": \"Palavras silenciadas\",\n  \"navigation_bar.follow_requests\": \"Seguidores pendentes\",\n  \"navigation_bar.follows_and_followers\": \"Follows and followers\",\n  \"navigation_bar.info\": \"Mais informações\",\n  \"navigation_bar.keyboard_shortcuts\": \"Atalhos de teclado\",\n  \"navigation_bar.lists\": \"Listas\",\n  \"navigation_bar.logout\": \"Sair\",\n  \"navigation_bar.mutes\": \"Usuários silenciados\",\n  \"navigation_bar.personal\": \"Pessoal\",\n  \"navigation_bar.pins\": \"Postagens fixadas\",\n  \"navigation_bar.preferences\": \"Preferências\",\n  \"navigation_bar.profile_directory\": \"Profile directory\",\n  \"navigation_bar.public_timeline\": \"Global\",\n  \"navigation_bar.security\": \"Segurança\",\n  \"notification.favourite\": \"{name} adicionou a sua postagem aos favoritos\",\n  \"notification.follow\": \"{name} te seguiu\",\n  \"notification.mention\": \"{name} te mencionou\",\n  \"notification.poll\": \"Uma enquete em que você votou chegou ao fim\",\n  \"notification.reblog\": \"{name} compartilhou a sua postagem\",\n  \"notifications.clear\": \"Limpar notificações\",\n  \"notifications.clear_confirmation\": \"Você tem certeza de que quer limpar todas as suas notificações permanentemente?\",\n  \"notifications.column_settings.alert\": \"Notificações no computador\",\n  \"notifications.column_settings.favourite\": \"Favoritos:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Mostrar todas as categorias\",\n  \"notifications.column_settings.filter_bar.category\": \"Barra de filtro rápido\",\n  \"notifications.column_settings.filter_bar.show\": \"Mostrar\",\n  \"notifications.column_settings.follow\": \"Novos seguidores:\",\n  \"notifications.column_settings.mention\": \"Menções:\",\n  \"notifications.column_settings.poll\": \"Resultados da enquete:\",\n  \"notifications.column_settings.push\": \"Enviar notificações\",\n  \"notifications.column_settings.reblog\": \"Compartilhamento:\",\n  \"notifications.column_settings.show\": \"Mostrar nas colunas\",\n  \"notifications.column_settings.sound\": \"Reproduzir som\",\n  \"notifications.filter.all\": \"Tudo\",\n  \"notifications.filter.boosts\": \"Compartilhamentos\",\n  \"notifications.filter.favourites\": \"Favoritos\",\n  \"notifications.filter.follows\": \"Seguidores\",\n  \"notifications.filter.mentions\": \"Menções\",\n  \"notifications.filter.polls\": \"Resultados da enquete\",\n  \"notifications.group\": \"{count} notificações\",\n  \"poll.closed\": \"Fechada\",\n  \"poll.refresh\": \"Atualizar\",\n  \"poll.total_votes\": \"{count, plural, one {# voto} other {# votos}}\",\n  \"poll.vote\": \"Votar\",\n  \"poll_button.add_poll\": \"Adicionar uma enquete\",\n  \"poll_button.remove_poll\": \"Remover enquete\",\n  \"privacy.change\": \"Ajustar a privacidade da mensagem\",\n  \"privacy.direct.long\": \"Apenas para usuários mencionados\",\n  \"privacy.direct.short\": \"Direta\",\n  \"privacy.private.long\": \"Apenas para seus seguidores\",\n  \"privacy.private.short\": \"Privada\",\n  \"privacy.public.long\": \"Publicar em todos os feeds\",\n  \"privacy.public.short\": \"Pública\",\n  \"privacy.unlisted.long\": \"Não publicar em feeds públicos\",\n  \"privacy.unlisted.short\": \"Não listada\",\n  \"regeneration_indicator.label\": \"Carregando…\",\n  \"regeneration_indicator.sublabel\": \"Sua página inicial está sendo preparada!\",\n  \"relative_time.days\": \"{number}d\",\n  \"relative_time.hours\": \"{number}h\",\n  \"relative_time.just_now\": \"agora\",\n  \"relative_time.minutes\": \"{number}m\",\n  \"relative_time.seconds\": \"{number}s\",\n  \"reply_indicator.cancel\": \"Cancelar\",\n  \"report.forward\": \"Encaminhar para {target}\",\n  \"report.forward_hint\": \"Essa conta pertence à um outro servidor. Encaminhar uma cópia da denúncia com seus dados tornados anônimos para esse servidor?\",\n  \"report.hint\": \"A sua denúncia será enviada aos moderadores da instância. Você pode adicionar uma explicação de porque você está denunciando essa conta abaixo:\",\n  \"report.placeholder\": \"Comentários adicionais\",\n  \"report.submit\": \"Enviar\",\n  \"report.target\": \"Denunciar\",\n  \"search.placeholder\": \"Pesquisar\",\n  \"search_popout.search_format\": \"Formato de busca avançado\",\n  \"search_popout.tips.full_text\": \"Texto simples retorna status que você escreveu, favoritou, compartilhou ou em que tenha sido mencionado; também retorna nomes de exibição, usuários e hashtags correspondentes.\",\n  \"search_popout.tips.hashtag\": \"hashtag\",\n  \"search_popout.tips.status\": \"status\",\n  \"search_popout.tips.text\": \"Texto simples retorna nomes de exibição, usuários e hashtags correspondentes\",\n  \"search_popout.tips.user\": \"usuário\",\n  \"search_results.accounts\": \"Pessoas\",\n  \"search_results.hashtags\": \"Hashtags\",\n  \"search_results.statuses\": \"Toots\",\n  \"search_results.total\": \"{count, number} {count, plural, one {resultado} other {resultados}}\",\n  \"status.admin_account\": \"Abrir interface de moderação para @{name}\",\n  \"status.admin_status\": \"Abrir esse status na interface de moderação\",\n  \"status.block\": \"Block @{name}\",\n  \"status.cancel_reblog_private\": \"Desfazer compartilhamento\",\n  \"status.cannot_reblog\": \"Esta postagem não pode ser compartilhada\",\n  \"status.copy\": \"Copiar o link para o status\",\n  \"status.delete\": \"Excluir\",\n  \"status.detailed_status\": \"Visão detalhada da conversa\",\n  \"status.direct\": \"Enviar mensagem direta a @{name}\",\n  \"status.embed\": \"Incorporar\",\n  \"status.favourite\": \"Adicionar aos favoritos\",\n  \"status.filtered\": \"Filtrado\",\n  \"status.load_more\": \"Carregar mais\",\n  \"status.media_hidden\": \"Mídia escondida\",\n  \"status.mention\": \"Mencionar @{name}\",\n  \"status.more\": \"Mais\",\n  \"status.mute\": \"Silenciar @{name}\",\n  \"status.mute_conversation\": \"Silenciar conversa\",\n  \"status.open\": \"Expandir\",\n  \"status.pin\": \"Fixar no perfil\",\n  \"status.pinned\": \"Toot fixado\",\n  \"status.read_more\": \"Ler mais\",\n  \"status.reblog\": \"Compartilhar\",\n  \"status.reblog_private\": \"Compartilhar com a audiência original\",\n  \"status.reblogged_by\": \"{name} compartilhou\",\n  \"status.reblogs.empty\": \"Ninguém compartilhou esse toot até agora. Quando alguém o fizer, eles aparecerão aqui.\",\n  \"status.redraft\": \"Apagar & usar como rascunho\",\n  \"status.reply\": \"Responder\",\n  \"status.replyAll\": \"Responder à sequência\",\n  \"status.report\": \"Denunciar @{name}\",\n  \"status.sensitive_warning\": \"Conteúdo sensível\",\n  \"status.share\": \"Compartilhar\",\n  \"status.show_less\": \"Mostrar menos\",\n  \"status.show_less_all\": \"Mostrar menos para todas as mensagens\",\n  \"status.show_more\": \"Mostrar mais\",\n  \"status.show_more_all\": \"Mostrar mais para todas as mensagens\",\n  \"status.show_thread\": \"Mostrar sequência\",\n  \"status.unmute_conversation\": \"Desativar silêncio desta conversa\",\n  \"status.unpin\": \"Desafixar do perfil\",\n  \"suggestions.dismiss\": \"Ignorar a sugestão\",\n  \"suggestions.header\": \"Você pode se interessar por…\",\n  \"tabs_bar.federated_timeline\": \"Global\",\n  \"tabs_bar.home\": \"Página inicial\",\n  \"tabs_bar.local_timeline\": \"Local\",\n  \"tabs_bar.notifications\": \"Notificações\",\n  \"tabs_bar.search\": \"Buscar\",\n  \"time_remaining.days\": \"{number, plural, one {# dia restante} other {# dias restantes}}\",\n  \"time_remaining.hours\": \"{number, plural, one {# hora restante} other {# horas restantes}}\",\n  \"time_remaining.minutes\": \"{number, plural, one {# minuto restante} other {# minutos restantes}}\",\n  \"time_remaining.moments\": \"Momentos restantes\",\n  \"time_remaining.seconds\": \"{number, plural, one {# segundo restante} other {# segundos restantes}}\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {pessoa} other {pessoas}} falando sobre\",\n  \"ui.beforeunload\": \"Seu rascunho será perdido se você sair do Mastodon.\",\n  \"upload_area.title\": \"Arraste e solte para enviar\",\n  \"upload_button.label\": \"Adicionar mídia (JPEG, PNG, GIF, WebM, MP4, MOV)\",\n  \"upload_error.limit\": \"Limite de envio de arquivos excedido.\",\n  \"upload_error.poll\": \"Envio de arquivos não é permitido com enquetes.\",\n  \"upload_form.description\": \"Descreva a imagem para deficientes visuais\",\n  \"upload_form.focus\": \"Ajustar foco\",\n  \"upload_form.undo\": \"Remover\",\n  \"upload_progress.label\": \"Salvando...\",\n  \"video.close\": \"Fechar vídeo\",\n  \"video.exit_fullscreen\": \"Sair da tela cheia\",\n  \"video.expand\": \"Expandir vídeo\",\n  \"video.fullscreen\": \"Tela cheia\",\n  \"video.hide\": \"Esconder vídeo\",\n  \"video.mute\": \"Silenciar\",\n  \"video.pause\": \"Parar\",\n  \"video.play\": \"Reproduzir\",\n  \"video.unmute\": \"Retirar silêncio\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/pt.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Adicionar ou remover das listas\",\n  \"account.badges.bot\": \"Robô\",\n  \"account.block\": \"Bloquear @{name}\",\n  \"account.block_domain\": \"Esconder tudo do domínio {domain}\",\n  \"account.blocked\": \"Bloqueado\",\n  \"account.direct\": \"Mensagem directa @{name}\",\n  \"account.domain_blocked\": \"Domínio escondido\",\n  \"account.edit_profile\": \"Editar perfil\",\n  \"account.endorse\": \"Atributo no perfil\",\n  \"account.follow\": \"Seguir\",\n  \"account.followers\": \"Seguidores\",\n  \"account.followers.empty\": \"Ainda ninguém segue este utilizador.\",\n  \"account.follows\": \"Segue\",\n  \"account.follows.empty\": \"Este utilizador ainda não segue alguém.\",\n  \"account.follows_you\": \"É teu seguidor\",\n  \"account.hide_reblogs\": \"Esconder partilhas de @{name}\",\n  \"account.link_verified_on\": \"A posse deste link foi verificada em {date}\",\n  \"account.locked_info\": \"O estatuto de privacidade desta conta é fechado. O dono revê manualmente que a pode seguir.\",\n  \"account.media\": \"Media\",\n  \"account.mention\": \"Mencionar @{name}\",\n  \"account.moved_to\": \"{name} mudou a sua conta para:\",\n  \"account.mute\": \"Silenciar @{name}\",\n  \"account.mute_notifications\": \"Silenciar notificações de @{name}\",\n  \"account.muted\": \"Silenciada\",\n  \"account.posts\": \"Publicações\",\n  \"account.posts_with_replies\": \"Publicações e respostas\",\n  \"account.report\": \"Denunciar @{name}\",\n  \"account.requested\": \"A aguardar aprovação. Clique para cancelar o pedido de seguimento\",\n  \"account.share\": \"Partilhar o perfil @{name}\",\n  \"account.show_reblogs\": \"Mostrar partilhas de @{name}\",\n  \"account.unblock\": \"Desbloquear @{name}\",\n  \"account.unblock_domain\": \"Mostrar {domain}\",\n  \"account.unendorse\": \"Não mostrar no perfil\",\n  \"account.unfollow\": \"Deixar de seguir\",\n  \"account.unmute\": \"Não silenciar @{name}\",\n  \"account.unmute_notifications\": \"Deixar de silenciar @{name}\",\n  \"alert.unexpected.message\": \"Ocorreu um erro inesperado.\",\n  \"alert.unexpected.title\": \"Bolas!\",\n  \"boost_modal.combo\": \"Pode clicar {combo} para não voltar a ver\",\n  \"bundle_column_error.body\": \"Algo de errado aconteceu enquanto este componente era carregado.\",\n  \"bundle_column_error.retry\": \"Tente de novo\",\n  \"bundle_column_error.title\": \"Erro de rede\",\n  \"bundle_modal_error.close\": \"Fechar\",\n  \"bundle_modal_error.message\": \"Algo de errado aconteceu enquanto este componente era carregado.\",\n  \"bundle_modal_error.retry\": \"Tente de novo\",\n  \"column.blocks\": \"Utilizadores Bloqueados\",\n  \"column.community\": \"Cronologia local\",\n  \"column.direct\": \"Mensagens directas\",\n  \"column.domain_blocks\": \"Domínios escondidos\",\n  \"column.favourites\": \"Favoritos\",\n  \"column.follow_requests\": \"Seguidores Pendentes\",\n  \"column.home\": \"Início\",\n  \"column.lists\": \"Listas\",\n  \"column.mutes\": \"Utilizadores silenciados\",\n  \"column.notifications\": \"Notificações\",\n  \"column.pins\": \"Publicações fixas\",\n  \"column.public\": \"Cronologia federativa\",\n  \"column_back_button.label\": \"Voltar\",\n  \"column_header.hide_settings\": \"Esconder preferências\",\n  \"column_header.moveLeft_settings\": \"Mover coluna para a esquerda\",\n  \"column_header.moveRight_settings\": \"Mover coluna para a direita\",\n  \"column_header.pin\": \"Fixar\",\n  \"column_header.show_settings\": \"Mostrar preferências\",\n  \"column_header.unpin\": \"Desafixar\",\n  \"column_subheading.settings\": \"Preferências\",\n  \"community.column_settings.media_only\": \"Somente media\",\n  \"compose_form.direct_message_warning\": \"Esta publicação só  será enviada para os utilizadores mencionados.\",\n  \"compose_form.direct_message_warning_learn_more\": \"Aprender mais\",\n  \"compose_form.hashtag_warning\": \"Esta pulbicacção não será listada em nenhuma hashtag por ser não listada. Somente publicações públicas podem ser pesquisadas por hashtag.\",\n  \"compose_form.lock_disclaimer\": \"A tua conta não está {locked}. Qualquer pessoa pode seguir-te e ver as publicações direcionadas apenas a seguidores.\",\n  \"compose_form.lock_disclaimer.lock\": \"fechada\",\n  \"compose_form.placeholder\": \"Em que estás a pensar?\",\n  \"compose_form.poll.add_option\": \"Add a choice\",\n  \"compose_form.poll.duration\": \"Poll duration\",\n  \"compose_form.poll.option_placeholder\": \"Choice {number}\",\n  \"compose_form.poll.remove_option\": \"Remove this choice\",\n  \"compose_form.publish\": \"Publicar\",\n  \"compose_form.publish_loud\": \"{publicar}!\",\n  \"compose_form.sensitive.hide\": \"Mark media as sensitive\",\n  \"compose_form.sensitive.marked\": \"Media marcado como sensível\",\n  \"compose_form.sensitive.unmarked\": \"Media não está marcado como sensível\",\n  \"compose_form.spoiler.marked\": \"Texto escondido atrás de aviso\",\n  \"compose_form.spoiler.unmarked\": \"O texto não está escondido\",\n  \"compose_form.spoiler_placeholder\": \"Escreve o teu aviso aqui\",\n  \"confirmation_modal.cancel\": \"Cancelar\",\n  \"confirmations.block.block_and_report\": \"Block & Report\",\n  \"confirmations.block.confirm\": \"Bloquear\",\n  \"confirmations.block.message\": \"De certeza que queres bloquear {name}?\",\n  \"confirmations.delete.confirm\": \"Eliminar\",\n  \"confirmations.delete.message\": \"De certeza que queres eliminar esta publicação?\",\n  \"confirmations.delete_list.confirm\": \"Apagar\",\n  \"confirmations.delete_list.message\": \"Tens a certeza de que desejas apagar permanentemente esta lista?\",\n  \"confirmations.domain_block.confirm\": \"Esconder tudo deste domínio\",\n  \"confirmations.domain_block.message\": \"De certeza que queres bloquear completamente o domínio {domain}? Na maioria dos casos, silenciar ou bloquear alguns utilizadores é o suficiente e o recomendado. Não irás ver conteúdo daquele domínio em cronologia alguma, nem nas tuas notificações. Os teus seguidores daquele domínio serão removidos.\",\n  \"confirmations.mute.confirm\": \"Silenciar\",\n  \"confirmations.mute.message\": \"De certeza que queres silenciar {name}?\",\n  \"confirmations.redraft.confirm\": \"Apagar & redigir\",\n  \"confirmations.redraft.message\": \"Tens a certeza que queres apagar e redigir esta publicação?  Os favoritos e as partilhas perder-se-ão e as respostas à publicação original ficarão órfãs.\",\n  \"confirmations.reply.confirm\": \"Responder\",\n  \"confirmations.reply.message\": \"Responder agora irá reescrever a mensagem que estás a compor actualmente. Tens a certeza que queres continuar?\",\n  \"confirmations.unfollow.confirm\": \"Deixar de seguir\",\n  \"confirmations.unfollow.message\": \"De certeza que queres deixar de seguir {name}?\",\n  \"embed.instructions\": \"Publica esta publicação no teu site copiando o código abaixo.\",\n  \"embed.preview\": \"Podes ver aqui como irá ficar:\",\n  \"emoji_button.activity\": \"Actividade\",\n  \"emoji_button.custom\": \"Personalizar\",\n  \"emoji_button.flags\": \"Bandeiras\",\n  \"emoji_button.food\": \"Comida & Bebida\",\n  \"emoji_button.label\": \"Inserir Emoji\",\n  \"emoji_button.nature\": \"Natureza\",\n  \"emoji_button.not_found\": \"Não tem emojos!! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"Objectos\",\n  \"emoji_button.people\": \"Pessoas\",\n  \"emoji_button.recent\": \"Regularmente utilizados\",\n  \"emoji_button.search\": \"Procurar...\",\n  \"emoji_button.search_results\": \"Resultados da pesquisa\",\n  \"emoji_button.symbols\": \"Símbolos\",\n  \"emoji_button.travel\": \"Viagens & Lugares\",\n  \"empty_column.account_timeline\": \"Sem publicações!\",\n  \"empty_column.account_unavailable\": \"Profile unavailable\",\n  \"empty_column.blocks\": \"Ainda não bloqueaste qualquer utilizador.\",\n  \"empty_column.community\": \"Ainda não existe conteúdo local para mostrar!\",\n  \"empty_column.direct\": \"Ainda não tens qualquer mensagem directa. Quando enviares ou receberes alguma, ela irá aparecer aqui.\",\n  \"empty_column.domain_blocks\": \"Ainda não há qualquer domínio escondido.\",\n  \"empty_column.favourited_statuses\": \"Ainda não tens quaisquer publicações favoritas. Quando tiveres alguma, ela irá aparecer aqui.\",\n  \"empty_column.favourites\": \"Ainda ninguém favorizou esta publicação. Quando alguém o fizer, ela irá aparecer aqui.\",\n  \"empty_column.follow_requests\": \"Ainda não tens pedido de seguimento algum. Quando receberes algum, ele irá aparecer aqui.\",\n  \"empty_column.hashtag\": \"Não foram encontradas publicações com essa hashtag.\",\n  \"empty_column.home\": \"Ainda não segues qualquer utilizador. Visita {public} ou utiliza a pesquisa para procurar outros utilizadores.\",\n  \"empty_column.home.public_timeline\": \"Cronologia pública\",\n  \"empty_column.list\": \"Ainda não existem publicações nesta lista. Quando membros desta lista fizerem novas publicações, elas aparecerão aqui.\",\n  \"empty_column.lists\": \"Ainda não tens qualquer lista. Quando criares uma, ela irá aparecer aqui.\",\n  \"empty_column.mutes\": \"Ainda não silenciaste qualquer utilizador.\",\n  \"empty_column.notifications\": \"Não tens notificações. Interage com outros utilizadores para iniciar uma conversa.\",\n  \"empty_column.public\": \"Não há nada aqui! Escreve algo publicamente ou segue outros utilizadores para veres aqui os conteúdos públicos\",\n  \"follow_request.authorize\": \"Autorizar\",\n  \"follow_request.reject\": \"Rejeitar\",\n  \"getting_started.developers\": \"Responsáveis pelo desenvolvimento\",\n  \"getting_started.directory\": \"Directório de perfil\",\n  \"getting_started.documentation\": \"Documentation\",\n  \"getting_started.heading\": \"Primeiros passos\",\n  \"getting_started.invite\": \"Convidar pessoas\",\n  \"getting_started.open_source_notice\": \"Mastodon é software de fonte aberta. Podes contribuir ou repostar problemas no GitHub do projecto: {github}.\",\n  \"getting_started.security\": \"Segurança\",\n  \"getting_started.terms\": \"Termos de serviço\",\n  \"hashtag.column_header.tag_mode.all\": \"e {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"ou {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"sem {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"Não foram encontradas sugestões\",\n  \"hashtag.column_settings.select.placeholder\": \"Introduzir as hashtags…\",\n  \"hashtag.column_settings.tag_mode.all\": \"Todos estes\",\n  \"hashtag.column_settings.tag_mode.any\": \"Qualquer destes\",\n  \"hashtag.column_settings.tag_mode.none\": \"Nenhum destes\",\n  \"hashtag.column_settings.tag_toggle\": \"Incluir etiquetas adicionais para esta coluna\",\n  \"home.column_settings.basic\": \"Básico\",\n  \"home.column_settings.show_reblogs\": \"Mostrar as partilhas\",\n  \"home.column_settings.show_replies\": \"Mostrar as respostas\",\n  \"intervals.full.days\": \"{number, plural, one {# day} other {# days}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# hour} other {# hours}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minute} other {# minutes}}\",\n  \"introduction.federation.action\": \"Seguinte\",\n  \"introduction.federation.federated.headline\": \"Federated\",\n  \"introduction.federation.federated.text\": \"Publicações públicas de outros servidores do fediverse aparecerão na cronologia federativa.\",\n  \"introduction.federation.home.headline\": \"Home\",\n  \"introduction.federation.home.text\": \"As publicações das pessoas que tu segues aparecerão na tua coluna inicial. Tu podes seguir qualquer pessoa em qualquer servidor!\",\n  \"introduction.federation.local.headline\": \"Local\",\n  \"introduction.federation.local.text\": \"Publicações públicas de pessoas que tu segues no teu servidor aparecerão na coluna local.\",\n  \"introduction.interactions.action\": \"Terminar o tutorial!\",\n  \"introduction.interactions.favourite.headline\": \"Favorito\",\n  \"introduction.interactions.favourite.text\": \"Tu podes guardar um toot para depois e deixar o autor saber que gostaste dele, favoritando-o.\",\n  \"introduction.interactions.reblog.headline\": \"Partilhar\",\n  \"introduction.interactions.reblog.text\": \"Podes partilhar os toots de outras pessoas com os teus seguidores partilhando-os.\",\n  \"introduction.interactions.reply.headline\": \"Responder\",\n  \"introduction.interactions.reply.text\": \"Tu podes responder a toots de outras pessoas e aos teus, o que os irá juntar numa conversa.\",\n  \"introduction.welcome.action\": \"Vamos!\",\n  \"introduction.welcome.headline\": \"Primeiros passos\",\n  \"introduction.welcome.text\": \"Bem-vindo ao fediverse! Em pouco tempo poderás enviar mensagens e falar com os teus amigos numa grande variedade de servidores. Mas este servidor, {domain}, é especial—ele alberga o teu perfil. Por isso, lembra-te do seu nome.\",\n  \"keyboard_shortcuts.back\": \"para voltar\",\n  \"keyboard_shortcuts.blocked\": \"para abrir a lista de utilizadores bloqueados\",\n  \"keyboard_shortcuts.boost\": \"para partilhar\",\n  \"keyboard_shortcuts.column\": \"para focar uma publicação numa das colunas\",\n  \"keyboard_shortcuts.compose\": \"para focar na área de publicação\",\n  \"keyboard_shortcuts.description\": \"Descrição\",\n  \"keyboard_shortcuts.direct\": \"para abrir a coluna das mensagens directas\",\n  \"keyboard_shortcuts.down\": \"para mover para baixo na lista\",\n  \"keyboard_shortcuts.enter\": \"para expandir uma publicação\",\n  \"keyboard_shortcuts.favourite\": \"para adicionar aos favoritos\",\n  \"keyboard_shortcuts.favourites\": \"para abrir a lista dos favoritos\",\n  \"keyboard_shortcuts.federated\": \"para abrir a cronologia federativa\",\n  \"keyboard_shortcuts.heading\": \"Atalhos do teclado\",\n  \"keyboard_shortcuts.home\": \"para abrir a cronologia inicial\",\n  \"keyboard_shortcuts.hotkey\": \"Atalho\",\n  \"keyboard_shortcuts.legend\": \"para mostrar esta legenda\",\n  \"keyboard_shortcuts.local\": \"para abrir a cronologia local\",\n  \"keyboard_shortcuts.mention\": \"para mencionar o autor\",\n  \"keyboard_shortcuts.muted\": \"para abrir a lista dos utilizadores silenciados\",\n  \"keyboard_shortcuts.my_profile\": \"para abrir o teu perfil\",\n  \"keyboard_shortcuts.notifications\": \"para abrir a coluna das notificações\",\n  \"keyboard_shortcuts.pinned\": \"para abrir a lista dos toots fixados\",\n  \"keyboard_shortcuts.profile\": \"para abrir o perfil do autor\",\n  \"keyboard_shortcuts.reply\": \"para responder\",\n  \"keyboard_shortcuts.requests\": \"para abrir a lista dos pedidos de seguimento\",\n  \"keyboard_shortcuts.search\": \"para focar na pesquisa\",\n  \"keyboard_shortcuts.start\": \"para abrir a coluna dos \\\"primeiros passos\\\"\",\n  \"keyboard_shortcuts.toggle_hidden\": \"para mostrar/esconder texto atrás de CW\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"to show/hide media\",\n  \"keyboard_shortcuts.toot\": \"para compor um novo post\",\n  \"keyboard_shortcuts.unfocus\": \"para remover o foco da área de publicação/pesquisa\",\n  \"keyboard_shortcuts.up\": \"para mover para cima na lista\",\n  \"lightbox.close\": \"Fechar\",\n  \"lightbox.next\": \"Próximo\",\n  \"lightbox.previous\": \"Anterior\",\n  \"lightbox.view_context\": \"View context\",\n  \"lists.account.add\": \"Adicionar à lista\",\n  \"lists.account.remove\": \"Remover da lista\",\n  \"lists.delete\": \"Delete list\",\n  \"lists.edit\": \"Editar lista\",\n  \"lists.edit.submit\": \"Mudar o título\",\n  \"lists.new.create\": \"Adicionar lista\",\n  \"lists.new.title_placeholder\": \"Novo título da lista\",\n  \"lists.search\": \"Pesquisa entre as pessoas que segues\",\n  \"lists.subheading\": \"As tuas listas\",\n  \"loading_indicator.label\": \"A carregar...\",\n  \"media_gallery.toggle_visible\": \"Esconder/Mostrar\",\n  \"missing_indicator.label\": \"Não encontrado\",\n  \"missing_indicator.sublabel\": \"Este recurso não foi encontrado\",\n  \"mute_modal.hide_notifications\": \"Esconder notificações deste utilizador?\",\n  \"navigation_bar.apps\": \"Aplicações móveis\",\n  \"navigation_bar.blocks\": \"Utilizadores bloqueados\",\n  \"navigation_bar.community_timeline\": \"Local\",\n  \"navigation_bar.compose\": \"Escrever novo toot\",\n  \"navigation_bar.direct\": \"Mensagens directas\",\n  \"navigation_bar.discover\": \"Descobrir\",\n  \"navigation_bar.domain_blocks\": \"Domínios escondidos\",\n  \"navigation_bar.edit_profile\": \"Editar perfil\",\n  \"navigation_bar.favourites\": \"Favoritos\",\n  \"navigation_bar.filters\": \"Palavras silenciadas\",\n  \"navigation_bar.follow_requests\": \"Seguidores pendentes\",\n  \"navigation_bar.follows_and_followers\": \"Follows and followers\",\n  \"navigation_bar.info\": \"Sobre este servidor\",\n  \"navigation_bar.keyboard_shortcuts\": \"Atalhos de teclado\",\n  \"navigation_bar.lists\": \"Listas\",\n  \"navigation_bar.logout\": \"Sair\",\n  \"navigation_bar.mutes\": \"Utilizadores silenciados\",\n  \"navigation_bar.personal\": \"Personal\",\n  \"navigation_bar.pins\": \"Posts fixos\",\n  \"navigation_bar.preferences\": \"Preferências\",\n  \"navigation_bar.profile_directory\": \"Profile directory\",\n  \"navigation_bar.public_timeline\": \"Global\",\n  \"navigation_bar.security\": \"Segurança\",\n  \"notification.favourite\": \"{name} adicionou o teu post aos favoritos\",\n  \"notification.follow\": \"{name} seguiu-te\",\n  \"notification.mention\": \"{name} mencionou-te\",\n  \"notification.poll\": \"A poll you have voted in has ended\",\n  \"notification.reblog\": \"{name} partilhou o teu post\",\n  \"notifications.clear\": \"Limpar notificações\",\n  \"notifications.clear_confirmation\": \"Queres mesmo limpar todas as notificações?\",\n  \"notifications.column_settings.alert\": \"Notificações no computador\",\n  \"notifications.column_settings.favourite\": \"Favoritos:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Mostrar todas as categorias\",\n  \"notifications.column_settings.filter_bar.category\": \"Barra de filtros rápidos\",\n  \"notifications.column_settings.filter_bar.show\": \"Mostrar\",\n  \"notifications.column_settings.follow\": \"Novos seguidores:\",\n  \"notifications.column_settings.mention\": \"Menções:\",\n  \"notifications.column_settings.poll\": \"Poll results:\",\n  \"notifications.column_settings.push\": \"Notificações Push\",\n  \"notifications.column_settings.reblog\": \"Partilhas:\",\n  \"notifications.column_settings.show\": \"Mostrar nas colunas\",\n  \"notifications.column_settings.sound\": \"Reproduzir som\",\n  \"notifications.filter.all\": \"Todas\",\n  \"notifications.filter.boosts\": \"Partilhas\",\n  \"notifications.filter.favourites\": \"Favoritas\",\n  \"notifications.filter.follows\": \"Seguimento\",\n  \"notifications.filter.mentions\": \"Referências\",\n  \"notifications.filter.polls\": \"Poll results\",\n  \"notifications.group\": \"{count} notificações\",\n  \"poll.closed\": \"Fechado\",\n  \"poll.refresh\": \"Recarregar\",\n  \"poll.total_votes\": \"{contar, plural, um {# vote} outro {# votes}}\",\n  \"poll.vote\": \"Votar\",\n  \"poll_button.add_poll\": \"Add a poll\",\n  \"poll_button.remove_poll\": \"Remove poll\",\n  \"privacy.change\": \"Ajustar a privacidade da mensagem\",\n  \"privacy.direct.long\": \"Apenas para utilizadores mencionados\",\n  \"privacy.direct.short\": \"Directo\",\n  \"privacy.private.long\": \"Apenas para os seguidores\",\n  \"privacy.private.short\": \"Privado\",\n  \"privacy.public.long\": \"Publicar em todos os feeds\",\n  \"privacy.public.short\": \"Público\",\n  \"privacy.unlisted.long\": \"Não publicar nos feeds públicos\",\n  \"privacy.unlisted.short\": \"Não listar\",\n  \"regeneration_indicator.label\": \"A carregar…\",\n  \"regeneration_indicator.sublabel\": \"A tua home está a ser preparada!\",\n  \"relative_time.days\": \"{number}d\",\n  \"relative_time.hours\": \"{number}h\",\n  \"relative_time.just_now\": \"agora\",\n  \"relative_time.minutes\": \"{number}m\",\n  \"relative_time.seconds\": \"{number}s\",\n  \"reply_indicator.cancel\": \"Cancelar\",\n  \"report.forward\": \"Reenviar para {target}\",\n  \"report.forward_hint\": \"A conta é de outro servidor. Enviar uma cópia anónima do relatório para lá também?\",\n  \"report.hint\": \"O relatório será enviado para os moderadores do teu servidor. Podes fornecer, em baixo, uma explicação do motivo pelo qual estás a relatar esta conta:\",\n  \"report.placeholder\": \"Comentários adicionais\",\n  \"report.submit\": \"Enviar\",\n  \"report.target\": \"Denunciar\",\n  \"search.placeholder\": \"Pesquisar\",\n  \"search_popout.search_format\": \"Formato avançado de pesquisa\",\n  \"search_popout.tips.full_text\": \"Texto simples devolve publicações que tu escreveste, favoritaste, partilhaste ou em que foste mencionado, tal como nomes de utilizador correspondentes, alcunhas e hashtags.\",\n  \"search_popout.tips.hashtag\": \"hashtag\",\n  \"search_popout.tips.status\": \"estado\",\n  \"search_popout.tips.text\": \"O texto simples retorna a correspondência de nomes, utilizadores e hashtags\",\n  \"search_popout.tips.user\": \"utilizador\",\n  \"search_results.accounts\": \"Pessoas\",\n  \"search_results.hashtags\": \"Hashtags\",\n  \"search_results.statuses\": \"Publicações\",\n  \"search_results.total\": \"{count, number} {count, plural, one {resultado} other {resultados}}\",\n  \"status.admin_account\": \"Abrir a interface de moderação para @{name}\",\n  \"status.admin_status\": \"Abrir esta publicação na interface de moderação\",\n  \"status.block\": \"Block @{name}\",\n  \"status.cancel_reblog_private\": \"Não partilhar\",\n  \"status.cannot_reblog\": \"Este post não pode ser partilhado\",\n  \"status.copy\": \"Copiar o link para a publicação\",\n  \"status.delete\": \"Eliminar\",\n  \"status.detailed_status\": \"Vista de conversação detalhada\",\n  \"status.direct\": \"Mensagem directa @{name}\",\n  \"status.embed\": \"Incorporar\",\n  \"status.favourite\": \"Adicionar aos favoritos\",\n  \"status.filtered\": \"Filtrada\",\n  \"status.load_more\": \"Carregar mais\",\n  \"status.media_hidden\": \"Media escondida\",\n  \"status.mention\": \"Mencionar @{name}\",\n  \"status.more\": \"Mais\",\n  \"status.mute\": \"Silenciar @{name}\",\n  \"status.mute_conversation\": \"Silenciar conversa\",\n  \"status.open\": \"Expandir\",\n  \"status.pin\": \"Fixar no perfil\",\n  \"status.pinned\": \"Publicação fixa\",\n  \"status.read_more\": \"Ler mais\",\n  \"status.reblog\": \"Partilhar\",\n  \"status.reblog_private\": \"Partilhar com a audiência original\",\n  \"status.reblogged_by\": \"{name} partilhou\",\n  \"status.reblogs.empty\": \"Ainda ninguém partilhou esta publicação. Quando alguém o fizer, ela irá aparecer aqui.\",\n  \"status.redraft\": \"Apagar & reescrever\",\n  \"status.reply\": \"Responder\",\n  \"status.replyAll\": \"Responder à conversa\",\n  \"status.report\": \"Denunciar @{name}\",\n  \"status.sensitive_warning\": \"Conteúdo sensível\",\n  \"status.share\": \"Compartilhar\",\n  \"status.show_less\": \"Mostrar menos\",\n  \"status.show_less_all\": \"Mostrar menos para todas\",\n  \"status.show_more\": \"Mostrar mais\",\n  \"status.show_more_all\": \"Mostrar mais para todas\",\n  \"status.show_thread\": \"Mostrar conversa\",\n  \"status.unmute_conversation\": \"Deixar de silenciar esta conversa\",\n  \"status.unpin\": \"Não fixar no perfil\",\n  \"suggestions.dismiss\": \"Dispensar a sugestão\",\n  \"suggestions.header\": \"Tu podes estar interessado em…\",\n  \"tabs_bar.federated_timeline\": \"Global\",\n  \"tabs_bar.home\": \"Home\",\n  \"tabs_bar.local_timeline\": \"Local\",\n  \"tabs_bar.notifications\": \"Notificações\",\n  \"tabs_bar.search\": \"Pesquisar\",\n  \"time_remaining.days\": \"{número, plural, um {# day} outro {# days}} faltam\",\n  \"time_remaining.hours\": \"{número, plural, um {# hour} outro {# hours}} faltam\",\n  \"time_remaining.minutes\": \"{número, plural, um {# minute} outro {# minutes}} faltam\",\n  \"time_remaining.moments\": \"Momentos em falta\",\n  \"time_remaining.seconds\": \"{número, plural, um {# second} outro {# seconds}} faltam\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, uma {person} outra {people}} a falar\",\n  \"ui.beforeunload\": \"O teu rascunho vai ser perdido se abandonares o Mastodon.\",\n  \"upload_area.title\": \"Arraste e solte para enviar\",\n  \"upload_button.label\": \"Adicionar media\",\n  \"upload_error.limit\": \"Limite máximo do ficheiro a carregar excedido.\",\n  \"upload_error.poll\": \"File upload not allowed with polls.\",\n  \"upload_form.description\": \"Descrição da imagem para pessoas com dificuldades visuais\",\n  \"upload_form.focus\": \"Alterar previsualização\",\n  \"upload_form.undo\": \"Apagar\",\n  \"upload_progress.label\": \"A enviar...\",\n  \"video.close\": \"Fechar vídeo\",\n  \"video.exit_fullscreen\": \"Sair de full screen\",\n  \"video.expand\": \"Expandir vídeo\",\n  \"video.fullscreen\": \"Full screen\",\n  \"video.hide\": \"Esconder vídeo\",\n  \"video.mute\": \"Silenciar\",\n  \"video.pause\": \"Pausar\",\n  \"video.play\": \"Reproduzir\",\n  \"video.unmute\": \"Remover de silêncio\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/ro.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Adaugă sau Elimină din liste\",\n  \"account.badges.bot\": \"Bot\",\n  \"account.block\": \"Blochează @{name}\",\n  \"account.block_domain\": \"Ascunde tot de la {domain}\",\n  \"account.blocked\": \"Blocat\",\n  \"account.direct\": \"Mesaj direct @{name}\",\n  \"account.domain_blocked\": \"Domeniu ascuns\",\n  \"account.edit_profile\": \"Editează profilul\",\n  \"account.endorse\": \"Redistribuie pe profil\",\n  \"account.follow\": \"Urmărește\",\n  \"account.followers\": \"Urmăritori\",\n  \"account.followers.empty\": \"Acest utilizator nu are încă urmăritori.\",\n  \"account.follows\": \"Urmărește\",\n  \"account.follows.empty\": \"Acest utilizator nu urmărește pe nimeni incă.\",\n  \"account.follows_you\": \"Te urmărește\",\n  \"account.hide_reblogs\": \"Ascunde redistribuirile de la @{name}\",\n  \"account.link_verified_on\": \"Deținerea acestui link a fost verificată la {date}\",\n  \"account.locked_info\": \"Acest profil este privat. Această persoană gestioneaz manual cine o urmărește.\",\n  \"account.media\": \"Media\",\n  \"account.mention\": \"Menționează @{name}\",\n  \"account.moved_to\": \"{name} a fost mutat la:\",\n  \"account.mute\": \"Oprește @{name}\",\n  \"account.mute_notifications\": \"Oprește notificările de la @{name}\",\n  \"account.muted\": \"Oprit\",\n  \"account.posts\": \"Postări\",\n  \"account.posts_with_replies\": \"Postări și replici\",\n  \"account.report\": \"Raportează @{name}\",\n  \"account.requested\": \"Se așteaptă aprobarea. Apasă pentru a anula cererea de urmărire\",\n  \"account.share\": \"Distribuie profilul lui @{name}\",\n  \"account.show_reblogs\": \"Arată redistribuirile de la @{name}\",\n  \"account.unblock\": \"Deblochează @{name}\",\n  \"account.unblock_domain\": \"Arată {domain}\",\n  \"account.unendorse\": \"Nu promova pe profil\",\n  \"account.unfollow\": \"Nu mai urmări\",\n  \"account.unmute\": \"Activează notificările de la @{name}\",\n  \"account.unmute_notifications\": \"Activează notificările de la @{name}\",\n  \"alert.unexpected.message\": \"A apărut o eroare neașteptată.\",\n  \"alert.unexpected.title\": \"Hopa!\",\n  \"boost_modal.combo\": \"Poți apăsa {combo} pentru a omite asta data viitoare\",\n  \"bundle_column_error.body\": \"Ceva nu a funcționat la încărcarea acestui component.\",\n  \"bundle_column_error.retry\": \"Încearcă din nou\",\n  \"bundle_column_error.title\": \"Eroare de rețea\",\n  \"bundle_modal_error.close\": \"Închide\",\n  \"bundle_modal_error.message\": \"Ceva nu a funcționat în timupul încărcării acestui component.\",\n  \"bundle_modal_error.retry\": \"Încearcă din nou\",\n  \"column.blocks\": \"Utilizatori blocați\",\n  \"column.community\": \"Fluxul Local\",\n  \"column.direct\": \"Mesaje directe\",\n  \"column.domain_blocks\": \"Domenii ascunse\",\n  \"column.favourites\": \"Favorite\",\n  \"column.follow_requests\": \"Cereri de urmărire\",\n  \"column.home\": \"Acasă\",\n  \"column.lists\": \"Liste\",\n  \"column.mutes\": \"Utilizatori opriți\",\n  \"column.notifications\": \"Notificări\",\n  \"column.pins\": \"Postări fixate\",\n  \"column.public\": \"Flux global\",\n  \"column_back_button.label\": \"Înapoi\",\n  \"column_header.hide_settings\": \"Ascunde setările\",\n  \"column_header.moveLeft_settings\": \"Mută coloana la stânga\",\n  \"column_header.moveRight_settings\": \"Mută coloana la dreapta\",\n  \"column_header.pin\": \"Fixează\",\n  \"column_header.show_settings\": \"Arată setările\",\n  \"column_header.unpin\": \"Eliberează\",\n  \"column_subheading.settings\": \"Setări\",\n  \"community.column_settings.media_only\": \"Doar media\",\n  \"compose_form.direct_message_warning\": \"Această postare va fi trimisă doar utilizatorilor menționați.\",\n  \"compose_form.direct_message_warning_learn_more\": \"Află mai multe\",\n  \"compose_form.hashtag_warning\": \"Această postare nu va fi listată sub nici un hastag. Doar postările publice pot fi găsite dupa un hastag.\",\n  \"compose_form.lock_disclaimer\": \"Contul tău nu este {locked}. Oricine te poate urmări fără aprobarea ta și vedea toate postările tale.\",\n  \"compose_form.lock_disclaimer.lock\": \"privat\",\n  \"compose_form.placeholder\": \"La ce te gândești?\",\n  \"compose_form.poll.add_option\": \"Add a choice\",\n  \"compose_form.poll.duration\": \"Poll duration\",\n  \"compose_form.poll.option_placeholder\": \"Choice {number}\",\n  \"compose_form.poll.remove_option\": \"Remove this choice\",\n  \"compose_form.publish\": \"Postează\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"Mark media as sensitive\",\n  \"compose_form.sensitive.marked\": \"Conținutul media este marcat ca sensibil\",\n  \"compose_form.sensitive.unmarked\": \"Conținutul media nu este marcat ca sensibil\",\n  \"compose_form.spoiler.marked\": \"Textul este ascuns sub o avertizare\",\n  \"compose_form.spoiler.unmarked\": \"Textul nu este ascuns\",\n  \"compose_form.spoiler_placeholder\": \"Scrie averitzarea aici\",\n  \"confirmation_modal.cancel\": \"Anulează\",\n  \"confirmations.block.block_and_report\": \"Block & Report\",\n  \"confirmations.block.confirm\": \"Blochează\",\n  \"confirmations.block.message\": \"Ești sigur că vrei să blochezi {name}?\",\n  \"confirmations.delete.confirm\": \"Șterge\",\n  \"confirmations.delete.message\": \"Ești șigur că vrei să ștergi asta?\",\n  \"confirmations.delete_list.confirm\": \"Șterge\",\n  \"confirmations.delete_list.message\": \"Ești sigur că vrei să ștergi permanent această listă?\",\n  \"confirmations.domain_block.confirm\": \"Ascunde tot domeniul\",\n  \"confirmations.domain_block.message\": \"Ești absolut sigur că vrei să blochezi complet {domain}? În cele mai multe cazuri raportarea sau oprirea anumitor lucruri este suficientă și de preferat. Nu vei mai vedea nici un conținut de la acest domeniu in nici un flux public sau în notificările tale. Urmăritorii tăi de la acele domenii vor fi eliminați.\",\n  \"confirmations.mute.confirm\": \"Oprește\",\n  \"confirmations.mute.message\": \"Ești sigur că vrei să oprești {name}?\",\n  \"confirmations.redraft.confirm\": \"Șterge și salvează ca ciornă\",\n  \"confirmations.redraft.message\": \"Ești sigur că vrei să faci asta? Tot ce ține de această postare, inclusiv răspunsurile vor fi deconectate.\",\n  \"confirmations.reply.confirm\": \"Răspunde\",\n  \"confirmations.reply.message\": \"Răspunzând la asta acum, mesajul pe care îl compui în prezent se va șterge. Ești sigur că vrei să continui?\",\n  \"confirmations.unfollow.confirm\": \"Nu mai urmări\",\n  \"confirmations.unfollow.message\": \"Ești sigur că nu mai vrei să îl urmărești pe {name}?\",\n  \"embed.instructions\": \"Inserează această postare pe site-ul tău adăugând codul de mai jos.\",\n  \"embed.preview\": \"Cam așa va arăta:\",\n  \"emoji_button.activity\": \"Activitate\",\n  \"emoji_button.custom\": \"Personalizat\",\n  \"emoji_button.flags\": \"Marcaje\",\n  \"emoji_button.food\": \"Mâncare și Băuturi\",\n  \"emoji_button.label\": \"Inserează un emoji\",\n  \"emoji_button.nature\": \"Natură\",\n  \"emoji_button.not_found\": \"Fară emojiuri (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"Obiecte\",\n  \"emoji_button.people\": \"Persoane\",\n  \"emoji_button.recent\": \"Utilizate frecvent\",\n  \"emoji_button.search\": \"Caută...\",\n  \"emoji_button.search_results\": \"Rezultatele căutării\",\n  \"emoji_button.symbols\": \"Simboluri\",\n  \"emoji_button.travel\": \"Călătorii si Locuri\",\n  \"empty_column.account_timeline\": \"Nici o postare aici!\",\n  \"empty_column.account_unavailable\": \"Profile unavailable\",\n  \"empty_column.blocks\": \"Nu ai blocat nici un utilizator incă.\",\n  \"empty_column.community\": \"Fluxul local este gol. Scrie ceva public pentru a împinge bila la vale!\",\n  \"empty_column.direct\": \"Nu ai nici un mesaj direct incă. Când trimiți sau primești unul, va fi afișat aici.\",\n  \"empty_column.domain_blocks\": \"Nu sunt domenii ascunse incă.\",\n  \"empty_column.favourited_statuses\": \"Nu ai nici o postare favorită încă. Când vei avea, vor fi afișate aici.\",\n  \"empty_column.favourites\": \"Nimeni nu are această postare adăugată la favorite. Când cineva o va face va fi afișat aici.\",\n  \"empty_column.follow_requests\": \"Nu ai încă nici o cerere de urmărire. Când vei primi una, va fi afișată aici.\",\n  \"empty_column.hashtag\": \"Acest hastag nu a fost folosit încă.\",\n  \"empty_column.home\": \"Fluxul tău este gol. Vizitează {public} sau fă o căutare pentru a începe să cunoști oameni noi.\",\n  \"empty_column.home.public_timeline\": \"fluxul public\",\n  \"empty_column.list\": \"Nu este nimic încă în această listă. Când membrii acestei liste vor începe să posteze, va apărea aici.\",\n  \"empty_column.lists\": \"Nu ai încă nici o listă. Când vei crea una, va apărea aici.\",\n  \"empty_column.mutes\": \"Nu ai oprit nici un utilizator incă.\",\n  \"empty_column.notifications\": \"Nu ai nici o notificare încă. Interacționează cu alții pentru a începe o conversație.\",\n  \"empty_column.public\": \"Nu este nimci aici încă! Scrie ceva public, sau urmărește alți utilizatori din alte instanțe pentru a porni fluxul\",\n  \"follow_request.authorize\": \"Autorizează\",\n  \"follow_request.reject\": \"Respinge\",\n  \"getting_started.developers\": \"Dezvoltatori\",\n  \"getting_started.directory\": \"Explorează\",\n  \"getting_started.documentation\": \"Documentație\",\n  \"getting_started.heading\": \"Începe\",\n  \"getting_started.invite\": \"Invită prieteni\",\n  \"getting_started.open_source_notice\": \"Mastodon este o rețea de socializare de tip open source. Puteți contribuii la dezvoltarea ei sau să semnalați erorile pe GitHub la {github}.\",\n  \"getting_started.security\": \"Securitate\",\n  \"getting_started.terms\": \"Termeni de Utilizare\",\n  \"hashtag.column_header.tag_mode.all\": \"și {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"sau {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"fără {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"No suggestions found\",\n  \"hashtag.column_settings.select.placeholder\": \"Enter hashtags…\",\n  \"hashtag.column_settings.tag_mode.all\": \"Toate acestea\",\n  \"hashtag.column_settings.tag_mode.any\": \"Oricare din acestea\",\n  \"hashtag.column_settings.tag_mode.none\": \"Niciuna din aceastea\",\n  \"hashtag.column_settings.tag_toggle\": \"Adaugă etichete adiționale pentru această coloană\",\n  \"home.column_settings.basic\": \"De bază\",\n  \"home.column_settings.show_reblogs\": \"Arată redistribuirile\",\n  \"home.column_settings.show_replies\": \"Arată răspunsurile\",\n  \"intervals.full.days\": \"{number, plural, one {# day} other {# days}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# hour} other {# hours}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minute} other {# minutes}}\",\n  \"introduction.federation.action\": \"Următorul\",\n  \"introduction.federation.federated.headline\": \"Federalizat\",\n  \"introduction.federation.federated.text\": \"Postările publice de pe alte servere din rețea vor apărea in fluxul global.\",\n  \"introduction.federation.home.headline\": \"Acasă\",\n  \"introduction.federation.home.text\": \"Postările de la persoanele pe care le urmărești vor apărea in fluxul tău \\\"Acasă\\\". Poți urmări pe orice de pe orice server!\",\n  \"introduction.federation.local.headline\": \"Local\",\n  \"introduction.federation.local.text\": \"Postările publice de la persoanele de pe acest server vor apărea în fluxul local.\",\n  \"introduction.interactions.action\": \"Încheie ghidul!\",\n  \"introduction.interactions.favourite.headline\": \"Favorite\",\n  \"introduction.interactions.favourite.text\": \"Poți salva o postare pentru a fi citită mai târziu și poți lăsa autorul să știe că iți place adăugândo la favorite.\",\n  \"introduction.interactions.reblog.headline\": \"Redistribuie\",\n  \"introduction.interactions.reblog.text\": \"Poți împărtăși postările altora cu urmăritorii tăi redistribuindule.\",\n  \"introduction.interactions.reply.headline\": \"Răspunde\",\n  \"introduction.interactions.reply.text\": \"Poți răspunde la postările tale și alte altora, care se vor lărgii în discuții.\",\n  \"introduction.welcome.action\": \"Să începem!\",\n  \"introduction.welcome.headline\": \"Primii pași\",\n  \"introduction.welcome.text\": \"Bun Venit in federație! In câteva momente, vei putea să transmiți mesaje și să participi la discuții cu oameni noi intr-o varietate foarte largă de servere din întreaga lume. Dar în special acest server, {domain},găzduiește profilul tău, deci reține numele acestuia.\",\n  \"keyboard_shortcuts.back\": \"navighează inapoi\",\n  \"keyboard_shortcuts.blocked\": \"să deschidă lista utilizatorilor blocați\",\n  \"keyboard_shortcuts.boost\": \"să redistribuie\",\n  \"keyboard_shortcuts.column\": \"să focuzeze o postare in una dintre coloane\",\n  \"keyboard_shortcuts.compose\": \"sa focuzeze zona de compunere\",\n  \"keyboard_shortcuts.description\": \"Descriere\",\n  \"keyboard_shortcuts.direct\": \"să deschidă coloana de mesaje directe\",\n  \"keyboard_shortcuts.down\": \"să fie mutată jos in lista\",\n  \"keyboard_shortcuts.enter\": \"să deschidă un status\",\n  \"keyboard_shortcuts.favourite\": \"să adauge la favorite\",\n  \"keyboard_shortcuts.favourites\": \"să deschidă lista cu favorite\",\n  \"keyboard_shortcuts.federated\": \"să deschidă fluxul global\",\n  \"keyboard_shortcuts.heading\": \"Comenzi rapide\",\n  \"keyboard_shortcuts.home\": \"să deschidă fluxul Acasă\",\n  \"keyboard_shortcuts.hotkey\": \"Prescurtări\",\n  \"keyboard_shortcuts.legend\": \"să afișeze această legendă\",\n  \"keyboard_shortcuts.local\": \"să deschidă fluxul local\",\n  \"keyboard_shortcuts.mention\": \"să menționeze autorul\",\n  \"keyboard_shortcuts.muted\": \"să deschidă lista utilizatorilor opriți\",\n  \"keyboard_shortcuts.my_profile\": \"să deschidă profilul tău\",\n  \"keyboard_shortcuts.notifications\": \"să deschidă coloana cu notificări\",\n  \"keyboard_shortcuts.pinned\": \"să deschidă lista postărilor fixate\",\n  \"keyboard_shortcuts.profile\": \"să deschidă porfilul autorului\",\n  \"keyboard_shortcuts.reply\": \"să răspundă\",\n  \"keyboard_shortcuts.requests\": \"să deschidă lista cu cereri de urmărire\",\n  \"keyboard_shortcuts.search\": \"să focuseze căutarea\",\n  \"keyboard_shortcuts.start\": \"să deschidă coloana \\\"Începere\\\"\",\n  \"keyboard_shortcuts.toggle_hidden\": \"să arate/ascundă textul in spatele CW\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"to show/hide media\",\n  \"keyboard_shortcuts.toot\": \"să înceapă o postare nouă\",\n  \"keyboard_shortcuts.unfocus\": \"să dezactiveze zona de compunere/căutare\",\n  \"keyboard_shortcuts.up\": \"să mute mai sus în listă\",\n  \"lightbox.close\": \"Închide\",\n  \"lightbox.next\": \"Următorul\",\n  \"lightbox.previous\": \"Precedentul\",\n  \"lightbox.view_context\": \"View context\",\n  \"lists.account.add\": \"Adaugă în listă\",\n  \"lists.account.remove\": \"Elimină din listă\",\n  \"lists.delete\": \"Șterge lista\",\n  \"lists.edit\": \"Editează lista\",\n  \"lists.edit.submit\": \"Change title\",\n  \"lists.new.create\": \"Adaugă listă\",\n  \"lists.new.title_placeholder\": \"Titlu pentru noua listă\",\n  \"lists.search\": \"Caută printre persoanale pe care le urmărești\",\n  \"lists.subheading\": \"Listele tale\",\n  \"loading_indicator.label\": \"Încărcare...\",\n  \"media_gallery.toggle_visible\": \"Comutați vizibilitatea\",\n  \"missing_indicator.label\": \"Nu a fost găsit\",\n  \"missing_indicator.sublabel\": \"Această resursă nu a putut fi găsită\",\n  \"mute_modal.hide_notifications\": \"Ascunzi notificările de la acest utilizator?\",\n  \"navigation_bar.apps\": \"Aplicații mobile\",\n  \"navigation_bar.blocks\": \"Utilizatori blocați\",\n  \"navigation_bar.community_timeline\": \"Flux local\",\n  \"navigation_bar.compose\": \"Compune o nouă postare\",\n  \"navigation_bar.direct\": \"Mesaje directe\",\n  \"navigation_bar.discover\": \"Descoperă\",\n  \"navigation_bar.domain_blocks\": \"Domenii ascunse\",\n  \"navigation_bar.edit_profile\": \"Editează profilul\",\n  \"navigation_bar.favourites\": \"Favorite\",\n  \"navigation_bar.filters\": \"Cuvinte oprite\",\n  \"navigation_bar.follow_requests\": \"Cereri de urmărire\",\n  \"navigation_bar.follows_and_followers\": \"Follows and followers\",\n  \"navigation_bar.info\": \"Despre această instanță\",\n  \"navigation_bar.keyboard_shortcuts\": \"Prescurtări\",\n  \"navigation_bar.lists\": \"Liste\",\n  \"navigation_bar.logout\": \"Deconectare\",\n  \"navigation_bar.mutes\": \"Utilizatori opriți\",\n  \"navigation_bar.personal\": \"Personal\",\n  \"navigation_bar.pins\": \"Postări fixate\",\n  \"navigation_bar.preferences\": \"Preferințe\",\n  \"navigation_bar.profile_directory\": \"Profile directory\",\n  \"navigation_bar.public_timeline\": \"Flux global\",\n  \"navigation_bar.security\": \"Securitate\",\n  \"notification.favourite\": \"{name} a adăugat statusul tău la favorite\",\n  \"notification.follow\": \"{name} te urmărește\",\n  \"notification.mention\": \"{name} te-a menționat\",\n  \"notification.poll\": \"A poll you have voted in has ended\",\n  \"notification.reblog\": \"{name} a redistribuit postarea ta\",\n  \"notifications.clear\": \"Șterge notificările\",\n  \"notifications.clear_confirmation\": \"Ești sigur că vrei să ștergi toate notificările?\",\n  \"notifications.column_settings.alert\": \"Notificări pe desktop\",\n  \"notifications.column_settings.favourite\": \"Favorite:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Afișează toate categoriile\",\n  \"notifications.column_settings.filter_bar.category\": \"Bară de filtrare rapidă\",\n  \"notifications.column_settings.filter_bar.show\": \"Arată\",\n  \"notifications.column_settings.follow\": \"Noi urmăritori:\",\n  \"notifications.column_settings.mention\": \"Mențiuni:\",\n  \"notifications.column_settings.poll\": \"Poll results:\",\n  \"notifications.column_settings.push\": \"Notificări push\",\n  \"notifications.column_settings.reblog\": \"Redistribuite:\",\n  \"notifications.column_settings.show\": \"Arată în coloană\",\n  \"notifications.column_settings.sound\": \"Redă sunet\",\n  \"notifications.filter.all\": \"Toate\",\n  \"notifications.filter.boosts\": \"Redistribuiri\",\n  \"notifications.filter.favourites\": \"Favorite\",\n  \"notifications.filter.follows\": \"Urmărește\",\n  \"notifications.filter.mentions\": \"Menționări\",\n  \"notifications.filter.polls\": \"Poll results\",\n  \"notifications.group\": \"{count} notificări\",\n  \"poll.closed\": \"Closed\",\n  \"poll.refresh\": \"Refresh\",\n  \"poll.total_votes\": \"{count, plural, one {# vote} other {# votes}}\",\n  \"poll.vote\": \"Vote\",\n  \"poll_button.add_poll\": \"Add a poll\",\n  \"poll_button.remove_poll\": \"Remove poll\",\n  \"privacy.change\": \"Cine vede asta\",\n  \"privacy.direct.long\": \"Postează doar pentru utilizatorii menționați\",\n  \"privacy.direct.short\": \"Direct\",\n  \"privacy.private.long\": \"Postează doar pentru urmăritori\",\n  \"privacy.private.short\": \"Doar urmăritorii\",\n  \"privacy.public.long\": \"Postează în fluxul public\",\n  \"privacy.public.short\": \"Public\",\n  \"privacy.unlisted.long\": \"Nu afisa in fluxul public\",\n  \"privacy.unlisted.short\": \"Nelistat\",\n  \"regeneration_indicator.label\": \"Încărcare…\",\n  \"regeneration_indicator.sublabel\": \"Fluxul tău este în preparare!\",\n  \"relative_time.days\": \"{number}z\",\n  \"relative_time.hours\": \"{number}h\",\n  \"relative_time.just_now\": \"acum\",\n  \"relative_time.minutes\": \"{number}m\",\n  \"relative_time.seconds\": \"{number}s\",\n  \"reply_indicator.cancel\": \"Anulează\",\n  \"report.forward\": \"Redirecționează catre {target}\",\n  \"report.forward_hint\": \"Acest cont este de pe un alt server. Trimitem o copie anonimă a raportului și acolo?\",\n  \"report.hint\": \"Sesizarea va fi trimsă către moderatorii acestei instanțe. Poți oferi o explicație pentru această sesizare mai jos:\",\n  \"report.placeholder\": \"Comentarii opționale\",\n  \"report.submit\": \"Trimite\",\n  \"report.target\": \"Raportează {target}\",\n  \"search.placeholder\": \"Caută\",\n  \"search_popout.search_format\": \"Formate pentru căutare avansată\",\n  \"search_popout.tips.full_text\": \"Textele simple returnează statusuri pe care le-ai scris, favorizat, redistribuit, sau în care sunt menționate , deasmenea și utilizatorii sau hastagurile care se potrivesc.\",\n  \"search_popout.tips.hashtag\": \"hashtag\",\n  \"search_popout.tips.status\": \"status\",\n  \"search_popout.tips.text\": \"Textele simple returnează nume, nume de utilizarori și hastagurile care se potrivesc\",\n  \"search_popout.tips.user\": \"utilizator\",\n  \"search_results.accounts\": \"Oameni\",\n  \"search_results.hashtags\": \"Hashtaguri\",\n  \"search_results.statuses\": \"Postări\",\n  \"search_results.total\": \"{count, number} {count, plural, one {result} other {results}}\",\n  \"status.admin_account\": \"Open moderation interface for @{name}\",\n  \"status.admin_status\": \"Open this status in the moderation interface\",\n  \"status.block\": \"Blochează @{name}\",\n  \"status.cancel_reblog_private\": \"Nedistribuit\",\n  \"status.cannot_reblog\": \"Această postare nu poate fi redistribuită\",\n  \"status.copy\": \"Copy link to status\",\n  \"status.delete\": \"Șterge\",\n  \"status.detailed_status\": \"Conversația detailată\",\n  \"status.direct\": \"Mesaj direct @{name}\",\n  \"status.embed\": \"Încorporare\",\n  \"status.favourite\": \"Favorite\",\n  \"status.filtered\": \"Sortate\",\n  \"status.load_more\": \"Încarcă mai multe\",\n  \"status.media_hidden\": \"Media ascunsă\",\n  \"status.mention\": \"Mentionează @{name}\",\n  \"status.more\": \"Mai mult\",\n  \"status.mute\": \"Oprește @{name}\",\n  \"status.mute_conversation\": \"Oprește conversația\",\n  \"status.open\": \"Extinde acest status\",\n  \"status.pin\": \"Fixează pe profil\",\n  \"status.pinned\": \"Postare fixată\",\n  \"status.read_more\": \"Citește mai mult\",\n  \"status.reblog\": \"Redistribuie\",\n  \"status.reblog_private\": \"Redistribuie către audiența originală\",\n  \"status.reblogged_by\": \"{name} a redistribuit\",\n  \"status.reblogs.empty\": \"Nimeni nu a redistribuit această postare până acum. Când cineva o va face, va apărea aici.\",\n  \"status.redraft\": \"Șterge și adaugă la ciorne\",\n  \"status.reply\": \"Răspunde\",\n  \"status.replyAll\": \"Răspunde la topic\",\n  \"status.report\": \"Raportează @{name}\",\n  \"status.sensitive_warning\": \"Conținut sensibil\",\n  \"status.share\": \"Distribuie\",\n  \"status.show_less\": \"Arată mai puțin\",\n  \"status.show_less_all\": \"Arată mai puțin pentru toți\",\n  \"status.show_more\": \"Arată mai mult\",\n  \"status.show_more_all\": \"Arată mai mult pentru toți\",\n  \"status.show_thread\": \"Arată topicul\",\n  \"status.unmute_conversation\": \"Repornește conversația\",\n  \"status.unpin\": \"Eliberează din profil\",\n  \"suggestions.dismiss\": \"Omite sugestia\",\n  \"suggestions.header\": \"Ai putea fi interesat de…\",\n  \"tabs_bar.federated_timeline\": \"Global\",\n  \"tabs_bar.home\": \"Acasă\",\n  \"tabs_bar.local_timeline\": \"Local\",\n  \"tabs_bar.notifications\": \"Notificări\",\n  \"tabs_bar.search\": \"Căutare\",\n  \"time_remaining.days\": \"{number, plural, one {# day} other {# days}} left\",\n  \"time_remaining.hours\": \"{number, plural, one {# hour} other {# hours}} left\",\n  \"time_remaining.minutes\": \"{number, plural, one {# minute} other {# minutes}} left\",\n  \"time_remaining.moments\": \"Moments remaining\",\n  \"time_remaining.seconds\": \"{number, plural, one {# second} other {# seconds}} left\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {person} other {people}} vorbesc\",\n  \"ui.beforeunload\": \"Postarea se va pierde dacă părăsești pagina.\",\n  \"upload_area.title\": \"Trage și eliberează pentru a încărca\",\n  \"upload_button.label\": \"Adaugă media (JPEG, PNG, GIF, WebM, MP4, MOV)\",\n  \"upload_error.limit\": \"File upload limit exceeded.\",\n  \"upload_error.poll\": \"File upload not allowed with polls.\",\n  \"upload_form.description\": \"Adaugă o descriere pentru persoanele cu deficiențe de vedere\",\n  \"upload_form.focus\": \"Schimbă previzualizarea\",\n  \"upload_form.undo\": \"Șterge\",\n  \"upload_progress.label\": \"Se Încarcă...\",\n  \"video.close\": \"Închide video\",\n  \"video.exit_fullscreen\": \"Închide\",\n  \"video.expand\": \"Extinde video\",\n  \"video.fullscreen\": \"Ecran întreg\",\n  \"video.hide\": \"Ascunde video\",\n  \"video.mute\": \"Oprește sonorul\",\n  \"video.pause\": \"Pauză\",\n  \"video.play\": \"Redare\",\n  \"video.unmute\": \"Repornește sunetul\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/ru.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Добавить или удалить из списков\",\n  \"account.badges.bot\": \"Бот\",\n  \"account.block\": \"Блокировать\",\n  \"account.block_domain\": \"Блокировать все с {domain}\",\n  \"account.blocked\": \"Заблокирован(а)\",\n  \"account.direct\": \"Написать @{name}\",\n  \"account.domain_blocked\": \"Домен скрыт\",\n  \"account.edit_profile\": \"Изменить профиль\",\n  \"account.endorse\": \"Рекомендовать в профиле\",\n  \"account.follow\": \"Подписаться\",\n  \"account.followers\": \"Подписаны\",\n  \"account.followers.empty\": \"Никто не подписан на этого пользователя.\",\n  \"account.follows\": \"Подписки\",\n  \"account.follows.empty\": \"Этот пользователь ни на кого не подписан.\",\n  \"account.follows_you\": \"Подписан(а) на Вас\",\n  \"account.hide_reblogs\": \"Скрыть реблоги от @{name}\",\n  \"account.link_verified_on\": \"Владение этой ссылкой было проверено {date}\",\n  \"account.locked_info\": \"Это закрытый аккаунт. Его владелец вручную одобряет подписчиков.\",\n  \"account.media\": \"Медиа\",\n  \"account.mention\": \"Упомянуть\",\n  \"account.moved_to\": \"Ищите {name} здесь:\",\n  \"account.mute\": \"Заглушить\",\n  \"account.mute_notifications\": \"Скрыть уведомления от @{name}\",\n  \"account.muted\": \"Приглушён\",\n  \"account.posts\": \"Посты\",\n  \"account.posts_with_replies\": \"Посты и ответы\",\n  \"account.report\": \"Пожаловаться\",\n  \"account.requested\": \"Ожидает подтверждения\",\n  \"account.share\": \"Поделиться профилем @{name}\",\n  \"account.show_reblogs\": \"Показывать продвижения от @{name}\",\n  \"account.unblock\": \"Разблокировать\",\n  \"account.unblock_domain\": \"Разблокировать {domain}\",\n  \"account.unendorse\": \"Не рекомендовать в профиле\",\n  \"account.unfollow\": \"Отписаться\",\n  \"account.unmute\": \"Снять глушение\",\n  \"account.unmute_notifications\": \"Показывать уведомления от @{name}\",\n  \"alert.unexpected.message\": \"Что-то пошло не так.\",\n  \"alert.unexpected.title\": \"Ой!\",\n  \"boost_modal.combo\": \"Нажмите {combo}, чтобы пропустить это в следующий раз\",\n  \"bundle_column_error.body\": \"Что-то пошло не так при загрузке этого компонента.\",\n  \"bundle_column_error.retry\": \"Попробовать снова\",\n  \"bundle_column_error.title\": \"Ошибка сети\",\n  \"bundle_modal_error.close\": \"Закрыть\",\n  \"bundle_modal_error.message\": \"Что-то пошло не так при загрузке этого компонента.\",\n  \"bundle_modal_error.retry\": \"Попробовать снова\",\n  \"column.blocks\": \"Список блокировки\",\n  \"column.community\": \"Локальная лента\",\n  \"column.direct\": \"Личные сообщения\",\n  \"column.domain_blocks\": \"Скрытые домены\",\n  \"column.favourites\": \"Понравившееся\",\n  \"column.follow_requests\": \"Запросы на подписку\",\n  \"column.home\": \"Главная\",\n  \"column.lists\": \"Списки\",\n  \"column.mutes\": \"Список глушения\",\n  \"column.notifications\": \"Уведомления\",\n  \"column.pins\": \"Закреплённый пост\",\n  \"column.public\": \"Глобальная лента\",\n  \"column_back_button.label\": \"Назад\",\n  \"column_header.hide_settings\": \"Скрыть настройки\",\n  \"column_header.moveLeft_settings\": \"Передвинуть колонку влево\",\n  \"column_header.moveRight_settings\": \"Передвинуть колонку вправо\",\n  \"column_header.pin\": \"Закрепить\",\n  \"column_header.show_settings\": \"Показать настройки\",\n  \"column_header.unpin\": \"Открепить\",\n  \"column_subheading.settings\": \"Настройки\",\n  \"community.column_settings.media_only\": \"Только с медиа\",\n  \"compose_form.direct_message_warning\": \"Этот статус будет виден только упомянутым пользователям.\",\n  \"compose_form.direct_message_warning_learn_more\": \"Узнать больше\",\n  \"compose_form.hashtag_warning\": \"Этот пост не будет показывается в поиске по хэштегу, т.к. он непубличный. Только публичные посты можно найти в поиске по хэштегу.\",\n  \"compose_form.lock_disclaimer\": \"Ваш аккаунт не {locked}. Любой человек может подписаться на Вас и просматривать посты для подписчиков.\",\n  \"compose_form.lock_disclaimer.lock\": \"закрыт\",\n  \"compose_form.placeholder\": \"О чем Вы думаете?\",\n  \"compose_form.poll.add_option\": \"Добавить\",\n  \"compose_form.poll.duration\": \"Длительность опроса\",\n  \"compose_form.poll.option_placeholder\": \"Вариант {number}\",\n  \"compose_form.poll.remove_option\": \"Удалить этот вариант\",\n  \"compose_form.publish\": \"Трубить\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"Пометить медиафайл как чувствительный\",\n  \"compose_form.sensitive.marked\": \"Медиафайлы не отмечены как чувствительные\",\n  \"compose_form.sensitive.unmarked\": \"Медиафайлы не отмечены как чувствительные\",\n  \"compose_form.spoiler.marked\": \"Текст скрыт за предупреждением\",\n  \"compose_form.spoiler.unmarked\": \"Текст не скрыт\",\n  \"compose_form.spoiler_placeholder\": \"Текст предупреждения\",\n  \"confirmation_modal.cancel\": \"Отмена\",\n  \"confirmations.block.block_and_report\": \"Заблокировать и пожаловаться\",\n  \"confirmations.block.confirm\": \"Заблокировать\",\n  \"confirmations.block.message\": \"Вы уверены, что хотите заблокировать {name}?\",\n  \"confirmations.delete.confirm\": \"Удалить\",\n  \"confirmations.delete.message\": \"Вы уверены, что хотите удалить этот статус?\",\n  \"confirmations.delete_list.confirm\": \"Удалить\",\n  \"confirmations.delete_list.message\": \"Вы действительно хотите навсегда удалить этот список?\",\n  \"confirmations.domain_block.confirm\": \"Блокировать весь домен\",\n  \"confirmations.domain_block.message\": \"Вы на самом деле уверены, что хотите блокировать весь {domain}? В большинстве случаев нескольких отдельных блокировок или глушений достаточно.\",\n  \"confirmations.mute.confirm\": \"Заглушить\",\n  \"confirmations.mute.message\": \"Вы уверены, что хотите заглушить {name}?\",\n  \"confirmations.redraft.confirm\": \"Удалить и исправить\",\n  \"confirmations.redraft.message\": \"Вы уверены, что хотите удалить этот статус и превратить в черновик? Вы потеряете все ответы, продвижения и отметки 'нравится' к нему.\",\n  \"confirmations.reply.confirm\": \"Ответить\",\n  \"confirmations.reply.message\": \"При ответе текст набираемого сообщения будет перезаписан. Продолжить?\",\n  \"confirmations.unfollow.confirm\": \"Отписаться\",\n  \"confirmations.unfollow.message\": \"Вы уверены, что хотите отписаться от {name}?\",\n  \"embed.instructions\": \"Встройте этот статус на Вашем сайте, скопировав код внизу.\",\n  \"embed.preview\": \"Так это будет выглядеть:\",\n  \"emoji_button.activity\": \"Занятия\",\n  \"emoji_button.custom\": \"Собственные\",\n  \"emoji_button.flags\": \"Флаги\",\n  \"emoji_button.food\": \"Еда и напитки\",\n  \"emoji_button.label\": \"Вставить эмодзи\",\n  \"emoji_button.nature\": \"Природа\",\n  \"emoji_button.not_found\": \"Нет эмодзи!! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"Предметы\",\n  \"emoji_button.people\": \"Люди\",\n  \"emoji_button.recent\": \"Последние\",\n  \"emoji_button.search\": \"Найти...\",\n  \"emoji_button.search_results\": \"Результаты поиска\",\n  \"emoji_button.symbols\": \"Символы\",\n  \"emoji_button.travel\": \"Путешествия\",\n  \"empty_column.account_timeline\": \"Статусов нет!\",\n  \"empty_column.account_unavailable\": \"Профиль недоступен\",\n  \"empty_column.blocks\": \"Вы ещё никого не заблокировали.\",\n  \"empty_column.community\": \"Локальная лента пуста. Напишите что-нибудь, чтобы разогреть народ!\",\n  \"empty_column.direct\": \"У Вас пока нет личных сообщений. Когда Вы начнёте их отправлять или получать, они появятся здесь.\",\n  \"empty_column.domain_blocks\": \"Скрытых доменов пока нет.\",\n  \"empty_column.favourited_statuses\": \"Вы не добавили ни одного статуса в 'Избранное'. Как только Вы это сделаете, они появятся здесь.\",\n  \"empty_column.favourites\": \"Никто ещё не добавил этот статус в 'Избранное'. Как только кто-то это сделает, они появятся здесь.\",\n  \"empty_column.follow_requests\": \"Вам ещё не приходили запросы на подписку. Все новые запросы будут показаны здесь.\",\n  \"empty_column.hashtag\": \"Статусов с таким хэштегом еще не существует.\",\n  \"empty_column.home\": \"Пока Вы ни на кого не подписаны. Полистайте {public} или используйте поиск, чтобы освоиться и завести новые знакомства.\",\n  \"empty_column.home.public_timeline\": \"публичные ленты\",\n  \"empty_column.list\": \"В этом списке пока ничего нет.\",\n  \"empty_column.lists\": \"У Вас ещё нет списков. Все созданные Вами списки будут показаны здесь.\",\n  \"empty_column.mutes\": \"Вы ещё никого не заглушили.\",\n  \"empty_column.notifications\": \"У Вас еще нет уведомлений. Заведите знакомство с другими пользователями, чтобы начать разговор.\",\n  \"empty_column.public\": \"Здесь ничего нет! Опубликуйте что-нибудь или подпишитесь на пользователей с других узлов, чтобы заполнить ленту.\",\n  \"follow_request.authorize\": \"Авторизовать\",\n  \"follow_request.reject\": \"Отказать\",\n  \"getting_started.developers\": \"Для разработчиков\",\n  \"getting_started.directory\": \"Каталог профилей\",\n  \"getting_started.documentation\": \"Документация\",\n  \"getting_started.heading\": \"Добро пожаловать\",\n  \"getting_started.invite\": \"Пригласить людей\",\n  \"getting_started.open_source_notice\": \"Mastodon - сервис с открытым исходным кодом. Вы можете помочь проекту или сообщить о проблемах на GitHub по адресу {github}.\",\n  \"getting_started.security\": \"Безопасность\",\n  \"getting_started.terms\": \"Условия использования\",\n  \"hashtag.column_header.tag_mode.all\": \"и {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"или {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"без {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"Предложений не найдено\",\n  \"hashtag.column_settings.select.placeholder\": \"Введите хэштеги…\",\n  \"hashtag.column_settings.tag_mode.all\": \"Все из списка\",\n  \"hashtag.column_settings.tag_mode.any\": \"Любой из списка\",\n  \"hashtag.column_settings.tag_mode.none\": \"Ни один из списка\",\n  \"hashtag.column_settings.tag_toggle\": \"Включая дополнительные хэштеге из этой колонки\",\n  \"home.column_settings.basic\": \"Основные\",\n  \"home.column_settings.show_reblogs\": \"Показывать продвижения\",\n  \"home.column_settings.show_replies\": \"Показывать ответы\",\n  \"intervals.full.days\": \"{number, plural, one {# день} few {# дня} many {# дней} other {# дней}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# час} few {# часа} many {# часов} other {# часов}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# минута} few {# минуты} many {# минут} other {# минут}}\",\n  \"introduction.federation.action\": \"Далее\",\n  \"introduction.federation.federated.headline\": \"Глобальная лента\",\n  \"introduction.federation.federated.text\": \"Публичные статусы с других серверов федеративной сети расположатся в глобальной ленте.\",\n  \"introduction.federation.home.headline\": \"Домашняя лента\",\n  \"introduction.federation.home.text\": \"Статусы от тех, на кого вы подписаны, появятся в вашей домашней ленте. Вы можете подписаться на кого угодно с любого сервера!\",\n  \"introduction.federation.local.headline\": \"Локальная лента\",\n  \"introduction.federation.local.text\": \"Публичные статусы от людей с того же сервера, что и вы, будут отображены в локальной ленте.\",\n  \"introduction.interactions.action\": \"Завершить обучение\",\n  \"introduction.interactions.favourite.headline\": \"Отметки \\\"нравится\\\"\",\n  \"introduction.interactions.favourite.text\": \"Вы можете отметить статус, чтобы вернуться к нему позже и дать знать автору, что запись вам понравилась, поставив отметку \\\"нравится\\\".\",\n  \"introduction.interactions.reblog.headline\": \"Продвижения\",\n  \"introduction.interactions.reblog.text\": \"Вы можете делиться статусами других людей, продвигая их в своём аккаунте.\",\n  \"introduction.interactions.reply.headline\": \"Ответы\",\n  \"introduction.interactions.reply.text\": \"Вы можете отвечать свои и чужие посты, образуя цепочки сообщений (обсуждения).\",\n  \"introduction.welcome.action\": \"Поехали!\",\n  \"introduction.welcome.headline\": \"Первые шаги\",\n  \"introduction.welcome.text\": \"Добро пожаловать в федеративную сеть! Уже через мгновение вы сможете отправлять сообщения и общаться со своими друзьями на любом сервере. Но этот сервер — {domain} — особенный: на нём располагается ваш профиль. Запомните его название.\",\n  \"keyboard_shortcuts.back\": \"перейти назад\",\n  \"keyboard_shortcuts.blocked\": \"чтобы открыть список заблокированных\",\n  \"keyboard_shortcuts.boost\": \"продвинуть пост\",\n  \"keyboard_shortcuts.column\": \"фокус на одном из столбцов\",\n  \"keyboard_shortcuts.compose\": \"фокус на поле ввода\",\n  \"keyboard_shortcuts.description\": \"Описание\",\n  \"keyboard_shortcuts.direct\": \"чтобы показать колонку личных сообщений\",\n  \"keyboard_shortcuts.down\": \"вниз по списку\",\n  \"keyboard_shortcuts.enter\": \"развернуть пост\",\n  \"keyboard_shortcuts.favourite\": \"в избранное\",\n  \"keyboard_shortcuts.favourites\": \"открыть 'Избранное'\",\n  \"keyboard_shortcuts.federated\": \"перейти к глобальной ленте\",\n  \"keyboard_shortcuts.heading\": \"Сочетания клавиш\",\n  \"keyboard_shortcuts.home\": \"перейти к домашней ленте\",\n  \"keyboard_shortcuts.hotkey\": \"Гор. клавиша\",\n  \"keyboard_shortcuts.legend\": \"показать это окно\",\n  \"keyboard_shortcuts.local\": \"перейти к локальной ленте\",\n  \"keyboard_shortcuts.mention\": \"упомянуть автора поста\",\n  \"keyboard_shortcuts.muted\": \"открыть список заглушённых\",\n  \"keyboard_shortcuts.my_profile\": \"перейти к своему профилю\",\n  \"keyboard_shortcuts.notifications\": \"перейти к уведомлениям\",\n  \"keyboard_shortcuts.pinned\": \"перейти к закреплённым статусам\",\n  \"keyboard_shortcuts.profile\": \"перейти к профилю автора\",\n  \"keyboard_shortcuts.reply\": \"ответить\",\n  \"keyboard_shortcuts.requests\": \"перейти к запросам на подписку\",\n  \"keyboard_shortcuts.search\": \"перейти к поиску\",\n  \"keyboard_shortcuts.start\": \"перейти к разделу \\\"добро пожаловать\\\"\",\n  \"keyboard_shortcuts.toggle_hidden\": \"показать/скрыть текст за предупреждением\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"показать/скрыть медиафайлы\",\n  \"keyboard_shortcuts.toot\": \"начать писать новый пост\",\n  \"keyboard_shortcuts.unfocus\": \"убрать фокус с поля ввода/поиска\",\n  \"keyboard_shortcuts.up\": \"вверх по списку\",\n  \"lightbox.close\": \"Закрыть\",\n  \"lightbox.next\": \"Далее\",\n  \"lightbox.previous\": \"Назад\",\n  \"lightbox.view_context\": \"Контекст\",\n  \"lists.account.add\": \"Добавить в список\",\n  \"lists.account.remove\": \"Убрать из списка\",\n  \"lists.delete\": \"Удалить список\",\n  \"lists.edit\": \"Изменить список\",\n  \"lists.edit.submit\": \"Изменить название\",\n  \"lists.new.create\": \"Новый список\",\n  \"lists.new.title_placeholder\": \"Заголовок списка\",\n  \"lists.search\": \"Искать из ваших подписок\",\n  \"lists.subheading\": \"Ваши списки\",\n  \"loading_indicator.label\": \"Загрузка...\",\n  \"media_gallery.toggle_visible\": \"Показать/скрыть\",\n  \"missing_indicator.label\": \"Не найдено\",\n  \"missing_indicator.sublabel\": \"Запрашиваемый ресурс не найден\",\n  \"mute_modal.hide_notifications\": \"Убрать уведомления от этого пользователя?\",\n  \"navigation_bar.apps\": \"Мобильные приложения\",\n  \"navigation_bar.blocks\": \"Список блокировки\",\n  \"navigation_bar.community_timeline\": \"Локальная лента\",\n  \"navigation_bar.compose\": \"Создать новый статус\",\n  \"navigation_bar.direct\": \"Личные сообщения\",\n  \"navigation_bar.discover\": \"Изучайте\",\n  \"navigation_bar.domain_blocks\": \"Скрытые домены\",\n  \"navigation_bar.edit_profile\": \"Изменить профиль\",\n  \"navigation_bar.favourites\": \"Понравившееся\",\n  \"navigation_bar.filters\": \"Заглушенные слова\",\n  \"navigation_bar.follow_requests\": \"Запросы на подписку\",\n  \"navigation_bar.follows_and_followers\": \"Подписки и подписчики\",\n  \"navigation_bar.info\": \"Об узле\",\n  \"navigation_bar.keyboard_shortcuts\": \"Сочетания клавиш\",\n  \"navigation_bar.lists\": \"Списки\",\n  \"navigation_bar.logout\": \"Выйти\",\n  \"navigation_bar.mutes\": \"Список глушения\",\n  \"navigation_bar.personal\": \"Личное\",\n  \"navigation_bar.pins\": \"Закреплённые посты\",\n  \"navigation_bar.preferences\": \"Опции\",\n  \"navigation_bar.profile_directory\": \"Каталог профилей\",\n  \"navigation_bar.public_timeline\": \"Глобальная лента\",\n  \"navigation_bar.security\": \"Безопасность\",\n  \"notification.favourite\": \"{name} понравился Ваш статус\",\n  \"notification.follow\": \"{name} подписался(-лась) на Вас\",\n  \"notification.mention\": \"{name} упомянул(а) Вас\",\n  \"notification.poll\": \"Опрос, в котором вы приняли участие, завершился\",\n  \"notification.reblog\": \"{name} продвинул(а) Ваш статус\",\n  \"notifications.clear\": \"Очистить уведомления\",\n  \"notifications.clear_confirmation\": \"Вы уверены, что хотите очистить все уведомления?\",\n  \"notifications.column_settings.alert\": \"Десктопные уведомления\",\n  \"notifications.column_settings.favourite\": \"Нравится:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Отображать все категории\",\n  \"notifications.column_settings.filter_bar.category\": \"Фильтры по категориям\",\n  \"notifications.column_settings.filter_bar.show\": \"Показывать\",\n  \"notifications.column_settings.follow\": \"Новые подписчики:\",\n  \"notifications.column_settings.mention\": \"Упоминания:\",\n  \"notifications.column_settings.poll\": \"Результаты опроса:\",\n  \"notifications.column_settings.push\": \"Push-уведомления\",\n  \"notifications.column_settings.reblog\": \"Продвижения:\",\n  \"notifications.column_settings.show\": \"Показывать в колонке\",\n  \"notifications.column_settings.sound\": \"Проигрывать звук\",\n  \"notifications.filter.all\": \"Все\",\n  \"notifications.filter.boosts\": \"Продвижения\",\n  \"notifications.filter.favourites\": \"Отметки \\\"нравится\\\"\",\n  \"notifications.filter.follows\": \"Новые подписчики\",\n  \"notifications.filter.mentions\": \"Упоминания\",\n  \"notifications.filter.polls\": \"Результаты опросов\",\n  \"notifications.group\": \"{count} уведомл.\",\n  \"poll.closed\": \"Завершён\",\n  \"poll.refresh\": \"Обновить\",\n  \"poll.total_votes\": \"{count, plural, one {# голос} few {# голоса} many {# голосов} other {# голосов}}\",\n  \"poll.vote\": \"Голосовать\",\n  \"poll_button.add_poll\": \"Добавить опрос\",\n  \"poll_button.remove_poll\": \"Удалить опрос\",\n  \"privacy.change\": \"Изменить видимость статуса\",\n  \"privacy.direct.long\": \"Показать только упомянутым\",\n  \"privacy.direct.short\": \"Направленный\",\n  \"privacy.private.long\": \"Показать только подписчикам\",\n  \"privacy.private.short\": \"Приватный\",\n  \"privacy.public.long\": \"Показать в публичных лентах\",\n  \"privacy.public.short\": \"Публичный\",\n  \"privacy.unlisted.long\": \"Не показывать в лентах\",\n  \"privacy.unlisted.short\": \"Скрытый\",\n  \"regeneration_indicator.label\": \"Загрузка…\",\n  \"regeneration_indicator.sublabel\": \"Ваша домашняя лента готовится!\",\n  \"relative_time.days\": \"{number}д\",\n  \"relative_time.hours\": \"{number}ч\",\n  \"relative_time.just_now\": \"только что\",\n  \"relative_time.minutes\": \"{number}м\",\n  \"relative_time.seconds\": \"{number}с\",\n  \"reply_indicator.cancel\": \"Отмена\",\n  \"report.forward\": \"Переслать в {target}\",\n  \"report.forward_hint\": \"Этот аккаунт расположен на другом сервере. Отправить туда анонимную копию Вашей жалобы?\",\n  \"report.hint\": \"Жалоба будет отправлена модераторам Вашего сервера. Вы также можете указать подробную причину жалобы ниже:\",\n  \"report.placeholder\": \"Комментарий\",\n  \"report.submit\": \"Отправить\",\n  \"report.target\": \"Жалоба на {target}\",\n  \"search.placeholder\": \"Поиск\",\n  \"search_popout.search_format\": \"Продвинутый формат поиска\",\n  \"search_popout.tips.full_text\": \"Возвращает посты, которые Вы написали, отметили как 'избранное', продвинули или в которых были упомянуты, а также содержащие юзернейм, имя и хэштеги.\",\n  \"search_popout.tips.hashtag\": \"хэштег\",\n  \"search_popout.tips.status\": \"статус\",\n  \"search_popout.tips.text\": \"Простой ввод текста покажет совпадающие имена пользователей, отображаемые имена и хэштеги\",\n  \"search_popout.tips.user\": \"пользователь\",\n  \"search_results.accounts\": \"Люди\",\n  \"search_results.hashtags\": \"Хэштеги\",\n  \"search_results.statuses\": \"Посты\",\n  \"search_results.total\": \"{count, number} {count, plural, one {результат} few {результата} many {результатов} other {результатов}}\",\n  \"status.admin_account\": \"Открыть интерфейс модератора для @{name}\",\n  \"status.admin_status\": \"Открыть этот статус в интерфейсе модератора\",\n  \"status.block\": \"Заблокировать @{name}\",\n  \"status.cancel_reblog_private\": \"Не продвигать\",\n  \"status.cannot_reblog\": \"Этот статус не может быть продвинут\",\n  \"status.copy\": \"Копировать ссылку на запись\",\n  \"status.delete\": \"Удалить\",\n  \"status.detailed_status\": \"Подробный просмотр обсуждения\",\n  \"status.direct\": \"Написать @{name}\",\n  \"status.embed\": \"Встроить\",\n  \"status.favourite\": \"Нравится\",\n  \"status.filtered\": \"Отфильтровано\",\n  \"status.load_more\": \"Показать еще\",\n  \"status.media_hidden\": \"Медиа скрыто\",\n  \"status.mention\": \"Упомянуть @{name}\",\n  \"status.more\": \"Больше\",\n  \"status.mute\": \"Заглушить @{name}\",\n  \"status.mute_conversation\": \"Заглушить всё обсуждение\",\n  \"status.open\": \"Развернуть статус\",\n  \"status.pin\": \"Закрепить в профиле\",\n  \"status.pinned\": \"Закреплённый статус\",\n  \"status.read_more\": \"Ещё\",\n  \"status.reblog\": \"Продвинуть\",\n  \"status.reblog_private\": \"Продвинуть для своей аудитории\",\n  \"status.reblogged_by\": \"{name} продвинул(а)\",\n  \"status.reblogs.empty\": \"Никто ещё не продвинул этот статус. Как только кто-то это сделает, они появятся здесь.\",\n  \"status.redraft\": \"Удалить и исправить\",\n  \"status.reply\": \"Ответить\",\n  \"status.replyAll\": \"Ответить всем\",\n  \"status.report\": \"Пожаловаться\",\n  \"status.sensitive_warning\": \"Чувствительный контент\",\n  \"status.share\": \"Поделиться\",\n  \"status.show_less\": \"Свернуть\",\n  \"status.show_less_all\": \"Свернуть для всех\",\n  \"status.show_more\": \"Развернуть\",\n  \"status.show_more_all\": \"Развернуть для всех\",\n  \"status.show_thread\": \"Показать обсуждение\",\n  \"status.unmute_conversation\": \"Снять глушение с обсуждения\",\n  \"status.unpin\": \"Открепить от профиля\",\n  \"suggestions.dismiss\": \"Удалить предложение\",\n  \"suggestions.header\": \"Вам может быть интересно…\",\n  \"tabs_bar.federated_timeline\": \"Глобальная\",\n  \"tabs_bar.home\": \"Главная\",\n  \"tabs_bar.local_timeline\": \"Локальная\",\n  \"tabs_bar.notifications\": \"Уведомления\",\n  \"tabs_bar.search\": \"Поиск\",\n  \"time_remaining.days\": \"{number, plural, one {остался # день} few {осталось # дня} many {осталось # дней} other {осталось # дней}}\",\n  \"time_remaining.hours\": \"{number, plural, one {остался # час} few {осталось # часа} many {осталось # часов} other {осталось # часов}}\",\n  \"time_remaining.minutes\": \"{number, plural, one {осталась # минута} few {осталось # минуты} many {осталось # минут} other {осталось # минут}}\",\n  \"time_remaining.moments\": \"остались считанные мгновения\",\n  \"time_remaining.seconds\": \"{number, plural, one {осталась # секунду} few {осталось # секунды} many {осталось # секунд} other {осталось # секунд}}\",\n  \"trends.count_by_accounts\": \"Популярно у {count} {rawCount, plural, one {человека} few {человек} many {человек} other {человек}}\",\n  \"ui.beforeunload\": \"Ваш черновик будет утерян, если вы покинете Mastodon.\",\n  \"upload_area.title\": \"Перетащите сюда, чтобы загрузить\",\n  \"upload_button.label\": \"Добавить медиаконтент\",\n  \"upload_error.limit\": \"Достигнут лимит загруженных файлов.\",\n  \"upload_error.poll\": \"К опросам нельзя прикреплять файлы.\",\n  \"upload_form.description\": \"Описать для людей с нарушениями зрения\",\n  \"upload_form.focus\": \"Обрезать\",\n  \"upload_form.undo\": \"Отменить\",\n  \"upload_progress.label\": \"Загрузка...\",\n  \"video.close\": \"Закрыть видео\",\n  \"video.exit_fullscreen\": \"Покинуть полноэкранный режим\",\n  \"video.expand\": \"Развернуть видео\",\n  \"video.fullscreen\": \"Полноэкранный режим\",\n  \"video.hide\": \"Скрыть видео\",\n  \"video.mute\": \"Заглушить звук\",\n  \"video.pause\": \"Пауза\",\n  \"video.play\": \"Пуск\",\n  \"video.unmute\": \"Включить звук\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/sk.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Pridaj, alebo odstráň zo zoznamov\",\n  \"account.badges.bot\": \"Bot\",\n  \"account.block\": \"Blokuj @{name}\",\n  \"account.block_domain\": \"Ukry všetko z {domain}\",\n  \"account.blocked\": \"Blokovaný/á\",\n  \"account.direct\": \"Súkromná správa pre @{name}\",\n  \"account.domain_blocked\": \"Doména ukrytá\",\n  \"account.edit_profile\": \"Uprav profil\",\n  \"account.endorse\": \"Zobrazuj na profile\",\n  \"account.follow\": \"Následuj\",\n  \"account.followers\": \"Sledujúci\",\n  \"account.followers.empty\": \"Tohto užívateľa ešte nikto nenásleduje.\",\n  \"account.follows\": \"Následuje\",\n  \"account.follows.empty\": \"Tento užívateľ ešte nikoho nenásleduje.\",\n  \"account.follows_you\": \"Následuje ťa\",\n  \"account.hide_reblogs\": \"Skry vyzdvihnutia od @{name}\",\n  \"account.link_verified_on\": \"Vlastníctvo tohto odkazu bolo skontrolované {date}\",\n  \"account.locked_info\": \"Stav súkromia pre tento účet je nastavený na zamknutý. Jeho vlastník sám prehodnocuje, kto ho môže sledovať.\",\n  \"account.media\": \"Médiá\",\n  \"account.mention\": \"Spomeň @{name}\",\n  \"account.moved_to\": \"{name} sa presunul/a na:\",\n  \"account.mute\": \"Ignorovať @{name}\",\n  \"account.mute_notifications\": \"Stĺm oboznámenia od @{name}\",\n  \"account.muted\": \"Utíšený/á\",\n  \"account.posts\": \"Príspevky\",\n  \"account.posts_with_replies\": \"Príspevky aj s odpoveďami\",\n  \"account.report\": \"Nahlás @{name}\",\n  \"account.requested\": \"Čaká na schválenie. Klikni pre zrušenie žiadosti\",\n  \"account.share\": \"Zdieľaj @{name} profil\",\n  \"account.show_reblogs\": \"Ukáž vyzdvihnutia od @{name}\",\n  \"account.unblock\": \"Odblokuj @{name}\",\n  \"account.unblock_domain\": \"Prestaň skrývať {domain}\",\n  \"account.unendorse\": \"Nezobrazuj na profile\",\n  \"account.unfollow\": \"Prestaň následovať\",\n  \"account.unmute\": \"Prestaň ignorovať @{name}\",\n  \"account.unmute_notifications\": \"Zruš stĺmenie oboznámení od @{name}\",\n  \"alert.unexpected.message\": \"Vyskytla sa nečakaná chyba.\",\n  \"alert.unexpected.title\": \"Oops!\",\n  \"boost_modal.combo\": \"Nabudúce môžeš kliknúť {combo} pre preskočenie\",\n  \"bundle_column_error.body\": \"Pri načítaní tohto prvku nastala nejaká chyba.\",\n  \"bundle_column_error.retry\": \"Skús to znova\",\n  \"bundle_column_error.title\": \"Chyba siete\",\n  \"bundle_modal_error.close\": \"Zatvor\",\n  \"bundle_modal_error.message\": \"Nastala chyba pri načítaní tohto komponentu.\",\n  \"bundle_modal_error.retry\": \"Skúsiť znova\",\n  \"column.blocks\": \"Blokovaní užívatelia\",\n  \"column.community\": \"Miestna časová os\",\n  \"column.direct\": \"Súkromné správy\",\n  \"column.domain_blocks\": \"Skryté domény\",\n  \"column.favourites\": \"Obľúbené\",\n  \"column.follow_requests\": \"Žiadosti o sledovanie\",\n  \"column.home\": \"Domov\",\n  \"column.lists\": \"Zoznamy\",\n  \"column.mutes\": \"Ignorovaní užívatelia\",\n  \"column.notifications\": \"Oboznámenia\",\n  \"column.pins\": \"Pripnuté príspevky\",\n  \"column.public\": \"Federovaná časová os\",\n  \"column_back_button.label\": \"Späť\",\n  \"column_header.hide_settings\": \"Skryť nastavenia\",\n  \"column_header.moveLeft_settings\": \"Presuň stĺpec doľava\",\n  \"column_header.moveRight_settings\": \"Presuň stĺpec doprava\",\n  \"column_header.pin\": \"Pripni\",\n  \"column_header.show_settings\": \"Ukáž nastavenia\",\n  \"column_header.unpin\": \"Odopnúť\",\n  \"column_subheading.settings\": \"Nastavenia\",\n  \"community.column_settings.media_only\": \"Iba médiá\",\n  \"compose_form.direct_message_warning\": \"Tento príspevok bude videný výhradne iba spomenutými užívateľmi. Ber ale na vedomie že správci tvojej a všetkých iných zahrnutých instancií majú možnosť skontrolovať túto správu.\",\n  \"compose_form.direct_message_warning_learn_more\": \"Zistiť viac\",\n  \"compose_form.hashtag_warning\": \"Tento toot nebude zobrazený pod žiadným haštagom lebo nieje listovaný. Iba verejné tooty môžu byť nájdené podľa haštagu.\",\n  \"compose_form.lock_disclaimer\": \"Tvoj účet nie je {locked}. Ktokoľvek ťa môže nasledovať a vidieť tvoje správy pre sledujúcich.\",\n  \"compose_form.lock_disclaimer.lock\": \"zamknutý\",\n  \"compose_form.placeholder\": \"Čo máš na mysli?\",\n  \"compose_form.poll.add_option\": \"Pridaj voľbu\",\n  \"compose_form.poll.duration\": \"Trvanie ankety\",\n  \"compose_form.poll.option_placeholder\": \"Voľba {number}\",\n  \"compose_form.poll.remove_option\": \"Odstráň túto voľbu\",\n  \"compose_form.publish\": \"Pošli\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"Mark media as sensitive\",\n  \"compose_form.sensitive.marked\": \"Médiálny obsah je označený ako chúlostivý\",\n  \"compose_form.sensitive.unmarked\": \"Médiálny obsah nieje označený ako chúlostivý\",\n  \"compose_form.spoiler.marked\": \"Text je ukrytý za varovaním\",\n  \"compose_form.spoiler.unmarked\": \"Text nieje ukrytý\",\n  \"compose_form.spoiler_placeholder\": \"Sem napíš tvoje varovanie\",\n  \"confirmation_modal.cancel\": \"Zruš\",\n  \"confirmations.block.block_and_report\": \"Block & Report\",\n  \"confirmations.block.confirm\": \"Blokuj\",\n  \"confirmations.block.message\": \"Si si istý/á, že chceš blokovať {name}?\",\n  \"confirmations.delete.confirm\": \"Vymaž\",\n  \"confirmations.delete.message\": \"Si si istý/á, že chceš vymazať túto správu?\",\n  \"confirmations.delete_list.confirm\": \"Vymaž\",\n  \"confirmations.delete_list.message\": \"Si si istý/á, že chceš natrvalo vymazať tento zoznam?\",\n  \"confirmations.domain_block.confirm\": \"Skry celú doménu\",\n  \"confirmations.domain_block.message\": \"Si si naozaj istý/á, že chceš blokovať celú doménu {domain}? Vo väčšine prípadov stačí blokovať alebo ignorovať pár konkrétnych užívateľov, čo sa doporučuje. Neuvidíš obsah z tejto domény v žiadnej verejnej časovej osi, ani v oznámeniach. Tvoji následovníci pochádzajúci z tejto domény budú odstránení.\",\n  \"confirmations.mute.confirm\": \"Ignoruj\",\n  \"confirmations.mute.message\": \"Naozaj chceš ignorovať {name}?\",\n  \"confirmations.redraft.confirm\": \"Vyčisti a prepíš\",\n  \"confirmations.redraft.message\": \"Si si istý/á, že chceš premazať a prepísať tento príspevok? Jeho nadobudnuté vyzdvihnutia a obľúbenia, ale i odpovede na pôvodný príspevok budú odlúčené.\",\n  \"confirmations.reply.confirm\": \"Odpovedz\",\n  \"confirmations.reply.message\": \"Odpovedaním akurát teraz prepíšeš správu, ktorú máš práve rozpísanú. Si si istý/á, že chceš pokračovať?\",\n  \"confirmations.unfollow.confirm\": \"Nesleduj\",\n  \"confirmations.unfollow.message\": \"Naozaj chceš prestať sledovať {name}?\",\n  \"embed.instructions\": \"Umiestni kód uvedený nižšie pre pridanie tohto statusu na tvoju web stránku.\",\n  \"embed.preview\": \"Tu je ako to bude vyzerať:\",\n  \"emoji_button.activity\": \"Aktivita\",\n  \"emoji_button.custom\": \"Vlastné\",\n  \"emoji_button.flags\": \"Vlajky\",\n  \"emoji_button.food\": \"Jedlá a nápoje\",\n  \"emoji_button.label\": \"Vlož emotikony\",\n  \"emoji_button.nature\": \"Prírodné\",\n  \"emoji_button.not_found\": \"Nie emotikony!! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"Predmety\",\n  \"emoji_button.people\": \"Ľudia\",\n  \"emoji_button.recent\": \"Často používané\",\n  \"emoji_button.search\": \"Hľadaj...\",\n  \"emoji_button.search_results\": \"Nájdené\",\n  \"emoji_button.symbols\": \"Symboly\",\n  \"emoji_button.travel\": \"Cestovanie a miesta\",\n  \"empty_column.account_timeline\": \"Niesú tu žiadne príspevky!\",\n  \"empty_column.account_unavailable\": \"Profil nedostupný\",\n  \"empty_column.blocks\": \"Ešte si nikoho nezablokoval/a.\",\n  \"empty_column.community\": \"Lokálna časová os je prázdna. Napíšte niečo, aby sa to tu začalo hýbať!\",\n  \"empty_column.direct\": \"Ešte nemáš žiadne súkromné správy. Keď nejakú pošleš, alebo dostaneš, ukáže sa tu.\",\n  \"empty_column.domain_blocks\": \"Žiadne domény ešte niesú skryté.\",\n  \"empty_column.favourited_statuses\": \"Nemáš obľúbené ešte žiadne príspevky. Keď si nejaký obľúbiš, bude zobrazený práve tu.\",\n  \"empty_column.favourites\": \"Tento toot si ešte nikto neobľúbil. Ten kto si ho obľúbi, bude zobrazený tu.\",\n  \"empty_column.follow_requests\": \"Ešte nemáš žiadne požiadavky o následovanie. Keď nejaké dostaneš, budú tu zobrazené.\",\n  \"empty_column.hashtag\": \"Pod týmto hashtagom sa ešte nič nenachádza.\",\n  \"empty_column.home\": \"Tvoja lokálna osa je zatiaľ prázdna! Pre začiatok navštív {public}, alebo použi vyhľadávanie a nájdi tak aj iných užívateľov.\",\n  \"empty_column.home.public_timeline\": \"verejná časová os\",\n  \"empty_column.list\": \"Tento zoznam je ešte prázdny. Keď ale členovia tohoto zoznamu napíšu nové správy, tak tie sa objavia priamo tu.\",\n  \"empty_column.lists\": \"Nemáš ešte žiadne zoznamy. Keď nejaký vytvoríš, bude zobrazený práve tu.\",\n  \"empty_column.mutes\": \"Ešte si nestĺmil žiadných užívateľov.\",\n  \"empty_column.notifications\": \"Ešte nemáš žiadne oznámenia. Začni komunikovať s ostatnými, aby diskusia mohla začať.\",\n  \"empty_column.public\": \"Ešte tu nič nie je. Napíš niečo verejne, alebo začni sledovať užívateľov z iných serverov, aby tu niečo pribudlo\",\n  \"follow_request.authorize\": \"Povoľ prístup\",\n  \"follow_request.reject\": \"Odmietni\",\n  \"getting_started.developers\": \"Vývojári\",\n  \"getting_started.directory\": \"Databáza profilov\",\n  \"getting_started.documentation\": \"Dokumentácia\",\n  \"getting_started.heading\": \"Začni tu\",\n  \"getting_started.invite\": \"Pozvať ľudí\",\n  \"getting_started.open_source_notice\": \"Mastodon je softvér s otvoreným kódom. Nahlásiť chyby, alebo prispievať môžeš na GitHube v {github}.\",\n  \"getting_started.security\": \"Zabezpečenie\",\n  \"getting_started.terms\": \"Podmienky prevozu\",\n  \"hashtag.column_header.tag_mode.all\": \"a {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"alebo {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"bez {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"Žiadne návrhy neboli nájdené\",\n  \"hashtag.column_settings.select.placeholder\": \"Zadaj haštagy…\",\n  \"hashtag.column_settings.tag_mode.all\": \"Všetky tieto\",\n  \"hashtag.column_settings.tag_mode.any\": \"Hociktorý z týchto\",\n  \"hashtag.column_settings.tag_mode.none\": \"Žiaden z týchto\",\n  \"hashtag.column_settings.tag_toggle\": \"Vlož dodatočné haštagy pre tento stĺpec\",\n  \"home.column_settings.basic\": \"Základné\",\n  \"home.column_settings.show_reblogs\": \"Zobraziť povýšené\",\n  \"home.column_settings.show_replies\": \"Ukázať odpovede\",\n  \"intervals.full.days\": \"{number, plural, one {# deň} few {# dní} many {# dní} other {# dni}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# hodina} few {# hodín} many {# hodín} other {# hodiny}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minúta} few {# minút} many {# minút} other {# minúty}}\",\n  \"introduction.federation.action\": \"Ďalej\",\n  \"introduction.federation.federated.headline\": \"Federovaná\",\n  \"introduction.federation.federated.text\": \"Verejné príspevky z ostatných serverov vo fediverse budú zobrazené vo federovanej časovej osi.\",\n  \"introduction.federation.home.headline\": \"Domovská\",\n  \"introduction.federation.home.text\": \"Príspevky od ľudí ktorých následuješ sa zobrazia na tvojej domovskej nástenke. Môžeš následovať hocikoho na ktoromkoľvek serveri!\",\n  \"introduction.federation.local.headline\": \"Miestna\",\n  \"introduction.federation.local.text\": \"Verejné príspevky od ľudí v rámci toho istého serveru na akom si aj ty, budú zobrazované na miestnej časovej osi.\",\n  \"introduction.interactions.action\": \"Ukonči návod!\",\n  \"introduction.interactions.favourite.headline\": \"Obľúbené\",\n  \"introduction.interactions.favourite.text\": \"Obľúbením si môžeš príspevok uložiť na neskôr, a zároveň dať jeho autorovi vedieť, že sa ti páčil.\",\n  \"introduction.interactions.reblog.headline\": \"Vyzdvihni\",\n  \"introduction.interactions.reblog.text\": \"Môžeš zdieľať príspevky iných ľudí s vašimi následovateľmi tým, že ich povýšiš.\",\n  \"introduction.interactions.reply.headline\": \"Odpovedz\",\n  \"introduction.interactions.reply.text\": \"Odpovedať môžeš na príspevky iných ľudí, aj na svoje vlastné, čím sa spolu prepoja do konverzácie.\",\n  \"introduction.welcome.action\": \"Poďme do toho!\",\n  \"introduction.welcome.headline\": \"Prvé kroky\",\n  \"introduction.welcome.text\": \"Vitaj vo fediverse! Za malú chvíľu budeš môcť posielať správy a rozpovedať sa so svojími priateľmi cez širokú škálu rôznorodých serverov. Ale tento server, {domain}, je špeciálny v tom, že ukladá tvoj profil, takže si jeho názov zapametaj.\",\n  \"keyboard_shortcuts.back\": \"dostať sa naspäť\",\n  \"keyboard_shortcuts.blocked\": \"otvor zoznam blokovaných užívateľov\",\n  \"keyboard_shortcuts.boost\": \"vyzdvihnúť\",\n  \"keyboard_shortcuts.column\": \"zameraj sa na príspevok v jednom zo stĺpcov\",\n  \"keyboard_shortcuts.compose\": \"zameraj sa na písaciu plochu\",\n  \"keyboard_shortcuts.description\": \"Popis\",\n  \"keyboard_shortcuts.direct\": \"otvor panel súkromných správ\",\n  \"keyboard_shortcuts.down\": \"posunúť sa dole v zozname\",\n  \"keyboard_shortcuts.enter\": \"otvoriť správu\",\n  \"keyboard_shortcuts.favourite\": \"pridaj do obľúbených\",\n  \"keyboard_shortcuts.favourites\": \"otvor zoznam obľúbených\",\n  \"keyboard_shortcuts.federated\": \"otvor federovanú časovú os\",\n  \"keyboard_shortcuts.heading\": \"Klávesové skratky\",\n  \"keyboard_shortcuts.home\": \"otvor domácu časovú os\",\n  \"keyboard_shortcuts.hotkey\": \"Klávesa\",\n  \"keyboard_shortcuts.legend\": \"zobraz túto legendu\",\n  \"keyboard_shortcuts.local\": \"otvor miestnu časovú os\",\n  \"keyboard_shortcuts.mention\": \"spomeň autora\",\n  \"keyboard_shortcuts.muted\": \"otvor zoznam stíšených užívateľov\",\n  \"keyboard_shortcuts.my_profile\": \"otvor svoj profil\",\n  \"keyboard_shortcuts.notifications\": \"otvor panel oboznámení\",\n  \"keyboard_shortcuts.pinned\": \"otvor zoznam pripnutých príspevkov\",\n  \"keyboard_shortcuts.profile\": \"otvor autorov profil\",\n  \"keyboard_shortcuts.reply\": \"odpovedať\",\n  \"keyboard_shortcuts.requests\": \"otvor zoznam žiadostí o sledovanie\",\n  \"keyboard_shortcuts.search\": \"zameraj sa na vyhľadávanie\",\n  \"keyboard_shortcuts.start\": \"otvor panel ''začíname''\",\n  \"keyboard_shortcuts.toggle_hidden\": \"ukáž/skry text za CW\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"to show/hide media\",\n  \"keyboard_shortcuts.toot\": \"začni úplne nový príspevok\",\n  \"keyboard_shortcuts.unfocus\": \"nesústreď sa na písaciu plochu, alebo hľadanie\",\n  \"keyboard_shortcuts.up\": \"posuň sa vyššie v zozname\",\n  \"lightbox.close\": \"Zatvor\",\n  \"lightbox.next\": \"Ďalšie\",\n  \"lightbox.previous\": \"Predchádzajúci\",\n  \"lightbox.view_context\": \"View context\",\n  \"lists.account.add\": \"Pridaj do zoznamu\",\n  \"lists.account.remove\": \"Odober zo zoznamu\",\n  \"lists.delete\": \"Vymaž list\",\n  \"lists.edit\": \"Uprav zoznam\",\n  \"lists.edit.submit\": \"Zmeň názov\",\n  \"lists.new.create\": \"Pridaj zoznam\",\n  \"lists.new.title_placeholder\": \"Názov nového zoznamu\",\n  \"lists.search\": \"Vyhľadávaj medzi užívateľmi, ktorých sleduješ\",\n  \"lists.subheading\": \"Tvoje zoznamy\",\n  \"loading_indicator.label\": \"Načítam...\",\n  \"media_gallery.toggle_visible\": \"Zapni/Vypni viditeľnosť\",\n  \"missing_indicator.label\": \"Nenájdené\",\n  \"missing_indicator.sublabel\": \"Tento zdroj sa ešte nepodarilo nájsť\",\n  \"mute_modal.hide_notifications\": \"Skry oznámenia od tohto používateľa?\",\n  \"navigation_bar.apps\": \"Aplikácie\",\n  \"navigation_bar.blocks\": \"Blokovaní užívatelia\",\n  \"navigation_bar.community_timeline\": \"Miestna časová os\",\n  \"navigation_bar.compose\": \"Napíš nový príspevok\",\n  \"navigation_bar.direct\": \"Súkromné správy\",\n  \"navigation_bar.discover\": \"Objavuj\",\n  \"navigation_bar.domain_blocks\": \"Skryté domény\",\n  \"navigation_bar.edit_profile\": \"Uprav profil\",\n  \"navigation_bar.favourites\": \"Obľúbené\",\n  \"navigation_bar.filters\": \"Filtrované slová\",\n  \"navigation_bar.follow_requests\": \"Žiadosti o sledovanie\",\n  \"navigation_bar.follows_and_followers\": \"Follows and followers\",\n  \"navigation_bar.info\": \"O tomto serveri\",\n  \"navigation_bar.keyboard_shortcuts\": \"Klávesové skratky\",\n  \"navigation_bar.lists\": \"Zoznamy\",\n  \"navigation_bar.logout\": \"Odhlás sa\",\n  \"navigation_bar.mutes\": \"Ignorovaní užívatelia\",\n  \"navigation_bar.personal\": \"Osobné\",\n  \"navigation_bar.pins\": \"Pripnuté príspevky\",\n  \"navigation_bar.preferences\": \"Voľby\",\n  \"navigation_bar.profile_directory\": \"Profile directory\",\n  \"navigation_bar.public_timeline\": \"Federovaná časová os\",\n  \"navigation_bar.security\": \"Zabezbečenie\",\n  \"notification.favourite\": \"{name} si obľúbil/a tvoj príspevok\",\n  \"notification.follow\": \"{name} ťa začal/a následovať\",\n  \"notification.mention\": \"{name} ťa spomenul/a\",\n  \"notification.poll\": \"Anketa v ktorej si hlasoval/a sa skončila\",\n  \"notification.reblog\": \"{name} zdieľal/a tvoj príspevok\",\n  \"notifications.clear\": \"Vyčistiť zoznam oboznámení\",\n  \"notifications.clear_confirmation\": \"Naozaj chceš nenávratne prečistiť všetky tvoje oboznámenia?\",\n  \"notifications.column_settings.alert\": \"Oboznámenia na ploche\",\n  \"notifications.column_settings.favourite\": \"Obľúbené:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Zobraz všetky kategórie\",\n  \"notifications.column_settings.filter_bar.category\": \"Rýchle triedenie\",\n  \"notifications.column_settings.filter_bar.show\": \"Ukáž\",\n  \"notifications.column_settings.follow\": \"Noví sledujúci:\",\n  \"notifications.column_settings.mention\": \"Zmienenia:\",\n  \"notifications.column_settings.poll\": \"Výsledky ankiet:\",\n  \"notifications.column_settings.push\": \"Push notifikácie\",\n  \"notifications.column_settings.reblog\": \"Vyzdvihnutia:\",\n  \"notifications.column_settings.show\": \"Zobraz v stĺpci\",\n  \"notifications.column_settings.sound\": \"Prehraj zvuk\",\n  \"notifications.filter.all\": \"Všetky\",\n  \"notifications.filter.boosts\": \"Vyzdvihnutia\",\n  \"notifications.filter.favourites\": \"Obľúbené\",\n  \"notifications.filter.follows\": \"Sledovania\",\n  \"notifications.filter.mentions\": \"Iba spomenutia\",\n  \"notifications.filter.polls\": \"Výsledky ankiet\",\n  \"notifications.group\": \"{count} oboznámení\",\n  \"poll.closed\": \"Uzatvorená\",\n  \"poll.refresh\": \"Aktualizuj\",\n  \"poll.total_votes\": \"{count, plural, one {# hlas} few {# hlasov} many {# hlasov} other {# hlasy}}\",\n  \"poll.vote\": \"Hlasuj\",\n  \"poll_button.add_poll\": \"Pridaj anketu\",\n  \"poll_button.remove_poll\": \"Odstráň anketu\",\n  \"privacy.change\": \"Uprav súkromie príspevku\",\n  \"privacy.direct.long\": \"Pošli iba spomenutým užívateľom\",\n  \"privacy.direct.short\": \"Súkromne\",\n  \"privacy.private.long\": \"Pošli iba následovateľom\",\n  \"privacy.private.short\": \"Iba pre sledujúcich\",\n  \"privacy.public.long\": \"Pošli všetkým verejne\",\n  \"privacy.public.short\": \"Verejné\",\n  \"privacy.unlisted.long\": \"Neposielaj do verejných časových osí\",\n  \"privacy.unlisted.short\": \"Verejne, ale nezobraziť v osi\",\n  \"regeneration_indicator.label\": \"Načítava sa…\",\n  \"regeneration_indicator.sublabel\": \"Vaša domovská nástenka sa pripravuje!\",\n  \"relative_time.days\": \"{number}d\",\n  \"relative_time.hours\": \"{number}h\",\n  \"relative_time.just_now\": \"teraz\",\n  \"relative_time.minutes\": \"{number}m\",\n  \"relative_time.seconds\": \"{number}s\",\n  \"reply_indicator.cancel\": \"Zrušiť\",\n  \"report.forward\": \"Posuň ku {target}\",\n  \"report.forward_hint\": \"Tento účet je z iného serveru. Chceš poslať anonymnú kópiu hlásenia aj tam?\",\n  \"report.hint\": \"Toto nahlásenie bude zaslané správcom tvojho servera. Môžeš napísať odvôvodnenie, prečo nahlasuješ tento účet:\",\n  \"report.placeholder\": \"Ďalšie komentáre\",\n  \"report.submit\": \"Odošli\",\n  \"report.target\": \"Nahlás {target}\",\n  \"search.placeholder\": \"Hľadaj\",\n  \"search_popout.search_format\": \"Pokročilé vyhľadávanie\",\n  \"search_popout.tips.full_text\": \"Vráti jednoduchý textový výpis príspevkov ktoré si napísal/a, ktoré si obľúbil/a, povýšil/a, alebo aj tých, v ktorých si bol/a spomenutý/á, a potom všetky zadaniu odpovedajúce prezívky, mená a haštagy.\",\n  \"search_popout.tips.hashtag\": \"haštag\",\n  \"search_popout.tips.status\": \"status\",\n  \"search_popout.tips.text\": \"Vráti jednoduchý textový výpis zhodujúcich sa mien, prezývok a haštagov\",\n  \"search_popout.tips.user\": \"užívateľ\",\n  \"search_results.accounts\": \"Ľudia\",\n  \"search_results.hashtags\": \"Haštagy\",\n  \"search_results.statuses\": \"Príspevky\",\n  \"search_results.total\": \"{count, number} {count, plural, one {výsledok} many {výsledkov} other {výsledky}}\",\n  \"status.admin_account\": \"Otvor moderovacie rozhranie užívateľa @{name}\",\n  \"status.admin_status\": \"Otvor tento príspevok v moderovacom rozhraní\",\n  \"status.block\": \"Blokuj @{name}\",\n  \"status.cancel_reblog_private\": \"Nezdieľaj\",\n  \"status.cannot_reblog\": \"Tento príspevok nemôže byť zdieľaný\",\n  \"status.copy\": \"Skopíruj odkaz na príspevok\",\n  \"status.delete\": \"Zmazať\",\n  \"status.detailed_status\": \"Podrobný náhľad celej konverzácie\",\n  \"status.direct\": \"Súkromná správa @{name}\",\n  \"status.embed\": \"Vložiť\",\n  \"status.favourite\": \"Páči sa mi\",\n  \"status.filtered\": \"Filtrované\",\n  \"status.load_more\": \"Ukáž viac\",\n  \"status.media_hidden\": \"Skryté médiá\",\n  \"status.mention\": \"Spomeň @{name}\",\n  \"status.more\": \"Viac\",\n  \"status.mute\": \"Utíš @{name}\",\n  \"status.mute_conversation\": \"Ignoruj konverzáciu\",\n  \"status.open\": \"Otvor tento príspevok\",\n  \"status.pin\": \"Pripni na profil\",\n  \"status.pinned\": \"Pripnutý príspevok\",\n  \"status.read_more\": \"Čítaj ďalej\",\n  \"status.reblog\": \"Vyzdvihni\",\n  \"status.reblog_private\": \"Vyzdvihni k pôvodnému publiku\",\n  \"status.reblogged_by\": \"{name} povýšil/a\",\n  \"status.reblogs.empty\": \"Nikto ešte nevyzdvihol tento príspevok. Keď tak niekto urobí, bude to zobrazené práve tu.\",\n  \"status.redraft\": \"Vymaž a prepíš\",\n  \"status.reply\": \"Odpovedať\",\n  \"status.replyAll\": \"Odpovedz na diskusiu\",\n  \"status.report\": \"Nahlás @{name}\",\n  \"status.sensitive_warning\": \"Chúlostivý obsah\",\n  \"status.share\": \"Zdieľaj\",\n  \"status.show_less\": \"Zobraz menej\",\n  \"status.show_less_all\": \"Všetkým ukáž menej\",\n  \"status.show_more\": \"Ukáž viac\",\n  \"status.show_more_all\": \"Všetkým ukáž viac\",\n  \"status.show_thread\": \"Ukáž diskusné vlákno\",\n  \"status.unmute_conversation\": \"Prestaň ignorovať konverzáciu\",\n  \"status.unpin\": \"Odopni z profilu\",\n  \"suggestions.dismiss\": \"Zavrhni návrh\",\n  \"suggestions.header\": \"Mohlo by ťa zaujímať…\",\n  \"tabs_bar.federated_timeline\": \"Federovaná\",\n  \"tabs_bar.home\": \"Domovská\",\n  \"tabs_bar.local_timeline\": \"Miestna\",\n  \"tabs_bar.notifications\": \"Oboznámenia\",\n  \"tabs_bar.search\": \"Hľadaj\",\n  \"time_remaining.days\": \"Ostáva {number, plural, one {# deň} few {# dní} many {# dni} other {# dni}}\",\n  \"time_remaining.hours\": \"Ostáva {number, plural, one {# hodina} few {# hodín} many {# hodín} other {# hodiny}}\",\n  \"time_remaining.minutes\": \"Ostáva {number, plural, one {# minúta} few {# minút} many {# minút} other {# minúty}}\",\n  \"time_remaining.moments\": \"Ostáva už iba chviľka\",\n  \"time_remaining.seconds\": \"Ostáva {number, plural, one {# sekunda} few {# sekúnd} many {# sekúnd} other {# sekundy}}\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {človek vraví} other {ľudia vravia}}\",\n  \"ui.beforeunload\": \"Čo máš rozpísané sa stratí, ak opustíš Mastodon.\",\n  \"upload_area.title\": \"Pretiahni a pusť pre nahratie\",\n  \"upload_button.label\": \"Pridaj médiálny súbor (JPEG, PNG, GIF, WebM, MP4, MOV)\",\n  \"upload_error.limit\": \"Limit pre nahrávanie súborov bol prekročený.\",\n  \"upload_error.poll\": \"Nahrávanie súborov pri anketách nieje možné.\",\n  \"upload_form.description\": \"Opis pre slabo vidiacich\",\n  \"upload_form.focus\": \"Pozmeň náhľad\",\n  \"upload_form.undo\": \"Vymaž\",\n  \"upload_progress.label\": \"Nahráva sa...\",\n  \"video.close\": \"Zavri video\",\n  \"video.exit_fullscreen\": \"Vypni zobrazenie na celú obrazovku\",\n  \"video.expand\": \"Zväčši video\",\n  \"video.fullscreen\": \"Zobraz na celú obrazovku\",\n  \"video.hide\": \"Skry video\",\n  \"video.mute\": \"Vypni zvuk\",\n  \"video.pause\": \"Pauza\",\n  \"video.play\": \"Prehraj\",\n  \"video.unmute\": \"Zapni zvuk\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/sl.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Dodaj ali odstrani iz seznama\",\n  \"account.badges.bot\": \"Robot\",\n  \"account.block\": \"Blokiraj @{name}\",\n  \"account.block_domain\": \"Skrij vse iz {domain}\",\n  \"account.blocked\": \"Blokirano\",\n  \"account.direct\": \"Neposredno sporočilo @{name}\",\n  \"account.domain_blocked\": \"Skrita domena\",\n  \"account.edit_profile\": \"Uredi profil\",\n  \"account.endorse\": \"Zmožnost profila\",\n  \"account.follow\": \"Sledi\",\n  \"account.followers\": \"Sledilci\",\n  \"account.followers.empty\": \"Nihče ne sledi temu uporabniku.\",\n  \"account.follows\": \"Sledi\",\n  \"account.follows.empty\": \"Ta uporabnik še ne sledi nikomur.\",\n  \"account.follows_you\": \"Ti sledi\",\n  \"account.hide_reblogs\": \"Skrij sunke od @{name}\",\n  \"account.link_verified_on\": \"Lastništvo te povezave je bilo preverjeno {date}\",\n  \"account.locked_info\": \"This account privacy status is set to locked. The owner manually reviews who can follow them.\",\n  \"account.media\": \"Mediji\",\n  \"account.mention\": \"Omeni @{name}\",\n  \"account.moved_to\": \"{name} se je premaknil na:\",\n  \"account.mute\": \"Utišaj @{name}\",\n  \"account.mute_notifications\": \"Utišaj obvestila od @{name}\",\n  \"account.muted\": \"Utišan\",\n  \"account.posts\": \"Tuti\",\n  \"account.posts_with_replies\": \"Tuti in odgovori\",\n  \"account.report\": \"Prijavi @{name}\",\n  \"account.requested\": \"Čakanje na odobritev. Kliknite, da prekličete prošnjo za sledenje\",\n  \"account.share\": \"Delite profil osebe @{name}\",\n  \"account.show_reblogs\": \"Pokaži delitve osebe @{name}\",\n  \"account.unblock\": \"Odblokiraj @{name}\",\n  \"account.unblock_domain\": \"Razkrij {domain}\",\n  \"account.unendorse\": \"Don't feature on profile\",\n  \"account.unfollow\": \"Prenehaj slediti\",\n  \"account.unmute\": \"Odtišaj @{name}\",\n  \"account.unmute_notifications\": \"Vklopi obvestila od @{name}\",\n  \"alert.unexpected.message\": \"Zgodila se je nepričakovana napaka.\",\n  \"alert.unexpected.title\": \"Uups!\",\n  \"boost_modal.combo\": \"Če želite naslednjič preskočiti to, lahko pritisnete {combo}\",\n  \"bundle_column_error.body\": \"Med nalaganjem te komponente je prišlo do napake.\",\n  \"bundle_column_error.retry\": \"Poskusi ponovno\",\n  \"bundle_column_error.title\": \"Napaka omrežja\",\n  \"bundle_modal_error.close\": \"Zapri\",\n  \"bundle_modal_error.message\": \"Med nalaganjem te komponente je prišlo do napake.\",\n  \"bundle_modal_error.retry\": \"Poskusi ponovno\",\n  \"column.blocks\": \"Blokirani uporabniki\",\n  \"column.community\": \"Lokalna časovnica\",\n  \"column.direct\": \"Neposredna sporočila\",\n  \"column.domain_blocks\": \"Skrite domene\",\n  \"column.favourites\": \"Priljubljene\",\n  \"column.follow_requests\": \"Sledi prošnjam\",\n  \"column.home\": \"Domov\",\n  \"column.lists\": \"Seznami\",\n  \"column.mutes\": \"Utišani uporabniki\",\n  \"column.notifications\": \"Obvestila\",\n  \"column.pins\": \"Pripeti tuti\",\n  \"column.public\": \"Združena časovnica\",\n  \"column_back_button.label\": \"Nazaj\",\n  \"column_header.hide_settings\": \"Skrij nastavitve\",\n  \"column_header.moveLeft_settings\": \"Premakni stolpec na levo\",\n  \"column_header.moveRight_settings\": \"Premakni stolpec na desno\",\n  \"column_header.pin\": \"Pripni\",\n  \"column_header.show_settings\": \"Prikaži nastavitve\",\n  \"column_header.unpin\": \"Odpni\",\n  \"column_subheading.settings\": \"Nastavitve\",\n  \"community.column_settings.media_only\": \"Samo mediji\",\n  \"compose_form.direct_message_warning\": \"Ta tut bo viden le vsem omenjenim uporabnikom.\",\n  \"compose_form.direct_message_warning_learn_more\": \"Nauči se več\",\n  \"compose_form.hashtag_warning\": \"Ta tut ne bo naveden pod nobenim hashtagom, ker ni dodan hashtag. Samo javne tute lahko iščete pod hashtagom.\",\n  \"compose_form.lock_disclaimer\": \"Vaš račun ni {locked}. Vsakdo vam lahko sledi in si ogleda objave, ki so namenjene samo sledilcem.\",\n  \"compose_form.lock_disclaimer.lock\": \"zaklenjen\",\n  \"compose_form.placeholder\": \"O čem razmišljaš?\",\n  \"compose_form.poll.add_option\": \"Add a choice\",\n  \"compose_form.poll.duration\": \"Poll duration\",\n  \"compose_form.poll.option_placeholder\": \"Choice {number}\",\n  \"compose_form.poll.remove_option\": \"Remove this choice\",\n  \"compose_form.publish\": \"Tutni\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"Mark media as sensitive\",\n  \"compose_form.sensitive.marked\": \"Medij je označen kot občutljiv\",\n  \"compose_form.sensitive.unmarked\": \"Medij ni označen kot občutljiv\",\n  \"compose_form.spoiler.marked\": \"Besedilo je skrito za opozorilom\",\n  \"compose_form.spoiler.unmarked\": \"Besedilo ni skrito\",\n  \"compose_form.spoiler_placeholder\": \"Napišite opozorilo tukaj\",\n  \"confirmation_modal.cancel\": \"Prekliči\",\n  \"confirmations.block.block_and_report\": \"Block & Report\",\n  \"confirmations.block.confirm\": \"Block\",\n  \"confirmations.block.message\": \"Ali ste prepričani, da želite blokirati {name}?\",\n  \"confirmations.delete.confirm\": \"Delete\",\n  \"confirmations.delete.message\": \"Ali ste prepričani, da želite izbrisati to stanje?\",\n  \"confirmations.delete_list.confirm\": \"Delete\",\n  \"confirmations.delete_list.message\": \"Ali ste prepričani, da želite trajno izbrisati ta seznam?\",\n  \"confirmations.domain_block.confirm\": \"Skrij celotno domeno\",\n  \"confirmations.domain_block.message\": \"Ali ste res, res prepričani, da želite blokirati celotno {domain}? V večini primerov je nekaj ciljnih blokiranj ali utišanj dovolj in boljše.\",\n  \"confirmations.mute.confirm\": \"Utišanje\",\n  \"confirmations.mute.message\": \"Ali ste prepričani, da želite utišati {name}?\",\n  \"confirmations.redraft.confirm\": \"Izbriši in preoblikuj\",\n  \"confirmations.redraft.message\": \"Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.\",\n  \"confirmations.reply.confirm\": \"Reply\",\n  \"confirmations.reply.message\": \"Odgovarjanje bo prepisalo sporočilo, ki ga trenutno sestavljate. Ali ste prepričani, da želite nadaljevati?\",\n  \"confirmations.unfollow.confirm\": \"Prenehaj slediti\",\n  \"confirmations.unfollow.message\": \"Ali ste prepričani, da ne želite več slediti {name}?\",\n  \"embed.instructions\": \"Vstavi ta status na svojo spletno stran tako, da kopirate spodnjo kodo.\",\n  \"embed.preview\": \"Tukaj je, kako bo izgledalo:\",\n  \"emoji_button.activity\": \"Dejavnost\",\n  \"emoji_button.custom\": \"Po meri\",\n  \"emoji_button.flags\": \"Zastave\",\n  \"emoji_button.food\": \"Hrana in Pijača\",\n  \"emoji_button.label\": \"Vstavi emojija\",\n  \"emoji_button.nature\": \"Narava\",\n  \"emoji_button.not_found\": \"Ni emojijev!! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"Predmeti\",\n  \"emoji_button.people\": \"Ljudje\",\n  \"emoji_button.recent\": \"Pogosto uporabljeni\",\n  \"emoji_button.search\": \"Poišči...\",\n  \"emoji_button.search_results\": \"Rezultati iskanja\",\n  \"emoji_button.symbols\": \"Simboli\",\n  \"emoji_button.travel\": \"Potovanja in Kraji\",\n  \"empty_column.account_timeline\": \"No toots here!\",\n  \"empty_column.account_unavailable\": \"Profile unavailable\",\n  \"empty_column.blocks\": \"Niste še blokirali nobenega uporabnika.\",\n  \"empty_column.community\": \"Lokalna časovnica je prazna. Napišite nekaj javnega, da se bo žoga zakotalila!\",\n  \"empty_column.direct\": \"Nimate še nobenih neposrednih sporočil. Ko ga pošljete ali prejmete, se prikaže tukaj.\",\n  \"empty_column.domain_blocks\": \"Še vedno ni skritih domen.\",\n  \"empty_column.favourited_statuses\": \"You don't have any favourite toots yet. When you favourite one, it will show up here.\",\n  \"empty_column.favourites\": \"No one has favourited this toot yet. When someone does, they will show up here.\",\n  \"empty_column.follow_requests\": \"You don't have any follow requests yet. When you receive one, it will show up here.\",\n  \"empty_column.hashtag\": \"V tem hashtagu še ni nič.\",\n  \"empty_column.home\": \"Vaša domača časovnica je prazna! Obiščite {public} ali uporabite iskanje, da se boste srečali druge uporabnike.\",\n  \"empty_column.home.public_timeline\": \"javna časovnica\",\n  \"empty_column.list\": \"Na tem seznamu ni ničesar. Ko bodo člani tega seznama objavili nove statuse, se bodo pojavili tukaj.\",\n  \"empty_column.lists\": \"You don't have any lists yet. When you create one, it will show up here.\",\n  \"empty_column.mutes\": \"You haven't muted any users yet.\",\n  \"empty_column.notifications\": \"Nimate še nobenih obvestil. Poveži se z drugimi, da začnete pogovor.\",\n  \"empty_column.public\": \"Tukaj ni ničesar! Da ga napolnite, napišite nekaj javnega ali pa ročno sledite uporabnikom iz drugih vozlišč\",\n  \"follow_request.authorize\": \"Odobri\",\n  \"follow_request.reject\": \"Zavrni\",\n  \"getting_started.developers\": \"Developers\",\n  \"getting_started.directory\": \"Profile directory\",\n  \"getting_started.documentation\": \"Documentation\",\n  \"getting_started.heading\": \"Prvi koraki\",\n  \"getting_started.invite\": \"Invite people\",\n  \"getting_started.open_source_notice\": \"Mastodon je odprtokodna programska oprema. V GitHubu na {github} lahko prispevate ali poročate o napakah.\",\n  \"getting_started.security\": \"Security\",\n  \"getting_started.terms\": \"Terms of service\",\n  \"hashtag.column_header.tag_mode.all\": \"and {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"or {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"without {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"No suggestions found\",\n  \"hashtag.column_settings.select.placeholder\": \"Enter hashtags…\",\n  \"hashtag.column_settings.tag_mode.all\": \"All of these\",\n  \"hashtag.column_settings.tag_mode.any\": \"Any of these\",\n  \"hashtag.column_settings.tag_mode.none\": \"None of these\",\n  \"hashtag.column_settings.tag_toggle\": \"Include additional tags in this column\",\n  \"home.column_settings.basic\": \"Osnovno\",\n  \"home.column_settings.show_reblogs\": \"Pokaži sunke\",\n  \"home.column_settings.show_replies\": \"Pokaži odgovore\",\n  \"intervals.full.days\": \"{number, plural, one {# day} other {# days}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# hour} other {# hours}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minute} other {# minutes}}\",\n  \"introduction.federation.action\": \"Next\",\n  \"introduction.federation.federated.headline\": \"Federated\",\n  \"introduction.federation.federated.text\": \"Public posts from other servers of the fediverse will appear in the federated timeline.\",\n  \"introduction.federation.home.headline\": \"Home\",\n  \"introduction.federation.home.text\": \"Posts from people you follow will appear in your home feed. You can follow anyone on any server!\",\n  \"introduction.federation.local.headline\": \"Local\",\n  \"introduction.federation.local.text\": \"Public posts from people on the same server as you will appear in the local timeline.\",\n  \"introduction.interactions.action\": \"Finish toot-orial!\",\n  \"introduction.interactions.favourite.headline\": \"Favourite\",\n  \"introduction.interactions.favourite.text\": \"You can save a toot for later, and let the author know that you liked it, by favouriting it.\",\n  \"introduction.interactions.reblog.headline\": \"Boost\",\n  \"introduction.interactions.reblog.text\": \"You can share other people's toots with your followers by boosting them.\",\n  \"introduction.interactions.reply.headline\": \"Reply\",\n  \"introduction.interactions.reply.text\": \"You can reply to other people's and your own toots, which will chain them together in a conversation.\",\n  \"introduction.welcome.action\": \"Let's go!\",\n  \"introduction.welcome.headline\": \"First steps\",\n  \"introduction.welcome.text\": \"Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.\",\n  \"keyboard_shortcuts.back\": \"za krmarjenje nazaj\",\n  \"keyboard_shortcuts.blocked\": \"to open blocked users list\",\n  \"keyboard_shortcuts.boost\": \"suniti\",\n  \"keyboard_shortcuts.column\": \"osredotočiti status v enega od stolpcev\",\n  \"keyboard_shortcuts.compose\": \"osredotočiti na sestavljanje besedila\",\n  \"keyboard_shortcuts.description\": \"Opis\",\n  \"keyboard_shortcuts.direct\": \"to open direct messages column\",\n  \"keyboard_shortcuts.down\": \"premakniti navzdol po seznamu\",\n  \"keyboard_shortcuts.enter\": \"odpreti status\",\n  \"keyboard_shortcuts.favourite\": \"to favourite\",\n  \"keyboard_shortcuts.favourites\": \"to open favourites list\",\n  \"keyboard_shortcuts.federated\": \"to open federated timeline\",\n  \"keyboard_shortcuts.heading\": \"Tipkovne bližnjice\",\n  \"keyboard_shortcuts.home\": \"to open home timeline\",\n  \"keyboard_shortcuts.hotkey\": \"Hitra tipka\",\n  \"keyboard_shortcuts.legend\": \"to display this legend\",\n  \"keyboard_shortcuts.local\": \"to open local timeline\",\n  \"keyboard_shortcuts.mention\": \"to mention author\",\n  \"keyboard_shortcuts.muted\": \"to open muted users list\",\n  \"keyboard_shortcuts.my_profile\": \"to open your profile\",\n  \"keyboard_shortcuts.notifications\": \"to open notifications column\",\n  \"keyboard_shortcuts.pinned\": \"to open pinned toots list\",\n  \"keyboard_shortcuts.profile\": \"to open author's profile\",\n  \"keyboard_shortcuts.reply\": \"to reply\",\n  \"keyboard_shortcuts.requests\": \"to open follow requests list\",\n  \"keyboard_shortcuts.search\": \"to focus search\",\n  \"keyboard_shortcuts.start\": \"to open \\\"get started\\\" column\",\n  \"keyboard_shortcuts.toggle_hidden\": \"to show/hide text behind CW\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"to show/hide media\",\n  \"keyboard_shortcuts.toot\": \"da začnete povsem nov tut\",\n  \"keyboard_shortcuts.unfocus\": \"to un-focus compose textarea/search\",\n  \"keyboard_shortcuts.up\": \"to move up in the list\",\n  \"lightbox.close\": \"Close\",\n  \"lightbox.next\": \"Next\",\n  \"lightbox.previous\": \"Previous\",\n  \"lightbox.view_context\": \"View context\",\n  \"lists.account.add\": \"Add to list\",\n  \"lists.account.remove\": \"Remove from list\",\n  \"lists.delete\": \"Delete list\",\n  \"lists.edit\": \"Edit list\",\n  \"lists.edit.submit\": \"Change title\",\n  \"lists.new.create\": \"Add list\",\n  \"lists.new.title_placeholder\": \"New list title\",\n  \"lists.search\": \"Search among people you follow\",\n  \"lists.subheading\": \"Your lists\",\n  \"loading_indicator.label\": \"Loading...\",\n  \"media_gallery.toggle_visible\": \"Toggle visibility\",\n  \"missing_indicator.label\": \"Not found\",\n  \"missing_indicator.sublabel\": \"This resource could not be found\",\n  \"mute_modal.hide_notifications\": \"Hide notifications from this user?\",\n  \"navigation_bar.apps\": \"Mobile apps\",\n  \"navigation_bar.blocks\": \"Blocked users\",\n  \"navigation_bar.community_timeline\": \"Local timeline\",\n  \"navigation_bar.compose\": \"Compose new toot\",\n  \"navigation_bar.direct\": \"Direct messages\",\n  \"navigation_bar.discover\": \"Discover\",\n  \"navigation_bar.domain_blocks\": \"Hidden domains\",\n  \"navigation_bar.edit_profile\": \"Edit profile\",\n  \"navigation_bar.favourites\": \"Favourites\",\n  \"navigation_bar.filters\": \"Muted words\",\n  \"navigation_bar.follow_requests\": \"Follow requests\",\n  \"navigation_bar.follows_and_followers\": \"Follows and followers\",\n  \"navigation_bar.info\": \"O tem vozlišču\",\n  \"navigation_bar.keyboard_shortcuts\": \"Keyboard shortcuts\",\n  \"navigation_bar.lists\": \"Lists\",\n  \"navigation_bar.logout\": \"Logout\",\n  \"navigation_bar.mutes\": \"Muted users\",\n  \"navigation_bar.personal\": \"Personal\",\n  \"navigation_bar.pins\": \"Pripeti tuti\",\n  \"navigation_bar.preferences\": \"Preferences\",\n  \"navigation_bar.profile_directory\": \"Profile directory\",\n  \"navigation_bar.public_timeline\": \"Federated timeline\",\n  \"navigation_bar.security\": \"Security\",\n  \"notification.favourite\": \"{name} favourited your status\",\n  \"notification.follow\": \"{name} followed you\",\n  \"notification.mention\": \"{name} mentioned you\",\n  \"notification.poll\": \"A poll you have voted in has ended\",\n  \"notification.reblog\": \"{name} boosted your status\",\n  \"notifications.clear\": \"Clear notifications\",\n  \"notifications.clear_confirmation\": \"Are you sure you want to permanently clear all your notifications?\",\n  \"notifications.column_settings.alert\": \"Desktop notifications\",\n  \"notifications.column_settings.favourite\": \"Favourites:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Display all categories\",\n  \"notifications.column_settings.filter_bar.category\": \"Quick filter bar\",\n  \"notifications.column_settings.filter_bar.show\": \"Show\",\n  \"notifications.column_settings.follow\": \"New followers:\",\n  \"notifications.column_settings.mention\": \"Mentions:\",\n  \"notifications.column_settings.poll\": \"Poll results:\",\n  \"notifications.column_settings.push\": \"Push notifications\",\n  \"notifications.column_settings.reblog\": \"Boosts:\",\n  \"notifications.column_settings.show\": \"Show in column\",\n  \"notifications.column_settings.sound\": \"Play sound\",\n  \"notifications.filter.all\": \"All\",\n  \"notifications.filter.boosts\": \"Boosts\",\n  \"notifications.filter.favourites\": \"Favourites\",\n  \"notifications.filter.follows\": \"Follows\",\n  \"notifications.filter.mentions\": \"Mentions\",\n  \"notifications.filter.polls\": \"Poll results\",\n  \"notifications.group\": \"{count} notifications\",\n  \"poll.closed\": \"Closed\",\n  \"poll.refresh\": \"Refresh\",\n  \"poll.total_votes\": \"{count, plural, one {# vote} other {# votes}}\",\n  \"poll.vote\": \"Vote\",\n  \"poll_button.add_poll\": \"Add a poll\",\n  \"poll_button.remove_poll\": \"Remove poll\",\n  \"privacy.change\": \"Adjust status privacy\",\n  \"privacy.direct.long\": \"Post to mentioned users only\",\n  \"privacy.direct.short\": \"Direct\",\n  \"privacy.private.long\": \"Post to followers only\",\n  \"privacy.private.short\": \"Followers-only\",\n  \"privacy.public.long\": \"Post to public timelines\",\n  \"privacy.public.short\": \"Public\",\n  \"privacy.unlisted.long\": \"Do not show in public timelines\",\n  \"privacy.unlisted.short\": \"Unlisted\",\n  \"regeneration_indicator.label\": \"Loading…\",\n  \"regeneration_indicator.sublabel\": \"Your home feed is being prepared!\",\n  \"relative_time.days\": \"{number}d\",\n  \"relative_time.hours\": \"{number}h\",\n  \"relative_time.just_now\": \"now\",\n  \"relative_time.minutes\": \"{number}m\",\n  \"relative_time.seconds\": \"{number}s\",\n  \"reply_indicator.cancel\": \"Cancel\",\n  \"report.forward\": \"Forward to {target}\",\n  \"report.forward_hint\": \"The account is from another server. Send an anonymized copy of the report there as well?\",\n  \"report.hint\": \"The report will be sent to your instance moderators. You can provide an explanation of why you are reporting this account below:\",\n  \"report.placeholder\": \"Additional comments\",\n  \"report.submit\": \"Submit\",\n  \"report.target\": \"Report {target}\",\n  \"search.placeholder\": \"Search\",\n  \"search_popout.search_format\": \"Advanced search format\",\n  \"search_popout.tips.full_text\": \"Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.\",\n  \"search_popout.tips.hashtag\": \"hashtag\",\n  \"search_popout.tips.status\": \"status\",\n  \"search_popout.tips.text\": \"Simple text returns matching display names, usernames and hashtags\",\n  \"search_popout.tips.user\": \"user\",\n  \"search_results.accounts\": \"People\",\n  \"search_results.hashtags\": \"Hashtags\",\n  \"search_results.statuses\": \"Tuti\",\n  \"search_results.total\": \"{count, number} {count, plural, one {result} other {results}}\",\n  \"status.admin_account\": \"Open moderation interface for @{name}\",\n  \"status.admin_status\": \"Open this status in the moderation interface\",\n  \"status.block\": \"Block @{name}\",\n  \"status.cancel_reblog_private\": \"Unboost\",\n  \"status.cannot_reblog\": \"This post cannot be boosted\",\n  \"status.copy\": \"Copy link to status\",\n  \"status.delete\": \"Delete\",\n  \"status.detailed_status\": \"Detailed conversation view\",\n  \"status.direct\": \"Direct message @{name}\",\n  \"status.embed\": \"Embed\",\n  \"status.favourite\": \"Favourite\",\n  \"status.filtered\": \"Filtered\",\n  \"status.load_more\": \"Load more\",\n  \"status.media_hidden\": \"Media hidden\",\n  \"status.mention\": \"Mention @{name}\",\n  \"status.more\": \"More\",\n  \"status.mute\": \"Mute @{name}\",\n  \"status.mute_conversation\": \"Mute conversation\",\n  \"status.open\": \"Expand this status\",\n  \"status.pin\": \"Pin on profile\",\n  \"status.pinned\": \"Pripeti tut\",\n  \"status.read_more\": \"Read more\",\n  \"status.reblog\": \"Suni\",\n  \"status.reblog_private\": \"Suni v prvotno občinstvo\",\n  \"status.reblogged_by\": \"{name} sunjen\",\n  \"status.reblogs.empty\": \"No one has boosted this toot yet. When someone does, they will show up here.\",\n  \"status.redraft\": \"Delete & re-draft\",\n  \"status.reply\": \"Odgovori\",\n  \"status.replyAll\": \"Odgovori na objavo\",\n  \"status.report\": \"Prijavi @{name}\",\n  \"status.sensitive_warning\": \"Občutljiva vsebina\",\n  \"status.share\": \"Deli\",\n  \"status.show_less\": \"Prikaži manj\",\n  \"status.show_less_all\": \"Prikaži manj za vse\",\n  \"status.show_more\": \"Prikaži več\",\n  \"status.show_more_all\": \"Prikaži več za vse\",\n  \"status.show_thread\": \"Show thread\",\n  \"status.unmute_conversation\": \"Odtišaj pogovor\",\n  \"status.unpin\": \"Odpni iz profila\",\n  \"suggestions.dismiss\": \"Dismiss suggestion\",\n  \"suggestions.header\": \"You might be interested in…\",\n  \"tabs_bar.federated_timeline\": \"Združeno\",\n  \"tabs_bar.home\": \"Domov\",\n  \"tabs_bar.local_timeline\": \"Lokalno\",\n  \"tabs_bar.notifications\": \"Obvestila\",\n  \"tabs_bar.search\": \"Poišči\",\n  \"time_remaining.days\": \"{number, plural, one {# day} other {# days}} left\",\n  \"time_remaining.hours\": \"{number, plural, one {# hour} other {# hours}} left\",\n  \"time_remaining.minutes\": \"{number, plural, one {# minute} other {# minutes}} left\",\n  \"time_remaining.moments\": \"Moments remaining\",\n  \"time_remaining.seconds\": \"{number, plural, one {# second} other {# seconds}} left\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {person} other {people}} talking\",\n  \"ui.beforeunload\": \"Vaš osnutek bo izgubljen, če zapustite Mastodona.\",\n  \"upload_area.title\": \"Povlecite in spustite za pošiljanje\",\n  \"upload_button.label\": \"Dodaj medij\",\n  \"upload_error.limit\": \"File upload limit exceeded.\",\n  \"upload_error.poll\": \"File upload not allowed with polls.\",\n  \"upload_form.description\": \"Opišite za slabovidne\",\n  \"upload_form.focus\": \"Obreži\",\n  \"upload_form.undo\": \"Izbriši\",\n  \"upload_progress.label\": \"Pošiljanje...\",\n  \"video.close\": \"Zapri video\",\n  \"video.exit_fullscreen\": \"Izhod iz celozaslonskega načina\",\n  \"video.expand\": \"Razširi video\",\n  \"video.fullscreen\": \"Celozaslonski način\",\n  \"video.hide\": \"Skrij video\",\n  \"video.mute\": \"Utišaj zvok\",\n  \"video.pause\": \"Premor\",\n  \"video.play\": \"Predvajaj\",\n  \"video.unmute\": \"Vklopi zvok\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/sq.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Shtoni ose Hiqni prej listash\",\n  \"account.badges.bot\": \"Robot\",\n  \"account.block\": \"Blloko @{name}\",\n  \"account.block_domain\": \"Fshih gjithçka prej {domain}\",\n  \"account.blocked\": \"E bllokuar\",\n  \"account.direct\": \"Mesazh i drejtpërdrejt për @{name}\",\n  \"account.domain_blocked\": \"Përkatësi e fshehur\",\n  \"account.edit_profile\": \"Përpunoni profilin\",\n  \"account.endorse\": \"Pasqyrojeni në profil\",\n  \"account.follow\": \"Ndiqeni\",\n  \"account.followers\": \"Ndjekës\",\n  \"account.followers.empty\": \"Këtë përdorues ende s’e ndjek njeri.\",\n  \"account.follows\": \"Ndjekje\",\n  \"account.follows.empty\": \"Ky përdorues ende s’ndjek njeri.\",\n  \"account.follows_you\": \"Ju ndjek\",\n  \"account.hide_reblogs\": \"Fshih përforcime nga @{name}\",\n  \"account.link_verified_on\": \"Pronësia e kësaj lidhjeje qe kontrolluar më {date}\",\n  \"account.locked_info\": \"Gjendja e privatësisë së kësaj llogarie është caktuar si e kyçur. I zoti merr dorazi në shqyrtim cilët mund ta ndjekin.\",\n  \"account.media\": \"Media\",\n  \"account.mention\": \"Përmendni @{name}\",\n  \"account.moved_to\": \"{name} ka kaluar te:\",\n  \"account.mute\": \"Heshtoni @{name}\",\n  \"account.mute_notifications\": \"Heshtoji njoftimet prej @{name}\",\n  \"account.muted\": \"Heshtuar\",\n  \"account.posts\": \"Mesazhe\",\n  \"account.posts_with_replies\": \"Mesazhe dhe përgjigje\",\n  \"account.report\": \"Raportojeni @{name}\",\n  \"account.requested\": \"Në pritje të miratimit. Klikoni që të anulohet kërkesa për ndjekje\",\n  \"account.share\": \"Ndajeni profilin e @{name} me të tjerët\",\n  \"account.show_reblogs\": \"Shfaq përforcime nga @{name}\",\n  \"account.unblock\": \"Zhbllokoje @{name}\",\n  \"account.unblock_domain\": \"Shfshihe {domain}\",\n  \"account.unendorse\": \"Mos e përfshi në profil\",\n  \"account.unfollow\": \"Resht së ndjekuri\",\n  \"account.unmute\": \"Ktheji zërin @{name}\",\n  \"account.unmute_notifications\": \"Hiqua ndalimin e shfaqjes njoftimeve nga @{name}\",\n  \"alert.unexpected.message\": \"Ndodhi një gabim të papritur.\",\n  \"alert.unexpected.title\": \"Hëm!\",\n  \"boost_modal.combo\": \"Mund të shtypni {combo}, që të anashkalohet kjo herës tjetër\",\n  \"bundle_column_error.body\": \"Diç shkoi ters teksa ngarkohej ky përbërës.\",\n  \"bundle_column_error.retry\": \"Riprovoni\",\n  \"bundle_column_error.title\": \"Gabim rrjeti\",\n  \"bundle_modal_error.close\": \"Mbylle\",\n  \"bundle_modal_error.message\": \"Diç shkoi ters teksa ngarkohej ky përbërës.\",\n  \"bundle_modal_error.retry\": \"Riprovoni\",\n  \"column.blocks\": \"Përdorues të bllokuar\",\n  \"column.community\": \"Rrjedhë kohore vendore\",\n  \"column.direct\": \"Mesazhe të drejtpërdrejta\",\n  \"column.domain_blocks\": \"Përkatësi të fshehura\",\n  \"column.favourites\": \"Të parapëlqyer\",\n  \"column.follow_requests\": \"Kërkesa për ndjekje\",\n  \"column.home\": \"Kreu\",\n  \"column.lists\": \"Lista\",\n  \"column.mutes\": \"Përdorues të heshtuar\",\n  \"column.notifications\": \"Njoftime\",\n  \"column.pins\": \"Mesazhe të fiksuar\",\n  \"column.public\": \"Rrjedhë kohore e federuar\",\n  \"column_back_button.label\": \"Mbrapsht\",\n  \"column_header.hide_settings\": \"Fshihi rregullimet\",\n  \"column_header.moveLeft_settings\": \"Shpjere shtyllën majtas\",\n  \"column_header.moveRight_settings\": \"Shpjere shtyllën djathtas\",\n  \"column_header.pin\": \"Fiksoje\",\n  \"column_header.show_settings\": \"Shfaq rregullime\",\n  \"column_header.unpin\": \"Shfiksoje\",\n  \"column_subheading.settings\": \"Rregullime\",\n  \"community.column_settings.media_only\": \"Vetëm Media\",\n  \"compose_form.direct_message_warning\": \"Ky mesazh do t’u dërgohet përdoruesve të përmendur.\",\n  \"compose_form.direct_message_warning_learn_more\": \"Mësoni më tepër\",\n  \"compose_form.hashtag_warning\": \"Ky mesazh s’do të paraqitet nën ndonjë hashtag, ngaqë s’i është caktuar ndonjë. Vetëm mesazhet publike mund të kërkohen sipas hashtagësh.\",\n  \"compose_form.lock_disclaimer\": \"Llogaria juaj s’është {locked}. Mund ta ndjekë cilido, për të parë postimet tuaja vetëm për ndjekësit.\",\n  \"compose_form.lock_disclaimer.lock\": \"e bllokuar\",\n  \"compose_form.placeholder\": \"Ç’bluani në mendje?\",\n  \"compose_form.poll.add_option\": \"Add a choice\",\n  \"compose_form.poll.duration\": \"Poll duration\",\n  \"compose_form.poll.option_placeholder\": \"Choice {number}\",\n  \"compose_form.poll.remove_option\": \"Remove this choice\",\n  \"compose_form.publish\": \"Mesazh\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"Mark media as sensitive\",\n  \"compose_form.sensitive.marked\": \"Media është shënuar si rezervat\",\n  \"compose_form.sensitive.unmarked\": \"Media s’është shënuar si rezervat\",\n  \"compose_form.spoiler.marked\": \"Teksti është fshehur pas sinjalizimit\",\n  \"compose_form.spoiler.unmarked\": \"Teksti s’është i fshehur\",\n  \"compose_form.spoiler_placeholder\": \"Shkruani këtu sinjalizimin tuaj\",\n  \"confirmation_modal.cancel\": \"Anuloje\",\n  \"confirmations.block.block_and_report\": \"Block & Report\",\n  \"confirmations.block.confirm\": \"Bllokoje\",\n  \"confirmations.block.message\": \"Jeni i sigurt se doni të bllokohet {name}?\",\n  \"confirmations.delete.confirm\": \"Fshije\",\n  \"confirmations.delete.message\": \"Jeni i sigurt se doni të fshihet kjo gjendje?\",\n  \"confirmations.delete_list.confirm\": \"Fshije\",\n  \"confirmations.delete_list.message\": \"Jeni i sigurt që doni të fshihet përgjithmonë kjo listë?\",\n  \"confirmations.domain_block.confirm\": \"Fshih krejt përkatësinë\",\n  \"confirmations.domain_block.message\": \"Jeni i sigurt, shumë i sigurt se doni të bllokohet krejt {domain}? Në shumicën e rasteve, ndoca bllokime ose heshtime me synim të caktuar janë të mjaftueshme dhe të parapëlqyera. S’keni për të parë lëndë nga kjo përkatësi në ndonjë rrjedhë kohore publike, apo te njoftimet tuaja. Ndjekësit tuaj prej asaj përkatësie do të hiqen.\",\n  \"confirmations.mute.confirm\": \"Heshtoje\",\n  \"confirmations.mute.message\": \"Jeni i sigurt se doni të heshtohet {name}?\",\n  \"confirmations.redraft.confirm\": \"Fshijeni & rihartojeni\",\n  \"confirmations.redraft.message\": \"Jeni i sigurt se doni të fshihet kjo gjendje dhe të rihartohet? Parapëlqimet dhe boosts do të humbin, ndërsa përgjigjet te postimi origjinal do të bëhen jetime.\",\n  \"confirmations.reply.confirm\": \"Përgjigjuni\",\n  \"confirmations.reply.message\": \"Përgjigja tani do të shkaktojë mbishkrimin e mesazhit që po hartoni. Jeni i sigurt se doni të vazhdohet më tej?\",\n  \"confirmations.unfollow.confirm\": \"Resht së ndjekuri\",\n  \"confirmations.unfollow.message\": \"Jeni i sigurt se doni të mos ndiqet më {name}?\",\n  \"embed.instructions\": \"Trupëzojeni këtë gjendje në sajtin tuaj duke kopjuar kodin më poshtë.\",\n  \"embed.preview\": \"Ja si do të duket:\",\n  \"emoji_button.activity\": \"Veprimtari\",\n  \"emoji_button.custom\": \"Vetjak\",\n  \"emoji_button.flags\": \"Flamuj\",\n  \"emoji_button.food\": \"Ushqim & Pije\",\n  \"emoji_button.label\": \"Futni emoji\",\n  \"emoji_button.nature\": \"Natyrë\",\n  \"emoji_button.not_found\": \"No emojos!!! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"Objekte\",\n  \"emoji_button.people\": \"Persona\",\n  \"emoji_button.recent\": \"Të përdorur shpesh\",\n  \"emoji_button.search\": \"Kërkoni…\",\n  \"emoji_button.search_results\": \"Përfundime kërkimi\",\n  \"emoji_button.symbols\": \"Simbole\",\n  \"emoji_button.travel\": \"Udhëtime & Vende\",\n  \"empty_column.account_timeline\": \"S’ka mesazhe këtu!\",\n  \"empty_column.account_unavailable\": \"Profile unavailable\",\n  \"empty_column.blocks\": \"S’keni bllokuar ende ndonjë përdorues.\",\n  \"empty_column.community\": \"Rrjedha kohore vendore është e zbrazët. Shkruani diçka publikisht që t’i hyhet valles!\",\n  \"empty_column.direct\": \"S’keni ende ndonjë mesazh të drejtpërdrejt. Kur dërgoni ose merrni një të tillë, ai do të shfaqet këtu.\",\n  \"empty_column.domain_blocks\": \"Ende s’ka përkatësi të fshehura.\",\n  \"empty_column.favourited_statuses\": \"S’keni ende ndonjë mesazh të parapëlqyer. Kur parapëlqeni një të tillë, ai do të shfaqet këtu.\",\n  \"empty_column.favourites\": \"Askush s’e ka parapëlqyer ende këtë mesazh. Kur e bën dikush, ai do të shfaqet këtu.\",\n  \"empty_column.follow_requests\": \"Ende s’keni ndonjë kërkesë ndjekjeje. Kur të merrni një të tillë, do të shfaqet këtu.\",\n  \"empty_column.hashtag\": \"Ende s’ka gjë nën këtë hashtag.\",\n  \"empty_column.home\": \"Rrjedha juaj kohore është e zbrazët! Vizitoni {public} ose përdorni kërkimin që t’ia filloni dhe të takoni përdorues të tjerë.\",\n  \"empty_column.home.public_timeline\": \"rrjedha kohore publike\",\n  \"empty_column.list\": \"Në këtë listë ende s’ka gjë. Kur anëtarë të kësaj liste postojnë gjendje të reja, ato do të shfaqen këtu.\",\n  \"empty_column.lists\": \"Ende s’keni ndonjë listë. Kur të krijoni një të tillë, do të duket këtu.\",\n  \"empty_column.mutes\": \"S’keni heshtuar ende ndonjë përdorues.\",\n  \"empty_column.notifications\": \"Ende s’keni ndonjë njoftim. Ndërveproni me të tjerët që të nisë biseda.\",\n  \"empty_column.public\": \"S’ka gjë këtu! Shkruani diçka publikisht, ose ndiqni dorazi përdorues prej instancash të tjera, që ta mbushni këtë zonë\",\n  \"follow_request.authorize\": \"Autorizoje\",\n  \"follow_request.reject\": \"Hidhe tej\",\n  \"getting_started.developers\": \"Zhvillues\",\n  \"getting_started.directory\": \"Drejtori profilesh\",\n  \"getting_started.documentation\": \"Dokumentim\",\n  \"getting_started.heading\": \"Si t’ia fillohet\",\n  \"getting_started.invite\": \"Ftoni njerëz\",\n  \"getting_started.open_source_notice\": \"Mastodon-i është software me burim të hapur. Mund të jepni ndihmesë ose të njoftoni probleme në GitHub, te {github}.\",\n  \"getting_started.security\": \"Siguri\",\n  \"getting_started.terms\": \"Kushte shërbimi\",\n  \"hashtag.column_header.tag_mode.all\": \"dhe {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"ose {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"pa {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"No suggestions found\",\n  \"hashtag.column_settings.select.placeholder\": \"Enter hashtags…\",\n  \"hashtag.column_settings.tag_mode.all\": \"Krejt këto\",\n  \"hashtag.column_settings.tag_mode.any\": \"Cilëndo prej këtyre\",\n  \"hashtag.column_settings.tag_mode.none\": \"Asnjë prej këtyre\",\n  \"hashtag.column_settings.tag_toggle\": \"Përfshi etiketa shtesë për këtë shtyllë\",\n  \"home.column_settings.basic\": \"Bazë\",\n  \"home.column_settings.show_reblogs\": \"Shfaq përforcime\",\n  \"home.column_settings.show_replies\": \"Shfaq përgjigje\",\n  \"intervals.full.days\": \"{number, plural, one {# day} other {# days}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# hour} other {# hours}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minute} other {# minutes}}\",\n  \"introduction.federation.action\": \"Pasuesi\",\n  \"introduction.federation.federated.headline\": \"Të federuara\",\n  \"introduction.federation.federated.text\": \"Postimet publike nga shërbyes të tjerë të fediversit do të shfaqen te rrjedha kohore e të federuarve.\",\n  \"introduction.federation.home.headline\": \"Vatër\",\n  \"introduction.federation.home.text\": \"Postime prej personash që ndiqni do të shfaqen te prurja juaj vatër. Mund të ndiqni këdo, në çfarëdo shërbyesi!\",\n  \"introduction.federation.local.headline\": \"Vendore\",\n  \"introduction.federation.local.text\": \"Postimet publike prej personash në të njëjtin shërbyes me ju do të shfaqen te rrjedha kohore vendore.\",\n  \"introduction.interactions.action\": \"Përfundojeni përkujdesoren!\",\n  \"introduction.interactions.favourite.headline\": \"Parapëlqejeni\",\n  \"introduction.interactions.favourite.text\": \"Duke e parapëlqyer, një mesazh mund ta ruani për më vonë dhe t’i bëni të ditur autorit se e pëlqyet.\",\n  \"introduction.interactions.reblog.headline\": \"Përforcime\",\n  \"introduction.interactions.reblog.text\": \"Mesazhet e të tjerëve mund t’i ndani me ndjekësit tuaj duke i përforcuar.\",\n  \"introduction.interactions.reply.headline\": \"Përgjigjuni\",\n  \"introduction.interactions.reply.text\": \"Mund t'u përgjigjeni mesazheve tuaja dhe atyre të personave të tjerë, çka do t’i lidhë ato tok në një bisedë.\",\n  \"introduction.welcome.action\": \"Shkojmë!\",\n  \"introduction.welcome.headline\": \"Hapat e parë\",\n  \"introduction.welcome.text\": \"Mirë se vini në fedivers! Brenda pak çastesh do të jeni në gjendje të transmetoni mesazhe dhe të bisedoni me miqtë tuaj nëpër një larmi të madhe shërbyesish. Po ky shërbyes, {domain}, është i veçantë—strehon profilin tuaj, ndaj mbajeni mend emrin e tij.\",\n  \"keyboard_shortcuts.back\": \"për shkuarje mbrapsht\",\n  \"keyboard_shortcuts.blocked\": \"për hapje liste përdoruesish të bllokuar\",\n  \"keyboard_shortcuts.boost\": \"për përfocim\",\n  \"keyboard_shortcuts.column\": \"për kalim fokusi mbi një gjendje te një nga shtyllat\",\n  \"keyboard_shortcuts.compose\": \"për kalim fokusi te fusha e hartimit të mesazheve\",\n  \"keyboard_shortcuts.description\": \"Përshkrim\",\n  \"keyboard_shortcuts.direct\": \"për hapje shtylle mesazhesh të drejtpërdrejtë\",\n  \"keyboard_shortcuts.down\": \"për zbritje poshtë nëpër listë\",\n  \"keyboard_shortcuts.enter\": \"për hapje gjendjeje\",\n  \"keyboard_shortcuts.favourite\": \"për t’i vënë shenjë si të parapëlqyer\",\n  \"keyboard_shortcuts.favourites\": \"për hapje liste të parapëlqyerish\",\n  \"keyboard_shortcuts.federated\": \"për hapje rrjedhe kohore të të federuarve\",\n  \"keyboard_shortcuts.heading\": \"Shkurtore tastiere\",\n  \"keyboard_shortcuts.home\": \"për hapje rrjedhe kohore vetjake\",\n  \"keyboard_shortcuts.hotkey\": \"Tast përkatës\",\n  \"keyboard_shortcuts.legend\": \"për shfaqje të kësaj legjende\",\n  \"keyboard_shortcuts.local\": \"për hapje rrjedhe kohore vendore\",\n  \"keyboard_shortcuts.mention\": \"për përmendje të autorit\",\n  \"keyboard_shortcuts.muted\": \"për hapje liste përdoruesish të heshtuar\",\n  \"keyboard_shortcuts.my_profile\": \"për hapjen e profilit tuaj\",\n  \"keyboard_shortcuts.notifications\": \"për hapje shtylle njoftimesh\",\n  \"keyboard_shortcuts.pinned\": \"për hapje liste mesazhesh të fiksuar\",\n  \"keyboard_shortcuts.profile\": \"për hapje të profilit të autorit\",\n  \"keyboard_shortcuts.reply\": \"për t’u përgjigjur\",\n  \"keyboard_shortcuts.requests\": \"për hapje liste kërkesash për ndjekje\",\n  \"keyboard_shortcuts.search\": \"për kalim fokusi te kërkimi\",\n  \"keyboard_shortcuts.start\": \"për hapjen e shtyllës \\\"fillojani\\\"\",\n  \"keyboard_shortcuts.toggle_hidden\": \"për shfaqje/fshehje teksti pas CW\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"to show/hide media\",\n  \"keyboard_shortcuts.toot\": \"për të filluar një mesazh fringo të ri\",\n  \"keyboard_shortcuts.unfocus\": \"për heqjen e fokusit nga fusha e hartimit të mesazheve apo kërkimeve\",\n  \"keyboard_shortcuts.up\": \"për ngjitje sipër nëpër listë\",\n  \"lightbox.close\": \"Mbylle\",\n  \"lightbox.next\": \"Pasuesja\",\n  \"lightbox.previous\": \"E mëparshmja\",\n  \"lightbox.view_context\": \"View context\",\n  \"lists.account.add\": \"Shto në listë\",\n  \"lists.account.remove\": \"Hiqe nga lista\",\n  \"lists.delete\": \"Fshije listën\",\n  \"lists.edit\": \"Përpunoni listën\",\n  \"lists.edit.submit\": \"Change title\",\n  \"lists.new.create\": \"Shtoni listë\",\n  \"lists.new.title_placeholder\": \"Titull liste të re\",\n  \"lists.search\": \"Kërkoni mes personash që ndiqni\",\n  \"lists.subheading\": \"Listat tuaja\",\n  \"loading_indicator.label\": \"Po ngarkohet…\",\n  \"media_gallery.toggle_visible\": \"Ndërroni dukshmërinë\",\n  \"missing_indicator.label\": \"S’u gjet\",\n  \"missing_indicator.sublabel\": \"Ky burim s’u gjet dot\",\n  \"mute_modal.hide_notifications\": \"Të fshihen njoftimet prej këtij përdoruesi?\",\n  \"navigation_bar.apps\": \"Aplikacione për celular\",\n  \"navigation_bar.blocks\": \"Përdorues të bllokuar\",\n  \"navigation_bar.community_timeline\": \"Rrjedhë kohore vendore\",\n  \"navigation_bar.compose\": \"Hartoni mesazh të ri\",\n  \"navigation_bar.direct\": \"Mesazhe të drejtpërdrejta\",\n  \"navigation_bar.discover\": \"Zbuloni\",\n  \"navigation_bar.domain_blocks\": \"Përkatësi të fshehura\",\n  \"navigation_bar.edit_profile\": \"Përpunoni profilin\",\n  \"navigation_bar.favourites\": \"Të parapëlqyer\",\n  \"navigation_bar.filters\": \"Fjalë të heshtuara\",\n  \"navigation_bar.follow_requests\": \"Kërkesa për ndjekje\",\n  \"navigation_bar.follows_and_followers\": \"Follows and followers\",\n  \"navigation_bar.info\": \"Mbi këtë shërbyes\",\n  \"navigation_bar.keyboard_shortcuts\": \"Taste përkatës\",\n  \"navigation_bar.lists\": \"Lista\",\n  \"navigation_bar.logout\": \"Dalje\",\n  \"navigation_bar.mutes\": \"Përdorues të heshtuar\",\n  \"navigation_bar.personal\": \"Personale\",\n  \"navigation_bar.pins\": \"Mesazhe të fiksuar\",\n  \"navigation_bar.preferences\": \"Parapëlqime\",\n  \"navigation_bar.profile_directory\": \"Profile directory\",\n  \"navigation_bar.public_timeline\": \"Rrjedhë kohore të federuarish\",\n  \"navigation_bar.security\": \"Siguri\",\n  \"notification.favourite\": \"{name} parapëlqeu gjendjen tuaj\",\n  \"notification.follow\": \"{name} zuri t’ju ndjekë\",\n  \"notification.mention\": \"{name} ju ka përmendur\",\n  \"notification.poll\": \"A poll you have voted in has ended\",\n  \"notification.reblog\": \"{name} përforcoi gjendjen tuaj\",\n  \"notifications.clear\": \"Pastroji njoftimet\",\n  \"notifications.clear_confirmation\": \"Jeni i sigurt se doni të pastrohen përgjithmonë krejt njoftimet tuaja?\",\n  \"notifications.column_settings.alert\": \"Njoftime desktopi\",\n  \"notifications.column_settings.favourite\": \"Të parapëlqyer:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Shfaq krejt kategoritë\",\n  \"notifications.column_settings.filter_bar.category\": \"Shtyllë filtrimesh të shpejta\",\n  \"notifications.column_settings.filter_bar.show\": \"Shfaq\",\n  \"notifications.column_settings.follow\": \"Ndjekës të rinj:\",\n  \"notifications.column_settings.mention\": \"Përmendje:\",\n  \"notifications.column_settings.poll\": \"Poll results:\",\n  \"notifications.column_settings.push\": \"Njoftime Push\",\n  \"notifications.column_settings.reblog\": \"Përforcime:\",\n  \"notifications.column_settings.show\": \"Shfaq në shtylla\",\n  \"notifications.column_settings.sound\": \"Luaj një tingull\",\n  \"notifications.filter.all\": \"Krejt\",\n  \"notifications.filter.boosts\": \"Përforcime\",\n  \"notifications.filter.favourites\": \"Të parapëlqyer\",\n  \"notifications.filter.follows\": \"Ndjekje\",\n  \"notifications.filter.mentions\": \"Përmendje\",\n  \"notifications.filter.polls\": \"Poll results\",\n  \"notifications.group\": \"{count}s njoftime\",\n  \"poll.closed\": \"Closed\",\n  \"poll.refresh\": \"Refresh\",\n  \"poll.total_votes\": \"{count, plural, one {# vote} other {# votes}}\",\n  \"poll.vote\": \"Vote\",\n  \"poll_button.add_poll\": \"Add a poll\",\n  \"poll_button.remove_poll\": \"Remove poll\",\n  \"privacy.change\": \"Rregulloni privatësi gjendje\",\n  \"privacy.direct.long\": \"Postoja vetëm përdoruesve të përmendur\",\n  \"privacy.direct.short\": \"I drejtpërdrejtë\",\n  \"privacy.private.long\": \"Postojuani vetëm ndjekësve\",\n  \"privacy.private.short\": \"Vetëm ndjekësve\",\n  \"privacy.public.long\": \"Postojeni në rrjedha publike kohore\",\n  \"privacy.public.short\": \"Publike\",\n  \"privacy.unlisted.long\": \"Mos e postoni në rrjedha publike kohore\",\n  \"privacy.unlisted.short\": \"Jo në lista\",\n  \"regeneration_indicator.label\": \"Po ngarkohet…\",\n  \"regeneration_indicator.sublabel\": \"Prurja juaj vetjake po përgatiteet!\",\n  \"relative_time.days\": \"{number}d\",\n  \"relative_time.hours\": \"{number}h\",\n  \"relative_time.just_now\": \"tani\",\n  \"relative_time.minutes\": \"{number}m\",\n  \"relative_time.seconds\": \"{number}s\",\n  \"reply_indicator.cancel\": \"Anuloje\",\n  \"report.forward\": \"Përcillja {target}\",\n  \"report.forward_hint\": \"Llogaria është nga një shërbyes tjetër. Të dërgohet edhe një kopje e anonimizuar e raportimit?\",\n  \"report.hint\": \"Raportimi do t’u dërgohet moderatorëve të shërbyesit tuaj. Më poshtë mund të jepni një shpjegim se pse po e raportoni këtë llogari:\",\n  \"report.placeholder\": \"Komente shtesë\",\n  \"report.submit\": \"Parashtroje\",\n  \"report.target\": \"Raportim i {target}\",\n  \"search.placeholder\": \"Kërkoni\",\n  \"search_popout.search_format\": \"Format kërkimi të përparuar\",\n  \"search_popout.tips.full_text\": \"Kërkimi për tekst të thjeshtë përgjigjet me gjendje që keni shkruar, parapëlqyer, përforcuar, ose ku jeni përmendur, si dhe emra përdoruesish, emra ekrani dhe hashtagë që kanë përputhje me termin e kërkimit.\",\n  \"search_popout.tips.hashtag\": \"hashtag\",\n  \"search_popout.tips.status\": \"gjendje\",\n  \"search_popout.tips.text\": \"Kërkim për tekst të thjeshtë përgjigjet me emra, emra përdoruesish dhe hashtagë që kanë përputhje me termin e kërkimit\",\n  \"search_popout.tips.user\": \"përdorues\",\n  \"search_results.accounts\": \"Persona\",\n  \"search_results.hashtags\": \"Hashtagë\",\n  \"search_results.statuses\": \"Mesazhe\",\n  \"search_results.total\": \"{count, number} {count, plural, një {result} {results} të tjera}\",\n  \"status.admin_account\": \"Hap ndërfaqe moderimi për @{name}\",\n  \"status.admin_status\": \"Hape këtë gjendje te ndërfaqja e moderimit\",\n  \"status.block\": \"Blloko @{name}\",\n  \"status.cancel_reblog_private\": \"Shpërforcojeni\",\n  \"status.cannot_reblog\": \"Ky postim s’mund të përforcohet\",\n  \"status.copy\": \"Kopjoje lidhjen te gjendje\",\n  \"status.delete\": \"Fshije\",\n  \"status.detailed_status\": \"Pamje e hollësishme bisede\",\n  \"status.direct\": \"Mesazh i drejtpërdrejt për @{name}\",\n  \"status.embed\": \"Trupëzim\",\n  \"status.favourite\": \"I parapëlqyer\",\n  \"status.filtered\": \"I filtruar\",\n  \"status.load_more\": \"Ngarko më tepër\",\n  \"status.media_hidden\": \"Me media të fshehur\",\n  \"status.mention\": \"Përmendni @{name}\",\n  \"status.more\": \"Më tepër\",\n  \"status.mute\": \"Heshtoni @{name}\",\n  \"status.mute_conversation\": \"Heshtojeni bisedën\",\n  \"status.open\": \"Zgjeroje këtë gjendje\",\n  \"status.pin\": \"Fiksoje në profil\",\n  \"status.pinned\": \"Mesazh i fiksuar\",\n  \"status.read_more\": \"Lexoni më tepër\",\n  \"status.reblog\": \"Përforcojeni\",\n  \"status.reblog_private\": \"Përforcim për publikun origjinal\",\n  \"status.reblogged_by\": \"{name} përforcoi\",\n  \"status.reblogs.empty\": \"Këtë mesazh s’e ka përforcuar njeri deri tani. Kur ta bëjë dikush, kjo do të duket këtu.\",\n  \"status.redraft\": \"Fshijeni & rihartojeni\",\n  \"status.reply\": \"Përgjigjuni\",\n  \"status.replyAll\": \"Përgjigjuni rrjedhës\",\n  \"status.report\": \"Raportojeni @{name}\",\n  \"status.sensitive_warning\": \"Lëndë me spec\",\n  \"status.share\": \"Ndajeni me të tjerët\",\n  \"status.show_less\": \"Shfaq më pak\",\n  \"status.show_less_all\": \"Shfaq më pak për të tërë\",\n  \"status.show_more\": \"Shfaq më tepër\",\n  \"status.show_more_all\": \"Shfaq më tepër për të tërë\",\n  \"status.show_thread\": \"Shfaq rrjedhën\",\n  \"status.unmute_conversation\": \"Ktheji zërin bisedës\",\n  \"status.unpin\": \"Shfiksoje nga profili\",\n  \"suggestions.dismiss\": \"Mos e merr parasysh sugjerimin\",\n  \"suggestions.header\": \"Mund t’ju interesonte…\",\n  \"tabs_bar.federated_timeline\": \"E federuar\",\n  \"tabs_bar.home\": \"Kreu\",\n  \"tabs_bar.local_timeline\": \"Vendore\",\n  \"tabs_bar.notifications\": \"Njoftime\",\n  \"tabs_bar.search\": \"Kërkim\",\n  \"time_remaining.days\": \"{number, plural, one {# day} other {# days}} left\",\n  \"time_remaining.hours\": \"{number, plural, one {# hour} other {# hours}} left\",\n  \"time_remaining.minutes\": \"{number, plural, one {# minute} other {# minutes}} left\",\n  \"time_remaining.moments\": \"Moments remaining\",\n  \"time_remaining.seconds\": \"{number, plural, one {# second} other {# seconds}} left\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, një {person} {people} të tjerë} po flasin\",\n  \"ui.beforeunload\": \"Skica juaj do të humbë nëse dilni nga Mastodon-i.\",\n  \"upload_area.title\": \"Merreni & vëreni që të ngarkohet\",\n  \"upload_button.label\": \"Shtoni media (JPEG, PNG, GIF, WebM, MP4, MOV)\",\n  \"upload_error.limit\": \"U tejkalua kufi ngarkimi kartelash.\",\n  \"upload_error.poll\": \"File upload not allowed with polls.\",\n  \"upload_form.description\": \"Përshkruajeni për persona me probleme shikimi\",\n  \"upload_form.focus\": \"Ndryshoni parapamjen\",\n  \"upload_form.undo\": \"Fshije\",\n  \"upload_progress.label\": \"Po ngarkohet…\",\n  \"video.close\": \"Mbylle videon\",\n  \"video.exit_fullscreen\": \"Dil nga mënyra Sa Krejt Ekrani\",\n  \"video.expand\": \"Zgjeroje videon\",\n  \"video.fullscreen\": \"Sa krejt ekrani\",\n  \"video.hide\": \"Fshihe videon\",\n  \"video.mute\": \"Hiqi zërin\",\n  \"video.pause\": \"Ndalesë\",\n  \"video.play\": \"Luaje\",\n  \"video.unmute\": \"Riktheji zërin\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/sr-Latn.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Add or Remove from lists\",\n  \"account.badges.bot\": \"Bot\",\n  \"account.block\": \"Blokiraj korisnika @{name}\",\n  \"account.block_domain\": \"Sakrij sve sa domena {domain}\",\n  \"account.blocked\": \"Blocked\",\n  \"account.direct\": \"Direct Message @{name}\",\n  \"account.domain_blocked\": \"Domain hidden\",\n  \"account.edit_profile\": \"Izmeni profil\",\n  \"account.endorse\": \"Feature on profile\",\n  \"account.follow\": \"Zaprati\",\n  \"account.followers\": \"Pratioca\",\n  \"account.followers.empty\": \"No one follows this user yet.\",\n  \"account.follows\": \"Prati\",\n  \"account.follows.empty\": \"This user doesn't follow anyone yet.\",\n  \"account.follows_you\": \"Prati Vas\",\n  \"account.hide_reblogs\": \"Sakrij podrške koje daje korisnika @{name}\",\n  \"account.link_verified_on\": \"Ownership of this link was checked on {date}\",\n  \"account.locked_info\": \"This account privacy status is set to locked. The owner manually reviews who can follow them.\",\n  \"account.media\": \"Mediji\",\n  \"account.mention\": \"Pomeni korisnika @{name}\",\n  \"account.moved_to\": \"{name} se pomerio na:\",\n  \"account.mute\": \"Ućutkaj korisnika @{name}\",\n  \"account.mute_notifications\": \"Isključi obaveštenja od korisnika @{name}\",\n  \"account.muted\": \"Muted\",\n  \"account.posts\": \"Statusa\",\n  \"account.posts_with_replies\": \"Toots with replies\",\n  \"account.report\": \"Prijavi @{name}\",\n  \"account.requested\": \"Čekam odobrenje. Kliknite da poništite zahtev za praćenje\",\n  \"account.share\": \"Podeli profil korisnika @{name}\",\n  \"account.show_reblogs\": \"Prikaži podrške od korisnika @{name}\",\n  \"account.unblock\": \"Odblokiraj korisnika @{name}\",\n  \"account.unblock_domain\": \"Odblokiraj domen {domain}\",\n  \"account.unendorse\": \"Don't feature on profile\",\n  \"account.unfollow\": \"Otprati\",\n  \"account.unmute\": \"Ukloni ućutkavanje korisniku @{name}\",\n  \"account.unmute_notifications\": \"Uključi nazad obaveštenja od korisnika @{name}\",\n  \"alert.unexpected.message\": \"An unexpected error occurred.\",\n  \"alert.unexpected.title\": \"Oops!\",\n  \"boost_modal.combo\": \"Možete pritisnuti {combo} da preskočite ovo sledeći put\",\n  \"bundle_column_error.body\": \"Nešto je pošlo po zlu prilikom učitavanja ove komponente.\",\n  \"bundle_column_error.retry\": \"Pokušajte ponovo\",\n  \"bundle_column_error.title\": \"Mrežna greška\",\n  \"bundle_modal_error.close\": \"Zatvori\",\n  \"bundle_modal_error.message\": \"Nešto nije bilo u redu pri učitavanju ove komponente.\",\n  \"bundle_modal_error.retry\": \"Pokušajte ponovo\",\n  \"column.blocks\": \"Blokirani korisnici\",\n  \"column.community\": \"Lokalna lajna\",\n  \"column.direct\": \"Direct messages\",\n  \"column.domain_blocks\": \"Hidden domains\",\n  \"column.favourites\": \"Omiljeni\",\n  \"column.follow_requests\": \"Zahtevi za praćenje\",\n  \"column.home\": \"Početna\",\n  \"column.lists\": \"Liste\",\n  \"column.mutes\": \"Ućutkani korisnici\",\n  \"column.notifications\": \"Obaveštenja\",\n  \"column.pins\": \"Prikačeni tutovi\",\n  \"column.public\": \"Federisana lajna\",\n  \"column_back_button.label\": \"Nazad\",\n  \"column_header.hide_settings\": \"Sakrij postavke\",\n  \"column_header.moveLeft_settings\": \"Pomeri kolonu ulevo\",\n  \"column_header.moveRight_settings\": \"Pomeri kolonu udesno\",\n  \"column_header.pin\": \"Prikači\",\n  \"column_header.show_settings\": \"Prikaži postavke\",\n  \"column_header.unpin\": \"Otkači\",\n  \"column_subheading.settings\": \"Postavke\",\n  \"community.column_settings.media_only\": \"Media Only\",\n  \"compose_form.direct_message_warning\": \"This toot will only be visible to all the mentioned users.\",\n  \"compose_form.direct_message_warning_learn_more\": \"Learn more\",\n  \"compose_form.hashtag_warning\": \"This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.\",\n  \"compose_form.lock_disclaimer\": \"Vaš nalog nije {locked}. Svako može da Vas zaprati i da vidi objave namenjene samo Vašim pratiocima.\",\n  \"compose_form.lock_disclaimer.lock\": \"zaključan\",\n  \"compose_form.placeholder\": \"Šta Vam je na umu?\",\n  \"compose_form.poll.add_option\": \"Add a choice\",\n  \"compose_form.poll.duration\": \"Poll duration\",\n  \"compose_form.poll.option_placeholder\": \"Choice {number}\",\n  \"compose_form.poll.remove_option\": \"Remove this choice\",\n  \"compose_form.publish\": \"Tutni\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"Mark media as sensitive\",\n  \"compose_form.sensitive.marked\": \"Media is marked as sensitive\",\n  \"compose_form.sensitive.unmarked\": \"Media is not marked as sensitive\",\n  \"compose_form.spoiler.marked\": \"Text is hidden behind warning\",\n  \"compose_form.spoiler.unmarked\": \"Text is not hidden\",\n  \"compose_form.spoiler_placeholder\": \"Ovde upišite upozorenje\",\n  \"confirmation_modal.cancel\": \"Poništi\",\n  \"confirmations.block.block_and_report\": \"Block & Report\",\n  \"confirmations.block.confirm\": \"Blokiraj\",\n  \"confirmations.block.message\": \"Da li ste sigurni da želite da blokirate korisnika {name}?\",\n  \"confirmations.delete.confirm\": \"Obriši\",\n  \"confirmations.delete.message\": \"Da li ste sigurni da želite obrišete ovaj status?\",\n  \"confirmations.delete_list.confirm\": \"Obriši\",\n  \"confirmations.delete_list.message\": \"Da li ste sigurni da želite da bespovratno obrišete ovu listu?\",\n  \"confirmations.domain_block.confirm\": \"Sakrij ceo domen\",\n  \"confirmations.domain_block.message\": \"Da li ste stvarno, stvarno sigurno da želite da blokirate ceo domen {domain}? U većini slučajeva, par dobrih blokiranja ili ućutkavanja su dovoljna i preporučljiva.\",\n  \"confirmations.mute.confirm\": \"Ućutkaj\",\n  \"confirmations.mute.message\": \"Da li stvarno želite da ućutkate korisnika {name}?\",\n  \"confirmations.redraft.confirm\": \"Delete & redraft\",\n  \"confirmations.redraft.message\": \"Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.\",\n  \"confirmations.reply.confirm\": \"Reply\",\n  \"confirmations.reply.message\": \"Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?\",\n  \"confirmations.unfollow.confirm\": \"Otprati\",\n  \"confirmations.unfollow.message\": \"Da li ste sigurni da želite da otpratite korisnika {name}?\",\n  \"embed.instructions\": \"Ugradi ovaj status na Vaš veb sajt kopiranjem koda ispod.\",\n  \"embed.preview\": \"Ovako će da izgleda:\",\n  \"emoji_button.activity\": \"Aktivnost\",\n  \"emoji_button.custom\": \"Proizvoljno\",\n  \"emoji_button.flags\": \"Zastave\",\n  \"emoji_button.food\": \"Hrana & piće\",\n  \"emoji_button.label\": \"Ubaci smajli\",\n  \"emoji_button.nature\": \"Priroda\",\n  \"emoji_button.not_found\": \"Nema smajlija!! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"Objekti\",\n  \"emoji_button.people\": \"Ljudi\",\n  \"emoji_button.recent\": \"Najčešće korišćeni\",\n  \"emoji_button.search\": \"Pretraga...\",\n  \"emoji_button.search_results\": \"Rezultati pretrage\",\n  \"emoji_button.symbols\": \"Simboli\",\n  \"emoji_button.travel\": \"Putovanja & mesta\",\n  \"empty_column.account_timeline\": \"No toots here!\",\n  \"empty_column.account_unavailable\": \"Profile unavailable\",\n  \"empty_column.blocks\": \"You haven't blocked any users yet.\",\n  \"empty_column.community\": \"Lokalna lajna je prazna. Napišite nešto javno da lajna produva!\",\n  \"empty_column.direct\": \"You don't have any direct messages yet. When you send or receive one, it will show up here.\",\n  \"empty_column.domain_blocks\": \"There are no hidden domains yet.\",\n  \"empty_column.favourited_statuses\": \"You don't have any favourite toots yet. When you favourite one, it will show up here.\",\n  \"empty_column.favourites\": \"No one has favourited this toot yet. When someone does, they will show up here.\",\n  \"empty_column.follow_requests\": \"You don't have any follow requests yet. When you receive one, it will show up here.\",\n  \"empty_column.hashtag\": \"Trenutno nema ništa na ovom heštegu.\",\n  \"empty_column.home\": \"Vaša lajna je prazna! Posetite {public} ili koristite pretragu da počnete i upoznajete nove ljude.\",\n  \"empty_column.home.public_timeline\": \"javna lajna\",\n  \"empty_column.list\": \"U ovoj listi još nema ničega. Kada članovi liste objave nove statuse, oni će se pojavljivati ovde.\",\n  \"empty_column.lists\": \"You don't have any lists yet. When you create one, it will show up here.\",\n  \"empty_column.mutes\": \"You haven't muted any users yet.\",\n  \"empty_column.notifications\": \"Trenutno nemate obaveštenja. Družite se malo da započnete razgovore.\",\n  \"empty_column.public\": \"Ovde nema ničega! Napišite nešto javno, ili nađite korisnike sa drugih instanci koje ćete zapratiti da popunite ovu prazninu\",\n  \"follow_request.authorize\": \"Odobri\",\n  \"follow_request.reject\": \"Odbij\",\n  \"getting_started.developers\": \"Developers\",\n  \"getting_started.directory\": \"Profile directory\",\n  \"getting_started.documentation\": \"Documentation\",\n  \"getting_started.heading\": \"Da počnete\",\n  \"getting_started.invite\": \"Invite people\",\n  \"getting_started.open_source_notice\": \"Mastodont je softver otvorenog koda. Možete mu doprineti ili prijaviti probleme preko GitHub-a na {github}.\",\n  \"getting_started.security\": \"Security\",\n  \"getting_started.terms\": \"Terms of service\",\n  \"hashtag.column_header.tag_mode.all\": \"and {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"or {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"without {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"No suggestions found\",\n  \"hashtag.column_settings.select.placeholder\": \"Enter hashtags…\",\n  \"hashtag.column_settings.tag_mode.all\": \"All of these\",\n  \"hashtag.column_settings.tag_mode.any\": \"Any of these\",\n  \"hashtag.column_settings.tag_mode.none\": \"None of these\",\n  \"hashtag.column_settings.tag_toggle\": \"Include additional tags in this column\",\n  \"home.column_settings.basic\": \"Osnovno\",\n  \"home.column_settings.show_reblogs\": \"Prikaži i podržavanja\",\n  \"home.column_settings.show_replies\": \"Prikaži odgovore\",\n  \"intervals.full.days\": \"{number, plural, one {# day} other {# days}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# hour} other {# hours}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minute} other {# minutes}}\",\n  \"introduction.federation.action\": \"Next\",\n  \"introduction.federation.federated.headline\": \"Federated\",\n  \"introduction.federation.federated.text\": \"Public posts from other servers of the fediverse will appear in the federated timeline.\",\n  \"introduction.federation.home.headline\": \"Home\",\n  \"introduction.federation.home.text\": \"Posts from people you follow will appear in your home feed. You can follow anyone on any server!\",\n  \"introduction.federation.local.headline\": \"Local\",\n  \"introduction.federation.local.text\": \"Public posts from people on the same server as you will appear in the local timeline.\",\n  \"introduction.interactions.action\": \"Finish toot-orial!\",\n  \"introduction.interactions.favourite.headline\": \"Favourite\",\n  \"introduction.interactions.favourite.text\": \"You can save a toot for later, and let the author know that you liked it, by favouriting it.\",\n  \"introduction.interactions.reblog.headline\": \"Boost\",\n  \"introduction.interactions.reblog.text\": \"You can share other people's toots with your followers by boosting them.\",\n  \"introduction.interactions.reply.headline\": \"Reply\",\n  \"introduction.interactions.reply.text\": \"You can reply to other people's and your own toots, which will chain them together in a conversation.\",\n  \"introduction.welcome.action\": \"Let's go!\",\n  \"introduction.welcome.headline\": \"First steps\",\n  \"introduction.welcome.text\": \"Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.\",\n  \"keyboard_shortcuts.back\": \"da odete nazad\",\n  \"keyboard_shortcuts.blocked\": \"to open blocked users list\",\n  \"keyboard_shortcuts.boost\": \"da podržite\",\n  \"keyboard_shortcuts.column\": \"da se prebacite na status u jednoj od kolona\",\n  \"keyboard_shortcuts.compose\": \"da se prebacite na pisanje novog tuta\",\n  \"keyboard_shortcuts.description\": \"Opis\",\n  \"keyboard_shortcuts.direct\": \"to open direct messages column\",\n  \"keyboard_shortcuts.down\": \"da se pomerite na dole u listi\",\n  \"keyboard_shortcuts.enter\": \"da otvorite status\",\n  \"keyboard_shortcuts.favourite\": \"da označite kao omiljeno\",\n  \"keyboard_shortcuts.favourites\": \"to open favourites list\",\n  \"keyboard_shortcuts.federated\": \"to open federated timeline\",\n  \"keyboard_shortcuts.heading\": \"Prečice na tastaturi\",\n  \"keyboard_shortcuts.home\": \"to open home timeline\",\n  \"keyboard_shortcuts.hotkey\": \"Prečica\",\n  \"keyboard_shortcuts.legend\": \"da prikažete ovaj podsetnik\",\n  \"keyboard_shortcuts.local\": \"to open local timeline\",\n  \"keyboard_shortcuts.mention\": \"da pomenete autora\",\n  \"keyboard_shortcuts.muted\": \"to open muted users list\",\n  \"keyboard_shortcuts.my_profile\": \"to open your profile\",\n  \"keyboard_shortcuts.notifications\": \"to open notifications column\",\n  \"keyboard_shortcuts.pinned\": \"to open pinned toots list\",\n  \"keyboard_shortcuts.profile\": \"to open author's profile\",\n  \"keyboard_shortcuts.reply\": \"da odgovorite\",\n  \"keyboard_shortcuts.requests\": \"to open follow requests list\",\n  \"keyboard_shortcuts.search\": \"da se prebacite na pretragu\",\n  \"keyboard_shortcuts.start\": \"to open \\\"get started\\\" column\",\n  \"keyboard_shortcuts.toggle_hidden\": \"to show/hide text behind CW\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"to show/hide media\",\n  \"keyboard_shortcuts.toot\": \"da započnete skroz novi tut\",\n  \"keyboard_shortcuts.unfocus\": \"da ne budete više na pretrazi/pravljenju novog tuta\",\n  \"keyboard_shortcuts.up\": \"da se pomerite na gore u listi\",\n  \"lightbox.close\": \"Zatvori\",\n  \"lightbox.next\": \"Sledeći\",\n  \"lightbox.previous\": \"Prethodni\",\n  \"lightbox.view_context\": \"View context\",\n  \"lists.account.add\": \"Dodaj na listu\",\n  \"lists.account.remove\": \"Ukloni sa liste\",\n  \"lists.delete\": \"Obriši listu\",\n  \"lists.edit\": \"Izmeni listu\",\n  \"lists.edit.submit\": \"Change title\",\n  \"lists.new.create\": \"Dodaj listu\",\n  \"lists.new.title_placeholder\": \"Naslov nove liste\",\n  \"lists.search\": \"Pretraži među ljudima koje pratite\",\n  \"lists.subheading\": \"Vaše liste\",\n  \"loading_indicator.label\": \"Učitavam...\",\n  \"media_gallery.toggle_visible\": \"Uključi/isključi vidljivost\",\n  \"missing_indicator.label\": \"Nije pronađeno\",\n  \"missing_indicator.sublabel\": \"This resource could not be found\",\n  \"mute_modal.hide_notifications\": \"Sakrij obaveštenja od ovog korisnika?\",\n  \"navigation_bar.apps\": \"Mobile apps\",\n  \"navigation_bar.blocks\": \"Blokirani korisnici\",\n  \"navigation_bar.community_timeline\": \"Lokalna lajna\",\n  \"navigation_bar.compose\": \"Compose new toot\",\n  \"navigation_bar.direct\": \"Direct messages\",\n  \"navigation_bar.discover\": \"Discover\",\n  \"navigation_bar.domain_blocks\": \"Hidden domains\",\n  \"navigation_bar.edit_profile\": \"Izmeni profil\",\n  \"navigation_bar.favourites\": \"Omiljeni\",\n  \"navigation_bar.filters\": \"Muted words\",\n  \"navigation_bar.follow_requests\": \"Zahtevi za praćenje\",\n  \"navigation_bar.follows_and_followers\": \"Follows and followers\",\n  \"navigation_bar.info\": \"O ovoj instanci\",\n  \"navigation_bar.keyboard_shortcuts\": \"Prečice na tastaturi\",\n  \"navigation_bar.lists\": \"Liste\",\n  \"navigation_bar.logout\": \"Odjava\",\n  \"navigation_bar.mutes\": \"Ućutkani korisnici\",\n  \"navigation_bar.personal\": \"Personal\",\n  \"navigation_bar.pins\": \"Prikačeni tutovi\",\n  \"navigation_bar.preferences\": \"Podešavanja\",\n  \"navigation_bar.profile_directory\": \"Profile directory\",\n  \"navigation_bar.public_timeline\": \"Federisana lajna\",\n  \"navigation_bar.security\": \"Security\",\n  \"notification.favourite\": \"{name} je stavio Vaš status kao omiljeni\",\n  \"notification.follow\": \"{name} Vas je zapratio\",\n  \"notification.mention\": \"{name} Vas je pomenuo\",\n  \"notification.poll\": \"A poll you have voted in has ended\",\n  \"notification.reblog\": \"{name} je podržao(la) Vaš status\",\n  \"notifications.clear\": \"Očisti obaveštenja\",\n  \"notifications.clear_confirmation\": \"Da li ste sigurno da trajno želite da očistite Vaša obaveštenja?\",\n  \"notifications.column_settings.alert\": \"Obaveštenja na radnoj površini\",\n  \"notifications.column_settings.favourite\": \"Omiljeni:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Display all categories\",\n  \"notifications.column_settings.filter_bar.category\": \"Quick filter bar\",\n  \"notifications.column_settings.filter_bar.show\": \"Show\",\n  \"notifications.column_settings.follow\": \"Novi pratioci:\",\n  \"notifications.column_settings.mention\": \"Pominjanja:\",\n  \"notifications.column_settings.poll\": \"Poll results:\",\n  \"notifications.column_settings.push\": \"Guraj obaveštenja\",\n  \"notifications.column_settings.reblog\": \"Podrški:\",\n  \"notifications.column_settings.show\": \"Prikaži u koloni\",\n  \"notifications.column_settings.sound\": \"Puštaj zvuk\",\n  \"notifications.filter.all\": \"All\",\n  \"notifications.filter.boosts\": \"Boosts\",\n  \"notifications.filter.favourites\": \"Favourites\",\n  \"notifications.filter.follows\": \"Follows\",\n  \"notifications.filter.mentions\": \"Mentions\",\n  \"notifications.filter.polls\": \"Poll results\",\n  \"notifications.group\": \"{count} notifications\",\n  \"poll.closed\": \"Closed\",\n  \"poll.refresh\": \"Refresh\",\n  \"poll.total_votes\": \"{count, plural, one {# vote} other {# votes}}\",\n  \"poll.vote\": \"Vote\",\n  \"poll_button.add_poll\": \"Add a poll\",\n  \"poll_button.remove_poll\": \"Remove poll\",\n  \"privacy.change\": \"Podesi status privatnosti\",\n  \"privacy.direct.long\": \"Objavi samo korisnicima koji su pomenuti\",\n  \"privacy.direct.short\": \"Direktno\",\n  \"privacy.private.long\": \"Objavi samo pratiocima\",\n  \"privacy.private.short\": \"Samo za pratioce\",\n  \"privacy.public.long\": \"Objavi na javnoj lajni\",\n  \"privacy.public.short\": \"Javno\",\n  \"privacy.unlisted.long\": \"Ne objavljuj na javnim lajnama\",\n  \"privacy.unlisted.short\": \"Neizlistano\",\n  \"regeneration_indicator.label\": \"Loading…\",\n  \"regeneration_indicator.sublabel\": \"Your home feed is being prepared!\",\n  \"relative_time.days\": \"{number}d\",\n  \"relative_time.hours\": \"{number}h\",\n  \"relative_time.just_now\": \"sada\",\n  \"relative_time.minutes\": \"{number}m\",\n  \"relative_time.seconds\": \"{number}s\",\n  \"reply_indicator.cancel\": \"Poništi\",\n  \"report.forward\": \"Forward to {target}\",\n  \"report.forward_hint\": \"The account is from another server. Send an anonymized copy of the report there as well?\",\n  \"report.hint\": \"The report will be sent to your instance moderators. You can provide an explanation of why you are reporting this account below:\",\n  \"report.placeholder\": \"Dodatni komentari\",\n  \"report.submit\": \"Pošalji\",\n  \"report.target\": \"Prijavljujem {target}\",\n  \"search.placeholder\": \"Pretraga\",\n  \"search_popout.search_format\": \"Napredni format pretrage\",\n  \"search_popout.tips.full_text\": \"Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.\",\n  \"search_popout.tips.hashtag\": \"hešteg\",\n  \"search_popout.tips.status\": \"status\",\n  \"search_popout.tips.text\": \"Traženjem običnog teksta ćete dobiti sva pronađena imena, sva korisnička imena i sve nađene heštegove\",\n  \"search_popout.tips.user\": \"korisnik\",\n  \"search_results.accounts\": \"People\",\n  \"search_results.hashtags\": \"Hashtags\",\n  \"search_results.statuses\": \"Toots\",\n  \"search_results.total\": \"{count, number} {count, plural, one {rezultat} few {rezultata} other {rezultata}}\",\n  \"status.admin_account\": \"Open moderation interface for @{name}\",\n  \"status.admin_status\": \"Open this status in the moderation interface\",\n  \"status.block\": \"Block @{name}\",\n  \"status.cancel_reblog_private\": \"Unboost\",\n  \"status.cannot_reblog\": \"Ovaj status ne može da se podrži\",\n  \"status.copy\": \"Copy link to status\",\n  \"status.delete\": \"Obriši\",\n  \"status.detailed_status\": \"Detailed conversation view\",\n  \"status.direct\": \"Direct message @{name}\",\n  \"status.embed\": \"Ugradi na sajt\",\n  \"status.favourite\": \"Omiljeno\",\n  \"status.filtered\": \"Filtered\",\n  \"status.load_more\": \"Učitaj još\",\n  \"status.media_hidden\": \"Multimedija sakrivena\",\n  \"status.mention\": \"Pomeni korisnika @{name}\",\n  \"status.more\": \"Još\",\n  \"status.mute\": \"Mute @{name}\",\n  \"status.mute_conversation\": \"Ućutkaj prepisku\",\n  \"status.open\": \"Proširi ovaj status\",\n  \"status.pin\": \"Prikači na profil\",\n  \"status.pinned\": \"Pinned toot\",\n  \"status.read_more\": \"Read more\",\n  \"status.reblog\": \"Podrži\",\n  \"status.reblog_private\": \"Boost to original audience\",\n  \"status.reblogged_by\": \"{name} podržao(la)\",\n  \"status.reblogs.empty\": \"No one has boosted this toot yet. When someone does, they will show up here.\",\n  \"status.redraft\": \"Delete & re-draft\",\n  \"status.reply\": \"Odgovori\",\n  \"status.replyAll\": \"Odgovori na diskusiju\",\n  \"status.report\": \"Prijavi korisnika @{name}\",\n  \"status.sensitive_warning\": \"Osetljiv sadržaj\",\n  \"status.share\": \"Podeli\",\n  \"status.show_less\": \"Prikaži manje\",\n  \"status.show_less_all\": \"Show less for all\",\n  \"status.show_more\": \"Prikaži više\",\n  \"status.show_more_all\": \"Show more for all\",\n  \"status.show_thread\": \"Show thread\",\n  \"status.unmute_conversation\": \"Uključi prepisku\",\n  \"status.unpin\": \"Otkači sa profila\",\n  \"suggestions.dismiss\": \"Dismiss suggestion\",\n  \"suggestions.header\": \"You might be interested in…\",\n  \"tabs_bar.federated_timeline\": \"Federisano\",\n  \"tabs_bar.home\": \"Početna\",\n  \"tabs_bar.local_timeline\": \"Lokalno\",\n  \"tabs_bar.notifications\": \"Obaveštenja\",\n  \"tabs_bar.search\": \"Search\",\n  \"time_remaining.days\": \"{number, plural, one {# day} other {# days}} left\",\n  \"time_remaining.hours\": \"{number, plural, one {# hour} other {# hours}} left\",\n  \"time_remaining.minutes\": \"{number, plural, one {# minute} other {# minutes}} left\",\n  \"time_remaining.moments\": \"Moments remaining\",\n  \"time_remaining.seconds\": \"{number, plural, one {# second} other {# seconds}} left\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {person} other {people}} talking\",\n  \"ui.beforeunload\": \"Ako napustite Mastodont, izgubićete napisani nacrt.\",\n  \"upload_area.title\": \"Prevucite ovde da otpremite\",\n  \"upload_button.label\": \"Dodaj multimediju\",\n  \"upload_error.limit\": \"File upload limit exceeded.\",\n  \"upload_error.poll\": \"File upload not allowed with polls.\",\n  \"upload_form.description\": \"Opiši za slabovide osobe\",\n  \"upload_form.focus\": \"Crop\",\n  \"upload_form.undo\": \"Opozovi\",\n  \"upload_progress.label\": \"Otpremam...\",\n  \"video.close\": \"Zatvori video\",\n  \"video.exit_fullscreen\": \"Napusti ceo ekran\",\n  \"video.expand\": \"Proširi video\",\n  \"video.fullscreen\": \"Ceo ekran\",\n  \"video.hide\": \"Sakrij video\",\n  \"video.mute\": \"Ugasi zvuk\",\n  \"video.pause\": \"Pauziraj\",\n  \"video.play\": \"Pusti\",\n  \"video.unmute\": \"Vrati zvuk\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/sr.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Add or Remove from lists\",\n  \"account.badges.bot\": \"Бот\",\n  \"account.block\": \"Блокирај @{name}\",\n  \"account.block_domain\": \"Сакриј све са домена {domain}\",\n  \"account.blocked\": \"Блокиран\",\n  \"account.direct\": \"Директна порука @{name}\",\n  \"account.domain_blocked\": \"Домен сакривен\",\n  \"account.edit_profile\": \"Измени профил\",\n  \"account.endorse\": \"Приказати на профилу\",\n  \"account.follow\": \"Запрати\",\n  \"account.followers\": \"Пратиоци\",\n  \"account.followers.empty\": \"Тренутно нико не прати овог корисника.\",\n  \"account.follows\": \"Прати\",\n  \"account.follows.empty\": \"Корисник тренутно не прати никога.\",\n  \"account.follows_you\": \"Прати Вас\",\n  \"account.hide_reblogs\": \"Сакриј подршке које даје корисника @{name}\",\n  \"account.link_verified_on\": \"Ownership of this link was checked on {date}\",\n  \"account.locked_info\": \"This account privacy status is set to locked. The owner manually reviews who can follow them.\",\n  \"account.media\": \"Медији\",\n  \"account.mention\": \"Помени корисника @{name}\",\n  \"account.moved_to\": \"{name} се померио на:\",\n  \"account.mute\": \"Ућуткај корисника @{name}\",\n  \"account.mute_notifications\": \"Искључи обавештења од корисника @{name}\",\n  \"account.muted\": \"Ућуткан\",\n  \"account.posts\": \"Трубе\",\n  \"account.posts_with_replies\": \"Трубе и одговори\",\n  \"account.report\": \"Пријави @{name}\",\n  \"account.requested\": \"Чекам одобрење. Кликните да поништите захтев за праћење\",\n  \"account.share\": \"Подели профил корисника @{name}\",\n  \"account.show_reblogs\": \"Прикажи подршке од корисника @{name}\",\n  \"account.unblock\": \"Одблокирај корисника @{name}\",\n  \"account.unblock_domain\": \"Одблокирај домен {domain}\",\n  \"account.unendorse\": \"Не истичи на профилу\",\n  \"account.unfollow\": \"Отпрати\",\n  \"account.unmute\": \"Уклони ућуткавање кориснику @{name}\",\n  \"account.unmute_notifications\": \"Укључи назад обавештења од корисника @{name}\",\n  \"alert.unexpected.message\": \"Појавила се неочекивана грешка.\",\n  \"alert.unexpected.title\": \"Упс!\",\n  \"boost_modal.combo\": \"Можете притиснути {combo} да прескочите ово следећи пут\",\n  \"bundle_column_error.body\": \"Нешто је пошло по злу приликом учитавања ове компоненте.\",\n  \"bundle_column_error.retry\": \"Покушајте поново\",\n  \"bundle_column_error.title\": \"Мрежна грешка\",\n  \"bundle_modal_error.close\": \"Затвори\",\n  \"bundle_modal_error.message\": \"Нешто није било у реду при учитавању ове компоненте.\",\n  \"bundle_modal_error.retry\": \"Покушајте поново\",\n  \"column.blocks\": \"Блокирани корисници\",\n  \"column.community\": \"Локална временска линија\",\n  \"column.direct\": \"Директне поруке\",\n  \"column.domain_blocks\": \"Скривени домени\",\n  \"column.favourites\": \"Омиљене\",\n  \"column.follow_requests\": \"Захтеви за праћење\",\n  \"column.home\": \"Почетна\",\n  \"column.lists\": \"Листе\",\n  \"column.mutes\": \"Ућуткани корисници\",\n  \"column.notifications\": \"Обавештења\",\n  \"column.pins\": \"Прикачене трубе\",\n  \"column.public\": \"Здружена временска линија\",\n  \"column_back_button.label\": \"Назад\",\n  \"column_header.hide_settings\": \"Сакриј поставке\",\n  \"column_header.moveLeft_settings\": \"Помери колону улево\",\n  \"column_header.moveRight_settings\": \"Помери колону удесно\",\n  \"column_header.pin\": \"Прикачи\",\n  \"column_header.show_settings\": \"Прикажи поставке\",\n  \"column_header.unpin\": \"Откачи\",\n  \"column_subheading.settings\": \"Поставке\",\n  \"community.column_settings.media_only\": \"Само Медији\",\n  \"compose_form.direct_message_warning\": \"Ова труба ће бити послата споменутим корисницима.\",\n  \"compose_form.direct_message_warning_learn_more\": \"Сазнајте више\",\n  \"compose_form.hashtag_warning\": \"Ова труба неће бити излистана под било којом тарабом јер је сакривена. Само јавне трубе могу бити претражене тарабом.\",\n  \"compose_form.lock_disclaimer\": \"Ваш налог није {locked}. Свако може да Вас запрати и да види објаве намењене само Вашим пратиоцима.\",\n  \"compose_form.lock_disclaimer.lock\": \"закључан\",\n  \"compose_form.placeholder\": \"Шта Вам је на уму?\",\n  \"compose_form.poll.add_option\": \"Add a choice\",\n  \"compose_form.poll.duration\": \"Poll duration\",\n  \"compose_form.poll.option_placeholder\": \"Choice {number}\",\n  \"compose_form.poll.remove_option\": \"Remove this choice\",\n  \"compose_form.publish\": \"Труби\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"Mark media as sensitive\",\n  \"compose_form.sensitive.marked\": \"Медији су означени као осетљиви\",\n  \"compose_form.sensitive.unmarked\": \"Медији су означени као не-осетљиви\",\n  \"compose_form.spoiler.marked\": \"Текст је сакривен иза упозорења\",\n  \"compose_form.spoiler.unmarked\": \"Текст није сакривен\",\n  \"compose_form.spoiler_placeholder\": \"Овде упишите упозорење\",\n  \"confirmation_modal.cancel\": \"Поништи\",\n  \"confirmations.block.block_and_report\": \"Block & Report\",\n  \"confirmations.block.confirm\": \"Блокирај\",\n  \"confirmations.block.message\": \"Да ли сте сигурни да желите да блокирате корисника {name}?\",\n  \"confirmations.delete.confirm\": \"Обриши\",\n  \"confirmations.delete.message\": \"Да ли сте сигурни да желите обришете овај статус?\",\n  \"confirmations.delete_list.confirm\": \"Обриши\",\n  \"confirmations.delete_list.message\": \"Да ли сте сигурни да желите да бесповратно обришете ову листу?\",\n  \"confirmations.domain_block.confirm\": \"Сакриј цео домен\",\n  \"confirmations.domain_block.message\": \"Да ли сте заиста сигурни да желите да блокирате цео домен {domain}? У већини случајева, неколико добро промишљених блокирања или ућуткавања су довољна и препоручљива.\",\n  \"confirmations.mute.confirm\": \"Ућуткај\",\n  \"confirmations.mute.message\": \"Да ли стварно желите да ућуткате корисника {name}?\",\n  \"confirmations.redraft.confirm\": \"Избриши и преправи\",\n  \"confirmations.redraft.message\": \"Да ли сте сигурни да желите да избришете овај статус и да га преправите? Сва стављања у омиљене трубе, као и подршке ће бити изгубљене, а одговори на оригинални пост ће бити поништени.\",\n  \"confirmations.reply.confirm\": \"Reply\",\n  \"confirmations.reply.message\": \"Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?\",\n  \"confirmations.unfollow.confirm\": \"Отпрати\",\n  \"confirmations.unfollow.message\": \"Да ли сте сигурни да желите да отпратите корисника {name}?\",\n  \"embed.instructions\": \"Угради овај статус на Ваш веб сајт копирањем кода испод.\",\n  \"embed.preview\": \"Овако ће да изгледа:\",\n  \"emoji_button.activity\": \"Активност\",\n  \"emoji_button.custom\": \"Произвољно\",\n  \"emoji_button.flags\": \"Заставе\",\n  \"emoji_button.food\": \"Храна и пиће\",\n  \"emoji_button.label\": \"Убаци емоџи\",\n  \"emoji_button.nature\": \"Природа\",\n  \"emoji_button.not_found\": \"Нема емоџија!! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"Објекти\",\n  \"emoji_button.people\": \"Људи\",\n  \"emoji_button.recent\": \"Најчешће коришћени\",\n  \"emoji_button.search\": \"Претрага...\",\n  \"emoji_button.search_results\": \"Резултати претраге\",\n  \"emoji_button.symbols\": \"Симболи\",\n  \"emoji_button.travel\": \"Путовања и места\",\n  \"empty_column.account_timeline\": \"No toots here!\",\n  \"empty_column.account_unavailable\": \"Profile unavailable\",\n  \"empty_column.blocks\": \"Још увек немате блокираних корисника.\",\n  \"empty_column.community\": \"Локална временска линија је празна. Напишите нешто јавно да започнете!\",\n  \"empty_column.direct\": \"Још увек немате директних порука. Када пошаљете или примите једну, појавиће се овде.\",\n  \"empty_column.domain_blocks\": \"Још увек нема сакривених домена.\",\n  \"empty_column.favourited_statuses\": \"Још увек немате труба које су вам се свиделе. Када вам се једна свиди, појавиће се овде.\",\n  \"empty_column.favourites\": \"Још увек се никоме није свидела ова труба. Када се некоме свиди, појавиће се овде.\",\n  \"empty_column.follow_requests\": \"Још увек немате захтева за праћење. Када примите захтев, појавиће се овде.\",\n  \"empty_column.hashtag\": \"Тренутно нема ништа на овој означеној тараби.\",\n  \"empty_column.home\": \"Ваша временска линија је празна! Посетите {public} или користите претрагу да почнете и да упознате нове људе.\",\n  \"empty_column.home.public_timeline\": \"јавна временска линија\",\n  \"empty_column.list\": \"У овој листи још нема ничега. Када чланови листе објаве нове статусе, они ће се појавити овде.\",\n  \"empty_column.lists\": \"Још увек немате ниједну листу. Када направите једну, појавиће се овде.\",\n  \"empty_column.mutes\": \"Још увек немате ућутканих корисника.\",\n  \"empty_column.notifications\": \"Тренутно немате обавештења. Дружите се мало да започнете разговор.\",\n  \"empty_column.public\": \"Овде нема ничега! Напишите нешто јавно, или нађите кориснике са других инстанци које ћете запратити да попуните ову празнину\",\n  \"follow_request.authorize\": \"Одобри\",\n  \"follow_request.reject\": \"Одбиј\",\n  \"getting_started.developers\": \"Програмери\",\n  \"getting_started.directory\": \"Profile directory\",\n  \"getting_started.documentation\": \"Документација\",\n  \"getting_started.heading\": \"Да почнете\",\n  \"getting_started.invite\": \"Позовите људе\",\n  \"getting_started.open_source_notice\": \"Мастoдон је софтвер отвореног кода. Можете му допринети или пријавити проблеме преко ГитХаба на {github}.\",\n  \"getting_started.security\": \"Безбедност\",\n  \"getting_started.terms\": \"Услови коришћења\",\n  \"hashtag.column_header.tag_mode.all\": \"and {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"or {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"without {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"No suggestions found\",\n  \"hashtag.column_settings.select.placeholder\": \"Enter hashtags…\",\n  \"hashtag.column_settings.tag_mode.all\": \"All of these\",\n  \"hashtag.column_settings.tag_mode.any\": \"Any of these\",\n  \"hashtag.column_settings.tag_mode.none\": \"None of these\",\n  \"hashtag.column_settings.tag_toggle\": \"Include additional tags in this column\",\n  \"home.column_settings.basic\": \"Основно\",\n  \"home.column_settings.show_reblogs\": \"Прикажи и подржавања\",\n  \"home.column_settings.show_replies\": \"Прикажи одговоре\",\n  \"intervals.full.days\": \"{number, plural, one {# day} other {# days}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# hour} other {# hours}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minute} other {# minutes}}\",\n  \"introduction.federation.action\": \"Next\",\n  \"introduction.federation.federated.headline\": \"Federated\",\n  \"introduction.federation.federated.text\": \"Public posts from other servers of the fediverse will appear in the federated timeline.\",\n  \"introduction.federation.home.headline\": \"Home\",\n  \"introduction.federation.home.text\": \"Posts from people you follow will appear in your home feed. You can follow anyone on any server!\",\n  \"introduction.federation.local.headline\": \"Local\",\n  \"introduction.federation.local.text\": \"Public posts from people on the same server as you will appear in the local timeline.\",\n  \"introduction.interactions.action\": \"Finish toot-orial!\",\n  \"introduction.interactions.favourite.headline\": \"Favourite\",\n  \"introduction.interactions.favourite.text\": \"You can save a toot for later, and let the author know that you liked it, by favouriting it.\",\n  \"introduction.interactions.reblog.headline\": \"Boost\",\n  \"introduction.interactions.reblog.text\": \"You can share other people's toots with your followers by boosting them.\",\n  \"introduction.interactions.reply.headline\": \"Reply\",\n  \"introduction.interactions.reply.text\": \"You can reply to other people's and your own toots, which will chain them together in a conversation.\",\n  \"introduction.welcome.action\": \"Let's go!\",\n  \"introduction.welcome.headline\": \"First steps\",\n  \"introduction.welcome.text\": \"Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.\",\n  \"keyboard_shortcuts.back\": \"да одете назад\",\n  \"keyboard_shortcuts.blocked\": \"да отворите листу блокираних корисника\",\n  \"keyboard_shortcuts.boost\": \"да подржите\",\n  \"keyboard_shortcuts.column\": \"да се пребаците на статус у једној од колона\",\n  \"keyboard_shortcuts.compose\": \"да се пребаците на писање новог тута\",\n  \"keyboard_shortcuts.description\": \"Опис\",\n  \"keyboard_shortcuts.direct\": \"да отворите колону за директне поруке\",\n  \"keyboard_shortcuts.down\": \"да се померите на доле у листи\",\n  \"keyboard_shortcuts.enter\": \"да отворите статус\",\n  \"keyboard_shortcuts.favourite\": \"да означите као омиљено\",\n  \"keyboard_shortcuts.favourites\": \"да отворите листу фаворита\",\n  \"keyboard_shortcuts.federated\": \"да отворите здружену временску линију\",\n  \"keyboard_shortcuts.heading\": \"Пречице на тастатури\",\n  \"keyboard_shortcuts.home\": \"да отворите временску линију почетне\",\n  \"keyboard_shortcuts.hotkey\": \"Пречица\",\n  \"keyboard_shortcuts.legend\": \"да прикажете овај подсетник\",\n  \"keyboard_shortcuts.local\": \"да отворите локалну временску линију\",\n  \"keyboard_shortcuts.mention\": \"да поменете аутора\",\n  \"keyboard_shortcuts.muted\": \"да отворите листу ућутканих корисника\",\n  \"keyboard_shortcuts.my_profile\": \"да отворите ваш профил\",\n  \"keyboard_shortcuts.notifications\": \"да отворите колону обавештења\",\n  \"keyboard_shortcuts.pinned\": \"да отворите листу закачених труба\",\n  \"keyboard_shortcuts.profile\": \"да отворите профил аутора\",\n  \"keyboard_shortcuts.reply\": \"да одговорите\",\n  \"keyboard_shortcuts.requests\": \"да отворите листу примљених захтева за праћење\",\n  \"keyboard_shortcuts.search\": \"да се пребаците на претрагу\",\n  \"keyboard_shortcuts.start\": \"да отворите колону \\\"почнимо\\\"\",\n  \"keyboard_shortcuts.toggle_hidden\": \"да прикажете/сакријте текст иза CW-а\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"to show/hide media\",\n  \"keyboard_shortcuts.toot\": \"да започнете скроз нову трубу\",\n  \"keyboard_shortcuts.unfocus\": \"да одфокусирате/не будете више на претрази/прављењу нове трубе\",\n  \"keyboard_shortcuts.up\": \"да се померите на горе у листи\",\n  \"lightbox.close\": \"Затвори\",\n  \"lightbox.next\": \"Следећи\",\n  \"lightbox.previous\": \"Претходни\",\n  \"lightbox.view_context\": \"View context\",\n  \"lists.account.add\": \"Додај на листу\",\n  \"lists.account.remove\": \"Уклони са листе\",\n  \"lists.delete\": \"Обриши листу\",\n  \"lists.edit\": \"Измени листу\",\n  \"lists.edit.submit\": \"Change title\",\n  \"lists.new.create\": \"Додај листу\",\n  \"lists.new.title_placeholder\": \"Наслов нове листе\",\n  \"lists.search\": \"Претражи међу људима које пратите\",\n  \"lists.subheading\": \"Ваше листе\",\n  \"loading_indicator.label\": \"Учитавам...\",\n  \"media_gallery.toggle_visible\": \"Укључи/искључи видљивост\",\n  \"missing_indicator.label\": \"Није пронађено\",\n  \"missing_indicator.sublabel\": \"Овај ресурс није пронађен\",\n  \"mute_modal.hide_notifications\": \"Сакриј обавештења од овог корисника?\",\n  \"navigation_bar.apps\": \"Мобилне апликације\",\n  \"navigation_bar.blocks\": \"Блокирани корисници\",\n  \"navigation_bar.community_timeline\": \"Локална временска линија\",\n  \"navigation_bar.compose\": \"Саставите нову трубу\",\n  \"navigation_bar.direct\": \"Директне поруке\",\n  \"navigation_bar.discover\": \"Откриј\",\n  \"navigation_bar.domain_blocks\": \"Сакривени домени\",\n  \"navigation_bar.edit_profile\": \"Измени профил\",\n  \"navigation_bar.favourites\": \"Омиљене\",\n  \"navigation_bar.filters\": \"Пригушене речи\",\n  \"navigation_bar.follow_requests\": \"Захтеви за праћење\",\n  \"navigation_bar.follows_and_followers\": \"Follows and followers\",\n  \"navigation_bar.info\": \"О овој инстанци\",\n  \"navigation_bar.keyboard_shortcuts\": \"Пречице на тастатури\",\n  \"navigation_bar.lists\": \"Листе\",\n  \"navigation_bar.logout\": \"Одјава\",\n  \"navigation_bar.mutes\": \"Ућуткани корисници\",\n  \"navigation_bar.personal\": \"Personal\",\n  \"navigation_bar.pins\": \"Прикачене трубе\",\n  \"navigation_bar.preferences\": \"Подешавања\",\n  \"navigation_bar.profile_directory\": \"Profile directory\",\n  \"navigation_bar.public_timeline\": \"Здружена временска линија\",\n  \"navigation_bar.security\": \"Безбедност\",\n  \"notification.favourite\": \"{name} је ставио/ла Ваш статус као омиљени\",\n  \"notification.follow\": \"{name} Вас је запратио/ла\",\n  \"notification.mention\": \"{name} Вас је поменуо/ла\",\n  \"notification.poll\": \"A poll you have voted in has ended\",\n  \"notification.reblog\": \"{name} је подржао/ла Ваш статус\",\n  \"notifications.clear\": \"Очисти обавештења\",\n  \"notifications.clear_confirmation\": \"Да ли сте сигурно да трајно желите да очистите Ваша обавештења?\",\n  \"notifications.column_settings.alert\": \"Обавештења на радној површини\",\n  \"notifications.column_settings.favourite\": \"Омиљени:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Display all categories\",\n  \"notifications.column_settings.filter_bar.category\": \"Quick filter bar\",\n  \"notifications.column_settings.filter_bar.show\": \"Show\",\n  \"notifications.column_settings.follow\": \"Нови пратиоци:\",\n  \"notifications.column_settings.mention\": \"Помињања:\",\n  \"notifications.column_settings.poll\": \"Poll results:\",\n  \"notifications.column_settings.push\": \"Гурај обавештења\",\n  \"notifications.column_settings.reblog\": \"Подршки:\",\n  \"notifications.column_settings.show\": \"Прикажи у колони\",\n  \"notifications.column_settings.sound\": \"Пуштај звук\",\n  \"notifications.filter.all\": \"All\",\n  \"notifications.filter.boosts\": \"Boosts\",\n  \"notifications.filter.favourites\": \"Favourites\",\n  \"notifications.filter.follows\": \"Follows\",\n  \"notifications.filter.mentions\": \"Mentions\",\n  \"notifications.filter.polls\": \"Poll results\",\n  \"notifications.group\": \"{count} обавештења\",\n  \"poll.closed\": \"Closed\",\n  \"poll.refresh\": \"Refresh\",\n  \"poll.total_votes\": \"{count, plural, one {# vote} other {# votes}}\",\n  \"poll.vote\": \"Vote\",\n  \"poll_button.add_poll\": \"Add a poll\",\n  \"poll_button.remove_poll\": \"Remove poll\",\n  \"privacy.change\": \"Подеси статус приватности\",\n  \"privacy.direct.long\": \"Објави само корисницима који су поменути\",\n  \"privacy.direct.short\": \"Директно\",\n  \"privacy.private.long\": \"Објави само пратиоцима\",\n  \"privacy.private.short\": \"Само за пратиоце\",\n  \"privacy.public.long\": \"Објави на јавној лајни\",\n  \"privacy.public.short\": \"Јавно\",\n  \"privacy.unlisted.long\": \"Не објављуј на јавним временским линијама\",\n  \"privacy.unlisted.short\": \"Неизлистано\",\n  \"regeneration_indicator.label\": \"Учитавање…\",\n  \"regeneration_indicator.sublabel\": \"Ваша почетна страница се припрема!\",\n  \"relative_time.days\": \"{number}d\",\n  \"relative_time.hours\": \"{number}h\",\n  \"relative_time.just_now\": \"сада\",\n  \"relative_time.minutes\": \"{number}m\",\n  \"relative_time.seconds\": \"{number}s\",\n  \"reply_indicator.cancel\": \"Поништи\",\n  \"report.forward\": \"Проследити {target}\",\n  \"report.forward_hint\": \"Налог је са другог сервера. Послати анонимну копију пријаве и тамо?\",\n  \"report.hint\": \"Пријава ће бити послата модераторима ваше инстанце. Можете додати објашњење зашто пријављујете овај налог у наставку:\",\n  \"report.placeholder\": \"Додатни коментари\",\n  \"report.submit\": \"Пошаљи\",\n  \"report.target\": \"Пријављујем {target}\",\n  \"search.placeholder\": \"Претрага\",\n  \"search_popout.search_format\": \"Напредни формат претраге\",\n  \"search_popout.tips.full_text\": \"Једноставан текст враћа статусе које сте написали, фаворизовали, подржали или били поменути, као и подударање корисничких имена, приказаних имена, и тараба.\",\n  \"search_popout.tips.hashtag\": \"хештег\",\n  \"search_popout.tips.status\": \"статус\",\n  \"search_popout.tips.text\": \"Тражењем обичног текста ћете добити сва пронађена имена, сва корисничка имена и све нађене хештегове\",\n  \"search_popout.tips.user\": \"корисник\",\n  \"search_results.accounts\": \"Људи\",\n  \"search_results.hashtags\": \"Тарабе\",\n  \"search_results.statuses\": \"Трубе\",\n  \"search_results.total\": \"{count, number} {count, plural, one {резултат} few {резултата} other {резултата}}\",\n  \"status.admin_account\": \"Open moderation interface for @{name}\",\n  \"status.admin_status\": \"Open this status in the moderation interface\",\n  \"status.block\": \"Блокирај @{name}\",\n  \"status.cancel_reblog_private\": \"Уклони подршку\",\n  \"status.cannot_reblog\": \"Овај статус не може да се подржи\",\n  \"status.copy\": \"Copy link to status\",\n  \"status.delete\": \"Обриши\",\n  \"status.detailed_status\": \"Детаљни преглед разговора\",\n  \"status.direct\": \"Директна порука @{name}\",\n  \"status.embed\": \"Угради на сајт\",\n  \"status.favourite\": \"Омиљено\",\n  \"status.filtered\": \"Филтрирано\",\n  \"status.load_more\": \"Учитај још\",\n  \"status.media_hidden\": \"Мултимедија сакривена\",\n  \"status.mention\": \"Помени корисника @{name}\",\n  \"status.more\": \"Још\",\n  \"status.mute\": \"Ућуткај @{name}\",\n  \"status.mute_conversation\": \"Ућуткај преписку\",\n  \"status.open\": \"Прошири овај статус\",\n  \"status.pin\": \"Закачи на профил\",\n  \"status.pinned\": \"Закачена труба\",\n  \"status.read_more\": \"Read more\",\n  \"status.reblog\": \"Подржи\",\n  \"status.reblog_private\": \"Подржи да види првобитна публика\",\n  \"status.reblogged_by\": \"{name} подржао/ла\",\n  \"status.reblogs.empty\": \"Још увек нико није подржао ову трубу. Када буде подржана, појавиће се овде.\",\n  \"status.redraft\": \"Избриши и преправи\",\n  \"status.reply\": \"Одговори\",\n  \"status.replyAll\": \"Одговори на дискусију\",\n  \"status.report\": \"Пријави корисника @{name}\",\n  \"status.sensitive_warning\": \"Осетљив садржај\",\n  \"status.share\": \"Подели\",\n  \"status.show_less\": \"Прикажи мање\",\n  \"status.show_less_all\": \"Прикажи мање за све\",\n  \"status.show_more\": \"Прикажи више\",\n  \"status.show_more_all\": \"Прикажи више за све\",\n  \"status.show_thread\": \"Show thread\",\n  \"status.unmute_conversation\": \"Укључи преписку\",\n  \"status.unpin\": \"Откачи са профила\",\n  \"suggestions.dismiss\": \"Dismiss suggestion\",\n  \"suggestions.header\": \"You might be interested in…\",\n  \"tabs_bar.federated_timeline\": \"Федерисано\",\n  \"tabs_bar.home\": \"Почетна\",\n  \"tabs_bar.local_timeline\": \"Локално\",\n  \"tabs_bar.notifications\": \"Обавештења\",\n  \"tabs_bar.search\": \"Претрага\",\n  \"time_remaining.days\": \"{number, plural, one {# day} other {# days}} left\",\n  \"time_remaining.hours\": \"{number, plural, one {# hour} other {# hours}} left\",\n  \"time_remaining.minutes\": \"{number, plural, one {# minute} other {# minutes}} left\",\n  \"time_remaining.moments\": \"Moments remaining\",\n  \"time_remaining.seconds\": \"{number, plural, one {# second} other {# seconds}} left\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {човек} other {људи}} прича\",\n  \"ui.beforeunload\": \"Ако напустите Мастодонт, изгубићете написани нацрт.\",\n  \"upload_area.title\": \"Превуците овде да отпремите\",\n  \"upload_button.label\": \"Додај мултимедију (JPEG, PNG, GIF, WebM, MP4, MOV)\",\n  \"upload_error.limit\": \"File upload limit exceeded.\",\n  \"upload_error.poll\": \"File upload not allowed with polls.\",\n  \"upload_form.description\": \"Опишите за особе са оштећеним видом\",\n  \"upload_form.focus\": \"Подесите\",\n  \"upload_form.undo\": \"Обриши\",\n  \"upload_progress.label\": \"Отпремам...\",\n  \"video.close\": \"Затвори видео\",\n  \"video.exit_fullscreen\": \"Напусти цео екран\",\n  \"video.expand\": \"Прошири видео\",\n  \"video.fullscreen\": \"Цео екран\",\n  \"video.hide\": \"Сакриј видео\",\n  \"video.mute\": \"Угаси звук\",\n  \"video.pause\": \"Паузирај\",\n  \"video.play\": \"Пусти\",\n  \"video.unmute\": \"Врати звук\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/sv.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Lägg till eller ta bort från listor\",\n  \"account.badges.bot\": \"Robot\",\n  \"account.block\": \"Blockera @{name}\",\n  \"account.block_domain\": \"Dölj allt från {domain}\",\n  \"account.blocked\": \"Blockerad\",\n  \"account.direct\": \"Direktmeddelande @{name}\",\n  \"account.domain_blocked\": \"Domän dold\",\n  \"account.edit_profile\": \"Redigera profil\",\n  \"account.endorse\": \"Feature on profile\",\n  \"account.follow\": \"Följ\",\n  \"account.followers\": \"Följare\",\n  \"account.followers.empty\": \"Ingen följer denna användaren än.\",\n  \"account.follows\": \"Följer\",\n  \"account.follows.empty\": \"This user doesn't follow anyone yet.\",\n  \"account.follows_you\": \"Följer dig\",\n  \"account.hide_reblogs\": \"Dölj knuffar från @{name}\",\n  \"account.link_verified_on\": \"Ownership of this link was checked on {date}\",\n  \"account.locked_info\": \"This account privacy status is set to locked. The owner manually reviews who can follow them.\",\n  \"account.media\": \"Media\",\n  \"account.mention\": \"Nämna @{name}\",\n  \"account.moved_to\": \"{name} har flyttat till:\",\n  \"account.mute\": \"Tysta @{name}\",\n  \"account.mute_notifications\": \"Stäng av notifieringar från @{name}\",\n  \"account.muted\": \"Nertystad\",\n  \"account.posts\": \"Inlägg\",\n  \"account.posts_with_replies\": \"Toots och svar\",\n  \"account.report\": \"Rapportera @{name}\",\n  \"account.requested\": \"Inväntar godkännande. Klicka för att avbryta följförfrågan\",\n  \"account.share\": \"Dela @{name}'s profil\",\n  \"account.show_reblogs\": \"Visa knuffar från @{name}\",\n  \"account.unblock\": \"Avblockera @{name}\",\n  \"account.unblock_domain\": \"Ta fram {domain}\",\n  \"account.unendorse\": \"Don't feature on profile\",\n  \"account.unfollow\": \"Sluta följa\",\n  \"account.unmute\": \"Ta bort tystad @{name}\",\n  \"account.unmute_notifications\": \"Återaktivera notifikationer från @{name}\",\n  \"alert.unexpected.message\": \"Ett oväntat fel uppstod.\",\n  \"alert.unexpected.title\": \"Whups!\",\n  \"boost_modal.combo\": \"Du kan trycka {combo} för att slippa denna nästa gång\",\n  \"bundle_column_error.body\": \"Något gick fel när du laddade denna komponent.\",\n  \"bundle_column_error.retry\": \"Försök igen\",\n  \"bundle_column_error.title\": \"Nätverksfel\",\n  \"bundle_modal_error.close\": \"Stäng\",\n  \"bundle_modal_error.message\": \"Något gick fel när du laddade denna komponent.\",\n  \"bundle_modal_error.retry\": \"Försök igen\",\n  \"column.blocks\": \"Blockerade användare\",\n  \"column.community\": \"Lokal tidslinje\",\n  \"column.direct\": \"Direktmeddelande\",\n  \"column.domain_blocks\": \"Dolda domäner\",\n  \"column.favourites\": \"Favoriter\",\n  \"column.follow_requests\": \"Följ förfrågningar\",\n  \"column.home\": \"Hem\",\n  \"column.lists\": \"Listor\",\n  \"column.mutes\": \"Tystade användare\",\n  \"column.notifications\": \"Meddelanden\",\n  \"column.pins\": \"Nålade toots\",\n  \"column.public\": \"Förenad tidslinje\",\n  \"column_back_button.label\": \"Tillbaka\",\n  \"column_header.hide_settings\": \"Dölj inställningar\",\n  \"column_header.moveLeft_settings\": \"Flytta kolumnen till vänster\",\n  \"column_header.moveRight_settings\": \"Flytta kolumnen till höger\",\n  \"column_header.pin\": \"Fäst\",\n  \"column_header.show_settings\": \"Visa inställningar\",\n  \"column_header.unpin\": \"Ångra fäst\",\n  \"column_subheading.settings\": \"Inställningar\",\n  \"community.column_settings.media_only\": \"Enbart media\",\n  \"compose_form.direct_message_warning\": \"Denna toot kommer endast att skickas nämnda nämnda användare.\",\n  \"compose_form.direct_message_warning_learn_more\": \"Visa mer\",\n  \"compose_form.hashtag_warning\": \"Denna toot kommer inte att listas under någon hashtag eftersom den är onoterad. Endast offentliga toots kan sökas med hashtag.\",\n  \"compose_form.lock_disclaimer\": \"Ditt konto är inte {locked}. Vemsomhelst kan följa dig och även se dina inlägg skrivna för endast dina följare.\",\n  \"compose_form.lock_disclaimer.lock\": \"låst\",\n  \"compose_form.placeholder\": \"Vad funderar du på?\",\n  \"compose_form.poll.add_option\": \"Add a choice\",\n  \"compose_form.poll.duration\": \"Poll duration\",\n  \"compose_form.poll.option_placeholder\": \"Choice {number}\",\n  \"compose_form.poll.remove_option\": \"Remove this choice\",\n  \"compose_form.publish\": \"Toot\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"Mark media as sensitive\",\n  \"compose_form.sensitive.marked\": \"Media har markerats som känsligt\",\n  \"compose_form.sensitive.unmarked\": \"Media har inte markerats som känsligt\",\n  \"compose_form.spoiler.marked\": \"Texten har dolts bakom en varning\",\n  \"compose_form.spoiler.unmarked\": \"Texten är inte dold\",\n  \"compose_form.spoiler_placeholder\": \"Skriv din varning här\",\n  \"confirmation_modal.cancel\": \"Ångra\",\n  \"confirmations.block.block_and_report\": \"Block & Report\",\n  \"confirmations.block.confirm\": \"Blockera\",\n  \"confirmations.block.message\": \"Är du säker att du vill blockera {name}?\",\n  \"confirmations.delete.confirm\": \"Ta bort\",\n  \"confirmations.delete.message\": \"Är du säker att du vill ta bort denna status?\",\n  \"confirmations.delete_list.confirm\": \"Delete\",\n  \"confirmations.delete_list.message\": \"Är du säker på att du vill radera denna lista permanent?\",\n  \"confirmations.domain_block.confirm\": \"Blockera hela domänen\",\n  \"confirmations.domain_block.message\": \"Är du verkligen säker på att du vill blockera hela {domain}? I de flesta fall är några riktade blockeringar eller nedtystade konton tillräckligt och att föredra. Du kommer sluta se innehåll från {domain}-domänen i den allmänna tidslinjen och i dina egna notifieringar. Du kommer även sluta följa alla eventuella följare du har från {domain}.\",\n  \"confirmations.mute.confirm\": \"Tysta\",\n  \"confirmations.mute.message\": \"Är du säker du vill tysta ner {name}?\",\n  \"confirmations.redraft.confirm\": \"Radera och gör om\",\n  \"confirmations.redraft.message\": \"Är du säker på att du vill radera meddelandet och göra om det? Du kommer förlora alla svar, knuffar och favoriter som hänvisar till meddelandet.\",\n  \"confirmations.reply.confirm\": \"Reply\",\n  \"confirmations.reply.message\": \"Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?\",\n  \"confirmations.unfollow.confirm\": \"Sluta följa\",\n  \"confirmations.unfollow.message\": \"Är du säker på att du vill sluta följa {name}?\",\n  \"embed.instructions\": \"Bädda in den här statusen på din webbplats genom att kopiera koden nedan.\",\n  \"embed.preview\": \"Här ser du hur det kommer att se ut:\",\n  \"emoji_button.activity\": \"Aktivitet\",\n  \"emoji_button.custom\": \"Specialgjord\",\n  \"emoji_button.flags\": \"Flaggor\",\n  \"emoji_button.food\": \"Mat & Dryck\",\n  \"emoji_button.label\": \"Lägg till emoji\",\n  \"emoji_button.nature\": \"Natur\",\n  \"emoji_button.not_found\": \"Inga emojos!! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"Objekt\",\n  \"emoji_button.people\": \"Människor\",\n  \"emoji_button.recent\": \"Ofta använda\",\n  \"emoji_button.search\": \"Sök...\",\n  \"emoji_button.search_results\": \"Sökresultat\",\n  \"emoji_button.symbols\": \"Symboler\",\n  \"emoji_button.travel\": \"Resor & Platser\",\n  \"empty_column.account_timeline\": \"No toots here!\",\n  \"empty_column.account_unavailable\": \"Profile unavailable\",\n  \"empty_column.blocks\": \"You haven't blocked any users yet.\",\n  \"empty_column.community\": \"Den lokala tidslinjen är tom. Skriv något offentligt för att få bollen att rulla!\",\n  \"empty_column.direct\": \"Du har inga direktmeddelanden än. När du skickar eller tar emot kommer den att dyka upp här.\",\n  \"empty_column.domain_blocks\": \"There are no hidden domains yet.\",\n  \"empty_column.favourited_statuses\": \"You don't have any favourite toots yet. When you favourite one, it will show up here.\",\n  \"empty_column.favourites\": \"No one has favourited this toot yet. When someone does, they will show up here.\",\n  \"empty_column.follow_requests\": \"You don't have any follow requests yet. When you receive one, it will show up here.\",\n  \"empty_column.hashtag\": \"Det finns inget i denna hashtag ännu.\",\n  \"empty_column.home\": \"Din hemma-tidslinje är tom! Besök {public} eller använd sökning för att komma igång och träffa andra användare.\",\n  \"empty_column.home.public_timeline\": \"den publika tidslinjen\",\n  \"empty_column.list\": \"Det finns inget i denna lista än. När medlemmar i denna lista lägger till nya statusar kommer de att visas här.\",\n  \"empty_column.lists\": \"You don't have any lists yet. When you create one, it will show up here.\",\n  \"empty_column.mutes\": \"You haven't muted any users yet.\",\n  \"empty_column.notifications\": \"Du har inga meddelanden än. Interagera med andra för att starta konversationen.\",\n  \"empty_column.public\": \"Det finns inget här! Skriv något offentligt, eller följ manuellt användarna från andra instanser för att fylla på det\",\n  \"follow_request.authorize\": \"Godkänn\",\n  \"follow_request.reject\": \"Avvisa\",\n  \"getting_started.developers\": \"Utvecklare\",\n  \"getting_started.directory\": \"Profile directory\",\n  \"getting_started.documentation\": \"Documentation\",\n  \"getting_started.heading\": \"Kom igång\",\n  \"getting_started.invite\": \"Skicka inbjudningar\",\n  \"getting_started.open_source_notice\": \"Mastodon är programvara med öppen källkod. Du kan bidra eller rapportera problem via GitHub på {github}.\",\n  \"getting_started.security\": \"Säkerhet\",\n  \"getting_started.terms\": \"Användarvillkor\",\n  \"hashtag.column_header.tag_mode.all\": \"and {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"or {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"without {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"No suggestions found\",\n  \"hashtag.column_settings.select.placeholder\": \"Enter hashtags…\",\n  \"hashtag.column_settings.tag_mode.all\": \"All of these\",\n  \"hashtag.column_settings.tag_mode.any\": \"Any of these\",\n  \"hashtag.column_settings.tag_mode.none\": \"Ingen av dessa\",\n  \"hashtag.column_settings.tag_toggle\": \"Include additional tags in this column\",\n  \"home.column_settings.basic\": \"Grundläggande\",\n  \"home.column_settings.show_reblogs\": \"Visa knuffar\",\n  \"home.column_settings.show_replies\": \"Visa svar\",\n  \"intervals.full.days\": \"{number, plural, one {# day} other {# days}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# hour} other {# hours}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minute} other {# minutes}}\",\n  \"introduction.federation.action\": \"Nästa\",\n  \"introduction.federation.federated.headline\": \"Federated\",\n  \"introduction.federation.federated.text\": \"Public posts from other servers of the fediverse will appear in the federated timeline.\",\n  \"introduction.federation.home.headline\": \"Home\",\n  \"introduction.federation.home.text\": \"Posts from people you follow will appear in your home feed. You can follow anyone on any server!\",\n  \"introduction.federation.local.headline\": \"Local\",\n  \"introduction.federation.local.text\": \"Public posts from people on the same server as you will appear in the local timeline.\",\n  \"introduction.interactions.action\": \"Finish toot-orial!\",\n  \"introduction.interactions.favourite.headline\": \"Favourite\",\n  \"introduction.interactions.favourite.text\": \"You can save a toot for later, and let the author know that you liked it, by favouriting it.\",\n  \"introduction.interactions.reblog.headline\": \"Boost\",\n  \"introduction.interactions.reblog.text\": \"You can share other people's toots with your followers by boosting them.\",\n  \"introduction.interactions.reply.headline\": \"Reply\",\n  \"introduction.interactions.reply.text\": \"You can reply to other people's and your own toots, which will chain them together in a conversation.\",\n  \"introduction.welcome.action\": \"Let's go!\",\n  \"introduction.welcome.headline\": \"First steps\",\n  \"introduction.welcome.text\": \"Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.\",\n  \"keyboard_shortcuts.back\": \"att navigera tillbaka\",\n  \"keyboard_shortcuts.blocked\": \"to open blocked users list\",\n  \"keyboard_shortcuts.boost\": \"att knuffa\",\n  \"keyboard_shortcuts.column\": \"att fokusera en status i en av kolumnerna\",\n  \"keyboard_shortcuts.compose\": \"att fokusera komponera text fältet\",\n  \"keyboard_shortcuts.description\": \"Description\",\n  \"keyboard_shortcuts.direct\": \"to open direct messages column\",\n  \"keyboard_shortcuts.down\": \"att flytta ner i listan\",\n  \"keyboard_shortcuts.enter\": \"to open status\",\n  \"keyboard_shortcuts.favourite\": \"att favorisera\",\n  \"keyboard_shortcuts.favourites\": \"to open favourites list\",\n  \"keyboard_shortcuts.federated\": \"to open federated timeline\",\n  \"keyboard_shortcuts.heading\": \"Keyboard Shortcuts\",\n  \"keyboard_shortcuts.home\": \"to open home timeline\",\n  \"keyboard_shortcuts.hotkey\": \"Snabbvalstangent\",\n  \"keyboard_shortcuts.legend\": \"att visa denna översikt\",\n  \"keyboard_shortcuts.local\": \"to open local timeline\",\n  \"keyboard_shortcuts.mention\": \"att nämna författaren\",\n  \"keyboard_shortcuts.muted\": \"to open muted users list\",\n  \"keyboard_shortcuts.my_profile\": \"to open your profile\",\n  \"keyboard_shortcuts.notifications\": \"to open notifications column\",\n  \"keyboard_shortcuts.pinned\": \"to open pinned toots list\",\n  \"keyboard_shortcuts.profile\": \"to open author's profile\",\n  \"keyboard_shortcuts.reply\": \"att svara\",\n  \"keyboard_shortcuts.requests\": \"to open follow requests list\",\n  \"keyboard_shortcuts.search\": \"att fokusera sökfältet\",\n  \"keyboard_shortcuts.start\": \"to open \\\"get started\\\" column\",\n  \"keyboard_shortcuts.toggle_hidden\": \"att visa/gömma text bakom CW\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"to show/hide media\",\n  \"keyboard_shortcuts.toot\": \"att börja en helt ny toot\",\n  \"keyboard_shortcuts.unfocus\": \"att avfokusera komponera text fält / sökfält\",\n  \"keyboard_shortcuts.up\": \"att flytta upp i listan\",\n  \"lightbox.close\": \"Stäng\",\n  \"lightbox.next\": \"Nästa\",\n  \"lightbox.previous\": \"Tidigare\",\n  \"lightbox.view_context\": \"View context\",\n  \"lists.account.add\": \"Lägg till i lista\",\n  \"lists.account.remove\": \"Ta bort från lista\",\n  \"lists.delete\": \"Radera lista\",\n  \"lists.edit\": \"Redigera lista\",\n  \"lists.edit.submit\": \"Ändra titel\",\n  \"lists.new.create\": \"Lägg till lista\",\n  \"lists.new.title_placeholder\": \"Ny listrubrik\",\n  \"lists.search\": \"Sök bland personer du följer\",\n  \"lists.subheading\": \"Dina listor\",\n  \"loading_indicator.label\": \"Laddar...\",\n  \"media_gallery.toggle_visible\": \"Växla synlighet\",\n  \"missing_indicator.label\": \"Hittades inte\",\n  \"missing_indicator.sublabel\": \"Den här resursen kunde inte hittas\",\n  \"mute_modal.hide_notifications\": \"Dölj notifikationer från denna användare?\",\n  \"navigation_bar.apps\": \"Mobilappar\",\n  \"navigation_bar.blocks\": \"Blockerade användare\",\n  \"navigation_bar.community_timeline\": \"Lokal tidslinje\",\n  \"navigation_bar.compose\": \"Compose new toot\",\n  \"navigation_bar.direct\": \"Direktmeddelanden\",\n  \"navigation_bar.discover\": \"Upptäck\",\n  \"navigation_bar.domain_blocks\": \"Dolda domäner\",\n  \"navigation_bar.edit_profile\": \"Redigera profil\",\n  \"navigation_bar.favourites\": \"Favoriter\",\n  \"navigation_bar.filters\": \"Muted words\",\n  \"navigation_bar.follow_requests\": \"Följförfrågningar\",\n  \"navigation_bar.follows_and_followers\": \"Follows and followers\",\n  \"navigation_bar.info\": \"Om denna instans\",\n  \"navigation_bar.keyboard_shortcuts\": \"Tangentbordsgenvägar\",\n  \"navigation_bar.lists\": \"Listor\",\n  \"navigation_bar.logout\": \"Logga ut\",\n  \"navigation_bar.mutes\": \"Tystade användare\",\n  \"navigation_bar.personal\": \"Personal\",\n  \"navigation_bar.pins\": \"Nålade inlägg (toots)\",\n  \"navigation_bar.preferences\": \"Inställningar\",\n  \"navigation_bar.profile_directory\": \"Profile directory\",\n  \"navigation_bar.public_timeline\": \"Förenad tidslinje\",\n  \"navigation_bar.security\": \"Säkerhet\",\n  \"notification.favourite\": \"{name} favoriserade din status\",\n  \"notification.follow\": \"{name} följer dig\",\n  \"notification.mention\": \"{name} nämnde dig\",\n  \"notification.poll\": \"A poll you have voted in has ended\",\n  \"notification.reblog\": \"{name} knuffade din status\",\n  \"notifications.clear\": \"Rensa meddelanden\",\n  \"notifications.clear_confirmation\": \"Är du säker på att du vill radera alla dina meddelanden permanent?\",\n  \"notifications.column_settings.alert\": \"Skrivbordsmeddelanden\",\n  \"notifications.column_settings.favourite\": \"Favoriter:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Display all categories\",\n  \"notifications.column_settings.filter_bar.category\": \"Quick filter bar\",\n  \"notifications.column_settings.filter_bar.show\": \"Show\",\n  \"notifications.column_settings.follow\": \"Nya följare:\",\n  \"notifications.column_settings.mention\": \"Omnämningar:\",\n  \"notifications.column_settings.poll\": \"Poll results:\",\n  \"notifications.column_settings.push\": \"Push meddelanden\",\n  \"notifications.column_settings.reblog\": \"Knuffar:\",\n  \"notifications.column_settings.show\": \"Visa i kolumnen\",\n  \"notifications.column_settings.sound\": \"Spela upp ljud\",\n  \"notifications.filter.all\": \"All\",\n  \"notifications.filter.boosts\": \"Boosts\",\n  \"notifications.filter.favourites\": \"Favoriter\",\n  \"notifications.filter.follows\": \"Follows\",\n  \"notifications.filter.mentions\": \"Mentions\",\n  \"notifications.filter.polls\": \"Poll results\",\n  \"notifications.group\": \"{count} aviseringar\",\n  \"poll.closed\": \"Closed\",\n  \"poll.refresh\": \"Ladda om\",\n  \"poll.total_votes\": \"{count, plural, one {# vote} other {# votes}}\",\n  \"poll.vote\": \"Rösta\",\n  \"poll_button.add_poll\": \"Add a poll\",\n  \"poll_button.remove_poll\": \"Remove poll\",\n  \"privacy.change\": \"Justera sekretess\",\n  \"privacy.direct.long\": \"Skicka endast till nämnda användare\",\n  \"privacy.direct.short\": \"Direkt\",\n  \"privacy.private.long\": \"Skicka endast till följare\",\n  \"privacy.private.short\": \"Endast följare\",\n  \"privacy.public.long\": \"Skicka till publik tidslinje\",\n  \"privacy.public.short\": \"Publik\",\n  \"privacy.unlisted.long\": \"Skicka inte till publik tidslinje\",\n  \"privacy.unlisted.short\": \"Olistad\",\n  \"regeneration_indicator.label\": \"Laddar…\",\n  \"regeneration_indicator.sublabel\": \"Ditt hemmaflöde förbereds!\",\n  \"relative_time.days\": \"{number}d\",\n  \"relative_time.hours\": \"{number}h\",\n  \"relative_time.just_now\": \"nu\",\n  \"relative_time.minutes\": \"{number}m\",\n  \"relative_time.seconds\": \"{number}s\",\n  \"reply_indicator.cancel\": \"Ångra\",\n  \"report.forward\": \"Vidarebefordra till {target}\",\n  \"report.forward_hint\": \"Kontot är från en annan server. Skicka även en anonymiserad kopia av anmälan dit?\",\n  \"report.hint\": \"Anmälan skickas till din instans moderatorer. Du kan ge en förklaring till varför du har anmält detta konto nedan:\",\n  \"report.placeholder\": \"Ytterligare kommentarer\",\n  \"report.submit\": \"Skicka\",\n  \"report.target\": \"Rapporterar {target}\",\n  \"search.placeholder\": \"Sök\",\n  \"search_popout.search_format\": \"Avancerat sökformat\",\n  \"search_popout.tips.full_text\": \"Enkel text returnerar statusar där du har skrivit, favoriserat, knuffat eller nämnts samt med matchande användarnamn, visningsnamn och hashtags.\",\n  \"search_popout.tips.hashtag\": \"hashtag\",\n  \"search_popout.tips.status\": \"status\",\n  \"search_popout.tips.text\": \"Enkel text returnerar matchande visningsnamn, användarnamn och hashtags\",\n  \"search_popout.tips.user\": \"användare\",\n  \"search_results.accounts\": \"Människor\",\n  \"search_results.hashtags\": \"Hashtags\",\n  \"search_results.statuses\": \"Toots\",\n  \"search_results.total\": \"{count, number} {count, plural, ett {result} andra {results}}\",\n  \"status.admin_account\": \"Open moderation interface for @{name}\",\n  \"status.admin_status\": \"Open this status in the moderation interface\",\n  \"status.block\": \"Block @{name}\",\n  \"status.cancel_reblog_private\": \"Ta bort knuff\",\n  \"status.cannot_reblog\": \"Detta inlägg kan inte knuffas\",\n  \"status.copy\": \"Copy link to status\",\n  \"status.delete\": \"Ta bort\",\n  \"status.detailed_status\": \"Detailed conversation view\",\n  \"status.direct\": \"Direktmeddela @{name}\",\n  \"status.embed\": \"Bädda in\",\n  \"status.favourite\": \"Favorit\",\n  \"status.filtered\": \"Filtered\",\n  \"status.load_more\": \"Ladda fler\",\n  \"status.media_hidden\": \"Media dold\",\n  \"status.mention\": \"Omnämn @{name}\",\n  \"status.more\": \"Mer\",\n  \"status.mute\": \"Tysta @{name}\",\n  \"status.mute_conversation\": \"Tysta konversation\",\n  \"status.open\": \"Utvidga denna status\",\n  \"status.pin\": \"Fäst i profil\",\n  \"status.pinned\": \"Fäst toot\",\n  \"status.read_more\": \"Läs mer\",\n  \"status.reblog\": \"Knuff\",\n  \"status.reblog_private\": \"Knuffa till de ursprungliga åhörarna\",\n  \"status.reblogged_by\": \"{name} knuffade\",\n  \"status.reblogs.empty\": \"No one has boosted this toot yet. When someone does, they will show up here.\",\n  \"status.redraft\": \"Radera & gör om\",\n  \"status.reply\": \"Svara\",\n  \"status.replyAll\": \"Svara på tråden\",\n  \"status.report\": \"Rapportera @{name}\",\n  \"status.sensitive_warning\": \"Känsligt innehåll\",\n  \"status.share\": \"Dela\",\n  \"status.show_less\": \"Visa mindre\",\n  \"status.show_less_all\": \"Visa mindre för alla\",\n  \"status.show_more\": \"Visa mer\",\n  \"status.show_more_all\": \"Visa mer för alla\",\n  \"status.show_thread\": \"Visa tråd\",\n  \"status.unmute_conversation\": \"Öppna konversation\",\n  \"status.unpin\": \"Ångra fäst i profil\",\n  \"suggestions.dismiss\": \"Dismiss suggestion\",\n  \"suggestions.header\": \"You might be interested in…\",\n  \"tabs_bar.federated_timeline\": \"Förenad\",\n  \"tabs_bar.home\": \"Hem\",\n  \"tabs_bar.local_timeline\": \"Lokal\",\n  \"tabs_bar.notifications\": \"Meddelanden\",\n  \"tabs_bar.search\": \"Sök\",\n  \"time_remaining.days\": \"{number, plural, one {# day} other {# days}} left\",\n  \"time_remaining.hours\": \"{number, plural, one {# hour} other {# hours}} left\",\n  \"time_remaining.minutes\": \"{number, plural, one {# minute} other {# minutes}} left\",\n  \"time_remaining.moments\": \"Moments remaining\",\n  \"time_remaining.seconds\": \"{number, plural, one {# second} other {# seconds}} left\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, en {person} andra {people}} pratar\",\n  \"ui.beforeunload\": \"Ditt utkast kommer att förloras om du lämnar Mastodon.\",\n  \"upload_area.title\": \"Dra & släpp för att ladda upp\",\n  \"upload_button.label\": \"Lägg till media\",\n  \"upload_error.limit\": \"File upload limit exceeded.\",\n  \"upload_error.poll\": \"File upload not allowed with polls.\",\n  \"upload_form.description\": \"Beskriv för synskadade\",\n  \"upload_form.focus\": \"Beskär\",\n  \"upload_form.undo\": \"Ta bort\",\n  \"upload_progress.label\": \"Laddar upp...\",\n  \"video.close\": \"Stäng video\",\n  \"video.exit_fullscreen\": \"Stäng helskärm\",\n  \"video.expand\": \"Expandera video\",\n  \"video.fullscreen\": \"Helskärm\",\n  \"video.hide\": \"Dölj video\",\n  \"video.mute\": \"Stäng av ljud\",\n  \"video.pause\": \"Pause\",\n  \"video.play\": \"Spela upp\",\n  \"video.unmute\": \"Spela upp ljud\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/ta.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"பட்டியல்களில் இருந்து சேர் அல்லது நீக்குக\",\n  \"account.badges.bot\": \"பாட்\",\n  \"account.block\": \"Block @{name}\",\n  \"account.block_domain\": \"எல்லாவற்றையும் மறைக்க {domain}\",\n  \"account.blocked\": \"தடைமுட்டுகள்\",\n  \"account.direct\": \"நேரடி செய்தி @{name}\",\n  \"account.domain_blocked\": \"டொமைன் மறைக்கப்பட்டது\",\n  \"account.edit_profile\": \"சுயவிவரத்தைத் திருத்தவும்\",\n  \"account.endorse\": \"சுயவிவரத்தில் அம்சம்\",\n  \"account.follow\": \"பின்பற்று\",\n  \"account.followers\": \"பின்பற்றுபவர்கள்\",\n  \"account.followers.empty\": \"இதுவரை யாரும் இந்த பயனரைப் பின்தொடரவில்லை.\",\n  \"account.follows\": \"பின்பற்று\",\n  \"account.follows.empty\": \"இந்த பயனர் இதுவரை யாரையும் பின்தொடரவில்லை.\",\n  \"account.follows_you\": \"நீ பின் தொடர்கிறாய்\",\n  \"account.hide_reblogs\": \"இருந்து ஊக்கியாக மறை @{name}\",\n  \"account.link_verified_on\": \"இந்த இணைப்பை உரிமையாளர் சரிபார்க்கப்பட்டது {date}\",\n  \"account.locked_info\": \"இந்தக் கணக்கு தனியுரிமை நிலை பூட்டப்பட்டுள்ளது. அவர்களைப் பின்தொடர்பவர் யார் என்பதை உரிமையாளர் கைமுறையாக மதிப்பாய்வு செய்கிறார்.\",\n  \"account.media\": \"Media\",\n  \"account.mention\": \"குறிப்பிடு @{name}\",\n  \"account.moved_to\": \"{name} நகர்த்தப்பட்டது:\",\n  \"account.mute\": \"ஊமையான @{name}\",\n  \"account.mute_notifications\": \"அறிவிப்புகளை முடக்கு @{name}\",\n  \"account.muted\": \"முடக்கியது\",\n  \"account.posts\": \"Toots\",\n  \"account.posts_with_replies\": \"Toots மற்றும் பதில்கள்\",\n  \"account.report\": \"Report @{name}\",\n  \"account.requested\": \"ஒப்புதலுக்காக காத்திருக்கிறது. கோரிக்கையை ரத்துசெய்ய கிளிக் செய்க\",\n  \"account.share\": \"பங்கிடு @{name}'s மனித முகத்தின்\",\n  \"account.show_reblogs\": \"காட்டு boosts இருந்து @{name}\",\n  \"account.unblock\": \"விடுவி @{name}\",\n  \"account.unblock_domain\": \"காண்பி {domain}\",\n  \"account.unendorse\": \"சுயவிவரத்தில் அம்சம் இல்லை\",\n  \"account.unfollow\": \"பின்தொடராட்\",\n  \"account.unmute\": \"தடுப்புநீக்கு @{name}\",\n  \"account.unmute_notifications\": \"அறிவிப்புகளை அகற்றவும் @{name}\",\n  \"alert.unexpected.message\": \"எதிர் பாராத பிழை ஏற்பட்டு விட்டது.\",\n  \"alert.unexpected.title\": \"அச்சச்சோ!\",\n  \"boost_modal.combo\": \"நீங்கள் அழுத்தவும் {combo} அடுத்த முறை தவிர்க்கவும்\",\n  \"bundle_column_error.body\": \"இந்த கூறுகளை ஏற்றும்போது ஏதோ தவறு ஏற்பட்டது.\",\n  \"bundle_column_error.retry\": \"மீண்டும் முயற்சி செய்\",\n  \"bundle_column_error.title\": \"Network error\",\n  \"bundle_modal_error.close\": \"நெருக்கமாக\",\n  \"bundle_modal_error.message\": \"இந்த கூறுகளை ஏற்றும்போது ஏதோ தவறு ஏற்பட்டது.\",\n  \"bundle_modal_error.retry\": \"மீண்டும் முயற்சி செய்\",\n  \"column.blocks\": \"தடுக்கப்பட்ட பயனர்கள்\",\n  \"column.community\": \"உள்ளூர் காலக்கெடு\",\n  \"column.direct\": \"நேரடி செய்திகள்\",\n  \"column.domain_blocks\": \"மறைந்த களங்கள்\",\n  \"column.favourites\": \"விருப்பத்துக்குகந்த\",\n  \"column.follow_requests\": \"கோரிக்கைகளை பின்பற்றவும்\",\n  \"column.home\": \"Home\",\n  \"column.lists\": \"குதிரை வீர்ர்கள்\",\n  \"column.mutes\": \"முடக்கப்பட்ட பயனர்கள்\",\n  \"column.notifications\": \"Notifications\",\n  \"column.pins\": \"Pinned toot\",\n  \"column.public\": \"கூட்டாட்சி காலக்கெடு\",\n  \"column_back_button.label\": \"ஆதரி\",\n  \"column_header.hide_settings\": \"அமைப்புகளை மறை\",\n  \"column_header.moveLeft_settings\": \"நெடுவரிசையை இடதுபுறமாக நகர்த்தவும்\",\n  \"column_header.moveRight_settings\": \"நெடுவரிசை வலது புறமாக நகர்த்து\",\n  \"column_header.pin\": \"குண்டூசி\",\n  \"column_header.show_settings\": \"அமைப்புகளைக் காட்டு\",\n  \"column_header.unpin\": \"பொருத்தப்படாத\",\n  \"column_subheading.settings\": \"அமைப்புகள்\",\n  \"community.column_settings.media_only\": \"மீடியா மட்டுமே\",\n  \"compose_form.direct_message_warning\": \"This toot will only be sent to all the mentioned users.\",\n  \"compose_form.direct_message_warning_learn_more\": \"மேலும் அறிக\",\n  \"compose_form.hashtag_warning\": \"இந்த toot பட்டியலிடப்படாதது போல எந்த ஹேஸ்டேக்கின் கீழ் பட்டியலிடப்படாது. ஹேஸ்டேக் மூலம் பொது டோட்டல்கள் மட்டுமே தேட முடியும்.\",\n  \"compose_form.lock_disclaimer\": \"உங்கள் கணக்கு அல்ல {locked}. உங்களுடைய பின்தொடர்பவர் மட்டும் இடுகைகளை யாராவது காணலாம்.\",\n  \"compose_form.lock_disclaimer.lock\": \"தாழிடு\",\n  \"compose_form.placeholder\": \"What is on your mind?\",\n  \"compose_form.poll.add_option\": \"ஒரு விருப்பத்தைச் சேர்க்கவும்\",\n  \"compose_form.poll.duration\": \"வாக்கெடுப்பு காலம்\",\n  \"compose_form.poll.option_placeholder\": \"தேர்ந்தெடுப்ப {number}\",\n  \"compose_form.poll.remove_option\": \"இந்த விருப்பத்தை அகற்றவும்\",\n  \"compose_form.publish\": \"Toot\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"Mark media as sensitive\",\n  \"compose_form.sensitive.marked\": \"ஊடகம் உணர்திறன் என குறிக்கப்பட்டுள்ளது\",\n  \"compose_form.sensitive.unmarked\": \"ஊடகம் உணர்திறன் என குறிக்கப்படவில்லை\",\n  \"compose_form.spoiler.marked\": \"எச்சரிக்கை பின்னால் உரை மறைக்கப்பட்டுள்ளது\",\n  \"compose_form.spoiler.unmarked\": \"உரை மறைக்கப்படவில்லை\",\n  \"compose_form.spoiler_placeholder\": \"இங்கே உங்கள் எச்சரிக்கையை எழுதுங்கள்\",\n  \"confirmation_modal.cancel\": \"எதிராணை\",\n  \"confirmations.block.block_and_report\": \"Block & Report\",\n  \"confirmations.block.confirm\": \"Block\",\n  \"confirmations.block.message\": \"நீங்கள் நிச்சயமாக தடைசெய்ய விரும்புகிறீர்களா {name}?\",\n  \"confirmations.delete.confirm\": \"Delete\",\n  \"confirmations.delete.message\": \"இந்த நிலையை நிச்சயமாக நீக்க விரும்புகிறீர்களா?\",\n  \"confirmations.delete_list.confirm\": \"Delete\",\n  \"confirmations.delete_list.message\": \"இந்த பட்டியலில் நிரந்தரமாக நீக்க விரும்புகிறீர்களா?\",\n  \"confirmations.domain_block.confirm\": \"முழு டொமைனை மறை\",\n  \"confirmations.domain_block.message\": \"நீங்கள் உண்மையில், நிச்சயமாக நீங்கள் முழு தடுக்க வேண்டும் நிச்சயமாக {domain}? பெரும்பாலான சந்தர்ப்பங்களில் ஒரு சில இலக்குகள் அல்லது மியூட்கள் போதுமானவை மற்றும் சிறந்தவை. எந்த பொது நேரத்திலும் அல்லது உங்கள் அறிவிப்புகளிலும் அந்தக் களத்திலிருந்து உள்ளடக்கத்தை நீங்கள் பார்க்க மாட்டீர்கள். அந்த களத்தில் இருந்து உங்கள் ஆதரவாளர்கள் அகற்றப்படுவார்கள்.\",\n  \"confirmations.mute.confirm\": \"ஊமையான\",\n  \"confirmations.mute.message\": \"நிச்சயமாக நீங்கள் முடக்க விரும்புகிறீர்களா {name}?\",\n  \"confirmations.redraft.confirm\": \"நீக்கு & redraft\",\n  \"confirmations.redraft.message\": \"நிச்சயமாக இந்த நிலையை நீக்கி, அதை மறுபடியும் உருவாக்க வேண்டுமா? பிடித்தவை மற்றும் ஊக்கங்கள் இழக்கப்படும், மற்றும் அசல் இடுகையில் பதில்கள் அனாதையான இருக்கும்.\",\n  \"confirmations.reply.confirm\": \"பதில்\",\n  \"confirmations.reply.message\": \"இப்போது பதில், தற்போது நீங்கள் உருவாக்கும் செய்தி மேலெழுதப்படும். நீங்கள் தொடர விரும்புகிறீர்களா?\",\n  \"confirmations.unfollow.confirm\": \"பின்தொடராட்\",\n  \"confirmations.unfollow.message\": \"நிச்சயமாக நீங்கள் பின்தொடர விரும்புகிறீர்களா {name}?\",\n  \"embed.instructions\": \"கீழே உள்ள குறியீட்டை நகலெடுப்பதன் மூலம் உங்கள் இணையதளத்தில் இந்த நிலையை உட்பொதிக்கவும்.\",\n  \"embed.preview\": \"இது போன்ற தோற்றத்தை இங்கு காணலாம்:\",\n  \"emoji_button.activity\": \"நடவடிக்கை\",\n  \"emoji_button.custom\": \"வழக்கம்\",\n  \"emoji_button.flags\": \"கொடி\",\n  \"emoji_button.food\": \"உணவு மற்றும் பானம்\",\n  \"emoji_button.label\": \"Insert emoji\",\n  \"emoji_button.nature\": \"இயற்கை\",\n  \"emoji_button.not_found\": \"எமோஜோஸ் இல்லை! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"மறுப்ப கூறு\",\n  \"emoji_button.people\": \"People\",\n  \"emoji_button.recent\": \"அடிக்கடி பயன்படுத்தப்படும்\",\n  \"emoji_button.search\": \"தேடல்...\",\n  \"emoji_button.search_results\": \"தேடல் முடிவுகள்\",\n  \"emoji_button.symbols\": \"Symbols\",\n  \"emoji_button.travel\": \"சுற்றுலா மற்றும் இடங்கள்\",\n  \"empty_column.account_timeline\": \"இல்லை toots இங்கே!\",\n  \"empty_column.account_unavailable\": \"சுயவிவரம் கிடைக்கவில்லை\",\n  \"empty_column.blocks\": \"இதுவரை எந்த பயனர்களும் தடுக்கவில்லை.\",\n  \"empty_column.community\": \"உள்ளூர் காலக்கெடு காலியாக உள்ளது. பந்தை உருட்டிக்கொள்வதற்கு பகிரங்கமாக ஒன்றை எழுதுங்கள்!\",\n  \"empty_column.direct\": \"உங்களிடம் நேரடியான செய்திகள் எதுவும் இல்லை. நீங்கள் ஒன்றை அனுப்பி அல்லது பெறும் போது, அது இங்கே காண்பிக்கும்.\",\n  \"empty_column.domain_blocks\": \"இன்னும் மறைந்த களங்கள் இல்லை.\",\n  \"empty_column.favourited_statuses\": \"இதுவரை உங்களுக்கு பிடித்த டோட்டுகள் இல்லை. உங்களுக்கு பிடித்த ஒரு போது, அது இங்கே காண்பிக்கும்.\",\n  \"empty_column.favourites\": \"இதுவரை யாரும் இந்தத் தட்டுக்கு ஆதரவில்லை. யாராவது செய்தால், அவர்கள் இங்கே காண்பார்கள்.\",\n  \"empty_column.follow_requests\": \"உங்களுக்கு இன்னும் எந்தவொரு கோரிக்கைகளும் இல்லை. நீங்கள் ஒன்றைப் பெற்றுக்கொண்டால், அது இங்கே காண்பிக்கும்.\",\n  \"empty_column.hashtag\": \"இன்னும் இந்த ஹேஸ்டேக்கில் எதுவும் இல்லை.\",\n  \"empty_column.home\": \"உங்கள் வீட்டுக் காலம் காலியாக உள்ளது! வருகை {public} அல்லது தொடங்குவதற்கு தேடலைப் பயன்படுத்தலாம் மற்றும் பிற பயனர்களை சந்திக்கவும்.\",\n  \"empty_column.home.public_timeline\": \"பொது காலக்கெடு\",\n  \"empty_column.list\": \"இந்த பட்டியலில் இதுவரை எதுவும் இல்லை. இந்த பட்டியலின் உறுப்பினர்கள் புதிய நிலைகளை இடுகையிடுகையில், அவை இங்கே தோன்றும்.\",\n  \"empty_column.lists\": \"உங்களுக்கு இதுவரை எந்த பட்டியலும் இல்லை. நீங்கள் ஒன்றை உருவாக்கினால், அது இங்கே காண்பிக்கும்.\",\n  \"empty_column.mutes\": \"நீங்கள் இதுவரை எந்த பயனர்களையும் முடக்கியிருக்கவில்லை.\",\n  \"empty_column.notifications\": \"உங்களிடம் எந்த அறிவிப்புகளும் இல்லை. உரையாடலைத் தொடங்க பிறருடன் தொடர்புகொள்ளவும்.\",\n  \"empty_column.public\": \"இங்கே எதுவும் இல்லை! பகிரங்கமாக ஒன்றை எழுதவும் அல்லது மற்ற நிகழ்வுகளிலிருந்து பயனர்களை அதை நிரப்புவதற்கு கைமுறையாக பின்பற்றவும்\",\n  \"follow_request.authorize\": \"அதிகாரமளி\",\n  \"follow_request.reject\": \"விலக்கு\",\n  \"getting_started.developers\": \"உருவாக்குநர்கள்\",\n  \"getting_started.directory\": \"சுயவிவர அடைவு\",\n  \"getting_started.documentation\": \"Documentation\",\n  \"getting_started.heading\": \"தொடங்குதல்\",\n  \"getting_started.invite\": \"நபர்களை அழைக்கவும்\",\n  \"getting_started.open_source_notice\": \"Mastodon திறந்த மூல மென்பொருள். GitHub இல் நீங்கள் பங்களிக்கவோ அல்லது புகார் அளிக்கவோ முடியும் {github}.\",\n  \"getting_started.security\": \"பத்திரம்\",\n  \"getting_started.terms\": \"சேவை விதிமுறைகள்\",\n  \"hashtag.column_header.tag_mode.all\": \"மற்றும் {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"அல்லது {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"இல்லாமல் {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"பரிந்துரைகள் எதுவும் இல்லை\",\n  \"hashtag.column_settings.select.placeholder\": \"ஹாஷ்டேகுகளை உள்ளிடவும் …\",\n  \"hashtag.column_settings.tag_mode.all\": \"இவை அனைத்தும்\",\n  \"hashtag.column_settings.tag_mode.any\": \"இவை எதையும்\",\n  \"hashtag.column_settings.tag_mode.none\": \"இவற்றில் ஏதுமில்லை\",\n  \"hashtag.column_settings.tag_toggle\": \"இந்த நெடுவரிசையில் கூடுதல் குறிச்சொற்களை சேர்க்கவும்\",\n  \"home.column_settings.basic\": \"அடிப்படையான\",\n  \"home.column_settings.show_reblogs\": \"காட்டு boosts\",\n  \"home.column_settings.show_replies\": \"பதில்களைக் காண்பி\",\n  \"intervals.full.days\": \"{number, plural, one {# day} மற்ற {# days}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# hour} மற்ற {# hours}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minute} மற்ற {# minutes}}\",\n  \"introduction.federation.action\": \"அடுத்த\",\n  \"introduction.federation.federated.headline\": \"Federated\",\n  \"introduction.federation.federated.text\": \"கூட்டமைப்பின் பிற சேவையகங்களிலிருந்து பொது பதிவுகள் கூட்டப்பட்ட காலக்கெடுவில் தோன்றும்.\",\n  \"introduction.federation.home.headline\": \"Home\",\n  \"introduction.federation.home.text\": \"நீங்கள் பின்பற்றும் நபர்களின் இடுகைகள் உங்கள் வீட்டு ஊட்டத்தில் தோன்றும். நீங்கள் எந்த சர்வரில் யாரையும் பின்பற்ற முடியும்!\",\n  \"introduction.federation.local.headline\": \"Local\",\n  \"introduction.federation.local.text\": \"உள்ளூர் சேவையகத்தில் தோன்றும் அதே சர்வரில் உள்ளவர்களின் பொது இடுகைகள்.\",\n  \"introduction.interactions.action\": \"பயிற்சி முடிக்க!\",\n  \"introduction.interactions.favourite.headline\": \"விருப்பத்துக்குகந்த\",\n  \"introduction.interactions.favourite.text\": \"நீங்கள் ஒரு காப்பாற்ற முடியும் toot பின்னர், மற்றும் ஆசிரியர் அதை நீங்கள் பிடித்திருக்கிறது என்று, அதை பிடித்திருக்கிறது என்று தெரியப்படுத்துங்கள்.\",\n  \"introduction.interactions.reblog.headline\": \"மதிப்பை உயர்த்து\",\n  \"introduction.interactions.reblog.text\": \"மற்றவர்களின் பகிர்ந்து கொள்ளலாம் toots உங்கள் ஆதரவாளர்களுடன் அவர்களை அதிகரிக்கும்.\",\n  \"introduction.interactions.reply.headline\": \"மறுமொழி கூறு\",\n  \"introduction.interactions.reply.text\": \"நீங்கள் மற்றவர்களுக்கும் உங்கள் சொந்த டோட்ட்களிற்கும் பதிலளிப்பீர்கள், இது ஒரு உரையாடலில் சங்கிலி ஒன்றாகச் சேரும்.\",\n  \"introduction.welcome.action\": \"போகலாம்!\",\n  \"introduction.welcome.headline\": \"முதல் படிகள்\",\n  \"introduction.welcome.text\": \"கூட்டாளிக்கு வருக! ஒரு சில நிமிடங்களில், பலவிதமான சேவையகங்களில் செய்திகளை உரையாட மற்றும் உங்கள் நண்பர்களிடம் பேச முடியும். ஆனால் இந்த சர்வர், {domain}, சிறப்பு - இது உங்கள் சுயவிவரத்தை வழங்குகிறது, எனவே அதன் பெயரை நினைவில் கொள்ளுங்கள்.\",\n  \"keyboard_shortcuts.back\": \"மீண்டும் செல்லவும்\",\n  \"keyboard_shortcuts.blocked\": \"தடுக்கப்பட்ட பயனர்களின் பட்டியலைத் திறக்க\",\n  \"keyboard_shortcuts.boost\": \"அதிகரிக்கும்\",\n  \"keyboard_shortcuts.column\": \"நெடுவரிசைகளில் ஒன்றில் நிலைக்கு கவனம் செலுத்த வேண்டும்\",\n  \"keyboard_shortcuts.compose\": \"தொகு உரைப்பகுதியை கவனத்தில் கொள்ளவும்\",\n  \"keyboard_shortcuts.description\": \"Description\",\n  \"keyboard_shortcuts.direct\": \"நேரடி செய்திகள் பத்தி திறக்க\",\n  \"keyboard_shortcuts.down\": \"பட்டியலில் கீழே நகர்த்த\",\n  \"keyboard_shortcuts.enter\": \"to open status\",\n  \"keyboard_shortcuts.favourite\": \"பிடித்தது\",\n  \"keyboard_shortcuts.favourites\": \"பிடித்தவை பட்டியலை திறக்க\",\n  \"keyboard_shortcuts.federated\": \"ஒருங்கிணைந்த நேரத்தை திறக்க\",\n  \"keyboard_shortcuts.heading\": \"Keyboard Shortcuts\",\n  \"keyboard_shortcuts.home\": \"வீட்டு நேரத்தை திறக்க\",\n  \"keyboard_shortcuts.hotkey\": \"ஹாட் கீ\",\n  \"keyboard_shortcuts.legend\": \"இந்த புராணத்தை காட்சிப்படுத்த\",\n  \"keyboard_shortcuts.local\": \"உள்ளூர் காலவரிசை திறக்க\",\n  \"keyboard_shortcuts.mention\": \"எழுத்தாளர் குறிப்பிட வேண்டும்\",\n  \"keyboard_shortcuts.muted\": \"முடக்கப்பட்ட பயனர்களின் பட்டியலைத் திறக்க\",\n  \"keyboard_shortcuts.my_profile\": \"உங்கள் சுயவிவரத்தை திறக்க\",\n  \"keyboard_shortcuts.notifications\": \"அறிவிப்பு நெடுவரிசையைத் திறக்க\",\n  \"keyboard_shortcuts.pinned\": \"திறக்க பொருத்தப்பட்டன toots பட்டியல்\",\n  \"keyboard_shortcuts.profile\": \"ஆசிரியரின் சுயவிவரத்தைத் திறக்க\",\n  \"keyboard_shortcuts.reply\": \"பதிலளிக்க\",\n  \"keyboard_shortcuts.requests\": \"கோரிக்கைகள் பட்டியலைத் திறக்க\",\n  \"keyboard_shortcuts.search\": \"தேடல் கவனம் செலுத்த\",\n  \"keyboard_shortcuts.start\": \"'தொடங்குவதற்கு' நெடுவரிசை திறக்க\",\n  \"keyboard_shortcuts.toggle_hidden\": \"CW க்கு பின்னால் உரையை மறைக்க / மறைக்க\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"to show/hide media\",\n  \"keyboard_shortcuts.toot\": \"தொடங்க ஒரு புதிய toot\",\n  \"keyboard_shortcuts.unfocus\": \"உரை பகுதியை / தேடலை கவனம் செலுத்த வேண்டும்\",\n  \"keyboard_shortcuts.up\": \"பட்டியலில் மேலே செல்ல\",\n  \"lightbox.close\": \"நெருக்கமாக\",\n  \"lightbox.next\": \"அடுத்த\",\n  \"lightbox.previous\": \"சென்ற\",\n  \"lightbox.view_context\": \"View context\",\n  \"lists.account.add\": \"பட்டியலில் சேர்\",\n  \"lists.account.remove\": \"பட்டியலில் இருந்து அகற்று\",\n  \"lists.delete\": \"Delete list\",\n  \"lists.edit\": \"பட்டியலை திருத்து\",\n  \"lists.edit.submit\": \"தலைப்பு மாற்றவும்\",\n  \"lists.new.create\": \"பட்டியலில் சேர்\",\n  \"lists.new.title_placeholder\": \"புதிய பட்டியல் தலைப்பு\",\n  \"lists.search\": \"நீங்கள் பின்தொடரும் நபர்கள் மத்தியில் தேடுதல்\",\n  \"lists.subheading\": \"உங்கள் பட்டியல்கள்\",\n  \"loading_indicator.label\": \"ஏற்றுதல்...\",\n  \"media_gallery.toggle_visible\": \"நிலைமாற்று தெரியும்\",\n  \"missing_indicator.label\": \"கிடைக்கவில்லை\",\n  \"missing_indicator.sublabel\": \"இந்த ஆதாரத்தை காண முடியவில்லை\",\n  \"mute_modal.hide_notifications\": \"இந்த பயனரின் அறிவிப்புகளை மறைக்கவா?\",\n  \"navigation_bar.apps\": \"மொபைல் பயன்பாடுகள்\",\n  \"navigation_bar.blocks\": \"தடுக்கப்பட்ட பயனர்கள்\",\n  \"navigation_bar.community_timeline\": \"உள்ளூர் காலக்கெடு\",\n  \"navigation_bar.compose\": \"புதியவற்றை எழுதுக toot\",\n  \"navigation_bar.direct\": \"நேரடி செய்திகள்\",\n  \"navigation_bar.discover\": \"கண்டு பிடி\",\n  \"navigation_bar.domain_blocks\": \"மறைந்த களங்கள்\",\n  \"navigation_bar.edit_profile\": \"சுயவிவரத்தைத் திருத்தவும்\",\n  \"navigation_bar.favourites\": \"விருப்பத்துக்குகந்த\",\n  \"navigation_bar.filters\": \"முடக்கப்பட்ட வார்த்தைகள்\",\n  \"navigation_bar.follow_requests\": \"கோரிக்கைகளை பின்பற்றவும்\",\n  \"navigation_bar.follows_and_followers\": \"Follows and followers\",\n  \"navigation_bar.info\": \"இந்த நிகழ்வு பற்றி\",\n  \"navigation_bar.keyboard_shortcuts\": \"சுருக்குவிசைகள்\",\n  \"navigation_bar.lists\": \"குதிரை வீர்ர்கள்\",\n  \"navigation_bar.logout\": \"விடு பதிகை\",\n  \"navigation_bar.mutes\": \"முடக்கப்பட்ட பயனர்கள்\",\n  \"navigation_bar.personal\": \"Personal\",\n  \"navigation_bar.pins\": \"பொருத்தப்பட்டன toots\",\n  \"navigation_bar.preferences\": \"விருப்பங்கள்\",\n  \"navigation_bar.profile_directory\": \"Profile directory\",\n  \"navigation_bar.public_timeline\": \"கூட்டாட்சி காலக்கெடு\",\n  \"navigation_bar.security\": \"பத்திரம்\",\n  \"notification.favourite\": \"{name} ஆர்வம் கொண்டவர், உங்கள் நிலை\",\n  \"notification.follow\": \"{name} நீங்கள் தொடர்ந்து வந்தீர்கள்\",\n  \"notification.mention\": \"{name} நீங்கள் குறிப்பிட்டுள்ளீர்கள்\",\n  \"notification.poll\": \"நீங்கள் வாக்களித்த வாக்கெடுப்பு முடிவடைந்தது\",\n  \"notification.reblog\": \"{name} உங்கள் நிலை அதிகரித்தது\",\n  \"notifications.clear\": \"அறிவிப்புகளை அழிக்கவும்\",\n  \"notifications.clear_confirmation\": \"உங்கள் எல்லா அறிவிப்புகளையும் நிரந்தரமாக அழிக்க விரும்புகிறீர்களா?\",\n  \"notifications.column_settings.alert\": \"டெஸ்க்டாப் அறிவிப்புகள்\",\n  \"notifications.column_settings.favourite\": \"பிடித்தவை:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"எல்லா வகைகளையும் காட்டு\",\n  \"notifications.column_settings.filter_bar.category\": \"விரைவு வடிகட்டி பட்டை\",\n  \"notifications.column_settings.filter_bar.show\": \"காட்டு\",\n  \"notifications.column_settings.follow\": \"புதிய பின்பற்றுபவர்கள்:\",\n  \"notifications.column_settings.mention\": \"குறிப்பிடுகிறது:\",\n  \"notifications.column_settings.poll\": \"கருத்துக்கணிப்பு முடிவுகள்:\",\n  \"notifications.column_settings.push\": \"Push notifications\",\n  \"notifications.column_settings.reblog\": \"மதிப்பை உயர்த்து:\",\n  \"notifications.column_settings.show\": \"பத்தியில் காண்பி\",\n  \"notifications.column_settings.sound\": \"ஒலி விளையாட\",\n  \"notifications.filter.all\": \"எல்லா\",\n  \"notifications.filter.boosts\": \"மதிப்பை உயர்த்து\",\n  \"notifications.filter.favourites\": \"விருப்பத்துக்குகந்த\",\n  \"notifications.filter.follows\": \"பின்பற்று\",\n  \"notifications.filter.mentions\": \"குறிப்பிடுகிறார்\",\n  \"notifications.filter.polls\": \"கருத்துக்கணிப்பு முடிவுகள்\",\n  \"notifications.group\": \"{count} notifications\",\n  \"poll.closed\": \"மூடிய\",\n  \"poll.refresh\": \"பத்துயிர்ப்ப?ட்டு\",\n  \"poll.total_votes\": \"{count, plural, one {# vote} மற்ற {# votes}}\",\n  \"poll.vote\": \"வாக்களி\",\n  \"poll_button.add_poll\": \"வாக்கெடுப்பைச் சேர்க்கவும்\",\n  \"poll_button.remove_poll\": \"வாக்கெடுப்பை அகற்று\",\n  \"privacy.change\": \"நிலை தனியுரிமை\",\n  \"privacy.direct.long\": \"குறிப்பிடப்பட்ட பயனர்களுக்கு மட்டுமே இடுகையிடவும்\",\n  \"privacy.direct.short\": \"நடத்து\",\n  \"privacy.private.long\": \"பின்தொடர்பவர்களுக்கு மட்டுமே இடுகை\",\n  \"privacy.private.short\": \"பின்பற்றுபவர்கள் மட்டும்\",\n  \"privacy.public.long\": \"பொது நேரங்களுக்கான இடுகை\",\n  \"privacy.public.short\": \"Public\",\n  \"privacy.unlisted.long\": \"Do not show in public timelines\",\n  \"privacy.unlisted.short\": \"பட்டியலிடப்படாத\",\n  \"regeneration_indicator.label\": \"சுமையேற்றம்…\",\n  \"regeneration_indicator.sublabel\": \"உங்கள் வீட்டு ஊட்டம் தயார் செய்யப்படுகிறது!\",\n  \"relative_time.days\": \"{number}d\",\n  \"relative_time.hours\": \"{number}h\",\n  \"relative_time.just_now\": \"இப்பொழுது\",\n  \"relative_time.minutes\": \"{number}m\",\n  \"relative_time.seconds\": \"{number}s\",\n  \"reply_indicator.cancel\": \"எதிராணை\",\n  \"report.forward\": \"முன்னோக்கி {target}\",\n  \"report.forward_hint\": \"கணக்கு மற்றொரு சேவையகத்திலிருந்து வருகிறது. அறிக்கையின் அநாமதேய பிரதி ஒன்றை அனுப்பவும்.?\",\n  \"report.hint\": \"அறிக்கை உங்கள் மாதிரியாக மாற்றியமைக்கப்படும். கீழே உள்ள கணக்கை நீங்கள் ஏன் புகாரளிக்கிறீர்கள் என்பதற்கான விளக்கத்தை வழங்கலாம்:\",\n  \"report.placeholder\": \"கூடுதல் கருத்துரைகள்\",\n  \"report.submit\": \"Submit\",\n  \"report.target\": \"Report {target}\",\n  \"search.placeholder\": \"தேடு\",\n  \"search_popout.search_format\": \"மேம்பட்ட தேடல் வடிவம்\",\n  \"search_popout.tips.full_text\": \"எளிமையான உரை நீங்கள் எழுதப்பட்ட, புகழ், அதிகரித்தது, அல்லது குறிப்பிட்டுள்ள, அதே போல் பயனர் பெயர்கள், காட்சி பெயர்கள், மற்றும் ஹேஸ்டேகைகளை கொண்டுள்ளது என்று நிலைகளை கொடுக்கிறது.\",\n  \"search_popout.tips.hashtag\": \"ஹேஸ்டேக்\",\n  \"search_popout.tips.status\": \"status\",\n  \"search_popout.tips.text\": \"எளிய உரை காட்சி பெயர்கள், பயனர்பெயர்கள் மற்றும் ஹாஷ்டேட்களுடன் பொருந்துகிறது\",\n  \"search_popout.tips.user\": \"user\",\n  \"search_results.accounts\": \"People\",\n  \"search_results.hashtags\": \"ஹாஷ்டேக்குகளைச்\",\n  \"search_results.statuses\": \"Toots\",\n  \"search_results.total\": \"{count, number} {count, plural, one {result} மற்ற {results}}\",\n  \"status.admin_account\": \"மிதமான இடைமுகத்தை திறக்க @{name}\",\n  \"status.admin_status\": \"மிதமான இடைமுகத்தில் இந்த நிலையை திறக்கவும்\",\n  \"status.block\": \"Block @{name}\",\n  \"status.cancel_reblog_private\": \"இல்லை பூஸ்ட்\",\n  \"status.cannot_reblog\": \"இந்த இடுகை அதிகரிக்க முடியாது\",\n  \"status.copy\": \"நிலைக்கு இணைப்பை நகலெடு\",\n  \"status.delete\": \"Delete\",\n  \"status.detailed_status\": \"விரிவான உரையாடல் காட்சி\",\n  \"status.direct\": \"நேரடி செய்தி @{name}\",\n  \"status.embed\": \"கிடத்து\",\n  \"status.favourite\": \"விருப்பத்துக்குகந்த\",\n  \"status.filtered\": \"வடிகட்டு\",\n  \"status.load_more\": \"அதிகமாய் ஏற்று\",\n  \"status.media_hidden\": \"மீடியா மறைக்கப்பட்டது\",\n  \"status.mention\": \"குறிப்பிடு @{name}\",\n  \"status.more\": \"அதிக\",\n  \"status.mute\": \"ஊமையான @{name}\",\n  \"status.mute_conversation\": \"ஒலிதடு உரையாடல்\",\n  \"status.open\": \"இந்த நிலையை விரிவாக்கு\",\n  \"status.pin\": \"சுயவிவரத்தில் முள்\",\n  \"status.pinned\": \"பொருத்தப்பட்டன toot\",\n  \"status.read_more\": \"மேலும் வாசிக்க\",\n  \"status.reblog\": \"மதிப்பை உயர்த்து\",\n  \"status.reblog_private\": \"Boost அசல் பார்வையாளர்களுக்கு\",\n  \"status.reblogged_by\": \"{name} மதிப்பை உயர்த்து\",\n  \"status.reblogs.empty\": \"இதுவரை யாரும் இந்த மோதலை அதிகரிக்கவில்லை. யாராவது செய்தால், அவர்கள் இங்கே காண்பார்கள்.\",\n  \"status.redraft\": \"நீக்கு மற்றும் மீண்டும் வரைவு\",\n  \"status.reply\": \"பதில்\",\n  \"status.replyAll\": \"நூலுக்கு பதிலளிக்கவும்\",\n  \"status.report\": \"Report @{name}\",\n  \"status.sensitive_warning\": \"உணர்திறன் உள்ளடக்கம்\",\n  \"status.share\": \"பங்கிடு\",\n  \"status.show_less\": \"குறைவாகக் காண்பி\",\n  \"status.show_less_all\": \"அனைத்தையும் குறைவாக காட்டு\",\n  \"status.show_more\": \"மேலும் காட்ட\",\n  \"status.show_more_all\": \"அனைவருக்கும் மேலும் காட்டு\",\n  \"status.show_thread\": \"நூல் காட்டு\",\n  \"status.unmute_conversation\": \"ஊமையாக உரையாடல் இல்லை\",\n  \"status.unpin\": \"சுயவிவரத்திலிருந்து நீக்கவும்\",\n  \"suggestions.dismiss\": \"பரிந்துரை விலக்க\",\n  \"suggestions.header\": \"நீங்கள் ஆர்வமாக இருக்கலாம் …\",\n  \"tabs_bar.federated_timeline\": \"Federated\",\n  \"tabs_bar.home\": \"Home\",\n  \"tabs_bar.local_timeline\": \"Local\",\n  \"tabs_bar.notifications\": \"Notifications\",\n  \"tabs_bar.search\": \"தேடு\",\n  \"time_remaining.days\": \"{number, plural, one {# day} மற்ற {# days}} left\",\n  \"time_remaining.hours\": \"{number, plural, one {# hour} மற்ற {# hours}} left\",\n  \"time_remaining.minutes\": \"{number, plural, one {# minute} மற்ற {# minutes}} left\",\n  \"time_remaining.moments\": \"தருணங்கள் மீதமுள்ளன\",\n  \"time_remaining.seconds\": \"{number, plural, one {# second} மற்ற {# seconds}} left\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {person} மற்ற {people}} உரையாடு\",\n  \"ui.beforeunload\": \"நீங்கள் வெளியே சென்றால் உங்கள் வரைவு இழக்கப்படும் மஸ்தோடோன்.\",\n  \"upload_area.title\": \"பதிவேற்ற & இழுக்கவும்\",\n  \"upload_button.label\": \"மீடியாவைச் சேர்க்கவும் (JPEG, PNG, GIF, WebM, MP4, MOV)\",\n  \"upload_error.limit\": \"கோப்பு பதிவேற்ற வரம்பு மீறப்பட்டது.\",\n  \"upload_error.poll\": \"கோப்பு பதிவேற்றம் அனுமதிக்கப்படவில்லை.\",\n  \"upload_form.description\": \"பார்வையற்ற விவரிக்கவும்\",\n  \"upload_form.focus\": \"மாற்றம் முன்னோட்டம்\",\n  \"upload_form.undo\": \"Delete\",\n  \"upload_progress.label\": \"ஏற்றுகிறது ...\",\n  \"video.close\": \"வீடியோவை மூடு\",\n  \"video.exit_fullscreen\": \"முழு திரையில் இருந்து வெளியேறவும்\",\n  \"video.expand\": \"வீடியோவை விரிவாக்கு\",\n  \"video.fullscreen\": \"Full screen\",\n  \"video.hide\": \"வீடியோவை மறை\",\n  \"video.mute\": \"ஒலி முடக்கவும்\",\n  \"video.pause\": \"Pause\",\n  \"video.play\": \"விளையாடு\",\n  \"video.unmute\": \"ஒலி மெளனமாக இல்லை\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/te.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"జాబితాల నుండి చేర్చు లేదా తీసివేయి\",\n  \"account.badges.bot\": \"బాట్\",\n  \"account.block\": \"@{name} ను బ్లాక్ చేయి\",\n  \"account.block_domain\": \"{domain} నుంచి అన్నీ దాచిపెట్టు\",\n  \"account.blocked\": \"బ్లాక్ అయినవి\",\n  \"account.direct\": \"@{name}కు నేరుగా సందేశం పంపు\",\n  \"account.domain_blocked\": \"డొమైన్ దాచిపెట్టబడినది\",\n  \"account.edit_profile\": \"ప్రొఫైల్ని సవరించండి\",\n  \"account.endorse\": \"ప్రొఫైల్లో చూపించు\",\n  \"account.follow\": \"అనుసరించు\",\n  \"account.followers\": \"అనుచరులు\",\n  \"account.followers.empty\": \"ఈ వినియోగదారుడిని ఇంకా ఎవరూ అనుసరించడంలేదు.\",\n  \"account.follows\": \"అనుసరిస్తున్నవి\",\n  \"account.follows.empty\": \"ఈ వినియోగదారి ఇంకా ఎవరినీ అనుసరించడంలేదు.\",\n  \"account.follows_you\": \"మిమ్మల్ని అనుసరిస్తున్నారు\",\n  \"account.hide_reblogs\": \"@{name} నుంచి బూస్ట్ లను దాచిపెట్టు\",\n  \"account.link_verified_on\": \"ఈ లంకె యొక్క యాజమాన్యం {date}న పరీక్షించబడింది\",\n  \"account.locked_info\": \"ఈ ఖాతా యొక్క గోప్యత స్థితి లాక్ చేయబడి వుంది. ఈ ఖాతాను ఎవరు అనుసరించవచ్చో యజమానే నిర్ణయం తీసుకుంటారు.\",\n  \"account.media\": \"మీడియా\",\n  \"account.mention\": \"@{name}ను ప్రస్తావించు\",\n  \"account.moved_to\": \"{name} ఇక్కడికి మారారు:\",\n  \"account.mute\": \"@{name}ను మ్యూట్ చెయ్యి\",\n  \"account.mute_notifications\": \"@{name}నుంచి ప్రకటనలను మ్యూట్ చెయ్యి\",\n  \"account.muted\": \"మ్యూట్ అయినవి\",\n  \"account.posts\": \"టూట్లు\",\n  \"account.posts_with_replies\": \"టూట్లు మరియు ప్రత్యుత్తరములు\",\n  \"account.report\": \"@{name}పై ఫిర్యాదుచేయు\",\n  \"account.requested\": \"ఆమోదం కోసం వేచి ఉంది. అభ్యర్థనను రద్దు చేయడానికి క్లిక్ చేయండి\",\n  \"account.share\": \"@{name} యొక్క ప్రొఫైల్ను పంచుకోండి\",\n  \"account.show_reblogs\": \"@{name}నుంచి బూస్ట్ లను చూపించు\",\n  \"account.unblock\": \"@{name}పై బ్లాక్ ను తొలగించు\",\n  \"account.unblock_domain\": \"{domain}ను దాచవద్దు\",\n  \"account.unendorse\": \"ప్రొఫైల్లో చూపించవద్దు\",\n  \"account.unfollow\": \"అనుసరించవద్దు\",\n  \"account.unmute\": \"@{name}పై మ్యూట్ ని తొలగించు\",\n  \"account.unmute_notifications\": \"@{name} నుంచి ప్రకటనలపై మ్యూట్ ని తొలగించు\",\n  \"alert.unexpected.message\": \"అనుకోని తప్పు జరిగినది.\",\n  \"alert.unexpected.title\": \"అయ్యో!\",\n  \"boost_modal.combo\": \"మీరు తదుపరిసారి దీనిని దాటవేయడానికి {combo} నొక్కవచ్చు\",\n  \"bundle_column_error.body\": \"ఈ భాగం లోడ్ అవుతున్నప్పుడు ఏదో తప్పు జరిగింది.\",\n  \"bundle_column_error.retry\": \"మళ్ళీ ప్రయత్నించండి\",\n  \"bundle_column_error.title\": \"నెట్వర్క్ లోపం\",\n  \"bundle_modal_error.close\": \"మూసివేయు\",\n  \"bundle_modal_error.message\": \"ఈ భాగం లోడ్ అవుతున్నప్పుడు ఏదో తప్పు జరిగింది.\",\n  \"bundle_modal_error.retry\": \"మళ్ళీ ప్రయత్నించండి\",\n  \"column.blocks\": \"బ్లాక్ చేయబడిన వినియోగదారులు\",\n  \"column.community\": \"స్థానిక కాలక్రమం\",\n  \"column.direct\": \"ప్రత్యక్ష సందేశాలు\",\n  \"column.domain_blocks\": \"దాచిన డొమైన్లు\",\n  \"column.favourites\": \"ఇష్టపడినవి\",\n  \"column.follow_requests\": \"అనుసరించడానికి అభ్యర్ధనలు\",\n  \"column.home\": \"హోమ్\",\n  \"column.lists\": \"జాబితాలు\",\n  \"column.mutes\": \"మ్యూట్ చేయబడిన వినియోగదారులు\",\n  \"column.notifications\": \"ప్రకటనలు\",\n  \"column.pins\": \"Pinned toot\",\n  \"column.public\": \"సమాఖ్య కాలక్రమం\",\n  \"column_back_button.label\": \"వెనక్కి\",\n  \"column_header.hide_settings\": \"అమర్పులను దాచిపెట్టు\",\n  \"column_header.moveLeft_settings\": \"నిలువు వరుసను ఎడమకి తరలించు\",\n  \"column_header.moveRight_settings\": \"నిలువు వరుసను కుడికి తరలించు\",\n  \"column_header.pin\": \"అతికించు\",\n  \"column_header.show_settings\": \"అమర్పులను చూపించు\",\n  \"column_header.unpin\": \"పీకివేయు\",\n  \"column_subheading.settings\": \"అమర్పులు\",\n  \"community.column_settings.media_only\": \"మీడియా మాత్రమే\",\n  \"compose_form.direct_message_warning\": \"ఈ టూట్ పేర్కొన్న వినియోగదారులకు మాత్రమే పంపబడుతుంది.\",\n  \"compose_form.direct_message_warning_learn_more\": \"మరింత తెలుసుకోండి\",\n  \"compose_form.hashtag_warning\": \"ఈ టూట్ అన్లిస్టెడ్ కాబట్టి ఏ హాష్ ట్యాగ్ క్రిందకూ రాదు. పబ్లిక్ టూట్ లను మాత్రమే హాష్ ట్యాగ్ ద్వారా శోధించవచ్చు.\",\n  \"compose_form.lock_disclaimer\": \"మీ ఖాతా {locked} చేయబడలేదు. ఎవరైనా మిమ్మల్ని అనుసరించి మీ అనుచరులకు-మాత్రమే పోస్ట్లను వీక్షించవచ్చు.\",\n  \"compose_form.lock_disclaimer.lock\": \"బిగించబడినది\",\n  \"compose_form.placeholder\": \"మీ మనస్సులో ఏముంది?\",\n  \"compose_form.poll.add_option\": \"ఒక ఎంపికను చేర్చండి\",\n  \"compose_form.poll.duration\": \"ఎన్నిక వ్యవధి\",\n  \"compose_form.poll.option_placeholder\": \"ఎంపిక {number}\",\n  \"compose_form.poll.remove_option\": \"ఈ ఎంపికను తొలగించు\",\n  \"compose_form.publish\": \"టూట్\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"Mark media as sensitive\",\n  \"compose_form.sensitive.marked\": \"మీడియా సున్నితమైనదిగా గుర్తించబడింది\",\n  \"compose_form.sensitive.unmarked\": \"మీడియా సున్నితమైనదిగా గుర్తించబడలేదు\",\n  \"compose_form.spoiler.marked\": \"హెచ్చరిక వెనుక పాఠ్యం దాచబడింది\",\n  \"compose_form.spoiler.unmarked\": \"పాఠ్యం దాచబడలేదు\",\n  \"compose_form.spoiler_placeholder\": \"ఇక్కడ మీ హెచ్చరికను రాయండి\",\n  \"confirmation_modal.cancel\": \"రద్దు చెయ్యి\",\n  \"confirmations.block.block_and_report\": \"Block & Report\",\n  \"confirmations.block.confirm\": \"బ్లాక్ చేయి\",\n  \"confirmations.block.message\": \"మీరు ఖచ్చితంగా {name}ని బ్లాక్ చేయాలనుకుంటున్నారా?\",\n  \"confirmations.delete.confirm\": \"తొలగించు\",\n  \"confirmations.delete.message\": \"మీరు ఖచ్చితంగా ఈ స్టేటస్ ని తొలగించాలనుకుంటున్నారా?\",\n  \"confirmations.delete_list.confirm\": \"తొలగించు\",\n  \"confirmations.delete_list.message\": \"మీరు ఖచ్చితంగా ఈ జాబితాను శాశ్వతంగా తొలగించాలనుకుంటున్నారా?\",\n  \"confirmations.domain_block.confirm\": \"మొత్తం డొమైన్ను దాచు\",\n  \"confirmations.domain_block.message\": \"మీరు నిజంగా నిజంగా మొత్తం {domain} ని బ్లాక్ చేయాలనుకుంటున్నారా? చాలా సందర్భాలలో కొన్ని లక్ష్యంగా ఉన్న బ్లాక్స్ లేదా మ్యూట్స్ సరిపోతాయి మరియు ఉత్తమమైనవి. మీరు ఆ డొమైన్ నుండి కంటెంట్ను ఏ ప్రజా కాలక్రమాలలో లేదా మీ నోటిఫికేషన్లలో చూడలేరు. ఆ డొమైన్ నుండి మీ అనుచరులు తీసివేయబడతారు.\",\n  \"confirmations.mute.confirm\": \"మ్యూట్ చేయి\",\n  \"confirmations.mute.message\": \"{name}ను మీరు ఖచ్చితంగా మ్యూట్ చేయాలనుకుంటున్నారా?\",\n  \"confirmations.redraft.confirm\": \"తొలగించు & తిరగరాయు\",\n  \"confirmations.redraft.message\": \"మీరు ఖచ్చితంగా ఈ స్టేటస్ ని తొలగించి తిరగరాయాలనుకుంటున్నారా? ఈ స్టేటస్ యొక్క బూస్ట్ లు మరియు ఇష్టాలు పోతాయి,మరియు ప్రత్యుత్తరాలు అనాధలు అయిపోతాయి.\",\n  \"confirmations.reply.confirm\": \"ప్రత్యుత్తరమివ్వు\",\n  \"confirmations.reply.message\": \"ఇప్పుడే ప్రత్యుత్తరం ఇస్తే మీరు ప్రస్తుతం వ్రాస్తున్న సందేశం తిరగరాయబడుతుంది. మీరు ఖచ్చితంగా కొనసాగించాలనుకుంటున్నారా?\",\n  \"confirmations.unfollow.confirm\": \"అనుసరించవద్దు\",\n  \"confirmations.unfollow.message\": \"{name}ను మీరు ఖచ్చితంగా అనుసరించవద్దనుకుంటున్నారా?\",\n  \"embed.instructions\": \"దిగువ కోడ్ను కాపీ చేయడం ద్వారా మీ వెబ్సైట్లో ఈ స్టేటస్ ని పొందుపరచండి.\",\n  \"embed.preview\": \"అది ఈ క్రింది విధంగా కనిపిస్తుంది:\",\n  \"emoji_button.activity\": \"కార్యకలాపాలు\",\n  \"emoji_button.custom\": \"అనుకూలీకరించిన\",\n  \"emoji_button.flags\": \"ఫ్లాగ్స్\",\n  \"emoji_button.food\": \"ఆహారం & పానీయం\",\n  \"emoji_button.label\": \"ఎమోజి చొప్పించు\",\n  \"emoji_button.nature\": \"ప్రకృతి\",\n  \"emoji_button.not_found\": \"ఎమోజీలు లేవు!! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"వస్తువులు\",\n  \"emoji_button.people\": \"ప్రజలు\",\n  \"emoji_button.recent\": \"తరచుగా ఉపయోగించునవి\",\n  \"emoji_button.search\": \"వెదుకు...\",\n  \"emoji_button.search_results\": \"శోధన ఫలితాలు\",\n  \"emoji_button.symbols\": \"చిహ్నాలు\",\n  \"emoji_button.travel\": \"ప్రయాణం & ప్రదేశాలు\",\n  \"empty_column.account_timeline\": \"ఇక్కడ ఏ టూట్లూ లేవు!No toots here!\",\n  \"empty_column.account_unavailable\": \"Profile unavailable\",\n  \"empty_column.blocks\": \"మీరు ఇంకా ఏ వినియోగదారులనూ బ్లాక్ చేయలేదు.\",\n  \"empty_column.community\": \"స్థానిక కాలక్రమం ఖాళీగా ఉంది. మొదలుపెట్టడానికి బహిరంగంగా ఏదో ఒకటి వ్రాయండి!\",\n  \"empty_column.direct\": \"మీకు ఇంకా ఏ ప్రత్యక్ష సందేశాలు లేవు. మీరు ఒకదాన్ని పంపినప్పుడు లేదా స్వీకరించినప్పుడు, అది ఇక్కడ చూపబడుతుంది.\",\n  \"empty_column.domain_blocks\": \"దాచబడిన డొమైన్లు ఇంకా ఏమీ లేవు.\",\n  \"empty_column.favourited_statuses\": \"మీకు ఇష్టపడిన టూట్లు ఇంకా ఎమీ లేవు. మీరు ఒకదానిని ఇష్టపడినప్పుడు, అది ఇక్కడ కనిపిస్తుంది.\",\n  \"empty_column.favourites\": \"ఈ టూట్ను ఇంకా ఎవరూ ఇష్టపడలేదు. ఎవరైనా అలా చేసినప్పుడు, అవి ఇక్కడ కనబడతాయి.\",\n  \"empty_column.follow_requests\": \"మీకు ఇంకా ఫాలో రిక్వెస్టులు ఏమీ రాలేదు. మీకు ఒకటి రాగానే, అది ఇక్కడ కనబడుతుంది.\",\n  \"empty_column.hashtag\": \"ఇంకా హాష్ ట్యాగ్లో ఏమీ లేదు.\",\n  \"empty_column.home\": \"మీ హోమ్ కాలక్రమం ఖాళీగా ఉంది! {Public} ను సందర్శించండి లేదా ఇతర వినియోగదారులను కలుసుకోవడానికి మరియు అన్వేషణ కోసం శోధనను ఉపయోగించండి.\",\n  \"empty_column.home.public_timeline\": \"ప్రజా కాలక్రమం\",\n  \"empty_column.list\": \"ఇంకా ఈ జాబితాలో ఏదీ లేదు. ఈ జాబితాలోని సభ్యులు కొత్త స్టేటస్ లను పోస్ట్ చేసినప్పుడు, అవి ఇక్కడ కనిపిస్తాయి.\",\n  \"empty_column.lists\": \"మీకు ఇంకా జాబితాలు ఏమీ లేవు. మీరు ఒకటి సృష్టించగానే, అది ఇక్కడ కనబడుతుంది.\",\n  \"empty_column.mutes\": \"మీరు ఇంకా ఏ వినియోగదారులనూ మ్యూట్ చేయలేదు.\",\n  \"empty_column.notifications\": \"మీకు ఇంకా ఏ నోటిఫికేషన్లు లేవు. సంభాషణను ప్రారంభించడానికి ఇతరులతో ప్రతిస్పందించండి.\",\n  \"empty_column.public\": \"ఇక్కడ ఏమీ లేదు! దీన్ని నింపడానికి బహిరంగంగా ఏదైనా వ్రాయండి, లేదా ఇతర సేవికల నుండి వినియోగదారులను అనుసరించండి\",\n  \"follow_request.authorize\": \"అనుమతించు\",\n  \"follow_request.reject\": \"తిరస్కరించు\",\n  \"getting_started.developers\": \"డెవలపర్లు\",\n  \"getting_started.directory\": \"ప్రొఫైల్ డైరెక్టరీ\",\n  \"getting_started.documentation\": \"డాక్యుమెంటేషన్\",\n  \"getting_started.heading\": \"మొదలుపెడదాం\",\n  \"getting_started.invite\": \"వ్యక్తులను ఆహ్వానించండి\",\n  \"getting_started.open_source_notice\": \"మాస్టొడొన్ ఓపెన్ సోర్స్ సాఫ్ట్వేర్. మీరు {github} వద్ద GitHub పై సమస్యలను నివేదించవచ్చు లేదా తోడ్పడచ్చు.\",\n  \"getting_started.security\": \"భద్రత\",\n  \"getting_started.terms\": \"సేవా నిబంధనలు\",\n  \"hashtag.column_header.tag_mode.all\": \"మరియు {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"లేదా {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"{additional} లేకుండా\",\n  \"hashtag.column_settings.select.no_options_message\": \"ఎటువంటి సూచనలూ దొరకలేదు\",\n  \"hashtag.column_settings.select.placeholder\": \"హ్యాష్ టాగులు నింపండి…\",\n  \"hashtag.column_settings.tag_mode.all\": \"ఇవన్నీ\",\n  \"hashtag.column_settings.tag_mode.any\": \"వీటిలో ఏవైనా\",\n  \"hashtag.column_settings.tag_mode.none\": \"ఇవేవీ కావు\",\n  \"hashtag.column_settings.tag_toggle\": \"ఈ నిలువు వరుసలో మరికొన్ని ట్యాగులను చేర్చండి\",\n  \"home.column_settings.basic\": \"ప్రాథమిక\",\n  \"home.column_settings.show_reblogs\": \"బూస్ట్ లను చూపించు\",\n  \"home.column_settings.show_replies\": \"ప్రత్యుత్తరాలను చూపించు\",\n  \"intervals.full.days\": \"{number, plural, one {# day} other {# days}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# hour} other {# hours}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minute} other {# minutes}}\",\n  \"introduction.federation.action\": \"తరువాత\",\n  \"introduction.federation.federated.headline\": \"Federated\",\n  \"introduction.federation.federated.text\": \"ఫెడివర్స్ లోని ఇతర సర్వర్లకు చెందిన పబ్లిక్ టూట్లు ఫెడరేటెడ్ టైంలైన్ లో కనిపిస్తాయి.\",\n  \"introduction.federation.home.headline\": \"Home\",\n  \"introduction.federation.home.text\": \"మీరు అనుసరిస్తున్న ఖాతాల టూట్లు హోం ఫీడ్ లో కనిపిస్తాయి. ఏ సర్వర్లో ఎవరినైనా మీరు అనుసరించవచ్చు!\",\n  \"introduction.federation.local.headline\": \"Local\",\n  \"introduction.federation.local.text\": \"ఈ సర్వరుకు చెందిన ఖాతాల పబ్లిక్ టూట్లు లోకల్ టైంలైన్ లో కనిపిస్తాయి.\",\n  \"introduction.interactions.action\": \"బోధనను ముగించు!\",\n  \"introduction.interactions.favourite.headline\": \"ఇష్టం\",\n  \"introduction.interactions.favourite.text\": \"మీరు ఏదైనా టూట్‌ను భవిష్యత్తు కోసం దాచుకోవచ్చు మరియు మీకు ఆ టూట్ నచ్చినందని తెలియజేయడం కోసం \\\"ఇష్టం\\\" ను నొక్కి రచయితకు తెలియజేయవచ్చు.\",\n  \"introduction.interactions.reblog.headline\": \"బూస్ట్\",\n  \"introduction.interactions.reblog.text\": \"వేరే వ్యక్తుల టూట్లను బూస్ట్ చేయడం ద్వారా ఆ టూట్‌ను మీ అనుచరులతో పంచుకోవచ్చు.\",\n  \"introduction.interactions.reply.headline\": \"ప్రత్యుత్తరం\",\n  \"introduction.interactions.reply.text\": \"మీరు ఇతర వ్యక్తుల టూట్లకు, మీ స్వంత టూత్లకు ప్రత్యుత్తరం ఇవ్వడం వల్ల గొలుసు చర్చ ప్రారంభమవుతుంది.\",\n  \"introduction.welcome.action\": \"ఇక ప్రారంభించు!\",\n  \"introduction.welcome.headline\": \"మొదటి మెట్లు\",\n  \"introduction.welcome.text\": \"ఫెడివర్స్ కు స్వాగతం! మరి కొంతసేపట్లో మీరు సందేశాలను ప్రసారం చేయవచ్చు మరియు వేర్వేరు సర్వర్లలో వున్న మీ స్నేహితులతో మాట్లాడవచ్చు. కానీ ఈ సర్వరు, {domain}, ప్రత్యేకమైనది - ఇది మీ ప్రొఫైలును హోస్టు చేస్తుంది, కాబట్టి ఈ సర్వరు పేరును గుర్తుంచుకోండి.\",\n  \"keyboard_shortcuts.back\": \"వెనక్కి తిరిగి వెళ్ళడానికి\",\n  \"keyboard_shortcuts.blocked\": \"బ్లాక్ చేయబడిన వినియోగదారుల జాబితాను తెరవడానికి\",\n  \"keyboard_shortcuts.boost\": \"బూస్ట్ చేయడానికి\",\n  \"keyboard_shortcuts.column\": \"నిలువు వరుసలలో ఒకదానిపై దృష్టి పెట్టడానికి\",\n  \"keyboard_shortcuts.compose\": \"కంపోజ్ టెక్స్ట్ఏరియా పై దృష్టి పెట్టడానికి\",\n  \"keyboard_shortcuts.description\": \"Description\",\n  \"keyboard_shortcuts.direct\": \"నేరుగా పంపిన సందేశాల నిలువు వరుసను తెరువడానికి\",\n  \"keyboard_shortcuts.down\": \"జాబితాలో క్రిందికి వెళ్ళడానికి\",\n  \"keyboard_shortcuts.enter\": \"to open status\",\n  \"keyboard_shortcuts.favourite\": \"ఇష్టపడడానికి\",\n  \"keyboard_shortcuts.favourites\": \"ఇష్టాల జాబితాను తెరవడానికి\",\n  \"keyboard_shortcuts.federated\": \"సమాఖ్య కాలక్రమాన్ని తెరవడానికి\",\n  \"keyboard_shortcuts.heading\": \"కీబోర్డ్ సత్వరమార్గాలు\",\n  \"keyboard_shortcuts.home\": \"హోమ్ కాలక్రమాన్ని తెరవడానికి\",\n  \"keyboard_shortcuts.hotkey\": \"హాట్ కీ\",\n  \"keyboard_shortcuts.legend\": \"ఈ లెజెండ్ ప్రదర్శించడానికి\",\n  \"keyboard_shortcuts.local\": \"లోకల్ కాలక్రమాన్ని తెరవడానికి\",\n  \"keyboard_shortcuts.mention\": \"రచయితను ప్రస్తావించడానికి\",\n  \"keyboard_shortcuts.muted\": \"మ్యూట్ చేయబడిన వినియోగదారుల జాబితాను తెరవడానికి\",\n  \"keyboard_shortcuts.my_profile\": \"మీ ప్రొఫైల్ను తెరవడానికి\",\n  \"keyboard_shortcuts.notifications\": \"నోటిఫికేషన్ల నిలువు వరుసను తెరవడానికి\",\n  \"keyboard_shortcuts.pinned\": \"అతికించబడిన టూట్ల జాబితాను తెరవడానికి\",\n  \"keyboard_shortcuts.profile\": \"రచయిత ప్రొఫైల్ ను తెరవాలంటే\",\n  \"keyboard_shortcuts.reply\": \"ప్రత్యుత్తరం ఇవ్వడానికి\",\n  \"keyboard_shortcuts.requests\": \"ఫాలో రిక్వెస్ట్ల జాబితాను తెరవడానికి\",\n  \"keyboard_shortcuts.search\": \"శోధనపై దృష్టి పెట్టండి\",\n  \"keyboard_shortcuts.start\": \"\\\"ఇక్కడ ప్రారంభించండి\\\" నిలువు వరుసను తెరవడానికి\",\n  \"keyboard_shortcuts.toggle_hidden\": \"CW వెనుక ఉన్న పాఠ్యాన్ని చూపడానికి / దాచడానికి\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"to show/hide media\",\n  \"keyboard_shortcuts.toot\": \"ఒక సరికొత్త టూట్ను ప్రారంభించడానికి\",\n  \"keyboard_shortcuts.unfocus\": \"పాఠ్యం వ్రాసే ఏరియా/శోధన పట్టిక నుండి బయటకు రావడానికి\",\n  \"keyboard_shortcuts.up\": \"జాబితాలో పైకి తరలించడానికి\",\n  \"lightbox.close\": \"మూసివేయు\",\n  \"lightbox.next\": \"తరువాత\",\n  \"lightbox.previous\": \"మునుపటి\",\n  \"lightbox.view_context\": \"View context\",\n  \"lists.account.add\": \"జాబితాకు జోడించు\",\n  \"lists.account.remove\": \"జాబితా నుండి తొలగించు\",\n  \"lists.delete\": \"జాబితాను తొలగించు\",\n  \"lists.edit\": \"జాబితాను సవరించు\",\n  \"lists.edit.submit\": \"శీర్షిక మార్చు\",\n  \"lists.new.create\": \"జాబితాను జోడించు\",\n  \"lists.new.title_placeholder\": \"కొత్త జాబితా శీర్షిక\",\n  \"lists.search\": \"మీరు అనుసరించే వ్యక్తులలో శోధించండి\",\n  \"lists.subheading\": \"మీ జాబితాలు\",\n  \"loading_indicator.label\": \"లోడ్ అవుతోంది...\",\n  \"media_gallery.toggle_visible\": \"దృశ్యమానతను టోగుల్ చేయండి\",\n  \"missing_indicator.label\": \"దొరకలేదు\",\n  \"missing_indicator.sublabel\": \"ఈ వనరు కనుగొనబడలేదు\",\n  \"mute_modal.hide_notifications\": \"ఈ వినియోగదారు నుండి నోటిఫికేషన్లను దాచాలా?\",\n  \"navigation_bar.apps\": \"మొబైల్ ఆప్ లు\",\n  \"navigation_bar.blocks\": \"బ్లాక్ చేయబడిన వినియోగదారులు\",\n  \"navigation_bar.community_timeline\": \"స్థానిక కాలక్రమం\",\n  \"navigation_bar.compose\": \"కొత్త టూట్ను రాయండి\",\n  \"navigation_bar.direct\": \"ప్రత్యక్ష సందేశాలు\",\n  \"navigation_bar.discover\": \"కనుగొను\",\n  \"navigation_bar.domain_blocks\": \"దాచిన డొమైన్లు\",\n  \"navigation_bar.edit_profile\": \"ప్రొఫైల్ని సవరించండి\",\n  \"navigation_bar.favourites\": \"ఇష్టపడినవి\",\n  \"navigation_bar.filters\": \"మ్యూట్ చేయబడిన పదాలు\",\n  \"navigation_bar.follow_requests\": \"అనుసరించడానికి అభ్యర్ధనలు\",\n  \"navigation_bar.follows_and_followers\": \"Follows and followers\",\n  \"navigation_bar.info\": \"ఈ సేవిక గురించి\",\n  \"navigation_bar.keyboard_shortcuts\": \"హాట్ కీలు\",\n  \"navigation_bar.lists\": \"జాబితాలు\",\n  \"navigation_bar.logout\": \"లాగ్ అవుట్ చేయండి\",\n  \"navigation_bar.mutes\": \"మ్యూట్ చేయబడిన వినియోగదారులు\",\n  \"navigation_bar.personal\": \"వ్యక్తిగతం\",\n  \"navigation_bar.pins\": \"అతికించిన టూట్లు\",\n  \"navigation_bar.preferences\": \"ప్రాధాన్యతలు\",\n  \"navigation_bar.profile_directory\": \"Profile directory\",\n  \"navigation_bar.public_timeline\": \"సమాఖ్య కాలక్రమం\",\n  \"navigation_bar.security\": \"భద్రత\",\n  \"notification.favourite\": \"{name} మీ స్టేటస్ ను ఇష్టపడ్డారు\",\n  \"notification.follow\": \"{name} మిమ్మల్ని అనుసరిస్తున్నారు\",\n  \"notification.mention\": \"{name} మిమ్మల్ని ప్రస్తావించారు\",\n  \"notification.poll\": \"మీరు పాల్గొనిన ఎన్సిక ముగిసినది\",\n  \"notification.reblog\": \"{name} మీ స్టేటస్ ను బూస్ట్ చేసారు\",\n  \"notifications.clear\": \"ప్రకటనలను తుడిచివేయు\",\n  \"notifications.clear_confirmation\": \"మీరు మీ అన్ని నోటిఫికేషన్లను శాశ్వతంగా తొలగించాలనుకుంటున్నారా?\",\n  \"notifications.column_settings.alert\": \"డెస్క్టాప్ నోటిఫికేషన్లు\",\n  \"notifications.column_settings.favourite\": \"ఇష్టపడినవి:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"అన్ని విభాగాలను చూపించు\",\n  \"notifications.column_settings.filter_bar.category\": \"క్విక్ ఫిల్టర్ బార్\",\n  \"notifications.column_settings.filter_bar.show\": \"చూపించు\",\n  \"notifications.column_settings.follow\": \"క్రొత్త అనుచరులు:\",\n  \"notifications.column_settings.mention\": \"ప్రస్తావనలు:\",\n  \"notifications.column_settings.poll\": \"ఎన్నిక ఫలితాలు:\",\n  \"notifications.column_settings.push\": \"పుష్ ప్రకటనలు\",\n  \"notifications.column_settings.reblog\": \"బూస్ట్ లు:\",\n  \"notifications.column_settings.show\": \"నిలువు వరుసలో చూపు\",\n  \"notifications.column_settings.sound\": \"ధ్వనిని ప్లే చేయి\",\n  \"notifications.filter.all\": \"అన్నీ\",\n  \"notifications.filter.boosts\": \"బూస్ట్లు\",\n  \"notifications.filter.favourites\": \"ఇష్టాలు\",\n  \"notifications.filter.follows\": \"అనుసరిస్తున్నవి\",\n  \"notifications.filter.mentions\": \"పేర్కొన్నవి\",\n  \"notifications.filter.polls\": \"ఎన్నిక ఫలితాలు\",\n  \"notifications.group\": \"{count} ప్రకటనలు\",\n  \"poll.closed\": \"మూసివేయబడినవి\",\n  \"poll.refresh\": \"నవీకరించు\",\n  \"poll.total_votes\": \"{count, plural, one {# vote} other {# votes}}\",\n  \"poll.vote\": \"ఎన్నుకోండి\",\n  \"poll_button.add_poll\": \"ఒక ఎన్నికను చేర్చు\",\n  \"poll_button.remove_poll\": \"ఎన్నికను తొలగించు\",\n  \"privacy.change\": \"స్టేటస్ గోప్యతను సర్దుబాటు చేయండి\",\n  \"privacy.direct.long\": \"పేర్కొన్న వినియోగదారులకు మాత్రమే పోస్ట్ చేయి\",\n  \"privacy.direct.short\": \"ప్రత్యక్ష\",\n  \"privacy.private.long\": \"అనుచరులకు మాత్రమే పోస్ట్ చేయి\",\n  \"privacy.private.short\": \"అనుచరులకు మాత్రమే\",\n  \"privacy.public.long\": \"ప్రజా కాలక్రమాలకు పోస్ట్ చేయండి\",\n  \"privacy.public.short\": \"ప్రజా\",\n  \"privacy.unlisted.long\": \"ప్రజా కాలక్రమాలలో చూపించవద్దు\",\n  \"privacy.unlisted.short\": \"జాబితా చేయబడనిది\",\n  \"regeneration_indicator.label\": \"లోడ్ అవుతోంది…\",\n  \"regeneration_indicator.sublabel\": \"మీ హోమ్ ఫీడ్ సిద్ధమవుతోంది!\",\n  \"relative_time.days\": \"{number}d\",\n  \"relative_time.hours\": \"{number}h\",\n  \"relative_time.just_now\": \"ఇప్పుడు\",\n  \"relative_time.minutes\": \"{number}m\",\n  \"relative_time.seconds\": \"{number}s\",\n  \"reply_indicator.cancel\": \"రద్దు చెయ్యి\",\n  \"report.forward\": \"{target}కి ఫార్వార్డ్ చేయండి\",\n  \"report.forward_hint\": \"ఖాతా మరొక సర్వర్లో ఉంది. నివేదిక యొక్క ఒక అనామకంగా ఉన్న కాపీని అక్కడికి కూడా పంపించమంటారా?\",\n  \"report.hint\": \"మీ సేవిక మోడరేటర్లకు నివేదిక పంపబడుతుంది. ఈ ఖాతాను ఎందుకు నివేదిస్తున్నారనేదాని వివరణను మీరు దిగువన అందించవచ్చు:\",\n  \"report.placeholder\": \"అదనపు వ్యాఖ్యలు\",\n  \"report.submit\": \"సమర్పించండి\",\n  \"report.target\": \"{target}పై ఫిర్యాదు చేయండి\",\n  \"search.placeholder\": \"శోధన\",\n  \"search_popout.search_format\": \"అధునాతన శోధన ఆకృతి\",\n  \"search_popout.tips.full_text\": \"సాధారణ వచనం మీరు వ్రాసిన, ఇష్టపడే, పెంచబడిన లేదా పేర్కొనబడిన, అలాగే యూజర్పేర్లు, ప్రదర్శన పేర్లు, మరియు హ్యాష్ట్యాగ్లను నమోదు చేసిన హోదాలను అందిస్తుంది.\",\n  \"search_popout.tips.hashtag\": \"హాష్ ట్యాగ్\",\n  \"search_popout.tips.status\": \"స్టేటస్\",\n  \"search_popout.tips.text\": \"సింపుల్ టెక్స్ట్ ప్రదర్శన పేర్లు, యూజర్ పేర్లు మరియు హ్యాష్ట్యాగ్లను సరిపోలుస్తుంది\",\n  \"search_popout.tips.user\": \"వాడుకరి\",\n  \"search_results.accounts\": \"వ్యక్తులు\",\n  \"search_results.hashtags\": \"హాష్ ట్యాగ్లు\",\n  \"search_results.statuses\": \"టూట్లు\",\n  \"search_results.total\": \"{count, number} {count, plural, one {result} other {results}}\",\n  \"status.admin_account\": \"@{name} కొరకు సమన్వయ వినిమయసీమను తెరువు\",\n  \"status.admin_status\": \"సమన్వయ వినిమయసీమలో ఈ స్టేటస్ ను తెరవండి\",\n  \"status.block\": \"@{name} ను బ్లాక్ చేయి\",\n  \"status.cancel_reblog_private\": \"బూస్ట్ను తొలగించు\",\n  \"status.cannot_reblog\": \"ఈ పోస్ట్ను బూస్ట్ చేయడం సాధ్యం కాదు\",\n  \"status.copy\": \"లంకెను స్టేటస్కు కాపీ చేయి\",\n  \"status.delete\": \"తొలగించు\",\n  \"status.detailed_status\": \"వివరణాత్మక సంభాషణ వీక్షణ\",\n  \"status.direct\": \"@{name}కు నేరుగా సందేశం పంపు\",\n  \"status.embed\": \"ఎంబెడ్\",\n  \"status.favourite\": \"ఇష్టపడు\",\n  \"status.filtered\": \"వడకట్టబడిన\",\n  \"status.load_more\": \"మరిన్ని లోడ్ చేయి\",\n  \"status.media_hidden\": \"మీడియా దాచబడింది\",\n  \"status.mention\": \"@{name}ను ప్రస్తావించు\",\n  \"status.more\": \"ఇంకొన్ని\",\n  \"status.mute\": \"@{name}ను మ్యూట్ చెయ్యి\",\n  \"status.mute_conversation\": \"సంభాషణను మ్యూట్ చెయ్యి\",\n  \"status.open\": \"ఈ స్టేటస్ ను విస్తరించు\",\n  \"status.pin\": \"ప్రొఫైల్లో అతికించు\",\n  \"status.pinned\": \"అతికించిన టూట్\",\n  \"status.read_more\": \"ఇంకా చదవండి\",\n  \"status.reblog\": \"బూస్ట్\",\n  \"status.reblog_private\": \"అసలు ప్రేక్షకులకు బూస్ట్ చేయి\",\n  \"status.reblogged_by\": \"{name} బూస్ట్ చేసారు\",\n  \"status.reblogs.empty\": \"ఈ టూట్ను ఇంకా ఎవరూ బూస్ట్ చేయలేదు. ఎవరైనా చేసినప్పుడు, అవి ఇక్కడ కనబడతాయి.\",\n  \"status.redraft\": \"తొలగించు & తిరగరాయు\",\n  \"status.reply\": \"ప్రత్యుత్తరం\",\n  \"status.replyAll\": \"సంభాషణకు ప్రత్యుత్తరం ఇవ్వండి\",\n  \"status.report\": \"@{name}పై ఫిర్యాదుచేయు\",\n  \"status.sensitive_warning\": \"సున్నితమైన కంటెంట్\",\n  \"status.share\": \"పంచుకోండి\",\n  \"status.show_less\": \"తక్కువ చూపించు\",\n  \"status.show_less_all\": \"అన్నిటికీ తక్కువ చూపించు\",\n  \"status.show_more\": \"ఇంకా చూపించు\",\n  \"status.show_more_all\": \"అన్నిటికీ ఇంకా చూపించు\",\n  \"status.show_thread\": \"గొలుసును చూపించు\",\n  \"status.unmute_conversation\": \"సంభాషణను అన్మ్యూట్ చేయి\",\n  \"status.unpin\": \"ప్రొఫైల్ నుండి పీకివేయు\",\n  \"suggestions.dismiss\": \"సూచనను రద్దు చేయి\",\n  \"suggestions.header\": \"మీకు వీటి మీద ఆసక్తి ఉండవచ్చు…\",\n  \"tabs_bar.federated_timeline\": \"సమాఖ్య\",\n  \"tabs_bar.home\": \"హోమ్\",\n  \"tabs_bar.local_timeline\": \"స్థానిక\",\n  \"tabs_bar.notifications\": \"ప్రకటనలు\",\n  \"tabs_bar.search\": \"శోధన\",\n  \"time_remaining.days\": \"{number, plural, one {# day} other {# days}} left\",\n  \"time_remaining.hours\": \"{number, plural, one {# hour} other {# hours}} left\",\n  \"time_remaining.minutes\": \"{number, plural, one {# minute} other {# minutes}} left\",\n  \"time_remaining.moments\": \"కొన్ని క్షణాలు మాత్రమే మిగిలి ఉన్నాయి\",\n  \"time_remaining.seconds\": \"{number, plural, one {# second} other {# seconds}} left\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {person} other {people}} మాట్లాడుతున్నారు\",\n  \"ui.beforeunload\": \"మీరు మాస్టొడొన్ను వదిలివేస్తే మీ డ్రాఫ్ట్లు పోతాయి.\",\n  \"upload_area.title\": \"అప్లోడ్ చేయడానికి డ్రాగ్ & డ్రాప్ చేయండి\",\n  \"upload_button.label\": \"మీడియాను జోడించండి (JPEG, PNG, GIF, WebM, MP4, MOV)\",\n  \"upload_error.limit\": \"File upload limit exceeded.\",\n  \"upload_error.poll\": \"File upload not allowed with polls.\",\n  \"upload_form.description\": \"దృష్టి లోపమున్న వారి కోసం వివరించండి\",\n  \"upload_form.focus\": \"ప్రివ్యూను మార్చు\",\n  \"upload_form.undo\": \"తొలగించు\",\n  \"upload_progress.label\": \"అప్లోడ్ అవుతోంది...\",\n  \"video.close\": \"వీడియోని మూసివేయి\",\n  \"video.exit_fullscreen\": \"పూర్తి స్క్రీన్ నుండి నిష్క్రమించు\",\n  \"video.expand\": \"వీడియోను విస్తరించండి\",\n  \"video.fullscreen\": \"పూర్తి స్క్రీన్\",\n  \"video.hide\": \"వీడియోను దాచు\",\n  \"video.mute\": \"ధ్వనిని మ్యూట్ చేయి\",\n  \"video.pause\": \"పాజ్ చేయి\",\n  \"video.play\": \"ప్లే చేయి\",\n  \"video.unmute\": \"ధ్వనిని అన్మ్యూట్ చేయి\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/th.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"เพิ่มหรือเอาออกจากรายการ\",\n  \"account.badges.bot\": \"บอต\",\n  \"account.block\": \"ปิดกั้น @{name}\",\n  \"account.block_domain\": \"ซ่อนทุกอย่างจาก {domain}\",\n  \"account.blocked\": \"ปิดกั้นอยู่\",\n  \"account.direct\": \"ส่งข้อความโดยตรงถึง @{name}\",\n  \"account.domain_blocked\": \"ซ่อนโดเมนอยู่\",\n  \"account.edit_profile\": \"แก้ไขโปรไฟล์\",\n  \"account.endorse\": \"แสดงให้เห็นในโปรไฟล์\",\n  \"account.follow\": \"ติดตาม\",\n  \"account.followers\": \"ผู้ติดตาม\",\n  \"account.followers.empty\": \"ยังไม่มีใครติดตามผู้ใช้นี้\",\n  \"account.follows\": \"ติดตาม\",\n  \"account.follows.empty\": \"ผู้ใช้นี้ยังไม่ได้ติดตามใคร\",\n  \"account.follows_you\": \"ติดตามคุณ\",\n  \"account.hide_reblogs\": \"ซ่อนการดันจาก @{name}\",\n  \"account.link_verified_on\": \"ตรวจสอบความเป็นเจ้าของของลิงก์นี้เมื่อ {date}\",\n  \"account.locked_info\": \"บัญชีนี้ถูกล็อคไว้ เจ้าของจะต้องรับรองการติดตามของคุณด้วย\",\n  \"account.media\": \"สื่อ\",\n  \"account.mention\": \"กล่าวถึง @{name}\",\n  \"account.moved_to\": \"{name} ได้ย้ายไปยัง:\",\n  \"account.mute\": \"ปิดเสียง @{name}\",\n  \"account.mute_notifications\": \"ปิดเสียงการแจ้งเตือนจาก @{name}\",\n  \"account.muted\": \"ปิดเสียงอยู่\",\n  \"account.posts\": \"โพสต์\",\n  \"account.posts_with_replies\": \"โพสต์และการตอบกลับ\",\n  \"account.report\": \"รายงาน @{name}\",\n  \"account.requested\": \"กำลังรอการอนุมัติ คลิกเพื่อยกเลิกคำขอติดตาม\",\n  \"account.share\": \"แบ่งปันโปรไฟล์ของ @{name}\",\n  \"account.show_reblogs\": \"แสดงการดันจาก @{name}\",\n  \"account.unblock\": \"เลิกปิดกั้น @{name}\",\n  \"account.unblock_domain\": \"เลิกซ่อน {domain}\",\n  \"account.unendorse\": \"ไม่แสดงให้เห็นในโปรไฟล์\",\n  \"account.unfollow\": \"เลิกติดตาม\",\n  \"account.unmute\": \"เลิกปิดเสียง @{name}\",\n  \"account.unmute_notifications\": \"เลิกปิดเสียงการแจ้งเตือนจาก @{name}\",\n  \"alert.unexpected.message\": \"เกิดข้อผิดพลาดที่ไม่คาดคิด\",\n  \"alert.unexpected.title\": \"อุปส์!\",\n  \"boost_modal.combo\": \"กด {combo} เพื่อข้าม\",\n  \"bundle_column_error.body\": \"มีบางอย่างผิดพลาดขณะโหลดส่วนประกอบนี้\",\n  \"bundle_column_error.retry\": \"ลองอีกครั้ง\",\n  \"bundle_column_error.title\": \"ข้อผิดพลาดเครือข่าย\",\n  \"bundle_modal_error.close\": \"ปิด\",\n  \"bundle_modal_error.message\": \"มีบางอย่างผิดพลาดขณะโหลดส่วนประกอบนี้\",\n  \"bundle_modal_error.retry\": \"ลองอีกครั้ง\",\n  \"column.blocks\": \"ผู้ใช้ที่ปิดกั้นอยู่\",\n  \"column.community\": \"เส้นเวลาในเว็บ\",\n  \"column.direct\": \"ข้อความโดยตรง\",\n  \"column.domain_blocks\": \"โดเมนที่ซ่อนอยู่\",\n  \"column.favourites\": \"รายการโปรด\",\n  \"column.follow_requests\": \"คำขอติดตาม\",\n  \"column.home\": \"หน้าแรก\",\n  \"column.lists\": \"รายการ\",\n  \"column.mutes\": \"ผู้ใช้ที่ปิดเสียงอยู่\",\n  \"column.notifications\": \"การแจ้งเตือน\",\n  \"column.pins\": \"โพสต์ที่ปักหมุด\",\n  \"column.public\": \"เส้นเวลาที่ติดต่อกับภายนอก\",\n  \"column_back_button.label\": \"ย้อนกลับ\",\n  \"column_header.hide_settings\": \"ซ่อนการตั้งค่า\",\n  \"column_header.moveLeft_settings\": \"ย้ายคอลัมน์ไปทางซ้าย\",\n  \"column_header.moveRight_settings\": \"ย้ายคอลัมน์ไปทางขวา\",\n  \"column_header.pin\": \"ปักหมุด\",\n  \"column_header.show_settings\": \"แสดงการตั้งค่า\",\n  \"column_header.unpin\": \"ถอนหมุด\",\n  \"column_subheading.settings\": \"การตั้งค่า\",\n  \"community.column_settings.media_only\": \"สื่อเท่านั้น\",\n  \"compose_form.direct_message_warning\": \"This toot will only be visible to all the mentioned users.\",\n  \"compose_form.direct_message_warning_learn_more\": \"เรียนรู้เพิ่มเติม\",\n  \"compose_form.hashtag_warning\": \"This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.\",\n  \"compose_form.lock_disclaimer\": \"Your account is not {locked}. Anyone can follow you to view your follower-only posts.\",\n  \"compose_form.lock_disclaimer.lock\": \"locked\",\n  \"compose_form.placeholder\": \"What is on your mind?\",\n  \"compose_form.poll.add_option\": \"Add a choice\",\n  \"compose_form.poll.duration\": \"Poll duration\",\n  \"compose_form.poll.option_placeholder\": \"Choice {number}\",\n  \"compose_form.poll.remove_option\": \"Remove this choice\",\n  \"compose_form.publish\": \"โพสต์\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"Mark media as sensitive\",\n  \"compose_form.sensitive.marked\": \"Media is marked as sensitive\",\n  \"compose_form.sensitive.unmarked\": \"Media is not marked as sensitive\",\n  \"compose_form.spoiler.marked\": \"Text is hidden behind warning\",\n  \"compose_form.spoiler.unmarked\": \"Text is not hidden\",\n  \"compose_form.spoiler_placeholder\": \"เขียนคำเตือนของคุณที่นี่\",\n  \"confirmation_modal.cancel\": \"ยกเลิก\",\n  \"confirmations.block.block_and_report\": \"ปิดกั้นแล้วรายงาน\",\n  \"confirmations.block.confirm\": \"ปิดกั้น\",\n  \"confirmations.block.message\": \"คุณแน่ใจหรือไม่ว่าต้องการปิดกั้น {name}?\",\n  \"confirmations.delete.confirm\": \"ลบ\",\n  \"confirmations.delete.message\": \"คุณแน่ใจหรือไม่ว่าต้องการลบสถานะนี้?\",\n  \"confirmations.delete_list.confirm\": \"ลบ\",\n  \"confirmations.delete_list.message\": \"คุณแน่ใจหรือไม่ว่าต้องการลบรายการนี้อย่างถาวร?\",\n  \"confirmations.domain_block.confirm\": \"Hide entire domain\",\n  \"confirmations.domain_block.message\": \"Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.\",\n  \"confirmations.mute.confirm\": \"ปิดเสียง\",\n  \"confirmations.mute.message\": \"คุณแน่ใจหรือไม่ว่าต้องการปิดเสียง {name}?\",\n  \"confirmations.redraft.confirm\": \"ลบแล้วร่างใหม่\",\n  \"confirmations.redraft.message\": \"Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.\",\n  \"confirmations.reply.confirm\": \"ตอบกลับ\",\n  \"confirmations.reply.message\": \"Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?\",\n  \"confirmations.unfollow.confirm\": \"เลิกติดตาม\",\n  \"confirmations.unfollow.message\": \"คุณแน่ใจหรือไม่ว่าต้องการเลิกติดตาม {name}?\",\n  \"embed.instructions\": \"Embed this status on your website by copying the code below.\",\n  \"embed.preview\": \"Here is what it will look like:\",\n  \"emoji_button.activity\": \"กิจกรรม\",\n  \"emoji_button.custom\": \"กำหนดเอง\",\n  \"emoji_button.flags\": \"ธง\",\n  \"emoji_button.food\": \"อาหารและเครื่องดื่ม\",\n  \"emoji_button.label\": \"แทรกอีโมจิ\",\n  \"emoji_button.nature\": \"ธรรมชาติ\",\n  \"emoji_button.not_found\": \"No emojos!! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"วัตถุ\",\n  \"emoji_button.people\": \"ผู้คน\",\n  \"emoji_button.recent\": \"ที่ใช้บ่อย\",\n  \"emoji_button.search\": \"ค้นหา...\",\n  \"emoji_button.search_results\": \"ผลลัพธ์การค้นหา\",\n  \"emoji_button.symbols\": \"สัญลักษณ์\",\n  \"emoji_button.travel\": \"การเดินทางและสถานที่\",\n  \"empty_column.account_timeline\": \"ไม่มีโพสต์ที่นี่!\",\n  \"empty_column.account_unavailable\": \"Profile unavailable\",\n  \"empty_column.blocks\": \"You haven't blocked any users yet.\",\n  \"empty_column.community\": \"The local timeline is empty. Write something publicly to get the ball rolling!\",\n  \"empty_column.direct\": \"You don't have any direct messages yet. When you send or receive one, it will show up here.\",\n  \"empty_column.domain_blocks\": \"ยังไม่มีโดเมนที่ซ่อนอยู่\",\n  \"empty_column.favourited_statuses\": \"You don't have any favourite toots yet. When you favourite one, it will show up here.\",\n  \"empty_column.favourites\": \"No one has favourited this toot yet. When someone does, they will show up here.\",\n  \"empty_column.follow_requests\": \"You don't have any follow requests yet. When you receive one, it will show up here.\",\n  \"empty_column.hashtag\": \"There is nothing in this hashtag yet.\",\n  \"empty_column.home\": \"Your home timeline is empty! Visit {public} or use search to get started and meet other users.\",\n  \"empty_column.home.public_timeline\": \"เส้นเวลาสาธารณะ\",\n  \"empty_column.list\": \"There is nothing in this list yet.\",\n  \"empty_column.lists\": \"You don't have any lists yet. When you create one, it will show up here.\",\n  \"empty_column.mutes\": \"You haven't muted any users yet.\",\n  \"empty_column.notifications\": \"You don't have any notifications yet. Interact with others to start the conversation.\",\n  \"empty_column.public\": \"There is nothing here! Write something publicly, or manually follow users from other instances to fill it up\",\n  \"follow_request.authorize\": \"อนุญาต\",\n  \"follow_request.reject\": \"ปฏิเสธ\",\n  \"getting_started.developers\": \"นักพัฒนา\",\n  \"getting_started.directory\": \"ไดเรกทอรีโปรไฟล์\",\n  \"getting_started.documentation\": \"เอกสารประกอบ\",\n  \"getting_started.heading\": \"เริ่มต้นใช้งาน\",\n  \"getting_started.invite\": \"เชิญผู้คน\",\n  \"getting_started.open_source_notice\": \"Mastodon is open source software. You can contribute or report issues on GitHub at {github}.\",\n  \"getting_started.security\": \"ความปลอดภัย\",\n  \"getting_started.terms\": \"เงื่อนไขการให้บริการ\",\n  \"hashtag.column_header.tag_mode.all\": \"และ {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"หรือ {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"โดยไม่มี {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"ไม่พบข้อเสนอแนะ\",\n  \"hashtag.column_settings.select.placeholder\": \"ป้อนแฮชแท็ก…\",\n  \"hashtag.column_settings.tag_mode.all\": \"All of these\",\n  \"hashtag.column_settings.tag_mode.any\": \"Any of these\",\n  \"hashtag.column_settings.tag_mode.none\": \"None of these\",\n  \"hashtag.column_settings.tag_toggle\": \"Include additional tags in this column\",\n  \"home.column_settings.basic\": \"พื้นฐาน\",\n  \"home.column_settings.show_reblogs\": \"แสดงการดัน\",\n  \"home.column_settings.show_replies\": \"แสดงการตอบกลับ\",\n  \"intervals.full.days\": \"{number, plural, one {# day} other {# days}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# hour} other {# hours}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minute} other {# minutes}}\",\n  \"introduction.federation.action\": \"ถัดไป\",\n  \"introduction.federation.federated.headline\": \"Federated\",\n  \"introduction.federation.federated.text\": \"Public posts from other servers of the fediverse will appear in the federated timeline.\",\n  \"introduction.federation.home.headline\": \"Home\",\n  \"introduction.federation.home.text\": \"Posts from people you follow will appear in your home feed. You can follow anyone on any server!\",\n  \"introduction.federation.local.headline\": \"Local\",\n  \"introduction.federation.local.text\": \"Public posts from people on the same server as you will appear in the local timeline.\",\n  \"introduction.interactions.action\": \"Finish toot-orial!\",\n  \"introduction.interactions.favourite.headline\": \"Favourite\",\n  \"introduction.interactions.favourite.text\": \"You can save a toot for later, and let the author know that you liked it, by favouriting it.\",\n  \"introduction.interactions.reblog.headline\": \"Boost\",\n  \"introduction.interactions.reblog.text\": \"You can share other people's toots with your followers by boosting them.\",\n  \"introduction.interactions.reply.headline\": \"Reply\",\n  \"introduction.interactions.reply.text\": \"You can reply to other people's and your own toots, which will chain them together in a conversation.\",\n  \"introduction.welcome.action\": \"Let's go!\",\n  \"introduction.welcome.headline\": \"First steps\",\n  \"introduction.welcome.text\": \"Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.\",\n  \"keyboard_shortcuts.back\": \"to navigate back\",\n  \"keyboard_shortcuts.blocked\": \"to open blocked users list\",\n  \"keyboard_shortcuts.boost\": \"to boost\",\n  \"keyboard_shortcuts.column\": \"to focus a status in one of the columns\",\n  \"keyboard_shortcuts.compose\": \"to focus the compose textarea\",\n  \"keyboard_shortcuts.description\": \"คำอธิบาย\",\n  \"keyboard_shortcuts.direct\": \"to open direct messages column\",\n  \"keyboard_shortcuts.down\": \"to move down in the list\",\n  \"keyboard_shortcuts.enter\": \"to open status\",\n  \"keyboard_shortcuts.favourite\": \"to favourite\",\n  \"keyboard_shortcuts.favourites\": \"to open favourites list\",\n  \"keyboard_shortcuts.federated\": \"to open federated timeline\",\n  \"keyboard_shortcuts.heading\": \"Keyboard Shortcuts\",\n  \"keyboard_shortcuts.home\": \"to open home timeline\",\n  \"keyboard_shortcuts.hotkey\": \"ปุ่มลัด\",\n  \"keyboard_shortcuts.legend\": \"to display this legend\",\n  \"keyboard_shortcuts.local\": \"to open local timeline\",\n  \"keyboard_shortcuts.mention\": \"to mention author\",\n  \"keyboard_shortcuts.muted\": \"to open muted users list\",\n  \"keyboard_shortcuts.my_profile\": \"to open your profile\",\n  \"keyboard_shortcuts.notifications\": \"to open notifications column\",\n  \"keyboard_shortcuts.pinned\": \"to open pinned toots list\",\n  \"keyboard_shortcuts.profile\": \"to open author's profile\",\n  \"keyboard_shortcuts.reply\": \"to reply\",\n  \"keyboard_shortcuts.requests\": \"to open follow requests list\",\n  \"keyboard_shortcuts.search\": \"to focus search\",\n  \"keyboard_shortcuts.start\": \"to open \\\"get started\\\" column\",\n  \"keyboard_shortcuts.toggle_hidden\": \"to show/hide text behind CW\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"to show/hide media\",\n  \"keyboard_shortcuts.toot\": \"to start a brand new toot\",\n  \"keyboard_shortcuts.unfocus\": \"to un-focus compose textarea/search\",\n  \"keyboard_shortcuts.up\": \"to move up in the list\",\n  \"lightbox.close\": \"ปิด\",\n  \"lightbox.next\": \"ถัดไป\",\n  \"lightbox.previous\": \"ก่อนหน้า\",\n  \"lightbox.view_context\": \"View context\",\n  \"lists.account.add\": \"เพิ่มไปยังรายการ\",\n  \"lists.account.remove\": \"เอาออกจากรายการ\",\n  \"lists.delete\": \"ลบรายการ\",\n  \"lists.edit\": \"แก้ไขรายการ\",\n  \"lists.edit.submit\": \"เปลี่ยนชื่อเรื่อง\",\n  \"lists.new.create\": \"เพิ่มรายการ\",\n  \"lists.new.title_placeholder\": \"ชื่อเรื่องรายการใหม่\",\n  \"lists.search\": \"ค้นหาในหมู่ผู้คนที่คุณติดตาม\",\n  \"lists.subheading\": \"รายการของคุณ\",\n  \"loading_indicator.label\": \"กำลังโหลด...\",\n  \"media_gallery.toggle_visible\": \"เปิด/ปิดการมองเห็น\",\n  \"missing_indicator.label\": \"ไม่พบ\",\n  \"missing_indicator.sublabel\": \"ไม่พบทรัพยากรนี้\",\n  \"mute_modal.hide_notifications\": \"ซ่อนการแจ้งเตือนจากผู้ใช้นี้?\",\n  \"navigation_bar.apps\": \"แอปสำหรับมือถือ\",\n  \"navigation_bar.blocks\": \"ผู้ใช้ที่ปิดกั้นอยู่\",\n  \"navigation_bar.community_timeline\": \"เส้นเวลาในเว็บ\",\n  \"navigation_bar.compose\": \"เขียนโพสต์ใหม่\",\n  \"navigation_bar.direct\": \"ข้อความโดยตรง\",\n  \"navigation_bar.discover\": \"ค้นพบ\",\n  \"navigation_bar.domain_blocks\": \"โดเมนที่ซ่อนอยู่\",\n  \"navigation_bar.edit_profile\": \"แก้ไขโปรไฟล์\",\n  \"navigation_bar.favourites\": \"รายการโปรด\",\n  \"navigation_bar.filters\": \"คำที่ปิดเสียงอยู่\",\n  \"navigation_bar.follow_requests\": \"คำขอติดตาม\",\n  \"navigation_bar.follows_and_followers\": \"Follows and followers\",\n  \"navigation_bar.info\": \"เกี่ยวกับเซิร์ฟเวอร์นี้\",\n  \"navigation_bar.keyboard_shortcuts\": \"ปุ่มลัด\",\n  \"navigation_bar.lists\": \"รายการ\",\n  \"navigation_bar.logout\": \"ออกจากระบบ\",\n  \"navigation_bar.mutes\": \"ผู้ใช้ที่ปิดเสียงอยู่\",\n  \"navigation_bar.personal\": \"ส่วนบุคคล\",\n  \"navigation_bar.pins\": \"โพสต์ที่ปักหมุด\",\n  \"navigation_bar.preferences\": \"การกำหนดลักษณะ\",\n  \"navigation_bar.profile_directory\": \"Profile directory\",\n  \"navigation_bar.public_timeline\": \"เส้นเวลาที่ติดต่อกับภายนอก\",\n  \"navigation_bar.security\": \"ความปลอดภัย\",\n  \"notification.favourite\": \"{name} ได้ชื่นชอบสถานะของคุณ\",\n  \"notification.follow\": \"{name} ได้ติดตามคุณ\",\n  \"notification.mention\": \"{name} ได้กล่าวถึงคุณ\",\n  \"notification.poll\": \"A poll you have voted in has ended\",\n  \"notification.reblog\": \"{name} ได้ดันสถานะของคุณ\",\n  \"notifications.clear\": \"ล้างการแจ้งเตือน\",\n  \"notifications.clear_confirmation\": \"คุณแน่ใจหรือไม่ว่าต้องการล้างการแจ้งเตือนทั้งหมดของคุณอย่างถาวร?\",\n  \"notifications.column_settings.alert\": \"Desktop notifications\",\n  \"notifications.column_settings.favourite\": \"รายการโปรด:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"แสดงหมวดหมู่ทั้งหมด\",\n  \"notifications.column_settings.filter_bar.category\": \"แถบตัวกรองด่วน\",\n  \"notifications.column_settings.filter_bar.show\": \"แสดง\",\n  \"notifications.column_settings.follow\": \"ผู้ติดตามใหม่:\",\n  \"notifications.column_settings.mention\": \"การกล่าวถึง:\",\n  \"notifications.column_settings.poll\": \"Poll results:\",\n  \"notifications.column_settings.push\": \"การแจ้งเตือนแบบผลัก\",\n  \"notifications.column_settings.reblog\": \"การดัน:\",\n  \"notifications.column_settings.show\": \"แสดงในคอลัมน์\",\n  \"notifications.column_settings.sound\": \"เล่นเสียง\",\n  \"notifications.filter.all\": \"ทั้งหมด\",\n  \"notifications.filter.boosts\": \"การดัน\",\n  \"notifications.filter.favourites\": \"รายการโปรด\",\n  \"notifications.filter.follows\": \"การติดตาม\",\n  \"notifications.filter.mentions\": \"การกล่าวถึง\",\n  \"notifications.filter.polls\": \"Poll results\",\n  \"notifications.group\": \"{count} การแจ้งเตือน\",\n  \"poll.closed\": \"ปิดแล้ว\",\n  \"poll.refresh\": \"Refresh\",\n  \"poll.total_votes\": \"{count, plural, one {# vote} other {# votes}}\",\n  \"poll.vote\": \"Vote\",\n  \"poll_button.add_poll\": \"Add a poll\",\n  \"poll_button.remove_poll\": \"Remove poll\",\n  \"privacy.change\": \"Adjust status privacy\",\n  \"privacy.direct.long\": \"โพสต์ไปยังผู้ใช้ที่กล่าวถึงเท่านั้น\",\n  \"privacy.direct.short\": \"โดยตรง\",\n  \"privacy.private.long\": \"โพสต์ไปยังผู้ติดตามเท่านั้น\",\n  \"privacy.private.short\": \"ผู้ติดตามเท่านั้น\",\n  \"privacy.public.long\": \"โพสต์ไปยังเส้นเวลาสาธารณะ\",\n  \"privacy.public.short\": \"สาธารณะ\",\n  \"privacy.unlisted.long\": \"ไม่โพสต์ไปยังเส้นเวลาสาธารณะ\",\n  \"privacy.unlisted.short\": \"ไม่อยู่ในรายการ\",\n  \"regeneration_indicator.label\": \"กำลังโหลด…\",\n  \"regeneration_indicator.sublabel\": \"Your home feed is being prepared!\",\n  \"relative_time.days\": \"{number} วัน\",\n  \"relative_time.hours\": \"{number} ชั่วโมง\",\n  \"relative_time.just_now\": \"ตอนนี้\",\n  \"relative_time.minutes\": \"{number} นาที\",\n  \"relative_time.seconds\": \"{number} วินาที\",\n  \"reply_indicator.cancel\": \"ยกเลิก\",\n  \"report.forward\": \"ส่งต่อไปยัง {target}\",\n  \"report.forward_hint\": \"The account is from another server. Send an anonymized copy of the report there as well?\",\n  \"report.hint\": \"The report will be sent to your instance moderators. You can provide an explanation of why you are reporting this account below:\",\n  \"report.placeholder\": \"ความคิดเห็นเพิ่มเติม\",\n  \"report.submit\": \"ส่ง\",\n  \"report.target\": \"กำลังรายงาน {target}\",\n  \"search.placeholder\": \"ค้นหา\",\n  \"search_popout.search_format\": \"รูปแบบการค้นหาขั้นสูง\",\n  \"search_popout.tips.full_text\": \"Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.\",\n  \"search_popout.tips.hashtag\": \"แฮชแท็ก\",\n  \"search_popout.tips.status\": \"สถานะ\",\n  \"search_popout.tips.text\": \"Simple text returns matching display names, usernames and hashtags\",\n  \"search_popout.tips.user\": \"ผู้ใช้\",\n  \"search_results.accounts\": \"ผู้คน\",\n  \"search_results.hashtags\": \"แฮชแท็ก\",\n  \"search_results.statuses\": \"โพสต์\",\n  \"search_results.total\": \"{count, number} {count, plural, one {result} other {results}}\",\n  \"status.admin_account\": \"เปิดส่วนติดต่อการควบคุมสำหรับ @{name}\",\n  \"status.admin_status\": \"เปิดสถานะนี้ในส่วนติดต่อการควบคุม\",\n  \"status.block\": \"ปิดกั้น @{name}\",\n  \"status.cancel_reblog_private\": \"เลิกดัน\",\n  \"status.cannot_reblog\": \"ไม่สามารถดันโพสต์นี้\",\n  \"status.copy\": \"คัดลอกลิงก์ไปยังสถานะ\",\n  \"status.delete\": \"ลบ\",\n  \"status.detailed_status\": \"มุมมองการสนทนาโดยละเอียด\",\n  \"status.direct\": \"ส่งข้อความโดยตรงถึง @{name}\",\n  \"status.embed\": \"Embed\",\n  \"status.favourite\": \"ชื่นชอบ\",\n  \"status.filtered\": \"กรองอยู่\",\n  \"status.load_more\": \"โหลดเพิ่มเติม\",\n  \"status.media_hidden\": \"ซ่อนสื่ออยู่\",\n  \"status.mention\": \"กล่าวถึง @{name}\",\n  \"status.more\": \"เพิ่มเติม\",\n  \"status.mute\": \"ปิดเสียง @{name}\",\n  \"status.mute_conversation\": \"ปิดเสียงการสนทนา\",\n  \"status.open\": \"ขยายสถานะนี้\",\n  \"status.pin\": \"ปักหมุดในโปรไฟล์\",\n  \"status.pinned\": \"โพสต์ที่ปักหมุด\",\n  \"status.read_more\": \"อ่านเพิ่มเติม\",\n  \"status.reblog\": \"ดัน\",\n  \"status.reblog_private\": \"ดันไปยังผู้ชมดั้งเดิม\",\n  \"status.reblogged_by\": \"{name} ได้ดัน\",\n  \"status.reblogs.empty\": \"No one has boosted this toot yet. When someone does, they will show up here.\",\n  \"status.redraft\": \"ลบแล้วร่างใหม่\",\n  \"status.reply\": \"ตอบกลับ\",\n  \"status.replyAll\": \"ตอบกลับกระทู้\",\n  \"status.report\": \"รายงาน @{name}\",\n  \"status.sensitive_warning\": \"เนื้อหาที่ละเอียดอ่อน\",\n  \"status.share\": \"แบ่งปัน\",\n  \"status.show_less\": \"แสดงน้อยลง\",\n  \"status.show_less_all\": \"แสดงน้อยลงทั้งหมด\",\n  \"status.show_more\": \"แสดงเพิ่มเติม\",\n  \"status.show_more_all\": \"แสดงเพิ่มเติมทั้งหมด\",\n  \"status.show_thread\": \"แสดงกระทู้\",\n  \"status.unmute_conversation\": \"เลิกปิดเสียงการสนทนา\",\n  \"status.unpin\": \"ถอนหมุดจากโปรไฟล์\",\n  \"suggestions.dismiss\": \"ยกเลิกข้อเสนอแนะ\",\n  \"suggestions.header\": \"คุณอาจสนใจ…\",\n  \"tabs_bar.federated_timeline\": \"ที่ติดต่อกับภายนอก\",\n  \"tabs_bar.home\": \"หน้าแรก\",\n  \"tabs_bar.local_timeline\": \"ในเว็บ\",\n  \"tabs_bar.notifications\": \"การแจ้งเตือน\",\n  \"tabs_bar.search\": \"ค้นหา\",\n  \"time_remaining.days\": \"{number, plural, one {# day} other {# days}} left\",\n  \"time_remaining.hours\": \"{number, plural, one {# hour} other {# hours}} left\",\n  \"time_remaining.minutes\": \"{number, plural, one {# minute} other {# minutes}} left\",\n  \"time_remaining.moments\": \"Moments remaining\",\n  \"time_remaining.seconds\": \"{number, plural, one {# second} other {# seconds}} left\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {person} other {people}} talking\",\n  \"ui.beforeunload\": \"แบบร่างของคุณจะหายไปหากคุณออกจาก Mastodon\",\n  \"upload_area.title\": \"ลากแล้วปล่อยเพื่ออัปโหลด\",\n  \"upload_button.label\": \"เพิ่มสื่อ (JPEG, PNG, GIF, WebM, MP4, MOV)\",\n  \"upload_error.limit\": \"เกินขีดจำกัดการอัปโหลดไฟล์\",\n  \"upload_error.poll\": \"File upload not allowed with polls.\",\n  \"upload_form.description\": \"Describe for the visually impaired\",\n  \"upload_form.focus\": \"ตัวอย่างการเปลี่ยนแปลง\",\n  \"upload_form.undo\": \"ลบ\",\n  \"upload_progress.label\": \"กำลังอัปโหลด...\",\n  \"video.close\": \"ปิดวิดีโอ\",\n  \"video.exit_fullscreen\": \"ออกจากเต็มหน้าจอ\",\n  \"video.expand\": \"ขยายวิดีโอ\",\n  \"video.fullscreen\": \"เต็มหน้าจอ\",\n  \"video.hide\": \"ซ่อนวิดีโอ\",\n  \"video.mute\": \"ปิดเสียง\",\n  \"video.pause\": \"หยุดชั่วคราว\",\n  \"video.play\": \"เล่น\",\n  \"video.unmute\": \"เลิกปิดเสียง\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/tr.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Listelere ekle veya kaldır\",\n  \"account.badges.bot\": \"Bot\",\n  \"account.block\": \"Engelle @{name}\",\n  \"account.block_domain\": \"{domain} alanından her şeyi gizle\",\n  \"account.blocked\": \"Engellenmiş\",\n  \"account.direct\": \"Mesaj gönder : @{name}\",\n  \"account.domain_blocked\": \"Alan adı gizlendi\",\n  \"account.edit_profile\": \"Profili düzenle\",\n  \"account.endorse\": \"Profildeki özellik\",\n  \"account.follow\": \"Takip et\",\n  \"account.followers\": \"Takipçiler\",\n  \"account.followers.empty\": \"Henüz kimse bu kullanıcıyı takip etmiyor.\",\n  \"account.follows\": \"Takip ettikleri\",\n  \"account.follows.empty\": \"Bu kullanıcı henüz kimseyi takip etmiyor.\",\n  \"account.follows_you\": \"Seni takip ediyor\",\n  \"account.hide_reblogs\": \"@{name} kişisinden boost'ları gizle\",\n  \"account.link_verified_on\": \"Bu bağlantının mülkiyeti {date} tarihinde kontrol edildi\",\n  \"account.locked_info\": \"Bu hesabın gizlilik durumu kilitli olarak ayarlanmış. Sahibi, onu kimin takip edebileceğini elle inceler.\",\n  \"account.media\": \"Medya\",\n  \"account.mention\": \"@{name} kullanıcısından bahset\",\n  \"account.moved_to\": \"{name} şuraya taşındı:\",\n  \"account.mute\": \"@{name} kullanıcısını sessize al\",\n  \"account.mute_notifications\": \"@{name} kullanıcısının bildirimlerini kapat\",\n  \"account.muted\": \"Sesi kısık\",\n  \"account.posts\": \"Gönderiler\",\n  \"account.posts_with_replies\": \"Gönderiler ve yanıtlar\",\n  \"account.report\": \"@{name} kullanıcısını bildir\",\n  \"account.requested\": \"Onay bekliyor. Takip isteğini iptal etmek için tıklayın\",\n  \"account.share\": \"@{name} kullanıcısının profilini paylaş\",\n  \"account.show_reblogs\": \"@{name} kullanıcısından boostları göster\",\n  \"account.unblock\": \"Engeli kaldır @{name}\",\n  \"account.unblock_domain\": \"{domain} göster\",\n  \"account.unendorse\": \"Profilde özellik yok\",\n  \"account.unfollow\": \"Takipten vazgeç\",\n  \"account.unmute\": \"Sesi aç : @{name}\",\n  \"account.unmute_notifications\": \"@{name} kullanıcısından bildirimleri aç\",\n  \"alert.unexpected.message\": \"Beklenmedik bir hata oluştu.\",\n  \"alert.unexpected.title\": \"Hay aksi!\",\n  \"boost_modal.combo\": \"Bir dahaki sefere {combo} tuşuna basabilirsiniz\",\n  \"bundle_column_error.body\": \"Bu bileşen yüklenirken bir şeyler ters gitti.\",\n  \"bundle_column_error.retry\": \"Tekrar deneyin\",\n  \"bundle_column_error.title\": \"Ağ hatası\",\n  \"bundle_modal_error.close\": \"Kapat\",\n  \"bundle_modal_error.message\": \"Bu bileşen yüklenirken bir şeyler ters gitti.\",\n  \"bundle_modal_error.retry\": \"Tekrar deneyin\",\n  \"column.blocks\": \"Engellenen kullanıcılar\",\n  \"column.community\": \"Yerel zaman tüneli\",\n  \"column.direct\": \"Doğrudan mesajlar\",\n  \"column.domain_blocks\": \"Gizli alan adları\",\n  \"column.favourites\": \"Favoriler\",\n  \"column.follow_requests\": \"Takip istekleri\",\n  \"column.home\": \"Anasayfa\",\n  \"column.lists\": \"Listeler\",\n  \"column.mutes\": \"Susturulmuş kullanıcılar\",\n  \"column.notifications\": \"Bildirimler\",\n  \"column.pins\": \"Sabitlenmiş gönderi\",\n  \"column.public\": \"Federe zaman tüneli\",\n  \"column_back_button.label\": \"Geri\",\n  \"column_header.hide_settings\": \"Ayarları gizle\",\n  \"column_header.moveLeft_settings\": \"Sütunu sola taşı\",\n  \"column_header.moveRight_settings\": \"Sütunu sağa taşı\",\n  \"column_header.pin\": \"Sabitle\",\n  \"column_header.show_settings\": \"Ayarları göster\",\n  \"column_header.unpin\": \"Sabitlemeyi kaldır\",\n  \"column_subheading.settings\": \"Ayarlar\",\n  \"community.column_settings.media_only\": \"Sadece medya\",\n  \"compose_form.direct_message_warning\": \"Bu gönderi sadece belirtilen kullanıcılara gönderilecektir.\",\n  \"compose_form.direct_message_warning_learn_more\": \"Daha fazla bilgi edinin\",\n  \"compose_form.hashtag_warning\": \"Bu paylaşım liste dışı olduğu için hiç bir hashtag'de yer almayacak. Sadece herkese açık gönderiler hashtaglerde bulunabilir.\",\n  \"compose_form.lock_disclaimer\": \"Hesabınız {locked} değil. Sadece takipçilerle paylaştığınız gönderileri görebilmek için sizi herhangi bir kullanıcı takip edebilir.\",\n  \"compose_form.lock_disclaimer.lock\": \"kilitli\",\n  \"compose_form.placeholder\": \"Aklınızdan ne geçiyor?\",\n  \"compose_form.poll.add_option\": \"Bir seçenek ekleyin\",\n  \"compose_form.poll.duration\": \"Anket süresi\",\n  \"compose_form.poll.option_placeholder\": \"Seçim {number}\",\n  \"compose_form.poll.remove_option\": \"Bu seçimi kaldır\",\n  \"compose_form.publish\": \"Gönder\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"Mark media as sensitive\",\n  \"compose_form.sensitive.marked\": \"Medya hassas olarak işaretlendi\",\n  \"compose_form.sensitive.unmarked\": \"Medya hassas olarak işaretlenmemiş\",\n  \"compose_form.spoiler.marked\": \"Metin uyarının arkasına gizlenir\",\n  \"compose_form.spoiler.unmarked\": \"Metin gizli değil\",\n  \"compose_form.spoiler_placeholder\": \"İçerik uyarısı\",\n  \"confirmation_modal.cancel\": \"İptal\",\n  \"confirmations.block.block_and_report\": \"Engelle & Bildir\",\n  \"confirmations.block.confirm\": \"Engelle\",\n  \"confirmations.block.message\": \"{name} kullanıcısını engellemek istiyor musunuz?\",\n  \"confirmations.delete.confirm\": \"Sil\",\n  \"confirmations.delete.message\": \"Bu gönderiyi silmek istiyor musunuz?\",\n  \"confirmations.delete_list.confirm\": \"Sil\",\n  \"confirmations.delete_list.message\": \"Bu listeyi kalıcı olarak silmek istediğinize emin misiniz?\",\n  \"confirmations.domain_block.confirm\": \"Alan adının tamamını gizle\",\n  \"confirmations.domain_block.message\": \"tüm {domain} alan adını engellemek istediğinizden emin misiniz? Genellikle birkaç hedefli engel ve susturma işi görür ve tercih edilir.\",\n  \"confirmations.mute.confirm\": \"Sessize al\",\n  \"confirmations.mute.message\": \"{name} kullanıcısını sessize almak istiyor musunuz?\",\n  \"confirmations.redraft.confirm\": \"Sil ve yeniden tasarla\",\n  \"confirmations.redraft.message\": \"Bu durumu silip tekrar taslaklaştırmak istediğinizden emin misiniz? Tüm cevapları, boostları ve favorileri kaybedeceksiniz.\",\n  \"confirmations.reply.confirm\": \"Yanıtla\",\n  \"confirmations.reply.message\": \"Şimdi yanıtlarken o an oluşturduğunuz mesajın üzerine yazılır. Devam etmek istediğinize emin misiniz?\",\n  \"confirmations.unfollow.confirm\": \"Takibi kaldır\",\n  \"confirmations.unfollow.message\": \"{name}'yi takipten çıkarmak istediğinizden emin misiniz?\",\n  \"embed.instructions\": \"Aşağıdaki kodu kopyalayarak bu durumu sitenize gömün.\",\n  \"embed.preview\": \"İşte nasıl görüneceği:\",\n  \"emoji_button.activity\": \"Aktivite\",\n  \"emoji_button.custom\": \"Özel\",\n  \"emoji_button.flags\": \"Bayraklar\",\n  \"emoji_button.food\": \"Yiyecek ve İçecek\",\n  \"emoji_button.label\": \"Emoji ekle\",\n  \"emoji_button.nature\": \"Doğa\",\n  \"emoji_button.not_found\": \"İfade yok!! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"Nesneler\",\n  \"emoji_button.people\": \"İnsanlar\",\n  \"emoji_button.recent\": \"Sık kullanılan\",\n  \"emoji_button.search\": \"Ara...\",\n  \"emoji_button.search_results\": \"Arama sonuçları\",\n  \"emoji_button.symbols\": \"Semboller\",\n  \"emoji_button.travel\": \"Seyahat ve Yerler\",\n  \"empty_column.account_timeline\": \"Burada hiç gönderi yok!\",\n  \"empty_column.account_unavailable\": \"Profile unavailable\",\n  \"empty_column.blocks\": \"Henüz bir kullanıcıyı engellemediniz.\",\n  \"empty_column.community\": \"Yerel zaman çizelgesi boş. Daha fazla eğlence için herkese açık bir gönderi paylaşın!\",\n  \"empty_column.direct\": \"Henüz doğrudan mesajınız yok. Bir tane gönderdiğinizde veya aldığınızda burada görünecektir.\",\n  \"empty_column.domain_blocks\": \"Henüz hiçbir gizli alan adı yok.\",\n  \"empty_column.favourited_statuses\": \"Hiç favori gönderiminiz yok. Bir tane olursa burada görünecek.\",\n  \"empty_column.favourites\": \"Kimse bu gönderiyi favorilerine eklememiş. Biri eklerse burada görünecek.\",\n  \"empty_column.follow_requests\": \"Hiç takip isteğiniz yok. Bir tane aldığınızda burada görünecek.\",\n  \"empty_column.hashtag\": \"Henüz bu hashtag’e sahip hiçbir gönderi yok.\",\n  \"empty_column.home\": \"Henüz kimseyi takip etmiyorsunuz. {public} ziyaret edebilir veya arama kısmını kullanarak diğer kullanıcılarla iletişime geçebilirsiniz.\",\n  \"empty_column.home.public_timeline\": \"herkese açık zaman tüneli\",\n  \"empty_column.list\": \"Bu listede henüz hiçbir şey yok.\",\n  \"empty_column.lists\": \"Henüz hiç listeniz yok. Bir tane oluşturduğunuzda burada görünecek.\",\n  \"empty_column.mutes\": \"Henüz hiçbir kullanıcıyı sessize almadınız.\",\n  \"empty_column.notifications\": \"Henüz hiçbir bildiriminiz yok. Diğer insanlarla sobhet edebilmek için etkileşime geçebilirsiniz.\",\n  \"empty_column.public\": \"Burada hiçbir şey yok! Herkese açık bir şeyler yazın veya burayı doldurmak için diğer sunuculardaki kullanıcıları takip edin\",\n  \"follow_request.authorize\": \"Yetkilendir\",\n  \"follow_request.reject\": \"Reddet\",\n  \"getting_started.developers\": \"Geliştiriciler\",\n  \"getting_started.directory\": \"Profil dizini\",\n  \"getting_started.documentation\": \"Belgeler\",\n  \"getting_started.heading\": \"Başlangıç\",\n  \"getting_started.invite\": \"İnsanları davet edin\",\n  \"getting_started.open_source_notice\": \"Mastodon açık kaynaklı bir yazılımdır. Github {github}. {apps} üzerinden katkıda bulunabilir, hata raporlayabilirsiniz.\",\n  \"getting_started.security\": \"Güvenlik\",\n  \"getting_started.terms\": \"Hizmet koşulları\",\n  \"hashtag.column_header.tag_mode.all\": \"ve {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"ya da {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"{additional} olmadan\",\n  \"hashtag.column_settings.select.no_options_message\": \"Hiç öneri bulunamadı\",\n  \"hashtag.column_settings.select.placeholder\": \"Hashtagler girin…\",\n  \"hashtag.column_settings.tag_mode.all\": \"Bunların hepsi\",\n  \"hashtag.column_settings.tag_mode.any\": \"Bunların hiçbiri\",\n  \"hashtag.column_settings.tag_mode.none\": \"Bunların hiçbiri\",\n  \"hashtag.column_settings.tag_toggle\": \"Bu sütundaki ek etiketleri içer\",\n  \"home.column_settings.basic\": \"Temel\",\n  \"home.column_settings.show_reblogs\": \"Boost edilenleri göster\",\n  \"home.column_settings.show_replies\": \"Cevapları göster\",\n  \"intervals.full.days\": \"{number, plural, one {# day} other {# days}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# hour} other {# hours}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minute} other {# minutes}}\",\n  \"introduction.federation.action\": \"İleri\",\n  \"introduction.federation.federated.headline\": \"Birleşik\",\n  \"introduction.federation.federated.text\": \"Diğer dosya sunucularından gelen genel gönderiler, birleşik zaman çizelgesinde görünecektir.\",\n  \"introduction.federation.home.headline\": \"Ana sayfa\",\n  \"introduction.federation.home.text\": \"Posts from people you follow will appear in your home feed. You can follow anyone on any server!\",\n  \"introduction.federation.local.headline\": \"Yerel\",\n  \"introduction.federation.local.text\": \"Aynı sunucudaki kişilerin gönderileri yerel zaman tünelinde gözükecektir.\",\n  \"introduction.interactions.action\": \"Öğreticiyi bitirin!\",\n  \"introduction.interactions.favourite.headline\": \"Favori\",\n  \"introduction.interactions.favourite.text\": \"Bir gönderiyi favorilerinize alarak sonrası için saklayabilirsiniz ve yazara gönderiyi beğendiğinizi söyleyebilirsiniz.\",\n  \"introduction.interactions.reblog.headline\": \"Boost\",\n  \"introduction.interactions.reblog.text\": \"Başkalarının gönderilerini boostlayarak kendi takipçilerinizle paylaşabillirsiniz.\",\n  \"introduction.interactions.reply.headline\": \"Yanıt\",\n  \"introduction.interactions.reply.text\": \"Başkalarının gönderilerini ve kendi gönderilerinizi yanıtlayabilirsiniz. Bir konuşmada zincirli bir şekilde olacaklardır.\",\n  \"introduction.welcome.action\": \"Hadi gidelim!\",\n  \"introduction.welcome.headline\": \"İlk adımlar\",\n  \"introduction.welcome.text\": \"Krallığa hoş geldiniz! Az sonra, geniş bir sunucu yelpazesinde mesaj gönderip arkadaşlarınızla konuşabileceksiniz. Ama bu sunucu, {domain}, özel (profilinizi barındırır, bu yüzden adresini hatırlayın).\",\n  \"keyboard_shortcuts.back\": \"geriye gitmek için\",\n  \"keyboard_shortcuts.blocked\": \"engelli kullanıcılar listesini açmak için\",\n  \"keyboard_shortcuts.boost\": \"boostlamak için\",\n  \"keyboard_shortcuts.column\": \"sütunlardan birindeki duruma odaklanmak için\",\n  \"keyboard_shortcuts.compose\": \"yazma alanına odaklanmak için\",\n  \"keyboard_shortcuts.description\": \"Açıklama\",\n  \"keyboard_shortcuts.direct\": \"direkt mesajlar sütununu açmak için\",\n  \"keyboard_shortcuts.down\": \"listede aşağıya inmek için\",\n  \"keyboard_shortcuts.enter\": \"durumu açmak için\",\n  \"keyboard_shortcuts.favourite\": \"favorilere eklemek için\",\n  \"keyboard_shortcuts.favourites\": \"favoriler listesini açmak için\",\n  \"keyboard_shortcuts.federated\": \"federe edilmiş zaman tünelini açmak için\",\n  \"keyboard_shortcuts.heading\": \"Klavye kısayolları\",\n  \"keyboard_shortcuts.home\": \"ana sayfa zaman çizelgesini açmak için\",\n  \"keyboard_shortcuts.hotkey\": \"Kısatuş\",\n  \"keyboard_shortcuts.legend\": \"bu efsaneyi görüntülemek için\",\n  \"keyboard_shortcuts.local\": \"yerel zaman tünelini açmak için\",\n  \"keyboard_shortcuts.mention\": \"yazardan bahsetmek için\",\n  \"keyboard_shortcuts.muted\": \"susturulmuş kullanıcı listesini açmak için\",\n  \"keyboard_shortcuts.my_profile\": \"profilinizi açmak için\",\n  \"keyboard_shortcuts.notifications\": \"bildirimler sütununu açmak için\",\n  \"keyboard_shortcuts.pinned\": \"sabitlenmiş gönderiler listesini açmak için\",\n  \"keyboard_shortcuts.profile\": \"yazarın profilini açmak için\",\n  \"keyboard_shortcuts.reply\": \"cevaplamak için\",\n  \"keyboard_shortcuts.requests\": \"takip istekleri listesini açmak için\",\n  \"keyboard_shortcuts.search\": \"aramaya odaklanmak için\",\n  \"keyboard_shortcuts.start\": \"\\\"başlayın\\\" sütununu açmak için\",\n  \"keyboard_shortcuts.toggle_hidden\": \"CW'den önceki yazıyı göstermek/gizlemek için\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"to show/hide media\",\n  \"keyboard_shortcuts.toot\": \"yeni bir gönderiye başlamak için\",\n  \"keyboard_shortcuts.unfocus\": \"aramada bir gönderiye odaklanmamak için\",\n  \"keyboard_shortcuts.up\": \"listede yukarıya çıkmak için\",\n  \"lightbox.close\": \"Kapat\",\n  \"lightbox.next\": \"Sonraki\",\n  \"lightbox.previous\": \"Önceli\",\n  \"lightbox.view_context\": \"View context\",\n  \"lists.account.add\": \"Listeye ekle\",\n  \"lists.account.remove\": \"Listeden kaldır\",\n  \"lists.delete\": \"Listeyi sil\",\n  \"lists.edit\": \"listeyi düzenle\",\n  \"lists.edit.submit\": \"Başlığı değiştir\",\n  \"lists.new.create\": \"Liste ekle\",\n  \"lists.new.title_placeholder\": \"Yeni liste başlığı\",\n  \"lists.search\": \"Takip ettiğiniz kişiler arasından arayın\",\n  \"lists.subheading\": \"Listeleriniz\",\n  \"loading_indicator.label\": \"Yükleniyor...\",\n  \"media_gallery.toggle_visible\": \"Görünürlüğü değiştir\",\n  \"missing_indicator.label\": \"Bulunamadı\",\n  \"missing_indicator.sublabel\": \"Bu kaynak bulunamadı\",\n  \"mute_modal.hide_notifications\": \"Bu kullanıcıdan bildirimler gizlensin mı?\",\n  \"navigation_bar.apps\": \"Mobil uygulamalar\",\n  \"navigation_bar.blocks\": \"Engellenen kullanıcılar\",\n  \"navigation_bar.community_timeline\": \"Yerel zaman tüneli\",\n  \"navigation_bar.compose\": \"Yeni bir gönderi yazın\",\n  \"navigation_bar.direct\": \"Direkt Mesajlar\",\n  \"navigation_bar.discover\": \"Keşfet\",\n  \"navigation_bar.domain_blocks\": \"Gizli alan adları\",\n  \"navigation_bar.edit_profile\": \"Profili düzenle\",\n  \"navigation_bar.favourites\": \"Favoriler\",\n  \"navigation_bar.filters\": \"Susturulmuş kelimeler\",\n  \"navigation_bar.follow_requests\": \"Takip istekleri\",\n  \"navigation_bar.follows_and_followers\": \"Follows and followers\",\n  \"navigation_bar.info\": \"Genişletilmiş bilgi\",\n  \"navigation_bar.keyboard_shortcuts\": \"Klavye kısayolları\",\n  \"navigation_bar.lists\": \"Listeler\",\n  \"navigation_bar.logout\": \"Çıkış\",\n  \"navigation_bar.mutes\": \"Sessize alınmış kullanıcılar\",\n  \"navigation_bar.personal\": \"Kişisel\",\n  \"navigation_bar.pins\": \"Sabitlenmiş gönderiler\",\n  \"navigation_bar.preferences\": \"Tercihler\",\n  \"navigation_bar.profile_directory\": \"Profile directory\",\n  \"navigation_bar.public_timeline\": \"Federe zaman tüneli\",\n  \"navigation_bar.security\": \"Güvenlik\",\n  \"notification.favourite\": \"{name} senin durumunu favorilere ekledi\",\n  \"notification.follow\": \"{name} seni takip ediyor\",\n  \"notification.mention\": \"{name} mentioned you\",\n  \"notification.poll\": \"Oy verdiğiniz bir anket bitti\",\n  \"notification.reblog\": \"{name} senin durumunu boost etti\",\n  \"notifications.clear\": \"Bildirimleri temizle\",\n  \"notifications.clear_confirmation\": \"Tüm bildirimlerinizi kalıcı olarak temizlemek ister misiniz?\",\n  \"notifications.column_settings.alert\": \"Masaüstü bildirimleri\",\n  \"notifications.column_settings.favourite\": \"Favoriler:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Tüm kategorileri göster\",\n  \"notifications.column_settings.filter_bar.category\": \"Hızlı filtre çubuğu\",\n  \"notifications.column_settings.filter_bar.show\": \"Göster\",\n  \"notifications.column_settings.follow\": \"Yeni takipçiler:\",\n  \"notifications.column_settings.mention\": \"Bahsedilenler:\",\n  \"notifications.column_settings.poll\": \"Anket sonuçları:\",\n  \"notifications.column_settings.push\": \"Push bildirimleri\",\n  \"notifications.column_settings.reblog\": \"Boostlar:\",\n  \"notifications.column_settings.show\": \"Bildirimlerde göster\",\n  \"notifications.column_settings.sound\": \"Ses çal\",\n  \"notifications.filter.all\": \"Tümü\",\n  \"notifications.filter.boosts\": \"Boostlar\",\n  \"notifications.filter.favourites\": \"Favoriler\",\n  \"notifications.filter.follows\": \"Takip edilenler\",\n  \"notifications.filter.mentions\": \"Bahsetmeler\",\n  \"notifications.filter.polls\": \"Anket sonuçları\",\n  \"notifications.group\": \"{count} bildirim\",\n  \"poll.closed\": \"Kapandı\",\n  \"poll.refresh\": \"Yenile\",\n  \"poll.total_votes\": \"{count, plural, one {# vote} other {# votes}}\",\n  \"poll.vote\": \"Oy ver\",\n  \"poll_button.add_poll\": \"Bir anket ekleyin\",\n  \"poll_button.remove_poll\": \"Anket kaldır\",\n  \"privacy.change\": \"Gönderi gizliliğini ayarla\",\n  \"privacy.direct.long\": \"Sadece bahsedilen kişilere gönder\",\n  \"privacy.direct.short\": \"Direkt\",\n  \"privacy.private.long\": \"Sadece takipçilerime gönder\",\n  \"privacy.private.short\": \"Sadece takipçiler\",\n  \"privacy.public.long\": \"Herkese açık zaman tüneline gönder\",\n  \"privacy.public.short\": \"Herkese açık\",\n  \"privacy.unlisted.long\": \"Herkese açık zaman tüneline gönderme\",\n  \"privacy.unlisted.short\": \"Listelenmemiş\",\n  \"regeneration_indicator.label\": \"Yükleniyor…\",\n  \"regeneration_indicator.sublabel\": \"Ev akışınız hazırlanıyor!\",\n  \"relative_time.days\": \"{number}g\",\n  \"relative_time.hours\": \"{number}s\",\n  \"relative_time.just_now\": \"şimdi\",\n  \"relative_time.minutes\": \"{number}dk\",\n  \"relative_time.seconds\": \"{number}sn\",\n  \"reply_indicator.cancel\": \"İptal\",\n  \"report.forward\": \"Şu kişiye ilet : {target}\",\n  \"report.forward_hint\": \"Bu hesap başka bir sunucudan. Anonimleştirilmiş bir rapor oraya da gönderilsin mi?\",\n  \"report.hint\": \"Bu rapor sunucu moderatörlerine gönderilecek. Bu hesabı neden bildirdiğiniz hakkında bilgi verebirsiniz:\",\n  \"report.placeholder\": \"Ek yorumlar\",\n  \"report.submit\": \"Gönder\",\n  \"report.target\": \"Raporlama\",\n  \"search.placeholder\": \"Ara\",\n  \"search_popout.search_format\": \"Gelişmiş arama formatı\",\n  \"search_popout.tips.full_text\": \"Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.\",\n  \"search_popout.tips.hashtag\": \"hashtag\",\n  \"search_popout.tips.status\": \"durum\",\n  \"search_popout.tips.text\": \"Simple text returns matching display names, usernames and hashtags\",\n  \"search_popout.tips.user\": \"kullanıcı\",\n  \"search_results.accounts\": \"İnsanlar\",\n  \"search_results.hashtags\": \"Hashtagler\",\n  \"search_results.statuses\": \"Gönderiler\",\n  \"search_results.total\": \"{count, number} {count, plural, one {sonuç} other {sonuçlar}}\",\n  \"status.admin_account\": \"@{name} için denetim arayüzünü açın\",\n  \"status.admin_status\": \"Denetim arayüzünde bu durumu açın\",\n  \"status.block\": \"Engelle : @{name}\",\n  \"status.cancel_reblog_private\": \"Boost'u geri al\",\n  \"status.cannot_reblog\": \"Bu gönderi boost edilemez\",\n  \"status.copy\": \"Bağlantı durumunu kopyala\",\n  \"status.delete\": \"Sil\",\n  \"status.detailed_status\": \"Detaylı yazışma dökümü\",\n  \"status.direct\": \"@{name}'e gönder\",\n  \"status.embed\": \"Gömülü\",\n  \"status.favourite\": \"Favorilere ekle\",\n  \"status.filtered\": \"Filtrelenmiş\",\n  \"status.load_more\": \"Daha fazla\",\n  \"status.media_hidden\": \"Gizli görsel\",\n  \"status.mention\": \"Bahset : @{name}\",\n  \"status.more\": \"Daha fazla\",\n  \"status.mute\": \"Sustur : @{name}\",\n  \"status.mute_conversation\": \"Yazışmayı sustur\",\n  \"status.open\": \"Bu gönderiyi genişlet\",\n  \"status.pin\": \"Profile sabitle\",\n  \"status.pinned\": \"Sabitlenmiş gönderi\",\n  \"status.read_more\": \"Daha dazla oku\",\n  \"status.reblog\": \"Boostla\",\n  \"status.reblog_private\": \"Boost to original audience\",\n  \"status.reblogged_by\": \"{name} boost etti\",\n  \"status.reblogs.empty\": \"Kimse bu gönderiyi boostlamadı. Biri yaptığında burada gözükecek.\",\n  \"status.redraft\": \"Sil & tekrar taslakla\",\n  \"status.reply\": \"Cevapla\",\n  \"status.replyAll\": \"Konuşmayı cevapla\",\n  \"status.report\": \"@{name}'i raporla\",\n  \"status.sensitive_warning\": \"Hassas içerik\",\n  \"status.share\": \"Paylaş\",\n  \"status.show_less\": \"Daha az göster\",\n  \"status.show_less_all\": \"Hepsi için daha az göster\",\n  \"status.show_more\": \"Daha fazla göster\",\n  \"status.show_more_all\": \"Hepsi için daha fazla göster\",\n  \"status.show_thread\": \"Başlığı göster\",\n  \"status.unmute_conversation\": \"Unmute conversation\",\n  \"status.unpin\": \"Profilden sabitlemeyi kaldır\",\n  \"suggestions.dismiss\": \"Öneriyi görmezden gel\",\n  \"suggestions.header\": \"Şuna ilgi duyuyor olabilirsiniz…\",\n  \"tabs_bar.federated_timeline\": \"Federe\",\n  \"tabs_bar.home\": \"Ana sayfa\",\n  \"tabs_bar.local_timeline\": \"Yerel\",\n  \"tabs_bar.notifications\": \"Bildirimler\",\n  \"tabs_bar.search\": \"Ara\",\n  \"time_remaining.days\": \"{number, plural, one {# day} other {# days}} left\",\n  \"time_remaining.hours\": \"{number, plural, one {# hour} other {# hours}} left\",\n  \"time_remaining.minutes\": \"{number, plural, one {# minute} other {# minutes}} left\",\n  \"time_remaining.moments\": \"Moments remaining\",\n  \"time_remaining.seconds\": \"{number, plural, one {# second} other {# seconds}} left\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {person} other {people}} talking\",\n  \"ui.beforeunload\": \"Mastodon'dan ayrılırsanız taslağınız kaybolacak.\",\n  \"upload_area.title\": \"Karşıya yükleme için sürükle bırak yapınız\",\n  \"upload_button.label\": \"Görsel ekle\",\n  \"upload_error.limit\": \"Dosya yükleme sınırı aşıldı.\",\n  \"upload_error.poll\": \"Anketlerde dosya yüklemesine izin verilmez.\",\n  \"upload_form.description\": \"Describe for the visually impaired\",\n  \"upload_form.focus\": \"Kırp\",\n  \"upload_form.undo\": \"Geri al\",\n  \"upload_progress.label\": \"Yükleniyor...\",\n  \"video.close\": \"Videoyu kapat\",\n  \"video.exit_fullscreen\": \"Tam ekrandan çık\",\n  \"video.expand\": \"Videoyu genişlet\",\n  \"video.fullscreen\": \"Tam ekran\",\n  \"video.hide\": \"Videoyu gizle\",\n  \"video.mute\": \"Sesi kıs\",\n  \"video.pause\": \"Duraklat\",\n  \"video.play\": \"Oynat\",\n  \"video.unmute\": \"Sesi aç\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/uk.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Add or Remove from lists\",\n  \"account.badges.bot\": \"Бот\",\n  \"account.block\": \"Заблокувати @{name}\",\n  \"account.block_domain\": \"Заглушити {domain}\",\n  \"account.blocked\": \"Заблоковані\",\n  \"account.direct\": \"Пряме повідомлення @{name}\",\n  \"account.domain_blocked\": \"Домен приховано\",\n  \"account.edit_profile\": \"Редагувати профіль\",\n  \"account.endorse\": \"Feature on profile\",\n  \"account.follow\": \"Підписатися\",\n  \"account.followers\": \"Підписники\",\n  \"account.followers.empty\": \"No one follows this user yet.\",\n  \"account.follows\": \"Підписки\",\n  \"account.follows.empty\": \"This user doesn't follow anyone yet.\",\n  \"account.follows_you\": \"Підписаний(-а) на Вас\",\n  \"account.hide_reblogs\": \"Сховати передмухи від @{name}\",\n  \"account.link_verified_on\": \"Ownership of this link was checked on {date}\",\n  \"account.locked_info\": \"This account privacy status is set to locked. The owner manually reviews who can follow them.\",\n  \"account.media\": \"Медіа\",\n  \"account.mention\": \"Згадати @{name}\",\n  \"account.moved_to\": \"{name} переїхав на:\",\n  \"account.mute\": \"Заглушити @{name}\",\n  \"account.mute_notifications\": \"Не показувати сповіщення від @{name}\",\n  \"account.muted\": \"Заглушений\",\n  \"account.posts\": \"Дмухи\",\n  \"account.posts_with_replies\": \"Дмухи й відповіді\",\n  \"account.report\": \"Поскаржитися на @{name}\",\n  \"account.requested\": \"Очікує підтвердження. Натисніть щоб відмінити запит\",\n  \"account.share\": \"Поширити профіль @{name}\",\n  \"account.show_reblogs\": \"Показати передмухи від @{name}\",\n  \"account.unblock\": \"Розблокувати\",\n  \"account.unblock_domain\": \"Розблокувати {domain}\",\n  \"account.unendorse\": \"Don't feature on profile\",\n  \"account.unfollow\": \"Відписатися\",\n  \"account.unmute\": \"Зняти глушення @{name}\",\n  \"account.unmute_notifications\": \"Показувати сповіщення від @{name}\",\n  \"alert.unexpected.message\": \"Трапилась неочікувана помилка.\",\n  \"alert.unexpected.title\": \"Ой!\",\n  \"boost_modal.combo\": \"Ви можете натиснути {combo}, щоб пропустити це наступного разу\",\n  \"bundle_column_error.body\": \"Щось пішло не так при завантаженні компоненту.\",\n  \"bundle_column_error.retry\": \"Спробуйте ще\",\n  \"bundle_column_error.title\": \"Помилка мережі\",\n  \"bundle_modal_error.close\": \"Закрити\",\n  \"bundle_modal_error.message\": \"Щось пішло не так при завантаженні компоненту.\",\n  \"bundle_modal_error.retry\": \"Спробувати ще\",\n  \"column.blocks\": \"Заблоковані користувачі\",\n  \"column.community\": \"Локальна стрічка\",\n  \"column.direct\": \"Прямі повідомлення\",\n  \"column.domain_blocks\": \"Приховані домени\",\n  \"column.favourites\": \"Вподобане\",\n  \"column.follow_requests\": \"Запити на підписку\",\n  \"column.home\": \"Головна\",\n  \"column.lists\": \"Списки\",\n  \"column.mutes\": \"Заглушені користувачі\",\n  \"column.notifications\": \"Сповіщення\",\n  \"column.pins\": \"Закріплені дмухи\",\n  \"column.public\": \"Глобальна стрічка\",\n  \"column_back_button.label\": \"Назад\",\n  \"column_header.hide_settings\": \"Приховати налаштування\",\n  \"column_header.moveLeft_settings\": \"Move column to the left\",\n  \"column_header.moveRight_settings\": \"Змістити колонку вправо\",\n  \"column_header.pin\": \"Закріпити\",\n  \"column_header.show_settings\": \"Показати налаштування\",\n  \"column_header.unpin\": \"Відкріпити\",\n  \"column_subheading.settings\": \"Налаштування\",\n  \"community.column_settings.media_only\": \"Тільки медіа\",\n  \"compose_form.direct_message_warning\": \"Цей дмух буде видимий тільки згаданим користувачам.\",\n  \"compose_form.direct_message_warning_learn_more\": \"Дізнатись більше\",\n  \"compose_form.hashtag_warning\": \"Цей дмух не буде відображений у жодній стрічці хештеґу, так як він прихований. Тільки публічні дмухи можуть бути знайдені за хештеґом.\",\n  \"compose_form.lock_disclaimer\": \"Ваш акаунт не {locked}. Кожен може підписатися на Вас та бачити Ваші приватні пости.\",\n  \"compose_form.lock_disclaimer.lock\": \"приватний\",\n  \"compose_form.placeholder\": \"Що у Вас на думці?\",\n  \"compose_form.poll.add_option\": \"Add a choice\",\n  \"compose_form.poll.duration\": \"Poll duration\",\n  \"compose_form.poll.option_placeholder\": \"Choice {number}\",\n  \"compose_form.poll.remove_option\": \"Remove this choice\",\n  \"compose_form.publish\": \"Дмухнути\",\n  \"compose_form.publish_loud\": \"{publish}!\",\n  \"compose_form.sensitive.hide\": \"Mark media as sensitive\",\n  \"compose_form.sensitive.marked\": \"Медіа відмічене <b>несприйнятливим</b>\",\n  \"compose_form.sensitive.unmarked\": \"Медіа відмічене сприйнятливим\",\n  \"compose_form.spoiler.marked\": \"Текст приховано за попередженням\",\n  \"compose_form.spoiler.unmarked\": \"Текст видимий\",\n  \"compose_form.spoiler_placeholder\": \"Попередження щодо прихованого тексту\",\n  \"confirmation_modal.cancel\": \"Відмінити\",\n  \"confirmations.block.block_and_report\": \"Block & Report\",\n  \"confirmations.block.confirm\": \"Заблокувати\",\n  \"confirmations.block.message\": \"Ви впевнені, що хочете заблокувати {name}?\",\n  \"confirmations.delete.confirm\": \"Видалити\",\n  \"confirmations.delete.message\": \"Ви впевнені, що хочете видалити цей допис?\",\n  \"confirmations.delete_list.confirm\": \"Видалити\",\n  \"confirmations.delete_list.message\": \"Ви впевнені, що хочете видалити цей список назавжди?\",\n  \"confirmations.domain_block.confirm\": \"Сховати весь домен\",\n  \"confirmations.domain_block.message\": \"Ви точно, точно впевнені, що хочете заблокувати весь домен {domain}? У більшості випадків для нормальної роботи краще заблокувати/заглушити лише деяких користувачів. Ви не зможете бачити контент з цього домену у будь-яких стрічках або ваших сповіщеннях. Ваші підписники з цього домену будуть відписані від вас.\",\n  \"confirmations.mute.confirm\": \"Заглушити\",\n  \"confirmations.mute.message\": \"Ви впевнені, що хочете заглушити {name}?\",\n  \"confirmations.redraft.confirm\": \"Видалити і перестворити\",\n  \"confirmations.redraft.message\": \"Ви впевнені, що хочете видалити допис і перестворити його? Ви втратите всі відповіді, передмухи та вподобайки допису.\",\n  \"confirmations.reply.confirm\": \"Reply\",\n  \"confirmations.reply.message\": \"Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?\",\n  \"confirmations.unfollow.confirm\": \"Відписатися\",\n  \"confirmations.unfollow.message\": \"Ви впевнені, що хочете відписатися від {name}?\",\n  \"embed.instructions\": \"Інтегруйте цей статус на вашому вебсайті, скопіювавши код нижче.\",\n  \"embed.preview\": \"Ось як він виглядатиме:\",\n  \"emoji_button.activity\": \"Заняття\",\n  \"emoji_button.custom\": \"Особливі\",\n  \"emoji_button.flags\": \"Прапори\",\n  \"emoji_button.food\": \"Їжа та напої\",\n  \"emoji_button.label\": \"Вставити емодзі\",\n  \"emoji_button.nature\": \"Природа\",\n  \"emoji_button.not_found\": \"Немає емодзі!! (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"Предмети\",\n  \"emoji_button.people\": \"Люди\",\n  \"emoji_button.recent\": \"Часто використовувані\",\n  \"emoji_button.search\": \"Знайти...\",\n  \"emoji_button.search_results\": \"Результати пошуку\",\n  \"emoji_button.symbols\": \"Символи\",\n  \"emoji_button.travel\": \"Подорожі\",\n  \"empty_column.account_timeline\": \"No toots here!\",\n  \"empty_column.account_unavailable\": \"Profile unavailable\",\n  \"empty_column.blocks\": \"You haven't blocked any users yet.\",\n  \"empty_column.community\": \"Локальна стрічка пуста. Напишіть щось, щоб розігріти народ!\",\n  \"empty_column.direct\": \"У вас ще немає прямих повідомлень. Коли ви відправите чи отримаєте якесь, воно з'явиться тут.\",\n  \"empty_column.domain_blocks\": \"There are no hidden domains yet.\",\n  \"empty_column.favourited_statuses\": \"You don't have any favourite toots yet. When you favourite one, it will show up here.\",\n  \"empty_column.favourites\": \"No one has favourited this toot yet. When someone does, they will show up here.\",\n  \"empty_column.follow_requests\": \"You don't have any follow requests yet. When you receive one, it will show up here.\",\n  \"empty_column.hashtag\": \"Дописів з цим хештегом поки не існує.\",\n  \"empty_column.home\": \"Ви поки ні на кого не підписані. Погортайте {public}, або скористуйтесь пошуком, щоб освоїтися та познайомитися з іншими користувачами.\",\n  \"empty_column.home.public_timeline\": \"публічні стрічки\",\n  \"empty_column.list\": \"Немає нічого в цьому списку. Коли його учасники дмухнуть нові статуси, вони з'являться тут.\",\n  \"empty_column.lists\": \"You don't have any lists yet. When you create one, it will show up here.\",\n  \"empty_column.mutes\": \"You haven't muted any users yet.\",\n  \"empty_column.notifications\": \"У вас ще немає сповіщень. Переписуйтесь з іншими користувачами, щоб почати розмову.\",\n  \"empty_column.public\": \"Тут поки нічого немає! Опублікуйте щось, або вручну підпишіться на користувачів інших інстанцій, щоб заповнити стрічку\",\n  \"follow_request.authorize\": \"Авторизувати\",\n  \"follow_request.reject\": \"Відмовити\",\n  \"getting_started.developers\": \"Розробникам\",\n  \"getting_started.directory\": \"Profile directory\",\n  \"getting_started.documentation\": \"Документація\",\n  \"getting_started.heading\": \"Ласкаво просимо\",\n  \"getting_started.invite\": \"Запросіть людей\",\n  \"getting_started.open_source_notice\": \"Mastodon - програма з відкритим вихідним кодом. Ви можете допомогти проекту, або повідомити про проблеми на GitHub за адресою {github}.\",\n  \"getting_started.security\": \"Безпека\",\n  \"getting_started.terms\": \"Умови використання\",\n  \"hashtag.column_header.tag_mode.all\": \"and {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"or {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"without {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"No suggestions found\",\n  \"hashtag.column_settings.select.placeholder\": \"Enter hashtags…\",\n  \"hashtag.column_settings.tag_mode.all\": \"All of these\",\n  \"hashtag.column_settings.tag_mode.any\": \"Any of these\",\n  \"hashtag.column_settings.tag_mode.none\": \"None of these\",\n  \"hashtag.column_settings.tag_toggle\": \"Include additional tags in this column\",\n  \"home.column_settings.basic\": \"Основні\",\n  \"home.column_settings.show_reblogs\": \"Показувати передмухи\",\n  \"home.column_settings.show_replies\": \"Показувати відповіді\",\n  \"intervals.full.days\": \"{number, plural, one {# day} other {# days}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# hour} other {# hours}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minute} other {# minutes}}\",\n  \"introduction.federation.action\": \"Next\",\n  \"introduction.federation.federated.headline\": \"Federated\",\n  \"introduction.federation.federated.text\": \"Public posts from other servers of the fediverse will appear in the federated timeline.\",\n  \"introduction.federation.home.headline\": \"Home\",\n  \"introduction.federation.home.text\": \"Posts from people you follow will appear in your home feed. You can follow anyone on any server!\",\n  \"introduction.federation.local.headline\": \"Local\",\n  \"introduction.federation.local.text\": \"Public posts from people on the same server as you will appear in the local timeline.\",\n  \"introduction.interactions.action\": \"Finish toot-orial!\",\n  \"introduction.interactions.favourite.headline\": \"Favourite\",\n  \"introduction.interactions.favourite.text\": \"You can save a toot for later, and let the author know that you liked it, by favouriting it.\",\n  \"introduction.interactions.reblog.headline\": \"Boost\",\n  \"introduction.interactions.reblog.text\": \"You can share other people's toots with your followers by boosting them.\",\n  \"introduction.interactions.reply.headline\": \"Reply\",\n  \"introduction.interactions.reply.text\": \"You can reply to other people's and your own toots, which will chain them together in a conversation.\",\n  \"introduction.welcome.action\": \"Let's go!\",\n  \"introduction.welcome.headline\": \"First steps\",\n  \"introduction.welcome.text\": \"Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.\",\n  \"keyboard_shortcuts.back\": \"переходити назад\",\n  \"keyboard_shortcuts.blocked\": \"to open blocked users list\",\n  \"keyboard_shortcuts.boost\": \"передмухувати\",\n  \"keyboard_shortcuts.column\": \"фокусуватися на одній з колонок\",\n  \"keyboard_shortcuts.compose\": \"фокусуватися на полі введення\",\n  \"keyboard_shortcuts.description\": \"Опис\",\n  \"keyboard_shortcuts.direct\": \"to open direct messages column\",\n  \"keyboard_shortcuts.down\": \"рухатися вниз стрічкою\",\n  \"keyboard_shortcuts.enter\": \"відкрити статус\",\n  \"keyboard_shortcuts.favourite\": \"вподобати\",\n  \"keyboard_shortcuts.favourites\": \"to open favourites list\",\n  \"keyboard_shortcuts.federated\": \"to open federated timeline\",\n  \"keyboard_shortcuts.heading\": \"Гарячі клавіші\",\n  \"keyboard_shortcuts.home\": \"to open home timeline\",\n  \"keyboard_shortcuts.hotkey\": \"Гаряча клавіша\",\n  \"keyboard_shortcuts.legend\": \"показати підказку\",\n  \"keyboard_shortcuts.local\": \"to open local timeline\",\n  \"keyboard_shortcuts.mention\": \"згадати автора\",\n  \"keyboard_shortcuts.muted\": \"to open muted users list\",\n  \"keyboard_shortcuts.my_profile\": \"to open your profile\",\n  \"keyboard_shortcuts.notifications\": \"to open notifications column\",\n  \"keyboard_shortcuts.pinned\": \"to open pinned toots list\",\n  \"keyboard_shortcuts.profile\": \"відкрити профіль автора\",\n  \"keyboard_shortcuts.reply\": \"відповісти\",\n  \"keyboard_shortcuts.requests\": \"to open follow requests list\",\n  \"keyboard_shortcuts.search\": \"сфокусуватися на пошуку\",\n  \"keyboard_shortcuts.start\": \"to open \\\"get started\\\" column\",\n  \"keyboard_shortcuts.toggle_hidden\": \"показати/приховати прихований текст\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"to show/hide media\",\n  \"keyboard_shortcuts.toot\": \"почати писати новий дмух\",\n  \"keyboard_shortcuts.unfocus\": \"розфокусуватися з нового допису чи пошуку\",\n  \"keyboard_shortcuts.up\": \"рухатися вверх списком\",\n  \"lightbox.close\": \"Закрити\",\n  \"lightbox.next\": \"Далі\",\n  \"lightbox.previous\": \"Назад\",\n  \"lightbox.view_context\": \"View context\",\n  \"lists.account.add\": \"Додати до списку\",\n  \"lists.account.remove\": \"Видалити зі списку\",\n  \"lists.delete\": \"Видалити список\",\n  \"lists.edit\": \"Редагувати список\",\n  \"lists.edit.submit\": \"Change title\",\n  \"lists.new.create\": \"Додати список\",\n  \"lists.new.title_placeholder\": \"Нова назва списку\",\n  \"lists.search\": \"Шукати серед людей, на яких ви підписані\",\n  \"lists.subheading\": \"Ваші списки\",\n  \"loading_indicator.label\": \"Завантаження...\",\n  \"media_gallery.toggle_visible\": \"Показати/приховати\",\n  \"missing_indicator.label\": \"Не знайдено\",\n  \"missing_indicator.sublabel\": \"Ресурс не знайдений\",\n  \"mute_modal.hide_notifications\": \"Приховати сповіщення від користувача?\",\n  \"navigation_bar.apps\": \"Mobile apps\",\n  \"navigation_bar.blocks\": \"Заблоковані користувачі\",\n  \"navigation_bar.community_timeline\": \"Локальна стрічка\",\n  \"navigation_bar.compose\": \"Compose new toot\",\n  \"navigation_bar.direct\": \"Прямі повідомлення\",\n  \"navigation_bar.discover\": \"Знайти\",\n  \"navigation_bar.domain_blocks\": \"Приховані домени\",\n  \"navigation_bar.edit_profile\": \"Редагувати профіль\",\n  \"navigation_bar.favourites\": \"Вподобане\",\n  \"navigation_bar.filters\": \"Приховані слова\",\n  \"navigation_bar.follow_requests\": \"Запити на підписку\",\n  \"navigation_bar.follows_and_followers\": \"Follows and followers\",\n  \"navigation_bar.info\": \"Про сайт\",\n  \"navigation_bar.keyboard_shortcuts\": \"Гарячі клавіши\",\n  \"navigation_bar.lists\": \"Списки\",\n  \"navigation_bar.logout\": \"Вийти\",\n  \"navigation_bar.mutes\": \"Заглушені користувачі\",\n  \"navigation_bar.personal\": \"Особисте\",\n  \"navigation_bar.pins\": \"Закріплені дмухи\",\n  \"navigation_bar.preferences\": \"Налаштування\",\n  \"navigation_bar.profile_directory\": \"Profile directory\",\n  \"navigation_bar.public_timeline\": \"Глобальна стрічка\",\n  \"navigation_bar.security\": \"Безпека\",\n  \"notification.favourite\": \"{name} вподобав(-ла) ваш допис\",\n  \"notification.follow\": \"{name} підписався(-лась) на Вас\",\n  \"notification.mention\": \"{name} згадав(-ла) Вас\",\n  \"notification.poll\": \"A poll you have voted in has ended\",\n  \"notification.reblog\": \"{name} передмухнув(-ла) Ваш допис\",\n  \"notifications.clear\": \"Очистити сповіщення\",\n  \"notifications.clear_confirmation\": \"Ви впевнені, що хочете назавжди видалити всі сповіщеня?\",\n  \"notifications.column_settings.alert\": \"Сповіщення на комп'ютері\",\n  \"notifications.column_settings.favourite\": \"Вподобане:\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Display all categories\",\n  \"notifications.column_settings.filter_bar.category\": \"Quick filter bar\",\n  \"notifications.column_settings.filter_bar.show\": \"Show\",\n  \"notifications.column_settings.follow\": \"Нові підписники:\",\n  \"notifications.column_settings.mention\": \"Згадки:\",\n  \"notifications.column_settings.poll\": \"Poll results:\",\n  \"notifications.column_settings.push\": \"Push-сповіщення\",\n  \"notifications.column_settings.reblog\": \"Передмухи:\",\n  \"notifications.column_settings.show\": \"Показати в колонці\",\n  \"notifications.column_settings.sound\": \"Відтворювати звуки\",\n  \"notifications.filter.all\": \"All\",\n  \"notifications.filter.boosts\": \"Boosts\",\n  \"notifications.filter.favourites\": \"Favourites\",\n  \"notifications.filter.follows\": \"Follows\",\n  \"notifications.filter.mentions\": \"Mentions\",\n  \"notifications.filter.polls\": \"Poll results\",\n  \"notifications.group\": \"{count} сповіщень\",\n  \"poll.closed\": \"Closed\",\n  \"poll.refresh\": \"Refresh\",\n  \"poll.total_votes\": \"{count, plural, one {# vote} other {# votes}}\",\n  \"poll.vote\": \"Vote\",\n  \"poll_button.add_poll\": \"Add a poll\",\n  \"poll_button.remove_poll\": \"Remove poll\",\n  \"privacy.change\": \"Змінити видимість допису\",\n  \"privacy.direct.long\": \"Показати тільки згаданим користувачам\",\n  \"privacy.direct.short\": \"Направлений\",\n  \"privacy.private.long\": \"Показати тільки підписникам\",\n  \"privacy.private.short\": \"Тільки для підписників\",\n  \"privacy.public.long\": \"Показувати у публічних стрічках\",\n  \"privacy.public.short\": \"Публічний\",\n  \"privacy.unlisted.long\": \"Не показувати у публічних стрічках\",\n  \"privacy.unlisted.short\": \"Прихований\",\n  \"regeneration_indicator.label\": \"Завантаження…\",\n  \"regeneration_indicator.sublabel\": \"Ваша домашня стрічка готова!\",\n  \"relative_time.days\": \"{number}д\",\n  \"relative_time.hours\": \"{number}г\",\n  \"relative_time.just_now\": \"щойно\",\n  \"relative_time.minutes\": \"{number}х\",\n  \"relative_time.seconds\": \"{number}с\",\n  \"reply_indicator.cancel\": \"Відмінити\",\n  \"report.forward\": \"Надіслати до {target}\",\n  \"report.forward_hint\": \"Це аккаунт з іншого серверу. Відправити анонімізовану копію скарги і туди?\",\n  \"report.hint\": \"Скаргу буде відправлено модераторам Вашого сайту. Ви можете надати їм пояснення, чому ви скаржитесь на аккаунт нижче:\",\n  \"report.placeholder\": \"Додаткові коментарі\",\n  \"report.submit\": \"Відправити\",\n  \"report.target\": \"Скаржимося на\",\n  \"search.placeholder\": \"Пошук\",\n  \"search_popout.search_format\": \"Advanced search format\",\n  \"search_popout.tips.full_text\": \"Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.\",\n  \"search_popout.tips.hashtag\": \"hashtag\",\n  \"search_popout.tips.status\": \"status\",\n  \"search_popout.tips.text\": \"Simple text returns matching display names, usernames and hashtags\",\n  \"search_popout.tips.user\": \"user\",\n  \"search_results.accounts\": \"People\",\n  \"search_results.hashtags\": \"Hashtags\",\n  \"search_results.statuses\": \"Toots\",\n  \"search_results.total\": \"{count, number} {count, plural, one {результат} few {результати} many {результатів} other {результатів}}\",\n  \"status.admin_account\": \"Open moderation interface for @{name}\",\n  \"status.admin_status\": \"Open this status in the moderation interface\",\n  \"status.block\": \"Block @{name}\",\n  \"status.cancel_reblog_private\": \"Unboost\",\n  \"status.cannot_reblog\": \"Цей допис не може бути передмухнутий\",\n  \"status.copy\": \"Copy link to status\",\n  \"status.delete\": \"Видалити\",\n  \"status.detailed_status\": \"Detailed conversation view\",\n  \"status.direct\": \"Direct message @{name}\",\n  \"status.embed\": \"Embed\",\n  \"status.favourite\": \"Подобається\",\n  \"status.filtered\": \"Filtered\",\n  \"status.load_more\": \"Завантажити більше\",\n  \"status.media_hidden\": \"Медіаконтент приховано\",\n  \"status.mention\": \"Згадати\",\n  \"status.more\": \"More\",\n  \"status.mute\": \"Mute @{name}\",\n  \"status.mute_conversation\": \"Заглушити діалог\",\n  \"status.open\": \"Розгорнути допис\",\n  \"status.pin\": \"Pin on profile\",\n  \"status.pinned\": \"Pinned toot\",\n  \"status.read_more\": \"Read more\",\n  \"status.reblog\": \"Передмухнути\",\n  \"status.reblog_private\": \"Boost to original audience\",\n  \"status.reblogged_by\": \"{name} передмухнув(-ла)\",\n  \"status.reblogs.empty\": \"No one has boosted this toot yet. When someone does, they will show up here.\",\n  \"status.redraft\": \"Delete & re-draft\",\n  \"status.reply\": \"Відповісти\",\n  \"status.replyAll\": \"Відповісти на тред\",\n  \"status.report\": \"Поскаржитися\",\n  \"status.sensitive_warning\": \"Непристойний зміст\",\n  \"status.share\": \"Share\",\n  \"status.show_less\": \"Згорнути\",\n  \"status.show_less_all\": \"Show less for all\",\n  \"status.show_more\": \"Розгорнути\",\n  \"status.show_more_all\": \"Show more for all\",\n  \"status.show_thread\": \"Show thread\",\n  \"status.unmute_conversation\": \"Зняти глушення з діалогу\",\n  \"status.unpin\": \"Unpin from profile\",\n  \"suggestions.dismiss\": \"Dismiss suggestion\",\n  \"suggestions.header\": \"You might be interested in…\",\n  \"tabs_bar.federated_timeline\": \"Глобальна\",\n  \"tabs_bar.home\": \"Головна\",\n  \"tabs_bar.local_timeline\": \"Локальна\",\n  \"tabs_bar.notifications\": \"Сповіщення\",\n  \"tabs_bar.search\": \"Пошук\",\n  \"time_remaining.days\": \"{number, plural, one {# day} other {# days}} left\",\n  \"time_remaining.hours\": \"{number, plural, one {# hour} other {# hours}} left\",\n  \"time_remaining.minutes\": \"{number, plural, one {# minute} other {# minutes}} left\",\n  \"time_remaining.moments\": \"Moments remaining\",\n  \"time_remaining.seconds\": \"{number, plural, one {# second} other {# seconds}} left\",\n  \"trends.count_by_accounts\": \"{count} {rawCount, plural, one {person} other {people}} talking\",\n  \"ui.beforeunload\": \"Вашу чернетку буде втрачено, якщо ви покинете Mastodon.\",\n  \"upload_area.title\": \"Перетягніть сюди, щоб завантажити\",\n  \"upload_button.label\": \"Додати медіаконтент\",\n  \"upload_error.limit\": \"File upload limit exceeded.\",\n  \"upload_error.poll\": \"File upload not allowed with polls.\",\n  \"upload_form.description\": \"Опишіть для людей з вадами зору\",\n  \"upload_form.focus\": \"Обрізати\",\n  \"upload_form.undo\": \"Видалити\",\n  \"upload_progress.label\": \"Завантаження...\",\n  \"video.close\": \"Закрити відео\",\n  \"video.exit_fullscreen\": \"Вийти з повного екрану\",\n  \"video.expand\": \"Розширити відео\",\n  \"video.fullscreen\": \"На весь екран\",\n  \"video.hide\": \"Приховати відео\",\n  \"video.mute\": \"Вимкнути звук\",\n  \"video.pause\": \"Призупинити\",\n  \"video.play\": \"Програвати\",\n  \"video.unmute\": \"Увімкнути звук\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_ar.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_ast.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_bg.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_bn.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_ca.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_co.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_cs.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_cy.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_da.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_de.json",
    "content": "[\n  \"relative_time.seconds\",\n  \"relative_time.minutes\",\n  \"relative_time.hours\",\n  \"relative_time.days\",\n  \"account.badges.bot\",\n  \"compose_form.publish_loud\",\n  \"search_results.hashtags\"\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_el.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_en.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_eo.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_es.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_eu.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_fa.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_fi.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_fr.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_gl.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_he.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_hi.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_hr.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_hu.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_hy.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_id.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_io.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_it.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_ja.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_ka.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_kk.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_ko.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_lt.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_lv.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_ms.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_nl.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_no.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_oc.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_pl.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_pt-BR.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_pt.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_ro.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_ru.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_sk.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_sl.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_sq.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_sr-Latn.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_sr.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_sv.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_ta.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_te.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_th.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_tr.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_uk.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_zh-CN.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_zh-HK.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/whitelist_zh-TW.json",
    "content": "[\n]\n"
  },
  {
    "path": "app/javascript/mastodon/locales/zh-CN.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"从列表中添加或删除\",\n  \"account.badges.bot\": \"机器人\",\n  \"account.block\": \"屏蔽 @{name}\",\n  \"account.block_domain\": \"隐藏来自 {domain} 的内容\",\n  \"account.blocked\": \"已屏蔽\",\n  \"account.direct\": \"发送私信给 @{name}\",\n  \"account.domain_blocked\": \"网站已屏蔽\",\n  \"account.edit_profile\": \"修改个人资料\",\n  \"account.endorse\": \"在个人资料中推荐此用户\",\n  \"account.follow\": \"关注\",\n  \"account.followers\": \"关注者\",\n  \"account.followers.empty\": \"目前无人关注此用户。\",\n  \"account.follows\": \"正在关注\",\n  \"account.follows.empty\": \"此用户目前没有关注任何人。\",\n  \"account.follows_you\": \"关注了你\",\n  \"account.hide_reblogs\": \"隐藏来自 @{name} 的转嘟\",\n  \"account.link_verified_on\": \"此链接的所有权已在 {date} 检查\",\n  \"account.locked_info\": \"此账户已锁嘟。账户的主人会手动审核关注者。\",\n  \"account.media\": \"媒体\",\n  \"account.mention\": \"提及 @{name}\",\n  \"account.moved_to\": \"{name} 已经迁移到：\",\n  \"account.mute\": \"隐藏 @{name}\",\n  \"account.mute_notifications\": \"隐藏来自 @{name} 的通知\",\n  \"account.muted\": \"已隐藏\",\n  \"account.posts\": \"嘟文\",\n  \"account.posts_with_replies\": \"嘟文和回复\",\n  \"account.report\": \"举报 @{name}\",\n  \"account.requested\": \"正在等待对方同意。点击以取消发送关注请求\",\n  \"account.share\": \"分享 @{name} 的个人资料\",\n  \"account.show_reblogs\": \"显示来自 @{name} 的转嘟\",\n  \"account.unblock\": \"不再屏蔽 @{name}\",\n  \"account.unblock_domain\": \"不再隐藏来自 {domain} 的内容\",\n  \"account.unendorse\": \"不在个人资料中推荐此用户\",\n  \"account.unfollow\": \"取消关注\",\n  \"account.unmute\": \"不再隐藏 @{name}\",\n  \"account.unmute_notifications\": \"不再隐藏来自 @{name} 的通知\",\n  \"alert.unexpected.message\": \"发生了意外错误。\",\n  \"alert.unexpected.title\": \"哎呀！\",\n  \"boost_modal.combo\": \"下次按住 {combo} 即可跳过此提示\",\n  \"bundle_column_error.body\": \"载入这个组件时发生了错误。\",\n  \"bundle_column_error.retry\": \"重试\",\n  \"bundle_column_error.title\": \"网络错误\",\n  \"bundle_modal_error.close\": \"关闭\",\n  \"bundle_modal_error.message\": \"载入这个组件时发生了错误。\",\n  \"bundle_modal_error.retry\": \"重试\",\n  \"column.blocks\": \"已屏蔽的用户\",\n  \"column.community\": \"本站时间轴\",\n  \"column.direct\": \"私信\",\n  \"column.domain_blocks\": \"已屏蔽的网站\",\n  \"column.favourites\": \"收藏过的嘟文\",\n  \"column.follow_requests\": \"关注请求\",\n  \"column.home\": \"主页\",\n  \"column.lists\": \"列表\",\n  \"column.mutes\": \"已隐藏的用户\",\n  \"column.notifications\": \"通知\",\n  \"column.pins\": \"置顶嘟文\",\n  \"column.public\": \"跨站公共时间轴\",\n  \"column_back_button.label\": \"返回\",\n  \"column_header.hide_settings\": \"隐藏设置\",\n  \"column_header.moveLeft_settings\": \"将此栏左移\",\n  \"column_header.moveRight_settings\": \"将此栏右移\",\n  \"column_header.pin\": \"固定\",\n  \"column_header.show_settings\": \"显示设置\",\n  \"column_header.unpin\": \"取消固定\",\n  \"column_subheading.settings\": \"设置\",\n  \"community.column_settings.media_only\": \"仅媒体\",\n  \"compose_form.direct_message_warning\": \"这条嘟文仅对所有被提及的用户可见。\",\n  \"compose_form.direct_message_warning_learn_more\": \"了解详情\",\n  \"compose_form.hashtag_warning\": \"这条嘟文被设置为“不公开”，因此它不会出现在任何话题标签的列表下。只有公开的嘟文才能通过话题标签进行搜索。\",\n  \"compose_form.lock_disclaimer\": \"你的帐户没有{locked}。任何人都可以在关注你后立即查看仅关注者可见的嘟文。\",\n  \"compose_form.lock_disclaimer.lock\": \"开启保护\",\n  \"compose_form.placeholder\": \"在想啥？\",\n  \"compose_form.poll.add_option\": \"添加一个选项\",\n  \"compose_form.poll.duration\": \"投票持续时间\",\n  \"compose_form.poll.option_placeholder\": \"选项 {number}\",\n  \"compose_form.poll.remove_option\": \"移除这个选项\",\n  \"compose_form.publish\": \"嘟嘟\",\n  \"compose_form.publish_loud\": \"{publish}！\",\n  \"compose_form.sensitive.hide\": \"标记媒体为敏感内容\",\n  \"compose_form.sensitive.marked\": \"媒体已被标记为敏感内容\",\n  \"compose_form.sensitive.unmarked\": \"媒体未被标记为敏感内容\",\n  \"compose_form.spoiler.marked\": \"正文已被折叠在警告信息之后\",\n  \"compose_form.spoiler.unmarked\": \"正文未被折叠\",\n  \"compose_form.spoiler_placeholder\": \"折叠部分的警告消息\",\n  \"confirmation_modal.cancel\": \"取消\",\n  \"confirmations.block.block_and_report\": \"屏蔽与举报\",\n  \"confirmations.block.confirm\": \"屏蔽\",\n  \"confirmations.block.message\": \"你确定要屏蔽 {name} 吗？\",\n  \"confirmations.delete.confirm\": \"删除\",\n  \"confirmations.delete.message\": \"你确定要删除这条嘟文吗？\",\n  \"confirmations.delete_list.confirm\": \"删除\",\n  \"confirmations.delete_list.message\": \"你确定要永久删除这个列表吗？\",\n  \"confirmations.domain_block.confirm\": \"隐藏整个网站的内容\",\n  \"confirmations.domain_block.message\": \"你真的确定要隐藏所有来自 {domain} 的内容吗？多数情况下，屏蔽或隐藏几个特定的用户应该就能满足你的需要了。来自该网站的内容将不再出现在你的公共时间轴或通知列表里。来自该网站的关注者将会被移除。\",\n  \"confirmations.mute.confirm\": \"隐藏\",\n  \"confirmations.mute.message\": \"你确定要隐藏 {name} 吗？\",\n  \"confirmations.redraft.confirm\": \"删除并重新编辑\",\n  \"confirmations.redraft.message\": \"你确定要删除这条嘟文并重新编辑它吗？所有相关的转嘟和收藏都会被清除，回复将会被孤立。\",\n  \"confirmations.reply.confirm\": \"回复\",\n  \"confirmations.reply.message\": \"回复此消息会覆盖掉当前正在编辑的消息。确定继续吗？\",\n  \"confirmations.unfollow.confirm\": \"取消关注\",\n  \"confirmations.unfollow.message\": \"你确定要取消关注 {name} 吗？\",\n  \"embed.instructions\": \"要在你的网站上嵌入这条嘟文，请复制以下代码。\",\n  \"embed.preview\": \"它会像这样显示出来：\",\n  \"emoji_button.activity\": \"活动\",\n  \"emoji_button.custom\": \"自定义\",\n  \"emoji_button.flags\": \"旗帜\",\n  \"emoji_button.food\": \"食物和饮料\",\n  \"emoji_button.label\": \"加入表情符号\",\n  \"emoji_button.nature\": \"自然\",\n  \"emoji_button.not_found\": \"木有这个表情符号！(╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"物体\",\n  \"emoji_button.people\": \"人物\",\n  \"emoji_button.recent\": \"常用\",\n  \"emoji_button.search\": \"搜索…\",\n  \"emoji_button.search_results\": \"搜索结果\",\n  \"emoji_button.symbols\": \"符号\",\n  \"emoji_button.travel\": \"旅行和地点\",\n  \"empty_column.account_timeline\": \"这里没有嘟文！\",\n  \"empty_column.account_unavailable\": \"个人资料不可用\",\n  \"empty_column.blocks\": \"你目前没有屏蔽任何用户。\",\n  \"empty_column.community\": \"本站时间轴暂时没有内容，快嘟几个来抢头香啊！\",\n  \"empty_column.direct\": \"你还没有使用过私信。当你发出或者收到私信时，它会在这里显示。\",\n  \"empty_column.domain_blocks\": \"目前没有被隐藏的站点。\",\n  \"empty_column.favourited_statuses\": \"你还没有收藏过任何嘟文。收藏过的嘟文会显示在这里。\",\n  \"empty_column.favourites\": \"没人收藏过这条嘟文。假如有人收藏了，就会显示在这里。\",\n  \"empty_column.follow_requests\": \"你没有收到新的关注请求。收到了之后就会显示在这里。\",\n  \"empty_column.hashtag\": \"这个话题标签下暂时没有内容。\",\n  \"empty_column.home\": \"你还没有关注任何用户。快看看{public}，向其他用户搭讪吧。\",\n  \"empty_column.home.public_timeline\": \"公共时间轴\",\n  \"empty_column.list\": \"这个列表中暂时没有内容。列表中用户所发送的的新嘟文将会在这里显示。\",\n  \"empty_column.lists\": \"你没有创建过列表。你创建的列表会在这里显示。\",\n  \"empty_column.mutes\": \"你没有隐藏任何用户。\",\n  \"empty_column.notifications\": \"你还没有收到过任何通知，快向其他用户搭讪吧。\",\n  \"empty_column.public\": \"这里什么都没有！写一些公开的嘟文，或者关注其他服务器的用户后，这里就会有嘟文出现了\",\n  \"follow_request.authorize\": \"同意\",\n  \"follow_request.reject\": \"拒绝\",\n  \"getting_started.developers\": \"开发\",\n  \"getting_started.directory\": \"用户资料目录\",\n  \"getting_started.documentation\": \"文档\",\n  \"getting_started.heading\": \"开始使用\",\n  \"getting_started.invite\": \"邀请用户\",\n  \"getting_started.open_source_notice\": \"Mastodon 是一个开源软件。欢迎前往 GitHub（{github}）贡献代码或反馈问题。\",\n  \"getting_started.security\": \"帐户安全\",\n  \"getting_started.terms\": \"使用条款\",\n  \"hashtag.column_header.tag_mode.all\": \"以及 {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"或是 {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"而不用 {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"没有找到建议\",\n  \"hashtag.column_settings.select.placeholder\": \"输入话题标签…\",\n  \"hashtag.column_settings.tag_mode.all\": \"全部\",\n  \"hashtag.column_settings.tag_mode.any\": \"任一\",\n  \"hashtag.column_settings.tag_mode.none\": \"全都不要\",\n  \"hashtag.column_settings.tag_toggle\": \"在此栏加入额外的标签\",\n  \"home.column_settings.basic\": \"基本设置\",\n  \"home.column_settings.show_reblogs\": \"显示转嘟\",\n  \"home.column_settings.show_replies\": \"显示回复\",\n  \"intervals.full.days\": \"{number} 天\",\n  \"intervals.full.hours\": \"{number} 小时\",\n  \"intervals.full.minutes\": \"{number} 分钟\",\n  \"introduction.federation.action\": \"下一步\",\n  \"introduction.federation.federated.headline\": \"跨站\",\n  \"introduction.federation.federated.text\": \"其他跨站服务器的公共动态会显示在跨站时间线中。\",\n  \"introduction.federation.home.headline\": \"主页\",\n  \"introduction.federation.home.text\": \"你所关注的用户的动态会显示在主页里。你可以关注任何服务器上的任何人!\",\n  \"introduction.federation.local.headline\": \"本站\",\n  \"introduction.federation.local.text\": \"你所关注的用户的动态会显示在主页里，你可以关注任何服务器上的任何人。\",\n  \"introduction.interactions.action\": \"教程结束！\",\n  \"introduction.interactions.favourite.headline\": \"收藏\",\n  \"introduction.interactions.favourite.text\": \"你可以保存嘟文以便以后阅读。或者通过收藏功能告诉作者你点了个赞。\",\n  \"introduction.interactions.reblog.headline\": \"转嘟\",\n  \"introduction.interactions.reblog.text\": \"通过转嘟，你可以向你的关注者分享其他人的嘟文。\",\n  \"introduction.interactions.reply.headline\": \"回复\",\n  \"introduction.interactions.reply.text\": \"你可以向其他人回复，这些回复会像对话一样串在一起。\",\n  \"introduction.welcome.action\": \"让我们开始吧！\",\n  \"introduction.welcome.headline\": \"首先\",\n  \"introduction.welcome.text\": \"欢迎来到联邦！稍后，您将可以广播消息冰河您的朋友交流，这些消息将穿越于联邦中的各式服务器。但是这台服务器，{domain}，是特殊的——它保存了你的个人资料，所以请记住它的名字。\",\n  \"keyboard_shortcuts.back\": \"返回上一页\",\n  \"keyboard_shortcuts.blocked\": \"打开被屏蔽用户列表\",\n  \"keyboard_shortcuts.boost\": \"转嘟\",\n  \"keyboard_shortcuts.column\": \"选择某一栏中的嘟文\",\n  \"keyboard_shortcuts.compose\": \"选择嘟文撰写框\",\n  \"keyboard_shortcuts.description\": \"说明\",\n  \"keyboard_shortcuts.direct\": \"打开私信栏\",\n  \"keyboard_shortcuts.down\": \"在列表中让光标下移\",\n  \"keyboard_shortcuts.enter\": \"展开嘟文\",\n  \"keyboard_shortcuts.favourite\": \"收藏嘟文\",\n  \"keyboard_shortcuts.favourites\": \"打开收藏列表\",\n  \"keyboard_shortcuts.federated\": \"打开跨站时间线\",\n  \"keyboard_shortcuts.heading\": \"快捷键列表\",\n  \"keyboard_shortcuts.home\": \"打开主页时间线\",\n  \"keyboard_shortcuts.hotkey\": \"快捷键\",\n  \"keyboard_shortcuts.legend\": \"显示此列表\",\n  \"keyboard_shortcuts.local\": \"打开本站时间线\",\n  \"keyboard_shortcuts.mention\": \"提及嘟文作者\",\n  \"keyboard_shortcuts.muted\": \"打开屏蔽用户列表\",\n  \"keyboard_shortcuts.my_profile\": \"打开你的个人资料\",\n  \"keyboard_shortcuts.notifications\": \"打卡通知栏\",\n  \"keyboard_shortcuts.pinned\": \"打开置顶嘟文列表\",\n  \"keyboard_shortcuts.profile\": \"打开作者的个人资料\",\n  \"keyboard_shortcuts.reply\": \"回复嘟文\",\n  \"keyboard_shortcuts.requests\": \"打开关注请求列表\",\n  \"keyboard_shortcuts.search\": \"选择搜索框\",\n  \"keyboard_shortcuts.start\": \"打开“开始使用”栏\",\n  \"keyboard_shortcuts.toggle_hidden\": \"显示或隐藏被折叠的正文\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"显示/隐藏媒体\",\n  \"keyboard_shortcuts.toot\": \"发送新嘟文\",\n  \"keyboard_shortcuts.unfocus\": \"取消输入\",\n  \"keyboard_shortcuts.up\": \"在列表中让光标上移\",\n  \"lightbox.close\": \"关闭\",\n  \"lightbox.next\": \"下一个\",\n  \"lightbox.previous\": \"上一个\",\n  \"lightbox.view_context\": \"查看上下文\",\n  \"lists.account.add\": \"添加到列表\",\n  \"lists.account.remove\": \"从列表中删除\",\n  \"lists.delete\": \"删除列表\",\n  \"lists.edit\": \"编辑列表\",\n  \"lists.edit.submit\": \"更改标题\",\n  \"lists.new.create\": \"新建列表\",\n  \"lists.new.title_placeholder\": \"新列表的标题\",\n  \"lists.search\": \"搜索你关注的人\",\n  \"lists.subheading\": \"你的列表\",\n  \"loading_indicator.label\": \"加载中……\",\n  \"media_gallery.toggle_visible\": \"切换显示/隐藏\",\n  \"missing_indicator.label\": \"找不到内容\",\n  \"missing_indicator.sublabel\": \"无法找到此资源\",\n  \"mute_modal.hide_notifications\": \"同时隐藏来自这个用户的通知？\",\n  \"navigation_bar.apps\": \"移动应用\",\n  \"navigation_bar.blocks\": \"已屏蔽的用户\",\n  \"navigation_bar.community_timeline\": \"本站时间轴\",\n  \"navigation_bar.compose\": \"撰写新嘟文\",\n  \"navigation_bar.direct\": \"私信\",\n  \"navigation_bar.discover\": \"发现\",\n  \"navigation_bar.domain_blocks\": \"已屏蔽的网站\",\n  \"navigation_bar.edit_profile\": \"修改个人资料\",\n  \"navigation_bar.favourites\": \"收藏的内容\",\n  \"navigation_bar.filters\": \"被隐藏的词\",\n  \"navigation_bar.follow_requests\": \"关注请求\",\n  \"navigation_bar.follows_and_followers\": \"正在关注以及关注者\",\n  \"navigation_bar.info\": \"关于本站\",\n  \"navigation_bar.keyboard_shortcuts\": \"快捷键列表\",\n  \"navigation_bar.lists\": \"列表\",\n  \"navigation_bar.logout\": \"注销\",\n  \"navigation_bar.mutes\": \"已隐藏的用户\",\n  \"navigation_bar.personal\": \"个人\",\n  \"navigation_bar.pins\": \"置顶嘟文\",\n  \"navigation_bar.preferences\": \"首选项\",\n  \"navigation_bar.profile_directory\": \"用户资料目录\",\n  \"navigation_bar.public_timeline\": \"跨站公共时间轴\",\n  \"navigation_bar.security\": \"安全\",\n  \"notification.favourite\": \"{name} 收藏了你的嘟文\",\n  \"notification.follow\": \"{name} 开始关注你\",\n  \"notification.mention\": \"{name} 提及你\",\n  \"notification.poll\": \"你参与的一个投票已经结束\",\n  \"notification.reblog\": \"{name} 转嘟了你的嘟文\",\n  \"notifications.clear\": \"清空通知列表\",\n  \"notifications.clear_confirmation\": \"你确定要永久清空通知列表吗？\",\n  \"notifications.column_settings.alert\": \"桌面通知\",\n  \"notifications.column_settings.favourite\": \"当你的嘟文被收藏时：\",\n  \"notifications.column_settings.filter_bar.advanced\": \"显示所有类别\",\n  \"notifications.column_settings.filter_bar.category\": \"快速过滤栏\",\n  \"notifications.column_settings.filter_bar.show\": \"显示\",\n  \"notifications.column_settings.follow\": \"当有人关注你时：\",\n  \"notifications.column_settings.mention\": \"当有人在嘟文中提及你时：\",\n  \"notifications.column_settings.poll\": \"投票结果：\",\n  \"notifications.column_settings.push\": \"推送通知\",\n  \"notifications.column_settings.reblog\": \"当有人转嘟了你的嘟文时：\",\n  \"notifications.column_settings.show\": \"在通知栏显示\",\n  \"notifications.column_settings.sound\": \"播放音效\",\n  \"notifications.filter.all\": \"全部\",\n  \"notifications.filter.boosts\": \"转嘟\",\n  \"notifications.filter.favourites\": \"收藏\",\n  \"notifications.filter.follows\": \"关注\",\n  \"notifications.filter.mentions\": \"提及\",\n  \"notifications.filter.polls\": \"投票结果\",\n  \"notifications.group\": \"{count} 条通知\",\n  \"poll.closed\": \"已关闭\",\n  \"poll.refresh\": \"刷新\",\n  \"poll.total_votes\": \"{count} 票\",\n  \"poll.vote\": \"投票\",\n  \"poll_button.add_poll\": \"发起投票\",\n  \"poll_button.remove_poll\": \"移除投票\",\n  \"privacy.change\": \"设置嘟文可见范围\",\n  \"privacy.direct.long\": \"只有被提及的用户能看到\",\n  \"privacy.direct.short\": \"私信\",\n  \"privacy.private.long\": \"只有关注你的用户能看到\",\n  \"privacy.private.short\": \"仅关注者\",\n  \"privacy.public.long\": \"所有人可见，并会出现在公共时间轴上\",\n  \"privacy.public.short\": \"公开\",\n  \"privacy.unlisted.long\": \"所有人可见，但不会出现在公共时间轴上\",\n  \"privacy.unlisted.short\": \"不公开\",\n  \"regeneration_indicator.label\": \"加载中……\",\n  \"regeneration_indicator.sublabel\": \"你的主页时间轴正在准备中！\",\n  \"relative_time.days\": \"{number}天\",\n  \"relative_time.hours\": \"{number}时\",\n  \"relative_time.just_now\": \"刚刚\",\n  \"relative_time.minutes\": \"{number}分\",\n  \"relative_time.seconds\": \"{number}秒\",\n  \"reply_indicator.cancel\": \"取消\",\n  \"report.forward\": \"发送举报至 {target}\",\n  \"report.forward_hint\": \"这名用户来自另一个服务器。是否要向那个服务器发送一条匿名的举报？\",\n  \"report.hint\": \"举报将会发送给你所在服务器的监察员。你可以在下面填写举报这个用户的理由：\",\n  \"report.placeholder\": \"附言\",\n  \"report.submit\": \"提交\",\n  \"report.target\": \"举报 {target}\",\n  \"search.placeholder\": \"搜索\",\n  \"search_popout.search_format\": \"高级搜索格式\",\n  \"search_popout.tips.full_text\": \"输入其他内容将会返回所有你撰写、收藏、转嘟过或提及到你的嘟文，同时也会在用户名、昵称和话题标签中进行搜索。\",\n  \"search_popout.tips.hashtag\": \"话题标签\",\n  \"search_popout.tips.status\": \"嘟文\",\n  \"search_popout.tips.text\": \"输入其他内容将会返回昵称、用户名和话题标签\",\n  \"search_popout.tips.user\": \"用户\",\n  \"search_results.accounts\": \"用户\",\n  \"search_results.hashtags\": \"话题标签\",\n  \"search_results.statuses\": \"嘟文\",\n  \"search_results.total\": \"共 {count, number} 个结果\",\n  \"status.admin_account\": \"打开 @{name} 的管理界面\",\n  \"status.admin_status\": \"打开这条嘟文的管理界面\",\n  \"status.block\": \"屏蔽 @{name}\",\n  \"status.cancel_reblog_private\": \"取消转嘟\",\n  \"status.cannot_reblog\": \"无法转嘟这条嘟文\",\n  \"status.copy\": \"复制链接到嘟文中\",\n  \"status.delete\": \"删除\",\n  \"status.detailed_status\": \"对话详情\",\n  \"status.direct\": \"发送私信给 @{name}\",\n  \"status.embed\": \"嵌入\",\n  \"status.favourite\": \"收藏\",\n  \"status.filtered\": \"已过滤\",\n  \"status.load_more\": \"加载更多\",\n  \"status.media_hidden\": \"隐藏媒体内容\",\n  \"status.mention\": \"提及 @{name}\",\n  \"status.more\": \"更多\",\n  \"status.mute\": \"隐藏 @{name}\",\n  \"status.mute_conversation\": \"隐藏此对话\",\n  \"status.open\": \"展开嘟文\",\n  \"status.pin\": \"在个人资料页面置顶\",\n  \"status.pinned\": \"置顶嘟文\",\n  \"status.read_more\": \"阅读全文\",\n  \"status.reblog\": \"转嘟\",\n  \"status.reblog_private\": \"转嘟给原有关注者\",\n  \"status.reblogged_by\": \"{name} 转嘟了\",\n  \"status.reblogs.empty\": \"无人转嘟此条。如果有人转嘟了，就会显示在这里。\",\n  \"status.redraft\": \"删除并重新编辑\",\n  \"status.reply\": \"回复\",\n  \"status.replyAll\": \"回复所有人\",\n  \"status.report\": \"举报 @{name}\",\n  \"status.sensitive_warning\": \"敏感内容\",\n  \"status.share\": \"分享\",\n  \"status.show_less\": \"隐藏内容\",\n  \"status.show_less_all\": \"隐藏所有内容\",\n  \"status.show_more\": \"显示内容\",\n  \"status.show_more_all\": \"显示所有内容\",\n  \"status.show_thread\": \"显示全部对话\",\n  \"status.unmute_conversation\": \"不再隐藏此对话\",\n  \"status.unpin\": \"在个人资料页面取消置顶\",\n  \"suggestions.dismiss\": \"关闭建议\",\n  \"suggestions.header\": \"您可能会感兴趣…\",\n  \"tabs_bar.federated_timeline\": \"跨站\",\n  \"tabs_bar.home\": \"主页\",\n  \"tabs_bar.local_timeline\": \"本站\",\n  \"tabs_bar.notifications\": \"通知\",\n  \"tabs_bar.search\": \"搜索\",\n  \"time_remaining.days\": \"剩余 {number, plural, one {# 天} other {# 天}}\",\n  \"time_remaining.hours\": \"剩余 {number, plural, one {# 小时} other {# 小时}}\",\n  \"time_remaining.minutes\": \"剩余 {number, plural, one {# 分钟} other {# 分钟}}\",\n  \"time_remaining.moments\": \"即将结束\",\n  \"time_remaining.seconds\": \"剩余 {number, plural, one {# 秒} other {# 秒}}\",\n  \"trends.count_by_accounts\": \"{count} 人正在讨论\",\n  \"ui.beforeunload\": \"如果你现在离开 Mastodon，你的草稿内容将会被丢弃。\",\n  \"upload_area.title\": \"将文件拖放到此处开始上传\",\n  \"upload_button.label\": \"上传媒体文件 (JPEG, PNG, GIF, WebM, MP4, MOV)\",\n  \"upload_error.limit\": \"超过文件上传限制。\",\n  \"upload_error.poll\": \"投票中不允许上传文件。\",\n  \"upload_form.description\": \"为视觉障碍人士添加文字说明\",\n  \"upload_form.focus\": \"剪裁\",\n  \"upload_form.undo\": \"删除\",\n  \"upload_progress.label\": \"上传中…\",\n  \"video.close\": \"关闭视频\",\n  \"video.exit_fullscreen\": \"退出全屏\",\n  \"video.expand\": \"展开视频\",\n  \"video.fullscreen\": \"全屏\",\n  \"video.hide\": \"隐藏视频\",\n  \"video.mute\": \"静音\",\n  \"video.pause\": \"暂停\",\n  \"video.play\": \"播放\",\n  \"video.unmute\": \"取消静音\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/zh-HK.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"Add or Remove from lists\",\n  \"account.badges.bot\": \"機械人\",\n  \"account.block\": \"封鎖 @{name}\",\n  \"account.block_domain\": \"隱藏來自 {domain} 的一切文章\",\n  \"account.blocked\": \"封鎖\",\n  \"account.direct\": \"私訊 @{name}\",\n  \"account.domain_blocked\": \"服務站被隱藏\",\n  \"account.edit_profile\": \"修改個人資料\",\n  \"account.endorse\": \"Feature on profile\",\n  \"account.follow\": \"關注\",\n  \"account.followers\": \"關注的人\",\n  \"account.followers.empty\": \"No one follows this user yet.\",\n  \"account.follows\": \"正關注\",\n  \"account.follows.empty\": \"This user doesn't follow anyone yet.\",\n  \"account.follows_you\": \"關注你\",\n  \"account.hide_reblogs\": \"隱藏 @{name} 的轉推\",\n  \"account.link_verified_on\": \"Ownership of this link was checked on {date}\",\n  \"account.locked_info\": \"This account privacy status is set to locked. The owner manually reviews who can follow them.\",\n  \"account.media\": \"媒體\",\n  \"account.mention\": \"提及 @{name}\",\n  \"account.moved_to\": \"{name} 已經遷移到：\",\n  \"account.mute\": \"將 @{name} 靜音\",\n  \"account.mute_notifications\": \"將來自 @{name} 的通知靜音\",\n  \"account.muted\": \"靜音\",\n  \"account.posts\": \"文章\",\n  \"account.posts_with_replies\": \"包含回覆的文章\",\n  \"account.report\": \"舉報 @{name}\",\n  \"account.requested\": \"等候審批\",\n  \"account.share\": \"分享 @{name} 的個人資料\",\n  \"account.show_reblogs\": \"顯示 @{name} 的推文\",\n  \"account.unblock\": \"解除對 @{name} 的封鎖\",\n  \"account.unblock_domain\": \"不再隱藏 {domain}\",\n  \"account.unendorse\": \"Don't feature on profile\",\n  \"account.unfollow\": \"取消關注\",\n  \"account.unmute\": \"取消 @{name} 的靜音\",\n  \"account.unmute_notifications\": \"取消來自 @{name} 通知的靜音\",\n  \"alert.unexpected.message\": \"發生不可預期的錯誤。\",\n  \"alert.unexpected.title\": \"噢！\",\n  \"boost_modal.combo\": \"如你想在下次路過這顯示，請按{combo}，\",\n  \"bundle_column_error.body\": \"加載本組件出錯。\",\n  \"bundle_column_error.retry\": \"重試\",\n  \"bundle_column_error.title\": \"網絡錯誤\",\n  \"bundle_modal_error.close\": \"關閉\",\n  \"bundle_modal_error.message\": \"加載本組件出錯。\",\n  \"bundle_modal_error.retry\": \"重試\",\n  \"column.blocks\": \"封鎖用戶\",\n  \"column.community\": \"本站時間軸\",\n  \"column.direct\": \"個人訊息\",\n  \"column.domain_blocks\": \"隱藏的服務站\",\n  \"column.favourites\": \"最愛的文章\",\n  \"column.follow_requests\": \"關注請求\",\n  \"column.home\": \"主頁\",\n  \"column.lists\": \"列表\",\n  \"column.mutes\": \"靜音名單\",\n  \"column.notifications\": \"通知\",\n  \"column.pins\": \"置頂文章\",\n  \"column.public\": \"跨站時間軸\",\n  \"column_back_button.label\": \"返回\",\n  \"column_header.hide_settings\": \"隱藏設定\",\n  \"column_header.moveLeft_settings\": \"將欄左移\",\n  \"column_header.moveRight_settings\": \"將欄右移\",\n  \"column_header.pin\": \"固定\",\n  \"column_header.show_settings\": \"顯示設定\",\n  \"column_header.unpin\": \"取下\",\n  \"column_subheading.settings\": \"設定\",\n  \"community.column_settings.media_only\": \"僅媒體\",\n  \"compose_form.direct_message_warning\": \"這文章只有被提及的用戶才可以看到。\",\n  \"compose_form.direct_message_warning_learn_more\": \"了解更多\",\n  \"compose_form.hashtag_warning\": \"這文章因為不是公開，所以不會被標籤搜索。只有公開的文章才會被標籤搜索。\",\n  \"compose_form.lock_disclaimer\": \"你的用戶狀態為「{locked}」，任何人都能立即關注你，然後看到「只有關注者能看」的文章。\",\n  \"compose_form.lock_disclaimer.lock\": \"公共\",\n  \"compose_form.placeholder\": \"你在想甚麼？\",\n  \"compose_form.poll.add_option\": \"Add a choice\",\n  \"compose_form.poll.duration\": \"Poll duration\",\n  \"compose_form.poll.option_placeholder\": \"Choice {number}\",\n  \"compose_form.poll.remove_option\": \"Remove this choice\",\n  \"compose_form.publish\": \"發文\",\n  \"compose_form.publish_loud\": \"{publish}！\",\n  \"compose_form.sensitive.hide\": \"Mark media as sensitive\",\n  \"compose_form.sensitive.marked\": \"媒體被標示為敏感\",\n  \"compose_form.sensitive.unmarked\": \"媒體沒有被標示為敏感\",\n  \"compose_form.spoiler.marked\": \"文字被警告隱藏\",\n  \"compose_form.spoiler.unmarked\": \"文字沒有被隱藏\",\n  \"compose_form.spoiler_placeholder\": \"敏感警告訊息\",\n  \"confirmation_modal.cancel\": \"取消\",\n  \"confirmations.block.block_and_report\": \"Block & Report\",\n  \"confirmations.block.confirm\": \"封鎖\",\n  \"confirmations.block.message\": \"你確定要封鎖{name}嗎？\",\n  \"confirmations.delete.confirm\": \"刪除\",\n  \"confirmations.delete.message\": \"你確定要刪除這文章嗎？\",\n  \"confirmations.delete_list.confirm\": \"刪除\",\n  \"confirmations.delete_list.message\": \"你確定要永久刪除這列表嗎？\",\n  \"confirmations.domain_block.confirm\": \"隱藏整個網站\",\n  \"confirmations.domain_block.message\": \"你真的真的確定要隱藏整個 {domain} ？多數情況下，比較推薦封鎖或靜音幾個特定目標就好。你從此將不會再看到該站的內容和通知。來自該站的關注者亦會被移除。\",\n  \"confirmations.mute.confirm\": \"靜音\",\n  \"confirmations.mute.message\": \"你確定要將{name}靜音嗎？\",\n  \"confirmations.redraft.confirm\": \"刪除並編輯\",\n  \"confirmations.redraft.message\": \"你確定要刪除並重新編輯嗎？所有相關的回覆、轉推與最愛都會被刪除。\",\n  \"confirmations.reply.confirm\": \"Reply\",\n  \"confirmations.reply.message\": \"Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?\",\n  \"confirmations.unfollow.confirm\": \"取消關注\",\n  \"confirmations.unfollow.message\": \"真的不要繼續關注 {name} 了嗎？\",\n  \"embed.instructions\": \"要內嵌此文章，請將以下代碼貼進你的網站。\",\n  \"embed.preview\": \"看上去會是這樣：\",\n  \"emoji_button.activity\": \"活動\",\n  \"emoji_button.custom\": \"自訂\",\n  \"emoji_button.flags\": \"旗幟\",\n  \"emoji_button.food\": \"飲飲食食\",\n  \"emoji_button.label\": \"加入表情符號\",\n  \"emoji_button.nature\": \"自然\",\n  \"emoji_button.not_found\": \"沒有表情符號！！ (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"物品\",\n  \"emoji_button.people\": \"人物\",\n  \"emoji_button.recent\": \"常用\",\n  \"emoji_button.search\": \"搜尋…\",\n  \"emoji_button.search_results\": \"搜尋結果\",\n  \"emoji_button.symbols\": \"符號\",\n  \"emoji_button.travel\": \"旅遊景物\",\n  \"empty_column.account_timeline\": \"No toots here!\",\n  \"empty_column.account_unavailable\": \"Profile unavailable\",\n  \"empty_column.blocks\": \"You haven't blocked any users yet.\",\n  \"empty_column.community\": \"本站時間軸暫時未有內容，快寫一點東西來搶頭香啊！\",\n  \"empty_column.direct\": \"你沒有個人訊息。當你發出或接收個人訊息，就會在這裡出現。\",\n  \"empty_column.domain_blocks\": \"There are no hidden domains yet.\",\n  \"empty_column.favourited_statuses\": \"You don't have any favourite toots yet. When you favourite one, it will show up here.\",\n  \"empty_column.favourites\": \"No one has favourited this toot yet. When someone does, they will show up here.\",\n  \"empty_column.follow_requests\": \"You don't have any follow requests yet. When you receive one, it will show up here.\",\n  \"empty_column.hashtag\": \"這個標籤暫時未有內容。\",\n  \"empty_column.home\": \"你還沒有關注任何用戶。快看看{public}，向其他用戶搭訕吧。\",\n  \"empty_column.home.public_timeline\": \"公共時間軸\",\n  \"empty_column.list\": \"這個列表暫時未有內容。\",\n  \"empty_column.lists\": \"You don't have any lists yet. When you create one, it will show up here.\",\n  \"empty_column.mutes\": \"You haven't muted any users yet.\",\n  \"empty_column.notifications\": \"你沒有任何通知紀錄，快向其他用戶搭訕吧。\",\n  \"empty_column.public\": \"跨站時間軸暫時沒有內容！快寫一些公共的文章，或者關注另一些服務站的用戶吧！你和本站、友站的交流，將決定這裏出現的內容。\",\n  \"follow_request.authorize\": \"批准\",\n  \"follow_request.reject\": \"拒絕\",\n  \"getting_started.developers\": \"開發者\",\n  \"getting_started.directory\": \"Profile directory\",\n  \"getting_started.documentation\": \"Documentation\",\n  \"getting_started.heading\": \"開始使用\",\n  \"getting_started.invite\": \"邀請使用者\",\n  \"getting_started.open_source_notice\": \"Mastodon（萬象）是一個開放源碼的軟件。你可以在官方 GitHub ({github}) 貢獻或者回報問題。\",\n  \"getting_started.security\": \"帳戶安全\",\n  \"getting_started.terms\": \"服務條款\",\n  \"hashtag.column_header.tag_mode.all\": \"and {additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"or {additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"without {additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"No suggestions found\",\n  \"hashtag.column_settings.select.placeholder\": \"Enter hashtags…\",\n  \"hashtag.column_settings.tag_mode.all\": \"All of these\",\n  \"hashtag.column_settings.tag_mode.any\": \"Any of these\",\n  \"hashtag.column_settings.tag_mode.none\": \"None of these\",\n  \"hashtag.column_settings.tag_toggle\": \"Include additional tags in this column\",\n  \"home.column_settings.basic\": \"基本\",\n  \"home.column_settings.show_reblogs\": \"顯示被轉推的文章\",\n  \"home.column_settings.show_replies\": \"顯示回應文章\",\n  \"intervals.full.days\": \"{number, plural, one {# day} other {# days}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# hour} other {# hours}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# minute} other {# minutes}}\",\n  \"introduction.federation.action\": \"Next\",\n  \"introduction.federation.federated.headline\": \"Federated\",\n  \"introduction.federation.federated.text\": \"Public posts from other servers of the fediverse will appear in the federated timeline.\",\n  \"introduction.federation.home.headline\": \"Home\",\n  \"introduction.federation.home.text\": \"Posts from people you follow will appear in your home feed. You can follow anyone on any server!\",\n  \"introduction.federation.local.headline\": \"Local\",\n  \"introduction.federation.local.text\": \"Public posts from people on the same server as you will appear in the local timeline.\",\n  \"introduction.interactions.action\": \"Finish toot-orial!\",\n  \"introduction.interactions.favourite.headline\": \"Favourite\",\n  \"introduction.interactions.favourite.text\": \"You can save a toot for later, and let the author know that you liked it, by favouriting it.\",\n  \"introduction.interactions.reblog.headline\": \"Boost\",\n  \"introduction.interactions.reblog.text\": \"You can share other people's toots with your followers by boosting them.\",\n  \"introduction.interactions.reply.headline\": \"Reply\",\n  \"introduction.interactions.reply.text\": \"You can reply to other people's and your own toots, which will chain them together in a conversation.\",\n  \"introduction.welcome.action\": \"Let's go!\",\n  \"introduction.welcome.headline\": \"First steps\",\n  \"introduction.welcome.text\": \"Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.\",\n  \"keyboard_shortcuts.back\": \"後退\",\n  \"keyboard_shortcuts.blocked\": \"to open blocked users list\",\n  \"keyboard_shortcuts.boost\": \"轉推\",\n  \"keyboard_shortcuts.column\": \"把標示移動到其中一列\",\n  \"keyboard_shortcuts.compose\": \"把標示移動到文字輸入區\",\n  \"keyboard_shortcuts.description\": \"描述\",\n  \"keyboard_shortcuts.direct\": \"to open direct messages column\",\n  \"keyboard_shortcuts.down\": \"在列表往下移動\",\n  \"keyboard_shortcuts.enter\": \"打開文章\",\n  \"keyboard_shortcuts.favourite\": \"收藏\",\n  \"keyboard_shortcuts.favourites\": \"to open favourites list\",\n  \"keyboard_shortcuts.federated\": \"to open federated timeline\",\n  \"keyboard_shortcuts.heading\": \"鍵盤快速鍵\",\n  \"keyboard_shortcuts.home\": \"to open home timeline\",\n  \"keyboard_shortcuts.hotkey\": \"快速鍵\",\n  \"keyboard_shortcuts.legend\": \"顯示這個說明\",\n  \"keyboard_shortcuts.local\": \"to open local timeline\",\n  \"keyboard_shortcuts.mention\": \"提及作者\",\n  \"keyboard_shortcuts.muted\": \"to open muted users list\",\n  \"keyboard_shortcuts.my_profile\": \"to open your profile\",\n  \"keyboard_shortcuts.notifications\": \"to open notifications column\",\n  \"keyboard_shortcuts.pinned\": \"to open pinned toots list\",\n  \"keyboard_shortcuts.profile\": \"to open author's profile\",\n  \"keyboard_shortcuts.reply\": \"回覆\",\n  \"keyboard_shortcuts.requests\": \"to open follow requests list\",\n  \"keyboard_shortcuts.search\": \"把標示移動到搜索\",\n  \"keyboard_shortcuts.start\": \"to open \\\"get started\\\" column\",\n  \"keyboard_shortcuts.toggle_hidden\": \"顯示或隱藏被標為敏感的文字\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"to show/hide media\",\n  \"keyboard_shortcuts.toot\": \"新的推文\",\n  \"keyboard_shortcuts.unfocus\": \"把標示移離文字輸入和搜索\",\n  \"keyboard_shortcuts.up\": \"在列表往上移動\",\n  \"lightbox.close\": \"關閉\",\n  \"lightbox.next\": \"繼續\",\n  \"lightbox.previous\": \"回退\",\n  \"lightbox.view_context\": \"View context\",\n  \"lists.account.add\": \"新增到列表\",\n  \"lists.account.remove\": \"從列表刪除\",\n  \"lists.delete\": \"刪除列表\",\n  \"lists.edit\": \"編輯列表\",\n  \"lists.edit.submit\": \"Change title\",\n  \"lists.new.create\": \"新增列表\",\n  \"lists.new.title_placeholder\": \"新列表標題\",\n  \"lists.search\": \"從你關注的用戶中搜索\",\n  \"lists.subheading\": \"列表\",\n  \"loading_indicator.label\": \"載入中...\",\n  \"media_gallery.toggle_visible\": \"打開或關上\",\n  \"missing_indicator.label\": \"找不到內容\",\n  \"missing_indicator.sublabel\": \"無法找到內容\",\n  \"mute_modal.hide_notifications\": \"隱藏來自這用戶的通知嗎？\",\n  \"navigation_bar.apps\": \"Mobile apps\",\n  \"navigation_bar.blocks\": \"被你封鎖的用戶\",\n  \"navigation_bar.community_timeline\": \"本站時間軸\",\n  \"navigation_bar.compose\": \"Compose new toot\",\n  \"navigation_bar.direct\": \"個人訊息\",\n  \"navigation_bar.discover\": \"探索\",\n  \"navigation_bar.domain_blocks\": \"隱藏的服務站\",\n  \"navigation_bar.edit_profile\": \"修改個人資料\",\n  \"navigation_bar.favourites\": \"最愛的內容\",\n  \"navigation_bar.filters\": \"Muted words\",\n  \"navigation_bar.follow_requests\": \"關注請求\",\n  \"navigation_bar.follows_and_followers\": \"Follows and followers\",\n  \"navigation_bar.info\": \"關於本服務站\",\n  \"navigation_bar.keyboard_shortcuts\": \"鍵盤快速鍵\",\n  \"navigation_bar.lists\": \"列表\",\n  \"navigation_bar.logout\": \"登出\",\n  \"navigation_bar.mutes\": \"被你靜音的用戶\",\n  \"navigation_bar.personal\": \"Personal\",\n  \"navigation_bar.pins\": \"置頂文章\",\n  \"navigation_bar.preferences\": \"偏好設定\",\n  \"navigation_bar.profile_directory\": \"Profile directory\",\n  \"navigation_bar.public_timeline\": \"跨站時間軸\",\n  \"navigation_bar.security\": \"安全\",\n  \"notification.favourite\": \"{name} 收藏了你的文章\",\n  \"notification.follow\": \"{name} 開始關注你\",\n  \"notification.mention\": \"{name} 提及你\",\n  \"notification.poll\": \"A poll you have voted in has ended\",\n  \"notification.reblog\": \"{name} 轉推你的文章\",\n  \"notifications.clear\": \"清空通知紀錄\",\n  \"notifications.clear_confirmation\": \"你確定要清空通知紀錄嗎？\",\n  \"notifications.column_settings.alert\": \"顯示桌面通知\",\n  \"notifications.column_settings.favourite\": \"收藏了你的文章：\",\n  \"notifications.column_settings.filter_bar.advanced\": \"Display all categories\",\n  \"notifications.column_settings.filter_bar.category\": \"Quick filter bar\",\n  \"notifications.column_settings.filter_bar.show\": \"Show\",\n  \"notifications.column_settings.follow\": \"關注你：\",\n  \"notifications.column_settings.mention\": \"提及你：\",\n  \"notifications.column_settings.poll\": \"Poll results:\",\n  \"notifications.column_settings.push\": \"推送通知\",\n  \"notifications.column_settings.reblog\": \"轉推你的文章：\",\n  \"notifications.column_settings.show\": \"在通知欄顯示\",\n  \"notifications.column_settings.sound\": \"播放音效\",\n  \"notifications.filter.all\": \"All\",\n  \"notifications.filter.boosts\": \"Boosts\",\n  \"notifications.filter.favourites\": \"Favourites\",\n  \"notifications.filter.follows\": \"Follows\",\n  \"notifications.filter.mentions\": \"Mentions\",\n  \"notifications.filter.polls\": \"Poll results\",\n  \"notifications.group\": \"{count} 條通知\",\n  \"poll.closed\": \"Closed\",\n  \"poll.refresh\": \"Refresh\",\n  \"poll.total_votes\": \"{count, plural, one {# vote} other {# votes}}\",\n  \"poll.vote\": \"Vote\",\n  \"poll_button.add_poll\": \"Add a poll\",\n  \"poll_button.remove_poll\": \"Remove poll\",\n  \"privacy.change\": \"調整私隱設定\",\n  \"privacy.direct.long\": \"只有提及的用戶能看到\",\n  \"privacy.direct.short\": \"私人訊息\",\n  \"privacy.private.long\": \"只有關注你用戶能看到\",\n  \"privacy.private.short\": \"關注者\",\n  \"privacy.public.long\": \"在公共時間軸顯示\",\n  \"privacy.public.short\": \"公共\",\n  \"privacy.unlisted.long\": \"公開，但不在公共時間軸顯示\",\n  \"privacy.unlisted.short\": \"公開\",\n  \"regeneration_indicator.label\": \"載入中……\",\n  \"regeneration_indicator.sublabel\": \"你的主頁時間軸正在準備中！\",\n  \"relative_time.days\": \"{number}日\",\n  \"relative_time.hours\": \"{number}小時\",\n  \"relative_time.just_now\": \"剛剛\",\n  \"relative_time.minutes\": \"{number}分鐘\",\n  \"relative_time.seconds\": \"{number}秒\",\n  \"reply_indicator.cancel\": \"取消\",\n  \"report.forward\": \"轉寄到 {target}\",\n  \"report.forward_hint\": \"這個帳戶屬於其他服務站。要向該服務站發送匿名的舉報訊息嗎？\",\n  \"report.hint\": \"這訊息會發送到你服務站的管理員。你可以提供舉報這個帳戶的理由：\",\n  \"report.placeholder\": \"額外訊息\",\n  \"report.submit\": \"提交\",\n  \"report.target\": \"舉報\",\n  \"search.placeholder\": \"搜尋\",\n  \"search_popout.search_format\": \"高級搜索格式\",\n  \"search_popout.tips.full_text\": \"輸入簡單的文字，搜索由你發放、收藏、轉推和提及你的文章，以及符合的用戶名稱，帳號名稱和標籤。\",\n  \"search_popout.tips.hashtag\": \"標籤\",\n  \"search_popout.tips.status\": \"文章\",\n  \"search_popout.tips.text\": \"輸入簡單的文字，搜索符合的用戶名稱，帳號名稱和標籤\",\n  \"search_popout.tips.user\": \"用戶\",\n  \"search_results.accounts\": \"使用者\",\n  \"search_results.hashtags\": \"標籤\",\n  \"search_results.statuses\": \"文章\",\n  \"search_results.total\": \"{count, number} 項結果\",\n  \"status.admin_account\": \"Open moderation interface for @{name}\",\n  \"status.admin_status\": \"Open this status in the moderation interface\",\n  \"status.block\": \"封鎖 @{name}\",\n  \"status.cancel_reblog_private\": \"取消轉推\",\n  \"status.cannot_reblog\": \"這篇文章無法被轉推\",\n  \"status.copy\": \"Copy link to status\",\n  \"status.delete\": \"刪除\",\n  \"status.detailed_status\": \"Detailed conversation view\",\n  \"status.direct\": \"私訊 @{name}\",\n  \"status.embed\": \"鑲嵌\",\n  \"status.favourite\": \"收藏\",\n  \"status.filtered\": \"Filtered\",\n  \"status.load_more\": \"載入更多\",\n  \"status.media_hidden\": \"隱藏媒體內容\",\n  \"status.mention\": \"提及 @{name}\",\n  \"status.more\": \"更多\",\n  \"status.mute\": \"把 @{name} 靜音\",\n  \"status.mute_conversation\": \"靜音對話\",\n  \"status.open\": \"展開文章\",\n  \"status.pin\": \"置頂到資料頁\",\n  \"status.pinned\": \"置頂文章\",\n  \"status.read_more\": \"Read more\",\n  \"status.reblog\": \"轉推\",\n  \"status.reblog_private\": \"轉推到原讀者\",\n  \"status.reblogged_by\": \"{name} 轉推\",\n  \"status.reblogs.empty\": \"No one has boosted this toot yet. When someone does, they will show up here.\",\n  \"status.redraft\": \"刪除並編輯\",\n  \"status.reply\": \"回應\",\n  \"status.replyAll\": \"回應所有人\",\n  \"status.report\": \"舉報 @{name}\",\n  \"status.sensitive_warning\": \"敏感內容\",\n  \"status.share\": \"分享\",\n  \"status.show_less\": \"減少顯示\",\n  \"status.show_less_all\": \"減少顯示這類文章\",\n  \"status.show_more\": \"顯示更多\",\n  \"status.show_more_all\": \"顯示更多這類文章\",\n  \"status.show_thread\": \"Show thread\",\n  \"status.unmute_conversation\": \"解禁對話\",\n  \"status.unpin\": \"解除置頂\",\n  \"suggestions.dismiss\": \"Dismiss suggestion\",\n  \"suggestions.header\": \"You might be interested in…\",\n  \"tabs_bar.federated_timeline\": \"跨站\",\n  \"tabs_bar.home\": \"主頁\",\n  \"tabs_bar.local_timeline\": \"本站\",\n  \"tabs_bar.notifications\": \"通知\",\n  \"tabs_bar.search\": \"搜尋\",\n  \"time_remaining.days\": \"{number, plural, one {# day} other {# days}} left\",\n  \"time_remaining.hours\": \"{number, plural, one {# hour} other {# hours}} left\",\n  \"time_remaining.minutes\": \"{number, plural, one {# minute} other {# minutes}} left\",\n  \"time_remaining.moments\": \"Moments remaining\",\n  \"time_remaining.seconds\": \"{number, plural, one {# second} other {# seconds}} left\",\n  \"trends.count_by_accounts\": \"{count} 位用戶在討論\",\n  \"ui.beforeunload\": \"如果你現在離開 Mastodon，你的草稿內容將會被丟棄。\",\n  \"upload_area.title\": \"將檔案拖放至此上載\",\n  \"upload_button.label\": \"上載媒體檔案\",\n  \"upload_error.limit\": \"File upload limit exceeded.\",\n  \"upload_error.poll\": \"File upload not allowed with polls.\",\n  \"upload_form.description\": \"為視覺障礙人士添加文字說明\",\n  \"upload_form.focus\": \"裁切\",\n  \"upload_form.undo\": \"刪除\",\n  \"upload_progress.label\": \"上載中……\",\n  \"video.close\": \"關閉影片\",\n  \"video.exit_fullscreen\": \"退出全熒幕\",\n  \"video.expand\": \"展開影片\",\n  \"video.fullscreen\": \"全熒幕\",\n  \"video.hide\": \"隱藏影片\",\n  \"video.mute\": \"靜音\",\n  \"video.pause\": \"暫停\",\n  \"video.play\": \"播放\",\n  \"video.unmute\": \"解除靜音\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/locales/zh-TW.json",
    "content": "{\n  \"account.add_or_remove_from_list\": \"從名單中新增或移除\",\n  \"account.badges.bot\": \"機器人\",\n  \"account.block\": \"封鎖 @{name}\",\n  \"account.block_domain\": \"隱藏來自 {domain} 的所有嘟文\",\n  \"account.blocked\": \"已封鎖\",\n  \"account.direct\": \"傳私訊給 @{name}\",\n  \"account.domain_blocked\": \"已隱藏網域\",\n  \"account.edit_profile\": \"編輯個人資料\",\n  \"account.endorse\": \"在個人資料推薦對方\",\n  \"account.follow\": \"關注\",\n  \"account.followers\": \"關注者\",\n  \"account.followers.empty\": \"還沒有人關注這位使用者。\",\n  \"account.follows\": \"正在關注\",\n  \"account.follows.empty\": \"這個使用者尚未關注任何使用者。\",\n  \"account.follows_you\": \"關注了你\",\n  \"account.hide_reblogs\": \"隱藏來自 @{name} 的轉推\",\n  \"account.link_verified_on\": \"此連結的所有權已在 {date} 檢查\",\n  \"account.locked_info\": \"此帳號的隱私狀態被設為鎖定，擁有者將手動審核可關注此帳號的人。\",\n  \"account.media\": \"媒體\",\n  \"account.mention\": \"提及 @{name}\",\n  \"account.moved_to\": \"{name} 已遷移至：\",\n  \"account.mute\": \"靜音 @{name}\",\n  \"account.mute_notifications\": \"靜音來自 @{name} 的通知\",\n  \"account.muted\": \"已靜音\",\n  \"account.posts\": \"嘟文\",\n  \"account.posts_with_replies\": \"嘟文與回覆\",\n  \"account.report\": \"檢舉 @{name}\",\n  \"account.requested\": \"正在等待核准。按一下取消關注請求\",\n  \"account.share\": \"分享 @{name} 的個人資料\",\n  \"account.show_reblogs\": \"顯示來自 @{name} 的嘟文\",\n  \"account.unblock\": \"取消封鎖 @{name}\",\n  \"account.unblock_domain\": \"取消隱藏 {domain}\",\n  \"account.unendorse\": \"不再於個人資料頁面推薦對方\",\n  \"account.unfollow\": \"取消關注\",\n  \"account.unmute\": \"不再靜音 @{name}\",\n  \"account.unmute_notifications\": \"不再靜音來自 @{name} 的通知\",\n  \"alert.unexpected.message\": \"發生了非預期的錯誤。\",\n  \"alert.unexpected.title\": \"哎呀！\",\n  \"boost_modal.combo\": \"下次您可以按 {combo} 跳過\",\n  \"bundle_column_error.body\": \"載入此組件時發生錯誤。\",\n  \"bundle_column_error.retry\": \"重試\",\n  \"bundle_column_error.title\": \"網路錯誤\",\n  \"bundle_modal_error.close\": \"關閉\",\n  \"bundle_modal_error.message\": \"載入此組件時發生錯誤。\",\n  \"bundle_modal_error.retry\": \"重試\",\n  \"column.blocks\": \"封鎖的使用者\",\n  \"column.community\": \"本地時間軸\",\n  \"column.direct\": \"私訊\",\n  \"column.domain_blocks\": \"隱藏的網域\",\n  \"column.favourites\": \"最愛\",\n  \"column.follow_requests\": \"關注請求\",\n  \"column.home\": \"主頁\",\n  \"column.lists\": \"名單\",\n  \"column.mutes\": \"被靜音的使用者\",\n  \"column.notifications\": \"通知\",\n  \"column.pins\": \"釘選的嘟文\",\n  \"column.public\": \"聯邦時間軸\",\n  \"column_back_button.label\": \"上一頁\",\n  \"column_header.hide_settings\": \"隱藏設定\",\n  \"column_header.moveLeft_settings\": \"將欄位向左移動\",\n  \"column_header.moveRight_settings\": \"將欄位向右移動\",\n  \"column_header.pin\": \"釘選\",\n  \"column_header.show_settings\": \"顯示設定\",\n  \"column_header.unpin\": \"取消釘選\",\n  \"column_subheading.settings\": \"設定\",\n  \"community.column_settings.media_only\": \"僅媒體\",\n  \"compose_form.direct_message_warning\": \"這條嘟文只有被提及的使用者才能看到。\",\n  \"compose_form.direct_message_warning_learn_more\": \"了解更多\",\n  \"compose_form.hashtag_warning\": \"因這則嘟文設成「不公開」，因此它不會列在任何「#」標籤下。只有公開嘟文才能用「#」標籤找到。\",\n  \"compose_form.lock_disclaimer\": \"您的帳戶尚未{locked}。任何人都能關注您並看到您設定成僅關注者能看的嘟文。\",\n  \"compose_form.lock_disclaimer.lock\": \"上鎖\",\n  \"compose_form.placeholder\": \"您正在想些什麼？\",\n  \"compose_form.poll.add_option\": \"新增選擇\",\n  \"compose_form.poll.duration\": \"投票期限\",\n  \"compose_form.poll.option_placeholder\": \"第 {number} 個選擇\",\n  \"compose_form.poll.remove_option\": \"移除此選擇\",\n  \"compose_form.publish\": \"嘟掉\",\n  \"compose_form.publish_loud\": \"{publish}！\",\n  \"compose_form.sensitive.hide\": \"Mark media as sensitive\",\n  \"compose_form.sensitive.marked\": \"此媒體被標記為敏感內容\",\n  \"compose_form.sensitive.unmarked\": \"此媒體未被標記為敏感內容\",\n  \"compose_form.spoiler.marked\": \"正文已隱藏在警告之後\",\n  \"compose_form.spoiler.unmarked\": \"正文未被隱藏\",\n  \"compose_form.spoiler_placeholder\": \"請在此處寫入警告訊息\",\n  \"confirmation_modal.cancel\": \"取消\",\n  \"confirmations.block.block_and_report\": \"Block & Report\",\n  \"confirmations.block.confirm\": \"封鎖\",\n  \"confirmations.block.message\": \"你確定要封鎖 {name} ？\",\n  \"confirmations.delete.confirm\": \"刪除\",\n  \"confirmations.delete.message\": \"你確定要刪除這條嘟文？\",\n  \"confirmations.delete_list.confirm\": \"刪除\",\n  \"confirmations.delete_list.message\": \"確定要永久刪除此名單？\",\n  \"confirmations.domain_block.confirm\": \"隱藏整個網域\",\n  \"confirmations.domain_block.message\": \"確定封鎖整個 {domain} 嗎？多數情況下，封鎖或靜音幾個特定使用者應該就能滿足你的需求了。您將不能在任何公開時間軸或通知中看到來自該網域的內容。來自該網域的關注者將被移除。\",\n  \"confirmations.mute.confirm\": \"靜音\",\n  \"confirmations.mute.message\": \"確定靜音 {name} ？\",\n  \"confirmations.redraft.confirm\": \"刪除並重新編輯\",\n  \"confirmations.redraft.message\": \"你確定要刪除這條嘟文並重新編輯它嗎？這麼做將失去轉嘟和最愛，而對原始嘟文的回覆將被孤立。\",\n  \"confirmations.reply.confirm\": \"回覆\",\n  \"confirmations.reply.message\": \"現在回覆將蓋掉您目前正在撰寫的訊息。是否仍要回覆？\",\n  \"confirmations.unfollow.confirm\": \"取消關注\",\n  \"confirmations.unfollow.message\": \"真的要取消關注 {name} 嗎？\",\n  \"embed.instructions\": \"要嵌入此嘟文，請將以下代碼貼進你的網站。\",\n  \"embed.preview\": \"他會顯示成這樣：\",\n  \"emoji_button.activity\": \"活動\",\n  \"emoji_button.custom\": \"自訂\",\n  \"emoji_button.flags\": \"旗標\",\n  \"emoji_button.food\": \"飲食\",\n  \"emoji_button.label\": \"插入表情符號\",\n  \"emoji_button.nature\": \"大自然\",\n  \"emoji_button.not_found\": \"就沒這表情符號吼！！ (╯°□°）╯︵ ┻━┻\",\n  \"emoji_button.objects\": \"物件\",\n  \"emoji_button.people\": \"使用者\",\n  \"emoji_button.recent\": \"最常使用\",\n  \"emoji_button.search\": \"搜尋…\",\n  \"emoji_button.search_results\": \"搜尋結果\",\n  \"emoji_button.symbols\": \"符號\",\n  \"emoji_button.travel\": \"旅遊與地點\",\n  \"empty_column.account_timeline\": \"這裡還沒有嘟文！\",\n  \"empty_column.account_unavailable\": \"Profile unavailable\",\n  \"empty_column.blocks\": \"你還沒有封鎖任何使用者。\",\n  \"empty_column.community\": \"本地時間軸是空的。快公開嘟些文搶頭香啊！\",\n  \"empty_column.direct\": \"您還沒有任何私訊。當您私訊別人或收到私訊時，它將於此顯示。\",\n  \"empty_column.domain_blocks\": \"尚未隱藏任何網域。\",\n  \"empty_column.favourited_statuses\": \"你還沒有將任何嘟文標為最愛。最愛的嘟文將顯示於此。\",\n  \"empty_column.favourites\": \"還沒有人將此嘟文標為最愛。如果有人標成最愛，則會顯示在這裡。\",\n  \"empty_column.follow_requests\": \"您尚未收到任何關注請求。收到時會顯示於此。\",\n  \"empty_column.hashtag\": \"這個「#」標籤下什麼都沒有。\",\n  \"empty_column.home\": \"您的首頁時間軸是空的！前往 {public} 或使用搜尋功能來認識其他人。\",\n  \"empty_column.home.public_timeline\": \"公開時間軸\",\n  \"empty_column.list\": \"此份名單還沒有東西。當此名單的成員嘟出了新的嘟文時，它們就會出現在這裡。\",\n  \"empty_column.lists\": \"你還沒有建立任何名單。你建立的名單將會顯示在這裡。\",\n  \"empty_column.mutes\": \"你還沒有靜音任何使用者。\",\n  \"empty_column.notifications\": \"您尚未收到任何通知，和別人互動開啟對話吧。\",\n  \"empty_column.public\": \"這裡什麼都沒有！嘗試寫些公開的嘟文，或著自己關注其他伺服器的使用者後就會有嘟文出現了\",\n  \"follow_request.authorize\": \"授權\",\n  \"follow_request.reject\": \"拒絕\",\n  \"getting_started.developers\": \"開發者\",\n  \"getting_started.directory\": \"個人資料目錄\",\n  \"getting_started.documentation\": \"文件\",\n  \"getting_started.heading\": \"開始使用\",\n  \"getting_started.invite\": \"邀請使用者\",\n  \"getting_started.open_source_notice\": \"Mastodon 是開源軟體。你可以在 GitHub {github} 上貢獻或是回報問題。\",\n  \"getting_started.security\": \"安全性\",\n  \"getting_started.terms\": \"服務條款\",\n  \"hashtag.column_header.tag_mode.all\": \"以及{additional}\",\n  \"hashtag.column_header.tag_mode.any\": \"或是{additional}\",\n  \"hashtag.column_header.tag_mode.none\": \"而不用{additional}\",\n  \"hashtag.column_settings.select.no_options_message\": \"找不到建議\",\n  \"hashtag.column_settings.select.placeholder\": \"輸入「#」標籤…\",\n  \"hashtag.column_settings.tag_mode.all\": \"全部\",\n  \"hashtag.column_settings.tag_mode.any\": \"任一\",\n  \"hashtag.column_settings.tag_mode.none\": \"全都不要\",\n  \"hashtag.column_settings.tag_toggle\": \"對此欄位加入額外標籤\",\n  \"home.column_settings.basic\": \"基本\",\n  \"home.column_settings.show_reblogs\": \"顯示轉推\",\n  \"home.column_settings.show_replies\": \"顯示回覆\",\n  \"intervals.full.days\": \"{number, plural, one {# 天} other {# 天}}\",\n  \"intervals.full.hours\": \"{number, plural, one {# 小時} other {# 小時}}\",\n  \"intervals.full.minutes\": \"{number, plural, one {# 分鐘} other {# 分鐘}}\",\n  \"introduction.federation.action\": \"下一步\",\n  \"introduction.federation.federated.headline\": \"聯邦\",\n  \"introduction.federation.federated.text\": \"來自聯邦網路中其他伺服器的公開嘟文將會在聯邦網路時間軸中顯示。\",\n  \"introduction.federation.home.headline\": \"首頁\",\n  \"introduction.federation.home.text\": \"您所關注使用者所發的嘟文將顯示在首頁的訊息來源。您能關注任何伺服器上的任何人！\",\n  \"introduction.federation.local.headline\": \"本地\",\n  \"introduction.federation.local.text\": \"跟您同伺服器之使用者所發的公開嘟文將會顯示在本地時間軸中。\",\n  \"introduction.interactions.action\": \"完成教學！\",\n  \"introduction.interactions.favourite.headline\": \"最愛\",\n  \"introduction.interactions.favourite.text\": \"您能稍候儲存嘟文，或者將嘟文加到最愛，讓作者知道您喜歡這嘟文。\",\n  \"introduction.interactions.reblog.headline\": \"轉嘟\",\n  \"introduction.interactions.reblog.text\": \"您能透過轉嘟他人嘟文來分享給您的關注者。\",\n  \"introduction.interactions.reply.headline\": \"回覆\",\n  \"introduction.interactions.reply.text\": \"您能回覆其他人或自己的嘟文。將會把這些回覆串成一串對話。\",\n  \"introduction.welcome.action\": \"開始！\",\n  \"introduction.welcome.headline\": \"第一步\",\n  \"introduction.welcome.text\": \"歡迎來到聯邦！稍候您將可以廣播訊息並跨各種各式各樣的伺服器與朋友聊天。但這台伺服器，{domain}，十分特殊 -- 它寄管了您的個人資料，所以請記住這台伺服器的名稱。\",\n  \"keyboard_shortcuts.back\": \"返回上一頁\",\n  \"keyboard_shortcuts.blocked\": \"開啟「封鎖的使用者」名單\",\n  \"keyboard_shortcuts.boost\": \"轉嘟\",\n  \"keyboard_shortcuts.column\": \"將焦點放在其中一欄的嘟文\",\n  \"keyboard_shortcuts.compose\": \"將焦點移至撰寫文字區塊\",\n  \"keyboard_shortcuts.description\": \"描述\",\n  \"keyboard_shortcuts.direct\": \"開啟私訊欄\",\n  \"keyboard_shortcuts.down\": \"在名單中往下移動\",\n  \"keyboard_shortcuts.enter\": \"檢視嘟文\",\n  \"keyboard_shortcuts.favourite\": \"加入最愛\",\n  \"keyboard_shortcuts.favourites\": \"開啟最愛名單\",\n  \"keyboard_shortcuts.federated\": \"開啟聯邦時間軸\",\n  \"keyboard_shortcuts.heading\": \"鍵盤快速鍵\",\n  \"keyboard_shortcuts.home\": \"開啟首頁時間軸\",\n  \"keyboard_shortcuts.hotkey\": \"快速鍵\",\n  \"keyboard_shortcuts.legend\": \"顯示此說明\",\n  \"keyboard_shortcuts.local\": \"開啟本地時間軸\",\n  \"keyboard_shortcuts.mention\": \"提及作者\",\n  \"keyboard_shortcuts.muted\": \"開啟靜音使用者名單\",\n  \"keyboard_shortcuts.my_profile\": \"開啟個人資料頁面\",\n  \"keyboard_shortcuts.notifications\": \"開啟通知欄\",\n  \"keyboard_shortcuts.pinned\": \"開啟釘選的嘟文名單\",\n  \"keyboard_shortcuts.profile\": \"開啟作者的個人資料頁\",\n  \"keyboard_shortcuts.reply\": \"回應嘟文\",\n  \"keyboard_shortcuts.requests\": \"開啟關注請求名單\",\n  \"keyboard_shortcuts.search\": \"將焦點移至搜尋框\",\n  \"keyboard_shortcuts.start\": \"開啟「開始使用」欄位\",\n  \"keyboard_shortcuts.toggle_hidden\": \"顯示/隱藏在內容警告之後的正文\",\n  \"keyboard_shortcuts.toggle_sensitivity\": \"to show/hide media\",\n  \"keyboard_shortcuts.toot\": \"開始發出新嘟文\",\n  \"keyboard_shortcuts.unfocus\": \"取消輸入文字區塊 / 搜尋的焦點\",\n  \"keyboard_shortcuts.up\": \"在名單中往上移動\",\n  \"lightbox.close\": \"關閉\",\n  \"lightbox.next\": \"下一步\",\n  \"lightbox.previous\": \"上一步\",\n  \"lightbox.view_context\": \"View context\",\n  \"lists.account.add\": \"新增至名單\",\n  \"lists.account.remove\": \"從名單中移除\",\n  \"lists.delete\": \"刪除名單\",\n  \"lists.edit\": \"編輯名單\",\n  \"lists.edit.submit\": \"變更標題\",\n  \"lists.new.create\": \"新增名單\",\n  \"lists.new.title_placeholder\": \"新名單標題\",\n  \"lists.search\": \"搜尋您關注的使用者\",\n  \"lists.subheading\": \"您的名單\",\n  \"loading_indicator.label\": \"讀取中...\",\n  \"media_gallery.toggle_visible\": \"切換可見性\",\n  \"missing_indicator.label\": \"找不到\",\n  \"missing_indicator.sublabel\": \"找不到此資源\",\n  \"mute_modal.hide_notifications\": \"隱藏來自這個使用者的通知？\",\n  \"navigation_bar.apps\": \"行動應用程式\",\n  \"navigation_bar.blocks\": \"封鎖的使用者\",\n  \"navigation_bar.community_timeline\": \"本地時間軸\",\n  \"navigation_bar.compose\": \"撰寫新嘟文\",\n  \"navigation_bar.direct\": \"私訊\",\n  \"navigation_bar.discover\": \"探索\",\n  \"navigation_bar.domain_blocks\": \"隱藏的網域\",\n  \"navigation_bar.edit_profile\": \"編輯個人資料\",\n  \"navigation_bar.favourites\": \"最愛內容\",\n  \"navigation_bar.filters\": \"靜音詞彙\",\n  \"navigation_bar.follow_requests\": \"關注請求\",\n  \"navigation_bar.follows_and_followers\": \"Follows and followers\",\n  \"navigation_bar.info\": \"關於此伺服器\",\n  \"navigation_bar.keyboard_shortcuts\": \"快速鍵\",\n  \"navigation_bar.lists\": \"名單\",\n  \"navigation_bar.logout\": \"登出\",\n  \"navigation_bar.mutes\": \"靜音的使用者\",\n  \"navigation_bar.personal\": \"個人\",\n  \"navigation_bar.pins\": \"釘選的嘟文\",\n  \"navigation_bar.preferences\": \"偏好設定\",\n  \"navigation_bar.profile_directory\": \"Profile directory\",\n  \"navigation_bar.public_timeline\": \"聯邦時間軸\",\n  \"navigation_bar.security\": \"安全性\",\n  \"notification.favourite\": \"{name} 把你的嘟文加入了最愛\",\n  \"notification.follow\": \"{name} 關注了你\",\n  \"notification.mention\": \"{name} 提到了你\",\n  \"notification.poll\": \"您投過的投票已經結束\",\n  \"notification.reblog\": \"{name}轉嘟了你的嘟文\",\n  \"notifications.clear\": \"清除通知\",\n  \"notifications.clear_confirmation\": \"確定要永久清除你的通知嗎？\",\n  \"notifications.column_settings.alert\": \"桌面通知\",\n  \"notifications.column_settings.favourite\": \"最愛：\",\n  \"notifications.column_settings.filter_bar.advanced\": \"顯示所有分類\",\n  \"notifications.column_settings.filter_bar.category\": \"快速過濾欄\",\n  \"notifications.column_settings.filter_bar.show\": \"顯示\",\n  \"notifications.column_settings.follow\": \"新關注者：\",\n  \"notifications.column_settings.mention\": \"提及：\",\n  \"notifications.column_settings.poll\": \"投票結果：\",\n  \"notifications.column_settings.push\": \"推送通知\",\n  \"notifications.column_settings.reblog\": \"轉嘟：\",\n  \"notifications.column_settings.show\": \"在欄位中顯示\",\n  \"notifications.column_settings.sound\": \"播放音效\",\n  \"notifications.filter.all\": \"全部\",\n  \"notifications.filter.boosts\": \"轉嘟\",\n  \"notifications.filter.favourites\": \"最愛\",\n  \"notifications.filter.follows\": \"關注的使用者\",\n  \"notifications.filter.mentions\": \"提及\",\n  \"notifications.filter.polls\": \"投票結果\",\n  \"notifications.group\": \"{count} 條通知\",\n  \"poll.closed\": \"已關閉\",\n  \"poll.refresh\": \"重新整理\",\n  \"poll.total_votes\": \"{count, plural, one {# 個投票} other {# 個投票}}\",\n  \"poll.vote\": \"投票\",\n  \"poll_button.add_poll\": \"建立投票\",\n  \"poll_button.remove_poll\": \"移除投票\",\n  \"privacy.change\": \"調整隱私狀態\",\n  \"privacy.direct.long\": \"只有被提到的使用者能看到\",\n  \"privacy.direct.short\": \"私訊\",\n  \"privacy.private.long\": \"只有關注你的使用者能看到\",\n  \"privacy.private.short\": \"僅關注者\",\n  \"privacy.public.long\": \"嘟到公開時間軸\",\n  \"privacy.public.short\": \"公開\",\n  \"privacy.unlisted.long\": \"公開，但不會顯示在公開時間軸\",\n  \"privacy.unlisted.short\": \"不公開\",\n  \"regeneration_indicator.label\": \"載入中…\",\n  \"regeneration_indicator.sublabel\": \"你的主頁時間軸正在準備中!\",\n  \"relative_time.days\": \"{number} 天\",\n  \"relative_time.hours\": \"{number} 小時\",\n  \"relative_time.just_now\": \"剛剛\",\n  \"relative_time.minutes\": \"{number} 分\",\n  \"relative_time.seconds\": \"{number} 秒\",\n  \"reply_indicator.cancel\": \"取消\",\n  \"report.forward\": \"轉寄到 {target}\",\n  \"report.forward_hint\": \"這個帳戶屬於其他站點。要像該站點發送匿名的檢舉訊息嗎?\",\n  \"report.hint\": \"這項訊息會發送到您伺服器的管理員。你可以提供檢舉這個帳戶的理由：\",\n  \"report.placeholder\": \"更多訊息\",\n  \"report.submit\": \"送出\",\n  \"report.target\": \"檢舉 {target}\",\n  \"search.placeholder\": \"搜尋\",\n  \"search_popout.search_format\": \"進階搜尋格式\",\n  \"search_popout.tips.full_text\": \"輸入簡單的文字，搜尋由你撰寫、最愛、轉嘟或提你的嘟文，以及符合使用者名稱、帳戶名稱和標籤。\",\n  \"search_popout.tips.hashtag\": \"主題標籤\",\n  \"search_popout.tips.status\": \"嘟文\",\n  \"search_popout.tips.text\": \"輸入簡單的文字，搜尋符合的使用者名稱，帳戶名稱與標籤\",\n  \"search_popout.tips.user\": \"使用者\",\n  \"search_results.accounts\": \"使用者\",\n  \"search_results.hashtags\": \"主題標籤\",\n  \"search_results.statuses\": \"嘟文\",\n  \"search_results.total\": \"{count, number} 項結果\",\n  \"status.admin_account\": \"開啟 @{name} 的管理介面\",\n  \"status.admin_status\": \"在管理介面開啟此嘟文\",\n  \"status.block\": \"封鎖 @{name}\",\n  \"status.cancel_reblog_private\": \"取消轉嘟\",\n  \"status.cannot_reblog\": \"這篇嘟文無法被轉嘟\",\n  \"status.copy\": \"將連結複製到嘟文中\",\n  \"status.delete\": \"刪除\",\n  \"status.detailed_status\": \"對話的詳細內容\",\n  \"status.direct\": \"發送私訊給 @{name}\",\n  \"status.embed\": \"嵌入\",\n  \"status.favourite\": \"最愛\",\n  \"status.filtered\": \"已過濾\",\n  \"status.load_more\": \"載入更多\",\n  \"status.media_hidden\": \"隱藏媒體內容\",\n  \"status.mention\": \"提到 @{name}\",\n  \"status.more\": \"更多\",\n  \"status.mute\": \"靜音 @{name}\",\n  \"status.mute_conversation\": \"靜音對話\",\n  \"status.open\": \"展開嘟文\",\n  \"status.pin\": \"釘選到個人資料頁\",\n  \"status.pinned\": \"釘選的嘟文\",\n  \"status.read_more\": \"閱讀更多\",\n  \"status.reblog\": \"轉嘟\",\n  \"status.reblog_private\": \"轉嘟給原有關注者\",\n  \"status.reblogged_by\": \"{name} 轉嘟了\",\n  \"status.reblogs.empty\": \"還沒有人轉嘟。如果有，會顯示在這裡。\",\n  \"status.redraft\": \"刪除 & 編輯\",\n  \"status.reply\": \"回覆\",\n  \"status.replyAll\": \"回覆所有人\",\n  \"status.report\": \"檢舉 @{name}\",\n  \"status.sensitive_warning\": \"敏感內容\",\n  \"status.share\": \"分享\",\n  \"status.show_less\": \"減少顯示\",\n  \"status.show_less_all\": \"減少顯示這類嘟文\",\n  \"status.show_more\": \"顯示更多\",\n  \"status.show_more_all\": \"顯示更多這類嘟文\",\n  \"status.show_thread\": \"顯示討論串\",\n  \"status.unmute_conversation\": \"解除此對話的靜音\",\n  \"status.unpin\": \"解除置頂\",\n  \"suggestions.dismiss\": \"關閉建議\",\n  \"suggestions.header\": \"您可能對這些東西有興趣…\",\n  \"tabs_bar.federated_timeline\": \"其他站點\",\n  \"tabs_bar.home\": \"主頁\",\n  \"tabs_bar.local_timeline\": \"本站\",\n  \"tabs_bar.notifications\": \"通知\",\n  \"tabs_bar.search\": \"搜尋\",\n  \"time_remaining.days\": \"剩餘{number, plural, one {# 天數} other {# 天數}}\",\n  \"time_remaining.hours\": \"剩餘{number, plural, one {# 小時} other {# 小時}}\",\n  \"time_remaining.minutes\": \"剩餘{number, plural, one {# 分鐘} other {# 分鐘}}\",\n  \"time_remaining.moments\": \"剩餘時間\",\n  \"time_remaining.seconds\": \"剩餘 {number, plural, one {# 秒} other {# 秒}}\",\n  \"trends.count_by_accounts\": \"{count} 位使用者在討論\",\n  \"ui.beforeunload\": \"如果離開 Mastodon，你的草稿將會不見。\",\n  \"upload_area.title\": \"拖放來上傳\",\n  \"upload_button.label\": \"上傳媒體檔案 (JPEG, PNG, GIF, WebM, MP4, MOV)\",\n  \"upload_error.limit\": \"已達到檔案上傳限制。\",\n  \"upload_error.poll\": \"不允許在投票上傳檔案。\",\n  \"upload_form.description\": \"為視障人士增加文字說明\",\n  \"upload_form.focus\": \"變更預覽\",\n  \"upload_form.undo\": \"刪除\",\n  \"upload_progress.label\": \"上傳中...\",\n  \"video.close\": \"關閉影片\",\n  \"video.exit_fullscreen\": \"退出全螢幕\",\n  \"video.expand\": \"展開影片\",\n  \"video.fullscreen\": \"全螢幕\",\n  \"video.hide\": \"隱藏影片\",\n  \"video.mute\": \"靜音\",\n  \"video.pause\": \"暫停\",\n  \"video.play\": \"播放\",\n  \"video.unmute\": \"解除靜音\"\n}\n"
  },
  {
    "path": "app/javascript/mastodon/main.js",
    "content": "import * as registerPushNotifications from './actions/push_notifications';\nimport { default as Mastodon, store } from './containers/mastodon';\nimport React from 'react';\nimport ReactDOM from 'react-dom';\nimport ready from './ready';\n\nconst perf = require('./performance');\n\nfunction main() {\n  perf.start('main()');\n\n  if (window.history && history.replaceState) {\n    const { pathname, search, hash } = window.location;\n    const path = pathname + search + hash;\n    if (!(/^\\/web[$/]/).test(path)) {\n      history.replaceState(null, document.title, `/web${path}`);\n    }\n  }\n\n  ready(() => {\n    const mountNode = document.getElementById('mastodon');\n    const props = JSON.parse(mountNode.getAttribute('data-props'));\n\n    ReactDOM.render(<Mastodon {...props} />, mountNode);\n    if (process.env.NODE_ENV === 'production') {\n      // avoid offline in dev mode because it's harder to debug\n      require('offline-plugin/runtime').install();\n      store.dispatch(registerPushNotifications.register());\n    }\n    perf.stop('main()');\n  });\n}\n\nexport default main;\n"
  },
  {
    "path": "app/javascript/mastodon/middleware/errors.js",
    "content": "import { showAlertForError } from '../actions/alerts';\n\nconst defaultFailSuffix = 'FAIL';\n\nexport default function errorsMiddleware() {\n  return ({ dispatch }) => next => action => {\n    if (action.type && !action.skipAlert) {\n      const isFail = new RegExp(`${defaultFailSuffix}$`, 'g');\n\n      if (action.type.match(isFail)) {\n        dispatch(showAlertForError(action.error));\n      }\n    }\n\n    return next(action);\n  };\n};\n"
  },
  {
    "path": "app/javascript/mastodon/middleware/loading_bar.js",
    "content": "import { showLoading, hideLoading } from 'react-redux-loading-bar';\n\nconst defaultTypeSuffixes = ['PENDING', 'FULFILLED', 'REJECTED'];\n\nexport default function loadingBarMiddleware(config = {}) {\n  const promiseTypeSuffixes = config.promiseTypeSuffixes || defaultTypeSuffixes;\n\n  return ({ dispatch }) => next => (action) => {\n    if (action.type && !action.skipLoading) {\n      const [PENDING, FULFILLED, REJECTED] = promiseTypeSuffixes;\n\n      const isPending = new RegExp(`${PENDING}$`, 'g');\n      const isFulfilled = new RegExp(`${FULFILLED}$`, 'g');\n      const isRejected = new RegExp(`${REJECTED}$`, 'g');\n\n      if (action.type.match(isPending)) {\n        dispatch(showLoading());\n      } else if (action.type.match(isFulfilled) || action.type.match(isRejected)) {\n        dispatch(hideLoading());\n      }\n    }\n\n    return next(action);\n  };\n};\n"
  },
  {
    "path": "app/javascript/mastodon/middleware/sounds.js",
    "content": "const createAudio = sources => {\n  const audio = new Audio();\n  sources.forEach(({ type, src }) => {\n    const source = document.createElement('source');\n    source.type = type;\n    source.src = src;\n    audio.appendChild(source);\n  });\n  return audio;\n};\n\nconst play = audio => {\n  if (!audio.paused) {\n    audio.pause();\n    if (typeof audio.fastSeek === 'function') {\n      audio.fastSeek(0);\n    } else {\n      audio.currentTime = 0;\n    }\n  }\n\n  audio.play();\n};\n\nexport default function soundsMiddleware() {\n  const soundCache = {\n    boop: createAudio([\n      {\n        src: '/sounds/boop.ogg',\n        type: 'audio/ogg',\n      },\n      {\n        src: '/sounds/boop.mp3',\n        type: 'audio/mpeg',\n      },\n    ]),\n  };\n\n  return () => next => action => {\n    if (action.meta && action.meta.sound && soundCache[action.meta.sound]) {\n      play(soundCache[action.meta.sound]);\n    }\n\n    return next(action);\n  };\n};\n"
  },
  {
    "path": "app/javascript/mastodon/performance.js",
    "content": "//\n// Tools for performance debugging, only enabled in development mode.\n// Open up Chrome Dev Tools, then Timeline, then User Timing to see output.\n// Also see config/webpack/loaders/mark.js for the webpack loader marks.\n//\n\nlet marky;\n\nif (process.env.NODE_ENV === 'development') {\n  if (typeof performance !== 'undefined' && performance.setResourceTimingBufferSize) {\n    // Increase Firefox's performance entry limit; otherwise it's capped to 150.\n    // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1331135\n    performance.setResourceTimingBufferSize(Infinity);\n  }\n  marky = require('marky');\n  // allows us to easily do e.g. ReactPerf.printWasted() while debugging\n  //window.ReactPerf = require('react-addons-perf');\n  //window.ReactPerf.start();\n}\n\nexport function start(name) {\n  if (process.env.NODE_ENV === 'development') {\n    marky.mark(name);\n  }\n}\n\nexport function stop(name) {\n  if (process.env.NODE_ENV === 'development') {\n    marky.stop(name);\n  }\n}\n"
  },
  {
    "path": "app/javascript/mastodon/ready.js",
    "content": "export default function ready(loaded) {\n  if (['interactive', 'complete'].includes(document.readyState)) {\n    loaded();\n  } else {\n    document.addEventListener('DOMContentLoaded', loaded);\n  }\n}\n"
  },
  {
    "path": "app/javascript/mastodon/reducers/accounts.js",
    "content": "import { ACCOUNT_IMPORT, ACCOUNTS_IMPORT } from '../actions/importer';\nimport { Map as ImmutableMap, fromJS } from 'immutable';\n\nconst initialState = ImmutableMap();\n\nconst normalizeAccount = (state, account) => {\n  account = { ...account };\n\n  delete account.followers_count;\n  delete account.following_count;\n  delete account.statuses_count;\n\n  return state.set(account.id, fromJS(account));\n};\n\nconst normalizeAccounts = (state, accounts) => {\n  accounts.forEach(account => {\n    state = normalizeAccount(state, account);\n  });\n\n  return state;\n};\n\nexport default function accounts(state = initialState, action) {\n  switch(action.type) {\n  case ACCOUNT_IMPORT:\n    return normalizeAccount(state, action.account);\n  case ACCOUNTS_IMPORT:\n    return normalizeAccounts(state, action.accounts);\n  default:\n    return state;\n  }\n};\n"
  },
  {
    "path": "app/javascript/mastodon/reducers/accounts_counters.js",
    "content": "import {\n  ACCOUNT_FOLLOW_SUCCESS,\n  ACCOUNT_UNFOLLOW_SUCCESS,\n} from '../actions/accounts';\nimport { ACCOUNT_IMPORT, ACCOUNTS_IMPORT } from '../actions/importer';\nimport { Map as ImmutableMap, fromJS } from 'immutable';\n\nconst normalizeAccount = (state, account) => state.set(account.id, fromJS({\n  followers_count: account.followers_count,\n  following_count: account.following_count,\n  statuses_count: account.statuses_count,\n}));\n\nconst normalizeAccounts = (state, accounts) => {\n  accounts.forEach(account => {\n    state = normalizeAccount(state, account);\n  });\n\n  return state;\n};\n\nconst initialState = ImmutableMap();\n\nexport default function accountsCounters(state = initialState, action) {\n  switch(action.type) {\n  case ACCOUNT_IMPORT:\n    return normalizeAccount(state, action.account);\n  case ACCOUNTS_IMPORT:\n    return normalizeAccounts(state, action.accounts);\n  case ACCOUNT_FOLLOW_SUCCESS:\n    return action.alreadyFollowing ? state :\n      state.updateIn([action.relationship.id, 'followers_count'], num => num + 1);\n  case ACCOUNT_UNFOLLOW_SUCCESS:\n    return state.updateIn([action.relationship.id, 'followers_count'], num => Math.max(0, num - 1));\n  default:\n    return state;\n  }\n};\n"
  },
  {
    "path": "app/javascript/mastodon/reducers/alerts.js",
    "content": "import {\n  ALERT_SHOW,\n  ALERT_DISMISS,\n  ALERT_CLEAR,\n} from '../actions/alerts';\nimport { Map as ImmutableMap, List as ImmutableList } from 'immutable';\n\nconst initialState = ImmutableList([]);\n\nexport default function alerts(state = initialState, action) {\n  switch(action.type) {\n  case ALERT_SHOW:\n    return state.push(ImmutableMap({\n      key: state.size > 0 ? state.last().get('key') + 1 : 0,\n      title: action.title,\n      message: action.message,\n    }));\n  case ALERT_DISMISS:\n    return state.filterNot(item => item.get('key') === action.alert.key);\n  case ALERT_CLEAR:\n    return state.clear();\n  default:\n    return state;\n  }\n};\n"
  },
  {
    "path": "app/javascript/mastodon/reducers/compose.js",
    "content": "import {\n  COMPOSE_MOUNT,\n  COMPOSE_UNMOUNT,\n  COMPOSE_CHANGE,\n  COMPOSE_REPLY,\n  COMPOSE_REPLY_CANCEL,\n  COMPOSE_DIRECT,\n  COMPOSE_MENTION,\n  COMPOSE_SUBMIT_REQUEST,\n  COMPOSE_SUBMIT_SUCCESS,\n  COMPOSE_SUBMIT_FAIL,\n  COMPOSE_UPLOAD_REQUEST,\n  COMPOSE_UPLOAD_SUCCESS,\n  COMPOSE_UPLOAD_FAIL,\n  COMPOSE_UPLOAD_UNDO,\n  COMPOSE_UPLOAD_PROGRESS,\n  COMPOSE_SUGGESTIONS_CLEAR,\n  COMPOSE_SUGGESTIONS_READY,\n  COMPOSE_SUGGESTION_SELECT,\n  COMPOSE_SUGGESTION_TAGS_UPDATE,\n  COMPOSE_TAG_HISTORY_UPDATE,\n  COMPOSE_SENSITIVITY_CHANGE,\n  COMPOSE_SPOILERNESS_CHANGE,\n  COMPOSE_SPOILER_TEXT_CHANGE,\n  COMPOSE_VISIBILITY_CHANGE,\n  COMPOSE_COMPOSING_CHANGE,\n  COMPOSE_EMOJI_INSERT,\n  COMPOSE_UPLOAD_CHANGE_REQUEST,\n  COMPOSE_UPLOAD_CHANGE_SUCCESS,\n  COMPOSE_UPLOAD_CHANGE_FAIL,\n  COMPOSE_RESET,\n  COMPOSE_POLL_ADD,\n  COMPOSE_POLL_REMOVE,\n  COMPOSE_POLL_OPTION_ADD,\n  COMPOSE_POLL_OPTION_CHANGE,\n  COMPOSE_POLL_OPTION_REMOVE,\n  COMPOSE_POLL_SETTINGS_CHANGE,\n} from '../actions/compose';\nimport { TIMELINE_DELETE } from '../actions/timelines';\nimport { STORE_HYDRATE } from '../actions/store';\nimport { REDRAFT } from '../actions/statuses';\nimport { Map as ImmutableMap, List as ImmutableList, OrderedSet as ImmutableOrderedSet, fromJS } from 'immutable';\nimport uuid from '../uuid';\nimport { me } from '../initial_state';\nimport { unescapeHTML } from '../utils/html';\n\nconst initialState = ImmutableMap({\n  mounted: 0,\n  sensitive: false,\n  spoiler: false,\n  spoiler_text: '',\n  privacy: null,\n  text: '',\n  focusDate: null,\n  caretPosition: null,\n  preselectDate: null,\n  in_reply_to: null,\n  is_composing: false,\n  is_submitting: false,\n  is_changing_upload: false,\n  is_uploading: false,\n  progress: 0,\n  media_attachments: ImmutableList(),\n  poll: null,\n  suggestion_token: null,\n  suggestions: ImmutableList(),\n  default_privacy: 'public',\n  default_sensitive: false,\n  resetFileKey: Math.floor((Math.random() * 0x10000)),\n  idempotencyKey: null,\n  tagHistory: ImmutableList(),\n});\n\nconst initialPoll = ImmutableMap({\n  options: ImmutableList(['', '']),\n  expires_in: 24 * 3600,\n  multiple: false,\n});\n\nfunction statusToTextMentions(state, status) {\n  let set = ImmutableOrderedSet([]);\n\n  if (status.getIn(['account', 'id']) !== me) {\n    set = set.add(`@${status.getIn(['account', 'acct'])} `);\n  }\n\n  return set.union(status.get('mentions').filterNot(mention => mention.get('id') === me).map(mention => `@${mention.get('acct')} `)).join('');\n};\n\nfunction clearAll(state) {\n  return state.withMutations(map => {\n    map.set('text', '');\n    map.set('spoiler', false);\n    map.set('spoiler_text', '');\n    map.set('is_submitting', false);\n    map.set('is_changing_upload', false);\n    map.set('in_reply_to', null);\n    map.set('privacy', state.get('default_privacy'));\n    map.set('sensitive', false);\n    map.update('media_attachments', list => list.clear());\n    map.set('poll', null);\n    map.set('idempotencyKey', uuid());\n  });\n};\n\nfunction appendMedia(state, media) {\n  const prevSize = state.get('media_attachments').size;\n\n  return state.withMutations(map => {\n    map.update('media_attachments', list => list.push(media));\n    map.set('is_uploading', false);\n    map.set('resetFileKey', Math.floor((Math.random() * 0x10000)));\n    map.set('idempotencyKey', uuid());\n\n    if (prevSize === 0 && (state.get('default_sensitive') || state.get('spoiler'))) {\n      map.set('sensitive', true);\n    }\n  });\n};\n\nfunction removeMedia(state, mediaId) {\n  const prevSize = state.get('media_attachments').size;\n\n  return state.withMutations(map => {\n    map.update('media_attachments', list => list.filterNot(item => item.get('id') === mediaId));\n    map.set('idempotencyKey', uuid());\n\n    if (prevSize === 1) {\n      map.set('sensitive', false);\n    }\n  });\n};\n\nconst insertSuggestion = (state, position, token, completion, path) => {\n  return state.withMutations(map => {\n    map.updateIn(path, oldText => `${oldText.slice(0, position)}${completion} ${oldText.slice(position + token.length)}`);\n    map.set('suggestion_token', null);\n    map.set('suggestions', ImmutableList());\n    if (path.length === 1 && path[0] === 'text') {\n      map.set('focusDate', new Date());\n      map.set('caretPosition', position + completion.length + 1);\n    }\n    map.set('idempotencyKey', uuid());\n  });\n};\n\nconst updateSuggestionTags = (state, token) => {\n  const prefix = token.slice(1);\n\n  return state.merge({\n    suggestions: state.get('tagHistory')\n      .filter(tag => tag.toLowerCase().startsWith(prefix.toLowerCase()))\n      .slice(0, 4)\n      .map(tag => '#' + tag),\n    suggestion_token: token,\n  });\n};\n\nconst insertEmoji = (state, position, emojiData, needsSpace) => {\n  const oldText = state.get('text');\n  const emoji = needsSpace ? ' ' + emojiData.native : emojiData.native;\n\n  return state.merge({\n    text: `${oldText.slice(0, position)}${emoji} ${oldText.slice(position)}`,\n    focusDate: new Date(),\n    caretPosition: position + emoji.length + 1,\n    idempotencyKey: uuid(),\n  });\n};\n\nconst privacyPreference = (a, b) => {\n  const order = ['public', 'unlisted', 'private', 'direct'];\n  return order[Math.max(order.indexOf(a), order.indexOf(b), 0)];\n};\n\nconst hydrate = (state, hydratedState) => {\n  state = clearAll(state.merge(hydratedState));\n\n  if (hydratedState.has('text')) {\n    state = state.set('text', hydratedState.get('text'));\n  }\n\n  return state;\n};\n\nconst domParser = new DOMParser();\n\nconst expandMentions = status => {\n  const fragment = domParser.parseFromString(status.get('content'), 'text/html').documentElement;\n\n  status.get('mentions').forEach(mention => {\n    fragment.querySelector(`a[href=\"${mention.get('url')}\"]`).textContent = `@${mention.get('acct')}`;\n  });\n\n  return fragment.innerHTML;\n};\n\nexport default function compose(state = initialState, action) {\n  switch(action.type) {\n  case STORE_HYDRATE:\n    return hydrate(state, action.state.get('compose'));\n  case COMPOSE_MOUNT:\n    return state.set('mounted', state.get('mounted') + 1);\n  case COMPOSE_UNMOUNT:\n    return state\n      .set('mounted', Math.max(state.get('mounted') - 1, 0))\n      .set('is_composing', false);\n  case COMPOSE_SENSITIVITY_CHANGE:\n    return state.withMutations(map => {\n      if (!state.get('spoiler')) {\n        map.set('sensitive', !state.get('sensitive'));\n      }\n\n      map.set('idempotencyKey', uuid());\n    });\n  case COMPOSE_SPOILERNESS_CHANGE:\n    return state.withMutations(map => {\n      map.set('spoiler_text', '');\n      map.set('spoiler', !state.get('spoiler'));\n      map.set('idempotencyKey', uuid());\n\n      if (!state.get('sensitive') && state.get('media_attachments').size >= 1) {\n        map.set('sensitive', true);\n      }\n    });\n  case COMPOSE_SPOILER_TEXT_CHANGE:\n    return state\n      .set('spoiler_text', action.text)\n      .set('idempotencyKey', uuid());\n  case COMPOSE_VISIBILITY_CHANGE:\n    return state\n      .set('privacy', action.value)\n      .set('idempotencyKey', uuid());\n  case COMPOSE_CHANGE:\n    return state\n      .set('text', action.text)\n      .set('idempotencyKey', uuid());\n  case COMPOSE_COMPOSING_CHANGE:\n    return state.set('is_composing', action.value);\n  case COMPOSE_REPLY:\n    return state.withMutations(map => {\n      map.set('in_reply_to', action.status.get('id'));\n      map.set('text', statusToTextMentions(state, action.status));\n      map.set('privacy', privacyPreference(action.status.get('visibility'), state.get('default_privacy')));\n      map.set('focusDate', new Date());\n      map.set('caretPosition', null);\n      map.set('preselectDate', new Date());\n      map.set('idempotencyKey', uuid());\n\n      if (action.status.get('spoiler_text').length > 0) {\n        map.set('spoiler', true);\n        map.set('spoiler_text', action.status.get('spoiler_text'));\n      } else {\n        map.set('spoiler', false);\n        map.set('spoiler_text', '');\n      }\n    });\n  case COMPOSE_REPLY_CANCEL:\n  case COMPOSE_RESET:\n    return state.withMutations(map => {\n      map.set('in_reply_to', null);\n      map.set('text', '');\n      map.set('spoiler', false);\n      map.set('spoiler_text', '');\n      map.set('privacy', state.get('default_privacy'));\n      map.set('poll', null);\n      map.set('idempotencyKey', uuid());\n    });\n  case COMPOSE_SUBMIT_REQUEST:\n    return state.set('is_submitting', true);\n  case COMPOSE_UPLOAD_CHANGE_REQUEST:\n    return state.set('is_changing_upload', true);\n  case COMPOSE_SUBMIT_SUCCESS:\n    return clearAll(state);\n  case COMPOSE_SUBMIT_FAIL:\n    return state.set('is_submitting', false);\n  case COMPOSE_UPLOAD_CHANGE_FAIL:\n    return state.set('is_changing_upload', false);\n  case COMPOSE_UPLOAD_REQUEST:\n    return state.set('is_uploading', true);\n  case COMPOSE_UPLOAD_SUCCESS:\n    return appendMedia(state, fromJS(action.media));\n  case COMPOSE_UPLOAD_FAIL:\n    return state.set('is_uploading', false);\n  case COMPOSE_UPLOAD_UNDO:\n    return removeMedia(state, action.media_id);\n  case COMPOSE_UPLOAD_PROGRESS:\n    return state.set('progress', Math.round((action.loaded / action.total) * 100));\n  case COMPOSE_MENTION:\n    return state.withMutations(map => {\n      map.update('text', text => [text.trim(), `@${action.account.get('acct')} `].filter((str) => str.length !== 0).join(' '));\n      map.set('focusDate', new Date());\n      map.set('caretPosition', null);\n      map.set('idempotencyKey', uuid());\n    });\n  case COMPOSE_DIRECT:\n    return state.withMutations(map => {\n      map.update('text', text => [text.trim(), `@${action.account.get('acct')} `].filter((str) => str.length !== 0).join(' '));\n      map.set('privacy', 'direct');\n      map.set('focusDate', new Date());\n      map.set('caretPosition', null);\n      map.set('idempotencyKey', uuid());\n    });\n  case COMPOSE_SUGGESTIONS_CLEAR:\n    return state.update('suggestions', ImmutableList(), list => list.clear()).set('suggestion_token', null);\n  case COMPOSE_SUGGESTIONS_READY:\n    return state.set('suggestions', ImmutableList(action.accounts ? action.accounts.map(item => item.id) : action.emojis)).set('suggestion_token', action.token);\n  case COMPOSE_SUGGESTION_SELECT:\n    return insertSuggestion(state, action.position, action.token, action.completion, action.path);\n  case COMPOSE_SUGGESTION_TAGS_UPDATE:\n    return updateSuggestionTags(state, action.token);\n  case COMPOSE_TAG_HISTORY_UPDATE:\n    return state.set('tagHistory', fromJS(action.tags));\n  case TIMELINE_DELETE:\n    if (action.id === state.get('in_reply_to')) {\n      return state.set('in_reply_to', null);\n    } else {\n      return state;\n    }\n  case COMPOSE_EMOJI_INSERT:\n    return insertEmoji(state, action.position, action.emoji, action.needsSpace);\n  case COMPOSE_UPLOAD_CHANGE_SUCCESS:\n    return state\n      .set('is_changing_upload', false)\n      .update('media_attachments', list => list.map(item => {\n        if (item.get('id') === action.media.id) {\n          return fromJS(action.media);\n        }\n\n        return item;\n      }));\n  case REDRAFT:\n    return state.withMutations(map => {\n      map.set('text', action.raw_text || unescapeHTML(expandMentions(action.status)));\n      map.set('in_reply_to', action.status.get('in_reply_to_id'));\n      map.set('privacy', action.status.get('visibility'));\n      map.set('media_attachments', action.status.get('media_attachments'));\n      map.set('focusDate', new Date());\n      map.set('caretPosition', null);\n      map.set('idempotencyKey', uuid());\n      map.set('sensitive', action.status.get('sensitive'));\n\n      if (action.status.get('spoiler_text').length > 0) {\n        map.set('spoiler', true);\n        map.set('spoiler_text', action.status.get('spoiler_text'));\n      } else {\n        map.set('spoiler', false);\n        map.set('spoiler_text', '');\n      }\n\n      if (action.status.get('poll')) {\n        map.set('poll', ImmutableMap({\n          options: action.status.getIn(['poll', 'options']).map(x => x.get('title')),\n          multiple: action.status.getIn(['poll', 'multiple']),\n          expires_in: 24 * 3600,\n        }));\n      }\n    });\n  case COMPOSE_POLL_ADD:\n    return state.set('poll', initialPoll);\n  case COMPOSE_POLL_REMOVE:\n    return state.set('poll', null);\n  case COMPOSE_POLL_OPTION_ADD:\n    return state.updateIn(['poll', 'options'], options => options.push(action.title));\n  case COMPOSE_POLL_OPTION_CHANGE:\n    return state.setIn(['poll', 'options', action.index], action.title);\n  case COMPOSE_POLL_OPTION_REMOVE:\n    return state.updateIn(['poll', 'options'], options => options.delete(action.index));\n  case COMPOSE_POLL_SETTINGS_CHANGE:\n    return state.update('poll', poll => poll.set('expires_in', action.expiresIn).set('multiple', action.isMultiple));\n  default:\n    return state;\n  }\n};\n"
  },
  {
    "path": "app/javascript/mastodon/reducers/contexts.js",
    "content": "import {\n  ACCOUNT_BLOCK_SUCCESS,\n  ACCOUNT_MUTE_SUCCESS,\n} from '../actions/accounts';\nimport { CONTEXT_FETCH_SUCCESS } from '../actions/statuses';\nimport { TIMELINE_DELETE, TIMELINE_UPDATE } from '../actions/timelines';\nimport { Map as ImmutableMap, List as ImmutableList } from 'immutable';\nimport compareId from '../compare_id';\n\nconst initialState = ImmutableMap({\n  inReplyTos: ImmutableMap(),\n  replies: ImmutableMap(),\n});\n\nconst normalizeContext = (immutableState, id, ancestors, descendants) => immutableState.withMutations(state => {\n  state.update('inReplyTos', immutableAncestors => immutableAncestors.withMutations(inReplyTos => {\n    state.update('replies', immutableDescendants => immutableDescendants.withMutations(replies => {\n      function addReply({ id, in_reply_to_id }) {\n        if (in_reply_to_id && !inReplyTos.has(id)) {\n\n          replies.update(in_reply_to_id, ImmutableList(), siblings => {\n            const index = siblings.findLastIndex(sibling => compareId(sibling, id) < 0);\n            return siblings.insert(index + 1, id);\n          });\n\n          inReplyTos.set(id, in_reply_to_id);\n        }\n      }\n\n      // We know in_reply_to_id of statuses but `id` itself.\n      // So we assume that the status of the id replies to last ancestors.\n\n      ancestors.forEach(addReply);\n\n      if (ancestors[0]) {\n        addReply({ id, in_reply_to_id: ancestors[ancestors.length - 1].id });\n      }\n\n      descendants.forEach(addReply);\n    }));\n  }));\n});\n\nconst deleteFromContexts = (immutableState, ids) => immutableState.withMutations(state => {\n  state.update('inReplyTos', immutableAncestors => immutableAncestors.withMutations(inReplyTos => {\n    state.update('replies', immutableDescendants => immutableDescendants.withMutations(replies => {\n      ids.forEach(id => {\n        const inReplyToIdOfId = inReplyTos.get(id);\n        const repliesOfId = replies.get(id);\n        const siblings = replies.get(inReplyToIdOfId);\n\n        if (siblings) {\n          replies.set(inReplyToIdOfId, siblings.filterNot(sibling => sibling === id));\n        }\n\n\n        if (repliesOfId) {\n          repliesOfId.forEach(reply => inReplyTos.delete(reply));\n        }\n\n        inReplyTos.delete(id);\n        replies.delete(id);\n      });\n    }));\n  }));\n});\n\nconst filterContexts = (state, relationship, statuses) => {\n  const ownedStatusIds = statuses\n    .filter(status => status.get('account') === relationship.id)\n    .map(status => status.get('id'));\n\n  return deleteFromContexts(state, ownedStatusIds);\n};\n\nconst updateContext = (state, status) => {\n  if (status.in_reply_to_id) {\n    return state.withMutations(mutable => {\n      const replies = mutable.getIn(['replies', status.in_reply_to_id], ImmutableList());\n\n      mutable.setIn(['inReplyTos', status.id], status.in_reply_to_id);\n\n      if (!replies.includes(status.id)) {\n        mutable.setIn(['replies', status.in_reply_to_id], replies.push(status.id));\n      }\n    });\n  }\n\n  return state;\n};\n\nexport default function replies(state = initialState, action) {\n  switch(action.type) {\n  case ACCOUNT_BLOCK_SUCCESS:\n  case ACCOUNT_MUTE_SUCCESS:\n    return filterContexts(state, action.relationship, action.statuses);\n  case CONTEXT_FETCH_SUCCESS:\n    return normalizeContext(state, action.id, action.ancestors, action.descendants);\n  case TIMELINE_DELETE:\n    return deleteFromContexts(state, [action.id]);\n  case TIMELINE_UPDATE:\n    return updateContext(state, action.status);\n  default:\n    return state;\n  }\n};\n"
  },
  {
    "path": "app/javascript/mastodon/reducers/conversations.js",
    "content": "import { Map as ImmutableMap, List as ImmutableList } from 'immutable';\nimport {\n  CONVERSATIONS_MOUNT,\n  CONVERSATIONS_UNMOUNT,\n  CONVERSATIONS_FETCH_REQUEST,\n  CONVERSATIONS_FETCH_SUCCESS,\n  CONVERSATIONS_FETCH_FAIL,\n  CONVERSATIONS_UPDATE,\n  CONVERSATIONS_READ,\n} from '../actions/conversations';\nimport compareId from '../compare_id';\n\nconst initialState = ImmutableMap({\n  items: ImmutableList(),\n  isLoading: false,\n  hasMore: true,\n  mounted: false,\n});\n\nconst conversationToMap = item => ImmutableMap({\n  id: item.id,\n  unread: item.unread,\n  accounts: ImmutableList(item.accounts.map(a => a.id)),\n  last_status: item.last_status ? item.last_status.id : null,\n});\n\nconst updateConversation = (state, item) => state.update('items', list => {\n  const index   = list.findIndex(x => x.get('id') === item.id);\n  const newItem = conversationToMap(item);\n\n  if (index === -1) {\n    return list.unshift(newItem);\n  } else {\n    return list.set(index, newItem);\n  }\n});\n\nconst expandNormalizedConversations = (state, conversations, next, isLoadingRecent) => {\n  let items = ImmutableList(conversations.map(conversationToMap));\n\n  return state.withMutations(mutable => {\n    if (!items.isEmpty()) {\n      mutable.update('items', list => {\n        list = list.map(oldItem => {\n          const newItemIndex = items.findIndex(x => x.get('id') === oldItem.get('id'));\n\n          if (newItemIndex === -1) {\n            return oldItem;\n          }\n\n          const newItem = items.get(newItemIndex);\n          items = items.delete(newItemIndex);\n\n          return newItem;\n        });\n\n        list = list.concat(items);\n\n        return list.sortBy(x => x.get('last_status'), (a, b) => {\n          if(a === null || b === null) {\n            return -1;\n          }\n\n          return compareId(a, b) * -1;\n        });\n      });\n    }\n\n    if (!next && !isLoadingRecent) {\n      mutable.set('hasMore', false);\n    }\n\n    mutable.set('isLoading', false);\n  });\n};\n\nexport default function conversations(state = initialState, action) {\n  switch (action.type) {\n  case CONVERSATIONS_FETCH_REQUEST:\n    return state.set('isLoading', true);\n  case CONVERSATIONS_FETCH_FAIL:\n    return state.set('isLoading', false);\n  case CONVERSATIONS_FETCH_SUCCESS:\n    return expandNormalizedConversations(state, action.conversations, action.next, action.isLoadingRecent);\n  case CONVERSATIONS_UPDATE:\n    return updateConversation(state, action.conversation);\n  case CONVERSATIONS_MOUNT:\n    return state.update('mounted', count => count + 1);\n  case CONVERSATIONS_UNMOUNT:\n    return state.update('mounted', count => count - 1);\n  case CONVERSATIONS_READ:\n    return state.update('items', list => list.map(item => {\n      if (item.get('id') === action.id) {\n        return item.set('unread', false);\n      }\n\n      return item;\n    }));\n  default:\n    return state;\n  }\n};\n"
  },
  {
    "path": "app/javascript/mastodon/reducers/custom_emojis.js",
    "content": "import { List as ImmutableList, fromJS as ConvertToImmutable } from 'immutable';\nimport { CUSTOM_EMOJIS_FETCH_SUCCESS } from '../actions/custom_emojis';\nimport { search as emojiSearch } from '../features/emoji/emoji_mart_search_light';\nimport { buildCustomEmojis } from '../features/emoji/emoji';\n\nconst initialState = ImmutableList([]);\n\nexport default function custom_emojis(state = initialState, action) {\n  if(action.type === CUSTOM_EMOJIS_FETCH_SUCCESS) {\n    state = ConvertToImmutable(action.custom_emojis);\n    emojiSearch('', { custom: buildCustomEmojis(state) });\n  }\n\n  return state;\n};\n"
  },
  {
    "path": "app/javascript/mastodon/reducers/domain_lists.js",
    "content": "import {\n  DOMAIN_BLOCKS_FETCH_SUCCESS,\n  DOMAIN_BLOCKS_EXPAND_SUCCESS,\n  DOMAIN_UNBLOCK_SUCCESS,\n} from '../actions/domain_blocks';\nimport { Map as ImmutableMap, OrderedSet as ImmutableOrderedSet } from 'immutable';\n\nconst initialState = ImmutableMap({\n  blocks: ImmutableMap({\n    items: ImmutableOrderedSet(),\n  }),\n});\n\nexport default function domainLists(state = initialState, action) {\n  switch(action.type) {\n  case DOMAIN_BLOCKS_FETCH_SUCCESS:\n    return state.setIn(['blocks', 'items'], ImmutableOrderedSet(action.domains)).setIn(['blocks', 'next'], action.next);\n  case DOMAIN_BLOCKS_EXPAND_SUCCESS:\n    return state.updateIn(['blocks', 'items'], set => set.union(action.domains)).setIn(['blocks', 'next'], action.next);\n  case DOMAIN_UNBLOCK_SUCCESS:\n    return state.updateIn(['blocks', 'items'], set => set.delete(action.domain));\n  default:\n    return state;\n  }\n};\n"
  },
  {
    "path": "app/javascript/mastodon/reducers/dropdown_menu.js",
    "content": "import Immutable from 'immutable';\nimport {\n  DROPDOWN_MENU_OPEN,\n  DROPDOWN_MENU_CLOSE,\n} from '../actions/dropdown_menu';\n\nconst initialState = Immutable.Map({ openId: null, placement: null, keyboard: false });\n\nexport default function dropdownMenu(state = initialState, action) {\n  switch (action.type) {\n  case DROPDOWN_MENU_OPEN:\n    return state.merge({ openId: action.id, placement: action.placement, keyboard: action.keyboard });\n  case DROPDOWN_MENU_CLOSE:\n    return state.get('openId') === action.id ? state.set('openId', null) : state;\n  default:\n    return state;\n  }\n}\n"
  },
  {
    "path": "app/javascript/mastodon/reducers/filters.js",
    "content": "import { FILTERS_FETCH_SUCCESS } from '../actions/filters';\nimport { List as ImmutableList, fromJS } from 'immutable';\n\nexport default function filters(state = ImmutableList(), action) {\n  switch(action.type) {\n  case FILTERS_FETCH_SUCCESS:\n    return fromJS(action.filters);\n  default:\n    return state;\n  }\n};\n"
  },
  {
    "path": "app/javascript/mastodon/reducers/height_cache.js",
    "content": "import { Map as ImmutableMap } from 'immutable';\nimport { HEIGHT_CACHE_SET, HEIGHT_CACHE_CLEAR } from '../actions/height_cache';\n\nconst initialState = ImmutableMap();\n\nconst setHeight = (state, key, id, height) => {\n  return state.update(key, ImmutableMap(), map => map.set(id, height));\n};\n\nconst clearHeights = () => {\n  return ImmutableMap();\n};\n\nexport default function statuses(state = initialState, action) {\n  switch(action.type) {\n  case HEIGHT_CACHE_SET:\n    return setHeight(state, action.key, action.id, action.height);\n  case HEIGHT_CACHE_CLEAR:\n    return clearHeights();\n  default:\n    return state;\n  }\n};\n"
  },
  {
    "path": "app/javascript/mastodon/reducers/identity_proofs.js",
    "content": "import { Map as ImmutableMap, fromJS } from 'immutable';\nimport {\n  IDENTITY_PROOFS_ACCOUNT_FETCH_REQUEST,\n  IDENTITY_PROOFS_ACCOUNT_FETCH_SUCCESS,\n  IDENTITY_PROOFS_ACCOUNT_FETCH_FAIL,\n} from '../actions/identity_proofs';\n\nconst initialState = ImmutableMap();\n\nexport default function identityProofsReducer(state = initialState, action) {\n  switch(action.type) {\n  case IDENTITY_PROOFS_ACCOUNT_FETCH_REQUEST:\n    return state.set('isLoading', true);\n  case IDENTITY_PROOFS_ACCOUNT_FETCH_FAIL:\n    return state.set('isLoading', false);\n  case IDENTITY_PROOFS_ACCOUNT_FETCH_SUCCESS:\n    return state.update(identity_proofs => identity_proofs.withMutations(map => {\n      map.set('isLoading', false);\n      map.set('loaded', true);\n      map.set(action.accountId, fromJS(action.identity_proofs));\n    }));\n  default:\n    return state;\n  }\n};\n"
  },
  {
    "path": "app/javascript/mastodon/reducers/index.js",
    "content": "import { combineReducers } from 'redux-immutable';\nimport dropdown_menu from './dropdown_menu';\nimport timelines from './timelines';\nimport meta from './meta';\nimport alerts from './alerts';\nimport { loadingBarReducer } from 'react-redux-loading-bar';\nimport modal from './modal';\nimport user_lists from './user_lists';\nimport domain_lists from './domain_lists';\nimport accounts from './accounts';\nimport accounts_counters from './accounts_counters';\nimport statuses from './statuses';\nimport relationships from './relationships';\nimport settings from './settings';\nimport push_notifications from './push_notifications';\nimport status_lists from './status_lists';\nimport mutes from './mutes';\nimport reports from './reports';\nimport contexts from './contexts';\nimport compose from './compose';\nimport search from './search';\nimport media_attachments from './media_attachments';\nimport notifications from './notifications';\nimport height_cache from './height_cache';\nimport custom_emojis from './custom_emojis';\nimport lists from './lists';\nimport listEditor from './list_editor';\nimport listAdder from './list_adder';\nimport filters from './filters';\nimport conversations from './conversations';\nimport suggestions from './suggestions';\nimport polls from './polls';\nimport identity_proofs from './identity_proofs';\n\nconst reducers = {\n  dropdown_menu,\n  timelines,\n  meta,\n  alerts,\n  loadingBar: loadingBarReducer,\n  modal,\n  user_lists,\n  domain_lists,\n  status_lists,\n  accounts,\n  accounts_counters,\n  statuses,\n  relationships,\n  settings,\n  push_notifications,\n  mutes,\n  reports,\n  contexts,\n  compose,\n  search,\n  media_attachments,\n  notifications,\n  height_cache,\n  custom_emojis,\n  identity_proofs,\n  lists,\n  listEditor,\n  listAdder,\n  filters,\n  conversations,\n  suggestions,\n  polls,\n};\n\nexport default combineReducers(reducers);\n"
  },
  {
    "path": "app/javascript/mastodon/reducers/list_adder.js",
    "content": "import { Map as ImmutableMap, List as ImmutableList } from 'immutable';\nimport {\n  LIST_ADDER_RESET,\n  LIST_ADDER_SETUP,\n  LIST_ADDER_LISTS_FETCH_REQUEST,\n  LIST_ADDER_LISTS_FETCH_SUCCESS,\n  LIST_ADDER_LISTS_FETCH_FAIL,\n  LIST_EDITOR_ADD_SUCCESS,\n  LIST_EDITOR_REMOVE_SUCCESS,\n} from '../actions/lists';\n\nconst initialState = ImmutableMap({\n  accountId: null,\n\n  lists: ImmutableMap({\n    items: ImmutableList(),\n    loaded: false,\n    isLoading: false,\n  }),\n});\n\nexport default function listAdderReducer(state = initialState, action) {\n  switch(action.type) {\n  case LIST_ADDER_RESET:\n    return initialState;\n  case LIST_ADDER_SETUP:\n    return state.withMutations(map => {\n      map.set('accountId', action.account.get('id'));\n    });\n  case LIST_ADDER_LISTS_FETCH_REQUEST:\n    return state.setIn(['lists', 'isLoading'], true);\n  case LIST_ADDER_LISTS_FETCH_FAIL:\n    return state.setIn(['lists', 'isLoading'], false);\n  case LIST_ADDER_LISTS_FETCH_SUCCESS:\n    return state.update('lists', lists => lists.withMutations(map => {\n      map.set('isLoading', false);\n      map.set('loaded', true);\n      map.set('items', ImmutableList(action.lists.map(item => item.id)));\n    }));\n  case LIST_EDITOR_ADD_SUCCESS:\n    return state.updateIn(['lists', 'items'], list => list.unshift(action.listId));\n  case LIST_EDITOR_REMOVE_SUCCESS:\n    return state.updateIn(['lists', 'items'], list => list.filterNot(item => item === action.listId));\n  default:\n    return state;\n  }\n};\n"
  },
  {
    "path": "app/javascript/mastodon/reducers/list_editor.js",
    "content": "import { Map as ImmutableMap, List as ImmutableList } from 'immutable';\nimport {\n  LIST_CREATE_REQUEST,\n  LIST_CREATE_FAIL,\n  LIST_CREATE_SUCCESS,\n  LIST_UPDATE_REQUEST,\n  LIST_UPDATE_FAIL,\n  LIST_UPDATE_SUCCESS,\n  LIST_EDITOR_RESET,\n  LIST_EDITOR_SETUP,\n  LIST_EDITOR_TITLE_CHANGE,\n  LIST_ACCOUNTS_FETCH_REQUEST,\n  LIST_ACCOUNTS_FETCH_SUCCESS,\n  LIST_ACCOUNTS_FETCH_FAIL,\n  LIST_EDITOR_SUGGESTIONS_READY,\n  LIST_EDITOR_SUGGESTIONS_CLEAR,\n  LIST_EDITOR_SUGGESTIONS_CHANGE,\n  LIST_EDITOR_ADD_SUCCESS,\n  LIST_EDITOR_REMOVE_SUCCESS,\n} from '../actions/lists';\n\nconst initialState = ImmutableMap({\n  listId: null,\n  isSubmitting: false,\n  isChanged: false,\n  title: '',\n\n  accounts: ImmutableMap({\n    items: ImmutableList(),\n    loaded: false,\n    isLoading: false,\n  }),\n\n  suggestions: ImmutableMap({\n    value: '',\n    items: ImmutableList(),\n  }),\n});\n\nexport default function listEditorReducer(state = initialState, action) {\n  switch(action.type) {\n  case LIST_EDITOR_RESET:\n    return initialState;\n  case LIST_EDITOR_SETUP:\n    return state.withMutations(map => {\n      map.set('listId', action.list.get('id'));\n      map.set('title', action.list.get('title'));\n      map.set('isSubmitting', false);\n    });\n  case LIST_EDITOR_TITLE_CHANGE:\n    return state.withMutations(map => {\n      map.set('title', action.value);\n      map.set('isChanged', true);\n    });\n  case LIST_CREATE_REQUEST:\n  case LIST_UPDATE_REQUEST:\n    return state.withMutations(map => {\n      map.set('isSubmitting', true);\n      map.set('isChanged', false);\n    });\n  case LIST_CREATE_FAIL:\n  case LIST_UPDATE_FAIL:\n    return state.set('isSubmitting', false);\n  case LIST_CREATE_SUCCESS:\n  case LIST_UPDATE_SUCCESS:\n    return state.withMutations(map => {\n      map.set('isSubmitting', false);\n      map.set('listId', action.list.id);\n    });\n  case LIST_ACCOUNTS_FETCH_REQUEST:\n    return state.setIn(['accounts', 'isLoading'], true);\n  case LIST_ACCOUNTS_FETCH_FAIL:\n    return state.setIn(['accounts', 'isLoading'], false);\n  case LIST_ACCOUNTS_FETCH_SUCCESS:\n    return state.update('accounts', accounts => accounts.withMutations(map => {\n      map.set('isLoading', false);\n      map.set('loaded', true);\n      map.set('items', ImmutableList(action.accounts.map(item => item.id)));\n    }));\n  case LIST_EDITOR_SUGGESTIONS_CHANGE:\n    return state.setIn(['suggestions', 'value'], action.value);\n  case LIST_EDITOR_SUGGESTIONS_READY:\n    return state.setIn(['suggestions', 'items'], ImmutableList(action.accounts.map(item => item.id)));\n  case LIST_EDITOR_SUGGESTIONS_CLEAR:\n    return state.update('suggestions', suggestions => suggestions.withMutations(map => {\n      map.set('items', ImmutableList());\n      map.set('value', '');\n    }));\n  case LIST_EDITOR_ADD_SUCCESS:\n    return state.updateIn(['accounts', 'items'], list => list.unshift(action.accountId));\n  case LIST_EDITOR_REMOVE_SUCCESS:\n    return state.updateIn(['accounts', 'items'], list => list.filterNot(item => item === action.accountId));\n  default:\n    return state;\n  }\n};\n"
  },
  {
    "path": "app/javascript/mastodon/reducers/lists.js",
    "content": "import {\n  LIST_FETCH_SUCCESS,\n  LIST_FETCH_FAIL,\n  LISTS_FETCH_SUCCESS,\n  LIST_CREATE_SUCCESS,\n  LIST_UPDATE_SUCCESS,\n  LIST_DELETE_SUCCESS,\n} from '../actions/lists';\nimport { Map as ImmutableMap, fromJS } from 'immutable';\n\nconst initialState = ImmutableMap();\n\nconst normalizeList = (state, list) => state.set(list.id, fromJS(list));\n\nconst normalizeLists = (state, lists) => {\n  lists.forEach(list => {\n    state = normalizeList(state, list);\n  });\n\n  return state;\n};\n\nexport default function lists(state = initialState, action) {\n  switch(action.type) {\n  case LIST_FETCH_SUCCESS:\n  case LIST_CREATE_SUCCESS:\n  case LIST_UPDATE_SUCCESS:\n    return normalizeList(state, action.list);\n  case LISTS_FETCH_SUCCESS:\n    return normalizeLists(state, action.lists);\n  case LIST_DELETE_SUCCESS:\n  case LIST_FETCH_FAIL:\n    return state.set(action.id, false);\n  default:\n    return state;\n  }\n};\n"
  },
  {
    "path": "app/javascript/mastodon/reducers/media_attachments.js",
    "content": "import { STORE_HYDRATE } from '../actions/store';\nimport { Map as ImmutableMap } from 'immutable';\n\nconst initialState = ImmutableMap({\n  accept_content_types: [],\n});\n\nexport default function meta(state = initialState, action) {\n  switch(action.type) {\n  case STORE_HYDRATE:\n    return state.merge(action.state.get('media_attachments'));\n  default:\n    return state;\n  }\n};\n"
  },
  {
    "path": "app/javascript/mastodon/reducers/meta.js",
    "content": "import { STORE_HYDRATE } from '../actions/store';\nimport { Map as ImmutableMap } from 'immutable';\n\nconst initialState = ImmutableMap({\n  streaming_api_base_url: null,\n  access_token: null,\n});\n\nexport default function meta(state = initialState, action) {\n  switch(action.type) {\n  case STORE_HYDRATE:\n    return state.merge(action.state.get('meta'));\n  default:\n    return state;\n  }\n};\n"
  },
  {
    "path": "app/javascript/mastodon/reducers/modal.js",
    "content": "import { MODAL_OPEN, MODAL_CLOSE } from '../actions/modal';\n\nconst initialState = {\n  modalType: null,\n  modalProps: {},\n};\n\nexport default function modal(state = initialState, action) {\n  switch(action.type) {\n  case MODAL_OPEN:\n    return { modalType: action.modalType, modalProps: action.modalProps };\n  case MODAL_CLOSE:\n    return initialState;\n  default:\n    return state;\n  }\n};\n"
  },
  {
    "path": "app/javascript/mastodon/reducers/mutes.js",
    "content": "import Immutable from 'immutable';\n\nimport {\n  MUTES_INIT_MODAL,\n  MUTES_TOGGLE_HIDE_NOTIFICATIONS,\n} from '../actions/mutes';\n\nconst initialState = Immutable.Map({\n  new: Immutable.Map({\n    isSubmitting: false,\n    account: null,\n    notifications: true,\n  }),\n});\n\nexport default function mutes(state = initialState, action) {\n  switch (action.type) {\n  case MUTES_INIT_MODAL:\n    return state.withMutations((state) => {\n      state.setIn(['new', 'isSubmitting'], false);\n      state.setIn(['new', 'account'], action.account);\n      state.setIn(['new', 'notifications'], true);\n    });\n  case MUTES_TOGGLE_HIDE_NOTIFICATIONS:\n    return state.updateIn(['new', 'notifications'], (old) => !old);\n  default:\n    return state;\n  }\n}\n"
  },
  {
    "path": "app/javascript/mastodon/reducers/notifications.js",
    "content": "import {\n  NOTIFICATIONS_UPDATE,\n  NOTIFICATIONS_EXPAND_SUCCESS,\n  NOTIFICATIONS_EXPAND_REQUEST,\n  NOTIFICATIONS_EXPAND_FAIL,\n  NOTIFICATIONS_FILTER_SET,\n  NOTIFICATIONS_CLEAR,\n  NOTIFICATIONS_SCROLL_TOP,\n} from '../actions/notifications';\nimport {\n  ACCOUNT_BLOCK_SUCCESS,\n  ACCOUNT_MUTE_SUCCESS,\n} from '../actions/accounts';\nimport { TIMELINE_DELETE, TIMELINE_DISCONNECT } from '../actions/timelines';\nimport { Map as ImmutableMap, List as ImmutableList } from 'immutable';\nimport compareId from '../compare_id';\n\nconst initialState = ImmutableMap({\n  items: ImmutableList(),\n  hasMore: true,\n  top: false,\n  unread: 0,\n  isLoading: false,\n});\n\nconst notificationToMap = notification => ImmutableMap({\n  id: notification.id,\n  type: notification.type,\n  account: notification.account.id,\n  created_at: notification.created_at,\n  status: notification.status ? notification.status.id : null,\n});\n\nconst normalizeNotification = (state, notification) => {\n  const top = state.get('top');\n\n  if (!top) {\n    state = state.update('unread', unread => unread + 1);\n  }\n\n  return state.update('items', list => {\n    if (top && list.size > 40) {\n      list = list.take(20);\n    }\n\n    return list.unshift(notificationToMap(notification));\n  });\n};\n\nconst expandNormalizedNotifications = (state, notifications, next) => {\n  let items = ImmutableList();\n\n  notifications.forEach((n, i) => {\n    items = items.set(i, notificationToMap(n));\n  });\n\n  return state.withMutations(mutable => {\n    if (!items.isEmpty()) {\n      mutable.update('items', list => {\n        const lastIndex = 1 + list.findLastIndex(\n          item => item !== null && (compareId(item.get('id'), items.last().get('id')) > 0 || item.get('id') === items.last().get('id'))\n        );\n\n        const firstIndex = 1 + list.take(lastIndex).findLastIndex(\n          item => item !== null && compareId(item.get('id'), items.first().get('id')) > 0\n        );\n\n        return list.take(firstIndex).concat(items, list.skip(lastIndex));\n      });\n    }\n\n    if (!next) {\n      mutable.set('hasMore', false);\n    }\n\n    mutable.set('isLoading', false);\n  });\n};\n\nconst filterNotifications = (state, relationship) => {\n  return state.update('items', list => list.filterNot(item => item !== null && item.get('account') === relationship.id));\n};\n\nconst updateTop = (state, top) => {\n  if (top) {\n    state = state.set('unread', 0);\n  }\n\n  return state.set('top', top);\n};\n\nconst deleteByStatus = (state, statusId) => {\n  return state.update('items', list => list.filterNot(item => item !== null && item.get('status') === statusId));\n};\n\nexport default function notifications(state = initialState, action) {\n  switch(action.type) {\n  case NOTIFICATIONS_EXPAND_REQUEST:\n    return state.set('isLoading', true);\n  case NOTIFICATIONS_EXPAND_FAIL:\n    return state.set('isLoading', false);\n  case NOTIFICATIONS_FILTER_SET:\n    return state.set('items', ImmutableList()).set('hasMore', true);\n  case NOTIFICATIONS_SCROLL_TOP:\n    return updateTop(state, action.top);\n  case NOTIFICATIONS_UPDATE:\n    return normalizeNotification(state, action.notification);\n  case NOTIFICATIONS_EXPAND_SUCCESS:\n    return expandNormalizedNotifications(state, action.notifications, action.next);\n  case ACCOUNT_BLOCK_SUCCESS:\n    return filterNotifications(state, action.relationship);\n  case ACCOUNT_MUTE_SUCCESS:\n    return action.relationship.muting_notifications ? filterNotifications(state, action.relationship) : state;\n  case NOTIFICATIONS_CLEAR:\n    return state.set('items', ImmutableList()).set('hasMore', false);\n  case TIMELINE_DELETE:\n    return deleteByStatus(state, action.id);\n  case TIMELINE_DISCONNECT:\n    return action.timeline === 'home' ?\n      state.update('items', items => items.first() ? items.unshift(null) : items) :\n      state;\n  default:\n    return state;\n  }\n};\n"
  },
  {
    "path": "app/javascript/mastodon/reducers/polls.js",
    "content": "import { POLLS_IMPORT } from 'mastodon/actions/importer';\nimport { Map as ImmutableMap, fromJS } from 'immutable';\n\nconst importPolls = (state, polls) => state.withMutations(map => polls.forEach(poll => map.set(poll.id, fromJS(poll))));\n\nconst initialState = ImmutableMap();\n\nexport default function polls(state = initialState, action) {\n  switch(action.type) {\n  case POLLS_IMPORT:\n    return importPolls(state, action.polls);\n  default:\n    return state;\n  }\n}\n"
  },
  {
    "path": "app/javascript/mastodon/reducers/push_notifications.js",
    "content": "import { STORE_HYDRATE } from '../actions/store';\nimport { SET_BROWSER_SUPPORT, SET_SUBSCRIPTION, CLEAR_SUBSCRIPTION, SET_ALERTS } from '../actions/push_notifications';\nimport Immutable from 'immutable';\n\nconst initialState = Immutable.Map({\n  subscription: null,\n  alerts: new Immutable.Map({\n    follow: false,\n    favourite: false,\n    reblog: false,\n    mention: false,\n    poll: false,\n  }),\n  isSubscribed: false,\n  browserSupport: false,\n});\n\nexport default function push_subscriptions(state = initialState, action) {\n  switch(action.type) {\n  case STORE_HYDRATE: {\n    const push_subscription = action.state.get('push_subscription');\n\n    if (push_subscription) {\n      return state\n        .set('subscription', new Immutable.Map({\n          id: push_subscription.get('id'),\n          endpoint: push_subscription.get('endpoint'),\n        }))\n        .set('alerts', push_subscription.get('alerts') || initialState.get('alerts'))\n        .set('isSubscribed', true);\n    }\n\n    return state;\n  }\n  case SET_SUBSCRIPTION:\n    return state\n      .set('subscription', new Immutable.Map({\n        id: action.subscription.id,\n        endpoint: action.subscription.endpoint,\n      }))\n      .set('alerts', new Immutable.Map(action.subscription.alerts))\n      .set('isSubscribed', true);\n  case SET_BROWSER_SUPPORT:\n    return state.set('browserSupport', action.value);\n  case CLEAR_SUBSCRIPTION:\n    return initialState;\n  case SET_ALERTS:\n    return state.setIn(action.path, action.value);\n  default:\n    return state;\n  }\n};\n"
  },
  {
    "path": "app/javascript/mastodon/reducers/relationships.js",
    "content": "import {\n  ACCOUNT_FOLLOW_SUCCESS,\n  ACCOUNT_FOLLOW_REQUEST,\n  ACCOUNT_FOLLOW_FAIL,\n  ACCOUNT_UNFOLLOW_SUCCESS,\n  ACCOUNT_UNFOLLOW_REQUEST,\n  ACCOUNT_UNFOLLOW_FAIL,\n  ACCOUNT_BLOCK_SUCCESS,\n  ACCOUNT_UNBLOCK_SUCCESS,\n  ACCOUNT_MUTE_SUCCESS,\n  ACCOUNT_UNMUTE_SUCCESS,\n  ACCOUNT_PIN_SUCCESS,\n  ACCOUNT_UNPIN_SUCCESS,\n  RELATIONSHIPS_FETCH_SUCCESS,\n} from '../actions/accounts';\nimport {\n  DOMAIN_BLOCK_SUCCESS,\n  DOMAIN_UNBLOCK_SUCCESS,\n} from '../actions/domain_blocks';\nimport { Map as ImmutableMap, fromJS } from 'immutable';\n\nconst normalizeRelationship = (state, relationship) => state.set(relationship.id, fromJS(relationship));\n\nconst normalizeRelationships = (state, relationships) => {\n  relationships.forEach(relationship => {\n    state = normalizeRelationship(state, relationship);\n  });\n\n  return state;\n};\n\nconst setDomainBlocking = (state, accounts, blocking) => {\n  return state.withMutations(map => {\n    accounts.forEach(id => {\n      map.setIn([id, 'domain_blocking'], blocking);\n    });\n  });\n};\n\nconst initialState = ImmutableMap();\n\nexport default function relationships(state = initialState, action) {\n  switch(action.type) {\n  case ACCOUNT_FOLLOW_REQUEST:\n    return state.setIn([action.id, action.locked ? 'requested' : 'following'], true);\n  case ACCOUNT_FOLLOW_FAIL:\n    return state.setIn([action.id, action.locked ? 'requested' : 'following'], false);\n  case ACCOUNT_UNFOLLOW_REQUEST:\n    return state.setIn([action.id, 'following'], false);\n  case ACCOUNT_UNFOLLOW_FAIL:\n    return state.setIn([action.id, 'following'], true);\n  case ACCOUNT_FOLLOW_SUCCESS:\n  case ACCOUNT_UNFOLLOW_SUCCESS:\n  case ACCOUNT_BLOCK_SUCCESS:\n  case ACCOUNT_UNBLOCK_SUCCESS:\n  case ACCOUNT_MUTE_SUCCESS:\n  case ACCOUNT_UNMUTE_SUCCESS:\n  case ACCOUNT_PIN_SUCCESS:\n  case ACCOUNT_UNPIN_SUCCESS:\n    return normalizeRelationship(state, action.relationship);\n  case RELATIONSHIPS_FETCH_SUCCESS:\n    return normalizeRelationships(state, action.relationships);\n  case DOMAIN_BLOCK_SUCCESS:\n    return setDomainBlocking(state, action.accounts, true);\n  case DOMAIN_UNBLOCK_SUCCESS:\n    return setDomainBlocking(state, action.accounts, false);\n  default:\n    return state;\n  }\n};\n"
  },
  {
    "path": "app/javascript/mastodon/reducers/reports.js",
    "content": "import {\n  REPORT_INIT,\n  REPORT_SUBMIT_REQUEST,\n  REPORT_SUBMIT_SUCCESS,\n  REPORT_SUBMIT_FAIL,\n  REPORT_CANCEL,\n  REPORT_STATUS_TOGGLE,\n  REPORT_COMMENT_CHANGE,\n  REPORT_FORWARD_CHANGE,\n} from '../actions/reports';\nimport { Map as ImmutableMap, Set as ImmutableSet } from 'immutable';\n\nconst initialState = ImmutableMap({\n  new: ImmutableMap({\n    isSubmitting: false,\n    account_id: null,\n    status_ids: ImmutableSet(),\n    comment: '',\n    forward: false,\n  }),\n});\n\nexport default function reports(state = initialState, action) {\n  switch(action.type) {\n  case REPORT_INIT:\n    return state.withMutations(map => {\n      map.setIn(['new', 'isSubmitting'], false);\n      map.setIn(['new', 'account_id'], action.account.get('id'));\n\n      if (state.getIn(['new', 'account_id']) !== action.account.get('id')) {\n        map.setIn(['new', 'status_ids'], action.status ? ImmutableSet([action.status.getIn(['reblog', 'id'], action.status.get('id'))]) : ImmutableSet());\n        map.setIn(['new', 'comment'], '');\n      } else if (action.status) {\n        map.updateIn(['new', 'status_ids'], ImmutableSet(), set => set.add(action.status.getIn(['reblog', 'id'], action.status.get('id'))));\n      }\n    });\n  case REPORT_STATUS_TOGGLE:\n    return state.updateIn(['new', 'status_ids'], ImmutableSet(), set => {\n      if (action.checked) {\n        return set.add(action.statusId);\n      }\n\n      return set.remove(action.statusId);\n    });\n  case REPORT_COMMENT_CHANGE:\n    return state.setIn(['new', 'comment'], action.comment);\n  case REPORT_FORWARD_CHANGE:\n    return state.setIn(['new', 'forward'], action.forward);\n  case REPORT_SUBMIT_REQUEST:\n    return state.setIn(['new', 'isSubmitting'], true);\n  case REPORT_SUBMIT_FAIL:\n    return state.setIn(['new', 'isSubmitting'], false);\n  case REPORT_CANCEL:\n  case REPORT_SUBMIT_SUCCESS:\n    return state.withMutations(map => {\n      map.setIn(['new', 'account_id'], null);\n      map.setIn(['new', 'status_ids'], ImmutableSet());\n      map.setIn(['new', 'comment'], '');\n      map.setIn(['new', 'isSubmitting'], false);\n    });\n  default:\n    return state;\n  }\n};\n"
  },
  {
    "path": "app/javascript/mastodon/reducers/search.js",
    "content": "import {\n  SEARCH_CHANGE,\n  SEARCH_CLEAR,\n  SEARCH_FETCH_SUCCESS,\n  SEARCH_SHOW,\n} from '../actions/search';\nimport {\n  COMPOSE_MENTION,\n  COMPOSE_REPLY,\n  COMPOSE_DIRECT,\n} from '../actions/compose';\nimport { Map as ImmutableMap, List as ImmutableList, fromJS } from 'immutable';\n\nconst initialState = ImmutableMap({\n  value: '',\n  submitted: false,\n  hidden: false,\n  results: ImmutableMap(),\n});\n\nexport default function search(state = initialState, action) {\n  switch(action.type) {\n  case SEARCH_CHANGE:\n    return state.set('value', action.value);\n  case SEARCH_CLEAR:\n    return state.withMutations(map => {\n      map.set('value', '');\n      map.set('results', ImmutableMap());\n      map.set('submitted', false);\n      map.set('hidden', false);\n    });\n  case SEARCH_SHOW:\n    return state.set('hidden', false);\n  case COMPOSE_REPLY:\n  case COMPOSE_MENTION:\n  case COMPOSE_DIRECT:\n    return state.set('hidden', true);\n  case SEARCH_FETCH_SUCCESS:\n    return state.set('results', ImmutableMap({\n      accounts: ImmutableList(action.results.accounts.map(item => item.id)),\n      statuses: ImmutableList(action.results.statuses.map(item => item.id)),\n      hashtags: fromJS(action.results.hashtags),\n    })).set('submitted', true);\n  default:\n    return state;\n  }\n};\n"
  },
  {
    "path": "app/javascript/mastodon/reducers/settings.js",
    "content": "import { SETTING_CHANGE, SETTING_SAVE } from '../actions/settings';\nimport { NOTIFICATIONS_FILTER_SET } from '../actions/notifications';\nimport { COLUMN_ADD, COLUMN_REMOVE, COLUMN_MOVE, COLUMN_PARAMS_CHANGE } from '../actions/columns';\nimport { STORE_HYDRATE } from '../actions/store';\nimport { EMOJI_USE } from '../actions/emojis';\nimport { LIST_DELETE_SUCCESS, LIST_FETCH_FAIL } from '../actions/lists';\nimport { Map as ImmutableMap, fromJS } from 'immutable';\nimport uuid from '../uuid';\n\nconst initialState = ImmutableMap({\n  saved: true,\n\n  onboarded: false,\n\n  skinTone: 1,\n\n  home: ImmutableMap({\n    shows: ImmutableMap({\n      reblog: true,\n      reply: true,\n    }),\n\n    regex: ImmutableMap({\n      body: '',\n    }),\n  }),\n\n  notifications: ImmutableMap({\n    alerts: ImmutableMap({\n      follow: true,\n      favourite: true,\n      reblog: true,\n      mention: true,\n      poll: true,\n    }),\n\n    quickFilter: ImmutableMap({\n      active: 'all',\n      show: true,\n      advanced: false,\n    }),\n\n    shows: ImmutableMap({\n      follow: true,\n      favourite: true,\n      reblog: true,\n      mention: true,\n      poll: true,\n    }),\n\n    sounds: ImmutableMap({\n      follow: true,\n      favourite: true,\n      reblog: true,\n      mention: true,\n      poll: true,\n    }),\n  }),\n\n  community: ImmutableMap({\n    regex: ImmutableMap({\n      body: '',\n    }),\n  }),\n\n  public: ImmutableMap({\n    regex: ImmutableMap({\n      body: '',\n    }),\n  }),\n\n  direct: ImmutableMap({\n    regex: ImmutableMap({\n      body: '',\n    }),\n  }),\n\n  trends: ImmutableMap({\n    show: true,\n  }),\n});\n\nconst defaultColumns = fromJS([\n  { id: 'COMPOSE', uuid: uuid(), params: {} },\n  { id: 'HOME', uuid: uuid(), params: {} },\n  { id: 'NOTIFICATIONS', uuid: uuid(), params: {} },\n]);\n\nconst hydrate = (state, settings) => state.mergeDeep(settings).update('columns', (val = defaultColumns) => val);\n\nconst moveColumn = (state, uuid, direction) => {\n  const columns  = state.get('columns');\n  const index    = columns.findIndex(item => item.get('uuid') === uuid);\n  const newIndex = index + direction;\n\n  let newColumns;\n\n  newColumns = columns.splice(index, 1);\n  newColumns = newColumns.splice(newIndex, 0, columns.get(index));\n\n  return state\n    .set('columns', newColumns)\n    .set('saved', false);\n};\n\nconst changeColumnParams = (state, uuid, path, value) => {\n  const columns = state.get('columns');\n  const index   = columns.findIndex(item => item.get('uuid') === uuid);\n\n  const newColumns = columns.update(index, column => column.updateIn(['params', ...path], () => value));\n\n  return state\n    .set('columns', newColumns)\n    .set('saved', false);\n};\n\nconst updateFrequentEmojis = (state, emoji) => state.update('frequentlyUsedEmojis', ImmutableMap(), map => map.update(emoji.id, 0, count => count + 1)).set('saved', false);\n\nconst filterDeadListColumns = (state, listId) => state.update('columns', columns => columns.filterNot(column => column.get('id') === 'LIST' && column.get('params').get('id') === listId));\n\nexport default function settings(state = initialState, action) {\n  switch(action.type) {\n  case STORE_HYDRATE:\n    return hydrate(state, action.state.get('settings'));\n  case NOTIFICATIONS_FILTER_SET:\n  case SETTING_CHANGE:\n    return state\n      .setIn(action.path, action.value)\n      .set('saved', false);\n  case COLUMN_ADD:\n    return state\n      .update('columns', list => list.push(fromJS({ id: action.id, uuid: uuid(), params: action.params })))\n      .set('saved', false);\n  case COLUMN_REMOVE:\n    return state\n      .update('columns', list => list.filterNot(item => item.get('uuid') === action.uuid))\n      .set('saved', false);\n  case COLUMN_MOVE:\n    return moveColumn(state, action.uuid, action.direction);\n  case COLUMN_PARAMS_CHANGE:\n    return changeColumnParams(state, action.uuid, action.path, action.value);\n  case EMOJI_USE:\n    return updateFrequentEmojis(state, action.emoji);\n  case SETTING_SAVE:\n    return state.set('saved', true);\n  case LIST_FETCH_FAIL:\n    return action.error.response.status === 404 ? filterDeadListColumns(state, action.id) : state;\n  case LIST_DELETE_SUCCESS:\n    return filterDeadListColumns(state, action.id);\n  default:\n    return state;\n  }\n};\n"
  },
  {
    "path": "app/javascript/mastodon/reducers/status_lists.js",
    "content": "import {\n  FAVOURITED_STATUSES_FETCH_REQUEST,\n  FAVOURITED_STATUSES_FETCH_SUCCESS,\n  FAVOURITED_STATUSES_FETCH_FAIL,\n  FAVOURITED_STATUSES_EXPAND_REQUEST,\n  FAVOURITED_STATUSES_EXPAND_SUCCESS,\n  FAVOURITED_STATUSES_EXPAND_FAIL,\n} from '../actions/favourites';\nimport {\n  PINNED_STATUSES_FETCH_SUCCESS,\n} from '../actions/pin_statuses';\nimport { Map as ImmutableMap, List as ImmutableList } from 'immutable';\nimport {\n  FAVOURITE_SUCCESS,\n  UNFAVOURITE_SUCCESS,\n  PIN_SUCCESS,\n  UNPIN_SUCCESS,\n} from '../actions/interactions';\n\nconst initialState = ImmutableMap({\n  favourites: ImmutableMap({\n    next: null,\n    loaded: false,\n    items: ImmutableList(),\n  }),\n  pins: ImmutableMap({\n    next: null,\n    loaded: false,\n    items: ImmutableList(),\n  }),\n});\n\nconst normalizeList = (state, listType, statuses, next) => {\n  return state.update(listType, listMap => listMap.withMutations(map => {\n    map.set('next', next);\n    map.set('loaded', true);\n    map.set('isLoading', false);\n    map.set('items', ImmutableList(statuses.map(item => item.id)));\n  }));\n};\n\nconst appendToList = (state, listType, statuses, next) => {\n  return state.update(listType, listMap => listMap.withMutations(map => {\n    map.set('next', next);\n    map.set('isLoading', false);\n    map.set('items', map.get('items').concat(statuses.map(item => item.id)));\n  }));\n};\n\nconst prependOneToList = (state, listType, status) => {\n  return state.update(listType, listMap => listMap.withMutations(map => {\n    map.set('items', map.get('items').unshift(status.get('id')));\n  }));\n};\n\nconst removeOneFromList = (state, listType, status) => {\n  return state.update(listType, listMap => listMap.withMutations(map => {\n    map.set('items', map.get('items').filter(item => item !== status.get('id')));\n  }));\n};\n\nexport default function statusLists(state = initialState, action) {\n  switch(action.type) {\n  case FAVOURITED_STATUSES_FETCH_REQUEST:\n  case FAVOURITED_STATUSES_EXPAND_REQUEST:\n    return state.setIn(['favourites', 'isLoading'], true);\n  case FAVOURITED_STATUSES_FETCH_FAIL:\n  case FAVOURITED_STATUSES_EXPAND_FAIL:\n    return state.setIn(['favourites', 'isLoading'], false);\n  case FAVOURITED_STATUSES_FETCH_SUCCESS:\n    return normalizeList(state, 'favourites', action.statuses, action.next);\n  case FAVOURITED_STATUSES_EXPAND_SUCCESS:\n    return appendToList(state, 'favourites', action.statuses, action.next);\n  case FAVOURITE_SUCCESS:\n    return prependOneToList(state, 'favourites', action.status);\n  case UNFAVOURITE_SUCCESS:\n    return removeOneFromList(state, 'favourites', action.status);\n  case PINNED_STATUSES_FETCH_SUCCESS:\n    return normalizeList(state, 'pins', action.statuses, action.next);\n  case PIN_SUCCESS:\n    return prependOneToList(state, 'pins', action.status);\n  case UNPIN_SUCCESS:\n    return removeOneFromList(state, 'pins', action.status);\n  default:\n    return state;\n  }\n};\n"
  },
  {
    "path": "app/javascript/mastodon/reducers/statuses.js",
    "content": "import {\n  REBLOG_REQUEST,\n  REBLOG_FAIL,\n  FAVOURITE_REQUEST,\n  FAVOURITE_FAIL,\n} from '../actions/interactions';\nimport {\n  STATUS_MUTE_SUCCESS,\n  STATUS_UNMUTE_SUCCESS,\n  STATUS_REVEAL,\n  STATUS_HIDE,\n} from '../actions/statuses';\nimport { TIMELINE_DELETE } from '../actions/timelines';\nimport { STATUS_IMPORT, STATUSES_IMPORT } from '../actions/importer';\nimport { Map as ImmutableMap, fromJS } from 'immutable';\n\nconst importStatus = (state, status) => state.set(status.id, fromJS(status));\n\nconst importStatuses = (state, statuses) =>\n  state.withMutations(mutable => statuses.forEach(status => importStatus(mutable, status)));\n\nconst deleteStatus = (state, id, references) => {\n  references.forEach(ref => {\n    state = deleteStatus(state, ref[0], []);\n  });\n\n  return state.delete(id);\n};\n\nconst initialState = ImmutableMap();\n\nexport default function statuses(state = initialState, action) {\n  switch(action.type) {\n  case STATUS_IMPORT:\n    return importStatus(state, action.status);\n  case STATUSES_IMPORT:\n    return importStatuses(state, action.statuses);\n  case FAVOURITE_REQUEST:\n    return state.setIn([action.status.get('id'), 'favourited'], true);\n  case FAVOURITE_FAIL:\n    return state.get(action.status.get('id')) === undefined ? state : state.setIn([action.status.get('id'), 'favourited'], false);\n  case REBLOG_REQUEST:\n    return state.setIn([action.status.get('id'), 'reblogged'], true);\n  case REBLOG_FAIL:\n    return state.get(action.status.get('id')) === undefined ? state : state.setIn([action.status.get('id'), 'reblogged'], false);\n  case STATUS_MUTE_SUCCESS:\n    return state.setIn([action.id, 'muted'], true);\n  case STATUS_UNMUTE_SUCCESS:\n    return state.setIn([action.id, 'muted'], false);\n  case STATUS_REVEAL:\n    return state.withMutations(map => {\n      action.ids.forEach(id => {\n        if (!(state.get(id) === undefined)) {\n          map.setIn([id, 'hidden'], false);\n        }\n      });\n    });\n  case STATUS_HIDE:\n    return state.withMutations(map => {\n      action.ids.forEach(id => {\n        if (!(state.get(id) === undefined)) {\n          map.setIn([id, 'hidden'], true);\n        }\n      });\n    });\n  case TIMELINE_DELETE:\n    return deleteStatus(state, action.id, action.references);\n  default:\n    return state;\n  }\n};\n"
  },
  {
    "path": "app/javascript/mastodon/reducers/suggestions.js",
    "content": "import {\n  SUGGESTIONS_FETCH_REQUEST,\n  SUGGESTIONS_FETCH_SUCCESS,\n  SUGGESTIONS_FETCH_FAIL,\n  SUGGESTIONS_DISMISS,\n} from '../actions/suggestions';\nimport { Map as ImmutableMap, List as ImmutableList, fromJS } from 'immutable';\n\nconst initialState = ImmutableMap({\n  items: ImmutableList(),\n  isLoading: false,\n});\n\nexport default function suggestionsReducer(state = initialState, action) {\n  switch(action.type) {\n  case SUGGESTIONS_FETCH_REQUEST:\n    return state.set('isLoading', true);\n  case SUGGESTIONS_FETCH_SUCCESS:\n    return state.withMutations(map => {\n      map.set('items', fromJS(action.accounts.map(x => x.id)));\n      map.set('isLoading', false);\n    });\n  case SUGGESTIONS_FETCH_FAIL:\n    return state.set('isLoading', false);\n  case SUGGESTIONS_DISMISS:\n    return state.update('items', list => list.filterNot(id => id === action.id));\n  default:\n    return state;\n  }\n};\n"
  },
  {
    "path": "app/javascript/mastodon/reducers/timelines.js",
    "content": "import {\n  TIMELINE_UPDATE,\n  TIMELINE_DELETE,\n  TIMELINE_CLEAR,\n  TIMELINE_EXPAND_SUCCESS,\n  TIMELINE_EXPAND_REQUEST,\n  TIMELINE_EXPAND_FAIL,\n  TIMELINE_SCROLL_TOP,\n  TIMELINE_CONNECT,\n  TIMELINE_DISCONNECT,\n} from '../actions/timelines';\nimport {\n  ACCOUNT_BLOCK_SUCCESS,\n  ACCOUNT_MUTE_SUCCESS,\n  ACCOUNT_UNFOLLOW_SUCCESS,\n} from '../actions/accounts';\nimport { Map as ImmutableMap, List as ImmutableList, fromJS } from 'immutable';\nimport compareId from '../compare_id';\n\nconst initialState = ImmutableMap();\n\nconst initialTimeline = ImmutableMap({\n  unread: 0,\n  online: false,\n  top: true,\n  isLoading: false,\n  hasMore: true,\n  items: ImmutableList(),\n});\n\nconst expandNormalizedTimeline = (state, timeline, statuses, next, isPartial, isLoadingRecent) => {\n  return state.update(timeline, initialTimeline, map => map.withMutations(mMap => {\n    mMap.set('isLoading', false);\n    mMap.set('isPartial', isPartial);\n\n    if (!next && !isLoadingRecent) mMap.set('hasMore', false);\n\n    if (timeline.endsWith(':pinned')) {\n      mMap.set('items', statuses.map(status => status.get('id')));\n    } else if (!statuses.isEmpty()) {\n      mMap.update('items', ImmutableList(), oldIds => {\n        const newIds = statuses.map(status => status.get('id'));\n\n        const lastIndex = oldIds.findLastIndex(id => id !== null && compareId(id, newIds.last()) >= 0) + 1;\n        const firstIndex = oldIds.take(lastIndex).findLastIndex(id => id !== null && compareId(id, newIds.first()) > 0);\n\n        if (firstIndex < 0) {\n          return (isPartial ? newIds.unshift(null) : newIds).concat(oldIds.skip(lastIndex));\n        }\n\n        return oldIds.take(firstIndex + 1).concat(\n          isPartial && oldIds.get(firstIndex) !== null ? newIds.unshift(null) : newIds,\n          oldIds.skip(lastIndex)\n        );\n      });\n    }\n  }));\n};\n\nconst updateTimeline = (state, timeline, status) => {\n  const top        = state.getIn([timeline, 'top']);\n  const ids        = state.getIn([timeline, 'items'], ImmutableList());\n  const includesId = ids.includes(status.get('id'));\n  const unread     = state.getIn([timeline, 'unread'], 0);\n\n  if (includesId) {\n    return state;\n  }\n\n  let newIds = ids;\n\n  return state.update(timeline, initialTimeline, map => map.withMutations(mMap => {\n    if (!top) mMap.set('unread', unread + 1);\n    if (top && ids.size > 40) newIds = newIds.take(20);\n    mMap.set('items', newIds.unshift(status.get('id')));\n  }));\n};\n\nconst deleteStatus = (state, id, accountId, references, exclude_account = null) => {\n  state.keySeq().forEach(timeline => {\n    if (exclude_account === null || (timeline !== `account:${exclude_account}` && !timeline.startsWith(`account:${exclude_account}:`)))\n      state = state.updateIn([timeline, 'items'], list => list.filterNot(item => item === id));\n  });\n\n  // Remove reblogs of deleted status\n  references.forEach(ref => {\n    state = deleteStatus(state, ref[0], ref[1], [], exclude_account);\n  });\n\n  return state;\n};\n\nconst clearTimeline = (state, timeline) => {\n  return state.set(timeline, initialTimeline);\n};\n\nconst filterTimelines = (state, relationship, statuses) => {\n  let references;\n\n  statuses.forEach(status => {\n    if (status.get('account') !== relationship.id) {\n      return;\n    }\n\n    references = statuses.filter(item => item.get('reblog') === status.get('id')).map(item => [item.get('id'), item.get('account')]);\n    state      = deleteStatus(state, status.get('id'), status.get('account'), references, relationship.id);\n  });\n\n  return state;\n};\n\nconst filterTimeline = (timeline, state, relationship, statuses) =>\n  state.updateIn([timeline, 'items'], ImmutableList(), list =>\n    list.filterNot(statusId =>\n      statuses.getIn([statusId, 'account']) === relationship.id\n    ));\n\nconst updateTop = (state, timeline, top) => {\n  return state.update(timeline, initialTimeline, map => map.withMutations(mMap => {\n    if (top) mMap.set('unread', 0);\n    mMap.set('top', top);\n  }));\n};\n\nexport default function timelines(state = initialState, action) {\n  switch(action.type) {\n  case TIMELINE_EXPAND_REQUEST:\n    return state.update(action.timeline, initialTimeline, map => map.set('isLoading', true));\n  case TIMELINE_EXPAND_FAIL:\n    return state.update(action.timeline, initialTimeline, map => map.set('isLoading', false));\n  case TIMELINE_EXPAND_SUCCESS:\n    return expandNormalizedTimeline(state, action.timeline, fromJS(action.statuses), action.next, action.partial, action.isLoadingRecent);\n  case TIMELINE_UPDATE:\n    return updateTimeline(state, action.timeline, fromJS(action.status));\n  case TIMELINE_DELETE:\n    return deleteStatus(state, action.id, action.accountId, action.references, action.reblogOf);\n  case TIMELINE_CLEAR:\n    return clearTimeline(state, action.timeline);\n  case ACCOUNT_BLOCK_SUCCESS:\n  case ACCOUNT_MUTE_SUCCESS:\n    return filterTimelines(state, action.relationship, action.statuses);\n  case ACCOUNT_UNFOLLOW_SUCCESS:\n    return filterTimeline('home', state, action.relationship, action.statuses);\n  case TIMELINE_SCROLL_TOP:\n    return updateTop(state, action.timeline, action.top);\n  case TIMELINE_CONNECT:\n    return state.update(action.timeline, initialTimeline, map => map.set('online', true));\n  case TIMELINE_DISCONNECT:\n    return state.update(\n      action.timeline,\n      initialTimeline,\n      map => map.set('online', false).update('items', items => items.first() ? items.unshift(null) : items)\n    );\n  default:\n    return state;\n  }\n};\n"
  },
  {
    "path": "app/javascript/mastodon/reducers/user_lists.js",
    "content": "import {\n  FOLLOWERS_FETCH_SUCCESS,\n  FOLLOWERS_EXPAND_SUCCESS,\n  FOLLOWING_FETCH_SUCCESS,\n  FOLLOWING_EXPAND_SUCCESS,\n  FOLLOW_REQUESTS_FETCH_SUCCESS,\n  FOLLOW_REQUESTS_EXPAND_SUCCESS,\n  FOLLOW_REQUEST_AUTHORIZE_SUCCESS,\n  FOLLOW_REQUEST_REJECT_SUCCESS,\n} from '../actions/accounts';\nimport {\n  REBLOGS_FETCH_SUCCESS,\n  FAVOURITES_FETCH_SUCCESS,\n} from '../actions/interactions';\nimport {\n  BLOCKS_FETCH_SUCCESS,\n  BLOCKS_EXPAND_SUCCESS,\n} from '../actions/blocks';\nimport {\n  MUTES_FETCH_SUCCESS,\n  MUTES_EXPAND_SUCCESS,\n} from '../actions/mutes';\nimport { Map as ImmutableMap, List as ImmutableList } from 'immutable';\n\nconst initialState = ImmutableMap({\n  followers: ImmutableMap(),\n  following: ImmutableMap(),\n  reblogged_by: ImmutableMap(),\n  favourited_by: ImmutableMap(),\n  follow_requests: ImmutableMap(),\n  blocks: ImmutableMap(),\n  mutes: ImmutableMap(),\n});\n\nconst normalizeList = (state, type, id, accounts, next) => {\n  return state.setIn([type, id], ImmutableMap({\n    next,\n    items: ImmutableList(accounts.map(item => item.id)),\n  }));\n};\n\nconst appendToList = (state, type, id, accounts, next) => {\n  return state.updateIn([type, id], map => {\n    return map.set('next', next).update('items', list => list.concat(accounts.map(item => item.id)));\n  });\n};\n\nexport default function userLists(state = initialState, action) {\n  switch(action.type) {\n  case FOLLOWERS_FETCH_SUCCESS:\n    return normalizeList(state, 'followers', action.id, action.accounts, action.next);\n  case FOLLOWERS_EXPAND_SUCCESS:\n    return appendToList(state, 'followers', action.id, action.accounts, action.next);\n  case FOLLOWING_FETCH_SUCCESS:\n    return normalizeList(state, 'following', action.id, action.accounts, action.next);\n  case FOLLOWING_EXPAND_SUCCESS:\n    return appendToList(state, 'following', action.id, action.accounts, action.next);\n  case REBLOGS_FETCH_SUCCESS:\n    return state.setIn(['reblogged_by', action.id], ImmutableList(action.accounts.map(item => item.id)));\n  case FAVOURITES_FETCH_SUCCESS:\n    return state.setIn(['favourited_by', action.id], ImmutableList(action.accounts.map(item => item.id)));\n  case FOLLOW_REQUESTS_FETCH_SUCCESS:\n    return state.setIn(['follow_requests', 'items'], ImmutableList(action.accounts.map(item => item.id))).setIn(['follow_requests', 'next'], action.next);\n  case FOLLOW_REQUESTS_EXPAND_SUCCESS:\n    return state.updateIn(['follow_requests', 'items'], list => list.concat(action.accounts.map(item => item.id))).setIn(['follow_requests', 'next'], action.next);\n  case FOLLOW_REQUEST_AUTHORIZE_SUCCESS:\n  case FOLLOW_REQUEST_REJECT_SUCCESS:\n    return state.updateIn(['follow_requests', 'items'], list => list.filterNot(item => item === action.id));\n  case BLOCKS_FETCH_SUCCESS:\n    return state.setIn(['blocks', 'items'], ImmutableList(action.accounts.map(item => item.id))).setIn(['blocks', 'next'], action.next);\n  case BLOCKS_EXPAND_SUCCESS:\n    return state.updateIn(['blocks', 'items'], list => list.concat(action.accounts.map(item => item.id))).setIn(['blocks', 'next'], action.next);\n  case MUTES_FETCH_SUCCESS:\n    return state.setIn(['mutes', 'items'], ImmutableList(action.accounts.map(item => item.id))).setIn(['mutes', 'next'], action.next);\n  case MUTES_EXPAND_SUCCESS:\n    return state.updateIn(['mutes', 'items'], list => list.concat(action.accounts.map(item => item.id))).setIn(['mutes', 'next'], action.next);\n  default:\n    return state;\n  }\n};\n"
  },
  {
    "path": "app/javascript/mastodon/rtl.js",
    "content": "// U+0590  to U+05FF  - Hebrew\n// U+0600  to U+06FF  - Arabic\n// U+0700  to U+074F  - Syriac\n// U+0750  to U+077F  - Arabic Supplement\n// U+0780  to U+07BF  - Thaana\n// U+07C0  to U+07FF  - N'Ko\n// U+0800  to U+083F  - Samaritan\n// U+08A0  to U+08FF  - Arabic Extended-A\n// U+FB1D  to U+FB4F  - Hebrew presentation forms\n// U+FB50  to U+FDFF  - Arabic presentation forms A\n// U+FE70  to U+FEFF  - Arabic presentation forms B\n\nconst rtlChars = /[\\u0590-\\u083F]|[\\u08A0-\\u08FF]|[\\uFB1D-\\uFDFF]|[\\uFE70-\\uFEFF]/mg;\n\nexport function isRtl(text) {\n  if (text.length === 0) {\n    return false;\n  }\n\n  text = text.replace(/(?:^|[^\\/\\w])@([a-z0-9_]+(@[a-z0-9\\.\\-]+)?)/ig, '');\n  text = text.replace(/(?:^|[^\\/\\w])#([\\S]+)/ig, '');\n  text = text.replace(/\\s+/g, '');\n\n  const matches = text.match(rtlChars);\n\n  if (!matches) {\n    return false;\n  }\n\n  return matches.length / text.length > 0.3;\n};\n"
  },
  {
    "path": "app/javascript/mastodon/scroll.js",
    "content": "const easingOutQuint = (x, t, b, c, d) => c * ((t = t / d - 1) * t * t * t * t + 1) + b;\n\nconst scroll = (node, key, target) => {\n  const startTime = Date.now();\n  const offset    = node[key];\n  const gap       = target - offset;\n  const duration  = 1000;\n  let interrupt   = false;\n\n  const step = () => {\n    const elapsed    = Date.now() - startTime;\n    const percentage = elapsed / duration;\n\n    if (percentage > 1 || interrupt) {\n      return;\n    }\n\n    node[key] = easingOutQuint(0, elapsed, offset, gap, duration);\n    requestAnimationFrame(step);\n  };\n\n  step();\n\n  return () => {\n    interrupt = true;\n  };\n};\n\nexport const scrollRight = (node, position) => scroll(node, 'scrollLeft', position);\nexport const scrollTop = (node) => scroll(node, 'scrollTop', 0);\n"
  },
  {
    "path": "app/javascript/mastodon/selectors/index.js",
    "content": "import { createSelector } from 'reselect';\nimport { List as ImmutableList } from 'immutable';\nimport { me } from '../initial_state';\n\nconst getAccountBase         = (state, id) => state.getIn(['accounts', id], null);\nconst getAccountCounters     = (state, id) => state.getIn(['accounts_counters', id], null);\nconst getAccountRelationship = (state, id) => state.getIn(['relationships', id], null);\nconst getAccountMoved        = (state, id) => state.getIn(['accounts', state.getIn(['accounts', id, 'moved'])]);\n\nexport const makeGetAccount = () => {\n  return createSelector([getAccountBase, getAccountCounters, getAccountRelationship, getAccountMoved], (base, counters, relationship, moved) => {\n    if (base === null) {\n      return null;\n    }\n\n    return base.merge(counters).withMutations(map => {\n      map.set('relationship', relationship);\n      map.set('moved', moved);\n    });\n  });\n};\n\nconst toServerSideType = columnType => {\n  switch (columnType) {\n  case 'home':\n  case 'notifications':\n  case 'public':\n  case 'thread':\n    return columnType;\n  default:\n    if (columnType.indexOf('list:') > -1) {\n      return 'home';\n    } else {\n      return 'public'; // community, account, hashtag\n    }\n  }\n};\n\nexport const getFilters = (state, { contextType }) => state.get('filters', ImmutableList()).filter(filter => contextType && filter.get('context').includes(toServerSideType(contextType)) && (filter.get('expires_at') === null || Date.parse(filter.get('expires_at')) > (new Date())));\n\nconst escapeRegExp = string =>\n  string.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'); // $& means the whole matched string\n\nexport const regexFromFilters = filters => {\n  if (filters.size === 0) {\n    return null;\n  }\n\n  return new RegExp(filters.map(filter => {\n    let expr = escapeRegExp(filter.get('phrase'));\n\n    if (filter.get('whole_word')) {\n      if (/^[\\w]/.test(expr)) {\n        expr = `\\\\b${expr}`;\n      }\n\n      if (/[\\w]$/.test(expr)) {\n        expr = `${expr}\\\\b`;\n      }\n    }\n\n    return expr;\n  }).join('|'), 'i');\n};\n\nexport const makeGetStatus = () => {\n  return createSelector(\n    [\n      (state, { id }) => state.getIn(['statuses', id]),\n      (state, { id }) => state.getIn(['statuses', state.getIn(['statuses', id, 'reblog'])]),\n      (state, { id }) => state.getIn(['accounts', state.getIn(['statuses', id, 'account'])]),\n      (state, { id }) => state.getIn(['accounts', state.getIn(['statuses', state.getIn(['statuses', id, 'reblog']), 'account'])]),\n      getFilters,\n    ],\n\n    (statusBase, statusReblog, accountBase, accountReblog, filters) => {\n      if (!statusBase) {\n        return null;\n      }\n\n      if (statusReblog) {\n        statusReblog = statusReblog.set('account', accountReblog);\n      } else {\n        statusReblog = null;\n      }\n\n      const regex    = (accountReblog || accountBase).get('id') !== me && regexFromFilters(filters);\n      const filtered = regex && regex.test(statusBase.get('reblog') ? statusReblog.get('search_index') : statusBase.get('search_index'));\n\n      return statusBase.withMutations(map => {\n        map.set('reblog', statusReblog);\n        map.set('account', accountBase);\n        map.set('filtered', filtered);\n      });\n    }\n  );\n};\n\nconst getAlertsBase = state => state.get('alerts');\n\nexport const getAlerts = createSelector([getAlertsBase], (base) => {\n  let arr = [];\n\n  base.forEach(item => {\n    arr.push({\n      message: item.get('message'),\n      title: item.get('title'),\n      key: item.get('key'),\n      dismissAfter: 5000,\n      barStyle: {\n        zIndex: 200,\n      },\n    });\n  });\n\n  return arr;\n});\n\nexport const makeGetNotification = () => {\n  return createSelector([\n    (_, base)             => base,\n    (state, _, accountId) => state.getIn(['accounts', accountId]),\n  ], (base, account) => {\n    return base.set('account', account);\n  });\n};\n\nexport const getAccountGallery = createSelector([\n  (state, id) => state.getIn(['timelines', `account:${id}:media`, 'items'], ImmutableList()),\n  state       => state.get('statuses'),\n], (statusIds, statuses) => {\n  let medias = ImmutableList();\n\n  statusIds.forEach(statusId => {\n    const status = statuses.get(statusId);\n    medias = medias.concat(status.get('media_attachments').map(media => media.set('status', status)));\n  });\n\n  return medias;\n});\n"
  },
  {
    "path": "app/javascript/mastodon/service_worker/entry.js",
    "content": "// import { freeStorage, storageFreeable } from '../storage/modifier';\nimport './web_push_notifications';\n\n// function openSystemCache() {\n//   return caches.open('mastodon-system');\n// }\n\nfunction openWebCache() {\n  return caches.open('mastodon-web');\n}\n\nfunction fetchRoot() {\n  return fetch('/', { credentials: 'include', redirect: 'manual' });\n}\n\n// const firefox = navigator.userAgent.match(/Firefox\\/(\\d+)/);\n// const invalidOnlyIfCached = firefox && firefox[1] < 60;\n\n// Cause a new version of a registered Service Worker to replace an existing one\n// that is already installed, and replace the currently active worker on open pages.\nself.addEventListener('install', function(event) {\n  event.waitUntil(Promise.all([openWebCache(), fetchRoot()]).then(([cache, root]) => cache.put('/', root)));\n});\nself.addEventListener('activate', function(event) {\n  event.waitUntil(self.clients.claim());\n});\nself.addEventListener('fetch', function(event) {\n  const url = new URL(event.request.url);\n\n  if (url.pathname.startsWith('/web/')) {\n    const asyncResponse = fetchRoot();\n    const asyncCache = openWebCache();\n\n    event.respondWith(asyncResponse.then(\n      response => {\n        const clonedResponse = response.clone();\n        asyncCache.then(cache => cache.put('/', clonedResponse)).catch();\n        return response;\n      },\n      () => asyncCache.then(cache => cache.match('/'))));\n  } else if (url.pathname === '/auth/sign_out') {\n    const asyncResponse = fetch(event.request);\n    const asyncCache = openWebCache();\n\n    event.respondWith(asyncResponse.then(response => {\n      if (response.ok || response.type === 'opaqueredirect') {\n        return Promise.all([\n          asyncCache.then(cache => cache.delete('/')),\n          indexedDB.deleteDatabase('mastodon'),\n        ]).then(() => response);\n      }\n\n      return response;\n    }));\n  } /* else if (storageFreeable && (ATTACHMENT_HOST ? url.host === ATTACHMENT_HOST : url.pathname.startsWith('/system/'))) {\n    event.respondWith(openSystemCache().then(cache => {\n      return cache.match(event.request.url).then(cached => {\n        if (cached === undefined) {\n          const asyncResponse = invalidOnlyIfCached && event.request.cache === 'only-if-cached' ?\n            fetch(event.request, { cache: 'no-cache' }) : fetch(event.request);\n\n          return asyncResponse.then(response => {\n            if (response.ok) {\n              cache\n                .put(event.request.url, response.clone())\n                .catch(()=>{}).then(freeStorage()).catch();\n            }\n\n            return response;\n          });\n        }\n\n        return cached;\n      });\n    }));\n  } */\n});\n"
  },
  {
    "path": "app/javascript/mastodon/service_worker/web_push_locales.js",
    "content": "/* @preval */\n\nconst fs   = require('fs');\nconst path = require('path');\n\nconst filtered  = {};\nconst filenames = fs.readdirSync(path.resolve(__dirname, '../locales'));\n\nfilenames.forEach(filename => {\n  if (!filename.match(/\\.json$/) || filename.match(/defaultMessages|whitelist/)) return;\n\n  const content = fs.readFileSync(path.resolve(__dirname, `../locales/${filename}`), 'utf-8');\n  const full    = JSON.parse(content);\n  const locale  = filename.split('.')[0];\n\n  filtered[locale] = {\n    'notification.favourite': full['notification.favourite'] || '',\n    'notification.follow': full['notification.follow'] || '',\n    'notification.mention': full['notification.mention'] || '',\n    'notification.reblog': full['notification.reblog'] || '',\n    'notification.poll': full['notification.poll'] || '',\n\n    'status.show_more': full['status.show_more'] || '',\n    'status.reblog': full['status.reblog'] || '',\n    'status.favourite': full['status.favourite'] || '',\n\n    'notifications.group': full['notifications.group'] || '',\n  };\n});\n\nmodule.exports = JSON.parse(JSON.stringify(filtered));\n"
  },
  {
    "path": "app/javascript/mastodon/service_worker/web_push_notifications.js",
    "content": "import IntlMessageFormat from 'intl-messageformat';\nimport locales from './web_push_locales';\nimport { unescape } from 'lodash';\n\nconst MAX_NOTIFICATIONS = 5;\nconst GROUP_TAG = 'tag';\n\nconst notify = options =>\n  self.registration.getNotifications().then(notifications => {\n    if (notifications.length >= MAX_NOTIFICATIONS) { // Reached the maximum number of notifications, proceed with grouping\n      const group = {\n        title: formatMessage('notifications.group', options.data.preferred_locale, { count: notifications.length + 1 }),\n        body: notifications.sort((n1, n2) => n1.timestamp < n2.timestamp).map(notification => notification.title).join('\\n'),\n        badge: '/badge.png',\n        icon: '/android-chrome-192x192.png',\n        tag: GROUP_TAG,\n        data: {\n          url: (new URL('/web/notifications', self.location)).href,\n          count: notifications.length + 1,\n          preferred_locale: options.data.preferred_locale,\n        },\n      };\n\n      notifications.forEach(notification => notification.close());\n\n      return self.registration.showNotification(group.title, group);\n    } else if (notifications.length === 1 && notifications[0].tag === GROUP_TAG) { // Already grouped, proceed with appending the notification to the group\n      const group = cloneNotification(notifications[0]);\n\n      group.title = formatMessage('notifications.group', options.data.preferred_locale, { count: group.data.count + 1 });\n      group.body  = `${options.title}\\n${group.body}`;\n      group.data  = { ...group.data, count: group.data.count + 1 };\n\n      return self.registration.showNotification(group.title, group);\n    }\n\n    return self.registration.showNotification(options.title, options);\n  });\n\nconst fetchFromApi = (path, method, accessToken) => {\n  const url = (new URL(path, self.location)).href;\n\n  return fetch(url, {\n    headers: {\n      'Authorization': `Bearer ${accessToken}`,\n      'Content-Type': 'application/json',\n    },\n\n    method: method,\n    credentials: 'include',\n  }).then(res => {\n    if (res.ok) {\n      return res;\n    } else {\n      throw new Error(res.status);\n    }\n  }).then(res => res.json());\n};\n\nconst cloneNotification = notification => {\n  const clone = {};\n  let k;\n\n  // Object.assign() does not work with notifications\n  for(k in notification) {\n    clone[k] = notification[k];\n  }\n\n  return clone;\n};\n\nconst formatMessage = (messageId, locale, values = {}) =>\n  (new IntlMessageFormat(locales[locale][messageId], locale)).format(values);\n\nconst htmlToPlainText = html =>\n  unescape(html.replace(/<br\\s*\\/?>/g, '\\n').replace(/<\\/p><p>/g, '\\n\\n').replace(/<[^>]*>/g, ''));\n\nconst handlePush = (event) => {\n  const { access_token, notification_id, preferred_locale, title, body, icon } = event.data.json();\n\n  // Placeholder until more information can be loaded\n  event.waitUntil(\n    fetchFromApi(`/api/v1/notifications/${notification_id}`, 'get', access_token).then(notification => {\n      const options = {};\n\n      options.title     = formatMessage(`notification.${notification.type}`, preferred_locale, { name: notification.account.display_name.length > 0 ? notification.account.display_name : notification.account.username });\n      options.body      = notification.status && htmlToPlainText(notification.status.content);\n      options.icon      = notification.account.avatar_static;\n      options.timestamp = notification.created_at && new Date(notification.created_at);\n      options.tag       = notification.id;\n      options.badge     = '/badge.png';\n      options.image     = notification.status && notification.status.media_attachments.length > 0 && notification.status.media_attachments[0].preview_url || undefined;\n      options.data      = { access_token, preferred_locale, id: notification.status ? notification.status.id : notification.account.id, url: notification.status ? `/web/statuses/${notification.status.id}` : `/web/accounts/${notification.account.id}` };\n\n      if (notification.status && notification.status.spoiler_text || notification.status.sensitive) {\n        options.data.hiddenBody  = htmlToPlainText(notification.status.content);\n        options.data.hiddenImage = notification.status.media_attachments.length > 0 && notification.status.media_attachments[0].preview_url;\n\n        if (notification.status.spoiler_text) {\n          options.body    = notification.status.spoiler_text;\n        }\n\n        options.image   = undefined;\n        options.actions = [actionExpand(preferred_locale)];\n      } else if (notification.type === 'mention') {\n        options.actions = [actionReblog(preferred_locale), actionFavourite(preferred_locale)];\n      }\n\n      return notify(options);\n    }).catch(() => {\n      return notify({\n        title,\n        body,\n        icon,\n        tag: notification_id,\n        timestamp: new Date(),\n        badge: '/badge.png',\n        data: { access_token, preferred_locale, url: '/web/notifications' },\n      });\n    })\n  );\n};\n\nconst actionExpand = preferred_locale => ({\n  action: 'expand',\n  icon: '/web-push-icon_expand.png',\n  title: formatMessage('status.show_more', preferred_locale),\n});\n\nconst actionReblog = preferred_locale => ({\n  action: 'reblog',\n  icon: '/web-push-icon_reblog.png',\n  title: formatMessage('status.reblog', preferred_locale),\n});\n\nconst actionFavourite = preferred_locale => ({\n  action: 'favourite',\n  icon: '/web-push-icon_favourite.png',\n  title: formatMessage('status.favourite', preferred_locale),\n});\n\nconst findBestClient = clients => {\n  const focusedClient = clients.find(client => client.focused);\n  const visibleClient = clients.find(client => client.visibilityState === 'visible');\n\n  return focusedClient || visibleClient || clients[0];\n};\n\nconst expandNotification = notification => {\n  const newNotification = cloneNotification(notification);\n\n  newNotification.body    = newNotification.data.hiddenBody;\n  newNotification.image   = newNotification.data.hiddenImage;\n  newNotification.actions = [actionReblog(notification.data.preferred_locale), actionFavourite(notification.data.preferred_locale)];\n\n  return self.registration.showNotification(newNotification.title, newNotification);\n};\n\nconst removeActionFromNotification = (notification, action) => {\n  const newNotification = cloneNotification(notification);\n\n  newNotification.actions = newNotification.actions.filter(item => item.action !== action);\n\n  return self.registration.showNotification(newNotification.title, newNotification);\n};\n\nconst openUrl = url =>\n  self.clients.matchAll({ type: 'window' }).then(clientList => {\n    if (clientList.length !== 0) {\n      const webClients = clientList.filter(client => /\\/web\\//.test(client.url));\n\n      if (webClients.length !== 0) {\n        const client       = findBestClient(webClients);\n        const { pathname } = new URL(url, self.location);\n\n        if (pathname.startsWith('/web/')) {\n          return client.focus().then(client => client.postMessage({\n            type: 'navigate',\n            path: pathname.slice('/web/'.length - 1),\n          }));\n        }\n      } else if ('navigate' in clientList[0]) { // Chrome 42-48 does not support navigate\n        const client = findBestClient(clientList);\n\n        return client.navigate(url).then(client => client.focus());\n      }\n    }\n\n    return self.clients.openWindow(url);\n  });\n\nconst handleNotificationClick = (event) => {\n  const reactToNotificationClick = new Promise((resolve, reject) => {\n    if (event.action) {\n      if (event.action === 'expand') {\n        resolve(expandNotification(event.notification));\n      } else if (event.action === 'reblog') {\n        const { data } = event.notification;\n        resolve(fetchFromApi(`/api/v1/statuses/${data.id}/reblog`, 'post', data.access_token).then(() => removeActionFromNotification(event.notification, 'reblog')));\n      } else if (event.action === 'favourite') {\n        const { data } = event.notification;\n        resolve(fetchFromApi(`/api/v1/statuses/${data.id}/favourite`, 'post', data.access_token).then(() => removeActionFromNotification(event.notification, 'favourite')));\n      } else {\n        reject(`Unknown action: ${event.action}`);\n      }\n    } else {\n      event.notification.close();\n      resolve(openUrl(event.notification.data.url));\n    }\n  });\n\n  event.waitUntil(reactToNotificationClick);\n};\n\nself.addEventListener('push', handlePush);\nself.addEventListener('notificationclick', handleNotificationClick);\n"
  },
  {
    "path": "app/javascript/mastodon/settings.js",
    "content": "export default class Settings {\n\n  constructor(keyBase = null) {\n    this.keyBase = keyBase;\n  }\n\n  generateKey(id) {\n    return this.keyBase ? [this.keyBase, `id${id}`].join('.') : id;\n  }\n\n  set(id, data) {\n    const key = this.generateKey(id);\n    try {\n      const encodedData = JSON.stringify(data);\n      localStorage.setItem(key, encodedData);\n      return data;\n    } catch (e) {\n      return null;\n    }\n  }\n\n  get(id) {\n    const key = this.generateKey(id);\n    try {\n      const rawData = localStorage.getItem(key);\n      return JSON.parse(rawData);\n    } catch (e) {\n      return null;\n    }\n  }\n\n  remove(id) {\n    const data = this.get(id);\n    if (data) {\n      const key = this.generateKey(id);\n      try {\n        localStorage.removeItem(key);\n      } catch (e) {\n      }\n    }\n    return data;\n  }\n\n}\n\nexport const pushNotificationsSetting = new Settings('mastodon_push_notification_data');\nexport const tagHistory = new Settings('mastodon_tag_history');\n"
  },
  {
    "path": "app/javascript/mastodon/storage/db.js",
    "content": "export default () => new Promise((resolve, reject) => {\n  // ServiceWorker is required to synchronize the login state.\n  // Microsoft Edge 17 does not support getAll according to:\n  // Catalog of standard and vendor APIs across browsers - Microsoft Edge Development\n  // https://developer.microsoft.com/en-us/microsoft-edge/platform/catalog/?q=specName%3Aindexeddb\n  if (!('caches' in self && 'getAll' in IDBObjectStore.prototype)) {\n    reject();\n    return;\n  }\n\n  const request = indexedDB.open('mastodon');\n\n  request.onerror = reject;\n  request.onsuccess = ({ target }) => resolve(target.result);\n\n  request.onupgradeneeded = ({ target }) => {\n    const accounts = target.result.createObjectStore('accounts', { autoIncrement: true });\n    const statuses = target.result.createObjectStore('statuses', { autoIncrement: true });\n\n    accounts.createIndex('id', 'id', { unique: true });\n    accounts.createIndex('moved', 'moved');\n\n    statuses.createIndex('id', 'id', { unique: true });\n    statuses.createIndex('account', 'account');\n    statuses.createIndex('reblog', 'reblog');\n  };\n});\n"
  },
  {
    "path": "app/javascript/mastodon/storage/modifier.js",
    "content": "import openDB from './db';\n\nconst accountAssetKeys = ['avatar', 'avatar_static', 'header', 'header_static'];\nconst storageMargin = 8388608;\nconst storeLimit = 1024;\n\n// navigator.storage is not present on:\n// Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.100 Safari/537.36 Edge/16.16299\n// estimate method is not present on Chrome 57.0.2987.98 on Linux.\nexport const storageFreeable = 'storage' in navigator && 'estimate' in navigator.storage;\n\nfunction openCache() {\n  // ServiceWorker and Cache API is not available on iOS 11\n  // https://webkit.org/status/#specification-service-workers\n  return self.caches ? caches.open('mastodon-system') : Promise.reject();\n}\n\nfunction printErrorIfAvailable(error) {\n  if (error) {\n    console.warn(error);\n  }\n}\n\nfunction put(name, objects, onupdate, oncreate) {\n  return openDB().then(db => (new Promise((resolve, reject) => {\n    const putTransaction = db.transaction(name, 'readwrite');\n    const putStore = putTransaction.objectStore(name);\n    const putIndex = putStore.index('id');\n\n    objects.forEach(object => {\n      putIndex.getKey(object.id).onsuccess = retrieval => {\n        function addObject() {\n          putStore.add(object);\n        }\n\n        function deleteObject() {\n          putStore.delete(retrieval.target.result).onsuccess = addObject;\n        }\n\n        if (retrieval.target.result) {\n          if (onupdate) {\n            onupdate(object, retrieval.target.result, putStore, deleteObject);\n          } else {\n            deleteObject();\n          }\n        } else {\n          if (oncreate) {\n            oncreate(object, addObject);\n          } else {\n            addObject();\n          }\n        }\n      };\n    });\n\n    putTransaction.oncomplete = () => {\n      const readTransaction = db.transaction(name, 'readonly');\n      const readStore = readTransaction.objectStore(name);\n      const count = readStore.count();\n\n      count.onsuccess = () => {\n        const excess = count.result - storeLimit;\n\n        if (excess > 0) {\n          const retrieval = readStore.getAll(null, excess);\n\n          retrieval.onsuccess = () => resolve(retrieval.result);\n          retrieval.onerror = reject;\n        } else {\n          resolve([]);\n        }\n      };\n\n      count.onerror = reject;\n    };\n\n    putTransaction.onerror = reject;\n  })).then(resolved => {\n    db.close();\n    return resolved;\n  }, error => {\n    db.close();\n    throw error;\n  }));\n}\n\nfunction evictAccountsByRecords(records) {\n  return openDB().then(db => {\n    const transaction = db.transaction(['accounts', 'statuses'], 'readwrite');\n    const accounts = transaction.objectStore('accounts');\n    const accountsIdIndex = accounts.index('id');\n    const accountsMovedIndex = accounts.index('moved');\n    const statuses = transaction.objectStore('statuses');\n    const statusesIndex = statuses.index('account');\n\n    function evict(toEvict) {\n      toEvict.forEach(record => {\n        openCache()\n          .then(cache => accountAssetKeys.forEach(key => cache.delete(records[key])))\n          .catch(printErrorIfAvailable);\n\n        accountsMovedIndex.getAll(record.id).onsuccess = ({ target }) => evict(target.result);\n\n        statusesIndex.getAll(record.id).onsuccess =\n          ({ target }) => evictStatusesByRecords(target.result);\n\n        accountsIdIndex.getKey(record.id).onsuccess =\n          ({ target }) => target.result && accounts.delete(target.result);\n      });\n    }\n\n    evict(records);\n\n    db.close();\n  }).catch(printErrorIfAvailable);\n}\n\nexport function evictStatus(id) {\n  evictStatuses([id]);\n}\n\nexport function evictStatuses(ids) {\n  return openDB().then(db => {\n    const transaction = db.transaction('statuses', 'readwrite');\n    const store = transaction.objectStore('statuses');\n    const idIndex = store.index('id');\n    const reblogIndex = store.index('reblog');\n\n    ids.forEach(id => {\n      reblogIndex.getAllKeys(id).onsuccess =\n        ({ target }) => target.result.forEach(reblogKey => store.delete(reblogKey));\n\n      idIndex.getKey(id).onsuccess =\n        ({ target }) => target.result && store.delete(target.result);\n    });\n\n    db.close();\n  }).catch(printErrorIfAvailable);\n}\n\nfunction evictStatusesByRecords(records) {\n  return evictStatuses(records.map(({ id }) => id));\n}\n\nexport function putAccounts(records, avatarStatic) {\n  const avatarKey = avatarStatic ? 'avatar_static' : 'avatar';\n  const newURLs = [];\n\n  put('accounts', records, (newRecord, oldKey, store, oncomplete) => {\n    store.get(oldKey).onsuccess = ({ target }) => {\n      accountAssetKeys.forEach(key => {\n        const newURL = newRecord[key];\n        const oldURL = target.result[key];\n\n        if (newURL !== oldURL) {\n          openCache()\n            .then(cache => cache.delete(oldURL))\n            .catch(printErrorIfAvailable);\n        }\n      });\n\n      const newURL = newRecord[avatarKey];\n      const oldURL = target.result[avatarKey];\n\n      if (newURL !== oldURL) {\n        newURLs.push(newURL);\n      }\n\n      oncomplete();\n    };\n  }, (newRecord, oncomplete) => {\n    newURLs.push(newRecord[avatarKey]);\n    oncomplete();\n  }).then(records => Promise.all([\n    evictAccountsByRecords(records),\n    openCache().then(cache => cache.addAll(newURLs)),\n  ])).then(freeStorage, error => {\n    freeStorage();\n    throw error;\n  }).catch(printErrorIfAvailable);\n}\n\nexport function putStatuses(records) {\n  put('statuses', records)\n    .then(evictStatusesByRecords)\n    .catch(printErrorIfAvailable);\n}\n\nexport function freeStorage() {\n  return storageFreeable && navigator.storage.estimate().then(({ quota, usage }) => {\n    if (usage + storageMargin < quota) {\n      return null;\n    }\n\n    return openDB().then(db => new Promise((resolve, reject) => {\n      const retrieval = db.transaction('accounts', 'readonly').objectStore('accounts').getAll(null, 1);\n\n      retrieval.onsuccess = () => {\n        if (retrieval.result.length > 0) {\n          resolve(evictAccountsByRecords(retrieval.result).then(freeStorage));\n        } else {\n          resolve(caches.delete('mastodon-system'));\n        }\n      };\n\n      retrieval.onerror = reject;\n\n      db.close();\n    }));\n  });\n}\n"
  },
  {
    "path": "app/javascript/mastodon/store/configureStore.js",
    "content": "import { createStore, applyMiddleware, compose } from 'redux';\nimport thunk from 'redux-thunk';\nimport appReducer from '../reducers';\nimport loadingBarMiddleware from '../middleware/loading_bar';\nimport errorsMiddleware from '../middleware/errors';\nimport soundsMiddleware from '../middleware/sounds';\n\nexport default function configureStore() {\n  return createStore(appReducer, compose(applyMiddleware(\n    thunk,\n    loadingBarMiddleware({ promiseTypeSuffixes: ['REQUEST', 'SUCCESS', 'FAIL'] }),\n    errorsMiddleware(),\n    soundsMiddleware()\n  ), window.__REDUX_DEVTOOLS_EXTENSION__ ? window.__REDUX_DEVTOOLS_EXTENSION__() : f => f));\n};\n"
  },
  {
    "path": "app/javascript/mastodon/stream.js",
    "content": "import WebSocketClient from 'websocket.js';\n\nconst randomIntUpTo = max => Math.floor(Math.random() * Math.floor(max));\n\nexport function connectStream(path, pollingRefresh = null, callbacks = () => ({ onConnect() {}, onDisconnect() {}, onReceive() {} })) {\n  return (dispatch, getState) => {\n    const streamingAPIBaseURL = getState().getIn(['meta', 'streaming_api_base_url']);\n    const accessToken = getState().getIn(['meta', 'access_token']);\n    const { onConnect, onDisconnect, onReceive } = callbacks(dispatch, getState);\n\n    let polling = null;\n\n    const setupPolling = () => {\n      pollingRefresh(dispatch, () => {\n        polling = setTimeout(() => setupPolling(), 20000 + randomIntUpTo(20000));\n      });\n    };\n\n    const clearPolling = () => {\n      if (polling) {\n        clearTimeout(polling);\n        polling = null;\n      }\n    };\n\n    const subscription = getStream(streamingAPIBaseURL, accessToken, path, {\n      connected () {\n        if (pollingRefresh) {\n          clearPolling();\n        }\n\n        onConnect();\n      },\n\n      disconnected () {\n        if (pollingRefresh) {\n          polling = setTimeout(() => setupPolling(), randomIntUpTo(40000));\n        }\n\n        onDisconnect();\n      },\n\n      received (data) {\n        onReceive(data);\n      },\n\n      reconnected () {\n        if (pollingRefresh) {\n          clearPolling();\n          pollingRefresh(dispatch);\n        }\n\n        onConnect();\n      },\n\n    });\n\n    const disconnect = () => {\n      if (subscription) {\n        subscription.close();\n      }\n\n      clearPolling();\n    };\n\n    return disconnect;\n  };\n}\n\n\nexport default function getStream(streamingAPIBaseURL, accessToken, stream, { connected, received, disconnected, reconnected }) {\n  const params = [ `stream=${stream}` ];\n\n  const ws = new WebSocketClient(`${streamingAPIBaseURL}/api/v1/streaming/?${params.join('&')}`, accessToken);\n\n  ws.onopen      = connected;\n  ws.onmessage   = e => received(JSON.parse(e.data));\n  ws.onclose     = disconnected;\n  ws.onreconnect = reconnected;\n\n  return ws;\n};\n"
  },
  {
    "path": "app/javascript/mastodon/test_setup.js",
    "content": "import { configure } from 'enzyme';\nimport Adapter from 'enzyme-adapter-react-16';\n\nconst adapter = new Adapter();\nconfigure({ adapter });\n"
  },
  {
    "path": "app/javascript/mastodon/utils/__tests__/base64-test.js",
    "content": "import * as base64 from '../base64';\n\ndescribe('base64', () => {\n  describe('decode', () => {\n    it('returns a uint8 array', () => {\n      const arr = base64.decode('dGVzdA==');\n      expect(arr).toEqual(new Uint8Array([116, 101, 115, 116]));\n    });\n  });\n});\n"
  },
  {
    "path": "app/javascript/mastodon/utils/__tests__/html-test.js",
    "content": "import * as html from '../html';\n\ndescribe('html', () => {\n  describe('unsecapeHTML', () => {\n    it('returns unescaped HTML', () => {\n      const output = html.unescapeHTML('<p>lorem</p><p>ipsum</p><br>&lt;br&gt;');\n      expect(output).toEqual('lorem\\n\\nipsum\\n<br>');\n    });\n  });\n});\n"
  },
  {
    "path": "app/javascript/mastodon/utils/base64.js",
    "content": "export const decode = base64 => {\n  const rawData = window.atob(base64);\n  const outputArray = new Uint8Array(rawData.length);\n\n  for (let i = 0; i < rawData.length; ++i) {\n    outputArray[i] = rawData.charCodeAt(i);\n  }\n\n  return outputArray;\n};\n"
  },
  {
    "path": "app/javascript/mastodon/utils/html.js",
    "content": "// NB: This function can still return unsafe HTML\nexport const unescapeHTML = (html) => {\n  const wrapper = document.createElement('div');\n  wrapper.innerHTML = html.replace(/<br\\s*\\/?>/g, '\\n').replace(/<\\/p><p>/g, '\\n\\n').replace(/<[^>]*>/g, '');\n  return wrapper.textContent;\n};\n"
  },
  {
    "path": "app/javascript/mastodon/utils/numbers.js",
    "content": "import React, { Fragment } from 'react';\nimport { FormattedNumber } from 'react-intl';\n\nexport const shortNumberFormat = number => {\n  if (number < 1000) {\n    return <FormattedNumber value={number} />;\n  } else {\n    return <Fragment><FormattedNumber value={number / 1000} maximumFractionDigits={1} />K</Fragment>;\n  }\n};\n"
  },
  {
    "path": "app/javascript/mastodon/utils/resize_image.js",
    "content": "import EXIF from 'exif-js';\n\nconst MAX_IMAGE_PIXELS = 1638400; // 1280x1280px\n\nconst getImageUrl = inputFile => new Promise((resolve, reject) => {\n  if (window.URL && URL.createObjectURL) {\n    try {\n      resolve(URL.createObjectURL(inputFile));\n    } catch (error) {\n      reject(error);\n    }\n    return;\n  }\n\n  const reader = new FileReader();\n  reader.onerror = (...args) => reject(...args);\n  reader.onload  = ({ target }) => resolve(target.result);\n\n  reader.readAsDataURL(inputFile);\n});\n\nconst loadImage = inputFile => new Promise((resolve, reject) => {\n  getImageUrl(inputFile).then(url => {\n    const img = new Image();\n\n    img.onerror = (...args) => reject(...args);\n    img.onload  = () => resolve(img);\n\n    img.src = url;\n  }).catch(reject);\n});\n\nconst getOrientation = (img, type = 'image/png') => new Promise(resolve => {\n  if (!['image/jpeg', 'image/webp'].includes(type)) {\n    resolve(1);\n    return;\n  }\n\n  EXIF.getData(img, () => {\n    const orientation = EXIF.getTag(img, 'Orientation');\n    resolve(orientation);\n  });\n});\n\nconst processImage = (img, { width, height, orientation, type = 'image/png' }) => new Promise(resolve => {\n  const canvas  = document.createElement('canvas');\n\n  if (4 < orientation && orientation < 9) {\n    canvas.width  = height;\n    canvas.height = width;\n  } else {\n    canvas.width  = width;\n    canvas.height = height;\n  }\n\n  const context = canvas.getContext('2d');\n\n  switch (orientation) {\n  case 2: context.transform(-1, 0, 0, 1, width, 0); break;\n  case 3: context.transform(-1, 0, 0, -1, width, height); break;\n  case 4: context.transform(1, 0, 0, -1, 0, height); break;\n  case 5: context.transform(0, 1, 1, 0, 0, 0); break;\n  case 6: context.transform(0, 1, -1, 0, height, 0); break;\n  case 7: context.transform(0, -1, -1, 0, height, width); break;\n  case 8: context.transform(0, -1, 1, 0, 0, width); break;\n  }\n\n  context.drawImage(img, 0, 0, width, height);\n\n  canvas.toBlob(resolve, type);\n});\n\nconst resizeImage = (img, type = 'image/png') => new Promise((resolve, reject) => {\n  const { width, height } = img;\n\n  const newWidth  = Math.round(Math.sqrt(MAX_IMAGE_PIXELS * (width / height)));\n  const newHeight = Math.round(Math.sqrt(MAX_IMAGE_PIXELS * (height / width)));\n\n  getOrientation(img, type)\n    .then(orientation => processImage(img, {\n      width: newWidth,\n      height: newHeight,\n      orientation,\n      type,\n    }))\n    .then(resolve)\n    .catch(reject);\n});\n\nexport default inputFile => new Promise((resolve, reject) => {\n  if (!inputFile.type.match(/image.*/) || inputFile.type === 'image/gif') {\n    resolve(inputFile);\n    return;\n  }\n\n  loadImage(inputFile).then(img => {\n    if (img.width * img.height < MAX_IMAGE_PIXELS) {\n      resolve(inputFile);\n      return;\n    }\n\n    resizeImage(img, inputFile.type)\n      .then(resolve)\n      .catch(() => resolve(inputFile));\n  }).catch(reject);\n});\n"
  },
  {
    "path": "app/javascript/mastodon/uuid.js",
    "content": "export default function uuid(a) {\n  return a ? (a^Math.random() * 16 >> a / 4).toString(16) : ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, uuid);\n};\n"
  },
  {
    "path": "app/javascript/packs/about.js",
    "content": "import loadPolyfills from '../mastodon/load_polyfills';\nimport { start } from '../mastodon/common';\n\nstart();\n\nfunction loaded() {\n  const TimelineContainer = require('../mastodon/containers/timeline_container').default;\n  const React             = require('react');\n  const ReactDOM          = require('react-dom');\n  const mountNode         = document.getElementById('mastodon-timeline');\n\n  if (mountNode !== null) {\n    const props = JSON.parse(mountNode.getAttribute('data-props'));\n    ReactDOM.render(<TimelineContainer {...props} />, mountNode);\n  }\n}\n\nfunction main() {\n  const ready = require('../mastodon/ready').default;\n  ready(loaded);\n}\n\nloadPolyfills().then(main).catch(error => {\n  console.error(error);\n});\n"
  },
  {
    "path": "app/javascript/packs/admin.js",
    "content": "import { delegate } from 'rails-ujs';\n\nconst batchCheckboxClassName = '.batch-checkbox input[type=\"checkbox\"]';\n\ndelegate(document, '#batch_checkbox_all', 'change', ({ target }) => {\n  [].forEach.call(document.querySelectorAll(batchCheckboxClassName), (content) => {\n    content.checked = target.checked;\n  });\n});\n\ndelegate(document, batchCheckboxClassName, 'change', () => {\n  const checkAllElement = document.querySelector('#batch_checkbox_all');\n\n  if (checkAllElement) {\n    checkAllElement.checked = [].every.call(document.querySelectorAll(batchCheckboxClassName), (content) => content.checked);\n    checkAllElement.indeterminate = !checkAllElement.checked && [].some.call(document.querySelectorAll(batchCheckboxClassName), (content) => content.checked);\n  }\n});\n\ndelegate(document, '.media-spoiler-show-button', 'click', () => {\n  [].forEach.call(document.querySelectorAll('button.media-spoiler'), (element) => {\n    element.click();\n  });\n});\n\ndelegate(document, '.media-spoiler-hide-button', 'click', () => {\n  [].forEach.call(document.querySelectorAll('.spoiler-button.spoiler-button--visible button'), (element) => {\n    element.click();\n  });\n});\n\ndelegate(document, '#domain_block_severity', 'change', ({ target }) => {\n  const rejectMediaDiv   = document.querySelector('.input.with_label.domain_block_reject_media');\n  const rejectReportsDiv = document.querySelector('.input.with_label.domain_block_reject_reports');\n\n  if (rejectMediaDiv) {\n    rejectMediaDiv.style.display = (target.value === 'suspend') ? 'none' : 'block';\n  }\n\n  if (rejectReportsDiv) {\n    rejectReportsDiv.style.display = (target.value === 'suspend') ? 'none' : 'block';\n  }\n});\n"
  },
  {
    "path": "app/javascript/packs/application.js",
    "content": "import loadPolyfills from '../mastodon/load_polyfills';\nimport { start } from '../mastodon/common';\n\nstart();\n\nloadPolyfills().then(() => {\n  require('../mastodon/main').default();\n}).catch(e => {\n  console.error(e);\n});\n"
  },
  {
    "path": "app/javascript/packs/error.js",
    "content": "import ready from '../mastodon/ready';\n\nready(() => {\n  const image = document.querySelector('img');\n\n  image.addEventListener('mouseenter', () => {\n    image.src = '/oops.gif';\n  });\n\n  image.addEventListener('mouseleave', () => {\n    image.src = '/oops.png';\n  });\n});\n"
  },
  {
    "path": "app/javascript/packs/mailer.js",
    "content": "require('../styles/mailer.scss');\n"
  },
  {
    "path": "app/javascript/packs/public.js",
    "content": "import escapeTextContentForBrowser from 'escape-html';\nimport loadPolyfills from '../mastodon/load_polyfills';\nimport ready from '../mastodon/ready';\nimport { start } from '../mastodon/common';\nimport { maxBioChars } from '../mastodon/initial_state';\n\nstart();\n\nwindow.addEventListener('message', e => {\n  const data = e.data || {};\n\n  if (!window.parent || data.type !== 'setHeight') {\n    return;\n  }\n\n  ready(() => {\n    window.parent.postMessage({\n      type: 'setHeight',\n      id: data.id,\n      height: document.getElementsByTagName('html')[0].scrollHeight,\n    }, '*');\n\n    if (document.fonts && document.fonts.ready) {\n      document.fonts.ready.then(sizeBioText);\n    } else {\n      sizeBioText();\n    }\n  });\n});\n\nfunction main() {\n  const IntlMessageFormat = require('intl-messageformat').default;\n  const { timeAgoString } = require('../mastodon/components/relative_timestamp');\n  const { delegate } = require('rails-ujs');\n  const emojify = require('../mastodon/features/emoji/emoji').default;\n  const { getLocale } = require('../mastodon/locales');\n  const { messages } = getLocale();\n  const React = require('react');\n  const ReactDOM = require('react-dom');\n  const Rellax = require('rellax');\n  const createHistory = require('history').createBrowserHistory;\n\n  const scrollToDetailedStatus = () => {\n    const history = createHistory();\n    const detailedStatuses = document.querySelectorAll('.public-layout .detailed-status');\n    const location = history.location;\n\n    if (detailedStatuses.length === 1 && (!location.state || !location.state.scrolledToDetailedStatus)) {\n      detailedStatuses[0].scrollIntoView();\n      history.replace(location.pathname, { ...location.state, scrolledToDetailedStatus: true });\n    }\n  };\n\n  ready(() => {\n    const locale = document.documentElement.lang;\n\n    const dateTimeFormat = new Intl.DateTimeFormat(locale, {\n      year: 'numeric',\n      month: 'long',\n      day: 'numeric',\n      hour: 'numeric',\n      minute: 'numeric',\n    });\n\n    [].forEach.call(document.querySelectorAll('.emojify'), (content) => {\n      content.innerHTML = emojify(content.innerHTML);\n    });\n\n    [].forEach.call(document.querySelectorAll('time.formatted'), (content) => {\n      const datetime = new Date(content.getAttribute('datetime'));\n      const formattedDate = dateTimeFormat.format(datetime);\n\n      content.title = formattedDate;\n      content.textContent = formattedDate;\n    });\n\n    [].forEach.call(document.querySelectorAll('time.time-ago'), (content) => {\n      const datetime = new Date(content.getAttribute('datetime'));\n      const now      = new Date();\n\n      content.title = dateTimeFormat.format(datetime);\n      content.textContent = timeAgoString({\n        formatMessage: ({ id, defaultMessage }, values) => (new IntlMessageFormat(messages[id] || defaultMessage, locale)).format(values),\n        formatDate: (date, options) => (new Intl.DateTimeFormat(locale, options)).format(date),\n      }, datetime, now, now.getFullYear());\n    });\n\n    const reactComponents = document.querySelectorAll('[data-component]');\n\n    if (reactComponents.length > 0) {\n      import(/* webpackChunkName: \"containers/media_container\" */ '../mastodon/containers/media_container')\n        .then(({ default: MediaContainer }) => {\n          [].forEach.call(reactComponents, (component) => {\n            [].forEach.call(component.children, (child) => {\n              component.removeChild(child);\n            });\n          });\n\n          const content = document.createElement('div');\n\n          ReactDOM.render(<MediaContainer locale={locale} components={reactComponents} />, content);\n          document.body.appendChild(content);\n          scrollToDetailedStatus();\n        })\n        .catch(error => {\n          console.error(error);\n          scrollToDetailedStatus();\n        });\n    } else {\n      scrollToDetailedStatus();\n    }\n\n    const parallaxComponents = document.querySelectorAll('.parallax');\n\n    if (parallaxComponents.length > 0 ) {\n      new Rellax('.parallax', { speed: -1 });\n    }\n\n    if (document.body.classList.contains('with-modals')) {\n      const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;\n      const scrollbarWidthStyle = document.createElement('style');\n      scrollbarWidthStyle.id = 'scrollbar-width';\n      document.head.appendChild(scrollbarWidthStyle);\n      scrollbarWidthStyle.sheet.insertRule(`body.with-modals--active { margin-right: ${scrollbarWidth}px; }`, 0);\n    }\n    [].forEach.call(document.querySelectorAll('[data-component=\"Card\"]'), (content) => {\n      const props = JSON.parse(content.getAttribute('data-props'));\n      ReactDOM.render(<CardContainer locale={locale} {...props} />, content);\n    });\n\n    if (document.fonts && document.fonts.ready) {\n      document.fonts.ready.then(sizeBioText);\n    } else {\n      sizeBioText();\n    }\n  });\n\n  delegate(document, '.webapp-btn', 'click', ({ target, button }) => {\n    if (button !== 0) {\n      return true;\n    }\n    window.location.href = target.href;\n    return false;\n  });\n\n  delegate(document, '.status__content__spoiler-link', 'click', function() {\n    const contentEl = this.parentNode.parentNode.querySelector('.e-content');\n\n    if (contentEl.style.display === 'block') {\n      contentEl.style.display = 'none';\n      this.parentNode.style.marginBottom = 0;\n    } else {\n      contentEl.style.display = 'block';\n      this.parentNode.style.marginBottom = null;\n    }\n\n    return false;\n  });\n\n  delegate(document, '.modal-button', 'click', e => {\n    e.preventDefault();\n\n    let href;\n\n    if (e.target.nodeName !== 'A') {\n      href = e.target.parentNode.href;\n    } else {\n      href = e.target.href;\n    }\n\n    window.open(href, 'mastodon-intent', 'width=445,height=600,resizable=no,menubar=no,status=no,scrollbars=yes');\n  });\n\n  delegate(document, '#account_display_name', 'input', ({ target }) => {\n    const name = document.querySelector('.card .display-name strong');\n    if (name) {\n      if (target.value) {\n        name.innerHTML = emojify(escapeTextContentForBrowser(target.value));\n      } else {\n        name.textContent = document.querySelector('#default_account_display_name').textContent;\n      }\n    }\n  });\n\n  delegate(document, '#account_avatar', 'change', ({ target }) => {\n    const avatar = document.querySelector('.card .avatar img');\n    const [file] = target.files || [];\n    const url = file ? URL.createObjectURL(file) : avatar.dataset.originalSrc;\n\n    avatar.src = url;\n  });\n\n  const getProfileAvatarAnimationHandler = (swapTo) => {\n    //animate avatar gifs on the profile page when moused over\n    return ({ target }) => {\n      const swapSrc = target.getAttribute(swapTo);\n      //only change the img source if autoplay is off and the image src is actually different\n      if(target.getAttribute('data-autoplay') === 'false' && target.src !== swapSrc) {\n        target.src = swapSrc;\n      }\n    };\n  };\n\n  delegate(document, 'img#profile_page_avatar', 'mouseover', getProfileAvatarAnimationHandler('data-original'));\n\n  delegate(document, 'img#profile_page_avatar', 'mouseout', getProfileAvatarAnimationHandler('data-static'));\n\n  delegate(document, '#account_header', 'change', ({ target }) => {\n    const header = document.querySelector('.card .card__img img');\n    const [file] = target.files || [];\n    const url = file ? URL.createObjectURL(file) : header.dataset.originalSrc;\n\n    header.src = url;\n  });\n\n  delegate(document, '#account_locked', 'change', ({ target }) => {\n    const lock = document.querySelector('.card .display-name i');\n\n    if (target.checked) {\n      lock.style.display = 'inline';\n    } else {\n      lock.style.display = 'none';\n    }\n  });\n\n  delegate(document, '.input-copy input', 'click', ({ target }) => {\n    target.focus();\n    target.select();\n    target.setSelectionRange(0, target.value.length);\n  });\n\n  delegate(document, '.input-copy button', 'click', ({ target }) => {\n    const input = target.parentNode.querySelector('.input-copy__wrapper input');\n\n    const oldReadOnly = input.readonly;\n\n    input.readonly = false;\n    input.focus();\n    input.select();\n    input.setSelectionRange(0, input.value.length);\n\n    try {\n      if (document.execCommand('copy')) {\n        input.blur();\n        target.parentNode.classList.add('copied');\n\n        setTimeout(() => {\n          target.parentNode.classList.remove('copied');\n        }, 700);\n      }\n    } catch (err) {\n      console.error(err);\n    }\n\n    input.readonly = oldReadOnly;\n  });\n\n  delegate(document, '#account_note', 'input', sizeBioText);\n\n  function sizeBioText() {\n    const noteCounter = document.querySelector('.note-counter');\n    const bioTextArea = document.querySelector('#account_note');\n\n    if (noteCounter) {\n      noteCounter.textContent = maxBioChars - length(bioTextArea.value);\n    }\n\n    if (bioTextArea) {\n      bioTextArea.style.height = 'auto';\n      bioTextArea.style.height = (bioTextArea.scrollHeight+3) + 'px';\n    }\n  }\n}\n\nloadPolyfills().then(main).catch(error => {\n  console.error(error);\n});\n"
  },
  {
    "path": "app/javascript/packs/share.js",
    "content": "import loadPolyfills from '../mastodon/load_polyfills';\nimport { start } from '../mastodon/common';\n\nstart();\n\nfunction loaded() {\n  const ComposeContainer = require('../mastodon/containers/compose_container').default;\n  const React = require('react');\n  const ReactDOM = require('react-dom');\n  const mountNode = document.getElementById('mastodon-compose');\n\n  if (mountNode !== null) {\n    const props = JSON.parse(mountNode.getAttribute('data-props'));\n    ReactDOM.render(<ComposeContainer {...props} />, mountNode);\n  }\n}\n\nfunction main() {\n  const ready = require('../mastodon/ready').default;\n  ready(loaded);\n}\n\nloadPolyfills().then(main).catch(error => {\n  console.error(error);\n});\n"
  },
  {
    "path": "app/javascript/styles/application.scss",
    "content": "@import 'mastodon/mixins';\n@import 'mastodon/variables';\n@import 'fonts/roboto';\n@import 'fonts/roboto-mono';\n@import 'fonts/montserrat';\n\n@import 'mastodon/reset';\n@import 'mastodon/basics';\n@import 'mastodon/containers';\n@import 'mastodon/lists';\n@import 'mastodon/footer';\n@import 'mastodon/compact_header';\n@import 'mastodon/widgets';\n@import 'mastodon/forms';\n@import 'mastodon/accounts';\n@import 'mastodon/stream_entries';\n@import 'mastodon/boost';\n@import 'mastodon/components';\n@import 'mastodon/polls';\n@import 'mastodon/introduction';\n@import 'mastodon/modal';\n@import 'mastodon/emoji_picker';\n@import 'mastodon/about';\n@import 'mastodon/tables';\n@import 'mastodon/admin';\n@import 'mastodon/dashboard';\n@import 'mastodon/rtl';\n@import 'mastodon/accessibility';\n"
  },
  {
    "path": "app/javascript/styles/contrast/diff.scss",
    "content": "// components.scss\n.compose-form {\n  .compose-form__modifiers {\n    .compose-form__upload {\n      &-description {\n        input {\n          &::placeholder {\n            opacity: 1;\n          }\n        }\n      }\n    }\n  }\n}\n\n.rich-formatting a,\n.rich-formatting p a,\n.rich-formatting li a,\n.landing-page__short-description p a,\n.status__content a,\n.reply-indicator__content a {\n  color: lighten($ui-highlight-color, 12%);\n  text-decoration: underline;\n\n  &.mention {\n    text-decoration: none;\n  }\n\n  &.mention span {\n    text-decoration: underline;\n\n    &:hover,\n    &:focus,\n    &:active {\n      text-decoration: none;\n    }\n  }\n\n  &:hover,\n  &:focus,\n  &:active {\n    text-decoration: none;\n  }\n\n  &.status__content__spoiler-link {\n    color: $secondary-text-color;\n    text-decoration: none;\n  }\n}\n\n.status__content__read-more-button {\n  text-decoration: underline;\n\n  &:hover,\n  &:focus,\n  &:active {\n    text-decoration: none;\n  }\n}\n\n.getting-started__footer a {\n  text-decoration: underline;\n\n  &:hover,\n  &:focus,\n  &:active {\n    text-decoration: none;\n  }\n}\n\n.nothing-here {\n  color: $darker-text-color;\n}\n\n.public-layout .public-account-header__tabs__tabs .counter.active::after {\n  border-bottom: 4px solid $ui-highlight-color;\n}\n"
  },
  {
    "path": "app/javascript/styles/contrast/variables.scss",
    "content": "// Dependent colors\n$black: #000000;\n\n$classic-base-color: #282c37;\n$classic-primary-color: #9baec8;\n$classic-secondary-color: #d9e1e8;\n$classic-highlight-color: #2b90d9;\n\n$ui-base-color: $classic-base-color !default;\n$ui-primary-color: $classic-primary-color !default;\n$ui-secondary-color: $classic-secondary-color !default;\n\n// Differences\n$ui-highlight-color: #2b5fd9;\n\n$darker-text-color: lighten($ui-primary-color, 20%) !default;\n$dark-text-color: lighten($ui-primary-color, 12%) !default;\n$secondary-text-color: lighten($ui-secondary-color, 6%) !default;\n$highlight-text-color: $classic-highlight-color !default;\n$action-button-color: #8d9ac2;\n\n$inverted-text-color: $black !default;\n$lighter-text-color: darken($ui-base-color, 6%) !default;\n$light-text-color: darken($ui-primary-color, 40%) !default;\n"
  },
  {
    "path": "app/javascript/styles/contrast.scss",
    "content": "@import 'contrast/variables';\n@import 'application';\n@import 'contrast/diff';\n"
  },
  {
    "path": "app/javascript/styles/fonts/montserrat.scss",
    "content": "@font-face {\n  font-family: 'mastodon-font-display';\n  src: local('Montserrat'),\n    url('../fonts/montserrat/Montserrat-Regular.woff2') format('woff2'),\n    url('../fonts/montserrat/Montserrat-Regular.woff') format('woff'),\n    url('../fonts/montserrat/Montserrat-Regular.ttf') format('truetype');\n  font-weight: 400;\n  font-style: normal;\n}\n\n@font-face {\n  font-family: 'mastodon-font-display';\n  src: local('Montserrat Medium'),\n    url('../fonts/montserrat/Montserrat-Medium.ttf') format('truetype');\n  font-weight: 500;\n  font-style: normal;\n}\n"
  },
  {
    "path": "app/javascript/styles/fonts/roboto-mono.scss",
    "content": "@font-face {\n  font-family: 'mastodon-font-monospace';\n  src: local('Roboto Mono'),\n    url('../fonts/roboto-mono/robotomono-regular-webfont.woff2') format('woff2'),\n    url('../fonts/roboto-mono/robotomono-regular-webfont.woff') format('woff'),\n    url('../fonts/roboto-mono/robotomono-regular-webfont.ttf') format('truetype'),\n    url('../fonts/roboto-mono/robotomono-regular-webfont.svg#roboto_monoregular') format('svg');\n  font-weight: 400;\n  font-style: normal;\n}\n"
  },
  {
    "path": "app/javascript/styles/fonts/roboto.scss",
    "content": "@font-face {\n  font-family: 'mastodon-font-sans-serif';\n  src: local('Roboto Italic'),\n    url('../fonts/roboto/roboto-italic-webfont.woff2') format('woff2'),\n    url('../fonts/roboto/roboto-italic-webfont.woff') format('woff'),\n    url('../fonts/roboto/roboto-italic-webfont.ttf') format('truetype'),\n    url('../fonts/roboto/roboto-italic-webfont.svg#roboto-italic-webfont') format('svg');\n  font-weight: normal;\n  font-style: italic;\n}\n\n@font-face {\n  font-family: 'mastodon-font-sans-serif';\n  src: local('Roboto Bold'),\n    url('../fonts/roboto/roboto-bold-webfont.woff2') format('woff2'),\n    url('../fonts/roboto/roboto-bold-webfont.woff') format('woff'),\n    url('../fonts/roboto/roboto-bold-webfont.ttf') format('truetype'),\n    url('../fonts/roboto/roboto-bold-webfont.svg#roboto-bold-webfont') format('svg');\n  font-weight: bold;\n  font-style: normal;\n}\n\n@font-face {\n  font-family: 'mastodon-font-sans-serif';\n  src: local('Roboto Medium'),\n    url('../fonts/roboto/roboto-medium-webfont.woff2') format('woff2'),\n    url('../fonts/roboto/roboto-medium-webfont.woff') format('woff'),\n    url('../fonts/roboto/roboto-medium-webfont.ttf') format('truetype'),\n    url('../fonts/roboto/roboto-medium-webfont.svg#roboto-medium-webfont') format('svg');\n  font-weight: 500;\n  font-style: normal;\n}\n\n@font-face {\n  font-family: 'mastodon-font-sans-serif';\n  src: local('Roboto'),\n    url('../fonts/roboto/roboto-regular-webfont.woff2') format('woff2'),\n    url('../fonts/roboto/roboto-regular-webfont.woff') format('woff'),\n    url('../fonts/roboto/roboto-regular-webfont.ttf') format('truetype'),\n    url('../fonts/roboto/roboto-regular-webfont.svg#roboto-regular-webfont') format('svg');\n  font-weight: normal;\n  font-style: normal;\n}\n"
  },
  {
    "path": "app/javascript/styles/mailer.scss",
    "content": "@import 'mastodon/variables';\n@import 'fonts/roboto';\n\ntable,\ntd,\ndiv {\n  box-sizing: border-box;\n}\n\nhtml,\nbody {\n  width: 100% !important;\n  min-width: 100%;\n  margin: 0;\n  padding: 0;\n  -webkit-text-size-adjust: 100%;\n  -ms-text-size-adjust: 100%;\n}\n\n.email-body {\n  td,\n  div,\n  a,\n  span {\n    line-height: inherit;\n  }\n}\n\na {\n  &,\n  &:visited,\n  span {\n    text-decoration: none;\n    color: $ui-highlight-color;\n  }\n\n  #outlook & {\n    padding: 0;\n  }\n}\n\nimg {\n  outline: none;\n  border: 0;\n  text-decoration: none;\n  -ms-interpolation-mode: bicubic;\n  clear: both;\n  line-height: 100%;\n}\n\ntable {\n  border-spacing: 0;\n  mso-table-lspace: 0;\n  mso-table-rspace: 0;\n}\n\ntd {\n  vertical-align: top;\n}\n\n.email-table,\n.content-section,\n.column,\n.column-cell {\n  width: 100%;\n  min-width: 100%;\n}\n\n.email-body {\n  font-size: 0 !important;\n  line-height: 100%;\n  text-align: center;\n  padding-left: 16px;\n  padding-right: 16px;\n}\n\n.email-start {\n  padding-top: 32px;\n}\n\n.email-end {\n  padding-bottom: 32px;\n}\n\n.email-body,\nhtml,\nbody {\n  background-color: lighten($ui-base-color, 4%);\n}\n\n.email-container,\n.email-row,\n.col-0,\n.col-1,\n.col-2,\n.col-3,\n.col-4,\n.col-5,\n.col-6, {\n  font-size: 0;\n  display: inline-block;\n  width: 100%;\n  min-width: 100%;\n  min-width: 0 !important;\n  vertical-align: top;\n}\n\n.content-cell {\n  width: 100%;\n  min-width: 100%;\n  min-width: 0 !important;\n}\n\n.column-cell {\n  padding-top: 16px;\n  padding-bottom: 16px;\n  vertical-align: top;\n\n  &.button-cell {\n    padding-top: 0;\n  }\n}\n\n.email-container {\n  max-width: 632px;\n  margin: 0 auto;\n  text-align: center;\n}\n\n.email-row {\n  display: block;\n  max-width: 600px !important;\n  margin: 0 auto;\n  text-align: center;\n  clear: both;\n}\n\n.col-0 {\n  max-width: 50px;\n}\n\n.col-1 {\n  max-width: 100px;\n}\n\n.col-2 {\n  max-width: 200px;\n}\n\n.col-3 {\n  max-width: 300px;\n}\n\n.col-4 {\n  max-width: 400px;\n}\n\n.col-5 {\n  max-width: 500px;\n}\n\n.col-6 {\n  max-width: 600px;\n}\n\n.column-cell,\n.column-cell td,\np {\n  font-family: Helvetica, Arial, sans-serif;\n\n  @media only screen {\n    font-family: $font-sans-serif, sans-serif !important;\n  }\n}\n\n.email-body .column-cell,\n.column-cell,\np {\n  font-size: 15px;\n  line-height: 23px;\n  color: $ui-primary-color;\n  mso-line-height-rule: exactly;\n  text-rendering: optimizelegibility;\n}\n\np {\n  display: block;\n  margin-top: 0;\n  margin-bottom: 16px;\n\n  &.small {\n    font-size: 13px;\n  }\n\n  &.lead {\n    font-size: 19px;\n    line-height: 27px;\n  }\n}\n\nh1,\nh2,\nh3,\nh4,\nh5,\nh6 {\n  color: $ui-secondary-color;\n  margin-left: 0;\n  margin-right: 0;\n  margin-top: 20px;\n  margin-bottom: 8px;\n  padding: 0;\n  font-weight: 500;\n}\n\nh1 {\n  font-size: 26px;\n  line-height: 36px;\n}\n\nh2 {\n  font-size: 23px;\n  line-height: 30px;\n}\n\nh3 {\n  font-size: 19px;\n  line-height: 25px;\n}\n\nh5 {\n  font-size: 16px;\n  line-height: 21px;\n  font-weight: 700;\n  color: lighten($ui-base-color, 34%);\n}\n\n.input-cell {\n  h5 {\n    margin-top: 4px;\n  }\n}\n\n.input {\n  td {\n    background: darken($ui-base-color, 8%);\n    border-radius: 4px;\n    padding: 16px;\n    line-height: 20px;\n    mso-line-height-rule: exactly;\n    border-radius: 4px;\n    text-align: center;\n    font-weight: 500;\n    font-size: 17px;\n  }\n}\n\n.content-cell,\n.blank-cell {\n  width: 100%;\n  font-size: 0;\n  text-align: center;\n  vertical-align: top;\n  padding-left: 16px;\n  padding-right: 16px;\n}\n\n.content-cell {\n  background-color: darken($ui-base-color, 4%);\n\n  &.darker {\n    background-color: darken($ui-base-color, 8%);\n  }\n}\n\n.hero {\n  background-color: $ui-base-color;\n  padding-top: 20px;\n}\n\n.hero-with-button {\n  padding-bottom: 16px;\n\n  h1 {\n    margin-bottom: 4px;\n  }\n\n  p.lead {\n    margin-bottom: 32px;\n  }\n}\n\n.header {\n  border-radius: 5px 5px 0 0;\n  background-color: darken($ui-base-color, 8%);\n\n  .column-cell {\n    text-align: center;\n    padding-top: 20px;\n    padding-bottom: 8px;\n  }\n}\n\n.content-start {\n  padding-top: 32px;\n}\n\n.content-end {\n  border-radius: 0 0 5px 5px;\n  padding-top: 16px;\n}\n\n.footer {\n  .column-cell,\n  p {\n    color: lighten($ui-base-color, 34%);\n  }\n\n  p {\n    margin-bottom: 0;\n    font-size: 13px;\n\n    &.small {\n      margin-bottom: 0;\n    }\n  }\n\n  a {\n    color: lighten($ui-base-color, 34%);\n    text-decoration: underline;\n  }\n\n  img {\n    opacity: 0.3;\n  }\n}\n\n.logo {\n  position: relative;\n  left: -4px;\n}\n\n.button {\n  display: table;\n  margin-left: auto;\n  margin-right: auto;\n\n  td {\n    line-height: 20px;\n    mso-line-height-rule: exactly;\n    border-radius: 4px;\n    text-align: center;\n    font-weight: 500;\n    font-size: 17px;\n    padding: 0 !important;\n\n    a,\n    a span {\n      color: $primary-text-color;\n      display: block !important;\n      text-align: center !important;\n      vertical-align: top !important;\n      line-height: inherit !important;\n    }\n\n    a {\n      padding: 10px 22px !important;\n      line-height: 26px !important;\n      font-weight: 500 !important;\n    }\n  }\n\n  &.button-small {\n    td {\n      border-radius: 4px;\n      font-size: 14px;\n      padding: 8px 16px;\n\n      a {\n        padding: 5px 16px !important;\n        line-height: 26px !important;\n      }\n    }\n  }\n}\n\n.button-default {\n  background-color: darken($ui-base-color, 8%);\n}\n\n.button-primary {\n  background-color: darken($ui-highlight-color, 3%);\n}\n\n.text-center {\n  text-align: center;\n}\n\n.text-right {\n  text-align: right;\n}\n\n.padded {\n  padding-left: 16px;\n  padding-right: 16px;\n}\n\n.padded-bottom {\n  padding-bottom: 32px;\n}\n\n.margin-bottom {\n  margin-bottom: 20px;\n}\n\n.hero-icon {\n  width: 64px;\n\n  td {\n    text-align: center;\n    vertical-align: middle;\n    line-height: 100%;\n    mso-line-height-rule: exactly;\n    padding: 16px;\n    border-radius: 80px;\n    background: $success-green;\n  }\n\n  &.alert-icon td {\n    background: $error-red;\n  }\n\n  img {\n    max-width: 32px;\n    width: 32px;\n    height: 32px;\n    display: block;\n    line-height: 100%;\n  }\n}\n\n.hr {\n  width: 100%;\n\n  td {\n    font-size: 0;\n    line-height: 1px;\n    mso-line-height-rule: exactly;\n    min-height: 1px;\n    overflow: hidden;\n    height: 2px;\n    background-color: transparent !important;\n    border-top: 1px solid lighten($ui-base-color, 8%);\n  }\n}\n\n.status {\n  padding-bottom: 32px;\n\n  .status-header {\n    td {\n      font-size: 14px;\n      padding-bottom: 15px;\n    }\n\n    bdi {\n      color: $white;\n      font-size: 16px;\n      display: block;\n      font-weight: 500;\n    }\n\n    td:first-child {\n      padding-right: 10px;\n    }\n\n    img {\n      width: 48px;\n      height: 48px;\n      border-radius: 4px;\n    }\n  }\n\n  p {\n    font-size: 19px;\n    margin-bottom: 20px;\n\n    &.status-footer {\n      color: lighten($ui-base-color, 26%);\n      font-size: 14px;\n      margin-bottom: 0;\n\n      a {\n        color: lighten($ui-base-color, 26%);\n      }\n    }\n  }\n}\n\n.border-top {\n  border-top: 1px solid lighten($ui-base-color, 8%);\n}\n\nul {\n  padding-left: 15px;\n  margin-top: 0;\n  margin-bottom: 0;\n  padding-top: 16px;\n\n  li {\n    margin-bottom: 16px;\n    color: lighten($ui-base-color, 26%);\n\n    span {\n      color: $ui-primary-color;\n    }\n  }\n}\n\n@media only screen and (min-device-width: 768px) and (max-device-width: 1024px) and (orientation: landscape) {\n  body {\n    min-height: 1024px !important;\n  }\n}\n\n@media (max-width: 697px) {\n  .email-container,\n  .col-1,\n  .col-2,\n  .col-3,\n  .col-4,\n  .col-5,\n  .col-6 {\n    width: 100% !important;\n    max-width: none !important;\n  }\n\n  .email-start {\n    padding-top: 16px !important;\n  }\n\n  .email-end {\n    padding-bottom: 16px !important;\n  }\n\n  .padded {\n    padding-left: 0 !important;\n    padding-right: 0 !important;\n  }\n}\n"
  },
  {
    "path": "app/javascript/styles/mastodon/_mixins.scss",
    "content": "@mixin avatar-radius {\n  border-radius: 4px;\n  background: transparent no-repeat;\n  background-position: 50%;\n  background-clip: padding-box;\n}\n\n@mixin avatar-size($size: 48px) {\n  width: $size;\n  height: $size;\n  background-size: $size $size;\n}\n\n@mixin search-input {\n  outline: 0;\n  box-sizing: border-box;\n  width: 100%;\n  border: 0;\n  box-shadow: none;\n  font-family: inherit;\n  background: $ui-base-color;\n  color: $darker-text-color;\n  font-size: 14px;\n  margin: 0;\n\n  &::-moz-focus-inner {\n    border: 0;\n  }\n\n  &::-moz-focus-inner,\n  &:focus,\n  &:active {\n    outline: 0 !important;\n  }\n\n  &:focus {\n    background: lighten($ui-base-color, 4%);\n  }\n\n  @media screen and (max-width: 600px) {\n    font-size: 16px;\n  }\n}\n\n@mixin search-popout {\n  background: $simple-background-color;\n  border-radius: 4px;\n  padding: 10px 14px;\n  padding-bottom: 14px;\n  margin-top: 10px;\n  color: $light-text-color;\n  box-shadow: 2px 4px 15px rgba($base-shadow-color, 0.4);\n\n  h4 {\n    text-transform: uppercase;\n    color: $light-text-color;\n    font-size: 13px;\n    font-weight: 500;\n    margin-bottom: 10px;\n  }\n\n  li {\n    padding: 4px 0;\n  }\n\n  ul {\n    margin-bottom: 10px;\n  }\n\n  em {\n    font-weight: 500;\n    color: $inverted-text-color;\n  }\n}\n"
  },
  {
    "path": "app/javascript/styles/mastodon/about.scss",
    "content": "$maximum-width: 1235px;\n$fluid-breakpoint: $maximum-width + 20px;\n$column-breakpoint: 700px;\n$small-breakpoint: 960px;\n\n.container {\n  box-sizing: border-box;\n  max-width: $maximum-width;\n  margin: 0 auto;\n  position: relative;\n\n  @media screen and (max-width: $fluid-breakpoint) {\n    width: 100%;\n    padding: 0 10px;\n  }\n}\n\n.rich-formatting {\n  font-family: $font-sans-serif, sans-serif;\n  font-size: 16px;\n  font-weight: 400;\n  font-size: 16px;\n  line-height: 30px;\n  color: $darker-text-color;\n  padding-right: 10px;\n\n  a {\n    color: $highlight-text-color;\n    text-decoration: underline;\n  }\n\n  p,\n  li {\n    font-family: $font-sans-serif, sans-serif;\n    font-size: 16px;\n    font-weight: 400;\n    font-size: 16px;\n    line-height: 30px;\n    margin-bottom: 12px;\n    color: $darker-text-color;\n\n    a {\n      color: $highlight-text-color;\n      text-decoration: underline;\n    }\n\n    &:last-child {\n      margin-bottom: 0;\n    }\n  }\n\n  strong,\n  em {\n    font-weight: 700;\n    color: lighten($darker-text-color, 10%);\n  }\n\n  h1 {\n    font-family: $font-display, sans-serif;\n    font-size: 26px;\n    line-height: 30px;\n    font-weight: 500;\n    margin-bottom: 20px;\n    color: $secondary-text-color;\n\n    small {\n      font-family: $font-sans-serif, sans-serif;\n      display: block;\n      font-size: 18px;\n      font-weight: 400;\n      color: lighten($darker-text-color, 10%);\n    }\n  }\n\n  h2 {\n    font-family: $font-display, sans-serif;\n    font-size: 22px;\n    line-height: 26px;\n    font-weight: 500;\n    margin-bottom: 20px;\n    color: $secondary-text-color;\n  }\n\n  h3 {\n    font-family: $font-display, sans-serif;\n    font-size: 18px;\n    line-height: 24px;\n    font-weight: 500;\n    margin-bottom: 20px;\n    color: $secondary-text-color;\n  }\n\n  h4 {\n    font-family: $font-display, sans-serif;\n    font-size: 16px;\n    line-height: 24px;\n    font-weight: 500;\n    margin-bottom: 20px;\n    color: $secondary-text-color;\n  }\n\n  h5 {\n    font-family: $font-display, sans-serif;\n    font-size: 14px;\n    line-height: 24px;\n    font-weight: 500;\n    margin-bottom: 20px;\n    color: $secondary-text-color;\n  }\n\n  h6 {\n    font-family: $font-display, sans-serif;\n    font-size: 12px;\n    line-height: 24px;\n    font-weight: 500;\n    margin-bottom: 20px;\n    color: $secondary-text-color;\n  }\n\n  ul,\n  ol {\n    margin-left: 20px;\n\n    &[type='a'] {\n      list-style-type: lower-alpha;\n    }\n\n    &[type='i'] {\n      list-style-type: lower-roman;\n    }\n  }\n\n  ul {\n    list-style: disc;\n  }\n\n  ol {\n    list-style: decimal;\n  }\n\n  li > ol,\n  li > ul {\n    margin-top: 6px;\n  }\n\n  hr {\n    width: 100%;\n    height: 0;\n    border: 0;\n    border-bottom: 1px solid rgba($ui-base-lighter-color, .6);\n    margin: 20px 0;\n\n    &.spacer {\n      height: 1px;\n      border: 0;\n    }\n  }\n}\n\n.information-board {\n  background: darken($ui-base-color, 4%);\n  padding: 20px 0;\n\n  .container-alt {\n    position: relative;\n    padding-right: 280px + 15px;\n  }\n\n  &__sections {\n    display: flex;\n    justify-content: space-between;\n    flex-wrap: wrap;\n  }\n\n  &__section {\n    flex: 1 0 0;\n    font-family: $font-sans-serif, sans-serif;\n    font-size: 16px;\n    line-height: 28px;\n    color: $primary-text-color;\n    text-align: right;\n    padding: 10px 15px;\n\n    span,\n    strong {\n      display: block;\n    }\n\n    span {\n      &:last-child {\n        color: $secondary-text-color;\n      }\n    }\n\n    strong {\n      font-family: $font-display, sans-serif;\n      font-weight: 500;\n      font-size: 32px;\n      line-height: 48px;\n    }\n\n    @media screen and (max-width: $column-breakpoint) {\n      text-align: center;\n    }\n  }\n\n  .panel {\n    position: absolute;\n    width: 280px;\n    box-sizing: border-box;\n    background: darken($ui-base-color, 8%);\n    padding: 20px;\n    padding-top: 10px;\n    border-radius: 4px 4px 0 0;\n    right: 0;\n    bottom: -40px;\n\n    .panel-header {\n      font-family: $font-display, sans-serif;\n      font-size: 14px;\n      line-height: 24px;\n      font-weight: 500;\n      color: $darker-text-color;\n      padding-bottom: 5px;\n      margin-bottom: 15px;\n      border-bottom: 1px solid lighten($ui-base-color, 4%);\n      text-overflow: ellipsis;\n      white-space: nowrap;\n      overflow: hidden;\n\n      a,\n      span {\n        font-weight: 400;\n        color: darken($darker-text-color, 10%);\n      }\n\n      a {\n        text-decoration: none;\n      }\n    }\n  }\n\n  .owner {\n    text-align: center;\n\n    .avatar {\n      width: 80px;\n      height: 80px;\n      margin: 0 auto;\n      margin-bottom: 15px;\n\n      img {\n        display: block;\n        width: 80px;\n        height: 80px;\n        border-radius: 48px;\n      }\n    }\n\n    .name {\n      font-size: 14px;\n\n      a {\n        display: block;\n        color: $primary-text-color;\n        text-decoration: none;\n\n        &:hover {\n          .display_name {\n            text-decoration: underline;\n          }\n        }\n      }\n\n      .username {\n        display: block;\n        color: $darker-text-color;\n      }\n    }\n  }\n}\n\n.landing-page {\n  p,\n  li {\n    font-family: $font-sans-serif, sans-serif;\n    font-size: 16px;\n    font-weight: 400;\n    font-size: 16px;\n    line-height: 30px;\n    margin-bottom: 12px;\n    color: $darker-text-color;\n\n    a {\n      color: $highlight-text-color;\n      text-decoration: underline;\n    }\n  }\n\n  em {\n    display: inline;\n    margin: 0;\n    padding: 0;\n    font-weight: 700;\n    background: transparent;\n    font-family: inherit;\n    font-size: inherit;\n    line-height: inherit;\n    color: lighten($darker-text-color, 10%);\n  }\n\n  h1 {\n    font-family: $font-display, sans-serif;\n    font-size: 26px;\n    line-height: 30px;\n    font-weight: 500;\n    margin-bottom: 20px;\n    color: $secondary-text-color;\n\n    small {\n      font-family: $font-sans-serif, sans-serif;\n      display: block;\n      font-size: 18px;\n      font-weight: 400;\n      color: lighten($darker-text-color, 10%);\n    }\n  }\n\n  h2 {\n    font-family: $font-display, sans-serif;\n    font-size: 22px;\n    line-height: 26px;\n    font-weight: 500;\n    margin-bottom: 20px;\n    color: $secondary-text-color;\n  }\n\n  h3 {\n    font-family: $font-display, sans-serif;\n    font-size: 18px;\n    line-height: 24px;\n    font-weight: 500;\n    margin-bottom: 20px;\n    color: $secondary-text-color;\n  }\n\n  h4 {\n    font-family: $font-display, sans-serif;\n    font-size: 16px;\n    line-height: 24px;\n    font-weight: 500;\n    margin-bottom: 20px;\n    color: $secondary-text-color;\n  }\n\n  h5 {\n    font-family: $font-display, sans-serif;\n    font-size: 14px;\n    line-height: 24px;\n    font-weight: 500;\n    margin-bottom: 20px;\n    color: $secondary-text-color;\n  }\n\n  h6 {\n    font-family: $font-display, sans-serif;\n    font-size: 12px;\n    line-height: 24px;\n    font-weight: 500;\n    margin-bottom: 20px;\n    color: $secondary-text-color;\n  }\n\n  ul,\n  ol {\n    margin-left: 20px;\n\n    &[type='a'] {\n      list-style-type: lower-alpha;\n    }\n\n    &[type='i'] {\n      list-style-type: lower-roman;\n    }\n  }\n\n  ul {\n    list-style: disc;\n  }\n\n  ol {\n    list-style: decimal;\n  }\n\n  li > ol,\n  li > ul {\n    margin-top: 6px;\n  }\n\n  hr {\n    width: 100%;\n    height: 0;\n    border: 0;\n    border-bottom: 1px solid rgba($ui-base-lighter-color, .6);\n    margin: 20px 0;\n\n    &.spacer {\n      height: 1px;\n      border: 0;\n    }\n  }\n\n  &__information,\n  &__forms {\n    padding: 20px;\n  }\n\n  &__call-to-action {\n    background: darken($ui-base-color, 4%);\n    border-radius: 4px;\n    padding: 25px 40px;\n    overflow: hidden;\n    box-sizing: border-box;\n\n    .row {\n      width: 100%;\n      display: flex;\n      flex-direction: row-reverse;\n      flex-wrap: nowrap;\n      justify-content: space-between;\n      align-items: center;\n    }\n\n    .row__information-board {\n      display: flex;\n      justify-content: flex-end;\n      align-items: flex-end;\n\n      .information-board__section {\n        flex: 1 0 auto;\n        padding: 0 10px;\n      }\n\n      @media screen and (max-width: $no-gap-breakpoint) {\n        width: 100%;\n        justify-content: space-between;\n      }\n    }\n\n    .row__mascot {\n      flex: 1;\n      margin: 10px -50px 0 0;\n\n      @media screen and (max-width: $no-gap-breakpoint) {\n        display: none;\n      }\n    }\n  }\n\n  &__logo {\n    margin-right: 20px;\n\n    img {\n      height: 50px;\n      width: auto;\n      mix-blend-mode: lighten;\n    }\n  }\n\n  &__information {\n    padding: 45px 40px;\n    margin-bottom: 10px;\n\n    &:last-child {\n      margin-bottom: 0;\n    }\n\n    strong {\n      font-weight: 500;\n      color: lighten($darker-text-color, 10%);\n    }\n\n    .account {\n      border-bottom: 0;\n      padding: 0;\n\n      &__display-name {\n        align-items: center;\n        display: flex;\n        margin-right: 5px;\n      }\n\n      div.account__display-name {\n        &:hover {\n          .display-name strong {\n            text-decoration: none;\n          }\n        }\n\n        .account__avatar {\n          cursor: default;\n        }\n      }\n\n      &__avatar-wrapper {\n        margin-left: 0;\n        flex: 0 0 auto;\n      }\n\n      &__avatar {\n        width: 44px;\n        height: 44px;\n        background-size: 44px 44px;\n      }\n\n      .display-name {\n        font-size: 15px;\n\n        &__account {\n          font-size: 14px;\n        }\n      }\n    }\n\n    @media screen and (max-width: $small-breakpoint) {\n      .contact {\n        margin-top: 30px;\n      }\n    }\n\n    @media screen and (max-width: $column-breakpoint) {\n      padding: 25px 20px;\n    }\n  }\n\n  &__information,\n  &__forms,\n  #mastodon-timeline {\n    box-sizing: border-box;\n    background: $ui-base-color;\n    border-radius: 4px;\n    box-shadow: 0 0 6px rgba($black, 0.1);\n  }\n\n  &__mascot {\n    height: 104px;\n    position: relative;\n    left: -40px;\n    bottom: 25px;\n\n    img {\n      height: 190px;\n      width: auto;\n    }\n  }\n\n  &__short-description {\n    .row {\n      display: flex;\n      flex-wrap: wrap;\n      align-items: center;\n      margin-bottom: 40px;\n    }\n\n    @media screen and (max-width: $column-breakpoint) {\n      .row {\n        margin-bottom: 20px;\n      }\n    }\n\n    p a {\n      color: $secondary-text-color;\n    }\n\n    h1 {\n      font-weight: 500;\n      color: $primary-text-color;\n      margin-bottom: 0;\n\n      small {\n        color: $darker-text-color;\n\n        span {\n          color: $secondary-text-color;\n        }\n      }\n    }\n\n    p:last-child {\n      margin-bottom: 0;\n    }\n  }\n\n  &__hero {\n    margin-bottom: 10px;\n\n    img {\n      display: block;\n      margin: 0;\n      max-width: 100%;\n      height: auto;\n      border-radius: 4px;\n    }\n  }\n\n  @media screen and (max-width: 840px) {\n    .information-board {\n      .container-alt {\n        padding-right: 20px;\n      }\n\n      .panel {\n        position: static;\n        margin-top: 20px;\n        width: 100%;\n        border-radius: 4px;\n\n        .panel-header {\n          text-align: center;\n        }\n      }\n    }\n  }\n\n  @media screen and (max-width: 675px) {\n    .header-wrapper {\n      padding-top: 0;\n\n      &.compact {\n        padding-bottom: 0;\n      }\n\n      &.compact .hero .heading {\n        text-align: initial;\n      }\n    }\n\n    .header .container-alt,\n    .features .container-alt {\n      display: block;\n    }\n  }\n\n  .cta {\n    margin: 20px;\n  }\n}\n\n.landing {\n  margin-bottom: 100px;\n\n  @media screen and (max-width: 738px) {\n    margin-bottom: 0;\n  }\n\n  &__brand {\n    display: flex;\n    justify-content: center;\n    align-items: center;\n    padding: 50px;\n\n    svg {\n      fill: $primary-text-color;\n      height: 52px;\n    }\n\n    @media screen and (max-width: $no-gap-breakpoint) {\n      padding: 0;\n      margin-bottom: 30px;\n    }\n  }\n\n  .directory {\n    margin-top: 30px;\n    background: transparent;\n    box-shadow: none;\n    border-radius: 0;\n  }\n\n  .hero-widget {\n    margin-top: 30px;\n    margin-bottom: 0;\n\n    h4 {\n      padding: 10px;\n      text-transform: uppercase;\n      font-weight: 700;\n      font-size: 13px;\n      color: $darker-text-color;\n    }\n\n    &__text {\n      border-radius: 0;\n      padding-bottom: 0;\n    }\n\n    &__footer {\n      background: $ui-base-color;\n      padding: 10px;\n      border-radius: 0 0 4px 4px;\n      display: flex;\n\n      &__column {\n        flex: 1 1 50%;\n      }\n    }\n\n    .account {\n      padding: 10px 0;\n      border-bottom: 0;\n\n      .account__display-name {\n        display: flex;\n        align-items: center;\n      }\n\n      .account__avatar {\n        width: 44px;\n        height: 44px;\n        background-size: 44px 44px;\n      }\n    }\n\n    &__counter {\n      padding: 10px;\n\n      strong {\n        font-family: $font-display, sans-serif;\n        font-size: 15px;\n        font-weight: 700;\n        display: block;\n      }\n\n      span {\n        font-size: 14px;\n        color: $darker-text-color;\n      }\n    }\n  }\n\n  .simple_form .user_agreement .label_input > label {\n    font-weight: 400;\n    color: $darker-text-color;\n  }\n\n  .simple_form p.lead {\n    color: $darker-text-color;\n    font-size: 15px;\n    line-height: 20px;\n    font-weight: 400;\n    margin-bottom: 25px;\n  }\n\n  &__grid {\n    max-width: 960px;\n    margin: 0 auto;\n    display: grid;\n    grid-template-columns: minmax(0, 50%) minmax(0, 50%);\n    grid-gap: 30px;\n\n    @media screen and (max-width: 738px) {\n      grid-template-columns: minmax(0, 100%);\n      grid-gap: 10px;\n\n      &__column-login {\n        grid-row: 1;\n        display: flex;\n        flex-direction: column;\n\n        .box-widget {\n          order: 2;\n          flex: 0 0 auto;\n        }\n\n        .hero-widget {\n          margin-top: 0;\n          margin-bottom: 10px;\n          order: 1;\n          flex: 0 0 auto;\n        }\n      }\n\n      &__column-registration {\n        grid-row: 2;\n      }\n\n      .directory {\n        margin-top: 10px;\n      }\n    }\n\n    @media screen and (max-width: $no-gap-breakpoint) {\n      grid-gap: 0;\n\n      .hero-widget {\n        display: block;\n        margin-bottom: 0;\n        box-shadow: none;\n\n        &__img,\n        &__img img,\n        &__footer {\n          border-radius: 0;\n        }\n      }\n\n      .hero-widget,\n      .box-widget,\n      .directory__tag {\n        border-bottom: 1px solid lighten($ui-base-color, 8%);\n      }\n\n      .directory {\n        margin-top: 0;\n\n        &__tag {\n          margin-bottom: 0;\n\n          & > a,\n          & > div {\n            border-radius: 0;\n            box-shadow: none;\n          }\n\n          &:last-child {\n            border-bottom: 0;\n          }\n        }\n      }\n    }\n  }\n}\n\n.brand {\n  position: relative;\n  text-decoration: none;\n}\n\n.brand__tagline {\n  display: block;\n  position: absolute;\n  bottom: -10px;\n  left: 50px;\n  width: 300px;\n  color: $ui-primary-color;\n  text-decoration: none;\n  font-size: 14px;\n\n  @media screen and (max-width: $no-gap-breakpoint) {\n    position: static;\n    width: auto;\n    margin-top: 20px;\n    color: $dark-text-color;\n  }\n}\n\n"
  },
  {
    "path": "app/javascript/styles/mastodon/accessibility.scss",
    "content": "$black-emojis: '8ball' 'ant' 'back' 'black_circle' 'black_heart' 'black_large_square' 'black_medium_small_square' 'black_medium_square' 'black_nib' 'black_small_square' 'bomb' 'bowling' 'bust_in_silhouette' 'busts_in_silhouette' 'camera' 'camera_with_flash' 'clubs' 'copyright' 'curly_loop' 'currency_exchange' 'dark_sunglasses' 'eight_pointed_black_star' 'electric_plug' 'end' 'female-guard' 'film_projector' 'fried_egg' 'gorilla' 'guardsman' 'heavy_check_mark' 'heavy_division_sign' 'heavy_dollar_sign' 'heavy_minus_sign' 'heavy_multiplication_x' 'heavy_plus_sign' 'hocho' 'hole' 'joystick' 'kaaba' 'lower_left_ballpoint_pen' 'lower_left_fountain_pen' 'male-guard' 'microphone' 'mortar_board' 'movie_camera' 'musical_score' 'on' 'registered' 'soon' 'spades' 'speaking_head_in_silhouette' 'spider' 'telephone_receiver' 'tm' 'top' 'tophat' 'turkey' 'vhs' 'video_camera' 'video_game' 'water_buffalo' 'waving_black_flag' 'wavy_dash';\n\n%white-emoji-outline {\n  filter: drop-shadow(1px 1px 0 $white) drop-shadow(-1px 1px 0 $white) drop-shadow(1px -1px 0 $white) drop-shadow(-1px -1px 0 $white);\n  transform: scale(.71);\n}\n\n.emojione {\n  @each $emoji in $black-emojis {\n    &[title=':#{$emoji}:'] {\n      @extend %white-emoji-outline;\n    }\n  }\n}\n"
  },
  {
    "path": "app/javascript/styles/mastodon/accounts.scss",
    "content": ".card {\n  & > a {\n    display: block;\n    text-decoration: none;\n    color: inherit;\n    box-shadow: 0 0 15px rgba($base-shadow-color, 0.2);\n\n    @media screen and (max-width: $no-gap-breakpoint) {\n      box-shadow: none;\n    }\n\n    &:hover,\n    &:active,\n    &:focus {\n      .card__bar {\n        background: lighten($ui-base-color, 8%);\n      }\n    }\n  }\n\n  &__img {\n    height: 130px;\n    position: relative;\n    background: darken($ui-base-color, 12%);\n    border-radius: 4px 4px 0 0;\n\n    img {\n      display: block;\n      width: 100%;\n      height: 100%;\n      margin: 0;\n      object-fit: cover;\n      border-radius: 4px 4px 0 0;\n    }\n\n    @media screen and (max-width: 600px) {\n      height: 200px;\n    }\n\n    @media screen and (max-width: $no-gap-breakpoint) {\n      display: none;\n    }\n  }\n\n  &__bar {\n    position: relative;\n    padding: 15px;\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    background: lighten($ui-base-color, 4%);\n    border-radius: 0 0 4px 4px;\n\n    @media screen and (max-width: $no-gap-breakpoint) {\n      border-radius: 0;\n    }\n\n    .avatar {\n      flex: 0 0 auto;\n      width: 48px;\n      height: 48px;\n      padding-top: 2px;\n\n      img {\n        width: 100%;\n        height: 100%;\n        display: block;\n        margin: 0;\n        border-radius: 4px;\n        background: darken($ui-base-color, 8%);\n        object-fit: cover;\n      }\n    }\n\n    .display-name {\n      margin-left: 15px;\n      text-align: left;\n\n      strong {\n        font-size: 15px;\n        color: $primary-text-color;\n        font-weight: 500;\n        overflow: hidden;\n        text-overflow: ellipsis;\n      }\n\n      span {\n        display: block;\n        font-size: 14px;\n        color: $darker-text-color;\n        font-weight: 400;\n        overflow: hidden;\n        text-overflow: ellipsis;\n      }\n    }\n  }\n}\n\n.pagination {\n  padding: 30px 0;\n  text-align: center;\n  overflow: hidden;\n\n  a,\n  .current,\n  .newer,\n  .older,\n  .page,\n  .gap {\n    font-size: 14px;\n    color: $primary-text-color;\n    font-weight: 500;\n    display: inline-block;\n    padding: 6px 10px;\n    text-decoration: none;\n  }\n\n  .current {\n    background: $simple-background-color;\n    border-radius: 100px;\n    color: $inverted-text-color;\n    cursor: default;\n    margin: 0 10px;\n  }\n\n  .gap {\n    cursor: default;\n  }\n\n  .older,\n  .newer {\n    text-transform: uppercase;\n    color: $secondary-text-color;\n  }\n\n  .older {\n    float: left;\n    padding-left: 0;\n\n    .fa {\n      display: inline-block;\n      margin-right: 5px;\n    }\n  }\n\n  .newer {\n    float: right;\n    padding-right: 0;\n\n    .fa {\n      display: inline-block;\n      margin-left: 5px;\n    }\n  }\n\n  .disabled {\n    cursor: default;\n    color: lighten($inverted-text-color, 10%);\n  }\n\n  @media screen and (max-width: 700px) {\n    padding: 30px 20px;\n\n    .page {\n      display: none;\n    }\n\n    .newer,\n    .older {\n      display: inline-block;\n    }\n  }\n}\n\n.nothing-here {\n  background: $ui-base-color;\n  box-shadow: 0 0 15px rgba($base-shadow-color, 0.2);\n  color: $light-text-color;\n  font-size: 14px;\n  font-weight: 500;\n  text-align: center;\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  cursor: default;\n  border-radius: 4px;\n  padding: 20px;\n  min-height: 30vh;\n\n  &--under-tabs {\n    border-radius: 0 0 4px 4px;\n  }\n\n  &--flexible {\n    box-sizing: border-box;\n    min-height: 100%;\n  }\n}\n\n.account-role,\n.simple_form .recommended {\n  display: inline-block;\n  padding: 4px 6px;\n  cursor: default;\n  border-radius: 3px;\n  font-size: 12px;\n  line-height: 12px;\n  font-weight: 500;\n  color: $ui-secondary-color;\n  background-color: rgba($ui-secondary-color, 0.1);\n  border: 1px solid rgba($ui-secondary-color, 0.5);\n\n  &.moderator {\n    color: $success-green;\n    background-color: rgba($success-green, 0.1);\n    border-color: rgba($success-green, 0.5);\n  }\n\n  &.admin {\n    color: lighten($error-red, 12%);\n    background-color: rgba(lighten($error-red, 12%), 0.1);\n    border-color: rgba(lighten($error-red, 12%), 0.5);\n  }\n}\n\n.account__header__fields {\n  padding: 0;\n  margin: 15px -15px -15px;\n  border: 0 none;\n  border-top: 1px solid lighten($ui-base-color, 12%);\n  border-bottom: 1px solid lighten($ui-base-color, 12%);\n  font-size: 14px;\n  line-height: 20px;\n\n  dl {\n    display: flex;\n    border-bottom: 1px solid lighten($ui-base-color, 12%);\n  }\n\n  dt,\n  dd {\n    box-sizing: border-box;\n    padding: 14px;\n    text-align: center;\n    max-height: 48px;\n    overflow: hidden;\n    white-space: nowrap;\n    text-overflow: ellipsis;\n  }\n\n  dt {\n    font-weight: 500;\n    width: 120px;\n    flex: 0 0 auto;\n    color: $secondary-text-color;\n    background: rgba(darken($ui-base-color, 8%), 0.5);\n  }\n\n  dd {\n    flex: 1 1 auto;\n    color: $darker-text-color;\n  }\n\n  a {\n    color: $highlight-text-color;\n    text-decoration: none;\n\n    &:hover,\n    &:focus,\n    &:active {\n      text-decoration: underline;\n    }\n  }\n\n  .verified {\n    border: 1px solid rgba($valid-value-color, 0.5);\n    background: rgba($valid-value-color, 0.25);\n\n    a {\n      color: $valid-value-color;\n      font-weight: 500;\n    }\n\n    &__mark {\n      color: $valid-value-color;\n    }\n  }\n\n  dl:last-child {\n    border-bottom: 0;\n  }\n}\n\n.directory__tag .trends__item__current {\n  width: auto;\n}\n\n.pending-account {\n  &__header {\n    color: $darker-text-color;\n\n    a {\n      color: $ui-secondary-color;\n      text-decoration: none;\n\n      &:hover,\n      &:active,\n      &:focus {\n        text-decoration: underline;\n      }\n    }\n\n    strong {\n      color: $primary-text-color;\n      font-weight: 700;\n    }\n  }\n\n  &__body {\n    margin-top: 10px;\n  }\n}\n"
  },
  {
    "path": "app/javascript/styles/mastodon/admin.scss",
    "content": "$no-columns-breakpoint: 600px;\n$sidebar-width: 240px;\n$content-width: 840px;\n\n.admin-wrapper {\n  display: flex;\n  justify-content: center;\n  height: 100%;\n\n  .sidebar-wrapper {\n    flex: 1 1 $sidebar-width;\n    height: 100%;\n    background: $ui-base-color;\n    display: flex;\n    justify-content: flex-end;\n  }\n\n  .sidebar {\n    width: $sidebar-width;\n    height: 100%;\n    padding: 0;\n    overflow-y: auto;\n\n    .logo {\n      display: block;\n      margin: 40px auto;\n      width: 100px;\n      height: 100px;\n    }\n\n    @media screen and (max-width: $no-columns-breakpoint) {\n      & > a:first-child {\n        display: none;\n      }\n    }\n\n    ul {\n      list-style: none;\n      border-radius: 4px 0 0 4px;\n      overflow: hidden;\n      margin-bottom: 20px;\n\n      @media screen and (max-width: $no-columns-breakpoint) {\n        margin-bottom: 0;\n      }\n\n      a {\n        display: block;\n        padding: 15px;\n        color: $darker-text-color;\n        text-decoration: none;\n        transition: all 200ms linear;\n        transition-property: color, background-color;\n        border-radius: 4px 0 0 4px;\n\n        i.fa {\n          margin-right: 5px;\n        }\n\n        &:hover {\n          color: $primary-text-color;\n          background-color: darken($ui-base-color, 5%);\n          transition: all 100ms linear;\n          transition-property: color, background-color;\n        }\n\n        &.selected {\n          background: darken($ui-base-color, 2%);\n          border-radius: 4px 0 0;\n        }\n      }\n\n      ul {\n        background: darken($ui-base-color, 4%);\n        border-radius: 0 0 0 4px;\n        margin: 0;\n\n        a {\n          border: 0;\n          padding: 15px 35px;\n        }\n      }\n\n      .simple-navigation-active-leaf a {\n        color: $primary-text-color;\n        background-color: $ui-highlight-color;\n        border-bottom: 0;\n        border-radius: 0;\n\n        &:hover {\n          background-color: lighten($ui-highlight-color, 5%);\n        }\n      }\n    }\n\n    & > ul > .simple-navigation-active-leaf a {\n      border-radius: 4px 0 0 4px;\n    }\n  }\n\n  .content-wrapper {\n    flex: 2 1 $content-width;\n    overflow: auto;\n  }\n\n  .content {\n    max-width: $content-width;\n    padding: 20px 15px;\n    padding-top: 60px;\n    padding-left: 25px;\n\n    @media screen and (max-width: $no-columns-breakpoint) {\n      max-width: none;\n      padding: 15px;\n      padding-top: 30px;\n    }\n\n    h2 {\n      color: $secondary-text-color;\n      font-size: 24px;\n      line-height: 28px;\n      font-weight: 400;\n      padding-bottom: 40px;\n      border-bottom: 1px solid lighten($ui-base-color, 8%);\n      margin-bottom: 40px;\n    }\n\n    h3 {\n      color: $secondary-text-color;\n      font-size: 20px;\n      line-height: 28px;\n      font-weight: 400;\n      margin-bottom: 30px;\n    }\n\n    h4 {\n      text-transform: uppercase;\n      font-size: 13px;\n      font-weight: 700;\n      color: $darker-text-color;\n      padding-bottom: 8px;\n      margin-bottom: 8px;\n      border-bottom: 1px solid lighten($ui-base-color, 8%);\n    }\n\n    h6 {\n      font-size: 16px;\n      color: $secondary-text-color;\n      line-height: 28px;\n      font-weight: 400;\n    }\n\n    .fields-group h6 {\n      color: $primary-text-color;\n      font-weight: 500;\n    }\n\n    .directory__tag > a,\n    .directory__tag > div {\n      box-shadow: none;\n    }\n\n    .directory__tag .table-action-link .fa {\n      color: inherit;\n    }\n\n    .directory__tag h4 {\n      font-size: 18px;\n      font-weight: 700;\n      color: $primary-text-color;\n      text-transform: none;\n      padding-bottom: 0;\n      margin-bottom: 0;\n      border-bottom: 0;\n    }\n\n    & > p {\n      font-size: 14px;\n      line-height: 18px;\n      color: $secondary-text-color;\n      margin-bottom: 20px;\n\n      strong {\n        color: $primary-text-color;\n        font-weight: 500;\n\n        @each $lang in $cjk-langs {\n          &:lang(#{$lang}) {\n            font-weight: 700;\n          }\n        }\n      }\n    }\n\n    hr {\n      width: 100%;\n      height: 0;\n      border: 0;\n      border-bottom: 1px solid rgba($ui-base-lighter-color, .6);\n      margin: 20px 0;\n\n      &.spacer {\n        height: 1px;\n        border: 0;\n      }\n    }\n\n    .muted-hint {\n      color: $darker-text-color;\n\n      a {\n        color: $highlight-text-color;\n      }\n    }\n\n    .positive-hint {\n      color: $valid-value-color;\n      font-weight: 500;\n    }\n\n    .negative-hint {\n      color: $error-value-color;\n      font-weight: 500;\n    }\n\n    .neutral-hint {\n      color: $dark-text-color;\n      font-weight: 500;\n    }\n  }\n\n  @media screen and (max-width: $no-columns-breakpoint) {\n    display: block;\n    overflow-y: auto;\n    -webkit-overflow-scrolling: touch;\n\n    .sidebar-wrapper,\n    .content-wrapper {\n      flex: 0 0 auto;\n      height: auto;\n      overflow: initial;\n    }\n\n    .sidebar {\n      width: 100%;\n      padding: 0;\n      height: auto;\n    }\n  }\n}\n\n.filters {\n  display: flex;\n  flex-wrap: wrap;\n\n  .filter-subset {\n    flex: 0 0 auto;\n    margin: 0 40px 10px 0;\n\n    &:last-child {\n      margin-bottom: 20px;\n    }\n\n    ul {\n      margin-top: 5px;\n      list-style: none;\n\n      li {\n        display: inline-block;\n        margin-right: 5px;\n      }\n    }\n\n    strong {\n      font-weight: 500;\n      text-transform: uppercase;\n      font-size: 12px;\n\n      @each $lang in $cjk-langs {\n        &:lang(#{$lang}) {\n          font-weight: 700;\n        }\n      }\n    }\n\n    a {\n      display: inline-block;\n      color: $darker-text-color;\n      text-decoration: none;\n      text-transform: uppercase;\n      font-size: 12px;\n      font-weight: 500;\n      border-bottom: 2px solid $ui-base-color;\n\n      &:hover {\n        color: $primary-text-color;\n        border-bottom: 2px solid lighten($ui-base-color, 5%);\n      }\n\n      &.selected {\n        color: $highlight-text-color;\n        border-bottom: 2px solid $ui-highlight-color;\n      }\n    }\n  }\n}\n\n.report-accounts {\n  display: flex;\n  flex-wrap: wrap;\n  margin-bottom: 20px;\n}\n\n.report-accounts__item {\n  display: flex;\n  flex: 250px;\n  flex-direction: column;\n  margin: 0 5px;\n\n  & > strong {\n    display: block;\n    margin: 0 0 10px -5px;\n    font-weight: 500;\n    font-size: 14px;\n    line-height: 18px;\n    color: $secondary-text-color;\n\n    @each $lang in $cjk-langs {\n      &:lang(#{$lang}) {\n        font-weight: 700;\n      }\n    }\n  }\n\n  .account-card {\n    flex: 1 1 auto;\n  }\n}\n\n.report-status,\n.account-status {\n  display: flex;\n  margin-bottom: 10px;\n\n  .activity-stream {\n    flex: 2 0 0;\n    margin-right: 20px;\n    max-width: calc(100% - 60px);\n\n    .entry {\n      border-radius: 4px;\n    }\n  }\n}\n\n.report-status__actions,\n.account-status__actions {\n  flex: 0 0 auto;\n  display: flex;\n  flex-direction: column;\n\n  .icon-button {\n    font-size: 24px;\n    width: 24px;\n    text-align: center;\n    margin-bottom: 10px;\n  }\n}\n\n.simple_form.new_report_note,\n.simple_form.new_account_moderation_note {\n  max-width: 100%;\n}\n\n.batch-form-box {\n  display: flex;\n  flex-wrap: wrap;\n  margin-bottom: 5px;\n\n  #form_status_batch_action {\n    margin: 0 5px 5px 0;\n    font-size: 14px;\n  }\n\n  input.button {\n    margin: 0 5px 5px 0;\n  }\n\n  .media-spoiler-toggle-buttons {\n    margin-left: auto;\n\n    .button {\n      overflow: visible;\n      margin: 0 0 5px 5px;\n      float: right;\n    }\n  }\n}\n\n.back-link {\n  margin-bottom: 10px;\n  font-size: 14px;\n\n  a {\n    color: $highlight-text-color;\n    text-decoration: none;\n\n    &:hover {\n      text-decoration: underline;\n    }\n  }\n}\n\n.spacer {\n  flex: 1 1 auto;\n}\n\n.log-entry {\n  margin-bottom: 20px;\n  line-height: 20px;\n\n  &__header {\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    padding: 10px;\n    background: $ui-base-color;\n    color: $darker-text-color;\n    border-radius: 4px 4px 0 0;\n    font-size: 14px;\n    position: relative;\n  }\n\n  &__avatar {\n    margin-right: 10px;\n\n    .avatar {\n      display: block;\n      margin: 0;\n      border-radius: 50%;\n      width: 40px;\n      height: 40px;\n    }\n  }\n\n  &__content {\n    max-width: calc(100% - 90px);\n  }\n\n  &__title {\n    word-wrap: break-word;\n  }\n\n  &__timestamp {\n    color: $dark-text-color;\n  }\n\n  &__extras {\n    background: lighten($ui-base-color, 6%);\n    border-radius: 0 0 4px 4px;\n    padding: 10px;\n    color: $darker-text-color;\n    font-family: $font-monospace, monospace;\n    font-size: 12px;\n    word-wrap: break-word;\n    min-height: 20px;\n  }\n\n  &__icon {\n    font-size: 28px;\n    margin-right: 10px;\n    color: $dark-text-color;\n  }\n\n  &__icon__overlay {\n    position: absolute;\n    top: 10px;\n    right: 10px;\n    width: 10px;\n    height: 10px;\n    border-radius: 50%;\n\n    &.positive {\n      background: $success-green;\n    }\n\n    &.negative {\n      background: lighten($error-red, 12%);\n    }\n\n    &.neutral {\n      background: $ui-highlight-color;\n    }\n  }\n\n  a,\n  .username,\n  .target {\n    color: $secondary-text-color;\n    text-decoration: none;\n    font-weight: 500;\n  }\n\n  .diff-old {\n    color: lighten($error-red, 12%);\n  }\n\n  .diff-neutral {\n    color: $secondary-text-color;\n  }\n\n  .diff-new {\n    color: $success-green;\n  }\n}\n\na.name-tag,\n.name-tag,\na.inline-name-tag,\n.inline-name-tag {\n  text-decoration: none;\n  color: $secondary-text-color;\n\n  .username {\n    font-weight: 500;\n  }\n\n  &.suspended {\n    .username {\n      text-decoration: line-through;\n      color: lighten($error-red, 12%);\n    }\n\n    .avatar {\n      filter: grayscale(100%);\n      opacity: 0.8;\n    }\n  }\n}\n\na.name-tag,\n.name-tag {\n  display: flex;\n  align-items: center;\n\n  .avatar {\n    display: block;\n    margin: 0;\n    margin-right: 5px;\n    border-radius: 50%;\n  }\n\n  &.suspended {\n    .avatar {\n      filter: grayscale(100%);\n      opacity: 0.8;\n    }\n  }\n}\n\n.speech-bubble {\n  margin-bottom: 20px;\n  border-left: 4px solid $ui-highlight-color;\n\n  &.positive {\n    border-left-color: $success-green;\n  }\n\n  &.negative {\n    border-left-color: lighten($error-red, 12%);\n  }\n\n  &.warning {\n    border-left-color: $gold-star;\n  }\n\n  &__bubble {\n    padding: 16px;\n    padding-left: 14px;\n    font-size: 15px;\n    line-height: 20px;\n    border-radius: 4px 4px 4px 0;\n    position: relative;\n    font-weight: 500;\n\n    a {\n      color: $darker-text-color;\n    }\n  }\n\n  &__owner {\n    padding: 8px;\n    padding-left: 12px;\n  }\n\n  time {\n    color: $dark-text-color;\n  }\n}\n\n.report-card {\n  background: $ui-base-color;\n  border-radius: 4px;\n  margin-bottom: 20px;\n\n  &__profile {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 15px;\n\n    .account {\n      padding: 0;\n      border: 0;\n\n      &__avatar-wrapper {\n        margin-left: 0;\n      }\n    }\n\n    &__stats {\n      flex: 0 0 auto;\n      font-weight: 500;\n      color: $darker-text-color;\n      text-transform: uppercase;\n      text-align: right;\n\n      a {\n        color: inherit;\n        text-decoration: none;\n\n        &:focus,\n        &:hover,\n        &:active {\n          color: lighten($darker-text-color, 8%);\n        }\n      }\n\n      .red {\n        color: $error-value-color;\n      }\n    }\n  }\n\n  &__summary {\n    &__item {\n      display: flex;\n      justify-content: flex-start;\n      border-top: 1px solid darken($ui-base-color, 4%);\n\n      &:hover {\n        background: lighten($ui-base-color, 2%);\n      }\n\n      &__reported-by,\n      &__assigned {\n        padding: 15px;\n        flex: 0 0 auto;\n        box-sizing: border-box;\n        width: 150px;\n        color: $darker-text-color;\n\n        &,\n        .username {\n          white-space: nowrap;\n          overflow: hidden;\n          text-overflow: ellipsis;\n        }\n      }\n\n      &__content {\n        flex: 1 1 auto;\n        max-width: calc(100% - 300px);\n\n        &__icon {\n          color: $dark-text-color;\n          margin-right: 4px;\n          font-weight: 500;\n        }\n      }\n\n      &__content a {\n        display: block;\n        box-sizing: border-box;\n        width: 100%;\n        padding: 15px;\n        text-decoration: none;\n        color: $darker-text-color;\n      }\n    }\n  }\n}\n\n.one-line {\n  white-space: nowrap;\n  overflow: hidden;\n  text-overflow: ellipsis;\n}\n\n.ellipsized-ip {\n  display: inline-block;\n  max-width: 120px;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  vertical-align: middle;\n}\n"
  },
  {
    "path": "app/javascript/styles/mastodon/basics.scss",
    "content": "@function hex-color($color) {\n  @if type-of($color) == 'color' {\n    $color: str-slice(ie-hex-str($color), 4);\n  }\n\n  @return '%23' + unquote($color);\n}\n\nbody {\n  font-family: $font-sans-serif, sans-serif;\n  background: darken($ui-base-color, 8%);\n  font-size: 13px;\n  line-height: 18px;\n  font-weight: 400;\n  color: $primary-text-color;\n  text-rendering: optimizelegibility;\n  font-feature-settings: \"kern\";\n  text-size-adjust: none;\n  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n  -webkit-tap-highlight-color: transparent;\n\n  &.system-font {\n    // system-ui => standard property (Chrome/Android WebView 56+, Opera 43+, Safari 11+)\n    // -apple-system => Safari <11 specific\n    // BlinkMacSystemFont => Chrome <56 on macOS specific\n    // Segoe UI => Windows 7/8/10\n    // Oxygen => KDE\n    // Ubuntu => Unity/Ubuntu\n    // Cantarell => GNOME\n    // Fira Sans => Firefox OS\n    // Droid Sans => Older Androids (<4.0)\n    // Helvetica Neue => Older macOS <10.11\n    // $font-sans-serif => web-font (Roboto) fallback and newer Androids (>=4.0)\n    font-family: system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Oxygen\", \"Ubuntu\", \"Cantarell\", \"Fira Sans\", \"Droid Sans\", \"Helvetica Neue\", $font-sans-serif, sans-serif;\n  }\n\n  &.app-body {\n    position: absolute;\n    width: 100%;\n    height: 100%;\n    padding: 0;\n    background: $ui-base-color;\n\n    &.with-modals--active {\n      overflow-y: hidden;\n    }\n  }\n\n  &.lighter {\n    background: $ui-base-color;\n  }\n\n  &.with-modals {\n    overflow-x: hidden;\n    overflow-y: scroll;\n\n    &--active {\n      overflow-y: hidden;\n      margin-right: 13px;\n    }\n  }\n\n  &.player {\n    text-align: center;\n  }\n\n  &.embed {\n    background: lighten($ui-base-color, 4%);\n    margin: 0;\n    padding-bottom: 0;\n\n    .container {\n      position: absolute;\n      width: 100%;\n      height: 100%;\n      overflow: hidden;\n    }\n  }\n\n  &.admin {\n    background: darken($ui-base-color, 4%);\n    position: fixed;\n    width: 100%;\n    height: 100%;\n    padding: 0;\n  }\n\n  &.error {\n    position: absolute;\n    text-align: center;\n    color: $darker-text-color;\n    background: $ui-base-color;\n    width: 100%;\n    height: 100%;\n    padding: 0;\n    display: flex;\n    justify-content: center;\n    align-items: center;\n\n    .dialog {\n      vertical-align: middle;\n      margin: 20px;\n\n      &__illustration {\n        img {\n          display: block;\n          max-width: 470px;\n          width: 100%;\n          height: auto;\n          margin-top: -120px;\n        }\n      }\n\n      h1 {\n        font-size: 20px;\n        line-height: 28px;\n        font-weight: 400;\n      }\n    }\n  }\n}\n\nbutton {\n  font-family: inherit;\n  cursor: pointer;\n\n  &:focus {\n    outline: none;\n  }\n}\n\n.app-holder {\n  &,\n  & > div {\n    display: flex;\n    width: 100%;\n    height: 100%;\n    align-items: center;\n    justify-content: center;\n    outline: 0 !important;\n  }\n}\n"
  },
  {
    "path": "app/javascript/styles/mastodon/boost.scss",
    "content": "button.icon-button i.fa-retweet {\n  background-image: url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='22' height='209'><path d='M4.97 3.16c-.1.03-.17.1-.22.18L.8 8.24c-.2.3.03.78.4.8H3.6v2.68c0 4.26-.55 3.62 3.66 3.62h7.66l-2.3-2.84c-.03-.02-.03-.04-.05-.06H7.27c-.44 0-.72-.3-.72-.72v-2.7h2.5c.37.03.63-.48.4-.77L5.5 3.35c-.12-.17-.34-.25-.53-.2zm12.16.43c-.55-.02-1.32.02-2.4.02H7.1l2.32 2.85.03.06h5.25c.42 0 .72.28.72.72v2.7h-2.5c-.36.02-.56.54-.3.8l3.92 4.9c.18.25.6.25.78 0l3.94-4.9c.26-.28 0-.83-.37-.8H18.4v-2.7c0-3.15.4-3.62-1.25-3.66z' fill='#{hex-color($action-button-color)}' stroke-width='0'/><path d='M7.78 19.66c-.24.02-.44.25-.44.5v2.46h-.06c-1.08 0-1.86-.03-2.4-.03-1.64 0-1.25.43-1.25 3.65v4.47c0 4.26-.56 3.62 3.65 3.62H8.5l-1.3-1.06c-.1-.08-.18-.2-.2-.3-.02-.17.06-.35.2-.45l1.33-1.1H7.28c-.44 0-.72-.3-.72-.7v-4.48c0-.44.28-.72.72-.72h.06v2.5c0 .38.54.63.82.38l4.9-3.93c.25-.18.25-.6 0-.78l-4.9-3.92c-.1-.1-.24-.14-.38-.12zm9.34 2.93c-.54-.02-1.3.02-2.4.02h-1.25l1.3 1.07c.1.07.18.2.2.33.02.16-.06.3-.2.4l-1.33 1.1h1.28c.42 0 .72.28.72.72v4.47c0 .42-.3.72-.72.72h-.1v-2.47c0-.3-.3-.53-.6-.47-.07 0-.14.05-.2.1l-4.9 3.93c-.26.18-.26.6 0 .78l4.9 3.92c.27.25.82 0 .8-.38v-2.5h.1c4.27 0 3.65.67 3.65-3.62v-4.47c0-3.15.4-3.62-1.25-3.66zM10.34 38.66c-.24.02-.44.25-.43.5v2.47H7.3c-1.08 0-1.86-.04-2.4-.04-1.64 0-1.25.43-1.25 3.65v4.47c0 3.66-.23 3.7 2.34 3.66l-1.34-1.1c-.1-.08-.18-.2-.2-.3 0-.17.07-.35.2-.45l1.96-1.6c-.03-.06-.04-.13-.04-.2v-4.48c0-.44.28-.72.72-.72H9.9v2.5c0 .36.5.6.8.38l4.93-3.93c.24-.18.24-.6 0-.78l-4.94-3.92c-.1-.08-.23-.13-.36-.12zm5.63 2.93l1.34 1.1c.1.07.18.2.2.33.02.16-.03.3-.16.4l-1.96 1.6c.02.07.06.13.06.22v4.47c0 .42-.3.72-.72.72h-2.66v-2.47c0-.3-.3-.53-.6-.47-.06.02-.12.05-.18.1l-4.94 3.93c-.24.18-.24.6 0 .78l4.94 3.92c.28.22.78-.02.78-.38v-2.5h2.66c4.27 0 3.65.67 3.65-3.62v-4.47c0-3.66.34-3.7-2.4-3.66zM13.06 57.66c-.23.03-.4.26-.4.5v2.47H7.28c-1.08 0-1.86-.04-2.4-.04-1.64 0-1.25.43-1.25 3.65v4.87l2.93-2.37v-2.5c0-.44.28-.72.72-.72h5.38v2.5c0 .36.5.6.78.38l4.94-3.93c.24-.18.24-.6 0-.78l-4.94-3.92c-.1-.1-.24-.14-.38-.12zm5.3 6.15l-2.92 2.4v2.52c0 .42-.3.72-.72.72h-5.4v-2.47c0-.3-.32-.53-.6-.47-.07.02-.13.05-.2.1L3.6 70.52c-.25.18-.25.6 0 .78l4.93 3.92c.28.22.78-.02.78-.38v-2.5h5.42c4.27 0 3.65.67 3.65-3.62v-4.47-.44zM19.25 78.8c-.1.03-.2.1-.28.17l-.9.9c-.44-.3-1.36-.25-3.35-.25H7.28c-1.08 0-1.86-.03-2.4-.03-1.64 0-1.25.43-1.25 3.65v.7l2.93.3v-1c0-.44.28-.72.72-.72h7.44c.2 0 .37.08.5.2l-1.8 1.8c-.25.26-.08.76.27.8l6.27.7c.28.03.56-.25.53-.53l-.7-6.25c0-.27-.3-.48-.55-.44zm-17.2 6.1c-.2.07-.36.3-.33.54l.7 6.25c.02.36.58.55.83.27l.8-.8c.02 0 .04-.02.04 0 .46.24 1.37.17 3.18.17h7.44c4.27 0 3.65.67 3.65-3.62v-.75l-2.93-.3v1.05c0 .42-.3.72-.72.72H7.28c-.15 0-.3-.03-.4-.1L8.8 86.4c.3-.24.1-.8-.27-.84l-6.28-.65h-.2zM4.88 98.6c-1.33 0-1.34.48-1.3 2.3l1.14-1.37c.08-.1.22-.17.34-.2.16 0 .34.08.44.2l1.66 2.03c.04 0 .07-.03.12-.03h7.44c.34 0 .57.2.65.5h-2.43c-.34.05-.53.52-.3.78l3.92 4.95c.18.24.6.24.78 0l3.94-4.94c.22-.27-.02-.76-.37-.77H18.4c.02-3.9.6-3.4-3.66-3.4H7.28c-1.08 0-1.86-.04-2.4-.04zm.15 2.46c-.1.03-.2.1-.28.2l-3.94 4.9c-.2.28.03.77.4.78H3.6c-.02 3.94-.45 3.4 3.66 3.4h7.44c3.65 0 3.74.3 3.7-2.25l-1.1 1.34c-.1.1-.2.17-.32.2-.16 0-.34-.08-.44-.2l-1.65-2.03c-.06.02-.1.04-.18.04H7.28c-.35 0-.57-.2-.66-.5h2.44c.37 0 .63-.5.4-.78l-3.96-4.9c-.1-.15-.3-.23-.47-.2zM4.88 117.6c-1.16 0-1.3.3-1.3 1.56l1.14-1.38c.08-.1.22-.14.34-.16.16 0 .34.04.44.16l2.22 2.75h7c.42 0 .72.28.72.72v.53h-2.6c-.3.1-.43.54-.2.78l3.92 4.9c.18.25.6.25.78 0l3.94-4.9c.22-.28-.02-.77-.37-.78H18.4v-.53c0-4.2.72-3.63-3.66-3.63H7.28c-1.08 0-1.86-.03-2.4-.03zm.1 1.74c-.1.03-.17.1-.23.16L.8 124.44c-.2.28.03.77.4.78H3.6v.5c0 4.26-.55 3.62 3.66 3.62h7.44c1.03 0 1.74.02 2.28 0-.16.02-.34-.03-.44-.15l-2.22-2.76H7.28c-.44 0-.72-.3-.72-.72v-.5h2.5c.37.02.63-.5.4-.78L5.5 119.5c-.12-.15-.34-.22-.53-.16zm12.02 10c1.2-.02 1.4-.25 1.4-1.53l-1.1 1.36c-.07.1-.17.17-.3.18zM5.94 136.6l2.37 2.93h6.42c.42 0 .72.28.72.72v1.25h-2.6c-.3.1-.43.54-.2.78l3.92 4.9c.18.25.6.25.78 0l3.94-4.9c.22-.28-.02-.77-.37-.78H18.4v-1.25c0-4.2.72-3.63-3.66-3.63H7.28c-.6 0-.92-.02-1.34-.03zm-1.72.06c-.4.08-.54.3-.6.75l.6-.74zm.84.93c-.12 0-.24.08-.3.18l-3.95 4.9c-.24.3 0 .83.4.82H3.6v1.22c0 4.26-.55 3.62 3.66 3.62h7.44c.63 0 .97.02 1.4.03l-2.37-2.93H7.28c-.44 0-.72-.3-.72-.72v-1.22h2.5c.4.04.67-.53.4-.8l-3.96-4.92c-.1-.13-.27-.2-.44-.2zm13.28 10.03l-.56.7c.36-.07.5-.3.56-.7zM17.13 155.6c-.55-.02-1.32.03-2.4.03h-8.2l2.38 2.9h5.82c.42 0 .72.28.72.72v1.97H12.9c-.32.06-.48.52-.28.78l3.94 4.94c.2.23.6.22.78-.03l3.94-4.9c.22-.28-.02-.77-.37-.78H18.4v-1.97c0-3.15.4-3.62-1.25-3.66zm-12.1.28c-.1.02-.2.1-.28.18l-3.94 4.9c-.2.3.03.78.4.8H3.6v1.96c0 4.26-.55 3.62 3.66 3.62h8.24l-2.36-2.9H7.28c-.44 0-.72-.3-.72-.72v-1.97h2.5c.37.02.63-.5.4-.78l-3.96-4.9c-.1-.15-.3-.22-.47-.2zM5.13 174.5c-.15 0-.3.07-.38.2L.8 179.6c-.24.27 0 .82.4.8H3.6v2.32c0 4.26-.55 3.62 3.66 3.62h7.94l-2.35-2.9h-5.6c-.43 0-.7-.3-.7-.72v-2.3h2.5c.38.03.66-.54.4-.83l-3.97-4.9c-.1-.13-.23-.2-.38-.2zm12 .1c-.55-.02-1.32.03-2.4.03H6.83l2.35 2.9h5.52c.42 0 .72.28.72.72v2.34h-2.6c-.3.1-.43.53-.2.78l3.92 4.9c.18.24.6.24.78 0l3.94-4.9c.22-.3-.02-.78-.37-.8H18.4v-2.33c0-3.15.4-3.62-1.25-3.66zM4.97 193.16c-.1.03-.17.1-.22.18l-3.94 4.9c-.2.3.03.78.4.8H3.6v2.68c0 4.26-.55 3.62 3.66 3.62h7.66l-2.3-2.84c-.03-.02-.03-.04-.05-.06H7.27c-.44 0-.72-.3-.72-.72v-2.7h2.5c.37.03.63-.48.4-.77l-3.96-4.9c-.12-.17-.34-.25-.53-.2zm12.16.43c-.55-.02-1.32.03-2.4.03H7.1l2.32 2.84.03.06h5.25c.42 0 .72.28.72.72v2.7h-2.5c-.36.02-.56.54-.3.8l3.92 4.9c.18.25.6.25.78 0l3.94-4.9c.26-.28 0-.83-.37-.8H18.4v-2.7c0-3.15.4-3.62-1.25-3.66z' fill='#{hex-color($highlight-text-color)}' stroke-width='0'/></svg>\");\n\n  &:hover {\n    background-image: url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='22' height='209'><path d='M4.97 3.16c-.1.03-.17.1-.22.18L.8 8.24c-.2.3.03.78.4.8H3.6v2.68c0 4.26-.55 3.62 3.66 3.62h7.66l-2.3-2.84c-.03-.02-.03-.04-.05-.06H7.27c-.44 0-.72-.3-.72-.72v-2.7h2.5c.37.03.63-.48.4-.77L5.5 3.35c-.12-.17-.34-.25-.53-.2zm12.16.43c-.55-.02-1.32.02-2.4.02H7.1l2.32 2.85.03.06h5.25c.42 0 .72.28.72.72v2.7h-2.5c-.36.02-.56.54-.3.8l3.92 4.9c.18.25.6.25.78 0l3.94-4.9c.26-.28 0-.83-.37-.8H18.4v-2.7c0-3.15.4-3.62-1.25-3.66z' fill='#{hex-color(lighten($action-button-color, 7%))}' stroke-width='0'/><path d='M7.78 19.66c-.24.02-.44.25-.44.5v2.46h-.06c-1.08 0-1.86-.03-2.4-.03-1.64 0-1.25.43-1.25 3.65v4.47c0 4.26-.56 3.62 3.65 3.62H8.5l-1.3-1.06c-.1-.08-.18-.2-.2-.3-.02-.17.06-.35.2-.45l1.33-1.1H7.28c-.44 0-.72-.3-.72-.7v-4.48c0-.44.28-.72.72-.72h.06v2.5c0 .38.54.63.82.38l4.9-3.93c.25-.18.25-.6 0-.78l-4.9-3.92c-.1-.1-.24-.14-.38-.12zm9.34 2.93c-.54-.02-1.3.02-2.4.02h-1.25l1.3 1.07c.1.07.18.2.2.33.02.16-.06.3-.2.4l-1.33 1.1h1.28c.42 0 .72.28.72.72v4.47c0 .42-.3.72-.72.72h-.1v-2.47c0-.3-.3-.53-.6-.47-.07 0-.14.05-.2.1l-4.9 3.93c-.26.18-.26.6 0 .78l4.9 3.92c.27.25.82 0 .8-.38v-2.5h.1c4.27 0 3.65.67 3.65-3.62v-4.47c0-3.15.4-3.62-1.25-3.66zM10.34 38.66c-.24.02-.44.25-.43.5v2.47H7.3c-1.08 0-1.86-.04-2.4-.04-1.64 0-1.25.43-1.25 3.65v4.47c0 3.66-.23 3.7 2.34 3.66l-1.34-1.1c-.1-.08-.18-.2-.2-.3 0-.17.07-.35.2-.45l1.96-1.6c-.03-.06-.04-.13-.04-.2v-4.48c0-.44.28-.72.72-.72H9.9v2.5c0 .36.5.6.8.38l4.93-3.93c.24-.18.24-.6 0-.78l-4.94-3.92c-.1-.08-.23-.13-.36-.12zm5.63 2.93l1.34 1.1c.1.07.18.2.2.33.02.16-.03.3-.16.4l-1.96 1.6c.02.07.06.13.06.22v4.47c0 .42-.3.72-.72.72h-2.66v-2.47c0-.3-.3-.53-.6-.47-.06.02-.12.05-.18.1l-4.94 3.93c-.24.18-.24.6 0 .78l4.94 3.92c.28.22.78-.02.78-.38v-2.5h2.66c4.27 0 3.65.67 3.65-3.62v-4.47c0-3.66.34-3.7-2.4-3.66zM13.06 57.66c-.23.03-.4.26-.4.5v2.47H7.28c-1.08 0-1.86-.04-2.4-.04-1.64 0-1.25.43-1.25 3.65v4.87l2.93-2.37v-2.5c0-.44.28-.72.72-.72h5.38v2.5c0 .36.5.6.78.38l4.94-3.93c.24-.18.24-.6 0-.78l-4.94-3.92c-.1-.1-.24-.14-.38-.12zm5.3 6.15l-2.92 2.4v2.52c0 .42-.3.72-.72.72h-5.4v-2.47c0-.3-.32-.53-.6-.47-.07.02-.13.05-.2.1L3.6 70.52c-.25.18-.25.6 0 .78l4.93 3.92c.28.22.78-.02.78-.38v-2.5h5.42c4.27 0 3.65.67 3.65-3.62v-4.47-.44zM19.25 78.8c-.1.03-.2.1-.28.17l-.9.9c-.44-.3-1.36-.25-3.35-.25H7.28c-1.08 0-1.86-.03-2.4-.03-1.64 0-1.25.43-1.25 3.65v.7l2.93.3v-1c0-.44.28-.72.72-.72h7.44c.2 0 .37.08.5.2l-1.8 1.8c-.25.26-.08.76.27.8l6.27.7c.28.03.56-.25.53-.53l-.7-6.25c0-.27-.3-.48-.55-.44zm-17.2 6.1c-.2.07-.36.3-.33.54l.7 6.25c.02.36.58.55.83.27l.8-.8c.02 0 .04-.02.04 0 .46.24 1.37.17 3.18.17h7.44c4.27 0 3.65.67 3.65-3.62v-.75l-2.93-.3v1.05c0 .42-.3.72-.72.72H7.28c-.15 0-.3-.03-.4-.1L8.8 86.4c.3-.24.1-.8-.27-.84l-6.28-.65h-.2zM4.88 98.6c-1.33 0-1.34.48-1.3 2.3l1.14-1.37c.08-.1.22-.17.34-.2.16 0 .34.08.44.2l1.66 2.03c.04 0 .07-.03.12-.03h7.44c.34 0 .57.2.65.5h-2.43c-.34.05-.53.52-.3.78l3.92 4.95c.18.24.6.24.78 0l3.94-4.94c.22-.27-.02-.76-.37-.77H18.4c.02-3.9.6-3.4-3.66-3.4H7.28c-1.08 0-1.86-.04-2.4-.04zm.15 2.46c-.1.03-.2.1-.28.2l-3.94 4.9c-.2.28.03.77.4.78H3.6c-.02 3.94-.45 3.4 3.66 3.4h7.44c3.65 0 3.74.3 3.7-2.25l-1.1 1.34c-.1.1-.2.17-.32.2-.16 0-.34-.08-.44-.2l-1.65-2.03c-.06.02-.1.04-.18.04H7.28c-.35 0-.57-.2-.66-.5h2.44c.37 0 .63-.5.4-.78l-3.96-4.9c-.1-.15-.3-.23-.47-.2zM4.88 117.6c-1.16 0-1.3.3-1.3 1.56l1.14-1.38c.08-.1.22-.14.34-.16.16 0 .34.04.44.16l2.22 2.75h7c.42 0 .72.28.72.72v.53h-2.6c-.3.1-.43.54-.2.78l3.92 4.9c.18.25.6.25.78 0l3.94-4.9c.22-.28-.02-.77-.37-.78H18.4v-.53c0-4.2.72-3.63-3.66-3.63H7.28c-1.08 0-1.86-.03-2.4-.03zm.1 1.74c-.1.03-.17.1-.23.16L.8 124.44c-.2.28.03.77.4.78H3.6v.5c0 4.26-.55 3.62 3.66 3.62h7.44c1.03 0 1.74.02 2.28 0-.16.02-.34-.03-.44-.15l-2.22-2.76H7.28c-.44 0-.72-.3-.72-.72v-.5h2.5c.37.02.63-.5.4-.78L5.5 119.5c-.12-.15-.34-.22-.53-.16zm12.02 10c1.2-.02 1.4-.25 1.4-1.53l-1.1 1.36c-.07.1-.17.17-.3.18zM5.94 136.6l2.37 2.93h6.42c.42 0 .72.28.72.72v1.25h-2.6c-.3.1-.43.54-.2.78l3.92 4.9c.18.25.6.25.78 0l3.94-4.9c.22-.28-.02-.77-.37-.78H18.4v-1.25c0-4.2.72-3.63-3.66-3.63H7.28c-.6 0-.92-.02-1.34-.03zm-1.72.06c-.4.08-.54.3-.6.75l.6-.74zm.84.93c-.12 0-.24.08-.3.18l-3.95 4.9c-.24.3 0 .83.4.82H3.6v1.22c0 4.26-.55 3.62 3.66 3.62h7.44c.63 0 .97.02 1.4.03l-2.37-2.93H7.28c-.44 0-.72-.3-.72-.72v-1.22h2.5c.4.04.67-.53.4-.8l-3.96-4.92c-.1-.13-.27-.2-.44-.2zm13.28 10.03l-.56.7c.36-.07.5-.3.56-.7zM17.13 155.6c-.55-.02-1.32.03-2.4.03h-8.2l2.38 2.9h5.82c.42 0 .72.28.72.72v1.97H12.9c-.32.06-.48.52-.28.78l3.94 4.94c.2.23.6.22.78-.03l3.94-4.9c.22-.28-.02-.77-.37-.78H18.4v-1.97c0-3.15.4-3.62-1.25-3.66zm-12.1.28c-.1.02-.2.1-.28.18l-3.94 4.9c-.2.3.03.78.4.8H3.6v1.96c0 4.26-.55 3.62 3.66 3.62h8.24l-2.36-2.9H7.28c-.44 0-.72-.3-.72-.72v-1.97h2.5c.37.02.63-.5.4-.78l-3.96-4.9c-.1-.15-.3-.22-.47-.2zM5.13 174.5c-.15 0-.3.07-.38.2L.8 179.6c-.24.27 0 .82.4.8H3.6v2.32c0 4.26-.55 3.62 3.66 3.62h7.94l-2.35-2.9h-5.6c-.43 0-.7-.3-.7-.72v-2.3h2.5c.38.03.66-.54.4-.83l-3.97-4.9c-.1-.13-.23-.2-.38-.2zm12 .1c-.55-.02-1.32.03-2.4.03H6.83l2.35 2.9h5.52c.42 0 .72.28.72.72v2.34h-2.6c-.3.1-.43.53-.2.78l3.92 4.9c.18.24.6.24.78 0l3.94-4.9c.22-.3-.02-.78-.37-.8H18.4v-2.33c0-3.15.4-3.62-1.25-3.66zM4.97 193.16c-.1.03-.17.1-.22.18l-3.94 4.9c-.2.3.03.78.4.8H3.6v2.68c0 4.26-.55 3.62 3.66 3.62h7.66l-2.3-2.84c-.03-.02-.03-.04-.05-.06H7.27c-.44 0-.72-.3-.72-.72v-2.7h2.5c.37.03.63-.48.4-.77l-3.96-4.9c-.12-.17-.34-.25-.53-.2zm12.16.43c-.55-.02-1.32.03-2.4.03H7.1l2.32 2.84.03.06h5.25c.42 0 .72.28.72.72v2.7h-2.5c-.36.02-.56.54-.3.8l3.92 4.9c.18.25.6.25.78 0l3.94-4.9c.26-.28 0-.83-.37-.8H18.4v-2.7c0-3.15.4-3.62-1.25-3.66z' fill='#{hex-color($highlight-text-color)}' stroke-width='0'/></svg>\");\n  }\n}\n\nbutton.icon-button.disabled i.fa-retweet {\n  background-image: url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='22' height='209'><path d='M4.97 3.16c-.1.03-.17.1-.22.18L.8 8.24c-.2.3.03.78.4.8H3.6v2.68c0 4.26-.55 3.62 3.66 3.62h7.66l-2.3-2.84c-.03-.02-.03-.04-.05-.06H7.27c-.44 0-.72-.3-.72-.72v-2.7h2.5c.37.03.63-.48.4-.77L5.5 3.35c-.12-.17-.34-.25-.53-.2zm12.16.43c-.55-.02-1.32.02-2.4.02H7.1l2.32 2.85.03.06h5.25c.42 0 .72.28.72.72v2.7h-2.5c-.36.02-.56.54-.3.8l3.92 4.9c.18.25.6.25.78 0l3.94-4.9c.26-.28 0-.83-.37-.8H18.4v-2.7c0-3.15.4-3.62-1.25-3.66z' fill='#{hex-color(darken($action-button-color, 13%))}' stroke-width='0'/><path d='M7.78 19.66c-.24.02-.44.25-.44.5v2.46h-.06c-1.08 0-1.86-.03-2.4-.03-1.64 0-1.25.43-1.25 3.65v4.47c0 4.26-.56 3.62 3.65 3.62H8.5l-1.3-1.06c-.1-.08-.18-.2-.2-.3-.02-.17.06-.35.2-.45l1.33-1.1H7.28c-.44 0-.72-.3-.72-.7v-4.48c0-.44.28-.72.72-.72h.06v2.5c0 .38.54.63.82.38l4.9-3.93c.25-.18.25-.6 0-.78l-4.9-3.92c-.1-.1-.24-.14-.38-.12zm9.34 2.93c-.54-.02-1.3.02-2.4.02h-1.25l1.3 1.07c.1.07.18.2.2.33.02.16-.06.3-.2.4l-1.33 1.1h1.28c.42 0 .72.28.72.72v4.47c0 .42-.3.72-.72.72h-.1v-2.47c0-.3-.3-.53-.6-.47-.07 0-.14.05-.2.1l-4.9 3.93c-.26.18-.26.6 0 .78l4.9 3.92c.27.25.82 0 .8-.38v-2.5h.1c4.27 0 3.65.67 3.65-3.62v-4.47c0-3.15.4-3.62-1.25-3.66zM10.34 38.66c-.24.02-.44.25-.43.5v2.47H7.3c-1.08 0-1.86-.04-2.4-.04-1.64 0-1.25.43-1.25 3.65v4.47c0 3.66-.23 3.7 2.34 3.66l-1.34-1.1c-.1-.08-.18-.2-.2-.3 0-.17.07-.35.2-.45l1.96-1.6c-.03-.06-.04-.13-.04-.2v-4.48c0-.44.28-.72.72-.72H9.9v2.5c0 .36.5.6.8.38l4.93-3.93c.24-.18.24-.6 0-.78l-4.94-3.92c-.1-.08-.23-.13-.36-.12zm5.63 2.93l1.34 1.1c.1.07.18.2.2.33.02.16-.03.3-.16.4l-1.96 1.6c.02.07.06.13.06.22v4.47c0 .42-.3.72-.72.72h-2.66v-2.47c0-.3-.3-.53-.6-.47-.06.02-.12.05-.18.1l-4.94 3.93c-.24.18-.24.6 0 .78l4.94 3.92c.28.22.78-.02.78-.38v-2.5h2.66c4.27 0 3.65.67 3.65-3.62v-4.47c0-3.66.34-3.7-2.4-3.66zM13.06 57.66c-.23.03-.4.26-.4.5v2.47H7.28c-1.08 0-1.86-.04-2.4-.04-1.64 0-1.25.43-1.25 3.65v4.87l2.93-2.37v-2.5c0-.44.28-.72.72-.72h5.38v2.5c0 .36.5.6.78.38l4.94-3.93c.24-.18.24-.6 0-.78l-4.94-3.92c-.1-.1-.24-.14-.38-.12zm5.3 6.15l-2.92 2.4v2.52c0 .42-.3.72-.72.72h-5.4v-2.47c0-.3-.32-.53-.6-.47-.07.02-.13.05-.2.1L3.6 70.52c-.25.18-.25.6 0 .78l4.93 3.92c.28.22.78-.02.78-.38v-2.5h5.42c4.27 0 3.65.67 3.65-3.62v-4.47-.44zM19.25 78.8c-.1.03-.2.1-.28.17l-.9.9c-.44-.3-1.36-.25-3.35-.25H7.28c-1.08 0-1.86-.03-2.4-.03-1.64 0-1.25.43-1.25 3.65v.7l2.93.3v-1c0-.44.28-.72.72-.72h7.44c.2 0 .37.08.5.2l-1.8 1.8c-.25.26-.08.76.27.8l6.27.7c.28.03.56-.25.53-.53l-.7-6.25c0-.27-.3-.48-.55-.44zm-17.2 6.1c-.2.07-.36.3-.33.54l.7 6.25c.02.36.58.55.83.27l.8-.8c.02 0 .04-.02.04 0 .46.24 1.37.17 3.18.17h7.44c4.27 0 3.65.67 3.65-3.62v-.75l-2.93-.3v1.05c0 .42-.3.72-.72.72H7.28c-.15 0-.3-.03-.4-.1L8.8 86.4c.3-.24.1-.8-.27-.84l-6.28-.65h-.2zM4.88 98.6c-1.33 0-1.34.48-1.3 2.3l1.14-1.37c.08-.1.22-.17.34-.2.16 0 .34.08.44.2l1.66 2.03c.04 0 .07-.03.12-.03h7.44c.34 0 .57.2.65.5h-2.43c-.34.05-.53.52-.3.78l3.92 4.95c.18.24.6.24.78 0l3.94-4.94c.22-.27-.02-.76-.37-.77H18.4c.02-3.9.6-3.4-3.66-3.4H7.28c-1.08 0-1.86-.04-2.4-.04zm.15 2.46c-.1.03-.2.1-.28.2l-3.94 4.9c-.2.28.03.77.4.78H3.6c-.02 3.94-.45 3.4 3.66 3.4h7.44c3.65 0 3.74.3 3.7-2.25l-1.1 1.34c-.1.1-.2.17-.32.2-.16 0-.34-.08-.44-.2l-1.65-2.03c-.06.02-.1.04-.18.04H7.28c-.35 0-.57-.2-.66-.5h2.44c.37 0 .63-.5.4-.78l-3.96-4.9c-.1-.15-.3-.23-.47-.2zM4.88 117.6c-1.16 0-1.3.3-1.3 1.56l1.14-1.38c.08-.1.22-.14.34-.16.16 0 .34.04.44.16l2.22 2.75h7c.42 0 .72.28.72.72v.53h-2.6c-.3.1-.43.54-.2.78l3.92 4.9c.18.25.6.25.78 0l3.94-4.9c.22-.28-.02-.77-.37-.78H18.4v-.53c0-4.2.72-3.63-3.66-3.63H7.28c-1.08 0-1.86-.03-2.4-.03zm.1 1.74c-.1.03-.17.1-.23.16L.8 124.44c-.2.28.03.77.4.78H3.6v.5c0 4.26-.55 3.62 3.66 3.62h7.44c1.03 0 1.74.02 2.28 0-.16.02-.34-.03-.44-.15l-2.22-2.76H7.28c-.44 0-.72-.3-.72-.72v-.5h2.5c.37.02.63-.5.4-.78L5.5 119.5c-.12-.15-.34-.22-.53-.16zm12.02 10c1.2-.02 1.4-.25 1.4-1.53l-1.1 1.36c-.07.1-.17.17-.3.18zM5.94 136.6l2.37 2.93h6.42c.42 0 .72.28.72.72v1.25h-2.6c-.3.1-.43.54-.2.78l3.92 4.9c.18.25.6.25.78 0l3.94-4.9c.22-.28-.02-.77-.37-.78H18.4v-1.25c0-4.2.72-3.63-3.66-3.63H7.28c-.6 0-.92-.02-1.34-.03zm-1.72.06c-.4.08-.54.3-.6.75l.6-.74zm.84.93c-.12 0-.24.08-.3.18l-3.95 4.9c-.24.3 0 .83.4.82H3.6v1.22c0 4.26-.55 3.62 3.66 3.62h7.44c.63 0 .97.02 1.4.03l-2.37-2.93H7.28c-.44 0-.72-.3-.72-.72v-1.22h2.5c.4.04.67-.53.4-.8l-3.96-4.92c-.1-.13-.27-.2-.44-.2zm13.28 10.03l-.56.7c.36-.07.5-.3.56-.7zM17.13 155.6c-.55-.02-1.32.03-2.4.03h-8.2l2.38 2.9h5.82c.42 0 .72.28.72.72v1.97H12.9c-.32.06-.48.52-.28.78l3.94 4.94c.2.23.6.22.78-.03l3.94-4.9c.22-.28-.02-.77-.37-.78H18.4v-1.97c0-3.15.4-3.62-1.25-3.66zm-12.1.28c-.1.02-.2.1-.28.18l-3.94 4.9c-.2.3.03.78.4.8H3.6v1.96c0 4.26-.55 3.62 3.66 3.62h8.24l-2.36-2.9H7.28c-.44 0-.72-.3-.72-.72v-1.97h2.5c.37.02.63-.5.4-.78l-3.96-4.9c-.1-.15-.3-.22-.47-.2zM5.13 174.5c-.15 0-.3.07-.38.2L.8 179.6c-.24.27 0 .82.4.8H3.6v2.32c0 4.26-.55 3.62 3.66 3.62h7.94l-2.35-2.9h-5.6c-.43 0-.7-.3-.7-.72v-2.3h2.5c.38.03.66-.54.4-.83l-3.97-4.9c-.1-.13-.23-.2-.38-.2zm12 .1c-.55-.02-1.32.03-2.4.03H6.83l2.35 2.9h5.52c.42 0 .72.28.72.72v2.34h-2.6c-.3.1-.43.53-.2.78l3.92 4.9c.18.24.6.24.78 0l3.94-4.9c.22-.3-.02-.78-.37-.8H18.4v-2.33c0-3.15.4-3.62-1.25-3.66zM4.97 193.16c-.1.03-.17.1-.22.18l-3.94 4.9c-.2.3.03.78.4.8H3.6v2.68c0 4.26-.55 3.62 3.66 3.62h7.66l-2.3-2.84c-.03-.02-.03-.04-.05-.06H7.27c-.44 0-.72-.3-.72-.72v-2.7h2.5c.37.03.63-.48.4-.77l-3.96-4.9c-.12-.17-.34-.25-.53-.2zm12.16.43c-.55-.02-1.32.03-2.4.03H7.1l2.32 2.84.03.06h5.25c.42 0 .72.28.72.72v2.7h-2.5c-.36.02-.56.54-.3.8l3.92 4.9c.18.25.6.25.78 0l3.94-4.9c.26-.28 0-.83-.37-.8H18.4v-2.7c0-3.15.4-3.62-1.25-3.66z' fill='#{hex-color($highlight-text-color)}' stroke-width='0'/></svg>\");\n}\n"
  },
  {
    "path": "app/javascript/styles/mastodon/compact_header.scss",
    "content": ".compact-header {\n  h1 {\n    font-size: 24px;\n    line-height: 28px;\n    color: $darker-text-color;\n    font-weight: 500;\n    margin-bottom: 20px;\n    padding: 0 10px;\n    word-wrap: break-word;\n\n    @media screen and (max-width: 740px) {\n      text-align: center;\n      padding: 20px 10px 0;\n    }\n\n    a {\n      color: inherit;\n      text-decoration: none;\n    }\n\n    small {\n      font-weight: 400;\n      color: $secondary-text-color;\n    }\n\n    img {\n      display: inline-block;\n      margin-bottom: -5px;\n      margin-right: 15px;\n      width: 36px;\n      height: 36px;\n    }\n  }\n}\n"
  },
  {
    "path": "app/javascript/styles/mastodon/components.scss",
    "content": ".app-body {\n  -webkit-overflow-scrolling: touch;\n  -ms-overflow-style: -ms-autohiding-scrollbar;\n}\n\n.button {\n  background-color: $ui-highlight-color;\n  border: 10px none;\n  border-radius: 4px;\n  box-sizing: border-box;\n  color: $primary-text-color;\n  cursor: pointer;\n  display: inline-block;\n  font-family: inherit;\n  font-size: 14px;\n  font-weight: 500;\n  height: 36px;\n  letter-spacing: 0;\n  line-height: 36px;\n  overflow: hidden;\n  padding: 0 16px;\n  position: relative;\n  text-align: center;\n  text-transform: uppercase;\n  text-decoration: none;\n  text-overflow: ellipsis;\n  transition: all 100ms ease-in;\n  white-space: nowrap;\n  width: auto;\n\n  &:active,\n  &:focus,\n  &:hover {\n    background-color: lighten($ui-highlight-color, 10%);\n    transition: all 200ms ease-out;\n  }\n\n  &--destructive {\n    transition: none;\n\n    &:active,\n    &:focus,\n    &:hover {\n      background-color: $error-red;\n      transition: none;\n    }\n  }\n\n  &:disabled,\n  &.disabled {\n    background-color: $ui-primary-color;\n    cursor: default;\n  }\n\n  &::-moz-focus-inner {\n    border: 0;\n  }\n\n  &::-moz-focus-inner,\n  &:focus,\n  &:active {\n    outline: 0 !important;\n  }\n\n  &.button-primary,\n  &.button-alternative,\n  &.button-secondary,\n  &.button-alternative-2 {\n    font-size: 16px;\n    line-height: 36px;\n    height: auto;\n    text-transform: none;\n    padding: 4px 16px;\n  }\n\n  &.button-alternative {\n    color: $inverted-text-color;\n    background: $ui-primary-color;\n\n    &:active,\n    &:focus,\n    &:hover {\n      background-color: lighten($ui-primary-color, 4%);\n    }\n  }\n\n  &.button-alternative-2 {\n    background: $ui-base-lighter-color;\n\n    &:active,\n    &:focus,\n    &:hover {\n      background-color: lighten($ui-base-lighter-color, 4%);\n    }\n  }\n\n  &.button-secondary {\n    color: $darker-text-color;\n    background: transparent;\n    padding: 3px 15px;\n    border: 1px solid $ui-primary-color;\n\n    &:active,\n    &:focus,\n    &:hover {\n      border-color: lighten($ui-primary-color, 4%);\n      color: lighten($darker-text-color, 4%);\n    }\n\n    &:disabled {\n      opacity: 0.5;\n    }\n  }\n\n  &.button--block {\n    display: block;\n    width: 100%;\n  }\n}\n\n.column__wrapper {\n  display: flex;\n  flex: 1 1 auto;\n  position: relative;\n}\n\n.icon-button {\n  display: inline-block;\n  padding: 0;\n  color: $action-button-color;\n  border: 0;\n  background: transparent;\n  cursor: pointer;\n  transition: color 100ms ease-in;\n\n  &:hover,\n  &:active,\n  &:focus {\n    color: lighten($action-button-color, 7%);\n    transition: color 200ms ease-out;\n  }\n\n  &.disabled {\n    color: darken($action-button-color, 13%);\n    cursor: default;\n  }\n\n  &.active {\n    color: $highlight-text-color;\n  }\n\n  &::-moz-focus-inner {\n    border: 0;\n  }\n\n  &::-moz-focus-inner,\n  &:focus,\n  &:active {\n    outline: 0 !important;\n  }\n\n  &.inverted {\n    color: $lighter-text-color;\n\n    &:hover,\n    &:active,\n    &:focus {\n      color: darken($lighter-text-color, 7%);\n    }\n\n    &.disabled {\n      color: lighten($lighter-text-color, 7%);\n    }\n\n    &.active {\n      color: $highlight-text-color;\n\n      &.disabled {\n        color: lighten($highlight-text-color, 13%);\n      }\n    }\n  }\n\n  &.overlayed {\n    box-sizing: content-box;\n    background: rgba($base-overlay-background, 0.6);\n    color: rgba($primary-text-color, 0.7);\n    border-radius: 4px;\n    padding: 2px;\n\n    &:hover {\n      background: rgba($base-overlay-background, 0.9);\n    }\n  }\n}\n\n.text-icon-button {\n  color: $lighter-text-color;\n  border: 0;\n  background: transparent;\n  cursor: pointer;\n  font-weight: 600;\n  font-size: 11px;\n  padding: 0 3px;\n  line-height: 27px;\n  outline: 0;\n  transition: color 100ms ease-in;\n\n  &:hover,\n  &:active,\n  &:focus {\n    color: darken($lighter-text-color, 7%);\n    transition: color 200ms ease-out;\n  }\n\n  &.disabled {\n    color: lighten($lighter-text-color, 20%);\n    cursor: default;\n  }\n\n  &.active {\n    color: $highlight-text-color;\n  }\n\n  &::-moz-focus-inner {\n    border: 0;\n  }\n\n  &::-moz-focus-inner,\n  &:focus,\n  &:active {\n    outline: 0 !important;\n  }\n}\n\n.dropdown-menu {\n  position: absolute;\n}\n\n.invisible {\n  font-size: 0;\n  line-height: 0;\n  display: inline-block;\n  width: 0;\n  height: 0;\n  position: absolute;\n\n  img,\n  svg {\n    margin: 0 !important;\n    border: 0 !important;\n    padding: 0 !important;\n    width: 0 !important;\n    height: 0 !important;\n  }\n}\n\n.ellipsis {\n  &::after {\n    content: \"…\";\n  }\n}\n\n.compose-form {\n  padding: 10px;\n\n  &__sensitive-button {\n    padding: 10px;\n    padding-top: 0;\n\n    font-size: 14px;\n    font-weight: 500;\n\n    &.active {\n      color: $highlight-text-color;\n    }\n\n    input[type=checkbox] {\n      display: none;\n    }\n\n    .checkbox {\n      display: inline-block;\n      position: relative;\n      border: 1px solid $ui-primary-color;\n      box-sizing: border-box;\n      width: 18px;\n      height: 18px;\n      flex: 0 0 auto;\n      margin-right: 10px;\n      top: -1px;\n      border-radius: 4px;\n      vertical-align: middle;\n\n      &.active {\n        border-color: $highlight-text-color;\n        background: $highlight-text-color;\n      }\n    }\n  }\n\n  .compose-form__warning {\n    color: $inverted-text-color;\n    margin-bottom: 10px;\n    background: $ui-primary-color;\n    box-shadow: 0 2px 6px rgba($base-shadow-color, 0.3);\n    padding: 8px 10px;\n    border-radius: 4px;\n    font-size: 13px;\n    font-weight: 400;\n\n    strong {\n      color: $inverted-text-color;\n      font-weight: 500;\n\n      @each $lang in $cjk-langs {\n        &:lang(#{$lang}) {\n          font-weight: 700;\n        }\n      }\n    }\n\n    a {\n      color: $lighter-text-color;\n      font-weight: 500;\n      text-decoration: underline;\n\n      &:hover,\n      &:active,\n      &:focus {\n        text-decoration: none;\n      }\n    }\n  }\n\n  .emoji-picker-dropdown {\n    position: absolute;\n    top: 5px;\n    right: 5px;\n  }\n\n  .compose-form__autosuggest-wrapper {\n    position: relative;\n  }\n\n  .autosuggest-textarea,\n  .autosuggest-input,\n  .spoiler-input {\n    position: relative;\n  }\n\n  .spoiler-input {\n    height: 0;\n    transform-origin: bottom;\n    opacity: 0;\n\n    &.spoiler-input--visible {\n      height: 36px;\n      margin-bottom: 11px;\n      opacity: 1;\n    }\n  }\n\n  .autosuggest-textarea__textarea,\n  .spoiler-input__input {\n    display: block;\n    box-sizing: border-box;\n    width: 100%;\n    margin: 0;\n    color: $inverted-text-color;\n    background: $simple-background-color;\n    padding: 10px;\n    font-family: inherit;\n    font-size: 14px;\n    resize: vertical;\n    border: 0;\n    outline: 0;\n\n    &:focus {\n      outline: 0;\n    }\n\n    @media screen and (max-width: 600px) {\n      font-size: 16px;\n    }\n  }\n\n  .spoiler-input__input {\n    border-radius: 4px;\n  }\n\n  .autosuggest-textarea__textarea {\n    min-height: 100px;\n    border-radius: 4px 4px 0 0;\n    padding-bottom: 0;\n    padding-right: 10px + 22px;\n    resize: none;\n    scrollbar-color: initial;\n\n    &::-webkit-scrollbar {\n      all: unset;\n    }\n\n    @media screen and (max-width: 600px) {\n      height: 100px !important; // prevent auto-resize textarea\n      resize: vertical;\n    }\n  }\n\n  .autosuggest-textarea__suggestions-wrapper {\n    position: relative;\n    height: 0;\n  }\n\n  .autosuggest-textarea__suggestions {\n    box-sizing: border-box;\n    display: none;\n    position: absolute;\n    top: 100%;\n    width: 100%;\n    z-index: 99;\n    box-shadow: 4px 4px 6px rgba($base-shadow-color, 0.4);\n    background: $ui-secondary-color;\n    border-radius: 0 0 4px 4px;\n    color: $inverted-text-color;\n    font-size: 14px;\n    padding: 6px;\n\n    &.autosuggest-textarea__suggestions--visible {\n      display: block;\n    }\n  }\n\n  .autosuggest-textarea__suggestions__item {\n    padding: 10px;\n    cursor: pointer;\n    border-radius: 4px;\n\n    &:hover,\n    &:focus,\n    &:active,\n    &.selected {\n      background: darken($ui-secondary-color, 10%);\n    }\n  }\n\n  .autosuggest-account,\n  .autosuggest-emoji {\n    display: flex;\n    flex-direction: row;\n    align-items: center;\n    justify-content: flex-start;\n    line-height: 18px;\n    font-size: 14px;\n  }\n\n  .autosuggest-account-icon,\n  .autosuggest-emoji img {\n    display: block;\n    margin-right: 8px;\n    width: 16px;\n    height: 16px;\n  }\n\n  .autosuggest-account .display-name__account {\n    color: $lighter-text-color;\n  }\n\n  .compose-form__modifiers {\n    color: $inverted-text-color;\n    font-family: inherit;\n    font-size: 14px;\n    background: $simple-background-color;\n\n    .compose-form__upload-wrapper {\n      overflow: hidden;\n    }\n\n    .compose-form__uploads-wrapper {\n      display: flex;\n      flex-direction: row;\n      padding: 5px;\n      flex-wrap: wrap;\n    }\n\n    .compose-form__upload {\n      flex: 1 1 0;\n      min-width: 40%;\n      margin: 5px;\n\n      &__actions {\n        background: linear-gradient(180deg, rgba($base-shadow-color, 0.8) 0, rgba($base-shadow-color, 0.35) 80%, transparent);\n        display: flex;\n        align-items: flex-start;\n        justify-content: space-between;\n        opacity: 0;\n        transition: opacity .1s ease;\n\n        .icon-button {\n          flex: 0 1 auto;\n          color: $secondary-text-color;\n          font-size: 14px;\n          font-weight: 500;\n          padding: 10px;\n          font-family: inherit;\n\n          &:hover,\n          &:focus,\n          &:active {\n            color: lighten($secondary-text-color, 7%);\n          }\n        }\n\n        &.active {\n          opacity: 1;\n        }\n      }\n\n      &-description {\n        position: absolute;\n        z-index: 2;\n        bottom: 0;\n        left: 0;\n        right: 0;\n        box-sizing: border-box;\n        background: linear-gradient(0deg, rgba($base-shadow-color, 0.8) 0, rgba($base-shadow-color, 0.35) 80%, transparent);\n        padding: 10px;\n        opacity: 0;\n        transition: opacity .1s ease;\n\n        textarea {\n          background: transparent;\n          color: $secondary-text-color;\n          border: 0;\n          padding: 0;\n          margin: 0;\n          width: 100%;\n          font-family: inherit;\n          font-size: 14px;\n          font-weight: 500;\n\n          &:focus {\n            color: $white;\n          }\n\n          &::placeholder {\n            opacity: 0.75;\n            color: $secondary-text-color;\n          }\n        }\n\n        &.active {\n          opacity: 1;\n        }\n      }\n    }\n\n    .compose-form__upload-thumbnail {\n      border-radius: 4px;\n      background-position: center;\n      background-size: cover;\n      background-repeat: no-repeat;\n      height: 140px;\n      width: 100%;\n      overflow: hidden;\n    }\n  }\n\n  .compose-form__buttons-wrapper {\n    padding: 10px;\n    background: darken($simple-background-color, 8%);\n    border-radius: 0 0 4px 4px;\n    display: flex;\n    justify-content: space-between;\n    flex: 0 0 auto;\n\n    .compose-form__buttons {\n      display: flex;\n\n      .compose-form__upload-button-icon {\n        line-height: 27px;\n      }\n\n      .compose-form__sensitive-button {\n        display: none;\n\n        &.compose-form__sensitive-button--visible {\n          display: block;\n        }\n\n        .compose-form__sensitive-button__icon {\n          line-height: 27px;\n        }\n      }\n    }\n\n    .icon-button {\n      box-sizing: content-box;\n      padding: 0 3px;\n    }\n\n    .character-counter__wrapper {\n      align-self: center;\n      margin-right: 4px;\n\n      .character-counter {\n        cursor: default;\n        font-family: $font-sans-serif, sans-serif;\n        font-size: 14px;\n        font-weight: 600;\n        color: $lighter-text-color;\n\n        &.character-counter--over {\n          color: $warning-red;\n        }\n      }\n    }\n  }\n\n  .compose-form__publish {\n    display: flex;\n    justify-content: flex-end;\n    min-width: 0;\n    flex: 0 0 auto;\n\n    .compose-form__publish-button-wrapper {\n      overflow: hidden;\n      padding-top: 10px;\n    }\n  }\n}\n\n.no-reduce-motion .spoiler-input {\n  transition: height 0.4s ease, opacity 0.4s ease;\n}\n\n.emojione {\n  font-size: inherit;\n  vertical-align: middle;\n  object-fit: contain;\n  margin: -.2ex .15em .2ex;\n  width: 16px;\n  height: 16px;\n\n  img {\n    width: auto;\n  }\n}\n\n.reply-indicator {\n  border-radius: 4px;\n  margin-bottom: 10px;\n  background: $ui-primary-color;\n  padding: 10px;\n  min-height: 23px;\n  overflow-y: auto;\n  flex: 0 2 auto;\n}\n\n.reply-indicator__header {\n  margin-bottom: 5px;\n  overflow: hidden;\n}\n\n.reply-indicator__cancel {\n  float: right;\n  line-height: 24px;\n}\n\n.reply-indicator__display-name {\n  color: $inverted-text-color;\n  display: block;\n  max-width: 100%;\n  line-height: 24px;\n  overflow: hidden;\n  padding-right: 25px;\n  text-decoration: none;\n}\n\n.reply-indicator__display-avatar {\n  float: left;\n  margin-right: 5px;\n}\n\n.status__content--with-action {\n  cursor: pointer;\n}\n\n.status__content,\n.reply-indicator__content {\n  position: relative;\n  font-size: 15px;\n  line-height: 20px;\n  word-wrap: break-word;\n  font-weight: 400;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  padding-top: 2px;\n  color: $primary-text-color;\n\n  &:focus {\n    outline: 0;\n  }\n\n  &.status__content--with-spoiler {\n    white-space: normal;\n\n    .status__content__text {\n      white-space: pre-wrap;\n    }\n  }\n\n  .emojione {\n    width: 20px;\n    height: 20px;\n    margin: -3px 0 0;\n  }\n\n  p {\n    margin-bottom: 20px;\n    white-space: pre-wrap;\n\n    &:last-child {\n      margin-bottom: 2px;\n    }\n  }\n\n  a {\n    color: $secondary-text-color;\n    text-decoration: none;\n\n    &:hover {\n      text-decoration: underline;\n\n      .fa {\n        color: lighten($dark-text-color, 7%);\n      }\n    }\n\n    &.mention {\n      &:hover {\n        text-decoration: none;\n\n        span {\n          text-decoration: underline;\n        }\n      }\n    }\n\n    .fa {\n      color: $dark-text-color;\n    }\n  }\n\n  .status__content__spoiler-link {\n    background: $action-button-color;\n\n    &:hover {\n      background: lighten($action-button-color, 7%);\n      text-decoration: none;\n    }\n\n    &::-moz-focus-inner {\n      border: 0;\n    }\n\n    &::-moz-focus-inner,\n    &:focus,\n    &:active {\n      outline: 0 !important;\n    }\n  }\n\n  .status__content__text {\n    display: none;\n\n    &.status__content__text--visible {\n      display: block;\n    }\n  }\n}\n\n.status__content.status__content--collapsed {\n  max-height: 20px * 15; // 15 lines is roughly above 500 characters\n}\n\n.status__content__read-more-button {\n  display: block;\n  font-size: 15px;\n  line-height: 20px;\n  color: lighten($ui-highlight-color, 8%);\n  border: 0;\n  background: transparent;\n  padding: 0;\n  padding-top: 8px;\n\n  &:hover,\n  &:active {\n    text-decoration: underline;\n  }\n}\n\n.status__content__spoiler-link {\n  display: inline-block;\n  border-radius: 2px;\n  background: transparent;\n  border: 0;\n  color: $inverted-text-color;\n  font-weight: 700;\n  font-size: 11px;\n  padding: 0 6px;\n  text-transform: uppercase;\n  line-height: 20px;\n  cursor: pointer;\n  vertical-align: middle;\n}\n\n.status__wrapper--filtered {\n  color: $dark-text-color;\n  border: 0;\n  font-size: inherit;\n  text-align: center;\n  line-height: inherit;\n  margin: 0;\n  padding: 15px;\n  box-sizing: border-box;\n  width: 100%;\n  clear: both;\n  border-bottom: 1px solid lighten($ui-base-color, 8%);\n}\n\n.status__prepend-icon-wrapper {\n  left: -26px;\n  position: absolute;\n}\n\n.focusable {\n  &:focus {\n    outline: 0;\n    background: lighten($ui-base-color, 4%);\n\n    .status.status-direct {\n      background: lighten($ui-base-color, 12%);\n\n      &.muted {\n        background: transparent;\n      }\n    }\n\n    .detailed-status,\n    .detailed-status__action-bar {\n      background: lighten($ui-base-color, 8%);\n    }\n  }\n}\n\n.status {\n  padding: 8px 10px;\n  padding-left: 68px;\n  position: relative;\n  min-height: 54px;\n  border-bottom: 1px solid lighten($ui-base-color, 8%);\n  cursor: default;\n\n  @supports (-ms-overflow-style: -ms-autohiding-scrollbar) {\n    // Add margin to avoid Edge auto-hiding scrollbar appearing over content.\n    // On Edge 16 this is 16px and Edge <=15 it's 12px, so aim for 16px.\n    padding-right: 26px; // 10px + 16px\n  }\n\n  @keyframes fade {\n    0% { opacity: 0; }\n    100% { opacity: 1; }\n  }\n\n  opacity: 1;\n  animation: fade 150ms linear;\n\n  .video-player {\n    margin-top: 8px;\n  }\n\n  &.status-direct:not(.read) {\n    background: lighten($ui-base-color, 8%);\n    border-bottom-color: lighten($ui-base-color, 12%);\n  }\n\n  &.light {\n    .status__relative-time {\n      color: $light-text-color;\n    }\n\n    .status__display-name {\n      color: $inverted-text-color;\n    }\n\n    .display-name {\n      strong {\n        color: $inverted-text-color;\n      }\n\n      span {\n        color: $light-text-color;\n      }\n    }\n\n    .status__content {\n      color: $inverted-text-color;\n\n      a {\n        color: $highlight-text-color;\n      }\n\n      a.status__content__spoiler-link {\n        color: $primary-text-color;\n        background: $ui-primary-color;\n\n        &:hover {\n          background: lighten($ui-primary-color, 8%);\n        }\n      }\n    }\n  }\n}\n\n.notification-favourite {\n  .status.status-direct {\n    background: transparent;\n\n    .icon-button.disabled {\n      color: lighten($action-button-color, 13%);\n    }\n  }\n}\n\n.status__relative-time,\n.notification__relative_time {\n  color: $dark-text-color;\n  float: right;\n  font-size: 14px;\n}\n\n.status__display-name {\n  color: $dark-text-color;\n}\n\n.status__info .status__display-name {\n  display: block;\n  max-width: 100%;\n  padding-right: 25px;\n}\n\n.status__info {\n  font-size: 15px;\n}\n\n.status-check-box {\n  border-bottom: 1px solid $ui-secondary-color;\n  display: flex;\n\n  .status-check-box__status {\n    margin: 10px 0 10px 10px;\n    flex: 1;\n\n    .media-gallery {\n      max-width: 250px;\n    }\n\n    .status__content {\n      padding: 0;\n      white-space: normal;\n    }\n\n    .video-player {\n      margin-top: 8px;\n      max-width: 250px;\n    }\n\n    .media-gallery__item-thumbnail {\n      cursor: default;\n    }\n  }\n}\n\n.status-check-box-toggle {\n  align-items: center;\n  display: flex;\n  flex: 0 0 auto;\n  justify-content: center;\n  padding: 10px;\n}\n\n.status__prepend {\n  margin-left: 68px;\n  color: $dark-text-color;\n  padding: 8px 0;\n  padding-bottom: 2px;\n  font-size: 14px;\n  position: relative;\n\n  .status__display-name strong {\n    color: $dark-text-color;\n  }\n\n  > span {\n    display: block;\n    overflow: hidden;\n    text-overflow: ellipsis;\n  }\n}\n\n.status__action-bar {\n  align-items: center;\n  display: flex;\n  margin-top: 8px;\n\n  &__counter {\n    display: inline-flex;\n    margin-right: 11px;\n    align-items: center;\n\n    .status__action-bar-button {\n      margin-right: 4px;\n    }\n\n    &__label {\n      display: inline-block;\n      width: 14px;\n      font-size: 12px;\n      font-weight: 500;\n      color: $action-button-color;\n    }\n  }\n}\n\n.status__action-bar-button {\n  margin-right: 18px;\n}\n\n.status__action-bar-dropdown {\n  height: 23.15px;\n  width: 23.15px;\n}\n\n.detailed-status__action-bar-dropdown {\n  flex: 1 1 auto;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  position: relative;\n}\n\n.detailed-status {\n  background: lighten($ui-base-color, 4%);\n  padding: 14px 10px;\n\n  &--flex {\n    display: flex;\n    flex-wrap: wrap;\n    justify-content: space-between;\n    align-items: flex-start;\n\n    .status__content,\n    .detailed-status__meta {\n      flex: 100%;\n    }\n  }\n\n  .status__content {\n    font-size: 19px;\n    line-height: 24px;\n\n    .emojione {\n      width: 24px;\n      height: 24px;\n      margin: -1px 0 0;\n    }\n\n    .status__content__spoiler-link {\n      line-height: 24px;\n      margin: -1px 0 0;\n    }\n  }\n\n  .video-player {\n    margin-top: 8px;\n  }\n}\n\n.detailed-status__meta {\n  margin-top: 15px;\n  color: $dark-text-color;\n  font-size: 14px;\n  line-height: 18px;\n}\n\n.detailed-status__action-bar {\n  background: lighten($ui-base-color, 4%);\n  border-top: 1px solid lighten($ui-base-color, 8%);\n  border-bottom: 1px solid lighten($ui-base-color, 8%);\n  display: flex;\n  flex-direction: row;\n  padding: 10px 0;\n}\n\n.detailed-status__link {\n  color: inherit;\n  text-decoration: none;\n}\n\n.detailed-status__favorites,\n.detailed-status__reblogs {\n  display: inline-block;\n  font-weight: 500;\n  font-size: 12px;\n  margin-left: 6px;\n}\n\n.reply-indicator__content {\n  color: $inverted-text-color;\n  font-size: 14px;\n\n  a {\n    color: $lighter-text-color;\n  }\n}\n\n.domain {\n  padding: 10px;\n  border-bottom: 1px solid lighten($ui-base-color, 8%);\n\n  .domain__domain-name {\n    flex: 1 1 auto;\n    display: block;\n    color: $primary-text-color;\n    text-decoration: none;\n    font-size: 14px;\n    font-weight: 500;\n  }\n}\n\n.domain__wrapper {\n  display: flex;\n}\n\n.domain_buttons {\n  height: 18px;\n  padding: 10px;\n  white-space: nowrap;\n}\n\n.account {\n  padding: 10px;\n  border-bottom: 1px solid lighten($ui-base-color, 8%);\n\n  &.compact {\n    padding: 0;\n    border-bottom: 0;\n\n    .account__avatar-wrapper {\n      margin-left: 0;\n    }\n  }\n\n  .account__display-name {\n    flex: 1 1 auto;\n    display: block;\n    color: $darker-text-color;\n    overflow: hidden;\n    text-decoration: none;\n    font-size: 14px;\n  }\n}\n\n.account__wrapper {\n  display: flex;\n}\n\n.account__avatar-wrapper {\n  float: left;\n  margin-left: 12px;\n  margin-right: 12px;\n}\n\n.account__avatar {\n  @include avatar-radius;\n  position: relative;\n\n  &-inline {\n    display: inline-block;\n    vertical-align: middle;\n    margin-right: 5px;\n  }\n\n  &-composite {\n    @include avatar-radius;\n    overflow: hidden;\n\n    & > div {\n      @include avatar-radius;\n      float: left;\n      position: relative;\n      box-sizing: border-box;\n    }\n  }\n}\n\na .account__avatar {\n  cursor: pointer;\n}\n\n.account__avatar-overlay {\n  @include avatar-size(48px);\n\n  &-base {\n    @include avatar-radius;\n    @include avatar-size(36px);\n  }\n\n  &-overlay {\n    @include avatar-radius;\n    @include avatar-size(24px);\n\n    position: absolute;\n    bottom: 0;\n    right: 0;\n    z-index: 1;\n  }\n}\n\n.account__relationship {\n  height: 18px;\n  padding: 10px;\n  white-space: nowrap;\n}\n\n.account__disclaimer {\n  padding: 10px;\n  border-top: 1px solid lighten($ui-base-color, 8%);\n  color: $dark-text-color;\n\n  strong {\n    font-weight: 500;\n\n    @each $lang in $cjk-langs {\n      &:lang(#{$lang}) {\n        font-weight: 700;\n      }\n    }\n  }\n\n  a {\n    font-weight: 500;\n    color: inherit;\n    text-decoration: underline;\n\n    &:hover,\n    &:focus,\n    &:active {\n      text-decoration: none;\n    }\n  }\n}\n\n.account__action-bar {\n  border-top: 1px solid lighten($ui-base-color, 8%);\n  border-bottom: 1px solid lighten($ui-base-color, 8%);\n  line-height: 36px;\n  overflow: hidden;\n  flex: 0 0 auto;\n  display: flex;\n}\n\n.account__action-bar-dropdown {\n  padding: 10px;\n\n  .icon-button {\n    vertical-align: middle;\n  }\n\n  .dropdown--active {\n    .dropdown__content.dropdown__right {\n      left: 6px;\n      right: initial;\n    }\n\n    &::after {\n      bottom: initial;\n      margin-left: 11px;\n      margin-top: -7px;\n      right: initial;\n    }\n  }\n}\n\n.account__action-bar-links {\n  display: flex;\n  flex: 1 1 auto;\n  line-height: 18px;\n  text-align: center;\n}\n\n.account__action-bar__tab {\n  text-decoration: none;\n  overflow: hidden;\n  flex: 0 1 100%;\n  border-right: 1px solid lighten($ui-base-color, 8%);\n  padding: 10px 0;\n  border-bottom: 4px solid transparent;\n\n  &.active {\n    border-bottom: 4px solid $ui-highlight-color;\n  }\n\n  & > span {\n    display: block;\n    text-transform: uppercase;\n    font-size: 11px;\n    color: $darker-text-color;\n  }\n\n  strong {\n    display: block;\n    font-size: 15px;\n    font-weight: 500;\n    color: $primary-text-color;\n\n    @each $lang in $cjk-langs {\n      &:lang(#{$lang}) {\n        font-weight: 700;\n      }\n    }\n  }\n}\n\n.account-authorize {\n  padding: 14px 10px;\n\n  .detailed-status__display-name {\n    display: block;\n    margin-bottom: 15px;\n    overflow: hidden;\n  }\n}\n\n.account-authorize__avatar {\n  float: left;\n  margin-right: 10px;\n}\n\n.status__display-name,\n.status__relative-time,\n.detailed-status__display-name,\n.detailed-status__datetime,\n.detailed-status__application,\n.account__display-name {\n  text-decoration: none;\n}\n\n.status__display-name,\n.account__display-name {\n  strong {\n    color: $primary-text-color;\n  }\n}\n\n.muted {\n  .emojione {\n    opacity: 0.5;\n  }\n}\n\n.status__display-name,\n.reply-indicator__display-name,\n.detailed-status__display-name,\na.account__display-name {\n  &:hover strong {\n    text-decoration: underline;\n  }\n}\n\n.account__display-name strong {\n  display: block;\n  overflow: hidden;\n  text-overflow: ellipsis;\n}\n\n.detailed-status__application,\n.detailed-status__datetime {\n  color: inherit;\n}\n\n.detailed-status__display-name {\n  color: $secondary-text-color;\n  display: block;\n  line-height: 24px;\n  margin-bottom: 15px;\n  overflow: hidden;\n\n  strong,\n  span {\n    display: block;\n    text-overflow: ellipsis;\n    overflow: hidden;\n  }\n\n  strong {\n    font-size: 16px;\n    color: $primary-text-color;\n  }\n}\n\n.detailed-status__display-avatar {\n  float: left;\n  margin-right: 10px;\n}\n\n.status__avatar {\n  height: 48px;\n  left: 10px;\n  position: absolute;\n  top: 10px;\n  width: 48px;\n}\n\n.status__expand {\n  width: 68px;\n  position: absolute;\n  left: 0;\n  top: 0;\n  height: 100%;\n  cursor: pointer;\n}\n\n.muted {\n  .status__content p,\n  .status__content a {\n    color: $dark-text-color;\n  }\n\n  .status__display-name strong {\n    color: $dark-text-color;\n  }\n\n  .status__avatar {\n    opacity: 0.5;\n  }\n\n  a.status__content__spoiler-link {\n    background: $ui-base-lighter-color;\n    color: $inverted-text-color;\n\n    &:hover {\n      background: lighten($ui-base-lighter-color, 7%);\n      text-decoration: none;\n    }\n  }\n}\n\n.notification__message {\n  margin: 0 10px 0 68px;\n  padding: 8px 0 0;\n  cursor: default;\n  color: $darker-text-color;\n  font-size: 15px;\n  line-height: 22px;\n  position: relative;\n\n  .fa {\n    color: $highlight-text-color;\n  }\n\n  > span {\n    display: inline;\n    overflow: hidden;\n    text-overflow: ellipsis;\n  }\n}\n\n.notification__favourite-icon-wrapper {\n  left: -26px;\n  position: absolute;\n\n  .star-icon {\n    color: $gold-star;\n  }\n}\n\n.star-icon.active {\n  color: $gold-star;\n}\n\n.notification__display-name {\n  color: inherit;\n  font-weight: 500;\n  text-decoration: none;\n\n  &:hover {\n    color: $primary-text-color;\n    text-decoration: underline;\n  }\n}\n\n.notification__relative_time {\n  float: right;\n}\n\n.display-name {\n  display: block;\n  max-width: 100%;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n}\n\n.display-name__html {\n  font-weight: 500;\n}\n\n.display-name__account {\n  font-size: 14px;\n}\n\n.status__relative-time,\n.detailed-status__datetime {\n  &:hover {\n    text-decoration: underline;\n  }\n}\n\n.image-loader {\n  position: relative;\n  width: 100%;\n  height: 100%;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  flex-direction: column;\n\n  .image-loader__preview-canvas {\n    max-width: $media-modal-media-max-width;\n    max-height: $media-modal-media-max-height;\n    background: url('../images/void.png') repeat;\n    object-fit: contain;\n  }\n\n  .loading-bar {\n    position: relative;\n  }\n\n  &.image-loader--amorphous .image-loader__preview-canvas {\n    display: none;\n  }\n}\n\n.zoomable-image {\n  position: relative;\n  width: 100%;\n  height: 100%;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n\n  img {\n    max-width: $media-modal-media-max-width;\n    max-height: $media-modal-media-max-height;\n    width: auto;\n    height: auto;\n    object-fit: contain;\n  }\n}\n\n.navigation-bar {\n  padding: 10px;\n  display: flex;\n  align-items: center;\n  flex-shrink: 0;\n  cursor: default;\n  color: $darker-text-color;\n\n  strong {\n    color: $secondary-text-color;\n  }\n\n  a {\n    color: inherit;\n  }\n\n  .permalink {\n    text-decoration: none;\n  }\n\n  .navigation-bar__actions {\n    position: relative;\n\n    .icon-button.close {\n      position: absolute;\n      pointer-events: none;\n      transform: scale(0, 1) translate(-100%, 0);\n      opacity: 0;\n    }\n\n    .compose__action-bar .icon-button {\n      pointer-events: auto;\n      transform: scale(1, 1) translate(0, 0);\n      opacity: 1;\n    }\n  }\n}\n\n.navigation-bar__profile {\n  flex: 1 1 auto;\n  margin-left: 8px;\n  line-height: 20px;\n  margin-top: -1px;\n  overflow: hidden;\n}\n\n.navigation-bar__profile-account {\n  display: block;\n  font-weight: 500;\n  overflow: hidden;\n  text-overflow: ellipsis;\n}\n\n.navigation-bar__profile-edit {\n  color: inherit;\n  text-decoration: none;\n}\n\n.dropdown {\n  display: inline-block;\n}\n\n.dropdown__content {\n  display: none;\n  position: absolute;\n}\n\n.dropdown-menu__separator {\n  border-bottom: 1px solid darken($ui-secondary-color, 8%);\n  margin: 5px 7px 6px;\n  height: 0;\n}\n\n.dropdown-menu {\n  background: $ui-secondary-color;\n  padding: 4px 0;\n  border-radius: 4px;\n  box-shadow: 2px 4px 15px rgba($base-shadow-color, 0.4);\n  z-index: 9999;\n\n  ul {\n    list-style: none;\n  }\n\n  &.left {\n    transform-origin: 100% 50%;\n  }\n\n  &.top {\n    transform-origin: 50% 100%;\n  }\n\n  &.bottom {\n    transform-origin: 50% 0;\n  }\n\n  &.right {\n    transform-origin: 0 50%;\n  }\n}\n\n.dropdown-menu__arrow {\n  position: absolute;\n  width: 0;\n  height: 0;\n  border: 0 solid transparent;\n\n  &.left {\n    right: -5px;\n    margin-top: -5px;\n    border-width: 5px 0 5px 5px;\n    border-left-color: $ui-secondary-color;\n  }\n\n  &.top {\n    bottom: -5px;\n    margin-left: -7px;\n    border-width: 5px 7px 0;\n    border-top-color: $ui-secondary-color;\n  }\n\n  &.bottom {\n    top: -5px;\n    margin-left: -7px;\n    border-width: 0 7px 5px;\n    border-bottom-color: $ui-secondary-color;\n  }\n\n  &.right {\n    left: -5px;\n    margin-top: -5px;\n    border-width: 5px 5px 5px 0;\n    border-right-color: $ui-secondary-color;\n  }\n}\n\n.dropdown-menu__item {\n  a {\n    font-size: 13px;\n    line-height: 18px;\n    display: block;\n    padding: 4px 14px;\n    box-sizing: border-box;\n    text-decoration: none;\n    background: $ui-secondary-color;\n    color: $inverted-text-color;\n    overflow: hidden;\n    text-overflow: ellipsis;\n    white-space: nowrap;\n\n    &:focus,\n    &:hover,\n    &:active {\n      background: $ui-highlight-color;\n      color: $secondary-text-color;\n      outline: 0;\n    }\n  }\n}\n\n.dropdown--active .dropdown__content {\n  display: block;\n  line-height: 18px;\n  max-width: 311px;\n  right: 0;\n  text-align: left;\n  z-index: 9999;\n\n  & > ul {\n    list-style: none;\n    background: $ui-secondary-color;\n    padding: 4px 0;\n    border-radius: 4px;\n    box-shadow: 0 0 15px rgba($base-shadow-color, 0.4);\n    min-width: 140px;\n    position: relative;\n  }\n\n  &.dropdown__right {\n    right: 0;\n  }\n\n  &.dropdown__left {\n    & > ul {\n      left: -98px;\n    }\n  }\n\n  & > ul > li > a {\n    font-size: 13px;\n    line-height: 18px;\n    display: block;\n    padding: 4px 14px;\n    box-sizing: border-box;\n    text-decoration: none;\n    background: $ui-secondary-color;\n    color: $inverted-text-color;\n    overflow: hidden;\n    text-overflow: ellipsis;\n    white-space: nowrap;\n\n    &:focus {\n      outline: 0;\n    }\n\n    &:hover {\n      background: $ui-highlight-color;\n      color: $secondary-text-color;\n    }\n  }\n}\n\n.dropdown__icon {\n  vertical-align: middle;\n}\n\n.columns-area {\n  display: flex;\n  flex: 1 1 auto;\n  flex-direction: row;\n  justify-content: flex-start;\n  overflow-x: auto;\n  position: relative;\n\n  &.unscrollable {\n    overflow-x: hidden;\n  }\n\n  &__panels {\n    display: flex;\n    justify-content: center;\n    width: 100%;\n    height: 100%;\n\n    &__pane {\n      height: 100%;\n      overflow: hidden;\n      pointer-events: none;\n      display: flex;\n      justify-content: flex-end;\n\n      &--start {\n        justify-content: flex-start;\n      }\n\n      &__inner {\n        width: 285px;\n        pointer-events: auto;\n        height: 100%;\n      }\n    }\n\n    &__main {\n      box-sizing: border-box;\n      width: 100%;\n      max-width: 600px;\n      display: flex;\n      flex-direction: column;\n\n      @media screen and (min-width: $no-gap-breakpoint) {\n        padding: 0 10px;\n      }\n    }\n  }\n}\n\n.react-swipeable-view-container {\n  &,\n  .columns-area,\n  .drawer,\n  .column {\n    height: 100%;\n  }\n}\n\n.react-swipeable-view-container > * {\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  height: 100%;\n}\n\n.column {\n  width: 350px;\n  position: relative;\n  box-sizing: border-box;\n  display: flex;\n  flex-direction: column;\n\n  > .scrollable {\n    background: $ui-base-color;\n  }\n}\n\n.ui {\n  flex: 0 0 auto;\n  display: flex;\n  flex-direction: column;\n  width: 100%;\n  height: 100%;\n  background: darken($ui-base-color, 7%);\n}\n\n.drawer {\n  width: 300px;\n  box-sizing: border-box;\n  display: flex;\n  flex-direction: column;\n  overflow-y: hidden;\n}\n\n.drawer__tab {\n  display: block;\n  flex: 1 1 auto;\n  padding: 15px 5px 13px;\n  color: $darker-text-color;\n  text-decoration: none;\n  text-align: center;\n  font-size: 16px;\n  border-bottom: 2px solid transparent;\n}\n\n.column,\n.drawer {\n  flex: 1 1 100%;\n  overflow: hidden;\n}\n\n@media screen and (min-width: 631px) {\n  .columns-area {\n    padding: 0;\n  }\n\n  .column,\n  .drawer {\n    flex: 0 0 auto;\n    padding: 10px;\n    padding-left: 5px;\n    padding-right: 5px;\n\n    &:first-child {\n      padding-left: 10px;\n    }\n\n    &:last-child {\n      padding-right: 10px;\n    }\n  }\n\n  .columns-area > div {\n    .column,\n    .drawer {\n      padding-left: 5px;\n      padding-right: 5px;\n    }\n  }\n}\n\n.tabs-bar {\n  box-sizing: border-box;\n  display: flex;\n  background: lighten($ui-base-color, 8%);\n  flex: 0 0 auto;\n  overflow-y: auto;\n}\n\n.tabs-bar__link {\n  display: block;\n  flex: 1 1 auto;\n  padding: 15px 10px;\n  padding-bottom: 13px;\n  color: $primary-text-color;\n  text-decoration: none;\n  text-align: center;\n  font-size: 14px;\n  font-weight: 500;\n  border-bottom: 2px solid lighten($ui-base-color, 8%);\n  transition: all 50ms linear;\n  transition-property: border-bottom, background, color;\n\n  .fa {\n    font-weight: 400;\n    font-size: 16px;\n  }\n\n  &:hover,\n  &:focus,\n  &:active {\n    @media screen and (min-width: 631px) {\n      background: lighten($ui-base-color, 14%);\n      border-bottom-color: lighten($ui-base-color, 14%);\n    }\n  }\n\n  &.active {\n    border-bottom: 2px solid $highlight-text-color;\n    color: $highlight-text-color;\n  }\n\n  span {\n    margin-left: 5px;\n    display: none;\n  }\n}\n\n@media screen and (min-width: 600px) {\n  .tabs-bar__link {\n    span {\n      display: inline;\n    }\n  }\n}\n\n.columns-area--mobile {\n  flex-direction: column;\n  width: 100%;\n  height: 100%;\n  margin: 0 auto;\n\n  .column,\n  .drawer {\n    width: 100%;\n    height: 100%;\n    padding: 0;\n  }\n\n  .autosuggest-textarea__textarea {\n    font-size: 16px;\n  }\n\n  .search__input {\n    line-height: 18px;\n    font-size: 16px;\n    padding: 15px;\n    padding-right: 30px;\n  }\n\n  .search__icon .fa {\n    top: 15px;\n  }\n\n  @media screen and (min-width: $no-gap-breakpoint) {\n    padding: 10px 0;\n  }\n\n  @media screen and (min-width: 630px) {\n    .detailed-status {\n      padding: 15px;\n\n      .media-gallery,\n      .video-player {\n        margin-top: 15px;\n      }\n    }\n\n    .account__header__bar {\n      padding: 5px 10px;\n    }\n\n    .navigation-bar,\n    .compose-form {\n      padding: 15px;\n    }\n\n    .compose-form .compose-form__publish .compose-form__publish-button-wrapper {\n      padding-top: 15px;\n    }\n\n    .status {\n      padding: 15px 15px 15px (48px + 15px * 2);\n      min-height: 48px + 2px;\n\n      &__avatar {\n        left: 15px;\n        top: 17px;\n      }\n\n      &__content {\n        padding-top: 5px;\n      }\n\n      &__prepend {\n        margin-left: 48px + 15px * 2;\n        padding-top: 15px;\n      }\n\n      &__prepend-icon-wrapper {\n        left: -32px;\n      }\n\n      .media-gallery,\n      &__action-bar,\n      .video-player {\n        margin-top: 10px;\n      }\n    }\n\n    .account {\n      padding: 15px 10px;\n\n      &__header__bio {\n        margin: 0 -10px;\n      }\n    }\n\n    .notification {\n      &__message {\n        margin-left: 48px + 15px * 2;\n        padding-top: 15px;\n      }\n\n      &__favourite-icon-wrapper {\n        left: -32px;\n      }\n\n      .status {\n        padding-top: 8px;\n      }\n\n      .account {\n        padding-top: 8px;\n      }\n\n      .account__avatar-wrapper {\n        margin-left: 17px;\n        margin-right: 15px;\n      }\n    }\n  }\n}\n\n.floating-action-button {\n  position: fixed;\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  width: 3.9375rem;\n  height: 3.9375rem;\n  bottom: 1.3125rem;\n  right: 1.3125rem;\n  background: darken($ui-highlight-color, 3%);\n  color: $white;\n  border-radius: 50%;\n  font-size: 21px;\n  line-height: 21px;\n  text-decoration: none;\n  box-shadow: 2px 3px 9px rgba($base-shadow-color, 0.4);\n\n  &:hover,\n  &:focus,\n  &:active {\n    background: lighten($ui-highlight-color, 7%);\n  }\n}\n\n@media screen and (min-width: $no-gap-breakpoint) {\n  .tabs-bar {\n    margin: 10px auto;\n    margin-bottom: 0;\n    width: 100%;\n  }\n\n  .react-swipeable-view-container .columns-area--mobile {\n    height: calc(100% - 20px) !important;\n  }\n\n  .getting-started__wrapper,\n  .getting-started__trends,\n  .search {\n    margin-bottom: 10px;\n  }\n}\n\n@media screen and (max-width: 600px + (285px * 1) + (10px * 1)) {\n  .columns-area__panels__pane--compositional {\n    display: none;\n  }\n}\n\n@media screen and (min-width: 600px + (285px * 1) + (10px * 1)) {\n  .floating-action-button,\n  .tabs-bar__link.optional {\n    display: none;\n  }\n\n  .search-page .search {\n    display: none;\n  }\n}\n\n@media screen and (max-width: 600px + (285px * 2) + (10px * 2)) {\n  .columns-area__panels__pane--navigational {\n    display: none;\n  }\n}\n\n@media screen and (min-width: 600px + (285px * 2) + (10px * 2)) {\n  .tabs-bar {\n    display: none;\n  }\n}\n\n.icon-with-badge {\n  position: relative;\n\n  &__badge {\n    position: absolute;\n    left: 9px;\n    top: -13px;\n    background: $ui-highlight-color;\n    border: 2px solid lighten($ui-base-color, 8%);\n    padding: 1px 6px;\n    border-radius: 6px;\n    font-size: 10px;\n    font-weight: 500;\n    line-height: 14px;\n    color: $primary-text-color;\n  }\n}\n\n.column-link--transparent .icon-with-badge__badge {\n  border-color: darken($ui-base-color, 8%);\n}\n\n.compose-panel {\n  width: 285px;\n  margin-top: 10px;\n  display: flex;\n  flex-direction: column;\n  height: calc(100% - 10px);\n  overflow-y: hidden;\n\n  .navigation-bar {\n    padding-top: 20px;\n    padding-bottom: 20px;\n    flex: 0 1 48px;\n    min-height: 20px;\n  }\n\n  .flex-spacer {\n    background: transparent;\n  }\n\n  .compose-form {\n    flex: 1;\n    overflow-y: hidden;\n    display: flex;\n    flex-direction: column;\n    min-height: 310px;\n    padding-bottom: 71px;\n    margin-bottom: -71px;\n  }\n\n  .compose-form__autosuggest-wrapper {\n    overflow-y: auto;\n    background-color: $white;\n    border-radius: 4px 4px 0 0;\n    flex: 0 1 auto;\n  }\n\n  .autosuggest-textarea__textarea {\n    overflow-y: hidden;\n  }\n\n  .compose-form__upload-thumbnail {\n    height: 80px;\n  }\n}\n\n.navigation-panel {\n  margin-top: 10px;\n  margin-bottom: 10px;\n  height: calc(100% - 20px);\n  overflow-y: auto;\n\n  hr {\n    border: 0;\n    background: transparent;\n    border-top: 1px solid lighten($ui-base-color, 4%);\n    margin: 10px 0;\n  }\n}\n\n.drawer__pager {\n  box-sizing: border-box;\n  padding: 0;\n  flex-grow: 1;\n  position: relative;\n  overflow: hidden;\n  display: flex;\n}\n\n.drawer__inner {\n  position: absolute;\n  top: 0;\n  left: 0;\n  background: lighten($ui-base-color, 13%);\n  box-sizing: border-box;\n  padding: 0;\n  display: flex;\n  flex-direction: column;\n  overflow: hidden;\n  overflow-y: auto;\n  width: 100%;\n  height: 100%;\n\n  &.darker {\n    background: $ui-base-color;\n  }\n}\n\n.drawer__inner__mastodon {\n  background: lighten($ui-base-color, 13%) url('data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 234.80078 31.757813\" width=\"234.80078\" height=\"31.757812\"><path d=\"M19.599609 0c-1.05 0-2.10039.375-2.90039 1.125L0 16.925781v14.832031h234.80078V17.025391l-16.5-15.900391c-1.6-1.5-4.20078-1.5-5.80078 0l-13.80078 13.099609c-1.6 1.5-4.19883 1.5-5.79883 0L179.09961 1.125c-1.6-1.5-4.19883-1.5-5.79883 0L159.5 14.224609c-1.6 1.5-4.20078 1.5-5.80078 0L139.90039 1.125c-1.6-1.5-4.20078-1.5-5.80078 0l-13.79883 13.099609c-1.6 1.5-4.20078 1.5-5.80078 0L100.69922 1.125c-1.600001-1.5-4.198829-1.5-5.798829 0l-13.59961 13.099609c-1.6 1.5-4.200781 1.5-5.800781 0L61.699219 1.125c-1.6-1.5-4.198828-1.5-5.798828 0L42.099609 14.224609c-1.6 1.5-4.198828 1.5-5.798828 0L22.5 1.125C21.7.375 20.649609 0 19.599609 0z\" fill=\"#{hex-color($ui-base-color)}\"/></svg>') no-repeat bottom / 100% auto;\n  flex: 1;\n  min-height: 47px;\n  display: none;\n\n  > img {\n    display: block;\n    object-fit: contain;\n    object-position: bottom left;\n    width: 100%;\n    height: 100%;\n    pointer-events: none;\n    user-drag: none;\n    user-select: none;\n  }\n\n  @media screen and (min-height: 640px) {\n    display: block;\n  }\n}\n\n.pseudo-drawer {\n  background: lighten($ui-base-color, 13%);\n  font-size: 13px;\n  text-align: left;\n}\n\n.drawer__header {\n  flex: 0 0 auto;\n  font-size: 16px;\n  background: lighten($ui-base-color, 8%);\n  margin-bottom: 10px;\n  display: flex;\n  flex-direction: row;\n\n  a {\n    transition: background 100ms ease-in;\n\n    &:hover {\n      background: lighten($ui-base-color, 3%);\n      transition: background 200ms ease-out;\n    }\n  }\n}\n\n.scrollable {\n  overflow-y: scroll;\n  overflow-x: hidden;\n  flex: 1 1 auto;\n  -webkit-overflow-scrolling: touch;\n  will-change: transform; // improves perf in mobile Chrome\n\n  &.optionally-scrollable {\n    overflow-y: auto;\n  }\n\n  @supports(display: grid) { // hack to fix Chrome <57\n    contain: strict;\n  }\n\n  &--flex {\n    display: flex;\n    flex-direction: column;\n  }\n\n  &__append {\n    flex: 1 1 auto;\n    position: relative;\n    min-height: 120px;\n  }\n}\n\n.scrollable.fullscreen {\n  @supports(display: grid) { // hack to fix Chrome <57\n    contain: none;\n  }\n}\n\n.column-back-button {\n  background: lighten($ui-base-color, 4%);\n  color: $highlight-text-color;\n  cursor: pointer;\n  flex: 0 0 auto;\n  font-size: 16px;\n  line-height: inherit;\n  border: 0;\n  text-align: unset;\n  padding: 15px;\n  margin: 0;\n  z-index: 3;\n  outline: 0;\n\n  &:hover {\n    text-decoration: underline;\n  }\n}\n\n.column-header__back-button {\n  background: lighten($ui-base-color, 4%);\n  border: 0;\n  font-family: inherit;\n  color: $highlight-text-color;\n  cursor: pointer;\n  white-space: nowrap;\n  font-size: 16px;\n  padding: 0 5px 0 0;\n  z-index: 3;\n\n  &:hover {\n    text-decoration: underline;\n  }\n\n  &:last-child {\n    padding: 0 15px 0 0;\n  }\n}\n\n.column-back-button__icon {\n  display: inline-block;\n  margin-right: 5px;\n}\n\n.column-back-button--slim {\n  position: relative;\n}\n\n.column-back-button--slim-button {\n  cursor: pointer;\n  flex: 0 0 auto;\n  font-size: 16px;\n  padding: 15px;\n  position: absolute;\n  right: 0;\n  top: -48px;\n}\n\n.react-toggle {\n  display: inline-block;\n  position: relative;\n  cursor: pointer;\n  background-color: transparent;\n  border: 0;\n  padding: 0;\n  user-select: none;\n  -webkit-tap-highlight-color: rgba($base-overlay-background, 0);\n  -webkit-tap-highlight-color: transparent;\n}\n\n.react-toggle-screenreader-only {\n  border: 0;\n  clip: rect(0 0 0 0);\n  height: 1px;\n  margin: -1px;\n  overflow: hidden;\n  padding: 0;\n  position: absolute;\n  width: 1px;\n}\n\n.react-toggle--disabled {\n  cursor: not-allowed;\n  opacity: 0.5;\n  transition: opacity 0.25s;\n}\n\n.react-toggle-track {\n  width: 50px;\n  height: 24px;\n  padding: 0;\n  border-radius: 30px;\n  background-color: $ui-base-color;\n  transition: background-color 0.2s ease;\n}\n\n.react-toggle:hover:not(.react-toggle--disabled) .react-toggle-track {\n  background-color: darken($ui-base-color, 10%);\n}\n\n.react-toggle--checked .react-toggle-track {\n  background-color: $ui-highlight-color;\n}\n\n.react-toggle--checked:hover:not(.react-toggle--disabled) .react-toggle-track {\n  background-color: lighten($ui-highlight-color, 10%);\n}\n\n.react-toggle-track-check {\n  position: absolute;\n  width: 14px;\n  height: 10px;\n  top: 0;\n  bottom: 0;\n  margin-top: auto;\n  margin-bottom: auto;\n  line-height: 0;\n  left: 8px;\n  opacity: 0;\n  transition: opacity 0.25s ease;\n}\n\n.react-toggle--checked .react-toggle-track-check {\n  opacity: 1;\n  transition: opacity 0.25s ease;\n}\n\n.react-toggle-track-x {\n  position: absolute;\n  width: 10px;\n  height: 10px;\n  top: 0;\n  bottom: 0;\n  margin-top: auto;\n  margin-bottom: auto;\n  line-height: 0;\n  right: 10px;\n  opacity: 1;\n  transition: opacity 0.25s ease;\n}\n\n.react-toggle--checked .react-toggle-track-x {\n  opacity: 0;\n}\n\n.react-toggle-thumb {\n  position: absolute;\n  top: 1px;\n  left: 1px;\n  width: 22px;\n  height: 22px;\n  border: 1px solid $ui-base-color;\n  border-radius: 50%;\n  background-color: darken($simple-background-color, 2%);\n  box-sizing: border-box;\n  transition: all 0.25s ease;\n  transition-property: border-color, left;\n}\n\n.react-toggle--checked .react-toggle-thumb {\n  left: 27px;\n  border-color: $ui-highlight-color;\n}\n\n.column-link {\n  background: lighten($ui-base-color, 8%);\n  color: $primary-text-color;\n  display: block;\n  font-size: 16px;\n  padding: 15px;\n  text-decoration: none;\n\n  &:hover,\n  &:focus,\n  &:active {\n    background: lighten($ui-base-color, 11%);\n  }\n\n  &:focus {\n    outline: 0;\n  }\n\n  &--transparent {\n    background: transparent;\n    color: $ui-secondary-color;\n\n    &:hover,\n    &:focus,\n    &:active {\n      background: transparent;\n      color: $primary-text-color;\n    }\n\n    &.active {\n      color: $ui-highlight-color;\n    }\n  }\n}\n\n.column-link__icon {\n  display: inline-block;\n  margin-right: 5px;\n}\n\n.column-link__badge {\n  display: inline-block;\n  border-radius: 4px;\n  font-size: 12px;\n  line-height: 19px;\n  font-weight: 500;\n  background: $ui-base-color;\n  padding: 4px 8px;\n  margin: -6px 10px;\n}\n\n.column-subheading {\n  background: $ui-base-color;\n  color: $dark-text-color;\n  padding: 8px 20px;\n  font-size: 12px;\n  font-weight: 500;\n  text-transform: uppercase;\n  cursor: default;\n}\n\n.getting-started__wrapper,\n.getting-started,\n.flex-spacer {\n  background: $ui-base-color;\n}\n\n.getting-started__wrapper {\n  flex: 0 0 auto;\n}\n\n.flex-spacer {\n  flex: 1 1 auto;\n}\n\n.getting-started {\n  color: $dark-text-color;\n  overflow: auto;\n\n  &__footer {\n    flex: 0 0 auto;\n    padding: 10px;\n    padding-top: 20px;\n\n    ul {\n      margin-bottom: 10px;\n    }\n\n    ul li {\n      display: inline;\n    }\n\n    p {\n      color: $dark-text-color;\n      font-size: 13px;\n      margin-bottom: 20px;\n\n      a {\n        color: $dark-text-color;\n        text-decoration: underline;\n      }\n    }\n\n    a {\n      text-decoration: none;\n      color: $darker-text-color;\n\n      &:hover,\n      &:focus,\n      &:active {\n        text-decoration: underline;\n      }\n    }\n  }\n\n  &__trends {\n    background: $ui-base-color;\n    flex: 0 1 auto;\n\n    @media screen and (max-height: 810px) {\n      .trends__item:nth-child(3) {\n        display: none;\n      }\n    }\n\n    @media screen and (max-height: 720px) {\n      .trends__item:nth-child(2) {\n        display: none;\n      }\n    }\n\n    @media screen and (max-height: 670px) {\n      display: none;\n    }\n  }\n\n  &__scrollable {\n    max-height: 100%;\n    overflow-y: auto;\n  }\n}\n\n.keyboard-shortcuts {\n  padding: 8px 0 0;\n  overflow: hidden;\n\n  thead {\n    position: absolute;\n    left: -9999px;\n  }\n\n  td {\n    padding: 0 10px 8px;\n  }\n\n  kbd {\n    display: inline-block;\n    padding: 3px 5px;\n    background-color: lighten($ui-base-color, 8%);\n    border: 1px solid darken($ui-base-color, 4%);\n  }\n}\n\n.setting-text {\n  display: block;\n  box-sizing: border-box;\n  width: 100%;\n  margin: 0;\n  color: $inverted-text-color;\n  background: $simple-background-color;\n  padding: 10px;\n  font-family: inherit;\n  font-size: 14px;\n  resize: vertical;\n  border: 0;\n  outline: 0;\n  border-radius: 4px;\n\n  &:focus {\n    outline: 0;\n  }\n\n  @media screen and (max-width: 600px) {\n    font-size: 16px;\n  }\n}\n\n.no-reduce-motion button.icon-button i.fa-retweet {\n  background-position: 0 0;\n  height: 19px;\n  transition: background-position 0.9s steps(10);\n  transition-duration: 0s;\n  vertical-align: middle;\n  width: 22px;\n\n  &::before {\n    display: none !important;\n  }\n\n}\n\n.no-reduce-motion button.icon-button.active i.fa-retweet {\n  transition-duration: 0.9s;\n  background-position: 0 100%;\n}\n\n.reduce-motion button.icon-button i.fa-retweet {\n  color: $action-button-color;\n  transition: color 100ms ease-in;\n}\n\n.reduce-motion button.icon-button.active i.fa-retweet {\n  color: $highlight-text-color;\n}\n\n.status-card {\n  display: flex;\n  font-size: 14px;\n  border: 1px solid lighten($ui-base-color, 8%);\n  border-radius: 4px;\n  color: $dark-text-color;\n  margin-top: 14px;\n  text-decoration: none;\n  overflow: hidden;\n\n  &__actions {\n    bottom: 0;\n    left: 0;\n    position: absolute;\n    right: 0;\n    top: 0;\n    display: flex;\n    justify-content: center;\n    align-items: center;\n\n    & > div {\n      background: rgba($base-shadow-color, 0.6);\n      border-radius: 8px;\n      padding: 12px 9px;\n      flex: 0 0 auto;\n      display: flex;\n      justify-content: center;\n      align-items: center;\n    }\n\n    button,\n    a {\n      display: inline;\n      color: $secondary-text-color;\n      background: transparent;\n      border: 0;\n      padding: 0 8px;\n      text-decoration: none;\n      font-size: 18px;\n      line-height: 18px;\n\n      &:hover,\n      &:active,\n      &:focus {\n        color: $primary-text-color;\n      }\n    }\n\n    a {\n      font-size: 19px;\n      position: relative;\n      bottom: -1px;\n    }\n  }\n}\n\na.status-card {\n  cursor: pointer;\n\n  &:hover {\n    background: lighten($ui-base-color, 8%);\n  }\n}\n\n.status-card-photo {\n  cursor: zoom-in;\n  display: block;\n  text-decoration: none;\n  width: 100%;\n  height: auto;\n  margin: 0;\n}\n\n.status-card-video {\n  iframe {\n    width: 100%;\n    height: 100%;\n  }\n}\n\n.status-card__title {\n  display: block;\n  font-weight: 500;\n  margin-bottom: 5px;\n  color: $darker-text-color;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n  text-decoration: none;\n}\n\n.status-card__content {\n  flex: 1 1 auto;\n  overflow: hidden;\n  padding: 14px 14px 14px 8px;\n}\n\n.status-card__description {\n  color: $darker-text-color;\n}\n\n.status-card__host {\n  display: block;\n  margin-top: 5px;\n  font-size: 13px;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n}\n\n.status-card__image {\n  flex: 0 0 100px;\n  background: lighten($ui-base-color, 8%);\n  position: relative;\n\n  & > .fa {\n    font-size: 21px;\n    position: absolute;\n    transform-origin: 50% 50%;\n    top: 50%;\n    left: 50%;\n    transform: translate(-50%, -50%);\n  }\n}\n\n.status-card.horizontal {\n  display: block;\n\n  .status-card__image {\n    width: 100%;\n  }\n\n  .status-card__image-image {\n    border-radius: 4px 4px 0 0;\n  }\n\n  .status-card__title {\n    white-space: inherit;\n  }\n}\n\n.status-card.compact {\n  border-color: lighten($ui-base-color, 4%);\n\n  &.interactive {\n    border: 0;\n  }\n\n  .status-card__content {\n    padding: 8px;\n    padding-top: 10px;\n  }\n\n  .status-card__title {\n    white-space: nowrap;\n  }\n\n  .status-card__image {\n    flex: 0 0 60px;\n  }\n}\n\na.status-card.compact:hover {\n  background-color: lighten($ui-base-color, 4%);\n}\n\n.status-card__image-image {\n  border-radius: 4px 0 0 4px;\n  display: block;\n  margin: 0;\n  width: 100%;\n  height: 100%;\n  object-fit: cover;\n  background-size: cover;\n  background-position: center center;\n}\n\n.load-more {\n  display: block;\n  color: $dark-text-color;\n  background-color: transparent;\n  border: 0;\n  font-size: inherit;\n  text-align: center;\n  line-height: inherit;\n  margin: 0;\n  padding: 15px;\n  box-sizing: border-box;\n  width: 100%;\n  clear: both;\n  text-decoration: none;\n\n  &:hover {\n    background: lighten($ui-base-color, 2%);\n  }\n}\n\n.load-gap {\n  border-bottom: 1px solid lighten($ui-base-color, 8%);\n}\n\n.regeneration-indicator {\n  text-align: center;\n  font-size: 16px;\n  font-weight: 500;\n  color: $dark-text-color;\n  background: $ui-base-color;\n  cursor: default;\n  display: flex;\n  flex: 1 1 auto;\n  align-items: center;\n  justify-content: center;\n  padding: 20px;\n\n  & > div {\n    width: 100%;\n    background: transparent;\n    padding-top: 0;\n  }\n\n  &__figure {\n    background: url('../images/elephant_ui_working.svg') no-repeat center 0;\n    width: 100%;\n    height: 160px;\n    background-size: contain;\n    position: absolute;\n    top: 50%;\n    left: 50%;\n    transform: translate(-50%, -50%);\n  }\n\n  &.missing-indicator {\n    padding-top: 20px + 48px;\n\n    .regeneration-indicator__figure {\n      background-image: url('../images/elephant_ui_disappointed.svg');\n    }\n  }\n\n  &__label {\n    margin-top: 200px;\n\n    strong {\n      display: block;\n      margin-bottom: 10px;\n      color: $dark-text-color;\n    }\n\n    span {\n      font-size: 15px;\n      font-weight: 400;\n    }\n  }\n}\n\n.column-header__wrapper {\n  position: relative;\n  flex: 0 0 auto;\n\n  &.active {\n    &::before {\n      display: block;\n      content: \"\";\n      position: absolute;\n      top: 35px;\n      left: 0;\n      right: 0;\n      margin: 0 auto;\n      width: 60%;\n      pointer-events: none;\n      height: 28px;\n      z-index: 1;\n      background: radial-gradient(ellipse, rgba($ui-highlight-color, 0.23) 0%, rgba($ui-highlight-color, 0) 60%);\n    }\n  }\n}\n\n.column-header {\n  display: flex;\n  font-size: 16px;\n  background: lighten($ui-base-color, 4%);\n  flex: 0 0 auto;\n  cursor: pointer;\n  position: relative;\n  z-index: 2;\n  outline: 0;\n  overflow: hidden;\n\n  & > button {\n    margin: 0;\n    border: 0;\n    padding: 15px 0 15px 15px;\n    color: inherit;\n    background: transparent;\n    font: inherit;\n    text-align: left;\n    text-overflow: ellipsis;\n    overflow: hidden;\n    white-space: nowrap;\n    flex: 1;\n  }\n\n  & > .column-header__back-button {\n    color: $highlight-text-color;\n  }\n\n  &.active {\n    box-shadow: 0 1px 0 rgba($highlight-text-color, 0.3);\n\n    .column-header__icon {\n      color: $highlight-text-color;\n      text-shadow: 0 0 10px rgba($highlight-text-color, 0.4);\n    }\n  }\n\n  &:focus,\n  &:active {\n    outline: 0;\n  }\n}\n\n.column-header__buttons {\n  height: 48px;\n  display: flex;\n}\n\n.column-header__links {\n  margin-bottom: 14px;\n}\n\n.column-header__links .text-btn {\n  margin-right: 10px;\n}\n\n.column-header__button {\n  background: lighten($ui-base-color, 4%);\n  border: 0;\n  color: $darker-text-color;\n  cursor: pointer;\n  font-size: 16px;\n  padding: 0 15px;\n\n  &:hover {\n    color: lighten($darker-text-color, 7%);\n  }\n\n  &.active {\n    color: $primary-text-color;\n    background: lighten($ui-base-color, 8%);\n\n    &:hover {\n      color: $primary-text-color;\n      background: lighten($ui-base-color, 8%);\n    }\n  }\n}\n\n.column-header__collapsible {\n  max-height: 70vh;\n  overflow: hidden;\n  overflow-y: auto;\n  color: $darker-text-color;\n  transition: max-height 150ms ease-in-out, opacity 300ms linear;\n  opacity: 1;\n\n  &.collapsed {\n    max-height: 0;\n    opacity: 0.5;\n  }\n\n  &.animating {\n    overflow-y: hidden;\n  }\n\n  hr {\n    height: 0;\n    background: transparent;\n    border: 0;\n    border-top: 1px solid lighten($ui-base-color, 12%);\n    margin: 10px 0;\n  }\n}\n\n.column-header__collapsible-inner {\n  background: lighten($ui-base-color, 8%);\n  padding: 15px;\n}\n\n.column-header__setting-btn {\n  &:hover {\n    color: $darker-text-color;\n    text-decoration: underline;\n  }\n}\n\n.column-header__setting-arrows {\n  float: right;\n\n  .column-header__setting-btn {\n    padding: 0 10px;\n\n    &:last-child {\n      padding-right: 0;\n    }\n  }\n}\n\n.text-btn {\n  display: inline-block;\n  padding: 0;\n  font-family: inherit;\n  font-size: inherit;\n  color: inherit;\n  border: 0;\n  background: transparent;\n  cursor: pointer;\n}\n\n.column-header__icon {\n  display: inline-block;\n  margin-right: 5px;\n}\n\n.loading-indicator {\n  color: $dark-text-color;\n  font-size: 12px;\n  font-weight: 400;\n  text-transform: uppercase;\n  overflow: visible;\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  transform: translate(-50%, -50%);\n\n  span {\n    display: block;\n    float: left;\n    margin-left: 50%;\n    transform: translateX(-50%);\n    margin: 82px 0 0 50%;\n    white-space: nowrap;\n  }\n}\n\n.loading-indicator__figure {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  transform: translate(-50%, -50%);\n  width: 42px;\n  height: 42px;\n  box-sizing: border-box;\n  background-color: transparent;\n  border: 0 solid lighten($ui-base-color, 26%);\n  border-width: 6px;\n  border-radius: 50%;\n}\n\n.no-reduce-motion .loading-indicator span {\n  animation: loader-label 1.15s infinite cubic-bezier(0.215, 0.61, 0.355, 1);\n}\n\n.no-reduce-motion .loading-indicator__figure {\n  animation: loader-figure 1.15s infinite cubic-bezier(0.215, 0.61, 0.355, 1);\n}\n\n@keyframes loader-figure {\n  0% {\n    width: 0;\n    height: 0;\n    background-color: lighten($ui-base-color, 26%);\n  }\n\n  29% {\n    background-color: lighten($ui-base-color, 26%);\n  }\n\n  30% {\n    width: 42px;\n    height: 42px;\n    background-color: transparent;\n    border-width: 21px;\n    opacity: 1;\n  }\n\n  100% {\n    width: 42px;\n    height: 42px;\n    border-width: 0;\n    opacity: 0;\n    background-color: transparent;\n  }\n}\n\n@keyframes loader-label {\n  0% { opacity: 0.25; }\n  30% { opacity: 1; }\n  100% { opacity: 0.25; }\n}\n\n.video-error-cover {\n  align-items: center;\n  background: $base-overlay-background;\n  color: $primary-text-color;\n  cursor: pointer;\n  display: flex;\n  flex-direction: column;\n  height: 100%;\n  justify-content: center;\n  margin-top: 8px;\n  position: relative;\n  text-align: center;\n  z-index: 100;\n}\n\n.media-spoiler {\n  background: $base-overlay-background;\n  color: $darker-text-color;\n  border: 0;\n  padding: 0;\n  width: 100%;\n  height: 100%;\n  border-radius: 4px;\n  appearance: none;\n\n  &:hover,\n  &:active,\n  &:focus {\n    padding: 0;\n    color: lighten($darker-text-color, 8%);\n  }\n}\n\n.media-spoiler__warning {\n  display: block;\n  font-size: 14px;\n}\n\n.media-spoiler__trigger {\n  display: block;\n  font-size: 11px;\n  font-weight: 700;\n}\n\n.spoiler-button {\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  position: absolute;\n  z-index: 100;\n\n  &--minified {\n    display: block;\n    left: 4px;\n    top: 4px;\n    width: auto;\n    height: auto;\n  }\n\n  &--hidden {\n    display: none;\n  }\n\n  &__overlay {\n    display: block;\n    background: transparent;\n    width: 100%;\n    height: 100%;\n    border: 0;\n\n    &__label {\n      display: inline-block;\n      background: rgba($base-overlay-background, 0.5);\n      border-radius: 8px;\n      padding: 8px 12px;\n      color: $primary-text-color;\n      font-weight: 500;\n      font-size: 14px;\n    }\n\n    &:hover,\n    &:focus,\n    &:active {\n      .spoiler-button__overlay__label {\n        background: rgba($base-overlay-background, 0.8);\n      }\n    }\n  }\n}\n\n.modal-container--preloader {\n  background: lighten($ui-base-color, 8%);\n}\n\n.account--panel {\n  background: lighten($ui-base-color, 4%);\n  border-top: 1px solid lighten($ui-base-color, 8%);\n  border-bottom: 1px solid lighten($ui-base-color, 8%);\n  display: flex;\n  flex-direction: row;\n  padding: 10px 0;\n}\n\n.account--panel__button,\n.detailed-status__button {\n  flex: 1 1 auto;\n  text-align: center;\n}\n\n.column-settings__outer {\n  background: lighten($ui-base-color, 8%);\n  padding: 15px;\n}\n\n.column-settings__section {\n  color: $darker-text-color;\n  cursor: default;\n  display: block;\n  font-weight: 500;\n  margin-bottom: 10px;\n}\n\n.column-settings__hashtags {\n  .column-settings__row {\n    margin-bottom: 15px;\n  }\n\n  .column-select {\n    &__control {\n      @include search-input;\n    }\n\n    &__placeholder {\n      color: $dark-text-color;\n      padding-left: 2px;\n      font-size: 12px;\n    }\n\n    &__value-container {\n      padding-left: 6px;\n    }\n\n    &__multi-value {\n      background: lighten($ui-base-color, 8%);\n\n      &__remove {\n        cursor: pointer;\n\n        &:hover,\n        &:active,\n        &:focus {\n          background: lighten($ui-base-color, 12%);\n          color: lighten($darker-text-color, 4%);\n        }\n      }\n    }\n\n    &__multi-value__label,\n    &__input {\n      color: $darker-text-color;\n    }\n\n    &__clear-indicator,\n    &__dropdown-indicator {\n      cursor: pointer;\n      transition: none;\n      color: $dark-text-color;\n\n      &:hover,\n      &:active,\n      &:focus {\n        color: lighten($dark-text-color, 4%);\n      }\n    }\n\n    &__indicator-separator {\n      background-color: lighten($ui-base-color, 8%);\n    }\n\n    &__menu {\n      @include search-popout;\n      padding: 0;\n      background: $ui-secondary-color;\n    }\n\n    &__menu-list {\n      padding: 6px;\n    }\n\n    &__option {\n      color: $inverted-text-color;\n      border-radius: 4px;\n      font-size: 14px;\n\n      &--is-focused,\n      &--is-selected {\n        background: darken($ui-secondary-color, 10%);\n      }\n    }\n  }\n}\n\n.column-settings__row {\n  .text-btn {\n    margin-bottom: 15px;\n  }\n}\n\n.relationship-tag {\n  color: $primary-text-color;\n  margin-bottom: 4px;\n  display: block;\n  vertical-align: top;\n  background-color: $base-overlay-background;\n  text-transform: uppercase;\n  font-size: 11px;\n  font-weight: 500;\n  padding: 4px;\n  border-radius: 4px;\n  opacity: 0.7;\n\n  &:hover {\n    opacity: 1;\n  }\n}\n\n.setting-toggle {\n  display: block;\n  line-height: 24px;\n}\n\n.setting-toggle__label {\n  color: $darker-text-color;\n  display: inline-block;\n  margin-bottom: 14px;\n  margin-left: 8px;\n  vertical-align: middle;\n}\n\n.empty-column-indicator,\n.error-column {\n  color: $dark-text-color;\n  background: $ui-base-color;\n  text-align: center;\n  padding: 20px;\n  font-size: 15px;\n  font-weight: 400;\n  cursor: default;\n  display: flex;\n  flex: 1 1 auto;\n  align-items: center;\n  justify-content: center;\n\n  @supports(display: grid) { // hack to fix Chrome <57\n    contain: strict;\n  }\n\n  & > span {\n    max-width: 400px;\n  }\n\n  a {\n    color: $highlight-text-color;\n    text-decoration: none;\n\n    &:hover {\n      text-decoration: underline;\n    }\n  }\n}\n\n.error-column {\n  flex-direction: column;\n}\n\n@keyframes heartbeat {\n  from {\n    transform: scale(1);\n    animation-timing-function: ease-out;\n  }\n\n  10% {\n    transform: scale(0.91);\n    animation-timing-function: ease-in;\n  }\n\n  17% {\n    transform: scale(0.98);\n    animation-timing-function: ease-out;\n  }\n\n  33% {\n    transform: scale(0.87);\n    animation-timing-function: ease-in;\n  }\n\n  45% {\n    transform: scale(1);\n    animation-timing-function: ease-out;\n  }\n}\n\n.no-reduce-motion .pulse-loading {\n  transform-origin: center center;\n  animation: heartbeat 1.5s ease-in-out infinite both;\n}\n\n@keyframes shake-bottom {\n  0%,\n  100% {\n    transform: rotate(0deg);\n    transform-origin: 50% 100%;\n  }\n\n  10% {\n    transform: rotate(2deg);\n  }\n\n  20%,\n  40%,\n  60% {\n    transform: rotate(-4deg);\n  }\n\n  30%,\n  50%,\n  70% {\n    transform: rotate(4deg);\n  }\n\n  80% {\n    transform: rotate(-2deg);\n  }\n\n  90% {\n    transform: rotate(2deg);\n  }\n}\n\n.no-reduce-motion .shake-bottom {\n  transform-origin: 50% 100%;\n  animation: shake-bottom 0.8s cubic-bezier(0.455, 0.03, 0.515, 0.955) 2s 2 both;\n}\n\n.emoji-picker-dropdown__menu {\n  background: $simple-background-color;\n  position: absolute;\n  box-shadow: 4px 4px 6px rgba($base-shadow-color, 0.4);\n  border-radius: 4px;\n  margin-top: 5px;\n  z-index: 2;\n\n  .emoji-mart-scroll {\n    transition: opacity 200ms ease;\n  }\n\n  &.selecting .emoji-mart-scroll {\n    opacity: 0.5;\n  }\n}\n\n.emoji-picker-dropdown__modifiers {\n  position: absolute;\n  top: 60px;\n  right: 11px;\n  cursor: pointer;\n}\n\n.emoji-picker-dropdown__modifiers__menu {\n  position: absolute;\n  z-index: 4;\n  top: -4px;\n  left: -8px;\n  background: $simple-background-color;\n  border-radius: 4px;\n  box-shadow: 1px 2px 6px rgba($base-shadow-color, 0.2);\n  overflow: hidden;\n\n  button {\n    display: block;\n    cursor: pointer;\n    border: 0;\n    padding: 4px 8px;\n    background: transparent;\n\n    &:hover,\n    &:focus,\n    &:active {\n      background: rgba($ui-secondary-color, 0.4);\n    }\n  }\n\n  .emoji-mart-emoji {\n    height: 22px;\n  }\n}\n\n.emoji-mart-emoji {\n  span {\n    background-repeat: no-repeat;\n  }\n}\n\n.upload-area {\n  align-items: center;\n  background: rgba($base-overlay-background, 0.8);\n  display: flex;\n  height: 100%;\n  justify-content: center;\n  left: 0;\n  opacity: 0;\n  position: absolute;\n  top: 0;\n  visibility: hidden;\n  width: 100%;\n  z-index: 2000;\n\n  * {\n    pointer-events: none;\n  }\n}\n\n.upload-area__drop {\n  width: 320px;\n  height: 160px;\n  display: flex;\n  box-sizing: border-box;\n  position: relative;\n  padding: 8px;\n}\n\n.upload-area__background {\n  position: absolute;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: -1;\n  border-radius: 4px;\n  background: $ui-base-color;\n  box-shadow: 0 0 5px rgba($base-shadow-color, 0.2);\n}\n\n.upload-area__content {\n  flex: 1;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  color: $secondary-text-color;\n  font-size: 18px;\n  font-weight: 500;\n  border: 2px dashed $ui-base-lighter-color;\n  border-radius: 4px;\n}\n\n.upload-progress {\n  padding: 10px;\n  color: $lighter-text-color;\n  overflow: hidden;\n  display: flex;\n\n  .fa {\n    font-size: 34px;\n    margin-right: 10px;\n  }\n\n  span {\n    font-size: 12px;\n    text-transform: uppercase;\n    font-weight: 500;\n    display: block;\n  }\n}\n\n.upload-progess__message {\n  flex: 1 1 auto;\n}\n\n.upload-progress__backdrop {\n  width: 100%;\n  height: 6px;\n  border-radius: 6px;\n  background: $ui-base-lighter-color;\n  position: relative;\n  margin-top: 5px;\n}\n\n.upload-progress__tracker {\n  position: absolute;\n  left: 0;\n  top: 0;\n  height: 6px;\n  background: $ui-highlight-color;\n  border-radius: 6px;\n}\n\n.emoji-button {\n  display: block;\n  font-size: 24px;\n  line-height: 24px;\n  margin-left: 2px;\n  width: 24px;\n  outline: 0;\n  cursor: pointer;\n\n  &:active,\n  &:focus {\n    outline: 0 !important;\n  }\n\n  img {\n    filter: grayscale(100%);\n    opacity: 0.8;\n    display: block;\n    margin: 0;\n    width: 22px;\n    height: 22px;\n    margin-top: 2px;\n  }\n\n  &:hover,\n  &:active,\n  &:focus {\n    img {\n      opacity: 1;\n      filter: none;\n    }\n  }\n}\n\n.dropdown--active .emoji-button img {\n  opacity: 1;\n  filter: none;\n}\n\n.privacy-dropdown__dropdown {\n  position: absolute;\n  background: $simple-background-color;\n  box-shadow: 2px 4px 15px rgba($base-shadow-color, 0.4);\n  border-radius: 4px;\n  margin-left: 40px;\n  overflow: hidden;\n\n  &.top {\n    transform-origin: 50% 100%;\n  }\n\n  &.bottom {\n    transform-origin: 50% 0;\n  }\n}\n\n.privacy-dropdown__option {\n  color: $inverted-text-color;\n  padding: 10px;\n  cursor: pointer;\n  display: flex;\n\n  &:hover,\n  &.active {\n    background: $ui-highlight-color;\n    color: $primary-text-color;\n    outline: 0;\n\n    .privacy-dropdown__option__content {\n      color: $primary-text-color;\n\n      strong {\n        color: $primary-text-color;\n      }\n    }\n  }\n\n  &.active:hover {\n    background: lighten($ui-highlight-color, 4%);\n  }\n}\n\n.privacy-dropdown__option__icon {\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  margin-right: 10px;\n}\n\n.privacy-dropdown__option__content {\n  flex: 1 1 auto;\n  color: $lighter-text-color;\n\n  strong {\n    font-weight: 500;\n    display: block;\n    color: $inverted-text-color;\n\n    @each $lang in $cjk-langs {\n      &:lang(#{$lang}) {\n        font-weight: 700;\n      }\n    }\n  }\n}\n\n.privacy-dropdown.active {\n  .privacy-dropdown__value {\n    background: $simple-background-color;\n    border-radius: 4px 4px 0 0;\n    box-shadow: 0 -4px 4px rgba($base-shadow-color, 0.1);\n\n    .icon-button {\n      transition: none;\n    }\n\n    &.active {\n      background: $ui-highlight-color;\n\n      .icon-button {\n        color: $primary-text-color;\n      }\n    }\n  }\n\n  &.top .privacy-dropdown__value {\n    border-radius: 0 0 4px 4px;\n  }\n\n  .privacy-dropdown__dropdown {\n    display: block;\n    box-shadow: 2px 4px 6px rgba($base-shadow-color, 0.1);\n  }\n}\n\n.search {\n  position: relative;\n}\n\n.search__input {\n  @include search-input;\n\n  display: block;\n  padding: 15px;\n  padding-right: 30px;\n  line-height: 18px;\n  font-size: 16px;\n}\n\n.search__icon {\n  &::-moz-focus-inner {\n    border: 0;\n  }\n\n  &::-moz-focus-inner,\n  &:focus {\n    outline: 0 !important;\n  }\n\n  .fa {\n    position: absolute;\n    top: 16px;\n    right: 10px;\n    z-index: 2;\n    display: inline-block;\n    opacity: 0;\n    transition: all 100ms linear;\n    transition-property: transform, opacity;\n    font-size: 18px;\n    width: 18px;\n    height: 18px;\n    color: $secondary-text-color;\n    cursor: default;\n    pointer-events: none;\n\n    &.active {\n      pointer-events: auto;\n      opacity: 0.3;\n    }\n  }\n\n  .fa-search {\n    transform: rotate(90deg);\n\n    &.active {\n      pointer-events: none;\n      transform: rotate(0deg);\n    }\n  }\n\n  .fa-times-circle {\n    top: 17px;\n    transform: rotate(0deg);\n    color: $action-button-color;\n    cursor: pointer;\n\n    &.active {\n      transform: rotate(90deg);\n    }\n\n    &:hover {\n      color: lighten($action-button-color, 7%);\n    }\n  }\n}\n\n.search-results__header {\n  color: $dark-text-color;\n  background: lighten($ui-base-color, 2%);\n  padding: 15px;\n  font-weight: 500;\n  font-size: 16px;\n  cursor: default;\n\n  .fa {\n    display: inline-block;\n    margin-right: 5px;\n  }\n}\n\n.search-results__section {\n  margin-bottom: 5px;\n\n  h5 {\n    background: darken($ui-base-color, 4%);\n    border-bottom: 1px solid lighten($ui-base-color, 8%);\n    cursor: default;\n    display: flex;\n    padding: 15px;\n    font-weight: 500;\n    font-size: 16px;\n    color: $dark-text-color;\n\n    .fa {\n      display: inline-block;\n      margin-right: 5px;\n    }\n  }\n\n  .account:last-child,\n  & > div:last-child .status {\n    border-bottom: 0;\n  }\n}\n\n.search-results__hashtag {\n  display: block;\n  padding: 10px;\n  color: $secondary-text-color;\n  text-decoration: none;\n\n  &:hover,\n  &:active,\n  &:focus {\n    color: lighten($secondary-text-color, 4%);\n    text-decoration: underline;\n  }\n}\n\n.modal-root {\n  position: relative;\n  transition: opacity 0.3s linear;\n  will-change: opacity;\n  z-index: 9999;\n}\n\n.modal-root__overlay {\n  position: fixed;\n  top: 0;\n  left: 0;\n  right: 0;\n  bottom: 0;\n  background: rgba($base-overlay-background, 0.7);\n}\n\n.modal-root__container {\n  position: fixed;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  justify-content: center;\n  align-content: space-around;\n  z-index: 9999;\n  pointer-events: none;\n  user-select: none;\n}\n\n.modal-root__modal {\n  pointer-events: auto;\n  display: flex;\n  z-index: 9999;\n}\n\n.video-modal {\n  max-width: 100vw;\n  max-height: 100vh;\n  position: relative;\n}\n\n.media-modal {\n  width: 100%;\n  height: 100%;\n  position: relative;\n\n  .extended-video-player {\n    width: 100%;\n    height: 100%;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n\n    video {\n      max-width: $media-modal-media-max-width;\n      max-height: $media-modal-media-max-height;\n    }\n  }\n}\n\n.media-modal__closer {\n  position: absolute;\n  top: 0;\n  left: 0;\n  right: 0;\n  bottom: 0;\n}\n\n.media-modal__navigation {\n  position: absolute;\n  top: 0;\n  left: 0;\n  right: 0;\n  bottom: 0;\n  pointer-events: none;\n  transition: opacity 0.3s linear;\n  will-change: opacity;\n\n  * {\n    pointer-events: auto;\n  }\n\n  &.media-modal__navigation--hidden {\n    opacity: 0;\n\n    * {\n      pointer-events: none;\n    }\n  }\n}\n\n.media-modal__nav {\n  background: rgba($base-overlay-background, 0.5);\n  box-sizing: border-box;\n  border: 0;\n  color: $primary-text-color;\n  cursor: pointer;\n  display: flex;\n  align-items: center;\n  font-size: 24px;\n  height: 20vmax;\n  margin: auto 0;\n  padding: 30px 15px;\n  position: absolute;\n  top: 0;\n  bottom: 0;\n}\n\n.media-modal__nav--left {\n  left: 0;\n}\n\n.media-modal__nav--right {\n  right: 0;\n}\n\n.media-modal__pagination {\n  width: 100%;\n  text-align: center;\n  position: absolute;\n  left: 0;\n  bottom: 20px;\n  pointer-events: none;\n}\n\n.media-modal__meta {\n  text-align: center;\n  position: absolute;\n  left: 0;\n  bottom: 20px;\n  width: 100%;\n  pointer-events: none;\n\n  &--shifted {\n    bottom: 62px;\n  }\n\n  a {\n    text-decoration: none;\n    font-weight: 500;\n    color: $ui-secondary-color;\n\n    &:hover,\n    &:focus,\n    &:active {\n      text-decoration: underline;\n    }\n  }\n}\n\n.media-modal__page-dot {\n  display: inline-block;\n}\n\n.media-modal__button {\n  background-color: $primary-text-color;\n  height: 12px;\n  width: 12px;\n  border-radius: 6px;\n  margin: 10px;\n  padding: 0;\n  border: 0;\n  font-size: 0;\n}\n\n.media-modal__button--active {\n  background-color: $highlight-text-color;\n}\n\n.media-modal__close {\n  position: absolute;\n  right: 8px;\n  top: 8px;\n  z-index: 100;\n}\n\n.onboarding-modal,\n.error-modal,\n.embed-modal {\n  background: $ui-secondary-color;\n  color: $inverted-text-color;\n  border-radius: 8px;\n  overflow: hidden;\n  display: flex;\n  flex-direction: column;\n}\n\n.error-modal__body {\n  height: 80vh;\n  width: 80vw;\n  max-width: 520px;\n  max-height: 420px;\n  position: relative;\n\n  & > div {\n    position: absolute;\n    top: 0;\n    left: 0;\n    width: 100%;\n    height: 100%;\n    box-sizing: border-box;\n    padding: 25px;\n    display: none;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    display: flex;\n    opacity: 0;\n    user-select: text;\n  }\n}\n\n.error-modal__body {\n  display: flex;\n  flex-direction: column;\n  justify-content: center;\n  align-items: center;\n  text-align: center;\n}\n\n.onboarding-modal__paginator,\n.error-modal__footer {\n  flex: 0 0 auto;\n  background: darken($ui-secondary-color, 8%);\n  display: flex;\n  padding: 25px;\n\n  & > div {\n    min-width: 33px;\n  }\n\n  .onboarding-modal__nav,\n  .error-modal__nav {\n    color: $lighter-text-color;\n    border: 0;\n    font-size: 14px;\n    font-weight: 500;\n    padding: 10px 25px;\n    line-height: inherit;\n    height: auto;\n    margin: -10px;\n    border-radius: 4px;\n    background-color: transparent;\n\n    &:hover,\n    &:focus,\n    &:active {\n      color: darken($lighter-text-color, 4%);\n      background-color: darken($ui-secondary-color, 16%);\n    }\n\n    &.onboarding-modal__done,\n    &.onboarding-modal__next {\n      color: $inverted-text-color;\n\n      &:hover,\n      &:focus,\n      &:active {\n        color: lighten($inverted-text-color, 4%);\n      }\n    }\n  }\n}\n\n.error-modal__footer {\n  justify-content: center;\n}\n\n.display-case {\n  text-align: center;\n  font-size: 15px;\n  margin-bottom: 15px;\n\n  &__label {\n    font-weight: 500;\n    color: $inverted-text-color;\n    margin-bottom: 5px;\n    text-transform: uppercase;\n    font-size: 12px;\n  }\n\n  &__case {\n    background: $ui-base-color;\n    color: $secondary-text-color;\n    font-weight: 500;\n    padding: 10px;\n    border-radius: 4px;\n  }\n}\n\n.onboard-sliders {\n  display: inline-block;\n  max-width: 30px;\n  max-height: auto;\n  margin-left: 10px;\n}\n\n.boost-modal,\n.confirmation-modal,\n.report-modal,\n.actions-modal,\n.mute-modal {\n  background: lighten($ui-secondary-color, 8%);\n  color: $inverted-text-color;\n  border-radius: 8px;\n  overflow: hidden;\n  max-width: 90vw;\n  width: 480px;\n  position: relative;\n  flex-direction: column;\n\n  .status__display-name {\n    display: block;\n    max-width: 100%;\n    padding-right: 25px;\n  }\n\n  .status__avatar {\n    height: 28px;\n    left: 10px;\n    position: absolute;\n    top: 10px;\n    width: 48px;\n  }\n\n  .status__content__spoiler-link {\n    color: lighten($secondary-text-color, 8%);\n  }\n}\n\n.actions-modal {\n  .status {\n    background: $white;\n    border-bottom-color: $ui-secondary-color;\n    padding-top: 10px;\n    padding-bottom: 10px;\n  }\n\n  .dropdown-menu__separator {\n    border-bottom-color: $ui-secondary-color;\n  }\n}\n\n.boost-modal__container {\n  overflow-x: scroll;\n  padding: 10px;\n\n  .status {\n    user-select: text;\n    border-bottom: 0;\n  }\n}\n\n.boost-modal__action-bar,\n.confirmation-modal__action-bar,\n.mute-modal__action-bar {\n  display: flex;\n  justify-content: space-between;\n  background: $ui-secondary-color;\n  padding: 10px;\n  line-height: 36px;\n\n  & > div {\n    flex: 1 1 auto;\n    text-align: right;\n    color: $lighter-text-color;\n    padding-right: 10px;\n  }\n\n  .button {\n    flex: 0 0 auto;\n  }\n}\n\n.boost-modal__status-header {\n  font-size: 15px;\n}\n\n.boost-modal__status-time {\n  float: right;\n  font-size: 14px;\n}\n\n.mute-modal {\n  line-height: 24px;\n}\n\n.mute-modal .react-toggle {\n  vertical-align: middle;\n}\n\n.report-modal {\n  width: 90vw;\n  max-width: 700px;\n}\n\n.report-modal__container {\n  display: flex;\n  border-top: 1px solid $ui-secondary-color;\n\n  @media screen and (max-width: 480px) {\n    flex-wrap: wrap;\n    overflow-y: auto;\n  }\n}\n\n.report-modal__statuses,\n.report-modal__comment {\n  box-sizing: border-box;\n  width: 50%;\n\n  @media screen and (max-width: 480px) {\n    width: 100%;\n  }\n}\n\n.report-modal__statuses {\n  flex: 1 1 auto;\n  min-height: 20vh;\n  max-height: 80vh;\n  overflow-y: auto;\n  overflow-x: hidden;\n\n  .status__content a {\n    color: $highlight-text-color;\n  }\n\n  .status__content,\n  .status__content p {\n    color: $inverted-text-color;\n  }\n\n  @media screen and (max-width: 480px) {\n    max-height: 10vh;\n  }\n}\n\n.report-modal__comment {\n  padding: 20px;\n  border-right: 1px solid $ui-secondary-color;\n  max-width: 320px;\n\n  p {\n    font-size: 14px;\n    line-height: 20px;\n    margin-bottom: 20px;\n  }\n\n  .setting-text {\n    display: block;\n    box-sizing: border-box;\n    width: 100%;\n    margin: 0;\n    color: $inverted-text-color;\n    background: $white;\n    padding: 10px;\n    font-family: inherit;\n    font-size: 14px;\n    resize: vertical;\n    border: 0;\n    outline: 0;\n    border-radius: 4px;\n    border: 1px solid $ui-secondary-color;\n    margin-bottom: 20px;\n\n    &:focus {\n      border: 1px solid darken($ui-secondary-color, 8%);\n    }\n  }\n\n  .setting-toggle {\n    margin-top: 20px;\n    margin-bottom: 24px;\n\n    &__label {\n      color: $inverted-text-color;\n      font-size: 14px;\n    }\n  }\n\n  @media screen and (max-width: 480px) {\n    padding: 10px;\n    max-width: 100%;\n    order: 2;\n\n    .setting-toggle {\n      margin-bottom: 4px;\n    }\n  }\n}\n\n.actions-modal {\n  max-height: 80vh;\n  max-width: 80vw;\n\n  .status {\n    overflow-y: auto;\n    max-height: 300px;\n  }\n\n  .actions-modal__item-label {\n    font-weight: 500;\n  }\n\n  ul {\n    overflow-y: auto;\n    flex-shrink: 0;\n    max-height: 80vh;\n\n    &.with-status {\n      max-height: calc(80vh - 75px);\n    }\n\n    li:empty {\n      margin: 0;\n    }\n\n    li:not(:empty) {\n      a {\n        color: $inverted-text-color;\n        display: flex;\n        padding: 12px 16px;\n        font-size: 15px;\n        align-items: center;\n        text-decoration: none;\n\n        &,\n        button {\n          transition: none;\n        }\n\n        &.active,\n        &:hover,\n        &:active,\n        &:focus {\n          &,\n          button {\n            background: $ui-highlight-color;\n            color: $primary-text-color;\n          }\n        }\n\n        button:first-child {\n          margin-right: 10px;\n        }\n      }\n    }\n  }\n}\n\n.confirmation-modal__action-bar,\n.mute-modal__action-bar {\n  .confirmation-modal__secondary-button,\n  .confirmation-modal__cancel-button,\n  .mute-modal__cancel-button {\n    background-color: transparent;\n    color: $lighter-text-color;\n    font-size: 14px;\n    font-weight: 500;\n\n    &:hover,\n    &:focus,\n    &:active {\n      color: darken($lighter-text-color, 4%);\n    }\n  }\n\n  .confirmation-modal__secondary-button {\n    flex-shrink: 1;\n  }\n}\n\n.confirmation-modal__container,\n.mute-modal__container,\n.report-modal__target {\n  padding: 30px;\n  font-size: 16px;\n  text-align: center;\n\n  strong {\n    font-weight: 500;\n\n    @each $lang in $cjk-langs {\n      &:lang(#{$lang}) {\n        font-weight: 700;\n      }\n    }\n  }\n}\n\n.report-modal__target {\n  padding: 20px;\n\n  .media-modal__close {\n    top: 19px;\n    right: 15px;\n  }\n}\n\n.loading-bar {\n  background-color: $highlight-text-color;\n  height: 3px;\n  position: absolute;\n  top: 0;\n  left: 0;\n}\n\n.media-gallery__gifv__label {\n  display: block;\n  position: absolute;\n  color: $primary-text-color;\n  background: rgba($base-overlay-background, 0.5);\n  bottom: 6px;\n  left: 6px;\n  padding: 2px 6px;\n  border-radius: 2px;\n  font-size: 11px;\n  font-weight: 600;\n  z-index: 1;\n  pointer-events: none;\n  opacity: 0.9;\n  transition: opacity 0.1s ease;\n  line-height: 18px;\n}\n\n.media-gallery__gifv {\n  &.autoplay {\n    .media-gallery__gifv__label {\n      display: none;\n    }\n  }\n\n  &:hover {\n    .media-gallery__gifv__label {\n      opacity: 1;\n    }\n  }\n}\n\n.attachment-list {\n  display: flex;\n  font-size: 14px;\n  border: 1px solid lighten($ui-base-color, 8%);\n  border-radius: 4px;\n  margin-top: 14px;\n  overflow: hidden;\n\n  &__icon {\n    flex: 0 0 auto;\n    color: $dark-text-color;\n    padding: 8px 18px;\n    cursor: default;\n    border-right: 1px solid lighten($ui-base-color, 8%);\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    font-size: 26px;\n\n    .fa {\n      display: block;\n    }\n  }\n\n  &__list {\n    list-style: none;\n    padding: 4px 0;\n    padding-left: 8px;\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n\n    li {\n      display: block;\n      padding: 4px 0;\n    }\n\n    a {\n      text-decoration: none;\n      color: $dark-text-color;\n      font-weight: 500;\n\n      &:hover {\n        text-decoration: underline;\n      }\n    }\n  }\n\n  &.compact {\n    border: 0;\n    margin-top: 4px;\n\n    .attachment-list__list {\n      padding: 0;\n      display: block;\n    }\n\n    .fa {\n      color: $dark-text-color;\n    }\n  }\n}\n\n/* Media Gallery */\n.media-gallery {\n  box-sizing: border-box;\n  margin-top: 8px;\n  overflow: hidden;\n  border-radius: 4px;\n  position: relative;\n  width: 100%;\n}\n\n.media-gallery__item {\n  border: 0;\n  box-sizing: border-box;\n  display: block;\n  float: left;\n  position: relative;\n  border-radius: 4px;\n  overflow: hidden;\n\n  &.standalone {\n    .media-gallery__item-gifv-thumbnail {\n      transform: none;\n      top: 0;\n    }\n  }\n}\n\n.media-gallery__item-thumbnail {\n  cursor: zoom-in;\n  display: block;\n  text-decoration: none;\n  color: $secondary-text-color;\n  position: relative;\n  z-index: 1;\n\n  &,\n  img {\n    height: 100%;\n    width: 100%;\n  }\n\n  img {\n    object-fit: cover;\n  }\n}\n\n.media-gallery__preview {\n  width: 100%;\n  height: 100%;\n  object-fit: cover;\n  position: absolute;\n  top: 0;\n  left: 0;\n  z-index: 0;\n  background: $base-overlay-background;\n\n  &--hidden {\n    display: none;\n  }\n}\n\n.media-gallery__gifv {\n  height: 100%;\n  overflow: hidden;\n  position: relative;\n  width: 100%;\n}\n\n.media-gallery__item-gifv-thumbnail {\n  cursor: zoom-in;\n  height: 100%;\n  object-fit: cover;\n  position: relative;\n  top: 50%;\n  transform: translateY(-50%);\n  width: 100%;\n  z-index: 1;\n}\n\n.media-gallery__item-thumbnail-label {\n  clip: rect(1px 1px 1px 1px); /* IE6, IE7 */\n  clip: rect(1px, 1px, 1px, 1px);\n  overflow: hidden;\n  position: absolute;\n}\n/* End Media Gallery */\n\n/* Status Video Player */\n.status__video-player {\n  background: $base-overlay-background;\n  box-sizing: border-box;\n  cursor: default; /* May not be needed */\n  margin-top: 8px;\n  overflow: hidden;\n  position: relative;\n}\n\n.status__video-player-video {\n  height: 100%;\n  object-fit: cover;\n  position: relative;\n  top: 50%;\n  transform: translateY(-50%);\n  width: 100%;\n  z-index: 1;\n}\n\n.status__video-player-expand,\n.status__video-player-mute {\n  color: $primary-text-color;\n  opacity: 0.8;\n  position: absolute;\n  right: 4px;\n  text-shadow: 0 1px 1px $base-shadow-color, 1px 0 1px $base-shadow-color;\n}\n\n.status__video-player-spoiler {\n  display: none;\n  color: $primary-text-color;\n  left: 4px;\n  position: absolute;\n  text-shadow: 0 1px 1px $base-shadow-color, 1px 0 1px $base-shadow-color;\n  top: 4px;\n  z-index: 100;\n\n  &.status__video-player-spoiler--visible {\n    display: block;\n  }\n}\n\n.status__video-player-expand {\n  bottom: 4px;\n  z-index: 100;\n}\n\n.status__video-player-mute {\n  top: 4px;\n  z-index: 5;\n}\n\n.detailed,\n.fullscreen {\n  .video-player__volume__current,\n  .video-player__volume::before {\n    bottom: 27px;\n  }\n\n  .video-player__volume__handle {\n    bottom: 23px;\n  }\n\n}\n\n.video-player {\n  overflow: hidden;\n  position: relative;\n  background: $base-shadow-color;\n  max-width: 100%;\n  border-radius: 4px;\n\n  &:focus {\n    outline: 0;\n  }\n\n  video {\n    max-width: 100vw;\n    max-height: 80vh;\n    z-index: 1;\n  }\n\n  &.fullscreen {\n    width: 100% !important;\n    height: 100% !important;\n    margin: 0;\n\n    video {\n      max-width: 100% !important;\n      max-height: 100% !important;\n      width: 100% !important;\n      height: 100% !important;\n    }\n  }\n\n  &.inline {\n    video {\n      object-fit: contain;\n      position: relative;\n      top: 50%;\n      transform: translateY(-50%);\n    }\n  }\n\n  &__controls {\n    position: absolute;\n    z-index: 2;\n    bottom: 0;\n    left: 0;\n    right: 0;\n    box-sizing: border-box;\n    background: linear-gradient(0deg, rgba($base-shadow-color, 0.85) 0, rgba($base-shadow-color, 0.45) 60%, transparent);\n    padding: 0 15px;\n    opacity: 0;\n    transition: opacity .1s ease;\n\n    &.active {\n      opacity: 1;\n    }\n  }\n\n  &.inactive {\n    video,\n    .video-player__controls {\n      visibility: hidden;\n    }\n  }\n\n  &__spoiler {\n    display: none;\n    position: absolute;\n    top: 0;\n    left: 0;\n    width: 100%;\n    height: 100%;\n    z-index: 4;\n    border: 0;\n    background: $base-overlay-background;\n    color: $darker-text-color;\n    transition: none;\n    pointer-events: none;\n\n    &.active {\n      display: block;\n      pointer-events: auto;\n\n      &:hover,\n      &:active,\n      &:focus {\n        color: lighten($darker-text-color, 7%);\n      }\n    }\n\n    &__title {\n      display: block;\n      font-size: 14px;\n    }\n\n    &__subtitle {\n      display: block;\n      font-size: 11px;\n      font-weight: 500;\n    }\n  }\n\n  &__buttons-bar {\n    display: flex;\n    justify-content: space-between;\n    padding-bottom: 10px;\n  }\n\n  &__buttons {\n    font-size: 16px;\n    white-space: nowrap;\n    overflow: hidden;\n    text-overflow: ellipsis;\n\n    &.left {\n      button {\n        padding-left: 0;\n      }\n    }\n\n    &.right {\n      button {\n        padding-right: 0;\n      }\n    }\n\n    button {\n      background: transparent;\n      padding: 2px 10px;\n      font-size: 16px;\n      border: 0;\n      color: rgba($white, 0.75);\n\n      &:active,\n      &:hover,\n      &:focus {\n        color: $white;\n      }\n    }\n  }\n\n  &__time-sep,\n  &__time-total,\n  &__time-current {\n    font-size: 14px;\n    font-weight: 500;\n  }\n\n  &__time-current {\n    color: $white;\n    margin-left: 60px;\n  }\n\n  &__time-sep {\n    display: inline-block;\n    margin: 0 6px;\n  }\n\n  &__time-sep,\n  &__time-total {\n    color: $white;\n  }\n\n  &__volume {\n    cursor: pointer;\n    height: 24px;\n    display: inline;\n\n    &::before {\n      content: \"\";\n      width: 50px;\n      background: rgba($white, 0.35);\n      border-radius: 4px;\n      display: block;\n      position: absolute;\n      height: 4px;\n      left: 70px;\n      bottom: 20px;\n    }\n\n    &__current {\n      display: block;\n      position: absolute;\n      height: 4px;\n      border-radius: 4px;\n      left: 70px;\n      bottom: 20px;\n      background: lighten($ui-highlight-color, 8%);\n    }\n\n    &__handle {\n      position: absolute;\n      z-index: 3;\n      border-radius: 50%;\n      width: 12px;\n      height: 12px;\n      bottom: 16px;\n      left: 70px;\n      transition: opacity .1s ease;\n      background: lighten($ui-highlight-color, 8%);\n      box-shadow: 1px 2px 6px rgba($base-shadow-color, 0.2);\n      pointer-events: none;\n    }\n  }\n\n  &__link {\n    padding: 2px 10px;\n\n    a {\n      text-decoration: none;\n      font-size: 14px;\n      font-weight: 500;\n      color: $white;\n\n      &:hover,\n      &:active,\n      &:focus {\n        text-decoration: underline;\n      }\n    }\n  }\n\n  &__seek {\n    cursor: pointer;\n    height: 24px;\n    position: relative;\n\n    &::before {\n      content: \"\";\n      width: 100%;\n      background: rgba($white, 0.35);\n      border-radius: 4px;\n      display: block;\n      position: absolute;\n      height: 4px;\n      top: 10px;\n    }\n\n    &__progress,\n    &__buffer {\n      display: block;\n      position: absolute;\n      height: 4px;\n      border-radius: 4px;\n      top: 10px;\n      background: lighten($ui-highlight-color, 8%);\n    }\n\n    &__buffer {\n      background: rgba($white, 0.2);\n    }\n\n    &__handle {\n      position: absolute;\n      z-index: 3;\n      opacity: 0;\n      border-radius: 50%;\n      width: 12px;\n      height: 12px;\n      top: 6px;\n      margin-left: -6px;\n      transition: opacity .1s ease;\n      background: lighten($ui-highlight-color, 8%);\n      box-shadow: 1px 2px 6px rgba($base-shadow-color, 0.2);\n      pointer-events: none;\n\n      &.active {\n        opacity: 1;\n      }\n    }\n\n    &:hover {\n      .video-player__seek__handle {\n        opacity: 1;\n      }\n    }\n  }\n\n  &.detailed,\n  &.fullscreen {\n    .video-player__buttons {\n      button {\n        padding-top: 10px;\n        padding-bottom: 10px;\n      }\n    }\n  }\n}\n\n.media-spoiler-video {\n  background-size: cover;\n  background-repeat: no-repeat;\n  background-position: center;\n  cursor: pointer;\n  margin-top: 8px;\n  position: relative;\n  border: 0;\n  display: block;\n}\n\n.media-spoiler-video-play-icon {\n  border-radius: 100px;\n  color: rgba($primary-text-color, 0.8);\n  font-size: 36px;\n  left: 50%;\n  padding: 5px;\n  position: absolute;\n  top: 50%;\n  transform: translate(-50%, -50%);\n}\n/* End Video Player */\n\n.account-gallery__container {\n  display: flex;\n  flex-wrap: wrap;\n  padding: 4px 2px;\n}\n\n.account-gallery__item {\n  border: 0;\n  box-sizing: border-box;\n  display: block;\n  position: relative;\n  border-radius: 4px;\n  overflow: hidden;\n  margin: 2px;\n\n  &__icons {\n    position: absolute;\n    top: 50%;\n    left: 50%;\n    transform: translate(-50%, -50%);\n    font-size: 24px;\n  }\n}\n\n.notification__filter-bar,\n.account__section-headline {\n  background: darken($ui-base-color, 4%);\n  border-bottom: 1px solid lighten($ui-base-color, 8%);\n  cursor: default;\n  display: flex;\n  flex-shrink: 0;\n\n  button {\n    background: darken($ui-base-color, 4%);\n    border: 0;\n    margin: 0;\n  }\n\n  button,\n  a {\n    display: block;\n    flex: 1 1 auto;\n    color: $darker-text-color;\n    padding: 15px 0;\n    font-size: 14px;\n    font-weight: 500;\n    text-align: center;\n    text-decoration: none;\n    position: relative;\n\n    &.active {\n      color: $secondary-text-color;\n\n      &::before,\n      &::after {\n        display: block;\n        content: \"\";\n        position: absolute;\n        bottom: 0;\n        left: 50%;\n        width: 0;\n        height: 0;\n        transform: translateX(-50%);\n        border-style: solid;\n        border-width: 0 10px 10px;\n        border-color: transparent transparent lighten($ui-base-color, 8%);\n      }\n\n      &::after {\n        bottom: -1px;\n        border-color: transparent transparent $ui-base-color;\n      }\n    }\n  }\n}\n\n::-webkit-scrollbar-thumb {\n  border-radius: 0;\n}\n\n.search-popout {\n  @include search-popout;\n}\n\nnoscript {\n  text-align: center;\n\n  img {\n    width: 200px;\n    opacity: 0.5;\n    animation: flicker 4s infinite;\n  }\n\n  div {\n    font-size: 14px;\n    margin: 30px auto;\n    color: $secondary-text-color;\n    max-width: 400px;\n\n    a {\n      color: $highlight-text-color;\n      text-decoration: underline;\n\n      &:hover {\n        text-decoration: none;\n      }\n    }\n  }\n}\n\n@keyframes flicker {\n  0% { opacity: 1; }\n  30% { opacity: 0.75; }\n  100% { opacity: 1; }\n}\n\n@media screen and (max-width: 630px) and (max-height: 400px) {\n  $duration: 400ms;\n  $delay: 100ms;\n\n  .tabs-bar,\n  .search {\n    will-change: margin-top;\n    transition: margin-top $duration $delay;\n  }\n\n  .navigation-bar {\n    will-change: padding-bottom;\n    transition: padding-bottom $duration $delay;\n  }\n\n  .navigation-bar {\n    & > a:first-child {\n      will-change: margin-top, margin-left, margin-right, width;\n      transition: margin-top $duration $delay, margin-left $duration ($duration + $delay), margin-right $duration ($duration + $delay);\n    }\n\n    & > .navigation-bar__profile-edit {\n      will-change: margin-top;\n      transition: margin-top $duration $delay;\n    }\n\n    .navigation-bar__actions {\n      & > .icon-button.close {\n        will-change: opacity transform;\n        transition: opacity $duration * 0.5 $delay,\n                    transform $duration $delay;\n      }\n\n      & > .compose__action-bar .icon-button {\n        will-change: opacity transform;\n        transition: opacity $duration * 0.5 $delay + $duration * 0.5,\n                    transform $duration $delay;\n      }\n    }\n  }\n\n  .is-composing {\n    .tabs-bar,\n    .search {\n      margin-top: -50px;\n    }\n\n    .navigation-bar {\n      padding-bottom: 0;\n\n      & > a:first-child {\n        margin: -100px 10px 0 -50px;\n      }\n\n      .navigation-bar__profile {\n        padding-top: 2px;\n      }\n\n      .navigation-bar__profile-edit {\n        position: absolute;\n        margin-top: -60px;\n      }\n\n      .navigation-bar__actions {\n        .icon-button.close {\n          pointer-events: auto;\n          opacity: 1;\n          transform: scale(1, 1) translate(0, 0);\n          bottom: 5px;\n        }\n\n        .compose__action-bar .icon-button {\n          pointer-events: none;\n          opacity: 0;\n          transform: scale(0, 1) translate(100%, 0);\n        }\n      }\n    }\n  }\n}\n\n.embed-modal {\n  max-width: 80vw;\n  max-height: 80vh;\n\n  h4 {\n    padding: 30px;\n    font-weight: 500;\n    font-size: 16px;\n    text-align: center;\n  }\n\n  .embed-modal__container {\n    padding: 10px;\n\n    .hint {\n      margin-bottom: 15px;\n    }\n\n    .embed-modal__html {\n      outline: 0;\n      box-sizing: border-box;\n      display: block;\n      width: 100%;\n      border: 0;\n      padding: 10px;\n      font-family: $font-monospace, monospace;\n      background: $ui-base-color;\n      color: $primary-text-color;\n      font-size: 14px;\n      margin: 0;\n      margin-bottom: 15px;\n\n      &::-moz-focus-inner {\n        border: 0;\n      }\n\n      &::-moz-focus-inner,\n      &:focus,\n      &:active {\n        outline: 0 !important;\n      }\n\n      &:focus {\n        background: lighten($ui-base-color, 4%);\n      }\n\n      @media screen and (max-width: 600px) {\n        font-size: 16px;\n      }\n    }\n\n    .embed-modal__iframe {\n      width: 400px;\n      max-width: 100%;\n      overflow: hidden;\n      border: 0;\n    }\n  }\n}\n\n.account__moved-note {\n  padding: 14px 10px;\n  padding-bottom: 16px;\n  background: lighten($ui-base-color, 4%);\n  border-top: 1px solid lighten($ui-base-color, 8%);\n  border-bottom: 1px solid lighten($ui-base-color, 8%);\n\n  &__message {\n    position: relative;\n    margin-left: 58px;\n    color: $dark-text-color;\n    padding: 8px 0;\n    padding-top: 0;\n    padding-bottom: 4px;\n    font-size: 14px;\n\n    > span {\n      display: block;\n      overflow: hidden;\n      text-overflow: ellipsis;\n    }\n  }\n\n  &__icon-wrapper {\n    left: -26px;\n    position: absolute;\n  }\n\n  .detailed-status__display-avatar {\n    position: relative;\n  }\n\n  .detailed-status__display-name {\n    margin-bottom: 0;\n  }\n}\n\n.column-inline-form {\n  padding: 15px;\n  padding-right: 0;\n  display: flex;\n  justify-content: flex-start;\n  align-items: center;\n  background: lighten($ui-base-color, 4%);\n\n  label {\n    flex: 1 1 auto;\n\n    input {\n      width: 100%;\n\n      &:focus {\n        outline: 0;\n      }\n    }\n  }\n\n  .icon-button {\n    flex: 0 0 auto;\n    margin: 0 10px;\n  }\n}\n\n.drawer__backdrop {\n  cursor: pointer;\n  position: absolute;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  background: rgba($base-overlay-background, 0.5);\n}\n\n.list-editor {\n  background: $ui-base-color;\n  flex-direction: column;\n  border-radius: 8px;\n  box-shadow: 2px 4px 15px rgba($base-shadow-color, 0.4);\n  width: 380px;\n  overflow: hidden;\n\n  @media screen and (max-width: 420px) {\n    width: 90%;\n  }\n\n  h4 {\n    padding: 15px 0;\n    background: lighten($ui-base-color, 13%);\n    font-weight: 500;\n    font-size: 16px;\n    text-align: center;\n    border-radius: 8px 8px 0 0;\n  }\n\n  .drawer__pager {\n    height: 50vh;\n  }\n\n  .drawer__inner {\n    border-radius: 0 0 8px 8px;\n\n    &.backdrop {\n      width: calc(100% - 60px);\n      box-shadow: 2px 4px 15px rgba($base-shadow-color, 0.4);\n      border-radius: 0 0 0 8px;\n    }\n  }\n\n  &__accounts {\n    overflow-y: auto;\n  }\n\n  .account__display-name {\n    &:hover strong {\n      text-decoration: none;\n    }\n  }\n\n  .account__avatar {\n    cursor: default;\n  }\n\n  .search {\n    margin-bottom: 0;\n  }\n}\n\n.list-adder {\n  background: $ui-base-color;\n  flex-direction: column;\n  border-radius: 8px;\n  box-shadow: 2px 4px 15px rgba($base-shadow-color, 0.4);\n  width: 380px;\n  overflow: hidden;\n\n  @media screen and (max-width: 420px) {\n    width: 90%;\n  }\n\n  &__account {\n    background: lighten($ui-base-color, 13%);\n  }\n\n  &__lists {\n    background: lighten($ui-base-color, 13%);\n    height: 50vh;\n    border-radius: 0 0 8px 8px;\n    overflow-y: auto;\n  }\n\n  .list {\n    padding: 10px;\n    border-bottom: 1px solid lighten($ui-base-color, 8%);\n  }\n\n  .list__wrapper {\n    display: flex;\n  }\n\n  .list__display-name {\n    flex: 1 1 auto;\n    overflow: hidden;\n    text-decoration: none;\n    font-size: 16px;\n    padding: 10px;\n  }\n}\n\n.focal-point-modal {\n  max-width: 80vw;\n  max-height: 80vh;\n  position: relative;\n}\n\n.focal-point {\n  position: relative;\n  cursor: pointer;\n  overflow: hidden;\n\n  &.dragging {\n    cursor: move;\n  }\n\n  img {\n    max-width: 80vw;\n    max-height: 80vh;\n    width: auto;\n    height: auto;\n    margin: auto;\n  }\n\n  &__reticle {\n    position: absolute;\n    width: 100px;\n    height: 100px;\n    transform: translate(-50%, -50%);\n    background: url('../images/reticle.png') no-repeat 0 0;\n    border-radius: 50%;\n    box-shadow: 0 0 0 9999em rgba($base-shadow-color, 0.35);\n  }\n\n  &__overlay {\n    position: absolute;\n    width: 100%;\n    height: 100%;\n    top: 0;\n    left: 0;\n  }\n}\n\n.account__header__content {\n  color: $darker-text-color;\n  font-size: 14px;\n  font-weight: 400;\n  overflow: hidden;\n  word-break: normal;\n  word-wrap: break-word;\n\n  p {\n    margin-bottom: 20px;\n\n    &:last-child {\n      margin-bottom: 0;\n    }\n  }\n\n  a {\n    color: inherit;\n    text-decoration: underline;\n\n    &:hover {\n      text-decoration: none;\n    }\n  }\n}\n\n.account__header {\n  overflow: hidden;\n\n  &.inactive {\n    opacity: 0.5;\n\n    .account__header__image,\n    .account__avatar {\n      filter: grayscale(100%);\n    }\n  }\n\n  &__info {\n    position: absolute;\n    top: 10px;\n    left: 10px;\n  }\n\n  &__image {\n    overflow: hidden;\n    height: 145px;\n    position: relative;\n    background: darken($ui-base-color, 4%);\n\n    img {\n      object-fit: cover;\n      display: block;\n      width: 100%;\n      height: 100%;\n      margin: 0;\n    }\n  }\n\n  &__bar {\n    position: relative;\n    background: lighten($ui-base-color, 4%);\n    padding: 5px;\n    border-bottom: 1px solid lighten($ui-base-color, 12%);\n\n    .avatar {\n      display: block;\n      flex: 0 0 auto;\n      width: 94px;\n      margin-left: -2px;\n\n      .account__avatar {\n        background: darken($ui-base-color, 8%);\n        border: 2px solid lighten($ui-base-color, 4%);\n      }\n    }\n  }\n\n  &__tabs {\n    display: flex;\n    align-items: flex-start;\n    padding: 7px 5px;\n    margin-top: -55px;\n\n    &__buttons {\n      display: flex;\n      align-items: center;\n      padding-top: 55px;\n      overflow: hidden;\n\n      .icon-button {\n        border: 1px solid lighten($ui-base-color, 12%);\n        border-radius: 4px;\n        box-sizing: content-box;\n        padding: 2px;\n      }\n\n      .button {\n        margin: 0 8px;\n      }\n    }\n\n    &__name {\n      padding: 5px;\n\n      .account-role {\n        vertical-align: top;\n      }\n\n      .emojione {\n        width: 22px;\n        height: 22px;\n      }\n\n      h1 {\n        font-size: 16px;\n        line-height: 24px;\n        color: $primary-text-color;\n        font-weight: 500;\n        overflow: hidden;\n        white-space: nowrap;\n        text-overflow: ellipsis;\n\n        small {\n          display: block;\n          font-size: 14px;\n          color: $darker-text-color;\n          font-weight: 400;\n          overflow: hidden;\n          text-overflow: ellipsis;\n        }\n      }\n    }\n\n    .spacer {\n      flex: 1 1 auto;\n    }\n  }\n\n  &__bio {\n    overflow: hidden;\n    margin: 0 -5px;\n\n    .account__header__content {\n      padding: 20px 15px;\n      padding-bottom: 5px;\n      color: $primary-text-color;\n    }\n\n    .account__header__fields {\n      margin: 0;\n      border-top: 1px solid lighten($ui-base-color, 12%);\n\n      a {\n        color: lighten($ui-highlight-color, 8%);\n      }\n\n      dl:first-child .verified {\n        border-radius: 0 4px 0 0;\n      }\n\n      .verified a {\n        color: $valid-value-color;\n      }\n    }\n  }\n\n  &__extra {\n    margin-top: 4px;\n\n    &__links {\n      font-size: 14px;\n      color: $darker-text-color;\n\n      a {\n        display: inline-block;\n        color: $darker-text-color;\n        text-decoration: none;\n        padding: 10px;\n        padding-top: 20px;\n        font-weight: 500;\n\n        strong {\n          font-weight: 700;\n          color: $primary-text-color;\n        }\n      }\n    }\n  }\n}\n\n.trends {\n  &__header {\n    color: $dark-text-color;\n    background: lighten($ui-base-color, 2%);\n    border-bottom: 1px solid darken($ui-base-color, 4%);\n    font-weight: 500;\n    padding: 15px;\n    font-size: 16px;\n    cursor: default;\n\n    .fa {\n      display: inline-block;\n      margin-right: 5px;\n    }\n  }\n\n  &__item {\n    display: flex;\n    align-items: center;\n    padding: 15px;\n    border-bottom: 1px solid lighten($ui-base-color, 8%);\n\n    &:last-child {\n      border-bottom: 0;\n    }\n\n    &__name {\n      flex: 1 1 auto;\n      color: $dark-text-color;\n      overflow: hidden;\n      text-overflow: ellipsis;\n      white-space: nowrap;\n\n      strong {\n        font-weight: 500;\n      }\n\n      a {\n        color: $darker-text-color;\n        text-decoration: none;\n        font-size: 14px;\n        font-weight: 500;\n        display: block;\n        overflow: hidden;\n        text-overflow: ellipsis;\n        white-space: nowrap;\n\n        &:hover,\n        &:focus,\n        &:active {\n          span {\n            text-decoration: underline;\n          }\n        }\n      }\n    }\n\n    &__current {\n      flex: 0 0 auto;\n      width: 100px;\n      font-size: 24px;\n      line-height: 36px;\n      font-weight: 500;\n      text-align: center;\n      color: $secondary-text-color;\n    }\n\n    &__sparkline {\n      flex: 0 0 auto;\n      width: 50px;\n\n      path {\n        stroke: lighten($highlight-text-color, 6%) !important;\n      }\n    }\n  }\n}\n\n.layout-toggle {\n  display: flex;\n  padding: 5px;\n\n  button {\n    box-sizing: border-box;\n    flex: 0 0 50%;\n    background: transparent;\n    padding: 5px;\n    border: 0;\n    position: relative;\n\n    &:hover,\n    &:focus,\n    &:active {\n      svg path:first-child {\n        fill: lighten($ui-base-color, 16%);\n      }\n    }\n  }\n\n  svg {\n    width: 100%;\n    height: auto;\n\n    path:first-child {\n      fill: lighten($ui-base-color, 12%);\n    }\n\n    path:last-child {\n      fill: darken($ui-base-color, 14%);\n    }\n  }\n\n  &__active {\n    color: $ui-highlight-color;\n    position: absolute;\n    top: 50%;\n    left: 50%;\n    transform: translate(-50%, -50%);\n    background: lighten($ui-base-color, 12%);\n    border-radius: 50%;\n    padding: 0.35rem;\n  }\n}\n"
  },
  {
    "path": "app/javascript/styles/mastodon/containers.scss",
    "content": ".container-alt {\n  width: 700px;\n  margin: 0 auto;\n  margin-top: 40px;\n\n  @media screen and (max-width: 740px) {\n    width: 100%;\n    margin: 0;\n  }\n}\n\n.logo-container {\n  margin: 100px auto 50px;\n\n  @media screen and (max-width: 500px) {\n    margin: 40px auto 0;\n  }\n\n  h1 {\n    display: flex;\n    justify-content: center;\n    align-items: center;\n\n    svg {\n      fill: $primary-text-color;\n      height: 42px;\n      margin-right: 10px;\n    }\n\n    a {\n      display: flex;\n      justify-content: center;\n      align-items: center;\n      color: $primary-text-color;\n      text-decoration: none;\n      outline: 0;\n      padding: 12px 16px;\n      line-height: 32px;\n      font-family: $font-display, sans-serif;\n      font-weight: 500;\n      font-size: 14px;\n    }\n  }\n}\n\n.compose-standalone {\n  .compose-form {\n    width: 400px;\n    margin: 0 auto;\n    padding: 20px 0;\n    margin-top: 40px;\n    box-sizing: border-box;\n\n    @media screen and (max-width: 400px) {\n      width: 100%;\n      margin-top: 0;\n      padding: 20px;\n    }\n  }\n}\n\n.account-header {\n  width: 400px;\n  margin: 0 auto;\n  display: flex;\n  font-size: 13px;\n  line-height: 18px;\n  box-sizing: border-box;\n  padding: 20px 0;\n  padding-bottom: 0;\n  margin-bottom: -30px;\n  margin-top: 40px;\n\n  @media screen and (max-width: 440px) {\n    width: 100%;\n    margin: 0;\n    margin-bottom: 10px;\n    padding: 20px;\n    padding-bottom: 0;\n  }\n\n  .avatar {\n    width: 40px;\n    height: 40px;\n    margin-right: 8px;\n\n    img {\n      width: 100%;\n      height: 100%;\n      display: block;\n      margin: 0;\n      border-radius: 4px;\n    }\n  }\n\n  .name {\n    flex: 1 1 auto;\n    color: $secondary-text-color;\n    width: calc(100% - 88px);\n\n    .username {\n      display: block;\n      font-weight: 500;\n      text-overflow: ellipsis;\n      overflow: hidden;\n    }\n  }\n\n  .logout-link {\n    display: block;\n    font-size: 32px;\n    line-height: 40px;\n    margin-left: 8px;\n  }\n}\n\n.grid-3 {\n  display: grid;\n  grid-gap: 10px;\n  grid-template-columns: 3fr 1fr;\n  grid-auto-columns: 25%;\n  grid-auto-rows: max-content;\n\n  .column-0 {\n    grid-column: 1 / 3;\n    grid-row: 1;\n  }\n\n  .column-1 {\n    grid-column: 1;\n    grid-row: 2;\n  }\n\n  .column-2 {\n    grid-column: 2;\n    grid-row: 2;\n  }\n\n  .column-3 {\n    grid-column: 1 / 3;\n    grid-row: 3;\n  }\n\n  .landing-page__call-to-action {\n    min-height: 100%;\n  }\n\n  @media screen and (max-width: 738px) {\n    grid-template-columns: minmax(0, 50%) minmax(0, 50%);\n\n    .landing-page__call-to-action {\n      padding: 20px;\n      display: flex;\n      align-items: center;\n      justify-content: center;\n    }\n\n    .row__information-board {\n      width: 100%;\n      justify-content: center;\n      align-items: center;\n    }\n\n    .row__mascot {\n      display: none;\n    }\n  }\n\n  @media screen and (max-width: $no-gap-breakpoint) {\n    grid-gap: 0;\n    grid-template-columns: minmax(0, 100%);\n\n    .column-0 {\n      grid-column: 1;\n    }\n\n    .column-1 {\n      grid-column: 1;\n      grid-row: 3;\n    }\n\n    .column-2 {\n      grid-column: 1;\n      grid-row: 2;\n    }\n\n    .column-3 {\n      grid-column: 1;\n      grid-row: 4;\n    }\n  }\n}\n\n.public-layout {\n  @media screen and (max-width: $no-gap-breakpoint) {\n    padding-top: 48px;\n  }\n\n  .container {\n    max-width: 960px;\n\n    @media screen and (max-width: $no-gap-breakpoint) {\n      padding: 0;\n    }\n  }\n\n  .header {\n    background: lighten($ui-base-color, 8%);\n    box-shadow: 0 0 15px rgba($base-shadow-color, 0.2);\n    border-radius: 4px;\n    height: 48px;\n    margin: 10px 0;\n    display: flex;\n    align-items: stretch;\n    justify-content: center;\n    flex-wrap: nowrap;\n    overflow: hidden;\n\n    @media screen and (max-width: $no-gap-breakpoint) {\n      position: fixed;\n      width: 100%;\n      top: 0;\n      left: 0;\n      margin: 0;\n      border-radius: 0;\n      box-shadow: none;\n      z-index: 110;\n    }\n\n    & > div {\n      flex: 1 1 33.3%;\n      min-height: 1px;\n    }\n\n    .nav-left {\n      display: flex;\n      align-items: stretch;\n      justify-content: flex-start;\n      flex-wrap: nowrap;\n    }\n\n    .nav-center {\n      display: flex;\n      align-items: stretch;\n      justify-content: center;\n      flex-wrap: nowrap;\n    }\n\n    .nav-right {\n      display: flex;\n      align-items: stretch;\n      justify-content: flex-end;\n      flex-wrap: nowrap;\n    }\n\n    .brand {\n      display: block;\n      padding: 15px;\n\n      svg {\n        display: block;\n        height: 18px;\n        width: auto;\n        position: relative;\n        bottom: -2px;\n        fill: $primary-text-color;\n\n        @media screen and (max-width: $no-gap-breakpoint) {\n          height: 20px;\n        }\n      }\n\n      &:hover,\n      &:focus,\n      &:active {\n        background: lighten($ui-base-color, 12%);\n      }\n    }\n\n    .nav-link {\n      display: flex;\n      align-items: center;\n      padding: 0 1rem;\n      font-size: 12px;\n      font-weight: 500;\n      text-decoration: none;\n      color: $darker-text-color;\n      white-space: nowrap;\n      text-align: center;\n\n      &:hover,\n      &:focus,\n      &:active {\n        text-decoration: underline;\n        color: $primary-text-color;\n      }\n\n      @media screen and (max-width: 550px) {\n        &.optional {\n          display: none;\n        }\n      }\n    }\n\n    .nav-button {\n      background: lighten($ui-base-color, 16%);\n      margin: 8px;\n      margin-left: 0;\n      border-radius: 4px;\n\n      &:hover,\n      &:focus,\n      &:active {\n        text-decoration: none;\n        background: lighten($ui-base-color, 20%);\n      }\n    }\n  }\n\n  $no-columns-breakpoint: 600px;\n\n  .grid {\n    display: grid;\n    grid-gap: 10px;\n    grid-template-columns: minmax(300px, 3fr) minmax(298px, 1fr);\n    grid-auto-columns: 25%;\n    grid-auto-rows: max-content;\n\n    .column-0 {\n      grid-row: 1;\n      grid-column: 1;\n    }\n\n    .column-1 {\n      grid-row: 1;\n      grid-column: 2;\n    }\n\n    @media screen and (max-width: $no-columns-breakpoint) {\n      grid-template-columns: 100%;\n      grid-gap: 0;\n\n      .column-1 {\n        display: none;\n      }\n    }\n  }\n\n  .public-account-header {\n    overflow: hidden;\n    margin-bottom: 10px;\n    box-shadow: 0 0 15px rgba($base-shadow-color, 0.2);\n\n    &.inactive {\n      opacity: 0.5;\n\n      .public-account-header__image,\n      .avatar {\n        filter: grayscale(100%);\n      }\n\n      .logo-button {\n        background-color: $secondary-text-color;\n      }\n    }\n\n    &__image {\n      border-radius: 4px 4px 0 0;\n      overflow: hidden;\n      height: 300px;\n      position: relative;\n      background: darken($ui-base-color, 12%);\n\n      &::after {\n        content: \"\";\n        display: block;\n        position: absolute;\n        width: 100%;\n        height: 100%;\n        box-shadow: inset 0 -1px 1px 1px rgba($base-shadow-color, 0.15);\n        top: 0;\n        left: 0;\n      }\n\n      img {\n        object-fit: cover;\n        display: block;\n        width: 100%;\n        height: 100%;\n        margin: 0;\n        border-radius: 4px 4px 0 0;\n      }\n\n      @media screen and (max-width: 600px) {\n        height: 200px;\n      }\n    }\n\n    &--no-bar {\n      margin-bottom: 0;\n\n      .public-account-header__image,\n      .public-account-header__image img {\n        border-radius: 4px;\n\n        @media screen and (max-width: $no-gap-breakpoint) {\n          border-radius: 0;\n        }\n      }\n    }\n\n    @media screen and (max-width: $no-gap-breakpoint) {\n      margin-bottom: 0;\n      box-shadow: none;\n\n      &__image::after {\n        display: none;\n      }\n\n      &__image,\n      &__image img {\n        border-radius: 0;\n      }\n    }\n\n    &__bar {\n      position: relative;\n      margin-top: -80px;\n      display: flex;\n      justify-content: flex-start;\n\n      &::before {\n        content: \"\";\n        display: block;\n        background: lighten($ui-base-color, 4%);\n        position: absolute;\n        bottom: 0;\n        left: 0;\n        right: 0;\n        height: 60px;\n        border-radius: 0 0 4px 4px;\n        z-index: -1;\n      }\n\n      .avatar {\n        display: block;\n        width: 120px;\n        height: 120px;\n        padding-left: 20px - 4px;\n        flex: 0 0 auto;\n\n        img {\n          display: block;\n          width: 100%;\n          height: 100%;\n          margin: 0;\n          border-radius: 50%;\n          border: 4px solid lighten($ui-base-color, 4%);\n          background: darken($ui-base-color, 8%);\n        }\n      }\n\n      @media screen and (max-width: 600px) {\n        margin-top: 0;\n        background: lighten($ui-base-color, 4%);\n        border-radius: 0 0 4px 4px;\n        padding: 5px;\n\n        &::before {\n          display: none;\n        }\n\n        .avatar {\n          width: 48px;\n          height: 48px;\n          padding: 7px 0;\n          padding-left: 10px;\n\n          img {\n            border: 0;\n            border-radius: 4px;\n          }\n\n          @media screen and (max-width: 360px) {\n            display: none;\n          }\n        }\n      }\n\n      @media screen and (max-width: $no-gap-breakpoint) {\n        border-radius: 0;\n      }\n\n      @media screen and (max-width: $no-columns-breakpoint) {\n        flex-wrap: wrap;\n      }\n    }\n\n    &__tabs {\n      flex: 1 1 auto;\n      margin-left: 20px;\n\n      &__name {\n        padding-top: 20px;\n        padding-bottom: 8px;\n\n        h1 {\n          font-size: 20px;\n          line-height: 18px * 1.5;\n          color: $primary-text-color;\n          font-weight: 500;\n          overflow: hidden;\n          white-space: nowrap;\n          text-overflow: ellipsis;\n          text-shadow: 1px 1px 1px $base-shadow-color;\n\n          small {\n            display: block;\n            font-size: 14px;\n            color: $primary-text-color;\n            font-weight: 400;\n            overflow: hidden;\n            text-overflow: ellipsis;\n          }\n        }\n      }\n\n      @media screen and (max-width: 600px) {\n        margin-left: 15px;\n        display: flex;\n        justify-content: space-between;\n        align-items: center;\n\n        &__name {\n          padding-top: 0;\n          padding-bottom: 0;\n\n          h1 {\n            font-size: 16px;\n            line-height: 24px;\n            text-shadow: none;\n\n            small {\n              color: $darker-text-color;\n            }\n          }\n        }\n      }\n\n      &__tabs {\n        display: flex;\n        justify-content: flex-start;\n        align-items: stretch;\n        height: 58px;\n\n        .details-counters {\n          display: flex;\n          flex-direction: row;\n          min-width: 300px;\n        }\n\n        @media screen and (max-width: $no-columns-breakpoint) {\n          .details-counters {\n            display: none;\n          }\n        }\n\n        .counter {\n          width: 33.3%;\n          box-sizing: border-box;\n          flex: 0 0 auto;\n          color: $darker-text-color;\n          padding: 10px;\n          border-right: 1px solid lighten($ui-base-color, 4%);\n          cursor: default;\n          text-align: center;\n          position: relative;\n\n          a {\n            display: block;\n          }\n\n          &:last-child {\n            border-right: 0;\n          }\n\n          &::after {\n            display: block;\n            content: \"\";\n            position: absolute;\n            bottom: 0;\n            left: 0;\n            width: 100%;\n            border-bottom: 4px solid $ui-primary-color;\n            opacity: 0.5;\n            transition: all 400ms ease;\n          }\n\n          &.active {\n            &::after {\n              border-bottom: 4px solid $highlight-text-color;\n              opacity: 1;\n            }\n\n            &.inactive::after {\n              border-bottom-color: $secondary-text-color;\n            }\n          }\n\n          &:hover {\n            &::after {\n              opacity: 1;\n              transition-duration: 100ms;\n            }\n          }\n\n          a {\n            text-decoration: none;\n            color: inherit;\n          }\n\n          .counter-label {\n            font-size: 12px;\n            display: block;\n          }\n\n          .counter-number {\n            font-weight: 500;\n            font-size: 18px;\n            margin-bottom: 5px;\n            color: $primary-text-color;\n            font-family: $font-display, sans-serif;\n          }\n        }\n\n        .spacer {\n          flex: 1 1 auto;\n          height: 1px;\n        }\n\n        &__buttons {\n          padding: 7px 8px;\n        }\n      }\n    }\n\n    &__extra {\n      display: none;\n      margin-top: 4px;\n\n      .public-account-bio {\n        border-radius: 0;\n        box-shadow: none;\n        background: transparent;\n        margin: 0 -5px;\n\n        .account__header__fields {\n          border-top: 1px solid lighten($ui-base-color, 12%);\n        }\n\n        .roles {\n          display: none;\n        }\n      }\n\n      &__links {\n        margin-top: -15px;\n        font-size: 14px;\n        color: $darker-text-color;\n\n        a {\n          display: inline-block;\n          color: $darker-text-color;\n          text-decoration: none;\n          padding: 15px;\n          font-weight: 500;\n\n          strong {\n            font-weight: 700;\n            color: $primary-text-color;\n          }\n        }\n      }\n\n      @media screen and (max-width: $no-columns-breakpoint) {\n        display: block;\n        flex: 100%;\n      }\n    }\n  }\n\n  .account__section-headline {\n    border-radius: 4px 4px 0 0;\n\n    @media screen and (max-width: $no-gap-breakpoint) {\n      border-radius: 0;\n    }\n  }\n\n  .detailed-status__meta {\n    margin-top: 25px;\n  }\n\n  .public-account-bio {\n    background: lighten($ui-base-color, 8%);\n    box-shadow: 0 0 15px rgba($base-shadow-color, 0.2);\n    border-radius: 4px;\n    overflow: hidden;\n    margin-bottom: 10px;\n\n    @media screen and (max-width: $no-gap-breakpoint) {\n      box-shadow: none;\n      margin-bottom: 0;\n      border-radius: 0;\n    }\n\n    .account__header__fields {\n      margin: 0;\n      border-top: 0;\n\n      a {\n        color: lighten($ui-highlight-color, 8%);\n      }\n\n      dl:first-child .verified {\n        border-radius: 0 4px 0 0;\n      }\n\n      .verified a {\n        color: $valid-value-color;\n      }\n    }\n\n    .account__header__content {\n      padding: 20px;\n      padding-bottom: 0;\n      color: $primary-text-color;\n    }\n\n    &__extra,\n    .roles {\n      padding: 20px;\n      font-size: 14px;\n      color: $darker-text-color;\n    }\n\n    .roles {\n      padding-bottom: 0;\n    }\n  }\n\n  .static-icon-button {\n    color: $action-button-color;\n    font-size: 18px;\n\n    & > span {\n      font-size: 14px;\n      font-weight: 500;\n    }\n  }\n\n  .card-grid {\n    display: flex;\n    flex-wrap: wrap;\n    min-width: 100%;\n    margin: 0 -5px;\n\n    & > div {\n      box-sizing: border-box;\n      flex: 1 0 auto;\n      width: 300px;\n      padding: 0 5px;\n      margin-bottom: 10px;\n      max-width: 33.333%;\n\n      @media screen and (max-width: 900px) {\n        max-width: 50%;\n      }\n\n      @media screen and (max-width: 600px) {\n        max-width: 100%;\n      }\n    }\n\n    @media screen and (max-width: $no-gap-breakpoint) {\n      margin: 0;\n      border-top: 1px solid lighten($ui-base-color, 8%);\n\n      & > div {\n        width: 100%;\n        padding: 0;\n        margin-bottom: 0;\n        border-bottom: 1px solid lighten($ui-base-color, 8%);\n\n        &:last-child {\n          border-bottom: 0;\n        }\n\n        .card__bar {\n          background: $ui-base-color;\n\n          &:hover,\n          &:active,\n          &:focus {\n            background: lighten($ui-base-color, 4%);\n          }\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "app/javascript/styles/mastodon/dashboard.scss",
    "content": ".dashboard__counters {\n  display: flex;\n  flex-wrap: wrap;\n  margin: 0 -5px;\n  margin-bottom: 20px;\n\n  & > div {\n    box-sizing: border-box;\n    flex: 0 0 33.333%;\n    padding: 0 5px;\n    margin-bottom: 10px;\n\n    & > div,\n    & > a {\n      padding: 20px;\n      background: lighten($ui-base-color, 4%);\n      border-radius: 4px;\n    }\n\n    & > a {\n      text-decoration: none;\n      color: inherit;\n      display: block;\n\n      &:hover,\n      &:focus,\n      &:active {\n        background: lighten($ui-base-color, 8%);\n      }\n    }\n  }\n\n  &__num,\n  &__text {\n    text-align: center;\n    font-weight: 500;\n    font-size: 24px;\n    line-height: 21px;\n    color: $primary-text-color;\n    font-family: $font-display, sans-serif;\n    margin-bottom: 20px;\n    line-height: 30px;\n  }\n\n  &__text {\n    font-size: 18px;\n  }\n\n  &__label {\n    font-size: 14px;\n    color: $darker-text-color;\n    text-align: center;\n    font-weight: 500;\n  }\n}\n\n.dashboard__widgets {\n  display: flex;\n  flex-wrap: wrap;\n  margin: 0 -5px;\n\n  & > div {\n    flex: 0 0 33.333%;\n    margin-bottom: 20px;\n\n    & > div {\n      padding: 0 5px;\n    }\n  }\n\n  a:not(.name-tag) {\n    color: $ui-secondary-color;\n    font-weight: 500;\n    text-decoration: none;\n  }\n}\n"
  },
  {
    "path": "app/javascript/styles/mastodon/emoji_picker.scss",
    "content": ".emoji-mart {\n  font-size: 13px;\n  display: inline-block;\n  color: $inverted-text-color;\n\n  &,\n  * {\n    box-sizing: border-box;\n    line-height: 1.15;\n  }\n\n  .emoji-mart-emoji {\n    padding: 6px;\n  }\n}\n\n.emoji-mart-bar {\n  border: 0 solid darken($ui-secondary-color, 8%);\n\n  &:first-child {\n    border-bottom-width: 1px;\n    border-top-left-radius: 5px;\n    border-top-right-radius: 5px;\n    background: $ui-secondary-color;\n  }\n\n  &:last-child {\n    border-top-width: 1px;\n    border-bottom-left-radius: 5px;\n    border-bottom-right-radius: 5px;\n    display: none;\n  }\n}\n\n.emoji-mart-anchors {\n  display: flex;\n  justify-content: space-between;\n  padding: 0 6px;\n  color: $lighter-text-color;\n  line-height: 0;\n}\n\n.emoji-mart-anchor {\n  position: relative;\n  flex: 1;\n  text-align: center;\n  padding: 12px 4px;\n  overflow: hidden;\n  transition: color .1s ease-out;\n  cursor: pointer;\n\n  &:hover {\n    color: darken($lighter-text-color, 4%);\n  }\n}\n\n.emoji-mart-anchor-selected {\n  color: $highlight-text-color;\n\n  &:hover {\n    color: darken($highlight-text-color, 4%);\n  }\n\n  .emoji-mart-anchor-bar {\n    bottom: -1px;\n  }\n}\n\n.emoji-mart-anchor-bar {\n  position: absolute;\n  bottom: -5px;\n  left: 0;\n  width: 100%;\n  height: 4px;\n  background-color: $highlight-text-color;\n}\n\n.emoji-mart-anchors {\n  i {\n    display: inline-block;\n    width: 100%;\n    max-width: 22px;\n  }\n\n  svg {\n    fill: currentColor;\n    max-height: 18px;\n  }\n}\n\n.emoji-mart-scroll {\n  overflow-y: scroll;\n  height: 270px;\n  max-height: 35vh;\n  padding: 0 6px 6px;\n  background: $simple-background-color;\n  will-change: transform;\n\n  &::-webkit-scrollbar-track:hover,\n  &::-webkit-scrollbar-track:active {\n    background-color: rgba($base-overlay-background, 0.3);\n  }\n}\n\n.emoji-mart-search {\n  padding: 10px;\n  padding-right: 45px;\n  background: $simple-background-color;\n\n  input {\n    font-size: 14px;\n    font-weight: 400;\n    padding: 7px 9px;\n    font-family: inherit;\n    display: block;\n    width: 100%;\n    background: rgba($ui-secondary-color, 0.3);\n    color: $inverted-text-color;\n    border: 1px solid $ui-secondary-color;\n    border-radius: 4px;\n\n    &::-moz-focus-inner {\n      border: 0;\n    }\n\n    &::-moz-focus-inner,\n    &:focus,\n    &:active {\n      outline: 0 !important;\n    }\n  }\n}\n\n.emoji-mart-category .emoji-mart-emoji {\n  cursor: pointer;\n\n  span {\n    z-index: 1;\n    position: relative;\n    text-align: center;\n  }\n\n  &:hover::before {\n    z-index: 0;\n    content: \"\";\n    position: absolute;\n    top: 0;\n    left: 0;\n    width: 100%;\n    height: 100%;\n    background-color: rgba($ui-secondary-color, 0.7);\n    border-radius: 100%;\n  }\n}\n\n.emoji-mart-category-label {\n  z-index: 2;\n  position: relative;\n  position: -webkit-sticky;\n  position: sticky;\n  top: 0;\n\n  span {\n    display: block;\n    width: 100%;\n    font-weight: 500;\n    padding: 5px 6px;\n    background: $simple-background-color;\n  }\n}\n\n.emoji-mart-emoji {\n  position: relative;\n  display: inline-block;\n  font-size: 0;\n\n  span {\n    width: 22px;\n    height: 22px;\n  }\n}\n\n.emoji-mart-no-results {\n  font-size: 14px;\n  text-align: center;\n  padding-top: 70px;\n  color: $light-text-color;\n\n  .emoji-mart-category-label {\n    display: none;\n  }\n\n  .emoji-mart-no-results-label {\n    margin-top: .2em;\n  }\n\n  .emoji-mart-emoji:hover::before {\n    content: none;\n  }\n}\n\n.emoji-mart-preview {\n  display: none;\n}\n"
  },
  {
    "path": "app/javascript/styles/mastodon/footer.scss",
    "content": ".public-layout {\n  .footer {\n    text-align: left;\n    padding-top: 20px;\n    padding-bottom: 60px;\n    font-size: 12px;\n    color: lighten($ui-base-color, 34%);\n\n    @media screen and (max-width: $no-gap-breakpoint) {\n      padding-left: 20px;\n      padding-right: 20px;\n    }\n\n    .grid {\n      display: grid;\n      grid-gap: 10px;\n      grid-template-columns: 1fr 1fr 2fr 1fr 1fr;\n\n      .column-0 {\n        grid-column: 1;\n        grid-row: 1;\n        min-width: 0;\n      }\n\n      .column-1 {\n        grid-column: 2;\n        grid-row: 1;\n        min-width: 0;\n      }\n\n      .column-2 {\n        grid-column: 3;\n        grid-row: 1;\n        min-width: 0;\n        text-align: center;\n\n        h4 a {\n          color: lighten($ui-base-color, 34%);\n        }\n      }\n\n      .column-3 {\n        grid-column: 4;\n        grid-row: 1;\n        min-width: 0;\n      }\n\n      .column-4 {\n        grid-column: 5;\n        grid-row: 1;\n        min-width: 0;\n      }\n\n      @media screen and (max-width: 690px) {\n        grid-template-columns: 1fr 2fr 1fr;\n\n        .column-0,\n        .column-1 {\n          grid-column: 1;\n        }\n\n        .column-1 {\n          grid-row: 2;\n        }\n\n        .column-2 {\n          grid-column: 2;\n        }\n\n        .column-3,\n        .column-4 {\n          grid-column: 3;\n        }\n\n        .column-4 {\n          grid-row: 2;\n        }\n      }\n\n      @media screen and (max-width: 600px) {\n        .column-1 {\n          display: block;\n        }\n      }\n\n      @media screen and (max-width: $no-gap-breakpoint) {\n        .column-0,\n        .column-1,\n        .column-3,\n        .column-4 {\n          display: none;\n        }\n      }\n    }\n\n    h4 {\n      text-transform: uppercase;\n      font-weight: 700;\n      margin-bottom: 8px;\n      color: $darker-text-color;\n\n      a {\n        color: inherit;\n        text-decoration: none;\n      }\n    }\n\n    ul a {\n      text-decoration: none;\n      color: lighten($ui-base-color, 34%);\n\n      &:hover,\n      &:active,\n      &:focus {\n        text-decoration: underline;\n      }\n    }\n\n    .brand {\n      svg {\n        display: block;\n        height: 36px;\n        width: auto;\n        margin: 0 auto;\n        fill: lighten($ui-base-color, 34%);\n      }\n\n      &:hover,\n      &:focus,\n      &:active {\n        svg path {\n          fill: lighten($ui-base-color, 38%);\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "app/javascript/styles/mastodon/forms.scss",
    "content": "$no-columns-breakpoint: 600px;\n\ncode {\n  font-family: $font-monospace, monospace;\n  font-weight: 400;\n}\n\n.form-container {\n  max-width: 400px;\n  padding: 20px;\n  margin: 0 auto;\n}\n\n.simple_form {\n  .input {\n    margin-bottom: 15px;\n    overflow: hidden;\n\n    &.hidden {\n      margin: 0;\n    }\n\n    &.radio_buttons {\n      .radio {\n        margin-bottom: 15px;\n\n        &:last-child {\n          margin-bottom: 0;\n        }\n      }\n\n      .radio > label {\n        position: relative;\n        padding-left: 28px;\n\n        input {\n          position: absolute;\n          top: -2px;\n          left: 0;\n        }\n      }\n    }\n\n    &.boolean {\n      position: relative;\n      margin-bottom: 0;\n\n      .label_input > label {\n        font-family: inherit;\n        font-size: 14px;\n        padding-top: 5px;\n        color: $primary-text-color;\n        display: block;\n        width: auto;\n      }\n\n      .label_input,\n      .hint {\n        padding-left: 28px;\n      }\n\n      .label_input__wrapper {\n        position: static;\n      }\n\n      label.checkbox {\n        position: absolute;\n        top: 2px;\n        left: 0;\n      }\n\n      label a {\n        color: $highlight-text-color;\n        text-decoration: underline;\n\n        &:hover,\n        &:active,\n        &:focus {\n          text-decoration: none;\n        }\n      }\n\n      .recommended {\n        position: absolute;\n        margin: 0 4px;\n        margin-top: -2px;\n      }\n    }\n  }\n\n  .row {\n    display: flex;\n    margin: 0 -5px;\n\n    .input {\n      box-sizing: border-box;\n      flex: 1 1 auto;\n      width: 50%;\n      padding: 0 5px;\n    }\n  }\n\n  .hint {\n    color: $darker-text-color;\n\n    a {\n      color: $highlight-text-color;\n    }\n\n    code {\n      border-radius: 3px;\n      padding: 0.2em 0.4em;\n      background: darken($ui-base-color, 12%);\n    }\n  }\n\n  span.hint {\n    display: block;\n    font-size: 12px;\n    margin-top: 4px;\n  }\n\n  p.hint {\n    margin-bottom: 15px;\n    color: $darker-text-color;\n\n    &.subtle-hint {\n      text-align: center;\n      font-size: 12px;\n      line-height: 18px;\n      margin-top: 15px;\n      margin-bottom: 0;\n    }\n  }\n\n  .card {\n    margin-bottom: 15px;\n  }\n\n  strong {\n    font-weight: 500;\n\n    @each $lang in $cjk-langs {\n      &:lang(#{$lang}) {\n        font-weight: 700;\n      }\n    }\n  }\n\n  .input.with_floating_label {\n    .label_input {\n      display: flex;\n\n      & > label {\n        font-family: inherit;\n        font-size: 14px;\n        color: $primary-text-color;\n        font-weight: 500;\n        min-width: 150px;\n        flex: 0 0 auto;\n      }\n\n      input,\n      select {\n        flex: 1 1 auto;\n      }\n    }\n\n    &.select .hint {\n      margin-top: 6px;\n      margin-left: 150px;\n    }\n  }\n\n  .input.with_label {\n    .label_input > label {\n      font-family: inherit;\n      font-size: 14px;\n      color: $primary-text-color;\n      display: block;\n      margin-bottom: 8px;\n      word-wrap: break-word;\n      font-weight: 500;\n    }\n\n    .hint {\n      margin-top: 6px;\n    }\n\n    ul {\n      flex: 390px;\n    }\n  }\n\n  .input.with_block_label {\n    max-width: none;\n\n    & > label {\n      font-family: inherit;\n      font-size: 16px;\n      color: $primary-text-color;\n      display: block;\n      font-weight: 500;\n      padding-top: 5px;\n    }\n\n    .hint {\n      margin-bottom: 15px;\n    }\n\n    ul {\n      columns: 2;\n    }\n  }\n\n  .required abbr {\n    text-decoration: none;\n    color: lighten($error-value-color, 12%);\n  }\n\n  .fields-group {\n    margin-bottom: 25px;\n\n    .input:last-child {\n      margin-bottom: 0;\n    }\n  }\n\n  .fields-row {\n    display: flex;\n    margin: 0 -10px;\n    padding-top: 5px;\n    margin-bottom: 25px;\n\n    .input {\n      max-width: none;\n    }\n\n    &__column {\n      box-sizing: border-box;\n      padding: 0 10px;\n      flex: 1 1 auto;\n      min-height: 1px;\n\n      &-6 {\n        max-width: 50%;\n      }\n    }\n\n    .fields-group:last-child,\n    .fields-row__column.fields-group {\n      margin-bottom: 0;\n    }\n\n    @media screen and (max-width: $no-columns-breakpoint) {\n      display: block;\n      margin-bottom: 0;\n\n      &__column {\n        max-width: none;\n      }\n\n      .fields-group:last-child,\n      .fields-row__column.fields-group,\n      .fields-row__column {\n        margin-bottom: 25px;\n      }\n    }\n  }\n\n  .input.radio_buttons .radio label {\n    margin-bottom: 5px;\n    font-family: inherit;\n    font-size: 14px;\n    color: $primary-text-color;\n    display: block;\n    width: auto;\n  }\n\n  .check_boxes {\n    .checkbox {\n      label {\n        font-family: inherit;\n        font-size: 14px;\n        color: $primary-text-color;\n        display: inline-block;\n        width: auto;\n        position: relative;\n        padding-top: 5px;\n        padding-left: 25px;\n        flex: 1 1 auto;\n      }\n\n      input[type=checkbox] {\n        position: absolute;\n        left: 0;\n        top: 5px;\n        margin: 0;\n      }\n    }\n  }\n\n  input[type=text],\n  input[type=number],\n  input[type=email],\n  input[type=password],\n  textarea {\n    box-sizing: border-box;\n    font-size: 16px;\n    color: $primary-text-color;\n    display: block;\n    width: 100%;\n    outline: 0;\n    font-family: inherit;\n    resize: vertical;\n    background: darken($ui-base-color, 10%);\n    border: 1px solid darken($ui-base-color, 14%);\n    border-radius: 4px;\n    padding: 10px;\n\n    &:invalid {\n      box-shadow: none;\n    }\n\n    &:focus:invalid:not(:placeholder-shown) {\n      border-color: lighten($error-red, 12%);\n    }\n\n    &:required:valid {\n      border-color: $valid-value-color;\n    }\n\n    &:hover {\n      border-color: darken($ui-base-color, 20%);\n    }\n\n    &:active,\n    &:focus {\n      border-color: $highlight-text-color;\n      background: darken($ui-base-color, 8%);\n    }\n  }\n\n  .input.field_with_errors {\n    label {\n      color: lighten($error-red, 12%);\n    }\n\n    input[type=text],\n    input[type=number],\n    input[type=email],\n    input[type=password],\n    textarea,\n    select {\n      border-color: lighten($error-red, 12%);\n    }\n\n    .error {\n      display: block;\n      font-weight: 500;\n      color: lighten($error-red, 12%);\n      margin-top: 4px;\n    }\n  }\n\n  .input.disabled {\n    opacity: 0.5;\n  }\n\n  .actions {\n    margin-top: 30px;\n    display: flex;\n\n    &.actions--top {\n      margin-top: 0;\n      margin-bottom: 30px;\n    }\n  }\n\n  button,\n  .button,\n  .block-button {\n    display: block;\n    width: 100%;\n    border: 0;\n    border-radius: 4px;\n    background: $ui-highlight-color;\n    color: $primary-text-color;\n    font-size: 18px;\n    line-height: inherit;\n    height: auto;\n    padding: 10px;\n    text-transform: uppercase;\n    text-decoration: none;\n    text-align: center;\n    box-sizing: border-box;\n    cursor: pointer;\n    font-weight: 500;\n    outline: 0;\n    margin-bottom: 10px;\n    margin-right: 10px;\n\n    &:last-child {\n      margin-right: 0;\n    }\n\n    &:hover {\n      background-color: lighten($ui-highlight-color, 5%);\n    }\n\n    &:active,\n    &:focus {\n      background-color: darken($ui-highlight-color, 5%);\n    }\n\n    &:disabled:hover {\n      background-color: $ui-primary-color;\n    }\n\n    &.negative {\n      background: $error-value-color;\n\n      &:hover {\n        background-color: lighten($error-value-color, 5%);\n      }\n\n      &:active,\n      &:focus {\n        background-color: darken($error-value-color, 5%);\n      }\n    }\n  }\n\n  select {\n    appearance: none;\n    box-sizing: border-box;\n    font-size: 16px;\n    color: $primary-text-color;\n    display: block;\n    width: 100%;\n    outline: 0;\n    font-family: inherit;\n    resize: vertical;\n    background: darken($ui-base-color, 10%) url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14.933 18.467' height='19.698' width='15.929'><path d='M3.467 14.967l-3.393-3.5H14.86l-3.392 3.5c-1.866 1.925-3.666 3.5-4 3.5-.335 0-2.135-1.575-4-3.5zm.266-11.234L7.467 0 11.2 3.733l3.733 3.734H0l3.733-3.734z' fill='#{hex-color(lighten($ui-base-color, 12%))}'/></svg>\") no-repeat right 8px center / auto 16px;\n    border: 1px solid darken($ui-base-color, 14%);\n    border-radius: 4px;\n    padding-left: 10px;\n    padding-right: 30px;\n    height: 41px;\n  }\n\n  h4 {\n    margin-bottom: 15px !important;\n  }\n\n  .label_input {\n    &__wrapper {\n      position: relative;\n    }\n\n    &__append {\n      position: absolute;\n      right: 3px;\n      top: 1px;\n      padding: 10px;\n      padding-bottom: 9px;\n      font-size: 16px;\n      color: $dark-text-color;\n      font-family: inherit;\n      pointer-events: none;\n      cursor: default;\n      max-width: 140px;\n      white-space: nowrap;\n      overflow: hidden;\n\n      &::after {\n        content: '';\n        display: block;\n        position: absolute;\n        top: 0;\n        right: 0;\n        bottom: 1px;\n        width: 5px;\n        background-image: linear-gradient(to right, rgba(darken($ui-base-color, 10%), 0), darken($ui-base-color, 10%));\n      }\n    }\n  }\n\n  &__overlay-area {\n    position: relative;\n\n    &__overlay {\n      position: absolute;\n      top: 0;\n      left: 0;\n      width: 100%;\n      height: 100%;\n      display: flex;\n      justify-content: center;\n      align-items: center;\n      background: rgba($ui-base-color, 0.65);\n      backdrop-filter: blur(2px);\n      border-radius: 4px;\n\n      &__content {\n        text-align: center;\n\n        &.rich-formatting {\n          &,\n          p {\n            color: $primary-text-color;\n          }\n        }\n      }\n    }\n  }\n}\n\n.block-icon {\n  display: block;\n  margin: 0 auto;\n  margin-bottom: 10px;\n  font-size: 24px;\n}\n\n.flash-message {\n  background: lighten($ui-base-color, 8%);\n  color: $darker-text-color;\n  border-radius: 4px;\n  padding: 15px 10px;\n  margin-bottom: 30px;\n  text-align: center;\n\n  &.notice {\n    border: 1px solid rgba($valid-value-color, 0.5);\n    background: rgba($valid-value-color, 0.25);\n    color: $valid-value-color;\n  }\n\n  &.alert {\n    border: 1px solid rgba($error-value-color, 0.5);\n    background: rgba($error-value-color, 0.25);\n    color: $error-value-color;\n  }\n\n  a {\n    display: inline-block;\n    color: $darker-text-color;\n    text-decoration: none;\n\n    &:hover {\n      color: $primary-text-color;\n      text-decoration: underline;\n    }\n  }\n\n  p {\n    margin-bottom: 15px;\n  }\n\n  .oauth-code {\n    outline: 0;\n    box-sizing: border-box;\n    display: block;\n    width: 100%;\n    border: 0;\n    padding: 10px;\n    font-family: $font-monospace, monospace;\n    background: $ui-base-color;\n    color: $primary-text-color;\n    font-size: 14px;\n    margin: 0;\n\n    &::-moz-focus-inner {\n      border: 0;\n    }\n\n    &::-moz-focus-inner,\n    &:focus,\n    &:active {\n      outline: 0 !important;\n    }\n\n    &:focus {\n      background: lighten($ui-base-color, 4%);\n    }\n  }\n\n  strong {\n    font-weight: 500;\n\n    @each $lang in $cjk-langs {\n      &:lang(#{$lang}) {\n        font-weight: 700;\n      }\n    }\n  }\n\n  @media screen and (max-width: 740px) and (min-width: 441px) {\n    margin-top: 40px;\n  }\n}\n\n.form-footer {\n  margin-top: 30px;\n  text-align: center;\n\n  a {\n    color: $darker-text-color;\n    text-decoration: none;\n\n    &:hover {\n      text-decoration: underline;\n    }\n  }\n}\n\n.quick-nav {\n  list-style: none;\n  margin-bottom: 25px;\n  font-size: 14px;\n\n  li {\n    display: inline-block;\n    margin-right: 10px;\n  }\n\n  a {\n    color: $highlight-text-color;\n    text-transform: uppercase;\n    text-decoration: none;\n    font-weight: 700;\n\n    &:hover,\n    &:focus,\n    &:active {\n      color: lighten($highlight-text-color, 8%);\n    }\n  }\n}\n\n.oauth-prompt,\n.follow-prompt {\n  margin-bottom: 30px;\n  color: $darker-text-color;\n\n  h2 {\n    font-size: 16px;\n    margin-bottom: 30px;\n    text-align: center;\n  }\n\n  strong {\n    color: $secondary-text-color;\n    font-weight: 500;\n\n    @each $lang in $cjk-langs {\n      &:lang(#{$lang}) {\n        font-weight: 700;\n      }\n    }\n  }\n\n  @media screen and (max-width: 740px) and (min-width: 441px) {\n    margin-top: 40px;\n  }\n}\n\n.qr-wrapper {\n  display: flex;\n  flex-wrap: wrap;\n  align-items: flex-start;\n}\n\n.qr-code {\n  flex: 0 0 auto;\n  background: $simple-background-color;\n  padding: 4px;\n  margin: 0 10px 20px 0;\n  box-shadow: 0 0 15px rgba($base-shadow-color, 0.2);\n  display: inline-block;\n\n  svg {\n    display: block;\n    margin: 0;\n  }\n}\n\n.qr-alternative {\n  margin-bottom: 20px;\n  color: $secondary-text-color;\n  flex: 150px;\n\n  samp {\n    display: block;\n    font-size: 14px;\n  }\n}\n\n.table-form {\n  p {\n    margin-bottom: 15px;\n\n    strong {\n      font-weight: 500;\n\n      @each $lang in $cjk-langs {\n        &:lang(#{$lang}) {\n          font-weight: 700;\n        }\n      }\n    }\n  }\n}\n\n.simple_form,\n.table-form {\n  .warning {\n    box-sizing: border-box;\n    background: rgba($error-value-color, 0.5);\n    color: $primary-text-color;\n    text-shadow: 1px 1px 0 rgba($base-shadow-color, 0.3);\n    box-shadow: 0 2px 6px rgba($base-shadow-color, 0.4);\n    border-radius: 4px;\n    padding: 10px;\n    margin-bottom: 15px;\n\n    a {\n      color: $primary-text-color;\n      text-decoration: underline;\n\n      &:hover,\n      &:focus,\n      &:active {\n        text-decoration: none;\n      }\n    }\n\n    strong {\n      font-weight: 600;\n      display: block;\n      margin-bottom: 5px;\n\n      @each $lang in $cjk-langs {\n        &:lang(#{$lang}) {\n          font-weight: 700;\n        }\n      }\n\n      .fa {\n        font-weight: 400;\n      }\n    }\n  }\n}\n\n.action-pagination {\n  display: flex;\n  flex-wrap: wrap;\n  align-items: center;\n\n  .actions,\n  .pagination {\n    flex: 1 1 auto;\n  }\n\n  .actions {\n    padding: 30px 0;\n    padding-right: 20px;\n    flex: 0 0 auto;\n  }\n}\n\n.post-follow-actions {\n  text-align: center;\n  color: $darker-text-color;\n\n  div {\n    margin-bottom: 4px;\n  }\n}\n\n.alternative-login {\n  margin-top: 20px;\n  margin-bottom: 20px;\n\n  h4 {\n    font-size: 16px;\n    color: $primary-text-color;\n    text-align: center;\n    margin-bottom: 20px;\n    border: 0;\n    padding: 0;\n  }\n\n  .button {\n    display: block;\n  }\n}\n\n.scope-danger {\n  color: $warning-red;\n}\n\n.form_admin_settings_site_short_description,\n.form_admin_settings_site_description,\n.form_admin_settings_site_extended_description,\n.form_admin_settings_site_terms,\n.form_admin_settings_custom_css,\n.form_admin_settings_closed_registrations_message {\n  textarea {\n    font-family: $font-monospace, monospace;\n  }\n}\n\n.input-copy {\n  background: darken($ui-base-color, 10%);\n  border: 1px solid darken($ui-base-color, 14%);\n  border-radius: 4px;\n  display: flex;\n  align-items: center;\n  padding-right: 4px;\n  position: relative;\n  top: 1px;\n  transition: border-color 300ms linear;\n\n  &__wrapper {\n    flex: 1 1 auto;\n  }\n\n  input[type=text] {\n    background: transparent;\n    border: 0;\n    padding: 10px;\n    font-size: 14px;\n    font-family: $font-monospace, monospace;\n  }\n\n  button {\n    flex: 0 0 auto;\n    margin: 4px;\n    text-transform: none;\n    font-weight: 400;\n    font-size: 14px;\n    padding: 7px 18px;\n    padding-bottom: 6px;\n    width: auto;\n    transition: background 300ms linear;\n  }\n\n  &.copied {\n    border-color: $valid-value-color;\n    transition: none;\n\n    button {\n      background: $valid-value-color;\n      transition: none;\n    }\n  }\n}\n\n.connection-prompt {\n  margin-bottom: 25px;\n\n  .fa-link {\n    background-color: darken($ui-base-color, 4%);\n    border-radius: 100%;\n    font-size: 24px;\n    padding: 10px;\n  }\n\n  &__column {\n    align-items: center;\n    display: flex;\n    flex: 1;\n    flex-direction: column;\n    flex-shrink: 1;\n    max-width: 50%;\n\n    &-sep {\n      align-self: center;\n      flex-grow: 0;\n      overflow: visible;\n      position: relative;\n      z-index: 1;\n    }\n\n    p {\n      word-break: break-word;\n    }\n  }\n\n  .account__avatar {\n    margin-bottom: 20px;\n  }\n\n  &__connection {\n    background-color: lighten($ui-base-color, 8%);\n    box-shadow: 0 0 15px rgba($base-shadow-color, 0.2);\n    border-radius: 4px;\n    padding: 25px 10px;\n    position: relative;\n    text-align: center;\n\n    &::after {\n      background-color: darken($ui-base-color, 4%);\n      content: '';\n      display: block;\n      height: 100%;\n      left: 50%;\n      position: absolute;\n      top: 0;\n      width: 1px;\n    }\n  }\n\n  &__row {\n    align-items: flex-start;\n    display: flex;\n    flex-direction: row;\n  }\n}\n"
  },
  {
    "path": "app/javascript/styles/mastodon/introduction.scss",
    "content": ".introduction {\n  display: flex;\n  flex-direction: column;\n  justify-content: center;\n  align-items: center;\n\n  @media screen and (max-width: 920px) {\n    background: darken($ui-base-color, 8%);\n    display: block !important;\n  }\n\n  &__pager {\n    background: darken($ui-base-color, 8%);\n    box-shadow: 0 0 15px rgba($base-shadow-color, 0.2);\n    overflow: hidden;\n  }\n\n  &__pager,\n  &__frame {\n    border-radius: 10px;\n    width: 50vw;\n    min-width: 920px;\n\n    @media screen and (max-width: 920px) {\n      min-width: 0;\n      width: 100%;\n      border-radius: 0;\n      box-shadow: none;\n    }\n  }\n\n  &__frame-wrapper {\n    opacity: 0;\n    transition: opacity 500ms linear;\n\n    &.active {\n      opacity: 1;\n      transition: opacity 50ms linear;\n    }\n  }\n\n  &__frame {\n    overflow: hidden;\n  }\n\n  &__illustration {\n    height: 50vh;\n\n    @media screen and (max-width: 630px) {\n      height: auto;\n    }\n\n    img {\n      object-fit: cover;\n      display: block;\n      margin: 0;\n      width: 100%;\n      height: 100%;\n    }\n  }\n\n  &__text {\n    border-top: 2px solid $ui-highlight-color;\n\n    &--columnized {\n      display: flex;\n\n      & > div {\n        flex: 1 1 33.33%;\n        text-align: center;\n        padding: 25px;\n        padding-bottom: 30px;\n      }\n\n      @media screen and (max-width: 630px) {\n        display: block;\n        padding: 15px 0;\n        padding-bottom: 20px;\n\n        & > div {\n          padding: 10px 25px;\n        }\n      }\n    }\n\n    h3 {\n      font-size: 24px;\n      line-height: 1.5;\n      font-weight: 700;\n      margin-bottom: 10px;\n    }\n\n    p {\n      font-size: 16px;\n      line-height: 24px;\n      font-weight: 400;\n      color: $darker-text-color;\n\n      code {\n        display: inline-block;\n        background: darken($ui-base-color, 8%);\n        font-size: 15px;\n        border: 1px solid lighten($ui-base-color, 8%);\n        border-radius: 2px;\n        padding: 1px 3px;\n      }\n    }\n\n    &--centered {\n      padding: 25px;\n      padding-bottom: 30px;\n      text-align: center;\n    }\n  }\n\n  &__dots {\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    padding: 25px;\n\n    @media screen and (max-width: 630px) {\n      display: none;\n    }\n  }\n\n  &__dot {\n    width: 14px;\n    height: 14px;\n    border-radius: 14px;\n    border: 1px solid $ui-highlight-color;\n    background: transparent;\n    margin: 0 3px;\n    cursor: pointer;\n\n    &:hover {\n      background: lighten($ui-base-color, 8%);\n    }\n\n    &.active {\n      cursor: default;\n      background: $ui-highlight-color;\n    }\n  }\n\n  &__action {\n    padding: 25px;\n    padding-top: 0;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n  }\n}\n"
  },
  {
    "path": "app/javascript/styles/mastodon/lists.scss",
    "content": ".no-list {\n  list-style: none;\n\n  li {\n    display: inline-block;\n    margin: 0 5px;\n  }\n}\n\n.recovery-codes {\n  list-style: none;\n  margin: 0 auto;\n\n  li {\n    font-size: 125%;\n    line-height: 1.5;\n    letter-spacing: 1px;\n  }\n}\n"
  },
  {
    "path": "app/javascript/styles/mastodon/modal.scss",
    "content": ".modal-layout {\n  background: $ui-base-color url('data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 234.80078 31.757813\" width=\"234.80078\" height=\"31.757812\"><path d=\"M19.599609 0c-1.05 0-2.10039.375-2.90039 1.125L0 16.925781v14.832031h234.80078V17.025391l-16.5-15.900391c-1.6-1.5-4.20078-1.5-5.80078 0l-13.80078 13.099609c-1.6 1.5-4.19883 1.5-5.79883 0L179.09961 1.125c-1.6-1.5-4.19883-1.5-5.79883 0L159.5 14.224609c-1.6 1.5-4.20078 1.5-5.80078 0L139.90039 1.125c-1.6-1.5-4.20078-1.5-5.80078 0l-13.79883 13.099609c-1.6 1.5-4.20078 1.5-5.80078 0L100.69922 1.125c-1.600001-1.5-4.198829-1.5-5.798829 0l-13.59961 13.099609c-1.6 1.5-4.200781 1.5-5.800781 0L61.699219 1.125c-1.6-1.5-4.198828-1.5-5.798828 0L42.099609 14.224609c-1.6 1.5-4.198828 1.5-5.798828 0L22.5 1.125C21.7.375 20.649609 0 19.599609 0z\" fill=\"#{hex-color($ui-base-lighter-color)}\"/></svg>') repeat-x bottom fixed;\n  display: flex;\n  flex-direction: column;\n  height: 100vh;\n  padding: 0;\n}\n\n.modal-layout__mastodon {\n  display: flex;\n  flex: 1;\n  flex-direction: column;\n  justify-content: flex-end;\n\n  > * {\n    flex: 1;\n    max-height: 235px;\n    background: url('../images/elephant_ui_plane.svg') no-repeat left bottom / contain;\n  }\n}\n\n@media screen and (max-width: 600px) {\n  .account-header {\n    margin-top: 0;\n  }\n}\n"
  },
  {
    "path": "app/javascript/styles/mastodon/polls.scss",
    "content": ".poll {\n  margin-top: 16px;\n  font-size: 14px;\n\n  li {\n    margin-bottom: 10px;\n    position: relative;\n    height: 18px + 12px;\n  }\n\n  &__chart {\n    position: absolute;\n    top: 0;\n    left: 0;\n    height: 100%;\n    display: inline-block;\n    border-radius: 4px;\n    background: darken($ui-primary-color, 14%);\n\n    &.leading {\n      background: $ui-highlight-color;\n    }\n  }\n\n  &__text {\n    position: relative;\n    display: inline-block;\n    padding: 6px 0;\n    line-height: 18px;\n    cursor: default;\n    white-space: nowrap;\n    overflow: hidden;\n    text-overflow: ellipsis;\n\n    input[type=radio],\n    input[type=checkbox] {\n      display: none;\n    }\n\n    .autossugest-input {\n      flex: 1 1 auto;\n    }\n\n    input[type=text] {\n      display: block;\n      box-sizing: border-box;\n      width: 100%;\n      font-size: 14px;\n      color: $inverted-text-color;\n      outline: 0;\n      font-family: inherit;\n      background: $simple-background-color;\n      border: 1px solid darken($simple-background-color, 14%);\n      border-radius: 4px;\n      padding: 6px 10px;\n\n      &:focus {\n        border-color: $highlight-text-color;\n      }\n    }\n\n    &.selectable {\n      cursor: pointer;\n    }\n\n    &.editable {\n      display: flex;\n      align-items: center;\n      overflow: visible;\n    }\n  }\n\n  &__input {\n    display: inline-block;\n    position: relative;\n    border: 1px solid $ui-primary-color;\n    box-sizing: border-box;\n    width: 18px;\n    height: 18px;\n    flex: 0 0 auto;\n    margin-right: 10px;\n    top: -1px;\n    border-radius: 50%;\n    vertical-align: middle;\n\n    &.checkbox {\n      border-radius: 4px;\n    }\n\n    &.active {\n      border-color: $valid-value-color;\n      background: $valid-value-color;\n    }\n  }\n\n  &__number {\n    display: inline-block;\n    width: 36px;\n    font-weight: 700;\n    padding: 0 10px;\n    text-align: right;\n  }\n\n  &__footer {\n    padding-top: 6px;\n    padding-bottom: 5px;\n    color: $dark-text-color;\n  }\n\n  &__link {\n    display: inline;\n    background: transparent;\n    padding: 0;\n    margin: 0;\n    border: 0;\n    color: $dark-text-color;\n    text-decoration: underline;\n    font-size: inherit;\n\n    &:hover {\n      text-decoration: none;\n    }\n\n    &:active,\n    &:focus {\n      background-color: rgba($dark-text-color, .1);\n    }\n  }\n\n  .button {\n    height: 36px;\n    padding: 0 16px;\n    margin-right: 10px;\n    font-size: 14px;\n  }\n}\n\n.compose-form__poll-wrapper {\n  border-top: 1px solid darken($simple-background-color, 8%);\n\n  ul {\n    padding: 10px;\n  }\n\n  .poll__footer {\n    border-top: 1px solid darken($simple-background-color, 8%);\n    padding: 10px;\n    display: flex;\n    align-items: center;\n\n    button,\n    select {\n      flex: 1 1 50%;\n    }\n  }\n\n  .button.button-secondary {\n    font-size: 14px;\n    font-weight: 400;\n    padding: 6px 10px;\n    height: auto;\n    line-height: inherit;\n    color: $action-button-color;\n    border-color: $action-button-color;\n    margin-right: 5px;\n  }\n\n  li {\n    display: flex;\n    align-items: center;\n\n    .poll__text {\n      flex: 0 0 auto;\n      width: calc(100% - (23px + 6px));\n      margin-right: 6px;\n    }\n  }\n\n  select {\n    appearance: none;\n    box-sizing: border-box;\n    font-size: 14px;\n    color: $inverted-text-color;\n    display: inline-block;\n    width: auto;\n    outline: 0;\n    font-family: inherit;\n    background: $simple-background-color url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14.933 18.467' height='19.698' width='15.929'><path d='M3.467 14.967l-3.393-3.5H14.86l-3.392 3.5c-1.866 1.925-3.666 3.5-4 3.5-.335 0-2.135-1.575-4-3.5zm.266-11.234L7.467 0 11.2 3.733l3.733 3.734H0l3.733-3.734z' fill='#{hex-color(darken($simple-background-color, 14%))}'/></svg>\") no-repeat right 8px center / auto 16px;\n    border: 1px solid darken($simple-background-color, 14%);\n    border-radius: 4px;\n    padding: 6px 10px;\n    padding-right: 30px;\n  }\n\n  .icon-button.disabled {\n    color: darken($simple-background-color, 14%);\n  }\n}\n\n.muted .poll {\n  color: $dark-text-color;\n\n  &__chart {\n    background: rgba(darken($ui-primary-color, 14%), 0.2);\n\n    &.leading {\n      background: rgba($ui-highlight-color, 0.2);\n    }\n  }\n}\n"
  },
  {
    "path": "app/javascript/styles/mastodon/reset.scss",
    "content": "/* http://meyerweb.com/eric/tools/css/reset/\n   v2.0 | 20110126\n   License: none (public domain)\n*/\n\nhtml, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header, hgroup,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n  margin: 0;\n  padding: 0;\n  border: 0;\n  font-size: 100%;\n  font: inherit;\n  vertical-align: baseline;\n}\n\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, hgroup, menu, nav, section {\n  display: block;\n}\n\nbody {\n  line-height: 1;\n}\n\nol, ul {\n  list-style: none;\n}\n\nblockquote, q {\n  quotes: none;\n}\n\nblockquote:before, blockquote:after,\nq:before, q:after {\n  content: '';\n  content: none;\n}\n\ntable {\n  border-collapse: collapse;\n  border-spacing: 0;\n}\n\nhtml {\n  scrollbar-color: lighten($ui-base-color, 4%) rgba($base-overlay-background, 0.1);\n}\n\n::-webkit-scrollbar {\n  width: 12px;\n  height: 12px;\n}\n\n::-webkit-scrollbar-thumb {\n  background: lighten($ui-base-color, 4%);\n  border: 0px none $base-border-color;\n  border-radius: 50px;\n}\n\n::-webkit-scrollbar-thumb:hover {\n  background: lighten($ui-base-color, 6%);\n}\n\n::-webkit-scrollbar-thumb:active {\n  background: lighten($ui-base-color, 4%);\n}\n\n::-webkit-scrollbar-track {\n  border: 0px none $base-border-color;\n  border-radius: 0;\n  background: rgba($base-overlay-background, 0.1);\n}\n\n::-webkit-scrollbar-track:hover {\n  background: $ui-base-color;\n}\n\n::-webkit-scrollbar-track:active {\n  background: $ui-base-color;\n}\n\n::-webkit-scrollbar-corner {\n  background: transparent;\n}\n"
  },
  {
    "path": "app/javascript/styles/mastodon/rtl.scss",
    "content": "body.rtl {\n  direction: rtl;\n\n  .column-header > button {\n    text-align: right;\n    padding-left: 0;\n    padding-right: 15px;\n  }\n\n  .landing-page__logo {\n    margin-right: 0;\n    margin-left: 20px;\n  }\n\n  .landing-page .features-list .features-list__row .visual {\n    margin-left: 0;\n    margin-right: 15px;\n  }\n\n  .column-link__icon,\n  .column-header__icon {\n    margin-right: 0;\n    margin-left: 5px;\n  }\n\n  .compose-form .compose-form__buttons-wrapper .character-counter__wrapper {\n    margin-right: 0;\n    margin-left: 4px;\n  }\n\n  .navigation-bar__profile {\n    margin-left: 0;\n    margin-right: 8px;\n  }\n\n  .search__input {\n    padding-right: 10px;\n    padding-left: 30px;\n  }\n\n  .search__icon .fa {\n    right: auto;\n    left: 10px;\n  }\n\n  .columns-area {\n    direction: rtl;\n  }\n\n  .column-header__buttons {\n    left: 0;\n    right: auto;\n    margin-left: 0;\n    margin-right: -15px;\n  }\n\n  .column-inline-form .icon-button {\n    margin-left: 0;\n    margin-right: 5px;\n  }\n\n  .column-header__links .text-btn {\n    margin-left: 10px;\n    margin-right: 0;\n  }\n\n  .account__avatar-wrapper {\n    float: right;\n  }\n\n  .column-header__back-button {\n    padding-left: 5px;\n    padding-right: 0;\n  }\n\n  .column-header__setting-arrows {\n    float: left;\n  }\n\n  .setting-toggle__label {\n    margin-left: 0;\n    margin-right: 8px;\n  }\n\n  .status__avatar {\n    left: auto;\n    right: 10px;\n  }\n\n  .status,\n  .activity-stream .status.light {\n    padding-left: 10px;\n    padding-right: 68px;\n  }\n\n  .status__info .status__display-name,\n  .activity-stream .status.light .status__display-name {\n    padding-left: 25px;\n    padding-right: 0;\n  }\n\n  .activity-stream .pre-header {\n    padding-right: 68px;\n    padding-left: 0;\n  }\n\n  .status__prepend {\n    margin-left: 0;\n    margin-right: 68px;\n  }\n\n  .status__prepend-icon-wrapper {\n    left: auto;\n    right: -26px;\n  }\n\n  .activity-stream .pre-header .pre-header__icon {\n    left: auto;\n    right: 42px;\n  }\n\n  .account__avatar-overlay-overlay {\n    right: auto;\n    left: 0;\n  }\n\n  .column-back-button--slim-button {\n    right: auto;\n    left: 0;\n  }\n\n  .status__relative-time,\n  .activity-stream .status.light .status__header .status__meta {\n    float: left;\n  }\n\n  .status__action-bar {\n\n    &__counter {\n      margin-right: 0;\n      margin-left: 11px;\n\n      .status__action-bar-button {\n        margin-right: 0;\n        margin-left: 4px;\n      }\n    }\n  }\n\n  .status__action-bar-button {\n    float: right;\n    margin-right: 0;\n    margin-left: 18px;\n  }\n\n  .status__action-bar-dropdown {\n    float: right;\n  }\n\n  .privacy-dropdown__dropdown {\n    margin-left: 0;\n    margin-right: 40px;\n  }\n\n  .privacy-dropdown__option__icon {\n    margin-left: 10px;\n    margin-right: 0;\n  }\n\n  .detailed-status__display-name .display-name {\n    text-align: right;\n  }\n\n  .detailed-status__display-avatar {\n    margin-right: 0;\n    margin-left: 10px;\n    float: right;\n  }\n\n  .detailed-status__favorites,\n  .detailed-status__reblogs {\n    margin-left: 0;\n    margin-right: 6px;\n  }\n\n  .fa-ul {\n    margin-left: 2.14285714em;\n  }\n\n  .fa-li {\n    left: auto;\n    right: -2.14285714em;\n  }\n\n  .admin-wrapper {\n    direction: rtl;\n  }\n\n  .admin-wrapper .sidebar ul a i.fa,\n  a.table-action-link i.fa {\n    margin-right: 0;\n    margin-left: 5px;\n  }\n\n  .simple_form .check_boxes .checkbox label {\n    padding-left: 0;\n    padding-right: 25px;\n  }\n\n  .simple_form .input.with_label.boolean label.checkbox {\n    padding-left: 25px;\n    padding-right: 0;\n  }\n\n  .simple_form .check_boxes .checkbox input[type=\"checkbox\"],\n  .simple_form .input.boolean input[type=\"checkbox\"] {\n    left: auto;\n    right: 0;\n  }\n\n  .simple_form .input.radio_buttons .radio {\n    left: auto;\n    right: 0;\n  }\n\n  .simple_form .input.radio_buttons .radio > label {\n    padding-right: 28px;\n    padding-left: 0;\n  }\n\n  .simple_form .input-with-append .input input {\n    padding-left: 142px;\n    padding-right: 0;\n  }\n\n  .simple_form .input.boolean label.checkbox {\n    left: auto;\n    right: 0;\n  }\n\n  .simple_form .input.boolean .label_input,\n  .simple_form .input.boolean .hint {\n    padding-left: 0;\n    padding-right: 28px;\n  }\n\n  .simple_form .label_input__append {\n    right: auto;\n    left: 3px;\n\n    &::after {\n      right: auto;\n      left: 0;\n      background-image: linear-gradient(to left, rgba(darken($ui-base-color, 10%), 0), darken($ui-base-color, 10%));\n    }\n  }\n\n  .simple_form select {\n    background: darken($ui-base-color, 10%) url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14.933 18.467' height='19.698' width='15.929'><path d='M3.467 14.967l-3.393-3.5H14.86l-3.392 3.5c-1.866 1.925-3.666 3.5-4 3.5-.335 0-2.135-1.575-4-3.5zm.266-11.234L7.467 0 11.2 3.733l3.733 3.734H0l3.733-3.734z' fill='#{hex-color(lighten($ui-base-color, 12%))}'/></svg>\") no-repeat left 8px center / auto 16px;\n  }\n\n  .table th,\n  .table td {\n    text-align: right;\n  }\n\n  .filters .filter-subset {\n    margin-right: 0;\n    margin-left: 45px;\n  }\n\n  .landing-page .header-wrapper .mascot {\n    right: 60px;\n    left: auto;\n  }\n\n  .landing-page__call-to-action .row__information-board {\n    direction: rtl;\n  }\n\n  .landing-page .header .hero .floats .float-1 {\n    left: -120px;\n    right: auto;\n  }\n\n  .landing-page .header .hero .floats .float-2 {\n    left: 210px;\n    right: auto;\n  }\n\n  .landing-page .header .hero .floats .float-3 {\n    left: 110px;\n    right: auto;\n  }\n\n  .landing-page .header .links .brand img {\n    left: 0;\n  }\n\n  .landing-page .fa-external-link {\n    padding-right: 5px;\n    padding-left: 0 !important;\n  }\n\n  .landing-page .features #mastodon-timeline {\n    margin-right: 0;\n    margin-left: 30px;\n  }\n\n  @media screen and (min-width: 631px) {\n    .column,\n    .drawer {\n      padding-left: 5px;\n      padding-right: 5px;\n\n      &:first-child {\n        padding-left: 5px;\n        padding-right: 10px;\n      }\n    }\n\n    .columns-area > div {\n      .column,\n      .drawer {\n        padding-left: 5px;\n        padding-right: 5px;\n      }\n    }\n  }\n\n  .public-layout {\n    .header {\n      .nav-button {\n        margin-left: 8px;\n        margin-right: 0;\n      }\n    }\n\n    .public-account-header__tabs {\n      margin-left: 0;\n      margin-right: 20px;\n    }\n  }\n\n  .landing-page__information {\n    .account__display-name {\n      margin-right: 0;\n      margin-left: 5px;\n    }\n\n    .account__avatar-wrapper {\n      margin-left: 12px;\n      margin-right: 0;\n    }\n  }\n\n  .card__bar .display-name {\n    margin-left: 0;\n    margin-right: 15px;\n    text-align: right;\n  }\n\n  .fa-chevron-left::before {\n    content: \"\\F054\";\n  }\n\n  .fa-chevron-right::before {\n    content: \"\\F053\";\n  }\n\n  .column-back-button__icon {\n    margin-right: 0;\n    margin-left: 5px;\n  }\n\n  .column-header__setting-arrows .column-header__setting-btn:last-child {\n    padding-left: 0;\n    padding-right: 10px;\n  }\n\n  .simple_form .input.radio_buttons .radio > label input {\n    left: auto;\n    right: 0;\n  }\n}\n"
  },
  {
    "path": "app/javascript/styles/mastodon/stream_entries.scss",
    "content": ".activity-stream {\n  box-shadow: 0 0 15px rgba($base-shadow-color, 0.2);\n  border-radius: 4px;\n  overflow: hidden;\n  margin-bottom: 10px;\n\n  &--under-tabs {\n    border-radius: 0 0 4px 4px;\n  }\n\n  @media screen and (max-width: $no-gap-breakpoint) {\n    margin-bottom: 0;\n    border-radius: 0;\n    box-shadow: none;\n  }\n\n  &--headless {\n    border-radius: 0;\n    margin: 0;\n    box-shadow: none;\n\n    .detailed-status,\n    .status {\n      border-radius: 0 !important;\n    }\n  }\n\n  div[data-component] {\n    width: 100%;\n  }\n\n  .entry {\n    background: $ui-base-color;\n\n    .detailed-status,\n    .status,\n    .load-more {\n      animation: none;\n    }\n\n    &:last-child {\n      .detailed-status,\n      .status,\n      .load-more {\n        border-bottom: 0;\n        border-radius: 0 0 4px 4px;\n      }\n    }\n\n    &:first-child {\n      .detailed-status,\n      .status,\n      .load-more {\n        border-radius: 4px 4px 0 0;\n      }\n\n      &:last-child {\n        .detailed-status,\n        .status,\n        .load-more {\n          border-radius: 4px;\n        }\n      }\n    }\n\n    @media screen and (max-width: 740px) {\n      .detailed-status,\n      .status,\n      .load-more {\n        border-radius: 0 !important;\n      }\n    }\n  }\n\n  &--highlighted .entry {\n    background: lighten($ui-base-color, 8%);\n  }\n}\n\n.button.logo-button {\n  flex: 0 auto;\n  font-size: 14px;\n  background: $ui-highlight-color;\n  color: $primary-text-color;\n  text-transform: none;\n  line-height: 36px;\n  height: auto;\n  padding: 3px 15px;\n  border: 0;\n\n  svg {\n    width: 20px;\n    height: auto;\n    vertical-align: middle;\n    margin-right: 5px;\n    fill: $primary-text-color;\n  }\n\n  &:active,\n  &:focus,\n  &:hover {\n    background: lighten($ui-highlight-color, 10%);\n  }\n\n  &:disabled,\n  &.disabled {\n    &:active,\n    &:focus,\n    &:hover {\n      background: $ui-primary-color;\n    }\n  }\n\n  &.button--destructive {\n    &:active,\n    &:focus,\n    &:hover {\n      background: $error-red;\n    }\n  }\n\n  @media screen and (max-width: $no-gap-breakpoint) {\n    svg {\n      display: none;\n    }\n  }\n}\n\n.embed,\n.public-layout {\n  .detailed-status {\n    padding: 15px;\n  }\n\n  .status {\n    padding: 15px 15px 15px (48px + 15px * 2);\n    min-height: 48px + 2px;\n\n    &__avatar {\n      left: 15px;\n      top: 17px;\n    }\n\n    &__content {\n      padding-top: 5px;\n    }\n\n    &__prepend {\n      margin-left: 48px + 15px * 2;\n      padding-top: 15px;\n    }\n\n    &__prepend-icon-wrapper {\n      left: -32px;\n    }\n\n    .media-gallery,\n    &__action-bar,\n    .video-player {\n      margin-top: 10px;\n    }\n  }\n}\n"
  },
  {
    "path": "app/javascript/styles/mastodon/tables.scss",
    "content": ".table {\n  width: 100%;\n  max-width: 100%;\n  border-spacing: 0;\n  border-collapse: collapse;\n\n  th,\n  td {\n    padding: 8px;\n    line-height: 18px;\n    vertical-align: top;\n    border-top: 1px solid $ui-base-color;\n    text-align: left;\n    background: darken($ui-base-color, 4%);\n  }\n\n  & > thead > tr > th {\n    vertical-align: bottom;\n    border-bottom: 2px solid $ui-base-color;\n    border-top: 0;\n    font-weight: 500;\n  }\n\n  & > tbody > tr > th {\n    font-weight: 500;\n  }\n\n  & > tbody > tr:nth-child(odd) > td,\n  & > tbody > tr:nth-child(odd) > th {\n    background: $ui-base-color;\n  }\n\n  a {\n    color: $highlight-text-color;\n    text-decoration: underline;\n\n    &:hover {\n      text-decoration: none;\n    }\n  }\n\n  strong {\n    font-weight: 500;\n\n    @each $lang in $cjk-langs {\n      &:lang(#{$lang}) {\n        font-weight: 700;\n      }\n    }\n  }\n\n  &.inline-table {\n    & > tbody > tr:nth-child(odd) {\n      & > td,\n      & > th {\n        background: transparent;\n      }\n    }\n\n    & > tbody > tr:first-child {\n      & > td,\n      & > th {\n        border-top: 0;\n      }\n    }\n  }\n\n  &.batch-table {\n    & > thead > tr > th {\n      background: $ui-base-color;\n      border-top: 1px solid darken($ui-base-color, 8%);\n      border-bottom: 1px solid darken($ui-base-color, 8%);\n\n      &:first-child {\n        border-radius: 4px 0 0;\n        border-left: 1px solid darken($ui-base-color, 8%);\n      }\n\n      &:last-child {\n        border-radius: 0 4px 0 0;\n        border-right: 1px solid darken($ui-base-color, 8%);\n      }\n    }\n  }\n\n  &--invites tbody td {\n    vertical-align: middle;\n  }\n}\n\n.table-wrapper {\n  overflow: auto;\n  margin-bottom: 20px;\n}\n\nsamp {\n  font-family: $font-monospace, monospace;\n}\n\nbutton.table-action-link {\n  background: transparent;\n  border: 0;\n  font: inherit;\n}\n\nbutton.table-action-link,\na.table-action-link {\n  text-decoration: none;\n  display: inline-block;\n  margin-right: 5px;\n  padding: 0 10px;\n  color: $darker-text-color;\n  font-weight: 500;\n\n  &:hover {\n    color: $primary-text-color;\n  }\n\n  i.fa {\n    font-weight: 400;\n    margin-right: 5px;\n  }\n\n  &:first-child {\n    padding-left: 0;\n  }\n}\n\n.batch-table {\n  &__toolbar,\n  &__row {\n    display: flex;\n\n    &__select {\n      box-sizing: border-box;\n      padding: 8px 16px;\n      cursor: pointer;\n      min-height: 100%;\n\n      input {\n        margin-top: 8px;\n      }\n\n      &--aligned {\n        display: flex;\n        align-items: center;\n\n        input {\n          margin-top: 0;\n        }\n      }\n\n      @media screen and (max-width: $no-gap-breakpoint) {\n        display: none;\n      }\n    }\n\n    &__actions,\n    &__content {\n      padding: 8px 0;\n      padding-right: 16px;\n      flex: 1 1 auto;\n    }\n  }\n\n  &__toolbar {\n    border: 1px solid darken($ui-base-color, 8%);\n    background: $ui-base-color;\n    border-radius: 4px 0 0;\n    height: 47px;\n    align-items: center;\n\n    &__actions {\n      text-align: right;\n      padding-right: 16px - 5px;\n    }\n\n    @media screen and (max-width: $no-gap-breakpoint) {\n      display: none;\n    }\n  }\n\n  &__row {\n    border: 1px solid darken($ui-base-color, 8%);\n    border-top: 0;\n    background: darken($ui-base-color, 4%);\n\n    @media screen and (max-width: $no-gap-breakpoint) {\n      &:first-child {\n        border-top: 1px solid darken($ui-base-color, 8%);\n      }\n    }\n\n    &:hover {\n      background: darken($ui-base-color, 2%);\n    }\n\n    &:nth-child(even) {\n      background: $ui-base-color;\n\n      &:hover {\n        background: lighten($ui-base-color, 2%);\n      }\n    }\n\n    &__content {\n      padding-top: 12px;\n      padding-bottom: 16px;\n\n      &--unpadded {\n        padding: 0;\n      }\n    }\n  }\n\n  .status__content {\n    padding-top: 0;\n\n    summary {\n      display: list-item;\n    }\n\n    strong {\n      font-weight: 700;\n    }\n  }\n\n  .nothing-here {\n    border: 1px solid darken($ui-base-color, 8%);\n    border-top: 0;\n    box-shadow: none;\n\n    @media screen and (max-width: $no-gap-breakpoint) {\n      border-top: 1px solid darken($ui-base-color, 8%);\n    }\n  }\n\n  @media screen and (max-width: 870px) {\n    .accounts-table tbody td.optional {\n      display: none;\n    }\n  }\n}\n"
  },
  {
    "path": "app/javascript/styles/mastodon/variables.scss",
    "content": "// Commonly used web colors\n$black: #000000;            // Black\n$white: #ffffff;            // White\n$success-green: #79bd9a !default;    // Padua\n$error-red: #df405a !default;        // Cerise\n$warning-red: #ff5050 !default;      // Sunset Orange\n$gold-star: #ca8f04 !default;        // Dark Goldenrod\n\n// Values from the classic Mastodon UI\n$classic-base-color: #282c37;         // Midnight Express\n$classic-primary-color: #9baec8;      // Echo Blue\n$classic-secondary-color: #d9e1e8;    // Pattens Blue\n$classic-highlight-color: #2b90d9;    // Summer Sky\n\n// Variables for defaults in UI\n$base-shadow-color: $black !default;\n$base-overlay-background: $black !default;\n$base-border-color: $white !default;\n$simple-background-color: $white !default;\n$valid-value-color: $success-green !default;\n$error-value-color: $error-red !default;\n\n// Tell UI to use selected colors\n$ui-base-color: $classic-base-color !default;                  // Darkest\n$ui-base-lighter-color: lighten($ui-base-color, 26%) !default; // Lighter darkest\n$ui-primary-color: $classic-primary-color !default;            // Lighter\n$ui-secondary-color: $classic-secondary-color !default;        // Lightest\n$ui-highlight-color: $classic-highlight-color !default;\n\n// Variables for texts\n$primary-text-color: $white !default;\n$darker-text-color: $ui-primary-color !default;\n$dark-text-color: $ui-base-lighter-color !default;\n$secondary-text-color: $ui-secondary-color !default;\n$highlight-text-color: $ui-highlight-color !default;\n$action-button-color: $ui-base-lighter-color !default;\n// For texts on inverted backgrounds\n$inverted-text-color: $ui-base-color !default;\n$lighter-text-color: $ui-base-lighter-color !default;\n$light-text-color: $ui-primary-color !default;\n\n// Language codes that uses CJK fonts\n$cjk-langs: ja, ko, zh-CN, zh-HK, zh-TW;\n\n// Variables for components\n$media-modal-media-max-width: 100%;\n// put margins on top and bottom of image to avoid the screen covered by image.\n$media-modal-media-max-height: 80%;\n\n$no-gap-breakpoint: 415px;\n\n$font-sans-serif: 'mastodon-font-sans-serif' !default;\n$font-display: 'mastodon-font-display' !default;\n$font-monospace: 'mastodon-font-monospace' !default;\n"
  },
  {
    "path": "app/javascript/styles/mastodon/widgets.scss",
    "content": ".hero-widget {\n  margin-bottom: 10px;\n  box-shadow: 0 0 15px rgba($base-shadow-color, 0.2);\n\n  &__img {\n    width: 100%;\n    position: relative;\n    overflow: hidden;\n    border-radius: 4px 4px 0 0;\n    background: $base-shadow-color;\n\n    img {\n      object-fit: cover;\n      display: block;\n      width: 100%;\n      height: 100%;\n      margin: 0;\n      border-radius: 4px 4px 0 0;\n    }\n  }\n\n  &__text {\n    background: $ui-base-color;\n    padding: 20px;\n    border-radius: 0 0 4px 4px;\n    font-size: 15px;\n    color: $darker-text-color;\n    line-height: 20px;\n    word-wrap: break-word;\n    font-weight: 400;\n\n    .emojione {\n      width: 20px;\n      height: 20px;\n      margin: -3px 0 0;\n    }\n\n    p {\n      margin-bottom: 20px;\n\n      &:last-child {\n        margin-bottom: 0;\n      }\n    }\n\n    em {\n      display: inline;\n      margin: 0;\n      padding: 0;\n      font-weight: 700;\n      background: transparent;\n      font-family: inherit;\n      font-size: inherit;\n      line-height: inherit;\n      color: lighten($darker-text-color, 10%);\n    }\n\n    a {\n      color: $secondary-text-color;\n      text-decoration: none;\n\n      &:hover {\n        text-decoration: underline;\n      }\n    }\n  }\n\n  @media screen and (max-width: $no-gap-breakpoint) {\n    display: none;\n  }\n}\n\n.endorsements-widget {\n  margin-bottom: 10px;\n  padding-bottom: 10px;\n\n  h4 {\n    padding: 10px;\n    text-transform: uppercase;\n    font-weight: 700;\n    font-size: 13px;\n    color: $darker-text-color;\n  }\n\n  .account {\n    padding: 10px 0;\n\n    &:last-child {\n      border-bottom: 0;\n    }\n\n    .account__display-name {\n      display: flex;\n      align-items: center;\n    }\n\n    .account__avatar {\n      width: 44px;\n      height: 44px;\n      background-size: 44px 44px;\n    }\n  }\n}\n\n.box-widget {\n  padding: 20px;\n  border-radius: 4px;\n  background: $ui-base-color;\n  box-shadow: 0 0 15px rgba($base-shadow-color, 0.2);\n}\n\n.contact-widget,\n.landing-page__information.contact-widget {\n  box-sizing: border-box;\n  padding: 20px;\n  min-height: 100%;\n  border-radius: 4px;\n  background: $ui-base-color;\n  box-shadow: 0 0 15px rgba($base-shadow-color, 0.2);\n}\n\n.contact-widget {\n  font-size: 15px;\n  color: $darker-text-color;\n  line-height: 20px;\n  word-wrap: break-word;\n  font-weight: 400;\n\n  strong {\n    font-weight: 500;\n  }\n\n  p {\n    margin-bottom: 10px;\n\n    &:last-child {\n      margin-bottom: 0;\n    }\n  }\n\n  &__mail {\n    margin-top: 10px;\n\n    a {\n      color: $primary-text-color;\n      text-decoration: none;\n    }\n  }\n}\n\n.moved-account-widget {\n  padding: 15px;\n  padding-bottom: 20px;\n  border-radius: 4px;\n  background: $ui-base-color;\n  box-shadow: 0 0 15px rgba($base-shadow-color, 0.2);\n  color: $secondary-text-color;\n  font-weight: 400;\n  margin-bottom: 10px;\n\n  strong,\n  a {\n    font-weight: 500;\n\n    @each $lang in $cjk-langs {\n      &:lang(#{$lang}) {\n        font-weight: 700;\n      }\n    }\n  }\n\n  a {\n    color: inherit;\n    text-decoration: underline;\n\n    &.mention {\n      text-decoration: none;\n\n      span {\n        text-decoration: none;\n      }\n\n      &:focus,\n      &:hover,\n      &:active {\n        text-decoration: none;\n\n        span {\n          text-decoration: underline;\n        }\n      }\n    }\n  }\n\n  &__message {\n    margin-bottom: 15px;\n\n    .fa {\n      margin-right: 5px;\n      color: $darker-text-color;\n    }\n  }\n\n  &__card {\n    .detailed-status__display-avatar {\n      position: relative;\n      cursor: pointer;\n    }\n\n    .detailed-status__display-name {\n      margin-bottom: 0;\n      text-decoration: none;\n\n      span {\n        font-weight: 400;\n      }\n    }\n  }\n}\n\n.memoriam-widget {\n  padding: 20px;\n  border-radius: 4px;\n  background: $base-shadow-color;\n  box-shadow: 0 0 15px rgba($base-shadow-color, 0.2);\n  font-size: 14px;\n  color: $darker-text-color;\n  margin-bottom: 10px;\n}\n\n.page-header {\n  background: lighten($ui-base-color, 8%);\n  box-shadow: 0 0 15px rgba($base-shadow-color, 0.2);\n  border-radius: 4px;\n  padding: 60px 15px;\n  text-align: center;\n  margin: 10px 0;\n\n  h1 {\n    color: $primary-text-color;\n    font-size: 36px;\n    line-height: 1.1;\n    font-weight: 700;\n    margin-bottom: 10px;\n  }\n\n  p {\n    font-size: 15px;\n    color: $darker-text-color;\n  }\n\n  @media screen and (max-width: $no-gap-breakpoint) {\n    margin-top: 0;\n    background: lighten($ui-base-color, 4%);\n\n    h1 {\n      font-size: 24px;\n    }\n  }\n}\n\n.directory {\n  background: $ui-base-color;\n  border-radius: 4px;\n  box-shadow: 0 0 15px rgba($base-shadow-color, 0.2);\n\n  &__tag {\n    box-sizing: border-box;\n    margin-bottom: 10px;\n\n    & > a,\n    & > div {\n      display: flex;\n      align-items: center;\n      justify-content: space-between;\n      background: $ui-base-color;\n      border-radius: 4px;\n      padding: 15px;\n      text-decoration: none;\n      color: inherit;\n      box-shadow: 0 0 15px rgba($base-shadow-color, 0.2);\n    }\n\n    & > a {\n      &:hover,\n      &:active,\n      &:focus {\n        background: lighten($ui-base-color, 8%);\n      }\n    }\n\n    &.active > a {\n      background: $ui-highlight-color;\n      cursor: default;\n    }\n\n    &.disabled > div {\n      opacity: 0.5;\n      cursor: default;\n    }\n\n    h4 {\n      flex: 1 1 auto;\n      font-size: 18px;\n      font-weight: 700;\n      color: $primary-text-color;\n      white-space: nowrap;\n      overflow: hidden;\n      text-overflow: ellipsis;\n\n      .fa {\n        color: $darker-text-color;\n      }\n\n      small {\n        display: block;\n        font-weight: 400;\n        font-size: 15px;\n        margin-top: 8px;\n        color: $darker-text-color;\n      }\n    }\n\n    &.active h4 {\n      &,\n      .fa,\n      small {\n        color: $primary-text-color;\n      }\n    }\n\n    .avatar-stack {\n      flex: 0 0 auto;\n      width: (36px + 4px) * 3;\n    }\n\n    &.active .avatar-stack .account__avatar {\n      border-color: $ui-highlight-color;\n    }\n  }\n}\n\n.avatar-stack {\n  display: flex;\n  justify-content: flex-end;\n\n  .account__avatar {\n    flex: 0 0 auto;\n    width: 36px;\n    height: 36px;\n    border-radius: 50%;\n    position: relative;\n    margin-left: -10px;\n    background: darken($ui-base-color, 8%);\n    border: 2px solid $ui-base-color;\n\n    &:nth-child(1) {\n      z-index: 1;\n    }\n\n    &:nth-child(2) {\n      z-index: 2;\n    }\n\n    &:nth-child(3) {\n      z-index: 3;\n    }\n  }\n}\n\n.accounts-table {\n  width: 100%;\n\n  .account {\n    padding: 0;\n    border: 0;\n  }\n\n  strong {\n    font-weight: 700;\n  }\n\n  thead th {\n    text-align: center;\n    text-transform: uppercase;\n    color: $darker-text-color;\n    font-weight: 700;\n    padding: 10px;\n\n    &:first-child {\n      text-align: left;\n    }\n  }\n\n  tbody td {\n    padding: 15px 0;\n    vertical-align: middle;\n    border-bottom: 1px solid lighten($ui-base-color, 8%);\n  }\n\n  tbody tr:last-child td {\n    border-bottom: 0;\n  }\n\n  &__count {\n    width: 120px;\n    text-align: center;\n    font-size: 15px;\n    font-weight: 500;\n    color: $primary-text-color;\n\n    small {\n      display: block;\n      color: $darker-text-color;\n      font-weight: 400;\n      font-size: 14px;\n    }\n  }\n\n  &__comment {\n    width: 50%;\n    vertical-align: initial !important;\n  }\n\n  @media screen and (max-width: $no-gap-breakpoint) {\n    tbody td.optional {\n      display: none;\n    }\n  }\n}\n\n.moved-account-widget,\n.memoriam-widget,\n.box-widget,\n.contact-widget,\n.landing-page__information.contact-widget,\n.directory,\n.page-header {\n  @media screen and (max-width: $no-gap-breakpoint) {\n    margin-bottom: 0;\n    box-shadow: none;\n    border-radius: 0;\n  }\n}\n\n$maximum-width: 1235px;\n$fluid-breakpoint: $maximum-width + 20px;\n\n.statuses-grid {\n  min-height: 600px;\n\n  @media screen and (max-width: 640px) {\n    width: 100% !important; // Masonry layout is unnecessary at this width\n  }\n\n  &__item {\n    width: (960px - 20px) / 3;\n\n    @media screen and (max-width: $fluid-breakpoint) {\n      width: (940px - 20px) / 3;\n    }\n\n    @media screen and (max-width: 640px) {\n      width: 100%;\n    }\n\n    @media screen and (max-width: $no-gap-breakpoint) {\n      width: 100vw;\n    }\n  }\n\n  .detailed-status {\n    border-radius: 4px;\n\n    @media screen and (max-width: $no-gap-breakpoint) {\n      border-top: 1px solid lighten($ui-base-color, 16%);\n    }\n\n    &.compact {\n      .detailed-status__meta {\n        margin-top: 15px;\n      }\n\n      .status__content {\n        font-size: 15px;\n        line-height: 20px;\n\n        .emojione {\n          width: 20px;\n          height: 20px;\n          margin: -3px 0 0;\n        }\n\n        .status__content__spoiler-link {\n          line-height: 20px;\n          margin: 0;\n        }\n      }\n\n      .media-gallery,\n      .status-card,\n      .video-player {\n        margin-top: 15px;\n      }\n    }\n  }\n}\n\n.notice-widget {\n  margin-bottom: 10px;\n  color: $darker-text-color;\n\n  p {\n    margin-bottom: 10px;\n\n    &:last-child {\n      margin-bottom: 0;\n    }\n  }\n\n  a {\n    font-size: 14px;\n    line-height: 20px;\n    text-decoration: none;\n    font-weight: 500;\n    color: $ui-highlight-color;\n\n    &:hover,\n    &:focus,\n    &:active {\n      text-decoration: underline;\n    }\n  }\n}\n"
  },
  {
    "path": "app/javascript/styles/mastodon-light/diff.scss",
    "content": "// Notes!\n// Sass color functions, \"darken\" and \"lighten\" are automatically replaced.\n\nhtml {\n  scrollbar-color: $ui-base-color rgba($ui-base-color, 0.25);\n}\n\n// Change the colors of button texts\n.button {\n  color: $white;\n\n  &.button-alternative-2 {\n    color: $white;\n  }\n}\n\n// Change default background colors of columns\n.column > .scrollable,\n.getting-started,\n.column-inline-form {\n  background: $white;\n  border: 1px solid lighten($ui-base-color, 8%);\n  border-top: 0;\n}\n\n.column-back-button,\n.column-header {\n  background: $white;\n  border: 1px solid lighten($ui-base-color, 8%);\n\n  @media screen and (max-width: $no-gap-breakpoint) {\n    border-top: 0;\n  }\n\n  &--slim-button {\n    border: 0;\n    top: -49px;\n    right: 1px;\n  }\n}\n\n.column-header__back-button,\n.column-header__button,\n.column-header__button.active,\n.account__header__bar {\n  background: $white;\n}\n\n.column-header__button.active {\n  color: $ui-highlight-color;\n\n  &:hover,\n  &:active,\n  &:focus {\n    color: $ui-highlight-color;\n    background: $white;\n  }\n}\n\n.account__header__bar .avatar .account__avatar {\n  border-color: $white;\n}\n\n.getting-started__footer a {\n  color: $ui-secondary-color;\n  text-decoration: underline;\n}\n\n.column-subheading {\n  background: darken($ui-base-color, 4%);\n  border-bottom: 1px solid lighten($ui-base-color, 8%);\n}\n\n.getting-started,\n.scrollable {\n  .column-link {\n    background: $white;\n    border-bottom: 1px solid lighten($ui-base-color, 8%);\n\n    &:hover,\n    &:active,\n    &:focus {\n      background: $ui-base-color;\n    }\n  }\n}\n\n.getting-started .navigation-bar {\n  border-top: 1px solid lighten($ui-base-color, 8%);\n  border-bottom: 1px solid lighten($ui-base-color, 8%);\n\n  @media screen and (max-width: $no-gap-breakpoint) {\n    border-top: 0;\n  }\n}\n\n.compose-form__autosuggest-wrapper,\n.poll__text input[type=\"text\"],\n.compose-form .spoiler-input__input,\n.compose-form__poll-wrapper select,\n.search__input,\n.setting-text,\n.box-widget input[type=\"text\"],\n.box-widget input[type=\"email\"],\n.box-widget input[type=\"password\"],\n.box-widget textarea,\n.statuses-grid .detailed-status {\n  border: 1px solid lighten($ui-base-color, 8%);\n}\n\n.search__input {\n  @media screen and (max-width: $no-gap-breakpoint) {\n    border-top: 0;\n    border-bottom: 0;\n  }\n}\n\n.list-editor .search .search__input {\n  border-top: 0;\n  border-bottom: 0;\n}\n\n.compose-form__poll-wrapper select {\n  background: $simple-background-color url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14.933 18.467' height='19.698' width='15.929'><path d='M3.467 14.967l-3.393-3.5H14.86l-3.392 3.5c-1.866 1.925-3.666 3.5-4 3.5-.335 0-2.135-1.575-4-3.5zm.266-11.234L7.467 0 11.2 3.733l3.733 3.734H0l3.733-3.734z' fill='#{hex-color(lighten($ui-base-color, 8%))}'/></svg>\") no-repeat right 8px center / auto 16px;\n}\n\n.compose-form__poll-wrapper,\n.compose-form__poll-wrapper .poll__footer {\n  border-top-color: lighten($ui-base-color, 8%);\n}\n\n.notification__filter-bar {\n  border: 1px solid lighten($ui-base-color, 8%);\n  border-top: 0;\n}\n\n.compose-form .compose-form__buttons-wrapper {\n  background: $ui-base-color;\n  border: 1px solid lighten($ui-base-color, 8%);\n  border-top: 0;\n}\n\n.drawer__header,\n.drawer__inner {\n  background: $white;\n  border: 1px solid lighten($ui-base-color, 8%);\n}\n\n.drawer__inner__mastodon {\n  background: $white url('data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 234.80078 31.757813\" width=\"234.80078\" height=\"31.757812\"><path d=\"M19.599609 0c-1.05 0-2.10039.375-2.90039 1.125L0 16.925781v14.832031h234.80078V17.025391l-16.5-15.900391c-1.6-1.5-4.20078-1.5-5.80078 0l-13.80078 13.099609c-1.6 1.5-4.19883 1.5-5.79883 0L179.09961 1.125c-1.6-1.5-4.19883-1.5-5.79883 0L159.5 14.224609c-1.6 1.5-4.20078 1.5-5.80078 0L139.90039 1.125c-1.6-1.5-4.20078-1.5-5.80078 0l-13.79883 13.099609c-1.6 1.5-4.20078 1.5-5.80078 0L100.69922 1.125c-1.600001-1.5-4.198829-1.5-5.798829 0l-13.59961 13.099609c-1.6 1.5-4.200781 1.5-5.800781 0L61.699219 1.125c-1.6-1.5-4.198828-1.5-5.798828 0L42.099609 14.224609c-1.6 1.5-4.198828 1.5-5.798828 0L22.5 1.125C21.7.375 20.649609 0 19.599609 0z\" fill=\"#{hex-color($ui-base-color)}\"/></svg>') no-repeat bottom / 100% auto;\n}\n\n// Change the colors used in compose-form\n.compose-form {\n  .compose-form__modifiers {\n    .compose-form__upload__actions .icon-button {\n      color: lighten($white, 7%);\n\n      &:active,\n      &:focus,\n      &:hover {\n        color: $white;\n      }\n    }\n\n    .compose-form__upload-description input {\n      color: lighten($white, 7%);\n\n      &::placeholder {\n        color: lighten($white, 7%);\n      }\n    }\n  }\n\n  .compose-form__buttons-wrapper {\n    background: darken($ui-base-color, 6%);\n  }\n\n  .autosuggest-textarea__suggestions {\n    background: darken($ui-base-color, 6%);\n  }\n\n  .autosuggest-textarea__suggestions__item {\n    &:hover,\n    &:focus,\n    &:active,\n    &.selected {\n      background: lighten($ui-base-color, 4%);\n    }\n  }\n}\n\n.emoji-mart-bar {\n  border-color: lighten($ui-base-color, 4%);\n\n  &:first-child {\n    background: darken($ui-base-color, 6%);\n  }\n}\n\n.emoji-mart-search input {\n  background: rgba($ui-base-color, 0.3);\n  border-color: $ui-base-color;\n}\n\n// Change the background colors of statuses\n.focusable:focus {\n  background: $ui-base-color;\n}\n\n.status.status-direct {\n  background: lighten($ui-base-color, 4%);\n}\n\n.focusable:focus .status.status-direct {\n  background: lighten($ui-base-color, 8%);\n}\n\n.detailed-status,\n.detailed-status__action-bar {\n  background: $white;\n}\n\n// Change the background colors of status__content__spoiler-link\n.reply-indicator__content .status__content__spoiler-link,\n.status__content .status__content__spoiler-link {\n  background: $ui-base-color;\n\n  &:hover {\n    background: lighten($ui-base-color, 4%);\n  }\n}\n\n// Change the background colors of media and video spoilers\n.media-spoiler,\n.video-player__spoiler {\n  background: $ui-base-color;\n}\n\n.privacy-dropdown.active .privacy-dropdown__value.active .icon-button {\n  color: $white;\n}\n\n.account-gallery__item a {\n  background-color: $ui-base-color;\n}\n\n// Change the colors used in the dropdown menu\n.dropdown-menu {\n  background: $white;\n\n  &__arrow {\n    &.left {\n      border-left-color: $white;\n    }\n\n    &.top {\n      border-top-color: $white;\n    }\n\n    &.bottom {\n      border-bottom-color: $white;\n    }\n\n    &.right {\n      border-right-color: $white;\n    }\n  }\n\n  &__item {\n    a {\n      background: $white;\n      color: $darker-text-color;\n    }\n  }\n}\n\n// Change the text colors on inverted background\n.privacy-dropdown__option.active,\n.privacy-dropdown__option:hover,\n.privacy-dropdown__option.active .privacy-dropdown__option__content,\n.privacy-dropdown__option.active .privacy-dropdown__option__content strong,\n.privacy-dropdown__option:hover .privacy-dropdown__option__content,\n.privacy-dropdown__option:hover .privacy-dropdown__option__content strong,\n.dropdown-menu__item a:active,\n.dropdown-menu__item a:focus,\n.dropdown-menu__item a:hover,\n.actions-modal ul li:not(:empty) a.active,\n.actions-modal ul li:not(:empty) a.active button,\n.actions-modal ul li:not(:empty) a:active,\n.actions-modal ul li:not(:empty) a:active button,\n.actions-modal ul li:not(:empty) a:focus,\n.actions-modal ul li:not(:empty) a:focus button,\n.actions-modal ul li:not(:empty) a:hover,\n.actions-modal ul li:not(:empty) a:hover button,\n.admin-wrapper .sidebar ul .simple-navigation-active-leaf a,\n.simple_form .block-button,\n.simple_form .button,\n.simple_form button {\n  color: $white;\n}\n\n.dropdown-menu__separator {\n  border-bottom-color: lighten($ui-base-color, 4%);\n}\n\n// Change the background colors of modals\n.actions-modal,\n.boost-modal,\n.confirmation-modal,\n.mute-modal,\n.report-modal,\n.embed-modal,\n.error-modal,\n.onboarding-modal {\n  background: $ui-base-color;\n}\n\n.column-header__collapsible-inner {\n  background: darken($ui-base-color, 4%);\n  border: 1px solid lighten($ui-base-color, 8%);\n  border-top: 0;\n}\n\n.boost-modal__action-bar,\n.confirmation-modal__action-bar,\n.mute-modal__action-bar,\n.onboarding-modal__paginator,\n.error-modal__footer {\n  background: darken($ui-base-color, 6%);\n\n  .onboarding-modal__nav,\n  .error-modal__nav {\n    &:hover,\n    &:focus,\n    &:active {\n      background-color: darken($ui-base-color, 12%);\n    }\n  }\n}\n\n.display-case__case {\n  background: $white;\n}\n\n.embed-modal .embed-modal__container .embed-modal__html {\n  background: $white;\n\n  &:focus {\n    background: darken($ui-base-color, 6%);\n  }\n}\n\n.react-toggle-track {\n  background: $ui-secondary-color;\n}\n\n.react-toggle:hover:not(.react-toggle--disabled) .react-toggle-track {\n  background: darken($ui-secondary-color, 10%);\n}\n\n.react-toggle.react-toggle--checked:hover:not(.react-toggle--disabled) .react-toggle-track {\n  background: lighten($ui-highlight-color, 10%);\n}\n\n// Change the default color used for the text in an empty column or on the error column\n.empty-column-indicator,\n.error-column {\n  color: $primary-text-color;\n  background: $white;\n}\n\n.tabs-bar {\n  background: $white;\n  border: 1px solid lighten($ui-base-color, 8%);\n  border-bottom: 0;\n\n  @media screen and (max-width: $no-gap-breakpoint) {\n    border-top: 0;\n  }\n\n  &__link {\n    padding-bottom: 14px;\n    border-bottom-width: 1px;\n    border-bottom-color: lighten($ui-base-color, 8%);\n\n    &:hover,\n    &:active,\n    &:focus {\n      background: $ui-base-color;\n    }\n\n    &.active {\n      &:hover,\n      &:active,\n      &:focus {\n        background: transparent;\n        border-bottom-color: $ui-highlight-color;\n      }\n    }\n  }\n}\n\n// Change the default colors used on some parts of the profile pages\n.activity-stream-tabs {\n  background: $account-background-color;\n  border-bottom-color: lighten($ui-base-color, 8%);\n}\n\n.box-widget,\n.nothing-here,\n.page-header,\n.directory__tag > a,\n.directory__tag > div,\n.landing-page__call-to-action,\n.contact-widget,\n.landing .hero-widget__text,\n.landing-page__information.contact-widget {\n  background: $white;\n  border: 1px solid lighten($ui-base-color, 8%);\n\n  @media screen and (max-width: $no-gap-breakpoint) {\n    border-left: 0;\n    border-right: 0;\n    border-top: 0;\n  }\n}\n\n.landing .hero-widget__text {\n  border-top: 0;\n  border-bottom: 0;\n}\n\n.simple_form {\n  input[type=text],\n  input[type=number],\n  input[type=email],\n  input[type=password],\n  textarea {\n    &:hover {\n      border-color: lighten($ui-base-color, 12%);\n    }\n  }\n}\n\n.landing .hero-widget__footer {\n  background: $white;\n  border: 1px solid lighten($ui-base-color, 8%);\n  border-top: 0;\n\n  @media screen and (max-width: $no-gap-breakpoint) {\n    border: 0;\n  }\n}\n\n.brand__tagline {\n  color: $ui-secondary-color;\n}\n\n.directory__tag > a {\n  &:hover,\n  &:active,\n  &:focus {\n    background: $ui-base-color;\n  }\n\n  @media screen and (max-width: $no-gap-breakpoint) {\n    border: 0;\n  }\n}\n\n.directory__tag.active > a,\n.directory__tag.active > div {\n  border-color: $ui-highlight-color;\n\n  &,\n  h4,\n  h4 small,\n  .fa,\n  .trends__item__current {\n    color: $white;\n  }\n\n  &:hover,\n  &:active,\n  &:focus {\n    background: $ui-highlight-color;\n  }\n}\n\n.batch-table {\n  &__toolbar,\n  &__row,\n  .nothing-here {\n    border-color: lighten($ui-base-color, 8%);\n  }\n}\n\n.activity-stream {\n  border: 1px solid lighten($ui-base-color, 8%);\n\n  &--under-tabs {\n    border-top: 0;\n  }\n\n  .entry {\n    background: $account-background-color;\n\n    .detailed-status.light,\n    .more.light,\n    .status.light {\n      border-bottom-color: lighten($ui-base-color, 8%);\n    }\n  }\n\n  .status.light {\n    .status__content {\n      color: $primary-text-color;\n    }\n\n    .display-name {\n      strong {\n        color: $primary-text-color;\n      }\n    }\n  }\n}\n\n.accounts-grid {\n  .account-grid-card {\n    .controls {\n      .icon-button {\n        color: $darker-text-color;\n      }\n    }\n\n    .name {\n      a {\n        color: $primary-text-color;\n      }\n    }\n\n    .username {\n      color: $darker-text-color;\n    }\n\n    .account__header__content {\n      color: $primary-text-color;\n    }\n  }\n}\n\n.simple_form,\n.table-form {\n  .warning {\n    box-shadow: none;\n    background: rgba($error-red, 0.5);\n    text-shadow: none;\n  }\n\n  .recommended {\n    border-color: $ui-highlight-color;\n    color: $ui-highlight-color;\n    background-color: rgba($ui-highlight-color, 0.1);\n  }\n}\n\n.compose-form .compose-form__warning {\n  border-color: $ui-highlight-color;\n  background-color: rgba($ui-highlight-color, 0.1);\n\n  &,\n  a {\n    color: $ui-highlight-color;\n  }\n}\n\n.status__content,\n.reply-indicator__content {\n  a {\n    color: $highlight-text-color;\n  }\n}\n\n.button.logo-button {\n  color: $white;\n\n  svg {\n    fill: $white;\n  }\n}\n\n.public-layout {\n  .account__section-headline {\n    border: 1px solid lighten($ui-base-color, 8%);\n\n    @media screen and (max-width: $no-gap-breakpoint) {\n      border-top: 0;\n    }\n  }\n\n  .header,\n  .public-account-header,\n  .public-account-bio {\n    box-shadow: none;\n  }\n\n  .public-account-bio,\n  .hero-widget__text {\n    background: $account-background-color;\n    border: 1px solid lighten($ui-base-color, 8%);\n  }\n\n  .header {\n    background: $ui-base-color;\n    border: 1px solid lighten($ui-base-color, 8%);\n\n    @media screen and (max-width: $no-gap-breakpoint) {\n      border: 0;\n    }\n\n    .brand {\n      &:hover,\n      &:focus,\n      &:active {\n        background: lighten($ui-base-color, 4%);\n      }\n    }\n  }\n\n  .public-account-header {\n    &__image {\n      background: lighten($ui-base-color, 12%);\n\n      &::after {\n        box-shadow: none;\n      }\n    }\n\n    &__bar {\n      &::before {\n        background: $account-background-color;\n        border: 1px solid lighten($ui-base-color, 8%);\n        border-top: 0;\n      }\n\n      .avatar img {\n        border-color: $account-background-color;\n      }\n\n      @media screen and (max-width: $no-columns-breakpoint) {\n        background: $account-background-color;\n        border: 1px solid lighten($ui-base-color, 8%);\n        border-top: 0;\n      }\n    }\n\n    &__tabs {\n      &__name {\n        h1,\n        h1 small {\n          color: $white;\n\n          @media screen and (max-width: $no-columns-breakpoint) {\n            color: $primary-text-color;\n          }\n        }\n      }\n    }\n\n    &__extra {\n      .public-account-bio {\n        border: 0;\n      }\n\n      .public-account-bio .account__header__fields {\n        border-color: lighten($ui-base-color, 8%);\n      }\n    }\n  }\n}\n\n.notification__filter-bar button.active::after,\n.account__section-headline a.active::after {\n  border-color: transparent transparent $white;\n}\n\n.hero-widget,\n.box-widget,\n.contact-widget,\n.landing-page__information.contact-widget,\n.moved-account-widget,\n.memoriam-widget,\n.activity-stream,\n.nothing-here,\n.directory__tag > a,\n.directory__tag > div,\n.card > a,\n.page-header,\n.compose-form .compose-form__warning {\n  box-shadow: none;\n}\n"
  },
  {
    "path": "app/javascript/styles/mastodon-light/variables.scss",
    "content": "// Dependent colors\n$black: #000000;\n$white: #ffffff;\n\n$classic-base-color: #282c37;\n$classic-primary-color: #9baec8;\n$classic-secondary-color: #d9e1e8;\n$classic-highlight-color: #2b90d9;\n\n// Differences\n$success-green: #3c754d;\n\n$base-overlay-background: $white !default;\n$valid-value-color: $success-green !default;\n\n$ui-base-color: $classic-secondary-color !default;\n$ui-base-lighter-color: #b0c0cf;\n$ui-primary-color: #9bcbed;\n$ui-secondary-color: $classic-base-color !default;\n$ui-highlight-color: #2b90d9;\n\n$primary-text-color: $black !default;\n$darker-text-color: $classic-base-color !default;\n$dark-text-color: #444b5d;\n$action-button-color: #606984;\n\n$inverted-text-color: $black !default;\n$lighter-text-color: $classic-base-color !default;\n$light-text-color: #444b5d;\n\n//Newly added colors\n$account-background-color: $white !default;\n\n//Invert darkened and lightened colors\n@function darken($color, $amount) {\n  @return hsl(hue($color), saturation($color), lightness($color) + $amount);\n}\n\n@function lighten($color, $amount) {\n  @return hsl(hue($color), saturation($color), lightness($color) - $amount);\n}\n"
  },
  {
    "path": "app/javascript/styles/mastodon-light.scss",
    "content": "@import 'mastodon-light/variables';\n@import 'application';\n@import 'mastodon-light/diff';\n"
  },
  {
    "path": "app/lib/activity_tracker.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityTracker\n  EXPIRE_AFTER = 90.days.seconds\n\n  class << self\n    include Redisable\n\n    def increment(prefix)\n      key = [prefix, current_week].join(':')\n\n      redis.incrby(key, 1)\n      redis.expire(key, EXPIRE_AFTER)\n    end\n\n    def record(prefix, value)\n      key = [prefix, current_week].join(':')\n\n      redis.pfadd(key, value)\n      redis.expire(key, EXPIRE_AFTER)\n    end\n\n    private\n\n    def current_week\n      Time.zone.today.cweek\n    end\n  end\nend\n"
  },
  {
    "path": "app/lib/activitypub/activity/accept.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::Activity::Accept < ActivityPub::Activity\n  def perform\n    case @object['type']\n    when 'Follow'\n      accept_follow\n    end\n  end\n\n  private\n\n  def accept_follow\n    return accept_follow_for_relay if relay_follow?\n\n    target_account = account_from_uri(target_uri)\n\n    return if target_account.nil? || !target_account.local?\n\n    follow_request = FollowRequest.find_by(account: target_account, target_account: @account)\n    follow_request&.authorize!\n  end\n\n  def accept_follow_for_relay\n    relay.update!(state: :accepted)\n  end\n\n  def relay\n    @relay ||= Relay.find_by(follow_activity_id: object_uri) unless object_uri.nil?\n  end\n\n  def relay_follow?\n    relay.present?\n  end\n\n  def target_uri\n    @target_uri ||= value_or_id(@object['actor'])\n  end\nend\n"
  },
  {
    "path": "app/lib/activitypub/activity/add.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::Activity::Add < ActivityPub::Activity\n  def perform\n    return unless @json['target'].present? && value_or_id(@json['target']) == @account.featured_collection_url\n\n    status   = status_from_uri(object_uri)\n    status ||= fetch_remote_original_status\n\n    return unless !status.nil? && status.account_id == @account.id && !@account.pinned?(status)\n\n    StatusPin.create!(account: @account, status: status)\n  end\nend\n"
  },
  {
    "path": "app/lib/activitypub/activity/announce.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::Activity::Announce < ActivityPub::Activity\n  def perform\n    return reject_payload! if delete_arrived_first?(@json['id']) || !related_to_local_activity?\n\n    original_status = status_from_object\n\n    return reject_payload! if original_status.nil? || !announceable?(original_status)\n\n    status = Status.find_by(account: @account, reblog: original_status)\n\n    return status unless status.nil?\n\n    status = Status.create!(\n      account: @account,\n      reblog: original_status,\n      uri: @json['id'],\n      created_at: @json['published'],\n      override_timestamps: @options[:override_timestamps],\n      visibility: visibility_from_audience\n    )\n\n    distribute(status)\n    status\n  end\n\n  private\n\n  def visibility_from_audience\n    if equals_or_includes?(@json['to'], ActivityPub::TagManager::COLLECTIONS[:public])\n      :public\n    elsif equals_or_includes?(@json['cc'], ActivityPub::TagManager::COLLECTIONS[:public])\n      :unlisted\n    elsif equals_or_includes?(@json['to'], @account.followers_url)\n      :private\n    else\n      :direct\n    end\n  end\n\n  def announceable?(status)\n    status.account_id == @account.id || status.public_visibility? || status.unlisted_visibility?\n  end\n\n  def related_to_local_activity?\n    followed_by_local_accounts? || requested_through_relay? || reblog_of_local_status?\n  end\n\n  def requested_through_relay?\n    super || Relay.find_by(inbox_url: @account.inbox_url)&.enabled?\n  end\n\n  def reblog_of_local_status?\n    status_from_uri(object_uri)&.account&.local?\n  end\nend\n"
  },
  {
    "path": "app/lib/activitypub/activity/block.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::Activity::Block < ActivityPub::Activity\n  def perform\n    target_account = account_from_uri(object_uri)\n\n    return if target_account.nil? || !target_account.local? || @account.blocking?(target_account)\n\n    UnfollowService.new.call(target_account, @account) if target_account.following?(@account)\n\n    @account.block!(target_account, uri: @json['id']) unless delete_arrived_first?(@json['id'])\n  end\nend\n"
  },
  {
    "path": "app/lib/activitypub/activity/create.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::Activity::Create < ActivityPub::Activity\n  def perform\n    return reject_payload! if unsupported_object_type? || invalid_origin?(@object['id']) || Tombstone.exists?(uri: @object['id']) || !related_to_local_activity?\n\n    RedisLock.acquire(lock_options) do |lock|\n      if lock.acquired?\n        return if delete_arrived_first?(object_uri) || poll_vote?\n\n        @status = find_existing_status\n\n        if @status.nil?\n          process_status\n        elsif @options[:delivered_to_account_id].present?\n          postprocess_audience_and_deliver\n        end\n      else\n        raise Mastodon::RaceConditionError\n      end\n    end\n\n    @status\n  end\n\n  private\n\n  def process_status\n    @tags     = []\n    @mentions = []\n    @params   = {}\n\n    process_status_params\n    process_tags\n    process_audience\n\n    ApplicationRecord.transaction do\n      @status = Status.create!(@params)\n      attach_tags(@status)\n    end\n\n    resolve_thread(@status)\n    fetch_replies(@status)\n    distribute(@status)\n    forward_for_reply if @status.public_visibility? || @status.unlisted_visibility?\n  end\n\n  def find_existing_status\n    status   = status_from_uri(object_uri)\n    status ||= Status.find_by(uri: @object['atomUri']) if @object['atomUri'].present?\n    status\n  end\n\n  def process_status_params\n    @params = begin\n      {\n        uri: @object['id'],\n        url: object_url || @object['id'],\n        account: @account,\n        text: text_from_content || '',\n        language: detected_language,\n        spoiler_text: converted_object_type? ? '' : (text_from_summary || ''),\n        created_at: @object['published'],\n        override_timestamps: @options[:override_timestamps],\n        reply: @object['inReplyTo'].present?,\n        sensitive: @object['sensitive'] || false,\n        visibility: visibility_from_audience,\n        thread: replied_to_status,\n        conversation: conversation_from_uri(@object['conversation']),\n        media_attachment_ids: process_attachments.take(4).map(&:id),\n        poll: process_poll,\n      }\n    end\n  end\n\n  def process_audience\n    (as_array(@object['to']) + as_array(@object['cc'])).uniq.each do |audience|\n      next if audience == ActivityPub::TagManager::COLLECTIONS[:public]\n\n      # Unlike with tags, there is no point in resolving accounts we don't already\n      # know here, because silent mentions would only be used for local access\n      # control anyway\n      account = account_from_uri(audience)\n\n      next if account.nil? || @mentions.any? { |mention| mention.account_id == account.id }\n\n      @mentions << Mention.new(account: account, silent: true)\n\n      # If there is at least one silent mention, then the status can be considered\n      # as a limited-audience status, and not strictly a direct message, but only\n      # if we considered a direct message in the first place\n      next unless @params[:visibility] == :direct\n\n      @params[:visibility] = :limited\n    end\n\n    # If the payload was delivered to a specific inbox, the inbox owner must have\n    # access to it, unless they already have access to it anyway\n    return if @options[:delivered_to_account_id].nil? || @mentions.any? { |mention| mention.account_id == @options[:delivered_to_account_id] }\n\n    @mentions << Mention.new(account_id: @options[:delivered_to_account_id], silent: true)\n\n    return unless @params[:visibility] == :direct\n\n    @params[:visibility] = :limited\n  end\n\n  def postprocess_audience_and_deliver\n    return if @status.mentions.find_by(account_id: @options[:delivered_to_account_id])\n\n    delivered_to_account = Account.find(@options[:delivered_to_account_id])\n\n    @status.mentions.create(account: delivered_to_account, silent: true)\n    @status.update(visibility: :limited) if @status.direct_visibility?\n\n    return unless delivered_to_account.following?(@account)\n\n    FeedInsertWorker.perform_async(@status.id, delivered_to_account.id, :home)\n  end\n\n  def attach_tags(status)\n    @tags.each do |tag|\n      status.tags << tag\n      TrendingTags.record_use!(tag, status.account, status.created_at) if status.public_visibility?\n    end\n\n    @mentions.each do |mention|\n      mention.status = status\n      mention.save\n    end\n  end\n\n  def process_tags\n    return if @object['tag'].nil?\n\n    as_array(@object['tag']).each do |tag|\n      if equals_or_includes?(tag['type'], 'Hashtag')\n        process_hashtag tag\n      elsif equals_or_includes?(tag['type'], 'Mention')\n        process_mention tag\n      elsif equals_or_includes?(tag['type'], 'Emoji')\n        process_emoji tag\n      end\n    end\n  end\n\n  def process_hashtag(tag)\n    return if tag['name'].blank?\n\n    hashtag = tag['name'].gsub(/\\A#/, '').mb_chars.downcase\n    hashtag = Tag.where(name: hashtag).first_or_create!(name: hashtag)\n\n    return if @tags.include?(hashtag)\n\n    @tags << hashtag\n  rescue ActiveRecord::RecordInvalid\n    nil\n  end\n\n  def process_mention(tag)\n    return if tag['href'].blank?\n\n    account = account_from_uri(tag['href'])\n    account = ::FetchRemoteAccountService.new.call(tag['href']) if account.nil?\n\n    return if account.nil?\n\n    @mentions << Mention.new(account: account, silent: false)\n  end\n\n  def process_emoji(tag)\n    return if skip_download?\n    return if tag['name'].blank? || tag['icon'].blank? || tag['icon']['url'].blank?\n\n    shortcode = tag['name'].delete(':')\n    image_url = tag['icon']['url']\n    uri       = tag['id']\n    updated   = tag['updated']\n    emoji     = CustomEmoji.find_by(shortcode: shortcode, domain: @account.domain)\n\n    return unless emoji.nil? || image_url != emoji.image_remote_url || (updated && updated >= emoji.updated_at)\n\n    emoji ||= CustomEmoji.new(domain: @account.domain, shortcode: shortcode, uri: uri)\n    emoji.image_remote_url = image_url\n    emoji.save\n  end\n\n  def process_attachments\n    return [] if @object['attachment'].nil?\n\n    media_attachments = []\n\n    as_array(@object['attachment']).each do |attachment|\n      next if attachment['url'].blank?\n\n      href             = Addressable::URI.parse(attachment['url']).normalize.to_s\n      media_attachment = MediaAttachment.create(account: @account, remote_url: href, description: attachment['name'].presence, focus: attachment['focalPoint'], blurhash: supported_blurhash?(attachment['blurhash']) ? attachment['blurhash'] : nil)\n      media_attachments << media_attachment\n\n      next if unsupported_media_type?(attachment['mediaType']) || skip_download?\n\n      media_attachment.file_remote_url = href\n      media_attachment.save\n    end\n\n    media_attachments\n  rescue Addressable::URI::InvalidURIError => e\n    Rails.logger.debug e\n\n    media_attachments\n  end\n\n  def process_poll\n    return unless @object['type'] == 'Question' && (@object['anyOf'].is_a?(Array) || @object['oneOf'].is_a?(Array))\n\n    expires_at = begin\n      if @object['closed'].is_a?(String)\n        @object['closed']\n      elsif !@object['closed'].nil? && !@object['closed'].is_a?(FalseClass)\n        Time.now.utc\n      else\n        @object['endTime']\n      end\n    end\n\n    if @object['anyOf'].is_a?(Array)\n      multiple = true\n      items    = @object['anyOf']\n    else\n      multiple = false\n      items    = @object['oneOf']\n    end\n\n    @account.polls.new(\n      multiple: multiple,\n      expires_at: expires_at,\n      options: items.map { |item| item['name'].presence || item['content'] }.compact,\n      cached_tallies: items.map { |item| item.dig('replies', 'totalItems') || 0 }\n    )\n  end\n\n  def poll_vote?\n    return false if replied_to_status.nil? || replied_to_status.preloadable_poll.nil? || !replied_to_status.local? || !replied_to_status.preloadable_poll.options.include?(@object['name'])\n\n    unless replied_to_status.preloadable_poll.expired?\n      replied_to_status.preloadable_poll.votes.create!(account: @account, choice: replied_to_status.preloadable_poll.options.index(@object['name']), uri: @object['id'])\n      ActivityPub::DistributePollUpdateWorker.perform_in(3.minutes, replied_to_status.id) unless replied_to_status.preloadable_poll.hide_totals?\n    end\n\n    true\n  end\n\n  def resolve_thread(status)\n    return unless status.reply? && status.thread.nil? && Request.valid_url?(in_reply_to_uri)\n    ThreadResolveWorker.perform_async(status.id, in_reply_to_uri)\n  end\n\n  def fetch_replies(status)\n    collection = @object['replies']\n    return if collection.nil?\n    replies = ActivityPub::FetchRepliesService.new.call(status, collection, false)\n    return unless replies.nil?\n    uri = value_or_id(collection)\n    ActivityPub::FetchRepliesWorker.perform_async(status.id, uri) unless uri.nil?\n  end\n\n  def conversation_from_uri(uri)\n    return nil if uri.nil?\n    return Conversation.find_by(id: OStatus::TagManager.instance.unique_tag_to_local_id(uri, 'Conversation')) if OStatus::TagManager.instance.local_id?(uri)\n    begin\n      Conversation.find_or_create_by!(uri: uri)\n    rescue ActiveRecord::RecordInvalid, ActiveRecord::RecordNotUnique\n      retry\n    end\n  end\n\n  def visibility_from_audience\n    if equals_or_includes?(@object['to'], ActivityPub::TagManager::COLLECTIONS[:public])\n      :public\n    elsif equals_or_includes?(@object['cc'], ActivityPub::TagManager::COLLECTIONS[:public])\n      :unlisted\n    elsif equals_or_includes?(@object['to'], @account.followers_url)\n      :private\n    else\n      :direct\n    end\n  end\n\n  def audience_includes?(account)\n    uri = ActivityPub::TagManager.instance.uri_for(account)\n    equals_or_includes?(@object['to'], uri) || equals_or_includes?(@object['cc'], uri)\n  end\n\n  def replied_to_status\n    return @replied_to_status if defined?(@replied_to_status)\n\n    if in_reply_to_uri.blank?\n      @replied_to_status = nil\n    else\n      @replied_to_status   = status_from_uri(in_reply_to_uri)\n      @replied_to_status ||= status_from_uri(@object['inReplyToAtomUri']) if @object['inReplyToAtomUri'].present?\n      @replied_to_status\n    end\n  end\n\n  def in_reply_to_uri\n    value_or_id(@object['inReplyTo'])\n  end\n\n  def text_from_content\n    return Formatter.instance.linkify([[text_from_name, text_from_summary.presence].compact.join(\"\\n\\n\"), object_url || @object['id']].join(' ')) if converted_object_type?\n\n    if @object['content'].present?\n      @object['content']\n    elsif content_language_map?\n      @object['contentMap'].values.first\n    end\n  end\n\n  def text_from_summary\n    if @object['summary'].present?\n      @object['summary']\n    elsif summary_language_map?\n      @object['summaryMap'].values.first\n    end\n  end\n\n  def text_from_name\n    if @object['name'].present?\n      @object['name']\n    elsif name_language_map?\n      @object['nameMap'].values.first\n    end\n  end\n\n  def detected_language\n    if content_language_map?\n      @object['contentMap'].keys.first\n    elsif name_language_map?\n      @object['nameMap'].keys.first\n    elsif summary_language_map?\n      @object['summaryMap'].keys.first\n    elsif supported_object_type?\n      LanguageDetector.instance.detect(text_from_content, @account)\n    end\n  end\n\n  def object_url\n    return if @object['url'].blank?\n\n    url_candidate = url_to_href(@object['url'], 'text/html')\n\n    if invalid_origin?(url_candidate)\n      nil\n    else\n      url_candidate\n    end\n  end\n\n  def summary_language_map?\n    @object['summaryMap'].is_a?(Hash) && !@object['summaryMap'].empty?\n  end\n\n  def content_language_map?\n    @object['contentMap'].is_a?(Hash) && !@object['contentMap'].empty?\n  end\n\n  def name_language_map?\n    @object['nameMap'].is_a?(Hash) && !@object['nameMap'].empty?\n  end\n\n  def unsupported_media_type?(mime_type)\n    mime_type.present? && !(MediaAttachment::IMAGE_MIME_TYPES + MediaAttachment::VIDEO_MIME_TYPES).include?(mime_type)\n  end\n\n  def supported_blurhash?(blurhash)\n    components = blurhash.blank? ? nil : Blurhash.components(blurhash)\n    components.present? && components.none? { |comp| comp > 5 }\n  end\n\n  def skip_download?\n    return @skip_download if defined?(@skip_download)\n    @skip_download ||= DomainBlock.find_by(domain: @account.domain)&.reject_media?\n  end\n\n  def reply_to_local?\n    !replied_to_status.nil? && replied_to_status.account.local?\n  end\n\n  def related_to_local_activity?\n    fetch? || followed_by_local_accounts? || requested_through_relay? ||\n      responds_to_followed_account? || addresses_local_accounts?\n  end\n\n  def responds_to_followed_account?\n    !replied_to_status.nil? && (replied_to_status.account.local? || replied_to_status.account.passive_relationships.exists?)\n  end\n\n  def addresses_local_accounts?\n    return true if @options[:delivered_to_account_id]\n\n    local_usernames = (as_array(@object['to']) + as_array(@object['cc'])).uniq.select { |uri| ActivityPub::TagManager.instance.local_uri?(uri) }.map { |uri| ActivityPub::TagManager.instance.uri_to_local_id(uri, :username) }\n\n    return false if local_usernames.empty?\n\n    Account.local.where(username: local_usernames).exists?\n  end\n\n  def forward_for_reply\n    return unless @json['signature'].present? && reply_to_local?\n    ActivityPub::RawDistributionWorker.perform_async(Oj.dump(@json), replied_to_status.account_id, [@account.preferred_inbox_url])\n  end\n\n  def lock_options\n    { redis: Redis.current, key: \"create:#{@object['id']}\" }\n  end\nend\n"
  },
  {
    "path": "app/lib/activitypub/activity/delete.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::Activity::Delete < ActivityPub::Activity\n  def perform\n    if @account.uri == object_uri\n      delete_person\n    else\n      delete_note\n    end\n  end\n\n  private\n\n  def delete_person\n    lock_or_return(\"delete_in_progress:#{@account.id}\") do\n      SuspendAccountService.new.call(@account)\n      @account.destroy!\n    end\n  end\n\n  def delete_note\n    return if object_uri.nil?\n\n    unless invalid_origin?(object_uri)\n      RedisLock.acquire(lock_options) { |_lock| delete_later!(object_uri) }\n      Tombstone.find_or_create_by(uri: object_uri, account: @account)\n    end\n\n    @status   = Status.find_by(uri: object_uri, account: @account)\n    @status ||= Status.find_by(uri: @object['atomUri'], account: @account) if @object.is_a?(Hash) && @object['atomUri'].present?\n\n    return if @status.nil?\n\n    if @status.public_visibility? || @status.unlisted_visibility?\n      forward_for_reply\n      forward_for_reblogs\n    end\n\n    delete_now!\n  end\n\n  def forward_for_reblogs\n    return if @json['signature'].blank?\n\n    rebloggers_ids = @status.reblogs.includes(:account).references(:account).merge(Account.local).pluck(:account_id)\n    inboxes        = Account.where(id: ::Follow.where(target_account_id: rebloggers_ids).select(:account_id)).inboxes - [@account.preferred_inbox_url]\n\n    ActivityPub::LowPriorityDeliveryWorker.push_bulk(inboxes) do |inbox_url|\n      [payload, rebloggers_ids.first, inbox_url]\n    end\n  end\n\n  def replied_to_status\n    return @replied_to_status if defined?(@replied_to_status)\n    @replied_to_status = @status.thread\n  end\n\n  def reply_to_local?\n    !replied_to_status.nil? && replied_to_status.account.local?\n  end\n\n  def forward_for_reply\n    return unless @json['signature'].present? && reply_to_local?\n\n    inboxes = replied_to_status.account.followers.inboxes - [@account.preferred_inbox_url]\n\n    ActivityPub::LowPriorityDeliveryWorker.push_bulk(inboxes) do |inbox_url|\n      [payload, replied_to_status.account_id, inbox_url]\n    end\n  end\n\n  def delete_now!\n    RemoveStatusService.new.call(@status)\n  end\n\n  def payload\n    @payload ||= Oj.dump(@json)\n  end\n\n  def lock_options\n    { redis: Redis.current, key: \"create:#{object_uri}\" }\n  end\nend\n"
  },
  {
    "path": "app/lib/activitypub/activity/flag.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::Activity::Flag < ActivityPub::Activity\n  def perform\n    return if skip_reports?\n\n    target_accounts            = object_uris.map { |uri| account_from_uri(uri) }.compact.select(&:local?)\n    target_statuses_by_account = object_uris.map { |uri| status_from_uri(uri) }.compact.select(&:local?).group_by(&:account_id)\n\n    target_accounts.each do |target_account|\n      target_statuses = target_statuses_by_account[target_account.id]\n\n      ReportService.new.call(\n        @account,\n        target_account,\n        status_ids: target_statuses.nil? ? [] : target_statuses.map(&:id),\n        comment: @json['content'] || '',\n        uri: report_uri\n      )\n    end\n  end\n\n  private\n\n  def skip_reports?\n    DomainBlock.find_by(domain: @account.domain)&.reject_reports?\n  end\n\n  def object_uris\n    @object_uris ||= Array(@object.is_a?(Array) ? @object.map { |item| value_or_id(item) } : value_or_id(@object))\n  end\n\n  def report_uri\n    @json['id'] unless @json['id'].nil? || invalid_origin?(@json['id'])\n  end\nend\n"
  },
  {
    "path": "app/lib/activitypub/activity/follow.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::Activity::Follow < ActivityPub::Activity\n  include Payloadable\n\n  def perform\n    target_account = account_from_uri(object_uri)\n\n    return if target_account.nil? || !target_account.local? || delete_arrived_first?(@json['id']) || @account.requested?(target_account)\n\n    if target_account.blocking?(@account) || target_account.domain_blocking?(@account.domain) || target_account.moved?\n      reject_follow_request!(target_account)\n      return\n    end\n\n    # Fast-forward repeat follow requests\n    if @account.following?(target_account)\n      AuthorizeFollowService.new.call(@account, target_account, skip_follow_request: true, follow_request_uri: @json['id'])\n      return\n    end\n\n    follow_request = FollowRequest.create!(account: @account, target_account: target_account, uri: @json['id'])\n\n    if target_account.locked?\n      NotifyService.new.call(target_account, follow_request)\n    else\n      AuthorizeFollowService.new.call(@account, target_account)\n      NotifyService.new.call(target_account, ::Follow.find_by(account: @account, target_account: target_account))\n    end\n  end\n\n  def reject_follow_request!(target_account)\n    json = Oj.dump(serialize_payload(FollowRequest.new(account: @account, target_account: target_account, uri: @json['id']), ActivityPub::RejectFollowSerializer))\n    ActivityPub::DeliveryWorker.perform_async(json, target_account.id, @account.inbox_url)\n  end\nend\n"
  },
  {
    "path": "app/lib/activitypub/activity/like.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::Activity::Like < ActivityPub::Activity\n  def perform\n    original_status = status_from_uri(object_uri)\n\n    return if original_status.nil? || !original_status.account.local? || delete_arrived_first?(@json['id']) || @account.favourited?(original_status)\n\n    favourite = original_status.favourites.create!(account: @account)\n    NotifyService.new.call(original_status.account, favourite)\n  end\nend\n"
  },
  {
    "path": "app/lib/activitypub/activity/move.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::Activity::Move < ActivityPub::Activity\n  PROCESSING_COOLDOWN = 7.days.seconds\n\n  def perform\n    return if origin_account.uri != object_uri || processed?\n\n    mark_as_processing!\n\n    target_account = ActivityPub::FetchRemoteAccountService.new.call(target_uri)\n\n    return if target_account.nil? || !target_account.also_known_as.include?(origin_account.uri)\n\n    # In case for some reason we didn't have a redirect for the profile already, set it\n    origin_account.update(moved_to_account: target_account) if origin_account.moved_to_account_id.nil?\n\n    # Initiate a re-follow for each follower\n    origin_account.followers.local.select(:id).find_in_batches do |follower_accounts|\n      UnfollowFollowWorker.push_bulk(follower_accounts.map(&:id)) do |follower_account_id|\n        [follower_account_id, origin_account.id, target_account.id]\n      end\n    end\n  end\n\n  private\n\n  def origin_account\n    @account\n  end\n\n  def target_uri\n    value_or_id(@json['target'])\n  end\n\n  def processed?\n    redis.exists(\"move_in_progress:#{@account.id}\")\n  end\n\n  def mark_as_processing!\n    redis.setex(\"move_in_progress:#{@account.id}\", PROCESSING_COOLDOWN, true)\n  end\nend\n"
  },
  {
    "path": "app/lib/activitypub/activity/reject.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::Activity::Reject < ActivityPub::Activity\n  def perform\n    case @object['type']\n    when 'Follow'\n      reject_follow\n    end\n  end\n\n  private\n\n  def reject_follow\n    return reject_follow_for_relay if relay_follow?\n\n    target_account = account_from_uri(target_uri)\n\n    return if target_account.nil? || !target_account.local?\n\n    follow_request = FollowRequest.find_by(account: target_account, target_account: @account)\n    follow_request&.reject!\n\n    UnfollowService.new.call(target_account, @account) if target_account.following?(@account)\n  end\n\n  def reject_follow_for_relay\n    relay.update!(state: :rejected)\n  end\n\n  def relay\n    @relay ||= Relay.find_by(follow_activity_id: object_uri) unless object_uri.nil?\n  end\n\n  def relay_follow?\n    relay.present?\n  end\n\n  def target_uri\n    @target_uri ||= value_or_id(@object['actor'])\n  end\nend\n"
  },
  {
    "path": "app/lib/activitypub/activity/remove.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::Activity::Remove < ActivityPub::Activity\n  def perform\n    return unless @json['target'].present? && value_or_id(@json['target']) == @account.featured_collection_url\n\n    status = status_from_uri(object_uri)\n\n    return unless !status.nil? && status.account_id == @account.id\n\n    pin = StatusPin.find_by(account: @account, status: status)\n    pin&.destroy!\n  end\nend\n"
  },
  {
    "path": "app/lib/activitypub/activity/undo.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::Activity::Undo < ActivityPub::Activity\n  def perform\n    case @object['type']\n    when 'Announce'\n      undo_announce\n    when 'Accept'\n      undo_accept\n    when 'Follow'\n      undo_follow\n    when 'Like'\n      undo_like\n    when 'Block'\n      undo_block\n    end\n  end\n\n  private\n\n  def undo_announce\n    return if object_uri.nil?\n\n    status   = Status.find_by(uri: object_uri, account: @account)\n    status ||= Status.find_by(uri: @object['atomUri'], account: @account) if @object.is_a?(Hash) && @object['atomUri'].present?\n\n    if status.nil?\n      delete_later!(object_uri)\n    else\n      RemoveStatusService.new.call(status)\n    end\n  end\n\n  def undo_accept\n    ::Follow.find_by(target_account: @account, uri: target_uri)&.revoke_request!\n  end\n\n  def undo_follow\n    target_account = account_from_uri(target_uri)\n\n    return if target_account.nil? || !target_account.local?\n\n    if @account.following?(target_account)\n      @account.unfollow!(target_account)\n    elsif @account.requested?(target_account)\n      FollowRequest.find_by(account: @account, target_account: target_account)&.destroy\n    else\n      delete_later!(object_uri)\n    end\n  end\n\n  def undo_like\n    status = status_from_uri(target_uri)\n\n    return if status.nil? || !status.account.local?\n\n    if @account.favourited?(status)\n      favourite = status.favourites.where(account: @account).first\n      favourite&.destroy\n    else\n      delete_later!(object_uri)\n    end\n  end\n\n  def undo_block\n    target_account = account_from_uri(target_uri)\n\n    return if target_account.nil? || !target_account.local?\n\n    if @account.blocking?(target_account)\n      UnblockService.new.call(@account, target_account)\n    else\n      delete_later!(object_uri)\n    end\n  end\n\n  def target_uri\n    @target_uri ||= value_or_id(@object['object'])\n  end\nend\n"
  },
  {
    "path": "app/lib/activitypub/activity/update.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::Activity::Update < ActivityPub::Activity\n  SUPPORTED_TYPES = %w(Application Group Organization Person Service).freeze\n\n  def perform\n    if equals_or_includes_any?(@object['type'], SUPPORTED_TYPES)\n      update_account\n    elsif equals_or_includes_any?(@object['type'], %w(Question))\n      update_poll\n    end\n  end\n\n  private\n\n  def update_account\n    return if @account.uri != object_uri\n\n    ActivityPub::ProcessAccountService.new.call(@account.username, @account.domain, @object, signed_with_known_key: true)\n  end\n\n  def update_poll\n    return reject_payload! if invalid_origin?(@object['id'])\n\n    status = Status.find_by(uri: object_uri, account_id: @account.id)\n    return if status.nil? || status.preloadable_poll.nil?\n\n    ActivityPub::ProcessPollService.new.call(status.preloadable_poll, @object)\n  end\nend\n"
  },
  {
    "path": "app/lib/activitypub/activity.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::Activity\n  include JsonLdHelper\n  include Redisable\n\n  SUPPORTED_TYPES = %w(Note Question).freeze\n  CONVERTED_TYPES = %w(Image Video Article Page).freeze\n\n  def initialize(json, account, **options)\n    @json    = json\n    @account = account\n    @object  = @json['object']\n    @options = options\n  end\n\n  def perform\n    raise NotImplementedError\n  end\n\n  class << self\n    def factory(json, account, **options)\n      @json = json\n      klass&.new(json, account, options)\n    end\n\n    private\n\n    def klass\n      case @json['type']\n      when 'Create'\n        ActivityPub::Activity::Create\n      when 'Announce'\n        ActivityPub::Activity::Announce\n      when 'Delete'\n        ActivityPub::Activity::Delete\n      when 'Follow'\n        ActivityPub::Activity::Follow\n      when 'Like'\n        ActivityPub::Activity::Like\n      when 'Block'\n        ActivityPub::Activity::Block\n      when 'Update'\n        ActivityPub::Activity::Update\n      when 'Undo'\n        ActivityPub::Activity::Undo\n      when 'Accept'\n        ActivityPub::Activity::Accept\n      when 'Reject'\n        ActivityPub::Activity::Reject\n      when 'Flag'\n        ActivityPub::Activity::Flag\n      when 'Add'\n        ActivityPub::Activity::Add\n      when 'Remove'\n        ActivityPub::Activity::Remove\n      when 'Move'\n        ActivityPub::Activity::Move\n      end\n    end\n  end\n\n  protected\n\n  def status_from_uri(uri)\n    ActivityPub::TagManager.instance.uri_to_resource(uri, Status)\n  end\n\n  def account_from_uri(uri)\n    ActivityPub::TagManager.instance.uri_to_resource(uri, Account)\n  end\n\n  def object_uri\n    @object_uri ||= value_or_id(@object)\n  end\n\n  def unsupported_object_type?\n    @object.is_a?(String) || !(supported_object_type? || converted_object_type?)\n  end\n\n  def supported_object_type?\n    equals_or_includes_any?(@object['type'], SUPPORTED_TYPES)\n  end\n\n  def converted_object_type?\n    equals_or_includes_any?(@object['type'], CONVERTED_TYPES)\n  end\n\n  def distribute(status)\n    crawl_links(status)\n\n    notify_about_reblog(status) if reblog_of_local_account?(status)\n    notify_about_mentions(status)\n\n    # Only continue if the status is supposed to have arrived in real-time.\n    # Note that if @options[:override_timestamps] isn't set, the status\n    # may have a lower snowflake id than other existing statuses, potentially\n    # \"hiding\" it from paginated API calls\n    return unless @options[:override_timestamps] || status.within_realtime_window?\n\n    distribute_to_followers(status)\n  end\n\n  def reblog_of_local_account?(status)\n    status.reblog? && status.reblog.account.local?\n  end\n\n  def notify_about_reblog(status)\n    NotifyService.new.call(status.reblog.account, status)\n  end\n\n  def notify_about_mentions(status)\n    status.active_mentions.includes(:account).each do |mention|\n      next unless mention.account.local? && audience_includes?(mention.account)\n      NotifyService.new.call(mention.account, mention)\n    end\n  end\n\n  def crawl_links(status)\n    return if status.spoiler_text?\n\n    # Spread out crawling randomly to avoid DDoSing the link\n    LinkCrawlWorker.perform_in(rand(1..59).seconds, status.id)\n  end\n\n  def distribute_to_followers(status)\n    ::DistributionWorker.perform_async(status.id)\n  end\n\n  def delete_arrived_first?(uri)\n    redis.exists(\"delete_upon_arrival:#{@account.id}:#{uri}\")\n  end\n\n  def delete_later!(uri)\n    redis.setex(\"delete_upon_arrival:#{@account.id}:#{uri}\", 6.hours.seconds, uri)\n  end\n\n  def status_from_object\n    # If the status is already known, return it\n    status = status_from_uri(object_uri)\n\n    return status unless status.nil?\n\n    # If the boosted toot is embedded and it is a self-boost, handle it like a Create\n    unless unsupported_object_type?\n      actor_id = value_or_id(first_of_value(@object['attributedTo']))\n\n      if actor_id == @account.uri\n        return ActivityPub::Activity.factory({ 'type' => 'Create', 'actor' => actor_id, 'object' => @object }, @account).perform\n      end\n    end\n\n    fetch_remote_original_status\n  end\n\n  def fetch_remote_original_status\n    if object_uri.start_with?('http')\n      return if ActivityPub::TagManager.instance.local_uri?(object_uri)\n      ActivityPub::FetchRemoteStatusService.new.call(object_uri, id: true, on_behalf_of: @account.followers.local.first)\n    elsif @object['url'].present?\n      ::FetchRemoteStatusService.new.call(@object['url'])\n    end\n  end\n\n  def lock_or_return(key, expire_after = 7.days.seconds)\n    yield if redis.set(key, true, nx: true, ex: expire_after)\n  ensure\n    redis.del(key)\n  end\n\n  def fetch?\n    !@options[:delivery]\n  end\n\n  def followed_by_local_accounts?\n    @account.passive_relationships.exists?\n  end\n\n  def requested_through_relay?\n    @options[:relayed_through_account] && Relay.find_by(inbox_url: @options[:relayed_through_account].inbox_url)&.enabled?\n  end\n\n  def reject_payload!\n    Rails.logger.info(\"Rejected #{@json['type']} activity #{@json['id']} from #{@account.uri}#{@options[:relayed_through_account] && \"via #{@options[:relayed_through_account].uri}\"}\")\n    nil\n  end\nend\n"
  },
  {
    "path": "app/lib/activitypub/adapter.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::Adapter < ActiveModelSerializers::Adapter::Base\n  NAMED_CONTEXT_MAP = {\n    activitystreams: 'https://www.w3.org/ns/activitystreams',\n    security: 'https://w3id.org/security/v1',\n  }.freeze\n\n  CONTEXT_EXTENSION_MAP = {\n    manually_approves_followers: { 'manuallyApprovesFollowers' => 'as:manuallyApprovesFollowers' },\n    sensitive: { 'sensitive' => 'as:sensitive' },\n    hashtag: { 'Hashtag' => 'as:Hashtag' },\n    moved_to: { 'movedTo' => { '@id' => 'as:movedTo', '@type' => '@id' } },\n    also_known_as: { 'alsoKnownAs' => { '@id' => 'as:alsoKnownAs', '@type' => '@id' } },\n    emoji: { 'toot' => 'http://joinmastodon.org/ns#', 'Emoji' => 'toot:Emoji' },\n    featured: { 'toot' => 'http://joinmastodon.org/ns#', 'featured' => { '@id' => 'toot:featured', '@type' => '@id' } },\n    property_value: { 'schema' => 'http://schema.org#', 'PropertyValue' => 'schema:PropertyValue', 'value' => 'schema:value' },\n    atom_uri: { 'ostatus' => 'http://ostatus.org#', 'atomUri' => 'ostatus:atomUri' },\n    conversation: { 'ostatus' => 'http://ostatus.org#', 'inReplyToAtomUri' => 'ostatus:inReplyToAtomUri', 'conversation' => 'ostatus:conversation' },\n    focal_point: { 'toot' => 'http://joinmastodon.org/ns#', 'focalPoint' => { '@container' => '@list', '@id' => 'toot:focalPoint' } },\n    identity_proof: { 'toot' => 'http://joinmastodon.org/ns#', 'IdentityProof' => 'toot:IdentityProof' },\n    blurhash: { 'toot' => 'http://joinmastodon.org/ns#', 'blurhash' => 'toot:blurhash' },\n  }.freeze\n\n  def self.default_key_transform\n    :camel_lower\n  end\n\n  def self.transform_key_casing!(value, _options)\n    ActivityPub::CaseTransform.camel_lower(value)\n  end\n\n  def serializable_hash(options = nil)\n    options         = serialization_options(options)\n    serialized_hash = serializer.serializable_hash(options)\n    serialized_hash = self.class.transform_key_casing!(serialized_hash, instance_options)\n\n    { '@context' => serialized_context }.merge(serialized_hash)\n  end\n\n  private\n\n  def serialized_context\n    context_array = []\n\n    serializer_options = serializer.send(:instance_options) || {}\n    named_contexts     = [:activitystreams] + serializer._named_contexts.keys + serializer_options.fetch(:named_contexts, {}).keys\n    context_extensions = serializer._context_extensions.keys + serializer_options.fetch(:context_extensions, {}).keys\n\n    named_contexts.each do |key|\n      context_array << NAMED_CONTEXT_MAP[key]\n    end\n\n    extensions = context_extensions.each_with_object({}) do |key, h|\n      h.merge!(CONTEXT_EXTENSION_MAP[key])\n    end\n\n    context_array << extensions unless extensions.empty?\n\n    if context_array.size == 1\n      context_array.first\n    else\n      context_array\n    end\n  end\nend\n"
  },
  {
    "path": "app/lib/activitypub/case_transform.rb",
    "content": "# frozen_string_literal: true\n\nmodule ActivityPub::CaseTransform\n  class << self\n    def camel_lower_cache\n      @camel_lower_cache ||= {}\n    end\n\n    def camel_lower(value)\n      case value\n      when Array then value.map { |item| camel_lower(item) }\n      when Hash then value.deep_transform_keys! { |key| camel_lower(key) }\n      when Symbol then camel_lower(value.to_s).to_sym\n      when String\n        camel_lower_cache[value] ||= if value.start_with?('_:')\n                                       '_:' + value.gsub(/\\A_:/, '').underscore.camelize(:lower)\n                                     else\n                                       value.underscore.camelize(:lower)\n                                     end\n      else value\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "app/lib/activitypub/linked_data_signature.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::LinkedDataSignature\n  include JsonLdHelper\n\n  CONTEXT = 'https://w3id.org/identity/v1'\n\n  def initialize(json)\n    @json = json.with_indifferent_access\n  end\n\n  def verify_account!\n    return unless @json['signature'].is_a?(Hash)\n\n    type        = @json['signature']['type']\n    creator_uri = @json['signature']['creator']\n    signature   = @json['signature']['signatureValue']\n\n    return unless type == 'RsaSignature2017'\n\n    creator   = ActivityPub::TagManager.instance.uri_to_resource(creator_uri, Account)\n    creator ||= ActivityPub::FetchRemoteKeyService.new.call(creator_uri, id: false)\n\n    return if creator.nil?\n\n    options_hash   = hash(@json['signature'].without('type', 'id', 'signatureValue').merge('@context' => CONTEXT))\n    document_hash  = hash(@json.without('signature'))\n    to_be_verified = options_hash + document_hash\n\n    if creator.keypair.public_key.verify(OpenSSL::Digest::SHA256.new, Base64.decode64(signature), to_be_verified)\n      creator\n    end\n  end\n\n  def sign!(creator, sign_with: nil)\n    options = {\n      'type'    => 'RsaSignature2017',\n      'creator' => [ActivityPub::TagManager.instance.uri_for(creator), '#main-key'].join,\n      'created' => Time.now.utc.iso8601,\n    }\n\n    options_hash  = hash(options.without('type', 'id', 'signatureValue').merge('@context' => CONTEXT))\n    document_hash = hash(@json.without('signature'))\n    to_be_signed  = options_hash + document_hash\n    keypair       = sign_with.present? ? OpenSSL::PKey::RSA.new(sign_with) : creator.keypair\n\n    signature = Base64.strict_encode64(keypair.sign(OpenSSL::Digest::SHA256.new, to_be_signed))\n\n    @json.merge('signature' => options.merge('signatureValue' => signature))\n  end\n\n  private\n\n  def hash(obj)\n    Digest::SHA256.hexdigest(canonicalize(obj))\n  end\nend\n"
  },
  {
    "path": "app/lib/activitypub/serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::Serializer < ActiveModel::Serializer\n  with_options instance_writer: false, instance_reader: true do |serializer|\n    serializer.class_attribute :_named_contexts\n    serializer.class_attribute :_context_extensions\n\n    self._named_contexts     ||= {}\n    self._context_extensions ||= {}\n  end\n\n  def self.inherited(base)\n    super\n\n    base._named_contexts     = _named_contexts.dup\n    base._context_extensions = _context_extensions.dup\n  end\n\n  def self.context(*named_contexts)\n    named_contexts.each do |context|\n      _named_contexts[context] = true\n    end\n  end\n\n  def self.context_extensions(*extension_names)\n    extension_names.each do |extension_name|\n      _context_extensions[extension_name] = true\n    end\n  end\nend\n"
  },
  {
    "path": "app/lib/activitypub/tag_manager.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'singleton'\n\nclass ActivityPub::TagManager\n  include Singleton\n  include RoutingHelper\n\n  CONTEXT = 'https://www.w3.org/ns/activitystreams'\n\n  COLLECTIONS = {\n    public: 'https://www.w3.org/ns/activitystreams#Public',\n  }.freeze\n\n  def url_for(target)\n    return target.url if target.respond_to?(:local?) && !target.local?\n\n    case target.object_type\n    when :person\n      short_account_url(target)\n    when :note, :comment, :activity\n      return activity_account_status_url(target.account, target) if target.reblog?\n      short_account_status_url(target.account, target)\n    end\n  end\n\n  def uri_for(target)\n    return target.uri if target.respond_to?(:local?) && !target.local?\n\n    case target.object_type\n    when :person\n      account_url(target)\n    when :note, :comment, :activity\n      return activity_account_status_url(target.account, target) if target.reblog?\n      account_status_url(target.account, target)\n    when :emoji\n      emoji_url(target)\n    end\n  end\n\n  def generate_uri_for(_target)\n    URI.join(root_url, 'payloads', SecureRandom.uuid)\n  end\n\n  def activity_uri_for(target)\n    raise ArgumentError, 'target must be a local activity' unless %i(note comment activity).include?(target.object_type) && target.local?\n\n    activity_account_status_url(target.account, target)\n  end\n\n  def replies_uri_for(target, page_params = nil)\n    raise ArgumentError, 'target must be a local activity' unless %i(note comment activity).include?(target.object_type) && target.local?\n\n    replies_account_status_url(target.account, target, page_params)\n  end\n\n  # Primary audience of a status\n  # Public statuses go out to primarily the public collection\n  # Unlisted and private statuses go out primarily to the followers collection\n  # Others go out only to the people they mention\n  def to(status)\n    case status.visibility\n    when 'public'\n      [COLLECTIONS[:public]]\n    when 'unlisted', 'private'\n      [account_followers_url(status.account)]\n    when 'direct', 'limited'\n      if status.account.silenced?\n        # Only notify followers if the account is locally silenced\n        account_ids = status.active_mentions.pluck(:account_id)\n        to = status.account.followers.where(id: account_ids).map { |account| uri_for(account) }\n        to.concat(FollowRequest.where(target_account_id: status.account_id, account_id: account_ids).map { |request| uri_for(request.account) })\n      else\n        status.active_mentions.map { |mention| uri_for(mention.account) }\n      end\n    end\n  end\n\n  # Secondary audience of a status\n  # Public statuses go out to followers as well\n  # Unlisted statuses go to the public as well\n  # Both of those and private statuses also go to the people mentioned in them\n  # Direct ones don't have a secondary audience\n  def cc(status)\n    cc = []\n\n    cc << uri_for(status.reblog.account) if status.reblog?\n\n    case status.visibility\n    when 'public'\n      cc << account_followers_url(status.account)\n    when 'unlisted'\n      cc << COLLECTIONS[:public]\n    end\n\n    unless status.direct_visibility? || status.limited_visibility?\n      if status.account.silenced?\n        # Only notify followers if the account is locally silenced\n        account_ids = status.active_mentions.pluck(:account_id)\n        cc.concat(status.account.followers.where(id: account_ids).map { |account| uri_for(account) })\n        cc.concat(FollowRequest.where(target_account_id: status.account_id, account_id: account_ids).map { |request| uri_for(request.account) })\n      else\n        cc.concat(status.active_mentions.map { |mention| uri_for(mention.account) })\n      end\n    end\n\n    cc\n  end\n\n  def local_uri?(uri)\n    return false if uri.nil?\n\n    uri  = Addressable::URI.parse(uri)\n    host = uri.normalized_host\n    host = \"#{host}:#{uri.port}\" if uri.port\n\n    !host.nil? && (::TagManager.instance.local_domain?(host) || ::TagManager.instance.web_domain?(host))\n  end\n\n  def uri_to_local_id(uri, param = :id)\n    path_params = Rails.application.routes.recognize_path(uri)\n    path_params[param]\n  end\n\n  def uri_to_resource(uri, klass)\n    return if uri.nil?\n\n    if local_uri?(uri)\n      case klass.name\n      when 'Account'\n        klass.find_local(uri_to_local_id(uri, :username))\n      else\n        StatusFinder.new(uri).status\n      end\n    elsif OStatus::TagManager.instance.local_id?(uri)\n      klass.find_by(id: OStatus::TagManager.instance.unique_tag_to_local_id(uri, klass.to_s))\n    else\n      klass.find_by(uri: uri.split('#').first)\n    end\n  rescue ActiveRecord::RecordNotFound\n    nil\n  end\nend\n"
  },
  {
    "path": "app/lib/application_extension.rb",
    "content": "# frozen_string_literal: true\n\nmodule ApplicationExtension\n  extend ActiveSupport::Concern\n\n  included do\n    validates :website, url: true, if: :website?\n  end\nend\n"
  },
  {
    "path": "app/lib/delivery_failure_tracker.rb",
    "content": "# frozen_string_literal: true\n\nclass DeliveryFailureTracker\n  FAILURE_DAYS_THRESHOLD = 7\n\n  def initialize(inbox_url)\n    @inbox_url = inbox_url\n  end\n\n  def track_failure!\n    Redis.current.sadd(exhausted_deliveries_key, today)\n    Redis.current.sadd('unavailable_inboxes', @inbox_url) if reached_failure_threshold?\n  end\n\n  def track_success!\n    Redis.current.del(exhausted_deliveries_key)\n    Redis.current.srem('unavailable_inboxes', @inbox_url)\n  end\n\n  def days\n    Redis.current.scard(exhausted_deliveries_key) || 0\n  end\n\n  class << self\n    def filter(arr)\n      arr.reject(&method(:unavailable?))\n    end\n\n    def unavailable?(url)\n      Redis.current.sismember('unavailable_inboxes', url)\n    end\n\n    def available?(url)\n      !unavailable?(url)\n    end\n\n    def track_inverse_success!(from_account)\n      new(from_account.inbox_url).track_success! if from_account.inbox_url.present?\n      new(from_account.shared_inbox_url).track_success! if from_account.shared_inbox_url.present?\n    end\n  end\n\n  private\n\n  def exhausted_deliveries_key\n    \"exhausted_deliveries:#{@inbox_url}\"\n  end\n\n  def today\n    Time.now.utc.strftime('%Y%m%d')\n  end\n\n  def reached_failure_threshold?\n    days >= FAILURE_DAYS_THRESHOLD\n  end\nend\n"
  },
  {
    "path": "app/lib/entity_cache.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'singleton'\n\nclass EntityCache\n  include Singleton\n\n  MAX_EXPIRATION = 7.days.freeze\n\n  def mention(username, domain)\n    Rails.cache.fetch(to_key(:mention, username, domain), expires_in: MAX_EXPIRATION) { Account.select(:username, :domain, :url).find_remote(username, domain) }\n  end\n\n  def emoji(shortcodes, domain)\n    shortcodes   = [shortcodes] unless shortcodes.is_a?(Array)\n    cached       = Rails.cache.read_multi(*shortcodes.map { |shortcode| to_key(:emoji, shortcode, domain) })\n    uncached_ids = []\n\n    shortcodes.each do |shortcode|\n      uncached_ids << shortcode unless cached.key?(to_key(:emoji, shortcode, domain))\n    end\n\n    unless uncached_ids.empty?\n      uncached = CustomEmoji.where(shortcode: shortcodes, domain: domain, disabled: false).each_with_object({}) { |item, h| h[item.shortcode] = item }\n      uncached.each_value { |item| Rails.cache.write(to_key(:emoji, item.shortcode, domain), item, expires_in: MAX_EXPIRATION) }\n    end\n\n    shortcodes.map { |shortcode| cached[to_key(:emoji, shortcode, domain)] || uncached[shortcode] }.compact\n  end\n\n  def to_key(type, *ids)\n    \"#{type}:#{ids.compact.map(&:downcase).join(':')}\"\n  end\nend\n"
  },
  {
    "path": "app/lib/exceptions.rb",
    "content": "# frozen_string_literal: true\n\nmodule Mastodon\n  class Error < StandardError; end\n  class NotPermittedError < Error; end\n  class ValidationError < Error; end\n  class HostValidationError < ValidationError; end\n  class LengthValidationError < ValidationError; end\n  class DimensionsValidationError < ValidationError; end\n  class RaceConditionError < Error; end\n\n  class UnexpectedResponseError < Error\n    def initialize(response = nil)\n      if response.respond_to? :uri\n        super(\"#{response.uri} returned code #{response.code}\")\n      else\n        super\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "app/lib/extractor.rb",
    "content": "# frozen_string_literal: true\n\nmodule Extractor\n  extend Twitter::Extractor\n\n  module_function\n\n  # :yields: username, list_slug, start, end\n  def extract_mentions_or_lists_with_indices(text)\n    return [] unless text =~ Twitter::Regex[:at_signs]\n\n    possible_entries = []\n\n    text.to_s.scan(Account::MENTION_RE) do |screen_name, _|\n      match_data = $LAST_MATCH_INFO\n      after = $'\n      unless after =~ Twitter::Regex[:end_mention_match]\n        start_position = match_data.char_begin(1) - 1\n        end_position = match_data.char_end(1)\n        possible_entries << {\n          screen_name: screen_name,\n          indices: [start_position, end_position],\n        }\n      end\n    end\n\n    if block_given?\n      possible_entries.each do |mention|\n        yield mention[:screen_name], mention[:indices].first, mention[:indices].last\n      end\n    end\n    possible_entries\n  end\n\n  def extract_hashtags_with_indices(text, **)\n    return [] unless text =~ /#/\n\n    tags = []\n    text.scan(Tag::HASHTAG_RE) do |hash_text, _|\n      match_data = $LAST_MATCH_INFO\n      start_position = match_data.char_begin(1) - 1\n      end_position = match_data.char_end(1)\n      after = $'\n      if after =~ %r{\\A://}\n        hash_text.match(/(.+)(https?\\Z)/) do |matched|\n          hash_text = matched[1]\n          end_position -= matched[2].char_length\n        end\n      end\n\n      tags << {\n        hashtag: hash_text,\n        indices: [start_position, end_position],\n      }\n    end\n\n    tags.each { |tag| yield tag[:hashtag], tag[:indices].first, tag[:indices].last } if block_given?\n    tags\n  end\n\n  def extract_cashtags_with_indices(_text)\n    [] # always returns empty array\n  end\nend\n"
  },
  {
    "path": "app/lib/fast_geometry_parser.rb",
    "content": "# frozen_string_literal: true\n\nclass FastGeometryParser\n  def self.from_file(file)\n    width, height = FastImage.size(file.path)\n\n    raise Paperclip::Errors::NotIdentifiedByImageMagickError if width.nil?\n\n    Paperclip::Geometry.new(width, height)\n  end\nend\n"
  },
  {
    "path": "app/lib/feed_manager.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'singleton'\n\nclass FeedManager\n  include Singleton\n  include Redisable\n\n  MAX_ITEMS = 400\n\n  # Must be <= MAX_ITEMS or the tracking sets will grow forever\n  REBLOG_FALLOFF = 40\n\n  def key(type, id, subtype = nil)\n    return \"feed:#{type}:#{id}\" unless subtype\n\n    \"feed:#{type}:#{id}:#{subtype}\"\n  end\n\n  def filter?(timeline_type, status, receiver_id)\n    if timeline_type == :home\n      filter_from_home?(status, receiver_id)\n    elsif timeline_type == :mentions\n      filter_from_mentions?(status, receiver_id)\n    else\n      false\n    end\n  end\n\n  def push_to_home(account, status)\n    return false unless add_to_feed(:home, account.id, status, account.user&.aggregates_reblogs?)\n    trim(:home, account.id)\n    PushUpdateWorker.perform_async(account.id, status.id, \"timeline:#{account.id}\") if push_update_required?(\"timeline:#{account.id}\")\n    true\n  end\n\n  def unpush_from_home(account, status)\n    return false unless remove_from_feed(:home, account.id, status)\n    redis.publish(\"timeline:#{account.id}\", Oj.dump(event: :delete, payload: status.id.to_s))\n    true\n  end\n\n  def push_to_list(list, status)\n    if status.reply? && status.in_reply_to_account_id != status.account_id\n      should_filter = status.in_reply_to_account_id != list.account_id\n      should_filter &&= !ListAccount.where(list_id: list.id, account_id: status.in_reply_to_account_id).exists?\n      return false if should_filter\n    end\n    return false unless add_to_feed(:list, list.id, status, list.account.user&.aggregates_reblogs?)\n    trim(:list, list.id)\n    PushUpdateWorker.perform_async(list.account_id, status.id, \"timeline:list:#{list.id}\") if push_update_required?(\"timeline:list:#{list.id}\")\n    true\n  end\n\n  def unpush_from_list(list, status)\n    return false unless remove_from_feed(:list, list.id, status)\n    redis.publish(\"timeline:list:#{list.id}\", Oj.dump(event: :delete, payload: status.id.to_s))\n    true\n  end\n\n  def trim(type, account_id)\n    timeline_key = key(type, account_id)\n    reblog_key   = key(type, account_id, 'reblogs')\n\n    # Remove any items past the MAX_ITEMS'th entry in our feed\n    redis.zremrangebyrank(timeline_key, '0', (-(FeedManager::MAX_ITEMS + 1)).to_s)\n\n    # Get the score of the REBLOG_FALLOFF'th item in our feed, and stop\n    # tracking anything after it for deduplication purposes.\n    falloff_rank  = FeedManager::REBLOG_FALLOFF - 1\n    falloff_range = redis.zrevrange(timeline_key, falloff_rank, falloff_rank, with_scores: true)\n    falloff_score = falloff_range&.first&.last&.to_i || 0\n\n    # Get any reblogs we might have to clean up after.\n    redis.zrangebyscore(reblog_key, 0, falloff_score).each do |reblogged_id|\n      # Remove it from the set of reblogs we're tracking *first* to avoid races.\n      redis.zrem(reblog_key, reblogged_id)\n      # Just drop any set we might have created to track additional reblogs.\n      # This means that if this reblog is deleted, we won't automatically insert\n      # another reblog, but also that any new reblog can be inserted into the\n      # feed.\n      redis.del(key(type, account_id, \"reblogs:#{reblogged_id}\"))\n    end\n  end\n\n  def merge_into_timeline(from_account, into_account)\n    timeline_key = key(:home, into_account.id)\n    query        = from_account.statuses.limit(FeedManager::MAX_ITEMS / 4)\n\n    if redis.zcard(timeline_key) >= FeedManager::MAX_ITEMS / 4\n      oldest_home_score = redis.zrange(timeline_key, 0, 0, with_scores: true)&.first&.last&.to_i || 0\n      query = query.where('id > ?', oldest_home_score)\n    end\n\n    query.each do |status|\n      next if (status.direct_visibility? && !into_account.user&.home_dms?) || status.limited_visibility? || filter?(:home, status, into_account)\n      add_to_feed(:home, into_account.id, status, into_account.user&.aggregates_reblogs?)\n    end\n\n    trim(:home, into_account.id)\n  end\n\n  def unmerge_from_timeline(from_account, into_account)\n    timeline_key      = key(:home, into_account.id)\n    oldest_home_score = redis.zrange(timeline_key, 0, 0, with_scores: true)&.first&.last&.to_i || 0\n\n    from_account.statuses.select('id, reblog_of_id').where('id > ?', oldest_home_score).reorder(nil).find_each do |status|\n      remove_from_feed(:home, into_account.id, status)\n    end\n  end\n\n  def clear_from_timeline(account, target_account)\n    timeline_key        = key(:home, account.id)\n    timeline_status_ids = redis.zrange(timeline_key, 0, -1)\n    target_statuses     = Status.where(id: timeline_status_ids, account: target_account)\n\n    target_statuses.each do |status|\n      unpush_from_home(account, status)\n    end\n  end\n\n  def populate_feed(account)\n    added  = 0\n    limit  = FeedManager::MAX_ITEMS / 2\n    max_id = nil\n\n    loop do\n      statuses = Status.as_home_timeline(account)\n                       .paginate_by_max_id(limit, max_id)\n\n      break if statuses.empty?\n\n      statuses.each do |status|\n        next if filter_from_home?(status, account)\n        added += 1 if add_to_feed(:home, account.id, status, account.user&.aggregates_reblogs?)\n      end\n\n      break unless added.zero?\n\n      max_id = statuses.last.id\n    end\n  end\n\n  private\n\n  def push_update_required?(timeline_id)\n    redis.exists(\"subscribed:#{timeline_id}\")\n  end\n\n  def blocks_or_mutes?(receiver_id, account_ids, context)\n    Block.where(account_id: receiver_id, target_account_id: account_ids).any? ||\n      (context == :home ? Mute.where(account_id: receiver_id, target_account_id: account_ids).any? : Mute.where(account_id: receiver_id, target_account_id: account_ids, hide_notifications: true).any?)\n  end\n\n  def filter_from_home?(status, receiver_id)\n    return false if receiver_id == status.account_id\n    return true  if status.reply? && (status.in_reply_to_id.nil? || status.in_reply_to_account_id.nil?)\n    return true  if phrase_filtered?(status, receiver_id, :home)\n\n    check_for_blocks = status.active_mentions.pluck(:account_id)\n    check_for_blocks.concat([status.account_id])\n\n    if status.reblog?\n      check_for_blocks.concat([status.reblog.account_id])\n      check_for_blocks.concat(status.reblog.active_mentions.pluck(:account_id))\n    end\n\n    return true if blocks_or_mutes?(receiver_id, check_for_blocks, :home)\n\n    if status.reply? && !status.in_reply_to_account_id.nil?                                                                      # Filter out if it's a reply\n      should_filter   = !Follow.where(account_id: receiver_id, target_account_id: status.in_reply_to_account_id).exists?         # and I'm not following the person it's a reply to\n      should_filter &&= receiver_id != status.in_reply_to_account_id                                                             # and it's not a reply to me\n      should_filter &&= status.account_id != status.in_reply_to_account_id                                                       # and it's not a self-reply\n      return should_filter\n    elsif status.reblog?                                                                                                         # Filter out a reblog\n      should_filter   = Follow.where(account_id: receiver_id, target_account_id: status.account_id, show_reblogs: false).exists? # if the reblogger's reblogs are suppressed\n      should_filter ||= Block.where(account_id: status.reblog.account_id, target_account_id: receiver_id).exists?                # or if the author of the reblogged status is blocking me\n      should_filter ||= AccountDomainBlock.where(account_id: receiver_id, domain: status.reblog.account.domain).exists?          # or the author's domain is blocked\n      return should_filter\n    end\n\n    false\n  end\n\n  def filter_from_mentions?(status, receiver_id)\n    return true if receiver_id == status.account_id\n    return true if phrase_filtered?(status, receiver_id, :notifications)\n\n    # This filter is called from NotifyService, but already after the sender of\n    # the notification has been checked for mute/block. Therefore, it's not\n    # necessary to check the author of the toot for mute/block again\n    check_for_blocks = status.active_mentions.pluck(:account_id)\n    check_for_blocks.concat([status.in_reply_to_account]) if status.reply? && !status.in_reply_to_account_id.nil?\n\n    should_filter   = blocks_or_mutes?(receiver_id, check_for_blocks, :mentions)                                                         # Filter if it's from someone I blocked, in reply to someone I blocked, or mentioning someone I blocked (or muted)\n    should_filter ||= (status.account.silenced? && !Follow.where(account_id: receiver_id, target_account_id: status.account_id).exists?) # of if the account is silenced and I'm not following them\n\n    should_filter\n  end\n\n  def phrase_filtered?(status, receiver_id, context)\n    active_filters = Rails.cache.fetch(\"filters:#{receiver_id}\") { CustomFilter.where(account_id: receiver_id).active_irreversible.to_a }.to_a\n\n    active_filters.select! { |filter| filter.context.include?(context.to_s) && !filter.expired? }\n\n    active_filters.map! do |filter|\n      if filter.whole_word\n        sb = filter.phrase =~ /\\A[[:word:]]/ ? '\\b' : ''\n        eb = filter.phrase =~ /[[:word:]]\\z/ ? '\\b' : ''\n\n        /(?mix:#{sb}#{Regexp.escape(filter.phrase)}#{eb})/\n      else\n        /#{Regexp.escape(filter.phrase)}/i\n      end\n    end\n\n    return false if active_filters.empty?\n\n    combined_regex = active_filters.reduce { |memo, obj| Regexp.union(memo, obj) }\n    status         = status.reblog if status.reblog?\n\n    !combined_regex.match(Formatter.instance.plaintext(status)).nil? ||\n      (status.spoiler_text.present? && !combined_regex.match(status.spoiler_text).nil?)\n  end\n\n  # Adds a status to an account's feed, returning true if a status was\n  # added, and false if it was not added to the feed. Note that this is\n  # an internal helper: callers must call trim or push updates if\n  # either action is appropriate.\n  def add_to_feed(timeline_type, account_id, status, aggregate_reblogs = true)\n    timeline_key = key(timeline_type, account_id)\n    reblog_key   = key(timeline_type, account_id, 'reblogs')\n\n    if status.reblog? && (aggregate_reblogs.nil? || aggregate_reblogs)\n      # If the original status or a reblog of it is within\n      # REBLOG_FALLOFF statuses from the top, do not re-insert it into\n      # the feed\n      rank = redis.zrevrank(timeline_key, status.reblog_of_id)\n\n      return false if !rank.nil? && rank < FeedManager::REBLOG_FALLOFF\n\n      reblog_rank = redis.zrevrank(reblog_key, status.reblog_of_id)\n\n      if reblog_rank.nil?\n        # This is not something we've already seen reblogged, so we\n        # can just add it to the feed (and note that we're\n        # reblogging it).\n        redis.zadd(timeline_key, status.id, status.id)\n        redis.zadd(reblog_key, status.id, status.reblog_of_id)\n      else\n        # Another reblog of the same status was already in the\n        # REBLOG_FALLOFF most recent statuses, so we note that this\n        # is an \"extra\" reblog, by storing it in reblog_set_key.\n        reblog_set_key = key(timeline_type, account_id, \"reblogs:#{status.reblog_of_id}\")\n        redis.sadd(reblog_set_key, status.id)\n        return false\n      end\n    else\n      # A reblog may reach earlier than the original status because of the\n      # delay of the worker deliverying the original status, the late addition\n      # by merging timelines, and other reasons.\n      # If such a reblog already exists, just do not re-insert it into the feed.\n      rank = redis.zrevrank(reblog_key, status.id)\n\n      return false unless rank.nil?\n\n      redis.zadd(timeline_key, status.id, status.id)\n    end\n\n    true\n  end\n\n  # Removes an individual status from a feed, correctly handling cases\n  # with reblogs, and returning true if a status was removed. As with\n  # `add_to_feed`, this does not trigger push updates, so callers must\n  # do so if appropriate.\n  def remove_from_feed(timeline_type, account_id, status)\n    timeline_key = key(timeline_type, account_id)\n\n    if status.reblog?\n      # 1. If the reblogging status is not in the feed, stop.\n      status_rank = redis.zrevrank(timeline_key, status.id)\n      return false if status_rank.nil?\n\n      # 2. Remove reblog from set of this status's reblogs.\n      reblog_set_key = key(timeline_type, account_id, \"reblogs:#{status.reblog_of_id}\")\n\n      redis.srem(reblog_set_key, status.id)\n      # 3. Re-insert another reblog or original into the feed if one\n      # remains in the set. We could pick a random element, but this\n      # set should generally be small, and it seems ideal to show the\n      # oldest potential such reblog.\n      other_reblog = redis.smembers(reblog_set_key).map(&:to_i).min\n\n      redis.zadd(timeline_key, other_reblog, other_reblog) if other_reblog\n\n      # 4. Remove the reblogging status from the feed (as normal)\n      # (outside conditional)\n    else\n      # If the original is getting deleted, no use for reblog references\n      redis.del(key(timeline_type, account_id, \"reblogs:#{status.id}\"))\n    end\n\n    redis.zrem(timeline_key, status.id)\n  end\nend\n"
  },
  {
    "path": "app/lib/formatter.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'singleton'\nrequire_relative './sanitize_config'\n\nclass Formatter\n  include Singleton\n  include RoutingHelper\n\n  include ActionView::Helpers::TextHelper\n\n  def format(status, **options)\n    if status.reblog?\n      prepend_reblog = status.reblog.account.acct\n      status         = status.proper\n    else\n      prepend_reblog = false\n    end\n\n    raw_content = status.text\n\n    if options[:inline_poll_options] && status.preloadable_poll\n      raw_content = raw_content + \"\\n\\n\" + status.preloadable_poll.options.map { |title| \"[ ] #{title}\" }.join(\"\\n\")\n    end\n\n    return '' if raw_content.blank?\n\n    unless status.local?\n      html = reformat(raw_content)\n      html = encode_custom_emojis(html, status.emojis, options[:autoplay]) if options[:custom_emojify]\n      return html.html_safe # rubocop:disable Rails/OutputSafety\n    end\n\n    linkable_accounts = status.active_mentions.map(&:account)\n    linkable_accounts << status.account\n\n    html = raw_content\n    html = \"RT @#{prepend_reblog} #{html}\" if prepend_reblog\n    html = encode_and_link_urls(html, linkable_accounts)\n    html = encode_custom_emojis(html, status.emojis, options[:autoplay]) if options[:custom_emojify]\n    html = simple_format(html, {}, sanitize: false)\n    html = html.delete(\"\\n\")\n\n    html.html_safe # rubocop:disable Rails/OutputSafety\n  end\n\n  def reformat(html)\n    sanitize(html, Sanitize::Config::MASTODON_STRICT)\n  end\n\n  def plaintext(status)\n    return status.text if status.local?\n\n    text = status.text.gsub(/(<br \\/>|<br>|<\\/p>)+/) { |match| \"#{match}\\n\" }\n    strip_tags(text)\n  end\n\n  def simplified_format(account, **options)\n    html = account.local? ? linkify(account.note) : reformat(account.note)\n    html = encode_custom_emojis(html, account.emojis, options[:autoplay]) if options[:custom_emojify]\n    html.html_safe # rubocop:disable Rails/OutputSafety\n  end\n\n  def sanitize(html, config)\n    Sanitize.fragment(html, config)\n  end\n\n  def format_spoiler(status, **options)\n    html = encode(status.spoiler_text)\n    html = encode_custom_emojis(html, status.emojis, options[:autoplay])\n    html.html_safe # rubocop:disable Rails/OutputSafety\n  end\n\n  def format_poll_option(status, option, **options)\n    html = encode(option.title)\n    html = encode_custom_emojis(html, status.emojis, options[:autoplay])\n    html.html_safe # rubocop:disable Rails/OutputSafety\n  end\n\n  def format_display_name(account, **options)\n    html = encode(account.display_name.presence || account.username)\n    html = encode_custom_emojis(html, account.emojis, options[:autoplay]) if options[:custom_emojify]\n    html.html_safe # rubocop:disable Rails/OutputSafety\n  end\n\n  def format_field(account, str, **options)\n    return reformat(str).html_safe unless account.local? # rubocop:disable Rails/OutputSafety\n    html = encode_and_link_urls(str, me: true)\n    html = encode_custom_emojis(html, account.emojis, options[:autoplay]) if options[:custom_emojify]\n    html.html_safe # rubocop:disable Rails/OutputSafety\n  end\n\n  def linkify(text)\n    html = encode_and_link_urls(text)\n    html = simple_format(html, {}, sanitize: false)\n    html = html.delete(\"\\n\")\n\n    html.html_safe # rubocop:disable Rails/OutputSafety\n  end\n\n  private\n\n  def html_entities\n    @html_entities ||= HTMLEntities.new\n  end\n\n  def encode(html)\n    html_entities.encode(html)\n  end\n\n  def encode_and_link_urls(html, accounts = nil, options = {})\n    entities = utf8_friendly_extractor(html, extract_url_without_protocol: false)\n\n    if accounts.is_a?(Hash)\n      options  = accounts\n      accounts = nil\n    end\n\n    rewrite(html.dup, entities) do |entity|\n      if entity[:url]\n        link_to_url(entity, options)\n      elsif entity[:hashtag]\n        link_to_hashtag(entity)\n      elsif entity[:screen_name]\n        link_to_mention(entity, accounts)\n      end\n    end\n  end\n\n  def count_tag_nesting(tag)\n    if tag[1] == '/' then -1\n    elsif tag[-2] == '/' then 0\n    else 1\n    end\n  end\n\n  def encode_custom_emojis(html, emojis, animate = false)\n    return html if emojis.empty?\n\n    emoji_map = if animate\n                  emojis.each_with_object({}) { |e, h| h[e.shortcode] = full_asset_url(e.image.url) }\n                else\n                  emojis.each_with_object({}) { |e, h| h[e.shortcode] = full_asset_url(e.image.url(:static)) }\n                end\n\n    i                     = -1\n    tag_open_index        = nil\n    inside_shortname      = false\n    shortname_start_index = -1\n    invisible_depth       = 0\n\n    while i + 1 < html.size\n      i += 1\n\n      if invisible_depth.zero? && inside_shortname && html[i] == ':'\n        shortcode = html[shortname_start_index + 1..i - 1]\n        emoji     = emoji_map[shortcode]\n\n        if emoji\n          replacement = \"<img draggable=\\\"false\\\" class=\\\"emojione\\\" alt=\\\":#{encode(shortcode)}:\\\" title=\\\":#{encode(shortcode)}:\\\" src=\\\"#{encode(emoji)}\\\" />\"\n          before_html = shortname_start_index.positive? ? html[0..shortname_start_index - 1] : ''\n          html        = before_html + replacement + html[i + 1..-1]\n          i          += replacement.size - (shortcode.size + 2) - 1\n        else\n          i -= 1\n        end\n\n        inside_shortname = false\n      elsif tag_open_index && html[i] == '>'\n        tag = html[tag_open_index..i]\n        tag_open_index = nil\n        if invisible_depth.positive?\n          invisible_depth += count_tag_nesting(tag)\n        elsif tag == '<span class=\"invisible\">'\n          invisible_depth = 1\n        end\n      elsif html[i] == '<'\n        tag_open_index   = i\n        inside_shortname = false\n      elsif !tag_open_index && html[i] == ':'\n        inside_shortname      = true\n        shortname_start_index = i\n      end\n    end\n\n    html\n  end\n\n  def rewrite(text, entities)\n    text = text.to_s\n\n    # Sort by start index\n    entities = entities.sort_by do |entity|\n      indices = entity.respond_to?(:indices) ? entity.indices : entity[:indices]\n      indices.first\n    end\n\n    result = []\n\n    last_index = entities.reduce(0) do |index, entity|\n      indices = entity.respond_to?(:indices) ? entity.indices : entity[:indices]\n      result << encode(text[index...indices.first])\n      result << yield(entity)\n      indices.last\n    end\n\n    result << encode(text[last_index..-1])\n\n    result.flatten.join\n  end\n\n  UNICODE_ESCAPE_BLACKLIST_RE = /\\p{Z}|\\p{P}/\n\n  def utf8_friendly_extractor(text, options = {})\n    old_to_new_index = [0]\n\n    escaped = text.chars.map do |c|\n      output = begin\n        if c.ord.to_s(16).length > 2 && UNICODE_ESCAPE_BLACKLIST_RE.match(c).nil?\n          CGI.escape(c)\n        else\n          c\n        end\n      end\n\n      old_to_new_index << old_to_new_index.last + output.length\n\n      output\n    end.join\n\n    # Note: I couldn't obtain list_slug with @user/list-name format\n    # for mention so this requires additional check\n    special = Extractor.extract_urls_with_indices(escaped, options).map do |extract|\n      new_indices = [\n        old_to_new_index.find_index(extract[:indices].first),\n        old_to_new_index.find_index(extract[:indices].last),\n      ]\n\n      next extract.merge(\n        indices: new_indices,\n        url: text[new_indices.first..new_indices.last - 1]\n      )\n    end\n\n    standard = Extractor.extract_entities_with_indices(text, options)\n\n    Extractor.remove_overlapping_entities(special + standard)\n  end\n\n  def link_to_url(entity, options = {})\n    url        = Addressable::URI.parse(entity[:url])\n    html_attrs = { target: '_blank', rel: 'nofollow noopener' }\n\n    html_attrs[:rel] = \"me #{html_attrs[:rel]}\" if options[:me]\n\n    Twitter::Autolink.send(:link_to_text, entity, link_html(entity[:url]), url, html_attrs)\n  rescue Addressable::URI::InvalidURIError, IDN::Idna::IdnaError\n    encode(entity[:url])\n  end\n\n  def link_to_mention(entity, linkable_accounts)\n    acct = entity[:screen_name]\n\n    return link_to_account(acct) unless linkable_accounts\n\n    account = linkable_accounts.find { |item| TagManager.instance.same_acct?(item.acct, acct) }\n    account ? mention_html(account) : \"@#{encode(acct)}\"\n  end\n\n  def link_to_account(acct)\n    username, domain = acct.split('@')\n\n    domain  = nil if TagManager.instance.local_domain?(domain)\n    account = EntityCache.instance.mention(username, domain)\n\n    account ? mention_html(account) : \"@#{encode(acct)}\"\n  end\n\n  def link_to_hashtag(entity)\n    hashtag_html(entity[:hashtag])\n  end\n\n  def link_html(url)\n    url    = Addressable::URI.parse(url).to_s\n    prefix = url.match(/\\Ahttps?:\\/\\/(www\\.)?/).to_s\n    text   = url[prefix.length, 30]\n    suffix = url[prefix.length + 30..-1]\n    cutoff = url[prefix.length..-1].length > 30\n\n    \"<span class=\\\"invisible\\\">#{encode(prefix)}</span><span class=\\\"#{cutoff ? 'ellipsis' : ''}\\\">#{encode(text)}</span><span class=\\\"invisible\\\">#{encode(suffix)}</span>\"\n  end\n\n  def hashtag_html(tag)\n    \"<a href=\\\"#{encode(tag_url(tag.downcase))}\\\" class=\\\"mention hashtag\\\" rel=\\\"tag\\\">#<span>#{encode(tag)}</span></a>\"\n  end\n\n  def mention_html(account)\n    \"<span class=\\\"h-card\\\"><a href=\\\"#{encode(TagManager.instance.url_for(account))}\\\" class=\\\"u-url mention\\\">@<span>#{encode(account.username)}</span></a></span>\"\n  end\nend\n"
  },
  {
    "path": "app/lib/hash_object.rb",
    "content": "# frozen_string_literal: true\n\nclass HashObject\n  def initialize(hash)\n    hash.each do |k, v|\n      instance_variable_set(\"@#{k}\", v)\n      self.class.send(:define_method, k, proc { instance_variable_get(\"@#{k}\") })\n    end\n  end\nend\n"
  },
  {
    "path": "app/lib/inline_renderer.rb",
    "content": "# frozen_string_literal: true\n\nclass InlineRenderer\n  def initialize(object, current_account, template)\n    @object          = object\n    @current_account = current_account\n    @template        = template\n  end\n\n  def render\n    case @template\n    when :status\n      serializer = REST::StatusSerializer\n    when :notification\n      serializer = REST::NotificationSerializer\n    when :conversation\n      serializer = REST::ConversationSerializer\n    else\n      return\n    end\n\n    serializable_resource = ActiveModelSerializers::SerializableResource.new(@object, serializer: serializer, scope: current_user, scope_name: :current_user)\n    serializable_resource.as_json\n  end\n\n  def self.render(object, current_account, template)\n    new(object, current_account, template).render\n  end\n\n  private\n\n  def current_user\n    @current_account&.user\n  end\nend\n"
  },
  {
    "path": "app/lib/language_detector.rb",
    "content": "# frozen_string_literal: true\n\nclass LanguageDetector\n  include Singleton\n\n  WORDS_THRESHOLD        = 4\n  RELIABLE_CHARACTERS_RE = /[\\p{Hebrew}\\p{Arabic}\\p{Syriac}\\p{Thaana}\\p{Nko}\\p{Han}\\p{Katakana}\\p{Hiragana}\\p{Hangul}]+/m\n\n  def initialize\n    @identifier = CLD3::NNetLanguageIdentifier.new(1, 2048)\n  end\n\n  def detect(text, account)\n    input_text = prepare_text(text)\n\n    return if input_text.blank?\n\n    detect_language_code(input_text) || default_locale(account)\n  end\n\n  def language_names\n    @language_names = CLD3::TaskContextParams::LANGUAGE_NAMES.map { |name| iso6391(name.to_s).to_sym }.uniq\n  end\n\n  private\n\n  def prepare_text(text)\n    simplify_text(text).strip\n  end\n\n  def unreliable_input?(text)\n    !reliable_input?(text)\n  end\n\n  def reliable_input?(text)\n    sufficient_text_length?(text) || language_specific_character_set?(text)\n  end\n\n  def sufficient_text_length?(text)\n    text.split(/\\s+/).size >= WORDS_THRESHOLD\n  end\n\n  def language_specific_character_set?(text)\n    words = text.scan(RELIABLE_CHARACTERS_RE)\n\n    if words.present?\n      words.reduce(0) { |acc, elem| acc + elem.size }.to_f / text.size.to_f > 0.3\n    else\n      false\n    end\n  end\n\n  def detect_language_code(text)\n    return if unreliable_input?(text)\n    result = @identifier.find_language(text)\n    iso6391(result.language.to_s).to_sym if result.reliable?\n  end\n\n  def iso6391(bcp47)\n    iso639 = bcp47.split('-').first\n\n    # CLD3 returns grandfathered language code for Hebrew\n    return 'he' if iso639 == 'iw'\n\n    ISO_639.find(iso639).alpha2\n  end\n\n  def simplify_text(text)\n    new_text = remove_html(text)\n    new_text.gsub!(FetchLinkCardService::URL_PATTERN, '')\n    new_text.gsub!(Account::MENTION_RE, '')\n    new_text.gsub!(Tag::HASHTAG_RE, '')\n    new_text.gsub!(/:#{CustomEmoji::SHORTCODE_RE_FRAGMENT}:/, '')\n    new_text.gsub!(/\\s+/, ' ')\n    new_text\n  end\n\n  def new_scrubber\n    scrubber = Rails::Html::PermitScrubber.new\n    scrubber.tags = %w(br p)\n    scrubber\n  end\n\n  def scrubber\n    @scrubber ||= new_scrubber\n  end\n\n  def remove_html(text)\n    text = Loofah.fragment(text).scrub!(scrubber).to_s\n    text.gsub!('<br>', \"\\n\")\n    text.gsub!('</p><p>', \"\\n\\n\")\n    text.gsub!(/(^<p>|<\\/p>$)/, '')\n    text\n  end\n\n  def default_locale(account)\n    account.user_locale&.to_sym || I18n.default_locale if account.local?\n  end\nend\n"
  },
  {
    "path": "app/lib/ostatus/activity/base.rb",
    "content": "# frozen_string_literal: true\n\nclass OStatus::Activity::Base\n  include Redisable\n\n  def initialize(xml, account = nil, **options)\n    @xml     = xml\n    @account = account\n    @options = options\n  end\n\n  def status?\n    [:activity, :note, :comment].include?(type)\n  end\n\n  def verb\n    raw = @xml.at_xpath('./activity:verb', activity: OStatus::TagManager::AS_XMLNS).content\n    OStatus::TagManager::VERBS.key(raw)\n  rescue\n    :post\n  end\n\n  def type\n    raw = @xml.at_xpath('./activity:object-type', activity: OStatus::TagManager::AS_XMLNS).content\n    OStatus::TagManager::TYPES.key(raw)\n  rescue\n    :activity\n  end\n\n  def id\n    @xml.at_xpath('./xmlns:id', xmlns: OStatus::TagManager::XMLNS).content\n  end\n\n  def url\n    link = @xml.xpath('./xmlns:link[@rel=\"alternate\"]', xmlns: OStatus::TagManager::XMLNS).find { |link_candidate| link_candidate['type'] == 'text/html' }\n    link.nil? ? nil : link['href']\n  end\n\n  def activitypub_uri\n    link = @xml.xpath('./xmlns:link[@rel=\"alternate\"]', xmlns: OStatus::TagManager::XMLNS).find { |link_candidate| ['application/activity+json', 'application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"'].include?(link_candidate['type']) }\n    link.nil? ? nil : link['href']\n  end\n\n  def activitypub_uri?\n    activitypub_uri.present?\n  end\n\n  private\n\n  def find_status(uri)\n    if OStatus::TagManager.instance.local_id?(uri)\n      local_id = OStatus::TagManager.instance.unique_tag_to_local_id(uri, 'Status')\n      return Status.find_by(id: local_id)\n    elsif ActivityPub::TagManager.instance.local_uri?(uri)\n      local_id = ActivityPub::TagManager.instance.uri_to_local_id(uri)\n      return Status.find_by(id: local_id)\n    end\n\n    Status.find_by(uri: uri)\n  end\n\n  def find_activitypub_status(uri, href)\n    tag_matches = /tag:([^,:]+)[^:]*:objectId=([\\d]+)/.match(uri)\n    href_matches = %r{/users/([^/]+)}.match(href)\n\n    unless tag_matches.nil? || href_matches.nil?\n      uri = \"https://#{tag_matches[1]}/users/#{href_matches[1]}/statuses/#{tag_matches[2]}\"\n      Status.find_by(uri: uri)\n    end\n  end\nend\n"
  },
  {
    "path": "app/lib/ostatus/activity/creation.rb",
    "content": "# frozen_string_literal: true\n\nclass OStatus::Activity::Creation < OStatus::Activity::Base\n  def perform\n    if redis.exists(\"delete_upon_arrival:#{@account.id}:#{id}\")\n      Rails.logger.debug \"Delete for status #{id} was queued, ignoring\"\n      return [nil, false]\n    end\n\n    return [nil, false] if @account.suspended? || invalid_origin?\n\n    RedisLock.acquire(lock_options) do |lock|\n      if lock.acquired?\n        # Return early if status already exists in db\n        @status = find_status(id)\n        return [@status, false] unless @status.nil?\n        @status = process_status\n      else\n        raise Mastodon::RaceConditionError\n      end\n    end\n\n    [@status, true]\n  end\n\n  def process_status\n    Rails.logger.debug \"Creating remote status #{id}\"\n    cached_reblog = reblog\n    status = nil\n\n    # Skip if the reblogged status is not public\n    return if cached_reblog && !(cached_reblog.public_visibility? || cached_reblog.unlisted_visibility?)\n\n    media_attachments = save_media.take(4)\n\n    ApplicationRecord.transaction do\n      status = Status.create!(\n        uri: id,\n        url: url,\n        account: @account,\n        reblog: cached_reblog,\n        text: content,\n        spoiler_text: content_warning,\n        created_at: published,\n        override_timestamps: @options[:override_timestamps],\n        reply: thread?,\n        language: content_language,\n        visibility: visibility_scope,\n        conversation: find_or_create_conversation,\n        thread: thread? ? find_status(thread.first) || find_activitypub_status(thread.first, thread.second) : nil,\n        media_attachment_ids: media_attachments.map(&:id),\n        sensitive: sensitive?\n      )\n\n      save_mentions(status)\n      save_hashtags(status)\n      save_emojis(status)\n    end\n\n    if thread? && status.thread.nil? && Request.valid_url?(thread.second)\n      Rails.logger.debug \"Trying to attach #{status.id} (#{id}) to #{thread.first}\"\n      ThreadResolveWorker.perform_async(status.id, thread.second)\n    end\n\n    Rails.logger.debug \"Queuing remote status #{status.id} (#{id}) for distribution\"\n\n    LinkCrawlWorker.perform_async(status.id) unless status.spoiler_text?\n\n    # Only continue if the status is supposed to have arrived in real-time.\n    # Note that if @options[:override_timestamps] isn't set, the status\n    # may have a lower snowflake id than other existing statuses, potentially\n    # \"hiding\" it from paginated API calls\n    return status unless @options[:override_timestamps] || status.within_realtime_window?\n\n    DistributionWorker.perform_async(status.id)\n\n    status\n  end\n\n  def content\n    @xml.at_xpath('./xmlns:content', xmlns: OStatus::TagManager::XMLNS).content\n  end\n\n  def content_language\n    @xml.at_xpath('./xmlns:content', xmlns: OStatus::TagManager::XMLNS)['xml:lang']&.presence || 'en'\n  end\n\n  def content_warning\n    @xml.at_xpath('./xmlns:summary', xmlns: OStatus::TagManager::XMLNS)&.content || ''\n  end\n\n  def visibility_scope\n    @xml.at_xpath('./mastodon:scope', mastodon: OStatus::TagManager::MTDN_XMLNS)&.content&.to_sym || :public\n  end\n\n  def published\n    @xml.at_xpath('./xmlns:published', xmlns: OStatus::TagManager::XMLNS).content\n  end\n\n  def thread?\n    !@xml.at_xpath('./thr:in-reply-to', thr: OStatus::TagManager::THR_XMLNS).nil?\n  end\n\n  def thread\n    thr = @xml.at_xpath('./thr:in-reply-to', thr: OStatus::TagManager::THR_XMLNS)\n    [thr['ref'], thr['href']]\n  end\n\n  private\n\n  def sensitive?\n    # OStatus-specific convention (not standard)\n    @xml.xpath('./xmlns:category', xmlns: OStatus::TagManager::XMLNS).any? { |category| category['term'] == 'nsfw' }\n  end\n\n  def find_or_create_conversation\n    uri = @xml.at_xpath('./ostatus:conversation', ostatus: OStatus::TagManager::OS_XMLNS)&.attribute('ref')&.content\n    return if uri.nil?\n\n    if OStatus::TagManager.instance.local_id?(uri)\n      local_id = OStatus::TagManager.instance.unique_tag_to_local_id(uri, 'Conversation')\n      return Conversation.find_by(id: local_id)\n    end\n\n    Conversation.find_by(uri: uri) || Conversation.create!(uri: uri)\n  end\n\n  def save_mentions(parent)\n    processed_account_ids = []\n\n    @xml.xpath('./xmlns:link[@rel=\"mentioned\"]', xmlns: OStatus::TagManager::XMLNS).each do |link|\n      next if [OStatus::TagManager::TYPES[:group], OStatus::TagManager::TYPES[:collection]].include? link['ostatus:object-type']\n\n      mentioned_account = account_from_href(link['href'])\n\n      next if mentioned_account.nil? || processed_account_ids.include?(mentioned_account.id)\n\n      mentioned_account.mentions.where(status: parent).first_or_create(status: parent)\n\n      # So we can skip duplicate mentions\n      processed_account_ids << mentioned_account.id\n    end\n  end\n\n  def save_hashtags(parent)\n    tags = @xml.xpath('./xmlns:category', xmlns: OStatus::TagManager::XMLNS).map { |category| category['term'] }.select(&:present?)\n    ProcessHashtagsService.new.call(parent, tags)\n  end\n\n  def save_media\n    do_not_download = DomainBlock.find_by(domain: @account.domain)&.reject_media?\n    media_attachments = []\n\n    @xml.xpath('./xmlns:link[@rel=\"enclosure\"]', xmlns: OStatus::TagManager::XMLNS).each do |link|\n      next unless link['href']\n\n      media = MediaAttachment.where(status: nil, remote_url: link['href']).first_or_initialize(account: @account, status: nil, remote_url: link['href'])\n      parsed_url = Addressable::URI.parse(link['href']).normalize\n\n      next if !%w(http https).include?(parsed_url.scheme) || parsed_url.host.empty?\n\n      media.save\n      media_attachments << media\n\n      next if do_not_download\n\n      begin\n        media.file_remote_url = link['href']\n        media.save!\n      rescue ActiveRecord::RecordInvalid\n        next\n      end\n    end\n\n    media_attachments\n  end\n\n  def save_emojis(parent)\n    do_not_download = DomainBlock.find_by(domain: parent.account.domain)&.reject_media?\n\n    return if do_not_download\n\n    @xml.xpath('./xmlns:link[@rel=\"emoji\"]', xmlns: OStatus::TagManager::XMLNS).each do |link|\n      next unless link['href'] && link['name']\n\n      shortcode = link['name'].delete(':')\n      emoji     = CustomEmoji.find_by(shortcode: shortcode, domain: parent.account.domain)\n\n      next unless emoji.nil?\n\n      emoji = CustomEmoji.new(shortcode: shortcode, domain: parent.account.domain)\n      emoji.image_remote_url = link['href']\n      emoji.save\n    end\n  end\n\n  def account_from_href(href)\n    url = Addressable::URI.parse(href).normalize\n\n    if TagManager.instance.web_domain?(url.host)\n      Account.find_local(url.path.gsub('/users/', ''))\n    else\n      Account.where(uri: href).or(Account.where(url: href)).first || FetchRemoteAccountService.new.call(href)\n    end\n  end\n\n  def invalid_origin?\n    return false unless id.start_with?('http') # Legacy IDs cannot be checked\n\n    needle = Addressable::URI.parse(id).normalized_host\n\n    !(needle.casecmp(@account.domain).zero? ||\n      needle.casecmp(Addressable::URI.parse(@account.remote_url.presence || @account.uri).normalized_host).zero?)\n  end\n\n  def lock_options\n    { redis: Redis.current, key: \"create:#{id}\" }\n  end\nend\n"
  },
  {
    "path": "app/lib/ostatus/activity/deletion.rb",
    "content": "# frozen_string_literal: true\n\nclass OStatus::Activity::Deletion < OStatus::Activity::Base\n  def perform\n    Rails.logger.debug \"Deleting remote status #{id}\"\n\n    status   = Status.find_by(uri: id, account: @account)\n    status ||= Status.find_by(uri: activitypub_uri, account: @account) if activitypub_uri?\n\n    if status.nil?\n      redis.setex(\"delete_upon_arrival:#{@account.id}:#{id}\", 6 * 3_600, id)\n    else\n      RemoveStatusService.new.call(status)\n    end\n  end\nend\n"
  },
  {
    "path": "app/lib/ostatus/activity/general.rb",
    "content": "# frozen_string_literal: true\n\nclass OStatus::Activity::General < OStatus::Activity::Base\n  def specialize\n    special_class&.new(@xml, @account, @options)\n  end\n\n  private\n\n  def special_class\n    case verb\n    when :post\n      OStatus::Activity::Post\n    when :share\n      OStatus::Activity::Share\n    when :delete\n      OStatus::Activity::Deletion\n    end\n  end\nend\n"
  },
  {
    "path": "app/lib/ostatus/activity/post.rb",
    "content": "# frozen_string_literal: true\n\nclass OStatus::Activity::Post < OStatus::Activity::Creation\n  def perform\n    status, just_created = super\n\n    if just_created\n      status.mentions.includes(:account).each do |mention|\n        mentioned_account = mention.account\n        next unless mentioned_account.local?\n        NotifyService.new.call(mentioned_account, mention)\n      end\n    end\n\n    status\n  end\n\n  private\n\n  def reblog\n    nil\n  end\nend\n"
  },
  {
    "path": "app/lib/ostatus/activity/remote.rb",
    "content": "# frozen_string_literal: true\n\nclass OStatus::Activity::Remote < OStatus::Activity::Base\n  def perform\n    if activitypub_uri?\n      find_status(activitypub_uri) || FetchRemoteStatusService.new.call(url)\n    else\n      find_status(id) || FetchRemoteStatusService.new.call(url)\n    end\n  end\nend\n"
  },
  {
    "path": "app/lib/ostatus/activity/share.rb",
    "content": "# frozen_string_literal: true\n\nclass OStatus::Activity::Share < OStatus::Activity::Creation\n  def perform\n    return if reblog.nil?\n\n    status, just_created = super\n    NotifyService.new.call(reblog.account, status) if reblog.account.local? && just_created\n    status\n  end\n\n  def object\n    @xml.at_xpath('.//activity:object', activity: OStatus::TagManager::AS_XMLNS)\n  end\n\n  private\n\n  def reblog\n    return @reblog if defined? @reblog\n\n    original_status = OStatus::Activity::Remote.new(object).perform\n    return if original_status.nil?\n\n    @reblog = original_status.reblog? ? original_status.reblog : original_status\n  end\nend\n"
  },
  {
    "path": "app/lib/ostatus/atom_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass OStatus::AtomSerializer\n  include RoutingHelper\n  include ActionView::Helpers::SanitizeHelper\n\n  class << self\n    def render(element)\n      document = Ox::Document.new(version: '1.0')\n      document << element\n      ('<?xml version=\"1.0\"?>' + Ox.dump(element, effort: :tolerant)).force_encoding('UTF-8')\n    end\n  end\n\n  def author(account)\n    author = Ox::Element.new('author')\n\n    uri = OStatus::TagManager.instance.uri_for(account)\n\n    append_element(author, 'id', uri)\n    append_element(author, 'activity:object-type', OStatus::TagManager::TYPES[:person])\n    append_element(author, 'uri', uri)\n    append_element(author, 'name', account.username)\n    append_element(author, 'email', account.local? ? account.local_username_and_domain : account.acct)\n    append_element(author, 'summary', Formatter.instance.simplified_format(account).to_str, type: :html) if account.note?\n    append_element(author, 'link', nil, rel: :alternate, type: 'text/html', href: ::TagManager.instance.url_for(account))\n    append_element(author, 'link', nil, rel: :avatar, type: account.avatar_content_type, 'media:width': 120, 'media:height': 120, href: full_asset_url(account.avatar.url(:original))) if account.avatar?\n    append_element(author, 'link', nil, rel: :header, type: account.header_content_type, 'media:width': 700, 'media:height': 335, href: full_asset_url(account.header.url(:original))) if account.header?\n    account.emojis.each do |emoji|\n      append_element(author, 'link', nil, rel: :emoji, href: full_asset_url(emoji.image.url), name: emoji.shortcode)\n    end\n    append_element(author, 'poco:preferredUsername', account.username)\n    append_element(author, 'poco:displayName', account.display_name) if account.display_name?\n    append_element(author, 'poco:note', account.local? ? account.note : strip_tags(account.note)) if account.note?\n    append_element(author, 'mastodon:scope', account.locked? ? :private : :public)\n\n    author\n  end\n\n  def feed(account, stream_entries)\n    feed = Ox::Element.new('feed')\n\n    add_namespaces(feed)\n\n    append_element(feed, 'id', account_url(account, format: 'atom'))\n    append_element(feed, 'title', account.display_name.presence || account.username)\n    append_element(feed, 'subtitle', account.note)\n    append_element(feed, 'updated', account.updated_at.iso8601)\n    append_element(feed, 'logo', full_asset_url(account.avatar.url(:original)))\n\n    feed << author(account)\n\n    append_element(feed, 'link', nil, rel: :alternate, type: 'text/html', href: ::TagManager.instance.url_for(account))\n    append_element(feed, 'link', nil, rel: :self, type: 'application/atom+xml', href: account_url(account, format: 'atom'))\n    append_element(feed, 'link', nil, rel: :next, type: 'application/atom+xml', href: account_url(account, format: 'atom', max_id: stream_entries.last.id)) if stream_entries.size == 20\n    append_element(feed, 'link', nil, rel: :hub, href: api_push_url)\n    append_element(feed, 'link', nil, rel: :salmon, href: api_salmon_url(account.id))\n\n    stream_entries.each do |stream_entry|\n      feed << entry(stream_entry)\n    end\n\n    feed\n  end\n\n  def entry(stream_entry, root = false)\n    entry = Ox::Element.new('entry')\n\n    add_namespaces(entry) if root\n\n    append_element(entry, 'id', OStatus::TagManager.instance.uri_for(stream_entry.status))\n    append_element(entry, 'published', stream_entry.created_at.iso8601)\n    append_element(entry, 'updated', stream_entry.updated_at.iso8601)\n    append_element(entry, 'title', stream_entry&.status&.title || \"#{stream_entry.account.acct} deleted status\")\n\n    entry << author(stream_entry.account) if root\n\n    append_element(entry, 'activity:object-type', OStatus::TagManager::TYPES[stream_entry.object_type])\n    append_element(entry, 'activity:verb', OStatus::TagManager::VERBS[stream_entry.verb])\n\n    entry << object(stream_entry.target) if stream_entry.targeted?\n\n    if stream_entry.status.nil?\n      append_element(entry, 'content', 'Deleted status')\n    elsif stream_entry.status.destroyed?\n      append_element(entry, 'content', 'Deleted status')\n      append_element(entry, 'link', nil, rel: :alternate, type: 'application/activity+json', href: ActivityPub::TagManager.instance.uri_for(stream_entry.status)) if stream_entry.account.local?\n    else\n      serialize_status_attributes(entry, stream_entry.status)\n    end\n\n    append_element(entry, 'link', nil, rel: :alternate, type: 'text/html', href: ::TagManager.instance.url_for(stream_entry.status))\n    append_element(entry, 'link', nil, rel: :self, type: 'application/atom+xml', href: account_stream_entry_url(stream_entry.account, stream_entry, format: 'atom'))\n    append_element(entry, 'thr:in-reply-to', nil, ref: OStatus::TagManager.instance.uri_for(stream_entry.thread), href: ::TagManager.instance.url_for(stream_entry.thread)) if stream_entry.threaded?\n    append_element(entry, 'ostatus:conversation', nil, ref: conversation_uri(stream_entry.status.conversation)) unless stream_entry&.status&.conversation_id.nil?\n\n    entry\n  end\n\n  def object(status)\n    object = Ox::Element.new('activity:object')\n\n    append_element(object, 'id', OStatus::TagManager.instance.uri_for(status))\n    append_element(object, 'published', status.created_at.iso8601)\n    append_element(object, 'updated', status.updated_at.iso8601)\n    append_element(object, 'title', status.title)\n\n    object << author(status.account)\n\n    append_element(object, 'activity:object-type', OStatus::TagManager::TYPES[status.object_type])\n    append_element(object, 'activity:verb', OStatus::TagManager::VERBS[status.verb])\n\n    serialize_status_attributes(object, status)\n\n    append_element(object, 'link', nil, rel: :alternate, type: 'text/html', href: ::TagManager.instance.url_for(status))\n    append_element(object, 'thr:in-reply-to', nil, ref: OStatus::TagManager.instance.uri_for(status.thread), href: ::TagManager.instance.url_for(status.thread)) unless status.thread.nil?\n    append_element(object, 'ostatus:conversation', nil, ref: conversation_uri(status.conversation)) unless status.conversation_id.nil?\n\n    object\n  end\n\n  def follow_salmon(follow)\n    entry = Ox::Element.new('entry')\n    add_namespaces(entry)\n\n    description = \"#{follow.account.acct} started following #{follow.target_account.acct}\"\n\n    append_element(entry, 'id', OStatus::TagManager.instance.unique_tag(follow.created_at, follow.id, 'Follow'))\n    append_element(entry, 'title', description)\n    append_element(entry, 'content', description, type: :html)\n\n    entry << author(follow.account)\n\n    append_element(entry, 'activity:object-type', OStatus::TagManager::TYPES[:activity])\n    append_element(entry, 'activity:verb', OStatus::TagManager::VERBS[:follow])\n\n    object = author(follow.target_account)\n    object.value = 'activity:object'\n\n    entry << object\n    entry\n  end\n\n  def follow_request_salmon(follow_request)\n    entry = Ox::Element.new('entry')\n    add_namespaces(entry)\n\n    append_element(entry, 'id', OStatus::TagManager.instance.unique_tag(follow_request.created_at, follow_request.id, 'FollowRequest'))\n    append_element(entry, 'title', \"#{follow_request.account.acct} requested to follow #{follow_request.target_account.acct}\")\n\n    entry << author(follow_request.account)\n\n    append_element(entry, 'activity:object-type', OStatus::TagManager::TYPES[:activity])\n    append_element(entry, 'activity:verb', OStatus::TagManager::VERBS[:request_friend])\n\n    object = author(follow_request.target_account)\n    object.value = 'activity:object'\n\n    entry << object\n    entry\n  end\n\n  def authorize_follow_request_salmon(follow_request)\n    entry = Ox::Element.new('entry')\n    add_namespaces(entry)\n\n    append_element(entry, 'id', OStatus::TagManager.instance.unique_tag(Time.now.utc, follow_request.id, 'FollowRequest'))\n    append_element(entry, 'title', \"#{follow_request.target_account.acct} authorizes follow request by #{follow_request.account.acct}\")\n\n    entry << author(follow_request.target_account)\n\n    append_element(entry, 'activity:object-type', OStatus::TagManager::TYPES[:activity])\n    append_element(entry, 'activity:verb', OStatus::TagManager::VERBS[:authorize])\n\n    object = Ox::Element.new('activity:object')\n    object << author(follow_request.account)\n\n    append_element(object, 'activity:object-type', OStatus::TagManager::TYPES[:activity])\n    append_element(object, 'activity:verb', OStatus::TagManager::VERBS[:request_friend])\n\n    inner_object = author(follow_request.target_account)\n    inner_object.value = 'activity:object'\n\n    object << inner_object\n    entry  << object\n    entry\n  end\n\n  def reject_follow_request_salmon(follow_request)\n    entry = Ox::Element.new('entry')\n    add_namespaces(entry)\n\n    append_element(entry, 'id', OStatus::TagManager.instance.unique_tag(Time.now.utc, follow_request.id, 'FollowRequest'))\n    append_element(entry, 'title', \"#{follow_request.target_account.acct} rejects follow request by #{follow_request.account.acct}\")\n\n    entry << author(follow_request.target_account)\n\n    append_element(entry, 'activity:object-type', OStatus::TagManager::TYPES[:activity])\n    append_element(entry, 'activity:verb', OStatus::TagManager::VERBS[:reject])\n\n    object = Ox::Element.new('activity:object')\n    object << author(follow_request.account)\n\n    append_element(object, 'activity:object-type', OStatus::TagManager::TYPES[:activity])\n    append_element(object, 'activity:verb', OStatus::TagManager::VERBS[:request_friend])\n\n    inner_object = author(follow_request.target_account)\n    inner_object.value = 'activity:object'\n\n    object << inner_object\n    entry  << object\n    entry\n  end\n\n  def unfollow_salmon(follow)\n    entry = Ox::Element.new('entry')\n    add_namespaces(entry)\n\n    description = \"#{follow.account.acct} is no longer following #{follow.target_account.acct}\"\n\n    append_element(entry, 'id', OStatus::TagManager.instance.unique_tag(Time.now.utc, follow.id, 'Follow'))\n    append_element(entry, 'title', description)\n    append_element(entry, 'content', description, type: :html)\n\n    entry << author(follow.account)\n\n    append_element(entry, 'activity:object-type', OStatus::TagManager::TYPES[:activity])\n    append_element(entry, 'activity:verb', OStatus::TagManager::VERBS[:unfollow])\n\n    object = author(follow.target_account)\n    object.value = 'activity:object'\n\n    entry << object\n    entry\n  end\n\n  def block_salmon(block)\n    entry = Ox::Element.new('entry')\n    add_namespaces(entry)\n\n    description = \"#{block.account.acct} no longer wishes to interact with #{block.target_account.acct}\"\n\n    append_element(entry, 'id', OStatus::TagManager.instance.unique_tag(Time.now.utc, block.id, 'Block'))\n    append_element(entry, 'title', description)\n\n    entry << author(block.account)\n\n    append_element(entry, 'activity:object-type', OStatus::TagManager::TYPES[:activity])\n    append_element(entry, 'activity:verb', OStatus::TagManager::VERBS[:block])\n\n    object = author(block.target_account)\n    object.value = 'activity:object'\n\n    entry << object\n    entry\n  end\n\n  def unblock_salmon(block)\n    entry = Ox::Element.new('entry')\n    add_namespaces(entry)\n\n    description = \"#{block.account.acct} no longer blocks #{block.target_account.acct}\"\n\n    append_element(entry, 'id', OStatus::TagManager.instance.unique_tag(Time.now.utc, block.id, 'Block'))\n    append_element(entry, 'title', description)\n\n    entry << author(block.account)\n\n    append_element(entry, 'activity:object-type', OStatus::TagManager::TYPES[:activity])\n    append_element(entry, 'activity:verb', OStatus::TagManager::VERBS[:unblock])\n\n    object = author(block.target_account)\n    object.value = 'activity:object'\n\n    entry << object\n    entry\n  end\n\n  def favourite_salmon(favourite)\n    entry = Ox::Element.new('entry')\n    add_namespaces(entry)\n\n    description = \"#{favourite.account.acct} favourited a status by #{favourite.status.account.acct}\"\n\n    append_element(entry, 'id', OStatus::TagManager.instance.unique_tag(favourite.created_at, favourite.id, 'Favourite'))\n    append_element(entry, 'title', description)\n    append_element(entry, 'content', description, type: :html)\n\n    entry << author(favourite.account)\n\n    append_element(entry, 'activity:object-type', OStatus::TagManager::TYPES[:activity])\n    append_element(entry, 'activity:verb', OStatus::TagManager::VERBS[:favorite])\n\n    entry << object(favourite.status)\n\n    append_element(entry, 'thr:in-reply-to', nil, ref: OStatus::TagManager.instance.uri_for(favourite.status), href: ::TagManager.instance.url_for(favourite.status))\n\n    entry\n  end\n\n  def unfavourite_salmon(favourite)\n    entry = Ox::Element.new('entry')\n    add_namespaces(entry)\n\n    description = \"#{favourite.account.acct} no longer favourites a status by #{favourite.status.account.acct}\"\n\n    append_element(entry, 'id', OStatus::TagManager.instance.unique_tag(Time.now.utc, favourite.id, 'Favourite'))\n    append_element(entry, 'title', description)\n    append_element(entry, 'content', description, type: :html)\n\n    entry << author(favourite.account)\n\n    append_element(entry, 'activity:object-type', OStatus::TagManager::TYPES[:activity])\n    append_element(entry, 'activity:verb', OStatus::TagManager::VERBS[:unfavorite])\n\n    entry << object(favourite.status)\n\n    append_element(entry, 'thr:in-reply-to', nil, ref: OStatus::TagManager.instance.uri_for(favourite.status), href: ::TagManager.instance.url_for(favourite.status))\n\n    entry\n  end\n\n  private\n\n  def append_element(parent, name, content = nil, **attributes)\n    element = Ox::Element.new(name)\n    attributes.each { |k, v| element[k] = sanitize_str(v) }\n    element << sanitize_str(content) unless content.nil?\n    parent  << element\n  end\n\n  def sanitize_str(raw_str)\n    raw_str.to_s\n  end\n\n  def conversation_uri(conversation)\n    return conversation.uri if conversation.uri?\n    OStatus::TagManager.instance.unique_tag(conversation.created_at, conversation.id, 'Conversation')\n  end\n\n  def add_namespaces(parent)\n    parent['xmlns']          = OStatus::TagManager::XMLNS\n    parent['xmlns:thr']      = OStatus::TagManager::THR_XMLNS\n    parent['xmlns:activity'] = OStatus::TagManager::AS_XMLNS\n    parent['xmlns:poco']     = OStatus::TagManager::POCO_XMLNS\n    parent['xmlns:media']    = OStatus::TagManager::MEDIA_XMLNS\n    parent['xmlns:ostatus']  = OStatus::TagManager::OS_XMLNS\n    parent['xmlns:mastodon'] = OStatus::TagManager::MTDN_XMLNS\n  end\n\n  def serialize_status_attributes(entry, status)\n    append_element(entry, 'link', nil, rel: :alternate, type: 'application/activity+json', href: ActivityPub::TagManager.instance.uri_for(status)) if status.account.local?\n\n    append_element(entry, 'summary', status.spoiler_text, 'xml:lang': status.language) if status.spoiler_text?\n    append_element(entry, 'content', Formatter.instance.format(status, inline_poll_options: true).to_str || '.', type: 'html', 'xml:lang': status.language)\n\n    status.active_mentions.sort_by(&:id).each do |mentioned|\n      append_element(entry, 'link', nil, rel: :mentioned, 'ostatus:object-type': OStatus::TagManager::TYPES[:person], href: OStatus::TagManager.instance.uri_for(mentioned.account))\n    end\n\n    append_element(entry, 'link', nil, rel: :mentioned, 'ostatus:object-type': OStatus::TagManager::TYPES[:collection], href: OStatus::TagManager::COLLECTIONS[:public]) if status.public_visibility?\n\n    status.tags.each do |tag|\n      append_element(entry, 'category', nil, term: tag.name)\n    end\n\n    status.media_attachments.each do |media|\n      append_element(entry, 'link', nil, rel: :enclosure, type: media.file_content_type, length: media.file_file_size, href: full_asset_url(media.file.url(:original, false)))\n    end\n\n    append_element(entry, 'category', nil, term: 'nsfw') if status.sensitive? && status.media_attachments.any?\n    append_element(entry, 'mastodon:scope', status.visibility)\n\n    status.emojis.each do |emoji|\n      append_element(entry, 'link', nil, rel: :emoji, href: full_asset_url(emoji.image.url), name: emoji.shortcode)\n    end\n  end\nend\n"
  },
  {
    "path": "app/lib/ostatus/tag_manager.rb",
    "content": "# frozen_string_literal: true\n\nclass OStatus::TagManager\n  include Singleton\n  include RoutingHelper\n\n  VERBS = {\n    post:           'http://activitystrea.ms/schema/1.0/post',\n    share:          'http://activitystrea.ms/schema/1.0/share',\n    favorite:       'http://activitystrea.ms/schema/1.0/favorite',\n    unfavorite:     'http://activitystrea.ms/schema/1.0/unfavorite',\n    delete:         'http://activitystrea.ms/schema/1.0/delete',\n    follow:         'http://activitystrea.ms/schema/1.0/follow',\n    request_friend: 'http://activitystrea.ms/schema/1.0/request-friend',\n    authorize:      'http://activitystrea.ms/schema/1.0/authorize',\n    reject:         'http://activitystrea.ms/schema/1.0/reject',\n    unfollow:       'http://ostatus.org/schema/1.0/unfollow',\n    block:          'http://mastodon.social/schema/1.0/block',\n    unblock:        'http://mastodon.social/schema/1.0/unblock',\n  }.freeze\n\n  TYPES = {\n    activity:   'http://activitystrea.ms/schema/1.0/activity',\n    note:       'http://activitystrea.ms/schema/1.0/note',\n    comment:    'http://activitystrea.ms/schema/1.0/comment',\n    person:     'http://activitystrea.ms/schema/1.0/person',\n    collection: 'http://activitystrea.ms/schema/1.0/collection',\n    group:      'http://activitystrea.ms/schema/1.0/group',\n  }.freeze\n\n  COLLECTIONS = {\n    public: 'http://activityschema.org/collection/public',\n  }.freeze\n\n  XMLNS       = 'http://www.w3.org/2005/Atom'\n  MEDIA_XMLNS = 'http://purl.org/syndication/atommedia'\n  AS_XMLNS    = 'http://activitystrea.ms/spec/1.0/'\n  THR_XMLNS   = 'http://purl.org/syndication/thread/1.0'\n  POCO_XMLNS  = 'http://portablecontacts.net/spec/1.0'\n  DFRN_XMLNS  = 'http://purl.org/macgirvin/dfrn/1.0'\n  OS_XMLNS    = 'http://ostatus.org/schema/1.0'\n  MTDN_XMLNS  = 'http://mastodon.social/schema/1.0'\n\n  def unique_tag(date, id, type)\n    \"tag:#{Rails.configuration.x.local_domain},#{date.strftime('%Y-%m-%d')}:objectId=#{id}:objectType=#{type}\"\n  end\n\n  def unique_tag_to_local_id(tag, expected_type)\n    return nil unless local_id?(tag)\n\n    if ActivityPub::TagManager.instance.local_uri?(tag)\n      ActivityPub::TagManager.instance.uri_to_local_id(tag)\n    else\n      matches = Regexp.new(\"objectId=([\\\\d]+):objectType=#{expected_type}\").match(tag)\n      return matches[1] unless matches.nil?\n    end\n  end\n\n  def local_id?(id)\n    id.start_with?(\"tag:#{Rails.configuration.x.local_domain}\") || ActivityPub::TagManager.instance.local_uri?(id)\n  end\n\n  def uri_for(target)\n    return target.uri if target.respond_to?(:local?) && !target.local?\n\n    case target.object_type\n    when :person\n      account_url(target)\n    when :note, :comment, :activity\n      target.uri || unique_tag(target.created_at, target.id, 'Status')\n    end\n  end\nend\n"
  },
  {
    "path": "app/lib/potential_friendship_tracker.rb",
    "content": "# frozen_string_literal: true\n\nclass PotentialFriendshipTracker\n  EXPIRE_AFTER = 90.days.seconds\n  MAX_ITEMS    = 80\n\n  WEIGHTS = {\n    reply: 1,\n    favourite: 10,\n    reblog: 20,\n  }.freeze\n\n  class << self\n    include Redisable\n\n    def record(account_id, target_account_id, action)\n      return if account_id == target_account_id\n\n      key    = \"interactions:#{account_id}\"\n      weight = WEIGHTS[action]\n\n      redis.zincrby(key, weight, target_account_id)\n      redis.zremrangebyrank(key, 0, -MAX_ITEMS)\n      redis.expire(key, EXPIRE_AFTER)\n    end\n\n    def remove(account_id, target_account_id)\n      redis.zrem(\"interactions:#{account_id}\", target_account_id)\n    end\n\n    def get(account_id, limit: 20, offset: 0)\n      account_ids = redis.zrevrange(\"interactions:#{account_id}\", offset, limit)\n      return [] if account_ids.empty?\n      Account.searchable.where(id: account_ids)\n    end\n  end\nend\n"
  },
  {
    "path": "app/lib/proof_provider/keybase/badge.rb",
    "content": "# frozen_string_literal: true\n\nclass ProofProvider::Keybase::Badge\n  include RoutingHelper\n\n  def initialize(local_username, provider_username, token, domain)\n    @local_username    = local_username\n    @provider_username = provider_username\n    @token             = token\n    @domain            = domain\n  end\n\n  def proof_url\n    \"#{ProofProvider::Keybase::BASE_URL}/#{@provider_username}/sigchain\\##{@token}\"\n  end\n\n  def profile_url\n    \"#{ProofProvider::Keybase::BASE_URL}/#{@provider_username}\"\n  end\n\n  def icon_url\n    \"#{ProofProvider::Keybase::BASE_URL}/#{@provider_username}/proof_badge/#{@token}?username=#{@local_username}&domain=#{@domain}\"\n  end\n\n  def avatar_url\n    Rails.cache.fetch(\"proof_providers/keybase/#{@provider_username}/avatar_url\", expires_in: 5.minutes) { remote_avatar_url } || default_avatar_url\n  end\n\n  private\n\n  def remote_avatar_url\n    request = Request.new(:get, \"#{ProofProvider::Keybase::BASE_URL}/_/api/1.0/user/pic_url.json\", params: { username: @provider_username })\n\n    request.perform do |res|\n      json = Oj.load(res.body_with_limit, mode: :strict)\n      json['pic_url'] if json.is_a?(Hash)\n    end\n  rescue Oj::ParseError, HTTP::Error, OpenSSL::SSL::SSLError\n    nil\n  end\n\n  def default_avatar_url\n    asset_pack_path('media/images/proof_providers/keybase.png')\n  end\nend\n"
  },
  {
    "path": "app/lib/proof_provider/keybase/config_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass ProofProvider::Keybase::ConfigSerializer < ActiveModel::Serializer\n  include RoutingHelper\n  include ActionView::Helpers::TextHelper\n\n  attributes :version, :domain, :display_name, :username,\n             :brand_color, :logo, :description, :prefill_url,\n             :profile_url, :check_url, :check_path, :avatar_path,\n             :contact\n\n  def version\n    1\n  end\n\n  def domain\n    ProofProvider::Keybase::DOMAIN\n  end\n\n  def display_name\n    Setting.site_title\n  end\n\n  def logo\n    { svg_black: full_asset_url(asset_pack_path('media/images/logo_transparent_black.svg')), svg_full: full_asset_url(asset_pack_path('media/images/logo.svg')) }\n  end\n\n  def brand_color\n    '#282c37'\n  end\n\n  def description\n    strip_tags(Setting.site_short_description.presence || I18n.t('about.about_mastodon_html'))\n  end\n\n  def username\n    { min: 1, max: 30, re: '[a-z0-9_]+([a-z0-9_.-]+[a-z0-9_]+)?' }\n  end\n\n  def prefill_url\n    params = {\n      provider: 'keybase',\n      token: '%{sig_hash}',\n      provider_username: '%{kb_username}',\n      username: '%{username}',\n      user_agent: '%{kb_ua}',\n    }\n\n    CGI.unescape(new_settings_identity_proof_url(params))\n  end\n\n  def profile_url\n    CGI.unescape(short_account_url('%{username}')) # rubocop:disable Style/FormatStringToken\n  end\n\n  def check_url\n    CGI.unescape(api_proofs_url(username: '%{username}', provider: 'keybase'))\n  end\n\n  def check_path\n    ['signatures']\n  end\n\n  def avatar_path\n    ['avatar']\n  end\n\n  def contact\n    [Setting.site_contact_email.presence || 'unknown'].compact\n  end\nend\n"
  },
  {
    "path": "app/lib/proof_provider/keybase/serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass ProofProvider::Keybase::Serializer < ActiveModel::Serializer\n  include RoutingHelper\n\n  attribute :avatar\n\n  has_many :identity_proofs, key: :signatures\n\n  def avatar\n    full_asset_url(object.avatar_original_url)\n  end\n\n  class AccountIdentityProofSerializer < ActiveModel::Serializer\n    attributes :sig_hash, :kb_username\n\n    def sig_hash\n      object.token\n    end\n\n    def kb_username\n      object.provider_username\n    end\n  end\nend\n"
  },
  {
    "path": "app/lib/proof_provider/keybase/verifier.rb",
    "content": "# frozen_string_literal: true\n\nclass ProofProvider::Keybase::Verifier\n  def initialize(local_username, provider_username, token, domain)\n    @local_username    = local_username\n    @provider_username = provider_username\n    @token             = token\n    @domain            = domain\n  end\n\n  def valid?\n    request = Request.new(:get, \"#{ProofProvider::Keybase::BASE_URL}/_/api/1.0/sig/proof_valid.json\", params: query_params)\n\n    request.perform do |res|\n      json = Oj.load(res.body_with_limit, mode: :strict)\n\n      if json.is_a?(Hash)\n        json.fetch('proof_valid', false)\n      else\n        false\n      end\n    end\n  rescue Oj::ParseError, HTTP::Error, OpenSSL::SSL::SSLError\n    false\n  end\n\n  def on_success_path(user_agent = nil)\n    url = Addressable::URI.parse(\"#{ProofProvider::Keybase::BASE_URL}/_/proof_creation_success\")\n    url.query_values = query_params.merge(kb_ua: user_agent || 'unknown')\n    url.to_s\n  end\n\n  def status\n    request = Request.new(:get, \"#{ProofProvider::Keybase::BASE_URL}/_/api/1.0/sig/proof_live.json\", params: query_params)\n\n    request.perform do |res|\n      raise ProofProvider::Keybase::UnexpectedResponseError unless res.code == 200\n\n      json = Oj.load(res.body_with_limit, mode: :strict)\n\n      raise ProofProvider::Keybase::UnexpectedResponseError unless json.is_a?(Hash) && json.key?('proof_valid') && json.key?('proof_live')\n\n      json\n    end\n  rescue Oj::ParseError, HTTP::Error, OpenSSL::SSL::SSLError\n    raise ProofProvider::Keybase::UnexpectedResponseError\n  end\n\n  private\n\n  def query_params\n    {\n      domain: @domain,\n      kb_username: @provider_username,\n      username: @local_username,\n      sig_hash: @token,\n    }\n  end\nend\n"
  },
  {
    "path": "app/lib/proof_provider/keybase/worker.rb",
    "content": "# frozen_string_literal: true\n\nclass ProofProvider::Keybase::Worker\n  include Sidekiq::Worker\n\n  sidekiq_options queue: 'pull', retry: 20, unique: :until_executed\n\n  sidekiq_retry_in do |count, exception|\n    # Retry aggressively when the proof is valid but not live in Keybase.\n    # This is likely because Keybase just hasn't noticed the proof being\n    # served from here yet.\n\n    if exception.class == ProofProvider::Keybase::ExpectedProofLiveError\n      case count\n      when 0..2 then 0.seconds\n      when 2..6 then 1.second\n      end\n    end\n  end\n\n  def perform(proof_id)\n    proof  = proof_id.is_a?(AccountIdentityProof) ? proof_id : AccountIdentityProof.find(proof_id)\n    status = proof.provider_instance.verifier.status\n\n    # If Keybase thinks the proof is valid, and it exists here in Mastodon,\n    # then it should be live. Keybase just has to notice that it's here\n    # and then update its state. That might take a couple seconds.\n    raise ProofProvider::Keybase::ExpectedProofLiveError if status['proof_valid'] && !status['proof_live']\n\n    proof.update!(verified: status['proof_valid'], live: status['proof_live'])\n  end\nend\n"
  },
  {
    "path": "app/lib/proof_provider/keybase.rb",
    "content": "# frozen_string_literal: true\n\nclass ProofProvider::Keybase\n  BASE_URL = ENV.fetch('KEYBASE_BASE_URL', 'https://keybase.io')\n  DOMAIN   = ENV.fetch('KEYBASE_DOMAIN', Rails.configuration.x.web_domain)\n\n  class Error < StandardError; end\n\n  class ExpectedProofLiveError < Error; end\n\n  class UnexpectedResponseError < Error; end\n\n  def initialize(proof = nil)\n    @proof = proof\n  end\n\n  def serializer_class\n    ProofProvider::Keybase::Serializer\n  end\n\n  def worker_class\n    ProofProvider::Keybase::Worker\n  end\n\n  def validate!\n    unless @proof.token&.size == 66\n      @proof.errors.add(:base, I18n.t('identity_proofs.errors.keybase.invalid_token'))\n      return\n    end\n\n    # Do not perform synchronous validation for remote accounts\n    return if @proof.provider_username.blank? || !@proof.account.local?\n\n    if verifier.valid?\n      @proof.verified = true\n      @proof.live     = false\n    else\n      @proof.errors.add(:base, I18n.t('identity_proofs.errors.keybase.verification_failed', kb_username: @proof.provider_username))\n    end\n  end\n\n  def refresh!\n    worker_class.new.perform(@proof)\n  rescue ProofProvider::Keybase::Error\n    nil\n  end\n\n  def on_success_path(user_agent = nil)\n    verifier.on_success_path(user_agent)\n  end\n\n  def badge\n    @badge ||= ProofProvider::Keybase::Badge.new(@proof.account.username, @proof.provider_username, @proof.token, domain)\n  end\n\n  def verifier\n    @verifier ||= ProofProvider::Keybase::Verifier.new(@proof.account.username, @proof.provider_username, @proof.token, domain)\n  end\n\n  private\n\n  def domain\n    if @proof.account.local?\n      DOMAIN\n    else\n      @proof.account.domain\n    end\n  end\nend\n"
  },
  {
    "path": "app/lib/proof_provider.rb",
    "content": "# frozen_string_literal: true\n\nmodule ProofProvider\n  SUPPORTED_PROVIDERS = %w(keybase).freeze\n\n  def self.find(identifier, proof = nil)\n    case identifier\n    when 'keybase'\n      ProofProvider::Keybase.new(proof)\n    end\n  end\nend\n"
  },
  {
    "path": "app/lib/request.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'ipaddr'\nrequire 'socket'\nrequire 'resolv'\n\n# Monkey-patch the HTTP.rb timeout class to avoid using a timeout block\n# around the Socket#open method, since we use our own timeout blocks inside\n# that method\nclass HTTP::Timeout::PerOperation\n  def connect(socket_class, host, port, nodelay = false)\n    @socket = socket_class.open(host, port)\n    @socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1) if nodelay\n  end\nend\n\nclass Request\n  REQUEST_TARGET = '(request-target)'\n\n  include RoutingHelper\n\n  def initialize(verb, url, **options)\n    raise ArgumentError if url.blank?\n\n    @verb    = verb\n    @url     = Addressable::URI.parse(url).normalize\n    @options = options.merge(use_proxy? ? Rails.configuration.x.http_client_proxy : { socket_class: Socket })\n    @headers = {}\n\n    raise Mastodon::HostValidationError, 'Instance does not support hidden service connections' if block_hidden_service?\n\n    set_common_headers!\n    set_digest! if options.key?(:body)\n  end\n\n  def on_behalf_of(account, key_id_format = :acct, sign_with: nil)\n    raise ArgumentError unless account.local?\n\n    @account       = account\n    @keypair       = sign_with.present? ? OpenSSL::PKey::RSA.new(sign_with) : @account.keypair\n    @key_id_format = key_id_format\n\n    self\n  end\n\n  def add_headers(new_headers)\n    @headers.merge!(new_headers)\n    self\n  end\n\n  def perform\n    begin\n      response = http_client.headers(headers).public_send(@verb, @url.to_s, @options)\n    rescue => e\n      raise e.class, \"#{e.message} on #{@url}\", e.backtrace[0]\n    end\n\n    begin\n      yield response.extend(ClientLimit) if block_given?\n    ensure\n      http_client.close\n    end\n  end\n\n  def headers\n    (@account ? @headers.merge('Signature' => signature) : @headers).without(REQUEST_TARGET)\n  end\n\n  class << self\n    def valid_url?(url)\n      begin\n        parsed_url = Addressable::URI.parse(url)\n      rescue Addressable::URI::InvalidURIError\n        return false\n      end\n\n      %w(http https).include?(parsed_url.scheme) && parsed_url.host.present?\n    end\n  end\n\n  private\n\n  def set_common_headers!\n    @headers[REQUEST_TARGET]    = \"#{@verb} #{@url.path}\"\n    @headers['User-Agent']      = Mastodon::Version.user_agent\n    @headers['Host']            = @url.host\n    @headers['Date']            = Time.now.utc.httpdate\n    @headers['Accept-Encoding'] = 'gzip' if @verb != :head\n  end\n\n  def set_digest!\n    @headers['Digest'] = \"SHA-256=#{Digest::SHA256.base64digest(@options[:body])}\"\n  end\n\n  def signature\n    algorithm = 'rsa-sha256'\n    signature = Base64.strict_encode64(@keypair.sign(OpenSSL::Digest::SHA256.new, signed_string))\n\n    \"keyId=\\\"#{key_id}\\\",algorithm=\\\"#{algorithm}\\\",headers=\\\"#{signed_headers.keys.join(' ').downcase}\\\",signature=\\\"#{signature}\\\"\"\n  end\n\n  def signed_string\n    signed_headers.map { |key, value| \"#{key.downcase}: #{value}\" }.join(\"\\n\")\n  end\n\n  def signed_headers\n    @headers.without('User-Agent', 'Accept-Encoding')\n  end\n\n  def key_id\n    case @key_id_format\n    when :acct\n      @account.to_webfinger_s\n    when :uri\n      [ActivityPub::TagManager.instance.uri_for(@account), '#main-key'].join\n    end\n  end\n\n  def timeout\n    # We enforce a 1s timeout on DNS resolving, 10s timeout on socket opening\n    # and 5s timeout on the TLS handshake, meaning the worst case should take\n    # about 16s in total\n\n    { connect: 5, read: 10, write: 10 }\n  end\n\n  def http_client\n    @http_client ||= HTTP.use(:auto_inflate).timeout(:per_operation, timeout).follow(max_hops: 2)\n  end\n\n  def use_proxy?\n    Rails.configuration.x.http_client_proxy.present?\n  end\n\n  def block_hidden_service?\n    !Rails.configuration.x.access_to_hidden_service && /\\.(onion|i2p)$/.match(@url.host)\n  end\n\n  module ClientLimit\n    def body_with_limit(limit = 1.megabyte)\n      raise Mastodon::LengthValidationError if content_length.present? && content_length > limit\n\n      if charset.nil?\n        encoding = Encoding::BINARY\n      else\n        begin\n          encoding = Encoding.find(charset)\n        rescue ArgumentError\n          encoding = Encoding::BINARY\n        end\n      end\n\n      contents = String.new(encoding: encoding)\n\n      while (chunk = readpartial)\n        contents << chunk\n        chunk.clear\n\n        raise Mastodon::LengthValidationError if contents.bytesize > limit\n      end\n\n      contents\n    end\n  end\n\n  class Socket < TCPSocket\n    class << self\n      def open(host, *args)\n        return super(host, *args) if thru_hidden_service?(host)\n\n        outer_e = nil\n\n        Resolv::DNS.open do |dns|\n          dns.timeouts = 5\n\n          addresses = dns.getaddresses(host).take(2)\n          time_slot = 10.0 / addresses.size\n\n          addresses.each do |address|\n            begin\n              raise Mastodon::HostValidationError if PrivateAddressCheck.private_address?(IPAddr.new(address.to_s))\n\n              ::Timeout.timeout(time_slot, HTTP::TimeoutError) do\n                return super(address.to_s, *args)\n              end\n            rescue => e\n              outer_e = e\n            end\n          end\n        end\n\n        if outer_e\n          raise outer_e\n        else\n          raise SocketError, \"No address for #{host}\"\n        end\n      end\n\n      alias new open\n\n      def thru_hidden_service?(host)\n        Rails.configuration.x.access_to_hidden_service && /\\.(onion|i2p)$/.match(host)\n      end\n    end\n  end\n\n  private_constant :ClientLimit, :Socket\nend\n"
  },
  {
    "path": "app/lib/rss_builder.rb",
    "content": "# frozen_string_literal: true\n\nclass RSSBuilder\n  class ItemBuilder\n    def initialize\n      @item = Ox::Element.new('item')\n    end\n\n    def title(str)\n      @item << (Ox::Element.new('title') << str)\n\n      self\n    end\n\n    def link(str)\n      @item << Ox::Element.new('guid').tap do |guid|\n        guid['isPermalink'] = 'true'\n        guid << str\n      end\n\n      @item << (Ox::Element.new('link') << str)\n\n      self\n    end\n\n    def pub_date(date)\n      @item << (Ox::Element.new('pubDate') << date.to_formatted_s(:rfc822))\n\n      self\n    end\n\n    def description(str)\n      @item << (Ox::Element.new('description') << str)\n\n      self\n    end\n\n    def enclosure(url, type, size)\n      @item << Ox::Element.new('enclosure').tap do |enclosure|\n        enclosure['url']    = url\n        enclosure['length'] = size\n        enclosure['type']   = type\n      end\n\n      self\n    end\n\n    def to_element\n      @item\n    end\n  end\n\n  def initialize\n    @document = Ox::Document.new(version: '1.0')\n    @channel  = Ox::Element.new('channel')\n\n    @document << (rss << @channel)\n  end\n\n  def title(str)\n    @channel << (Ox::Element.new('title') << str)\n\n    self\n  end\n\n  def link(str)\n    @channel << (Ox::Element.new('link') << str)\n\n    self\n  end\n\n  def image(str)\n    @channel << Ox::Element.new('image').tap do |image|\n      image << (Ox::Element.new('url') << str)\n      image << (Ox::Element.new('title') << '')\n      image << (Ox::Element.new('link') << '')\n    end\n\n    @channel << (Ox::Element.new('webfeeds:icon') << str)\n\n    self\n  end\n\n  def cover(str)\n    @channel << Ox::Element.new('webfeeds:cover').tap do |cover|\n      cover['image'] = str\n    end\n\n    self\n  end\n\n  def logo(str)\n    @channel << (Ox::Element.new('webfeeds:logo') << str)\n\n    self\n  end\n\n  def accent_color(str)\n    @channel << (Ox::Element.new('webfeeds:accentColor') << str)\n\n    self\n  end\n\n  def description(str)\n    @channel << (Ox::Element.new('description') << str)\n\n    self\n  end\n\n  def item\n    @channel << ItemBuilder.new.tap do |item|\n      yield item\n    end.to_element\n\n    self\n  end\n\n  def to_xml\n    ('<?xml version=\"1.0\" encoding=\"UTF-8\"?>' + Ox.dump(@document, effort: :tolerant)).force_encoding('UTF-8')\n  end\n\n  private\n\n  def rss\n    Ox::Element.new('rss').tap do |rss|\n      rss['version']        = '2.0'\n      rss['xmlns:webfeeds'] = 'http://webfeeds.org/rss/1.0'\n    end\n  end\nend\n"
  },
  {
    "path": "app/lib/sanitize_config.rb",
    "content": "# frozen_string_literal: true\n\nclass Sanitize\n  module Config\n    HTTP_PROTOCOLS ||= ['http', 'https', 'dat', 'dweb', 'ipfs', 'ipns', 'ssb', 'gopher', :relative].freeze\n\n    CLASS_WHITELIST_TRANSFORMER = lambda do |env|\n      node = env[:node]\n      class_list = node['class']&.split(/[\\t\\n\\f\\r ]/)\n\n      return unless class_list\n\n      class_list.keep_if do |e|\n        next true if e =~ /^(h|p|u|dt|e)-/ # microformats classes\n        next true if e =~ /^(mention|hashtag)$/ # semantic classes\n        next true if e =~ /^(ellipsis|invisible)$/ # link formatting classes\n      end\n\n      node['class'] = class_list.join(' ')\n    end\n\n    MASTODON_STRICT ||= freeze_config(\n      elements: %w(p br span a),\n\n      attributes: {\n        'a'    => %w(href rel class),\n        'span' => %w(class),\n      },\n\n      add_attributes: {\n        'a' => {\n          'rel' => 'nofollow noopener',\n          'target' => '_blank',\n        },\n      },\n\n      protocols: {\n        'a' => { 'href' => HTTP_PROTOCOLS },\n      },\n\n      transformers: [\n        CLASS_WHITELIST_TRANSFORMER,\n      ]\n    )\n\n    MASTODON_OEMBED ||= freeze_config merge(\n      RELAXED,\n      elements: RELAXED[:elements] + %w(audio embed iframe source video),\n\n      attributes: merge(\n        RELAXED[:attributes],\n        'audio'  => %w(controls),\n        'embed'  => %w(height src type width),\n        'iframe' => %w(allowfullscreen frameborder height scrolling src width),\n        'source' => %w(src type),\n        'video'  => %w(controls height loop width),\n        'div'    => [:data]\n      ),\n\n      protocols: merge(\n        RELAXED[:protocols],\n        'embed'  => { 'src' => HTTP_PROTOCOLS },\n        'iframe' => { 'src' => HTTP_PROTOCOLS },\n        'source' => { 'src' => HTTP_PROTOCOLS }\n      )\n    )\n  end\nend\n"
  },
  {
    "path": "app/lib/settings/extend.rb",
    "content": "# frozen_string_literal: true\n\nmodule Settings\n  module Extend\n    def settings\n      @settings ||= ScopedSettings.new(self)\n    end\n  end\nend\n"
  },
  {
    "path": "app/lib/settings/scoped_settings.rb",
    "content": "# frozen_string_literal: true\n\nmodule Settings\n  class ScopedSettings\n    DEFAULTING_TO_UNSCOPED = %w(\n      theme\n    ).freeze\n\n    def initialize(object)\n      @object = object\n    end\n\n    # rubocop:disable Style/MethodMissing\n    def method_missing(method, *args)\n      method_name = method.to_s\n      # set a value for a variable\n      if method_name[-1] == '='\n        var_name = method_name.sub('=', '')\n        value = args.first\n        self[var_name] = value\n      else\n        # retrieve a value\n        self[method_name]\n      end\n    end\n    # rubocop:enable Style/MethodMissing\n\n    def respond_to_missing?(*)\n      true\n    end\n\n    def all_as_records\n      vars = thing_scoped\n      records = vars.each_with_object({}) { |r, h| h[r.var] = r }\n\n      Setting.default_settings.each do |key, default_value|\n        next if records.key?(key) || default_value.is_a?(Hash)\n        records[key] = Setting.new(var: key, value: default_value)\n      end\n\n      records\n    end\n\n    def []=(key, value)\n      key = key.to_s\n      record = thing_scoped.find_or_initialize_by(var: key)\n      record.update!(value: value)\n\n      Rails.cache.write(Setting.cache_key(key, @object), value)\n      value\n    end\n\n    def [](key)\n      Rails.cache.fetch(Setting.cache_key(key, @object)) do\n        db_val = thing_scoped.find_by(var: key.to_s)\n        if db_val\n          default_value = ScopedSettings.default_settings[key]\n          return default_value.with_indifferent_access.merge!(db_val.value) if default_value.is_a?(Hash)\n          db_val.value\n        else\n          ScopedSettings.default_settings[key]\n        end\n      end\n    end\n\n    class << self\n      def default_settings\n        defaulting = DEFAULTING_TO_UNSCOPED.each_with_object({}) { |k, h| h[k] = Setting[k] }\n        Setting.default_settings.merge!(defaulting)\n      end\n    end\n\n    protected\n\n    def thing_scoped\n      Setting.unscoped.where(thing_type: @object.class.base_class.to_s, thing_id: @object.id)\n    end\n  end\nend\n"
  },
  {
    "path": "app/lib/sidekiq_error_handler.rb",
    "content": "# frozen_string_literal: true\n\nclass SidekiqErrorHandler\n  def call(*)\n    yield\n  rescue Mastodon::HostValidationError => e\n    Rails.logger.error \"#{e.class}: #{e.message}\"\n    Rails.logger.error e.backtrace.join(\"\\n\")\n    # Do not retry\n  end\nend\n"
  },
  {
    "path": "app/lib/status_filter.rb",
    "content": "# frozen_string_literal: true\n\nclass StatusFilter\n  attr_reader :status, :account\n\n  def initialize(status, account, preloaded_relations = {})\n    @status              = status\n    @account             = account\n    @preloaded_relations = preloaded_relations\n  end\n\n  def filtered?\n    return false if !account.nil? && account.id == status.account_id\n    blocked_by_policy? || (account_present? && filtered_status?) || silenced_account?\n  end\n\n  private\n\n  def account_present?\n    !account.nil?\n  end\n\n  def filtered_status?\n    blocking_account? || blocking_domain? || muting_account?\n  end\n\n  def blocking_account?\n    @preloaded_relations[:blocking] ? @preloaded_relations[:blocking][status.account_id] : account.blocking?(status.account_id)\n  end\n\n  def blocking_domain?\n    @preloaded_relations[:domain_blocking_by_domain] ? @preloaded_relations[:domain_blocking_by_domain][status.account_domain] : account.domain_blocking?(status.account_domain)\n  end\n\n  def muting_account?\n    @preloaded_relations[:muting] ? @preloaded_relations[:muting][status.account_id] : account.muting?(status.account_id)\n  end\n\n  def silenced_account?\n    !account&.silenced? && status_account_silenced? && !account_following_status_account?\n  end\n\n  def status_account_silenced?\n    status.account.silenced?\n  end\n\n  def account_following_status_account?\n    @preloaded_relations[:following] ? @preloaded_relations[:following][status.account_id] : account&.following?(status.account_id)\n  end\n\n  def blocked_by_policy?\n    !policy_allows_show?\n  end\n\n  def policy_allows_show?\n    StatusPolicy.new(account, status, @preloaded_relations).show?\n  end\nend\n"
  },
  {
    "path": "app/lib/status_finder.rb",
    "content": "# frozen_string_literal: true\n\nclass StatusFinder\n  attr_reader :url\n\n  def initialize(url)\n    @url = url\n  end\n\n  def status\n    verify_action!\n\n    raise ActiveRecord::RecordNotFound unless TagManager.instance.local_url?(url)\n\n    case recognized_params[:controller]\n    when 'stream_entries'\n      StreamEntry.find(recognized_params[:id]).status\n    when 'statuses'\n      Status.find(recognized_params[:id])\n    else\n      raise ActiveRecord::RecordNotFound\n    end\n  end\n\n  private\n\n  def recognized_params\n    Rails.application.routes.recognize_path(url)\n  end\n\n  def verify_action!\n    unless recognized_params[:action] == 'show'\n      raise ActiveRecord::RecordNotFound\n    end\n  end\nend\n"
  },
  {
    "path": "app/lib/tag_manager.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'singleton'\n\nclass TagManager\n  include Singleton\n  include RoutingHelper\n\n  def web_domain?(domain)\n    domain.nil? || domain.gsub(/[\\/]/, '').casecmp(Rails.configuration.x.web_domain).zero?\n  end\n\n  def local_domain?(domain)\n    domain.nil? || domain.gsub(/[\\/]/, '').casecmp(Rails.configuration.x.local_domain).zero?\n  end\n\n  def normalize_domain(domain)\n    return if domain.nil?\n\n    uri = Addressable::URI.new\n    uri.host = domain.gsub(/[\\/]/, '')\n    uri.normalized_host\n  end\n\n  def same_acct?(canonical, needle)\n    return true if canonical.casecmp(needle).zero?\n    username, domain = needle.split('@')\n    local_domain?(domain) && canonical.casecmp(username).zero?\n  end\n\n  def local_url?(url)\n    uri    = Addressable::URI.parse(url).normalize\n    domain = uri.host + (uri.port ? \":#{uri.port}\" : '')\n    TagManager.instance.web_domain?(domain)\n  end\n\n  def url_for(target)\n    return target.url if target.respond_to?(:local?) && !target.local?\n\n    case target.object_type\n    when :person\n      short_account_url(target)\n    when :note, :comment, :activity\n      short_account_status_url(target.account, target)\n    end\n  end\nend\n"
  },
  {
    "path": "app/lib/themes.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'singleton'\nrequire 'yaml'\n\nclass Themes\n  include Singleton\n\n  def initialize\n    @conf = YAML.load_file(Rails.root.join('config', 'themes.yml'))\n  end\n\n  def names\n    @conf.keys\n  end\nend\n"
  },
  {
    "path": "app/lib/user_settings_decorator.rb",
    "content": "# frozen_string_literal: true\n\nclass UserSettingsDecorator\n  attr_reader :user, :settings\n\n  def initialize(user)\n    @user = user\n  end\n\n  def update(settings)\n    @settings = settings\n    process_update\n  end\n\n  private\n\n  def process_update\n    user.settings['notification_emails'] = merged_notification_emails if change?('notification_emails')\n    user.settings['interactions']        = merged_interactions if change?('interactions')\n    user.settings['default_privacy']     = default_privacy_preference if change?('setting_default_privacy')\n    user.settings['default_sensitive']   = default_sensitive_preference if change?('setting_default_sensitive')\n    user.settings['default_language']    = default_language_preference if change?('setting_default_language')\n    user.settings['unfollow_modal']      = unfollow_modal_preference if change?('setting_unfollow_modal')\n    user.settings['boost_modal']         = boost_modal_preference if change?('setting_boost_modal')\n    user.settings['delete_modal']        = delete_modal_preference if change?('setting_delete_modal')\n    user.settings['auto_play_gif']       = auto_play_gif_preference if change?('setting_auto_play_gif')\n    user.settings['display_media']       = display_media_preference if change?('setting_display_media')\n    user.settings['expand_spoilers']     = expand_spoilers_preference if change?('setting_expand_spoilers')\n    user.settings['reduce_motion']       = reduce_motion_preference if change?('setting_reduce_motion')\n    user.settings['system_font_ui']      = system_font_ui_preference if change?('setting_system_font_ui')\n    user.settings['noindex']             = noindex_preference if change?('setting_noindex')\n    user.settings['theme']               = theme_preference if change?('setting_theme')\n    user.settings['hide_network']        = hide_network_preference if change?('setting_hide_network')\n    user.settings['aggregate_reblogs']   = aggregate_reblogs_preference if change?('setting_aggregate_reblogs')\n    user.settings['home_dms']            = home_dms_preference if change?('setting_home_dms')\n    user.settings['show_application']    = show_application_preference if change?('setting_show_application')\n    user.settings['advanced_layout']     = advanced_layout_preference if change?('setting_advanced_layout')\n  end\n\n  def merged_notification_emails\n    user.settings['notification_emails'].merge coerced_settings('notification_emails').to_h\n  end\n\n  def merged_interactions\n    user.settings['interactions'].merge coerced_settings('interactions').to_h\n  end\n\n  def default_privacy_preference\n    settings['setting_default_privacy']\n  end\n\n  def default_sensitive_preference\n    boolean_cast_setting 'setting_default_sensitive'\n  end\n\n  def unfollow_modal_preference\n    boolean_cast_setting 'setting_unfollow_modal'\n  end\n\n  def boost_modal_preference\n    boolean_cast_setting 'setting_boost_modal'\n  end\n\n  def delete_modal_preference\n    boolean_cast_setting 'setting_delete_modal'\n  end\n\n  def system_font_ui_preference\n    boolean_cast_setting 'setting_system_font_ui'\n  end\n\n  def auto_play_gif_preference\n    boolean_cast_setting 'setting_auto_play_gif'\n  end\n\n  def display_media_preference\n    settings['setting_display_media']\n  end\n\n  def expand_spoilers_preference\n    boolean_cast_setting 'setting_expand_spoilers'\n  end\n\n  def reduce_motion_preference\n    boolean_cast_setting 'setting_reduce_motion'\n  end\n\n  def noindex_preference\n    boolean_cast_setting 'setting_noindex'\n  end\n\n  def hide_network_preference\n    boolean_cast_setting 'setting_hide_network'\n  end\n\n  def show_application_preference\n    boolean_cast_setting 'setting_show_application'\n  end\n\n  def theme_preference\n    settings['setting_theme']\n  end\n\n  def default_language_preference\n    settings['setting_default_language']\n  end\n\n  def aggregate_reblogs_preference\n    boolean_cast_setting 'setting_aggregate_reblogs'\n  end\n\n  def advanced_layout_preference\n    boolean_cast_setting 'setting_advanced_layout'\n  end\n\n  def boolean_cast_setting(key)\n    ActiveModel::Type::Boolean.new.cast(settings[key])\n  end\n\n  def coerced_settings(key)\n    coerce_values settings.fetch(key, {})\n  end\n\n  def coerce_values(params_hash)\n    params_hash.transform_values { |x| ActiveModel::Type::Boolean.new.cast(x) }\n  end\n\n  def change?(key)\n    !settings[key].nil?\n  end\nend\n"
  },
  {
    "path": "app/lib/webfinger_resource.rb",
    "content": "# frozen_string_literal: true\n\nclass WebfingerResource\n  attr_reader :resource\n\n  def initialize(resource)\n    @resource = resource\n  end\n\n  def username\n    case resource\n    when /\\Ahttps?/i\n      username_from_url\n    when /\\@/\n      username_from_acct\n    else\n      raise(ActiveRecord::RecordNotFound)\n    end\n  end\n\n  private\n\n  def username_from_url\n    if account_show_page?\n      path_params[:username]\n    else\n      raise ActiveRecord::RecordNotFound\n    end\n  end\n\n  def account_show_page?\n    path_params[:controller] == 'accounts' && path_params[:action] == 'show'\n  end\n\n  def path_params\n    Rails.application.routes.recognize_path(resource)\n  end\n\n  def username_from_acct\n    if domain_matches_local?\n      local_username\n    else\n      raise ActiveRecord::RecordNotFound\n    end\n  end\n\n  def split_acct\n    resource_without_acct_string.split('@')\n  end\n\n  def resource_without_acct_string\n    resource.gsub(/\\Aacct:/, '')\n  end\n\n  def local_username\n    split_acct.first\n  end\n\n  def local_domain\n    split_acct.last\n  end\n\n  def domain_matches_local?\n    TagManager.instance.local_domain?(local_domain) || TagManager.instance.web_domain?(local_domain)\n  end\nend\n"
  },
  {
    "path": "app/mailers/admin_mailer.rb",
    "content": "# frozen_string_literal: true\n\nclass AdminMailer < ApplicationMailer\n  layout 'plain_mailer'\n\n  helper :stream_entries\n\n  def new_report(recipient, report)\n    @report   = report\n    @me       = recipient\n    @instance = Rails.configuration.x.local_domain\n\n    locale_for_account(@me) do\n      mail to: @me.user_email, subject: I18n.t('admin_mailer.new_report.subject', instance: @instance, id: @report.id)\n    end\n  end\n\n  def new_pending_account(recipient, user)\n    @account  = user.account\n    @me       = recipient\n    @instance = Rails.configuration.x.local_domain\n\n    locale_for_account(@me) do\n      mail to: @me.user_email, subject: I18n.t('admin_mailer.new_pending_account.subject', instance: @instance, username: @account.username)\n    end\n  end\nend\n"
  },
  {
    "path": "app/mailers/application_mailer.rb",
    "content": "# frozen_string_literal: true\n\nclass ApplicationMailer < ActionMailer::Base\n  layout 'mailer'\n\n  helper :application\n  helper :instance\n\n  protected\n\n  def locale_for_account(account)\n    I18n.with_locale(account.user_locale || I18n.default_locale) do\n      yield\n    end\n  end\nend\n"
  },
  {
    "path": "app/mailers/notification_mailer.rb",
    "content": "# frozen_string_literal: true\n\nclass NotificationMailer < ApplicationMailer\n  helper :stream_entries\n\n  add_template_helper RoutingHelper\n\n  def mention(recipient, notification)\n    @me     = recipient\n    @status = notification.target_status\n\n    return if @me.user.disabled? || @status.nil?\n\n    locale_for_account(@me) do\n      thread_by_conversation(@status.conversation)\n      mail to: @me.user.email, subject: I18n.t('notification_mailer.mention.subject', name: @status.account.acct)\n    end\n  end\n\n  def follow(recipient, notification)\n    @me      = recipient\n    @account = notification.from_account\n\n    return if @me.user.disabled?\n\n    locale_for_account(@me) do\n      mail to: @me.user.email, subject: I18n.t('notification_mailer.follow.subject', name: @account.acct)\n    end\n  end\n\n  def favourite(recipient, notification)\n    @me      = recipient\n    @account = notification.from_account\n    @status  = notification.target_status\n\n    return if @me.user.disabled? || @status.nil?\n\n    locale_for_account(@me) do\n      thread_by_conversation(@status.conversation)\n      mail to: @me.user.email, subject: I18n.t('notification_mailer.favourite.subject', name: @account.acct)\n    end\n  end\n\n  def reblog(recipient, notification)\n    @me      = recipient\n    @account = notification.from_account\n    @status  = notification.target_status\n\n    return if @me.user.disabled? || @status.nil?\n\n    locale_for_account(@me) do\n      thread_by_conversation(@status.conversation)\n      mail to: @me.user.email, subject: I18n.t('notification_mailer.reblog.subject', name: @account.acct)\n    end\n  end\n\n  def follow_request(recipient, notification)\n    @me      = recipient\n    @account = notification.from_account\n\n    return if @me.user.disabled?\n\n    locale_for_account(@me) do\n      mail to: @me.user.email, subject: I18n.t('notification_mailer.follow_request.subject', name: @account.acct)\n    end\n  end\n\n  def digest(recipient, **opts)\n    return if recipient.user.disabled?\n\n    @me                  = recipient\n    @since               = opts[:since] || [@me.user.last_emailed_at, (@me.user.current_sign_in_at + 1.day)].compact.max\n    @notifications_count = Notification.where(account: @me, activity_type: 'Mention').where('created_at > ?', @since).count\n\n    return if @notifications_count.zero?\n\n    @notifications = Notification.where(account: @me, activity_type: 'Mention').where('created_at > ?', @since).limit(40)\n    @follows_since = Notification.where(account: @me, activity_type: 'Follow').where('created_at > ?', @since).count\n\n    locale_for_account(@me) do\n      mail to: @me.user.email,\n           subject: I18n.t(:subject, scope: [:notification_mailer, :digest], count: @notifications_count)\n    end\n  end\n\n  private\n\n  def thread_by_conversation(conversation)\n    return if conversation.nil?\n    msg_id = \"<conversation-#{conversation.id}.#{conversation.created_at.strftime('%Y-%m-%d')}@#{Rails.configuration.x.local_domain}>\"\n    headers['In-Reply-To'] = msg_id\n    headers['References'] = msg_id\n  end\nend\n"
  },
  {
    "path": "app/mailers/user_mailer.rb",
    "content": "# frozen_string_literal: true\n\nclass UserMailer < Devise::Mailer\n  layout 'mailer'\n\n  helper :application\n  helper :instance\n\n  add_template_helper RoutingHelper\n\n  def confirmation_instructions(user, token, **)\n    @resource = user\n    @token    = token\n    @instance = Rails.configuration.x.local_domain\n\n    return if @resource.disabled?\n\n    I18n.with_locale(@resource.locale || I18n.default_locale) do\n      mail to: @resource.unconfirmed_email.presence || @resource.email,\n           subject: I18n.t(@resource.pending_reconfirmation? ? 'devise.mailer.reconfirmation_instructions.subject' : 'devise.mailer.confirmation_instructions.subject', instance: @instance),\n           template_name: @resource.pending_reconfirmation? ? 'reconfirmation_instructions' : 'confirmation_instructions'\n    end\n  end\n\n  def reset_password_instructions(user, token, **)\n    @resource = user\n    @token    = token\n    @instance = Rails.configuration.x.local_domain\n\n    return if @resource.disabled?\n\n    I18n.with_locale(@resource.locale || I18n.default_locale) do\n      mail to: @resource.email, subject: I18n.t('devise.mailer.reset_password_instructions.subject')\n    end\n  end\n\n  def password_change(user, **)\n    @resource = user\n    @instance = Rails.configuration.x.local_domain\n\n    return if @resource.disabled?\n\n    I18n.with_locale(@resource.locale || I18n.default_locale) do\n      mail to: @resource.email, subject: I18n.t('devise.mailer.password_change.subject')\n    end\n  end\n\n  def email_changed(user, **)\n    @resource = user\n    @instance = Rails.configuration.x.local_domain\n\n    return if @resource.disabled?\n\n    I18n.with_locale(@resource.locale || I18n.default_locale) do\n      mail to: @resource.email, subject: I18n.t('devise.mailer.email_changed.subject')\n    end\n  end\n\n  def welcome(user)\n    @resource = user\n    @instance = Rails.configuration.x.local_domain\n\n    return if @resource.disabled?\n\n    I18n.with_locale(@resource.locale || I18n.default_locale) do\n      mail to: @resource.email, subject: I18n.t('user_mailer.welcome.subject')\n    end\n  end\n\n  def backup_ready(user, backup)\n    @resource = user\n    @instance = Rails.configuration.x.local_domain\n    @backup   = backup\n\n    return if @resource.disabled?\n\n    I18n.with_locale(@resource.locale || I18n.default_locale) do\n      mail to: @resource.email, subject: I18n.t('user_mailer.backup_ready.subject')\n    end\n  end\n\n  def warning(user, warning)\n    @resource = user\n    @warning  = warning\n    @instance = Rails.configuration.x.local_domain\n\n    I18n.with_locale(@resource.locale || I18n.default_locale) do\n      mail to: @resource.email,\n           subject: I18n.t(\"user_mailer.warning.subject.#{@warning.action}\", acct: \"@#{user.account.local_username_and_domain}\"),\n           reply_to: Setting.site_contact_email\n    end\n  end\nend\n"
  },
  {
    "path": "app/models/account.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: accounts\n#\n#  id                      :bigint(8)        not null, primary key\n#  username                :string           default(\"\"), not null\n#  domain                  :string\n#  secret                  :string           default(\"\"), not null\n#  private_key             :text\n#  public_key              :text             default(\"\"), not null\n#  remote_url              :string           default(\"\"), not null\n#  salmon_url              :string           default(\"\"), not null\n#  hub_url                 :string           default(\"\"), not null\n#  created_at              :datetime         not null\n#  updated_at              :datetime         not null\n#  note                    :text             default(\"\"), not null\n#  display_name            :string           default(\"\"), not null\n#  uri                     :string           default(\"\"), not null\n#  url                     :string\n#  avatar_file_name        :string\n#  avatar_content_type     :string\n#  avatar_file_size        :integer\n#  avatar_updated_at       :datetime\n#  header_file_name        :string\n#  header_content_type     :string\n#  header_file_size        :integer\n#  header_updated_at       :datetime\n#  avatar_remote_url       :string\n#  subscription_expires_at :datetime\n#  locked                  :boolean          default(FALSE), not null\n#  header_remote_url       :string           default(\"\"), not null\n#  last_webfingered_at     :datetime\n#  inbox_url               :string           default(\"\"), not null\n#  outbox_url              :string           default(\"\"), not null\n#  shared_inbox_url        :string           default(\"\"), not null\n#  followers_url           :string           default(\"\"), not null\n#  protocol                :integer          default(\"ostatus\"), not null\n#  memorial                :boolean          default(FALSE), not null\n#  moved_to_account_id     :bigint(8)\n#  featured_collection_url :string\n#  fields                  :jsonb\n#  actor_type              :string\n#  discoverable            :boolean\n#  also_known_as           :string           is an Array\n#  silenced_at             :datetime\n#  suspended_at            :datetime\n#\n\nclass Account < ApplicationRecord\n  USERNAME_RE = /[a-z0-9_]+([a-z0-9_\\.-]+[a-z0-9_]+)?/i\n  MENTION_RE  = /(?<=^|[^\\/[:word:]])@((#{USERNAME_RE})(?:@[a-z0-9\\.\\-]+[a-z0-9]+)?)/i\n  MIN_FOLLOWERS_DISCOVERY = 10\n\n  include AccountAssociations\n  include AccountAvatar\n  include AccountFinderConcern\n  include AccountHeader\n  include AccountInteractions\n  include Attachmentable\n  include Paginable\n  include AccountCounters\n  include DomainNormalizable\n\n  enum protocol: [:ostatus, :activitypub]\n\n  validates :username, presence: true\n\n  # Remote user validations\n  validates :username, uniqueness: { scope: :domain, case_sensitive: true }, if: -> { !local? && will_save_change_to_username? }\n  validates :username, format: { with: /\\A#{USERNAME_RE}\\z/i }, if: -> { !local? && will_save_change_to_username? }\n\n  # Local user validations\n  validates :username, format: { with: /\\A[a-z0-9_]+\\z/i }, length: { maximum: 30 }, if: -> { local? && will_save_change_to_username? }\n  validates_with UniqueUsernameValidator, if: -> { local? && will_save_change_to_username? }\n  validates_with UnreservedUsernameValidator, if: -> { local? && will_save_change_to_username? }\n  validates :display_name, length: { maximum: 30 }, if: -> { local? && will_save_change_to_display_name? }\n  validates :note, note_length: { maximum: Setting.max_bio_chars.to_i }, if: -> { local? && will_save_change_to_note? }\n  validates :fields, length: { maximum: 4 }, if: -> { local? && will_save_change_to_fields? }\n\n  scope :remote, -> { where.not(domain: nil) }\n  scope :local, -> { where(domain: nil) }\n  scope :expiring, ->(time) { remote.where.not(subscription_expires_at: nil).where('subscription_expires_at < ?', time) }\n  scope :partitioned, -> { order(Arel.sql('row_number() over (partition by domain)')) }\n  scope :silenced, -> { where.not(silenced_at: nil) }\n  scope :suspended, -> { where.not(suspended_at: nil) }\n  scope :without_suspended, -> { where(suspended_at: nil) }\n  scope :without_silenced, -> { where(silenced_at: nil) }\n  scope :recent, -> { reorder(id: :desc) }\n  scope :bots, -> { where(actor_type: %w(Application Service)) }\n  scope :alphabetic, -> { order(domain: :asc, username: :asc) }\n  scope :by_domain_accounts, -> { group(:domain).select(:domain, 'COUNT(*) AS accounts_count').order('accounts_count desc') }\n  scope :matches_username, ->(value) { where(arel_table[:username].matches(\"#{value}%\")) }\n  scope :matches_display_name, ->(value) { where(arel_table[:display_name].matches(\"#{value}%\")) }\n  scope :matches_domain, ->(value) { where(arel_table[:domain].matches(\"%#{value}%\")) }\n  scope :searchable, -> { without_suspended.where(moved_to_account_id: nil) }\n  scope :discoverable, -> { searchable.without_silenced.where(discoverable: true).joins(:account_stat).where(AccountStat.arel_table[:followers_count].gteq(MIN_FOLLOWERS_DISCOVERY)) }\n  scope :tagged_with, ->(tag) { joins(:accounts_tags).where(accounts_tags: { tag_id: tag }) }\n  scope :by_recent_status, -> { order(Arel.sql('(case when account_stats.last_status_at is null then 1 else 0 end) asc, account_stats.last_status_at desc')) }\n  scope :popular, -> { order('account_stats.followers_count desc') }\n\n  delegate :email,\n           :unconfirmed_email,\n           :current_sign_in_ip,\n           :current_sign_in_at,\n           :confirmed?,\n           :approved?,\n           :pending?,\n           :admin?,\n           :moderator?,\n           :staff?,\n           :locale,\n           :hides_network?,\n           :shows_application?,\n           to: :user,\n           prefix: true,\n           allow_nil: true\n\n  delegate :chosen_languages, to: :user, prefix: false, allow_nil: true\n\n  def local?\n    domain.nil?\n  end\n\n  def moved?\n    moved_to_account_id.present?\n  end\n\n  def bot?\n    %w(Application Service).include? actor_type\n  end\n\n  alias bot bot?\n\n  def bot=(val)\n    self.actor_type = ActiveModel::Type::Boolean.new.cast(val) ? 'Service' : 'Person'\n  end\n\n  def acct\n    local? ? username : \"#{username}@#{domain}\"\n  end\n\n  def local_username_and_domain\n    \"#{username}@#{Rails.configuration.x.local_domain}\"\n  end\n\n  def local_followers_count\n    Follow.where(target_account_id: id).count\n  end\n\n  def to_webfinger_s\n    \"acct:#{local_username_and_domain}\"\n  end\n\n  def subscribed?\n    subscription_expires_at.present?\n  end\n\n  def possibly_stale?\n    last_webfingered_at.nil? || last_webfingered_at <= 1.day.ago\n  end\n\n  def refresh!\n    return if local?\n    ResolveAccountService.new.call(acct)\n  end\n\n  def silenced?\n    silenced_at.present?\n  end\n\n  def silence!(date = nil)\n    date ||= Time.now.utc\n    update!(silenced_at: date)\n  end\n\n  def unsilence!\n    update!(silenced_at: nil)\n  end\n\n  def suspended?\n    suspended_at.present?\n  end\n\n  def suspend!(date = nil)\n    date ||= Time.now.utc\n    transaction do\n      user&.disable! if local?\n      update!(suspended_at: date)\n    end\n  end\n\n  def unsuspend!\n    transaction do\n      user&.enable! if local?\n      update!(suspended_at: nil)\n    end\n  end\n\n  def memorialize!\n    transaction do\n      user&.disable! if local?\n      update!(memorial: true)\n    end\n  end\n\n  def sign?\n    true\n  end\n\n  def keypair\n    @keypair ||= OpenSSL::PKey::RSA.new(private_key || public_key)\n  end\n\n  def tags_as_strings=(tag_names)\n    tag_names.map! { |name| name.mb_chars.downcase.to_s }\n    tag_names.uniq!\n\n    # Existing hashtags\n    hashtags_map = Tag.where(name: tag_names).each_with_object({}) { |tag, h| h[tag.name] = tag }\n\n    # Initialize not yet existing hashtags\n    tag_names.each do |name|\n      next if hashtags_map.key?(name)\n      hashtags_map[name] = Tag.new(name: name)\n    end\n\n    # Remove hashtags that are to be deleted\n    tags.each do |tag|\n      if hashtags_map.key?(tag.name)\n        hashtags_map.delete(tag.name)\n      else\n        transaction do\n          tags.delete(tag)\n          tag.decrement_count!(:accounts_count)\n        end\n      end\n    end\n\n    # Add hashtags that were so far missing\n    hashtags_map.each_value do |tag|\n      transaction do\n        tags << tag\n        tag.increment_count!(:accounts_count)\n      end\n    end\n  end\n\n  def also_known_as\n    self[:also_known_as] || []\n  end\n\n  def fields\n    (self[:fields] || []).map { |f| Field.new(self, f) }\n  end\n\n  def fields_attributes=(attributes)\n    fields     = []\n    old_fields = self[:fields] || []\n    old_fields = [] if old_fields.is_a?(Hash)\n\n    if attributes.is_a?(Hash)\n      attributes.each_value do |attr|\n        next if attr[:name].blank?\n\n        previous = old_fields.find { |item| item['value'] == attr[:value] }\n\n        if previous && previous['verified_at'].present?\n          attr[:verified_at] = previous['verified_at']\n        end\n\n        fields << attr\n      end\n    end\n\n    self[:fields] = fields\n  end\n\n  DEFAULT_FIELDS_SIZE = 4\n\n  def build_fields\n    return if fields.size >= DEFAULT_FIELDS_SIZE\n\n    tmp = self[:fields] || []\n    tmp = [] if tmp.is_a?(Hash)\n\n    (DEFAULT_FIELDS_SIZE - tmp.size).times do\n      tmp << { name: '', value: '' }\n    end\n\n    self.fields = tmp\n  end\n\n  def magic_key\n    modulus, exponent = [keypair.public_key.n, keypair.public_key.e].map do |component|\n      result = []\n\n      until component.zero?\n        result << [component % 256].pack('C')\n        component >>= 8\n      end\n\n      result.reverse.join\n    end\n\n    (['RSA'] + [modulus, exponent].map { |n| Base64.urlsafe_encode64(n) }).join('.')\n  end\n\n  def subscription(webhook_url)\n    @subscription ||= OStatus2::Subscription.new(remote_url, secret: secret, webhook: webhook_url, hub: hub_url)\n  end\n\n  def save_with_optional_media!\n    save!\n  rescue ActiveRecord::RecordInvalid\n    self.avatar              = nil\n    self.header              = nil\n    self[:avatar_remote_url] = ''\n    self[:header_remote_url] = ''\n    save!\n  end\n\n  def object_type\n    :person\n  end\n\n  def to_param\n    username\n  end\n\n  def excluded_from_timeline_account_ids\n    Rails.cache.fetch(\"exclude_account_ids_for:#{id}\") { blocking.pluck(:target_account_id) + blocked_by.pluck(:account_id) + muting.pluck(:target_account_id) }\n  end\n\n  def excluded_from_timeline_domains\n    Rails.cache.fetch(\"exclude_domains_for:#{id}\") { domain_blocks.pluck(:domain) }\n  end\n\n  def preferred_inbox_url\n    shared_inbox_url.presence || inbox_url\n  end\n\n  class Field < ActiveModelSerializers::Model\n    attributes :name, :value, :verified_at, :account, :errors\n\n    def initialize(account, attributes)\n      @account     = account\n      @attributes  = attributes\n      @name        = attributes['name'].strip[0, string_limit]\n      @value       = attributes['value'].strip[0, string_limit]\n      @verified_at = attributes['verified_at']&.to_datetime\n      @errors      = {}\n    end\n\n    def verified?\n      verified_at.present?\n    end\n\n    def value_for_verification\n      @value_for_verification ||= begin\n        if account.local?\n          value\n        else\n          ActionController::Base.helpers.strip_tags(value)\n        end\n      end\n    end\n\n    def verifiable?\n      value_for_verification.present? && value_for_verification.start_with?('http://', 'https://')\n    end\n\n    def mark_verified!\n      @verified_at = Time.now.utc\n      @attributes['verified_at'] = @verified_at\n    end\n\n    def to_h\n      { name: @name, value: @value, verified_at: @verified_at }\n    end\n\n    private\n\n    def string_limit\n      if account.local?\n        255\n      else\n        2047\n      end\n    end\n  end\n\n  class << self\n    def readonly_attributes\n      super - %w(statuses_count following_count followers_count)\n    end\n\n    def domains\n      reorder(nil).pluck(Arel.sql('distinct accounts.domain'))\n    end\n\n    def inboxes\n      urls = reorder(nil).where(protocol: :activitypub).pluck(Arel.sql(\"distinct coalesce(nullif(accounts.shared_inbox_url, ''), accounts.inbox_url)\"))\n      DeliveryFailureTracker.filter(urls)\n    end\n\n    def search_for(terms, limit = 10, offset = 0)\n      textsearch, query = generate_query_for_search(terms)\n\n      sql = <<-SQL.squish\n        SELECT\n          accounts.*,\n          ts_rank_cd(#{textsearch}, #{query}, 32) AS rank\n        FROM accounts\n        WHERE #{query} @@ #{textsearch}\n          AND accounts.suspended_at IS NULL\n          AND accounts.moved_to_account_id IS NULL\n        ORDER BY rank DESC\n        LIMIT ? OFFSET ?\n      SQL\n\n      records = find_by_sql([sql, limit, offset])\n      ActiveRecord::Associations::Preloader.new.preload(records, :account_stat)\n      records\n    end\n\n    def advanced_search_for(terms, account, limit = 10, following = false, offset = 0)\n      textsearch, query = generate_query_for_search(terms)\n\n      if following\n        sql = <<-SQL.squish\n          WITH first_degree AS (\n            SELECT target_account_id\n            FROM follows\n            WHERE account_id = ?\n          )\n          SELECT\n            accounts.*,\n            (count(f.id) + 1) * ts_rank_cd(#{textsearch}, #{query}, 32) AS rank\n          FROM accounts\n          LEFT OUTER JOIN follows AS f ON (accounts.id = f.account_id AND f.target_account_id = ?) OR (accounts.id = f.target_account_id AND f.account_id = ?)\n          WHERE accounts.id IN (SELECT * FROM first_degree)\n            AND #{query} @@ #{textsearch}\n            AND accounts.suspended_at IS NULL\n            AND accounts.moved_to_account_id IS NULL\n          GROUP BY accounts.id\n          ORDER BY rank DESC\n          LIMIT ? OFFSET ?\n        SQL\n\n        records = find_by_sql([sql, account.id, account.id, account.id, limit, offset])\n      else\n        sql = <<-SQL.squish\n          SELECT\n            accounts.*,\n            (count(f.id) + 1) * ts_rank_cd(#{textsearch}, #{query}, 32) AS rank\n          FROM accounts\n          LEFT OUTER JOIN follows AS f ON (accounts.id = f.account_id AND f.target_account_id = ?) OR (accounts.id = f.target_account_id AND f.account_id = ?)\n          WHERE #{query} @@ #{textsearch}\n            AND accounts.suspended_at IS NULL\n            AND accounts.moved_to_account_id IS NULL\n          GROUP BY accounts.id\n          ORDER BY rank DESC\n          LIMIT ? OFFSET ?\n        SQL\n\n        records = find_by_sql([sql, account.id, account.id, limit, offset])\n      end\n\n      ActiveRecord::Associations::Preloader.new.preload(records, :account_stat)\n      records\n    end\n\n    private\n\n    def generate_query_for_search(terms)\n      terms      = Arel.sql(connection.quote(terms.gsub(/['?\\\\:]/, ' ')))\n      textsearch = \"(setweight(to_tsvector('simple', accounts.display_name), 'A') || setweight(to_tsvector('simple', accounts.username), 'B') || setweight(to_tsvector('simple', coalesce(accounts.domain, '')), 'C'))\"\n      query      = \"to_tsquery('simple', ''' ' || #{terms} || ' ''' || ':*')\"\n\n      [textsearch, query]\n    end\n  end\n\n  def emojis\n    @emojis ||= CustomEmoji.from_text(emojifiable_text, domain)\n  end\n\n  before_create :generate_keys\n  before_validation :prepare_contents, if: :local?\n  before_validation :prepare_username, on: :create\n  before_destroy :clean_feed_manager\n\n  private\n\n  def prepare_contents\n    display_name&.strip!\n    note&.strip!\n  end\n\n  def prepare_username\n    username&.squish!\n  end\n\n  def generate_keys\n    return unless local? && !Rails.env.test?\n\n    keypair = OpenSSL::PKey::RSA.new(2048)\n    self.private_key = keypair.to_pem\n    self.public_key  = keypair.public_key.to_pem\n  end\n\n  def normalize_domain\n    return if local?\n\n    super\n  end\n\n  def emojifiable_text\n    [note, display_name, fields.map(&:value)].join(' ')\n  end\n\n  def clean_feed_manager\n    reblog_key       = FeedManager.instance.key(:home, id, 'reblogs')\n    reblogged_id_set = Redis.current.zrange(reblog_key, 0, -1)\n\n    Redis.current.pipelined do\n      Redis.current.del(FeedManager.instance.key(:home, id))\n      Redis.current.del(reblog_key)\n\n      reblogged_id_set.each do |reblogged_id|\n        reblog_set_key = FeedManager.instance.key(:home, id, \"reblogs:#{reblogged_id}\")\n        Redis.current.del(reblog_set_key)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "app/models/account_conversation.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: account_conversations\n#\n#  id                      :bigint(8)        not null, primary key\n#  account_id              :bigint(8)\n#  conversation_id         :bigint(8)\n#  participant_account_ids :bigint(8)        default([]), not null, is an Array\n#  status_ids              :bigint(8)        default([]), not null, is an Array\n#  last_status_id          :bigint(8)\n#  lock_version            :integer          default(0), not null\n#  unread                  :boolean          default(FALSE), not null\n#\n\nclass AccountConversation < ApplicationRecord\n  after_commit :push_to_streaming_api\n\n  belongs_to :account\n  belongs_to :conversation\n  belongs_to :last_status, class_name: 'Status'\n\n  before_validation :set_last_status\n\n  def participant_account_ids=(arr)\n    self[:participant_account_ids] = arr.sort\n  end\n\n  def participant_accounts\n    if participant_account_ids.empty?\n      [account]\n    else\n      participants = Account.where(id: participant_account_ids)\n      participants.empty? ? [account] : participants\n    end\n  end\n\n  class << self\n    def paginate_by_id(limit, options = {})\n      if options[:min_id]\n        paginate_by_min_id(limit, options[:min_id]).reverse\n      else\n        paginate_by_max_id(limit, options[:max_id], options[:since_id])\n      end\n    end\n\n    def paginate_by_min_id(limit, min_id = nil)\n      query = order(arel_table[:last_status_id].asc).limit(limit)\n      query = query.where(arel_table[:last_status_id].gt(min_id)) if min_id.present?\n      query\n    end\n\n    def paginate_by_max_id(limit, max_id = nil, since_id = nil)\n      query = order(arel_table[:last_status_id].desc).limit(limit)\n      query = query.where(arel_table[:last_status_id].lt(max_id)) if max_id.present?\n      query = query.where(arel_table[:last_status_id].gt(since_id)) if since_id.present?\n      query\n    end\n\n    def add_status(recipient, status)\n      conversation = find_or_initialize_by(account: recipient, conversation_id: status.conversation_id, participant_account_ids: participants_from_status(recipient, status))\n\n      return conversation if conversation.status_ids.include?(status.id)\n\n      conversation.status_ids << status.id\n      conversation.unread = status.account_id != recipient.id\n      conversation.save\n      conversation\n    rescue ActiveRecord::StaleObjectError\n      retry\n    end\n\n    def remove_status(recipient, status)\n      conversation = find_by(account: recipient, conversation_id: status.conversation_id, participant_account_ids: participants_from_status(recipient, status))\n\n      return if conversation.nil?\n\n      conversation.status_ids.delete(status.id)\n\n      if conversation.status_ids.empty?\n        conversation.destroy\n      else\n        conversation.save\n      end\n\n      conversation\n    rescue ActiveRecord::StaleObjectError\n      retry\n    end\n\n    private\n\n    def participants_from_status(recipient, status)\n      ((status.active_mentions.pluck(:account_id) + [status.account_id]).uniq - [recipient.id]).sort\n    end\n  end\n\n  private\n\n  def set_last_status\n    self.status_ids     = status_ids.sort\n    self.last_status_id = status_ids.last\n  end\n\n  def push_to_streaming_api\n    return if destroyed? || !subscribed_to_timeline?\n    PushConversationWorker.perform_async(id)\n  end\n\n  def subscribed_to_timeline?\n    Redis.current.exists(\"subscribed:#{streaming_channel}\")\n  end\n\n  def streaming_channel\n    \"timeline:direct:#{account_id}\"\n  end\nend\n"
  },
  {
    "path": "app/models/account_domain_block.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: account_domain_blocks\n#\n#  id         :bigint(8)        not null, primary key\n#  domain     :string\n#  created_at :datetime         not null\n#  updated_at :datetime         not null\n#  account_id :bigint(8)\n#\n\nclass AccountDomainBlock < ApplicationRecord\n  include Paginable\n  include DomainNormalizable\n\n  belongs_to :account\n  validates :domain, presence: true, uniqueness: { scope: :account_id }\n\n  after_commit :remove_blocking_cache\n  after_commit :remove_relationship_cache\n\n  private\n\n  def remove_blocking_cache\n    Rails.cache.delete(\"exclude_domains_for:#{account_id}\")\n  end\n\n  def remove_relationship_cache\n    Rails.cache.delete_matched(\"relationship:#{account_id}:*\")\n  end\nend\n"
  },
  {
    "path": "app/models/account_filter.rb",
    "content": "# frozen_string_literal: true\n\nclass AccountFilter\n  attr_reader :params\n\n  def initialize(params)\n    @params = params\n    set_defaults!\n  end\n\n  def results\n    scope = Account.recent.includes(:user)\n\n    params.each do |key, value|\n      scope.merge!(scope_for(key, value.to_s.strip)) if value.present?\n    end\n\n    scope\n  end\n\n  private\n\n  def set_defaults!\n    params['local']  = '1' if params['remote'].blank?\n    params['active'] = '1' if params['suspended'].blank? && params['silenced'].blank? && params['pending'].blank?\n  end\n\n  def scope_for(key, value)\n    case key.to_s\n    when 'local'\n      Account.local\n    when 'remote'\n      Account.remote\n    when 'by_domain'\n      Account.where(domain: value)\n    when 'active'\n      Account.without_suspended\n    when 'pending'\n      accounts_with_users.merge User.pending\n    when 'silenced'\n      Account.silenced\n    when 'suspended'\n      Account.suspended\n    when 'username'\n      Account.matches_username(value)\n    when 'display_name'\n      Account.matches_display_name(value)\n    when 'email'\n      accounts_with_users.merge User.matches_email(value)\n    when 'ip'\n      valid_ip?(value) ? accounts_with_users.where('users.current_sign_in_ip <<= ?', value) : Account.none\n    when 'staff'\n      accounts_with_users.merge User.staff\n    else\n      raise \"Unknown filter: #{key}\"\n    end\n  end\n\n  def accounts_with_users\n    Account.joins(:user)\n  end\n\n  def valid_ip?(value)\n    IPAddr.new(value) && true\n  rescue IPAddr::InvalidAddressError\n    false\n  end\nend\n"
  },
  {
    "path": "app/models/account_identity_proof.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: account_identity_proofs\n#\n#  id                :bigint(8)        not null, primary key\n#  account_id        :bigint(8)\n#  provider          :string           default(\"\"), not null\n#  provider_username :string           default(\"\"), not null\n#  token             :text             default(\"\"), not null\n#  verified          :boolean          default(FALSE), not null\n#  live              :boolean          default(FALSE), not null\n#  created_at        :datetime         not null\n#  updated_at        :datetime         not null\n#\n\nclass AccountIdentityProof < ApplicationRecord\n  belongs_to :account\n\n  validates :provider, inclusion: { in: ProofProvider::SUPPORTED_PROVIDERS }\n  validates :provider_username, format: { with: /\\A[a-z0-9_]+\\z/i }, length: { minimum: 2, maximum: 30 }\n  validates :provider_username, uniqueness: { scope: [:account_id, :provider] }\n  validates :token, format: { with: /\\A[a-f0-9]+\\z/ }, length: { maximum: 66 }\n\n  validate :validate_with_provider, if: :token_changed?\n\n  scope :active, -> { where(verified: true, live: true) }\n\n  after_commit :queue_worker, if: :saved_change_to_token?\n\n  delegate :refresh!, :on_success_path, :badge, to: :provider_instance\n\n  def provider_instance\n    @provider_instance ||= ProofProvider.find(provider, self)\n  end\n\n  private\n\n  def queue_worker\n    provider_instance.worker_class.perform_async(id)\n  end\n\n  def validate_with_provider\n    provider_instance.validate!\n  end\nend\n"
  },
  {
    "path": "app/models/account_moderation_note.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: account_moderation_notes\n#\n#  id                :bigint(8)        not null, primary key\n#  content           :text             not null\n#  account_id        :bigint(8)        not null\n#  target_account_id :bigint(8)        not null\n#  created_at        :datetime         not null\n#  updated_at        :datetime         not null\n#\n\nclass AccountModerationNote < ApplicationRecord\n  belongs_to :account\n  belongs_to :target_account, class_name: 'Account'\n\n  scope :latest, -> { reorder('created_at DESC') }\n\n  validates :content, presence: true, length: { maximum: 500 }\nend\n"
  },
  {
    "path": "app/models/account_pin.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: account_pins\n#\n#  id                :bigint(8)        not null, primary key\n#  account_id        :bigint(8)\n#  target_account_id :bigint(8)\n#  created_at        :datetime         not null\n#  updated_at        :datetime         not null\n#\n\nclass AccountPin < ApplicationRecord\n  include Paginable\n  include RelationshipCacheable\n\n  belongs_to :account\n  belongs_to :target_account, class_name: 'Account'\n\n  validate :validate_follow_relationship\n\n  private\n\n  def validate_follow_relationship\n    errors.add(:base, I18n.t('accounts.pin_errors.following')) unless account.following?(target_account)\n  end\nend\n"
  },
  {
    "path": "app/models/account_stat.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: account_stats\n#\n#  id              :bigint(8)        not null, primary key\n#  account_id      :bigint(8)        not null\n#  statuses_count  :bigint(8)        default(0), not null\n#  following_count :bigint(8)        default(0), not null\n#  followers_count :bigint(8)        default(0), not null\n#  created_at      :datetime         not null\n#  updated_at      :datetime         not null\n#  last_status_at  :datetime\n#\n\nclass AccountStat < ApplicationRecord\n  belongs_to :account, inverse_of: :account_stat\n\n  def increment_count!(key)\n    update(attributes_for_increment(key))\n  end\n\n  def decrement_count!(key)\n    update(key => [public_send(key) - 1, 0].max)\n  end\n\n  private\n\n  def attributes_for_increment(key)\n    attrs = { key => public_send(key) + 1 }\n    attrs[:last_status_at] = Time.now.utc if key == :statuses_count\n    attrs\n  end\nend\n"
  },
  {
    "path": "app/models/account_tag_stat.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: account_tag_stats\n#\n#  id             :bigint(8)        not null, primary key\n#  tag_id         :bigint(8)        not null\n#  accounts_count :bigint(8)        default(0), not null\n#  hidden         :boolean          default(FALSE), not null\n#  created_at     :datetime         not null\n#  updated_at     :datetime         not null\n#\n\nclass AccountTagStat < ApplicationRecord\n  belongs_to :tag, inverse_of: :account_tag_stat\n\n  def increment_count!(key)\n    update(key => public_send(key) + 1)\n  end\n\n  def decrement_count!(key)\n    update(key => [public_send(key) - 1, 0].max)\n  end\nend\n"
  },
  {
    "path": "app/models/account_warning.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: account_warnings\n#\n#  id                :bigint(8)        not null, primary key\n#  account_id        :bigint(8)\n#  target_account_id :bigint(8)\n#  action            :integer          default(\"none\"), not null\n#  text              :text             default(\"\"), not null\n#  created_at        :datetime         not null\n#  updated_at        :datetime         not null\n#\n\nclass AccountWarning < ApplicationRecord\n  enum action: %i(none disable silence suspend), _suffix: :action\n\n  belongs_to :account, inverse_of: :account_warnings\n  belongs_to :target_account, class_name: 'Account', inverse_of: :targeted_account_warnings\n\n  scope :latest, -> { order(created_at: :desc) }\n  scope :custom, -> { where.not(text: '') }\nend\n"
  },
  {
    "path": "app/models/account_warning_preset.rb",
    "content": "# frozen_string_literal: true\n\n# == Schema Information\n#\n# Table name: account_warning_presets\n#\n#  id         :bigint(8)        not null, primary key\n#  text       :text             default(\"\"), not null\n#  created_at :datetime         not null\n#  updated_at :datetime         not null\n#\n\nclass AccountWarningPreset < ApplicationRecord\n  validates :text, presence: true\nend\n"
  },
  {
    "path": "app/models/admin/account_action.rb",
    "content": "# frozen_string_literal: true\n\nclass Admin::AccountAction\n  include ActiveModel::Model\n  include AccountableConcern\n  include Authorization\n\n  TYPES = %w(\n    none\n    disable\n    silence\n    suspend\n  ).freeze\n\n  attr_accessor :target_account,\n                :current_account,\n                :type,\n                :text,\n                :report_id,\n                :warning_preset_id,\n                :send_email_notification\n\n  attr_reader :warning\n\n  def save!\n    ApplicationRecord.transaction do\n      process_action!\n      process_warning!\n    end\n\n    queue_email!\n    process_reports!\n  end\n\n  def report\n    @report ||= Report.find(report_id) if report_id.present?\n  end\n\n  def with_report?\n    !report.nil?\n  end\n\n  class << self\n    def types_for_account(account)\n      if account.local?\n        TYPES\n      else\n        TYPES - %w(none disable)\n      end\n    end\n  end\n\n  private\n\n  def process_action!\n    case type\n    when 'disable'\n      handle_disable!\n    when 'silence'\n      handle_silence!\n    when 'suspend'\n      handle_suspend!\n    end\n  end\n\n  def process_warning!\n    return unless warnable?\n\n    authorize(target_account, :warn?)\n\n    @warning = AccountWarning.create!(target_account: target_account,\n                                      account: current_account,\n                                      action: type,\n                                      text: text_for_warning)\n\n    # A log entry is only interesting if the warning contains\n    # custom text from someone. Otherwise it's just noise.\n    log_action(:create, warning) if warning.text.present?\n  end\n\n  def process_reports!\n    return if report_id.blank?\n\n    authorize(report, :update?)\n\n    if type == 'none'\n      log_action(:resolve, report)\n      report.resolve!(current_account)\n    else\n      Report.where(target_account: target_account).unresolved.update_all(action_taken: true, action_taken_by_account_id: current_account.id)\n    end\n  end\n\n  def handle_disable!\n    authorize(target_account.user, :disable?)\n    log_action(:disable, target_account.user)\n    target_account.user&.disable!\n  end\n\n  def handle_silence!\n    authorize(target_account, :silence?)\n    log_action(:silence, target_account)\n    target_account.silence!\n  end\n\n  def handle_suspend!\n    authorize(target_account, :suspend?)\n    log_action(:suspend, target_account)\n    target_account.suspend!\n    queue_suspension_worker!\n  end\n\n  def text_for_warning\n    [warning_preset&.text, text].compact.join(\"\\n\\n\")\n  end\n\n  def queue_suspension_worker!\n    Admin::SuspensionWorker.perform_async(target_account.id)\n  end\n\n  def queue_email!\n    return unless warnable?\n\n    UserMailer.warning(target_account.user, warning).deliver_later!\n  end\n\n  def warnable?\n    send_email_notification && target_account.local?\n  end\n\n  def warning_preset\n    @warning_preset ||= AccountWarningPreset.find(warning_preset_id) if warning_preset_id.present?\n  end\nend\n"
  },
  {
    "path": "app/models/admin/action_log.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: admin_action_logs\n#\n#  id               :bigint(8)        not null, primary key\n#  account_id       :bigint(8)\n#  action           :string           default(\"\"), not null\n#  target_type      :string\n#  target_id        :bigint(8)\n#  recorded_changes :text             default(\"\"), not null\n#  created_at       :datetime         not null\n#  updated_at       :datetime         not null\n#\n\nclass Admin::ActionLog < ApplicationRecord\n  serialize :recorded_changes\n\n  belongs_to :account\n  belongs_to :target, polymorphic: true\n\n  default_scope -> { order('id desc') }\n\n  def action\n    super.to_sym\n  end\n\n  before_validation :set_changes\n\n  private\n\n  def set_changes\n    case action\n    when :destroy, :create\n      self.recorded_changes = target.attributes\n    when :update, :promote, :demote\n      self.recorded_changes = target.previous_changes\n    when :change_email\n      self.recorded_changes = ActiveSupport::HashWithIndifferentAccess.new(\n        email: [target.email, nil],\n        unconfirmed_email: [nil, target.unconfirmed_email]\n      )\n    end\n  end\nend\n"
  },
  {
    "path": "app/models/admin.rb",
    "content": "# frozen_string_literal: true\n\nmodule Admin\n  def self.table_name_prefix\n    'admin_'\n  end\nend\n"
  },
  {
    "path": "app/models/application_record.rb",
    "content": "# frozen_string_literal: true\n\nclass ApplicationRecord < ActiveRecord::Base\n  self.abstract_class = true\n  include Remotable\nend\n"
  },
  {
    "path": "app/models/backup.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: backups\n#\n#  id                :bigint(8)        not null, primary key\n#  user_id           :bigint(8)\n#  dump_file_name    :string\n#  dump_content_type :string\n#  dump_file_size    :integer\n#  dump_updated_at   :datetime\n#  processed         :boolean          default(FALSE), not null\n#  created_at        :datetime         not null\n#  updated_at        :datetime         not null\n#\n\nclass Backup < ApplicationRecord\n  belongs_to :user, inverse_of: :backups\n\n  has_attached_file :dump\n  do_not_validate_attachment_file_type :dump\nend\n"
  },
  {
    "path": "app/models/block.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: blocks\n#\n#  id                :bigint(8)        not null, primary key\n#  created_at        :datetime         not null\n#  updated_at        :datetime         not null\n#  account_id        :bigint(8)        not null\n#  target_account_id :bigint(8)        not null\n#  uri               :string\n#\n\nclass Block < ApplicationRecord\n  include Paginable\n  include RelationshipCacheable\n\n  belongs_to :account\n  belongs_to :target_account, class_name: 'Account'\n\n  validates :account_id, uniqueness: { scope: :target_account_id }\n\n  def local?\n    false # Force uri_for to use uri attribute\n  end\n\n  after_commit :remove_blocking_cache\n  before_validation :set_uri, only: :create\n\n  private\n\n  def remove_blocking_cache\n    Rails.cache.delete(\"exclude_account_ids_for:#{account_id}\")\n    Rails.cache.delete(\"exclude_account_ids_for:#{target_account_id}\")\n  end\n\n  def set_uri\n    self.uri = ActivityPub::TagManager.instance.generate_uri_for(self) if uri.nil?\n  end\nend\n"
  },
  {
    "path": "app/models/concerns/account_associations.rb",
    "content": "# frozen_string_literal: true\n\nmodule AccountAssociations\n  extend ActiveSupport::Concern\n\n  included do\n    # Local users\n    has_one :user, inverse_of: :account, dependent: :destroy\n\n    # Identity proofs\n    has_many :identity_proofs, class_name: 'AccountIdentityProof', dependent: :destroy, inverse_of: :account\n\n    # Timelines\n    has_many :stream_entries, inverse_of: :account, dependent: :destroy\n    has_many :statuses, inverse_of: :account, dependent: :destroy\n    has_many :favourites, inverse_of: :account, dependent: :destroy\n    has_many :mentions, inverse_of: :account, dependent: :destroy\n    has_many :notifications, inverse_of: :account, dependent: :destroy\n    has_many :conversations, class_name: 'AccountConversation', dependent: :destroy, inverse_of: :account\n    has_many :scheduled_statuses, inverse_of: :account, dependent: :destroy\n\n    # Pinned statuses\n    has_many :status_pins, inverse_of: :account, dependent: :destroy\n    has_many :pinned_statuses, -> { reorder('status_pins.created_at DESC') }, through: :status_pins, class_name: 'Status', source: :status\n\n    # Endorsements\n    has_many :account_pins, inverse_of: :account, dependent: :destroy\n    has_many :endorsed_accounts, through: :account_pins, class_name: 'Account', source: :target_account\n\n    # Media\n    has_many :media_attachments, dependent: :destroy\n    has_many :polls, dependent: :destroy\n\n    # PuSH subscriptions\n    has_many :subscriptions, dependent: :destroy\n\n    # Report relationships\n    has_many :reports, dependent: :destroy, inverse_of: :account\n    has_many :targeted_reports, class_name: 'Report', foreign_key: :target_account_id, dependent: :destroy, inverse_of: :target_account\n\n    has_many :report_notes, dependent: :destroy\n    has_many :custom_filters, inverse_of: :account, dependent: :destroy\n\n    # Moderation notes\n    has_many :account_moderation_notes, dependent: :destroy, inverse_of: :account\n    has_many :targeted_moderation_notes, class_name: 'AccountModerationNote', foreign_key: :target_account_id, dependent: :destroy, inverse_of: :target_account\n    has_many :account_warnings, dependent: :destroy, inverse_of: :account\n    has_many :targeted_account_warnings, class_name: 'AccountWarning', foreign_key: :target_account_id, dependent: :destroy, inverse_of: :target_account\n\n    # Lists (that the account is on, not owned by the account)\n    has_many :list_accounts, inverse_of: :account, dependent: :destroy\n    has_many :lists, through: :list_accounts\n\n    # Lists (owned by the account)\n    has_many :owned_lists, class_name: 'List', dependent: :destroy, inverse_of: :account\n\n    # Account migrations\n    belongs_to :moved_to_account, class_name: 'Account', optional: true\n\n    # Hashtags\n    has_and_belongs_to_many :tags\n    has_many :featured_tags, -> { includes(:tag) }, dependent: :destroy, inverse_of: :account\n  end\nend\n"
  },
  {
    "path": "app/models/concerns/account_avatar.rb",
    "content": "# frozen_string_literal: true\n\nmodule AccountAvatar\n  extend ActiveSupport::Concern\n\n  IMAGE_MIME_TYPES = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'].freeze\n  LIMIT = 2.megabytes\n\n  class_methods do\n    def avatar_styles(file)\n      styles = { original: { geometry: '400x400#', file_geometry_parser: FastGeometryParser } }\n      styles[:static] = { geometry: '400x400#', format: 'png', convert_options: '-coalesce', file_geometry_parser: FastGeometryParser } if file.content_type == 'image/gif'\n      styles\n    end\n\n    private :avatar_styles\n  end\n\n  included do\n    # Avatar upload\n    has_attached_file :avatar, styles: ->(f) { avatar_styles(f) }, convert_options: { all: '-strip' }, processors: [:lazy_thumbnail]\n    validates_attachment_content_type :avatar, content_type: IMAGE_MIME_TYPES\n    validates_attachment_size :avatar, less_than: LIMIT\n    remotable_attachment :avatar, LIMIT\n  end\n\n  def avatar_original_url\n    avatar.url(:original)\n  end\n\n  def avatar_static_url\n    avatar_content_type == 'image/gif' ? avatar.url(:static) : avatar_original_url\n  end\nend\n"
  },
  {
    "path": "app/models/concerns/account_counters.rb",
    "content": "# frozen_string_literal: true\n\nmodule AccountCounters\n  extend ActiveSupport::Concern\n\n  included do\n    has_one :account_stat, inverse_of: :account\n    after_save :save_account_stat\n  end\n\n  delegate :statuses_count,\n           :statuses_count=,\n           :following_count,\n           :following_count=,\n           :followers_count,\n           :followers_count=,\n           :increment_count!,\n           :decrement_count!,\n           :last_status_at,\n           to: :account_stat\n\n  def account_stat\n    super || build_account_stat\n  end\n\n  private\n\n  def save_account_stat\n    return unless account_stat&.changed?\n    account_stat.save\n  end\nend\n"
  },
  {
    "path": "app/models/concerns/account_finder_concern.rb",
    "content": "# frozen_string_literal: true\n\nmodule AccountFinderConcern\n  extend ActiveSupport::Concern\n\n  class_methods do\n    def find_local!(username)\n      find_local(username) || raise(ActiveRecord::RecordNotFound)\n    end\n\n    def find_remote!(username, domain)\n      find_remote(username, domain) || raise(ActiveRecord::RecordNotFound)\n    end\n\n    def representative\n      find_local(Setting.site_contact_username.strip.gsub(/\\A@/, '')) || Account.local.without_suspended.first\n    end\n\n    def find_local(username)\n      find_remote(username, nil)\n    end\n\n    def find_remote(username, domain)\n      AccountFinder.new(username, domain).account\n    end\n  end\n\n  class AccountFinder\n    attr_reader :username, :domain\n\n    def initialize(username, domain)\n      @username = username\n      @domain = domain\n    end\n\n    def account\n      scoped_accounts.order(id: :asc).take\n    end\n\n    private\n\n    def scoped_accounts\n      Account.unscoped.tap do |scope|\n        scope.merge! with_usernames\n        scope.merge! matching_username\n        scope.merge! matching_domain\n      end\n    end\n\n    def with_usernames\n      Account.where.not(username: '')\n    end\n\n    def matching_username\n      Account.where(Account.arel_table[:username].lower.eq username.to_s.downcase)\n    end\n\n    def matching_domain\n      if domain.nil?\n        Account.where(domain: nil)\n      else\n        Account.where(Account.arel_table[:domain].lower.eq domain.to_s.downcase)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "app/models/concerns/account_header.rb",
    "content": "# frozen_string_literal: true\n\nmodule AccountHeader\n  extend ActiveSupport::Concern\n\n  IMAGE_MIME_TYPES = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'].freeze\n  LIMIT = 2.megabytes\n  MAX_PIXELS = 750_000 # 1500x500px\n\n  class_methods do\n    def header_styles(file)\n      styles = { original: { pixels: MAX_PIXELS, file_geometry_parser: FastGeometryParser } }\n      styles[:static] = { format: 'png', convert_options: '-coalesce', file_geometry_parser: FastGeometryParser } if file.content_type == 'image/gif'\n      styles\n    end\n\n    private :header_styles\n  end\n\n  included do\n    # Header upload\n    has_attached_file :header, styles: ->(f) { header_styles(f) }, convert_options: { all: '-strip' }, processors: [:lazy_thumbnail]\n    validates_attachment_content_type :header, content_type: IMAGE_MIME_TYPES\n    validates_attachment_size :header, less_than: LIMIT\n    remotable_attachment :header, LIMIT\n  end\n\n  def header_original_url\n    header.url(:original)\n  end\n\n  def header_static_url\n    header_content_type == 'image/gif' ? header.url(:static) : header_original_url\n  end\nend\n"
  },
  {
    "path": "app/models/concerns/account_interactions.rb",
    "content": "# frozen_string_literal: true\n\nmodule AccountInteractions\n  extend ActiveSupport::Concern\n\n  class_methods do\n    def following_map(target_account_ids, account_id)\n      Follow.where(target_account_id: target_account_ids, account_id: account_id).each_with_object({}) do |follow, mapping|\n        mapping[follow.target_account_id] = {\n          reblogs: follow.show_reblogs?,\n        }\n      end\n    end\n\n    def followed_by_map(target_account_ids, account_id)\n      follow_mapping(Follow.where(account_id: target_account_ids, target_account_id: account_id), :account_id)\n    end\n\n    def blocking_map(target_account_ids, account_id)\n      follow_mapping(Block.where(target_account_id: target_account_ids, account_id: account_id), :target_account_id)\n    end\n\n    def blocked_by_map(target_account_ids, account_id)\n      follow_mapping(Block.where(account_id: target_account_ids, target_account_id: account_id), :account_id)\n    end\n\n    def muting_map(target_account_ids, account_id)\n      Mute.where(target_account_id: target_account_ids, account_id: account_id).each_with_object({}) do |mute, mapping|\n        mapping[mute.target_account_id] = {\n          notifications: mute.hide_notifications?,\n        }\n      end\n    end\n\n    def requested_map(target_account_ids, account_id)\n      FollowRequest.where(target_account_id: target_account_ids, account_id: account_id).each_with_object({}) do |follow_request, mapping|\n        mapping[follow_request.target_account_id] = {\n          reblogs: follow_request.show_reblogs?,\n        }\n      end\n    end\n\n    def endorsed_map(target_account_ids, account_id)\n      follow_mapping(AccountPin.where(account_id: account_id, target_account_id: target_account_ids), :target_account_id)\n    end\n\n    def domain_blocking_map(target_account_ids, account_id)\n      accounts_map    = Account.where(id: target_account_ids).select('id, domain').each_with_object({}) { |a, h| h[a.id] = a.domain }\n      blocked_domains = domain_blocking_map_by_domain(accounts_map.values.compact, account_id)\n      accounts_map.reduce({}) { |h, (id, domain)| h.merge(id => blocked_domains[domain]) }\n    end\n\n    def domain_blocking_map_by_domain(target_domains, account_id)\n      follow_mapping(AccountDomainBlock.where(account_id: account_id, domain: target_domains), :domain)\n    end\n\n    private\n\n    def follow_mapping(query, field)\n      query.pluck(field).each_with_object({}) { |id, mapping| mapping[id] = true }\n    end\n  end\n\n  included do\n    # Follow relations\n    has_many :follow_requests, dependent: :destroy\n\n    has_many :active_relationships,  class_name: 'Follow', foreign_key: 'account_id',        dependent: :destroy\n    has_many :passive_relationships, class_name: 'Follow', foreign_key: 'target_account_id', dependent: :destroy\n\n    has_many :following, -> { order('follows.id desc') }, through: :active_relationships,  source: :target_account\n    has_many :followers, -> { order('follows.id desc') }, through: :passive_relationships, source: :account\n\n    # Block relationships\n    has_many :block_relationships, class_name: 'Block', foreign_key: 'account_id', dependent: :destroy\n    has_many :blocking, -> { order('blocks.id desc') }, through: :block_relationships, source: :target_account\n    has_many :blocked_by_relationships, class_name: 'Block', foreign_key: :target_account_id, dependent: :destroy\n    has_many :blocked_by, -> { order('blocks.id desc') }, through: :blocked_by_relationships, source: :account\n\n    # Mute relationships\n    has_many :mute_relationships, class_name: 'Mute', foreign_key: 'account_id', dependent: :destroy\n    has_many :muting, -> { order('mutes.id desc') }, through: :mute_relationships, source: :target_account\n    has_many :muted_by_relationships, class_name: 'Mute', foreign_key: :target_account_id, dependent: :destroy\n    has_many :muted_by, -> { order('mutes.id desc') }, through: :muted_by_relationships, source: :account\n    has_many :conversation_mutes, dependent: :destroy\n    has_many :domain_blocks, class_name: 'AccountDomainBlock', dependent: :destroy\n  end\n\n  def follow!(other_account, reblogs: nil, uri: nil)\n    reblogs = true if reblogs.nil?\n\n    rel = active_relationships.create_with(show_reblogs: reblogs, uri: uri)\n                              .find_or_create_by!(target_account: other_account)\n\n    rel.update!(show_reblogs: reblogs)\n    remove_potential_friendship(other_account)\n\n    rel\n  end\n\n  def block!(other_account, uri: nil)\n    remove_potential_friendship(other_account)\n    block_relationships.create_with(uri: uri)\n                       .find_or_create_by!(target_account: other_account)\n  end\n\n  def mute!(other_account, notifications: nil)\n    notifications = true if notifications.nil?\n    mute = mute_relationships.create_with(hide_notifications: notifications).find_or_create_by!(target_account: other_account)\n    remove_potential_friendship(other_account)\n\n    # When toggling a mute between hiding and allowing notifications, the mute will already exist, so the find_or_create_by! call will return the existing Mute without updating the hide_notifications attribute. Therefore, we check that hide_notifications? is what we want and set it if it isn't.\n    if mute.hide_notifications? != notifications\n      mute.update!(hide_notifications: notifications)\n    end\n\n    mute\n  end\n\n  def mute_conversation!(conversation)\n    conversation_mutes.find_or_create_by!(conversation: conversation)\n  end\n\n  def block_domain!(other_domain)\n    domain_blocks.find_or_create_by!(domain: other_domain)\n  end\n\n  def unfollow!(other_account)\n    follow = active_relationships.find_by(target_account: other_account)\n    follow&.destroy\n  end\n\n  def unblock!(other_account)\n    block = block_relationships.find_by(target_account: other_account)\n    block&.destroy\n  end\n\n  def unmute!(other_account)\n    mute = mute_relationships.find_by(target_account: other_account)\n    mute&.destroy\n  end\n\n  def unmute_conversation!(conversation)\n    mute = conversation_mutes.find_by(conversation: conversation)\n    mute&.destroy!\n  end\n\n  def unblock_domain!(other_domain)\n    block = domain_blocks.find_by(domain: other_domain)\n    block&.destroy\n  end\n\n  def following?(other_account)\n    active_relationships.where(target_account: other_account).exists?\n  end\n\n  def blocking?(other_account)\n    block_relationships.where(target_account: other_account).exists?\n  end\n\n  def domain_blocking?(other_domain)\n    domain_blocks.where(domain: other_domain).exists?\n  end\n\n  def muting?(other_account)\n    mute_relationships.where(target_account: other_account).exists?\n  end\n\n  def muting_conversation?(conversation)\n    conversation_mutes.where(conversation: conversation).exists?\n  end\n\n  def muting_notifications?(other_account)\n    mute_relationships.where(target_account: other_account, hide_notifications: true).exists?\n  end\n\n  def muting_reblogs?(other_account)\n    active_relationships.where(target_account: other_account, show_reblogs: false).exists?\n  end\n\n  def requested?(other_account)\n    follow_requests.where(target_account: other_account).exists?\n  end\n\n  def favourited?(status)\n    status.proper.favourites.where(account: self).exists?\n  end\n\n  def reblogged?(status)\n    status.proper.reblogs.where(account: self).exists?\n  end\n\n  def pinned?(status)\n    status_pins.where(status: status).exists?\n  end\n\n  def endorsed?(account)\n    account_pins.where(target_account: account).exists?\n  end\n\n  def followers_for_local_distribution\n    followers.local\n             .joins(:user)\n             .where('users.current_sign_in_at > ?', User::ACTIVE_DURATION.ago)\n  end\n\n  def lists_for_local_distribution\n    lists.joins(account: :user)\n         .where('users.current_sign_in_at > ?', User::ACTIVE_DURATION.ago)\n  end\n\n  private\n\n  def remove_potential_friendship(other_account, mutual = false)\n    PotentialFriendshipTracker.remove(id, other_account.id)\n    PotentialFriendshipTracker.remove(other_account.id, id) if mutual\n  end\nend\n"
  },
  {
    "path": "app/models/concerns/attachmentable.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'mime/types'\n\nmodule Attachmentable\n  extend ActiveSupport::Concern\n\n  MAX_MATRIX_LIMIT = 16_777_216 # 4096x4096px or approx. 16MB\n\n  included do\n    before_post_process :set_file_extensions\n    before_post_process :check_image_dimensions\n  end\n\n  private\n\n  def set_file_extensions\n    self.class.attachment_definitions.each_key do |attachment_name|\n      attachment = send(attachment_name)\n\n      next if attachment.blank?\n\n      attachment.instance_write :file_name, [Paperclip::Interpolations.basename(attachment, :original), appropriate_extension(attachment)].delete_if(&:blank?).join('.')\n    end\n  end\n\n  def check_image_dimensions\n    self.class.attachment_definitions.each_key do |attachment_name|\n      attachment = send(attachment_name)\n\n      next if attachment.blank? || !/image.*/.match?(attachment.content_type) || attachment.queued_for_write[:original].blank?\n\n      width, height = FastImage.size(attachment.queued_for_write[:original].path)\n\n      raise Mastodon::DimensionsValidationError, \"#{width}x#{height} images are not supported\" if width.present? && height.present? && (width * height >= MAX_MATRIX_LIMIT)\n    end\n  end\n\n  def appropriate_extension(attachment)\n    mime_type = MIME::Types[attachment.content_type]\n\n    extensions_for_mime_type = mime_type.empty? ? [] : mime_type.first.extensions\n    original_extension       = Paperclip::Interpolations.extension(attachment, :original)\n    proper_extension         = extensions_for_mime_type.first.to_s\n    extension                = extensions_for_mime_type.include?(original_extension) ? original_extension : proper_extension\n    extension                = 'jpeg' if extension == 'jpe'\n\n    extension\n  end\nend\n"
  },
  {
    "path": "app/models/concerns/cacheable.rb",
    "content": "# frozen_string_literal: true\n\nmodule Cacheable\n  extend ActiveSupport::Concern\n\n  module ClassMethods\n    @cache_associated = []\n\n    def cache_associated(*associations)\n      @cache_associated = associations\n    end\n\n    def with_includes\n      includes(@cache_associated)\n    end\n\n    def cache_ids\n      select(:id, :updated_at)\n    end\n  end\nend\n"
  },
  {
    "path": "app/models/concerns/domain_normalizable.rb",
    "content": "# frozen_string_literal: true\n\nmodule DomainNormalizable\n  extend ActiveSupport::Concern\n\n  included do\n    before_validation :normalize_domain\n  end\n\n  private\n\n  def normalize_domain\n    self.domain = TagManager.instance.normalize_domain(domain&.strip)\n  end\nend\n"
  },
  {
    "path": "app/models/concerns/expireable.rb",
    "content": "# frozen_string_literal: true\n\nmodule Expireable\n  extend ActiveSupport::Concern\n\n  included do\n    scope :expired, -> { where.not(expires_at: nil).where('expires_at < ?', Time.now.utc) }\n\n    attr_reader :expires_in\n\n    def expires_in=(interval)\n      self.expires_at = interval.to_i.seconds.from_now if interval.present?\n      @expires_in     = interval\n    end\n\n    def expire!\n      touch(:expires_at)\n    end\n\n    def expired?\n      expires? && expires_at < Time.now.utc\n    end\n\n    def expires?\n      !expires_at.nil?\n    end\n  end\nend\n"
  },
  {
    "path": "app/models/concerns/ldap_authenticable.rb",
    "content": "# frozen_string_literal: true\n\nmodule LdapAuthenticable\n  extend ActiveSupport::Concern\n\n  def ldap_setup(_attributes)\n    self.confirmed_at = Time.now.utc\n    self.admin        = false\n    self.external     = true\n\n    save!\n  end\n\n  class_methods do\n    def ldap_get_user(attributes = {})\n      resource = joins(:account).find_by(accounts: { username: attributes[Devise.ldap_uid.to_sym].first })\n\n      if resource.blank?\n        resource = new(email: attributes[:mail].first, agreement: true, account_attributes: { username: attributes[Devise.ldap_uid.to_sym].first })\n        resource.ldap_setup(attributes)\n      end\n\n      resource\n    end\n  end\nend\n"
  },
  {
    "path": "app/models/concerns/omniauthable.rb",
    "content": "# frozen_string_literal: true\n\nmodule Omniauthable\n  extend ActiveSupport::Concern\n\n  TEMP_EMAIL_PREFIX = 'change@me'\n  TEMP_EMAIL_REGEX = /\\Achange@me/\n\n  included do\n    devise :omniauthable\n\n    def omniauth_providers\n      Devise.omniauth_configs.keys\n    end\n\n    def email_verified?\n      email && email !~ TEMP_EMAIL_REGEX\n    end\n  end\n\n  class_methods do\n    def find_for_oauth(auth, signed_in_resource = nil)\n      # EOLE-SSO Patch\n      auth.uid = (auth.uid[0][:uid] || auth.uid[0][:user]) if auth.uid.is_a? Hashie::Array\n      identity = Identity.find_for_oauth(auth)\n\n      # If a signed_in_resource is provided it always overrides the existing user\n      # to prevent the identity being locked with accidentally created accounts.\n      # Note that this may leave zombie accounts (with no associated identity) which\n      # can be cleaned up at a later date.\n      user = signed_in_resource || identity.user\n      user = create_for_oauth(auth) if user.nil?\n\n      if identity.user.nil?\n        identity.user = user\n        identity.save!\n      end\n\n      user\n    end\n\n    def create_for_oauth(auth)\n      # Check if the user exists with provided email if the provider gives us a\n      # verified email.  If no verified email was provided or the user already\n      # exists, we assign a temporary email and ask the user to verify it on\n      # the next step via Auth::ConfirmationsController.finish_signup\n\n      user = User.new(user_params_from_auth(auth))\n      user.account.avatar_remote_url = auth.info.image if auth.info.image =~ /\\A#{URI.regexp(%w(http https))}\\z/\n      user.skip_confirmation!\n      user.save!\n      user\n    end\n\n    private\n\n    def user_params_from_auth(auth)\n      strategy          = Devise.omniauth_configs[auth.provider.to_sym].strategy\n      assume_verified   = strategy.try(:security).try(:assume_email_is_verified)\n      email_is_verified = auth.info.verified || auth.info.verified_email || assume_verified\n      email             = auth.info.verified_email || auth.info.email\n      email             = email_is_verified && !User.exists?(email: auth.info.email) && email\n      display_name      = auth.info.full_name || [auth.info.first_name, auth.info.last_name].join(' ')\n\n      {\n        email: email || \"#{TEMP_EMAIL_PREFIX}-#{auth.uid}-#{auth.provider}.com\",\n        password: Devise.friendly_token[0, 20],\n        agreement: true,\n        external: true,\n        account_attributes: {\n          username: ensure_unique_username(auth.uid),\n          display_name: display_name,\n        },\n      }\n    end\n\n    def ensure_unique_username(starting_username)\n      username = starting_username\n      i        = 0\n\n      while Account.exists?(username: username)\n        i       += 1\n        username = \"#{starting_username}_#{i}\"\n      end\n\n      username\n    end\n  end\nend\n"
  },
  {
    "path": "app/models/concerns/paginable.rb",
    "content": "# frozen_string_literal: true\n\nmodule Paginable\n  extend ActiveSupport::Concern\n\n  included do\n    scope :paginate_by_max_id, ->(limit, max_id = nil, since_id = nil) {\n      query = order(arel_table[:id].desc).limit(limit)\n      query = query.where(arel_table[:id].lt(max_id)) if max_id.present?\n      query = query.where(arel_table[:id].gt(since_id)) if since_id.present?\n      query\n    }\n\n    # Differs from :paginate_by_max_id in that it gives the results immediately following min_id,\n    # whereas since_id gives the items with largest id, but with since_id as a cutoff.\n    # Results will be in ascending order by id.\n    scope :paginate_by_min_id, ->(limit, min_id = nil) {\n      query = reorder(arel_table[:id]).limit(limit)\n      query = query.where(arel_table[:id].gt(min_id)) if min_id.present?\n      query\n    }\n\n    scope :paginate_by_id, ->(limit, options = {}) {\n      if options[:min_id].present?\n        paginate_by_min_id(limit, options[:min_id]).reverse\n      else\n        paginate_by_max_id(limit, options[:max_id], options[:since_id])\n      end\n    }\n  end\nend\n"
  },
  {
    "path": "app/models/concerns/pam_authenticable.rb",
    "content": "# frozen_string_literal: true\n\nmodule PamAuthenticable\n  extend ActiveSupport::Concern\n\n  included do\n    devise :pam_authenticatable if ENV['PAM_ENABLED'] == 'true'\n\n    def pam_conflict(_attributes)\n      # Block pam login tries on traditional account\n    end\n\n    def pam_conflict?\n      if Devise.pam_authentication\n        encrypted_password.present? && pam_managed_user?\n      else\n        false\n      end\n    end\n\n    def pam_get_name\n      if account.present?\n        account.username\n      else\n        super\n      end\n    end\n\n    def pam_setup(_attributes)\n      account = Account.new(username: pam_get_name)\n      account.save!(validate: false)\n\n      self.email        = \"#{account.username}@#{find_pam_suffix}\" if email.nil? && find_pam_suffix\n      self.confirmed_at = Time.now.utc\n      self.admin        = false\n      self.account      = account\n      self.external     = true\n\n      account.destroy! unless save\n    end\n\n    def self.pam_get_user(attributes = {})\n      return nil unless attributes[:email]\n\n      resource = begin\n        if Devise.check_at_sign && !attributes[:email].index('@')\n          joins(:account).find_by(accounts: { username: attributes[:email] })\n        else\n          find_by(email: attributes[:email])\n        end\n      end\n\n      if resource.nil?\n        resource = new(email: attributes[:email], agreement: true)\n\n        if Devise.check_at_sign && !resource[:email].index('@')\n          resource[:email] = Rpam2.getenv(resource.find_pam_service, attributes[:email], attributes[:password], 'email', false)\n          resource[:email] = \"#{attributes[:email]}@#{resource.find_pam_suffix}\" unless resource[:email]\n        end\n      end\n\n      resource\n    end\n\n    def self.authenticate_with_pam(attributes = {})\n      super if Devise.pam_authentication\n    end\n  end\nend\n"
  },
  {
    "path": "app/models/concerns/redisable.rb",
    "content": "# frozen_string_literal: true\n\nmodule Redisable\n  extend ActiveSupport::Concern\n\n  private\n\n  def redis\n    Redis.current\n  end\nend\n"
  },
  {
    "path": "app/models/concerns/relationship_cacheable.rb",
    "content": "# frozen_string_literal: true\n\nmodule RelationshipCacheable\n  extend ActiveSupport::Concern\n\n  included do\n    after_commit :remove_relationship_cache\n  end\n\n  private\n\n  def remove_relationship_cache\n    Rails.cache.delete(\"relationship:#{account_id}:#{target_account_id}\")\n    Rails.cache.delete(\"relationship:#{target_account_id}:#{account_id}\")\n  end\nend\n"
  },
  {
    "path": "app/models/concerns/remotable.rb",
    "content": "# frozen_string_literal: true\n\nmodule Remotable\n  extend ActiveSupport::Concern\n\n  class_methods do\n    def remotable_attachment(attachment_name, limit)\n      attribute_name  = \"#{attachment_name}_remote_url\".to_sym\n      method_name     = \"#{attribute_name}=\".to_sym\n      alt_method_name = \"reset_#{attachment_name}!\".to_sym\n\n      define_method method_name do |url|\n        return if url.blank?\n\n        begin\n          parsed_url = Addressable::URI.parse(url).normalize\n        rescue Addressable::URI::InvalidURIError\n          return\n        end\n\n        return if !%w(http https).include?(parsed_url.scheme) || parsed_url.host.blank? || self[attribute_name] == url\n\n        begin\n          Request.new(:get, url).perform do |response|\n            next if response.code != 200\n\n            content_type = parse_content_type(response.headers.get('content-type').last)\n            extname      = detect_extname_from_content_type(content_type)\n\n            if extname.nil?\n              disposition = response.headers.get('content-disposition').last\n              matches     = disposition&.match(/filename=\"([^\"]*)\"/)\n              filename    = matches.nil? ? parsed_url.path.split('/').last : matches[1]\n              extname     = filename.nil? ? '' : File.extname(filename)\n            end\n\n            basename = SecureRandom.hex(8)\n\n            send(\"#{attachment_name}=\", StringIO.new(response.body_with_limit(limit)))\n            send(\"#{attachment_name}_file_name=\", basename + extname)\n\n            self[attribute_name] = url if has_attribute?(attribute_name)\n          end\n        rescue HTTP::TimeoutError, HTTP::ConnectionError, OpenSSL::SSL::SSLError, Paperclip::Errors::NotIdentifiedByImageMagickError, Addressable::URI::InvalidURIError, Mastodon::HostValidationError, Mastodon::LengthValidationError => e\n          Rails.logger.debug \"Error fetching remote #{attachment_name}: #{e}\"\n          nil\n        rescue Paperclip::Error, Mastodon::DimensionsValidationError => e\n          Rails.logger.debug \"Error processing remote #{attachment_name}: #{e}\"\n          nil\n        end\n      end\n\n      define_method alt_method_name do\n        url = self[attribute_name]\n\n        return if url.blank?\n\n        self[attribute_name] = ''\n        send(method_name, url)\n      end\n    end\n  end\n\n  private\n\n  def detect_extname_from_content_type(content_type)\n    return if content_type.nil?\n\n    type = MIME::Types[content_type].first\n\n    return if type.nil?\n\n    extname = type.extensions.first\n\n    return if extname.nil?\n\n    \".#{extname}\"\n  end\n\n  def parse_content_type(content_type)\n    return if content_type.nil?\n\n    content_type.split(/\\s*;\\s*/).first\n  end\nend\n"
  },
  {
    "path": "app/models/concerns/status_threading_concern.rb",
    "content": "# frozen_string_literal: true\n\nmodule StatusThreadingConcern\n  extend ActiveSupport::Concern\n\n  def ancestors(limit, account = nil)\n    find_statuses_from_tree_path(ancestor_ids(limit), account)\n  end\n\n  def descendants(limit, account = nil, max_child_id = nil, since_child_id = nil, depth = nil)\n    find_statuses_from_tree_path(descendant_ids(limit, max_child_id, since_child_id, depth), account, promote: true)\n  end\n\n  def self_replies(limit)\n    account.statuses.where(in_reply_to_id: id, visibility: [:public, :unlisted]).reorder(id: :asc).limit(limit)\n  end\n\n  private\n\n  def ancestor_ids(limit)\n    key = \"ancestors:#{id}\"\n    ancestors = Rails.cache.fetch(key)\n\n    if ancestors.nil? || ancestors[:limit] < limit\n      ids = ancestor_statuses(limit).pluck(:id).reverse!\n      Rails.cache.write key, limit: limit, ids: ids\n      ids\n    else\n      ancestors[:ids].last(limit)\n    end\n  end\n\n  def ancestor_statuses(limit)\n    Status.find_by_sql([<<-SQL.squish, id: in_reply_to_id, limit: limit])\n      WITH RECURSIVE search_tree(id, in_reply_to_id, path)\n      AS (\n        SELECT id, in_reply_to_id, ARRAY[id]\n        FROM statuses\n        WHERE id = :id\n        UNION ALL\n        SELECT statuses.id, statuses.in_reply_to_id, path || statuses.id\n        FROM search_tree\n        JOIN statuses ON statuses.id = search_tree.in_reply_to_id\n        WHERE NOT statuses.id = ANY(path)\n      )\n      SELECT id\n      FROM search_tree\n      ORDER BY path\n      LIMIT :limit\n    SQL\n  end\n\n  def descendant_ids(limit, max_child_id, since_child_id, depth)\n    descendant_statuses(limit, max_child_id, since_child_id, depth).pluck(:id)\n  end\n\n  def descendant_statuses(limit, max_child_id, since_child_id, depth)\n    # use limit + 1 and depth + 1 because 'self' is included\n    depth += 1 if depth.present?\n    limit += 1 if limit.present?\n\n    descendants_with_self = Status.find_by_sql([<<-SQL.squish, id: id, limit: limit, max_child_id: max_child_id, since_child_id: since_child_id, depth: depth])\n      WITH RECURSIVE search_tree(id, path)\n      AS (\n        SELECT id, ARRAY[id]\n        FROM statuses\n        WHERE id = :id AND COALESCE(id < :max_child_id, TRUE) AND COALESCE(id > :since_child_id, TRUE)\n        UNION ALL\n        SELECT statuses.id, path || statuses.id\n        FROM search_tree\n        JOIN statuses ON statuses.in_reply_to_id = search_tree.id\n        WHERE COALESCE(array_length(path, 1) < :depth, TRUE) AND NOT statuses.id = ANY(path)\n      )\n      SELECT id\n      FROM search_tree\n      ORDER BY path\n      LIMIT :limit\n    SQL\n\n    descendants_with_self - [self]\n  end\n\n  def find_statuses_from_tree_path(ids, account, promote: false)\n    statuses    = statuses_with_accounts(ids).to_a\n    account_ids = statuses.map(&:account_id).uniq\n    domains     = statuses.map(&:account_domain).compact.uniq\n    relations   = relations_map_for_account(account, account_ids, domains)\n\n    statuses.reject! { |status| filter_from_context?(status, account, relations) }\n\n    # Order ancestors/descendants by tree path\n    statuses.sort_by! { |status| ids.index(status.id) }\n\n    # Bring self-replies to the top\n    if promote\n      promote_by!(statuses) { |status| status.in_reply_to_account_id == status.account_id }\n    else\n      statuses\n    end\n  end\n\n  def promote_by!(arr)\n    insert_at = arr.find_index { |item| !yield(item) }\n\n    return arr if insert_at.nil?\n\n    arr.each_with_index do |item, index|\n      next if index <= insert_at || !yield(item)\n\n      arr.insert(insert_at, arr.delete_at(index))\n      insert_at += 1\n    end\n\n    arr\n  end\n\n  def relations_map_for_account(account, account_ids, domains)\n    return {} if account.nil?\n\n    {\n      blocking: Account.blocking_map(account_ids, account.id),\n      blocked_by: Account.blocked_by_map(account_ids, account.id),\n      muting: Account.muting_map(account_ids, account.id),\n      following: Account.following_map(account_ids, account.id),\n      domain_blocking_by_domain: Account.domain_blocking_map_by_domain(domains, account.id),\n    }\n  end\n\n  def statuses_with_accounts(ids)\n    Status.where(id: ids).includes(:account)\n  end\n\n  def filter_from_context?(status, account, relations)\n    StatusFilter.new(status, account, relations).filtered?\n  end\nend\n"
  },
  {
    "path": "app/models/concerns/streamable.rb",
    "content": "# frozen_string_literal: true\n\nmodule Streamable\n  extend ActiveSupport::Concern\n\n  included do\n    has_one :stream_entry, as: :activity\n\n    after_create do\n      account.stream_entries.create!(activity: self, hidden: hidden?) if needs_stream_entry?\n    end\n  end\n\n  def title\n    super\n  end\n\n  def content\n    title\n  end\n\n  def target\n    super\n  end\n\n  def object_type\n    :activity\n  end\n\n  def thread\n    super\n  end\n\n  def hidden?\n    false\n  end\n\n  private\n\n  def needs_stream_entry?\n    account.local?\n  end\nend\n"
  },
  {
    "path": "app/models/concerns/user_roles.rb",
    "content": "# frozen_string_literal: true\n\nmodule UserRoles\n  extend ActiveSupport::Concern\n\n  included do\n    scope :admins, -> { where(admin: true) }\n    scope :moderators, -> { where(moderator: true) }\n    scope :staff, -> { admins.or(moderators) }\n  end\n\n  def staff?\n    admin? || moderator?\n  end\n\n  def role\n    if admin?\n      'admin'\n    elsif moderator?\n      'moderator'\n    else\n      'user'\n    end\n  end\n\n  def role?(role)\n    case role\n    when 'user'\n      true\n    when 'moderator'\n      staff?\n    when 'admin'\n      admin?\n    else\n      false\n    end\n  end\n\n  def promote!\n    if moderator?\n      update!(moderator: false, admin: true)\n    elsif !admin?\n      update!(moderator: true)\n    end\n  end\n\n  def demote!\n    if admin?\n      update!(admin: false, moderator: true)\n    elsif moderator?\n      update!(moderator: false)\n    end\n  end\nend\n"
  },
  {
    "path": "app/models/context.rb",
    "content": "# frozen_string_literal: true\n\nclass Context < ActiveModelSerializers::Model\n  attributes :ancestors, :descendants\nend\n"
  },
  {
    "path": "app/models/conversation.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: conversations\n#\n#  id         :bigint(8)        not null, primary key\n#  uri        :string\n#  created_at :datetime         not null\n#  updated_at :datetime         not null\n#\n\nclass Conversation < ApplicationRecord\n  validates :uri, uniqueness: true, if: :uri?\n\n  has_many :statuses\n\n  def local?\n    uri.nil?\n  end\nend\n"
  },
  {
    "path": "app/models/conversation_mute.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: conversation_mutes\n#\n#  id              :bigint(8)        not null, primary key\n#  conversation_id :bigint(8)        not null\n#  account_id      :bigint(8)        not null\n#\n\nclass ConversationMute < ApplicationRecord\n  belongs_to :account\n  belongs_to :conversation\nend\n"
  },
  {
    "path": "app/models/custom_emoji.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: custom_emojis\n#\n#  id                 :bigint(8)        not null, primary key\n#  shortcode          :string           default(\"\"), not null\n#  domain             :string\n#  image_file_name    :string\n#  image_content_type :string\n#  image_file_size    :integer\n#  image_updated_at   :datetime\n#  created_at         :datetime         not null\n#  updated_at         :datetime         not null\n#  disabled           :boolean          default(FALSE), not null\n#  uri                :string\n#  image_remote_url   :string\n#  visible_in_picker  :boolean          default(TRUE), not null\n#\n\nclass CustomEmoji < ApplicationRecord\n  LIMIT = 50.kilobytes\n\n  SHORTCODE_RE_FRAGMENT = '[a-zA-Z0-9_]{2,}'\n\n  SCAN_RE = /(?<=[^[:alnum:]:]|\\n|^)\n    :(#{SHORTCODE_RE_FRAGMENT}):\n    (?=[^[:alnum:]:]|$)/x\n\n  has_one :local_counterpart, -> { where(domain: nil) }, class_name: 'CustomEmoji', primary_key: :shortcode, foreign_key: :shortcode\n\n  has_attached_file :image, styles: { static: { format: 'png', convert_options: '-coalesce -strip' } }\n\n  before_validation :downcase_domain\n\n  validates_attachment :image, content_type: { content_type: 'image/png' }, presence: true, size: { less_than: LIMIT }\n  validates :shortcode, uniqueness: { scope: :domain }, format: { with: /\\A#{SHORTCODE_RE_FRAGMENT}\\z/ }, length: { minimum: 2 }\n\n  scope :local,      -> { where(domain: nil) }\n  scope :remote,     -> { where.not(domain: nil) }\n  scope :alphabetic, -> { order(domain: :asc, shortcode: :asc) }\n\n  remotable_attachment :image, LIMIT\n\n  include Attachmentable\n\n  after_commit :remove_entity_cache\n\n  def local?\n    domain.nil?\n  end\n\n  def object_type\n    :emoji\n  end\n\n  class << self\n    def from_text(text, domain)\n      return [] if text.blank?\n\n      shortcodes = text.scan(SCAN_RE).map(&:first).uniq\n\n      return [] if shortcodes.empty?\n\n      EntityCache.instance.emoji(shortcodes, domain)\n    end\n\n    def search(shortcode)\n      where('\"custom_emojis\".\"shortcode\" ILIKE ?', \"%#{shortcode}%\")\n    end\n  end\n\n  private\n\n  def remove_entity_cache\n    Rails.cache.delete(EntityCache.instance.to_key(:emoji, shortcode, domain))\n  end\n\n  def downcase_domain\n    self.domain = domain.downcase unless domain.nil?\n  end\nend\n"
  },
  {
    "path": "app/models/custom_emoji_filter.rb",
    "content": "# frozen_string_literal: true\n\nclass CustomEmojiFilter\n  attr_reader :params\n\n  def initialize(params)\n    @params = params\n  end\n\n  def results\n    scope = CustomEmoji.alphabetic\n\n    params.each do |key, value|\n      scope.merge!(scope_for(key, value)) if value.present?\n    end\n\n    scope\n  end\n\n  private\n\n  def scope_for(key, value)\n    case key.to_s\n    when 'local'\n      CustomEmoji.local\n    when 'remote'\n      CustomEmoji.remote\n    when 'by_domain'\n      CustomEmoji.where(domain: value.downcase)\n    when 'shortcode'\n      CustomEmoji.search(value)\n    else\n      raise \"Unknown filter: #{key}\"\n    end\n  end\nend\n"
  },
  {
    "path": "app/models/custom_filter.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: custom_filters\n#\n#  id           :bigint(8)        not null, primary key\n#  account_id   :bigint(8)\n#  expires_at   :datetime\n#  phrase       :text             default(\"\"), not null\n#  context      :string           default([]), not null, is an Array\n#  whole_word   :boolean          default(TRUE), not null\n#  irreversible :boolean          default(FALSE), not null\n#  created_at   :datetime         not null\n#  updated_at   :datetime         not null\n#\n\nclass CustomFilter < ApplicationRecord\n  VALID_CONTEXTS = %w(\n    home\n    notifications\n    public\n    thread\n  ).freeze\n\n  include Expireable\n\n  belongs_to :account\n\n  validates :phrase, :context, presence: true\n  validate :context_must_be_valid\n  validate :irreversible_must_be_within_context\n\n  scope :active_irreversible, -> { where(irreversible: true).where(Arel.sql('expires_at IS NULL OR expires_at > NOW()')) }\n\n  before_validation :clean_up_contexts\n  after_commit :remove_cache\n\n  private\n\n  def clean_up_contexts\n    self.context = Array(context).map(&:strip).map(&:presence).compact\n  end\n\n  def remove_cache\n    Rails.cache.delete(\"filters:#{account_id}\")\n    Redis.current.publish(\"timeline:#{account_id}\", Oj.dump(event: :filters_changed))\n  end\n\n  def context_must_be_valid\n    errors.add(:context, I18n.t('filters.errors.invalid_context')) if context.empty? || context.any? { |c| !VALID_CONTEXTS.include?(c) }\n  end\n\n  def irreversible_must_be_within_context\n    errors.add(:irreversible, I18n.t('filters.errors.invalid_irreversible')) if irreversible? && !context.include?('home') && !context.include?('notifications')\n  end\nend\n"
  },
  {
    "path": "app/models/domain_block.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: domain_blocks\n#\n#  id             :bigint(8)        not null, primary key\n#  domain         :string           default(\"\"), not null\n#  created_at     :datetime         not null\n#  updated_at     :datetime         not null\n#  severity       :integer          default(\"silence\")\n#  reject_media   :boolean          default(FALSE), not null\n#  reject_reports :boolean          default(FALSE), not null\n#\n\nclass DomainBlock < ApplicationRecord\n  include DomainNormalizable\n\n  enum severity: [:silence, :suspend, :noop]\n\n  validates :domain, presence: true, uniqueness: true\n\n  has_many :accounts, foreign_key: :domain, primary_key: :domain\n  delegate :count, to: :accounts, prefix: true\n\n  scope :matches_domain, ->(value) { where(arel_table[:domain].matches(\"%#{value}%\")) }\n\n  def self.blocked?(domain)\n    where(domain: domain, severity: :suspend).exists?\n  end\n\n  def stricter_than?(other_block)\n    return true if suspend?\n    return false if other_block.suspend? && (silence? || noop?)\n    return false if other_block.silence? && noop?\n    (reject_media || !other_block.reject_media) && (reject_reports || !other_block.reject_reports)\n  end\n\n  def affected_accounts_count\n    scope = suspend? ? accounts.where(suspended_at: created_at) : accounts.where(silenced_at: created_at)\n    scope.count\n  end\nend\n"
  },
  {
    "path": "app/models/email_domain_block.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: email_domain_blocks\n#\n#  id         :bigint(8)        not null, primary key\n#  domain     :string           default(\"\"), not null\n#  created_at :datetime         not null\n#  updated_at :datetime         not null\n#\n\nclass EmailDomainBlock < ApplicationRecord\n  include DomainNormalizable\n\n  validates :domain, presence: true, uniqueness: true\n\n  def self.block?(email)\n    _, domain = email.split('@', 2)\n\n    return true if domain.nil?\n\n    begin\n      domain = TagManager.instance.normalize_domain(domain)\n    rescue Addressable::URI::InvalidURIError\n      return true\n    end\n\n    where(domain: domain).exists?\n  end\nend\n"
  },
  {
    "path": "app/models/export.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'csv'\n\nclass Export\n  attr_reader :account\n\n  def initialize(account)\n    @account = account\n  end\n\n  def to_blocked_accounts_csv\n    to_csv account.blocking.select(:username, :domain)\n  end\n\n  def to_muted_accounts_csv\n    CSV.generate(headers: ['Account address', 'Hide notifications'], write_headers: true) do |csv|\n      account.mute_relationships.includes(:target_account).reorder(id: :desc).each do |mute|\n        csv << [acct(mute.target_account), mute.hide_notifications]\n      end\n    end\n  end\n\n  def to_following_accounts_csv\n    CSV.generate(headers: ['Account address', 'Show boosts'], write_headers: true) do |csv|\n      account.active_relationships.includes(:target_account).reorder(id: :desc).each do |follow|\n        csv << [acct(follow.target_account), follow.show_reblogs]\n      end\n    end\n  end\n\n  def to_lists_csv\n    CSV.generate do |csv|\n      account.owned_lists.select(:title, :id).each do |list|\n        list.accounts.select(:username, :domain).each do |account|\n          csv << [list.title, acct(account)]\n        end\n      end\n    end\n  end\n\n  def to_blocked_domains_csv\n    CSV.generate do |csv|\n      account.domain_blocks.pluck(:domain).each do |domain|\n        csv << [domain]\n      end\n    end\n  end\n\n  def total_storage\n    account.media_attachments.sum(:file_file_size)\n  end\n\n  def total_statuses\n    account.statuses_count\n  end\n\n  def total_follows\n    account.following_count\n  end\n\n  def total_lists\n    account.owned_lists.count\n  end\n\n  def total_followers\n    account.followers_count\n  end\n\n  def total_blocks\n    account.blocking.count\n  end\n\n  def total_mutes\n    account.muting.count\n  end\n\n  def total_domain_blocks\n    account.domain_blocks.count\n  end\n\n  private\n\n  def to_csv(accounts)\n    CSV.generate do |csv|\n      accounts.each do |account|\n        csv << [acct(account)]\n      end\n    end\n  end\n\n  def acct(account)\n    account.local? ? account.local_username_and_domain : account.acct\n  end\nend\n"
  },
  {
    "path": "app/models/favourite.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: favourites\n#\n#  id         :bigint(8)        not null, primary key\n#  created_at :datetime         not null\n#  updated_at :datetime         not null\n#  account_id :bigint(8)        not null\n#  status_id  :bigint(8)        not null\n#\n\nclass Favourite < ApplicationRecord\n  include Paginable\n\n  update_index('statuses#status', :status) if Chewy.enabled?\n\n  belongs_to :account, inverse_of: :favourites\n  belongs_to :status,  inverse_of: :favourites\n\n  has_one :notification, as: :activity, dependent: :destroy\n\n  validates :status_id, uniqueness: { scope: :account_id }\n\n  before_validation do\n    self.status = status.reblog if status&.reblog?\n  end\n\n  after_create :increment_cache_counters\n  after_destroy :decrement_cache_counters\n\n  private\n\n  def increment_cache_counters\n    status&.increment_count!(:favourites_count)\n  end\n\n  def decrement_cache_counters\n    return if association(:status).loaded? && (status.marked_for_destruction? || status.marked_for_mass_destruction?)\n    status&.decrement_count!(:favourites_count)\n  end\nend\n"
  },
  {
    "path": "app/models/featured_tag.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: featured_tags\n#\n#  id             :bigint(8)        not null, primary key\n#  account_id     :bigint(8)\n#  tag_id         :bigint(8)\n#  statuses_count :bigint(8)        default(0), not null\n#  last_status_at :datetime\n#  created_at     :datetime         not null\n#  updated_at     :datetime         not null\n#\n\nclass FeaturedTag < ApplicationRecord\n  belongs_to :account, inverse_of: :featured_tags, required: true\n  belongs_to :tag, inverse_of: :featured_tags, required: true\n\n  delegate :name, to: :tag, allow_nil: true\n\n  validates_associated :tag, on: :create\n  validates :name, presence: true, on: :create\n  validate :validate_featured_tags_limit, on: :create\n\n  def name=(str)\n    self.tag = Tag.find_or_initialize_by(name: str.strip.delete('#').mb_chars.downcase.to_s)\n  end\n\n  def increment(timestamp)\n    update(statuses_count: statuses_count + 1, last_status_at: timestamp)\n  end\n\n  def decrement(deleted_status_id)\n    update(statuses_count: [0, statuses_count - 1].max, last_status_at: account.statuses.where(visibility: %i(public unlisted)).tagged_with(tag).where.not(id: deleted_status_id).select(:created_at).first&.created_at)\n  end\n\n  def reset_data\n    self.statuses_count = account.statuses.where(visibility: %i(public unlisted)).tagged_with(tag).count\n    self.last_status_at = account.statuses.where(visibility: %i(public unlisted)).tagged_with(tag).select(:created_at).first&.created_at\n  end\n\n  private\n\n  def validate_featured_tags_limit\n    errors.add(:base, I18n.t('featured_tags.errors.limit')) if account.featured_tags.count >= 10\n  end\nend\n"
  },
  {
    "path": "app/models/feed.rb",
    "content": "# frozen_string_literal: true\n\nclass Feed\n  include Redisable\n\n  def initialize(type, id)\n    @type = type\n    @id   = id\n  end\n\n  def get(limit, max_id = nil, since_id = nil, min_id = nil)\n    from_redis(limit, max_id, since_id, min_id)\n  end\n\n  protected\n\n  def from_redis(limit, max_id, since_id, min_id)\n    if min_id.blank?\n      max_id     = '+inf' if max_id.blank?\n      since_id   = '-inf' if since_id.blank?\n      unhydrated = redis.zrevrangebyscore(key, \"(#{max_id}\", \"(#{since_id}\", limit: [0, limit], with_scores: true).map(&:first).map(&:to_i)\n    else\n      unhydrated = redis.zrangebyscore(key, \"(#{min_id}\", '+inf', limit: [0, limit], with_scores: true).map(&:first).map(&:to_i)\n    end\n\n    Status.where(id: unhydrated).cache_ids\n  end\n\n  def key\n    FeedManager.instance.key(@type, @id)\n  end\nend\n"
  },
  {
    "path": "app/models/follow.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: follows\n#\n#  id                :bigint(8)        not null, primary key\n#  created_at        :datetime         not null\n#  updated_at        :datetime         not null\n#  account_id        :bigint(8)        not null\n#  target_account_id :bigint(8)        not null\n#  show_reblogs      :boolean          default(TRUE), not null\n#  uri               :string\n#\n\nclass Follow < ApplicationRecord\n  include Paginable\n  include RelationshipCacheable\n\n  belongs_to :account\n  belongs_to :target_account, class_name: 'Account'\n\n  has_one :notification, as: :activity, dependent: :destroy\n\n  validates :account_id, uniqueness: { scope: :target_account_id }\n  validates_with FollowLimitValidator, on: :create\n\n  scope :recent, -> { reorder(id: :desc) }\n\n  def local?\n    false # Force uri_for to use uri attribute\n  end\n\n  def revoke_request!\n    FollowRequest.create!(account: account, target_account: target_account, show_reblogs: show_reblogs, uri: uri)\n    destroy!\n  end\n\n  before_validation :set_uri, only: :create\n  after_create :increment_cache_counters\n  after_destroy :remove_endorsements\n  after_destroy :decrement_cache_counters\n\n  private\n\n  def set_uri\n    self.uri = ActivityPub::TagManager.instance.generate_uri_for(self) if uri.nil?\n  end\n\n  def remove_endorsements\n    AccountPin.where(target_account_id: target_account_id, account_id: account_id).delete_all\n  end\n\n  def increment_cache_counters\n    account&.increment_count!(:following_count)\n    target_account&.increment_count!(:followers_count)\n  end\n\n  def decrement_cache_counters\n    account&.decrement_count!(:following_count)\n    target_account&.decrement_count!(:followers_count)\n  end\nend\n"
  },
  {
    "path": "app/models/follow_request.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: follow_requests\n#\n#  id                :bigint(8)        not null, primary key\n#  created_at        :datetime         not null\n#  updated_at        :datetime         not null\n#  account_id        :bigint(8)        not null\n#  target_account_id :bigint(8)        not null\n#  show_reblogs      :boolean          default(TRUE), not null\n#  uri               :string\n#\n\nclass FollowRequest < ApplicationRecord\n  include Paginable\n  include RelationshipCacheable\n\n  belongs_to :account\n  belongs_to :target_account, class_name: 'Account'\n\n  has_one :notification, as: :activity, dependent: :destroy\n\n  validates :account_id, uniqueness: { scope: :target_account_id }\n  validates_with FollowLimitValidator, on: :create\n\n  def authorize!\n    account.follow!(target_account, reblogs: show_reblogs, uri: uri)\n    MergeWorker.perform_async(target_account.id, account.id) if account.local?\n    destroy!\n  end\n\n  alias reject! destroy!\n\n  def local?\n    false # Force uri_for to use uri attribute\n  end\n\n  before_validation :set_uri, only: :create\n\n  private\n\n  def set_uri\n    self.uri = ActivityPub::TagManager.instance.generate_uri_for(self) if uri.nil?\n  end\nend\n"
  },
  {
    "path": "app/models/form/account_batch.rb",
    "content": "# frozen_string_literal: true\n\nclass Form::AccountBatch\n  include ActiveModel::Model\n  include Authorization\n  include Payloadable\n\n  attr_accessor :account_ids, :action, :current_account\n\n  def save\n    case action\n    when 'unfollow'\n      unfollow!\n    when 'remove_from_followers'\n      remove_from_followers!\n    when 'block_domains'\n      block_domains!\n    when 'approve'\n      approve!\n    when 'reject'\n      reject!\n    end\n  end\n\n  private\n\n  def unfollow!\n    accounts.find_each do |target_account|\n      UnfollowService.new.call(current_account, target_account)\n    end\n  end\n\n  def remove_from_followers!\n    current_account.passive_relationships.where(account_id: account_ids).find_each do |follow|\n      reject_follow!(follow)\n    end\n  end\n\n  def block_domains!\n    AfterAccountDomainBlockWorker.push_bulk(account_domains) do |domain|\n      [current_account.id, domain]\n    end\n  end\n\n  def account_domains\n    accounts.pluck(Arel.sql('distinct domain')).compact\n  end\n\n  def accounts\n    Account.where(id: account_ids)\n  end\n\n  def reject_follow!(follow)\n    follow.destroy\n\n    return unless follow.account.activitypub?\n\n    ActivityPub::DeliveryWorker.perform_async(Oj.dump(serialize_payload(follow, ActivityPub::RejectFollowSerializer)), current_account.id, follow.account.inbox_url)\n  end\n\n  def approve!\n    users = accounts.includes(:user).map(&:user)\n\n    users.each { |user| authorize(user, :approve?) }\n         .each(&:approve!)\n  end\n\n  def reject!\n    records = accounts.includes(:user)\n\n    records.each { |account| authorize(account.user, :reject?) }\n           .each { |account| SuspendAccountService.new.call(account, including_user: true, destroy: true, skip_distribution: true) }\n  end\nend\n"
  },
  {
    "path": "app/models/form/admin_settings.rb",
    "content": "# frozen_string_literal: true\n\nclass Form::AdminSettings\n  include ActiveModel::Model\n\n  KEYS = %i(\n    site_contact_username\n    site_contact_email\n    site_title\n    site_short_description\n    site_description\n    site_extended_description\n    site_terms\n    max_bio_chars\n    max_toot_chars\n    registrations_mode\n    closed_registrations_message\n    open_deletion\n    timeline_preview\n    show_staff_badge\n    bootstrap_timeline_accounts\n    theme\n    min_invite_role\n    activity_api_enabled\n    peers_api_enabled\n    show_known_fediverse_at_about_page\n    preview_sensitive_media\n    custom_css\n    profile_directory\n    thumbnail\n    hero\n    mascot\n  ).freeze\n\n  BOOLEAN_KEYS = %i(\n    open_deletion\n    timeline_preview\n    show_staff_badge\n    activity_api_enabled\n    peers_api_enabled\n    show_known_fediverse_at_about_page\n    preview_sensitive_media\n    profile_directory\n  ).freeze\n  \n  INTEGER_KEYS = %i(\n    max_bio_chars\n    max_toot_chars\n  ).freeze\n\n  UPLOAD_KEYS = %i(\n    thumbnail\n    hero\n    mascot\n  ).freeze\n\n  attr_accessor(*KEYS)\n\n  validates :site_short_description, :site_description, html: { wrap_with: :p }\n  validates :site_extended_description, :site_terms, :closed_registrations_message, html: true\n  validates :registrations_mode, inclusion: { in: %w(open approved none) }\n  validates :min_invite_role, inclusion: { in: %w(disabled user moderator admin) }\n  validates :site_contact_email, :site_contact_username, presence: true\n  validates :site_contact_username, existing_username: true\n  validates :bootstrap_timeline_accounts, existing_username: { multiple: true }\n\n  def initialize(_attributes = {})\n    super\n    initialize_attributes\n  end\n\n  def save\n    return false unless valid?\n\n    KEYS.each do |key|\n      value = instance_variable_get(\"@#{key}\")\n\n      if UPLOAD_KEYS.include?(key) && !value.nil?\n        upload = SiteUpload.where(var: key).first_or_initialize(var: key)\n        upload.update(file: value)\n      else\n        setting = Setting.where(var: key).first_or_initialize(var: key)\n        setting.update(value: typecast_value(key, value))\n      end\n    end\n  end\n\n  private\n\n  def initialize_attributes\n    KEYS.each do |key|\n      instance_variable_set(\"@#{key}\", Setting.public_send(key)) if instance_variable_get(\"@#{key}\").nil?\n    end\n  end\n\n  def typecast_value(key, value)\n    if BOOLEAN_KEYS.include?(key)\n      value == '1'\n    elsif INTEGER_KEYS.include?(key)\n      value.to_i\n    else\n      value\n    end\n  end\n  delegate(\n    :site_contact_username,\n    :site_contact_username=,\n    :site_contact_email,\n    :site_contact_email=,\n    :site_title,\n    :site_title=,\n    :site_short_description,\n    :site_short_description=,\n    :site_description,\n    :site_description=,\n    :site_extended_description,\n    :site_extended_description=,\n    :site_terms,\n    :site_terms=,\n    :max_bio_chars,\n    :max_bio_chars=,\n    :max_toot_chars,\n    :max_toot_chars=,\n    :open_registrations,\n    :open_registrations=,\n    :closed_registrations_message,\n    :closed_registrations_message=,\n    :open_deletion,\n    :open_deletion=,\n    :timeline_preview,\n    :timeline_preview=,\n    :show_staff_badge,\n    :show_staff_badge=,\n    :bootstrap_timeline_accounts,\n    :bootstrap_timeline_accounts=,\n    :theme,\n    :theme=,\n    :min_invite_role,\n    :min_invite_role=,\n    :activity_api_enabled,\n    :activity_api_enabled=,\n    :peers_api_enabled,\n    :peers_api_enabled=,\n    :show_known_fediverse_at_about_page,\n    :show_known_fediverse_at_about_page=,\n    :preview_sensitive_media,\n    :preview_sensitive_media=,\n    :custom_css,\n    :custom_css=,\n    :profile_directory,\n    :profile_directory=,\n    to: Setting\n  )\nend\n"
  },
  {
    "path": "app/models/form/delete_confirmation.rb",
    "content": "# frozen_string_literal: true\n\nclass Form::DeleteConfirmation\n  include ActiveModel::Model\n\n  attr_accessor :password\nend\n"
  },
  {
    "path": "app/models/form/migration.rb",
    "content": "# frozen_string_literal: true\n\nclass Form::Migration\n  include ActiveModel::Validations\n\n  attr_accessor :acct, :account\n\n  def initialize(attrs = {})\n    @account = attrs[:account]\n    @acct    = attrs[:account].acct unless @account.nil?\n    @acct    = attrs[:acct].gsub(/\\A@/, '').strip unless attrs[:acct].nil?\n  end\n\n  def valid?\n    return false unless super\n    set_account\n    errors.empty?\n  end\n\n  private\n\n  def set_account\n    self.account = (ResolveAccountService.new.call(acct) if account.nil? && acct.present?)\n  end\nend\n"
  },
  {
    "path": "app/models/form/status_batch.rb",
    "content": "# frozen_string_literal: true\n\nclass Form::StatusBatch\n  include ActiveModel::Model\n  include AccountableConcern\n\n  attr_accessor :status_ids, :action, :current_account\n\n  def save\n    case action\n    when 'nsfw_on', 'nsfw_off'\n      change_sensitive(action == 'nsfw_on')\n    when 'delete'\n      delete_statuses\n    end\n  end\n\n  private\n\n  def change_sensitive(sensitive)\n    media_attached_status_ids = MediaAttachment.where(status_id: status_ids).pluck(:status_id)\n\n    ApplicationRecord.transaction do\n      Status.where(id: media_attached_status_ids).reorder(nil).find_each do |status|\n        status.update!(sensitive: sensitive)\n        log_action :update, status\n      end\n    end\n\n    true\n  rescue ActiveRecord::RecordInvalid\n    false\n  end\n\n  def delete_statuses\n    Status.where(id: status_ids).reorder(nil).find_each do |status|\n      RemovalWorker.perform_async(status.id)\n      Tombstone.find_or_create_by(uri: status.uri, account: status.account, by_moderator: true)\n      log_action :destroy, status\n    end\n\n    true\n  end\nend\n"
  },
  {
    "path": "app/models/form/two_factor_confirmation.rb",
    "content": "# frozen_string_literal: true\n\nclass Form::TwoFactorConfirmation\n  include ActiveModel::Model\n\n  attr_accessor :code\nend\n"
  },
  {
    "path": "app/models/home_feed.rb",
    "content": "# frozen_string_literal: true\n\nclass HomeFeed < Feed\n  def initialize(account)\n    @type    = :home\n    @id      = account.id\n    @account = account\n  end\n\n  def get(limit, max_id = nil, since_id = nil, min_id = nil)\n    if redis.exists(\"account:#{@account.id}:regeneration\")\n      from_database(limit, max_id, since_id, min_id)\n    else\n      super\n    end\n  end\n\n  private\n\n  def from_database(limit, max_id, since_id, min_id)\n    Status.as_home_timeline(@account)\n          .paginate_by_id(limit, max_id: max_id, since_id: since_id, min_id: min_id)\n          .reject { |status| FeedManager.instance.filter?(:home, status, @account.id) }\n  end\nend\n"
  },
  {
    "path": "app/models/identity.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: identities\n#\n#  provider   :string           default(\"\"), not null\n#  uid        :string           default(\"\"), not null\n#  created_at :datetime         not null\n#  updated_at :datetime         not null\n#  id         :bigint(8)        not null, primary key\n#  user_id    :bigint(8)\n#\n\nclass Identity < ApplicationRecord\n  belongs_to :user, dependent: :destroy\n  validates :uid, presence: true, uniqueness: { scope: :provider }\n  validates :provider, presence: true\n\n  def self.find_for_oauth(auth)\n    find_or_create_by(uid: auth.uid, provider: auth.provider)\n  end\nend\n"
  },
  {
    "path": "app/models/import.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: imports\n#\n#  id                :bigint(8)        not null, primary key\n#  type              :integer          not null\n#  approved          :boolean          default(FALSE), not null\n#  created_at        :datetime         not null\n#  updated_at        :datetime         not null\n#  data_file_name    :string\n#  data_content_type :string\n#  data_file_size    :integer\n#  data_updated_at   :datetime\n#  account_id        :bigint(8)        not null\n#  overwrite         :boolean          default(FALSE), not null\n#\n\nclass Import < ApplicationRecord\n  FILE_TYPES = %w(text/plain text/csv).freeze\n  MODES = %i(merge overwrite).freeze\n\n  self.inheritance_column = false\n\n  belongs_to :account\n\n  enum type: [:following, :blocking, :muting, :domain_blocking]\n\n  validates :type, presence: true\n\n  has_attached_file :data\n  validates_attachment_content_type :data, content_type: FILE_TYPES\n  validates_attachment_presence :data\n\n  def mode\n    overwrite? ? :overwrite : :merge\n  end\n\n  def mode=(str)\n    self.overwrite = str.to_sym == :overwrite\n  end\nend\n"
  },
  {
    "path": "app/models/instance.rb",
    "content": "# frozen_string_literal: true\n\nclass Instance\n  include ActiveModel::Model\n\n  attr_accessor :domain, :accounts_count, :domain_block\n\n  def initialize(resource)\n    @domain         = resource.domain\n    @accounts_count = resource.is_a?(DomainBlock) ? nil : resource.accounts_count\n    @domain_block   = resource.is_a?(DomainBlock) ? resource : DomainBlock.find_by(domain: domain)\n  end\n\n  def cached_sample_accounts\n    Rails.cache.fetch(\"#{cache_key}/sample_accounts\", expires_in: 12.hours) { Account.where(domain: domain).searchable.joins(:account_stat).popular.limit(3) }\n  end\n\n  def cached_accounts_count\n    @accounts_count || Rails.cache.fetch(\"#{cache_key}/count\", expires_in: 12.hours) { Account.where(domain: domain).count }\n  end\n\n  def to_param\n    domain\n  end\n\n  def cache_key\n    domain\n  end\nend\n"
  },
  {
    "path": "app/models/instance_filter.rb",
    "content": "# frozen_string_literal: true\n\nclass InstanceFilter\n  attr_reader :params\n\n  def initialize(params)\n    @params = params\n  end\n\n  def results\n    if params[:limited].present?\n      scope = DomainBlock\n      scope = scope.matches_domain(params[:by_domain]) if params[:by_domain].present?\n      scope.order(id: :desc)\n    else\n      scope = Account.remote\n      scope = scope.matches_domain(params[:by_domain]) if params[:by_domain].present?\n      scope.by_domain_accounts\n    end\n  end\nend\n"
  },
  {
    "path": "app/models/invite.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: invites\n#\n#  id         :bigint(8)        not null, primary key\n#  user_id    :bigint(8)        not null\n#  code       :string           default(\"\"), not null\n#  expires_at :datetime\n#  max_uses   :integer\n#  uses       :integer          default(0), not null\n#  created_at :datetime         not null\n#  updated_at :datetime         not null\n#  autofollow :boolean          default(FALSE), not null\n#\n\nclass Invite < ApplicationRecord\n  include Expireable\n\n  belongs_to :user\n  has_many :users, inverse_of: :invite\n\n  scope :available, -> { where(expires_at: nil).or(where('expires_at >= ?', Time.now.utc)) }\n\n  before_validation :set_code\n\n  def valid_for_use?\n    (max_uses.nil? || uses < max_uses) && !expired?\n  end\n\n  private\n\n  def set_code\n    loop do\n      self.code = ([*('a'..'z'), *('A'..'Z'), *('0'..'9')] - %w(0 1 I l O)).sample(8).join\n      break if Invite.find_by(code: code).nil?\n    end\n  end\nend\n"
  },
  {
    "path": "app/models/invite_filter.rb",
    "content": "# frozen_string_literal: true\n\nclass InviteFilter\n  attr_reader :params\n\n  def initialize(params)\n    @params = params\n  end\n\n  def results\n    scope = Invite.order(created_at: :desc)\n\n    params.each do |key, value|\n      scope.merge!(scope_for(key, value)) if value.present?\n    end\n\n    scope\n  end\n\n  private\n\n  def scope_for(key, _value)\n    case key.to_s\n    when 'available'\n      Invite.available\n    when 'expired'\n      Invite.expired\n    else\n      raise \"Unknown filter: #{key}\"\n    end\n  end\nend\n"
  },
  {
    "path": "app/models/list.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: lists\n#\n#  id         :bigint(8)        not null, primary key\n#  account_id :bigint(8)        not null\n#  title      :string           default(\"\"), not null\n#  created_at :datetime         not null\n#  updated_at :datetime         not null\n#\n\nclass List < ApplicationRecord\n  include Paginable\n\n  PER_ACCOUNT_LIMIT = 50\n\n  belongs_to :account, optional: true\n\n  has_many :list_accounts, inverse_of: :list, dependent: :destroy\n  has_many :accounts, through: :list_accounts\n\n  validates :title, presence: true\n\n  validates_each :account_id, on: :create do |record, _attr, value|\n    record.errors.add(:base, I18n.t('lists.errors.limit')) if List.where(account_id: value).count >= PER_ACCOUNT_LIMIT\n  end\n\n  before_destroy :clean_feed_manager\n\n  private\n\n  def clean_feed_manager\n    reblog_key       = FeedManager.instance.key(:list, id, 'reblogs')\n    reblogged_id_set = Redis.current.zrange(reblog_key, 0, -1)\n\n    Redis.current.pipelined do\n      Redis.current.del(FeedManager.instance.key(:list, id))\n      Redis.current.del(reblog_key)\n\n      reblogged_id_set.each do |reblogged_id|\n        reblog_set_key = FeedManager.instance.key(:list, id, \"reblogs:#{reblogged_id}\")\n        Redis.current.del(reblog_set_key)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "app/models/list_account.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: list_accounts\n#\n#  id         :bigint(8)        not null, primary key\n#  list_id    :bigint(8)        not null\n#  account_id :bigint(8)        not null\n#  follow_id  :bigint(8)        not null\n#\n\nclass ListAccount < ApplicationRecord\n  belongs_to :list\n  belongs_to :account\n  belongs_to :follow\n\n  validates :account_id, uniqueness: { scope: :list_id }\n\n  before_validation :set_follow\n\n  private\n\n  def set_follow\n    self.follow = Follow.find_by(account_id: list.account_id, target_account_id: account.id)\n  end\nend\n"
  },
  {
    "path": "app/models/list_feed.rb",
    "content": "# frozen_string_literal: true\n\nclass ListFeed < Feed\n  def initialize(list)\n    @type    = :list\n    @id      = list.id\n  end\nend\n"
  },
  {
    "path": "app/models/media_attachment.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: media_attachments\n#\n#  id                  :bigint(8)        not null, primary key\n#  status_id           :bigint(8)\n#  file_file_name      :string\n#  file_content_type   :string\n#  file_file_size      :integer\n#  file_updated_at     :datetime\n#  remote_url          :string           default(\"\"), not null\n#  created_at          :datetime         not null\n#  updated_at          :datetime         not null\n#  shortcode           :string\n#  type                :integer          default(\"image\"), not null\n#  file_meta           :json\n#  account_id          :bigint(8)\n#  description         :text\n#  scheduled_status_id :bigint(8)\n#  blurhash            :string\n#\n\nclass MediaAttachment < ApplicationRecord\n  self.inheritance_column = nil\n\n  enum type: [:image, :gifv, :video, :unknown]\n\n  IMAGE_FILE_EXTENSIONS = ['.jpg', '.jpeg', '.png', '.gif', '.webp'].freeze\n  VIDEO_FILE_EXTENSIONS = ['.webm', '.mp4', '.m4v', '.mov'].freeze\n\n  IMAGE_MIME_TYPES             = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'].freeze\n  VIDEO_MIME_TYPES             = ['video/webm', 'video/mp4', 'video/quicktime'].freeze\n  VIDEO_CONVERTIBLE_MIME_TYPES = ['video/webm', 'video/quicktime'].freeze\n\n  BLURHASH_OPTIONS = {\n    x_comp: 4,\n    y_comp: 4,\n  }.freeze\n\n  IMAGE_STYLES = {\n    original: {\n      pixels: 1_638_400, # 1280x1280px\n      file_geometry_parser: FastGeometryParser,\n    },\n\n    small: {\n      pixels: 160_000, # 400x400px\n      file_geometry_parser: FastGeometryParser,\n      blurhash: BLURHASH_OPTIONS,\n    },\n  }.freeze\n\n  VIDEO_STYLES = {\n    small: {\n      convert_options: {\n        output: {\n          vf: 'scale=\\'min(400\\, iw):min(400\\, ih)\\':force_original_aspect_ratio=decrease',\n        },\n      },\n      format: 'png',\n      time: 0,\n      file_geometry_parser: FastGeometryParser,\n      blurhash: BLURHASH_OPTIONS,\n    },\n  }.freeze\n\n  VIDEO_FORMAT = {\n    format: 'mp4',\n    convert_options: {\n      output: {\n        'loglevel' => 'fatal',\n        'movflags' => 'faststart',\n        'pix_fmt'  => 'yuv420p',\n        'vf'       => 'scale=\\'trunc(iw/2)*2:trunc(ih/2)*2\\'',\n        'vsync'    => 'cfr',\n        'c:v'      => 'h264',\n        'b:v'      => '500K',\n        'maxrate'  => '1300K',\n        'bufsize'  => '1300K',\n        'crf'      => 18,\n      },\n    },\n  }.freeze\n\n  IMAGE_LIMIT = 8.megabytes\n  VIDEO_LIMIT = 40.megabytes\n\n  belongs_to :account,          inverse_of: :media_attachments, optional: true\n  belongs_to :status,           inverse_of: :media_attachments, optional: true\n  belongs_to :scheduled_status, inverse_of: :media_attachments, optional: true\n\n  has_attached_file :file,\n                    styles: ->(f) { file_styles f },\n                    processors: ->(f) { file_processors f },\n                    convert_options: { all: '-quality 90 -strip' }\n\n  validates_attachment_content_type :file, content_type: IMAGE_MIME_TYPES + VIDEO_MIME_TYPES\n  validates_attachment_size :file, less_than: IMAGE_LIMIT, unless: :video_or_gifv?\n  validates_attachment_size :file, less_than: VIDEO_LIMIT, if: :video_or_gifv?\n  remotable_attachment :file, VIDEO_LIMIT\n\n  include Attachmentable\n\n  validates :account, presence: true\n  validates :description, length: { maximum: 420 }, if: :local?\n\n  scope :attached,   -> { where.not(status_id: nil).or(where.not(scheduled_status_id: nil)) }\n  scope :unattached, -> { where(status_id: nil, scheduled_status_id: nil) }\n  scope :local,      -> { where(remote_url: '') }\n  scope :remote,     -> { where.not(remote_url: '') }\n\n  default_scope { order(id: :asc) }\n\n  def local?\n    remote_url.blank?\n  end\n\n  def needs_redownload?\n    file.blank? && remote_url.present?\n  end\n\n  def video_or_gifv?\n    video? || gifv?\n  end\n\n  def to_param\n    shortcode\n  end\n\n  def focus=(point)\n    return if point.blank?\n\n    x, y = (point.is_a?(Enumerable) ? point : point.split(',')).map(&:to_f)\n\n    meta = file.instance_read(:meta) || {}\n    meta['focus'] = { 'x' => x, 'y' => y }\n\n    file.instance_write(:meta, meta)\n  end\n\n  def focus\n    x = file.meta['focus']['x']\n    y = file.meta['focus']['y']\n\n    \"#{x},#{y}\"\n  end\n\n  after_commit :reset_parent_cache, on: :update\n  before_create :prepare_description, unless: :local?\n  before_create :set_shortcode\n  before_post_process :set_type_and_extension\n  before_save :set_meta\n\n  class << self\n    private\n\n    def file_styles(f)\n      if f.instance.file_content_type == 'image/gif'\n        {\n          small: IMAGE_STYLES[:small],\n          original: VIDEO_FORMAT,\n        }\n      elsif IMAGE_MIME_TYPES.include? f.instance.file_content_type\n        IMAGE_STYLES\n      elsif VIDEO_CONVERTIBLE_MIME_TYPES.include?(f.instance.file_content_type)\n        {\n          small: VIDEO_STYLES[:small],\n          original: VIDEO_FORMAT,\n        }\n      else\n        VIDEO_STYLES\n      end\n    end\n\n    def file_processors(f)\n      if f.file_content_type == 'image/gif'\n        [:gif_transcoder, :blurhash_transcoder]\n      elsif VIDEO_MIME_TYPES.include? f.file_content_type\n        [:video_transcoder, :blurhash_transcoder]\n      else\n        [:lazy_thumbnail, :blurhash_transcoder]\n      end\n    end\n  end\n\n  private\n\n  def set_shortcode\n    self.type = :unknown if file.blank? && !type_changed?\n\n    return unless local?\n\n    loop do\n      self.shortcode = SecureRandom.urlsafe_base64(14)\n      break if MediaAttachment.find_by(shortcode: shortcode).nil?\n    end\n  end\n\n  def prepare_description\n    self.description = description.strip[0...420] unless description.nil?\n  end\n\n  def set_type_and_extension\n    self.type = VIDEO_MIME_TYPES.include?(file_content_type) ? :video : :image\n  end\n\n  def set_meta\n    meta = populate_meta\n    return if meta == {}\n    file.instance_write :meta, meta\n  end\n\n  def populate_meta\n    meta = file.instance_read(:meta) || {}\n\n    file.queued_for_write.each do |style, file|\n      meta[style] = style == :small || image? ? image_geometry(file) : video_metadata(file)\n    end\n\n    meta\n  end\n\n  def image_geometry(file)\n    width, height = FastImage.size(file.path)\n\n    return {} if width.nil?\n\n    {\n      width:  width,\n      height: height,\n      size: \"#{width}x#{height}\",\n      aspect: width.to_f / height.to_f,\n    }\n  end\n\n  def video_metadata(file)\n    movie = FFMPEG::Movie.new(file.path)\n\n    return {} unless movie.valid?\n\n    {\n      width: movie.width,\n      height: movie.height,\n      frame_rate: movie.frame_rate,\n      duration: movie.duration,\n      bitrate: movie.bitrate,\n    }\n  end\n\n  def reset_parent_cache\n    return if status_id.nil?\n    Rails.cache.delete(\"statuses/#{status_id}\")\n  end\nend\n"
  },
  {
    "path": "app/models/mention.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: mentions\n#\n#  id         :bigint(8)        not null, primary key\n#  status_id  :bigint(8)\n#  created_at :datetime         not null\n#  updated_at :datetime         not null\n#  account_id :bigint(8)\n#  silent     :boolean          default(FALSE), not null\n#\n\nclass Mention < ApplicationRecord\n  belongs_to :account, inverse_of: :mentions\n  belongs_to :status\n\n  has_one :notification, as: :activity, dependent: :destroy\n\n  validates :account, uniqueness: { scope: :status }\n\n  scope :active, -> { where(silent: false) }\n  scope :silent, -> { where(silent: true) }\n\n  delegate(\n    :username,\n    :acct,\n    to: :account,\n    prefix: true\n  )\n\n  def active?\n    !silent?\n  end\nend\n"
  },
  {
    "path": "app/models/mute.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: mutes\n#\n#  id                 :bigint(8)        not null, primary key\n#  created_at         :datetime         not null\n#  updated_at         :datetime         not null\n#  account_id         :bigint(8)        not null\n#  target_account_id  :bigint(8)        not null\n#  hide_notifications :boolean          default(TRUE), not null\n#\n\nclass Mute < ApplicationRecord\n  include Paginable\n  include RelationshipCacheable\n\n  belongs_to :account\n  belongs_to :target_account, class_name: 'Account'\n\n  validates :account_id, uniqueness: { scope: :target_account_id }\n\n  after_commit :remove_blocking_cache\n\n  private\n\n  def remove_blocking_cache\n    Rails.cache.delete(\"exclude_account_ids_for:#{account_id}\")\n  end\nend\n"
  },
  {
    "path": "app/models/notification.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: notifications\n#\n#  id              :bigint(8)        not null, primary key\n#  activity_id     :bigint(8)        not null\n#  activity_type   :string           not null\n#  created_at      :datetime         not null\n#  updated_at      :datetime         not null\n#  account_id      :bigint(8)        not null\n#  from_account_id :bigint(8)        not null\n#\n\nclass Notification < ApplicationRecord\n  include Paginable\n  include Cacheable\n\n  TYPE_CLASS_MAP = {\n    mention:        'Mention',\n    reblog:         'Status',\n    follow:         'Follow',\n    follow_request: 'FollowRequest',\n    favourite:      'Favourite',\n    poll:           'Poll',\n  }.freeze\n\n  STATUS_INCLUDES = [:account, :application, :preloadable_poll, :media_attachments, :tags, active_mentions: :account, reblog: [:account, :application, :preloadable_poll, :media_attachments, :tags, active_mentions: :account]].freeze\n\n  belongs_to :account, optional: true\n  belongs_to :from_account, class_name: 'Account', optional: true\n  belongs_to :activity, polymorphic: true, optional: true\n\n  belongs_to :mention,        foreign_type: 'Mention',       foreign_key: 'activity_id', optional: true\n  belongs_to :status,         foreign_type: 'Status',        foreign_key: 'activity_id', optional: true\n  belongs_to :follow,         foreign_type: 'Follow',        foreign_key: 'activity_id', optional: true\n  belongs_to :follow_request, foreign_type: 'FollowRequest', foreign_key: 'activity_id', optional: true\n  belongs_to :favourite,      foreign_type: 'Favourite',     foreign_key: 'activity_id', optional: true\n  belongs_to :poll,           foreign_type: 'Poll',          foreign_key: 'activity_id', optional: true\n\n  validates :account_id, uniqueness: { scope: [:activity_type, :activity_id] }\n  validates :activity_type, inclusion: { in: TYPE_CLASS_MAP.values }\n\n  scope :browserable, ->(exclude_types = [], account_id = nil) {\n    types = TYPE_CLASS_MAP.values - activity_types_from_types(exclude_types + [:follow_request])\n    if account_id.nil?\n      where(activity_type: types)\n    else\n      where(activity_type: types, from_account_id: account_id)\n    end\n  }\n\n  cache_associated :from_account, status: STATUS_INCLUDES, mention: [status: STATUS_INCLUDES], favourite: [:account, status: STATUS_INCLUDES], follow: :account, poll: [status: STATUS_INCLUDES]\n\n  def type\n    @type ||= TYPE_CLASS_MAP.invert[activity_type].to_sym\n  end\n\n  def target_status\n    case type\n    when :reblog\n      status&.reblog\n    when :favourite\n      favourite&.status\n    when :mention\n      mention&.status\n    when :poll\n      poll&.status\n    end\n  end\n\n  def browserable?\n    type != :follow_request\n  end\n\n  class << self\n    def cache_ids\n      select(:id, :updated_at, :activity_type, :activity_id)\n    end\n\n    def reload_stale_associations!(cached_items)\n      account_ids = (cached_items.map(&:from_account_id) + cached_items.map { |item| item.target_status&.account_id }.compact).uniq\n\n      return if account_ids.empty?\n\n      accounts = Account.where(id: account_ids).includes(:account_stat).each_with_object({}) { |a, h| h[a.id] = a }\n\n      cached_items.each do |item|\n        item.from_account = accounts[item.from_account_id]\n        item.target_status.account = accounts[item.target_status.account_id] if item.target_status\n      end\n    end\n\n    def activity_types_from_types(types)\n      types.map { |type| TYPE_CLASS_MAP[type.to_sym] }.compact\n    end\n  end\n\n  after_initialize :set_from_account\n  before_validation :set_from_account\n\n  private\n\n  def set_from_account\n    return unless new_record?\n\n    case activity_type\n    when 'Status', 'Follow', 'Favourite', 'FollowRequest', 'Poll'\n      self.from_account_id = activity&.account_id\n    when 'Mention'\n      self.from_account_id = activity&.status&.account_id\n    end\n  end\nend\n"
  },
  {
    "path": "app/models/poll.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: polls\n#\n#  id              :bigint(8)        not null, primary key\n#  account_id      :bigint(8)\n#  status_id       :bigint(8)\n#  expires_at      :datetime\n#  options         :string           default([]), not null, is an Array\n#  cached_tallies  :bigint(8)        default([]), not null, is an Array\n#  multiple        :boolean          default(FALSE), not null\n#  hide_totals     :boolean          default(FALSE), not null\n#  votes_count     :bigint(8)        default(0), not null\n#  last_fetched_at :datetime\n#  created_at      :datetime         not null\n#  updated_at      :datetime         not null\n#  lock_version    :integer          default(0), not null\n#\n\nclass Poll < ApplicationRecord\n  include Expireable\n\n  belongs_to :account\n  belongs_to :status\n\n  has_many :votes, class_name: 'PollVote', inverse_of: :poll, dependent: :destroy\n\n  has_many :notifications, as: :activity, dependent: :destroy\n\n  validates :options, presence: true\n  validates :expires_at, presence: true, if: :local?\n  validates_with PollValidator, on: :create, if: :local?\n\n  scope :attached, -> { where.not(status_id: nil) }\n  scope :unattached, -> { where(status_id: nil) }\n\n  before_validation :prepare_options\n  before_validation :prepare_votes_count\n\n  after_initialize :prepare_cached_tallies\n\n  after_commit :reset_parent_cache, on: :update\n\n  def loaded_options\n    options.map.with_index { |title, key| Option.new(self, key.to_s, title, show_totals_now? ? cached_tallies[key] : nil) }\n  end\n\n  def possibly_stale?\n    remote? && last_fetched_before_expiration? && time_passed_since_last_fetch?\n  end\n\n  def voted?(account)\n    account.id == account_id || votes.where(account: account).exists?\n  end\n\n  delegate :local?, to: :account\n\n  def remote?\n    !local?\n  end\n\n  def emojis\n    @emojis ||= CustomEmoji.from_text(options.join(' '), account.domain)\n  end\n\n  class Option < ActiveModelSerializers::Model\n    attributes :id, :title, :votes_count, :poll\n\n    def initialize(poll, id, title, votes_count)\n      @poll        = poll\n      @id          = id\n      @title       = title\n      @votes_count = votes_count\n    end\n  end\n\n  private\n\n  def prepare_cached_tallies\n    self.cached_tallies = options.map { 0 } if cached_tallies.empty?\n  end\n\n  def prepare_votes_count\n    self.votes_count = cached_tallies.sum unless cached_tallies.empty?\n  end\n\n  def prepare_options\n    self.options = options.map(&:strip).reject(&:blank?)\n  end\n\n  def reset_parent_cache\n    return if status_id.nil?\n    Rails.cache.delete(\"statuses/#{status_id}\")\n  end\n\n  def last_fetched_before_expiration?\n    last_fetched_at.nil? || expires_at.nil? || last_fetched_at < expires_at\n  end\n\n  def time_passed_since_last_fetch?\n    last_fetched_at.nil? || last_fetched_at < 1.minute.ago\n  end\n\n  def show_totals_now?\n    expired? || !hide_totals?\n  end\nend\n"
  },
  {
    "path": "app/models/poll_vote.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: poll_votes\n#\n#  id         :bigint(8)        not null, primary key\n#  account_id :bigint(8)\n#  poll_id    :bigint(8)\n#  choice     :integer          default(0), not null\n#  created_at :datetime         not null\n#  updated_at :datetime         not null\n#  uri        :string\n#\n\nclass PollVote < ApplicationRecord\n  belongs_to :account\n  belongs_to :poll, inverse_of: :votes\n\n  validates :choice, presence: true\n  validates_with VoteValidator\n\n  after_create_commit :increment_counter_cache\n\n  delegate :local?, to: :account\n\n  def object_type\n    :vote\n  end\n\n  private\n\n  def increment_counter_cache\n    poll.cached_tallies[choice] = (poll.cached_tallies[choice] || 0) + 1\n    poll.save\n  rescue ActiveRecord::StaleObjectError\n    poll.reload\n    retry\n  end\nend\n"
  },
  {
    "path": "app/models/preview_card.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: preview_cards\n#\n#  id                 :bigint(8)        not null, primary key\n#  url                :string           default(\"\"), not null\n#  title              :string           default(\"\"), not null\n#  description        :string           default(\"\"), not null\n#  image_file_name    :string\n#  image_content_type :string\n#  image_file_size    :integer\n#  image_updated_at   :datetime\n#  type               :integer          default(\"link\"), not null\n#  html               :text             default(\"\"), not null\n#  author_name        :string           default(\"\"), not null\n#  author_url         :string           default(\"\"), not null\n#  provider_name      :string           default(\"\"), not null\n#  provider_url       :string           default(\"\"), not null\n#  width              :integer          default(0), not null\n#  height             :integer          default(0), not null\n#  created_at         :datetime         not null\n#  updated_at         :datetime         not null\n#  embed_url          :string           default(\"\"), not null\n#\n\nclass PreviewCard < ApplicationRecord\n  IMAGE_MIME_TYPES = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'].freeze\n  LIMIT = 1.megabytes\n\n  self.inheritance_column = false\n\n  enum type: [:link, :photo, :video, :rich]\n\n  has_and_belongs_to_many :statuses\n\n  has_attached_file :image, styles: ->(f) { image_styles(f) }, convert_options: { all: '-quality 80 -strip' }\n\n  include Attachmentable\n\n  validates :url, presence: true, uniqueness: true\n  validates_attachment_content_type :image, content_type: IMAGE_MIME_TYPES\n  validates_attachment_size :image, less_than: LIMIT\n  remotable_attachment :image, LIMIT\n\n  before_save :extract_dimensions, if: :link?\n\n  def save_with_optional_image!\n    save!\n  rescue ActiveRecord::RecordInvalid\n    self.image = nil\n    save!\n  end\n\n  class << self\n    private\n\n    def image_styles(f)\n      styles = {\n        original: {\n          geometry: '400x400>',\n          file_geometry_parser: FastGeometryParser,\n          convert_options: '-coalesce -strip',\n        },\n      }\n\n      styles[:original][:format] = 'jpg' if f.instance.image_content_type == 'image/gif'\n      styles\n    end\n  end\n\n  private\n\n  def extract_dimensions\n    file = image.queued_for_write[:original]\n\n    return if file.nil?\n\n    width, height = FastImage.size(file.path)\n\n    return nil if width.nil?\n\n    self.width  = width\n    self.height = height\n  end\nend\n"
  },
  {
    "path": "app/models/relay.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: relays\n#\n#  id                 :bigint(8)        not null, primary key\n#  inbox_url          :string           default(\"\"), not null\n#  follow_activity_id :string\n#  created_at         :datetime         not null\n#  updated_at         :datetime         not null\n#  state              :integer          default(\"idle\"), not null\n#\n\nclass Relay < ApplicationRecord\n  PRESET_RELAY = 'https://relay.joinmastodon.org/inbox'\n\n  validates :inbox_url, presence: true, uniqueness: true, url: true, if: :will_save_change_to_inbox_url?\n\n  enum state: [:idle, :pending, :accepted, :rejected]\n\n  scope :enabled, -> { accepted }\n\n  before_destroy :ensure_disabled\n\n  alias enabled? accepted?\n\n  def enable!\n    activity_id = ActivityPub::TagManager.instance.generate_uri_for(nil)\n    payload     = Oj.dump(follow_activity(activity_id))\n\n    update!(state: :pending, follow_activity_id: activity_id)\n    DeliveryFailureTracker.new(inbox_url).track_success!\n    ActivityPub::DeliveryWorker.perform_async(payload, some_local_account.id, inbox_url)\n  end\n\n  def disable!\n    activity_id = ActivityPub::TagManager.instance.generate_uri_for(nil)\n    payload     = Oj.dump(unfollow_activity(activity_id))\n\n    update!(state: :idle, follow_activity_id: nil)\n    DeliveryFailureTracker.new(inbox_url).track_success!\n    ActivityPub::DeliveryWorker.perform_async(payload, some_local_account.id, inbox_url)\n  end\n\n  private\n\n  def follow_activity(activity_id)\n    {\n      '@context': ActivityPub::TagManager::CONTEXT,\n      id: activity_id,\n      type: 'Follow',\n      actor: ActivityPub::TagManager.instance.uri_for(some_local_account),\n      object: ActivityPub::TagManager::COLLECTIONS[:public],\n    }\n  end\n\n  def unfollow_activity(activity_id)\n    {\n      '@context': ActivityPub::TagManager::CONTEXT,\n      id: activity_id,\n      type: 'Undo',\n      actor: ActivityPub::TagManager.instance.uri_for(some_local_account),\n      object: {\n        id: follow_activity_id,\n        type: 'Follow',\n        actor: ActivityPub::TagManager.instance.uri_for(some_local_account),\n        object: ActivityPub::TagManager::COLLECTIONS[:public],\n      },\n    }\n  end\n\n  def some_local_account\n    @some_local_account ||= Account.representative\n  end\n\n  def ensure_disabled\n    return unless enabled?\n    disable!\n  end\nend\n"
  },
  {
    "path": "app/models/remote_follow.rb",
    "content": "# frozen_string_literal: true\n\nclass RemoteFollow\n  include ActiveModel::Validations\n\n  attr_accessor :acct, :addressable_template\n\n  validates :acct, presence: true\n\n  def initialize(attrs = nil)\n    @acct = attrs[:acct].gsub(/\\A@/, '').strip if !attrs.nil? && !attrs[:acct].nil?\n  end\n\n  def valid?\n    return false unless super\n\n    populate_template\n    errors.empty?\n  end\n\n  def subscribe_address_for(account)\n    addressable_template.expand(uri: account.local_username_and_domain).to_s\n  end\n\n  def interact_address_for(status)\n    addressable_template.expand(uri: ActivityPub::TagManager.instance.uri_for(status)).to_s\n  end\n\n  private\n\n  def populate_template\n    if acct.blank? || redirect_url_link.nil? || redirect_url_link.template.nil?\n      missing_resource_error\n    else\n      @addressable_template = Addressable::Template.new(redirect_uri_template)\n    end\n  end\n\n  def redirect_uri_template\n    redirect_url_link.template\n  end\n\n  def redirect_url_link\n    acct_resource&.link('http://ostatus.org/schema/1.0/subscribe')\n  end\n\n  def acct_resource\n    @_acct_resource ||= Goldfinger.finger(\"acct:#{acct}\")\n  rescue Goldfinger::Error, HTTP::ConnectionError\n    nil\n  end\n\n  def missing_resource_error\n    errors.add(:acct, I18n.t('remote_follow.missing_resource'))\n  end\nend\n"
  },
  {
    "path": "app/models/remote_profile.rb",
    "content": "# frozen_string_literal: true\n\nclass RemoteProfile\n  include ActiveModel::Model\n\n  attr_reader :document\n\n  def initialize(body)\n    @document = Nokogiri::XML.parse(body, nil, 'utf-8')\n  end\n\n  def root\n    @root ||= document.at_xpath('/atom:feed|/atom:entry', atom: OStatus::TagManager::XMLNS)\n  end\n\n  def author\n    @author ||= root.at_xpath('./atom:author|./dfrn:owner', atom: OStatus::TagManager::XMLNS, dfrn: OStatus::TagManager::DFRN_XMLNS)\n  end\n\n  def hub_link\n    @hub_link ||= link_href_from_xml(root, 'hub')\n  end\n\n  def display_name\n    @display_name ||= author.at_xpath('./poco:displayName', poco: OStatus::TagManager::POCO_XMLNS)&.content\n  end\n\n  def note\n    @note ||= author.at_xpath('./atom:summary|./poco:note', atom: OStatus::TagManager::XMLNS, poco: OStatus::TagManager::POCO_XMLNS)&.content\n  end\n\n  def scope\n    @scope ||= author.at_xpath('./mastodon:scope', mastodon: OStatus::TagManager::MTDN_XMLNS)&.content\n  end\n\n  def avatar\n    @avatar ||= link_href_from_xml(author, 'avatar')\n  end\n\n  def header\n    @header ||= link_href_from_xml(author, 'header')\n  end\n\n  def emojis\n    @emojis ||= author.xpath('./xmlns:link[@rel=\"emoji\"]', xmlns: OStatus::TagManager::XMLNS)\n  end\n\n  def locked?\n    scope == 'private'\n  end\n\n  private\n\n  def link_href_from_xml(xml, type)\n    xml.at_xpath(%(./atom:link[@rel=\"#{type}\"]/@href), atom: OStatus::TagManager::XMLNS)&.content\n  end\nend\n"
  },
  {
    "path": "app/models/report.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: reports\n#\n#  id                         :bigint(8)        not null, primary key\n#  status_ids                 :bigint(8)        default([]), not null, is an Array\n#  comment                    :text             default(\"\"), not null\n#  action_taken               :boolean          default(FALSE), not null\n#  created_at                 :datetime         not null\n#  updated_at                 :datetime         not null\n#  account_id                 :bigint(8)        not null\n#  action_taken_by_account_id :bigint(8)\n#  target_account_id          :bigint(8)        not null\n#  assigned_account_id        :bigint(8)\n#  uri                        :string\n#\n\nclass Report < ApplicationRecord\n  belongs_to :account\n  belongs_to :target_account, class_name: 'Account'\n  belongs_to :action_taken_by_account, class_name: 'Account', optional: true\n  belongs_to :assigned_account, class_name: 'Account', optional: true\n\n  has_many :notes, class_name: 'ReportNote', foreign_key: :report_id, inverse_of: :report, dependent: :destroy\n\n  scope :unresolved, -> { where(action_taken: false) }\n  scope :resolved,   -> { where(action_taken: true) }\n\n  validates :comment, length: { maximum: 1000 }\n\n  def local?\n    false # Force uri_for to use uri attribute\n  end\n\n  before_validation :set_uri, only: :create\n\n  def object_type\n    :flag\n  end\n\n  def statuses\n    Status.where(id: status_ids).includes(:account, :media_attachments, :mentions)\n  end\n\n  def media_attachments\n    MediaAttachment.where(status_id: status_ids)\n  end\n\n  def assign_to_self!(current_account)\n    update!(assigned_account_id: current_account.id)\n  end\n\n  def unassign!\n    update!(assigned_account_id: nil)\n  end\n\n  def resolve!(acting_account)\n    update!(action_taken: true, action_taken_by_account_id: acting_account.id)\n  end\n\n  def unresolve!\n    update!(action_taken: false, action_taken_by_account_id: nil)\n  end\n\n  def unresolved?\n    !action_taken?\n  end\n\n  def unresolved_siblings?\n    Report.where.not(id: id).where(target_account_id: target_account_id).unresolved.exists?\n  end\n\n  def history\n    time_range = created_at..updated_at\n\n    sql = [\n      Admin::ActionLog.where(\n        target_type: 'Report',\n        target_id: id,\n        created_at: time_range\n      ).unscope(:order),\n\n      Admin::ActionLog.where(\n        target_type: 'Account',\n        target_id: target_account_id,\n        created_at: time_range\n      ).unscope(:order),\n\n      Admin::ActionLog.where(\n        target_type: 'Status',\n        target_id: status_ids,\n        created_at: time_range\n      ).unscope(:order),\n    ].map { |query| \"(#{query.to_sql})\" }.join(' UNION ALL ')\n\n    Admin::ActionLog.from(\"(#{sql}) AS admin_action_logs\")\n  end\n\n  def set_uri\n    self.uri = ActivityPub::TagManager.instance.generate_uri_for(self) if uri.nil? && account.local?\n  end\nend\n"
  },
  {
    "path": "app/models/report_filter.rb",
    "content": "# frozen_string_literal: true\n\nclass ReportFilter\n  attr_reader :params\n\n  def initialize(params)\n    @params = params\n  end\n\n  def results\n    scope = Report.unresolved\n    params.each do |key, value|\n      scope = scope.merge scope_for(key, value)\n    end\n    scope\n  end\n\n  def scope_for(key, value)\n    case key.to_sym\n    when :resolved\n      Report.resolved\n    when :account_id\n      Report.where(account_id: value)\n    when :target_account_id\n      Report.where(target_account_id: value)\n    else\n      raise \"Unknown filter: #{key}\"\n    end\n  end\nend\n"
  },
  {
    "path": "app/models/report_note.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: report_notes\n#\n#  id         :bigint(8)        not null, primary key\n#  content    :text             not null\n#  report_id  :bigint(8)        not null\n#  account_id :bigint(8)        not null\n#  created_at :datetime         not null\n#  updated_at :datetime         not null\n#\n\nclass ReportNote < ApplicationRecord\n  belongs_to :account\n  belongs_to :report, inverse_of: :notes, touch: true\n\n  scope :latest, -> { reorder(created_at: :desc) }\n\n  validates :content, presence: true, length: { maximum: 500 }\nend\n"
  },
  {
    "path": "app/models/scheduled_status.rb",
    "content": "# frozen_string_literal: true\n\n# == Schema Information\n#\n# Table name: scheduled_statuses\n#\n#  id           :bigint(8)        not null, primary key\n#  account_id   :bigint(8)\n#  scheduled_at :datetime\n#  params       :jsonb\n#\n\nclass ScheduledStatus < ApplicationRecord\n  include Paginable\n\n  TOTAL_LIMIT = 300\n  DAILY_LIMIT = 25\n\n  belongs_to :account, inverse_of: :scheduled_statuses\n  has_many :media_attachments, inverse_of: :scheduled_status, dependent: :nullify\n\n  validate :validate_future_date\n  validate :validate_total_limit\n  validate :validate_daily_limit\n\n  private\n\n  def validate_future_date\n    errors.add(:scheduled_at, I18n.t('scheduled_statuses.too_soon')) if scheduled_at.present? && scheduled_at <= Time.now.utc + PostStatusService::MIN_SCHEDULE_OFFSET\n  end\n\n  def validate_total_limit\n    errors.add(:base, I18n.t('scheduled_statuses.over_total_limit', limit: TOTAL_LIMIT)) if account.scheduled_statuses.count >= TOTAL_LIMIT\n  end\n\n  def validate_daily_limit\n    errors.add(:base, I18n.t('scheduled_statuses.over_daily_limit', limit: DAILY_LIMIT)) if account.scheduled_statuses.where('scheduled_at::date = ?::date', scheduled_at).count >= DAILY_LIMIT\n  end\nend\n"
  },
  {
    "path": "app/models/search.rb",
    "content": "# frozen_string_literal: true\n\nclass Search < ActiveModelSerializers::Model\n  attributes :accounts, :statuses, :hashtags\nend\n"
  },
  {
    "path": "app/models/session_activation.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: session_activations\n#\n#  id                       :bigint(8)        not null, primary key\n#  session_id               :string           not null\n#  created_at               :datetime         not null\n#  updated_at               :datetime         not null\n#  user_agent               :string           default(\"\"), not null\n#  ip                       :inet\n#  access_token_id          :bigint(8)\n#  user_id                  :bigint(8)        not null\n#  web_push_subscription_id :bigint(8)\n#\n\nclass SessionActivation < ApplicationRecord\n  belongs_to :user, inverse_of: :session_activations\n  belongs_to :access_token, class_name: 'Doorkeeper::AccessToken', dependent: :destroy, optional: true\n  belongs_to :web_push_subscription, class_name: 'Web::PushSubscription', dependent: :destroy, optional: true\n\n  delegate :token,\n           to: :access_token,\n           allow_nil: true\n\n  def detection\n    @detection ||= Browser.new(user_agent)\n  end\n\n  def browser\n    detection.id\n  end\n\n  def platform\n    detection.platform.id\n  end\n\n  before_create :assign_access_token\n  before_save   :assign_user_agent\n\n  class << self\n    def active?(id)\n      id && where(session_id: id).exists?\n    end\n\n    def activate(**options)\n      activation = create!(options)\n      purge_old\n      activation\n    end\n\n    def deactivate(id)\n      return unless id\n      where(session_id: id).destroy_all\n    end\n\n    def purge_old\n      order('created_at desc').offset(Rails.configuration.x.max_session_activations).destroy_all\n    end\n\n    def exclusive(id)\n      where('session_id != ?', id).destroy_all\n    end\n  end\n\n  private\n\n  def assign_user_agent\n    self.user_agent = '' if user_agent.nil?\n  end\n\n  def assign_access_token\n    superapp = Doorkeeper::Application.find_by(superapp: true)\n\n    self.access_token = Doorkeeper::AccessToken.create!(application_id: superapp&.id,\n                                                        resource_owner_id: user_id,\n                                                        scopes: 'read write follow',\n                                                        expires_in: Doorkeeper.configuration.access_token_expires_in,\n                                                        use_refresh_token: Doorkeeper.configuration.refresh_token_enabled?)\n  end\nend\n"
  },
  {
    "path": "app/models/setting.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: settings\n#\n#  id         :bigint(8)        not null, primary key\n#  var        :string           not null\n#  value      :text\n#  thing_type :string\n#  created_at :datetime\n#  updated_at :datetime\n#  thing_id   :bigint(8)\n#\n\nclass Setting < RailsSettings::Base\n  source Rails.root.join('config', 'settings.yml')\n\n  def to_param\n    var\n  end\n\n  class << self\n    def [](key)\n      return super(key) unless rails_initialized?\n\n      val = Rails.cache.fetch(cache_key(key, nil)) do\n        db_val = object(key)\n\n        if db_val\n          default_value = default_settings[key]\n\n          return default_value.with_indifferent_access.merge!(db_val.value) if default_value.is_a?(Hash)\n          db_val.value\n        else\n          default_settings[key]\n        end\n      end\n      val\n    end\n\n    def all_as_records\n      vars    = thing_scoped\n      records = vars.each_with_object({}) { |r, h| h[r.var] = r }\n\n      default_settings.each do |key, default_value|\n        next if records.key?(key) || default_value.is_a?(Hash)\n        records[key] = Setting.new(var: key, value: default_value)\n      end\n\n      records\n    end\n\n    def default_settings\n      return {} unless RailsSettings::Default.enabled?\n      RailsSettings::Default.instance\n    end\n  end\nend\n"
  },
  {
    "path": "app/models/site_upload.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: site_uploads\n#\n#  id                :bigint(8)        not null, primary key\n#  var               :string           default(\"\"), not null\n#  file_file_name    :string\n#  file_content_type :string\n#  file_file_size    :integer\n#  file_updated_at   :datetime\n#  meta              :json\n#  created_at        :datetime         not null\n#  updated_at        :datetime         not null\n#\n\nclass SiteUpload < ApplicationRecord\n  has_attached_file :file\n\n  validates_attachment_content_type :file, content_type: /\\Aimage\\/.*\\z/\n  validates :file, presence: true\n  validates :var, presence: true, uniqueness: true\n\n  before_save :set_meta\n  after_commit :clear_cache\n\n  def cache_key\n    \"site_uploads/#{var}\"\n  end\n\n  private\n\n  def set_meta\n    tempfile = file.queued_for_write[:original]\n\n    return if tempfile.nil?\n\n    width, height = FastImage.size(tempfile.path)\n    self.meta = { width: width, height: height }\n  end\n\n  def clear_cache\n    Rails.cache.delete(cache_key)\n  end\nend\n"
  },
  {
    "path": "app/models/status.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: statuses\n#\n#  id                     :bigint(8)        not null, primary key\n#  uri                    :string\n#  text                   :text             default(\"\"), not null\n#  created_at             :datetime         not null\n#  updated_at             :datetime         not null\n#  in_reply_to_id         :bigint(8)\n#  reblog_of_id           :bigint(8)\n#  url                    :string\n#  sensitive              :boolean          default(FALSE), not null\n#  visibility             :integer          default(\"public\"), not null\n#  spoiler_text           :text             default(\"\"), not null\n#  reply                  :boolean          default(FALSE), not null\n#  language               :string\n#  conversation_id        :bigint(8)\n#  local                  :boolean\n#  account_id             :bigint(8)        not null\n#  application_id         :bigint(8)\n#  in_reply_to_account_id :bigint(8)\n#  poll_id                :bigint(8)\n#\n\nclass Status < ApplicationRecord\n  before_destroy :unlink_from_conversations\n\n  include Paginable\n  include Streamable\n  include Cacheable\n  include StatusThreadingConcern\n\n  # If `override_timestamps` is set at creation time, Snowflake ID creation\n  # will be based on current time instead of `created_at`\n  attr_accessor :override_timestamps\n\n  update_index('statuses#status', :proper) if Chewy.enabled?\n\n  enum visibility: [:public, :unlisted, :private, :direct, :limited], _suffix: :visibility\n\n  belongs_to :application, class_name: 'Doorkeeper::Application', optional: true\n\n  belongs_to :account, inverse_of: :statuses\n  belongs_to :in_reply_to_account, foreign_key: 'in_reply_to_account_id', class_name: 'Account', optional: true\n  belongs_to :conversation, optional: true\n  belongs_to :preloadable_poll, class_name: 'Poll', foreign_key: 'poll_id', optional: true\n\n  belongs_to :thread, foreign_key: 'in_reply_to_id', class_name: 'Status', inverse_of: :replies, optional: true\n  belongs_to :reblog, foreign_key: 'reblog_of_id', class_name: 'Status', inverse_of: :reblogs, optional: true\n\n  has_many :favourites, inverse_of: :status, dependent: :destroy\n  has_many :reblogs, foreign_key: 'reblog_of_id', class_name: 'Status', inverse_of: :reblog, dependent: :destroy\n  has_many :replies, foreign_key: 'in_reply_to_id', class_name: 'Status', inverse_of: :thread\n  has_many :mentions, dependent: :destroy, inverse_of: :status\n  has_many :active_mentions, -> { active }, class_name: 'Mention', inverse_of: :status\n  has_many :media_attachments, dependent: :nullify\n\n  has_and_belongs_to_many :tags\n  has_and_belongs_to_many :preview_cards\n\n  has_one :notification, as: :activity, dependent: :destroy\n  has_one :stream_entry, as: :activity, inverse_of: :status\n  has_one :status_stat, inverse_of: :status\n  has_one :poll, inverse_of: :status, dependent: :destroy\n\n  validates :uri, uniqueness: true, presence: true, unless: :local?\n  validates :text, presence: true, unless: -> { with_media? || reblog? }\n  validates_with StatusLengthValidator\n  validates_with DisallowedHashtagsValidator\n  validates :reblog, uniqueness: { scope: :account }, if: :reblog?\n  validates :visibility, exclusion: { in: %w(direct limited) }, if: :reblog?\n\n  accepts_nested_attributes_for :poll\n\n  default_scope { recent }\n\n  scope :recent, -> { reorder(id: :desc) }\n  scope :remote, -> { where(local: false).or(where.not(uri: nil)) }\n  scope :local,  -> { where(local: true).or(where(uri: nil)) }\n\n  scope :without_replies, -> { where('statuses.reply = FALSE OR statuses.in_reply_to_account_id = statuses.account_id') }\n  scope :without_reblogs, -> { where('statuses.reblog_of_id IS NULL') }\n  scope :with_public_visibility, -> { where(visibility: :public) }\n  scope :tagged_with, ->(tag) { joins(:statuses_tags).where(statuses_tags: { tag_id: tag }) }\n  scope :excluding_silenced_accounts, -> { left_outer_joins(:account).where(accounts: { silenced_at: nil }) }\n  scope :including_silenced_accounts, -> { left_outer_joins(:account).where.not(accounts: { silenced_at: nil }) }\n  scope :not_excluded_by_account, ->(account) { where.not(account_id: account.excluded_from_timeline_account_ids) }\n  scope :not_domain_blocked_by_account, ->(account) { account.excluded_from_timeline_domains.blank? ? left_outer_joins(:account) : left_outer_joins(:account).where('accounts.domain IS NULL OR accounts.domain NOT IN (?)', account.excluded_from_timeline_domains) }\n  scope :tagged_with_all, ->(tags) {\n    Array(tags).map(&:id).map(&:to_i).reduce(self) do |result, id|\n      result.joins(\"INNER JOIN statuses_tags t#{id} ON t#{id}.status_id = statuses.id AND t#{id}.tag_id = #{id}\")\n    end\n  }\n  scope :tagged_with_none, ->(tags) {\n    Array(tags).map(&:id).map(&:to_i).reduce(self) do |result, id|\n      result.joins(\"LEFT OUTER JOIN statuses_tags t#{id} ON t#{id}.status_id = statuses.id AND t#{id}.tag_id = #{id}\")\n            .where(\"t#{id}.tag_id IS NULL\")\n    end\n  }\n\n  cache_associated :application,\n                   :media_attachments,\n                   :conversation,\n                   :status_stat,\n                   :tags,\n                   :preview_cards,\n                   :stream_entry,\n                   :preloadable_poll,\n                   account: :account_stat,\n                   active_mentions: { account: :account_stat },\n                   reblog: [\n                     :application,\n                     :stream_entry,\n                     :tags,\n                     :preview_cards,\n                     :media_attachments,\n                     :conversation,\n                     :status_stat,\n                     :preloadable_poll,\n                     account: :account_stat,\n                     active_mentions: { account: :account_stat },\n                   ],\n                   thread: { account: :account_stat }\n\n  delegate :domain, to: :account, prefix: true\n\n  REAL_TIME_WINDOW = 6.hours\n\n  def searchable_by(preloaded = nil)\n    ids = [account_id]\n\n    if preloaded.nil?\n      ids += mentions.pluck(:account_id)\n      ids += favourites.pluck(:account_id)\n      ids += reblogs.pluck(:account_id)\n    else\n      ids += preloaded.mentions[id] || []\n      ids += preloaded.favourites[id] || []\n      ids += preloaded.reblogs[id] || []\n    end\n\n    ids.uniq\n  end\n\n  def reply?\n    !in_reply_to_id.nil? || attributes['reply']\n  end\n\n  def local?\n    attributes['local'] || uri.nil?\n  end\n\n  def reblog?\n    !reblog_of_id.nil?\n  end\n\n  def within_realtime_window?\n    created_at >= REAL_TIME_WINDOW.ago\n  end\n\n  def verb\n    if destroyed?\n      :delete\n    else\n      reblog? ? :share : :post\n    end\n  end\n\n  def object_type\n    reply? ? :comment : :note\n  end\n\n  def proper\n    reblog? ? reblog : self\n  end\n\n  def content\n    proper.text\n  end\n\n  def target\n    reblog\n  end\n\n  def preview_card\n    preview_cards.first\n  end\n\n  def title\n    if destroyed?\n      \"#{account.acct} deleted status\"\n    else\n      reblog? ? \"#{account.acct} shared a status by #{reblog.account.acct}\" : \"New status by #{account.acct}\"\n    end\n  end\n\n  def hidden?\n    private_visibility? || direct_visibility? || limited_visibility?\n  end\n\n  def distributable?\n    public_visibility? || unlisted_visibility?\n  end\n\n  alias sign? distributable?\n\n  def with_media?\n    media_attachments.any?\n  end\n\n  def non_sensitive_with_media?\n    !sensitive? && with_media?\n  end\n\n  def emojis\n    return @emojis if defined?(@emojis)\n\n    fields  = [spoiler_text, text]\n    fields += preloadable_poll.options unless preloadable_poll.nil?\n\n    @emojis = CustomEmoji.from_text(fields.join(' '), account.domain)\n  end\n\n  def mark_for_mass_destruction!\n    @marked_for_mass_destruction = true\n  end\n\n  def marked_for_mass_destruction?\n    @marked_for_mass_destruction\n  end\n\n  def replies_count\n    status_stat&.replies_count || 0\n  end\n\n  def reblogs_count\n    status_stat&.reblogs_count || 0\n  end\n\n  def favourites_count\n    status_stat&.favourites_count || 0\n  end\n\n  def increment_count!(key)\n    update_status_stat!(key => public_send(key) + 1)\n  end\n\n  def decrement_count!(key)\n    update_status_stat!(key => [public_send(key) - 1, 0].max)\n  end\n\n  after_create_commit  :increment_counter_caches\n  after_destroy_commit :decrement_counter_caches\n\n  after_create_commit :store_uri, if: :local?\n  after_create_commit :update_statistics, if: :local?\n\n  around_create Mastodon::Snowflake::Callbacks\n\n  before_validation :prepare_contents, if: :local?\n  before_validation :set_reblog\n  before_validation :set_visibility\n  before_validation :set_conversation\n  before_validation :set_local\n\n  after_create :set_poll_id\n\n  class << self\n    def selectable_visibilities\n      visibilities.keys - %w(direct limited)\n    end\n\n    def in_chosen_languages(account)\n      where(language: nil).or where(language: account.chosen_languages)\n    end\n\n    def as_home_timeline(account)\n      where(account: [account] + account.following).where(visibility: [:public, :unlisted, :private])\n    end\n\n    def as_direct_timeline(account, limit = 20, max_id = nil, since_id = nil, cache_ids = false)\n      # direct timeline is mix of direct message from_me and to_me.\n      # 2 queries are executed with pagination.\n      # constant expression using arel_table is required for partial index\n\n      # _from_me part does not require any timeline filters\n      query_from_me = where(account_id: account.id)\n                      .where(Status.arel_table[:visibility].eq(3))\n                      .limit(limit)\n                      .order('statuses.id DESC')\n\n      # _to_me part requires mute and block filter.\n      # FIXME: may we check mutes.hide_notifications?\n      query_to_me = Status\n                    .joins(:mentions)\n                    .merge(Mention.where(account_id: account.id))\n                    .where(Status.arel_table[:visibility].eq(3))\n                    .limit(limit)\n                    .order('mentions.status_id DESC')\n                    .not_excluded_by_account(account)\n\n      if max_id.present?\n        query_from_me = query_from_me.where('statuses.id < ?', max_id)\n        query_to_me = query_to_me.where('mentions.status_id < ?', max_id)\n      end\n\n      if since_id.present?\n        query_from_me = query_from_me.where('statuses.id > ?', since_id)\n        query_to_me = query_to_me.where('mentions.status_id > ?', since_id)\n      end\n\n      if cache_ids\n        # returns array of cache_ids object that have id and updated_at\n        (query_from_me.cache_ids.to_a + query_to_me.cache_ids.to_a).uniq(&:id).sort_by(&:id).reverse.take(limit)\n      else\n        # returns ActiveRecord.Relation\n        items = (query_from_me.select(:id).to_a + query_to_me.select(:id).to_a).uniq(&:id).sort_by(&:id).reverse.take(limit)\n        Status.where(id: items.map(&:id))\n      end\n    end\n\n    def as_public_timeline(account = nil, local_only = false)\n      query = timeline_scope(local_only).without_replies\n\n      apply_timeline_filters(query, account, local_only)\n    end\n\n    def as_tag_timeline(tag, account = nil, local_only = false)\n      query = timeline_scope(local_only).tagged_with(tag)\n\n      apply_timeline_filters(query, account, local_only)\n    end\n\n    def as_outbox_timeline(account)\n      where(account: account, visibility: :public)\n    end\n\n    def favourites_map(status_ids, account_id)\n      Favourite.select('status_id').where(status_id: status_ids).where(account_id: account_id).each_with_object({}) { |f, h| h[f.status_id] = true }\n    end\n\n    def reblogs_map(status_ids, account_id)\n      select('reblog_of_id').where(reblog_of_id: status_ids).where(account_id: account_id).reorder(nil).each_with_object({}) { |s, h| h[s.reblog_of_id] = true }\n    end\n\n    def mutes_map(conversation_ids, account_id)\n      ConversationMute.select('conversation_id').where(conversation_id: conversation_ids).where(account_id: account_id).each_with_object({}) { |m, h| h[m.conversation_id] = true }\n    end\n\n    def pins_map(status_ids, account_id)\n      StatusPin.select('status_id').where(status_id: status_ids).where(account_id: account_id).each_with_object({}) { |p, h| h[p.status_id] = true }\n    end\n\n    def reload_stale_associations!(cached_items)\n      account_ids = []\n\n      cached_items.each do |item|\n        account_ids << item.account_id\n        account_ids << item.reblog.account_id if item.reblog?\n      end\n\n      account_ids.uniq!\n\n      return if account_ids.empty?\n\n      accounts = Account.where(id: account_ids).includes(:account_stat).each_with_object({}) { |a, h| h[a.id] = a }\n\n      cached_items.each do |item|\n        item.account = accounts[item.account_id]\n        item.reblog.account = accounts[item.reblog.account_id] if item.reblog?\n      end\n    end\n\n    def permitted_for(target_account, account)\n      visibility = [:public, :unlisted]\n\n      if account.nil?\n        where(visibility: visibility)\n      elsif target_account.blocking?(account) # get rid of blocked peeps\n        none\n      elsif account.id == target_account.id # author can see own stuff\n        all\n      else\n        # followers can see followers-only stuff, but also things they are mentioned in.\n        # non-followers can see everything that isn't private/direct, but can see stuff they are mentioned in.\n        visibility.push(:private) if account.following?(target_account)\n\n        scope = left_outer_joins(:reblog)\n\n        scope.where(visibility: visibility)\n             .or(scope.where(id: account.mentions.select(:status_id)))\n             .merge(scope.where(reblog_of_id: nil).or(scope.where.not(reblogs_statuses: { account_id: account.excluded_from_timeline_account_ids })))\n      end\n    end\n\n    private\n\n    def timeline_scope(local_only = false)\n      starting_scope = local_only ? Status.local : Status\n      starting_scope\n        .with_public_visibility\n        .without_reblogs\n    end\n\n    def apply_timeline_filters(query, account, local_only)\n      if account.nil?\n        filter_timeline_default(query)\n      else\n        filter_timeline_for_account(query, account, local_only)\n      end\n    end\n\n    def filter_timeline_for_account(query, account, local_only)\n      query = query.not_excluded_by_account(account)\n      query = query.not_domain_blocked_by_account(account) unless local_only\n      query = query.in_chosen_languages(account) if account.chosen_languages.present?\n      query.merge(account_silencing_filter(account))\n    end\n\n    def filter_timeline_default(query)\n      query.excluding_silenced_accounts\n    end\n\n    def account_silencing_filter(account)\n      if account.silenced?\n        including_myself = left_outer_joins(:account).where(account_id: account.id).references(:accounts)\n        excluding_silenced_accounts.or(including_myself)\n      else\n        excluding_silenced_accounts\n      end\n    end\n  end\n\n  private\n\n  def update_status_stat!(attrs)\n    return if marked_for_destruction? || destroyed?\n\n    record = status_stat || build_status_stat\n    record.update(attrs)\n  end\n\n  def store_uri\n    update_column(:uri, ActivityPub::TagManager.instance.uri_for(self)) if uri.nil?\n  end\n\n  def prepare_contents\n    text&.strip!\n    spoiler_text&.strip!\n  end\n\n  def set_reblog\n    self.reblog = reblog.reblog if reblog? && reblog.reblog?\n  end\n\n  def set_poll_id\n    update_column(:poll_id, poll.id) unless poll.nil?\n  end\n\n  def set_visibility\n    self.visibility = reblog.visibility if reblog? && visibility.nil?\n    self.visibility = (account.locked? ? :private : :public) if visibility.nil?\n    self.sensitive  = false if sensitive.nil?\n  end\n\n  def set_conversation\n    self.thread = thread.reblog if thread&.reblog?\n\n    self.reply = !(in_reply_to_id.nil? && thread.nil?) unless reply\n\n    if reply? && !thread.nil?\n      self.in_reply_to_account_id = carried_over_reply_to_account_id\n      self.conversation_id        = thread.conversation_id if conversation_id.nil?\n    elsif conversation_id.nil?\n      self.conversation = Conversation.new\n    end\n  end\n\n  def carried_over_reply_to_account_id\n    if thread.account_id == account_id && thread.reply?\n      thread.in_reply_to_account_id\n    else\n      thread.account_id\n    end\n  end\n\n  def set_local\n    self.local = account.local?\n  end\n\n  def update_statistics\n    return unless public_visibility? || unlisted_visibility?\n    ActivityTracker.increment('activity:statuses:local')\n  end\n\n  def increment_counter_caches\n    return if direct_visibility?\n\n    account&.increment_count!(:statuses_count)\n    reblog&.increment_count!(:reblogs_count) if reblog?\n    thread&.increment_count!(:replies_count) if in_reply_to_id.present? && (public_visibility? || unlisted_visibility?)\n  end\n\n  def decrement_counter_caches\n    return if direct_visibility? || marked_for_mass_destruction?\n\n    account&.decrement_count!(:statuses_count)\n    reblog&.decrement_count!(:reblogs_count) if reblog?\n    thread&.decrement_count!(:replies_count) if in_reply_to_id.present? && (public_visibility? || unlisted_visibility?)\n  end\n\n  def unlink_from_conversations\n    return unless direct_visibility?\n\n    mentioned_accounts = mentions.includes(:account).map(&:account)\n    inbox_owners       = mentioned_accounts.select(&:local?) + (account.local? ? [account] : [])\n\n    inbox_owners.each do |inbox_owner|\n      AccountConversation.remove_status(inbox_owner, self)\n    end\n  end\nend\n"
  },
  {
    "path": "app/models/status_pin.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: status_pins\n#\n#  id         :bigint(8)        not null, primary key\n#  account_id :bigint(8)        not null\n#  status_id  :bigint(8)        not null\n#  created_at :datetime         not null\n#  updated_at :datetime         not null\n#\n\nclass StatusPin < ApplicationRecord\n  belongs_to :account\n  belongs_to :status\n\n  validates_with StatusPinValidator\nend\n"
  },
  {
    "path": "app/models/status_stat.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: status_stats\n#\n#  id               :bigint(8)        not null, primary key\n#  status_id        :bigint(8)        not null\n#  replies_count    :bigint(8)        default(0), not null\n#  reblogs_count    :bigint(8)        default(0), not null\n#  favourites_count :bigint(8)        default(0), not null\n#  created_at       :datetime         not null\n#  updated_at       :datetime         not null\n#\n\nclass StatusStat < ApplicationRecord\n  belongs_to :status, inverse_of: :status_stat\n\n  after_commit :reset_parent_cache\n\n  private\n\n  def reset_parent_cache\n    Rails.cache.delete(\"statuses/#{status_id}\")\n  end\nend\n"
  },
  {
    "path": "app/models/stream_entry.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: stream_entries\n#\n#  id            :bigint(8)        not null, primary key\n#  activity_id   :bigint(8)\n#  activity_type :string\n#  created_at    :datetime         not null\n#  updated_at    :datetime         not null\n#  hidden        :boolean          default(FALSE), not null\n#  account_id    :bigint(8)\n#\n\nclass StreamEntry < ApplicationRecord\n  include Paginable\n\n  belongs_to :account, inverse_of: :stream_entries\n  belongs_to :activity, polymorphic: true\n  belongs_to :status, foreign_type: 'Status', foreign_key: 'activity_id', inverse_of: :stream_entry\n\n  validates :account, :activity, presence: true\n\n  STATUS_INCLUDES = [:account, :stream_entry, :conversation, :media_attachments, :tags, mentions: :account, reblog: [:stream_entry, :account, :conversation, :media_attachments, :tags, mentions: :account], thread: [:stream_entry, :account]].freeze\n\n  default_scope { where(activity_type: 'Status') }\n  scope :recent, -> { reorder(id: :desc) }\n  scope :with_includes, -> { includes(:account, status: STATUS_INCLUDES) }\n\n  delegate :target, :title, :content, :thread,\n           to: :status,\n           allow_nil: true\n\n  def object_type\n    orphaned? || targeted? ? :activity : status.object_type\n  end\n\n  def verb\n    orphaned? ? :delete : status.verb\n  end\n\n  def targeted?\n    [:follow, :request_friend, :authorize, :reject, :unfollow, :block, :unblock, :share, :favorite].include? verb\n  end\n\n  def threaded?\n    (verb == :favorite || object_type == :comment) && !thread.nil?\n  end\n\n  def mentions\n    orphaned? ? [] : status.active_mentions.map(&:account)\n  end\n\n  private\n\n  def orphaned?\n    status.nil?\n  end\nend\n"
  },
  {
    "path": "app/models/subscription.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: subscriptions\n#\n#  id                          :bigint(8)        not null, primary key\n#  callback_url                :string           default(\"\"), not null\n#  secret                      :string\n#  expires_at                  :datetime\n#  confirmed                   :boolean          default(FALSE), not null\n#  created_at                  :datetime         not null\n#  updated_at                  :datetime         not null\n#  last_successful_delivery_at :datetime\n#  domain                      :string\n#  account_id                  :bigint(8)        not null\n#\n\nclass Subscription < ApplicationRecord\n  MIN_EXPIRATION = 1.day.to_i\n  MAX_EXPIRATION = 30.days.to_i\n\n  belongs_to :account\n\n  validates :callback_url, presence: true\n  validates :callback_url, uniqueness: { scope: :account_id }\n\n  scope :confirmed, -> { where(confirmed: true) }\n  scope :future_expiration, -> { where(arel_table[:expires_at].gt(Time.now.utc)) }\n  scope :expired, -> { where(arel_table[:expires_at].lt(Time.now.utc)) }\n  scope :active, -> { confirmed.future_expiration }\n\n  def lease_seconds=(value)\n    self.expires_at = future_expiration(value)\n  end\n\n  def lease_seconds\n    (expires_at - Time.now.utc).to_i\n  end\n\n  def expired?\n    Time.now.utc > expires_at\n  end\n\n  before_validation :set_min_expiration\n\n  private\n\n  def future_expiration(value)\n    Time.now.utc + future_offset(value).seconds\n  end\n\n  def future_offset(seconds)\n    [\n      [MIN_EXPIRATION, seconds.to_i].max,\n      MAX_EXPIRATION,\n    ].min\n  end\n\n  def set_min_expiration\n    self.lease_seconds = 0 unless expires_at\n  end\nend\n"
  },
  {
    "path": "app/models/tag.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: tags\n#\n#  id         :bigint(8)        not null, primary key\n#  name       :string           default(\"\"), not null\n#  created_at :datetime         not null\n#  updated_at :datetime         not null\n#\n\nclass Tag < ApplicationRecord\n  has_and_belongs_to_many :statuses\n  has_and_belongs_to_many :accounts\n  has_and_belongs_to_many :sample_accounts, -> { searchable.discoverable.popular.limit(3) }, class_name: 'Account'\n\n  has_many :featured_tags, dependent: :destroy, inverse_of: :tag\n  has_one :account_tag_stat, dependent: :destroy\n\n  HASHTAG_NAME_RE = '[[:word:]_]*[[:alpha:]_·][[:word:]_]*'\n  HASHTAG_RE = /(?:^|[^\\/\\)\\w])#(#{HASHTAG_NAME_RE})/i\n\n  validates :name, presence: true, uniqueness: true, format: { with: /\\A#{HASHTAG_NAME_RE}\\z/i }\n\n  scope :discoverable, -> { joins(:account_tag_stat).where(AccountTagStat.arel_table[:accounts_count].gt(0)).where(account_tag_stats: { hidden: false }).order(Arel.sql('account_tag_stats.accounts_count desc')) }\n  scope :hidden, -> { where(account_tag_stats: { hidden: true }) }\n  scope :most_used, ->(account) { joins(:statuses).where(statuses: { account: account }).group(:id).order(Arel.sql('count(*) desc')) }\n\n  delegate :accounts_count,\n           :accounts_count=,\n           :increment_count!,\n           :decrement_count!,\n           :hidden?,\n           to: :account_tag_stat\n\n  after_save :save_account_tag_stat\n\n  def account_tag_stat\n    super || build_account_tag_stat\n  end\n\n  def cached_sample_accounts\n    Rails.cache.fetch(\"#{cache_key}/sample_accounts\", expires_in: 12.hours) { sample_accounts }\n  end\n\n  def to_param\n    name\n  end\n\n  def history\n    days = []\n\n    7.times do |i|\n      day = i.days.ago.beginning_of_day.to_i\n\n      days << {\n        day: day.to_s,\n        uses: Redis.current.get(\"activity:tags:#{id}:#{day}\") || '0',\n        accounts: Redis.current.pfcount(\"activity:tags:#{id}:#{day}:accounts\").to_s,\n      }\n    end\n\n    days\n  end\n\n  class << self\n    def search_for(term, limit = 5, offset = 0)\n      pattern = sanitize_sql_like(term.strip) + '%'\n\n      Tag.where('lower(name) like lower(?)', pattern)\n         .order(:name)\n         .limit(limit)\n         .offset(offset)\n    end\n\n    def find_normalized(name)\n      find_by(name: name.mb_chars.downcase.to_s)\n    end\n\n    def find_normalized!(name)\n      find_normalized(name) || raise(ActiveRecord::RecordNotFound)\n    end\n  end\n\n  private\n\n  def save_account_tag_stat\n    return unless account_tag_stat&.changed?\n    account_tag_stat.save\n  end\nend\n"
  },
  {
    "path": "app/models/tombstone.rb",
    "content": "# frozen_string_literal: true\n\n# == Schema Information\n#\n# Table name: tombstones\n#\n#  id           :bigint(8)        not null, primary key\n#  account_id   :bigint(8)\n#  uri          :string           not null\n#  created_at   :datetime         not null\n#  updated_at   :datetime         not null\n#  by_moderator :boolean\n#\n\nclass Tombstone < ApplicationRecord\n  belongs_to :account\nend\n"
  },
  {
    "path": "app/models/trending_tags.rb",
    "content": "# frozen_string_literal: true\n\nclass TrendingTags\n  KEY                  = 'trending_tags'\n  EXPIRE_HISTORY_AFTER = 7.days.seconds\n  EXPIRE_TRENDS_AFTER  = 1.day.seconds\n  THRESHOLD            = 5\n\n  class << self\n    include Redisable\n\n    def record_use!(tag, account, at_time = Time.now.utc)\n      return if disallowed_hashtags.include?(tag.name) || account.silenced? || account.bot?\n\n      increment_historical_use!(tag.id, at_time)\n      increment_unique_use!(tag.id, account.id, at_time)\n      increment_vote!(tag.id, at_time)\n    end\n\n    def get(limit)\n      key     = \"#{KEY}:#{Time.now.utc.beginning_of_day.to_i}\"\n      tag_ids = redis.zrevrange(key, 0, limit - 1).map(&:to_i)\n      tags    = Tag.where(id: tag_ids).to_a.each_with_object({}) { |tag, h| h[tag.id] = tag }\n      tag_ids.map { |tag_id| tags[tag_id] }.compact\n    end\n\n    private\n\n    def increment_historical_use!(tag_id, at_time)\n      key = \"activity:tags:#{tag_id}:#{at_time.beginning_of_day.to_i}\"\n      redis.incrby(key, 1)\n      redis.expire(key, EXPIRE_HISTORY_AFTER)\n    end\n\n    def increment_unique_use!(tag_id, account_id, at_time)\n      key = \"activity:tags:#{tag_id}:#{at_time.beginning_of_day.to_i}:accounts\"\n      redis.pfadd(key, account_id)\n      redis.expire(key, EXPIRE_HISTORY_AFTER)\n    end\n\n    def increment_vote!(tag_id, at_time)\n      key      = \"#{KEY}:#{at_time.beginning_of_day.to_i}\"\n      expected = redis.pfcount(\"activity:tags:#{tag_id}:#{(at_time - 1.day).beginning_of_day.to_i}:accounts\").to_f\n      expected = 1.0 if expected.zero?\n      observed = redis.pfcount(\"activity:tags:#{tag_id}:#{at_time.beginning_of_day.to_i}:accounts\").to_f\n\n      if expected > observed || observed < THRESHOLD\n        redis.zrem(key, tag_id.to_s)\n      else\n        score = ((observed - expected)**2) / expected\n        redis.zadd(key, score, tag_id.to_s)\n      end\n\n      redis.expire(key, EXPIRE_TRENDS_AFTER)\n    end\n\n    def disallowed_hashtags\n      return @disallowed_hashtags if defined?(@disallowed_hashtags)\n\n      @disallowed_hashtags = Setting.disallowed_hashtags.nil? ? [] : Setting.disallowed_hashtags\n      @disallowed_hashtags = @disallowed_hashtags.split(' ') if @disallowed_hashtags.is_a? String\n      @disallowed_hashtags = @disallowed_hashtags.map(&:downcase)\n    end\n  end\nend\n"
  },
  {
    "path": "app/models/user.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: users\n#\n#  id                        :bigint(8)        not null, primary key\n#  email                     :string           default(\"\"), not null\n#  created_at                :datetime         not null\n#  updated_at                :datetime         not null\n#  encrypted_password        :string           default(\"\"), not null\n#  reset_password_token      :string\n#  reset_password_sent_at    :datetime\n#  remember_created_at       :datetime\n#  sign_in_count             :integer          default(0), not null\n#  current_sign_in_at        :datetime\n#  last_sign_in_at           :datetime\n#  current_sign_in_ip        :inet\n#  last_sign_in_ip           :inet\n#  admin                     :boolean          default(FALSE), not null\n#  confirmation_token        :string\n#  confirmed_at              :datetime\n#  confirmation_sent_at      :datetime\n#  unconfirmed_email         :string\n#  locale                    :string\n#  encrypted_otp_secret      :string\n#  encrypted_otp_secret_iv   :string\n#  encrypted_otp_secret_salt :string\n#  consumed_timestep         :integer\n#  otp_required_for_login    :boolean          default(FALSE), not null\n#  last_emailed_at           :datetime\n#  otp_backup_codes          :string           is an Array\n#  filtered_languages        :string           default([]), not null, is an Array\n#  account_id                :bigint(8)        not null\n#  disabled                  :boolean          default(FALSE), not null\n#  moderator                 :boolean          default(FALSE), not null\n#  invite_id                 :bigint(8)\n#  remember_token            :string\n#  chosen_languages          :string           is an Array\n#  created_by_application_id :bigint(8)\n#  approved                  :boolean          default(TRUE), not null\n#\n\nclass User < ApplicationRecord\n  include Settings::Extend\n  include UserRoles\n\n  # The home and list feeds will be stored in Redis for this amount\n  # of time, and status fan-out to followers will include only people\n  # within this time frame. Lowering the duration may improve performance\n  # if lots of people sign up, but not a lot of them check their feed\n  # every day. Raising the duration reduces the amount of expensive\n  # RegenerationWorker jobs that need to be run when those people come\n  # to check their feed\n  ACTIVE_DURATION = ENV.fetch('USER_ACTIVE_DAYS', 7).to_i.days.freeze\n\n  devise :two_factor_authenticatable,\n         otp_secret_encryption_key: Rails.configuration.x.otp_secret\n\n  devise :two_factor_backupable,\n         otp_number_of_backup_codes: 10\n\n  devise :registerable, :recoverable, :rememberable, :trackable, :validatable,\n         :confirmable\n\n  include Omniauthable\n  include PamAuthenticable\n  include LdapAuthenticable\n\n  belongs_to :account, inverse_of: :user\n  belongs_to :invite, counter_cache: :uses, optional: true\n  belongs_to :created_by_application, class_name: 'Doorkeeper::Application', optional: true\n  accepts_nested_attributes_for :account\n\n  has_many :applications, class_name: 'Doorkeeper::Application', as: :owner\n  has_many :backups, inverse_of: :user\n\n  has_one :invite_request, class_name: 'UserInviteRequest', inverse_of: :user, dependent: :destroy\n  accepts_nested_attributes_for :invite_request, reject_if: ->(attributes) { attributes['text'].blank? }\n\n  validates :locale, inclusion: I18n.available_locales.map(&:to_s), if: :locale?\n  validates_with BlacklistedEmailValidator, on: :create\n  validates_with EmailMxValidator, if: :validate_email_dns?\n  validates :agreement, acceptance: { allow_nil: false, accept: [true, 'true', '1'] }, on: :create\n\n  scope :recent, -> { order(id: :desc) }\n  scope :pending, -> { where(approved: false) }\n  scope :approved, -> { where(approved: true) }\n  scope :confirmed, -> { where.not(confirmed_at: nil) }\n  scope :enabled, -> { where(disabled: false) }\n  scope :inactive, -> { where(arel_table[:current_sign_in_at].lt(ACTIVE_DURATION.ago)) }\n  scope :active, -> { confirmed.where(arel_table[:current_sign_in_at].gteq(ACTIVE_DURATION.ago)).joins(:account).where.not(accounts: { suspended_at: nil }) }\n  scope :matches_email, ->(value) { where(arel_table[:email].matches(\"#{value}%\")) }\n  scope :emailable, -> { confirmed.enabled.joins(:account).merge(Account.searchable) }\n\n  before_validation :sanitize_languages\n  before_create :set_approved\n\n  # This avoids a deprecation warning from Rails 5.1\n  # It seems possible that a future release of devise-two-factor will\n  # handle this itself, and this can be removed from our User class.\n  attribute :otp_secret\n\n  has_many :session_activations, dependent: :destroy\n\n  delegate :auto_play_gif, :default_sensitive, :unfollow_modal, :boost_modal, :delete_modal,\n           :reduce_motion, :system_font_ui, :noindex, :theme, :display_media, :hide_network,\n           :expand_spoilers, :default_language, :aggregate_reblogs, :home_dms, :show_application,\n           :advanced_layout, to: :settings, prefix: :setting, allow_nil: false\n\n  attr_reader :invite_code\n  attr_writer :external\n\n  def confirmed?\n    confirmed_at.present?\n  end\n\n  def invited?\n    invite_id.present?\n  end\n\n  def valid_invitation?\n    invite_id.present? && invite.valid_for_use?\n  end\n\n  def disable!\n    update!(disabled: true,\n            last_sign_in_at: current_sign_in_at,\n            current_sign_in_at: nil)\n  end\n\n  def enable!\n    update!(disabled: false)\n  end\n\n  def confirm\n    new_user      = !confirmed?\n    self.approved = true if open_registrations?\n\n    super\n\n    if new_user && approved?\n      prepare_new_user!\n    elsif new_user\n      notify_staff_about_pending_account!\n    end\n  end\n\n  def confirm!\n    new_user      = !confirmed?\n    self.approved = true if open_registrations?\n\n    skip_confirmation!\n    save!\n\n    prepare_new_user! if new_user && approved?\n  end\n\n  def pending?\n    !approved?\n  end\n\n  def active_for_authentication?\n    super && approved?\n  end\n\n  def inactive_message\n    !approved? ? :pending : super\n  end\n\n  def approve!\n    return if approved?\n\n    update!(approved: true)\n    prepare_new_user!\n  end\n\n  def update_tracked_fields!(request)\n    super\n    prepare_returning_user!\n  end\n\n  def disable_two_factor!\n    self.otp_required_for_login = false\n    otp_backup_codes&.clear\n    save!\n  end\n\n  def setting_default_privacy\n    settings.default_privacy || (account.locked? ? 'private' : 'public')\n  end\n\n  def allows_digest_emails?\n    settings.notification_emails['digest']\n  end\n\n  def allows_report_emails?\n    settings.notification_emails['report']\n  end\n\n  def allows_pending_account_emails?\n    settings.notification_emails['pending_account']\n  end\n\n  def hides_network?\n    @hides_network ||= settings.hide_network\n  end\n\n  def aggregates_reblogs?\n    @aggregates_reblogs ||= settings.aggregate_reblogs\n  end\n\n  def home_dms?\n    @home_dms ||= settings.home_dms\n  end\n\n  def shows_application?\n    @shows_application ||= settings.show_application\n  end\n\n  def token_for_app(a)\n    return nil if a.nil? || a.owner != self\n    Doorkeeper::AccessToken\n      .find_or_create_by(application_id: a.id, resource_owner_id: id) do |t|\n\n      t.scopes = a.scopes\n      t.expires_in = Doorkeeper.configuration.access_token_expires_in\n      t.use_refresh_token = Doorkeeper.configuration.refresh_token_enabled?\n    end\n  end\n\n  def activate_session(request)\n    session_activations.activate(session_id: SecureRandom.hex,\n                                 user_agent: request.user_agent,\n                                 ip: request.remote_ip).session_id\n  end\n\n  def exclusive_session(id)\n    session_activations.exclusive(id)\n  end\n\n  def session_active?(id)\n    session_activations.active? id\n  end\n\n  def web_push_subscription(session)\n    session.web_push_subscription.nil? ? nil : session.web_push_subscription\n  end\n\n  def invite_code=(code)\n    self.invite  = Invite.find_by(code: code) if code.present?\n    @invite_code = code\n  end\n\n  def password_required?\n    return false if Devise.pam_authentication || Devise.ldap_authentication\n    super\n  end\n\n  def send_reset_password_instructions\n    return false if encrypted_password.blank? && (Devise.pam_authentication || Devise.ldap_authentication)\n    super\n  end\n\n  def reset_password!(new_password, new_password_confirmation)\n    return false if encrypted_password.blank? && (Devise.pam_authentication || Devise.ldap_authentication)\n    super\n  end\n\n  def show_all_media?\n    setting_display_media == 'show_all'\n  end\n\n  def hide_all_media?\n    setting_display_media == 'hide_all'\n  end\n\n  protected\n\n  def send_devise_notification(notification, *args)\n    devise_mailer.send(notification, self, *args).deliver_later\n  end\n\n  private\n\n  def set_approved\n    self.approved = open_registrations? || valid_invitation? || external?\n  end\n\n  def open_registrations?\n    Setting.registrations_mode == 'open'\n  end\n\n  def external?\n    !!@external\n  end\n\n  def sanitize_languages\n    return if chosen_languages.nil?\n    chosen_languages.reject!(&:blank?)\n    self.chosen_languages = nil if chosen_languages.empty?\n  end\n\n  def prepare_new_user!\n    BootstrapTimelineWorker.perform_async(account_id)\n    ActivityTracker.increment('activity:accounts:local')\n    UserMailer.welcome(self).deliver_later\n  end\n\n  def prepare_returning_user!\n    ActivityTracker.record('activity:logins', id)\n    regenerate_feed! if needs_feed_update?\n  end\n\n  def notify_staff_about_pending_account!\n    User.staff.includes(:account).each do |u|\n      next unless u.allows_pending_account_emails?\n      AdminMailer.new_pending_account(u.account, self).deliver_later\n    end\n  end\n\n  def regenerate_feed!\n    return unless Redis.current.setnx(\"account:#{account_id}:regeneration\", true)\n    Redis.current.expire(\"account:#{account_id}:regeneration\", 1.day.seconds)\n    RegenerationWorker.perform_async(account_id)\n  end\n\n  def needs_feed_update?\n    last_sign_in_at < ACTIVE_DURATION.ago\n  end\n\n  def validate_email_dns?\n    email_changed? && !(Rails.env.test? || Rails.env.development?)\n  end\nend\n"
  },
  {
    "path": "app/models/user_invite_request.rb",
    "content": "# frozen_string_literal: true\n\n# == Schema Information\n#\n# Table name: user_invite_requests\n#\n#  id         :bigint(8)        not null, primary key\n#  user_id    :bigint(8)\n#  text       :text\n#  created_at :datetime         not null\n#  updated_at :datetime         not null\n#\n\nclass UserInviteRequest < ApplicationRecord\n  belongs_to :user, inverse_of: :invite_request\n  validates :text, presence: true, length: { maximum: 420 }\nend\n"
  },
  {
    "path": "app/models/web/push_subscription.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: web_push_subscriptions\n#\n#  id              :bigint(8)        not null, primary key\n#  endpoint        :string           not null\n#  key_p256dh      :string           not null\n#  key_auth        :string           not null\n#  data            :json\n#  created_at      :datetime         not null\n#  updated_at      :datetime         not null\n#  access_token_id :bigint(8)\n#  user_id         :bigint(8)\n#\n\nclass Web::PushSubscription < ApplicationRecord\n  belongs_to :user, optional: true\n  belongs_to :access_token, class_name: 'Doorkeeper::AccessToken', optional: true\n\n  has_one :session_activation, foreign_key: 'web_push_subscription_id', inverse_of: :web_push_subscription\n\n  def push(notification)\n    I18n.with_locale(associated_user&.locale || I18n.default_locale) do\n      push_payload(payload_for_notification(notification), 48.hours.seconds)\n    end\n  end\n\n  def pushable?(notification)\n    data&.key?('alerts') && ActiveModel::Type::Boolean.new.cast(data['alerts'][notification.type.to_s])\n  end\n\n  def associated_user\n    return @associated_user if defined?(@associated_user)\n\n    @associated_user = if user_id.nil?\n                         session_activation.user\n                       else\n                         user\n                       end\n  end\n\n  def associated_access_token\n    return @associated_access_token if defined?(@associated_access_token)\n\n    @associated_access_token = if access_token_id.nil?\n                                 find_or_create_access_token.token\n                               else\n                                 access_token.token\n                               end\n  end\n\n  class << self\n    def unsubscribe_for(application_id, resource_owner)\n      access_token_ids = Doorkeeper::AccessToken.where(application_id: application_id, resource_owner_id: resource_owner.id, revoked_at: nil)\n                                                .pluck(:id)\n\n      where(access_token_id: access_token_ids).delete_all\n    end\n  end\n\n  private\n\n  def push_payload(message, ttl = 5.minutes.seconds)\n    Webpush.payload_send(\n      message: Oj.dump(message),\n      endpoint: endpoint,\n      p256dh: key_p256dh,\n      auth: key_auth,\n      ttl: ttl,\n      ssl_timeout: 10,\n      open_timeout: 10,\n      read_timeout: 10,\n      vapid: {\n        subject: \"mailto:#{::Setting.site_contact_email}\",\n        private_key: Rails.configuration.x.vapid_private_key,\n        public_key: Rails.configuration.x.vapid_public_key,\n      }\n    )\n  end\n\n  def payload_for_notification(notification)\n    ActiveModelSerializers::SerializableResource.new(\n      notification,\n      serializer: Web::NotificationSerializer,\n      scope: self,\n      scope_name: :current_push_subscription\n    ).as_json\n  end\n\n  def find_or_create_access_token\n    Doorkeeper::AccessToken.find_or_create_for(\n      Doorkeeper::Application.find_by(superapp: true),\n      session_activation.user_id,\n      Doorkeeper::OAuth::Scopes.from_string('read write follow push'),\n      Doorkeeper.configuration.access_token_expires_in,\n      Doorkeeper.configuration.refresh_token_enabled?\n    )\n  end\nend\n"
  },
  {
    "path": "app/models/web/setting.rb",
    "content": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: web_settings\n#\n#  id         :bigint(8)        not null, primary key\n#  data       :json\n#  created_at :datetime         not null\n#  updated_at :datetime         not null\n#  user_id    :bigint(8)        not null\n#\n\nclass Web::Setting < ApplicationRecord\n  belongs_to :user\n\n  validates :user, uniqueness: true\nend\n"
  },
  {
    "path": "app/models/web.rb",
    "content": "# frozen_string_literal: true\n\nmodule Web\n  def self.table_name_prefix\n    'web_'\n  end\nend\n"
  },
  {
    "path": "app/policies/account_moderation_note_policy.rb",
    "content": "# frozen_string_literal: true\n\nclass AccountModerationNotePolicy < ApplicationPolicy\n  def create?\n    staff?\n  end\n\n  def destroy?\n    admin? || owner?\n  end\n\n  private\n\n  def owner?\n    record.account_id == current_account&.id\n  end\nend\n"
  },
  {
    "path": "app/policies/account_policy.rb",
    "content": "# frozen_string_literal: true\n\nclass AccountPolicy < ApplicationPolicy\n  def index?\n    staff?\n  end\n\n  def show?\n    staff?\n  end\n\n  def warn?\n    staff? && !record.user&.staff?\n  end\n\n  def suspend?\n    staff? && !record.user&.staff?\n  end\n\n  def unsuspend?\n    staff?\n  end\n\n  def silence?\n    staff? && !record.user&.staff?\n  end\n\n  def unsilence?\n    staff?\n  end\n\n  def redownload?\n    admin?\n  end\n\n  def remove_avatar?\n    staff?\n  end\n\n  def remove_header?\n    staff?\n  end\n\n  def subscribe?\n    admin?\n  end\n\n  def unsubscribe?\n    admin?\n  end\n\n  def memorialize?\n    admin? && !record.user&.admin?\n  end\nend\n"
  },
  {
    "path": "app/policies/account_warning_preset_policy.rb",
    "content": "# frozen_string_literal: true\n\nclass AccountWarningPresetPolicy < ApplicationPolicy\n  def index?\n    staff?\n  end\n\n  def create?\n    staff?\n  end\n\n  def update?\n    staff?\n  end\n\n  def destroy?\n    staff?\n  end\nend\n"
  },
  {
    "path": "app/policies/application_policy.rb",
    "content": "# frozen_string_literal: true\n\nclass ApplicationPolicy\n  attr_reader :current_account, :record\n\n  def initialize(current_account, record)\n    @current_account = current_account\n    @record          = record\n  end\n\n  delegate :admin?, :moderator?, :staff?, to: :current_user, allow_nil: true\n\n  private\n\n  def current_user\n    current_account&.user\n  end\n\n  def user_signed_in?\n    !current_user.nil?\n  end\nend\n"
  },
  {
    "path": "app/policies/backup_policy.rb",
    "content": "# frozen_string_literal: true\n\nclass BackupPolicy < ApplicationPolicy\n  MIN_AGE = 1.week\n\n  def create?\n    user_signed_in? && current_user.backups.where('created_at >= ?', MIN_AGE.ago).count.zero?\n  end\nend\n"
  },
  {
    "path": "app/policies/custom_emoji_policy.rb",
    "content": "# frozen_string_literal: true\n\nclass CustomEmojiPolicy < ApplicationPolicy\n  def index?\n    staff?\n  end\n\n  def create?\n    admin?\n  end\n\n  def update?\n    admin?\n  end\n\n  def copy?\n    admin?\n  end\n\n  def enable?\n    staff?\n  end\n\n  def disable?\n    staff?\n  end\n\n  def destroy?\n    admin?\n  end\nend\n"
  },
  {
    "path": "app/policies/domain_block_policy.rb",
    "content": "# frozen_string_literal: true\n\nclass DomainBlockPolicy < ApplicationPolicy\n  def index?\n    admin?\n  end\n\n  def show?\n    admin?\n  end\n\n  def create?\n    admin?\n  end\n\n  def destroy?\n    admin?\n  end\nend\n"
  },
  {
    "path": "app/policies/email_domain_block_policy.rb",
    "content": "# frozen_string_literal: true\n\nclass EmailDomainBlockPolicy < ApplicationPolicy\n  def index?\n    admin?\n  end\n\n  def create?\n    admin?\n  end\n\n  def destroy?\n    admin?\n  end\nend\n"
  },
  {
    "path": "app/policies/instance_policy.rb",
    "content": "# frozen_string_literal: true\n\nclass InstancePolicy < ApplicationPolicy\n  def index?\n    admin?\n  end\n\n  def show?\n    admin?\n  end\nend\n"
  },
  {
    "path": "app/policies/invite_policy.rb",
    "content": "# frozen_string_literal: true\n\nclass InvitePolicy < ApplicationPolicy\n  def index?\n    staff?\n  end\n\n  def create?\n    min_required_role?\n  end\n\n  def deactivate_all?\n    admin?\n  end\n\n  def destroy?\n    owner? || (Setting.min_invite_role == 'admin' ? admin? : staff?)\n  end\n\n  private\n\n  def owner?\n    record.user_id == current_user&.id\n  end\n\n  def min_required_role?\n    current_user&.role?(Setting.min_invite_role)\n  end\nend\n"
  },
  {
    "path": "app/policies/poll_policy.rb",
    "content": "# frozen_string_literal: true\n\nclass PollPolicy < ApplicationPolicy\n  def vote?\n    StatusPolicy.new(current_account, record.status).show? && !current_account.blocking?(record.account) && !record.account.blocking?(current_account)\n  end\nend\n"
  },
  {
    "path": "app/policies/relay_policy.rb",
    "content": "# frozen_string_literal: true\n\nclass RelayPolicy < ApplicationPolicy\n  def update?\n    admin?\n  end\nend\n"
  },
  {
    "path": "app/policies/report_note_policy.rb",
    "content": "# frozen_string_literal: true\n\nclass ReportNotePolicy < ApplicationPolicy\n  def create?\n    staff?\n  end\n\n  def destroy?\n    admin? || owner?\n  end\n\n  private\n\n  def owner?\n    record.account_id == current_account&.id\n  end\nend\n"
  },
  {
    "path": "app/policies/report_policy.rb",
    "content": "# frozen_string_literal: true\n\nclass ReportPolicy < ApplicationPolicy\n  def update?\n    staff?\n  end\n\n  def index?\n    staff?\n  end\n\n  def show?\n    staff?\n  end\nend\n"
  },
  {
    "path": "app/policies/settings_policy.rb",
    "content": "# frozen_string_literal: true\n\nclass SettingsPolicy < ApplicationPolicy\n  def update?\n    admin?\n  end\n\n  def show?\n    admin?\n  end\nend\n"
  },
  {
    "path": "app/policies/status_policy.rb",
    "content": "# frozen_string_literal: true\n\nclass StatusPolicy < ApplicationPolicy\n  def initialize(current_account, record, preloaded_relations = {})\n    super(current_account, record)\n\n    @preloaded_relations = preloaded_relations\n  end\n\n  def index?\n    staff?\n  end\n\n  def show?\n    if requires_mention?\n      owned? || mention_exists?\n    elsif private?\n      owned? || following_author? || mention_exists?\n    else\n      current_account.nil? || !author_blocking?\n    end\n  end\n\n  def reblog?\n    !requires_mention? && (!private? || owned?) && show? && !blocking_author?\n  end\n\n  def favourite?\n    show? && !blocking_author?\n  end\n\n  def destroy?\n    staff? || owned?\n  end\n\n  alias unreblog? destroy?\n\n  def update?\n    staff?\n  end\n\n  private\n\n  def requires_mention?\n    record.direct_visibility? || record.limited_visibility?\n  end\n\n  def owned?\n    author.id == current_account&.id\n  end\n\n  def private?\n    record.private_visibility?\n  end\n\n  def mention_exists?\n    return false if current_account.nil?\n\n    if record.mentions.loaded?\n      record.mentions.any? { |mention| mention.account_id == current_account.id }\n    else\n      record.mentions.where(account: current_account).exists?\n    end\n  end\n\n  def blocking_author?\n    return false if current_account.nil?\n\n    @preloaded_relations[:blocking] ? @preloaded_relations[:blocking][author.id] : current_account.blocking?(author)\n  end\n\n  def author_blocking?\n    return false if current_account.nil?\n\n    @preloaded_relations[:blocked_by] ? @preloaded_relations[:blocked_by][author.id] : author.blocking?(current_account)\n  end\n\n  def following_author?\n    return false if current_account.nil?\n\n    @preloaded_relations[:following] ? @preloaded_relations[:following][author.id] : current_account.following?(author)\n  end\n\n  def author\n    record.account\n  end\nend\n"
  },
  {
    "path": "app/policies/subscription_policy.rb",
    "content": "# frozen_string_literal: true\n\nclass SubscriptionPolicy < ApplicationPolicy\n  def index?\n    admin?\n  end\nend\n"
  },
  {
    "path": "app/policies/tag_policy.rb",
    "content": "# frozen_string_literal: true\n\nclass TagPolicy < ApplicationPolicy\n  def index?\n    staff?\n  end\n\n  def hide?\n    staff?\n  end\n\n  def unhide?\n    staff?\n  end\nend\n"
  },
  {
    "path": "app/policies/user_policy.rb",
    "content": "# frozen_string_literal: true\n\nclass UserPolicy < ApplicationPolicy\n  def reset_password?\n    staff? && !record.staff?\n  end\n\n  def change_email?\n    staff? && !record.staff?\n  end\n\n  def disable_2fa?\n    admin? && !record.staff?\n  end\n\n  def confirm?\n    staff? && !record.confirmed?\n  end\n\n  def enable?\n    staff?\n  end\n\n  def approve?\n    staff? && !record.approved?\n  end\n\n  def reject?\n    staff? && !record.approved?\n  end\n\n  def disable?\n    staff? && !record.admin?\n  end\n\n  def promote?\n    admin? && promoteable?\n  end\n\n  def demote?\n    admin? && !record.admin? && demoteable?\n  end\n\n  private\n\n  def promoteable?\n    record.approved? && (!record.staff? || !record.admin?)\n  end\n\n  def demoteable?\n    record.staff?\n  end\nend\n"
  },
  {
    "path": "app/presenters/account_relationships_presenter.rb",
    "content": "# frozen_string_literal: true\n\nclass AccountRelationshipsPresenter\n  attr_reader :following, :followed_by, :blocking, :blocked_by,\n              :muting, :requested, :domain_blocking,\n              :endorsed\n\n  def initialize(account_ids, current_account_id, **options)\n    @account_ids        = account_ids.map { |a| a.is_a?(Account) ? a.id : a }\n    @current_account_id = current_account_id\n\n    @following       = cached[:following].merge(Account.following_map(@uncached_account_ids, @current_account_id))\n    @followed_by     = cached[:followed_by].merge(Account.followed_by_map(@uncached_account_ids, @current_account_id))\n    @blocking        = cached[:blocking].merge(Account.blocking_map(@uncached_account_ids, @current_account_id))\n    @blocked_by      = cached[:blocked_by].merge(Account.blocked_by_map(@uncached_account_ids, @current_account_id))\n    @muting          = cached[:muting].merge(Account.muting_map(@uncached_account_ids, @current_account_id))\n    @requested       = cached[:requested].merge(Account.requested_map(@uncached_account_ids, @current_account_id))\n    @domain_blocking = cached[:domain_blocking].merge(Account.domain_blocking_map(@uncached_account_ids, @current_account_id))\n    @endorsed        = cached[:endorsed].merge(Account.endorsed_map(@uncached_account_ids, @current_account_id))\n\n    cache_uncached!\n\n    @following.merge!(options[:following_map] || {})\n    @followed_by.merge!(options[:followed_by_map] || {})\n    @blocking.merge!(options[:blocking_map] || {})\n    @blocked_by.merge!(options[:blocked_by_map] || {})\n    @muting.merge!(options[:muting_map] || {})\n    @requested.merge!(options[:requested_map] || {})\n    @domain_blocking.merge!(options[:domain_blocking_map] || {})\n    @endorsed.merge!(options[:endorsed_map] || {})\n  end\n\n  private\n\n  def cached\n    return @cached if defined?(@cached)\n\n    @cached = {\n      following: {},\n      followed_by: {},\n      blocking: {},\n      blocked_by: {},\n      muting: {},\n      requested: {},\n      domain_blocking: {},\n      endorsed: {},\n    }\n\n    @uncached_account_ids = []\n\n    @account_ids.each do |account_id|\n      maps_for_account = Rails.cache.read(\"relationship:#{@current_account_id}:#{account_id}\")\n\n      if maps_for_account.is_a?(Hash)\n        @cached.deep_merge!(maps_for_account)\n      else\n        @uncached_account_ids << account_id\n      end\n    end\n\n    @cached\n  end\n\n  def cache_uncached!\n    @uncached_account_ids.each do |account_id|\n      maps_for_account = {\n        following:       { account_id => following[account_id] },\n        followed_by:     { account_id => followed_by[account_id] },\n        blocking:        { account_id => blocking[account_id] },\n        blocked_by:      { account_id => blocked_by[account_id] },\n        muting:          { account_id => muting[account_id] },\n        requested:       { account_id => requested[account_id] },\n        domain_blocking: { account_id => domain_blocking[account_id] },\n        endorsed:        { account_id => endorsed[account_id] },\n      }\n\n      Rails.cache.write(\"relationship:#{@current_account_id}:#{account_id}\", maps_for_account, expires_in: 1.day)\n    end\n  end\nend\n"
  },
  {
    "path": "app/presenters/activitypub/collection_presenter.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::CollectionPresenter < ActiveModelSerializers::Model\n  attributes :id, :type, :size, :items, :page, :part_of, :first, :last, :next, :prev\nend\n"
  },
  {
    "path": "app/presenters/initial_state_presenter.rb",
    "content": "# frozen_string_literal: true\n\nclass InitialStatePresenter < ActiveModelSerializers::Model\n  attributes :settings, :push_subscription, :token,\n             :current_account, :admin, :text\nend\n"
  },
  {
    "path": "app/presenters/instance_presenter.rb",
    "content": "# frozen_string_literal: true\n\nclass InstancePresenter\n  delegate(\n    :site_contact_email,\n    :site_title,\n    :site_short_description,\n    :site_description,\n    :site_extended_description,\n    :max_bio_chars,\n    :max_toot_chars,\n    :site_terms,\n    :closed_registrations_message,\n    to: Setting\n  )\n\n  def contact_account\n    Account.find_local(Setting.site_contact_username.strip.gsub(/\\A@/, ''))\n  end\n\n  def user_count\n    Rails.cache.fetch('user_count') { User.confirmed.joins(:account).merge(Account.without_suspended).count }\n  end\n\n  def active_user_count\n    Rails.cache.fetch('active_user_count') { Redis.current.pfcount(*(0..3).map { |i| \"activity:logins:#{i.weeks.ago.utc.to_date.cweek}\" }) }\n  end\n\n  def status_count\n    Rails.cache.fetch('local_status_count') { Account.local.joins(:account_stat).sum('account_stats.statuses_count') }.to_i\n  end\n\n  def domain_count\n    Rails.cache.fetch('distinct_domain_count') { Account.distinct.count(:domain) }\n  end\n\n  def sample_accounts\n    Rails.cache.fetch('sample_accounts', expires_in: 12.hours) { Account.discoverable.popular.limit(3) }\n  end\n\n  def version_number\n    Florence::Version\n  end\n\n  def source_url\n    Mastodon::Version.source_url\n  end\n\n  def thumbnail\n    @thumbnail ||= Rails.cache.fetch('site_uploads/thumbnail') { SiteUpload.find_by(var: 'thumbnail') }\n  end\n\n  def hero\n    @hero ||= Rails.cache.fetch('site_uploads/hero') { SiteUpload.find_by(var: 'hero') }\n  end\n\n  def mascot\n    @mascot ||= Rails.cache.fetch('site_uploads/mascot') { SiteUpload.find_by(var: 'mascot') }\n  end\nend\n"
  },
  {
    "path": "app/presenters/status_relationships_presenter.rb",
    "content": "# frozen_string_literal: true\n\nclass StatusRelationshipsPresenter\n  attr_reader :reblogs_map, :favourites_map, :mutes_map, :pins_map\n\n  def initialize(statuses, current_account_id = nil, **options)\n    if current_account_id.nil?\n      @reblogs_map    = {}\n      @favourites_map = {}\n      @mutes_map      = {}\n      @pins_map       = {}\n    else\n      statuses            = statuses.compact\n      status_ids          = statuses.flat_map { |s| [s.id, s.reblog_of_id] }.uniq.compact\n      conversation_ids    = statuses.map(&:conversation_id).compact.uniq\n      pinnable_status_ids = statuses.map(&:proper).select { |s| s.account_id == current_account_id && %w(public unlisted).include?(s.visibility) }.map(&:id)\n\n      @reblogs_map     = Status.reblogs_map(status_ids, current_account_id).merge(options[:reblogs_map] || {})\n      @favourites_map  = Status.favourites_map(status_ids, current_account_id).merge(options[:favourites_map] || {})\n      @mutes_map       = Status.mutes_map(conversation_ids, current_account_id).merge(options[:mutes_map] || {})\n      @pins_map        = Status.pins_map(pinnable_status_ids, current_account_id).merge(options[:pins_map] || {})\n    end\n  end\nend\n"
  },
  {
    "path": "app/serializers/activitypub/accept_follow_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::AcceptFollowSerializer < ActivityPub::Serializer\n  attributes :id, :type, :actor\n\n  has_one :object, serializer: ActivityPub::FollowSerializer\n\n  def id\n    [ActivityPub::TagManager.instance.uri_for(object.target_account), '#accepts/follows/', object.id].join\n  end\n\n  def type\n    'Accept'\n  end\n\n  def actor\n    ActivityPub::TagManager.instance.uri_for(object.target_account)\n  end\nend\n"
  },
  {
    "path": "app/serializers/activitypub/activity_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::ActivitySerializer < ActivityPub::Serializer\n  attributes :id, :type, :actor, :published, :to, :cc\n\n  has_one :proper, key: :object, serializer: ActivityPub::NoteSerializer, if: :serialize_object?\n  attribute :proper_uri, key: :object, unless: :serialize_object?\n  attribute :atom_uri, if: :announce?\n\n  def id\n    ActivityPub::TagManager.instance.activity_uri_for(object)\n  end\n\n  def type\n    announce? ? 'Announce' : 'Create'\n  end\n\n  def actor\n    ActivityPub::TagManager.instance.uri_for(object.account)\n  end\n\n  def published\n    object.created_at.iso8601\n  end\n\n  def to\n    ActivityPub::TagManager.instance.to(object)\n  end\n\n  def cc\n    ActivityPub::TagManager.instance.cc(object)\n  end\n\n  def proper_uri\n    ActivityPub::TagManager.instance.uri_for(object.proper)\n  end\n\n  def atom_uri\n    OStatus::TagManager.instance.uri_for(object)\n  end\n\n  def announce?\n    object.reblog?\n  end\n\n  def serialize_object?\n    return true unless announce?\n    # Serialize private self-boosts of local toots\n    object.account == object.proper.account && object.proper.private_visibility? && object.local?\n  end\nend\n"
  },
  {
    "path": "app/serializers/activitypub/actor_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::ActorSerializer < ActivityPub::Serializer\n  include RoutingHelper\n\n  context :security\n\n  context_extensions :manually_approves_followers, :featured, :also_known_as,\n                     :moved_to, :property_value, :hashtag, :emoji, :identity_proof\n\n  attributes :id, :type, :following, :followers,\n             :inbox, :outbox, :featured,\n             :preferred_username, :name, :summary,\n             :url, :manually_approves_followers\n\n  has_one :public_key, serializer: ActivityPub::PublicKeySerializer\n\n  has_many :virtual_tags, key: :tag\n  has_many :virtual_attachments, key: :attachment\n\n  attribute :moved_to, if: :moved?\n  attribute :also_known_as, if: :also_known_as?\n\n  class EndpointsSerializer < ActivityPub::Serializer\n    include RoutingHelper\n\n    attributes :shared_inbox\n\n    def shared_inbox\n      inbox_url\n    end\n  end\n\n  has_one :endpoints, serializer: EndpointsSerializer\n\n  has_one :icon,  serializer: ActivityPub::ImageSerializer, if: :avatar_exists?\n  has_one :image, serializer: ActivityPub::ImageSerializer, if: :header_exists?\n\n  delegate :moved?, to: :object\n\n  def id\n    account_url(object)\n  end\n\n  def type\n    object.bot? ? 'Service' : 'Person'\n  end\n\n  def following\n    account_following_index_url(object)\n  end\n\n  def followers\n    account_followers_url(object)\n  end\n\n  def inbox\n    account_inbox_url(object)\n  end\n\n  def outbox\n    account_outbox_url(object)\n  end\n\n  def featured\n    account_collection_url(object, :featured)\n  end\n\n  def endpoints\n    object\n  end\n\n  def preferred_username\n    object.username\n  end\n\n  def name\n    object.display_name\n  end\n\n  def summary\n    Formatter.instance.simplified_format(object)\n  end\n\n  def icon\n    object.avatar\n  end\n\n  def image\n    object.header\n  end\n\n  def public_key\n    object\n  end\n\n  def url\n    short_account_url(object)\n  end\n\n  def avatar_exists?\n    object.avatar?\n  end\n\n  def header_exists?\n    object.header?\n  end\n\n  def manually_approves_followers\n    object.locked\n  end\n\n  def virtual_tags\n    object.emojis + object.tags\n  end\n\n  def virtual_attachments\n    object.fields + object.identity_proofs.active\n  end\n\n  def moved_to\n    ActivityPub::TagManager.instance.uri_for(object.moved_to_account)\n  end\n\n  def also_known_as?\n    !object.also_known_as.empty?\n  end\n\n  class CustomEmojiSerializer < ActivityPub::EmojiSerializer\n  end\n\n  class TagSerializer < ActivityPub::Serializer\n    include RoutingHelper\n\n    attributes :type, :href, :name\n\n    def type\n      'Hashtag'\n    end\n\n    def href\n      explore_hashtag_url(object)\n    end\n\n    def name\n      \"##{object.name}\"\n    end\n  end\n\n  class Account::FieldSerializer < ActivityPub::Serializer\n    attributes :type, :name, :value\n\n    def type\n      'PropertyValue'\n    end\n\n    def value\n      Formatter.instance.format_field(object.account, object.value)\n    end\n  end\n\n  class AccountIdentityProofSerializer < ActivityPub::Serializer\n    attributes :type, :name, :signature_algorithm, :signature_value\n\n    def type\n      'IdentityProof'\n    end\n\n    def name\n      object.provider_username\n    end\n\n    def signature_algorithm\n      object.provider\n    end\n\n    def signature_value\n      object.token\n    end\n  end\nend\n"
  },
  {
    "path": "app/serializers/activitypub/add_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::AddSerializer < ActivityPub::Serializer\n  include RoutingHelper\n\n  attributes :type, :actor, :target\n  attribute :proper_object, key: :object\n\n  def type\n    'Add'\n  end\n\n  def actor\n    ActivityPub::TagManager.instance.uri_for(object.account)\n  end\n\n  def proper_object\n    ActivityPub::TagManager.instance.uri_for(object)\n  end\n\n  def target\n    account_collection_url(object.account, :featured)\n  end\nend\n"
  },
  {
    "path": "app/serializers/activitypub/block_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::BlockSerializer < ActivityPub::Serializer\n  attributes :id, :type, :actor\n  attribute :virtual_object, key: :object\n\n  def id\n    ActivityPub::TagManager.instance.uri_for(object) || [ActivityPub::TagManager.instance.uri_for(object.account), '#blocks/', object.id].join\n  end\n\n  def type\n    'Block'\n  end\n\n  def actor\n    ActivityPub::TagManager.instance.uri_for(object.account)\n  end\n\n  def virtual_object\n    ActivityPub::TagManager.instance.uri_for(object.target_account)\n  end\nend\n"
  },
  {
    "path": "app/serializers/activitypub/collection_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::CollectionSerializer < ActivityPub::Serializer\n  def self.serializer_for(model, options)\n    return ActivityPub::NoteSerializer if model.class.name == 'Status'\n    return ActivityPub::CollectionSerializer if model.class.name == 'ActivityPub::CollectionPresenter'\n    super\n  end\n\n  attribute :id, if: -> { object.id.present? }\n  attribute :type\n  attribute :total_items, if: -> { object.size.present? }\n  attribute :next, if: -> { object.next.present? }\n  attribute :prev, if: -> { object.prev.present? }\n  attribute :part_of, if: -> { object.part_of.present? }\n\n  has_one :first, if: -> { object.first.present? }\n  has_one :last, if: -> { object.last.present? }\n  has_many :items, key: :items, if: -> { (!object.items.nil? || page?) && !ordered? }\n  has_many :items, key: :ordered_items, if: -> { (!object.items.nil? || page?) && ordered? }\n\n  def type\n    if page?\n      ordered? ? 'OrderedCollectionPage' : 'CollectionPage'\n    else\n      ordered? ? 'OrderedCollection' : 'Collection'\n    end\n  end\n\n  def total_items\n    object.size\n  end\n\n  private\n\n  def ordered?\n    object.type == :ordered\n  end\n\n  def page?\n    object.part_of.present? || object.page.present?\n  end\nend\n"
  },
  {
    "path": "app/serializers/activitypub/delete_actor_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::DeleteActorSerializer < ActivityPub::Serializer\n  attributes :id, :type, :actor, :to\n  attribute :virtual_object, key: :object\n\n  def id\n    [ActivityPub::TagManager.instance.uri_for(object), '#delete'].join\n  end\n\n  def type\n    'Delete'\n  end\n\n  def actor\n    ActivityPub::TagManager.instance.uri_for(object)\n  end\n\n  def virtual_object\n    actor\n  end\n\n  def to\n    [ActivityPub::TagManager::COLLECTIONS[:public]]\n  end\nend\n"
  },
  {
    "path": "app/serializers/activitypub/delete_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::DeleteSerializer < ActivityPub::Serializer\n  class TombstoneSerializer < ActivityPub::Serializer\n    context_extensions :atom_uri\n\n    attributes :id, :type, :atom_uri\n\n    def id\n      ActivityPub::TagManager.instance.uri_for(object)\n    end\n\n    def type\n      'Tombstone'\n    end\n\n    def atom_uri\n      OStatus::TagManager.instance.uri_for(object)\n    end\n  end\n\n  attributes :id, :type, :actor, :to\n\n  has_one :object, serializer: TombstoneSerializer\n\n  def id\n    [ActivityPub::TagManager.instance.uri_for(object), '#delete'].join\n  end\n\n  def type\n    'Delete'\n  end\n\n  def actor\n    ActivityPub::TagManager.instance.uri_for(object.account)\n  end\n\n  def to\n    [ActivityPub::TagManager::COLLECTIONS[:public]]\n  end\nend\n"
  },
  {
    "path": "app/serializers/activitypub/emoji_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::EmojiSerializer < ActivityPub::Serializer\n  include RoutingHelper\n\n  context_extensions :emoji\n\n  attributes :id, :type, :name, :updated\n\n  has_one :icon, serializer: ActivityPub::ImageSerializer\n\n  def id\n    ActivityPub::TagManager.instance.uri_for(object)\n  end\n\n  def type\n    'Emoji'\n  end\n\n  def icon\n    object.image\n  end\n\n  def updated\n    object.updated_at.iso8601\n  end\n\n  def name\n    \":#{object.shortcode}:\"\n  end\nend\n"
  },
  {
    "path": "app/serializers/activitypub/flag_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::FlagSerializer < ActivityPub::Serializer\n  attributes :id, :type, :actor, :content\n  attribute :virtual_object, key: :object\n\n  def id\n    ActivityPub::TagManager.instance.uri_for(object)\n  end\n\n  def type\n    'Flag'\n  end\n\n  def actor\n    ActivityPub::TagManager.instance.uri_for(instance_options[:account] || object.account)\n  end\n\n  def virtual_object\n    [ActivityPub::TagManager.instance.uri_for(object.target_account)] + object.statuses.map { |s| ActivityPub::TagManager.instance.uri_for(s) }\n  end\n\n  def content\n    object.comment\n  end\nend\n"
  },
  {
    "path": "app/serializers/activitypub/follow_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::FollowSerializer < ActivityPub::Serializer\n  attributes :id, :type, :actor\n  attribute :virtual_object, key: :object\n\n  def id\n    ActivityPub::TagManager.instance.uri_for(object) || [ActivityPub::TagManager.instance.uri_for(object.account), '#follows/', object.id].join\n  end\n\n  def type\n    'Follow'\n  end\n\n  def actor\n    ActivityPub::TagManager.instance.uri_for(object.account)\n  end\n\n  def virtual_object\n    ActivityPub::TagManager.instance.uri_for(object.target_account)\n  end\nend\n"
  },
  {
    "path": "app/serializers/activitypub/image_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::ImageSerializer < ActivityPub::Serializer\n  include RoutingHelper\n\n  context_extensions :focal_point\n\n  attributes :type, :media_type, :url\n  attribute :focal_point, if: :focal_point?\n\n  def type\n    'Image'\n  end\n\n  def url\n    full_asset_url(object.url(:original))\n  end\n\n  def media_type\n    object.content_type\n  end\n\n  def focal_point?\n    object.respond_to?(:meta) && object.meta.is_a?(Hash) && object.meta['focus'].is_a?(Hash)\n  end\n\n  def focal_point\n    [object.meta['focus']['x'], object.meta['focus']['y']]\n  end\nend\n"
  },
  {
    "path": "app/serializers/activitypub/like_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::LikeSerializer < ActivityPub::Serializer\n  attributes :id, :type, :actor\n  attribute :virtual_object, key: :object\n\n  def id\n    [ActivityPub::TagManager.instance.uri_for(object.account), '#likes/', object.id].join\n  end\n\n  def type\n    'Like'\n  end\n\n  def actor\n    ActivityPub::TagManager.instance.uri_for(object.account)\n  end\n\n  def virtual_object\n    ActivityPub::TagManager.instance.uri_for(object.status)\n  end\nend\n"
  },
  {
    "path": "app/serializers/activitypub/note_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::NoteSerializer < ActivityPub::Serializer\n  context_extensions :atom_uri, :conversation, :sensitive,\n                     :hashtag, :emoji, :focal_point, :blurhash\n\n  attributes :id, :type, :summary,\n             :in_reply_to, :published, :url,\n             :attributed_to, :to, :cc, :sensitive,\n             :atom_uri, :in_reply_to_atom_uri,\n             :conversation\n\n  attribute :content\n  attribute :content_map, if: :language?\n\n  has_many :media_attachments, key: :attachment\n  has_many :virtual_tags, key: :tag\n\n  has_one :replies, serializer: ActivityPub::CollectionSerializer, if: :local?\n\n  has_many :poll_options, key: :one_of, if: :poll_and_not_multiple?\n  has_many :poll_options, key: :any_of, if: :poll_and_multiple?\n\n  attribute :end_time, if: :poll_and_expires?\n  attribute :closed, if: :poll_and_expired?\n\n  def id\n    ActivityPub::TagManager.instance.uri_for(object)\n  end\n\n  def type\n    object.preloadable_poll ? 'Question' : 'Note'\n  end\n\n  def summary\n    object.spoiler_text.presence\n  end\n\n  def content\n    Formatter.instance.format(object)\n  end\n\n  def content_map\n    { object.language => Formatter.instance.format(object) }\n  end\n\n  def replies\n    replies = object.self_replies(5).pluck(:id, :uri)\n    last_id = replies.last&.first\n\n    ActivityPub::CollectionPresenter.new(\n      type: :unordered,\n      id: ActivityPub::TagManager.instance.replies_uri_for(object),\n      first: ActivityPub::CollectionPresenter.new(\n        type: :unordered,\n        part_of: ActivityPub::TagManager.instance.replies_uri_for(object),\n        items: replies.map(&:second),\n        next: last_id ? ActivityPub::TagManager.instance.replies_uri_for(object, page: true, min_id: last_id) : nil\n      )\n    )\n  end\n\n  def language?\n    object.language.present?\n  end\n\n  def in_reply_to\n    return unless object.reply? && !object.thread.nil?\n\n    if object.thread.uri.nil? || object.thread.uri.start_with?('http')\n      ActivityPub::TagManager.instance.uri_for(object.thread)\n    else\n      object.thread.url\n    end\n  end\n\n  def published\n    object.created_at.iso8601\n  end\n\n  def url\n    ActivityPub::TagManager.instance.url_for(object)\n  end\n\n  def attributed_to\n    ActivityPub::TagManager.instance.uri_for(object.account)\n  end\n\n  def to\n    ActivityPub::TagManager.instance.to(object)\n  end\n\n  def cc\n    ActivityPub::TagManager.instance.cc(object)\n  end\n\n  def virtual_tags\n    object.active_mentions.to_a.sort_by(&:id) + object.tags + object.emojis\n  end\n\n  def atom_uri\n    return unless object.local?\n\n    OStatus::TagManager.instance.uri_for(object)\n  end\n\n  def in_reply_to_atom_uri\n    return unless object.reply? && !object.thread.nil?\n\n    OStatus::TagManager.instance.uri_for(object.thread)\n  end\n\n  def conversation\n    return if object.conversation.nil?\n\n    if object.conversation.uri?\n      object.conversation.uri\n    else\n      OStatus::TagManager.instance.unique_tag(object.conversation.created_at, object.conversation.id, 'Conversation')\n    end\n  end\n\n  def local?\n    object.account.local?\n  end\n\n  def poll_options\n    object.preloadable_poll.loaded_options\n  end\n\n  def poll_and_multiple?\n    object.preloadable_poll&.multiple?\n  end\n\n  def poll_and_not_multiple?\n    object.preloadable_poll && !object.preloadable_poll.multiple?\n  end\n\n  def closed\n    object.preloadable_poll.expires_at.iso8601\n  end\n\n  alias end_time closed\n\n  def poll_and_expires?\n    object.preloadable_poll&.expires_at&.present?\n  end\n\n  def poll_and_expired?\n    object.preloadable_poll&.expired?\n  end\n\n  class MediaAttachmentSerializer < ActivityPub::Serializer\n    include RoutingHelper\n\n    attributes :type, :media_type, :url, :name, :blurhash\n    attribute :focal_point, if: :focal_point?\n\n    def type\n      'Document'\n    end\n\n    def name\n      object.description\n    end\n\n    def media_type\n      object.file_content_type\n    end\n\n    def url\n      object.local? ? full_asset_url(object.file.url(:original, false)) : object.remote_url\n    end\n\n    def focal_point?\n      object.file.meta.is_a?(Hash) && object.file.meta['focus'].is_a?(Hash)\n    end\n\n    def focal_point\n      [object.file.meta['focus']['x'], object.file.meta['focus']['y']]\n    end\n  end\n\n  class MentionSerializer < ActivityPub::Serializer\n    attributes :type, :href, :name\n\n    def type\n      'Mention'\n    end\n\n    def href\n      ActivityPub::TagManager.instance.uri_for(object.account)\n    end\n\n    def name\n      \"@#{object.account.acct}\"\n    end\n  end\n\n  class TagSerializer < ActivityPub::Serializer\n    include RoutingHelper\n\n    attributes :type, :href, :name\n\n    def type\n      'Hashtag'\n    end\n\n    def href\n      tag_url(object)\n    end\n\n    def name\n      \"##{object.name}\"\n    end\n  end\n\n  class CustomEmojiSerializer < ActivityPub::EmojiSerializer\n  end\n\n  class OptionSerializer < ActivityPub::Serializer\n    class RepliesSerializer < ActivityPub::Serializer\n      attributes :type, :total_items\n\n      def type\n        'Collection'\n      end\n\n      def total_items\n        object.votes_count\n      end\n    end\n\n    attributes :type, :name\n\n    has_one :replies, serializer: ActivityPub::NoteSerializer::OptionSerializer::RepliesSerializer\n\n    def type\n      'Note'\n    end\n\n    def name\n      object.title\n    end\n\n    def replies\n      object\n    end\n  end\nend\n"
  },
  {
    "path": "app/serializers/activitypub/outbox_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::OutboxSerializer < ActivityPub::CollectionSerializer\n  def self.serializer_for(model, options)\n    return ActivityPub::ActivitySerializer if model.is_a?(Status)\n    super\n  end\nend\n"
  },
  {
    "path": "app/serializers/activitypub/public_key_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::PublicKeySerializer < ActivityPub::Serializer\n  context :security\n\n  attributes :id, :owner, :public_key_pem\n\n  def id\n    [ActivityPub::TagManager.instance.uri_for(object), '#main-key'].join\n  end\n\n  def owner\n    ActivityPub::TagManager.instance.uri_for(object)\n  end\n\n  def public_key_pem\n    object.public_key\n  end\nend\n"
  },
  {
    "path": "app/serializers/activitypub/reject_follow_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::RejectFollowSerializer < ActivityPub::Serializer\n  attributes :id, :type, :actor\n\n  has_one :object, serializer: ActivityPub::FollowSerializer\n\n  def id\n    [ActivityPub::TagManager.instance.uri_for(object.target_account), '#rejects/follows/', object.id].join\n  end\n\n  def type\n    'Reject'\n  end\n\n  def actor\n    ActivityPub::TagManager.instance.uri_for(object.target_account)\n  end\nend\n"
  },
  {
    "path": "app/serializers/activitypub/remove_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::RemoveSerializer < ActivityPub::Serializer\n  include RoutingHelper\n\n  attributes :type, :actor, :target\n  attribute :proper_object, key: :object\n\n  def type\n    'Remove'\n  end\n\n  def actor\n    ActivityPub::TagManager.instance.uri_for(object.account)\n  end\n\n  def proper_object\n    ActivityPub::TagManager.instance.uri_for(object)\n  end\n\n  def target\n    account_collection_url(object.account, :featured)\n  end\nend\n"
  },
  {
    "path": "app/serializers/activitypub/undo_announce_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::UndoAnnounceSerializer < ActivityPub::Serializer\n  attributes :id, :type, :actor, :to\n\n  has_one :object, serializer: ActivityPub::ActivitySerializer\n\n  def id\n    [ActivityPub::TagManager.instance.uri_for(object.account), '#announces/', object.id, '/undo'].join\n  end\n\n  def type\n    'Undo'\n  end\n\n  def actor\n    ActivityPub::TagManager.instance.uri_for(object.account)\n  end\n\n  def to\n    [ActivityPub::TagManager::COLLECTIONS[:public]]\n  end\nend\n"
  },
  {
    "path": "app/serializers/activitypub/undo_block_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::UndoBlockSerializer < ActivityPub::Serializer\n  attributes :id, :type, :actor\n\n  has_one :object, serializer: ActivityPub::BlockSerializer\n\n  def id\n    [ActivityPub::TagManager.instance.uri_for(object.account), '#blocks/', object.id, '/undo'].join\n  end\n\n  def type\n    'Undo'\n  end\n\n  def actor\n    ActivityPub::TagManager.instance.uri_for(object.account)\n  end\nend\n"
  },
  {
    "path": "app/serializers/activitypub/undo_follow_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::UndoFollowSerializer < ActivityPub::Serializer\n  attributes :id, :type, :actor\n\n  has_one :object, serializer: ActivityPub::FollowSerializer\n\n  def id\n    [ActivityPub::TagManager.instance.uri_for(object.account), '#follows/', object.id, '/undo'].join\n  end\n\n  def type\n    'Undo'\n  end\n\n  def actor\n    ActivityPub::TagManager.instance.uri_for(object.account)\n  end\nend\n"
  },
  {
    "path": "app/serializers/activitypub/undo_like_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::UndoLikeSerializer < ActivityPub::Serializer\n  attributes :id, :type, :actor\n\n  has_one :object, serializer: ActivityPub::LikeSerializer\n\n  def id\n    [ActivityPub::TagManager.instance.uri_for(object.account), '#likes/', object.id, '/undo'].join\n  end\n\n  def type\n    'Undo'\n  end\n\n  def actor\n    ActivityPub::TagManager.instance.uri_for(object.account)\n  end\nend\n"
  },
  {
    "path": "app/serializers/activitypub/update_poll_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::UpdatePollSerializer < ActivityPub::Serializer\n  attributes :id, :type, :actor, :to\n\n  has_one :object, serializer: ActivityPub::NoteSerializer\n\n  def id\n    [ActivityPub::TagManager.instance.uri_for(object), '#updates/', object.preloadable_poll.updated_at.to_i].join\n  end\n\n  def type\n    'Update'\n  end\n\n  def actor\n    ActivityPub::TagManager.instance.uri_for(object)\n  end\n\n  def to\n    ActivityPub::TagManager.instance.to(object)\n  end\n\n  def cc\n    ActivityPub::TagManager.instance.cc(object)\n  end\nend\n"
  },
  {
    "path": "app/serializers/activitypub/update_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::UpdateSerializer < ActivityPub::Serializer\n  attributes :id, :type, :actor, :to\n\n  has_one :object, serializer: ActivityPub::ActorSerializer\n\n  def id\n    [ActivityPub::TagManager.instance.uri_for(object), '#updates/', object.updated_at.to_i].join\n  end\n\n  def type\n    'Update'\n  end\n\n  def actor\n    ActivityPub::TagManager.instance.uri_for(object)\n  end\n\n  def to\n    [ActivityPub::TagManager::COLLECTIONS[:public]]\n  end\nend\n"
  },
  {
    "path": "app/serializers/activitypub/vote_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::VoteSerializer < ActivityPub::Serializer\n  class NoteSerializer < ActivityPub::Serializer\n    attributes :id, :type, :name, :attributed_to,\n               :in_reply_to, :to\n\n    def id\n      ActivityPub::TagManager.instance.uri_for(object) || [ActivityPub::TagManager.instance.uri_for(object.account), '#votes/', object.id].join\n    end\n\n    def type\n      'Note'\n    end\n\n    def name\n      object.poll.options[object.choice.to_i]\n    end\n\n    def attributed_to\n      ActivityPub::TagManager.instance.uri_for(object.account)\n    end\n\n    def in_reply_to\n      ActivityPub::TagManager.instance.uri_for(object.poll.status)\n    end\n\n    def to\n      ActivityPub::TagManager.instance.uri_for(object.poll.account)\n    end\n  end\n\n  attributes :id, :type, :actor, :to\n\n  has_one :object, serializer: ActivityPub::VoteSerializer::NoteSerializer\n\n  def id\n    [ActivityPub::TagManager.instance.uri_for(object.account), '#votes/', object.id, '/activity'].join\n  end\n\n  def type\n    'Create'\n  end\n\n  def actor\n    ActivityPub::TagManager.instance.uri_for(object.account)\n  end\n\n  def to\n    ActivityPub::TagManager.instance.uri_for(object.poll.account)\n  end\nend\n"
  },
  {
    "path": "app/serializers/initial_state_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass InitialStateSerializer < ActiveModel::Serializer\n  attributes :meta, :compose, :accounts,\n             :media_attachments, :settings\n\n  has_one :push_subscription, serializer: REST::WebPushSubscriptionSerializer\n\n  def meta\n    store = {\n      streaming_api_base_url: Rails.configuration.x.streaming_api_base_url,\n      access_token: object.token,\n      locale: I18n.locale,\n      domain: Rails.configuration.x.local_domain,\n      admin: object.admin&.id&.to_s,\n      search_enabled: Chewy.enabled?,\n      repository: Mastodon::Version.repository,\n      source_url: Mastodon::Version.source_url,\n      version: Florence::Version.to_s,\n      invites_enabled: Setting.min_invite_role == 'user',\n      mascot: instance_presenter.mascot&.file&.url,\n      profile_directory: Setting.profile_directory,\n      max_toot_chars: instance_presenter.max_toot_chars,\n      max_bio_chars: instance_presenter.max_bio_chars\n    }\n\n    if object.current_account\n      store[:me]              = object.current_account.id.to_s\n      store[:unfollow_modal]  = object.current_account.user.setting_unfollow_modal\n      store[:boost_modal]     = object.current_account.user.setting_boost_modal\n      store[:delete_modal]    = object.current_account.user.setting_delete_modal\n      store[:auto_play_gif]   = object.current_account.user.setting_auto_play_gif\n      store[:display_media]   = object.current_account.user.setting_display_media\n      store[:expand_spoilers] = object.current_account.user.setting_expand_spoilers\n      store[:reduce_motion]   = object.current_account.user.setting_reduce_motion\n      store[:advanced_layout] = object.current_account.user.setting_advanced_layout\n      store[:is_staff]        = object.current_account.user.staff?\n    end\n\n    store\n  end\n\n  def compose\n    store = {}\n\n    if object.current_account\n      store[:me]                = object.current_account.id.to_s\n      store[:default_privacy]   = object.current_account.user.setting_default_privacy\n      store[:default_sensitive] = object.current_account.user.setting_default_sensitive\n    end\n\n    store[:text] = object.text if object.text\n\n    store\n  end\n\n  def accounts\n    store = {}\n    store[object.current_account.id.to_s] = ActiveModelSerializers::SerializableResource.new(object.current_account, serializer: REST::AccountSerializer) if object.current_account\n    store[object.admin.id.to_s]           = ActiveModelSerializers::SerializableResource.new(object.admin, serializer: REST::AccountSerializer) if object.admin\n    store\n  end\n\n  def media_attachments\n    { accept_content_types: MediaAttachment::IMAGE_FILE_EXTENSIONS + MediaAttachment::VIDEO_FILE_EXTENSIONS + MediaAttachment::IMAGE_MIME_TYPES + MediaAttachment::VIDEO_MIME_TYPES }\n  end\n\n  private\n\n  def instance_presenter\n    @instance_presenter ||= InstancePresenter.new\n  end\nend\n"
  },
  {
    "path": "app/serializers/manifest_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass ManifestSerializer < ActiveModel::Serializer\n  include RoutingHelper\n  include ActionView::Helpers::TextHelper\n\n  attributes :name, :short_name, :description,\n             :icons, :theme_color, :background_color,\n             :display, :start_url, :scope,\n             :share_target\n\n  def name\n    object.site_title\n  end\n\n  def short_name\n    object.site_title\n  end\n\n  def description\n    strip_tags(object.site_short_description.presence || I18n.t('about.about_mastodon_html'))\n  end\n\n  def icons\n    [\n      {\n        src: '/android-chrome-192x192.png',\n        sizes: '192x192',\n        type: 'image/png',\n      },\n    ]\n  end\n\n  def theme_color\n    '#282c37'\n  end\n\n  def background_color\n    '#191b22'\n  end\n\n  def display\n    'standalone'\n  end\n\n  def start_url\n    '/web/timelines/home'\n  end\n\n  def scope\n    root_url\n  end\n\n  def share_target\n    {\n      url_template: 'share?title={title}&text={text}&url={url}',\n      action: 'share',\n      params: {\n        title: 'title',\n        text: 'text',\n        url: 'url',\n      },\n    }\n  end\nend\n"
  },
  {
    "path": "app/serializers/oembed_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass OEmbedSerializer < ActiveModel::Serializer\n  include RoutingHelper\n  include ActionView::Helpers::TagHelper\n\n  attributes :type, :version, :title, :author_name,\n             :author_url, :provider_name, :provider_url,\n             :cache_age, :html, :width, :height\n\n  def type\n    'rich'\n  end\n\n  def version\n    '1.0'\n  end\n\n  def author_name\n    object.account.display_name.presence || object.account.username\n  end\n\n  def author_url\n    short_account_url(object.account)\n  end\n\n  def provider_name\n    Rails.configuration.x.local_domain\n  end\n\n  def provider_url\n    root_url\n  end\n\n  def cache_age\n    86_400\n  end\n\n  def html\n    attributes = {\n      src: embed_short_account_status_url(object.account, object),\n      class: 'mastodon-embed',\n      style: 'max-width: 100%; border: 0',\n      width: width,\n      height: height,\n      allowfullscreen: true,\n    }\n\n    content_tag(:iframe, nil, attributes) + content_tag(:script, nil, src: full_asset_url('embed.js', skip_pipeline: true), async: true)\n  end\n\n  def width\n    instance_options[:width]\n  end\n\n  def height\n    instance_options[:height]\n  end\nend\n"
  },
  {
    "path": "app/serializers/rest/account_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass REST::AccountSerializer < ActiveModel::Serializer\n  include RoutingHelper\n\n  attributes :id, :username, :acct, :display_name, :locked, :bot, :created_at,\n             :note, :url, :avatar, :avatar_static, :header, :header_static,\n             :followers_count, :following_count, :statuses_count\n\n  has_one :moved_to_account, key: :moved, serializer: REST::AccountSerializer, if: :moved_and_not_nested?\n  has_many :emojis, serializer: REST::CustomEmojiSerializer\n\n  class FieldSerializer < ActiveModel::Serializer\n    attributes :name, :value, :verified_at\n\n    def value\n      Formatter.instance.format_field(object.account, object.value)\n    end\n  end\n\n  has_many :fields\n\n  def id\n    object.id.to_s\n  end\n\n  def note\n    Formatter.instance.simplified_format(object)\n  end\n\n  def url\n    TagManager.instance.url_for(object)\n  end\n\n  def avatar\n    full_asset_url(object.avatar_original_url)\n  end\n\n  def avatar_static\n    full_asset_url(object.avatar_static_url)\n  end\n\n  def header\n    full_asset_url(object.header_original_url)\n  end\n\n  def header_static\n    full_asset_url(object.header_static_url)\n  end\n\n  def moved_and_not_nested?\n    object.moved? && object.moved_to_account.moved_to_account_id.nil?\n  end\nend\n"
  },
  {
    "path": "app/serializers/rest/application_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass REST::ApplicationSerializer < ActiveModel::Serializer\n  attributes :id, :name, :website, :redirect_uri,\n             :client_id, :client_secret, :vapid_key\n\n  def id\n    object.id.to_s\n  end\n\n  def client_id\n    object.uid\n  end\n\n  def client_secret\n    object.secret\n  end\n\n  def website\n    object.website.presence\n  end\n\n  def vapid_key\n    Rails.configuration.x.vapid_public_key\n  end\nend\n"
  },
  {
    "path": "app/serializers/rest/context_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass REST::ContextSerializer < ActiveModel::Serializer\n  has_many :ancestors,   serializer: REST::StatusSerializer\n  has_many :descendants, serializer: REST::StatusSerializer\nend\n"
  },
  {
    "path": "app/serializers/rest/conversation_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass REST::ConversationSerializer < ActiveModel::Serializer\n  attributes :id, :unread\n\n  has_many :participant_accounts, key: :accounts, serializer: REST::AccountSerializer\n  has_one :last_status, serializer: REST::StatusSerializer\n\n  def id\n    object.id.to_s\n  end\nend\n"
  },
  {
    "path": "app/serializers/rest/credential_account_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass REST::CredentialAccountSerializer < REST::AccountSerializer\n  attributes :source\n\n  def source\n    user = object.user\n\n    {\n      privacy: user.setting_default_privacy,\n      sensitive: user.setting_default_sensitive,\n      language: user.setting_default_language,\n      note: object.note,\n      fields: object.fields.map(&:to_h),\n    }\n  end\nend\n"
  },
  {
    "path": "app/serializers/rest/custom_emoji_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass REST::CustomEmojiSerializer < ActiveModel::Serializer\n  include RoutingHelper\n\n  attributes :shortcode, :url, :static_url, :visible_in_picker\n\n  def url\n    full_asset_url(object.image.url)\n  end\n\n  def static_url\n    full_asset_url(object.image.url(:static))\n  end\nend\n"
  },
  {
    "path": "app/serializers/rest/filter_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass REST::FilterSerializer < ActiveModel::Serializer\n  attributes :id, :phrase, :context, :whole_word, :expires_at,\n             :irreversible\n\n  def id\n    object.id.to_s\n  end\nend\n"
  },
  {
    "path": "app/serializers/rest/identity_proof_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass REST::IdentityProofSerializer < ActiveModel::Serializer\n  attributes :provider, :provider_username, :updated_at, :proof_url, :profile_url\n\n  def proof_url\n    object.badge.proof_url\n  end\n\n  def profile_url\n    object.badge.profile_url\n  end\n\n  def provider\n    object.provider.capitalize\n  end\nend\n"
  },
  {
    "path": "app/serializers/rest/instance_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass REST::InstanceSerializer < ActiveModel::Serializer\n  include RoutingHelper\n\n  attributes :uri, :title, :description, :email,\n             :version, :urls, :stats, :thumbnail,\n             :languages, :registrations,\n             :max_toot_chars, :max_bio_chars\n\n  has_one :contact_account, serializer: REST::AccountSerializer\n\n  delegate :contact_account, to: :instance_presenter\n\n  def uri\n    Rails.configuration.x.local_domain\n  end\n\n  def title\n    Setting.site_title\n  end\n\n  def description\n    Setting.site_description\n  end\n\n  def email\n    Setting.site_contact_email\n  end\n\n  def version\n    Mastodon::Version.to_s\n  end\n\n  def thumbnail\n    instance_presenter.thumbnail ? full_asset_url(instance_presenter.thumbnail.file.url) : full_pack_url('media/images/preview.jpg')\n  end\n\n  def max_toot_chars\n    Setting.max_toot_chars.to_i\n  end\n\n  def max_bio_chars\n    Setting.max_bio_chars.to_i\n  end\n\n  def stats\n    {\n      user_count: instance_presenter.user_count,\n      status_count: instance_presenter.status_count,\n      domain_count: instance_presenter.domain_count,\n    }\n  end\n\n  def urls\n    { streaming_api: Rails.configuration.x.streaming_api_base_url }\n  end\n\n  def languages\n    [I18n.default_locale]\n  end\n\n  def registrations\n    Setting.registrations_mode != 'none' && !Rails.configuration.x.single_user_mode\n  end\n\n  private\n\n  def instance_presenter\n    @instance_presenter ||= InstancePresenter.new\n  end\nend\n"
  },
  {
    "path": "app/serializers/rest/list_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass REST::ListSerializer < ActiveModel::Serializer\n  attributes :id, :title\n\n  def id\n    object.id.to_s\n  end\nend\n"
  },
  {
    "path": "app/serializers/rest/media_attachment_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass REST::MediaAttachmentSerializer < ActiveModel::Serializer\n  include RoutingHelper\n\n  attributes :id, :type, :url, :preview_url,\n             :remote_url, :text_url, :meta,\n             :description, :blurhash\n\n  def id\n    object.id.to_s\n  end\n\n  def url\n    if object.needs_redownload?\n      media_proxy_url(object.id, :original)\n    else\n      full_asset_url(object.file.url(:original))\n    end\n  end\n\n  def remote_url\n    object.remote_url.presence\n  end\n\n  def preview_url\n    if object.needs_redownload?\n      media_proxy_url(object.id, :small)\n    else\n      full_asset_url(object.file.url(:small))\n    end\n  end\n\n  def text_url\n    object.local? ? medium_url(object) : nil\n  end\n\n  def meta\n    object.file.meta\n  end\nend\n"
  },
  {
    "path": "app/serializers/rest/notification_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass REST::NotificationSerializer < ActiveModel::Serializer\n  attributes :id, :type, :created_at\n\n  belongs_to :from_account, key: :account, serializer: REST::AccountSerializer\n  belongs_to :target_status, key: :status, if: :status_type?, serializer: REST::StatusSerializer\n\n  def id\n    object.id.to_s\n  end\n\n  def status_type?\n    [:favourite, :reblog, :mention, :poll].include?(object.type)\n  end\nend\n"
  },
  {
    "path": "app/serializers/rest/poll_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass REST::PollSerializer < ActiveModel::Serializer\n  attributes :id, :expires_at, :expired,\n             :multiple, :votes_count\n\n  has_many :loaded_options, key: :options\n  has_many :emojis, serializer: REST::CustomEmojiSerializer\n\n  attribute :voted, if: :current_user?\n\n  def id\n    object.id.to_s\n  end\n\n  def expired\n    object.expired?\n  end\n\n  def voted\n    object.voted?(current_user.account)\n  end\n\n  def current_user?\n    !current_user.nil?\n  end\n\n  class OptionSerializer < ActiveModel::Serializer\n    attributes :title, :votes_count\n  end\nend\n"
  },
  {
    "path": "app/serializers/rest/preferences_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass REST::PreferencesSerializer < ActiveModel::Serializer\n  attribute :posting_default_privacy, key: 'posting:default:visibility'\n  attribute :posting_default_sensitive, key: 'posting:default:sensitive'\n  attribute :posting_default_language, key: 'posting:default:language'\n\n  attribute :reading_default_sensitive_media, key: 'reading:expand:media'\n  attribute :reading_default_sensitive_text, key: 'reading:expand:spoilers'\n\n  def posting_default_privacy\n    object.user.setting_default_privacy\n  end\n\n  def posting_default_sensitive\n    object.user.setting_default_sensitive\n  end\n\n  def posting_default_language\n    object.user.setting_default_language.presence\n  end\n\n  def reading_default_sensitive_media\n    object.user.setting_display_media\n  end\n\n  def reading_default_sensitive_text\n    object.user.setting_expand_spoilers\n  end\nend\n"
  },
  {
    "path": "app/serializers/rest/preview_card_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass REST::PreviewCardSerializer < ActiveModel::Serializer\n  include RoutingHelper\n\n  attributes :url, :title, :description, :type,\n             :author_name, :author_url, :provider_name,\n             :provider_url, :html, :width, :height,\n             :image, :embed_url\n\n  def image\n    object.image? ? full_asset_url(object.image.url(:original)) : nil\n  end\nend\n"
  },
  {
    "path": "app/serializers/rest/relationship_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass REST::RelationshipSerializer < ActiveModel::Serializer\n  attributes :id, :following, :showing_reblogs, :followed_by, :blocking, :blocked_by,\n             :muting, :muting_notifications, :requested, :domain_blocking,\n             :endorsed\n\n  def id\n    object.id.to_s\n  end\n\n  def following\n    instance_options[:relationships].following[object.id] ? true : false\n  end\n\n  def showing_reblogs\n    (instance_options[:relationships].following[object.id] || {})[:reblogs] ||\n      (instance_options[:relationships].requested[object.id] || {})[:reblogs] ||\n      false\n  end\n\n  def followed_by\n    instance_options[:relationships].followed_by[object.id] || false\n  end\n\n  def blocking\n    instance_options[:relationships].blocking[object.id] || false\n  end\n\n  def blocked_by\n    instance_options[:relationships].blocked_by[object.id] || false\n  end\n\n  def muting\n    instance_options[:relationships].muting[object.id] ? true : false\n  end\n\n  def muting_notifications\n    (instance_options[:relationships].muting[object.id] || {})[:notifications] || false\n  end\n\n  def requested\n    instance_options[:relationships].requested[object.id] ? true : false\n  end\n\n  def domain_blocking\n    instance_options[:relationships].domain_blocking[object.id] || false\n  end\n\n  def endorsed\n    instance_options[:relationships].endorsed[object.id] || false\n  end\nend\n"
  },
  {
    "path": "app/serializers/rest/report_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass REST::ReportSerializer < ActiveModel::Serializer\n  attributes :id, :action_taken\n\n  def id\n    object.id.to_s\n  end\nend\n"
  },
  {
    "path": "app/serializers/rest/scheduled_status_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass REST::ScheduledStatusSerializer < ActiveModel::Serializer\n  attributes :id, :scheduled_at, :params\n\n  has_many :media_attachments, serializer: REST::MediaAttachmentSerializer\n\n  def id\n    object.id.to_s\n  end\n\n  def params\n    object.params.without(:application_id)\n  end\nend\n"
  },
  {
    "path": "app/serializers/rest/search_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass REST::SearchSerializer < ActiveModel::Serializer\n  attributes :hashtags\n\n  has_many :accounts, serializer: REST::AccountSerializer\n  has_many :statuses, serializer: REST::StatusSerializer\n\n  def hashtags\n    object.hashtags.map(&:name)\n  end\nend\n"
  },
  {
    "path": "app/serializers/rest/status_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass REST::StatusSerializer < ActiveModel::Serializer\n  attributes :id, :created_at, :in_reply_to_id, :in_reply_to_account_id,\n             :sensitive, :spoiler_text, :visibility, :language,\n             :uri, :url, :replies_count, :reblogs_count,\n             :favourites_count\n\n  attribute :favourited, if: :current_user?\n  attribute :reblogged, if: :current_user?\n  attribute :muted, if: :current_user?\n  attribute :pinned, if: :pinnable?\n\n  attribute :content, unless: :source_requested?\n  attribute :text, if: :source_requested?\n\n  belongs_to :reblog, serializer: REST::StatusSerializer\n  belongs_to :application, if: :show_application?\n  belongs_to :account, serializer: REST::AccountSerializer\n\n  has_many :media_attachments, serializer: REST::MediaAttachmentSerializer\n  has_many :ordered_mentions, key: :mentions\n  has_many :tags\n  has_many :emojis, serializer: REST::CustomEmojiSerializer\n\n  has_one :preview_card, key: :card, serializer: REST::PreviewCardSerializer\n  has_one :preloadable_poll, key: :poll, serializer: REST::PollSerializer\n\n  def id\n    object.id.to_s\n  end\n\n  def in_reply_to_id\n    object.in_reply_to_id&.to_s\n  end\n\n  def in_reply_to_account_id\n    object.in_reply_to_account_id&.to_s\n  end\n\n  def current_user?\n    !current_user.nil?\n  end\n\n  def show_application?\n    object.account.user_shows_application? || (current_user? && current_user.account_id == object.account_id)\n  end\n\n  def visibility\n    # This visibility is masked behind \"private\"\n    # to avoid API changes because there are no\n    # UX differences\n    if object.limited_visibility?\n      'private'\n    else\n      object.visibility\n    end\n  end\n\n  def uri\n    OStatus::TagManager.instance.uri_for(object)\n  end\n\n  def content\n    Formatter.instance.format(object)\n  end\n\n  def url\n    TagManager.instance.url_for(object)\n  end\n\n  def favourited\n    if instance_options && instance_options[:relationships]\n      instance_options[:relationships].favourites_map[object.id] || false\n    else\n      current_user.account.favourited?(object)\n    end\n  end\n\n  def reblogged\n    if instance_options && instance_options[:relationships]\n      instance_options[:relationships].reblogs_map[object.id] || false\n    else\n      current_user.account.reblogged?(object)\n    end\n  end\n\n  def muted\n    if instance_options && instance_options[:relationships]\n      instance_options[:relationships].mutes_map[object.conversation_id] || false\n    else\n      current_user.account.muting_conversation?(object.conversation)\n    end\n  end\n\n  def pinned\n    if instance_options && instance_options[:relationships]\n      instance_options[:relationships].pins_map[object.id] || false\n    else\n      current_user.account.pinned?(object)\n    end\n  end\n\n  def pinnable?\n    current_user? &&\n      current_user.account_id == object.account_id &&\n      !object.reblog? &&\n      %w(public unlisted).include?(object.visibility)\n  end\n\n  def source_requested?\n    instance_options[:source_requested]\n  end\n\n  def ordered_mentions\n    object.active_mentions.to_a.sort_by(&:id)\n  end\n\n  class ApplicationSerializer < ActiveModel::Serializer\n    attributes :name, :website\n  end\n\n  class MentionSerializer < ActiveModel::Serializer\n    attributes :id, :username, :url, :acct\n\n    def id\n      object.account_id.to_s\n    end\n\n    def username\n      object.account_username\n    end\n\n    def url\n      TagManager.instance.url_for(object.account)\n    end\n\n    def acct\n      object.account_acct\n    end\n  end\n\n  class TagSerializer < ActiveModel::Serializer\n    include RoutingHelper\n\n    attributes :name, :url\n\n    def url\n      tag_url(object)\n    end\n  end\nend\n"
  },
  {
    "path": "app/serializers/rest/tag_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass REST::TagSerializer < ActiveModel::Serializer\n  include RoutingHelper\n\n  attributes :name, :url, :history\n\n  def url\n    tag_url(object)\n  end\nend\n"
  },
  {
    "path": "app/serializers/rest/v2/search_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass REST::V2::SearchSerializer < ActiveModel::Serializer\n  has_many :accounts, serializer: REST::AccountSerializer\n  has_many :statuses, serializer: REST::StatusSerializer\n  has_many :hashtags, serializer: REST::TagSerializer\nend\n"
  },
  {
    "path": "app/serializers/rest/web_push_subscription_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass REST::WebPushSubscriptionSerializer < ActiveModel::Serializer\n  attributes :id, :endpoint, :alerts, :server_key\n\n  def alerts\n    object.data&.dig('alerts') || {}\n  end\n\n  def server_key\n    Rails.configuration.x.vapid_public_key\n  end\nend\n"
  },
  {
    "path": "app/serializers/rss/account_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass RSS::AccountSerializer\n  include ActionView::Helpers::NumberHelper\n  include StreamEntriesHelper\n  include RoutingHelper\n\n  def render(account, statuses)\n    builder = RSSBuilder.new\n\n    builder.title(\"#{display_name(account)} (@#{account.local_username_and_domain})\")\n           .description(account_description(account))\n           .link(TagManager.instance.url_for(account))\n           .logo(full_pack_url('media/images/logo.svg'))\n           .accent_color('2b90d9')\n\n    builder.image(full_asset_url(account.avatar.url(:original))) if account.avatar?\n    builder.cover(full_asset_url(account.header.url(:original))) if account.header?\n\n    statuses.each do |status|\n      builder.item do |item|\n        item.title(status.title)\n            .link(TagManager.instance.url_for(status))\n            .pub_date(status.created_at)\n            .description(status.spoiler_text.presence || Formatter.instance.format(status, inline_poll_options: true).to_str)\n\n        status.media_attachments.each do |media|\n          item.enclosure(full_asset_url(media.file.url(:original, false)), media.file.content_type, length: media.file.size)\n        end\n      end\n    end\n\n    builder.to_xml\n  end\n\n  def self.render(account, statuses)\n    new.render(account, statuses)\n  end\nend\n"
  },
  {
    "path": "app/serializers/rss/tag_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass RSS::TagSerializer\n  include ActionView::Helpers::NumberHelper\n  include ActionView::Helpers::SanitizeHelper\n  include StreamEntriesHelper\n  include RoutingHelper\n\n  def render(tag, statuses)\n    builder = RSSBuilder.new\n\n    builder.title(\"##{tag.name}\")\n           .description(strip_tags(I18n.t('about.about_hashtag_html', hashtag: tag.name)))\n           .link(tag_url(tag))\n           .logo(full_pack_url('media/images/logo.svg'))\n           .accent_color('2b90d9')\n\n    statuses.each do |status|\n      builder.item do |item|\n        item.title(status.title)\n            .link(TagManager.instance.url_for(status))\n            .pub_date(status.created_at)\n            .description(status.spoiler_text.presence || Formatter.instance.format(status).to_str)\n\n        status.media_attachments.each do |media|\n          item.enclosure(full_asset_url(media.file.url(:original, false)), media.file.content_type, length: media.file.size)\n        end\n      end\n    end\n\n    builder.to_xml\n  end\n\n  def self.render(tag, statuses)\n    new.render(tag, statuses)\n  end\nend\n"
  },
  {
    "path": "app/serializers/web/notification_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass Web::NotificationSerializer < ActiveModel::Serializer\n  include RoutingHelper\n  include ActionView::Helpers::TextHelper\n  include ActionView::Helpers::SanitizeHelper\n\n  attributes :access_token, :preferred_locale, :notification_id,\n             :notification_type, :icon, :title, :body\n\n  def access_token\n    current_push_subscription.associated_access_token\n  end\n\n  def preferred_locale\n    current_push_subscription.associated_user&.locale || I18n.default_locale\n  end\n\n  def notification_id\n    object.id\n  end\n\n  def notification_type\n    object.type\n  end\n\n  def icon\n    full_asset_url(object.from_account.avatar_static_url)\n  end\n\n  def title\n    I18n.t(\"notification_mailer.#{object.type}.subject\", name: object.from_account.display_name.presence || object.from_account.username)\n  end\n\n  def body\n    str = strip_tags(object.target_status&.spoiler_text&.presence || object.target_status&.text || object.from_account.note)\n    truncate(HTMLEntities.new.decode(str.to_str), length: 140) # Do not encode entities, since this value will not be used in HTML\n  end\nend\n"
  },
  {
    "path": "app/serializers/webfinger_serializer.rb",
    "content": "# frozen_string_literal: true\n\nclass WebfingerSerializer < ActiveModel::Serializer\n  include RoutingHelper\n\n  attributes :subject, :aliases, :links\n\n  def subject\n    object.to_webfinger_s\n  end\n\n  def aliases\n    [short_account_url(object), account_url(object)]\n  end\n\n  def links\n    [\n      { rel: 'http://webfinger.net/rel/profile-page', type: 'text/html', href: short_account_url(object) },\n      { rel: 'http://schemas.google.com/g/2010#updates-from', type: 'application/atom+xml', href: account_url(object, format: 'atom') },\n      { rel: 'self', type: 'application/activity+json', href: account_url(object) },\n      { rel: 'salmon', href: api_salmon_url(object.id) },\n      { rel: 'magic-public-key', href: \"data:application/magic-public-key,#{object.magic_key}\" },\n      { rel: 'http://ostatus.org/schema/1.0/subscribe', template: \"#{authorize_interaction_url}?uri={uri}\" },\n    ]\n  end\nend\n"
  },
  {
    "path": "app/services/account_search_service.rb",
    "content": "# frozen_string_literal: true\n\nclass AccountSearchService < BaseService\n  attr_reader :query, :limit, :offset, :options, :account\n\n  def call(query, account = nil, options = {})\n    @query   = query.strip\n    @limit   = options[:limit].to_i\n    @offset  = options[:offset].to_i\n    @options = options\n    @account = account\n\n    search_service_results\n  end\n\n  private\n\n  def search_service_results\n    return [] if query_blank_or_hashtag? || limit < 1\n\n    if resolving_non_matching_remote_account?\n      [ResolveAccountService.new.call(\"#{query_username}@#{query_domain}\")].compact\n    else\n      search_results_and_exact_match.compact.uniq.slice(0, limit)\n    end\n  end\n\n  def resolving_non_matching_remote_account?\n    options[:resolve] && !exact_match && !domain_is_local?\n  end\n\n  def search_results_and_exact_match\n    exact = [exact_match]\n    return exact if !exact[0].nil? && limit == 1\n    exact + search_results.to_a\n  end\n\n  def query_blank_or_hashtag?\n    query.blank? || query.start_with?('#')\n  end\n\n  def split_query_string\n    @_split_query_string ||= query.gsub(/\\A@/, '').split('@')\n  end\n\n  def query_username\n    @_query_username ||= split_query_string.first || ''\n  end\n\n  def query_domain\n    @_query_domain ||= query_without_split? ? nil : split_query_string.last\n  end\n\n  def query_without_split?\n    split_query_string.size == 1\n  end\n\n  def domain_is_local?\n    @_domain_is_local ||= TagManager.instance.local_domain?(query_domain)\n  end\n\n  def search_from\n    options[:following] && account ? account.following : Account\n  end\n\n  def exact_match\n    @_exact_match ||= begin\n      if domain_is_local?\n        search_from.without_suspended.find_local(query_username)\n      else\n        search_from.without_suspended.find_remote(query_username, query_domain)\n      end\n    end\n  end\n\n  def search_results\n    @_search_results ||= begin\n      if account\n        advanced_search_results\n      else\n        simple_search_results\n      end\n    end\n  end\n\n  def advanced_search_results\n    Account.advanced_search_for(terms_for_query, account, limit, options[:following], offset)\n  end\n\n  def simple_search_results\n    Account.search_for(terms_for_query, limit, offset)\n  end\n\n  def terms_for_query\n    if domain_is_local?\n      query_username\n    else\n      \"#{query_username} #{query_domain}\"\n    end\n  end\nend\n"
  },
  {
    "path": "app/services/activitypub/fetch_featured_collection_service.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::FetchFeaturedCollectionService < BaseService\n  include JsonLdHelper\n\n  def call(account)\n    return if account.featured_collection_url.blank?\n\n    @account = account\n    @json    = fetch_resource(@account.featured_collection_url, true)\n\n    return unless supported_context?\n    return if @account.suspended? || @account.local?\n\n    case @json['type']\n    when 'Collection', 'CollectionPage'\n      process_items @json['items']\n    when 'OrderedCollection', 'OrderedCollectionPage'\n      process_items @json['orderedItems']\n    end\n  end\n\n  private\n\n  def process_items(items)\n    status_ids = items.map { |item| value_or_id(item) }\n                      .reject { |uri| ActivityPub::TagManager.instance.local_uri?(uri) }\n                      .map { |uri| ActivityPub::FetchRemoteStatusService.new.call(uri) }\n                      .compact\n                      .select { |status| status.account_id == @account.id }\n                      .map(&:id)\n\n    to_remove = []\n    to_add    = status_ids\n\n    StatusPin.where(account: @account).pluck(:status_id).each do |status_id|\n      if status_ids.include?(status_id)\n        to_add.delete(status_id)\n      else\n        to_remove << status_id\n      end\n    end\n\n    StatusPin.where(account: @account, status_id: to_remove).delete_all unless to_remove.empty?\n\n    to_add.each do |status_id|\n      StatusPin.create!(account: @account, status_id: status_id)\n    end\n  end\n\n  def supported_context?\n    super(@json)\n  end\nend\n"
  },
  {
    "path": "app/services/activitypub/fetch_remote_account_service.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::FetchRemoteAccountService < BaseService\n  include JsonLdHelper\n\n  SUPPORTED_TYPES = %w(Application Group Organization Person Service).freeze\n\n  # Does a WebFinger roundtrip on each call, unless `only_key` is true\n  def call(uri, id: true, prefetched_body: nil, break_on_redirect: false, only_key: false)\n    return ActivityPub::TagManager.instance.uri_to_resource(uri, Account) if ActivityPub::TagManager.instance.local_uri?(uri)\n\n    @json = if prefetched_body.nil?\n              fetch_resource(uri, id)\n            else\n              body_to_json(prefetched_body, compare_id: id ? uri : nil)\n            end\n\n    return if !supported_context? || !expected_type? || (break_on_redirect && @json['movedTo'].present?)\n\n    @uri      = @json['id']\n    @username = @json['preferredUsername']\n    @domain   = Addressable::URI.parse(@uri).normalized_host\n\n    return unless only_key || verified_webfinger?\n\n    ActivityPub::ProcessAccountService.new.call(@username, @domain, @json, only_key: only_key)\n  rescue Oj::ParseError\n    nil\n  end\n\n  private\n\n  def verified_webfinger?\n    webfinger                            = Goldfinger.finger(\"acct:#{@username}@#{@domain}\")\n    confirmed_username, confirmed_domain = split_acct(webfinger.subject)\n\n    return webfinger.link('self')&.href == @uri if @username.casecmp(confirmed_username).zero? && @domain.casecmp(confirmed_domain).zero?\n\n    webfinger                            = Goldfinger.finger(\"acct:#{confirmed_username}@#{confirmed_domain}\")\n    @username, @domain                   = split_acct(webfinger.subject)\n    self_reference                       = webfinger.link('self')\n\n    return false unless @username.casecmp(confirmed_username).zero? && @domain.casecmp(confirmed_domain).zero?\n    return false if self_reference&.href != @uri\n\n    true\n  rescue Goldfinger::Error\n    false\n  end\n\n  def split_acct(acct)\n    acct.gsub(/\\Aacct:/, '').split('@')\n  end\n\n  def supported_context?\n    super(@json)\n  end\n\n  def expected_type?\n    equals_or_includes_any?(@json['type'], SUPPORTED_TYPES)\n  end\nend\n"
  },
  {
    "path": "app/services/activitypub/fetch_remote_key_service.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::FetchRemoteKeyService < BaseService\n  include JsonLdHelper\n\n  # Returns account that owns the key\n  def call(uri, id: true, prefetched_body: nil)\n    if prefetched_body.nil?\n      if id\n        @json = fetch_resource_without_id_validation(uri)\n        if person?\n          @json = fetch_resource(@json['id'], true)\n        elsif uri != @json['id']\n          return\n        end\n      else\n        @json = fetch_resource(uri, id)\n      end\n    else\n      @json = body_to_json(prefetched_body, compare_id: id ? uri : nil)\n    end\n\n    return unless supported_context?(@json) && expected_type?\n    return find_account(@json['id'], @json) if person?\n\n    @owner = fetch_resource(owner_uri, true)\n\n    return unless supported_context?(@owner) && confirmed_owner?\n\n    find_account(owner_uri, @owner)\n  end\n\n  private\n\n  def find_account(uri, prefetched_body)\n    account   = ActivityPub::TagManager.instance.uri_to_resource(uri, Account)\n    account ||= ActivityPub::FetchRemoteAccountService.new.call(uri, prefetched_body: prefetched_body)\n    account\n  end\n\n  def expected_type?\n    person? || public_key?\n  end\n\n  def person?\n    equals_or_includes_any?(@json['type'], ActivityPub::FetchRemoteAccountService::SUPPORTED_TYPES)\n  end\n\n  def public_key?\n    @json['publicKeyPem'].present? && @json['owner'].present?\n  end\n\n  def owner_uri\n    @owner_uri ||= value_or_id(@json['owner'])\n  end\n\n  def confirmed_owner?\n    equals_or_includes_any?(@owner['type'], ActivityPub::FetchRemoteAccountService::SUPPORTED_TYPES) && value_or_id(@owner['publicKey']) == @json['id']\n  end\nend\n"
  },
  {
    "path": "app/services/activitypub/fetch_remote_poll_service.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::FetchRemotePollService < BaseService\n  include JsonLdHelper\n\n  def call(poll, on_behalf_of = nil)\n    json = fetch_resource(poll.status.uri, true, on_behalf_of)\n    return unless supported_context?(json)\n    ActivityPub::ProcessPollService.new.call(poll, json)\n  end\nend\n"
  },
  {
    "path": "app/services/activitypub/fetch_remote_status_service.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::FetchRemoteStatusService < BaseService\n  include JsonLdHelper\n\n  # Should be called when uri has already been checked for locality\n  def call(uri, id: true, prefetched_body: nil, on_behalf_of: nil)\n    @json = if prefetched_body.nil?\n              fetch_resource(uri, id, on_behalf_of)\n            else\n              body_to_json(prefetched_body, compare_id: id ? uri : nil)\n            end\n\n    return unless supported_context? && expected_type?\n\n    return if actor_id.nil? || !trustworthy_attribution?(@json['id'], actor_id)\n\n    actor = ActivityPub::TagManager.instance.uri_to_resource(actor_id, Account)\n    actor = ActivityPub::FetchRemoteAccountService.new.call(actor_id, id: true) if actor.nil? || needs_update(actor)\n\n    return if actor.nil? || actor.suspended?\n\n    ActivityPub::Activity.factory(activity_json, actor).perform\n  end\n\n  private\n\n  def activity_json\n    { 'type' => 'Create', 'actor' => actor_id, 'object' => @json }\n  end\n\n  def actor_id\n    value_or_id(first_of_value(@json['attributedTo']))\n  end\n\n  def trustworthy_attribution?(uri, attributed_to)\n    return false if uri.nil? || attributed_to.nil?\n    Addressable::URI.parse(uri).normalized_host.casecmp(Addressable::URI.parse(attributed_to).normalized_host).zero?\n  end\n\n  def supported_context?\n    super(@json)\n  end\n\n  def expected_type?\n    equals_or_includes_any?(@json['type'], ActivityPub::Activity::Create::SUPPORTED_TYPES + ActivityPub::Activity::Create::CONVERTED_TYPES)\n  end\n\n  def needs_update(actor)\n    actor.possibly_stale?\n  end\nend\n"
  },
  {
    "path": "app/services/activitypub/fetch_replies_service.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::FetchRepliesService < BaseService\n  include JsonLdHelper\n\n  def call(parent_status, collection_or_uri, allow_synchronous_requests = true)\n    @account = parent_status.account\n    @allow_synchronous_requests = allow_synchronous_requests\n\n    @items = collection_items(collection_or_uri)\n    return if @items.nil?\n\n    FetchReplyWorker.push_bulk(filtered_replies)\n\n    @items\n  end\n\n  private\n\n  def collection_items(collection_or_uri)\n    collection = fetch_collection(collection_or_uri)\n    return unless collection.is_a?(Hash)\n\n    collection = fetch_collection(collection['first']) if collection['first'].present?\n    return unless collection.is_a?(Hash)\n\n    case collection['type']\n    when 'Collection', 'CollectionPage'\n      collection['items']\n    when 'OrderedCollection', 'OrderedCollectionPage'\n      collection['orderedItems']\n    end\n  end\n\n  def fetch_collection(collection_or_uri)\n    return collection_or_uri if collection_or_uri.is_a?(Hash)\n    return unless @allow_synchronous_requests\n    return if invalid_origin?(collection_or_uri)\n    fetch_resource_without_id_validation(collection_or_uri, nil, true)\n  end\n\n  def filtered_replies\n    # Only fetch replies to the same server as the original status to avoid\n    # amplification attacks.\n\n    # Also limit to 5 fetched replies to limit potential for DoS.\n    @items.map { |item| value_or_id(item) }.reject { |uri| invalid_origin?(uri) }.take(5)\n  end\nend\n"
  },
  {
    "path": "app/services/activitypub/process_account_service.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::ProcessAccountService < BaseService\n  include JsonLdHelper\n\n  # Should be called with confirmed valid JSON\n  # and WebFinger-resolved username and domain\n  def call(username, domain, json, options = {})\n    return if json['inbox'].blank? || unsupported_uri_scheme?(json['id'])\n\n    @options     = options\n    @json        = json\n    @uri         = @json['id']\n    @username    = username\n    @domain      = domain\n    @collections = {}\n\n    RedisLock.acquire(lock_options) do |lock|\n      if lock.acquired?\n        @account        = Account.find_remote(@username, @domain)\n        @old_public_key = @account&.public_key\n        @old_protocol   = @account&.protocol\n\n        create_account if @account.nil?\n        update_account\n        process_tags\n        process_attachments\n      else\n        raise Mastodon::RaceConditionError\n      end\n    end\n\n    return if @account.nil?\n\n    after_protocol_change! if protocol_changed?\n    after_key_change! if key_changed? && !@options[:signed_with_known_key]\n    clear_tombstones! if key_changed?\n\n    unless @options[:only_key]\n      check_featured_collection! if @account.featured_collection_url.present?\n      check_links! unless @account.fields.empty?\n    end\n\n    @account\n  rescue Oj::ParseError\n    nil\n  end\n\n  private\n\n  def create_account\n    @account = Account.new\n    @account.protocol     = :activitypub\n    @account.username     = @username\n    @account.domain       = @domain\n    @account.private_key  = nil\n    @account.suspended_at = domain_block.created_at if auto_suspend?\n    @account.silenced_at = domain_block.created_at if auto_silence?\n  end\n\n  def update_account\n    @account.last_webfingered_at = Time.now.utc unless @options[:only_key]\n    @account.protocol            = :activitypub\n\n    set_immediate_attributes!\n    set_fetchable_attributes! unless @options[:only_keys]\n\n    @account.save_with_optional_media!\n  end\n\n  def set_immediate_attributes!\n    @account.inbox_url               = @json['inbox'] || ''\n    @account.outbox_url              = @json['outbox'] || ''\n    @account.shared_inbox_url        = (@json['endpoints'].is_a?(Hash) ? @json['endpoints']['sharedInbox'] : @json['sharedInbox']) || ''\n    @account.followers_url           = @json['followers'] || ''\n    @account.featured_collection_url = @json['featured'] || ''\n    @account.url                     = url || @uri\n    @account.uri                     = @uri\n    @account.display_name            = @json['name'] || ''\n    @account.note                    = @json['summary'] || ''\n    @account.locked                  = @json['manuallyApprovesFollowers'] || false\n    @account.fields                  = property_values || {}\n    @account.also_known_as           = as_array(@json['alsoKnownAs'] || []).map { |item| value_or_id(item) }\n    @account.actor_type              = actor_type\n  end\n\n  def set_fetchable_attributes!\n    @account.avatar_remote_url = image_url('icon')  unless skip_download?\n    @account.header_remote_url = image_url('image') unless skip_download?\n    @account.public_key        = public_key || ''\n    @account.statuses_count    = outbox_total_items    if outbox_total_items.present?\n    @account.following_count   = following_total_items if following_total_items.present?\n    @account.followers_count   = followers_total_items if followers_total_items.present?\n    @account.moved_to_account  = @json['movedTo'].present? ? moved_account : nil\n  end\n\n  def after_protocol_change!\n    ActivityPub::PostUpgradeWorker.perform_async(@account.domain)\n  end\n\n  def after_key_change!\n    RefollowWorker.perform_async(@account.id)\n  end\n\n  def check_featured_collection!\n    ActivityPub::SynchronizeFeaturedCollectionWorker.perform_async(@account.id)\n  end\n\n  def check_links!\n    VerifyAccountLinksWorker.perform_async(@account.id)\n  end\n\n  def actor_type\n    if @json['type'].is_a?(Array)\n      @json['type'].find { |type| ActivityPub::FetchRemoteAccountService::SUPPORTED_TYPES.include?(type) }\n    else\n      @json['type']\n    end\n  end\n\n  def image_url(key)\n    value = first_of_value(@json[key])\n\n    return if value.nil?\n    return value['url'] if value.is_a?(Hash)\n\n    image = fetch_resource_without_id_validation(value)\n    image['url'] if image\n  end\n\n  def public_key\n    value = first_of_value(@json['publicKey'])\n\n    return if value.nil?\n    return value['publicKeyPem'] if value.is_a?(Hash)\n\n    key = fetch_resource_without_id_validation(value)\n    key['publicKeyPem'] if key\n  end\n\n  def url\n    return if @json['url'].blank?\n\n    url_candidate = url_to_href(@json['url'], 'text/html')\n\n    if unsupported_uri_scheme?(url_candidate) || mismatching_origin?(url_candidate)\n      nil\n    else\n      url_candidate\n    end\n  end\n\n  def property_values\n    return unless @json['attachment'].is_a?(Array)\n    as_array(@json['attachment']).select { |attachment| attachment['type'] == 'PropertyValue' }.map { |attachment| attachment.slice('name', 'value') }\n  end\n\n  def mismatching_origin?(url)\n    needle   = Addressable::URI.parse(url).host\n    haystack = Addressable::URI.parse(@uri).host\n\n    !haystack.casecmp(needle).zero?\n  end\n\n  def outbox_total_items\n    collection_total_items('outbox')\n  end\n\n  def following_total_items\n    collection_total_items('following')\n  end\n\n  def followers_total_items\n    collection_total_items('followers')\n  end\n\n  def collection_total_items(type)\n    return if @json[type].blank?\n    return @collections[type] if @collections.key?(type)\n\n    collection = fetch_resource_without_id_validation(@json[type])\n\n    @collections[type] = collection.is_a?(Hash) && collection['totalItems'].present? && collection['totalItems'].is_a?(Numeric) ? collection['totalItems'] : nil\n  rescue HTTP::Error, OpenSSL::SSL::SSLError\n    @collections[type] = nil\n  end\n\n  def moved_account\n    account   = ActivityPub::TagManager.instance.uri_to_resource(@json['movedTo'], Account)\n    account ||= ActivityPub::FetchRemoteAccountService.new.call(@json['movedTo'], id: true, break_on_redirect: true)\n    account\n  end\n\n  def skip_download?\n    @account.suspended? || domain_block&.reject_media?\n  end\n\n  def auto_suspend?\n    domain_block&.suspend?\n  end\n\n  def auto_silence?\n    domain_block&.silence?\n  end\n\n  def domain_block\n    return @domain_block if defined?(@domain_block)\n    @domain_block = DomainBlock.find_by(domain: @domain)\n  end\n\n  def key_changed?\n    !@old_public_key.nil? && @old_public_key != @account.public_key\n  end\n\n  def clear_tombstones!\n    Tombstone.where(account_id: @account.id).delete_all\n  end\n\n  def protocol_changed?\n    !@old_protocol.nil? && @old_protocol != @account.protocol\n  end\n\n  def lock_options\n    { redis: Redis.current, key: \"process_account:#{@uri}\" }\n  end\n\n  def process_tags\n    return if @json['tag'].blank?\n\n    as_array(@json['tag']).each do |tag|\n      process_emoji tag if equals_or_includes?(tag['type'], 'Emoji')\n    end\n  end\n\n  def process_attachments\n    return if @json['attachment'].blank?\n\n    previous_proofs = @account.identity_proofs.to_a\n    current_proofs  = []\n\n    as_array(@json['attachment']).each do |attachment|\n      next unless equals_or_includes?(attachment['type'], 'IdentityProof')\n      current_proofs << process_identity_proof(attachment)\n    end\n\n    previous_proofs.each do |previous_proof|\n      next if current_proofs.any? { |current_proof| current_proof.id == previous_proof.id }\n      previous_proof.delete\n    end\n  end\n\n  def process_emoji(tag)\n    return if skip_download?\n    return if tag['name'].blank? || tag['icon'].blank? || tag['icon']['url'].blank?\n\n    shortcode = tag['name'].delete(':')\n    image_url = tag['icon']['url']\n    uri       = tag['id']\n    updated   = tag['updated']\n    emoji     = CustomEmoji.find_by(shortcode: shortcode, domain: @account.domain)\n\n    return unless emoji.nil? || image_url != emoji.image_remote_url || (updated && updated >= emoji.updated_at)\n\n    emoji ||= CustomEmoji.new(domain: @account.domain, shortcode: shortcode, uri: uri)\n    emoji.image_remote_url = image_url\n    emoji.save\n  end\n\n  def process_identity_proof(attachment)\n    provider          = attachment['signatureAlgorithm']\n    provider_username = attachment['name']\n    token             = attachment['signatureValue']\n\n    @account.identity_proofs.where(provider: provider, provider_username: provider_username).find_or_create_by(provider: provider, provider_username: provider_username, token: token)\n  end\nend\n"
  },
  {
    "path": "app/services/activitypub/process_collection_service.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::ProcessCollectionService < BaseService\n  include JsonLdHelper\n\n  def call(body, account, **options)\n    @account = account\n    @json    = Oj.load(body, mode: :strict)\n    @options = options\n\n    return unless supported_context?\n    return if different_actor? && verify_account!.nil?\n    return if @account.suspended? || @account.local?\n\n    case @json['type']\n    when 'Collection', 'CollectionPage'\n      process_items @json['items']\n    when 'OrderedCollection', 'OrderedCollectionPage'\n      process_items @json['orderedItems']\n    else\n      process_items [@json]\n    end\n  rescue Oj::ParseError\n    nil\n  end\n\n  private\n\n  def different_actor?\n    @json['actor'].present? && value_or_id(@json['actor']) != @account.uri\n  end\n\n  def process_items(items)\n    items.reverse_each.map { |item| process_item(item) }.compact\n  end\n\n  def supported_context?\n    super(@json)\n  end\n\n  def process_item(item)\n    activity = ActivityPub::Activity.factory(item, @account, @options)\n    activity&.perform\n  end\n\n  def verify_account!\n    @options[:relayed_through_account] = @account\n    @account = ActivityPub::LinkedDataSignature.new(@json).verify_account!\n  rescue JSON::LD::JsonLdError => e\n    Rails.logger.debug \"Could not verify LD-Signature for #{value_or_id(@json['actor'])}: #{e.message}\"\n    nil\n  end\nend\n"
  },
  {
    "path": "app/services/activitypub/process_poll_service.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::ProcessPollService < BaseService\n  include JsonLdHelper\n\n  def call(poll, json)\n    @json = json\n    return unless expected_type?\n\n    previous_expires_at = poll.expires_at\n\n    expires_at = begin\n      if @json['closed'].is_a?(String)\n        @json['closed']\n      elsif !@json['closed'].nil? && !@json['closed'].is_a?(FalseClass)\n        Time.now.utc\n      else\n        @json['endTime']\n      end\n    end\n\n    items = begin\n      if @json['anyOf'].is_a?(Array)\n        @json['anyOf']\n      else\n        @json['oneOf']\n      end\n    end\n\n    latest_options = items.map { |item| item['name'].presence || item['content'] }\n\n    # If for some reasons the options were changed, it invalidates all previous\n    # votes, so we need to remove them\n    poll.votes.delete_all if latest_options != poll.options\n\n    begin\n      poll.update!(\n        last_fetched_at: Time.now.utc,\n        expires_at: expires_at,\n        options: latest_options,\n        cached_tallies: items.map { |item| item.dig('replies', 'totalItems') || 0 }\n      )\n    rescue ActiveRecord::StaleObjectError\n      poll.reload\n      retry\n    end\n\n    # If the poll had no expiration date set but now has, and people have voted,\n    # schedule a notification.\n    if previous_expires_at.nil? && poll.expires_at.present? && poll.votes.exists?\n      PollExpirationNotifyWorker.perform_at(poll.expires_at + 5.minutes, poll.id)\n    end\n  end\n\n  private\n\n  def expected_type?\n    equals_or_includes_any?(@json['type'], %w(Question))\n  end\nend\n"
  },
  {
    "path": "app/services/after_block_domain_from_account_service.rb",
    "content": "# frozen_string_literal: true\n\nclass AfterBlockDomainFromAccountService < BaseService\n  include Payloadable\n\n  # This service does not create an AccountDomainBlock record,\n  # it's meant to be called after such a record has been created\n  # synchronously, to \"clean up\"\n  def call(account, domain)\n    @account = account\n    @domain  = domain\n\n    reject_existing_followers!\n    reject_pending_follow_requests!\n  end\n\n  private\n\n  def reject_existing_followers!\n    @account.passive_relationships.where(account: Account.where(domain: @domain)).includes(:account).reorder(nil).find_each do |follow|\n      reject_follow!(follow)\n    end\n  end\n\n  def reject_pending_follow_requests!\n    FollowRequest.where(target_account: @account).where(account: Account.where(domain: @domain)).includes(:account).reorder(nil).find_each do |follow_request|\n      reject_follow!(follow_request)\n    end\n  end\n\n  def reject_follow!(follow)\n    follow.destroy\n\n    return unless follow.account.activitypub?\n\n    ActivityPub::DeliveryWorker.perform_async(Oj.dump(serialize_payload(follow, ActivityPub::RejectFollowSerializer)), @account.id, follow.account.inbox_url)\n  end\nend\n"
  },
  {
    "path": "app/services/after_block_service.rb",
    "content": "# frozen_string_literal: true\n\nclass AfterBlockService < BaseService\n  def call(account, target_account)\n    clear_home_feed(account, target_account)\n    clear_notifications(account, target_account)\n    clear_conversations(account, target_account)\n  end\n\n  private\n\n  def clear_home_feed(account, target_account)\n    FeedManager.instance.clear_from_timeline(account, target_account)\n  end\n\n  def clear_conversations(account, target_account)\n    AccountConversation.where(account: account)\n                       .where('? = ANY(participant_account_ids)', target_account.id)\n                       .in_batches\n                       .destroy_all\n  end\n\n  def clear_notifications(account, target_account)\n    Notification.where(account: account)\n                .joins(:follow)\n                .where(activity_type: 'Follow', follows: { account_id: target_account.id })\n                .delete_all\n\n    Notification.where(account: account)\n                .joins(mention: :status)\n                .where(activity_type: 'Mention', statuses: { account_id: target_account.id })\n                .delete_all\n\n    Notification.where(account: account)\n                .joins(:favourite)\n                .where(activity_type: 'Favourite', favourites: { account_id: target_account.id })\n                .delete_all\n\n    Notification.where(account: account)\n                .joins(:status)\n                .where(activity_type: 'Status', statuses: { account_id: target_account.id })\n                .delete_all\n  end\nend\n"
  },
  {
    "path": "app/services/app_sign_up_service.rb",
    "content": "# frozen_string_literal: true\n\nclass AppSignUpService < BaseService\n  def call(app, params)\n    return unless allowed_registrations?\n\n    user_params    = params.slice(:email, :password, :agreement, :locale)\n    account_params = params.slice(:username)\n    user           = User.create!(user_params.merge(created_by_application: app, password_confirmation: user_params[:password], account_attributes: account_params))\n\n    Doorkeeper::AccessToken.create!(application: app,\n                                    resource_owner_id: user.id,\n                                    scopes: app.scopes,\n                                    expires_in: Doorkeeper.configuration.access_token_expires_in,\n                                    use_refresh_token: Doorkeeper.configuration.refresh_token_enabled?)\n  end\n\n  private\n\n  def allowed_registrations?\n    Setting.registrations_mode != 'none' && !Rails.configuration.x.single_user_mode\n  end\nend\n"
  },
  {
    "path": "app/services/authorize_follow_service.rb",
    "content": "# frozen_string_literal: true\n\nclass AuthorizeFollowService < BaseService\n  include Payloadable\n\n  def call(source_account, target_account, **options)\n    if options[:skip_follow_request]\n      follow_request = FollowRequest.new(account: source_account, target_account: target_account, uri: options[:follow_request_uri])\n    else\n      follow_request = FollowRequest.find_by!(account: source_account, target_account: target_account)\n      follow_request.authorize!\n    end\n\n    create_notification(follow_request) unless source_account.local?\n    follow_request\n  end\n\n  private\n\n  def create_notification(follow_request)\n    if follow_request.account.ostatus?\n      NotificationWorker.perform_async(build_xml(follow_request), follow_request.target_account_id, follow_request.account_id)\n    elsif follow_request.account.activitypub?\n      ActivityPub::DeliveryWorker.perform_async(build_json(follow_request), follow_request.target_account_id, follow_request.account.inbox_url)\n    end\n  end\n\n  def build_json(follow_request)\n    Oj.dump(serialize_payload(follow_request, ActivityPub::AcceptFollowSerializer))\n  end\n\n  def build_xml(follow_request)\n    OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.authorize_follow_request_salmon(follow_request))\n  end\nend\n"
  },
  {
    "path": "app/services/backup_service.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rubygems/package'\n\nclass BackupService < BaseService\n  attr_reader :account, :backup, :collection\n\n  def call(backup)\n    @backup  = backup\n    @account = backup.user.account\n\n    build_json!\n    build_archive!\n  end\n\n  private\n\n  def build_json!\n    @collection = serialize(collection_presenter, ActivityPub::CollectionSerializer)\n\n    account.statuses.with_includes.reorder(nil).find_in_batches do |statuses|\n      statuses.each do |status|\n        item = serialize(status, ActivityPub::ActivitySerializer)\n        item.delete(:'@context')\n\n        unless item[:type] == 'Announce' || item[:object][:attachment].blank?\n          item[:object][:attachment].each do |attachment|\n            attachment[:url] = Addressable::URI.parse(attachment[:url]).path.gsub(/\\A\\/system\\//, '')\n          end\n        end\n\n        @collection[:orderedItems] << item\n      end\n\n      GC.start\n    end\n  end\n\n  def build_archive!\n    tmp_file = Tempfile.new(%w(archive .tar.gz))\n\n    File.open(tmp_file, 'wb') do |file|\n      Zlib::GzipWriter.wrap(file) do |gz|\n        Gem::Package::TarWriter.new(gz) do |tar|\n          dump_media_attachments!(tar)\n          dump_outbox!(tar)\n          dump_likes!(tar)\n          dump_actor!(tar)\n        end\n      end\n    end\n\n    archive_filename = ['archive', Time.now.utc.strftime('%Y%m%d%H%M%S'), SecureRandom.hex(16)].join('-') + '.tar.gz'\n\n    @backup.dump      = ActionDispatch::Http::UploadedFile.new(tempfile: tmp_file, filename: archive_filename)\n    @backup.processed = true\n    @backup.save!\n  ensure\n    tmp_file.close\n    tmp_file.unlink\n  end\n\n  def dump_media_attachments!(tar)\n    MediaAttachment.attached.where(account: account).reorder(nil).find_in_batches do |media_attachments|\n      media_attachments.each do |m|\n        download_to_tar(tar, m.file, m.file.path)\n      end\n\n      GC.start\n    end\n  end\n\n  def dump_outbox!(tar)\n    json = Oj.dump(collection)\n\n    tar.add_file_simple('outbox.json', 0o444, json.bytesize) do |io|\n      io.write(json)\n    end\n  end\n\n  def dump_actor!(tar)\n    actor = serialize(account, ActivityPub::ActorSerializer)\n\n    actor[:icon][:url]  = 'avatar' + File.extname(actor[:icon][:url])  if actor[:icon]\n    actor[:image][:url] = 'header' + File.extname(actor[:image][:url]) if actor[:image]\n    actor[:outbox]      = 'outbox.json'\n    actor[:likes]       = 'likes.json'\n\n    download_to_tar(tar, account.avatar, 'avatar' + File.extname(account.avatar.path)) if account.avatar.exists?\n    download_to_tar(tar, account.header, 'header' + File.extname(account.header.path)) if account.header.exists?\n\n    json = Oj.dump(actor)\n\n    tar.add_file_simple('actor.json', 0o444, json.bytesize) do |io|\n      io.write(json)\n    end\n  end\n\n  def dump_likes!(tar)\n    collection = serialize(ActivityPub::CollectionPresenter.new(id: 'likes.json', type: :ordered, size: 0, items: []), ActivityPub::CollectionSerializer)\n\n    Status.reorder(nil).joins(:favourites).includes(:account).merge(account.favourites).find_in_batches do |statuses|\n      statuses.each do |status|\n        collection[:totalItems] += 1\n        collection[:orderedItems] << ActivityPub::TagManager.instance.uri_for(status)\n      end\n\n      GC.start\n    end\n\n    json = Oj.dump(collection)\n\n    tar.add_file_simple('likes.json', 0o444, json.bytesize) do |io|\n      io.write(json)\n    end\n  end\n\n  def collection_presenter\n    ActivityPub::CollectionPresenter.new(\n      id: 'outbox.json',\n      type: :ordered,\n      size: account.statuses_count,\n      items: []\n    )\n  end\n\n  def serialize(object, serializer)\n    ActiveModelSerializers::SerializableResource.new(\n      object,\n      serializer: serializer,\n      adapter: ActivityPub::Adapter\n    ).as_json\n  end\n\n  CHUNK_SIZE = 1.megabyte\n\n  def download_to_tar(tar, attachment, filename)\n    adapter = Paperclip.io_adapters.for(attachment)\n\n    tar.add_file_simple(filename, 0o444, adapter.size) do |io|\n      while (buffer = adapter.read(CHUNK_SIZE))\n        io.write(buffer)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "app/services/base_service.rb",
    "content": "# frozen_string_literal: true\n\nclass BaseService\n  include ActionView::Helpers::TextHelper\n  include ActionView::Helpers::SanitizeHelper\n\n  include RoutingHelper\nend\n"
  },
  {
    "path": "app/services/batched_remove_status_service.rb",
    "content": "# frozen_string_literal: true\n\nclass BatchedRemoveStatusService < BaseService\n  include StreamEntryRenderer\n  include Redisable\n\n  # Delete given statuses and reblogs of them\n  # Dispatch PuSH updates of the deleted statuses, but only local ones\n  # Dispatch Salmon deletes, unique per domain, of the deleted statuses, but only local ones\n  # Remove statuses from home feeds\n  # Push delete events to streaming API for home feeds and public feeds\n  # @param [Status] statuses A preferably batched array of statuses\n  # @param [Hash] options\n  # @option [Boolean] :skip_side_effects\n  def call(statuses, **options)\n    statuses = Status.where(id: statuses.map(&:id)).includes(:account, :stream_entry).flat_map { |status| [status] + status.reblogs.includes(:account, :stream_entry).to_a }\n\n    @mentions = statuses.each_with_object({}) { |s, h| h[s.id] = s.active_mentions.includes(:account).to_a }\n    @tags     = statuses.each_with_object({}) { |s, h| h[s.id] = s.tags.pluck(:name) }\n\n    @stream_entry_batches  = []\n    @salmon_batches        = []\n    @json_payloads         = statuses.each_with_object({}) { |s, h| h[s.id] = Oj.dump(event: :delete, payload: s.id.to_s) }\n    @activity_xml          = {}\n\n    # Ensure that rendered XML reflects destroyed state\n    statuses.each do |status|\n      status.mark_for_mass_destruction!\n      status.destroy\n    end\n\n    return if options[:skip_side_effects]\n\n    # Batch by source account\n    statuses.group_by(&:account_id).each_value do |account_statuses|\n      account = account_statuses.first.account\n\n      next unless account\n\n      unpush_from_home_timelines(account, account_statuses)\n      unpush_from_list_timelines(account, account_statuses)\n\n      batch_stream_entries(account, account_statuses) if account.local?\n    end\n\n    # Cannot be batched\n    statuses.each do |status|\n      unpush_from_public_timelines(status)\n      batch_salmon_slaps(status) if status.local?\n    end\n\n    Pubsubhubbub::RawDistributionWorker.push_bulk(@stream_entry_batches) { |batch| batch }\n    NotificationWorker.push_bulk(@salmon_batches) { |batch| batch }\n  end\n\n  private\n\n  def batch_stream_entries(account, statuses)\n    statuses.each do |status|\n      @stream_entry_batches << [build_xml(status.stream_entry), account.id]\n    end\n  end\n\n  def unpush_from_home_timelines(account, statuses)\n    recipients = account.followers_for_local_distribution.to_a\n\n    recipients << account if account.local?\n\n    recipients.each do |follower|\n      statuses.each do |status|\n        FeedManager.instance.unpush_from_home(follower, status)\n      end\n    end\n  end\n\n  def unpush_from_list_timelines(account, statuses)\n    account.lists_for_local_distribution.select(:id, :account_id).each do |list|\n      statuses.each do |status|\n        FeedManager.instance.unpush_from_list(list, status)\n      end\n    end\n  end\n\n  def unpush_from_public_timelines(status)\n    return unless status.public_visibility?\n\n    payload = @json_payloads[status.id]\n\n    redis.pipelined do\n      redis.publish('timeline:public', payload)\n      redis.publish('timeline:public:local', payload) if status.local?\n\n      if status.media_attachments.any?\n        redis.publish('timeline:public:media', payload)\n        redis.publish('timeline:public:local:media', payload) if status.local?\n      end\n\n      @tags[status.id].each do |hashtag|\n        redis.publish(\"timeline:hashtag:#{hashtag}\", payload)\n        redis.publish(\"timeline:hashtag:#{hashtag}:local\", payload) if status.local?\n      end\n    end\n  end\n\n  def batch_salmon_slaps(status)\n    return if @mentions[status.id].empty?\n\n    recipients = @mentions[status.id].map(&:account).reject(&:local?).select(&:ostatus?).uniq(&:domain).map(&:id)\n\n    recipients.each do |recipient_id|\n      @salmon_batches << [build_xml(status.stream_entry), status.account_id, recipient_id]\n    end\n  end\n\n  def build_xml(stream_entry)\n    return @activity_xml[stream_entry.id] if @activity_xml.key?(stream_entry.id)\n\n    @activity_xml[stream_entry.id] = stream_entry_to_xml(stream_entry)\n  end\nend\n"
  },
  {
    "path": "app/services/block_domain_service.rb",
    "content": "# frozen_string_literal: true\n\nclass BlockDomainService < BaseService\n  attr_reader :domain_block\n\n  def call(domain_block)\n    @domain_block = domain_block\n    process_domain_block!\n  end\n\n  private\n\n  def process_domain_block!\n    clear_media! if domain_block.reject_media?\n\n    if domain_block.silence?\n      silence_accounts!\n    elsif domain_block.suspend?\n      suspend_accounts!\n    end\n  end\n\n  def invalidate_association_caches!\n    # Normally, associated models of a status are immutable (except for accounts)\n    # so they are aggressively cached. After updating the media attachments to no\n    # longer point to a local file, we need to clear the cache to make those\n    # changes appear in the API and UI\n    @affected_status_ids.each { |id| Rails.cache.delete_matched(\"statuses/#{id}-*\") }\n  end\n\n  def silence_accounts!\n    blocked_domain_accounts.without_silenced.in_batches.update_all(silenced_at: @domain_block.created_at)\n  end\n\n  def clear_media!\n    @affected_status_ids = []\n\n    clear_account_images!\n    clear_account_attachments!\n    clear_emojos!\n\n    invalidate_association_caches!\n  end\n\n  def suspend_accounts!\n    blocked_domain_accounts.without_suspended.reorder(nil).find_each do |account|\n      UnsubscribeService.new.call(account) if account.subscribed?\n      SuspendAccountService.new.call(account, suspended_at: @domain_block.created_at)\n    end\n  end\n\n  def clear_account_images!\n    blocked_domain_accounts.reorder(nil).find_each do |account|\n      account.avatar.destroy if account.avatar.exists?\n      account.header.destroy if account.header.exists?\n      account.save\n    end\n  end\n\n  def clear_account_attachments!\n    media_from_blocked_domain.reorder(nil).find_each do |attachment|\n      @affected_status_ids << attachment.status_id if attachment.status_id.present?\n\n      attachment.file.destroy if attachment.file.exists?\n      attachment.type = :unknown\n      attachment.save\n    end\n  end\n\n  def clear_emojos!\n    emojis_from_blocked_domains.destroy_all\n  end\n\n  def blocked_domain\n    domain_block.domain\n  end\n\n  def blocked_domain_accounts\n    Account.where(domain: blocked_domain)\n  end\n\n  def media_from_blocked_domain\n    MediaAttachment.joins(:account).merge(blocked_domain_accounts).reorder(nil)\n  end\n\n  def emojis_from_blocked_domains\n    CustomEmoji.where(domain: blocked_domain)\n  end\nend\n"
  },
  {
    "path": "app/services/block_service.rb",
    "content": "# frozen_string_literal: true\n\nclass BlockService < BaseService\n  include Payloadable\n\n  def call(account, target_account)\n    return if account.id == target_account.id\n\n    UnfollowService.new.call(account, target_account) if account.following?(target_account)\n    UnfollowService.new.call(target_account, account) if target_account.following?(account)\n    RejectFollowService.new.call(account, target_account) if target_account.requested?(account)\n\n    block = account.block!(target_account)\n\n    BlockWorker.perform_async(account.id, target_account.id)\n    create_notification(block) unless target_account.local?\n    block\n  end\n\n  private\n\n  def create_notification(block)\n    if block.target_account.ostatus?\n      NotificationWorker.perform_async(build_xml(block), block.account_id, block.target_account_id)\n    elsif block.target_account.activitypub?\n      ActivityPub::DeliveryWorker.perform_async(build_json(block), block.account_id, block.target_account.inbox_url)\n    end\n  end\n\n  def build_json(block)\n    Oj.dump(serialize_payload(block, ActivityPub::BlockSerializer))\n  end\n\n  def build_xml(block)\n    OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.block_salmon(block))\n  end\nend\n"
  },
  {
    "path": "app/services/bootstrap_timeline_service.rb",
    "content": "# frozen_string_literal: true\n\nclass BootstrapTimelineService < BaseService\n  def call(source_account)\n    @source_account = source_account\n\n    autofollow_inviter!\n    autofollow_bootstrap_timeline_accounts!\n  end\n\n  private\n\n  def autofollow_inviter!\n    return unless @source_account&.user&.invite&.autofollow?\n    FollowService.new.call(@source_account, @source_account.user.invite.user.account)\n  end\n\n  def autofollow_bootstrap_timeline_accounts!\n    bootstrap_timeline_accounts.each do |target_account|\n      FollowService.new.call(@source_account, target_account)\n    end\n  end\n\n  def bootstrap_timeline_accounts\n    return @bootstrap_timeline_accounts if defined?(@bootstrap_timeline_accounts)\n\n    @bootstrap_timeline_accounts = bootstrap_timeline_accounts_usernames.empty? ? admin_accounts : local_unlocked_accounts(bootstrap_timeline_accounts_usernames)\n  end\n\n  def bootstrap_timeline_accounts_usernames\n    @bootstrap_timeline_accounts_usernames ||= (Setting.bootstrap_timeline_accounts || '').split(',').map { |str| str.strip.gsub(/\\A@/, '') }.reject(&:blank?)\n  end\n\n  def admin_accounts\n    User.admins\n        .includes(:account)\n        .where(accounts: { locked: false })\n        .map(&:account)\n  end\n\n  def local_unlocked_accounts(usernames)\n    Account.local\n           .where(username: usernames)\n           .where(locked: false)\n  end\nend\n"
  },
  {
    "path": "app/services/concerns/author_extractor.rb",
    "content": "# frozen_string_literal: true\n\nmodule AuthorExtractor\n  def author_from_xml(xml, update_profile = true)\n    return nil if xml.nil?\n\n    # Try <email> for acct\n    acct = xml.at_xpath('./xmlns:author/xmlns:email', xmlns: OStatus::TagManager::XMLNS)&.content\n\n    # Try <name> + <uri>\n    if acct.blank?\n      username = xml.at_xpath('./xmlns:author/xmlns:name', xmlns: OStatus::TagManager::XMLNS)&.content\n      uri      = xml.at_xpath('./xmlns:author/xmlns:uri', xmlns: OStatus::TagManager::XMLNS)&.content\n\n      return nil if username.blank? || uri.blank?\n\n      domain = Addressable::URI.parse(uri).normalized_host\n      acct   = \"#{username}@#{domain}\"\n    end\n\n    ResolveAccountService.new.call(acct, update_profile: update_profile)\n  end\nend\n"
  },
  {
    "path": "app/services/concerns/payloadable.rb",
    "content": "# frozen_string_literal: true\n\nmodule Payloadable\n  def serialize_payload(record, serializer, options = {})\n    signer    = options.delete(:signer)\n    sign_with = options.delete(:sign_with)\n    payload   = ActiveModelSerializers::SerializableResource.new(record, options.merge(serializer: serializer, adapter: ActivityPub::Adapter)).as_json\n\n    if (record.respond_to?(:sign?) && record.sign?) && signer && signing_enabled?\n      ActivityPub::LinkedDataSignature.new(payload).sign!(signer, sign_with: sign_with)\n    else\n      payload\n    end\n  end\n\n  def signing_enabled?\n    true\n  end\nend\n"
  },
  {
    "path": "app/services/concerns/stream_entry_renderer.rb",
    "content": "# frozen_string_literal: true\n\nmodule StreamEntryRenderer\n  def stream_entry_to_xml(stream_entry)\n    OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.entry(stream_entry, true))\n  end\nend\n"
  },
  {
    "path": "app/services/fan_out_on_write_service.rb",
    "content": "# frozen_string_literal: true\n\nclass FanOutOnWriteService < BaseService\n  # Push a status into home and mentions feeds\n  # @param [Status] status\n  def call(status)\n    raise Mastodon::RaceConditionError if status.visibility.nil?\n\n    render_anonymous_payload(status)\n\n    if status.direct_visibility?\n      deliver_to_own_conversation(status)\n    elsif status.limited_visibility?\n      deliver_to_mentioned_followers(status)\n    else\n      deliver_to_self(status) if status.account.local?\n      deliver_to_followers(status)\n      deliver_to_lists(status)\n    end\n\n    return if status.account.silenced? || !status.public_visibility? || status.reblog?\n\n    deliver_to_hashtags(status)\n\n    return if status.reply? && status.in_reply_to_account_id != status.account_id\n\n    deliver_to_public(status)\n    deliver_to_media(status) if status.media_attachments.any?\n  end\n\n  private\n\n  def deliver_to_self(status)\n    Rails.logger.debug \"Delivering status #{status.id} to author\"\n    FeedManager.instance.push_to_home(status.account, status)\n  end\n\n  def deliver_to_followers(status)\n    Rails.logger.debug \"Delivering status #{status.id} to followers\"\n\n    status.account.followers_for_local_distribution.select(:id).reorder(nil).find_in_batches do |followers|\n      FeedInsertWorker.push_bulk(followers) do |follower|\n        [status.id, follower.id, :home]\n      end\n    end\n  end\n\n  def deliver_to_lists(status)\n    Rails.logger.debug \"Delivering status #{status.id} to lists\"\n\n    status.account.lists_for_local_distribution.select(:id).reorder(nil).find_in_batches do |lists|\n      FeedInsertWorker.push_bulk(lists) do |list|\n        [status.id, list.id, :list]\n      end\n    end\n  end\n\n  def deliver_to_mentioned_followers(status)\n    Rails.logger.debug \"Delivering status #{status.id} to limited followers\"\n\n    FeedInsertWorker.push_bulk(status.mentions.includes(:account).map(&:account).select { |mentioned_account| mentioned_account.local? && mentioned_account.following?(status.account) }) do |follower|\n      [status.id, follower.id, :home]\n    end\n  end\n\n  def render_anonymous_payload(status)\n    @payload = InlineRenderer.render(status, nil, :status)\n    @payload = Oj.dump(event: :update, payload: @payload)\n  end\n\n  def deliver_to_hashtags(status)\n    Rails.logger.debug \"Delivering status #{status.id} to hashtags\"\n\n    status.tags.pluck(:name).each do |hashtag|\n      Redis.current.publish(\"timeline:hashtag:#{hashtag}\", @payload)\n      Redis.current.publish(\"timeline:hashtag:#{hashtag}:local\", @payload) if status.local?\n    end\n  end\n\n  def deliver_to_public(status)\n    Rails.logger.debug \"Delivering status #{status.id} to public timeline\"\n\n    Redis.current.publish('timeline:public', @payload)\n    Redis.current.publish('timeline:public:local', @payload) if status.local?\n  end\n\n  def deliver_to_media(status)\n    Rails.logger.debug \"Delivering status #{status.id} to media timeline\"\n\n    Redis.current.publish('timeline:public:media', @payload)\n    Redis.current.publish('timeline:public:local:media', @payload) if status.local?\n  end\n\n  def deliver_to_own_conversation(status)\n    AccountConversation.add_status(status.account, status)\n\n    if status.mentions.count == 1 && status.mentions.includes(:account).first.account.user&.home_dms?\n      Rails.logger.debug \"Delivering status #{status.id} to home timeline\"\n      FeedManager.instance.push_to_home(status.mentions.first.account, status)\n    end\n  end\nend\n"
  },
  {
    "path": "app/services/favourite_service.rb",
    "content": "# frozen_string_literal: true\n\nclass FavouriteService < BaseService\n  include Authorization\n  include Payloadable\n\n  # Favourite a status and notify remote user\n  # @param [Account] account\n  # @param [Status] status\n  # @return [Favourite]\n  def call(account, status)\n    authorize_with account, status, :favourite?\n\n    favourite = Favourite.find_by(account: account, status: status)\n\n    return favourite unless favourite.nil?\n\n    favourite = Favourite.create!(account: account, status: status)\n\n    create_notification(favourite)\n    bump_potential_friendship(account, status)\n\n    favourite\n  end\n\n  private\n\n  def create_notification(favourite)\n    status = favourite.status\n\n    if status.account.local?\n      NotifyService.new.call(status.account, favourite)\n    elsif status.account.ostatus?\n      NotificationWorker.perform_async(build_xml(favourite), favourite.account_id, status.account_id)\n    elsif status.account.activitypub?\n      ActivityPub::DeliveryWorker.perform_async(build_json(favourite), favourite.account_id, status.account.inbox_url)\n    end\n  end\n\n  def bump_potential_friendship(account, status)\n    ActivityTracker.increment('activity:interactions')\n    return if account.following?(status.account_id)\n    PotentialFriendshipTracker.record(account.id, status.account_id, :favourite)\n  end\n\n  def build_json(favourite)\n    Oj.dump(serialize_payload(favourite, ActivityPub::LikeSerializer))\n  end\n\n  def build_xml(favourite)\n    OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.favourite_salmon(favourite))\n  end\nend\n"
  },
  {
    "path": "app/services/fetch_atom_service.rb",
    "content": "# frozen_string_literal: true\n\nclass FetchAtomService < BaseService\n  include JsonLdHelper\n\n  def call(url)\n    return if url.blank?\n\n    result = process(url)\n\n    # retry without ActivityPub\n    result ||= process(url) if @unsupported_activity\n\n    result\n  rescue OpenSSL::SSL::SSLError => e\n    Rails.logger.debug \"SSL error: #{e}\"\n    nil\n  rescue HTTP::ConnectionError => e\n    Rails.logger.debug \"HTTP ConnectionError: #{e}\"\n    nil\n  end\n\n  private\n\n  def process(url, terminal = false)\n    @url = url\n    perform_request { |response| process_response(response, terminal) }\n  end\n\n  def perform_request(&block)\n    accept = 'text/html'\n    accept = 'application/activity+json, application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\", application/atom+xml, ' + accept unless @unsupported_activity\n\n    Request.new(:get, @url).add_headers('Accept' => accept).perform(&block)\n  end\n\n  def process_response(response, terminal = false)\n    return nil if response.code != 200\n\n    if response.mime_type == 'application/atom+xml'\n      [@url, { prefetched_body: response.body_with_limit }, :ostatus]\n    elsif ['application/activity+json', 'application/ld+json'].include?(response.mime_type)\n      body = response.body_with_limit\n      json = body_to_json(body)\n      if supported_context?(json) && equals_or_includes_any?(json['type'], ActivityPub::FetchRemoteAccountService::SUPPORTED_TYPES) && json['inbox'].present?\n        [json['id'], { prefetched_body: body, id: true }, :activitypub]\n      elsif supported_context?(json) && expected_type?(json)\n        [json['id'], { prefetched_body: body, id: true }, :activitypub]\n      else\n        @unsupported_activity = true\n        nil\n      end\n    elsif !terminal\n      link_header = response['Link'] && parse_link_header(response)\n\n      if link_header&.find_link(%w(rel alternate))\n        process_link_headers(link_header)\n      elsif response.mime_type == 'text/html'\n        process_html(response)\n      end\n    end\n  end\n\n  def expected_type?(json)\n    equals_or_includes_any?(json['type'], ActivityPub::Activity::Create::SUPPORTED_TYPES + ActivityPub::Activity::Create::CONVERTED_TYPES)\n  end\n\n  def process_html(response)\n    page = Nokogiri::HTML(response.body_with_limit)\n\n    json_link = page.xpath('//link[@rel=\"alternate\"]').find { |link| ['application/activity+json', 'application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"'].include?(link['type']) }\n    atom_link = page.xpath('//link[@rel=\"alternate\"]').find { |link| link['type'] == 'application/atom+xml' }\n\n    result ||= process(json_link['href'], terminal: true) unless json_link.nil? || @unsupported_activity\n    result ||= process(atom_link['href'], terminal: true) unless atom_link.nil?\n\n    result\n  end\n\n  def process_link_headers(link_header)\n    json_link = link_header.find_link(%w(rel alternate), %w(type application/activity+json)) || link_header.find_link(%w(rel alternate), ['type', 'application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"'])\n    atom_link = link_header.find_link(%w(rel alternate), %w(type application/atom+xml))\n\n    result ||= process(json_link.href, terminal: true) unless json_link.nil? || @unsupported_activity\n    result ||= process(atom_link.href, terminal: true) unless atom_link.nil?\n\n    result\n  end\n\n  def parse_link_header(response)\n    LinkHeader.parse(response['Link'].is_a?(Array) ? response['Link'].first : response['Link'])\n  end\nend\n"
  },
  {
    "path": "app/services/fetch_link_card_service.rb",
    "content": "# frozen_string_literal: true\n\nclass FetchLinkCardService < BaseService\n  URL_PATTERN = %r{\n    (                                                                                                 #   $1 URL\n      (https?:\\/\\/)                                                                                   #   $2 Protocol (required)\n      (#{Twitter::Regex[:valid_domain]})                                                              #   $3 Domain(s)\n      (?::(#{Twitter::Regex[:valid_port_number]}))?                                                   #   $4 Port number (optional)\n      (/#{Twitter::Regex[:valid_url_path]}*)?                                                         #   $5 URL Path and anchor\n      (\\?#{Twitter::Regex[:valid_url_query_chars]}*#{Twitter::Regex[:valid_url_query_ending_chars]})? #   $6 Query String\n    )\n  }iox\n\n  def call(status)\n    @status = status\n    @url    = parse_urls\n\n    return if @url.nil? || @status.preview_cards.any?\n\n    @url = @url.to_s\n\n    RedisLock.acquire(lock_options) do |lock|\n      if lock.acquired?\n        @card = PreviewCard.find_by(url: @url)\n        process_url if @card.nil? || @card.updated_at <= 2.weeks.ago\n      else\n        raise Mastodon::RaceConditionError\n      end\n    end\n\n    attach_card if @card&.persisted?\n  rescue HTTP::Error, Addressable::URI::InvalidURIError, Mastodon::HostValidationError, Mastodon::LengthValidationError => e\n    Rails.logger.debug \"Error fetching link #{@url}: #{e}\"\n    nil\n  end\n\n  private\n\n  def process_url\n    @card ||= PreviewCard.new(url: @url)\n\n    failed = Request.new(:head, @url).perform do |res|\n      res.code != 405 && res.code != 501 && (res.code != 200 || res.mime_type != 'text/html')\n    end\n\n    return if failed\n\n    Request.new(:get, @url).perform do |res|\n      if res.code == 200 && res.mime_type == 'text/html'\n        @html = res.body_with_limit\n        @html_charset = res.charset\n      else\n        @html = nil\n        @html_charset = nil\n      end\n    end\n\n    return if @html.nil?\n\n    attempt_oembed || attempt_opengraph\n  end\n\n  def attach_card\n    @status.preview_cards << @card\n    Rails.cache.delete(@status)\n  end\n\n  def parse_urls\n    if @status.local?\n      urls = @status.text.scan(URL_PATTERN).map { |array| Addressable::URI.parse(array[0]).normalize }\n    else\n      html  = Nokogiri::HTML(@status.text)\n      links = html.css('a')\n      urls  = links.map { |a| Addressable::URI.parse(a['href']).normalize unless skip_link?(a) }.compact\n    end\n\n    urls.reject { |uri| bad_url?(uri) }.first\n  end\n\n  def bad_url?(uri)\n    # Avoid local instance URLs and invalid URLs\n    uri.host.blank? || TagManager.instance.local_url?(uri.to_s) || !%w(http https).include?(uri.scheme)\n  end\n\n  def mention_link?(a)\n    @status.mentions.any? do |mention|\n      a['href'] == TagManager.instance.url_for(mention.account)\n    end\n  end\n\n  def skip_link?(a)\n    # Avoid links for hashtags and mentions (microformats)\n    a['rel']&.include?('tag') || a['class']&.include?('u-url') || mention_link?(a)\n  end\n\n  def attempt_oembed\n    service = FetchOEmbedService.new\n    embed   = service.call(@url, html: @html)\n    url     = Addressable::URI.parse(service.endpoint_url)\n\n    return false if embed.nil?\n\n    @card.type          = embed[:type]\n    @card.title         = embed[:title]         || ''\n    @card.author_name   = embed[:author_name]   || ''\n    @card.author_url    = embed[:author_url].present? ? (url + embed[:author_url]).to_s : ''\n    @card.provider_name = embed[:provider_name] || ''\n    @card.provider_url  = embed[:provider_url].present? ? (url + embed[:provider_url]).to_s : ''\n    @card.width         = 0\n    @card.height        = 0\n\n    case @card.type\n    when 'link'\n      @card.image_remote_url = (url + embed[:thumbnail_url]).to_s if embed[:thumbnail_url].present?\n    when 'photo'\n      return false if embed[:url].blank?\n\n      @card.embed_url        = (url + embed[:url]).to_s\n      @card.image_remote_url = (url + embed[:url]).to_s\n      @card.width            = embed[:width].presence  || 0\n      @card.height           = embed[:height].presence || 0\n    when 'video'\n      @card.width            = embed[:width].presence  || 0\n      @card.height           = embed[:height].presence || 0\n      @card.html             = Formatter.instance.sanitize(embed[:html], Sanitize::Config::MASTODON_OEMBED)\n      @card.image_remote_url = (url + embed[:thumbnail_url]).to_s if embed[:thumbnail_url].present?\n    when 'rich'\n      # Most providers rely on <script> tags, which is a no-no\n      return false\n    end\n\n    @card.save_with_optional_image!\n  end\n\n  def attempt_opengraph\n    detector = CharlockHolmes::EncodingDetector.new\n    detector.strip_tags = true\n\n    guess      = detector.detect(@html, @html_charset)\n    encoding   = guess&.fetch(:confidence, 0).to_i > 60 ? guess&.fetch(:encoding, nil) : nil\n    page       = Nokogiri::HTML(@html, nil, encoding)\n    player_url = meta_property(page, 'twitter:player')\n\n    if player_url && !bad_url?(Addressable::URI.parse(player_url))\n      @card.type   = :video\n      @card.width  = meta_property(page, 'twitter:player:width') || 0\n      @card.height = meta_property(page, 'twitter:player:height') || 0\n      @card.html   = content_tag(:iframe, nil, src: player_url,\n                                               width: @card.width,\n                                               height: @card.height,\n                                               allowtransparency: 'true',\n                                               scrolling: 'no',\n                                               frameborder: '0')\n    else\n      @card.type = :link\n    end\n\n    @card.title            = meta_property(page, 'og:title').presence || page.at_xpath('//title')&.content || ''\n    @card.description      = meta_property(page, 'og:description').presence || meta_property(page, 'description') || ''\n    @card.image_remote_url = (Addressable::URI.parse(@url) + meta_property(page, 'og:image')).to_s if meta_property(page, 'og:image')\n\n    return if @card.title.blank? && @card.html.blank?\n\n    @card.save_with_optional_image!\n  end\n\n  def meta_property(page, property)\n    page.at_xpath(\"//meta[contains(concat(' ', normalize-space(@property), ' '), ' #{property} ')]\")&.attribute('content')&.value || page.at_xpath(\"//meta[@name=\\\"#{property}\\\"]\")&.attribute('content')&.value\n  end\n\n  def lock_options\n    { redis: Redis.current, key: \"fetch:#{@url}\" }\n  end\nend\n"
  },
  {
    "path": "app/services/fetch_oembed_service.rb",
    "content": "# frozen_string_literal: true\n\nclass FetchOEmbedService\n  attr_reader :url, :options, :format, :endpoint_url\n\n  def call(url, options = {})\n    @url     = url\n    @options = options\n\n    discover_endpoint!\n    fetch!\n  end\n\n  private\n\n  def discover_endpoint!\n    return if html.nil?\n\n    @format = @options[:format]\n    page    = Nokogiri::HTML(html)\n\n    if @format.nil? || @format == :json\n      @endpoint_url ||= page.at_xpath('//link[@type=\"application/json+oembed\"]')&.attribute('href')&.value\n      @format       ||= :json if @endpoint_url\n    end\n\n    if @format.nil? || @format == :xml\n      @endpoint_url ||= page.at_xpath('//link[@type=\"text/xml+oembed\"]')&.attribute('href')&.value\n      @format       ||= :xml if @endpoint_url\n    end\n\n    return if @endpoint_url.blank?\n\n    @endpoint_url = (Addressable::URI.parse(@url) + @endpoint_url).to_s\n  rescue Addressable::URI::InvalidURIError\n    @endpoint_url = nil\n  end\n\n  def fetch!\n    return if @endpoint_url.blank?\n\n    body = Request.new(:get, @endpoint_url).perform do |res|\n      res.code != 200 ? nil : res.body_with_limit\n    end\n\n    validate(parse_for_format(body)) if body.present?\n  rescue Oj::ParseError, Ox::ParseError\n    nil\n  end\n\n  def parse_for_format(body)\n    case @format\n    when :json\n      Oj.load(body, mode: :strict)&.with_indifferent_access\n    when :xml\n      Ox.load(body, mode: :hash_no_attrs)&.with_indifferent_access&.dig(:oembed)\n    end\n  end\n\n  def validate(oembed)\n    oembed if oembed[:version] == '1.0' && oembed[:type].present?\n  end\n\n  def html\n    return @html if defined?(@html)\n\n    @html = @options[:html] || Request.new(:get, @url).perform do |res|\n      res.code != 200 || res.mime_type != 'text/html' ? nil : res.body_with_limit\n    end\n  end\nend\n"
  },
  {
    "path": "app/services/fetch_remote_account_service.rb",
    "content": "# frozen_string_literal: true\n\nclass FetchRemoteAccountService < BaseService\n  include AuthorExtractor\n\n  def call(url, prefetched_body = nil, protocol = :ostatus)\n    if prefetched_body.nil?\n      resource_url, resource_options, protocol = FetchAtomService.new.call(url)\n    else\n      resource_url     = url\n      resource_options = { prefetched_body: prefetched_body }\n    end\n\n    case protocol\n    when :ostatus\n      process_atom(resource_url, **resource_options)\n    when :activitypub\n      ActivityPub::FetchRemoteAccountService.new.call(resource_url, **resource_options)\n    end\n  end\n\n  private\n\n  def process_atom(url, prefetched_body:)\n    xml = Nokogiri::XML(prefetched_body)\n    xml.encoding = 'utf-8'\n\n    account = author_from_xml(xml.at_xpath('/xmlns:feed', xmlns: OStatus::TagManager::XMLNS), false)\n\n    UpdateRemoteProfileService.new.call(xml, account) if account.present? && trusted_domain?(url, account)\n\n    account\n  rescue TypeError\n    Rails.logger.debug \"Unparseable URL given: #{url}\"\n    nil\n  rescue Nokogiri::XML::XPath::SyntaxError\n    Rails.logger.debug 'Invalid XML or missing namespace'\n    nil\n  end\n\n  def trusted_domain?(url, account)\n    domain = Addressable::URI.parse(url).normalized_host\n    domain.casecmp(account.domain).zero? || domain.casecmp(Addressable::URI.parse(account.remote_url.presence || account.uri).normalized_host).zero?\n  end\nend\n"
  },
  {
    "path": "app/services/fetch_remote_status_service.rb",
    "content": "# frozen_string_literal: true\n\nclass FetchRemoteStatusService < BaseService\n  include AuthorExtractor\n\n  def call(url, prefetched_body = nil, protocol = :ostatus)\n    if prefetched_body.nil?\n      resource_url, resource_options, protocol = FetchAtomService.new.call(url)\n    else\n      resource_url     = url\n      resource_options = { prefetched_body: prefetched_body }\n    end\n\n    case protocol\n    when :ostatus\n      process_atom(resource_url, **resource_options)\n    when :activitypub\n      ActivityPub::FetchRemoteStatusService.new.call(resource_url, **resource_options)\n    end\n  end\n\n  private\n\n  def process_atom(url, prefetched_body:)\n    Rails.logger.debug \"Processing Atom for remote status at #{url}\"\n\n    xml = Nokogiri::XML(prefetched_body)\n    xml.encoding = 'utf-8'\n\n    account = author_from_xml(xml.at_xpath('/xmlns:entry', xmlns: OStatus::TagManager::XMLNS))\n    domain  = Addressable::URI.parse(url).normalized_host\n\n    return nil unless !account.nil? && confirmed_domain?(domain, account)\n\n    statuses = ProcessFeedService.new.call(prefetched_body, account)\n    statuses.first\n  rescue Nokogiri::XML::XPath::SyntaxError\n    Rails.logger.debug 'Invalid XML or missing namespace'\n    nil\n  end\n\n  def confirmed_domain?(domain, account)\n    account.domain.nil? || domain.casecmp(account.domain).zero? || domain.casecmp(Addressable::URI.parse(account.remote_url.presence || account.uri).normalized_host).zero?\n  end\nend\n"
  },
  {
    "path": "app/services/follow_service.rb",
    "content": "# frozen_string_literal: true\n\nclass FollowService < BaseService\n  include Redisable\n  include Payloadable\n\n  # Follow a remote user, notify remote user about the follow\n  # @param [Account] source_account From which to follow\n  # @param [String, Account] uri User URI to follow in the form of username@domain (or account record)\n  # @param [true, false, nil] reblogs Whether or not to show reblogs, defaults to true\n  def call(source_account, target_account, reblogs: nil)\n    reblogs = true if reblogs.nil?\n    target_account = ResolveAccountService.new.call(target_account, skip_webfinger: true)\n\n    raise ActiveRecord::RecordNotFound if target_account.nil? || target_account.id == source_account.id || target_account.suspended?\n    raise Mastodon::NotPermittedError  if target_account.blocking?(source_account) || source_account.blocking?(target_account) || target_account.moved?\n\n    if source_account.following?(target_account)\n      # We're already following this account, but we'll call follow! again to\n      # make sure the reblogs status is set correctly.\n      source_account.follow!(target_account, reblogs: reblogs)\n      return\n    elsif source_account.requested?(target_account)\n      # This isn't managed by a method in AccountInteractions, so we modify it\n      # ourselves if necessary.\n      req = source_account.follow_requests.find_by(target_account: target_account)\n      req.update!(show_reblogs: reblogs)\n      return\n    end\n\n    ActivityTracker.increment('activity:interactions')\n\n    if target_account.locked? || target_account.activitypub?\n      request_follow(source_account, target_account, reblogs: reblogs)\n    else\n      direct_follow(source_account, target_account, reblogs: reblogs)\n    end\n  end\n\n  private\n\n  def request_follow(source_account, target_account, reblogs: true)\n    follow_request = FollowRequest.create!(account: source_account, target_account: target_account, show_reblogs: reblogs)\n\n    if target_account.local?\n      LocalNotificationWorker.perform_async(target_account.id, follow_request.id, follow_request.class.name)\n    elsif target_account.ostatus?\n      NotificationWorker.perform_async(build_follow_request_xml(follow_request), source_account.id, target_account.id)\n      AfterRemoteFollowRequestWorker.perform_async(follow_request.id)\n    elsif target_account.activitypub?\n      ActivityPub::DeliveryWorker.perform_async(build_json(follow_request), source_account.id, target_account.inbox_url)\n    end\n\n    follow_request\n  end\n\n  def direct_follow(source_account, target_account, reblogs: true)\n    follow = source_account.follow!(target_account, reblogs: reblogs)\n\n    if target_account.local?\n      LocalNotificationWorker.perform_async(target_account.id, follow.id, follow.class.name)\n    else\n      Pubsubhubbub::SubscribeWorker.perform_async(target_account.id) unless target_account.subscribed?\n      NotificationWorker.perform_async(build_follow_xml(follow), source_account.id, target_account.id)\n      AfterRemoteFollowWorker.perform_async(follow.id)\n    end\n\n    MergeWorker.perform_async(target_account.id, source_account.id)\n\n    follow\n  end\n\n  def build_follow_request_xml(follow_request)\n    OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.follow_request_salmon(follow_request))\n  end\n\n  def build_follow_xml(follow)\n    OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.follow_salmon(follow))\n  end\n\n  def build_json(follow_request)\n    Oj.dump(serialize_payload(follow_request, ActivityPub::FollowSerializer))\n  end\nend\n"
  },
  {
    "path": "app/services/hashtag_query_service.rb",
    "content": "# frozen_string_literal: true\n\nclass HashtagQueryService < BaseService\n  def call(tag, params, account = nil, local = false)\n    tags = tags_for(Array(tag.name) | Array(params[:any])).pluck(:id)\n    all  = tags_for(params[:all])\n    none = tags_for(params[:none])\n\n    Status.distinct\n          .as_tag_timeline(tags, account, local)\n          .tagged_with_all(all)\n          .tagged_with_none(none)\n  end\n\n  private\n\n  def tags_for(tags)\n    Tag.where(name: tags.map(&:downcase)) if tags.presence\n  end\nend\n"
  },
  {
    "path": "app/services/import_service.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'csv'\n\nclass ImportService < BaseService\n  ROWS_PROCESSING_LIMIT = 20_000\n\n  def call(import)\n    @import  = import\n    @account = @import.account\n\n    case @import.type\n    when 'following'\n      import_follows!\n    when 'blocking'\n      import_blocks!\n    when 'muting'\n      import_mutes!\n    when 'domain_blocking'\n      import_domain_blocks!\n    end\n  end\n\n  private\n\n  def import_follows!\n    parse_import_data!(['Account address'])\n    import_relationships!('follow', 'unfollow', @account.following, follow_limit, reblogs: 'Show boosts')\n  end\n\n  def import_blocks!\n    parse_import_data!(['Account address'])\n    import_relationships!('block', 'unblock', @account.blocking, ROWS_PROCESSING_LIMIT)\n  end\n\n  def import_mutes!\n    parse_import_data!(['Account address'])\n    import_relationships!('mute', 'unmute', @account.muting, ROWS_PROCESSING_LIMIT, notifications: 'Hide notifications')\n  end\n\n  def import_domain_blocks!\n    parse_import_data!(['#domain'])\n    items = @data.take(ROWS_PROCESSING_LIMIT).map { |row| row['#domain'].strip }\n\n    if @import.overwrite?\n      presence_hash = items.each_with_object({}) { |id, mapping| mapping[id] = true }\n\n      @account.domain_blocks.find_each do |domain_block|\n        if presence_hash[domain_block.domain]\n          items.delete(domain_block.domain)\n        else\n          @account.unblock_domain!(domain_block.domain)\n        end\n      end\n    end\n\n    items.each do |domain|\n      @account.block_domain!(domain)\n    end\n\n    AfterAccountDomainBlockWorker.push_bulk(items) do |domain|\n      [@account.id, domain]\n    end\n  end\n\n  def import_relationships!(action, undo_action, overwrite_scope, limit, extra_fields = {})\n    items = @data.take(limit).map { |row| [row['Account address']&.strip, Hash[extra_fields.map { |key, header| [key, row[header]&.strip] }]] }.reject { |(id, _)| id.blank? }\n\n    if @import.overwrite?\n      presence_hash = items.each_with_object({}) { |(id, extra), mapping| mapping[id] = [true, extra] }\n\n      overwrite_scope.find_each do |target_account|\n        if presence_hash[target_account.acct]\n          items.delete(target_account.acct)\n          extra = presence_hash[target_account.acct][1]\n          Import::RelationshipWorker.perform_async(@account.id, target_account.acct, action, extra)\n        else\n          Import::RelationshipWorker.perform_async(@account.id, target_account.acct, undo_action)\n        end\n      end\n    end\n\n    Import::RelationshipWorker.push_bulk(items) do |acct, extra|\n      [@account.id, acct, action, extra]\n    end\n  end\n\n  def parse_import_data!(default_headers)\n    data = CSV.parse(import_data, headers: true)\n    data = CSV.parse(import_data, headers: default_headers) unless data.headers&.first&.strip&.include?(' ')\n    @data = data.reject(&:blank?)\n  end\n\n  def import_data\n    Paperclip.io_adapters.for(@import.data).read\n  end\n\n  def follow_limit\n    FollowLimitValidator.limit_for_account(@account)\n  end\nend\n"
  },
  {
    "path": "app/services/mute_service.rb",
    "content": "# frozen_string_literal: true\n\nclass MuteService < BaseService\n  def call(account, target_account, notifications: nil)\n    return if account.id == target_account.id\n\n    mute = account.mute!(target_account, notifications: notifications)\n\n    if mute.hide_notifications?\n      BlockWorker.perform_async(account.id, target_account.id)\n    else\n      MuteWorker.perform_async(account.id, target_account.id)\n    end\n\n    mute\n  end\nend\n"
  },
  {
    "path": "app/services/notify_service.rb",
    "content": "# frozen_string_literal: true\n\nclass NotifyService < BaseService\n  def call(recipient, activity)\n    @recipient    = recipient\n    @activity     = activity\n    @notification = Notification.new(account: @recipient, activity: @activity)\n\n    return if recipient.user.nil? || blocked?\n\n    create_notification!\n    push_notification! if @notification.browserable?\n    push_to_conversation! if direct_message?\n    send_email! if email_enabled?\n  rescue ActiveRecord::RecordInvalid\n    return\n  end\n\n  private\n\n  def blocked_mention?\n    FeedManager.instance.filter?(:mentions, @notification.mention.status, @recipient.id)\n  end\n\n  def blocked_favourite?\n    false\n  end\n\n  def blocked_follow?\n    false\n  end\n\n  def blocked_reblog?\n    false\n  end\n\n  def blocked_follow_request?\n    false\n  end\n\n  def blocked_poll?\n    false\n  end\n\n  def following_sender?\n    return @following_sender if defined?(@following_sender)\n    @following_sender = @recipient.following?(@notification.from_account) || @recipient.requested?(@notification.from_account)\n  end\n\n  def optional_non_follower?\n    @recipient.user.settings.interactions['must_be_follower']  && !@notification.from_account.following?(@recipient)\n  end\n\n  def optional_non_following?\n    @recipient.user.settings.interactions['must_be_following'] && !following_sender?\n  end\n\n  def message?\n    @notification.type == :mention\n  end\n\n  def direct_message?\n    message? && @notification.target_status.direct_visibility?\n  end\n\n  def response_to_recipient?\n    @notification.target_status.in_reply_to_account_id == @recipient.id && @notification.target_status.thread&.direct_visibility?\n  end\n\n  def from_staff?\n    @notification.from_account.local? && @notification.from_account.user.present? && @notification.from_account.user.staff?\n  end\n\n  def optional_non_following_and_direct?\n    direct_message? &&\n      @recipient.user.settings.interactions['must_be_following_dm'] &&\n      !following_sender? &&\n      !response_to_recipient?\n  end\n\n  def hellbanned?\n    @notification.from_account.silenced? && !following_sender?\n  end\n\n  def from_self?\n    @recipient.id == @notification.from_account.id\n  end\n\n  def domain_blocking?\n    @recipient.domain_blocking?(@notification.from_account.domain) && !following_sender?\n  end\n\n  def blocked?\n    blocked   = @recipient.suspended?                            # Skip if the recipient account is suspended anyway\n    blocked ||= from_self? && @notification.type != :poll        # Skip for interactions with self\n\n    return blocked if message? && from_staff?\n\n    blocked ||= domain_blocking?                                 # Skip for domain blocked accounts\n    blocked ||= @recipient.blocking?(@notification.from_account) # Skip for blocked accounts\n    blocked ||= @recipient.muting_notifications?(@notification.from_account)\n    blocked ||= hellbanned?                                      # Hellban\n    blocked ||= optional_non_follower?                           # Options\n    blocked ||= optional_non_following?                          # Options\n    blocked ||= optional_non_following_and_direct?               # Options\n    blocked ||= conversation_muted?\n    blocked ||= send(\"blocked_#{@notification.type}?\")           # Type-dependent filters\n    blocked\n  end\n\n  def conversation_muted?\n    if @notification.target_status\n      @recipient.muting_conversation?(@notification.target_status.conversation)\n    else\n      false\n    end\n  end\n\n  def create_notification!\n    @notification.save!\n  end\n\n  def push_notification!\n    return if @notification.activity.nil?\n\n    Redis.current.publish(\"timeline:#{@recipient.id}\", Oj.dump(event: :notification, payload: InlineRenderer.render(@notification, @recipient, :notification)))\n    send_push_notifications!\n  end\n\n  def push_to_conversation!\n    return if @notification.activity.nil?\n    AccountConversation.add_status(@recipient, @notification.target_status)\n  end\n\n  def send_push_notifications!\n    subscriptions_ids = ::Web::PushSubscription.where(user_id: @recipient.user.id)\n                                               .select { |subscription| subscription.pushable?(@notification) }\n                                               .map(&:id)\n\n    ::Web::PushNotificationWorker.push_bulk(subscriptions_ids) do |subscription_id|\n      [subscription_id, @notification.id]\n    end\n  end\n\n  def send_email!\n    return if @notification.activity.nil?\n    NotificationMailer.public_send(@notification.type, @recipient, @notification).deliver_later(wait: 2.minutes)\n  end\n\n  def email_enabled?\n    @recipient.user.settings.notification_emails[@notification.type.to_s]\n  end\nend\n"
  },
  {
    "path": "app/services/post_status_service.rb",
    "content": "# frozen_string_literal: true\n\nclass PostStatusService < BaseService\n  include Redisable\n\n  MIN_SCHEDULE_OFFSET = 5.minutes.freeze\n\n  # Post a text status update, fetch and notify remote users mentioned\n  # @param [Account] account Account from which to post\n  # @param [Hash] options\n  # @option [String] :text Message\n  # @option [Status] :thread Optional status to reply to\n  # @option [Boolean] :sensitive\n  # @option [String] :visibility\n  # @option [String] :spoiler_text\n  # @option [String] :language\n  # @option [String] :scheduled_at\n  # @option [Hash] :poll Optional poll to attach\n  # @option [Enumerable] :media_ids Optional array of media IDs to attach\n  # @option [Doorkeeper::Application] :application\n  # @option [String] :idempotency Optional idempotency key\n  # @return [Status]\n  def call(account, options = {})\n    @account     = account\n    @options     = options\n    @text        = @options[:text] || ''\n    @in_reply_to = @options[:thread]\n\n    return idempotency_duplicate if idempotency_given? && idempotency_duplicate?\n\n    validate_media!\n    preprocess_attributes!\n\n    if scheduled?\n      schedule_status!\n    else\n      process_status!\n      postprocess_status!\n      bump_potential_friendship!\n    end\n\n    redis.setex(idempotency_key, 3_600, @status.id) if idempotency_given?\n\n    @status\n  end\n\n  private\n\n  def preprocess_attributes!\n    @text         = @options.delete(:spoiler_text) if @text.blank? && @options[:spoiler_text].present?\n    @visibility   = @options[:visibility] || @account.user&.setting_default_privacy\n    @visibility   = :unlisted if @visibility == :public && @account.silenced?\n    @scheduled_at = @options[:scheduled_at]&.to_datetime\n    @scheduled_at = nil if scheduled_in_the_past?\n  rescue ArgumentError\n    raise ActiveRecord::RecordInvalid\n  end\n\n  def process_status!\n    # The following transaction block is needed to wrap the UPDATEs to\n    # the media attachments when the status is created\n\n    ApplicationRecord.transaction do\n      @status = @account.statuses.create!(status_attributes)\n    end\n\n    process_hashtags_service.call(@status)\n    process_mentions_service.call(@status)\n  end\n\n  def schedule_status!\n    status_for_validation = @account.statuses.build(status_attributes)\n\n    if status_for_validation.valid?\n      status_for_validation.destroy\n\n      # The following transaction block is needed to wrap the UPDATEs to\n      # the media attachments when the scheduled status is created\n\n      ApplicationRecord.transaction do\n        @status = @account.scheduled_statuses.create!(scheduled_status_attributes)\n      end\n    else\n      raise ActiveRecord::RecordInvalid\n    end\n  end\n\n  def postprocess_status!\n    LinkCrawlWorker.perform_async(@status.id) unless @status.spoiler_text?\n    DistributionWorker.perform_async(@status.id)\n    Pubsubhubbub::DistributionWorker.perform_async(@status.stream_entry.id)\n    ActivityPub::DistributionWorker.perform_async(@status.id)\n    PollExpirationNotifyWorker.perform_at(@status.poll.expires_at, @status.poll.id) if @status.poll\n  end\n\n  def validate_media!\n    return if @options[:media_ids].blank? || !@options[:media_ids].is_a?(Enumerable)\n\n    raise Mastodon::ValidationError, I18n.t('media_attachments.validations.too_many') if @options[:media_ids].size > 4 || @options[:poll].present?\n\n    @media = @account.media_attachments.where(status_id: nil).where(id: @options[:media_ids].take(4).map(&:to_i))\n\n    raise Mastodon::ValidationError, I18n.t('media_attachments.validations.images_and_video') if @media.size > 1 && @media.find(&:video?)\n  end\n\n  def language_from_option(str)\n    ISO_639.find(str)&.alpha2\n  end\n\n  def process_mentions_service\n    ProcessMentionsService.new\n  end\n\n  def process_hashtags_service\n    ProcessHashtagsService.new\n  end\n\n  def scheduled?\n    @scheduled_at.present?\n  end\n\n  def idempotency_key\n    \"idempotency:status:#{@account.id}:#{@options[:idempotency]}\"\n  end\n\n  def idempotency_given?\n    @options[:idempotency].present?\n  end\n\n  def idempotency_duplicate\n    if scheduled?\n      @account.schedule_statuses.find(@idempotency_duplicate)\n    else\n      @account.statuses.find(@idempotency_duplicate)\n    end\n  end\n\n  def idempotency_duplicate?\n    @idempotency_duplicate = redis.get(idempotency_key)\n  end\n\n  def scheduled_in_the_past?\n    @scheduled_at.present? && @scheduled_at <= Time.now.utc + MIN_SCHEDULE_OFFSET\n  end\n\n  def bump_potential_friendship!\n    return if !@status.reply? || @account.id == @status.in_reply_to_account_id\n    ActivityTracker.increment('activity:interactions')\n    return if @account.following?(@status.in_reply_to_account_id)\n    PotentialFriendshipTracker.record(@account.id, @status.in_reply_to_account_id, :reply)\n  end\n\n  def status_attributes\n    {\n      text: @text,\n      media_attachments: @media || [],\n      thread: @in_reply_to,\n      poll_attributes: poll_attributes,\n      sensitive: (@options[:sensitive].nil? ? @account.user&.setting_default_sensitive : @options[:sensitive]) || @options[:spoiler_text].present?,\n      spoiler_text: @options[:spoiler_text] || '',\n      visibility: @visibility,\n      language: language_from_option(@options[:language]) || @account.user&.setting_default_language&.presence || LanguageDetector.instance.detect(@text, @account),\n      application: @options[:application],\n    }.compact\n  end\n\n  def scheduled_status_attributes\n    {\n      scheduled_at: @scheduled_at,\n      media_attachments: @media || [],\n      params: scheduled_options,\n    }\n  end\n\n  def poll_attributes\n    return if @options[:poll].blank?\n\n    @options[:poll].merge(account: @account)\n  end\n\n  def scheduled_options\n    @options.tap do |options_hash|\n      options_hash[:in_reply_to_id] = options_hash.delete(:thread)&.id\n      options_hash[:application_id] = options_hash.delete(:application)&.id\n      options_hash[:scheduled_at]   = nil\n      options_hash[:idempotency]    = nil\n    end\n  end\nend\n"
  },
  {
    "path": "app/services/precompute_feed_service.rb",
    "content": "# frozen_string_literal: true\n\nclass PrecomputeFeedService < BaseService\n  def call(account)\n    FeedManager.instance.populate_feed(account)\n  ensure\n    Redis.current.del(\"account:#{account.id}:regeneration\")\n  end\nend\n"
  },
  {
    "path": "app/services/process_feed_service.rb",
    "content": "# frozen_string_literal: true\n\nclass ProcessFeedService < BaseService\n  def call(body, account, **options)\n    @options = options\n\n    xml = Nokogiri::XML(body)\n    xml.encoding = 'utf-8'\n\n    update_author(body, account)\n    process_entries(xml, account)\n  end\n\n  private\n\n  def update_author(body, account)\n    RemoteProfileUpdateWorker.perform_async(account.id, body.force_encoding('UTF-8'), true)\n  end\n\n  def process_entries(xml, account)\n    xml.xpath('//xmlns:entry', xmlns: OStatus::TagManager::XMLNS).reverse_each.map { |entry| process_entry(entry, account) }.compact\n  end\n\n  def process_entry(xml, account)\n    activity = OStatus::Activity::General.new(xml, account, @options)\n    activity.specialize&.perform if activity.status?\n  rescue ActiveRecord::RecordInvalid => e\n    Rails.logger.debug \"Nothing was saved for #{activity.id} because: #{e}\"\n    nil\n  end\nend\n"
  },
  {
    "path": "app/services/process_hashtags_service.rb",
    "content": "# frozen_string_literal: true\n\nclass ProcessHashtagsService < BaseService\n  def call(status, tags = [])\n    tags    = Extractor.extract_hashtags(status.text) if status.local?\n    records = []\n\n    tags.map { |str| str.mb_chars.downcase }.uniq(&:to_s).each do |name|\n      tag = Tag.where(name: name).first_or_create(name: name)\n\n      status.tags << tag\n      records << tag\n\n      TrendingTags.record_use!(tag, status.account, status.created_at) if status.public_visibility?\n    end\n\n    return unless status.public_visibility? || status.unlisted_visibility?\n\n    status.account.featured_tags.where(tag_id: records.map(&:id)).each do |featured_tag|\n      featured_tag.increment(status.created_at)\n    end\n  end\nend\n"
  },
  {
    "path": "app/services/process_interaction_service.rb",
    "content": "# frozen_string_literal: true\n\nclass ProcessInteractionService < BaseService\n  include AuthorExtractor\n  include Authorization\n\n  # Record locally the remote interaction with our user\n  # @param [String] envelope Salmon envelope\n  # @param [Account] target_account Account the Salmon was addressed to\n  def call(envelope, target_account)\n    body = salmon.unpack(envelope)\n\n    xml = Nokogiri::XML(body)\n    xml.encoding = 'utf-8'\n\n    account = author_from_xml(xml.at_xpath('/xmlns:entry', xmlns: OStatus::TagManager::XMLNS))\n\n    return if account.nil? || account.suspended?\n\n    if salmon.verify(envelope, account.keypair)\n      RemoteProfileUpdateWorker.perform_async(account.id, body.force_encoding('UTF-8'), true)\n\n      case verb(xml)\n      when :follow\n        follow!(account, target_account) unless target_account.locked? || target_account.blocking?(account) || target_account.domain_blocking?(account.domain)\n      when :request_friend\n        follow_request!(account, target_account) unless !target_account.locked? || target_account.blocking?(account) || target_account.domain_blocking?(account.domain)\n      when :authorize\n        authorize_follow_request!(account, target_account)\n      when :reject\n        reject_follow_request!(account, target_account)\n      when :unfollow\n        unfollow!(account, target_account)\n      when :favorite\n        favourite!(xml, account)\n      when :unfavorite\n        unfavourite!(xml, account)\n      when :post\n        add_post!(body, account) if mentions_account?(xml, target_account)\n      when :share\n        add_post!(body, account) unless status(xml).nil?\n      when :delete\n        delete_post!(xml, account)\n      when :block\n        reflect_block!(account, target_account)\n      when :unblock\n        reflect_unblock!(account, target_account)\n      end\n    end\n  rescue HTTP::Error, OStatus2::BadSalmonError, Mastodon::NotPermittedError\n    nil\n  end\n\n  private\n\n  def mentions_account?(xml, account)\n    xml.xpath('/xmlns:entry/xmlns:link[@rel=\"mentioned\"]', xmlns: OStatus::TagManager::XMLNS).each { |mention_link| return true if [OStatus::TagManager.instance.uri_for(account), OStatus::TagManager.instance.url_for(account)].include?(mention_link.attribute('href').value) }\n    false\n  end\n\n  def verb(xml)\n    raw = xml.at_xpath('//activity:verb', activity: OStatus::TagManager::AS_XMLNS).content\n    OStatus::TagManager::VERBS.key(raw)\n  rescue\n    :post\n  end\n\n  def follow!(account, target_account)\n    follow = account.follow!(target_account)\n    FollowRequest.find_by(account: account, target_account: target_account)&.destroy\n    NotifyService.new.call(target_account, follow)\n  end\n\n  def follow_request!(account, target_account)\n    return if account.requested?(target_account)\n\n    follow_request = FollowRequest.create!(account: account, target_account: target_account)\n    NotifyService.new.call(target_account, follow_request)\n  end\n\n  def authorize_follow_request!(account, target_account)\n    follow_request = FollowRequest.find_by(account: target_account, target_account: account)\n    follow_request&.authorize!\n    Pubsubhubbub::SubscribeWorker.perform_async(account.id) unless account.subscribed?\n  end\n\n  def reject_follow_request!(account, target_account)\n    follow_request = FollowRequest.find_by(account: target_account, target_account: account)\n    follow_request&.reject!\n  end\n\n  def unfollow!(account, target_account)\n    account.unfollow!(target_account)\n    FollowRequest.find_by(account: account, target_account: target_account)&.destroy\n  end\n\n  def reflect_block!(account, target_account)\n    UnfollowService.new.call(target_account, account) if target_account.following?(account)\n    account.block!(target_account)\n  end\n\n  def reflect_unblock!(account, target_account)\n    UnblockService.new.call(account, target_account)\n  end\n\n  def delete_post!(xml, account)\n    status = Status.find(xml.at_xpath('//xmlns:id', xmlns: OStatus::TagManager::XMLNS).content)\n\n    return if status.nil?\n\n    authorize_with account, status, :destroy?\n\n    RemovalWorker.perform_async(status.id)\n  end\n\n  def favourite!(xml, from_account)\n    current_status = status(xml)\n\n    return if current_status.nil?\n\n    favourite = current_status.favourites.where(account: from_account).first_or_create!(account: from_account)\n    NotifyService.new.call(current_status.account, favourite)\n  end\n\n  def unfavourite!(xml, from_account)\n    current_status = status(xml)\n\n    return if current_status.nil?\n\n    favourite = current_status.favourites.where(account: from_account).first\n    favourite&.destroy\n  end\n\n  def add_post!(body, account)\n    ProcessingWorker.perform_async(account.id, body.force_encoding('UTF-8'))\n  end\n\n  def status(xml)\n    uri = activity_id(xml)\n    return nil unless OStatus::TagManager.instance.local_id?(uri)\n    Status.find(OStatus::TagManager.instance.unique_tag_to_local_id(uri, 'Status'))\n  end\n\n  def activity_id(xml)\n    xml.at_xpath('//activity:object', activity: OStatus::TagManager::AS_XMLNS).at_xpath('./xmlns:id', xmlns: OStatus::TagManager::XMLNS).content\n  end\n\n  def salmon\n    @salmon ||= OStatus2::Salmon.new\n  end\nend\n"
  },
  {
    "path": "app/services/process_mentions_service.rb",
    "content": "# frozen_string_literal: true\n\nclass ProcessMentionsService < BaseService\n  include StreamEntryRenderer\n  include Payloadable\n\n  # Scan status for mentions and fetch remote mentioned users, create\n  # local mention pointers, send Salmon notifications to mentioned\n  # remote users\n  # @param [Status] status\n  def call(status)\n    return unless status.local?\n\n    @status  = status\n    mentions = []\n\n    status.text = status.text.gsub(Account::MENTION_RE) do |match|\n      username, domain  = Regexp.last_match(1).split('@')\n      mentioned_account = Account.find_remote(username, domain)\n\n      if mention_undeliverable?(mentioned_account)\n        begin\n          mentioned_account = resolve_account_service.call(Regexp.last_match(1))\n        rescue Goldfinger::Error, HTTP::Error, OpenSSL::SSL::SSLError, Mastodon::UnexpectedResponseError\n          mentioned_account = nil\n        end\n      end\n\n      next match if mention_undeliverable?(mentioned_account) || mentioned_account&.suspended?\n\n      mentions << mentioned_account.mentions.where(status: status).first_or_create(status: status)\n\n      \"@#{mentioned_account.acct}\"\n    end\n\n    status.save!\n\n    mentions.each { |mention| create_notification(mention) }\n  end\n\n  private\n\n  def mention_undeliverable?(mentioned_account)\n    mentioned_account.nil? || (!mentioned_account.local? && mentioned_account.ostatus? && @status.stream_entry.hidden?)\n  end\n\n  def create_notification(mention)\n    mentioned_account = mention.account\n\n    if mentioned_account.local?\n      LocalNotificationWorker.perform_async(mentioned_account.id, mention.id, mention.class.name)\n    elsif mentioned_account.ostatus? && !@status.stream_entry.hidden?\n      NotificationWorker.perform_async(ostatus_xml, @status.account_id, mentioned_account.id)\n    elsif mentioned_account.activitypub?\n      ActivityPub::DeliveryWorker.perform_async(activitypub_json, mention.status.account_id, mentioned_account.inbox_url)\n    end\n  end\n\n  def ostatus_xml\n    @ostatus_xml ||= stream_entry_to_xml(@status.stream_entry)\n  end\n\n  def activitypub_json\n    return @activitypub_json if defined?(@activitypub_json)\n    @activitypub_json = Oj.dump(serialize_payload(@status, ActivityPub::ActivitySerializer, signer: @status.account))\n  end\n\n  def resolve_account_service\n    ResolveAccountService.new\n  end\nend\n"
  },
  {
    "path": "app/services/pubsubhubbub/subscribe_service.rb",
    "content": "# frozen_string_literal: true\n\nclass Pubsubhubbub::SubscribeService < BaseService\n  URL_PATTERN = /\\A#{URI.regexp(%w(http https))}\\z/\n\n  attr_reader :account, :callback, :secret,\n              :lease_seconds, :domain\n\n  def call(account, callback, secret, lease_seconds, verified_domain = nil)\n    @account       = account\n    @callback      = Addressable::URI.parse(callback).normalize.to_s\n    @secret        = secret\n    @lease_seconds = lease_seconds\n    @domain        = verified_domain\n\n    process_subscribe\n  end\n\n  private\n\n  def process_subscribe\n    if account.nil?\n      ['Invalid topic URL', 422]\n    elsif !valid_callback?\n      ['Invalid callback URL', 422]\n    elsif blocked_domain?\n      ['Callback URL not allowed', 403]\n    else\n      confirm_subscription\n      ['', 202]\n    end\n  end\n\n  def confirm_subscription\n    subscription = locate_subscription\n    Pubsubhubbub::ConfirmationWorker.perform_async(subscription.id, 'subscribe', secret, lease_seconds)\n  end\n\n  def valid_callback?\n    callback.present? && callback =~ URL_PATTERN\n  end\n\n  def blocked_domain?\n    DomainBlock.blocked? Addressable::URI.parse(callback).host\n  end\n\n  def locate_subscription\n    subscription = Subscription.find_or_initialize_by(account: account, callback_url: callback)\n    subscription.domain = domain\n    subscription.save!\n    subscription\n  end\nend\n"
  },
  {
    "path": "app/services/pubsubhubbub/unsubscribe_service.rb",
    "content": "# frozen_string_literal: true\n\nclass Pubsubhubbub::UnsubscribeService < BaseService\n  attr_reader :account, :callback\n\n  def call(account, callback)\n    @account  = account\n    @callback = Addressable::URI.parse(callback).normalize.to_s\n\n    process_unsubscribe\n  end\n\n  private\n\n  def process_unsubscribe\n    if account.nil?\n      ['Invalid topic URL', 422]\n    else\n      confirm_unsubscribe unless subscription.nil?\n      ['', 202]\n    end\n  end\n\n  def confirm_unsubscribe\n    Pubsubhubbub::ConfirmationWorker.perform_async(subscription.id, 'unsubscribe')\n  end\n\n  def subscription\n    @_subscription ||= Subscription.find_by(account: account, callback_url: callback)\n  end\nend\n"
  },
  {
    "path": "app/services/reblog_service.rb",
    "content": "# frozen_string_literal: true\n\nclass ReblogService < BaseService\n  include Authorization\n  include StreamEntryRenderer\n  include Payloadable\n\n  # Reblog a status and notify its remote author\n  # @param [Account] account Account to reblog from\n  # @param [Status] reblogged_status Status to be reblogged\n  # @param [Hash] options\n  # @return [Status]\n  def call(account, reblogged_status, options = {})\n    reblogged_status = reblogged_status.reblog if reblogged_status.reblog?\n\n    authorize_with account, reblogged_status, :reblog?\n\n    reblog = account.statuses.find_by(reblog: reblogged_status)\n\n    return reblog unless reblog.nil?\n\n    visibility = options[:visibility] || account.user&.setting_default_privacy\n    visibility = reblogged_status.visibility if reblogged_status.hidden?\n    reblog = account.statuses.create!(reblog: reblogged_status, text: '', visibility: visibility)\n\n    DistributionWorker.perform_async(reblog.id)\n    Pubsubhubbub::DistributionWorker.perform_async(reblog.stream_entry.id)\n    ActivityPub::DistributionWorker.perform_async(reblog.id)\n\n    create_notification(reblog)\n    bump_potential_friendship(account, reblog)\n\n    reblog\n  end\n\n  private\n\n  def create_notification(reblog)\n    reblogged_status = reblog.reblog\n\n    if reblogged_status.account.local?\n      LocalNotificationWorker.perform_async(reblogged_status.account_id, reblog.id, reblog.class.name)\n    elsif reblogged_status.account.ostatus?\n      NotificationWorker.perform_async(stream_entry_to_xml(reblog.stream_entry), reblog.account_id, reblogged_status.account_id)\n    elsif reblogged_status.account.activitypub? && !reblogged_status.account.following?(reblog.account)\n      ActivityPub::DeliveryWorker.perform_async(build_json(reblog), reblog.account_id, reblogged_status.account.inbox_url)\n    end\n  end\n\n  def bump_potential_friendship(account, reblog)\n    ActivityTracker.increment('activity:interactions')\n    return if account.following?(reblog.reblog.account_id)\n    PotentialFriendshipTracker.record(account.id, reblog.reblog.account_id, :reblog)\n  end\n\n  def build_json(reblog)\n    Oj.dump(serialize_payload(reblog, ActivityPub::ActivitySerializer, signer: reblog.account))\n  end\nend\n"
  },
  {
    "path": "app/services/reject_follow_service.rb",
    "content": "# frozen_string_literal: true\n\nclass RejectFollowService < BaseService\n  include Payloadable\n\n  def call(source_account, target_account)\n    follow_request = FollowRequest.find_by!(account: source_account, target_account: target_account)\n    follow_request.reject!\n    create_notification(follow_request) unless source_account.local?\n    follow_request\n  end\n\n  private\n\n  def create_notification(follow_request)\n    if follow_request.account.ostatus?\n      NotificationWorker.perform_async(build_xml(follow_request), follow_request.target_account_id, follow_request.account_id)\n    elsif follow_request.account.activitypub?\n      ActivityPub::DeliveryWorker.perform_async(build_json(follow_request), follow_request.target_account_id, follow_request.account.inbox_url)\n    end\n  end\n\n  def build_json(follow_request)\n    Oj.dump(serialize_payload(follow_request, ActivityPub::RejectFollowSerializer))\n  end\n\n  def build_xml(follow_request)\n    OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.reject_follow_request_salmon(follow_request))\n  end\nend\n"
  },
  {
    "path": "app/services/remove_status_service.rb",
    "content": "# frozen_string_literal: true\n\nclass RemoveStatusService < BaseService\n  include StreamEntryRenderer\n  include Redisable\n  include Payloadable\n\n  def call(status, **options)\n    @payload      = Oj.dump(event: :delete, payload: status.id.to_s)\n    @status       = status\n    @account      = status.account\n    @tags         = status.tags.pluck(:name).to_a\n    @mentions     = status.active_mentions.includes(:account).to_a\n    @reblogs      = status.reblogs.includes(:account).to_a\n    @stream_entry = status.stream_entry\n    @options      = options\n\n    RedisLock.acquire(lock_options) do |lock|\n      if lock.acquired?\n        remove_from_self if status.account.local?\n        remove_from_followers\n        remove_from_lists\n        remove_from_affected\n        remove_reblogs\n        remove_from_hashtags\n        remove_from_public\n        remove_from_media if status.media_attachments.any?\n\n        @status.destroy!\n      else\n        raise Mastodon::RaceConditionError\n      end\n    end\n\n    # There is no reason to send out Undo activities when the\n    # cause is that the original object has been removed, since\n    # original object being removed implicitly removes reblogs\n    # of it. The Delete activity of the original is forwarded\n    # separately.\n    return if !@account.local? || @options[:original_removed]\n\n    remove_from_remote_followers\n    remove_from_remote_affected\n  end\n\n  private\n\n  def remove_from_self\n    FeedManager.instance.unpush_from_home(@account, @status)\n  end\n\n  def remove_from_followers\n    @account.followers_for_local_distribution.reorder(nil).find_each do |follower|\n      FeedManager.instance.unpush_from_home(follower, @status)\n    end\n  end\n\n  def remove_from_lists\n    @account.lists_for_local_distribution.select(:id, :account_id).reorder(nil).find_each do |list|\n      FeedManager.instance.unpush_from_list(list, @status)\n    end\n  end\n\n  def remove_from_affected\n    @mentions.map(&:account).select(&:local?).each do |account|\n      redis.publish(\"timeline:#{account.id}\", @payload)\n    end\n  end\n\n  def remove_from_remote_affected\n    # People who got mentioned in the status, or who\n    # reblogged it from someone else might not follow\n    # the author and wouldn't normally receive the\n    # delete notification - so here, we explicitly\n    # send it to them\n\n    target_accounts = (@mentions.map(&:account).reject(&:local?) + @reblogs.map(&:account).reject(&:local?))\n    target_accounts << @status.reblog.account if @status.reblog? && !@status.reblog.account.local?\n    target_accounts.uniq!(&:id)\n\n    # Ostatus\n    NotificationWorker.push_bulk(target_accounts.select(&:ostatus?).uniq(&:domain)) do |target_account|\n      [salmon_xml, @account.id, target_account.id]\n    end\n\n    # ActivityPub\n    ActivityPub::DeliveryWorker.push_bulk(target_accounts.select(&:activitypub?).uniq(&:preferred_inbox_url)) do |target_account|\n      [signed_activity_json, @account.id, target_account.preferred_inbox_url]\n    end\n  end\n\n  def remove_from_remote_followers\n    # OStatus\n    Pubsubhubbub::RawDistributionWorker.perform_async(salmon_xml, @account.id)\n\n    # ActivityPub\n    ActivityPub::DeliveryWorker.push_bulk(@account.followers.inboxes) do |inbox_url|\n      [signed_activity_json, @account.id, inbox_url]\n    end\n\n    relay! if relayable?\n  end\n\n  def relayable?\n    @status.public_visibility?\n  end\n\n  def relay!\n    ActivityPub::DeliveryWorker.push_bulk(Relay.enabled.pluck(:inbox_url)) do |inbox_url|\n      [signed_activity_json, @account.id, inbox_url]\n    end\n  end\n\n  def salmon_xml\n    @salmon_xml ||= stream_entry_to_xml(@stream_entry)\n  end\n\n  def signed_activity_json\n    @signed_activity_json ||= Oj.dump(serialize_payload(@status, @status.reblog? ? ActivityPub::UndoAnnounceSerializer : ActivityPub::DeleteSerializer, signer: @account))\n  end\n\n  def remove_reblogs\n    # We delete reblogs of the status before the original status,\n    # because once original status is gone, reblogs will disappear\n    # without us being able to do all the fancy stuff\n\n    @reblogs.each do |reblog|\n      RemoveStatusService.new.call(reblog, original_removed: true)\n    end\n  end\n\n  def remove_from_hashtags\n    @account.featured_tags.where(tag_id: @status.tags.pluck(:id)).each do |featured_tag|\n      featured_tag.decrement(@status.id)\n    end\n\n    return unless @status.public_visibility?\n\n    @tags.each do |hashtag|\n      redis.publish(\"timeline:hashtag:#{hashtag}\", @payload)\n      redis.publish(\"timeline:hashtag:#{hashtag}:local\", @payload) if @status.local?\n    end\n  end\n\n  def remove_from_public\n    return unless @status.public_visibility?\n\n    redis.publish('timeline:public', @payload)\n    redis.publish('timeline:public:local', @payload) if @status.local?\n  end\n\n  def remove_from_media\n    return unless @status.public_visibility?\n\n    redis.publish('timeline:public:media', @payload)\n    redis.publish('timeline:public:local:media', @payload) if @status.local?\n  end\n\n  def lock_options\n    { redis: Redis.current, key: \"distribute:#{@status.id}\" }\n  end\nend\n"
  },
  {
    "path": "app/services/report_service.rb",
    "content": "# frozen_string_literal: true\n\nclass ReportService < BaseService\n  include Payloadable\n\n  def call(source_account, target_account, options = {})\n    @source_account = source_account\n    @target_account = target_account\n    @status_ids     = options.delete(:status_ids) || []\n    @comment        = options.delete(:comment) || ''\n    @options        = options\n\n    create_report!\n    notify_staff!\n    forward_to_origin! if !@target_account.local? && ActiveModel::Type::Boolean.new.cast(@options[:forward])\n\n    @report\n  end\n\n  private\n\n  def create_report!\n    @report = @source_account.reports.create!(\n      target_account: @target_account,\n      status_ids: @status_ids,\n      comment: @comment,\n      uri: @options[:uri]\n    )\n  end\n\n  def notify_staff!\n    return if @report.unresolved_siblings?\n\n    User.staff.includes(:account).each do |u|\n      next unless u.allows_report_emails?\n      AdminMailer.new_report(u.account, @report).deliver_later\n    end\n  end\n\n  def forward_to_origin!\n    ActivityPub::DeliveryWorker.perform_async(\n      payload,\n      some_local_account.id,\n      @target_account.inbox_url\n    )\n  end\n\n  def payload\n    Oj.dump(serialize_payload(@report, ActivityPub::FlagSerializer, account: some_local_account))\n  end\n\n  def some_local_account\n    @some_local_account ||= Account.representative\n  end\nend\n"
  },
  {
    "path": "app/services/resolve_account_service.rb",
    "content": "# frozen_string_literal: true\n\nclass ResolveAccountService < BaseService\n  include OStatus2::MagicKey\n  include JsonLdHelper\n\n  DFRN_NS = 'http://purl.org/macgirvin/dfrn/1.0'\n\n  # Find or create a local account for a remote user.\n  # When creating, look up the user's webfinger and fetch all\n  # important information from their feed\n  # @param [String, Account] uri User URI in the form of username@domain\n  # @param [Hash] options\n  # @return [Account]\n  def call(uri, options = {})\n    @options = options\n\n    if uri.is_a?(Account)\n      @account  = uri\n      @username = @account.username\n      @domain   = @account.domain\n      uri       = \"#{@username}@#{@domain}\"\n\n      return @account if @account.local? || !webfinger_update_due?\n    else\n      @username, @domain = uri.split('@')\n\n      return Account.find_local(@username) if TagManager.instance.local_domain?(@domain)\n\n      @account = Account.find_remote(@username, @domain)\n\n      return @account unless webfinger_update_due?\n    end\n\n    Rails.logger.debug \"Looking up webfinger for #{uri}\"\n\n    @webfinger = Goldfinger.finger(\"acct:#{uri}\")\n\n    confirmed_username, confirmed_domain = @webfinger.subject.gsub(/\\Aacct:/, '').split('@')\n\n    if confirmed_username.casecmp(@username).zero? && confirmed_domain.casecmp(@domain).zero?\n      @username = confirmed_username\n      @domain   = confirmed_domain\n    elsif options[:redirected].nil?\n      return call(\"#{confirmed_username}@#{confirmed_domain}\", options.merge(redirected: true))\n    else\n      Rails.logger.debug 'Requested and returned acct URIs do not match'\n      return\n    end\n\n    return if links_missing?\n    return Account.find_local(@username) if TagManager.instance.local_domain?(@domain)\n\n    RedisLock.acquire(lock_options) do |lock|\n      if lock.acquired?\n        @account = Account.find_remote(@username, @domain)\n\n        if activitypub_ready? || @account&.activitypub?\n          handle_activitypub\n        else\n          handle_ostatus\n        end\n      else\n        raise Mastodon::RaceConditionError\n      end\n    end\n\n    @account\n  rescue Goldfinger::Error => e\n    Rails.logger.debug \"Webfinger query for #{uri} unsuccessful: #{e}\"\n    nil\n  end\n\n  private\n\n  def links_missing?\n    !(activitypub_ready? || ostatus_ready?)\n  end\n\n  def ostatus_ready?\n    !(@webfinger.link('http://schemas.google.com/g/2010#updates-from').nil? ||\n      @webfinger.link('salmon').nil? ||\n      @webfinger.link('http://webfinger.net/rel/profile-page').nil? ||\n      @webfinger.link('magic-public-key').nil? ||\n      canonical_uri.nil? ||\n      hub_url.nil?)\n  end\n\n  def webfinger_update_due?\n    @account.nil? || ((!@options[:skip_webfinger] || @account.ostatus?) && @account.possibly_stale?)\n  end\n\n  def activitypub_ready?\n    !@webfinger.link('self').nil? &&\n      ['application/activity+json', 'application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"'].include?(@webfinger.link('self').type) &&\n      !actor_json.nil? &&\n      actor_json['inbox'].present?\n  end\n\n  def handle_ostatus\n    create_account if @account.nil?\n    update_account\n    update_account_profile if update_profile?\n  end\n\n  def update_profile?\n    @options[:update_profile]\n  end\n\n  def handle_activitypub\n    return if actor_json.nil?\n\n    @account = ActivityPub::ProcessAccountService.new.call(@username, @domain, actor_json)\n  rescue Oj::ParseError\n    nil\n  end\n\n  def create_account\n    Rails.logger.debug \"Creating new remote account for #{@username}@#{@domain}\"\n\n    @account = Account.new(username: @username, domain: @domain)\n    @account.suspended_at = domain_block.created_at if auto_suspend?\n    @account.silenced_at  = domain_block.created_at if auto_silence?\n    @account.private_key  = nil\n  end\n\n  def update_account\n    @account.last_webfingered_at = Time.now.utc\n    @account.protocol            = :ostatus\n    @account.remote_url          = atom_url\n    @account.salmon_url          = salmon_url\n    @account.url                 = url\n    @account.public_key          = public_key\n    @account.uri                 = canonical_uri\n    @account.hub_url             = hub_url\n    @account.save!\n  end\n\n  def auto_suspend?\n    domain_block&.suspend?\n  end\n\n  def auto_silence?\n    domain_block&.silence?\n  end\n\n  def domain_block\n    return @domain_block if defined?(@domain_block)\n    @domain_block = DomainBlock.find_by(domain: @domain)\n  end\n\n  def atom_url\n    @atom_url ||= @webfinger.link('http://schemas.google.com/g/2010#updates-from').href\n  end\n\n  def salmon_url\n    @salmon_url ||= @webfinger.link('salmon').href\n  end\n\n  def actor_url\n    @actor_url ||= @webfinger.link('self').href\n  end\n\n  def url\n    @url ||= @webfinger.link('http://webfinger.net/rel/profile-page').href\n  end\n\n  def public_key\n    @public_key ||= magic_key_to_pem(@webfinger.link('magic-public-key').href)\n  end\n\n  def canonical_uri\n    return @canonical_uri if defined?(@canonical_uri)\n\n    author_uri = atom.at_xpath('/xmlns:feed/xmlns:author/xmlns:uri')\n\n    if author_uri.nil?\n      owner      = atom.at_xpath('/xmlns:feed').at_xpath('./dfrn:owner', dfrn: DFRN_NS)\n      author_uri = owner.at_xpath('./xmlns:uri') unless owner.nil?\n    end\n\n    @canonical_uri = author_uri.nil? ? nil : author_uri.content\n  end\n\n  def hub_url\n    return @hub_url if defined?(@hub_url)\n\n    hubs     = atom.xpath('//xmlns:link[@rel=\"hub\"]')\n    @hub_url = hubs.empty? || hubs.first['href'].nil? ? nil : hubs.first['href']\n  end\n\n  def atom_body\n    return @atom_body if defined?(@atom_body)\n\n    @atom_body = Request.new(:get, atom_url).perform do |response|\n      raise Mastodon::UnexpectedResponseError, response unless response.code == 200\n      response.body_with_limit\n    end\n  end\n\n  def actor_json\n    return @actor_json if defined?(@actor_json)\n\n    json        = fetch_resource(actor_url, false)\n    @actor_json = supported_context?(json) && equals_or_includes_any?(json['type'], ActivityPub::FetchRemoteAccountService::SUPPORTED_TYPES) ? json : nil\n  end\n\n  def atom\n    return @atom if defined?(@atom)\n    @atom = Nokogiri::XML(atom_body)\n  end\n\n  def update_account_profile\n    RemoteProfileUpdateWorker.perform_async(@account.id, atom_body.force_encoding('UTF-8'), false)\n  end\n\n  def lock_options\n    { redis: Redis.current, key: \"resolve:#{@username}@#{@domain}\" }\n  end\nend\n"
  },
  {
    "path": "app/services/resolve_url_service.rb",
    "content": "# frozen_string_literal: true\n\nclass ResolveURLService < BaseService\n  include JsonLdHelper\n  include Authorization\n\n  attr_reader :url\n\n  def call(url, on_behalf_of: nil)\n    @url = url\n    @on_behalf_of = on_behalf_of\n\n    return process_local_url if local_url?\n\n    process_url unless fetched_atom_feed.nil?\n  end\n\n  private\n\n  def process_url\n    if equals_or_includes_any?(type, %w(Application Group Organization Person Service))\n      FetchRemoteAccountService.new.call(atom_url, body, protocol)\n    elsif equals_or_includes_any?(type, %w(Note Article Image Video Page Question))\n      FetchRemoteStatusService.new.call(atom_url, body, protocol)\n    end\n  end\n\n  def fetched_atom_feed\n    @_fetched_atom_feed ||= FetchAtomService.new.call(url)\n  end\n\n  def atom_url\n    fetched_atom_feed.first\n  end\n\n  def body\n    fetched_atom_feed.second[:prefetched_body]\n  end\n\n  def protocol\n    fetched_atom_feed.third\n  end\n\n  def type\n    return json_data['type'] if protocol == :activitypub\n\n    case xml_root\n    when 'feed'\n      'Person'\n    when 'entry'\n      'Note'\n    end\n  end\n\n  def json_data\n    @_json_data ||= body_to_json(body)\n  end\n\n  def xml_root\n    xml_data.root.name\n  end\n\n  def xml_data\n    @_xml_data ||= Nokogiri::XML(body, nil, 'utf-8')\n  end\n\n  def local_url?\n    TagManager.instance.local_url?(@url)\n  end\n\n  def process_local_url\n    recognized_params = Rails.application.routes.recognize_path(@url)\n\n    return unless recognized_params[:action] == 'show'\n\n    if recognized_params[:controller] == 'stream_entries'\n      status = StreamEntry.find_by(id: recognized_params[:id])&.status\n      check_local_status(status)\n    elsif recognized_params[:controller] == 'statuses'\n      status = Status.find_by(id: recognized_params[:id])\n      check_local_status(status)\n    elsif recognized_params[:controller] == 'accounts'\n      Account.find_local(recognized_params[:username])\n    end\n  end\n\n  def check_local_status(status)\n    return if status.nil?\n    authorize_with @on_behalf_of, status, :show?\n    status\n  rescue Mastodon::NotPermittedError\n    # Do not disclose the existence of status the user is not authorized to see\n    nil\n  end\nend\n"
  },
  {
    "path": "app/services/search_service.rb",
    "content": "# frozen_string_literal: true\n\nclass SearchService < BaseService\n  def call(query, account, limit, options = {})\n    @query   = query.strip\n    @account = account\n    @options = options\n    @limit   = limit.to_i\n    @offset  = options[:type].blank? ? 0 : options[:offset].to_i\n    @resolve = options[:resolve] || false\n\n    default_results.tap do |results|\n      if url_query?\n        results.merge!(url_resource_results) unless url_resource.nil?\n      elsif @query.present?\n        results[:accounts] = perform_accounts_search! if account_searchable?\n        results[:statuses] = perform_statuses_search! if full_text_searchable?\n        results[:hashtags] = perform_hashtags_search! if hashtag_searchable?\n      end\n    end\n  end\n\n  private\n\n  def perform_accounts_search!\n    AccountSearchService.new.call(\n      @query,\n      @account,\n      limit: @limit,\n      resolve: @resolve,\n      offset: @offset\n    )\n  end\n\n  def perform_statuses_search!\n    definition = StatusesIndex.filter(term: { searchable_by: @account.id })\n                              .query(multi_match: { type: 'most_fields', query: @query, operator: 'and', fields: %w(text text.stemmed) })\n\n    if @options[:account_id].present?\n      definition = definition.filter(term: { account_id: @options[:account_id] })\n    end\n\n    if @options[:min_id].present? || @options[:max_id].present?\n      range      = {}\n      range[:gt] = @options[:min_id].to_i if @options[:min_id].present?\n      range[:lt] = @options[:max_id].to_i if @options[:max_id].present?\n      definition = definition.filter(range: { id: range })\n    end\n\n    results             = definition.limit(@limit).offset(@offset).objects.compact\n    account_ids         = results.map(&:account_id)\n    account_domains     = results.map(&:account_domain)\n    preloaded_relations = relations_map_for_account(@account, account_ids, account_domains)\n\n    results.reject { |status| StatusFilter.new(status, @account, preloaded_relations).filtered? }\n  rescue Faraday::ConnectionFailed\n    []\n  end\n\n  def perform_hashtags_search!\n    Tag.search_for(\n      @query.gsub(/\\A#/, ''),\n      @limit,\n      @offset\n    )\n  end\n\n  def default_results\n    { accounts: [], hashtags: [], statuses: [] }\n  end\n\n  def url_query?\n    @options[:type].blank? && @query =~ /\\Ahttps?:\\/\\//\n  end\n\n  def url_resource_results\n    { url_resource_symbol => [url_resource] }\n  end\n\n  def url_resource\n    @_url_resource ||= ResolveURLService.new.call(@query, on_behalf_of: @account)\n  end\n\n  def url_resource_symbol\n    url_resource.class.name.downcase.pluralize.to_sym\n  end\n\n  def full_text_searchable?\n    return false unless Chewy.enabled?\n\n    statuses_search? && !@account.nil? && !((@query.start_with?('#') || @query.include?('@')) && !@query.include?(' '))\n  end\n\n  def account_searchable?\n    account_search? && !(@query.include?('@') && @query.include?(' '))\n  end\n\n  def hashtag_searchable?\n    hashtag_search? && !@query.include?('@')\n  end\n\n  def account_search?\n    @options[:type].blank? || @options[:type] == 'accounts'\n  end\n\n  def hashtag_search?\n    @options[:type].blank? || @options[:type] == 'hashtags'\n  end\n\n  def statuses_search?\n    @options[:type].blank? || @options[:type] == 'statuses'\n  end\n\n  def relations_map_for_account(account, account_ids, domains)\n    {\n      blocking: Account.blocking_map(account_ids, account.id),\n      blocked_by: Account.blocked_by_map(account_ids, account.id),\n      muting: Account.muting_map(account_ids, account.id),\n      following: Account.following_map(account_ids, account.id),\n      domain_blocking_by_domain: Account.domain_blocking_map_by_domain(domains, account.id),\n    }\n  end\nend\n"
  },
  {
    "path": "app/services/send_interaction_service.rb",
    "content": "# frozen_string_literal: true\n\nclass SendInteractionService < BaseService\n  # Send an Atom representation of an interaction to a remote Salmon endpoint\n  # @param [String] Entry XML\n  # @param [Account] source_account\n  # @param [Account] target_account\n  def call(xml, source_account, target_account)\n    @xml            = xml\n    @source_account = source_account\n    @target_account = target_account\n\n    return if !target_account.ostatus? || block_notification?\n\n    build_request.perform do |delivery|\n      raise Mastodon::UnexpectedResponseError, delivery unless delivery.code > 199 && delivery.code < 300\n    end\n  end\n\n  private\n\n  def build_request\n    request = Request.new(:post, @target_account.salmon_url, body: envelope)\n    request.add_headers('Content-Type' => 'application/magic-envelope+xml')\n    request\n  end\n\n  def envelope\n    salmon.pack(@xml, @source_account.keypair)\n  end\n\n  def block_notification?\n    DomainBlock.blocked?(@target_account.domain)\n  end\n\n  def salmon\n    @salmon ||= OStatus2::Salmon.new\n  end\nend\n"
  },
  {
    "path": "app/services/subscribe_service.rb",
    "content": "# frozen_string_literal: true\n\nclass SubscribeService < BaseService\n  def call(account)\n    return if account.hub_url.blank?\n\n    @account        = account\n    @account.secret = SecureRandom.hex\n\n    build_request.perform do |response|\n      if response_failed_permanently? response\n        # We're not allowed to subscribe. Fail and move on.\n        @account.secret = ''\n        @account.save!\n      elsif response_successful? response\n        # The subscription will be confirmed asynchronously.\n        @account.save!\n      else\n        # The response was either a 429 rate limit, or a 5xx error.\n        # We need to retry at a later time. Fail loudly!\n        raise Mastodon::UnexpectedResponseError, response\n      end\n    end\n  end\n\n  private\n\n  def build_request\n    request = Request.new(:post, @account.hub_url, form: subscription_params)\n    request.on_behalf_of(some_local_account) if some_local_account\n    request\n  end\n\n  def subscription_params\n    {\n      'hub.topic': @account.remote_url,\n      'hub.mode': 'subscribe',\n      'hub.callback': api_subscription_url(@account.id),\n      'hub.verify': 'async',\n      'hub.secret': @account.secret,\n      'hub.lease_seconds': 7.days.seconds,\n    }\n  end\n\n  def some_local_account\n    @some_local_account ||= Account.local.without_suspended.first\n  end\n\n  # Any response in the 3xx or 4xx range, except for 429 (rate limit)\n  def response_failed_permanently?(response)\n    (response.status.redirect? || response.status.client_error?) && !response.status.too_many_requests?\n  end\n\n  # Any response in the 2xx range\n  def response_successful?(response)\n    response.status.success?\n  end\nend\n"
  },
  {
    "path": "app/services/suspend_account_service.rb",
    "content": "# frozen_string_literal: true\n\nclass SuspendAccountService < BaseService\n  include Payloadable\n\n  ASSOCIATIONS_ON_SUSPEND = %w(\n    account_pins\n    active_relationships\n    block_relationships\n    blocked_by_relationships\n    conversation_mutes\n    conversations\n    custom_filters\n    domain_blocks\n    favourites\n    follow_requests\n    list_accounts\n    media_attachments\n    mute_relationships\n    muted_by_relationships\n    notifications\n    owned_lists\n    passive_relationships\n    report_notes\n    scheduled_statuses\n    status_pins\n    stream_entries\n    subscriptions\n  ).freeze\n\n  ASSOCIATIONS_ON_DESTROY = %w(\n    reports\n    targeted_moderation_notes\n    targeted_reports\n  ).freeze\n\n  # Suspend an account and remove as much of its data as possible\n  # @param [Account]\n  # @param [Hash] options\n  # @option [Boolean] :including_user Remove the user record as well\n  # @option [Boolean] :destroy Remove the account record instead of suspending\n  def call(account, **options)\n    @account = account\n    @options = options\n\n    reject_follows!\n    purge_user!\n    purge_profile!\n    purge_content!\n  end\n\n  private\n\n  def reject_follows!\n    return if @account.local? || !@account.activitypub?\n\n    ActivityPub::DeliveryWorker.push_bulk(Follow.where(account: @account)) do |follow|\n      [build_reject_json(follow), follow.target_account_id, follow.account.inbox_url]\n    end\n  end\n\n  def purge_user!\n    return if !@account.local? || @account.user.nil?\n\n    if @options[:including_user]\n      @account.user.destroy\n    else\n      @account.user.disable!\n    end\n  end\n\n  def purge_content!\n    distribute_delete_actor! if @account.local? && !@options[:skip_distribution]\n\n    @account.statuses.reorder(nil).find_in_batches do |statuses|\n      BatchedRemoveStatusService.new.call(statuses, skip_side_effects: @options[:destroy])\n    end\n\n    associations_for_destruction.each do |association_name|\n      destroy_all(@account.public_send(association_name))\n    end\n\n    @account.destroy if @options[:destroy]\n  end\n\n  def purge_profile!\n    # If the account is going to be destroyed\n    # there is no point wasting time updating\n    # its values first\n\n    return if @options[:destroy]\n\n    @account.silenced_at      = nil\n    @account.suspended_at     = @options[:suspended_at] || Time.now.utc\n    @account.locked           = false\n    @account.display_name     = ''\n    @account.note             = ''\n    @account.fields           = []\n    @account.statuses_count   = 0\n    @account.followers_count  = 0\n    @account.following_count  = 0\n    @account.moved_to_account = nil\n    @account.avatar.destroy\n    @account.header.destroy\n    @account.save!\n  end\n\n  def destroy_all(association)\n    association.in_batches.destroy_all\n  end\n\n  def distribute_delete_actor!\n    ActivityPub::DeliveryWorker.push_bulk(delivery_inboxes) do |inbox_url|\n      [delete_actor_json, @account.id, inbox_url]\n    end\n\n    ActivityPub::LowPriorityDeliveryWorker.push_bulk(low_priority_delivery_inboxes) do |inbox_url|\n      [delete_actor_json, @account.id, inbox_url]\n    end\n  end\n\n  def delete_actor_json\n    @delete_actor_json ||= Oj.dump(serialize_payload(@account, ActivityPub::DeleteActorSerializer, signer: @account))\n  end\n\n  def build_reject_json(follow)\n    Oj.dump(serialize_payload(follow, ActivityPub::RejectFollowSerializer))\n  end\n\n  def delivery_inboxes\n    @delivery_inboxes ||= @account.followers.inboxes + Relay.enabled.pluck(:inbox_url)\n  end\n\n  def low_priority_delivery_inboxes\n    Account.inboxes - delivery_inboxes\n  end\n\n  def associations_for_destruction\n    if @options[:destroy]\n      ASSOCIATIONS_ON_SUSPEND + ASSOCIATIONS_ON_DESTROY\n    else\n      ASSOCIATIONS_ON_SUSPEND\n    end\n  end\nend\n"
  },
  {
    "path": "app/services/unblock_domain_service.rb",
    "content": "# frozen_string_literal: true\n\nclass UnblockDomainService < BaseService\n  attr_accessor :domain_block\n\n  def call(domain_block)\n    @domain_block = domain_block\n    process_retroactive_updates\n    domain_block.destroy\n  end\n\n  def process_retroactive_updates\n    blocked_accounts.in_batches.update_all(update_options) unless domain_block.noop?\n  end\n\n  def blocked_accounts\n    scope = Account.where(domain: domain_block.domain)\n    if domain_block.silence?\n      scope.where(silenced_at: @domain_block.created_at)\n    else\n      scope.where(suspended_at: @domain_block.created_at)\n    end\n  end\n\n  def update_options\n    { domain_block_impact => nil }\n  end\n\n  def domain_block_impact\n    domain_block.silence? ? :silenced_at : :suspended_at\n  end\nend\n"
  },
  {
    "path": "app/services/unblock_service.rb",
    "content": "# frozen_string_literal: true\n\nclass UnblockService < BaseService\n  include Payloadable\n\n  def call(account, target_account)\n    return unless account.blocking?(target_account)\n\n    unblock = account.unblock!(target_account)\n    create_notification(unblock) unless target_account.local?\n    unblock\n  end\n\n  private\n\n  def create_notification(unblock)\n    if unblock.target_account.ostatus?\n      NotificationWorker.perform_async(build_xml(unblock), unblock.account_id, unblock.target_account_id)\n    elsif unblock.target_account.activitypub?\n      ActivityPub::DeliveryWorker.perform_async(build_json(unblock), unblock.account_id, unblock.target_account.inbox_url)\n    end\n  end\n\n  def build_json(unblock)\n    Oj.dump(serialize_payload(unblock, ActivityPub::UndoBlockSerializer))\n  end\n\n  def build_xml(block)\n    OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.unblock_salmon(block))\n  end\nend\n"
  },
  {
    "path": "app/services/unfavourite_service.rb",
    "content": "# frozen_string_literal: true\n\nclass UnfavouriteService < BaseService\n  include Payloadable\n\n  def call(account, status)\n    favourite = Favourite.find_by!(account: account, status: status)\n    favourite.destroy!\n    create_notification(favourite) unless status.local?\n    favourite\n  end\n\n  private\n\n  def create_notification(favourite)\n    status = favourite.status\n\n    if status.account.ostatus?\n      NotificationWorker.perform_async(build_xml(favourite), favourite.account_id, status.account_id)\n    elsif status.account.activitypub?\n      ActivityPub::DeliveryWorker.perform_async(build_json(favourite), favourite.account_id, status.account.inbox_url)\n    end\n  end\n\n  def build_json(favourite)\n    Oj.dump(serialize_payload(favourite, ActivityPub::UndoLikeSerializer))\n  end\n\n  def build_xml(favourite)\n    OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.unfavourite_salmon(favourite))\n  end\nend\n"
  },
  {
    "path": "app/services/unfollow_service.rb",
    "content": "# frozen_string_literal: true\n\nclass UnfollowService < BaseService\n  include Payloadable\n\n  # Unfollow and notify the remote user\n  # @param [Account] source_account Where to unfollow from\n  # @param [Account] target_account Which to unfollow\n  def call(source_account, target_account)\n    @source_account = source_account\n    @target_account = target_account\n\n    unfollow! || undo_follow_request!\n  end\n\n  private\n\n  def unfollow!\n    follow = Follow.find_by(account: @source_account, target_account: @target_account)\n\n    return unless follow\n\n    follow.destroy!\n    create_notification(follow) unless @target_account.local?\n    create_reject_notification(follow) if @target_account.local? && !@source_account.local?\n    UnmergeWorker.perform_async(@target_account.id, @source_account.id)\n    follow\n  end\n\n  def undo_follow_request!\n    follow_request = FollowRequest.find_by(account: @source_account, target_account: @target_account)\n\n    return unless follow_request\n\n    follow_request.destroy!\n    create_notification(follow_request) unless @target_account.local?\n    follow_request\n  end\n\n  def create_notification(follow)\n    if follow.target_account.ostatus?\n      NotificationWorker.perform_async(build_xml(follow), follow.account_id, follow.target_account_id)\n    elsif follow.target_account.activitypub?\n      ActivityPub::DeliveryWorker.perform_async(build_json(follow), follow.account_id, follow.target_account.inbox_url)\n    end\n  end\n\n  def create_reject_notification(follow)\n    # Rejecting an already-existing follow request\n    return unless follow.account.activitypub?\n    ActivityPub::DeliveryWorker.perform_async(build_reject_json(follow), follow.target_account_id, follow.account.inbox_url)\n  end\n\n  def build_json(follow)\n    Oj.dump(serialize_payload(follow, ActivityPub::UndoFollowSerializer))\n  end\n\n  def build_reject_json(follow)\n    Oj.dump(serialize_payload(follow, ActivityPub::RejectFollowSerializer))\n  end\n\n  def build_xml(follow)\n    OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.unfollow_salmon(follow))\n  end\nend\n"
  },
  {
    "path": "app/services/unmute_service.rb",
    "content": "# frozen_string_literal: true\n\nclass UnmuteService < BaseService\n  def call(account, target_account)\n    return unless account.muting?(target_account)\n\n    account.unmute!(target_account)\n\n    MergeWorker.perform_async(target_account.id, account.id) if account.following?(target_account)\n  end\nend\n"
  },
  {
    "path": "app/services/unsubscribe_service.rb",
    "content": "# frozen_string_literal: true\n\nclass UnsubscribeService < BaseService\n  def call(account)\n    return if account.hub_url.blank?\n\n    @account = account\n\n    begin\n      build_request.perform do |response|\n        Rails.logger.debug \"PuSH unsubscribe for #{@account.acct} failed: #{response.status}\" unless response.status.success?\n      end\n    rescue HTTP::Error, OpenSSL::SSL::SSLError => e\n      Rails.logger.debug \"PuSH unsubscribe for #{@account.acct} failed: #{e}\"\n    end\n\n    @account.secret = ''\n    @account.subscription_expires_at = nil\n    @account.save!\n  end\n\n  private\n\n  def build_request\n    Request.new(:post, @account.hub_url, form: subscription_params)\n  end\n\n  def subscription_params\n    {\n      'hub.topic': @account.remote_url,\n      'hub.mode': 'unsubscribe',\n      'hub.callback': api_subscription_url(@account.id),\n      'hub.verify': 'async',\n    }\n  end\nend\n"
  },
  {
    "path": "app/services/update_account_service.rb",
    "content": "# frozen_string_literal: true\n\nclass UpdateAccountService < BaseService\n  def call(account, params, raise_error: false)\n    was_locked    = account.locked\n    update_method = raise_error ? :update! : :update\n\n    account.send(update_method, params).tap do |ret|\n      next unless ret\n\n      authorize_all_follow_requests(account) if was_locked && !account.locked\n      check_links(account)\n      process_hashtags(account)\n    end\n  rescue Mastodon::DimensionsValidationError => de\n    account.errors.add(:avatar, de.message)\n    false\n  end\n\n  private\n\n  def authorize_all_follow_requests(account)\n    AuthorizeFollowWorker.push_bulk(FollowRequest.where(target_account: account).select(:account_id, :target_account_id)) do |req|\n      [req.account_id, req.target_account_id]\n    end\n  end\n\n  def check_links(account)\n    VerifyAccountLinksWorker.perform_async(account.id)\n  end\n\n  def process_hashtags(account)\n    account.tags_as_strings = Extractor.extract_hashtags(account.note)\n  end\nend\n"
  },
  {
    "path": "app/services/update_remote_profile_service.rb",
    "content": "# frozen_string_literal: true\n\nclass UpdateRemoteProfileService < BaseService\n  attr_reader :account, :remote_profile\n\n  def call(body, account, resubscribe = false)\n    @account        = account\n    @remote_profile = RemoteProfile.new(body)\n\n    return if remote_profile.root.nil?\n\n    update_account unless remote_profile.author.nil?\n\n    old_hub_url     = account.hub_url\n    account.hub_url = remote_profile.hub_link if remote_profile.hub_link.present? && remote_profile.hub_link != old_hub_url\n\n    account.save_with_optional_media!\n\n    Pubsubhubbub::SubscribeWorker.perform_async(account.id) if resubscribe && account.hub_url != old_hub_url\n  end\n\n  private\n\n  def update_account\n    account.display_name = remote_profile.display_name || ''\n    account.note         = remote_profile.note         || ''\n    account.locked       = remote_profile.locked?\n\n    if !account.suspended? && !DomainBlock.find_by(domain: account.domain)&.reject_media?\n      if remote_profile.avatar.present?\n        account.avatar_remote_url = remote_profile.avatar\n      else\n        account.avatar_remote_url = ''\n        account.avatar.destroy\n      end\n\n      if remote_profile.header.present?\n        account.header_remote_url = remote_profile.header\n      else\n        account.header_remote_url = ''\n        account.header.destroy\n      end\n\n      save_emojis if remote_profile.emojis.present?\n    end\n  end\n\n  def save_emojis\n    do_not_download = DomainBlock.find_by(domain: account.domain)&.reject_media?\n\n    return if do_not_download\n\n    remote_profile.emojis.each do |link|\n      next unless link['href'] && link['name']\n\n      shortcode = link['name'].delete(':')\n      emoji     = CustomEmoji.find_by(shortcode: shortcode, domain: account.domain)\n\n      next unless emoji.nil?\n\n      emoji = CustomEmoji.new(shortcode: shortcode, domain: account.domain)\n      emoji.image_remote_url = link['href']\n      emoji.save\n    end\n  end\nend\n"
  },
  {
    "path": "app/services/verify_link_service.rb",
    "content": "# frozen_string_literal: true\n\nclass VerifyLinkService < BaseService\n  def call(field)\n    @link_back = ActivityPub::TagManager.instance.url_for(field.account)\n    @url       = field.value_for_verification\n\n    perform_request!\n\n    return unless link_back_present?\n\n    field.mark_verified!\n  rescue OpenSSL::SSL::SSLError, HTTP::Error, Addressable::URI::InvalidURIError, Mastodon::HostValidationError, Mastodon::LengthValidationError => e\n    Rails.logger.debug \"Error fetching link #{@url}: #{e}\"\n    nil\n  end\n\n  private\n\n  def perform_request!\n    @body = Request.new(:get, @url).add_headers('Accept' => 'text/html').perform do |res|\n      res.code != 200 ? nil : res.body_with_limit\n    end\n  end\n\n  def link_back_present?\n    return false if @body.blank?\n\n    links = Nokogiri::HTML(@body).xpath('//a[contains(concat(\" \", normalize-space(@rel), \" \"), \" me \")]|//link[contains(concat(\" \", normalize-space(@rel), \" \"), \" me \")]')\n\n    if links.any? { |link| link['href'] == @link_back }\n      true\n    elsif links.empty?\n      false\n    else\n      link_redirects_back?(links.first['href'])\n    end\n  end\n\n  def link_redirects_back?(test_url)\n    redirect_to_url = Request.new(:head, test_url, follow: false).perform do |res|\n      res.headers['Location']\n    end\n\n    redirect_to_url == @link_back\n  end\nend\n"
  },
  {
    "path": "app/services/verify_salmon_service.rb",
    "content": "# frozen_string_literal: true\n\nclass VerifySalmonService < BaseService\n  include AuthorExtractor\n\n  def call(payload)\n    body = salmon.unpack(payload)\n\n    xml = Nokogiri::XML(body)\n    xml.encoding = 'utf-8'\n\n    account = author_from_xml(xml.at_xpath('/xmlns:entry', xmlns: OStatus::TagManager::XMLNS))\n\n    if account.nil?\n      false\n    else\n      salmon.verify(payload, account.keypair)\n    end\n  end\n\n  private\n\n  def salmon\n    @salmon ||= OStatus2::Salmon.new\n  end\nend\n"
  },
  {
    "path": "app/services/vote_service.rb",
    "content": "# frozen_string_literal: true\n\nclass VoteService < BaseService\n  include Authorization\n  include Payloadable\n\n  def call(account, poll, choices)\n    authorize_with account, poll, :vote?\n\n    @account = account\n    @poll    = poll\n    @choices = choices\n    @votes   = []\n\n    ApplicationRecord.transaction do\n      @choices.each do |choice|\n        @votes << @poll.votes.create!(account: @account, choice: choice)\n      end\n    end\n\n    ActivityTracker.increment('activity:interactions')\n\n    if @poll.account.local?\n      distribute_poll!\n    else\n      deliver_votes!\n      queue_final_poll_check!\n    end\n  end\n\n  private\n\n  def distribute_poll!\n    return if @poll.hide_totals?\n    ActivityPub::DistributePollUpdateWorker.perform_in(3.minutes, @poll.status.id)\n  end\n\n  def queue_final_poll_check!\n    return unless @poll.expires?\n    PollExpirationNotifyWorker.perform_at(@poll.expires_at + 5.minutes, @poll.id)\n  end\n\n  def deliver_votes!\n    @votes.each do |vote|\n      ActivityPub::DeliveryWorker.perform_async(\n        build_json(vote),\n        @account.id,\n        @poll.account.inbox_url\n      )\n    end\n  end\n\n  def build_json(vote)\n    Oj.dump(serialize_payload(vote, ActivityPub::VoteSerializer))\n  end\nend\n"
  },
  {
    "path": "app/validators/blacklisted_email_validator.rb",
    "content": "# frozen_string_literal: true\n\nclass BlacklistedEmailValidator < ActiveModel::Validator\n  def validate(user)\n    return if user.valid_invitation?\n\n    @email = user.email\n\n    user.errors.add(:email, I18n.t('users.invalid_email')) if blocked_email?\n  end\n\n  private\n\n  def blocked_email?\n    on_blacklist? || not_on_whitelist?\n  end\n\n  def on_blacklist?\n    return true  if EmailDomainBlock.block?(@email)\n    return false if Rails.configuration.x.email_domains_blacklist.blank?\n\n    domains = Rails.configuration.x.email_domains_blacklist.gsub('.', '\\.')\n    regexp  = Regexp.new(\"@(.+\\\\.)?(#{domains})\", true)\n\n    @email =~ regexp\n  end\n\n  def not_on_whitelist?\n    return false if Rails.configuration.x.email_domains_whitelist.blank?\n\n    domains = Rails.configuration.x.email_domains_whitelist.gsub('.', '\\.')\n    regexp  = Regexp.new(\"@(.+\\\\.)?(#{domains})$\", true)\n\n    @email !~ regexp\n  end\nend\n"
  },
  {
    "path": "app/validators/disallowed_hashtags_validator.rb",
    "content": "# frozen_string_literal: true\n\nclass DisallowedHashtagsValidator < ActiveModel::Validator\n  def validate(status)\n    return unless status.local? && !status.reblog?\n\n    @status = status\n    tags    = select_tags\n\n    status.errors.add(:text, I18n.t('statuses.disallowed_hashtags', tags: tags.join(', '), count: tags.size)) unless tags.empty?\n  end\n\n  private\n\n  def select_tags\n    tags = Extractor.extract_hashtags(@status.text)\n    tags.keep_if { |tag| disallowed_hashtags.include? tag.downcase }\n  end\n\n  def disallowed_hashtags\n    return @disallowed_hashtags if @disallowed_hashtags\n\n    @disallowed_hashtags = Setting.disallowed_hashtags.nil? ? [] : Setting.disallowed_hashtags\n    @disallowed_hashtags = @disallowed_hashtags.split(' ') if @disallowed_hashtags.is_a? String\n    @disallowed_hashtags = @disallowed_hashtags.map(&:downcase)\n  end\nend\n"
  },
  {
    "path": "app/validators/email_mx_validator.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'resolv'\n\nclass EmailMxValidator < ActiveModel::Validator\n  def validate(user)\n    user.errors.add(:email, I18n.t('users.invalid_email')) if invalid_mx?(user.email)\n  end\n\n  private\n\n  def invalid_mx?(value)\n    _, domain = value.split('@', 2)\n\n    return true if domain.nil?\n\n    hostnames = []\n    ips       = []\n\n    Resolv::DNS.open do |dns|\n      dns.timeouts = 1\n\n      hostnames = dns.getresources(domain, Resolv::DNS::Resource::IN::MX).to_a.map { |e| e.exchange.to_s }\n\n      ([domain] + hostnames).uniq.each do |hostname|\n        ips.concat(dns.getresources(hostname, Resolv::DNS::Resource::IN::A).to_a.map { |e| e.address.to_s })\n        ips.concat(dns.getresources(hostname, Resolv::DNS::Resource::IN::AAAA).to_a.map { |e| e.address.to_s })\n      end\n    end\n\n    ips.empty? || on_blacklist?(hostnames + ips)\n  end\n\n  def on_blacklist?(values)\n    EmailDomainBlock.where(domain: values.uniq).any?\n  end\nend\n"
  },
  {
    "path": "app/validators/existing_username_validator.rb",
    "content": "# frozen_string_literal: true\n\nclass ExistingUsernameValidator < ActiveModel::EachValidator\n  def validate_each(record, attribute, value)\n    return if value.blank?\n\n    if options[:multiple]\n      missing_usernames = value.split(',').map { |username| username.strip.gsub(/\\A@/, '') }.map { |username| username unless Account.find_local(username) }.compact\n      record.errors.add(attribute, I18n.t('existing_username_validator.not_found_multiple', usernames: missing_usernames.join(', '))) if missing_usernames.any?\n    else\n      record.errors.add(attribute, I18n.t('existing_username_validator.not_found')) unless Account.find_local(value.strip.gsub(/\\A@/, ''))\n    end\n  end\nend\n"
  },
  {
    "path": "app/validators/follow_limit_validator.rb",
    "content": "# frozen_string_literal: true\n\nclass FollowLimitValidator < ActiveModel::Validator\n  LIMIT = ENV.fetch('MAX_FOLLOWS_THRESHOLD', 7_500).to_i\n  RATIO = ENV.fetch('MAX_FOLLOWS_RATIO', 1.1).to_f\n\n  def validate(follow)\n    return if follow.account.nil? || !follow.account.local?\n    follow.errors.add(:base, I18n.t('users.follow_limit_reached', limit: self.class.limit_for_account(follow.account))) if limit_reached?(follow.account)\n  end\n\n  class << self\n    def limit_for_account(account)\n      if account.following_count < LIMIT\n        LIMIT\n      else\n        [(account.followers_count * RATIO).round, LIMIT].max\n      end\n    end\n  end\n\n  private\n\n  def limit_reached?(account)\n    account.following_count >= self.class.limit_for_account(account)\n  end\nend\n"
  },
  {
    "path": "app/validators/html_validator.rb",
    "content": "# frozen_string_literal: true\n\nclass HtmlValidator < ActiveModel::EachValidator\n  ERROR_RE = /Opening and ending tag mismatch|Unexpected end tag/\n\n  def validate_each(record, attribute, value)\n    return if value.blank?\n\n    errors = html_errors(value)\n\n    record.errors.add(attribute, I18n.t('html_validator.invalid_markup', error: errors.first.to_s)) unless errors.empty?\n  end\n\n  private\n\n  def html_errors(str)\n    fragment = Nokogiri::HTML.fragment(options[:wrap_with] ? \"<#{options[:wrap_with]}>#{str}</#{options[:wrap_with]}>\" : str)\n    fragment.errors.select { |error| ERROR_RE =~ error.message }\n  end\nend\n"
  },
  {
    "path": "app/validators/note_length_validator.rb",
    "content": "# frozen_string_literal: true\n\nclass NoteLengthValidator < ActiveModel::EachValidator\n  def validate_each(record, attribute, value)\n    record.errors.add(attribute, I18n.t('statuses.over_character_limit', max: options[:maximum])) if too_long?(value)\n  end\n\n  private\n\n  def too_long?(value)\n    countable_text(value).mb_chars.grapheme_length > options[:maximum]\n  end\n\n  def countable_text(value)\n    return '' if value.nil?\n\n    value.dup.tap do |new_text|\n      new_text.gsub!(FetchLinkCardService::URL_PATTERN, 'x' * 23)\n      new_text.gsub!(Account::MENTION_RE, '@\\2')\n    end\n  end\nend\n"
  },
  {
    "path": "app/validators/poll_validator.rb",
    "content": "# frozen_string_literal: true\n\nclass PollValidator < ActiveModel::Validator\n  MAX_OPTIONS      = 4\n  MAX_OPTION_CHARS = 25\n  MAX_EXPIRATION   = 1.month.freeze\n  MIN_EXPIRATION   = 5.minutes.freeze\n\n  def validate(poll)\n    current_time = Time.now.utc\n\n    poll.errors.add(:options, I18n.t('polls.errors.too_few_options')) unless poll.options.size > 1\n    poll.errors.add(:options, I18n.t('polls.errors.too_many_options', max: MAX_OPTIONS)) if poll.options.size > MAX_OPTIONS\n    poll.errors.add(:options, I18n.t('polls.errors.over_character_limit', max: MAX_OPTION_CHARS)) if poll.options.any? { |option| option.mb_chars.grapheme_length > MAX_OPTION_CHARS }\n    poll.errors.add(:options, I18n.t('polls.errors.duplicate_options')) unless poll.options.uniq.size == poll.options.size\n    poll.errors.add(:expires_at, I18n.t('polls.errors.duration_too_long')) if poll.expires_at.nil? || poll.expires_at - current_time > MAX_EXPIRATION\n    poll.errors.add(:expires_at, I18n.t('polls.errors.duration_too_short')) if poll.expires_at.present? && (poll.expires_at - current_time).ceil < MIN_EXPIRATION\n  end\nend\n"
  },
  {
    "path": "app/validators/status_length_validator.rb",
    "content": "# frozen_string_literal: true\n\nclass StatusLengthValidator < ActiveModel::Validator\n  def validate(status)\n    return unless status.local? && !status.reblog?\n\n    @status = status\n    status.errors.add(:text, I18n.t('statuses.over_character_limit', max: Setting.max_toot_chars)) if too_long?\n  end\n\n  private\n\n  def too_long?\n    countable_length > Setting.max_toot_chars.to_i\n  end\n\n  def countable_length\n    total_text.mb_chars.grapheme_length\n  end\n\n  def total_text\n    [@status.spoiler_text, countable_text].join\n  end\n\n  def countable_text\n    return '' if @status.text.nil?\n\n    @status.text.dup.tap do |new_text|\n      new_text.gsub!(FetchLinkCardService::URL_PATTERN, 'x' * 23)\n      new_text.gsub!(Account::MENTION_RE, '@\\2')\n    end\n  end\nend\n"
  },
  {
    "path": "app/validators/status_pin_validator.rb",
    "content": "# frozen_string_literal: true\n\nclass StatusPinValidator < ActiveModel::Validator\n  def validate(pin)\n    pin.errors.add(:base, I18n.t('statuses.pin_errors.reblog')) if pin.status.reblog?\n    pin.errors.add(:base, I18n.t('statuses.pin_errors.ownership')) if pin.account_id != pin.status.account_id\n    pin.errors.add(:base, I18n.t('statuses.pin_errors.private')) unless %w(public unlisted).include?(pin.status.visibility)\n    pin.errors.add(:base, I18n.t('statuses.pin_errors.limit')) if pin.account.status_pins.count > 4 && pin.account.local?\n  end\nend\n"
  },
  {
    "path": "app/validators/unique_username_validator.rb",
    "content": "# frozen_string_literal: true\n\nclass UniqueUsernameValidator < ActiveModel::Validator\n  def validate(account)\n    return if account.username.nil?\n\n    normalized_username = account.username.downcase.delete('.')\n\n    scope = Account.where(domain: nil).where('lower(username) = ?', normalized_username)\n    scope = scope.where.not(id: account.id) if account.persisted?\n\n    account.errors.add(:username, :taken) if scope.exists?\n  end\nend\n"
  },
  {
    "path": "app/validators/unreserved_username_validator.rb",
    "content": "# frozen_string_literal: true\n\nclass UnreservedUsernameValidator < ActiveModel::Validator\n  def validate(account)\n    @username = account.username\n    return if @username.nil?\n\n    account.errors.add(:username, I18n.t('accounts.reserved_username')) if reserved_username?\n  end\n\n  private\n\n  def pam_controlled?\n    return false unless Devise.pam_authentication && Devise.pam_controlled_service\n    Rpam2.account(Devise.pam_controlled_service, @username).present?\n  end\n\n  def reserved_username?\n    return true if pam_controlled?\n    return false unless Setting.reserved_usernames\n    Setting.reserved_usernames.include?(@username.downcase)\n  end\nend\n"
  },
  {
    "path": "app/validators/url_validator.rb",
    "content": "# frozen_string_literal: true\n\nclass UrlValidator < ActiveModel::EachValidator\n  def validate_each(record, attribute, value)\n    record.errors.add(attribute, I18n.t('applications.invalid_url')) unless compliant?(value)\n  end\n\n  private\n\n  def compliant?(url)\n    parsed_url = Addressable::URI.parse(url)\n    parsed_url && %w(http https).include?(parsed_url.scheme) && parsed_url.host\n  end\nend\n"
  },
  {
    "path": "app/validators/vote_validator.rb",
    "content": "# frozen_string_literal: true\n\nclass VoteValidator < ActiveModel::Validator\n  def validate(vote)\n    vote.errors.add(:base, I18n.t('polls.errors.expired')) if vote.poll.expired?\n\n    if vote.poll.multiple? && vote.poll.votes.where(account: vote.account, choice: vote.choice).exists?\n      vote.errors.add(:base, I18n.t('polls.errors.already_voted'))\n    elsif !vote.poll.multiple? && vote.poll.votes.where(account: vote.account).exists?\n      vote.errors.add(:base, I18n.t('polls.errors.already_voted'))\n    end\n  end\nend\n"
  },
  {
    "path": "app/views/about/_login.html.haml",
    "content": "= simple_form_for(new_user, url: user_session_path) do |f|\n  .fields-group\n    - if use_seamless_external_login?\n      = f.input :email, placeholder: t('simple_form.labels.defaults.username_or_email'), input_html: { 'aria-label' => t('simple_form.labels.defaults.username_or_email') }, hint: false\n    - else\n      = f.input :email, placeholder: t('simple_form.labels.defaults.email'), input_html: { 'aria-label' => t('simple_form.labels.defaults.email') }, hint: false\n\n    = f.input :password, placeholder: t('simple_form.labels.defaults.password'), input_html: { 'aria-label' => t('simple_form.labels.defaults.password') }, hint: false\n\n  .actions\n    = f.button :button, t('auth.login'), type: :submit, class: 'button button-primary'\n\n  %p.hint.subtle-hint= link_to t('auth.trouble_logging_in'), new_user_password_path\n"
  },
  {
    "path": "app/views/about/_registration.html.haml",
    "content": "= simple_form_for(new_user, url: user_registration_path) do |f|\n  .simple_form__overlay-area\n    %p.lead= t('about.federation_hint_html', instance: content_tag(:strong, site_hostname))\n\n    .fields-group\n      = f.simple_fields_for :account do |account_fields|\n        = account_fields.input :username, wrapper: :with_label, label: false, required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.username'), :autocomplete => 'off', placeholder: t('simple_form.labels.defaults.username') }, append: \"@#{site_hostname}\", hint: false, disabled: closed_registrations?\n\n      = f.input :email, placeholder: t('simple_form.labels.defaults.email'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.email'), :autocomplete => 'off' }, hint: false, disabled: closed_registrations?\n      = f.input :password, placeholder: t('simple_form.labels.defaults.password'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.password'), :autocomplete => 'off' }, hint: false, disabled: closed_registrations?\n      = f.input :password_confirmation, placeholder: t('simple_form.labels.defaults.confirm_password'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.confirm_password'), :autocomplete => 'off' }, hint: false, disabled: closed_registrations?\n\n    - if approved_registrations?\n      .fields-group\n        = f.simple_fields_for :invite_request do |invite_request_fields|\n          = invite_request_fields.input :text, as: :text, wrapper: :with_block_label, required: false\n\n    .fields-group\n      = f.input :agreement, as: :boolean, wrapper: :with_label, label: t('auth.checkbox_agreement_html', rules_path: about_more_path, terms_path: terms_path), disabled: closed_registrations?\n\n    .actions\n      = f.button :button, sign_up_message, type: :submit, class: 'button button-primary', disabled: closed_registrations?\n\n    - if closed_registrations? && @instance_presenter.closed_registrations_message.present?\n      .simple_form__overlay-area__overlay\n        .simple_form__overlay-area__overlay__content.rich-formatting\n          .block-icon= fa_icon 'warning'\n          = @instance_presenter.closed_registrations_message.html_safe\n"
  },
  {
    "path": "app/views/about/more.html.haml",
    "content": "- content_for :page_title do\n  = site_hostname\n\n- content_for :header_tags do\n  = javascript_pack_tag 'public', integrity: true, crossorigin: 'anonymous'\n  = render partial: 'shared/og'\n\n.grid-3\n  .column-0\n    .public-account-header.public-account-header--no-bar\n      .public-account-header__image\n        = image_tag @instance_presenter.hero&.file&.url || @instance_presenter.thumbnail&.file&.url || asset_pack_path('media/images/preview.jpg'), alt: @instance_presenter.site_title, class: 'parallax'\n\n  .column-1\n    .landing-page__call-to-action{ dir: 'ltr' }\n      .row\n        .row__information-board\n          .information-board__section\n            %span= t 'about.user_count_before'\n            %strong= number_with_delimiter @instance_presenter.user_count\n            %span= t 'about.user_count_after', count: @instance_presenter.user_count\n          .information-board__section\n            %span= t 'about.status_count_before'\n            %strong= number_with_delimiter @instance_presenter.status_count\n            %span= t 'about.status_count_after', count: @instance_presenter.status_count\n        .row__mascot\n          .landing-page__mascot\n            = image_tag @instance_presenter.mascot&.file&.url || asset_pack_path('media/images/elephant_ui_plane.svg'), alt: ''\n\n  .column-2\n    .landing-page__information.contact-widget\n      %p\n        %strong= t 'about.administered_by'\n\n      = account_link_to(@instance_presenter.contact_account)\n\n      - if @instance_presenter.site_contact_email.present?\n        %p.contact-widget__mail\n          %strong\n            = succeed ':' do\n              = t 'about.contact'\n          %br/\n          = mail_to @instance_presenter.site_contact_email, nil, title: @instance_presenter.site_contact_email\n\n  .column-3\n    .box-widget\n      .rich-formatting= @instance_presenter.site_extended_description.html_safe.presence || t('about.extended_description_html')\n"
  },
  {
    "path": "app/views/about/show.html.haml",
    "content": "- content_for :page_title do\n  = site_hostname\n\n- content_for :header_tags do\n  %link{ rel: 'canonical', href: about_url }/\n  = render partial: 'shared/og'\n\n.landing\n  .landing__brand\n    = link_to root_url, class: 'brand' do\n      = svg_logo_full\n      %span.brand__tagline=t 'about.tagline'\n\n  .landing__grid\n    .landing__grid__column.landing__grid__column-registration\n      .box-widget\n        = render 'registration'\n\n      .directory\n        - if Setting.profile_directory\n          .directory__tag\n            = optional_link_to Setting.profile_directory, explore_path do\n              %h4\n                = fa_icon 'address-book fw'\n                = t('about.discover_users')\n                %small= t('about.browse_directory')\n\n              .avatar-stack\n                - @instance_presenter.sample_accounts.each do |account|\n                  = image_tag current_account&.user&.setting_auto_play_gif ? account.avatar_original_url : account.avatar_static_url, width: 48, height: 48, alt: '', class: 'account__avatar'\n\n        - if Setting.timeline_preview\n          .directory__tag\n            = optional_link_to Setting.timeline_preview, public_timeline_path do\n              %h4\n                = fa_icon 'globe fw'\n                = t('about.see_whats_happening')\n                %small= t('about.browse_public_posts')\n\n        .directory__tag\n          = link_to 'https://joinmastodon.org/apps', target: '_blank', rel: 'noopener' do\n            %h4\n              = fa_icon 'tablet fw'\n              = t('about.get_apps')\n              %small= t('about.apps_platforms')\n\n    .landing__grid__column.landing__grid__column-login\n      .box-widget\n        = render 'login'\n\n      .hero-widget\n        .hero-widget__img\n          = image_tag @instance_presenter.hero&.file&.url || @instance_presenter.thumbnail&.file&.url || asset_pack_path('media/images/preview.jpg'), alt: @instance_presenter.site_title\n\n        - if @instance_presenter.site_short_description.present?\n          .hero-widget__text\n            %p\n              = @instance_presenter.site_short_description.html_safe.presence\n              = link_to about_more_path do\n                = t('about.learn_more')\n                = fa_icon 'angle-double-right'\n\n        .hero-widget__footer\n          .hero-widget__footer__column\n            %h4= t 'about.administered_by'\n\n            = account_link_to @instance_presenter.contact_account\n\n          .hero-widget__footer__column\n            %h4= t 'about.server_stats'\n\n            %div{ style: 'display: flex' }\n              .hero-widget__counter{ style: 'width: 50%' }\n                %strong= number_to_human @instance_presenter.user_count, strip_insignificant_zeros: true\n                %span= t 'about.user_count_after', count: @instance_presenter.user_count\n              .hero-widget__counter{ style: 'width: 50%' }\n                %strong= number_to_human @instance_presenter.active_user_count, strip_insignificant_zeros: true\n                %span\n                  = t 'about.active_count_after'\n                  %abbr{ title: t('about.active_footnote') } *\n"
  },
  {
    "path": "app/views/about/terms.html.haml",
    "content": "- content_for :page_title do\n  = t('terms.title', instance: site_hostname)\n\n.grid\n  .column-0\n    .box-widget\n      .rich-formatting= @instance_presenter.site_terms.html_safe.presence || t('terms.body_html')\n  .column-1\n    = render 'application/sidebar'\n"
  },
  {
    "path": "app/views/accounts/_bio.html.haml",
    "content": "- proofs = account.identity_proofs.active\n- fields = account.fields\n\n.public-account-bio\n  - unless fields.empty? && proofs.empty?\n    .account__header__fields\n      - proofs.each do |proof|\n        %dl\n          %dt= proof.provider.capitalize\n          %dd.verified\n            = link_to fa_icon('check'), proof.badge.proof_url, class: 'verified__mark', title: t('accounts.link_verified_on', date: l(proof.updated_at))\n            = link_to proof.provider_username, proof.badge.profile_url\n\n      - fields.each do |field|\n        %dl\n          %dt.emojify{ title: field.name }= Formatter.instance.format_field(account, field.name, custom_emojify: true)\n          %dd{ title: field.value, class: custom_field_classes(field) }\n            - if field.verified?\n              %span.verified__mark{ title: t('accounts.link_verified_on', date: l(field.verified_at)) }\n                = fa_icon 'check'\n            = Formatter.instance.format_field(account, field.value, custom_emojify: true)\n\n  = account_badge(account)\n\n  - if account.note.present?\n    .account__header__content.emojify= Formatter.instance.simplified_format(account, custom_emojify: true)\n\n  .public-account-bio__extra\n    = t 'accounts.joined', date: l(account.created_at, format: :month)\n"
  },
  {
    "path": "app/views/accounts/_header.html.haml",
    "content": ".public-account-header{:class => (\"inactive\" if account.moved?)}\n  .public-account-header__image\n    = image_tag (current_account&.user&.setting_auto_play_gif ? account.header_original_url : account.header_static_url), class: 'parallax'\n  .public-account-header__bar\n    = link_to short_account_url(account), class: 'avatar' do\n      = image_tag (current_account&.user&.setting_auto_play_gif ? account.avatar_original_url : account.avatar_static_url), id: 'profile_page_avatar', data: {original: full_asset_url(account.avatar_original_url), static: full_asset_url(account.avatar_static_url), autoplay: current_account&.user&.setting_auto_play_gif}\n    .public-account-header__tabs\n      .public-account-header__tabs__name\n        %h1\n          = display_name(account, custom_emojify: true)\n          %small\n            = acct(account)\n            = fa_icon('lock') if account.locked?\n      .public-account-header__tabs__tabs\n        .details-counters\n          .counter{ class: active_nav_class(short_account_url(account), short_account_with_replies_url(account), short_account_media_url(account)) }\n            = link_to short_account_url(account), class: 'u-url u-uid', title: number_with_delimiter(account.statuses_count) do\n              %span.counter-number= number_to_human account.statuses_count, strip_insignificant_zeros: true\n              %span.counter-label= t('accounts.posts', count: account.statuses_count)\n\n          .counter{ class: active_nav_class(account_following_index_url(account)) }\n            = link_to account_following_index_url(account), title: number_with_delimiter(account.following_count) do\n              %span.counter-number= number_to_human account.following_count, strip_insignificant_zeros: true\n              %span.counter-label= t('accounts.following', count: account.following_count)\n\n          .counter{ class: active_nav_class(account_followers_url(account)) }\n            = link_to account_followers_url(account), title: number_with_delimiter(account.followers_count) do\n              %span.counter-number= number_to_human account.followers_count, strip_insignificant_zeros: true\n              %span.counter-label= t('accounts.followers', count: account.followers_count)\n        .spacer\n        .public-account-header__tabs__tabs__buttons\n          = account_action_button(account)\n\n    .public-account-header__extra\n      = render 'accounts/bio', account: account\n\n      .public-account-header__extra__links\n        = link_to account_following_index_url(account) do\n          %strong= number_to_human account.following_count, strip_insignificant_zeros: true\n          = t('accounts.following', count: account.following_count)\n        = link_to account_followers_url(account) do\n          %strong= number_to_human account.followers_count, strip_insignificant_zeros: true\n          = t('accounts.followers', count: account.followers_count)\n"
  },
  {
    "path": "app/views/accounts/_moved.html.haml",
    "content": "- moved_to_account = account.moved_to_account\n\n.moved-account-widget\n  .moved-account-widget__message\n    = fa_icon 'suitcase'\n    = t('accounts.moved_html', name: content_tag(:bdi, content_tag(:strong, display_name(account, custom_emojify: true), class: :emojify)), new_profile_link: link_to(content_tag(:strong, safe_join(['@', content_tag(:span, moved_to_account.acct)])), TagManager.instance.url_for(moved_to_account), class: 'mention'))\n\n  .moved-account-widget__card\n    = link_to TagManager.instance.url_for(moved_to_account), class: 'detailed-status__display-name p-author h-card', target: '_blank', rel: 'me noopener' do\n      .detailed-status__display-avatar\n        .account__avatar-overlay\n          .account__avatar-overlay-base{ style: \"background-image: url('#{moved_to_account.avatar.url(:original)}')\" }\n          .account__avatar-overlay-overlay{ style: \"background-image: url('#{account.avatar.url(:original)}')\" }\n\n      %span.display-name\n        %bdi\n          %strong.emojify= display_name(moved_to_account, custom_emojify: true)\n        %span @#{moved_to_account.acct}\n"
  },
  {
    "path": "app/views/accounts/_og.html.haml",
    "content": "- description = account_description(account)\n\n%meta{ name: 'description', content: description }/\n\n= opengraph 'og:url', url\n= opengraph 'og:site_name', site_title\n= opengraph 'og:title', yield(:page_title).strip\n= opengraph 'og:description', description\n= opengraph 'og:image', full_asset_url(account.avatar.url(:original))\n= opengraph 'og:image:width', '120'\n= opengraph 'og:image:height', '120'\n= opengraph 'twitter:card', 'summary'\n= opengraph 'profile:username', account.local_username_and_domain\n"
  },
  {
    "path": "app/views/accounts/show.html.haml",
    "content": "- content_for :page_title do\n  = \"#{display_name(@account)} (@#{@account.local_username_and_domain})\"\n\n- content_for :header_tags do\n  %meta{ name: 'description', content: account_description(@account) }/\n\n  - if @account.user&.setting_noindex\n    %meta{ name: 'robots', content: 'noindex' }/\n\n  %link{ rel: 'salmon', href: api_salmon_url(@account.id) }/\n  %link{ rel: 'alternate', type: 'application/atom+xml', href: account_url(@account, format: 'atom') }/\n  %link{ rel: 'alternate', type: 'application/rss+xml', href: account_url(@account, format: 'rss') }/\n  %link{ rel: 'alternate', type: 'application/activity+json', href: ActivityPub::TagManager.instance.uri_for(@account) }/\n\n  - if @older_url\n    %link{ rel: 'next', href: @older_url }/\n  - if @newer_url\n    %link{ rel: 'prev', href: @newer_url }/\n\n  = opengraph 'og:type', 'profile'\n  = render 'og', account: @account, url: short_account_url(@account, only_path: false)\n\n\n= render 'header', account: @account, with_bio: true\n\n.grid\n  .column-0\n    .h-feed\n      %data.p-name{ value: \"#{@account.username} on #{site_hostname}\" }/\n\n      .account__section-headline\n        = active_link_to t('accounts.posts_tab_heading'), short_account_url(@account)\n        = active_link_to t('accounts.posts_with_replies'), short_account_with_replies_url(@account)\n        = active_link_to t('accounts.media'), short_account_media_url(@account)\n\n      - if user_signed_in? && @account.blocking?(current_account)\n        .nothing-here.nothing-here--under-tabs= t('accounts.unavailable')\n      - elsif @statuses.empty?\n        = nothing_here 'nothing-here--under-tabs'\n      - else\n        .activity-stream.activity-stream--under-tabs\n          - if params[:page].to_i.zero?\n            = render partial: 'stream_entries/status', collection: @pinned_statuses, as: :status, locals: { pinned: true }\n\n          - if @newer_url\n            .entry= link_to_more @newer_url\n\n          = render partial: 'stream_entries/status', collection: @statuses, as: :status\n\n          - if @older_url\n            .entry= link_to_more @older_url\n\n  .column-1\n    - if @account.memorial?\n      .memoriam-widget= t('in_memoriam_html')\n    - elsif @account.moved?\n      = render 'moved', account: @account\n\n    = render 'bio', account: @account\n\n    - unless @endorsed_accounts.empty?\n      .endorsements-widget\n        %h4= t 'accounts.choices_html', name: content_tag(:bdi, display_name(@account, custom_emojify: true))\n\n        - @endorsed_accounts.each do |account|\n          = account_link_to account\n\n    - @account.featured_tags.order(statuses_count: :desc).each do |featured_tag|\n      .directory__tag{ class: params[:tag] == featured_tag.name ? 'active' : nil }\n        = link_to short_account_tag_path(@account, featured_tag.tag) do\n          %h4\n            = fa_icon 'hashtag'\n            = featured_tag.name\n            %small\n              - if featured_tag.last_status_at.nil?\n                = t('accounts.nothing_here')\n              - else\n                %time{ datetime: featured_tag.last_status_at.iso8601, title: l(featured_tag.last_status_at) }= l featured_tag.last_status_at\n          .trends__item__current= number_to_human featured_tag.statuses_count, strip_insignificant_zeros: true\n\n    = render 'application/sidebar'\n"
  },
  {
    "path": "app/views/admin/account_actions/new.html.haml",
    "content": "- content_for :page_title do\n  = t('admin.account_actions.title', acct: @account.acct)\n\n= simple_form_for @account_action, url: admin_account_action_path(@account.id) do |f|\n  = f.input :report_id, as: :hidden\n\n  .fields-group\n    = f.input :type, collection: Admin::AccountAction.types_for_account(@account), include_blank: false, wrapper: :with_block_label, label_method: ->(type) { I18n.t(\"simple_form.labels.admin_account_action.types.#{type}\")}, hint: t('simple_form.hints.admin_account_action.type_html', acct: @account.acct)\n\n  - if @account.local?\n    %hr.spacer/\n\n    .fields-group\n      = f.input :send_email_notification, as: :boolean, wrapper: :with_label\n\n    %hr.spacer/\n\n    - unless @warning_presets.empty?\n      .fields-group\n        = f.input :warning_preset_id, collection: @warning_presets, label_method: :text, wrapper: :with_block_label\n\n    .fields-group\n      = f.input :text, as: :text, wrapper: :with_block_label, hint: t('simple_form.hints.admin_account_action.text_html', path: admin_warning_presets_path)\n\n  .actions\n    = f.button :button, t('admin.account_actions.action'), type: :submit\n"
  },
  {
    "path": "app/views/admin/account_moderation_notes/_account_moderation_note.html.haml",
    "content": ".speech-bubble\n  .speech-bubble__bubble\n    = simple_format(h(account_moderation_note.content))\n  .speech-bubble__owner\n    = admin_account_link_to account_moderation_note.account\n    %time.formatted{ datetime: account_moderation_note.created_at.iso8601 }= l account_moderation_note.created_at\n    = table_link_to 'trash', t('admin.account_moderation_notes.delete'), admin_account_moderation_note_path(account_moderation_note), method: :delete if can?(:destroy, account_moderation_note)\n"
  },
  {
    "path": "app/views/admin/account_warnings/_account_warning.html.haml",
    "content": ".speech-bubble.warning\n  .speech-bubble__bubble\n    = Formatter.instance.linkify(account_warning.text)\n  .speech-bubble__owner\n    = admin_account_link_to account_warning.account\n    %time.formatted{ datetime: account_warning.created_at.iso8601 }= l account_warning.created_at\n"
  },
  {
    "path": "app/views/admin/accounts/_account.html.haml",
    "content": "%tr\n  %td\n    = admin_account_link_to(account)\n  %td\n    %div{ style: 'margin: -2px 0' }= account_badge(account, all: true)\n  %td\n    - if account.user_current_sign_in_ip\n      %samp.ellipsized-ip{ title: account.user_current_sign_in_ip }= account.user_current_sign_in_ip\n    - else\n      \\-\n  %td\n    - if account.user_current_sign_in_at\n      %time.time-ago{ datetime: account.user_current_sign_in_at.iso8601, title: l(account.user_current_sign_in_at) }= l account.user_current_sign_in_at\n    - else\n      \\-\n  %td\n    - if account.local? && account.user_pending?\n      = table_link_to 'check', t('admin.accounts.approve'), approve_admin_account_path(account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') } if can?(:approve, account.user)\n      = table_link_to 'times', t('admin.accounts.reject'), reject_admin_account_path(account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') } if can?(:reject, account.user)\n    - else\n      = table_link_to 'circle', t('admin.accounts.web'), web_path(\"accounts/#{account.id}\")\n      = table_link_to 'globe', t('admin.accounts.public'), TagManager.instance.url_for(account)\n"
  },
  {
    "path": "app/views/admin/accounts/index.html.haml",
    "content": "- content_for :page_title do\n  = t('admin.accounts.title')\n\n.filters\n  .filter-subset\n    %strong= t('admin.accounts.location.title')\n    %ul\n      %li= filter_link_to t('admin.accounts.location.local'), remote: nil\n      %li= filter_link_to t('admin.accounts.location.remote'), remote: '1'\n  .filter-subset\n    %strong= t('admin.accounts.moderation.title')\n    %ul\n      %li= link_to safe_join([t('admin.accounts.moderation.pending'), \"(#{number_with_delimiter(User.pending.count)})\"], ' '), admin_pending_accounts_path\n      %li= filter_link_to t('admin.accounts.moderation.active'), silenced: nil, suspended: nil, pending: nil\n      %li= filter_link_to t('admin.accounts.moderation.silenced'), silenced: '1', suspended: nil, pending: nil\n      %li= filter_link_to t('admin.accounts.moderation.suspended'), suspended: '1', silenced: nil, pending: nil\n  .filter-subset\n    %strong= t('admin.accounts.role')\n    %ul\n      %li= filter_link_to t('admin.accounts.moderation.all'), staff: nil\n      %li= filter_link_to t('admin.accounts.roles.staff'), staff: '1'\n\n= form_tag admin_accounts_url, method: 'GET', class: 'simple_form' do\n  .fields-group\n    - Admin::FilterHelper::ACCOUNT_FILTERS.each do |key|\n      - if params[key].present?\n        = hidden_field_tag key, params[key]\n\n    - %i(username by_domain display_name email ip).each do |key|\n      - unless key == :by_domain && params[:remote].blank?\n        .input.string.optional\n          = text_field_tag key, params[key], class: 'string optional', placeholder: I18n.t(\"admin.accounts.#{key}\")\n\n    .actions\n      %button= t('admin.accounts.search')\n      = link_to t('admin.accounts.reset'), admin_accounts_path, class: 'button negative'\n\n.table-wrapper\n  %table.table\n    %thead\n      %tr\n        %th= t('admin.accounts.username')\n        %th= t('admin.accounts.role')\n        %th= t('admin.accounts.most_recent_ip')\n        %th= t('admin.accounts.most_recent_activity')\n        %th\n    %tbody\n      = render @accounts\n\n= paginate @accounts\n"
  },
  {
    "path": "app/views/admin/accounts/show.html.haml",
    "content": "- content_for :page_title do\n  = @account.acct\n\n= render 'application/card', account: @account\n\n.dashboard__counters{ style: 'margin-top: 10px' }\n  %div\n    = link_to admin_account_statuses_path(@account.id) do\n      .dashboard__counters__num= number_with_delimiter @account.statuses_count\n      .dashboard__counters__label= t 'admin.accounts.statuses'\n  %div\n    = link_to admin_account_statuses_path(@account.id, { media: true }) do\n      .dashboard__counters__num= number_to_human_size @account.media_attachments.sum('file_file_size')\n      .dashboard__counters__label= t 'admin.accounts.media_attachments'\n  %div\n    = link_to admin_account_followers_path(@account.id) do\n      .dashboard__counters__num= number_with_delimiter @account.local_followers_count\n      .dashboard__counters__label= t 'admin.accounts.followers'\n  %div\n    = link_to admin_reports_path(account_id: @account.id) do\n      .dashboard__counters__num= number_with_delimiter @account.reports.count\n      .dashboard__counters__label= t '.created_reports'\n  %div\n    = link_to admin_reports_path(target_account_id: @account.id) do\n      .dashboard__counters__num= number_with_delimiter @account.targeted_reports.count\n      .dashboard__counters__label= t '.targeted_reports'\n  %div\n    %div\n      .dashboard__counters__text\n        - if @account.local? && @account.user.nil?\n          %span.neutral= t('admin.accounts.deleted')\n        - elsif @account.suspended?\n          %span.red= t('admin.accounts.suspended')\n        - elsif @account.silenced?\n          %span.red= t('admin.accounts.silenced')\n        - elsif @account.local? && @account.user&.disabled?\n          %span.red= t('admin.accounts.disabled')\n        - elsif @account.local? && !@account.user&.confirmed?\n          %span.neutral= t('admin.accounts.confirming')\n        - elsif @account.local? && !@account.user_approved?\n          %span.neutral= t('admin.accounts.pending')\n        - else\n          %span.neutral= t('admin.accounts.no_limits_imposed')\n      .dashboard__counters__label= t 'admin.accounts.login_status'\n\n- unless @account.local? && @account.user.nil?\n  .table-wrapper\n    %table.table.inline-table\n      %tbody\n        - if @account.local?\n          - if @account.avatar?\n            %tr\n              %th= t('admin.accounts.avatar')\n              %td= table_link_to 'trash', t('admin.accounts.remove_avatar'), remove_avatar_admin_account_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') } if can?(:remove_avatar, @account)\n              %td\n\n          - if @account.header?\n            %tr\n              %th= t('admin.accounts.header')\n              %td= table_link_to 'trash', t('admin.accounts.remove_header'), remove_header_admin_account_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') } if can?(:remove_header, @account)\n              %td\n\n          %tr\n            %th= t('admin.accounts.role')\n            %td= t(\"admin.accounts.roles.#{@account.user&.role}\")\n            %td\n              = table_link_to 'angle-double-up', t('admin.accounts.promote'), promote_admin_account_role_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') } if can?(:promote, @account.user)\n              = table_link_to 'angle-double-down', t('admin.accounts.demote'), demote_admin_account_role_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') } if can?(:demote, @account.user)\n\n          %tr\n            %th= t('admin.accounts.email')\n            %td= @account.user_email\n            %td= table_link_to 'edit', t('admin.accounts.change_email.label'), admin_account_change_email_path(@account.id) if can?(:change_email, @account.user)\n\n          - if @account.user_unconfirmed_email.present?\n            %tr\n              %th= t('admin.accounts.unconfirmed_email')\n              %td= @account.user_unconfirmed_email\n              %td\n\n          %tr\n            %th= t('admin.accounts.email_status')\n            %td\n              - if @account.user&.confirmed?\n                = t('admin.accounts.confirmed')\n              - else\n                = t('admin.accounts.confirming')\n            %td= table_link_to 'refresh', t('admin.accounts.resend_confirmation.send'), resend_admin_account_confirmation_path(@account.id), method: :post if can?(:confirm, @account.user)\n\n          %tr\n            %th= t('admin.accounts.login_status')\n            %td\n              - if @account.user&.disabled?\n                = t('admin.accounts.disabled')\n              - else\n                = t('admin.accounts.enabled')\n            %td\n              - if @account.user&.disabled?\n                = table_link_to 'unlock', t('admin.accounts.enable'), enable_admin_account_path(@account.id), method: :post if can?(:enable, @account.user)\n              - elsif @account.user_approved?\n                = table_link_to 'lock', t('admin.accounts.disable'), new_admin_account_action_path(@account.id, type: 'disable') if can?(:disable, @account.user)\n\n          %tr\n            %th= t('simple_form.labels.defaults.locale')\n            %td= @account.user_locale\n            %td\n\n          %tr\n            %th= t('admin.accounts.joined')\n            %td\n              %time.formatted{ datetime: @account.created_at.iso8601, title: l(@account.created_at) }= l @account.created_at\n            %td\n\n          %tr\n            %th= t('admin.accounts.most_recent_ip')\n            %td= @account.user_current_sign_in_ip\n            %td\n\n          %tr\n            %th= t('admin.accounts.most_recent_activity')\n            %td\n              - if @account.user_current_sign_in_at\n                %time.formatted{ datetime: @account.user_current_sign_in_at.iso8601, title: l(@account.user_current_sign_in_at) }= l @account.user_current_sign_in_at\n\n          - if @account.user&.invited?\n            %tr\n              %th= t('admin.accounts.invited_by')\n              %td= admin_account_link_to @account.user.invite.user.account\n              %td\n\n        - else\n          %tr\n            %th= t('admin.accounts.inbox_url')\n            %td\n              = @account.inbox_url\n              = fa_icon DeliveryFailureTracker.unavailable?(@account.inbox_url) ? 'times' : 'check'\n          %tr\n            %th= t('admin.accounts.shared_inbox_url')\n            %td\n              = @account.shared_inbox_url\n              = fa_icon DeliveryFailureTracker.unavailable?(@account.shared_inbox_url) ? 'times' : 'check'\n\n  %div{ style: 'overflow: hidden' }\n    %div{ style: 'float: right' }\n      - if @account.local?\n        = link_to t('admin.accounts.reset_password'), admin_account_reset_path(@account.id), method: :create, class: 'button' if can?(:reset_password, @account.user)\n        - if @account.user&.otp_required_for_login?\n          = link_to t('admin.accounts.disable_two_factor_authentication'), admin_user_two_factor_authentication_path(@account.user.id), method: :delete, class: 'button' if can?(:disable_2fa, @account.user)\n        - if !@account.memorial? && @account.user_approved?\n          = link_to t('admin.accounts.memorialize'), memorialize_admin_account_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button button--destructive' if can?(:memorialize, @account)\n      - else\n        = link_to t('admin.accounts.redownload'), redownload_admin_account_path(@account.id), method: :post, class: 'button' if can?(:redownload, @account)\n\n    %div{ style: 'float: left' }\n      - if @account.local? && @account.user_approved?\n        = link_to t('admin.accounts.warn'), new_admin_account_action_path(@account.id, type: 'none'), class: 'button' if can?(:warn, @account)\n      - if @account.silenced?\n        = link_to t('admin.accounts.undo_silenced'), unsilence_admin_account_path(@account.id), method: :post, class: 'button' if can?(:unsilence, @account)\n      - elsif !@account.local? || @account.user_approved?\n        = link_to t('admin.accounts.silence'), new_admin_account_action_path(@account.id, type: 'silence'), class: 'button button--destructive' if can?(:silence, @account)\n\n      - if @account.local?\n        - if @account.user_pending?\n          = link_to t('admin.accounts.approve'), approve_admin_account_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button' if can?(:approve, @account.user)\n          = link_to t('admin.accounts.reject'), reject_admin_account_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button button--destructive' if can?(:reject, @account.user)\n\n        - unless @account.user_confirmed?\n          = link_to t('admin.accounts.confirm'), admin_account_confirmation_path(@account.id), method: :post, class: 'button' if can?(:confirm, @account.user)\n\n      - if @account.suspended?\n        = link_to t('admin.accounts.undo_suspension'), unsuspend_admin_account_path(@account.id), method: :post, class: 'button' if can?(:unsuspend, @account)\n      - elsif !@account.local? || @account.user_approved?\n        = link_to t('admin.accounts.perform_full_suspension'), new_admin_account_action_path(@account.id, type: 'suspend'), class: 'button button--destructive' if can?(:suspend, @account)\n\n      - unless @account.local?\n        - if DomainBlock.where(domain: @account.domain).exists?\n          = link_to t('admin.domain_blocks.undo'), admin_instance_path(@account.domain), class: 'button'\n        - else\n          = link_to t('admin.domain_blocks.add_new'), new_admin_domain_block_path(_domain: @account.domain), class: 'button button--destructive'\n\n  %hr.spacer/\n\n  - unless @warnings.empty?\n    = render @warnings\n\n    %hr.spacer/\n\n  = render @moderation_notes\n\n  = simple_form_for @account_moderation_note, url: admin_account_moderation_notes_path do |f|\n    = render 'shared/error_messages', object: @account_moderation_note\n\n    = f.input :content, placeholder: t('admin.reports.notes.placeholder'), rows: 6\n    = f.hidden_field :target_account_id\n\n    .actions\n      = f.button :button, t('admin.account_moderation_notes.create'), type: :submit\n"
  },
  {
    "path": "app/views/admin/action_logs/_action_log.html.haml",
    "content": ".log-entry\n  .log-entry__header\n    .log-entry__avatar\n      = image_tag action_log.account.avatar.url(:original), alt: '', width: 40, height: 40, class: 'avatar'\n    .log-entry__content\n      .log-entry__title\n        = t(\"admin.action_logs.actions.#{action_log.action}_#{action_log.target_type.underscore}\", name: content_tag(:span, action_log.account.username, class: 'username'), target: content_tag(:span, log_target(action_log), class: 'target')).html_safe\n      .log-entry__timestamp\n        %time.formatted{ datetime: action_log.created_at.iso8601 }\n    .spacer\n    .log-entry__icon\n      = fa_icon icon_for_log(action_log)\n      .log-entry__icon__overlay{ class: class_for_log_icon(action_log) }\n  .log-entry__extras\n    = log_extra_attributes relevant_log_changes(action_log)\n"
  },
  {
    "path": "app/views/admin/action_logs/index.html.haml",
    "content": "- content_for :page_title do\n  = t('admin.action_logs.title')\n\n= render @action_logs\n\n= paginate @action_logs\n"
  },
  {
    "path": "app/views/admin/change_emails/show.html.haml",
    "content": "- content_for :page_title do\n  = t('admin.accounts.change_email.title', username: @account.acct)\n\n= simple_form_for @user, url: admin_account_change_email_path(@account.id) do |f|\n  .fields-group\n    = f.input :email, wrapper: :with_label, hint: false, disabled: true, label: t('admin.accounts.change_email.current_email')\n\n  .fields-group\n    = f.input :unconfirmed_email, wrapper: :with_label, label: t('admin.accounts.change_email.new_email')\n\n  .actions\n    = f.button :submit, class: \"button\", value: t('admin.accounts.change_email.submit')\n"
  },
  {
    "path": "app/views/admin/custom_emojis/_custom_emoji.html.haml",
    "content": "%tr\n  %td\n    = custom_emoji_tag(custom_emoji)\n  %td\n    %samp= \":#{custom_emoji.shortcode}:\"\n  %td\n    - if custom_emoji.local?\n      = t('admin.accounts.location.local')\n    - else\n      = link_to custom_emoji.domain, admin_custom_emojis_path(by_domain: custom_emoji.domain)\n  %td\n    - if custom_emoji.local?\n      - if custom_emoji.visible_in_picker\n        = table_link_to 'eye', t('admin.custom_emojis.listed'), admin_custom_emoji_path(custom_emoji, custom_emoji: { visible_in_picker: false }, page: params[:page], **@filter_params), method: :patch\n      - else\n        = table_link_to 'eye-slash', t('admin.custom_emojis.unlisted'), admin_custom_emoji_path(custom_emoji, custom_emoji: { visible_in_picker: true }, page: params[:page], **@filter_params), method: :patch\n    - else\n      - if custom_emoji.local_counterpart.present?\n        = link_to safe_join([custom_emoji_tag(custom_emoji.local_counterpart), t('admin.custom_emojis.overwrite')]), copy_admin_custom_emoji_path(custom_emoji, page: params[:page], **@filter_params), method: :post, class: 'table-action-link'\n      - else\n        = table_link_to 'copy', t('admin.custom_emojis.copy'), copy_admin_custom_emoji_path(custom_emoji, page: params[:page], **@filter_params), method: :post\n  %td\n    - if custom_emoji.disabled?\n      = table_link_to 'power-off', t('admin.custom_emojis.enable'), enable_admin_custom_emoji_path(custom_emoji, page: params[:page], **@filter_params), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }\n    - else\n      = table_link_to 'power-off', t('admin.custom_emojis.disable'), disable_admin_custom_emoji_path(custom_emoji, page: params[:page], **@filter_params), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }\n  %td\n    = table_link_to 'times', t('admin.custom_emojis.delete'), admin_custom_emoji_path(custom_emoji, page: params[:page], **@filter_params), method: :delete, data: { confirm: t('admin.accounts.are_you_sure') }\n"
  },
  {
    "path": "app/views/admin/custom_emojis/index.html.haml",
    "content": "- content_for :page_title do\n  = t('admin.custom_emojis.title')\n\n.filters\n  .filter-subset\n    %strong= t('admin.accounts.location.title')\n    %ul\n      %li= filter_link_to t('admin.accounts.location.all'), local: nil, remote: nil\n      %li\n        - if selected? local: '1', remote: nil\n          = filter_link_to t('admin.accounts.location.local'), {local: nil, remote: nil}, {local: '1', remote: nil}\n        - else\n          = filter_link_to t('admin.accounts.location.local'), local: '1', remote: nil\n      %li\n        - if selected? remote: '1', local: nil\n          = filter_link_to t('admin.accounts.location.remote'), {remote: nil, local: nil}, {remote: '1', local: nil}\n        - else\n          = filter_link_to t('admin.accounts.location.remote'), remote: '1', local: nil\n\n= form_tag admin_custom_emojis_url, method: 'GET', class: 'simple_form' do\n  .fields-group\n    - Admin::FilterHelper::CUSTOM_EMOJI_FILTERS.each do |key|\n      - if params[key].present?\n        = hidden_field_tag key, params[key]\n\n    - %i(shortcode by_domain).each do |key|\n      .input.string.optional\n        = text_field_tag key, params[key], class: 'string optional', placeholder: I18n.t(\"admin.custom_emojis.#{key}\")\n\n    .actions\n      %button= t('admin.accounts.search')\n      = link_to t('admin.accounts.reset'), admin_custom_emojis_path, class: 'button negative'\n\n.table-wrapper\n  %table.table\n    %thead\n      %tr\n        %th= t('admin.custom_emojis.emoji')\n        %th= t('admin.custom_emojis.shortcode')\n        %th= t('admin.accounts.domain')\n        %th\n        %th\n        %th\n    %tbody\n      = render @custom_emojis\n\n= paginate @custom_emojis\n= link_to t('admin.custom_emojis.upload'), new_admin_custom_emoji_path, class: 'button'\n"
  },
  {
    "path": "app/views/admin/custom_emojis/new.html.haml",
    "content": "- content_for :page_title do\n  = t('.title')\n\n= simple_form_for @custom_emoji, url: admin_custom_emojis_path do |f|\n  = render 'shared/error_messages', object: @custom_emoji\n\n  .fields-group\n    = f.input :shortcode, wrapper: :with_label, label: t('admin.custom_emojis.shortcode'), hint: t('admin.custom_emojis.shortcode_hint')\n  .fields-group\n    = f.input :image, wrapper: :with_label, input_html: { accept: 'image/png' }, hint: t('admin.custom_emojis.image_hint')\n\n  .actions\n    = f.button :button, t('admin.custom_emojis.upload'), type: :submit\n"
  },
  {
    "path": "app/views/admin/dashboard/index.html.haml",
    "content": "- content_for :page_title do\n  = t('admin.dashboard.title')\n\n.dashboard__counters\n  %div\n    = link_to admin_accounts_url(local: 1, recent: 1) do\n      .dashboard__counters__num= number_with_delimiter @users_count\n      .dashboard__counters__label= t 'admin.dashboard.total_users'\n  %div\n    %div\n      .dashboard__counters__num= number_with_delimiter @registrations_week\n      .dashboard__counters__label= t 'admin.dashboard.week_users_new'\n  %div\n    %div\n      .dashboard__counters__num= number_with_delimiter @logins_week\n      .dashboard__counters__label= t 'admin.dashboard.week_users_active'\n  %div\n    %div\n      .dashboard__counters__num= number_with_delimiter @interactions_week\n      .dashboard__counters__label= t 'admin.dashboard.week_interactions'\n  %div\n    = link_to admin_reports_url do\n      .dashboard__counters__num= number_with_delimiter @reports_count\n      .dashboard__counters__label= t 'admin.dashboard.open_reports'\n  %div\n    = link_to sidekiq_url do\n      .dashboard__counters__num= number_with_delimiter @queue_backlog\n      .dashboard__counters__label= t 'admin.dashboard.backlog'\n\n.dashboard__widgets\n  .dashboard__widgets__users\n    %div\n      %h4= t 'admin.dashboard.recent_users'\n      %ul\n        - @recent_users.each do |user|\n          %li= admin_account_link_to(user.account)\n\n  .dashboard__widgets__features\n    %div\n      %h4= t 'admin.dashboard.features'\n      %ul\n        %li\n          = feature_hint(link_to(t('admin.dashboard.feature_registrations'), edit_admin_settings_path), @registrations_enabled)\n        %li\n          = feature_hint(link_to(t('admin.dashboard.feature_invites'), edit_admin_settings_path), @invites_enabled)\n        %li\n          = feature_hint(link_to(t('admin.dashboard.feature_deletions'), edit_admin_settings_path), @deletions_enabled)\n        %li\n          = feature_hint(link_to(t('admin.dashboard.feature_profile_directory'), edit_admin_settings_path), @profile_directory)\n        %li\n          = feature_hint(link_to(t('admin.dashboard.feature_timeline_preview'), edit_admin_settings_path), @timeline_preview)\n        %li\n          = feature_hint(link_to(t('admin.dashboard.feature_relay'), admin_relays_path), @relay_enabled)\n\n  .dashboard__widgets__versions\n    %div\n      %h4= t 'admin.dashboard.software'\n      %ul\n        %li\n          Florence\n          %span.pull-right= @version\n        %li\n          Mastodon\n          %span.pull-right= @masto_version\n        %li\n          Ruby\n          %span.pull-right= \"#{RUBY_VERSION}p#{RUBY_PATCHLEVEL}\"\n        %li\n          PostgreSQL\n          %span.pull-right= @database_version\n        %li\n          Redis\n          %span.pull-right= @redis_version\n\n  .dashboard__widgets__space\n    %div\n      %h4= t 'admin.dashboard.space'\n      %ul\n        %li\n          PostgreSQL\n          %span.pull-right= number_to_human_size @database_size\n        %li\n          Redis\n          %span.pull-right= number_to_human_size @redis_size\n\n  .dashboard__widgets__config\n    %div\n      %h4= t 'admin.dashboard.config'\n      %ul\n        %li\n          = feature_hint(t('admin.dashboard.search'), @search_enabled)\n        %li\n          = feature_hint(t('admin.dashboard.single_user_mode'), @single_user_mode)\n        %li\n          = feature_hint('LDAP', @ldap_enabled)\n        %li\n          = feature_hint('CAS', @cas_enabled)\n        %li\n          = feature_hint('SAML', @saml_enabled)\n        %li\n          = feature_hint('PAM', @pam_enabled)\n        %li\n          = feature_hint(t('admin.dashboard.hidden_service'), @hidden_service)\n\n  .dashboard__widgets__trends\n    %div\n      %h4= t 'admin.dashboard.trends'\n      %ul\n        - @trending_hashtags.each do |tag|\n          %li\n            = link_to \"##{tag.name}\", web_url(\"timelines/tag/#{tag.name}\")\n            %span.pull-right= number_with_delimiter(tag.history[0][:accounts].to_i)\n"
  },
  {
    "path": "app/views/admin/domain_blocks/new.html.haml",
    "content": "- content_for :header_tags do\n  = javascript_pack_tag 'admin', integrity: true, async: true, crossorigin: 'anonymous'\n\n- content_for :page_title do\n  = t('.title')\n\n= simple_form_for @domain_block, url: admin_domain_blocks_path do |f|\n  = render 'shared/error_messages', object: @domain_block\n\n  .fields-row\n    .fields-row__column.fields-row__column-6.fields-group\n      = f.input :domain, wrapper: :with_label, label: t('admin.domain_blocks.domain'), hint: t('.hint'), required: true\n\n    .fields-row__column.fields-row__column-6.fields-group\n      = f.input :severity, collection: DomainBlock.severities.keys, wrapper: :with_label, include_blank: false, label_method: lambda { |type| t(\".severity.#{type}\") }, hint: t('.severity.desc_html')\n\n  .fields-group\n    = f.input :reject_media, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_media'), hint: I18n.t('admin.domain_blocks.reject_media_hint')\n\n  .fields-group\n    = f.input :reject_reports, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_reports'), hint: I18n.t('admin.domain_blocks.reject_reports_hint')\n\n  .actions\n    = f.button :button, t('.create'), type: :submit\n"
  },
  {
    "path": "app/views/admin/domain_blocks/show.html.haml",
    "content": "- content_for :page_title do\n  = t('admin.domain_blocks.show.title', domain: @domain_block.domain)\n\n= simple_form_for @domain_block, url: admin_domain_block_path(@domain_block), method: :delete do |f|\n\n  - unless (@domain_block.noop?)\n    %p= t(\".retroactive.#{@domain_block.severity}\")\n    %p.hint= t(:affected_accounts,\n      scope: [:admin, :domain_blocks, :show],\n      count: @domain_block.affected_accounts_count)\n\n  .actions\n    = f.button :button, t('.undo'), type: :submit\n"
  },
  {
    "path": "app/views/admin/email_domain_blocks/_email_domain_block.html.haml",
    "content": "%tr\n  %td\n    %samp= email_domain_block.domain\n  %td\n    = table_link_to 'trash', t('admin.email_domain_blocks.delete'), admin_email_domain_block_path(email_domain_block), method: :delete\n"
  },
  {
    "path": "app/views/admin/email_domain_blocks/index.html.haml",
    "content": "- content_for :page_title do\n  = t('admin.email_domain_blocks.title')\n\n.table-wrapper\n  %table.table\n    %thead\n      %tr\n        %th= t('admin.email_domain_blocks.domain')\n        %th\n    %tbody\n      = render @email_domain_blocks\n\n= paginate @email_domain_blocks\n= link_to t('admin.email_domain_blocks.add_new'), new_admin_email_domain_block_path, class: 'button'\n"
  },
  {
    "path": "app/views/admin/email_domain_blocks/new.html.haml",
    "content": "- content_for :page_title do\n  = t('.title')\n\n= simple_form_for @email_domain_block, url: admin_email_domain_blocks_path do |f|\n  = render 'shared/error_messages', object: @email_domain_block\n\n  .fields-group\n    = f.input :domain, wrapper: :with_label, label: t('admin.email_domain_blocks.domain')\n\n  .actions\n    = f.button :button, t('.create'), type: :submit\n"
  },
  {
    "path": "app/views/admin/followers/index.html.haml",
    "content": "- content_for :page_title do\n  = t('admin.followers.title', acct: @account.acct)\n\n.filters\n  .filter-subset\n    %strong= t('admin.accounts.location.title')\n    %ul\n      %li= link_to t('admin.accounts.location.local'), admin_account_followers_path(@account.id), class: 'selected'\n  .back-link{ style: 'flex: 1 1 auto; text-align: right' }\n    = link_to admin_account_path(@account.id) do\n      = fa_icon 'chevron-left fw'\n      = t('admin.followers.back_to_account')\n\n%hr.spacer/\n\n.table-wrapper\n  %table.table\n    %thead\n      %tr\n        %th= t('admin.accounts.username')\n        %th= t('admin.accounts.role')\n        %th= t('admin.accounts.most_recent_ip')\n        %th= t('admin.accounts.most_recent_activity')\n        %th\n    %tbody\n      = render partial: 'admin/accounts/account', collection: @followers\n\n= paginate @followers\n"
  },
  {
    "path": "app/views/admin/instances/index.html.haml",
    "content": "- content_for :page_title do\n  = t('admin.instances.title')\n\n.filters\n  .filter-subset\n    %strong= t('admin.instances.moderation.title')\n    %ul\n      %li= filter_link_to t('admin.instances.moderation.all'), limited: nil\n      %li= filter_link_to t('admin.instances.moderation.limited'), limited: '1'\n\n  %div{ style: 'flex: 1 1 auto; text-align: right' }\n    = link_to t('admin.domain_blocks.add_new'), new_admin_domain_block_path, class: 'button'\n\n= form_tag admin_instances_url, method: 'GET', class: 'simple_form' do\n  .fields-group\n    - Admin::FilterHelper::INSTANCES_FILTERS.each do |key|\n      - if params[key].present?\n        = hidden_field_tag key, params[key]\n\n    - %i(by_domain).each do |key|\n      .input.string.optional\n        = text_field_tag key, params[key], class: 'string optional', placeholder: I18n.t(\"admin.instances.#{key}\")\n\n    .actions\n      %button= t('admin.accounts.search')\n      = link_to t('admin.accounts.reset'), admin_instances_path, class: 'button negative'\n\n%hr.spacer/\n\n- @instances.each do |instance|\n  .directory__tag\n    = link_to admin_instance_path(instance) do\n      %h4\n        = instance.domain\n        %small\n          = t('admin.instances.known_accounts', count: instance.cached_accounts_count)\n\n          - if instance.domain_block\n            - if !instance.domain_block.noop?\n              &bull;\n              = t(\"admin.domain_blocks.severity.#{instance.domain_block.severity}\")\n            - if instance.domain_block.reject_media?\n              &bull;\n              = t('admin.domain_blocks.rejecting_media')\n            - if instance.domain_block.reject_reports?\n              &bull;\n              = t('admin.domain_blocks.rejecting_reports')\n\n      .avatar-stack\n        - instance.cached_sample_accounts.each do |account|\n          = image_tag current_account&.user&.setting_auto_play_gif ? account.avatar_original_url : account.avatar_static_url, width: 48, height: 48, alt: '', class: 'account__avatar'\n\n= paginate paginated_instances\n"
  },
  {
    "path": "app/views/admin/instances/show.html.haml",
    "content": "- content_for :page_title do\n  = @instance.domain\n\n.dashboard__counters\n  %div\n    %div\n      .dashboard__counters__num= number_with_delimiter @following_count\n      .dashboard__counters__label= t 'admin.instances.total_followed_by_them'\n  %div\n    %div\n      .dashboard__counters__num= number_with_delimiter @followers_count\n      .dashboard__counters__label= t 'admin.instances.total_followed_by_us'\n  %div\n    %div\n      .dashboard__counters__num= number_to_human_size @media_storage\n      .dashboard__counters__label= t 'admin.instances.total_storage'\n  %div\n    %div\n      .dashboard__counters__num= number_with_delimiter @blocks_count\n      .dashboard__counters__label= t 'admin.instances.total_blocked_by_us'\n  %div\n    %div\n      .dashboard__counters__num= number_with_delimiter @reports_count\n      .dashboard__counters__label= t 'admin.instances.total_reported'\n  %div\n    %div\n      .dashboard__counters__num\n        - if @available\n          = fa_icon 'check'\n        - else\n          = fa_icon 'times'\n      .dashboard__counters__label= t 'admin.instances.delivery_available'\n\n%hr.spacer/\n\n%div{ style: 'overflow: hidden' }\n  %div{ style: 'float: left' }\n    = link_to t('admin.accounts.title'), admin_accounts_path(remote: '1', by_domain: @instance.domain), class: 'button'\n\n  %div{ style: 'float: right' }\n    - if @domain_block\n      = link_to t('admin.domain_blocks.undo'), admin_domain_block_path(@domain_block), class: 'button'\n    - else\n      = link_to t('admin.domain_blocks.add_new'), new_admin_domain_block_path(_domain: @instance.domain), class: 'button'\n"
  },
  {
    "path": "app/views/admin/invites/_invite.html.haml",
    "content": "%tr\n  %td\n    .input-copy\n      .input-copy__wrapper\n        %input{ type: :text, maxlength: '999', spellcheck: 'false', readonly: 'true', value: public_invite_url(invite_code: invite.code) }\n      %button{ type: :button }= t('generic.copy')\n\n  %td\n    .name-tag\n      = image_tag invite.user.account.avatar.url(:original), alt: '', width: 16, height: 16, class: 'avatar'\n      %span.username= invite.user.account.username\n\n  - if invite.valid_for_use?\n    %td\n      = fa_icon 'user fw'\n      = invite.uses\n      = \" / #{invite.max_uses}\" unless invite.max_uses.nil?\n    %td\n      - if invite.expires_at.nil?\n        ∞\n      - else\n        %time.formatted{ datetime: invite.expires_at.iso8601, title: l(invite.expires_at) }\n          = l invite.expires_at\n  - else\n    %td{ colspan: 2 }\n      = t('invites.expired')\n\n  %td\n    - if invite.valid_for_use? && policy(invite).destroy?\n      = table_link_to 'times', t('invites.delete'), admin_invite_path(invite), method: :delete\n"
  },
  {
    "path": "app/views/admin/invites/index.html.haml",
    "content": "- content_for :page_title do\n  = t('admin.invites.title')\n\n.filters\n  .filter-subset\n    %strong= t('admin.invites.filter.title')\n    %ul\n      %li= filter_link_to t('admin.invites.filter.all'), available: nil, expired: nil\n      %li= filter_link_to t('admin.invites.filter.available'), available: 1, expired: nil\n      %li= filter_link_to t('admin.invites.filter.expired'), available: nil, expired: 1\n\n%hr.spacer/\n\n- if policy(:invite).create?\n  %p= t('invites.prompt')\n\n  = render 'invites/form'\n\n  %hr.spacer/\n\n.table-wrapper.simple_form\n  %table.table.table--invites\n    %thead\n      %tr\n        %th\n        %th\n        %th= t('invites.table.uses')\n        %th= t('invites.table.expires_at')\n        %th\n    %tbody\n      = render @invites\n\n= paginate @invites\n\n- if policy(:invite).deactivate_all?\n  = link_to t('admin.invites.deactivate_all'), deactivate_all_admin_invites_path, method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button'\n"
  },
  {
    "path": "app/views/admin/pending_accounts/_account.html.haml",
    "content": ".batch-table__row\n  %label.batch-table__row__select.batch-table__row__select--aligned.batch-checkbox\n    = f.check_box :account_ids, { multiple: true, include_hidden: false }, account.id\n  .batch-table__row__content.pending-account\n    .pending-account__header\n      = link_to admin_account_path(account.id) do\n        %strong= account.user_email\n        = \"(@#{account.username})\"\n      %br/\n      = account.user_current_sign_in_ip\n      •\n      = t 'admin.accounts.time_in_queue', time: time_ago_in_words(account.user&.created_at)\n\n    - if account.user&.invite_request&.text&.present?\n      .pending-account__body\n        %p= account.user&.invite_request&.text\n"
  },
  {
    "path": "app/views/admin/pending_accounts/index.html.haml",
    "content": "- content_for :page_title do\n  = t('admin.pending_accounts.title', count: User.pending.count)\n\n- content_for :header_tags do\n  = javascript_pack_tag 'admin', integrity: true, async: true, crossorigin: 'anonymous'\n\n= form_for(@form, url: batch_admin_pending_accounts_path) do |f|\n  = hidden_field_tag :page, params[:page] || 1\n\n  .batch-table\n    .batch-table__toolbar\n      %label.batch-table__toolbar__select.batch-checkbox-all\n        = check_box_tag :batch_checkbox_all, nil, false\n      .batch-table__toolbar__actions\n        = f.button safe_join([fa_icon('check'), t('admin.accounts.approve')]), name: :approve, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }\n\n        = f.button safe_join([fa_icon('times'), t('admin.accounts.reject')]), name: :reject, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }\n    .batch-table__body\n      - if @accounts.empty?\n        = nothing_here 'nothing-here--under-tabs'\n      - else\n        = render partial: 'account', collection: @accounts, locals: { f: f }\n\n= paginate @accounts\n\n%hr.spacer/\n\n%div{ style: 'overflow: hidden' }\n  %div{ style: 'float: right' }\n    = link_to t('admin.accounts.reject_all'), reject_all_admin_pending_accounts_path, method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button button--destructive'\n\n  %div\n    = link_to t('admin.accounts.approve_all'), approve_all_admin_pending_accounts_path, method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button'\n"
  },
  {
    "path": "app/views/admin/relays/_relay.html.haml",
    "content": "%tr\n  %td\n    %samp= relay.inbox_url\n  %td\n    - if relay.accepted?\n      %span.positive-hint\n        = fa_icon('check')\n        = ' '\n        = t 'admin.relays.enabled'\n    - elsif relay.pending?\n      = fa_icon('hourglass')\n      = ' '\n      = t 'admin.relays.pending'\n    - else\n      %span.negative-hint\n        = fa_icon('times')\n        = ' '\n        = t 'admin.relays.disabled'\n  %td\n    - if relay.accepted?\n      = table_link_to 'power-off', t('admin.relays.disable'), disable_admin_relay_path(relay), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }\n    - elsif !relay.pending?\n      = table_link_to 'power-off', t('admin.relays.enable'), enable_admin_relay_path(relay), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }\n\n    = table_link_to 'times', t('admin.relays.delete'), admin_relay_path(relay), method: :delete, data: { confirm: t('admin.accounts.are_you_sure') }\n"
  },
  {
    "path": "app/views/admin/relays/index.html.haml",
    "content": "- content_for :page_title do\n  = t('admin.relays.title')\n\n.simple_form\n  %p.hint= t('admin.relays.description_html')\n  = link_to @relays.empty? ? t('admin.relays.setup') : t('admin.relays.add_new'), new_admin_relay_path, class: 'block-button'\n\n- unless @relays.empty?\n  %hr.spacer\n\n  .table-wrapper\n    %table.table\n      %thead\n        %tr\n          %th= t('admin.relays.inbox_url')\n          %th= t('admin.relays.status')\n          %th\n      %tbody\n        = render @relays\n\n"
  },
  {
    "path": "app/views/admin/relays/new.html.haml",
    "content": "- content_for :page_title do\n  = t('admin.relays.add_new')\n\n= simple_form_for @relay, url: admin_relays_path do |f|\n  = render 'shared/error_messages', object: @relay\n\n  .field-group\n    = f.input :inbox_url, as: :string, wrapper: :with_block_label\n\n  .actions\n    = f.button :button, t('admin.relays.save_and_enable'), type: :submit\n\n  %p.hint.subtle-hint= t('admin.relays.enable_hint')\n"
  },
  {
    "path": "app/views/admin/report_notes/_report_note.html.haml",
    "content": ".speech-bubble\n  .speech-bubble__bubble\n    = simple_format(h(report_note.content))\n  .speech-bubble__owner\n    = admin_account_link_to report_note.account\n    %time.formatted{ datetime: report_note.created_at.iso8601 }= l report_note.created_at\n    = table_link_to 'trash', t('admin.reports.notes.delete'), admin_report_note_path(report_note), method: :delete if can?(:destroy, report_note)\n"
  },
  {
    "path": "app/views/admin/reports/_action_log.html.haml",
    "content": ".speech-bubble.positive\n  .speech-bubble__bubble\n    = t(\"admin.action_logs.actions.#{action_log.action}_#{action_log.target_type.underscore}\", name: content_tag(:span, action_log.account.username, class: 'username'), target: content_tag(:span, log_target(action_log), class: 'target')).html_safe\n  .speech-bubble__owner\n    = admin_account_link_to(action_log.account)\n    %time.formatted{ datetime: action_log.created_at.iso8601 }= l action_log.created_at\n"
  },
  {
    "path": "app/views/admin/reports/_status.html.haml",
    "content": ".batch-table__row\n  %label.batch-table__row__select.batch-checkbox\n    = f.check_box :status_ids, { multiple: true, include_hidden: false }, status.id\n  .batch-table__row__content\n    .status__content><\n      - if status.proper.spoiler_text.blank?\n        = Formatter.instance.format(status.proper, custom_emojify: true)\n      - else\n        %details<\n          %summary><\n            %strong> Content warning: #{Formatter.instance.format_spoiler(status.proper)}\n          = Formatter.instance.format(status.proper, custom_emojify: true)\n\n    - unless status.proper.media_attachments.empty?\n      - if status.proper.media_attachments.first.video?\n        - video = status.proper.media_attachments.first\n        = react_component :video, src: video.file.url(:original), preview: video.file.url(:small), sensitive: !current_account&.user&.show_all_media? && status.proper.sensitive? || current_account&.user&.hide_all_media?, width: 610, height: 343, inline: true, alt: video.description\n      - else\n        = react_component :media_gallery, height: 343, sensitive: !current_account&.user&.show_all_media? && status.sensitive? || current_account&.user&.hide_all_media?, 'autoPlayGif': current_account&.user&.setting_auto_play_gif, media: status.proper.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json }\n\n    .detailed-status__meta\n      = link_to TagManager.instance.url_for(status), class: 'detailed-status__datetime', target: stream_link_target, rel: 'noopener' do\n        %time.formatted{ datetime: status.created_at.iso8601, title: l(status.created_at) }= l(status.created_at)\n      ·\n      - if status.reblog?\n        = fa_icon('retweet fw')\n        = t('statuses.boosted_from_html', acct_link: admin_account_inline_link_to(status.proper.account))\n      - else\n        = fa_visibility_icon(status)\n        = t(\"statuses.visibilities.#{status.visibility}\")\n      - if status.proper.sensitive?\n        ·\n        = fa_icon('eye-slash fw')\n        = t('stream_entries.sensitive_content')\n"
  },
  {
    "path": "app/views/admin/reports/index.html.haml",
    "content": "- content_for :page_title do\n  = t('admin.reports.title')\n\n.filters\n  .filter-subset\n    %strong= t('admin.reports.status')\n    %ul\n      %li= filter_link_to t('admin.reports.unresolved'), resolved: nil\n      %li= filter_link_to t('admin.reports.resolved'), resolved: '1'\n\n- @reports.group_by(&:target_account_id).each do |target_account_id, reports|\n  - target_account = reports.first.target_account\n  .report-card\n    .report-card__profile\n      = account_link_to target_account, '', size: 36, path: admin_account_path(target_account.id)\n      .report-card__profile__stats\n        = link_to pluralize(target_account.targeted_moderation_notes.count, t('admin.reports.account.note')), admin_account_path(target_account.id)\n        %br/\n        - if target_account.suspended?\n          %span.red= t('admin.accounts.suspended')\n        - elsif target_account.silenced?\n          %span.red= t('admin.accounts.silenced')\n        - elsif target_account.user&.disabled?\n          %span.red= t('admin.accounts.disabled')\n        - else\n          %span.neutral= t('admin.accounts.no_limits_imposed')\n    .report-card__summary\n      - reports.each do |report|\n        .report-card__summary__item\n          .report-card__summary__item__reported-by\n            - if report.account.local?\n              = admin_account_link_to report.account\n            - else\n              = report.account.domain\n          .report-card__summary__item__content\n            = link_to admin_report_path(report) do\n              .one-line= report.comment.presence || t('admin.reports.comment.none')\n\n              %span.report-card__summary__item__content__icon{ title: t('admin.accounts.statuses') }\n                = fa_icon('comment')\n                = report.statuses.count\n\n              %span.report-card__summary__item__content__icon{ title: t('admin.accounts.media_attachments') }\n                = fa_icon('camera')\n                = report.media_attachments.count\n\n          .report-card__summary__item__assigned\n            - if report.assigned_account.present?\n              = admin_account_link_to report.assigned_account\n            - else\n              \\-\n= paginate @reports\n"
  },
  {
    "path": "app/views/admin/reports/show.html.haml",
    "content": "- content_for :header_tags do\n  = javascript_pack_tag 'admin', integrity: true, async: true, crossorigin: 'anonymous'\n\n- content_for :page_title do\n  = t('admin.reports.report', id: @report.id)\n\n%div{ style: 'overflow: hidden; margin-bottom: 20px' }\n  - if @report.unresolved?\n    %div{ style: 'float: right' }\n      - if @report.target_account.local?\n        = link_to t('admin.accounts.warn'), new_admin_account_action_path(@report.target_account_id, type: 'none', report_id: @report.id), class: 'button'\n        = link_to t('admin.accounts.disable'), new_admin_account_action_path(@report.target_account_id, type: 'disable', report_id: @report.id), class: 'button button--destructive'\n      = link_to t('admin.accounts.silence'), new_admin_account_action_path(@report.target_account_id, type: 'silence', report_id: @report.id), class: 'button button--destructive'\n      = link_to t('admin.accounts.perform_full_suspension'), new_admin_account_action_path(@report.target_account_id, type: 'suspend', report_id: @report.id), class: 'button button--destructive'\n    %div{ style: 'float: left' }\n      = link_to t('admin.reports.mark_as_resolved'), resolve_admin_report_path(@report), method: :post, class: 'button'\n  - else\n    = link_to t('admin.reports.mark_as_unresolved'), reopen_admin_report_path(@report), method: :post, class: 'button'\n\n%hr.spacer\n\n.table-wrapper\n  %table.table.inline-table\n    %tbody\n      %tr\n        %th= t('admin.reports.reported_account')\n        %td= admin_account_link_to @report.target_account\n        %td= table_link_to 'flag', pluralize(@report.target_account.targeted_reports.count, t('admin.reports.account.report')), admin_reports_path(target_account_id: @report.target_account.id)\n        %td= table_link_to 'file', pluralize(@report.target_account.targeted_moderation_notes.count, t('admin.reports.account.note')), admin_reports_path(target_account_id: @report.target_account.id)\n      %tr\n        %th= t('admin.reports.reported_by')\n        - if @report.account.local?\n          %td= admin_account_link_to @report.account\n          %td= table_link_to 'flag', pluralize(@report.account.targeted_reports.count, t('admin.reports.account.report')), admin_reports_path(target_account_id: @report.account.id)\n          %td= table_link_to 'file', pluralize(@report.account.targeted_moderation_notes.count, t('admin.reports.account.note')), admin_reports_path(target_account_id: @report.account.id)\n        - else\n          %td{ colspan: 3 }= @report.account.domain\n      %tr\n        %th= t('admin.reports.created_at')\n        %td{ colspan: 3 }\n          %time.formatted{ datetime: @report.created_at.iso8601 }\n      %tr\n        %th= t('admin.reports.updated_at')\n        %td{ colspan: 3 }\n          %time.formatted{ datetime: @report.updated_at.iso8601 }\n      %tr\n        %th= t('admin.reports.status')\n        %td\n          - if @report.action_taken?\n            = t('admin.reports.resolved')\n          - else\n            = t('admin.reports.unresolved')\n        %td{ colspan: 2 }\n          - if @report.action_taken?\n            = table_link_to 'envelope-open', t('admin.reports.reopen'), admin_report_path(@report, outcome: 'reopen'), method: :put\n      - if !@report.action_taken_by_account.nil?\n        %tr\n          %th= t('admin.reports.action_taken_by')\n          %td{ colspan: 3 }\n            = admin_account_link_to @report.action_taken_by_account\n      - else\n        %tr\n          %th= t('admin.reports.assigned')\n          %td\n            - if @report.assigned_account.nil?\n              \\-\n            - else\n              = admin_account_link_to @report.assigned_account\n          %td\n            - if @report.assigned_account != current_user.account\n              = table_link_to 'user', t('admin.reports.assign_to_self'), assign_to_self_admin_report_path(@report), method: :post\n          %td\n            - if !@report.assigned_account.nil?\n              = table_link_to 'trash', t('admin.reports.unassign'), unassign_admin_report_path(@report), method: :post\n\n%hr.spacer\n\n.speech-bubble\n  .speech-bubble__bubble= simple_format(@report.comment.presence || t('admin.reports.comment.none'))\n  .speech-bubble__owner\n    - if @report.account.local?\n      = admin_account_link_to @report.account\n    - else\n      = @report.account.domain\n      %br/\n    %time.formatted{ datetime: @report.created_at.iso8601 }\n\n- unless @report.statuses.empty?\n  %hr.spacer/\n\n  = form_for(@form, url: admin_report_reported_statuses_path(@report.id)) do |f|\n    .batch-table\n      .batch-table__toolbar\n        %label.batch-table__toolbar__select.batch-checkbox-all\n          = check_box_tag :batch_checkbox_all, nil, false\n        .batch-table__toolbar__actions\n          = f.button safe_join([fa_icon('eye-slash'), t('admin.statuses.batch.nsfw_on')]), name: :nsfw_on, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }\n          = f.button safe_join([fa_icon('eye'), t('admin.statuses.batch.nsfw_off')]), name: :nsfw_off, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }\n          = f.button safe_join([fa_icon('trash'), t('admin.statuses.batch.delete')]), name: :delete, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }\n      .batch-table__body\n        = render partial: 'admin/reports/status', collection: @report.statuses, locals: { f: f }\n\n%hr.spacer/\n\n- @report_notes.each do |item|\n  - if item.is_a?(Admin::ActionLog)\n    = render partial: 'action_log', locals: { action_log: item }\n  - else\n    = render item\n\n= simple_form_for @report_note, url: admin_report_notes_path do |f|\n  = render 'shared/error_messages', object: @report_note\n  = f.input :report_id, as: :hidden\n\n  .field-group\n    = f.input :content, placeholder: t('admin.reports.notes.placeholder'), rows: 6\n\n  .actions\n    - if @report.unresolved?\n      = f.button :button, t('admin.reports.notes.create_and_resolve'), name: :create_and_resolve, type: :submit\n    - else\n      = f.button :button, t('admin.reports.notes.create_and_unresolve'), name: :create_and_unresolve, type: :submit\n    = f.button :button, t('admin.reports.notes.create'), type: :submit\n"
  },
  {
    "path": "app/views/admin/settings/edit.html.haml",
    "content": "- content_for :page_title do\n  = t('admin.settings.title')\n\n= simple_form_for @admin_settings, url: admin_settings_path, html: { method: :patch } do |f|\n  = render 'shared/error_messages', object: @admin_settings\n\n  .fields-group\n    = f.input :site_title, wrapper: :with_label, label: t('admin.settings.site_title')\n\n  .fields-row\n    .fields-row__column.fields-row__column-6.fields-group\n      = f.input :theme, collection: Themes.instance.names, label_method: lambda { |theme| I18n.t(\"themes.#{theme}\", default: theme) }, wrapper: :with_label, include_blank: false\n    .fields-row__column.fields-row__column-6.fields-group\n      = f.input :registrations_mode, collection: %w(open approved none), wrapper: :with_label, label: t('admin.settings.registrations_mode.title'), include_blank: false, label_method: lambda { |mode| I18n.t(\"admin.settings.registrations_mode.modes.#{mode}\") }\n\n  .fields-row\n    .fields-row__column.fields-row__column-6.fields-group\n      = f.input :site_contact_username, wrapper: :with_label, label: t('admin.settings.contact_information.username')\n    .fields-row__column.fields-row__column-6.fields-group\n      = f.input :site_contact_email, wrapper: :with_label, label: t('admin.settings.contact_information.email')\n\n  .fields-group\n    = f.input :max_bio_chars, as: :integer, wrapper: :with_label, label: t('admin.settings.max_bio_chars.title'), hint: t('admin.settings.max_bio_chars.desc_html')\n\n  .fields-group\n    = f.input :max_toot_chars, as: :integer, wrapper: :with_label, label: t('admin.settings.max_toot_chars.title'), hint: t('admin.settings.max_toot_chars.desc_html')\n\n  .fields-group\n    = f.input :site_description, wrapper: :with_block_label, as: :text, label: t('admin.settings.site_description.title'), hint: t('admin.settings.site_description.desc_html'), input_html: { rows: 4 }\n\n  .fields-group\n    = f.input :site_short_description, wrapper: :with_block_label, as: :text, label: t('admin.settings.site_short_description.title'), hint: t('admin.settings.site_short_description.desc_html'), input_html: { rows: 2 }\n\n  .fields-row\n    .fields-row__column.fields-row__column-6.fields-group\n      = f.input :thumbnail, as: :file, wrapper: :with_block_label, label: t('admin.settings.thumbnail.title'), hint: t('admin.settings.thumbnail.desc_html')\n    .fields-row__column.fields-row__column-6.fields-group\n      = f.input :hero, as: :file, wrapper: :with_block_label, label: t('admin.settings.hero.title'), hint: t('admin.settings.hero.desc_html')\n\n  .fields-row\n    .fields-row__column.fields-row__column-6.fields-group\n      = f.input :mascot, as: :file, wrapper: :with_block_label, label: t('admin.settings.mascot.title'), hint: t('admin.settings.mascot.desc_html')\n\n  %hr.spacer/\n\n  .fields-group\n    = f.input :bootstrap_timeline_accounts, wrapper: :with_block_label, label: t('admin.settings.bootstrap_timeline_accounts.title'), hint: t('admin.settings.bootstrap_timeline_accounts.desc_html')\n\n  %hr.spacer/\n\n  .fields-group\n    = f.input :timeline_preview, as: :boolean, wrapper: :with_label, label: t('admin.settings.timeline_preview.title'), hint: t('admin.settings.timeline_preview.desc_html')\n\n  .fields-group\n    = f.input :show_known_fediverse_at_about_page, as: :boolean, wrapper: :with_label, label: t('admin.settings.show_known_fediverse_at_about_page.title'), hint: t('admin.settings.show_known_fediverse_at_about_page.desc_html')\n\n  .fields-group\n    = f.input :show_staff_badge, as: :boolean, wrapper: :with_label, label: t('admin.settings.show_staff_badge.title'), hint: t('admin.settings.show_staff_badge.desc_html')\n\n  .fields-group\n    = f.input :open_deletion, as: :boolean, wrapper: :with_label, label: t('admin.settings.registrations.deletion.title'), hint: t('admin.settings.registrations.deletion.desc_html')\n\n  .fields-group\n    = f.input :activity_api_enabled, as: :boolean, wrapper: :with_label, label: t('admin.settings.activity_api_enabled.title'), hint: t('admin.settings.activity_api_enabled.desc_html')\n\n  .fields-group\n    = f.input :peers_api_enabled, as: :boolean, wrapper: :with_label, label: t('admin.settings.peers_api_enabled.title'), hint: t('admin.settings.peers_api_enabled.desc_html')\n\n  .fields-group\n    = f.input :preview_sensitive_media, as: :boolean, wrapper: :with_label, label: t('admin.settings.preview_sensitive_media.title'), hint: t('admin.settings.preview_sensitive_media.desc_html')\n\n  .fields-group\n    = f.input :profile_directory, as: :boolean, wrapper: :with_label, label: t('admin.settings.profile_directory.title'), hint: t('admin.settings.profile_directory.desc_html')\n\n  %hr.spacer/\n\n  .fields-group\n    = f.input :min_invite_role, wrapper: :with_label, collection: %i(disabled user moderator admin), label: t('admin.settings.registrations.min_invite_role.title'), label_method: lambda { |role| role == :disabled ? t('admin.settings.registrations.min_invite_role.disabled') : t(\"admin.accounts.roles.#{role}\") }, include_blank: false, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li'\n\n  .fields-group\n    = f.input :closed_registrations_message, as: :text, wrapper: :with_block_label, label: t('admin.settings.registrations.closed_message.title'), hint: t('admin.settings.registrations.closed_message.desc_html'), input_html: { rows: 8 }\n    = f.input :site_extended_description, wrapper: :with_block_label, as: :text, label: t('admin.settings.site_description_extended.title'), hint: t('admin.settings.site_description_extended.desc_html'), input_html: { rows: 8 }\n    = f.input :site_terms, wrapper: :with_block_label, as: :text, label: t('admin.settings.site_terms.title'), hint: t('admin.settings.site_terms.desc_html'), input_html: { rows: 8 }\n    = f.input :custom_css, wrapper: :with_block_label, as: :text, input_html: { rows: 8 }, label: t('admin.settings.custom_css.title'), hint: t('admin.settings.custom_css.desc_html')\n\n  .actions\n    = f.button :button, t('generic.save_changes'), type: :submit\n"
  },
  {
    "path": "app/views/admin/statuses/index.html.haml",
    "content": "- content_for :header_tags do\n  = javascript_pack_tag 'admin', integrity: true, async: true, crossorigin: 'anonymous'\n\n- content_for :page_title do\n  = t('admin.statuses.title')\n  \\-\n  = \"@#{@account.acct}\"\n\n.filters\n  .filter-subset\n    %strong= t('admin.statuses.media.title')\n    %ul\n      %li= link_to t('admin.statuses.no_media'), admin_account_statuses_path(@account.id, current_params.merge(media: nil)), class: !params[:media] && 'selected'\n      %li= link_to t('admin.statuses.with_media'), admin_account_statuses_path(@account.id, current_params.merge(media: true)), class: params[:media] && 'selected'\n  .back-link{ style: 'flex: 1 1 auto; text-align: right' }\n    = link_to admin_account_path(@account.id) do\n      = fa_icon 'chevron-left fw'\n      = t('admin.statuses.back_to_account')\n\n%hr.spacer/\n\n= form_for(@form, url: admin_account_statuses_path(@account.id)) do |f|\n  = hidden_field_tag :page, params[:page]\n  = hidden_field_tag :media, params[:media]\n\n  .batch-table\n    .batch-table__toolbar\n      %label.batch-table__toolbar__select.batch-checkbox-all\n        = check_box_tag :batch_checkbox_all, nil, false\n      .batch-table__toolbar__actions\n        = f.button safe_join([fa_icon('eye-slash'), t('admin.statuses.batch.nsfw_on')]), name: :nsfw_on, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }\n        = f.button safe_join([fa_icon('eye'), t('admin.statuses.batch.nsfw_off')]), name: :nsfw_off, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }\n        = f.button safe_join([fa_icon('trash'), t('admin.statuses.batch.delete')]), name: :delete, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }\n    .batch-table__body\n      = render partial: 'admin/reports/status', collection: @statuses, locals: { f: f }\n\n= paginate @statuses\n"
  },
  {
    "path": "app/views/admin/statuses/show.html.haml",
    "content": "- content_for :page_title do\n  = t('admin.statuses.title')\n  \\-\n  = \"@#{@account.acct}\"\n\n.filters\n  .back-link{ style: 'flex: 1 1 auto; text-align: right' }\n    = link_to admin_account_path(@account.id) do\n      %i.fa.fa-chevron-left.fa-fw\n      = t('admin.statuses.back_to_account')\n\n%hr.spacer/\n\n= form_for(@form, url: admin_account_statuses_path(@account.id)) do |f|\n  = hidden_field_tag :page, params[:page]\n  = hidden_field_tag :media, params[:media]\n\n  .batch-table\n    .batch-table__toolbar\n      %label.batch-table__toolbar__select.batch-checkbox-all\n        = check_box_tag :batch_checkbox_all, nil, false\n      .batch-table__toolbar__actions\n        = f.button safe_join([fa_icon('eye-slash'), t('admin.statuses.batch.nsfw_on')]), name: :nsfw_on, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }\n        = f.button safe_join([fa_icon('eye'), t('admin.statuses.batch.nsfw_off')]), name: :nsfw_off, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }\n        = f.button safe_join([fa_icon('trash'), t('admin.statuses.batch.delete')]), name: :delete, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }\n    .batch-table__body\n      = render partial: 'admin/reports/status', collection: @statuses, locals: { f: f }\n"
  },
  {
    "path": "app/views/admin/subscriptions/_subscription.html.haml",
    "content": "%tr\n  %td\n    %samp= subscription.account.acct\n  %td\n    %samp= subscription.callback_url\n  %td\n    - if subscription.confirmed?\n      %i.fa.fa-check\n  %td{ style: \"color: #{subscription.expired? ? 'red' : 'inherit'};\" }\n    %time.time-ago{ datetime: subscription.expires_at.iso8601, title: l(subscription.expires_at) }\n      = precede subscription.expired? ? '-' : '' do\n        = time_ago_in_words(subscription.expires_at)\n  %td\n    - if subscription.last_successful_delivery_at?\n      %time.formatted{ datetime: subscription.last_successful_delivery_at.iso8601, title: l(subscription.last_successful_delivery_at) }\n        = l subscription.last_successful_delivery_at\n    - else\n      %i.fa.fa-times\n"
  },
  {
    "path": "app/views/admin/subscriptions/index.html.haml",
    "content": "- content_for :page_title do\n  = t('admin.subscriptions.title')\n\n.table-wrapper\n  %table.table\n    %thead\n      %tr\n        %th= t('admin.subscriptions.topic')\n        %th= t('admin.subscriptions.callback_url')\n        %th= t('admin.subscriptions.confirmed')\n        %th= t('admin.subscriptions.expires_in')\n        %th= t('admin.subscriptions.last_delivery')\n    %tbody\n      = render @subscriptions\n\n= paginate @subscriptions\n"
  },
  {
    "path": "app/views/admin/tags/_tag.html.haml",
    "content": "%tr\n  %td\n    = link_to explore_hashtag_path(tag) do\n      = fa_icon 'hashtag'\n      = tag.name\n  %td\n    = t('directories.people', count: tag.accounts_count)\n  %td\n    - if tag.hidden?\n      = table_link_to 'eye', t('admin.tags.unhide'), unhide_admin_tag_path(tag.id, **@filter_params), method: :post\n    - else\n      = table_link_to 'eye-slash', t('admin.tags.hide'), hide_admin_tag_path(tag.id, **@filter_params), method: :post\n"
  },
  {
    "path": "app/views/admin/tags/index.html.haml",
    "content": "- content_for :page_title do\n  = t('admin.tags.title')\n\n.filters\n  .filter-subset\n    %strong= t('admin.reports.status')\n    %ul\n      %li= filter_link_to t('admin.tags.visible'), hidden: nil\n      %li= filter_link_to t('admin.tags.hidden'), hidden: '1'\n\n.table-wrapper\n  %table.table\n    %thead\n      %tr\n        %th= t('admin.tags.name')\n        %th= t('admin.tags.accounts')\n        %th\n    %tbody\n      = render @tags\n"
  },
  {
    "path": "app/views/admin/warning_presets/edit.html.haml",
    "content": "- content_for :page_title do\n  = t('admin.warning_presets.edit_preset')\n\n= simple_form_for @warning_preset, url: admin_warning_preset_path(@warning_preset) do |f|\n  = render 'shared/error_messages', object: @warning_preset\n\n  .fields-group\n    = f.input :text, wrapper: :with_block_label\n\n  .actions\n    = f.button :button, t('generic.save_changes'), type: :submit\n"
  },
  {
    "path": "app/views/admin/warning_presets/index.html.haml",
    "content": "- content_for :page_title do\n  = t('admin.warning_presets.title')\n\n- if can? :create, :account_warning_preset\n  = simple_form_for @warning_preset, url: admin_warning_presets_path do |f|\n    = render 'shared/error_messages', object: @warning_preset\n\n    .fields-group\n      = f.input :text, wrapper: :with_block_label\n\n    .actions\n      = f.button :button, t('admin.warning_presets.add_new'), type: :submit\n\n  %hr.spacer/\n\n- unless @warning_presets.empty?\n  .table-wrapper\n    %table.table\n      %thead\n        %tr\n          %th= t('simple_form.labels.account_warning_preset.text')\n          %th\n      %tbody\n        - @warning_presets.each do |preset|\n          %tr\n            %td\n              = Formatter.instance.linkify(preset.text)\n            %td\n              = table_link_to 'pencil', t('admin.warning_presets.edit'), edit_admin_warning_preset_path(preset)\n              = table_link_to 'trash', t('admin.warning_presets.delete'), admin_warning_preset_path(preset), method: :delete, data: { confirm: t('admin.accounts.are_you_sure') }\n"
  },
  {
    "path": "app/views/admin_mailer/new_pending_account.text.erb",
    "content": "<%= raw t('application_mailer.salutation', name: display_name(@me)) %>\n\n<%= raw t('admin_mailer.new_pending_account.body') %>\n\n<%= @account.user_email %> (@<%= @account.username %>)\n<%= @account.user_current_sign_in_ip %>\n<% if @account.user&.invite_request&.text.present? %>\n\n<%= quote_wrap(@account.user&.invite_request&.text) %>\n<% end %>\n\n<%= raw t('application_mailer.view')%> <%= admin_pending_accounts_url %>\n"
  },
  {
    "path": "app/views/admin_mailer/new_report.text.erb",
    "content": "<%= raw t('application_mailer.salutation', name: display_name(@me)) %>\n\n<%= raw(@report.account.local? ? t('admin_mailer.new_report.body', target: @report.target_account.acct, reporter: @report.account.acct) : t('admin_mailer.new_report.body_remote', target: @report.target_account.acct, domain: @report.account.domain)) %>\n\n<%= raw t('application_mailer.view')%> <%= admin_report_url(@report) %>\n"
  },
  {
    "path": "app/views/application/_card.html.haml",
    "content": "- account_url = local_assigns[:admin] ? admin_account_path(account.id) : TagManager.instance.url_for(account)\n\n.card.h-card\n  = link_to account_url, target: '_blank', rel: 'noopener' do\n    .card__img\n      = image_tag account.header.url, alt: ''\n    .card__bar\n      .avatar\n        = image_tag account.avatar.url, alt: '', width: 48, height: 48, class: 'u-photo'\n\n      .display-name\n        %span{id: \"default_account_display_name\", style: \"display:none;\"}= account.username\n        %bdi\n          %strong.emojify.p-name= display_name(account, custom_emojify: true)\n        %span\n          = acct(account)\n          = fa_icon('lock') if account.locked?\n"
  },
  {
    "path": "app/views/application/_flashes.html.haml",
    "content": "- user_facing_flashes.each do |key, value|\n  .flash-message{ class: key }\n    %strong= value\n"
  },
  {
    "path": "app/views/application/_sidebar.html.haml",
    "content": ".hero-widget\n  .hero-widget__img\n    = image_tag @instance_presenter.hero&.file&.url || @instance_presenter.thumbnail&.file&.url || asset_pack_path('media/images/preview.jpg'), alt: @instance_presenter.site_title\n\n  .hero-widget__text\n    %p= @instance_presenter.site_short_description.html_safe.presence || @instance_presenter.site_description.html_safe.presence || t('about.generic_description', domain: site_hostname)\n"
  },
  {
    "path": "app/views/auth/confirmations/finish_signup.html.haml",
    "content": "- content_for :page_title do\n  = t('auth.confirm_email')\n\n= simple_form_for(current_user, as: 'user', url: finish_signup_path, html: { role: 'form'}) do |f|\n  - if @show_errors && current_user.errors.any?\n    #error_explanation\n      - current_user.errors.full_messages.each do |msg|\n        = msg\n        %br\n\n  .fields-group\n    = f.input :email, wrapper: :with_label, required: true, hint: false\n\n  .actions\n    = f.submit t('auth.confirm_email'), class: 'button'\n"
  },
  {
    "path": "app/views/auth/confirmations/new.html.haml",
    "content": "- content_for :page_title do\n  = t('auth.resend_confirmation')\n\n= simple_form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f|\n  = render 'shared/error_messages', object: resource\n\n  .fields-group\n    = f.input :email, autofocus: true, wrapper: :with_label, label: t('simple_form.labels.defaults.email'), input_html: { 'aria-label' => t('simple_form.labels.defaults.email') }, hint: false\n\n  .actions\n    = f.button :button, t('auth.resend_confirmation'), type: :submit\n\n.form-footer= render 'auth/shared/links'\n"
  },
  {
    "path": "app/views/auth/passwords/edit.html.haml",
    "content": "- content_for :page_title do\n  = t('auth.set_new_password')\n\n= simple_form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f|\n  = render 'shared/error_messages', object: resource\n\n  - if !use_seamless_external_login? || resource.encrypted_password.present?\n    = f.input :reset_password_token, as: :hidden\n\n    .fields-group\n      = f.input :password, wrapper: :with_label, autofocus: true, label: t('simple_form.labels.defaults.new_password'), input_html: { 'aria-label' => t('simple_form.labels.defaults.new_password'), :autocomplete => 'off' }, required: true\n    .fields-group\n      = f.input :password_confirmation, wrapper: :with_label, label: t('simple_form.labels.defaults.confirm_new_password'), input_html: { 'aria-label' => t('simple_form.labels.defaults.confirm_new_password'), :autocomplete => 'off' }, required: true\n\n    .actions\n      = f.button :button, t('auth.set_new_password'), type: :submit\n  - else\n    %p.hint= t('users.seamless_external_login')\n\n.form-footer= render 'auth/shared/links'\n"
  },
  {
    "path": "app/views/auth/passwords/new.html.haml",
    "content": "- content_for :page_title do\n  = t('auth.reset_password')\n\n= simple_form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f|\n  = render 'shared/error_messages', object: resource\n\n  .fields-group\n    = f.input :email, autofocus: true, wrapper: :with_label, label: t('simple_form.labels.defaults.email'), input_html: { 'aria-label' => t('simple_form.labels.defaults.email') }, hint: false\n\n  .actions\n    = f.button :button, t('auth.reset_password'), type: :submit\n\n.form-footer= render 'auth/shared/links'\n"
  },
  {
    "path": "app/views/auth/registrations/_sessions.html.haml",
    "content": "%h4= t 'sessions.title'\n%p.muted-hint= t 'sessions.explanation'\n\n.table-wrapper\n  %table.table.inline-table\n    %thead\n      %tr\n        %th= t 'sessions.browser'\n        %th= t 'sessions.ip'\n        %th= t 'sessions.activity'\n        %th\n    %tbody\n      - @sessions.each do |session|\n        %tr\n          %td\n            %span{ title: session.user_agent }<\n              = fa_icon \"#{session_device_icon(session)} fw\", 'aria-label' => session_device_icon(session)\n              = ' '\n              = t 'sessions.description', browser: t(\"sessions.browsers.#{session.browser}\", default: \"#{session.browser}\"), platform: t(\"sessions.platforms.#{session.platform}\", default: \"#{session.platform}\")\n          %td\n            %samp= session.ip\n          %td\n            - if current_session.session_id == session.session_id\n              = t 'sessions.current_session'\n            - else\n              %time.time-ago{ datetime: session.updated_at.iso8601, title: l(session.updated_at) }= l(session.updated_at)\n          %td\n            - if current_session.session_id != session.session_id\n              = table_link_to 'times', t('sessions.revoke'), settings_session_path(session), method: :delete\n"
  },
  {
    "path": "app/views/auth/registrations/edit.html.haml",
    "content": "- content_for :page_title do\n  = t('auth.security')\n\n= simple_form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put, class: 'auth_edit' }) do |f|\n  = render 'shared/error_messages', object: resource\n\n  - if !use_seamless_external_login? || resource.encrypted_password.present?\n    .fields-group\n      = f.input :email, wrapper: :with_label, input_html: { 'aria-label' => t('simple_form.labels.defaults.email') }, required: true, hint: false\n\n    .fields-group\n      = f.input :current_password, wrapper: :with_label, input_html: { 'aria-label' => t('simple_form.labels.defaults.current_password'), :autocomplete => 'off' }, required: true\n\n    .fields-group\n      = f.input :password, wrapper: :with_label, label: t('simple_form.labels.defaults.new_password'), input_html: { 'aria-label' => t('simple_form.labels.defaults.new_password'), :autocomplete => 'off' }, hint: false\n\n    .fields-group\n      = f.input :password_confirmation, wrapper: :with_label, label: t('simple_form.labels.defaults.confirm_new_password'), input_html: { 'aria-label' => t('simple_form.labels.defaults.confirm_new_password'), :autocomplete => 'off' }\n\n\n    .actions\n      = f.button :button, t('generic.save_changes'), type: :submit\n  - else\n    %p.hint= t('users.seamless_external_login')\n\n%hr.spacer/\n\n= render 'sessions'\n\n- if open_deletion?\n  %hr.spacer/\n  %h4= t('auth.delete_account')\n  %p.muted-hint= t('auth.delete_account_html', path: settings_delete_path)\n"
  },
  {
    "path": "app/views/auth/registrations/new.html.haml",
    "content": "- content_for :page_title do\n  = t('auth.register')\n\n- content_for :header_tags do\n  = render partial: 'shared/og'\n\n= simple_form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f|\n  = render 'shared/error_messages', object: resource\n\n  - if @invite.present? && @invite.autofollow?\n    .fields-group{ style: 'margin-bottom: 30px' }\n      %p.hint{ style: 'text-align: center' }= t('invites.invited_by')\n      = render 'application/card', account: @invite.user.account\n\n  = f.simple_fields_for :account do |ff|\n    .fields-group\n      = ff.input :username, wrapper: :with_label, autofocus: true, label: t('simple_form.labels.defaults.username'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.username'), :autocomplete => 'off' }, append: \"@#{site_hostname}\", hint: t('simple_form.hints.defaults.username', domain: site_hostname)\n\n  .fields-group\n    = f.input :email, wrapper: :with_label, label: t('simple_form.labels.defaults.email'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.email'), :autocomplete => 'off' }\n\n  .fields-group\n    = f.input :password, wrapper: :with_label, label: t('simple_form.labels.defaults.password'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.password'), :autocomplete => 'off' }\n\n  .fields-group\n    = f.input :password_confirmation, wrapper: :with_label, label: t('simple_form.labels.defaults.confirm_password'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.confirm_password'), :autocomplete => 'off' }\n\n  - if approved_registrations? && !@invite.present?\n    .fields-group\n      = f.simple_fields_for :invite_request do |invite_request_fields|\n        = invite_request_fields.input :text, as: :text, wrapper: :with_block_label, required: false\n\n  = f.input :invite_code, as: :hidden\n\n  .fields-group\n    = f.input :agreement, as: :boolean, wrapper: :with_label, label: t('auth.checkbox_agreement_html', rules_path: about_more_path, terms_path: terms_path)\n\n  .actions\n    = f.button :button, @invite.present? ? t('auth.register') : sign_up_message, type: :submit\n\n.form-footer= render 'auth/shared/links'\n"
  },
  {
    "path": "app/views/auth/sessions/new.html.haml",
    "content": "- content_for :page_title do\n  = t('auth.login')\n\n- content_for :header_tags do\n  = render partial: 'shared/og'\n\n= simple_form_for(resource, as: resource_name, url: session_path(resource_name)) do |f|\n  .fields-group\n    - if use_seamless_external_login?\n      = f.input :email, autofocus: true, wrapper: :with_label, label: t('simple_form.labels.defaults.username_or_email'), input_html: { 'aria-label' => t('simple_form.labels.defaults.username_or_email') }, hint: false\n    - else\n      = f.input :email, autofocus: true, wrapper: :with_label, label: t('simple_form.labels.defaults.email'), input_html: { 'aria-label' => t('simple_form.labels.defaults.email') }, hint: false\n  .fields-group\n    = f.input :password, wrapper: :with_label, label: t('simple_form.labels.defaults.password'), input_html: { 'aria-label' => t('simple_form.labels.defaults.password'), :autocomplete => 'off' }, hint: false\n\n  .actions\n    = f.button :button, t('auth.login'), type: :submit\n\n- if devise_mapping.omniauthable? and resource_class.omniauth_providers.any?\n  .simple_form.alternative-login\n    %h4= t('auth.or_log_in_with')\n\n    .actions\n      - resource_class.omniauth_providers.each do |provider|\n        = link_to omniauth_authorize_path(resource_name, provider), class: \"button button-#{provider}\" do\n          = t(\"auth.providers.#{provider}\", default: provider.to_s.chomp(\"_oauth2\").capitalize)\n\n.form-footer= render 'auth/shared/links'\n"
  },
  {
    "path": "app/views/auth/sessions/two_factor.html.haml",
    "content": "- content_for :page_title do\n  = t('auth.login')\n\n= simple_form_for(resource, as: resource_name, url: session_path(resource_name), method: :post) do |f|\n  %p.hint{ style: 'margin-bottom: 25px' }= t('simple_form.hints.sessions.otp')\n\n  .fields-group\n    = f.input :otp_attempt, type: :number, wrapper: :with_label, label: t('simple_form.labels.defaults.otp_attempt'), input_html: { 'aria-label' => t('simple_form.labels.defaults.otp_attempt'), :autocomplete => 'off' }, autofocus: true\n\n  .actions\n    = f.button :button, t('auth.login'), type: :submit\n\n  - if Setting.site_contact_email.present?\n    %p.hint.subtle-hint= t('users.otp_lost_help_html', email: mail_to(Setting.site_contact_email, nil))\n"
  },
  {
    "path": "app/views/auth/shared/_links.html.haml",
    "content": "%ul.no-list\n  - if controller_name != 'sessions'\n    %li= link_to t('auth.login'), new_session_path(resource_name)\n\n  - if devise_mapping.registerable? && controller_name != 'registrations'\n    %li= link_to t('auth.register'), available_sign_up_path\n\n  - if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations'\n    %li= link_to t('auth.forgot_password'), new_password_path(resource_name)\n\n  - if devise_mapping.confirmable? && controller_name != 'confirmations'\n    %li= link_to t('auth.didnt_get_confirmation'), new_confirmation_path(resource_name)\n"
  },
  {
    "path": "app/views/authorize_interactions/_post_follow_actions.html.haml",
    "content": ".post-follow-actions\n  %div= link_to t('authorize_follow.post_follow.web'), web_url(\"accounts/#{@resource.id}\"), class: 'button button--block'\n  %div= link_to t('authorize_follow.post_follow.return'), TagManager.instance.url_for(@resource), class: 'button button--block'\n  %div= t('authorize_follow.post_follow.close')\n"
  },
  {
    "path": "app/views/authorize_interactions/error.html.haml",
    "content": ".form-container\n  .flash-message#error_explanation\n    = t('authorize_follow.error')\n"
  },
  {
    "path": "app/views/authorize_interactions/show.html.haml",
    "content": "- content_for :page_title do\n  = t('authorize_follow.title', acct: @resource.acct)\n\n.form-container\n  .follow-prompt\n    = render 'application/card', account: @resource\n\n  - if current_account.following?(@resource)\n    .flash-message\n      %strong\n        = t('authorize_follow.already_following')\n\n    = render 'post_follow_actions'\n  - else\n    = form_tag authorize_interaction_path, method: :post, class: 'simple_form' do\n      = hidden_field_tag :action, :follow\n      = hidden_field_tag :acct, @resource.acct\n      = button_tag t('authorize_follow.follow'), type: :submit\n"
  },
  {
    "path": "app/views/authorize_interactions/success.html.haml",
    "content": "- content_for :page_title do\n  = t('authorize_follow.title', acct: @resource.acct)\n\n.form-container\n  .follow-prompt\n    - if @resource.locked?\n      %h2= t('authorize_follow.follow_request')\n    - else\n      %h2= t('authorize_follow.following')\n\n    = render 'application/card', account: @resource\n\n  = render 'post_follow_actions'\n"
  },
  {
    "path": "app/views/directories/index.html.haml",
    "content": "- content_for :page_title do\n  = t('directories.explore_mastodon', title: site_title)\n\n- content_for :header_tags do\n  %meta{ name: 'description', content: t('directories.explanation') }\n\n  = opengraph 'og:site_name', t('about.hosted_on', domain: site_hostname)\n  = opengraph 'og:type', 'website'\n  = opengraph 'og:title', t('directories.explore_mastodon', title: site_title)\n  = opengraph 'og:description', t('directories.explanation')\n  = opengraph 'og:image', File.join(root_url, 'android-chrome-192x192.png')\n\n.page-header\n  %h1= t('directories.explore_mastodon', title: site_title)\n  %p= t('directories.explanation')\n\n.grid\n  .column-0\n    - if @accounts.empty?\n      = nothing_here\n    - else\n      .directory\n        %table.accounts-table\n          %tbody\n            - @accounts.each do |account|\n              %tr\n                %td= account_link_to account\n                %td.accounts-table__count.optional\n                  = number_to_human account.statuses_count, strip_insignificant_zeros: true\n                  %small= t('accounts.posts', count: account.statuses_count).downcase\n                %td.accounts-table__count.optional\n                  = number_to_human account.followers_count, strip_insignificant_zeros: true\n                  %small= t('accounts.followers', count: account.followers_count).downcase\n                %td.accounts-table__count\n                  - if account.last_status_at.present?\n                    %time.time-ago{ datetime: account.last_status_at.iso8601, title: l(account.last_status_at) }= l account.last_status_at\n                  - else\n                    \\-\n                  %small= t('accounts.last_active')\n\n      = paginate @accounts\n\n  .column-1\n    - if user_signed_in?\n      .box-widget.notice-widget\n        - if current_account.discoverable?\n          - if current_account.followers_count < Account::MIN_FOLLOWERS_DISCOVERY\n            %p= t('directories.enabled_but_waiting', min_followers: Account::MIN_FOLLOWERS_DISCOVERY)\n          - else\n            %p= t('directories.enabled')\n        - else\n          %p= t('directories.how_to_enable')\n\n          = link_to settings_profile_path do\n            = t('settings.edit_profile')\n            = fa_icon 'chevron-right fw'\n\n    - if @tags.empty? && !user_signed_in?\n      .nothing-here\n    - else\n      - @tags.each do |tag|\n        .directory__tag{ class: tag.id == @tag&.id ? 'active' : nil }\n          = link_to explore_hashtag_path(tag) do\n            %h4\n              = fa_icon 'hashtag'\n              = tag.name\n              %small= t('directories.people', count: tag.accounts_count)\n\n            .avatar-stack\n              - tag.cached_sample_accounts.each do |account|\n                = image_tag current_account&.user&.setting_auto_play_gif ? account.avatar_original_url : account.avatar_static_url, width: 48, height: 48, alt: '', class: 'account__avatar'\n"
  },
  {
    "path": "app/views/errors/403.html.haml",
    "content": "- content_for :page_title do\n  = t('errors.403')\n\n- content_for :content do\n  = t('errors.403')\n"
  },
  {
    "path": "app/views/errors/404.html.haml",
    "content": "- content_for :page_title do\n  = t('errors.404')\n\n- content_for :content do\n  = t('errors.404')\n"
  },
  {
    "path": "app/views/errors/410.html.haml",
    "content": "- content_for :page_title do\n  = t('errors.410')\n\n- content_for :content do\n  = t('errors.410')\n"
  },
  {
    "path": "app/views/errors/422.html.haml",
    "content": "- content_for :page_title do\n  = t('errors.422.title')\n\n- content_for :content do\n  = t('errors.422.content')\n"
  },
  {
    "path": "app/views/errors/500.html.haml",
    "content": "- content_for :page_title do\n  = t('errors.500.title')\n\n- content_for :content do\n  = t('errors.500.content')\n"
  },
  {
    "path": "app/views/filters/_fields.html.haml",
    "content": ".fields-row\n  .fields-row__column.fields-row__column-6.fields-group\n    = f.input :phrase, as: :string, wrapper: :with_label, hint: false\n  .fields-row__column.fields-row__column-6.fields-group\n    = f.input :expires_in, wrapper: :with_label, collection: [30.minutes, 1.hour, 6.hours, 12.hours, 1.day, 1.week].map(&:to_i), label_method: lambda { |i| I18n.t(\"invites.expires_in.#{i}\") }, prompt: I18n.t('invites.expires_in_prompt')\n\n.fields-group\n  = f.input :context, wrapper: :with_block_label, collection: CustomFilter::VALID_CONTEXTS, as: :check_boxes, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li', label_method: lambda { |context| I18n.t(\"filters.contexts.#{context}\") }, include_blank: false\n\n%hr.spacer/\n\n.fields-group\n  = f.input :irreversible, wrapper: :with_label\n\n.fields-group\n  = f.input :whole_word, wrapper: :with_label\n"
  },
  {
    "path": "app/views/filters/edit.html.haml",
    "content": "- content_for :page_title do\n  = t('filters.edit.title')\n\n= simple_form_for @filter, url: filter_path(@filter), method: :put do |f|\n  = render 'fields', f: f\n\n  .actions\n    = f.button :button, t('generic.save_changes'), type: :submit\n"
  },
  {
    "path": "app/views/filters/index.html.haml",
    "content": "- content_for :page_title do\n  = t('filters.index.title')\n\n.table-wrapper\n  %table.table\n    %thead\n      %tr\n        %th= t('simple_form.labels.defaults.phrase')\n        %th= t('simple_form.labels.defaults.context')\n        %th\n    %tbody\n      - @filters.each do |filter|\n        %tr\n          %td= filter.phrase\n          %td= filter.context.map { |context| I18n.t(\"filters.contexts.#{context}\") }.join(', ')\n          %td\n            = table_link_to 'pencil', t('filters.edit.title'), edit_filter_path(filter)\n            = table_link_to 'times', t('filters.index.delete'), filter_path(filter), method: :delete\n\n= link_to t('filters.new.title'), new_filter_path, class: 'button'\n"
  },
  {
    "path": "app/views/filters/new.html.haml",
    "content": "- content_for :page_title do\n  = t('filters.new.title')\n\n= simple_form_for @filter, url: filters_path do |f|\n  = render 'fields', f: f\n\n  .actions\n    = f.button :button, t('filters.new.title'), type: :submit\n"
  },
  {
    "path": "app/views/follower_accounts/index.html.haml",
    "content": "- content_for :page_title do\n  = t('accounts.people_who_follow', name: display_name(@account))\n\n- content_for :header_tags do\n  %meta{ name: 'robots', content: 'noindex' }/\n  = render 'accounts/og', account: @account, url: account_followers_url(@account, only_path: false)\n\n= render 'accounts/header', account: @account\n\n- if @account.user_hides_network?\n  .nothing-here= t('accounts.network_hidden')\n- elsif user_signed_in? && @account.blocking?(current_account)\n  .nothing-here= t('accounts.unavailable')\n- elsif @follows.empty?\n  = nothing_here\n- else\n  .card-grid\n    = render partial: 'application/card', collection: @follows.map(&:account), as: :account\n\n  = paginate @follows\n"
  },
  {
    "path": "app/views/following_accounts/index.html.haml",
    "content": "- content_for :page_title do\n  = t('accounts.people_followed_by', name: display_name(@account))\n\n- content_for :header_tags do\n  %meta{ name: 'robots', content: 'noindex' }/\n  = render 'accounts/og', account: @account, url: account_followers_url(@account, only_path: false)\n\n= render 'accounts/header', account: @account\n\n- if @account.user_hides_network?\n  .nothing-here= t('accounts.network_hidden')\n- elsif user_signed_in? && @account.blocking?(current_account)\n  .nothing-here= t('accounts.unavailable')\n- elsif @follows.empty?\n  = nothing_here\n- else\n  .card-grid\n    = render partial: 'application/card', collection: @follows.map(&:target_account), as: :account\n\n  = paginate @follows\n"
  },
  {
    "path": "app/views/home/index.html.haml",
    "content": "- content_for :header_tags do\n  = preload_link_tag asset_pack_path('features/getting_started.js'), crossorigin: 'anonymous'\n  = preload_link_tag asset_pack_path('features/compose.js'), crossorigin: 'anonymous'\n  = preload_link_tag asset_pack_path('features/home_timeline.js'), crossorigin: 'anonymous'\n  = preload_link_tag asset_pack_path('features/notifications.js'), crossorigin: 'anonymous'\n\n  %meta{name: 'applicationServerKey', content: Rails.configuration.x.vapid_public_key}\n  %script#initial-state{ type: 'application/json' }!= json_escape(@initial_state_json)\n\n  = javascript_pack_tag 'application', integrity: true, crossorigin: 'anonymous'\n\n.app-holder#mastodon{ data: { props: Oj.dump(default_props) } }\n  %noscript\n    = image_pack_tag 'logo.svg', alt: 'Mastodon'\n\n    %div\n      = t('errors.noscript_html', apps_path: 'https://joinmastodon.org/apps')\n"
  },
  {
    "path": "app/views/invites/_form.html.haml",
    "content": "= simple_form_for(@invite, url: controller.is_a?(Admin::InvitesController) ? admin_invites_path : invites_path) do |f|\n  = render 'shared/error_messages', object: @invite\n\n  .fields-row\n    .fields-row__column.fields-row__column-6.fields-group\n      = f.input :max_uses, wrapper: :with_label, collection: [1, 5, 10, 25, 50, 100], label_method: lambda { |num| I18n.t('invites.max_uses', count: num) }, prompt: I18n.t('invites.max_uses_prompt')\n    .fields-row__column.fields-row__column-6.fields-group\n      = f.input :expires_in, wrapper: :with_label, collection: [30.minutes, 1.hour, 6.hours, 12.hours, 1.day, 1.week].map(&:to_i), label_method: lambda { |i| I18n.t(\"invites.expires_in.#{i}\") }, prompt: I18n.t('invites.expires_in_prompt')\n\n  .fields-group\n    = f.input :autofollow, wrapper: :with_label\n\n  .actions\n    = f.button :button, t('invites.generate'), type: :submit\n"
  },
  {
    "path": "app/views/invites/_invite.html.haml",
    "content": "%tr\n  %td\n    .input-copy\n      .input-copy__wrapper\n        %input{ type: :text, maxlength: '999', spellcheck: 'false', readonly: 'true', value: public_invite_url(invite_code: invite.code) }\n      %button{ type: :button }= t('generic.copy')\n\n  - if invite.valid_for_use?\n    %td\n      = fa_icon 'user fw'\n      = invite.uses\n      = \" / #{invite.max_uses}\" unless invite.max_uses.nil?\n    %td\n      - if invite.expires_at.nil?\n        ∞\n      - else\n        %time.formatted{ datetime: invite.expires_at.iso8601, title: l(invite.expires_at) }\n          = l invite.expires_at\n  - else\n    %td{ colspan: 2 }\n      = t('invites.expired')\n\n  %td\n    - if invite.valid_for_use? && policy(invite).destroy?\n      = table_link_to 'times', t('invites.delete'), invite_path(invite), method: :delete\n"
  },
  {
    "path": "app/views/invites/index.html.haml",
    "content": "- content_for :page_title do\n  = t('invites.title')\n\n- if policy(:invite).create?\n  %p= t('invites.prompt')\n\n  = render 'form'\n\n  %hr.spacer/\n\n.simple_form\n  %table.table.table--invites\n    %thead\n      %tr\n        %th\n        %th= t('invites.table.uses')\n        %th= t('invites.table.expires_at')\n        %th\n    %tbody\n      = render @invites\n"
  },
  {
    "path": "app/views/kaminari/_next_page.html.haml",
    "content": "-#  Link to the \"Next\" page\n-#  available local variables\n-#    url:           url to the next page\n-#    current_page:  a page object for the currently displayed page\n-#    total_pages:   total number of pages\n-#    per_page:      number of items to fetch per page\n-#    remote:        data-remote\n%span.next\n  = link_to_unless current_page.last?, safe_join([t('pagination.next'), fa_icon('chevron-right')], ' '), url, rel: 'next', remote: remote\n"
  },
  {
    "path": "app/views/kaminari/_paginator.html.haml",
    "content": "-#  The container tag\n-#  available local variables\n-#    current_page:  a page object for the currently displayed page\n-#    total_pages:   total number of pages\n-#    per_page:      number of items to fetch per page\n-#    remote:        data-remote\n-#    paginator:     the paginator that renders the pagination tags inside\n= paginator.render do\n  %nav.pagination\n    = prev_page_tag unless current_page.first?\n    - each_page do |page|\n      - if page.display_tag?\n        = page_tag page\n      - elsif !page.was_truncated?\n        = gap_tag\n    = next_page_tag unless current_page.last?\n"
  },
  {
    "path": "app/views/kaminari/_prev_page.html.haml",
    "content": "-#  Link to the \"Previous\" page\n-#  available local variables\n-#    url:           url to the previous page\n-#    current_page:  a page object for the currently displayed page\n-#    total_pages:   total number of pages\n-#    per_page:      number of items to fetch per page\n-#    remote:        data-remote\n%span.prev\n  = link_to_unless current_page.first?, safe_join([fa_icon('chevron-left'), t('pagination.prev')], ' '), url, rel: 'prev', remote: remote\n"
  },
  {
    "path": "app/views/layouts/admin.html.haml",
    "content": "- content_for :header_tags do\n  = javascript_pack_tag 'public', integrity: true, crossorigin: 'anonymous'\n\n- content_for :content do\n  .admin-wrapper\n    .sidebar-wrapper\n      .sidebar\n        = link_to root_path do\n          = image_pack_tag 'logo.svg', class: 'logo', alt: 'Mastodon'\n\n        = render_navigation\n    .content-wrapper\n      .content\n        %h2= yield :page_title\n\n        = render 'application/flashes'\n\n        = yield\n\n= render template: 'layouts/application'\n"
  },
  {
    "path": "app/views/layouts/application.html.haml",
    "content": "!!! 5\n%html{ lang: I18n.locale }\n  %head\n    %meta{ charset: 'utf-8' }/\n    %meta{ name: 'viewport', content: 'width=device-width, initial-scale=1' }/\n\n    - if cdn_host?\n      %link{ rel: 'dns-prefetch', href: cdn_host }/\n\n    - if storage_host?\n      %link{ rel: 'dns-prefetch', href: storage_host }/\n\n    %link{ rel: 'icon', href: favicon_path, type: 'image/x-icon' }/\n    %link{ rel: 'apple-touch-icon', sizes: '180x180', href: '/apple-touch-icon.png' }/\n    %link{ rel: 'mask-icon', href: '/mask-icon.svg', color: '#2B90D9' }/\n    %link{ rel: 'manifest', href: '/manifest.json' }/\n    %meta{ name: 'msapplication-config', content: '/browserconfig.xml' }/\n    %meta{ name: 'theme-color', content: '#282c37' }/\n    %meta{ name: 'apple-mobile-web-app-capable', content: 'yes' }/\n\n    %title= content_for?(:page_title) ? safe_join([yield(:page_title).chomp.html_safe, title], ' - ') : title\n\n    = stylesheet_pack_tag 'common', media: 'all'\n    = stylesheet_pack_tag current_theme, media: 'all'\n    = javascript_pack_tag 'common', integrity: true, crossorigin: 'anonymous'\n    = javascript_pack_tag \"locale_#{I18n.locale}\", integrity: true, crossorigin: 'anonymous'\n    = csrf_meta_tags\n\n    - if Setting.custom_css.present?\n      = stylesheet_link_tag custom_css_path, media: 'all'\n\n    = yield :header_tags\n\n  %body{ class: body_classes }\n    = content_for?(:content) ? yield(:content) : yield\n\n    %div{ style: 'display: none'}\n      = render file: Rails.root.join('app', 'javascript', 'images', 'logo_transparent.svg')\n      = render file: Rails.root.join('app', 'javascript', 'images', 'logo_full.svg')\n"
  },
  {
    "path": "app/views/layouts/auth.html.haml",
    "content": "- content_for :header_tags do\n  = javascript_pack_tag 'public', integrity: true, crossorigin: 'anonymous'\n\n- content_for :content do\n  .container-alt\n    .logo-container\n      %h1\n        = link_to root_path do\n          = svg_logo_full\n\n    .form-container\n      = render 'flashes'\n\n      = yield\n\n= render template: 'layouts/application'\n"
  },
  {
    "path": "app/views/layouts/embedded.html.haml",
    "content": "!!! 5\n%html{ lang: I18n.locale }\n  %head\n    %meta{ charset: 'utf-8' }/\n    %meta{ name: 'robots', content: 'noindex' }/\n\n    - if cdn_host?\n      %link{ rel: 'dns-prefetch', href: cdn_host }/\n\n    - if storage_host?\n      %link{ rel: 'dns-prefetch', href: storage_host }/\n\n    = stylesheet_pack_tag 'common', media: 'all'\n    = stylesheet_pack_tag Setting.default_settings['theme'], media: 'all'\n    = javascript_pack_tag 'common', integrity: true, crossorigin: 'anonymous'\n    = javascript_pack_tag \"locale_#{I18n.locale}\", integrity: true, crossorigin: 'anonymous'\n    = javascript_pack_tag 'public', integrity: true, crossorigin: 'anonymous'\n  %body.embed\n    = yield\n"
  },
  {
    "path": "app/views/layouts/error.html.haml",
    "content": "!!!\n%html{ lang: I18n.locale }\n  %head\n    %meta{ content: 'text/html; charset=UTF-8', 'http-equiv' => 'Content-Type' }/\n    %meta{ charset: 'utf-8' }/\n    %title= safe_join([yield(:page_title), Setting.default_settings['site_title']], ' - ')\n    %meta{ content: 'width=device-width,initial-scale=1', name: 'viewport' }/\n    = stylesheet_pack_tag 'common', media: 'all'\n    = stylesheet_pack_tag Setting.default_settings['theme'], media: 'all'\n    = javascript_pack_tag 'common', integrity: true, crossorigin: 'anonymous'\n    = javascript_pack_tag 'error', integrity: true, crossorigin: 'anonymous'\n  %body.error\n    .dialog\n      .dialog__illustration\n        %img{ alt: Setting.default_settings['site_title'], src: '/oops.png' }/\n      .dialog__message\n        %h1= yield :content\n"
  },
  {
    "path": "app/views/layouts/mailer.html.haml",
    "content": "!!!\n%html{ lang: I18n.locale }\n  %head\n    %meta{ 'http-equiv' => 'Content-Type', 'content' => 'text/html; charset=utf-8' }/\n    %meta{ name: 'viewport', content: 'width=device-width, initial-scale=1.0, shrink-to-fit=no' }\n\n    %title/\n\n    = stylesheet_pack_tag 'mailer'\n  %body{ dir: locale_direction }\n    %table.email-table{ cellspacing: 0, cellpadding: 0 }\n      %tbody\n        %tr\n          %td.email-body.email-start\n            .email-container\n              %table.content-section{ cellspacing: 0, cellpadding: 0 }\n                %tbody\n                  %tr\n                    %td.content-cell.header\n                      .email-row\n                        .col-6\n                          %table.column{ cellspacing: 0, cellpadding: 0 }\n                            %tbody\n                              %tr\n                                %td.column-cell\n                                  = link_to root_url do\n                                    = image_tag full_pack_url('media/images/mailer/logo_full.png'), alt: 'Mastodon', height: 34, class: 'logo'\n\n    = yield\n\n    %table.email-table{ cellspacing: 0, cellpadding: 0 }\n      %tbody\n        %tr\n          %td.email-body.email-end\n            .email-container\n              %table.content-section{ cellspacing: 0, cellpadding: 0 }\n                %tbody\n                  %tr\n                    %td.content-cell.content-end\n                      != \"&nbsp; \"\n                  %tr\n                    %td.blank-cell.footer\n                      .email-row\n                        .col-6\n                          %table.column{ cellspacing: 0, cellpadding: 0 }\n                            %tbody\n                              %td.column-cell\n                                %p= t 'about.hosted_on', domain: site_hostname\n                                %p= link_to t('application_mailer.notification_preferences'), settings_preferences_notifications_url\n                              %td.column-cell.text-right\n                                = link_to root_url do\n                                  = image_tag full_pack_url('media/images/mailer/logo_transparent.png'), alt: 'Mastodon', height: 24\n"
  },
  {
    "path": "app/views/layouts/mailer.text.erb",
    "content": "<%= yield %>\n---\n\n<%= t 'about.hosted_on', domain: site_hostname %>\n<%= t('application_mailer.settings', link: settings_preferences_url) %>\n"
  },
  {
    "path": "app/views/layouts/modal.html.haml",
    "content": "- content_for :header_tags do\n  = javascript_pack_tag 'public', integrity: true, crossorigin: 'anonymous'\n\n- content_for :content do\n  - if user_signed_in? && !@hide_header\n    .account-header\n      .avatar= image_tag current_account.avatar.url(:original)\n      .name\n        = t 'users.signed_in_as'\n        %span.username @#{current_account.local_username_and_domain}\n      = link_to destroy_user_session_path(continue: true), method: :delete, class: 'logout-link icon-button' do\n        = fa_icon 'sign-out'\n\n  .container-alt= yield\n  .modal-layout__mastodon\n    %div\n\n= render template: 'layouts/application'\n"
  },
  {
    "path": "app/views/layouts/plain_mailer.html.haml",
    "content": "= yield\n"
  },
  {
    "path": "app/views/layouts/public.html.haml",
    "content": "- content_for :header_tags do\n  = javascript_pack_tag 'public', integrity: true, crossorigin: 'anonymous'\n\n- content_for :content do\n  .public-layout\n    - unless @hide_navbar\n      .container\n        %nav.header\n          .nav-left\n            = link_to root_url, class: 'brand' do\n              = svg_logo_full\n\n            = link_to t('directories.directory'), explore_path, class: 'nav-link optional' if Setting.profile_directory\n            = link_to t('about.about_this'), about_more_path, class: 'nav-link optional'\n            = link_to t('about.apps'), 'https://joinmastodon.org/apps', class: 'nav-link optional'\n          .nav-center\n          .nav-right\n            - if user_signed_in?\n              = link_to t('settings.back'), root_url, class: 'nav-link nav-button webapp-btn'\n            - else\n              = link_to t('auth.login'), new_user_session_path, class: 'webapp-btn nav-link nav-button'\n              = link_to t('auth.register'), available_sign_up_path, class: 'webapp-btn nav-link nav-button'\n\n    .container= yield\n\n    .container\n      .footer\n        .grid\n          .column-0\n            %h4= t 'footer.resources'\n            %ul\n              %li= link_to t('about.terms'), terms_path\n              %li= link_to t('about.privacy_policy'), terms_path\n          .column-1\n            %h4= t 'footer.developers'\n            %ul\n              %li= link_to t('about.documentation'), 'https://docs.joinmastodon.org/'\n              %li= link_to t('about.api'), 'https://docs.joinmastodon.org/api/guidelines/'\n          .column-2\n            %h4= link_to t('about.what_is_mastodon'), 'https://joinmastodon.org/'\n            = link_to svg_logo, root_url, class: 'brand'\n          .column-3\n            %h4= site_hostname\n            %ul\n              %li= link_to t('about.about_this'), about_more_path\n              %li= \"v#{Florence::Version.to_s}\"\n          .column-4\n            %h4= t 'footer.more'\n            %ul\n              %li= link_to t('about.source_code'), Mastodon::Version.source_url\n              %li= link_to t('about.apps'), 'https://joinmastodon.org/apps'\n\n= render template: 'layouts/application'\n"
  },
  {
    "path": "app/views/media/player.html.haml",
    "content": "%video{ poster: @media_attachment.file.url(:small), preload: 'auto', autoplay: 'autoplay', muted: 'muted', loop: 'loop', controls: 'controls', style: \"width: #{@media_attachment.file.meta.dig('original', 'width')}px; height: #{@media_attachment.file.meta.dig('original', 'height')}px\" }\n  %source{ src: @media_attachment.file.url(:original), type: @media_attachment.file_content_type }\n"
  },
  {
    "path": "app/views/notification_mailer/_status.html.haml",
    "content": "- i ||= 0\n\n%table.email-table{ cellspacing: 0, cellpadding: 0, dir: 'ltr' }\n  %tbody\n    %tr\n      %td.email-body\n        .email-container\n          %table.content-section{ cellspacing: 0, cellpadding: 0 }\n            %tbody\n              %tr\n                %td.content-cell{ class: i.zero? ? 'content-start' : nil }\n                  .email-row\n                    .col-6\n                      %table.column{ cellspacing: 0, cellpadding: 0 }\n                        %tbody\n                          %tr\n                            %td.column-cell.padded.status\n                              %table.status-header{ cellspacing: 0, cellpadding: 0 }\n                                %tbody\n                                  %tr\n                                    %td{ align: 'left', width: 48 }\n                                      = image_tag full_asset_url(status.account.avatar.url), alt:''\n                                    %td{ align: 'left' }\n                                      %bdi= display_name(status.account)\n                                      = \"@#{status.account.acct}\"\n\n                              - if status.spoiler_text?\n                                %div{ dir: rtl_status?(status) ? 'rtl' : 'ltr' }\n                                  %p\n                                    = Formatter.instance.format_spoiler(status)\n\n                              %div{ dir: rtl_status?(status) ? 'rtl' : 'ltr' }\n                                = Formatter.instance.format(status)\n\n                              %p.status-footer\n                                = link_to l(status.created_at), web_url(\"statuses/#{status.id}\")\n"
  },
  {
    "path": "app/views/notification_mailer/_status.text.erb",
    "content": "<% if status.spoiler_text? %>\n<%= raw status.spoiler_text %>\n----\n\n<% end %>\n<%= raw Formatter.instance.plaintext(status) %>\n\n<%= raw t('application_mailer.view')%> <%= web_url(\"statuses/#{status.id}\") %>\n"
  },
  {
    "path": "app/views/notification_mailer/digest.html.haml",
    "content": "%table.email-table{ cellspacing: 0, cellpadding: 0 }\n  %tbody\n    %tr\n      %td.email-body\n        .email-container\n          %table.content-section{ cellspacing: 0, cellpadding: 0 }\n            %tbody\n              %tr\n                %td.content-cell.darker.hero-with-button\n                  .email-row\n                    .col-6\n                      %table.column{ cellspacing: 0, cellpadding: 0 }\n                        %tbody\n                          %tr\n                            %td.column-cell.text-center.padded\n                              %h1= t 'notification_mailer.digest.title'\n                              %p.lead= t('notification_mailer.digest.body', since: l((@me.user_current_sign_in_at || @since).to_date, format: :short), instance: site_hostname)\n                              %table.button{ align: 'center', cellspacing: 0, cellpadding: 0 }\n                                %tbody\n                                  %tr\n                                    %td.button-primary\n                                      = link_to web_url do\n                                        %span= t 'notification_mailer.digest.action'\n\n- @notifications.each_with_index do |n, i|\n  = render 'status', status: n.target_status, i: i\n\n- unless @follows_since.zero?\n  %table.email-table{ cellspacing: 0, cellpadding: 0 }\n    %tbody\n      %tr\n        %td.email-body\n          .email-container\n            %table.content-section{ cellspacing: 0, cellpadding: 0 }\n              %tbody\n                %tr\n                  %td.content-cell.content-start.border-top\n                    .email-row\n                      .col-6\n                        %table.column{ cellspacing: 0, cellpadding: 0 }\n                          %tbody\n                            %tr\n                              %td.column-cell.text-center\n                                %p= t('notification_mailer.digest.new_followers_summary', count: @follows_since)\n"
  },
  {
    "path": "app/views/notification_mailer/digest.text.erb",
    "content": "<%= raw t('application_mailer.salutation', name: display_name(@me)) %>\n\n<%= raw t('notification_mailer.digest.body', since: l(@me.user_current_sign_in_at || @since), instance: root_url) %>\n<% @notifications.each do |notification| %>\n\n* <%= raw t('notification_mailer.digest.mention', name: notification.from_account.acct) %>\n\n  <%= raw Formatter.instance.plaintext(notification.target_status) %>\n\n  <%= raw t('application_mailer.view')%> <%= web_url(\"statuses/#{notification.target_status.id}\") %>\n<% end %>\n<% if @follows_since > 0 %>\n\n<%= raw t('notification_mailer.digest.new_followers_summary', count: @follows_since) %>\n<% end %>\n"
  },
  {
    "path": "app/views/notification_mailer/favourite.html.haml",
    "content": "%table.email-table{ cellspacing: 0, cellpadding: 0 }\n  %tbody\n    %tr\n      %td.email-body\n        .email-container\n          %table.content-section{ cellspacing: 0, cellpadding: 0 }\n            %tbody\n              %tr\n                %td.content-cell.hero\n                  .email-row\n                    .col-6\n                      %table.column{ cellspacing: 0, cellpadding: 0 }\n                        %tbody\n                          %tr\n                            %td.column-cell.text-center.padded\n                              %table.hero-icon{ align: 'center', cellspacing: 0, cellpadding: 0 }\n                                %tbody\n                                  %tr\n                                    %td\n                                      = image_tag full_pack_url('media/images/mailer/icon_grade.png'), alt:''\n\n                              %h1= t 'notification_mailer.favourite.title'\n                              %p.lead= t('notification_mailer.favourite.body', name: @account.acct)\n\n= render 'status', status: @status\n\n%table.email-table{ cellspacing: 0, cellpadding: 0 }\n  %tbody\n    %tr\n      %td.email-body\n        .email-container\n          %table.content-section{ cellspacing: 0, cellpadding: 0 }\n            %tbody\n              %tr\n                %td.content-cell.content-start.border-top\n                  %table.column{ cellspacing: 0, cellpadding: 0 }\n                    %tbody\n                      %tr\n                        %td.column-cell.button-cell\n                          %table.button{ align: 'center', cellspacing: 0, cellpadding: 0 }\n                            %tbody\n                              %tr\n                                %td.button-primary\n                                  = link_to web_url(\"statuses/#{@status.id}\") do\n                                    %span= t 'application_mailer.view_status'\n"
  },
  {
    "path": "app/views/notification_mailer/favourite.text.erb",
    "content": "<%= raw t('application_mailer.salutation', name: display_name(@me)) %>\n\n<%= raw t('notification_mailer.favourite.body', name: @account.acct) %>\n\n<%= render 'status', status: @status %>\n"
  },
  {
    "path": "app/views/notification_mailer/follow.html.haml",
    "content": "%table.email-table{ cellspacing: 0, cellpadding: 0 }\n  %tbody\n    %tr\n      %td.email-body\n        .email-container\n          %table.content-section{ cellspacing: 0, cellpadding: 0 }\n            %tbody\n              %tr\n                %td.content-cell.hero\n                  .email-row\n                    .col-6\n                      %table.column{ cellspacing: 0, cellpadding: 0 }\n                        %tbody\n                          %tr\n                            %td.column-cell.text-center.padded\n                              %table.hero-icon{ align: 'center', cellspacing: 0, cellpadding: 0 }\n                                %tbody\n                                  %tr\n                                    %td\n                                      = image_tag full_pack_url('media/images/mailer/icon_person_add.png'), alt: ''\n\n                              %h1= t 'notification_mailer.follow.title'\n                              %p.lead= t('notification_mailer.follow.body', name: @account.acct)\n\n%table.email-table{ cellspacing: 0, cellpadding: 0 }\n  %tbody\n    %tr\n      %td.email-body\n        .email-container\n          %table.content-section{ cellspacing: 0, cellpadding: 0 }\n            %tbody\n              %tr\n                %td.content-cell.content-start\n                  %table.column{ cellspacing: 0, cellpadding: 0 }\n                    %tbody\n                      %tr\n                        %td.column-cell.button-cell\n                          %table.button{ align: 'center', cellspacing: 0, cellpadding: 0 }\n                            %tbody\n                              %tr\n                                %td.button-primary\n                                  = link_to web_url(\"accounts/#{@account.id}\") do\n                                    %span= t 'application_mailer.view_profile'\n"
  },
  {
    "path": "app/views/notification_mailer/follow.text.erb",
    "content": "<%= raw t('application_mailer.salutation', name: display_name(@me)) %>\n\n<%= raw t('notification_mailer.follow.body', name: @account.acct) %>\n\n<%= raw t('application_mailer.view')%> <%= web_url(\"accounts/#{@account.id}\") %>\n"
  },
  {
    "path": "app/views/notification_mailer/follow_request.html.haml",
    "content": "%table.email-table{ cellspacing: 0, cellpadding: 0 }\n  %tbody\n    %tr\n      %td.email-body\n        .email-container\n          %table.content-section{ cellspacing: 0, cellpadding: 0 }\n            %tbody\n              %tr\n                %td.content-cell.hero\n                  .email-row\n                    .col-6\n                      %table.column{ cellspacing: 0, cellpadding: 0 }\n                        %tbody\n                          %tr\n                            %td.column-cell.text-center.padded\n                              %table.hero-icon{ align: 'center', cellspacing: 0, cellpadding: 0 }\n                                %tbody\n                                  %tr\n                                    %td\n                                      = image_tag full_pack_url('media/images/mailer/icon_person_add.png'), alt: ''\n\n                              %h1= t 'notification_mailer.follow_request.title'\n                              %p.lead= t('notification_mailer.follow_request.body', name: @account.acct)\n\n%table.email-table{ cellspacing: 0, cellpadding: 0 }\n  %tbody\n    %tr\n      %td.email-body\n        .email-container\n          %table.content-section{ cellspacing: 0, cellpadding: 0 }\n            %tbody\n              %tr\n                %td.content-cell.content-start\n                  %table.column{ cellspacing: 0, cellpadding: 0 }\n                    %tbody\n                      %tr\n                        %td.column-cell.button-cell\n                          %table.button{ align: 'center', cellspacing: 0, cellpadding: 0 }\n                            %tbody\n                              %tr\n                                %td.button-primary\n                                  = link_to web_url(\"follow_requests\") do\n                                    %span= t 'notification_mailer.follow_request.action'\n"
  },
  {
    "path": "app/views/notification_mailer/follow_request.text.erb",
    "content": "<%= raw t('application_mailer.salutation', name: display_name(@me)) %>\n\n<%= raw t('notification_mailer.follow_request.body', name: @account.acct) %>\n\n<%= raw t('application_mailer.view')%> <%= web_url(\"follow_requests\") %>\n"
  },
  {
    "path": "app/views/notification_mailer/mention.html.haml",
    "content": "%table.email-table{ cellspacing: 0, cellpadding: 0 }\n  %tbody\n    %tr\n      %td.email-body\n        .email-container\n          %table.content-section{ cellspacing: 0, cellpadding: 0 }\n            %tbody\n              %tr\n                %td.content-cell.hero\n                  .email-row\n                    .col-6\n                      %table.column{ cellspacing: 0, cellpadding: 0 }\n                        %tbody\n                          %tr\n                            %td.column-cell.text-center.padded\n                              %table.hero-icon{ align: 'center', cellspacing: 0, cellpadding: 0 }\n                                %tbody\n                                  %tr\n                                    %td\n                                      = image_tag full_pack_url('media/images/mailer/icon_reply.png'), alt: ''\n\n                              %h1= t 'notification_mailer.mention.title'\n                              %p.lead= t('notification_mailer.mention.body', name: @status.account.acct)\n\n= render 'status', status: @status\n\n%table.email-table{ cellspacing: 0, cellpadding: 0 }\n  %tbody\n    %tr\n      %td.email-body\n        .email-container\n          %table.content-section{ cellspacing: 0, cellpadding: 0 }\n            %tbody\n              %tr\n                %td.content-cell.content-start.border-top\n                  %table.column{ cellspacing: 0, cellpadding: 0 }\n                    %tbody\n                      %tr\n                        %td.column-cell.button-cell\n                          %table.button{ align: 'center', cellspacing: 0, cellpadding: 0 }\n                            %tbody\n                              %tr\n                                %td.button-primary\n                                  = link_to web_url(\"statuses/#{@status.id}\") do\n                                    %span= t 'notification_mailer.mention.action'\n"
  },
  {
    "path": "app/views/notification_mailer/mention.text.erb",
    "content": "<%= raw t('application_mailer.salutation', name: display_name(@me)) %>\n\n<%= raw t('notification_mailer.mention.body', name: @status.account.acct) %>\n\n<%= render 'status', status: @status %>\n"
  },
  {
    "path": "app/views/notification_mailer/reblog.html.haml",
    "content": "%table.email-table{ cellspacing: 0, cellpadding: 0 }\n  %tbody\n    %tr\n      %td.email-body\n        .email-container\n          %table.content-section{ cellspacing: 0, cellpadding: 0 }\n            %tbody\n              %tr\n                %td.content-cell.hero\n                  .email-row\n                    .col-6\n                      %table.column{ cellspacing: 0, cellpadding: 0 }\n                        %tbody\n                          %tr\n                            %td.column-cell.text-center.padded\n                              %table.hero-icon{ align: 'center', cellspacing: 0, cellpadding: 0 }\n                                %tbody\n                                  %tr\n                                    %td\n                                      = image_tag full_pack_url('media/images/mailer/icon_cached.png'), alt: ''\n\n                              %h1= t 'notification_mailer.reblog.title'\n                              %p.lead= t('notification_mailer.reblog.body', name: @account.acct)\n\n= render 'status', status: @status\n\n%table.email-table{ cellspacing: 0, cellpadding: 0 }\n  %tbody\n    %tr\n      %td.email-body\n        .email-container\n          %table.content-section{ cellspacing: 0, cellpadding: 0 }\n            %tbody\n              %tr\n                %td.content-cell.content-start.border-top\n                  %table.column{ cellspacing: 0, cellpadding: 0 }\n                    %tbody\n                      %tr\n                        %td.column-cell.button-cell\n                          %table.button{ align: 'center', cellspacing: 0, cellpadding: 0 }\n                            %tbody\n                              %tr\n                                %td.button-primary\n                                  = link_to web_url(\"statuses/#{@status.id}\") do\n                                    %span= t 'application_mailer.view_status'\n"
  },
  {
    "path": "app/views/notification_mailer/reblog.text.erb",
    "content": "<%= raw t('application_mailer.salutation', name: display_name(@me)) %>\n\n<%= raw t('notification_mailer.reblog.body', name: @account.acct) %>\n\n<%= render 'status', status: @status %>\n"
  },
  {
    "path": "app/views/oauth/authorizations/error.html.haml",
    "content": ".form-container\n  .flash-message#error_explanation\n    = @pre_auth.error_response.body[:error_description]\n"
  },
  {
    "path": "app/views/oauth/authorizations/new.html.haml",
    "content": "- content_for :page_title do\n  = t('doorkeeper.authorizations.new.title')\n\n.form-container\n  .oauth-prompt\n    %h2= t('doorkeeper.authorizations.new.prompt', client_name: @pre_auth.client.name)\n\n    %p\n      = t('doorkeeper.authorizations.new.able_to')\n      != @pre_auth.scopes.map { |scope| t(scope, scope: [:doorkeeper, :scopes]) }.map { |s| \"<strong>#{s}</strong>\" }.to_sentence\n\n  = form_tag oauth_authorization_path, method: :post, class: 'simple_form' do\n    = hidden_field_tag :client_id, @pre_auth.client.uid\n    = hidden_field_tag :redirect_uri, @pre_auth.redirect_uri\n    = hidden_field_tag :state, @pre_auth.state\n    = hidden_field_tag :response_type, @pre_auth.response_type\n    = hidden_field_tag :scope, @pre_auth.scope\n    = button_tag t('doorkeeper.authorizations.buttons.authorize'), type: :submit\n\n  = form_tag oauth_authorization_path, method: :delete, class: 'simple_form' do\n    = hidden_field_tag :client_id, @pre_auth.client.uid\n    = hidden_field_tag :redirect_uri, @pre_auth.redirect_uri\n    = hidden_field_tag :state, @pre_auth.state\n    = hidden_field_tag :response_type, @pre_auth.response_type\n    = hidden_field_tag :scope, @pre_auth.scope\n    = button_tag t('doorkeeper.authorizations.buttons.deny'), type: :submit, class: 'negative'\n"
  },
  {
    "path": "app/views/oauth/authorizations/show.html.haml",
    "content": ".form-container\n  .flash-message.simple_form\n    %p= t('doorkeeper.authorizations.show.title')\n    .input-copy\n      .input-copy__wrapper\n        %input{ type: 'text', class: 'oauth-code', spellcheck: 'false', readonly: true, value: params[:code] }\n      %button{ type: :button }= t('generic.copy')\n"
  },
  {
    "path": "app/views/oauth/authorized_applications/index.html.haml",
    "content": "- content_for :page_title do\n  = t('doorkeeper.authorized_applications.index.title')\n\n.table-wrapper\n  %table.table\n    %thead\n      %tr\n        %th= t('doorkeeper.authorized_applications.index.application')\n        %th= t('doorkeeper.authorized_applications.index.scopes')\n        %th= t('doorkeeper.authorized_applications.index.created_at')\n        %th\n    %tbody\n      - @applications.each do |application|\n        %tr\n          %td\n            - if application.website.blank?\n              = application.name\n            - else\n              = link_to application.name, application.website, target: '_blank', rel: 'noopener'\n          %th!= application.scopes.map { |scope| t(scope, scope: [:doorkeeper, :scopes]) }.join('<br />')\n          %td= l application.created_at\n          %td\n            - unless application.superapp?\n              = table_link_to 'times', t('doorkeeper.authorized_applications.buttons.revoke'), oauth_authorized_application_path(application), method: :delete, data: { confirm: t('doorkeeper.authorized_applications.confirmations.revoke') }\n"
  },
  {
    "path": "app/views/public_timelines/show.html.haml",
    "content": "- content_for :page_title do\n  = t('about.see_whats_happening')\n\n- content_for :header_tags do\n  %meta{ name: 'robots', content: 'noindex' }/\n  %script#initial-state{ type: 'application/json' }!= json_escape(@initial_state_json)\n  = javascript_pack_tag 'about', integrity: true, crossorigin: 'anonymous'\n\n.page-header\n  %h1= t('about.see_whats_happening')\n  %p= t('about.browse_public_posts')\n\n#mastodon-timeline{ data: { props: Oj.dump(default_props) }}\n#modal-container\n"
  },
  {
    "path": "app/views/relationships/_account.html.haml",
    "content": ".batch-table__row\n  %label.batch-table__row__select.batch-table__row__select--aligned.batch-checkbox\n    = f.check_box :account_ids, { multiple: true, include_hidden: false }, account.id\n  .batch-table__row__content.batch-table__row__content--unpadded\n    %table.accounts-table\n      %tbody\n        %tr\n          %td= account_link_to account\n          %td.accounts-table__count.optional\n            = number_to_human account.statuses_count, strip_insignificant_zeros: true\n            %small= t('accounts.posts', count: account.statuses_count).downcase\n          %td.accounts-table__count.optional\n            = number_to_human account.followers_count, strip_insignificant_zeros: true\n            %small= t('accounts.followers', count: account.followers_count).downcase\n          %td.accounts-table__count\n            - if account.last_status_at.present?\n              %time.time-ago{ datetime: account.last_status_at.iso8601, title: l(account.last_status_at) }= l account.last_status_at\n            - else\n              \\-\n            %small= t('accounts.last_active')\n"
  },
  {
    "path": "app/views/relationships/show.html.haml",
    "content": "- content_for :page_title do\n  = t('settings.relationships')\n\n- content_for :header_tags do\n  = javascript_pack_tag 'admin', integrity: true, async: true, crossorigin: 'anonymous'\n\n.filters\n  .filter-subset\n    %strong= t 'relationships.relationship'\n    %ul\n      %li= filter_link_to t('accounts.following', count: current_account.following_count), relationship: nil\n      %li= filter_link_to t('accounts.followers', count: current_account.followers_count), relationship: 'followed_by'\n      %li= filter_link_to t('relationships.mutual'), relationship: 'mutual'\n\n  .filter-subset\n    %strong= t 'relationships.status'\n    %ul\n      %li= filter_link_to t('generic.all'), status: nil\n      %li= filter_link_to t('relationships.primary'), status: 'primary'\n      %li= filter_link_to t('relationships.moved'), status: 'moved'\n\n  .filter-subset\n    %strong= t 'relationships.activity'\n    %ul\n      %li= filter_link_to t('generic.all'), activity: nil\n      %li= filter_link_to t('relationships.dormant'), activity: 'dormant'\n\n  .filter-subset\n    %strong= t 'generic.order_by'\n    %ul\n      %li= filter_link_to t('relationships.most_recent'), order: nil\n      %li= filter_link_to t('relationships.last_active'), order: 'active'\n\n= form_for(@form, url: relationships_path, method: :patch) do |f|\n  = hidden_field_tag :page, params[:page] || 1\n  = hidden_field_tag :relationship, params[:relationship]\n  = hidden_field_tag :status, params[:status]\n  = hidden_field_tag :activity, params[:activity]\n  = hidden_field_tag :order, params[:order]\n\n  .batch-table\n    .batch-table__toolbar\n      %label.batch-table__toolbar__select.batch-checkbox-all\n        = check_box_tag :batch_checkbox_all, nil, false\n      .batch-table__toolbar__actions\n        = f.button safe_join([fa_icon('user-times'), t('relationships.remove_selected_follows')]), name: :unfollow, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') } unless followed_by_relationship?\n\n        = f.button safe_join([fa_icon('trash'), t('relationships.remove_selected_followers')]), name: :remove_from_followers, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') } unless following_relationship?\n\n        = f.button safe_join([fa_icon('trash'), t('relationships.remove_selected_domains')]), name: :block_domains, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') } if followed_by_relationship?\n    .batch-table__body\n      - if @accounts.empty?\n        = nothing_here 'nothing-here--under-tabs'\n      - else\n        = render partial: 'account', collection: @accounts, locals: { f: f }\n\n= paginate @accounts\n"
  },
  {
    "path": "app/views/remote_follow/new.html.haml",
    "content": "- content_for :header_tags do\n  %meta{ name: 'robots', content: 'noindex' }/\n\n.form-container\n  .follow-prompt\n    %h2= t('remote_follow.prompt')\n\n    = render partial: 'application/card', locals: { account: @account }\n\n  = simple_form_for @remote_follow, as: :remote_follow, url: account_remote_follow_path(@account) do |f|\n    = render 'shared/error_messages', object: @remote_follow\n\n    = f.input :acct, placeholder: t('remote_follow.acct'), input_html: { autocapitalize: 'none', autocorrect: 'off' }\n\n    .actions\n      = f.button :button, t('remote_follow.proceed'), type: :submit\n\n    %p.hint.subtle-hint\n      = t('remote_follow.reason_html', instance: site_hostname)\n      = t('remote_follow.no_account_html', sign_up_path: available_sign_up_path)\n"
  },
  {
    "path": "app/views/remote_interaction/new.html.haml",
    "content": "- content_for :header_tags do\n  %meta{ name: 'robots', content: 'noindex' }/\n\n.form-container\n  .follow-prompt\n    %h2= t(\"remote_interaction.#{@interaction_type}.prompt\")\n\n    .public-layout\n      .activity-stream.activity-stream--highlighted\n        = render 'stream_entries/status', status: @status\n\n  = simple_form_for @remote_follow, as: :remote_follow, url: remote_interaction_path(@status) do |f|\n    = render 'shared/error_messages', object: @remote_follow\n\n    = hidden_field_tag :type, @interaction_type\n\n    = f.input :acct, placeholder: t('remote_follow.acct'), input_html: { autocapitalize: 'none', autocorrect: 'off' }\n\n    .actions\n      = f.button :button, t(\"remote_interaction.#{@interaction_type}.proceed\"), type: :submit\n\n    %p.hint.subtle-hint\n      = t('remote_follow.reason_html', instance: site_hostname)\n      = t('remote_follow.no_account_html', sign_up_path: available_sign_up_path)\n"
  },
  {
    "path": "app/views/remote_unfollows/_card.html.haml",
    "content": ".account-card\n  .detailed-status__display-name\n    %div\n      = image_tag account.avatar.url(:original), alt: '', width: 48, height: 48, class: 'avatar'\n\n    %span.display-name\n      - account_url = local_assigns[:admin] ? admin_account_path(account.id) : TagManager.instance.url_for(account)\n      = link_to account_url, class: 'detailed-status__display-name p-author h-card', target: '_blank', rel: 'noopener' do\n        %strong.emojify= display_name(account, custom_emojify: true)\n        %span @#{account.acct}\n\n  - if account.note?\n    .account__header__content.emojify= Formatter.instance.simplified_format(account)\n"
  },
  {
    "path": "app/views/remote_unfollows/_post_follow_actions.html.haml",
    "content": ".post-follow-actions\n  %div= link_to t('authorize_follow.post_follow.web'), web_url(\"accounts/#{@account.id}\"), class: 'button button--block'\n  %div= link_to t('authorize_follow.post_follow.return'), TagManager.instance.url_for(@account), class: 'button button--block'\n  %div= t('authorize_follow.post_follow.close')\n"
  },
  {
    "path": "app/views/remote_unfollows/error.html.haml",
    "content": ".form-container\n  .flash-message#error_explanation\n    = t('remote_unfollow.error')\n"
  },
  {
    "path": "app/views/remote_unfollows/success.html.haml",
    "content": "- content_for :page_title do\n  = t('remote_unfollow.title', acct: @account.acct)\n\n.form-container\n  .follow-prompt\n    %h2= t('remote_unfollow.unfollowed')\n\n    = render 'application/card', account: @account\n\n  = render 'post_follow_actions'\n"
  },
  {
    "path": "app/views/settings/applications/_fields.html.haml",
    "content": ".fields-group\n  = f.input :name, wrapper: :with_label, label: t('activerecord.attributes.doorkeeper/application.name')\n\n.fields-group\n  = f.input :website, wrapper: :with_label, label: t('activerecord.attributes.doorkeeper/application.website')\n\n.fields-group\n  = f.input :redirect_uri, wrapper: :with_block_label, label: t('activerecord.attributes.doorkeeper/application.redirect_uri'), hint: t('doorkeeper.applications.help.redirect_uri')\n\n  %p.hint= t('doorkeeper.applications.help.native_redirect_uri', native_redirect_uri: Doorkeeper.configuration.native_redirect_uri)\n\n.field-group\n  .input.with_block_label\n    %label= t('activerecord.attributes.doorkeeper/application.scopes')\n    %span.hint= t('simple_form.hints.defaults.scopes')\n\n  - Doorkeeper.configuration.scopes.group_by { |s| s.split(':').first }.each do |k, v|\n    = f.input :scopes, label: false, hint: false, collection: v.sort, wrapper: :with_block_label, include_blank: false, label_method: lambda { |scope| safe_join([content_tag(:samp, scope, class: class_for_scope(scope)), content_tag(:span, t(\"doorkeeper.scopes.#{scope}\"), class: 'hint')]) }, selected: f.object.scopes.all, required: false, as: :check_boxes, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li'\n"
  },
  {
    "path": "app/views/settings/applications/index.html.haml",
    "content": "- content_for :page_title do\n  = t('doorkeeper.applications.index.title')\n\n.table-wrapper\n  %table.table\n    %thead\n      %tr\n        %th= t('doorkeeper.applications.index.application')\n        %th= t('doorkeeper.applications.index.scopes')\n        %th\n    %tbody\n      - @applications.each do |application|\n        %tr\n          %td= link_to application.name, settings_application_path(application)\n          %th= application.scopes\n          %td\n            = table_link_to 'times', t('doorkeeper.applications.index.delete'), settings_application_path(application), method: :delete, data: { confirm: t('doorkeeper.applications.confirmations.destroy') }\n\n= paginate @applications\n= link_to t('doorkeeper.applications.index.new'), new_settings_application_path, class: 'button'\n"
  },
  {
    "path": "app/views/settings/applications/new.html.haml",
    "content": "- content_for :page_title do\n  = t('doorkeeper.applications.new.title')\n\n= simple_form_for @application, url: settings_applications_path do |f|\n  = render 'fields', f: f\n\n  .actions\n    = f.button :button, t('doorkeeper.applications.buttons.submit'), type: :submit\n"
  },
  {
    "path": "app/views/settings/applications/show.html.haml",
    "content": "- content_for :page_title do\n  = t('doorkeeper.applications.show.title', name: @application.name)\n\n%p.hint= t('applications.warning')\n\n.table-wrapper\n  %table.table\n    %tbody\n      %tr  \n        %th= t('doorkeeper.applications.show.application_id')\n        %td\n          %code= @application.uid\n      %tr\n        %th= t('doorkeeper.applications.show.secret')\n        %td\n          %code= @application.secret\n      %tr\n        %th{ rowspan: 2}= t('applications.your_token')\n        %td\n          %code= current_user.token_for_app(@application).token\n      %tr\n        %td= table_link_to 'refresh', t('applications.regenerate_token'), regenerate_settings_application_path(@application), method: :post\n\n%hr/\n\n= simple_form_for @application, url: settings_application_path(@application), method: :put do |f|\n  = render 'fields', f: f\n\n  .actions\n    = f.button :button, t('generic.save_changes'), type: :submit\n\n"
  },
  {
    "path": "app/views/settings/deletes/show.html.haml",
    "content": "- content_for :page_title do\n  = t('settings.delete')\n\n= simple_form_for @confirmation, url: settings_delete_path, method: :delete do |f|\n  .warning\n    %strong\n      = fa_icon('warning')\n      = t('deletes.warning_title')\n    = t('deletes.warning_html')\n\n  %p.hint= t('deletes.description_html')\n\n  = f.input :password, placeholder: t('simple_form.labels.defaults.current_password'), input_html: { 'aria-label' => t('simple_form.labels.defaults.current_password'), :autocomplete => 'off' }, hint: t('deletes.confirm_password')\n\n  .actions\n    = f.button :button, t('deletes.proceed'), type: :submit, class: 'negative'\n"
  },
  {
    "path": "app/views/settings/exports/show.html.haml",
    "content": "- content_for :page_title do\n  = t('settings.export')\n\n.table-wrapper\n  %table.table\n    %tbody\n      %tr\n        %th= t('exports.storage')\n        %td= number_to_human_size @export.total_storage\n        %td\n      %tr\n        %th= t('accounts.posts', count: @export.total_statuses)\n        %td= number_with_delimiter @export.total_statuses\n        %td\n      %tr\n        %th= t('exports.follows')\n        %td= number_with_delimiter @export.total_follows\n        %td= table_link_to 'download', t('exports.csv'), settings_exports_follows_path(format: :csv)\n      %tr\n        %th= t('exports.lists')\n        %td= number_with_delimiter @export.total_lists\n        %td= table_link_to 'download', t('exports.csv'), settings_exports_lists_path(format: :csv)\n      %tr\n        %th= t('accounts.followers', count: @export.total_followers)\n        %td= number_with_delimiter @export.total_followers\n        %td\n      %tr\n        %th= t('exports.blocks')\n        %td= number_with_delimiter @export.total_blocks\n        %td= table_link_to 'download', t('exports.csv'), settings_exports_blocks_path(format: :csv)\n      %tr\n        %th= t('exports.mutes')\n        %td= number_with_delimiter @export.total_mutes\n        %td= table_link_to 'download', t('exports.csv'), settings_exports_mutes_path(format: :csv)\n      %tr\n        %th= t('exports.domain_blocks')\n        %td= number_with_delimiter @export.total_domain_blocks\n        %td= table_link_to 'download', t('exports.csv'), settings_exports_domain_blocks_path(format: :csv)\n\n%p.muted-hint= t('exports.archive_takeout.hint_html')\n\n- if policy(:backup).create?\n  %p= link_to t('exports.archive_takeout.request'), settings_export_path, class: 'button', method: :post\n\n- unless @backups.empty?\n  .table-wrapper\n    %table.table\n      %thead\n        %tr\n          %th= t('exports.archive_takeout.date')\n          %th= t('exports.archive_takeout.size')\n          %th\n      %tbody\n        - @backups.each do |backup|\n          %tr\n            %td= l backup.created_at\n            - if backup.processed?\n              %td= number_to_human_size backup.dump_file_size\n              %td= table_link_to 'download', t('exports.archive_takeout.download'), backup.dump.url\n            - else\n              %td{ colspan: 2 }= t('exports.archive_takeout.in_progress')\n"
  },
  {
    "path": "app/views/settings/featured_tags/index.html.haml",
    "content": "- content_for :page_title do\n  = t('settings.featured_tags')\n\n= simple_form_for @featured_tag, url: settings_featured_tags_path do |f|\n  = render 'shared/error_messages', object: @featured_tag\n\n  .fields-group\n    = f.input :name, wrapper: :with_block_label, hint: safe_join([t('simple_form.hints.featured_tag.name'), safe_join(@most_used_tags.map { |tag| link_to(\"##{tag.name}\", settings_featured_tags_path(featured_tag: { name: tag.name }), method: :post) }, ', ')], ' ')\n\n  .actions\n    = f.button :button, t('featured_tags.add_new'), type: :submit\n\n%hr.spacer/\n\n- @featured_tags.each do |featured_tag|\n  .directory__tag{ class: params[:tag] == featured_tag.name ? 'active' : nil }\n    %div\n      %h4\n        = fa_icon 'hashtag'\n        = featured_tag.name\n        %small\n          - if featured_tag.last_status_at.nil?\n            = t('accounts.nothing_here')\n          - else\n            %time{ datetime: featured_tag.last_status_at.iso8601, title: l(featured_tag.last_status_at) }= l featured_tag.last_status_at\n          = table_link_to 'trash', t('filters.index.delete'), settings_featured_tag_path(featured_tag), method: :delete, data: { confirm: t('admin.accounts.are_you_sure') }\n      .trends__item__current= number_to_human featured_tag.statuses_count, strip_insignificant_zeros: true\n"
  },
  {
    "path": "app/views/settings/identity_proofs/_proof.html.haml",
    "content": "%tr\n  %td\n    = link_to proof.badge.profile_url, class: 'name-tag' do\n      = image_tag proof.badge.avatar_url, width: 15, height: 15, alt: '', class: 'avatar'\n      %span.username\n        = proof.provider_username\n        %span= \"(#{proof.provider.capitalize})\"\n\n  %td\n    - if proof.live?\n      %span.positive-hint\n        = fa_icon 'check-circle fw'\n        = t('identity_proofs.active')\n    - else\n      %span.negative-hint\n        = fa_icon 'times-circle fw'\n        = t('identity_proofs.inactive')\n\n  %td\n    = table_link_to 'external-link', t('identity_proofs.view_proof'), proof.badge.proof_url if proof.badge.proof_url\n"
  },
  {
    "path": "app/views/settings/identity_proofs/index.html.haml",
    "content": "- content_for :page_title do\n  = t('settings.identity_proofs')\n\n%p= t('identity_proofs.explanation_html')\n\n- unless @proofs.empty?\n  %hr.spacer/\n\n  .table-wrapper\n    %table.table\n      %thead\n        %tr\n          %th= t('identity_proofs.identity')\n          %th= t('identity_proofs.status')\n          %th\n      %tbody\n        = render partial: 'settings/identity_proofs/proof', collection: @proofs, as: :proof\n"
  },
  {
    "path": "app/views/settings/identity_proofs/new.html.haml",
    "content": "- content_for :page_title do\n  = t('identity_proofs.authorize_connection_prompt')\n\n.form-container\n  .oauth-prompt\n    %h2= t('identity_proofs.authorize_connection_prompt')\n\n  = simple_form_for @proof, url: settings_identity_proofs_url, html: { method: :post } do |f|\n    = f.input :provider, as: :hidden\n    = f.input :provider_username, as: :hidden\n    = f.input :token, as: :hidden\n\n    = hidden_field_tag :user_agent, params[:user_agent]\n\n    .connection-prompt\n      .connection-prompt__row.connection-prompt__connection\n        .connection-prompt__column\n          = image_tag current_account.avatar.url(:original), size: 96, class: 'account__avatar'\n\n          %p= t('identity_proofs.i_am_html', username: content_tag(:strong,current_account.username), service: site_hostname)\n\n        .connection-prompt__column.connection-prompt__column-sep\n          = fa_icon 'link'\n\n        .connection-prompt__column\n          = image_tag @proof.badge.avatar_url, size: 96, class: 'account__avatar'\n\n          %p= t('identity_proofs.i_am_html', username: content_tag(:strong, @proof.provider_username), service: @proof.provider.capitalize)\n\n    .connection-prompt__post\n      = f.input :post_status, label: t('identity_proofs.publicize_checkbox'), as: :boolean, wrapper: :with_label, :input_html => { checked: true }\n\n      = f.input :status_text, as: :text, input_html: { value: t('identity_proofs.publicize_toot', username: @proof.provider_username, service: @proof.provider.capitalize, url: @proof.badge.proof_url), rows: 4 }\n\n    = f.button :button, t('identity_proofs.authorize'), type: :submit\n    = link_to t('simple_form.no'), settings_identity_proofs_url, class: 'button negative'\n"
  },
  {
    "path": "app/views/settings/imports/show.html.haml",
    "content": "- content_for :page_title do\n  = t('settings.import')\n\n= simple_form_for @import, url: settings_import_path do |f|\n  .field-group\n    = f.input :type, collection: Import.types.keys, wrapper: :with_block_label, include_blank: false, label_method: lambda { |type| I18n.t(\"imports.types.#{type}\") }, hint: t('imports.preface')\n\n  .fields-row\n    .fields-group.fields-row__column.fields-row__column-6\n      = f.input :data, wrapper: :with_block_label, hint: t('simple_form.hints.imports.data')\n    .fields-group.fields-row__column.fields-row__column-6\n      = f.input :mode, as: :radio_buttons, collection: Import::MODES, label_method: lambda { |mode| safe_join([I18n.t(\"imports.modes.#{mode}\"), content_tag(:span, I18n.t(\"imports.modes.#{mode}_long\"), class: 'hint')]) }, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li'\n\n  .actions\n    = f.button :button, t('imports.upload'), type: :submit\n"
  },
  {
    "path": "app/views/settings/migrations/show.html.haml",
    "content": "- content_for :page_title do\n  = t('settings.migrate')\n\n= simple_form_for @migration, as: :migration, url: settings_migration_path, html: { method: :put } do |f|\n  - if @migration.account\n    %p.hint= t('migrations.currently_redirecting')\n\n    .fields-group\n      = render partial: 'application/card', locals: { account: @migration.account }\n\n  = render 'shared/error_messages', object: @migration\n\n  .fields-group\n    = f.input :acct, placeholder: t('migrations.acct')\n\n  .actions\n    = f.button :button, t('migrations.proceed'), type: :submit, class: 'negative'\n"
  },
  {
    "path": "app/views/settings/preferences/appearance/show.html.haml",
    "content": "- content_for :page_title do\n  = t('settings.appearance')\n\n= simple_form_for current_user, url: settings_preferences_appearance_path, html: { method: :put } do |f|\n  .fields-row\n    .fields-group.fields-row__column.fields-row__column-6\n      = f.input :locale, collection: I18n.available_locales, wrapper: :with_label, include_blank: false, label_method: lambda { |locale| human_locale(locale) }, selected: I18n.locale, hint: false\n    .fields-group.fields-row__column.fields-row__column-6\n      = f.input :setting_theme, collection: Themes.instance.names, label_method: lambda { |theme| I18n.t(\"themes.#{theme}\", default: theme) }, wrapper: :with_label, include_blank: false, hint: false\n\n  %h4= t 'appearance.advanced_web_interface'\n\n  %p.hint= t 'appearance.advanced_web_interface_hint'\n\n  .fields-group\n    = f.input :setting_advanced_layout, as: :boolean, wrapper: :with_label, hint: false\n\n  %h4= t 'appearance.animations_and_accessibility'\n\n  .fields-group\n    = f.input :setting_auto_play_gif, as: :boolean, wrapper: :with_label, recommended: true\n    = f.input :setting_reduce_motion, as: :boolean, wrapper: :with_label\n    = f.input :setting_system_font_ui, as: :boolean, wrapper: :with_label\n\n  %h4= t 'appearance.confirmation_dialogs'\n\n  .fields-group\n    = f.input :setting_unfollow_modal, as: :boolean, wrapper: :with_label\n    = f.input :setting_boost_modal, as: :boolean, wrapper: :with_label\n    = f.input :setting_delete_modal, as: :boolean, wrapper: :with_label\n\n  %h4= t 'appearance.sensitive_content'\n\n  .fields-group\n    = f.input :setting_display_media, collection: ['default', 'show_all', 'hide_all'],label_method: lambda { |item| t(\"simple_form.hints.defaults.setting_display_media_#{item}\") }, hint: false, as: :radio_buttons, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li', wrapper: :with_floating_label\n\n  .fields-group\n    = f.input :setting_expand_spoilers, as: :boolean, wrapper: :with_label\n\n  .actions\n    = f.button :button, t('generic.save_changes'), type: :submit\n"
  },
  {
    "path": "app/views/settings/preferences/notifications/show.html.haml",
    "content": "- content_for :page_title do\n  = t('settings.notifications')\n\n= simple_form_for current_user, url: settings_preferences_notifications_path, html: { method: :put } do |f|\n  = render 'shared/error_messages', object: current_user\n\n  .fields-group\n    = f.simple_fields_for :notification_emails, hash_to_object(current_user.settings.notification_emails) do |ff|\n      = ff.input :follow, as: :boolean, wrapper: :with_label\n      = ff.input :follow_request, as: :boolean, wrapper: :with_label\n      = ff.input :reblog, as: :boolean, wrapper: :with_label\n      = ff.input :favourite, as: :boolean, wrapper: :with_label\n      = ff.input :mention, as: :boolean, wrapper: :with_label\n\n      - if current_user.staff?\n        = ff.input :report, as: :boolean, wrapper: :with_label\n        = ff.input :pending_account, as: :boolean, wrapper: :with_label\n\n  .fields-group\n    = f.simple_fields_for :notification_emails, hash_to_object(current_user.settings.notification_emails) do |ff|\n      = ff.input :digest, as: :boolean, wrapper: :with_label\n\n  .fields-group\n    = f.simple_fields_for :interactions, hash_to_object(current_user.settings.interactions) do |ff|\n      = ff.input :must_be_follower, as: :boolean, wrapper: :with_label\n      = ff.input :must_be_following, as: :boolean, wrapper: :with_label\n      = ff.input :must_be_following_dm, as: :boolean, wrapper: :with_label\n\n  .actions\n    = f.button :button, t('generic.save_changes'), type: :submit\n"
  },
  {
    "path": "app/views/settings/preferences/other/show.html.haml",
    "content": "- content_for :page_title do\n  = t('settings.preferences')\n\n= simple_form_for current_user, url: settings_preferences_other_path, html: { method: :put } do |f|\n  = render 'shared/error_messages', object: current_user\n\n  .fields-group\n    = f.input :setting_noindex, as: :boolean, wrapper: :with_label\n\n  .fields-group\n    = f.input :setting_hide_network, as: :boolean, wrapper: :with_label\n\n  .fields-group\n    = f.input :setting_aggregate_reblogs, as: :boolean, wrapper: :with_label, recommended: true\n\n  %h4= t 'preferences.posting_defaults'\n\n  .fields-row\n    .fields-group.fields-row__column.fields-row__column-6\n      = f.input :setting_default_privacy, collection: Status.selectable_visibilities, wrapper: :with_label, include_blank: false, label_method: lambda { |visibility| safe_join([I18n.t(\"statuses.visibilities.#{visibility}\"), I18n.t(\"statuses.visibilities.#{visibility}_long\")], ' - ') }, required: false, hint: false\n\n    .fields-group.fields-row__column.fields-row__column-6\n      = f.input :setting_default_language, collection: [nil] + filterable_languages.sort, wrapper: :with_label, label_method: lambda { |locale| locale.nil? ? I18n.t('statuses.language_detection') : human_locale(locale) }, required: false, include_blank: false, hint: false\n\n  .fields-group\n    = f.input :setting_default_sensitive, as: :boolean, wrapper: :with_label\n\n  .fields-group\n    = f.input :setting_show_application, as: :boolean, wrapper: :with_label, recommended: true\n\n  %h4= t 'preferences.public_timelines'\n\n  .fields-group\n    = f.input :chosen_languages, collection: filterable_languages.sort, wrapper: :with_block_label, include_blank: false, label_method: lambda { |locale| human_locale(locale) }, required: false, as: :check_boxes, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li'\n\n  .actions\n    = f.button :button, t('generic.save_changes'), type: :submit\n"
  },
  {
    "path": "app/views/settings/profiles/show.html.haml",
    "content": "- content_for :page_title do\n  = t('settings.edit_profile')\n\n= simple_form_for @account, url: settings_profile_path, html: { method: :put } do |f|\n  = render 'shared/error_messages', object: @account\n\n  .fields-row\n    .fields-row__column.fields-group.fields-row__column-6\n      = f.input :display_name, wrapper: :with_label, input_html: { maxlength: 30 }, hint: false\n      = f.input :note, wrapper: :with_label, input_html: { maxlength: Setting.max_bio_chars.to_i }, hint: false\n\n  .fields-row\n    .fields-row__column.fields-row__column-6\n      = render 'application/card', account: @account\n\n    .fields-row__column.fields-group.fields-row__column-6\n      = f.input :header, wrapper: :with_label, input_html: { accept: AccountHeader::IMAGE_MIME_TYPES.join(',') }, hint: t('simple_form.hints.defaults.header', dimensions: '1500x500', size: number_to_human_size(AccountHeader::LIMIT))\n\n      = f.input :avatar, wrapper: :with_label, input_html: { accept: AccountAvatar::IMAGE_MIME_TYPES.join(',') }, hint: t('simple_form.hints.defaults.avatar', dimensions: '400x400', size: number_to_human_size(AccountAvatar::LIMIT))\n\n  %hr.spacer/\n\n  .fields-group\n    = f.input :locked, as: :boolean, wrapper: :with_label, hint: t('simple_form.hints.defaults.locked')\n\n  .fields-group\n    = f.input :bot, as: :boolean, wrapper: :with_label, hint: t('simple_form.hints.defaults.bot')\n\n  - if Setting.profile_directory\n    .fields-group\n      = f.input :discoverable, as: :boolean, wrapper: :with_label, hint: t('simple_form.hints.defaults.discoverable_html', min_followers: Account::MIN_FOLLOWERS_DISCOVERY, path: explore_path), recommended: true\n\n  %hr.spacer/\n\n  .fields-row\n    .fields-row__column.fields-group.fields-row__column-6\n      .input.with_block_label\n        %label= t('simple_form.labels.defaults.fields')\n        %span.hint= t('simple_form.hints.defaults.fields')\n\n        = f.simple_fields_for :fields do |fields_f|\n          .row\n            = fields_f.input :name, placeholder: t('simple_form.labels.account.fields.name'), input_html: { maxlength: 255 }\n            = fields_f.input :value, placeholder: t('simple_form.labels.account.fields.value'), input_html: { maxlength: 255 }\n\n    .fields-row__column.fields-group.fields-row__column-6\n      %h6= t('verification.verification')\n      %p.hint= t('verification.explanation_html')\n\n      .input-copy\n        .input-copy__wrapper\n          %input{ type: :text, maxlength: '999', spellcheck: 'false', readonly: 'true', value: link_to('Mastodon', ActivityPub::TagManager.instance.url_for(@account), rel: 'me').to_str }\n        %button{ type: :button }= t('generic.copy')\n\n  .actions\n    = f.button :button, t('generic.save_changes'), type: :submit\n\n%hr/\n\n%h6= t('auth.migrate_account')\n%p.muted-hint= t('auth.migrate_account_html', path: settings_migration_path)\n\n- if open_deletion?\n  %hr.spacer/\n\n  %h6= t('auth.delete_account')\n  %p.muted-hint= t('auth.delete_account_html', path: settings_delete_path)\n"
  },
  {
    "path": "app/views/settings/shared/_links.html.haml",
    "content": "%ul.no-list\n  - if controller_name != 'profiles'\n    %li= link_to t('settings.edit_profile'), settings_profile_path\n  - if controller_name != 'preferences'\n    %li= link_to t('settings.preferences'), settings_preferences_path\n  - if controller_name != 'registrations'\n    %li= link_to t('auth.change_password'), edit_user_registration_path\n  - if controller_name != 'two_factor_authentications'\n    %li= link_to t('settings.two_factor_authentication'), settings_two_factor_authentication_path\n  %li= link_to t('settings.back'), root_path\n"
  },
  {
    "path": "app/views/settings/two_factor_authentication/confirmations/new.html.haml",
    "content": "- content_for :page_title do\n  = t('settings.two_factor_authentication')\n\n= simple_form_for @confirmation, url: settings_two_factor_authentication_confirmation_path, method: :post do |f|\n  %p.hint= t('two_factor_authentication.instructions_html')\n\n  .qr-wrapper\n    .qr-code!= @qrcode.as_svg(padding: 0, module_size: 4)\n\n    .qr-alternative\n      %p.hint= t('two_factor_authentication.manual_instructions')\n      %samp.qr-alternative__code= current_user.otp_secret.scan(/.{4}/).join(' ')\n\n  .fields-group\n    = f.input :code, wrapper: :with_label, hint: t('two_factor_authentication.code_hint'), label: t('simple_form.labels.defaults.otp_attempt'), input_html: { :autocomplete => 'off' }, required: true\n\n  .actions\n    = f.button :button, t('two_factor_authentication.enable'), type: :submit\n"
  },
  {
    "path": "app/views/settings/two_factor_authentication/recovery_codes/index.html.haml",
    "content": "- content_for :page_title do\n  = t('settings.two_factor_authentication')\n\n%p.hint= t('two_factor_authentication.recovery_instructions_html')\n\n%ol.recovery-codes\n  - @recovery_codes.each do |code|\n    %li<\n      %samp= code\n"
  },
  {
    "path": "app/views/settings/two_factor_authentications/show.html.haml",
    "content": "- content_for :page_title do\n  = t('settings.two_factor_authentication')\n\n- if current_user.otp_required_for_login\n  %p.positive-hint\n    = fa_icon 'check'\n    = ' '\n    = t 'two_factor_authentication.enabled'\n\n  %hr/\n\n  = simple_form_for @confirmation, url: settings_two_factor_authentication_path, method: :delete do |f|\n    = f.input :code, wrapper: :with_label, hint: t('two_factor_authentication.code_hint'), label: t('simple_form.labels.defaults.otp_attempt'), input_html: { :autocomplete => 'off' }, required: true\n\n    .actions\n      = f.button :button, t('two_factor_authentication.disable'), type: :submit\n\n  %hr/\n\n  %h6= t('two_factor_authentication.recovery_codes')\n  %p.muted-hint\n    = t('two_factor_authentication.lost_recovery_codes')\n    = link_to t('two_factor_authentication.generate_recovery_codes'),\n      settings_two_factor_authentication_recovery_codes_path,\n      data: { method: :post }\n\n- else\n  .simple_form\n    %p.hint= t('two_factor_authentication.description_html')\n\n    = link_to t('two_factor_authentication.setup'),\n      settings_two_factor_authentication_path,\n      data: { method: :post },\n      class: 'block-button'\n"
  },
  {
    "path": "app/views/shared/_error_messages.html.haml",
    "content": "- if object.errors.any?\n  .flash-message.alert#error_explanation\n    %strong= t('generic.validation_errors', count: object.errors.count)\n"
  },
  {
    "path": "app/views/shared/_og.html.haml",
    "content": "- thumbnail = @instance_presenter.thumbnail\n- description = strip_tags(@instance_presenter.site_short_description.presence || @instance_presenter.site_description.presence || t('about.about_mastodon_html'))\n\n%meta{ name: 'description', content: description }/\n\n= opengraph 'og:site_name', t('about.hosted_on', domain: site_hostname)\n= opengraph 'og:url', url_for(only_path: false)\n= opengraph 'og:type', 'website'\n= opengraph 'og:title', @instance_presenter.site_title\n= opengraph 'og:description', description\n= opengraph 'og:image', full_asset_url(thumbnail&.file&.url || asset_pack_path('media/images/preview.jpg', protocol: :request))\n= opengraph 'og:image:width', thumbnail ? thumbnail.meta['width'] : '1200'\n= opengraph 'og:image:height', thumbnail ? thumbnail.meta['height'] : '630'\n= opengraph 'twitter:card', 'summary_large_image'\n"
  },
  {
    "path": "app/views/shares/show.html.haml",
    "content": "- content_for :header_tags do\n  %script#initial-state{ type: 'application/json' }!= json_escape(@initial_state_json)\n  = javascript_pack_tag 'share', integrity: true, crossorigin: 'anonymous'\n\n#mastodon-compose{ data: { props: Oj.dump(default_props) } }\n"
  },
  {
    "path": "app/views/stream_entries/_attachment_list.html.haml",
    "content": ".attachment-list\n  .attachment-list__icon\n    = fa_icon 'link'\n  %ul.attachment-list__list\n    - attachments.each do |media|\n      %li\n        - url = media.remote_url.presence || media.file.url\n        = link_to File.basename(url), url, title: media.description\n"
  },
  {
    "path": "app/views/stream_entries/_detailed_status.html.haml",
    "content": ".detailed-status.detailed-status--flex\n  .p-author.h-card\n    = link_to TagManager.instance.url_for(status.account), class: 'detailed-status__display-name u-url', target: stream_link_target, rel: 'noopener' do\n      .detailed-status__display-avatar\n        - if current_account&.user&.setting_auto_play_gif || autoplay\n          = image_tag status.account.avatar_original_url, width: 48, height: 48, alt: '', class: 'account__avatar u-photo'\n        - else\n          = image_tag status.account.avatar_static_url, width: 48, height: 48, alt: '', class: 'account__avatar u-photo'\n      %span.display-name\n        %bdi\n          %strong.display-name__html.p-name.emojify= display_name(status.account, custom_emojify: true, autoplay: autoplay)\n        %span.display-name__account\n          = acct(status.account)\n          = fa_icon('lock') if status.account.locked?\n\n  = account_action_button(status.account)\n\n  .status__content.emojify<\n    - if status.spoiler_text?\n      %p{ :style => ('margin-bottom: 0' unless current_account&.user&.setting_expand_spoilers) }<\n        %span.p-summary> #{Formatter.instance.format_spoiler(status, autoplay: autoplay)}&nbsp;\n        %button.status__content__spoiler-link= t('statuses.show_more')\n    .e-content{ lang: status.language, style: \"display: #{!current_account&.user&.setting_expand_spoilers && status.spoiler_text? ? 'none' : 'block'}; direction: #{rtl_status?(status) ? 'rtl' : 'ltr'}\" }\n      = Formatter.instance.format(status, custom_emojify: true, autoplay: autoplay)\n      - if status.preloadable_poll\n        = react_component :poll, disabled: true, poll: ActiveModelSerializers::SerializableResource.new(status.preloadable_poll, serializer: REST::PollSerializer, scope: current_user, scope_name: :current_user).as_json do\n          = render partial: 'stream_entries/poll', locals: { status: status, poll: status.preloadable_poll, autoplay: autoplay }\n\n  - if !status.media_attachments.empty?\n    - if status.media_attachments.first.video?\n      - video = status.media_attachments.first\n      = react_component :video, src: video.file.url(:original), preview: video.file.url(:small), blurhash: video.blurhash, sensitive: !current_account&.user&.show_all_media? && status.sensitive? || current_account&.user&.hide_all_media?, width: 670, height: 380, detailed: true, inline: true, alt: video.description do\n        = render partial: 'stream_entries/attachment_list', locals: { attachments: status.media_attachments }\n    - else\n      = react_component :media_gallery, height: 380, sensitive: !current_account&.user&.show_all_media? && status.sensitive? || current_account&.user&.hide_all_media?, standalone: true, 'autoPlayGif': current_account&.user&.setting_auto_play_gif || autoplay, 'reduceMotion': current_account&.user&.setting_reduce_motion, media: status.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json } do\n        = render partial: 'stream_entries/attachment_list', locals: { attachments: status.media_attachments }\n  - elsif status.preview_card\n    = react_component :card, 'maxDescription': 160, card: ActiveModelSerializers::SerializableResource.new(status.preview_card, serializer: REST::PreviewCardSerializer).as_json\n\n  .detailed-status__meta\n    %data.dt-published{ value: status.created_at.to_time.iso8601 }\n\n    = link_to TagManager.instance.url_for(status), class: 'detailed-status__datetime u-url u-uid', target: stream_link_target, rel: 'noopener' do\n      %time.formatted{ datetime: status.created_at.iso8601, title: l(status.created_at) }= l(status.created_at)\n    ·\n    - if status.application && @account.user&.setting_show_application\n      - if status.application.website.blank?\n        %strong.detailed-status__application= status.application.name\n      - else\n        = link_to status.application.name, status.application.website, class: 'detailed-status__application', target: '_blank', rel: 'noopener'\n      ·\n    = link_to remote_interaction_path(status, type: :reply), class: 'modal-button detailed-status__link' do\n      - if status.in_reply_to_id.nil?\n        = fa_icon('reply')\n      - else\n        = fa_icon('reply-all')\n      %span.detailed-status__reblogs>= number_to_human status.replies_count, strip_insignificant_zeros: true\n      = \" \"\n    ·\n    - if status.direct_visibility?\n      %span.detailed-status__link<\n        = fa_icon('envelope')\n    - elsif status.private_visibility? || status.limited_visibility?\n      %span.detailed-status__link<\n        = fa_icon('lock')\n    - else\n      = link_to remote_interaction_path(status, type: :reblog), class: 'modal-button detailed-status__link' do\n        = fa_icon('retweet')\n        %span.detailed-status__reblogs>= number_to_human status.reblogs_count, strip_insignificant_zeros: true\n        = \" \"\n    ·\n    = link_to remote_interaction_path(status, type: :favourite), class: 'modal-button detailed-status__link' do\n      = fa_icon('star')\n      %span.detailed-status__favorites>= number_to_human status.favourites_count, strip_insignificant_zeros: true\n      = \" \"\n\n    - if user_signed_in?\n      ·\n      = link_to t('statuses.open_in_web'), web_url(\"statuses/#{status.id}\"), class: 'detailed-status__application', target: '_blank'\n"
  },
  {
    "path": "app/views/stream_entries/_og_description.html.haml",
    "content": "- description = status_description(activity)\n\n%meta{ name: 'description', content: description }/\n= opengraph 'og:description', description\n"
  },
  {
    "path": "app/views/stream_entries/_og_image.html.haml",
    "content": "- if activity.is_a?(Status) && (activity.non_sensitive_with_media? || (activity.with_media? && Setting.preview_sensitive_media))\n  - player_card = false\n  - activity.media_attachments.each do |media|\n    - if media.image?\n      = opengraph 'og:image', full_asset_url(media.file.url(:original))\n      = opengraph 'og:image:type', media.file_content_type\n      - unless media.file.meta.nil?\n        = opengraph 'og:image:width', media.file.meta.dig('original', 'width')\n        = opengraph 'og:image:height', media.file.meta.dig('original', 'height')\n      - if media.description.present?\n        = opengraph 'og:image:alt', media.description\n    - elsif media.video? || media.gifv?\n      - player_card = true\n      = opengraph 'og:image', full_asset_url(media.file.url(:small))\n      = opengraph 'og:image:type', 'image/png'\n      - unless media.file.meta.nil?\n        = opengraph 'og:image:width', media.file.meta.dig('small', 'width')\n        = opengraph 'og:image:height', media.file.meta.dig('small', 'height')\n      = opengraph 'og:video', full_asset_url(media.file.url(:original))\n      = opengraph 'og:video:secure_url', full_asset_url(media.file.url(:original))\n      = opengraph 'og:video:type', media.file_content_type\n      = opengraph 'twitter:player', medium_player_url(media)\n      = opengraph 'twitter:player:stream', full_asset_url(media.file.url(:original))\n      = opengraph 'twitter:player:stream:content_type', media.file_content_type\n      - unless media.file.meta.nil?\n        = opengraph 'og:video:width', media.file.meta.dig('original', 'width')\n        = opengraph 'og:video:height', media.file.meta.dig('original', 'height')\n        = opengraph 'twitter:player:width', media.file.meta.dig('original', 'width')\n        = opengraph 'twitter:player:height', media.file.meta.dig('original', 'height')\n  - if player_card\n    = opengraph 'twitter:card', 'player'\n  - else\n    = opengraph 'twitter:card', 'summary_large_image'\n- else\n  = opengraph 'og:image', full_asset_url(account.avatar.url(:original))\n  = opengraph 'og:image:width', '120'\n  = opengraph 'og:image:height','120'\n  = opengraph 'twitter:card', 'summary'\n"
  },
  {
    "path": "app/views/stream_entries/_poll.html.haml",
    "content": "- show_results = (user_signed_in? && poll.voted?(current_account)) || poll.expired?\n\n.poll\n  %ul\n    - poll.loaded_options.each do |option|\n      %li\n        - if show_results\n          - percent = poll.votes_count > 0 ? 100 * option.votes_count / poll.votes_count : 0\n          %span.poll__chart{ style: \"width: #{percent}%\" }\n\n          %label.poll__text><\n            %span.poll__number= percent.round\n            = Formatter.instance.format_poll_option(status, option, autoplay: autoplay)\n        - else\n          %label.poll__text><\n            %span.poll__input{ class: poll.multiple? ? 'checkbox' : nil}><\n            = Formatter.instance.format_poll_option(status, option, autoplay: autoplay)\n  .poll__footer\n    - unless show_results\n      %button.button.button-secondary{ disabled: true }\n        = t('statuses.poll.vote')\n\n    %span= t('statuses.poll.total_votes', count: poll.votes_count)\n\n    - unless poll.expires_at.nil?\n      ·\n      %span= l poll.expires_at\n"
  },
  {
    "path": "app/views/stream_entries/_simple_status.html.haml",
    "content": ".status\n  .status__info\n    = link_to TagManager.instance.url_for(status), class: 'status__relative-time u-url u-uid', target: stream_link_target, rel: 'noopener' do\n      %time.time-ago{ datetime: status.created_at.iso8601, title: l(status.created_at) }= l(status.created_at)\n    %data.dt-published{ value: status.created_at.to_time.iso8601 }\n\n    .p-author.h-card\n      = link_to TagManager.instance.url_for(status.account), class: 'status__display-name u-url', target: stream_link_target, rel: 'noopener' do\n        .status__avatar\n          %div\n            - if current_account&.user&.setting_auto_play_gif || autoplay\n              = image_tag status.account.avatar_original_url, width: 48, height: 48, alt: '', class: 'u-photo account__avatar'\n            - else\n              = image_tag status.account.avatar_static_url, width: 48, height: 48, alt: '', class: 'u-photo account__avatar'\n        %span.display-name\n          %bdi\n            %strong.display-name__html.p-name.emojify= display_name(status.account, custom_emojify: true, autoplay: autoplay)\n          &nbsp;\n          %span.display-name__account\n            = acct(status.account)\n            = fa_icon('lock') if status.account.locked?\n  .status__content.emojify<\n    - if status.spoiler_text?\n      %p{ :style => ('margin-bottom: 0' unless current_account&.user&.setting_expand_spoilers) }<\n        %span.p-summary> #{Formatter.instance.format_spoiler(status, autoplay: autoplay)}&nbsp;\n        %button.status__content__spoiler-link= t('statuses.show_more')\n    .e-content{ lang: status.language, style: \"display: #{!current_account&.user&.setting_expand_spoilers && status.spoiler_text? ? 'none' : 'block'}; direction: #{rtl_status?(status) ? 'rtl' : 'ltr'}\" }\n      = Formatter.instance.format(status, custom_emojify: true, autoplay: autoplay)\n      - if status.preloadable_poll\n        = react_component :poll, disabled: true, poll: ActiveModelSerializers::SerializableResource.new(status.preloadable_poll, serializer: REST::PollSerializer, scope: current_user, scope_name: :current_user).as_json do\n          = render partial: 'stream_entries/poll', locals: { status: status, poll: status.preloadable_poll, autoplay: autoplay }\n\n  - if !status.media_attachments.empty?\n    - if status.media_attachments.first.video?\n      - video = status.media_attachments.first\n      = react_component :video, src: video.file.url(:original), preview: video.file.url(:small), blurhash: video.blurhash, sensitive: !current_account&.user&.show_all_media? && status.sensitive? || current_account&.user&.hide_all_media?, width: 610, height: 343, inline: true, alt: video.description do\n        = render partial: 'stream_entries/attachment_list', locals: { attachments: status.media_attachments }\n    - else\n      = react_component :media_gallery, height: 343, sensitive: !current_account&.user&.show_all_media? && status.sensitive? || current_account&.user&.hide_all_media?, 'autoPlayGif': current_account&.user&.setting_auto_play_gif || autoplay, media: status.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json } do\n        = render partial: 'stream_entries/attachment_list', locals: { attachments: status.media_attachments }\n  - elsif status.preview_card\n    = react_component :card, 'maxDescription': 160, card: ActiveModelSerializers::SerializableResource.new(status.preview_card, serializer: REST::PreviewCardSerializer).as_json\n\n  .status__action-bar\n    .status__action-bar__counter\n      = link_to remote_interaction_path(status, type: :reply), class: 'status__action-bar-button icon-button modal-button', style: 'font-size: 18px; width: 23.1429px; height: 23.1429px; line-height: 23.15px;' do\n        - if status.in_reply_to_id.nil?\n          = fa_icon 'reply fw'\n        - else\n          = fa_icon 'reply-all fw'\n      .status__action-bar__counter__label= obscured_counter status.replies_count\n    = link_to remote_interaction_path(status, type: :reblog), class: 'status__action-bar-button icon-button modal-button', style: 'font-size: 18px; width: 23.1429px; height: 23.1429px; line-height: 23.15px;' do\n      - if status.public_visibility? || status.unlisted_visibility?\n        = fa_icon 'retweet fw'\n      - elsif status.private_visibility?\n        = fa_icon 'lock fw'\n      - else\n        = fa_icon 'envelope fw'\n    = link_to remote_interaction_path(status, type: :favourite), class: 'status__action-bar-button icon-button modal-button', style: 'font-size: 18px; width: 23.1429px; height: 23.1429px; line-height: 23.15px;' do\n      = fa_icon 'star fw'\n"
  },
  {
    "path": "app/views/stream_entries/_status.html.haml",
    "content": ":ruby\n  pinned          ||= false\n  include_threads ||= false\n  is_predecessor  ||= false\n  is_successor    ||= false\n  direct_reply_id ||= false\n  parent_id       ||= false\n  autoplay        ||= current_account&.user&.setting_auto_play_gif\n  is_direct_parent  = direct_reply_id == status.id\n  is_direct_child   = parent_id == status.in_reply_to_id\n  centered        ||= include_threads && !is_predecessor && !is_successor\n  h_class           = microformats_h_class(status, is_predecessor, is_successor, include_threads)\n  style_classes     = style_classes(status, is_predecessor, is_successor, include_threads)\n  mf_classes        = microformats_classes(status, is_direct_parent, is_direct_child)\n  entry_classes     = h_class + ' ' + mf_classes + ' ' + style_classes\n\n- if status.reply? && include_threads\n  - if @next_ancestor\n    .entry{ class: entry_classes }\n      = link_to_more TagManager.instance.url_for(@next_ancestor)\n\n  = render partial: 'stream_entries/status', collection: @ancestors, as: :status, locals: { is_predecessor: true, direct_reply_id: status.in_reply_to_id }, autoplay: autoplay\n\n.entry{ class: entry_classes }\n\n  - if status.reblog?\n    .status__prepend\n      .status__prepend-icon-wrapper\n        %i.status__prepend-icon.fa.fa-fw.fa-retweet\n      %span\n        = link_to TagManager.instance.url_for(status.account), class: 'status__display-name muted' do\n          %bdi\n            %strong.emojify= display_name(status.account, custom_emojify: true)\n        = t('stream_entries.reblogged')\n  - elsif pinned\n    .status__prepend\n      .status__prepend-icon-wrapper\n        %i.status__prepend-icon.fa.fa-fw.fa-thumb-tack\n      %span\n        = t('stream_entries.pinned')\n\n  = render (centered ? 'stream_entries/detailed_status' : 'stream_entries/simple_status'), status: status.proper, autoplay: autoplay\n\n- if include_threads\n  - if @since_descendant_thread_id\n    .entry{ class: entry_classes }\n      = link_to_more short_account_status_url(status.account.username, status, max_descendant_thread_id: @since_descendant_thread_id + 1)\n  - @descendant_threads.each do |thread|\n    = render partial: 'stream_entries/status', collection: thread[:statuses], as: :status, locals: { is_successor: true, parent_id: status.id }, autoplay: autoplay\n\n    - if thread[:next_status]\n      .entry{ class: entry_classes }\n        = link_to_more TagManager.instance.url_for(thread[:next_status])\n  - if @next_descendant_thread\n    .entry{ class: entry_classes }\n      = link_to_more short_account_status_url(status.account.username, status, since_descendant_thread_id: @max_descendant_thread_id - 1)\n\n- if include_threads && !embedded_view? && !user_signed_in?\n  .entry{ class: entry_classes }\n    = link_to new_user_session_path, class: 'load-more load-gap' do\n      = fa_icon 'comments'\n      = t('statuses.sign_in_to_participate')\n"
  },
  {
    "path": "app/views/stream_entries/embed.html.haml",
    "content": "- cache @stream_entry.activity do\n  .activity-stream.activity-stream--headless\n    = render \"stream_entries/#{@type}\", @type.to_sym => @stream_entry.activity, centered: true, autoplay: @autoplay\n"
  },
  {
    "path": "app/views/stream_entries/show.html.haml",
    "content": "- content_for :page_title do\n  = t('statuses.title', name: display_name(@account), quote: truncate(@stream_entry.activity.spoiler_text.presence || @stream_entry.activity.text, length: 50, omission: '…', escape: false))\n\n- content_for :header_tags do\n  - if @account.user&.setting_noindex\n    %meta{ name: 'robots', content: 'noindex' }/\n\n  %link{ rel: 'alternate', type: 'application/atom+xml', href: account_stream_entry_url(@account, @stream_entry, format: 'atom') }/\n  %link{ rel: 'alternate', type: 'application/json+oembed', href: api_oembed_url(url: account_stream_entry_url(@account, @stream_entry), format: 'json') }/\n  %link{ rel: 'alternate', type: 'application/activity+json', href: ActivityPub::TagManager.instance.uri_for(@stream_entry.activity) }/\n\n  = opengraph 'og:site_name', site_title\n  = opengraph 'og:type', 'article'\n  = opengraph 'og:title', \"#{display_name(@account)} (@#{@account.local_username_and_domain})\"\n  = opengraph 'og:url', short_account_status_url(@account, @stream_entry.activity)\n\n  = render 'stream_entries/og_description', activity: @stream_entry.activity\n  = render 'stream_entries/og_image', activity: @stream_entry.activity, account: @account\n\n.grid\n  .column-0\n    .activity-stream.h-entry\n      = render partial: \"stream_entries/#{@type}\", locals: { @type.to_sym => @stream_entry.activity, include_threads: true }\n  .column-1\n    = render 'application/sidebar'\n"
  },
  {
    "path": "app/views/tags/_og.html.haml",
    "content": "= opengraph 'og:site_name', t('about.hosted_on', domain: site_hostname)\n= opengraph 'og:url', tag_url(@tag)\n= opengraph 'og:type', 'website'\n= opengraph 'og:title', \"##{@tag.name}\"\n= opengraph 'og:description', strip_tags(t('about.about_hashtag_html', hashtag: @tag.name))\n= opengraph 'twitter:card', 'summary'\n"
  },
  {
    "path": "app/views/tags/show.html.haml",
    "content": "- content_for :page_title do\n  = \"##{@tag.name}\"\n\n- content_for :header_tags do\n  %meta{ name: 'robots', content: 'noindex' }/\n  %link{ rel: 'alternate', type: 'application/rss+xml', href: tag_url(@tag, format: 'rss') }/\n\n  %script#initial-state{ type: 'application/json' }!= json_escape(@initial_state_json)\n  = javascript_pack_tag 'about', integrity: true, crossorigin: 'anonymous'\n  = render 'og'\n\n.page-header\n  %h1= \"##{@tag.name}\"\n  %p= t('about.about_hashtag_html', hashtag: @tag.name)\n\n#mastodon-timeline{ data: { props: Oj.dump(default_props.merge(hashtag: @tag.name)) }}\n#modal-container\n"
  },
  {
    "path": "app/views/user_mailer/backup_ready.html.haml",
    "content": "%table.email-table{ cellspacing: 0, cellpadding: 0 }\n  %tbody\n    %tr\n      %td.email-body\n        .email-container\n          %table.content-section{ cellspacing: 0, cellpadding: 0 }\n            %tbody\n              %tr\n                %td.content-cell.hero\n                  .email-row\n                    .col-6\n                      %table.column{ cellspacing: 0, cellpadding: 0 }\n                        %tbody\n                          %tr\n                            %td.column-cell.text-center.padded\n                              %table.hero-icon{ align: 'center', cellspacing: 0, cellpadding: 0 }\n                                %tbody\n                                  %tr\n                                    %td\n                                      = image_tag full_pack_url('media/images/mailer/icon_file_download.png'), alt: ''\n\n                              %h1= t 'user_mailer.backup_ready.title'\n\n%table.email-table{ cellspacing: 0, cellpadding: 0 }\n  %tbody\n    %tr\n      %td.email-body\n        .email-container\n          %table.content-section{ cellspacing: 0, cellpadding: 0 }\n            %tbody\n              %tr\n                %td.content-cell.content-start\n                  .email-row\n                    .col-6\n                      %table.column{ cellspacing: 0, cellpadding: 0 }\n                        %tbody\n                          %tr\n                            %td.column-cell.text-center\n                              %p= t 'user_mailer.backup_ready.explanation'\n\n%table.email-table{ cellspacing: 0, cellpadding: 0 }\n  %tbody\n    %tr\n      %td.email-body\n        .email-container\n          %table.content-section{ cellspacing: 0, cellpadding: 0 }\n            %tbody\n              %tr\n                %td.content-cell\n                  %table.column{ cellspacing: 0, cellpadding: 0 }\n                    %tbody\n                      %tr\n                        %td.column-cell.button-cell\n                          %table.button{ align: 'center', cellspacing: 0, cellpadding: 0 }\n                            %tbody\n                              %tr\n                                %td.button-primary\n                                  = link_to full_asset_url(@backup.dump.url) do\n                                    %span= t 'exports.archive_takeout.download'\n"
  },
  {
    "path": "app/views/user_mailer/backup_ready.text.erb",
    "content": "<%= t 'user_mailer.backup_ready.title' %>\n\n===\n\n<%= t 'user_mailer.backup_ready.explanation' %>\n\n=> <%= full_asset_url(@backup.dump.url) %>\n"
  },
  {
    "path": "app/views/user_mailer/confirmation_instructions.html.haml",
    "content": "%table.email-table{ cellspacing: 0, cellpadding: 0 }\n  %tbody\n    %tr\n      %td.email-body\n        .email-container\n          %table.content-section{ cellspacing: 0, cellpadding: 0 }\n            %tbody\n              %tr\n                %td.content-cell.hero\n                  .email-row\n                    .col-6\n                      %table.column{ cellspacing: 0, cellpadding: 0 }\n                        %tbody\n                          %tr\n                            %td.column-cell.text-center.padded\n                              %table.hero-icon{ align: 'center', cellspacing: 0, cellpadding: 0 }\n                                %tbody\n                                  %tr\n                                    %td\n                                      = image_tag full_pack_url('media/images/mailer/icon_email.png'), alt: ''\n\n                              %h1= t 'devise.mailer.confirmation_instructions.title'\n\n%table.email-table{ cellspacing: 0, cellpadding: 0 }\n  %tbody\n    %tr\n      %td.email-body\n        .email-container\n          %table.content-section{ cellspacing: 0, cellpadding: 0 }\n            %tbody\n              %tr\n                %td.content-cell.content-start\n                  .email-row\n                    .col-6\n                      %table.column{ cellspacing: 0, cellpadding: 0 }\n                        %tbody\n                          %tr\n                            %td.column-cell.text-center\n                              %p= t @resource.approved? ? 'devise.mailer.confirmation_instructions.explanation' : 'devise.mailer.confirmation_instructions.explanation_when_pending', host: site_hostname\n\n%table.email-table{ cellspacing: 0, cellpadding: 0 }\n  %tbody\n    %tr\n      %td.email-body\n        .email-container\n          %table.content-section{ cellspacing: 0, cellpadding: 0 }\n            %tbody\n              %tr\n                %td.content-cell\n                  %table.column{ cellspacing: 0, cellpadding: 0 }\n                    %tbody\n                      %tr\n                        %td.column-cell.button-cell\n                          %table.button{ align: 'center', cellspacing: 0, cellpadding: 0 }\n                            %tbody\n                              %tr\n                                %td.button-primary\n                                  - if @resource.created_by_application\n                                    = link_to confirmation_url(@resource, confirmation_token: @token, redirect_to_app: 'true') do\n                                      %span= t 'devise.mailer.confirmation_instructions.action_with_app', app: @resource.created_by_application.name\n                                  - else\n                                    = link_to confirmation_url(@resource, confirmation_token: @token) do\n                                      %span= t 'devise.mailer.confirmation_instructions.action'\n\n%table.email-table{ cellspacing: 0, cellpadding: 0 }\n  %tbody\n    %tr\n      %td.email-body\n        .email-container\n          %table.content-section{ cellspacing: 0, cellpadding: 0 }\n            %tbody\n              %tr\n                %td.content-cell\n                  .email-row\n                    .col-6\n                      %table.column{ cellspacing: 0, cellpadding: 0 }\n                        %tbody\n                          %tr\n                            %td.column-cell.text-center\n                              %p= t 'devise.mailer.confirmation_instructions.extra_html', terms_path: about_more_url, policy_path: terms_url\n"
  },
  {
    "path": "app/views/user_mailer/confirmation_instructions.text.erb",
    "content": "<%= t 'devise.mailer.confirmation_instructions.title' %>\n\n===\n\n<%= t @resource.approved? ? 'devise.mailer.confirmation_instructions.explanation' : 'devise.mailer.confirmation_instructions.explanation_when_pending', host: site_hostname %>\n\n=> <%= confirmation_url(@resource, confirmation_token: @token, redirect_to_app: @resource.created_by_application ? 'true' : nil) %>\n\n<%= strip_tags(t('devise.mailer.confirmation_instructions.extra_html', terms_path: about_more_url, policy_path: terms_url)) %>\n\n=> <%= about_more_url %>\n=> <%= terms_url %>\n"
  },
  {
    "path": "app/views/user_mailer/email_changed.html.haml",
    "content": "%table.email-table{ cellspacing: 0, cellpadding: 0 }\n  %tbody\n    %tr\n      %td.email-body\n        .email-container\n          %table.content-section{ cellspacing: 0, cellpadding: 0 }\n            %tbody\n              %tr\n                %td.content-cell.hero\n                  .email-row\n                    .col-6\n                      %table.column{ cellspacing: 0, cellpadding: 0 }\n                        %tbody\n                          %tr\n                            %td.column-cell.text-center.padded\n                              %table.hero-icon{ align: 'center', cellspacing: 0, cellpadding: 0 }\n                                %tbody\n                                  %tr\n                                    %td\n                                      = image_tag full_pack_url('media/images/mailer/icon_email.png'), alt: ''\n\n                              %h1= t 'devise.mailer.email_changed.title'\n                              %p.lead= t 'devise.mailer.email_changed.explanation'\n\n%table.email-table{ cellspacing: 0, cellpadding: 0 }\n  %tbody\n    %tr\n      %td.email-body\n        .email-container\n          %table.content-section{ cellspacing: 0, cellpadding: 0 }\n            %tbody\n              %tr\n                %td.content-cell.content-start\n                  %table.column{ cellspacing: 0, cellpadding: 0 }\n                    %tbody\n                      %tr\n                        %td.column-cell.input-cell\n                          %table.input{ align: 'center', cellspacing: 0, cellpadding: 0 }\n                            %tbody\n                              %tr\n                                %td= @resource.try(:unconfirmed_email) ? @resource.unconfirmed_email : @resource.email\n\n%table.email-table{ cellspacing: 0, cellpadding: 0 }\n  %tbody\n    %tr\n      %td.email-body\n        .email-container\n          %table.content-section{ cellspacing: 0, cellpadding: 0 }\n            %tbody\n              %tr\n                %td.content-cell\n                  .email-row\n                    .col-6\n                      %table.column{ cellspacing: 0, cellpadding: 0 }\n                        %tbody\n                          %tr\n                            %td.column-cell.text-center.padded\n                              %p= t 'devise.mailer.email_changed.extra'\n"
  },
  {
    "path": "app/views/user_mailer/email_changed.text.erb",
    "content": "<%= t 'devise.mailer.email_changed.title' %>\n\n===\n\n<%= t 'devise.mailer.email_changed.explanation' %>\n\n<%= @resource.try(:unconfirmed_email) ? @resource.unconfirmed_email : @resource.email %>\n\n<%= t 'devise.mailer.email_changed.extra' %>\n"
  },
  {
    "path": "app/views/user_mailer/password_change.html.haml",
    "content": "%table.email-table{ cellspacing: 0, cellpadding: 0 }\n  %tbody\n    %tr\n      %td.email-body\n        .email-container\n          %table.content-section{ cellspacing: 0, cellpadding: 0 }\n            %tbody\n              %tr\n                %td.content-cell.hero\n                  .email-row\n                    .col-6\n                      %table.column{ cellspacing: 0, cellpadding: 0 }\n                        %tbody\n                          %tr\n                            %td.column-cell.text-center.padded\n                              %table.hero-icon{ align: 'center', cellspacing: 0, cellpadding: 0 }\n                                %tbody\n                                  %tr\n                                    %td\n                                      = image_tag full_pack_url('media/images/mailer/icon_lock_open.png'), alt: ''\n\n                              %h1= t 'devise.mailer.password_change.title'\n                              %p.lead= t 'devise.mailer.password_change.explanation'\n\n%table.email-table{ cellspacing: 0, cellpadding: 0 }\n  %tbody\n    %tr\n      %td.email-body\n        .email-container\n          %table.content-section{ cellspacing: 0, cellpadding: 0 }\n            %tbody\n              %tr\n                %td.content-cell.content-start\n                  .email-row\n                    .col-6\n                      %table.column{ cellspacing: 0, cellpadding: 0 }\n                        %tbody\n                          %tr\n                            %td.column-cell.text-center.padded\n                              %p= t 'devise.mailer.password_change.extra'\n"
  },
  {
    "path": "app/views/user_mailer/password_change.text.erb",
    "content": "<%= t 'devise.mailer.password_change.title' %>\n\n===\n\n<%= t 'devise.mailer.password_change.explanation' %>\n\n<%= t 'devise.mailer.password_change.extra' %>\n"
  },
  {
    "path": "app/views/user_mailer/reconfirmation_instructions.html.haml",
    "content": "%table.email-table{ cellspacing: 0, cellpadding: 0 }\n  %tbody\n    %tr\n      %td.email-body\n        .email-container\n          %table.content-section{ cellspacing: 0, cellpadding: 0 }\n            %tbody\n              %tr\n                %td.content-cell.hero\n                  .email-row\n                    .col-6\n                      %table.column{ cellspacing: 0, cellpadding: 0 }\n                        %tbody\n                          %tr\n                            %td.column-cell.text-center.padded\n                              %table.hero-icon{ align: 'center', cellspacing: 0, cellpadding: 0 }\n                                %tbody\n                                  %tr\n                                    %td\n                                      = image_tag full_pack_url('media/images/mailer/icon_email.png'), alt: ''\n\n                              %h1= t 'devise.mailer.reconfirmation_instructions.title'\n                              %p.lead= t 'devise.mailer.reconfirmation_instructions.explanation'\n\n%table.email-table{ cellspacing: 0, cellpadding: 0 }\n  %tbody\n    %tr\n      %td.email-body\n        .email-container\n          %table.content-section{ cellspacing: 0, cellpadding: 0 }\n            %tbody\n              %tr\n                %td.content-cell.content-start\n                  %table.column{ cellspacing: 0, cellpadding: 0 }\n                    %tbody\n                      %tr\n                        %td.column-cell.button-cell\n                          %table.button{ align: 'center', cellspacing: 0, cellpadding: 0 }\n                            %tbody\n                              %tr\n                                %td.button-primary\n                                  = link_to confirmation_url(@resource, confirmation_token: @token) do\n                                    %span= t 'devise.mailer.confirmation_instructions.action'\n\n%table.email-table{ cellspacing: 0, cellpadding: 0 }\n  %tbody\n    %tr\n      %td.email-body\n        .email-container\n          %table.content-section{ cellspacing: 0, cellpadding: 0 }\n            %tbody\n              %tr\n                %td.content-cell\n                  .email-row\n                    .col-6\n                      %table.column{ cellspacing: 0, cellpadding: 0 }\n                        %tbody\n                          %tr\n                            %td.column-cell.text-center.padded\n                              %p= t 'devise.mailer.reconfirmation_instructions.extra'\n"
  },
  {
    "path": "app/views/user_mailer/reconfirmation_instructions.text.erb",
    "content": "<%= t 'devise.mailer.reconfirmation_instructions.title' %>\n\n===\n\n<%= t 'devise.mailer.reconfirmation_instructions.explanation' %>\n\n=> <%= confirmation_url(@resource, confirmation_token: @token) %>\n\n<%= t 'devise.mailer.reconfirmation_instructions.extra' %>\n"
  },
  {
    "path": "app/views/user_mailer/reset_password_instructions.html.haml",
    "content": "%table.email-table{ cellspacing: 0, cellpadding: 0 }\n  %tbody\n    %tr\n      %td.email-body\n        .email-container\n          %table.content-section{ cellspacing: 0, cellpadding: 0 }\n            %tbody\n              %tr\n                %td.content-cell.hero\n                  .email-row\n                    .col-6\n                      %table.column{ cellspacing: 0, cellpadding: 0 }\n                        %tbody\n                          %tr\n                            %td.column-cell.text-center.padded\n                              %table.hero-icon{ align: 'center', cellspacing: 0, cellpadding: 0 }\n                                %tbody\n                                  %tr\n                                    %td\n                                      = image_tag full_pack_url('media/images/mailer/icon_lock_open.png'), alt: ''\n\n                              %h1= t 'devise.mailer.reset_password_instructions.title'\n                              %p.lead= t 'devise.mailer.reset_password_instructions.explanation'\n\n%table.email-table{ cellspacing: 0, cellpadding: 0 }\n  %tbody\n    %tr\n      %td.email-body\n        .email-container\n          %table.content-section{ cellspacing: 0, cellpadding: 0 }\n            %tbody\n              %tr\n                %td.content-cell.content-start\n                  %table.column{ cellspacing: 0, cellpadding: 0 }\n                    %tbody\n                      %tr\n                        %td.column-cell.button-cell\n                          %table.button{ align: 'center', cellspacing: 0, cellpadding: 0 }\n                            %tbody\n                              %tr\n                                %td.button-primary\n                                  = link_to edit_password_url(@resource, reset_password_token: @token) do\n                                    %span= t 'devise.mailer.reset_password_instructions.action'\n\n%table.email-table{ cellspacing: 0, cellpadding: 0 }\n  %tbody\n    %tr\n      %td.email-body\n        .email-container\n          %table.content-section{ cellspacing: 0, cellpadding: 0 }\n            %tbody\n              %tr\n                %td.content-cell\n                  .email-row\n                    .col-6\n                      %table.column{ cellspacing: 0, cellpadding: 0 }\n                        %tbody\n                          %tr\n                            %td.column-cell.text-center.padded\n                              %p= t 'devise.mailer.reset_password_instructions.extra'\n"
  },
  {
    "path": "app/views/user_mailer/reset_password_instructions.text.erb",
    "content": "<%= t 'devise.mailer.reset_password_instructions.title' %>\n\n===\n\n<%= t 'devise.mailer.reset_password_instructions.explanation' %>\n\n=> <%= edit_password_url(@resource, reset_password_token: @token) %>\n\n<%= t 'devise.mailer.reset_password_instructions.extra' %>\n"
  },
  {
    "path": "app/views/user_mailer/warning.html.haml",
    "content": "%table.email-table{ cellspacing: 0, cellpadding: 0 }\n  %tbody\n    %tr\n      %td.email-body\n        .email-container\n          %table.content-section{ cellspacing: 0, cellpadding: 0 }\n            %tbody\n              %tr\n                %td.content-cell.hero\n                  .email-row\n                    .col-6\n                      %table.column{ cellspacing: 0, cellpadding: 0 }\n                        %tbody\n                          %tr\n                            %td.column-cell.text-center.padded\n                              %table.hero-icon.alert-icon{ align: 'center', cellspacing: 0, cellpadding: 0 }\n                                %tbody\n                                  %tr\n                                    %td\n                                      = image_tag full_pack_url('media/images/mailer/icon_warning.png'), alt: ''\n\n                              %h1= t \"user_mailer.warning.title.#{@warning.action}\"\n\n%table.email-table{ cellspacing: 0, cellpadding: 0 }\n  %tbody\n    %tr\n      %td.email-body\n        .email-container\n          %table.content-section{ cellspacing: 0, cellpadding: 0 }\n            %tbody\n              %tr\n                %td.content-cell.content-start\n                  .email-row\n                    .col-6\n                      %table.column{ cellspacing: 0, cellpadding: 0 }\n                        %tbody\n                          %tr\n                            %td.column-cell.text-center\n                              - unless @warning.none_action?\n                                %p= t \"user_mailer.warning.explanation.#{@warning.action}\"\n\n                              - unless @warning.text.blank?\n                                = Formatter.instance.linkify(@warning.text)\n\n%table.email-table{ cellspacing: 0, cellpadding: 0 }\n  %tbody\n    %tr\n      %td.email-body\n        .email-container\n          %table.content-section{ cellspacing: 0, cellpadding: 0 }\n            %tbody\n              %tr\n                %td.content-cell\n                  %table.column{ cellspacing: 0, cellpadding: 0 }\n                    %tbody\n                      %tr\n                        %td.column-cell.button-cell\n                          %table.button{ align: 'center', cellspacing: 0, cellpadding: 0 }\n                            %tbody\n                              %tr\n                                %td.button-primary\n                                  = link_to about_more_url do\n                                    %span= t 'user_mailer.warning.review_server_policies'\n"
  },
  {
    "path": "app/views/user_mailer/warning.text.erb",
    "content": "<%= t \"user_mailer.warning.title.#{@warning.action}\" %>\n\n===\n\n<% unless @warning.none_action? %>\n<%= t \"user_mailer.warning.explanation.#{@warning.action}\" %>\n\n<% end %>\n<%= @warning.text %>\n"
  },
  {
    "path": "app/views/user_mailer/welcome.html.haml",
    "content": "%table.email-table{ cellspacing: 0, cellpadding: 0 }\n  %tbody\n    %tr\n      %td.email-body\n        .email-container\n          %table.content-section{ cellspacing: 0, cellpadding: 0 }\n            %tbody\n              %tr\n                %td.content-cell.hero\n                  .email-row\n                    .col-6\n                      %table.column{ cellspacing: 0, cellpadding: 0 }\n                        %tbody\n                          %tr\n                            %td.column-cell.text-center.padded\n                              %table.hero-icon{ align: 'center', cellspacing: 0, cellpadding: 0 }\n                                %tbody\n                                  %tr\n                                    %td\n                                      = image_tag full_pack_url('media/images/mailer/icon_done.png'), alt: ''\n\n                              %h1= t 'user_mailer.welcome.title', name: @resource.account.username\n                              %p.lead= t 'user_mailer.welcome.explanation'\n\n%table.email-table{ cellspacing: 0, cellpadding: 0 }\n  %tbody\n    %tr\n      %td.email-body\n        .email-container\n          %table.content-section{ cellspacing: 0, cellpadding: 0 }\n            %tbody\n              %tr\n                %td.content-cell.content-start\n                  .email-row\n                    .col-3\n                      %table.column{ cellspacing: 0, cellpadding: 0 }\n                        %tbody\n                          %tr\n                            %td.column-cell.input-cell.text-center.padded-bottom\n                              %h5= t 'user_mailer.welcome.full_handle'\n                              %table.input{ align: 'center', cellspacing: 0, cellpadding: 0 }\n                                %tbody\n                                  %tr\n                                    %td= \"@#{@resource.account.username}@#{@instance}\"\n                    .col-3\n                      %table.column{ cellspacing: 0, cellpadding: 0 }\n                        %tbody\n                          %tr\n                            %td.column-cell\n                              %p= t 'user_mailer.welcome.full_handle_hint', instance: @instance\n\n%table.email-table{ cellspacing: 0, cellpadding: 0 }\n  %tbody\n    %tr\n      %td.email-body\n        .email-container\n          %table.content-section{ cellspacing: 0, cellpadding: 0 }\n            %tbody\n              %tr\n                %td.content-cell.content-start.border-top\n                  .email-row\n                    .col-4\n                      %table.column{ cellspacing: 0, cellpadding: 0 }\n                        %tbody\n                          %tr\n                            %td.column-cell.padded\n                              = t 'user_mailer.welcome.edit_profile_step'\n                    .col-2\n                      %table.column{ cellspacing: 0, cellpadding: 0 }\n                        %tbody\n                          %tr\n                            %td.column-cell.padded\n                              %table.button.button-small{ align: 'left', cellspacing: 0, cellpadding: 0 }\n                                %tbody\n                                  %tr\n                                    %td.button-primary\n                                      = link_to settings_profile_url do\n                                        %span= t 'user_mailer.welcome.edit_profile_action'\n              %tr\n                %td.content-cell\n                  .email-row\n                    .col-4\n                      %table.column{ cellspacing: 0, cellpadding: 0 }\n                        %tbody\n                          %tr\n                            %td.column-cell.padded\n                              = t 'user_mailer.welcome.review_preferences_step'\n                    .col-2\n                      %table.column{ cellspacing: 0, cellpadding: 0 }\n                        %tbody\n                          %tr\n                            %td.column-cell.padded\n                              %table.button.button-small{ align: 'left', cellspacing: 0, cellpadding: 0 }\n                                %tbody\n                                  %tr\n                                    %td.button-primary\n                                      = link_to settings_preferences_url do\n                                        %span= t 'user_mailer.welcome.review_preferences_action'\n              %tr\n                %td.content-cell.padded-bottom\n                  .email-row\n                    .col-4\n                      %table.column{ cellspacing: 0, cellpadding: 0 }\n                        %tbody\n                          %tr\n                            %td.column-cell.padded\n                              = t 'user_mailer.welcome.final_step'\n                    .col-2\n                      %table.column{ cellspacing: 0, cellpadding: 0 }\n                        %tbody\n                          %tr\n                            %td.column-cell.padded\n                              %table.button.button-small{ align: 'left', cellspacing: 0, cellpadding: 0 }\n                                %tbody\n                                  %tr\n                                    %td.button-primary\n                                      = link_to web_url do\n                                        %span= t 'user_mailer.welcome.final_action'\n\n%table.email-table{ cellspacing: 0, cellpadding: 0 }\n  %tbody\n    %tr\n      %td.email-body\n        .email-container\n          %table.content-section{ cellspacing: 0, cellpadding: 0 }\n            %tbody\n              %tr\n                %td.content-cell.border-top\n                  .email-row\n                    .col-6\n                      %table.column{ cellspacing: 0, cellpadding: 0 }\n                        %tbody\n                          %tr\n                            %td.column-cell.padded\n                              %h5= t 'user_mailer.welcome.tips'\n                              %ul\n                                %li\n                                  %span= t 'user_mailer.welcome.tip_mobile_webapp'\n                                %li\n                                  %span= t 'user_mailer.welcome.tip_following'\n                                %li\n                                  %span= t 'user_mailer.welcome.tip_local_timeline', instance: @instance\n                                %li\n                                  %span= t 'user_mailer.welcome.tip_federated_timeline'\n"
  },
  {
    "path": "app/views/user_mailer/welcome.text.erb",
    "content": "<%= t 'user_mailer.welcome.title', name: @resource.account.username %> <%= t 'user_mailer.welcome.explanation' %>\n\n===\n\n<%= t 'user_mailer.welcome.full_handle' %> (<%= \"@#{@resource.account.local_username_and_domain}\" %>)\n<%= t 'user_mailer.welcome.full_handle_hint', instance: @instance %>\n\n---\n\n<%= t 'user_mailer.welcome.edit_profile_step' %>\n\n=> <%= settings_profile_url %>\n\n<%= t 'user_mailer.welcome.review_preferences_step' %>\n\n=> <%= settings_preferences_url %>\n\n<%= t 'user_mailer.welcome.final_step' %>\n\n=> <%= web_url %>\n\n---\n\n<%= t 'user_mailer.welcome.tips' %>\n\n* <%= t 'user_mailer.welcome.tip_mobile_webapp' %>\n* <%= t 'user_mailer.welcome.tip_following' %>\n* <%= t 'user_mailer.welcome.tip_local_timeline', instance: @instance %>\n* <%= t 'user_mailer.welcome.tip_federated_timeline' %>\n"
  },
  {
    "path": "app/views/well_known/host_meta/show.xml.ruby",
    "content": "doc = Ox::Document.new(version: '1.0')\n\ndoc << Ox::Element.new('XRD').tap do |xrd|\n  xrd['xmlns'] = 'http://docs.oasis-open.org/ns/xri/xrd-1.0'\n\n  xrd << Ox::Element.new('Link').tap do |link|\n    link['rel']      = 'lrdd'\n    link['type']     = 'application/xrd+xml'\n    link['template'] = @webfinger_template\n  end\nend\n\n('<?xml version=\"1.0\" encoding=\"UTF-8\"?>' + Ox.dump(doc, effort: :tolerant)).force_encoding('UTF-8')\n"
  },
  {
    "path": "app/views/well_known/webfinger/show.xml.ruby",
    "content": "doc = Ox::Document.new(version: '1.0')\n\ndoc << Ox::Element.new('XRD').tap do |xrd|\n  xrd['xmlns'] = 'http://docs.oasis-open.org/ns/xri/xrd-1.0'\n\n  xrd << (Ox::Element.new('Subject') << @account.to_webfinger_s)\n  xrd << (Ox::Element.new('Alias') << short_account_url(@account))\n  xrd << (Ox::Element.new('Alias') << account_url(@account))\n\n  xrd << Ox::Element.new('Link').tap do |link|\n    link['rel']      = 'http://webfinger.net/rel/profile-page'\n    link['type']     = 'text/html'\n    link['href']     = short_account_url(@account)\n  end\n\n  xrd << Ox::Element.new('Link').tap do |link|\n    link['rel']      = 'http://schemas.google.com/g/2010#updates-from'\n    link['type']     = 'application/atom+xml'\n    link['href']     = account_url(@account, format: 'atom')\n  end\n\n  xrd << Ox::Element.new('Link').tap do |link|\n    link['rel']      = 'self'\n    link['type']     = 'application/activity+json'\n    link['href']     = account_url(@account)\n  end\n\n  xrd << Ox::Element.new('Link').tap do |link|\n    link['rel']      = 'salmon'\n    link['href']     = api_salmon_url(@account.id)\n  end\n\n  xrd << Ox::Element.new('Link').tap do |link|\n    link['rel']      = 'magic-public-key'\n    link['href']     = \"data:application/magic-public-key,#{@account.magic_key}\"\n  end\n\n  xrd << Ox::Element.new('Link').tap do |link|\n    link['rel']      = 'http://ostatus.org/schema/1.0/subscribe'\n    link['template'] = \"#{authorize_interaction_url}?acct={uri}\"\n  end\nend\n\n('<?xml version=\"1.0\" encoding=\"UTF-8\"?>' + Ox.dump(doc, effort: :tolerant)).force_encoding('UTF-8')\n"
  },
  {
    "path": "app/workers/activitypub/delivery_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::DeliveryWorker\n  include Sidekiq::Worker\n\n  STOPLIGHT_FAILURE_THRESHOLD = 10\n  STOPLIGHT_COOLDOWN = 60\n\n  sidekiq_options queue: 'push', retry: 16, dead: false\n\n  HEADERS = { 'Content-Type' => 'application/activity+json' }.freeze\n\n  def perform(json, source_account_id, inbox_url, options = {})\n    return if DeliveryFailureTracker.unavailable?(inbox_url)\n\n    @options        = options.with_indifferent_access\n    @json           = json\n    @source_account = Account.find(source_account_id)\n    @inbox_url      = inbox_url\n\n    perform_request\n\n    failure_tracker.track_success!\n  rescue => e\n    failure_tracker.track_failure!\n    raise e.class, \"Delivery failed for #{inbox_url}: #{e.message}\", e.backtrace[0]\n  end\n\n  private\n\n  def build_request\n    request = Request.new(:post, @inbox_url, body: @json)\n    request.on_behalf_of(@source_account, :uri, sign_with: @options[:sign_with])\n    request.add_headers(HEADERS)\n  end\n\n  def perform_request\n    light = Stoplight(@inbox_url) do\n      build_request.perform do |response|\n        raise Mastodon::UnexpectedResponseError, response unless response_successful?(response) || response_error_unsalvageable?(response)\n      end\n    end\n\n    light.with_threshold(STOPLIGHT_FAILURE_THRESHOLD)\n         .with_cool_off_time(STOPLIGHT_COOLDOWN)\n         .run\n  end\n\n  def response_successful?(response)\n    (200...300).cover?(response.code)\n  end\n\n  def response_error_unsalvageable?(response)\n    (400...500).cover?(response.code) && ![401, 408, 429].include?(response.code)\n  end\n\n  def failure_tracker\n    @failure_tracker ||= DeliveryFailureTracker.new(@inbox_url)\n  end\nend\n"
  },
  {
    "path": "app/workers/activitypub/distribute_poll_update_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::DistributePollUpdateWorker\n  include Sidekiq::Worker\n  include Payloadable\n\n  sidekiq_options queue: 'push', unique: :until_executed, retry: 0\n\n  def perform(status_id)\n    @status  = Status.find(status_id)\n    @account = @status.account\n\n    return unless @status.preloadable_poll\n\n    ActivityPub::DeliveryWorker.push_bulk(inboxes) do |inbox_url|\n      [payload, @account.id, inbox_url]\n    end\n\n    relay! if relayable?\n  rescue ActiveRecord::RecordNotFound\n    true\n  end\n\n  private\n\n  def relayable?\n    @status.public_visibility?\n  end\n\n  def inboxes\n    return @inboxes if defined?(@inboxes)\n\n    @inboxes = [@status.mentions, @status.reblogs, @status.preloadable_poll.votes].flat_map do |relation|\n      relation.includes(:account).map do |record|\n        record.account.preferred_inbox_url if !record.account.local? && record.account.activitypub?\n      end\n    end\n\n    @inboxes.concat(@account.followers.inboxes) unless @status.direct_visibility?\n    @inboxes.uniq!\n    @inboxes.compact!\n    @inboxes\n  end\n\n  def payload\n    @payload ||= Oj.dump(serialize_payload(@status, ActivityPub::UpdatePollSerializer, signer: @account))\n  end\n\n  def relay!\n    ActivityPub::DeliveryWorker.push_bulk(Relay.enabled.pluck(:inbox_url)) do |inbox_url|\n      [payload, @account.id, inbox_url]\n    end\n  end\nend\n"
  },
  {
    "path": "app/workers/activitypub/distribution_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::DistributionWorker\n  include Sidekiq::Worker\n  include Payloadable\n\n  sidekiq_options queue: 'push'\n\n  def perform(status_id)\n    @status  = Status.find(status_id)\n    @account = @status.account\n\n    return if skip_distribution?\n\n    ActivityPub::DeliveryWorker.push_bulk(inboxes) do |inbox_url|\n      [payload, @account.id, inbox_url]\n    end\n\n    relay! if relayable?\n  rescue ActiveRecord::RecordNotFound\n    true\n  end\n\n  private\n\n  def skip_distribution?\n    @status.direct_visibility? || @status.limited_visibility?\n  end\n\n  def relayable?\n    @status.public_visibility?\n  end\n\n  def inboxes\n    # Deliver the status to all followers.\n    # If the status is a reply to another local status, also forward it to that\n    # status' authors' followers.\n    @inboxes ||= if @status.reply? && @status.thread.account.local? && @status.distributable?\n                   @account.followers.or(@status.thread.account.followers).inboxes\n                 else\n                   @account.followers.inboxes\n                 end\n  end\n\n  def payload\n    @payload ||= Oj.dump(serialize_payload(@status, ActivityPub::ActivitySerializer, signer: @account))\n  end\n\n  def relay!\n    ActivityPub::DeliveryWorker.push_bulk(Relay.enabled.pluck(:inbox_url)) do |inbox_url|\n      [payload, @account.id, inbox_url]\n    end\n  end\nend\n"
  },
  {
    "path": "app/workers/activitypub/fetch_replies_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::FetchRepliesWorker\n  include Sidekiq::Worker\n  include ExponentialBackoff\n\n  sidekiq_options queue: 'pull', retry: 3\n\n  def perform(parent_status_id, replies_uri)\n    ActivityPub::FetchRepliesService.new.call(Status.find(parent_status_id), replies_uri)\n  rescue ActiveRecord::RecordNotFound\n    true\n  end\nend\n"
  },
  {
    "path": "app/workers/activitypub/low_priority_delivery_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::LowPriorityDeliveryWorker < ActivityPub::DeliveryWorker\n  sidekiq_options queue: 'pull', retry: 8, dead: false\nend\n"
  },
  {
    "path": "app/workers/activitypub/post_upgrade_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::PostUpgradeWorker\n  include Sidekiq::Worker\n\n  sidekiq_options queue: 'pull'\n\n  def perform(domain)\n    Account.where(domain: domain)\n           .where(protocol: :ostatus)\n           .where.not(last_webfingered_at: nil)\n           .in_batches\n           .update_all(last_webfingered_at: nil)\n  end\nend\n"
  },
  {
    "path": "app/workers/activitypub/processing_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::ProcessingWorker\n  include Sidekiq::Worker\n\n  sidekiq_options backtrace: true\n\n  def perform(account_id, body, delivered_to_account_id = nil)\n    ActivityPub::ProcessCollectionService.new.call(body, Account.find(account_id), override_timestamps: true, delivered_to_account_id: delivered_to_account_id, delivery: true)\n  rescue ActiveRecord::RecordInvalid => e\n    Rails.logger.debug \"Error processing incoming ActivityPub object: #{e}\"\n  end\nend\n"
  },
  {
    "path": "app/workers/activitypub/raw_distribution_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::RawDistributionWorker\n  include Sidekiq::Worker\n\n  sidekiq_options queue: 'push'\n\n  def perform(json, source_account_id, exclude_inboxes = [])\n    @account = Account.find(source_account_id)\n\n    ActivityPub::DeliveryWorker.push_bulk(inboxes - exclude_inboxes) do |inbox_url|\n      [json, @account.id, inbox_url]\n    end\n  rescue ActiveRecord::RecordNotFound\n    true\n  end\n\n  private\n\n  def inboxes\n    @inboxes ||= @account.followers.inboxes\n  end\nend\n"
  },
  {
    "path": "app/workers/activitypub/reply_distribution_worker.rb",
    "content": "# frozen_string_literal: true\n\n# Obsolete but kept around to make sure existing jobs do not fail after upgrade.\n# Should be removed in a subsequent release.\n\nclass ActivityPub::ReplyDistributionWorker\n  include Sidekiq::Worker\n  include Payloadable\n\n  sidekiq_options queue: 'push'\n\n  def perform(status_id)\n    @status  = Status.find(status_id)\n    @account = @status.thread&.account\n\n    return unless @account.present? && @status.distributable?\n\n    ActivityPub::DeliveryWorker.push_bulk(inboxes) do |inbox_url|\n      [payload, @status.account_id, inbox_url]\n    end\n  rescue ActiveRecord::RecordNotFound\n    true\n  end\n\n  private\n\n  def inboxes\n    @inboxes ||= @account.followers.inboxes\n  end\n\n  def payload\n    @payload ||= Oj.dump(serialize_payload(@status, ActivityPub::ActivitySerializer, signer: @status.account))\n  end\nend\n"
  },
  {
    "path": "app/workers/activitypub/synchronize_featured_collection_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::SynchronizeFeaturedCollectionWorker\n  include Sidekiq::Worker\n\n  sidekiq_options queue: 'pull', unique: :until_executed\n\n  def perform(account_id)\n    ActivityPub::FetchFeaturedCollectionService.new.call(Account.find(account_id))\n  rescue ActiveRecord::RecordNotFound\n    true\n  end\nend\n"
  },
  {
    "path": "app/workers/activitypub/update_distribution_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass ActivityPub::UpdateDistributionWorker\n  include Sidekiq::Worker\n  include Payloadable\n\n  sidekiq_options queue: 'push'\n\n  def perform(account_id, options = {})\n    @options = options.with_indifferent_access\n    @account = Account.find(account_id)\n\n    ActivityPub::DeliveryWorker.push_bulk(inboxes) do |inbox_url|\n      [signed_payload, @account.id, inbox_url]\n    end\n\n    ActivityPub::DeliveryWorker.push_bulk(Relay.enabled.pluck(:inbox_url)) do |inbox_url|\n      [signed_payload, @account.id, inbox_url]\n    end\n  rescue ActiveRecord::RecordNotFound\n    true\n  end\n\n  private\n\n  def inboxes\n    @inboxes ||= @account.followers.inboxes\n  end\n\n  def signed_payload\n    @signed_payload ||= Oj.dump(serialize_payload(@account, ActivityPub::UpdateSerializer, signer: @account, sign_with: @options[:sign_with]))\n  end\nend\n"
  },
  {
    "path": "app/workers/admin/suspension_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass Admin::SuspensionWorker\n  include Sidekiq::Worker\n\n  sidekiq_options queue: 'pull'\n\n  def perform(account_id, remove_user = false)\n    SuspendAccountService.new.call(Account.find(account_id), including_user: remove_user)\n  end\nend\n"
  },
  {
    "path": "app/workers/after_account_domain_block_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass AfterAccountDomainBlockWorker\n  include Sidekiq::Worker\n\n  def perform(account_id, domain)\n    AfterBlockDomainFromAccountService.new.call(Account.find(account_id), domain)\n  rescue ActiveRecord::RecordNotFound\n    true\n  end\nend\n"
  },
  {
    "path": "app/workers/after_remote_follow_request_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass AfterRemoteFollowRequestWorker\n  include Sidekiq::Worker\n\n  sidekiq_options queue: 'pull', retry: 5\n\n  attr_reader :follow_request\n\n  def perform(follow_request_id)\n    @follow_request = FollowRequest.find(follow_request_id)\n    process_follow_service if processing_required?\n  rescue ActiveRecord::RecordNotFound\n    true\n  end\n\n  private\n\n  def process_follow_service\n    follow_request.destroy\n    FollowService.new.call(follow_request.account, updated_account.acct)\n  end\n\n  def processing_required?\n    !updated_account.nil? && !updated_account.locked?\n  end\n\n  def updated_account\n    @_updated_account ||= FetchRemoteAccountService.new.call(follow_request.target_account.remote_url)\n  end\nend\n"
  },
  {
    "path": "app/workers/after_remote_follow_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass AfterRemoteFollowWorker\n  include Sidekiq::Worker\n\n  sidekiq_options queue: 'pull', retry: 5\n\n  attr_reader :follow\n\n  def perform(follow_id)\n    @follow = Follow.find(follow_id)\n    process_follow_service if processing_required?\n  rescue ActiveRecord::RecordNotFound\n    true\n  end\n\n  private\n\n  def process_follow_service\n    follow.destroy\n    FollowService.new.call(follow.account, updated_account.acct)\n  end\n\n  def updated_account\n    @_updated_account ||= FetchRemoteAccountService.new.call(follow.target_account.remote_url)\n  end\n\n  def processing_required?\n    !updated_account.nil? && updated_account.locked?\n  end\nend\n"
  },
  {
    "path": "app/workers/authorize_follow_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass AuthorizeFollowWorker\n  include Sidekiq::Worker\n\n  def perform(source_account_id, target_account_id)\n    source_account = Account.find(source_account_id)\n    target_account = Account.find(target_account_id)\n\n    AuthorizeFollowService.new.call(source_account, target_account)\n  rescue ActiveRecord::RecordNotFound\n    true\n  end\nend\n"
  },
  {
    "path": "app/workers/backup_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass BackupWorker\n  include Sidekiq::Worker\n\n  sidekiq_options queue: 'pull', backtrace: true, retry: 5, dead: false\n\n  sidekiq_retries_exhausted do |msg|\n    backup_id = msg['args'].first\n\n    ActiveRecord::Base.connection_pool.with_connection do\n      backup = Backup.find(backup_id)\n      backup&.destroy\n    end\n  end\n\n  def perform(backup_id)\n    backup = Backup.find(backup_id)\n    user   = backup.user\n\n    BackupService.new.call(backup)\n\n    user.backups.where.not(id: backup.id).destroy_all\n    UserMailer.backup_ready(user, backup).deliver_later\n  end\nend\n"
  },
  {
    "path": "app/workers/block_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass BlockWorker\n  include Sidekiq::Worker\n\n  def perform(account_id, target_account_id)\n    AfterBlockService.new.call(\n      Account.find(account_id),\n      Account.find(target_account_id)\n    )\n  end\nend\n"
  },
  {
    "path": "app/workers/bootstrap_timeline_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass BootstrapTimelineWorker\n  include Sidekiq::Worker\n\n  def perform(account_id)\n    BootstrapTimelineService.new.call(Account.find(account_id))\n  end\nend\n"
  },
  {
    "path": "app/workers/concerns/exponential_backoff.rb",
    "content": "# frozen_string_literal: true\n\nmodule ExponentialBackoff\n  extend ActiveSupport::Concern\n\n  included do\n    sidekiq_retry_in do |count|\n      15 + 10 * (count**4) + rand(10 * (count**4))\n    end\n  end\nend\n"
  },
  {
    "path": "app/workers/digest_mailer_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass DigestMailerWorker\n  include Sidekiq::Worker\n\n  sidekiq_options queue: 'mailers'\n\n  attr_reader :user\n\n  def perform(user_id)\n    @user = User.find(user_id)\n    deliver_digest if @user.allows_digest_emails?\n  end\n\n  private\n\n  def deliver_digest\n    NotificationMailer.digest(user.account).deliver_now!\n    user.touch(:last_emailed_at)\n  end\nend\n"
  },
  {
    "path": "app/workers/distribution_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass DistributionWorker\n  include Sidekiq::Worker\n\n  def perform(status_id)\n    RedisLock.acquire(redis: Redis.current, key: \"distribute:#{status_id}\") do |lock|\n      if lock.acquired?\n        FanOutOnWriteService.new.call(Status.find(status_id))\n      else\n        raise Mastodon::RaceConditionError\n      end\n    end\n  rescue ActiveRecord::RecordNotFound\n    true\n  end\nend\n"
  },
  {
    "path": "app/workers/domain_block_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass DomainBlockWorker\n  include Sidekiq::Worker\n\n  def perform(domain_block_id)\n    BlockDomainService.new.call(DomainBlock.find(domain_block_id))\n  rescue ActiveRecord::RecordNotFound\n    true\n  end\nend\n"
  },
  {
    "path": "app/workers/feed_insert_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass FeedInsertWorker\n  include Sidekiq::Worker\n\n  def perform(status_id, id, type = :home)\n    @type     = type.to_sym\n    @status   = Status.find(status_id)\n\n    case @type\n    when :home\n      @follower = Account.find(id)\n    when :list\n      @list     = List.find(id)\n      @follower = @list.account\n    end\n\n    check_and_insert\n  rescue ActiveRecord::RecordNotFound\n    true\n  end\n\n  private\n\n  def check_and_insert\n    perform_push unless feed_filtered?\n  end\n\n  def feed_filtered?\n    # Note: Lists are a variation of home, so the filtering rules\n    # of home apply to both\n    FeedManager.instance.filter?(:home, @status, @follower.id)\n  end\n\n  def perform_push\n    case @type\n    when :home\n      FeedManager.instance.push_to_home(@follower, @status)\n    when :list\n      FeedManager.instance.push_to_list(@list, @status)\n    end\n  end\nend\n"
  },
  {
    "path": "app/workers/fetch_reply_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass FetchReplyWorker\n  include Sidekiq::Worker\n  include ExponentialBackoff\n\n  sidekiq_options queue: 'pull', retry: 3\n\n  def perform(child_url)\n    FetchRemoteStatusService.new.call(child_url)\n  end\nend\n"
  },
  {
    "path": "app/workers/import/relationship_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass Import::RelationshipWorker\n  include Sidekiq::Worker\n\n  sidekiq_options queue: 'pull', retry: 8, dead: false\n\n  def perform(account_id, target_account_uri, relationship, options = {})\n    from_account   = Account.find(account_id)\n    target_account = ResolveAccountService.new.call(target_account_uri)\n    options.symbolize_keys!\n\n    return if target_account.nil?\n\n    case relationship\n    when 'follow'\n      FollowService.new.call(from_account, target_account, options)\n    when 'unfollow'\n      UnfollowService.new.call(from_account, target_account)\n    when 'block'\n      BlockService.new.call(from_account, target_account)\n    when 'unblock'\n      UnblockService.new.call(from_account, target_account)\n    when 'mute'\n      MuteService.new.call(from_account, target_account, options)\n    when 'unmute'\n      UnmuteService.new.call(from_account, target_account)\n    end\n  rescue ActiveRecord::RecordNotFound\n    true\n  end\nend\n"
  },
  {
    "path": "app/workers/import_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass ImportWorker\n  include Sidekiq::Worker\n\n  sidekiq_options queue: 'pull', retry: false\n\n  def perform(import_id)\n    import = Import.find(import_id)\n    ImportService.new.call(import)\n  ensure\n    import&.destroy\n  end\nend\n"
  },
  {
    "path": "app/workers/link_crawl_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass LinkCrawlWorker\n  include Sidekiq::Worker\n\n  sidekiq_options queue: 'pull', retry: 0\n\n  def perform(status_id)\n    FetchLinkCardService.new.call(Status.find(status_id))\n  rescue ActiveRecord::RecordNotFound\n    true\n  end\nend\n"
  },
  {
    "path": "app/workers/local_notification_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass LocalNotificationWorker\n  include Sidekiq::Worker\n\n  def perform(receiver_account_id, activity_id = nil, activity_class_name = nil)\n    if activity_id.nil? && activity_class_name.nil?\n      activity = Mention.find(receiver_account_id)\n      receiver = activity.account\n    else\n      receiver = Account.find(receiver_account_id)\n      activity = activity_class_name.constantize.find(activity_id)\n    end\n\n    NotifyService.new.call(receiver, activity)\n  rescue ActiveRecord::RecordNotFound\n    true\n  end\nend\n"
  },
  {
    "path": "app/workers/maintenance/destroy_media_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass Maintenance::DestroyMediaWorker\n  include Sidekiq::Worker\n\n  sidekiq_options queue: 'pull'\n\n  def perform(media_attachment_id)\n    media = media_attachment_id.is_a?(MediaAttachment) ? media_attachment_id : MediaAttachment.find(media_attachment_id)\n    media.destroy\n  rescue ActiveRecord::RecordNotFound\n    true\n  end\nend\n"
  },
  {
    "path": "app/workers/maintenance/redownload_account_media_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass Maintenance::RedownloadAccountMediaWorker\n  include Sidekiq::Worker\n\n  sidekiq_options queue: 'pull', retry: false\n\n  def perform(account_id)\n    account = account_id.is_a?(Account) ? account_id : Account.find(account_id)\n    account.reset_avatar!\n    account.reset_header!\n    account.save\n  rescue ActiveRecord::RecordNotFound\n    true\n  end\nend\n"
  },
  {
    "path": "app/workers/maintenance/uncache_media_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass Maintenance::UncacheMediaWorker\n  include Sidekiq::Worker\n\n  sidekiq_options queue: 'pull'\n\n  def perform(media_attachment_id)\n    media = media_attachment_id.is_a?(MediaAttachment) ? media_attachment_id : MediaAttachment.find(media_attachment_id)\n\n    return if media.file.blank?\n\n    media.file.destroy\n    media.save\n  rescue ActiveRecord::RecordNotFound\n    true\n  end\nend\n"
  },
  {
    "path": "app/workers/merge_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass MergeWorker\n  include Sidekiq::Worker\n\n  sidekiq_options queue: 'pull'\n\n  def perform(from_account_id, into_account_id)\n    FeedManager.instance.merge_into_timeline(Account.find(from_account_id), Account.find(into_account_id))\n  end\nend\n"
  },
  {
    "path": "app/workers/mute_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass MuteWorker\n  include Sidekiq::Worker\n\n  def perform(account_id, target_account_id)\n    FeedManager.instance.clear_from_timeline(\n      Account.find(account_id),\n      Account.find(target_account_id)\n    )\n  end\nend\n"
  },
  {
    "path": "app/workers/notification_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass NotificationWorker\n  include Sidekiq::Worker\n\n  sidekiq_options queue: 'push', retry: 5\n\n  def perform(xml, source_account_id, target_account_id)\n    SendInteractionService.new.call(xml, Account.find(source_account_id), Account.find(target_account_id))\n  end\nend\n"
  },
  {
    "path": "app/workers/poll_expiration_notify_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass PollExpirationNotifyWorker\n  include Sidekiq::Worker\n\n  sidekiq_options unique: :until_executed\n\n  def perform(poll_id)\n    poll = Poll.find(poll_id)\n\n    # Notify poll owner and remote voters\n    if poll.local?\n      ActivityPub::DistributePollUpdateWorker.perform_async(poll.status.id)\n      NotifyService.new.call(poll.account, poll)\n    end\n\n    # Notify local voters\n    poll.votes.includes(:account).map(&:account).select(&:local?).each do |account|\n      NotifyService.new.call(account, poll)\n    end\n  rescue ActiveRecord::RecordNotFound\n    true\n  end\nend\n"
  },
  {
    "path": "app/workers/processing_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass ProcessingWorker\n  include Sidekiq::Worker\n\n  sidekiq_options backtrace: true\n\n  def perform(account_id, body)\n    ProcessFeedService.new.call(body, Account.find(account_id), override_timestamps: true)\n  end\nend\n"
  },
  {
    "path": "app/workers/publish_scheduled_status_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass PublishScheduledStatusWorker\n  include Sidekiq::Worker\n\n  sidekiq_options unique: :until_executed\n\n  def perform(scheduled_status_id)\n    scheduled_status = ScheduledStatus.find(scheduled_status_id)\n    scheduled_status.destroy!\n\n    PostStatusService.new.call(\n      scheduled_status.account,\n      options_with_objects(scheduled_status.params.with_indifferent_access)\n    )\n  rescue ActiveRecord::RecordNotFound, ActiveRecord::RecordInvalid\n    true\n  end\n\n  def options_with_objects(options)\n    options.tap do |options_hash|\n      options_hash[:application] = Doorkeeper::Application.find(options_hash.delete(:application_id)) if options[:application_id]\n      options_hash[:thread]      = Status.find(options_hash.delete(:in_reply_to_id)) if options_hash[:in_reply_to_id]\n    end\n  end\nend\n"
  },
  {
    "path": "app/workers/pubsubhubbub/confirmation_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass Pubsubhubbub::ConfirmationWorker\n  include Sidekiq::Worker\n  include RoutingHelper\n\n  sidekiq_options queue: 'push', retry: false\n\n  attr_reader :subscription, :mode, :secret, :lease_seconds\n\n  def perform(subscription_id, mode, secret = nil, lease_seconds = nil)\n    @subscription = Subscription.find(subscription_id)\n    @mode = mode\n    @secret = secret\n    @lease_seconds = lease_seconds\n    process_confirmation\n  end\n\n  private\n\n  def process_confirmation\n    prepare_subscription\n\n    callback_get_with_params\n    logger.debug \"Confirming PuSH subscription for #{subscription.callback_url} with challenge #{challenge}: #{@callback_response_body}\"\n\n    update_subscription\n  end\n\n  def update_subscription\n    if successful_subscribe?\n      subscription.save!\n    elsif successful_unsubscribe?\n      subscription.destroy!\n    end\n  end\n\n  def successful_subscribe?\n    subscribing? && response_matches_challenge?\n  end\n\n  def successful_unsubscribe?\n    (unsubscribing? && response_matches_challenge?) || !subscription.confirmed?\n  end\n\n  def response_matches_challenge?\n    @callback_response_body == challenge\n  end\n\n  def subscribing?\n    mode == 'subscribe'\n  end\n\n  def unsubscribing?\n    mode == 'unsubscribe'\n  end\n\n  def callback_get_with_params\n    Request.new(:get, subscription.callback_url, params: callback_params).perform do |response|\n      @callback_response_body = response.body_with_limit\n    end\n  end\n\n  def callback_params\n    {\n      'hub.topic': account_url(subscription.account, format: :atom),\n      'hub.mode': mode,\n      'hub.challenge': challenge,\n      'hub.lease_seconds': subscription.lease_seconds,\n    }\n  end\n\n  def prepare_subscription\n    subscription.secret = secret\n    subscription.lease_seconds = lease_seconds\n    subscription.confirmed = true\n  end\n\n  def challenge\n    @_challenge ||= SecureRandom.hex\n  end\nend\n"
  },
  {
    "path": "app/workers/pubsubhubbub/delivery_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass Pubsubhubbub::DeliveryWorker\n  include Sidekiq::Worker\n  include RoutingHelper\n\n  sidekiq_options queue: 'push', retry: 3, dead: false\n\n  sidekiq_retry_in do |count|\n    5 * (count + 1)\n  end\n\n  attr_reader :subscription, :payload\n\n  def perform(subscription_id, payload)\n    @subscription = Subscription.find(subscription_id)\n    @payload = payload\n    process_delivery unless blocked_domain?\n  rescue => e\n    raise e.class, \"Delivery failed for #{subscription&.callback_url}: #{e.message}\", e.backtrace[0]\n  end\n\n  private\n\n  def process_delivery\n    callback_post_payload do |payload_delivery|\n      raise Mastodon::UnexpectedResponseError, payload_delivery unless response_successful? payload_delivery\n    end\n\n    subscription.touch(:last_successful_delivery_at)\n  end\n\n  def callback_post_payload(&block)\n    request = Request.new(:post, subscription.callback_url, body: payload)\n    request.add_headers(headers)\n    request.perform(&block)\n  end\n\n  def blocked_domain?\n    DomainBlock.blocked?(host)\n  end\n\n  def host\n    Addressable::URI.parse(subscription.callback_url).normalized_host\n  end\n\n  def headers\n    {\n      'Content-Type' => 'application/atom+xml',\n      'Link' => link_header,\n    }.merge(signature_headers.to_h)\n  end\n\n  def link_header\n    LinkHeader.new([hub_link_header, self_link_header]).to_s\n  end\n\n  def hub_link_header\n    [api_push_url, [%w(rel hub)]]\n  end\n\n  def self_link_header\n    [account_url(subscription.account, format: :atom), [%w(rel self)]]\n  end\n\n  def signature_headers\n    { 'X-Hub-Signature' => payload_signature } if subscription.secret?\n  end\n\n  def payload_signature\n    \"sha1=#{hmac_payload_digest}\"\n  end\n\n  def hmac_payload_digest\n    OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha1'), subscription.secret, payload)\n  end\n\n  def response_successful?(payload_delivery)\n    payload_delivery.code > 199 && payload_delivery.code < 300\n  end\nend\n"
  },
  {
    "path": "app/workers/pubsubhubbub/distribution_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass Pubsubhubbub::DistributionWorker\n  include Sidekiq::Worker\n\n  sidekiq_options queue: 'push'\n\n  def perform(stream_entry_ids)\n    stream_entries = StreamEntry.where(id: stream_entry_ids).includes(:status).reject { |e| e.status.nil? || e.status.hidden? }\n\n    return if stream_entries.empty?\n\n    @account       = stream_entries.first.account\n    @subscriptions = active_subscriptions.to_a\n\n    distribute_public!(stream_entries)\n  end\n\n  private\n\n  def distribute_public!(stream_entries)\n    @payload = OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.feed(@account, stream_entries))\n\n    Pubsubhubbub::DeliveryWorker.push_bulk(@subscriptions) do |subscription_id|\n      [subscription_id, @payload]\n    end\n  end\n\n  def active_subscriptions\n    Subscription.where(account: @account).active.pluck(:id)\n  end\nend\n"
  },
  {
    "path": "app/workers/pubsubhubbub/raw_distribution_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass Pubsubhubbub::RawDistributionWorker\n  include Sidekiq::Worker\n\n  sidekiq_options queue: 'push'\n\n  def perform(xml, source_account_id)\n    @account       = Account.find(source_account_id)\n    @subscriptions = active_subscriptions.to_a\n\n    Pubsubhubbub::DeliveryWorker.push_bulk(@subscriptions) do |subscription|\n      [subscription.id, xml]\n    end\n  end\n\n  private\n\n  def active_subscriptions\n    Subscription.where(account: @account).active.select('id, callback_url, domain')\n  end\nend\n"
  },
  {
    "path": "app/workers/pubsubhubbub/subscribe_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass Pubsubhubbub::SubscribeWorker\n  include Sidekiq::Worker\n\n  sidekiq_options queue: 'push', retry: 10, unique: :until_executed, dead: false\n\n  sidekiq_retry_in do |count|\n    case count\n    when 0\n      30.minutes.seconds\n    when 1\n      2.hours.seconds\n    when 2\n      12.hours.seconds\n    else\n      24.hours.seconds * (count - 2)\n    end\n  end\n\n  sidekiq_retries_exhausted do |msg, _e|\n    account = Account.find(msg['args'].first)\n    Sidekiq.logger.error \"PuSH subscription attempts for #{account.acct} exhausted. Unsubscribing\"\n    ::UnsubscribeService.new.call(account)\n  end\n\n  def perform(account_id)\n    account = Account.find(account_id)\n    logger.debug \"PuSH re-subscribing to #{account.acct}\"\n    ::SubscribeService.new.call(account)\n  rescue => e\n    raise e.class, \"Subscribe failed for #{account&.acct}: #{e.message}\", e.backtrace[0]\n  end\nend\n"
  },
  {
    "path": "app/workers/pubsubhubbub/unsubscribe_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass Pubsubhubbub::UnsubscribeWorker\n  include Sidekiq::Worker\n\n  sidekiq_options queue: 'push', retry: false, unique: :until_executed, dead: false\n\n  def perform(account_id)\n    account = Account.find(account_id)\n    logger.debug \"PuSH unsubscribing from #{account.acct}\"\n    ::UnsubscribeService.new.call(account)\n  rescue ActiveRecord::RecordNotFound\n    true\n  end\nend\n"
  },
  {
    "path": "app/workers/push_conversation_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass PushConversationWorker\n  include Sidekiq::Worker\n\n  def perform(conversation_account_id)\n    conversation = AccountConversation.find(conversation_account_id)\n    message      = InlineRenderer.render(conversation, conversation.account, :conversation)\n    timeline_id  = \"timeline:direct:#{conversation.account_id}\"\n\n    Redis.current.publish(timeline_id, Oj.dump(event: :conversation, payload: message, queued_at: (Time.now.to_f * 1000.0).to_i))\n  rescue ActiveRecord::RecordNotFound\n    true\n  end\nend\n"
  },
  {
    "path": "app/workers/push_update_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass PushUpdateWorker\n  include Sidekiq::Worker\n\n  def perform(account_id, status_id, timeline_id = nil)\n    account     = Account.find(account_id)\n    status      = Status.find(status_id)\n    message     = InlineRenderer.render(status, account, :status)\n    timeline_id = \"timeline:#{account.id}\" if timeline_id.nil?\n\n    Redis.current.publish(timeline_id, Oj.dump(event: :update, payload: message, queued_at: (Time.now.to_f * 1000.0).to_i))\n  rescue ActiveRecord::RecordNotFound\n    true\n  end\nend\n"
  },
  {
    "path": "app/workers/refollow_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass RefollowWorker\n  include Sidekiq::Worker\n\n  sidekiq_options queue: 'pull', retry: false\n\n  def perform(target_account_id)\n    target_account = Account.find(target_account_id)\n    return unless target_account.protocol == :activitypub\n\n    target_account.followers.where(domain: nil).reorder(nil).find_each do |follower|\n      # Locally unfollow remote account\n      follower.unfollow!(target_account)\n\n      # Schedule re-follow\n      begin\n        FollowService.new.call(follower, target_account)\n      rescue Mastodon::NotPermittedError, ActiveRecord::RecordNotFound, Mastodon::UnexpectedResponseError, HTTP::Error, OpenSSL::SSL::SSLError\n        next\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "app/workers/regeneration_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass RegenerationWorker\n  include Sidekiq::Worker\n\n  sidekiq_options unique: :until_executed\n\n  def perform(account_id, _ = :home)\n    account = Account.find(account_id)\n    PrecomputeFeedService.new.call(account)\n  rescue ActiveRecord::RecordNotFound\n    true\n  end\nend\n"
  },
  {
    "path": "app/workers/remote_profile_update_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass RemoteProfileUpdateWorker\n  include Sidekiq::Worker\n\n  sidekiq_options queue: 'pull'\n\n  def perform(account_id, body, resubscribe)\n    UpdateRemoteProfileService.new.call(body, Account.find(account_id), resubscribe)\n  rescue ActiveRecord::RecordNotFound\n    true\n  end\nend\n"
  },
  {
    "path": "app/workers/removal_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass RemovalWorker\n  include Sidekiq::Worker\n\n  def perform(status_id)\n    RemoveStatusService.new.call(Status.find(status_id))\n  rescue ActiveRecord::RecordNotFound\n    true\n  end\nend\n"
  },
  {
    "path": "app/workers/resolve_account_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass ResolveAccountWorker\n  include Sidekiq::Worker\n\n  sidekiq_options queue: 'pull', unique: :until_executed\n\n  def perform(uri)\n    ResolveAccountService.new.call(uri)\n  end\nend\n"
  },
  {
    "path": "app/workers/salmon_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass SalmonWorker\n  include Sidekiq::Worker\n\n  sidekiq_options backtrace: true\n\n  def perform(account_id, body)\n    ProcessInteractionService.new.call(body, Account.find(account_id))\n  rescue Nokogiri::XML::XPath::SyntaxError, ActiveRecord::RecordNotFound\n    true\n  end\nend\n"
  },
  {
    "path": "app/workers/scheduler/backup_cleanup_scheduler.rb",
    "content": "# frozen_string_literal: true\n\nclass Scheduler::BackupCleanupScheduler\n  include Sidekiq::Worker\n\n  sidekiq_options unique: :until_executed, retry: 0\n\n  def perform\n    old_backups.reorder(nil).find_each(&:destroy!)\n  end\n\n  private\n\n  def old_backups\n    Backup.where('created_at < ?', 7.days.ago)\n  end\nend\n"
  },
  {
    "path": "app/workers/scheduler/doorkeeper_cleanup_scheduler.rb",
    "content": "# frozen_string_literal: true\n\nclass Scheduler::DoorkeeperCleanupScheduler\n  include Sidekiq::Worker\n\n  sidekiq_options unique: :until_executed, retry: 0\n\n  def perform\n    Doorkeeper::AccessToken.where('revoked_at IS NOT NULL').where('revoked_at < NOW()').delete_all\n    Doorkeeper::AccessGrant.where('revoked_at IS NOT NULL').where('revoked_at < NOW()').delete_all\n  end\nend\n"
  },
  {
    "path": "app/workers/scheduler/email_scheduler.rb",
    "content": "# frozen_string_literal: true\n\nclass Scheduler::EmailScheduler\n  include Sidekiq::Worker\n\n  sidekiq_options unique: :until_executed, retry: 0\n\n  FREQUENCY      = 7.days.freeze\n  SIGN_IN_OFFSET = 1.day.freeze\n\n  def perform\n    eligible_users.reorder(nil).find_each do |user|\n      next unless user.allows_digest_emails?\n      DigestMailerWorker.perform_async(user.id)\n    end\n  end\n\n  private\n\n  def eligible_users\n    User.emailable\n        .where('current_sign_in_at < ?', (FREQUENCY + SIGN_IN_OFFSET).ago)\n        .where('last_emailed_at IS NULL OR last_emailed_at < ?', FREQUENCY.ago)\n  end\nend\n"
  },
  {
    "path": "app/workers/scheduler/feed_cleanup_scheduler.rb",
    "content": "# frozen_string_literal: true\n\nclass Scheduler::FeedCleanupScheduler\n  include Sidekiq::Worker\n  include Redisable\n\n  sidekiq_options unique: :until_executed, retry: 0\n\n  def perform\n    clean_home_feeds!\n    clean_list_feeds!\n  end\n\n  private\n\n  def clean_home_feeds!\n    clean_feeds!(inactive_account_ids, :home)\n  end\n\n  def clean_list_feeds!\n    clean_feeds!(inactive_list_ids, :list)\n  end\n\n  def clean_feeds!(ids, type)\n    reblogged_id_sets = {}\n\n    redis.pipelined do\n      ids.each do |feed_id|\n        redis.del(feed_manager.key(type, feed_id))\n        reblog_key = feed_manager.key(type, feed_id, 'reblogs')\n        # We collect a future for this: we don't block while getting\n        # it, but we can iterate over it later.\n        reblogged_id_sets[feed_id] = redis.zrange(reblog_key, 0, -1)\n        redis.del(reblog_key)\n      end\n    end\n\n    # Remove all of the reblog tracking keys we just removed the\n    # references to.\n    redis.pipelined do\n      reblogged_id_sets.each do |feed_id, future|\n        future.value.each do |reblogged_id|\n          reblog_set_key = feed_manager.key(type, feed_id, \"reblogs:#{reblogged_id}\")\n          redis.del(reblog_set_key)\n        end\n      end\n    end\n  end\n\n  def inactive_account_ids\n    @inactive_account_ids ||= User.confirmed.inactive.pluck(:account_id)\n  end\n\n  def inactive_list_ids\n    List.where(account_id: inactive_account_ids).pluck(:id)\n  end\n\n  def feed_manager\n    FeedManager.instance\n  end\nend\n"
  },
  {
    "path": "app/workers/scheduler/ip_cleanup_scheduler.rb",
    "content": "# frozen_string_literal: true\n\nclass Scheduler::IpCleanupScheduler\n  include Sidekiq::Worker\n\n  RETENTION_PERIOD = 1.year\n\n  sidekiq_options unique: :until_executed, retry: 0\n\n  def perform\n    time_ago = RETENTION_PERIOD.ago\n    SessionActivation.where('updated_at < ?', time_ago).destroy_all\n    User.where('last_sign_in_at < ?', time_ago).update_all(last_sign_in_ip: nil)\n  end\nend\n"
  },
  {
    "path": "app/workers/scheduler/media_cleanup_scheduler.rb",
    "content": "# frozen_string_literal: true\n\nclass Scheduler::MediaCleanupScheduler\n  include Sidekiq::Worker\n\n  sidekiq_options unique: :until_executed, retry: 0\n\n  def perform\n    unattached_media.find_each(&:destroy)\n  end\n\n  private\n\n  def unattached_media\n    MediaAttachment.reorder(nil).unattached.where('created_at < ?', 1.day.ago)\n  end\nend\n"
  },
  {
    "path": "app/workers/scheduler/pghero_scheduler.rb",
    "content": "# frozen_string_literal: true\n\nclass Scheduler::PgheroScheduler\n  include Sidekiq::Worker\n\n  sidekiq_options unique: :until_executed, retry: 0\n\n  def perform\n    PgHero.capture_space_stats\n  end\nend\n"
  },
  {
    "path": "app/workers/scheduler/scheduled_statuses_scheduler.rb",
    "content": "# frozen_string_literal: true\n\nclass Scheduler::ScheduledStatusesScheduler\n  include Sidekiq::Worker\n\n  sidekiq_options unique: :until_executed, retry: 0\n\n  def perform\n    due_statuses.find_each do |scheduled_status|\n      PublishScheduledStatusWorker.perform_at(scheduled_status.scheduled_at, scheduled_status.id)\n    end\n  end\n\n  private\n\n  def due_statuses\n    ScheduledStatus.where('scheduled_at <= ?', Time.now.utc + PostStatusService::MIN_SCHEDULE_OFFSET)\n  end\nend\n"
  },
  {
    "path": "app/workers/scheduler/subscriptions_cleanup_scheduler.rb",
    "content": "# frozen_string_literal: true\n\nclass Scheduler::SubscriptionsCleanupScheduler\n  include Sidekiq::Worker\n\n  sidekiq_options unique: :until_executed, retry: 0\n\n  def perform\n    Subscription.expired.in_batches.delete_all\n  end\nend\n"
  },
  {
    "path": "app/workers/scheduler/subscriptions_scheduler.rb",
    "content": "# frozen_string_literal: true\n\nclass Scheduler::SubscriptionsScheduler\n  include Sidekiq::Worker\n\n  sidekiq_options unique: :until_executed, retry: 0\n\n  def perform\n    Pubsubhubbub::SubscribeWorker.push_bulk(expiring_accounts.pluck(:id))\n  end\n\n  private\n\n  def expiring_accounts\n    Account.expiring(1.day.from_now).partitioned\n  end\nend\n"
  },
  {
    "path": "app/workers/scheduler/user_cleanup_scheduler.rb",
    "content": "# frozen_string_literal: true\n\nclass Scheduler::UserCleanupScheduler\n  include Sidekiq::Worker\n\n  sidekiq_options unique: :until_executed, retry: 0\n\n  def perform\n    User.where('confirmed_at is NULL AND confirmation_sent_at <= ?', 2.days.ago).reorder(nil).find_in_batches do |batch|\n      Account.where(id: batch.map(&:account_id)).delete_all\n      User.where(id: batch.map(&:id)).delete_all\n    end\n  end\nend\n"
  },
  {
    "path": "app/workers/thread_resolve_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass ThreadResolveWorker\n  include Sidekiq::Worker\n  include ExponentialBackoff\n\n  sidekiq_options queue: 'pull', retry: 3\n\n  def perform(child_status_id, parent_url)\n    child_status  = Status.find(child_status_id)\n    parent_status = FetchRemoteStatusService.new.call(parent_url)\n\n    return if parent_status.nil?\n\n    child_status.thread = parent_status\n    child_status.save!\n  end\nend\n"
  },
  {
    "path": "app/workers/unfavourite_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass UnfavouriteWorker\n  include Sidekiq::Worker\n\n  def perform(account_id, status_id)\n    UnfavouriteService.new.call(Account.find(account_id), Status.find(status_id))\n  rescue ActiveRecord::RecordNotFound\n    true\n  end\nend\n"
  },
  {
    "path": "app/workers/unfollow_follow_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass UnfollowFollowWorker\n  include Sidekiq::Worker\n\n  sidekiq_options queue: 'pull'\n\n  def perform(follower_account_id, old_target_account_id, new_target_account_id)\n    follower_account   = Account.find(follower_account_id)\n    old_target_account = Account.find(old_target_account_id)\n    new_target_account = Account.find(new_target_account_id)\n\n    FollowService.new.call(follower_account, new_target_account)\n    UnfollowService.new.call(follower_account, old_target_account)\n  rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError\n    true\n  end\nend\n"
  },
  {
    "path": "app/workers/unmerge_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass UnmergeWorker\n  include Sidekiq::Worker\n\n  sidekiq_options queue: 'pull'\n\n  def perform(from_account_id, into_account_id)\n    FeedManager.instance.unmerge_from_timeline(Account.find(from_account_id), Account.find(into_account_id))\n  end\nend\n"
  },
  {
    "path": "app/workers/verify_account_links_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass VerifyAccountLinksWorker\n  include Sidekiq::Worker\n\n  sidekiq_options queue: 'pull', retry: false, unique: :until_executed\n\n  def perform(account_id)\n    account = Account.find(account_id)\n\n    account.fields.each do |field|\n      next unless !field.verified? && field.verifiable?\n      VerifyLinkService.new.call(field)\n    end\n\n    account.save! if account.changed?\n  rescue ActiveRecord::RecordNotFound\n    true\n  end\nend\n"
  },
  {
    "path": "app/workers/web/push_notification_worker.rb",
    "content": "# frozen_string_literal: true\n\nclass Web::PushNotificationWorker\n  include Sidekiq::Worker\n\n  sidekiq_options backtrace: true\n\n  def perform(subscription_id, notification_id)\n    subscription = ::Web::PushSubscription.find(subscription_id)\n    notification = Notification.find(notification_id)\n\n    subscription.push(notification) unless notification.activity.nil?\n  rescue Webpush::ResponseError => e\n    subscription.destroy! if (400..499).cover?(e.response.code.to_i)\n  rescue ActiveRecord::RecordNotFound\n    true\n  end\nend\n"
  },
  {
    "path": "app.json",
    "content": "{\n  \"name\": \"Florence Mastodon\",\n  \"description\": \"A GNU Social-compatible microblogging server\",\n  \"repository\": \"https://github.com/florence-social/mastodon-fork\",\n  \"logo\": \"https://github.com/tootsuite.png\",\n  \"env\": {\n    \"HEROKU\": {\n      \"description\": \"Leave this as true\",\n      \"value\": \"true\",\n      \"required\": true\n    },\n    \"LOCAL_DOMAIN\": {\n      \"description\": \"The domain that your Mastodon instance will run on (this can be appname.herokuapp.com or a custom domain)\",\n      \"required\": true\n    },\n    \"LOCAL_HTTPS\": {\n      \"description\": \"Will your domain support HTTPS? (Automatic for herokuapp, requires manual configuration for custom domains)\",\n      \"value\": \"false\",\n      \"required\": true\n    },\n    \"PAPERCLIP_SECRET\": {\n      \"description\": \"The secret key for storing media files\",\n      \"generator\": \"secret\"\n    },\n    \"SECRET_KEY_BASE\": {\n      \"description\": \"The secret key base\",\n      \"generator\": \"secret\"\n    },\n    \"OTP_SECRET\": {\n      \"description\": \"One-time password secret\",\n      \"generator\": \"secret\"\n    },\n    \"SINGLE_USER_MODE\": {\n      \"description\": \"Should the instance run in single user mode? (Disable registrations, redirect to front page)\",\n      \"value\": \"false\",\n      \"required\": true\n    },\n    \"S3_ENABLED\": {\n      \"description\": \"Should Mastodon use Amazon S3 for storage? This is highly recommended, as Heroku does not have persistent file storage (files will be lost).\",\n      \"value\": \"true\",\n      \"required\": false\n    },\n    \"S3_BUCKET\": {\n      \"description\": \"Amazon S3 Bucket\",\n      \"required\": false\n    },\n    \"S3_REGION\": {\n      \"description\": \"Amazon S3 region that the bucket is located in\",\n      \"required\": false\n    },\n    \"AWS_ACCESS_KEY_ID\": {\n      \"description\": \"Amazon S3 Access Key\",\n      \"required\": false\n    },\n    \"AWS_SECRET_ACCESS_KEY\": {\n      \"description\": \"Amazon S3 Secret Key\",\n      \"required\": false\n    },\n    \"SMTP_SERVER\": {\n      \"description\": \"Hostname for SMTP server, if you want to enable email\",\n      \"required\": false\n    },\n    \"SMTP_PORT\": {\n      \"description\": \"Port for SMTP server\",\n      \"required\": false\n    },\n    \"SMTP_LOGIN\": {\n      \"description\": \"Username for SMTP server\",\n      \"required\": false\n    },\n    \"SMTP_PASSWORD\": {\n      \"description\": \"Password for SMTP server\",\n      \"required\": false\n    },\n    \"SMTP_DOMAIN\": {\n      \"description\": \"Domain for SMTP server. Will default to instance domain if blank.\",\n      \"required\": false\n    },\n    \"SMTP_FROM_ADDRESS\": {\n      \"description\": \"Address to send emails from\",\n      \"required\": false\n    },\n    \"SMTP_AUTH_METHOD\": {\n      \"description\": \"Authentication method to use with SMTP server. Default is 'plain'.\",\n      \"required\": false\n    },\n    \"SMTP_OPENSSL_VERIFY_MODE\": {\n      \"description\": \"SMTP server certificate verification mode. Defaults is 'peer'.\",\n      \"required\": false\n    },\n    \"SMTP_ENABLE_STARTTLS_AUTO\": {\n      \"description\": \"Enable STARTTLS if SMTP server supports it? Default is true.\",\n      \"required\": false\n    }\n  },\n  \"buildpacks\": [\n    {\n      \"url\": \"https://github.com/heroku/heroku-buildpack-apt\"\n    },\n    {\n      \"url\": \"heroku/nodejs\"\n    },\n    {\n      \"url\": \"heroku/ruby\"\n    }\n  ],\n  \"scripts\": {\n    \"postdeploy\": \"bundle exec rails db:migrate && bundle exec rails db:seed\"\n  },\n  \"addons\": [\n    \"heroku-postgresql\",\n    \"heroku-redis\"\n  ]\n}\n"
  },
  {
    "path": "babel.config.js",
    "content": "module.exports = (api) => {\n  const env = api.env();\n\n  const envOptions = {\n    debug: false,\n    loose: true,\n    modules: false,\n  };\n\n  const config = {\n    presets: [\n      '@babel/react',\n      ['@babel/env', envOptions],\n    ],\n    plugins: [\n      '@babel/syntax-dynamic-import',\n      ['@babel/proposal-object-rest-spread', { useBuiltIns: true }],\n      ['@babel/proposal-decorators', { legacy: true }],\n      '@babel/proposal-class-properties',\n      ['react-intl', { messagesDir: './build/messages/' }],\n      'preval',\n    ],\n  };\n\n  switch (env) {\n  case 'production':\n    envOptions.debug = false;\n    config.plugins.push(...[\n      'lodash',\n      [\n        'transform-react-remove-prop-types',\n        {\n          mode: 'remove',\n          removeImport: true,\n          additionalLibraries: [\n            'react-immutable-proptypes',\n          ],\n        },\n      ],\n      '@babel/transform-react-inline-elements',\n      [\n        '@babel/transform-runtime',\n        {\n          helpers: true,\n          regenerator: false,\n          useESModules: true,\n        },\n      ],\n    ]);\n    break;\n  case 'development':\n    envOptions.debug = true;\n    config.plugins.push(...[\n      '@babel/transform-react-jsx-source',\n      '@babel/transform-react-jsx-self',\n    ]);\n    break;\n  case 'test':\n    envOptions.modules = 'commonjs';\n    break;\n  }\n\n  return config;\n};\n\n"
  },
  {
    "path": "bin/bundle",
    "content": "#!/usr/bin/env ruby\nENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)\nload Gem.bin_path('bundler', 'bundle')\n"
  },
  {
    "path": "bin/rails",
    "content": "#!/usr/bin/env ruby\nAPP_PATH = File.expand_path('../config/application', __dir__)\nrequire_relative '../config/boot'\nrequire 'rails/commands'\n"
  },
  {
    "path": "bin/rake",
    "content": "#!/usr/bin/env ruby\nrequire_relative '../config/boot'\nrequire 'rake'\nRake.application.run\n"
  },
  {
    "path": "bin/retry",
    "content": "#!/bin/bash\n# https://github.com/travis-ci/travis-build/blob/cbe49ea239ab37b9b38b5b44d287b7ec7a108c16/lib/travis/build/templates/header.sh#L243-L260\n#\n# MIT LICENSE\n#\n# Copyright (c) 2016 Travis CI GmbH <contact@travis-ci.org>\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n# THE SOFTWARE.\nretry() {\n  local result=0\n  local count=1\n\n  while [ $count -le 3 ]; do\n    if [ $result -ne 0 ]; then\n      echo -e \"\\n${ANSI_RED}The command \\\"$@\\\" failed. Retrying, $count of 3.${ANSI_RESET}\\n\" >&2\n    fi\n\n    \"$@\" && { result=0 && break; } || result=$?\n    count=$(($count + 1))\n    sleep 1\n  done\n\n  if [ $count -gt 3 ]; then\n    echo -e \"\\n${ANSI_RED}The command \\\"$@\\\" failed 3 times.${ANSI_RESET}\\n\" >&2\n  fi\n\n  return $result\n}\n\nretry $@\n"
  },
  {
    "path": "bin/rspec",
    "content": "#!/usr/bin/env ruby\n# frozen_string_literal: true\n#\n# This file was generated by Bundler.\n#\n# The application 'rspec' is installed as part of a gem, and\n# this file is here to facilitate running it.\n#\n\nrequire \"pathname\"\nENV[\"BUNDLE_GEMFILE\"] ||= File.expand_path(\"../../Gemfile\",\n  Pathname.new(__FILE__).realpath)\n\nrequire \"rubygems\"\nrequire \"bundler/setup\"\n\nload Gem.bin_path(\"rspec-core\", \"rspec\")\n"
  },
  {
    "path": "bin/setup",
    "content": "#!/usr/bin/env ruby\nrequire 'fileutils'\ninclude FileUtils\n\n# path to your application root.\nAPP_ROOT = File.expand_path('..', __dir__)\n\ndef system!(*args)\n  system(*args) || abort(\"\\n== Command #{args} failed ==\")\nend\n\nchdir APP_ROOT do\n  # This script is a starting point to setup your application.\n  # Add necessary setup steps to this file.\n\n  puts '== Installing dependencies =='\n  system! 'gem install bundler --conservative'\n  system('bundle check') || system!('bundle install')\n  system!('yarn install')\n\n  # puts \"\\n== Copying sample files ==\"\n  # unless File.exist?('config/database.yml')\n  #   cp 'config/database.yml.sample', 'config/database.yml'\n  # end\n\n  puts \"\\n== Preparing database ==\"\n  system! 'bin/rails db:setup'\n\n  puts \"\\n== Removing old logs and tempfiles ==\"\n  system! 'bin/rails log:clear tmp:clear'\n\n  puts \"\\n== Restarting application server ==\"\n  system! 'bin/rails restart'\nend\n"
  },
  {
    "path": "bin/tootctl",
    "content": "#!/usr/bin/env ruby\nAPP_PATH = File.expand_path('../config/application', __dir__)\nrequire_relative '../config/boot'\nrequire_relative '../lib/cli'\nMastodon::CLI.start(ARGV)\n"
  },
  {
    "path": "bin/update",
    "content": "#!/usr/bin/env ruby\nrequire 'fileutils'\ninclude FileUtils\n\n# path to your application root.\nAPP_ROOT = File.expand_path('..', __dir__)\n\ndef system!(*args)\n  system(*args) || abort(\"\\n== Command #{args} failed ==\")\nend\n\nchdir APP_ROOT do\n  # This script is a way to update your development environment automatically.\n  # Add necessary update steps to this file.\n\n  puts '== Installing dependencies =='\n  system! 'gem install bundler --conservative'\n  system('bundle check') || system!('bundle install')\n\n  # Install JavaScript dependencies if using Yarn\n  system('bin/yarn')\n\n  puts \"\\n== Updating database ==\"\n  system! 'bin/rails db:migrate'\n\n  puts \"\\n== Removing old logs and tempfiles ==\"\n  system! 'bin/rails log:clear tmp:clear'\n\n  puts \"\\n== Restarting application server ==\"\n  system! 'bin/rails restart'\nend\n"
  },
  {
    "path": "bin/webpack",
    "content": "#!/usr/bin/env ruby\n\nENV[\"RAILS_ENV\"] ||= ENV[\"RACK_ENV\"] || \"development\"\nENV[\"NODE_ENV\"]  ||= \"development\"\n\nrequire \"pathname\"\nENV[\"BUNDLE_GEMFILE\"] ||= File.expand_path(\"../../Gemfile\",\n  Pathname.new(__FILE__).realpath)\n\nrequire \"rubygems\"\nrequire \"bundler/setup\"\n\nrequire \"webpacker\"\nrequire \"webpacker/webpack_runner\"\n\nAPP_ROOT = File.expand_path(\"..\", __dir__)\nDir.chdir(APP_ROOT) do\n  Webpacker::WebpackRunner.run(ARGV)\nend\n"
  },
  {
    "path": "bin/webpack-dev-server",
    "content": "#!/usr/bin/env ruby\n\nENV[\"RAILS_ENV\"] ||= ENV[\"RACK_ENV\"] || \"development\"\nENV[\"NODE_ENV\"]  ||= \"development\"\n\nrequire \"pathname\"\nENV[\"BUNDLE_GEMFILE\"] ||= File.expand_path(\"../../Gemfile\",\n  Pathname.new(__FILE__).realpath)\n\nrequire \"rubygems\"\nrequire \"bundler/setup\"\n\nrequire \"webpacker\"\nrequire \"webpacker/dev_server_runner\"\n\nAPP_ROOT = File.expand_path(\"..\", __dir__)\nDir.chdir(APP_ROOT) do\n  Webpacker::DevServerRunner.run(ARGV)\nend\n"
  },
  {
    "path": "bin/yarn",
    "content": "#!/usr/bin/env ruby\nAPP_ROOT = File.expand_path('..', __dir__)\nDir.chdir(APP_ROOT) do\n  begin\n    exec \"yarnpkg\", *ARGV\n  rescue Errno::ENOENT\n    $stderr.puts \"Yarn executable was not detected in the system.\"\n    $stderr.puts \"Download Yarn at https://yarnpkg.com/en/docs/install\"\n    exit 1\n  end\nend\n"
  },
  {
    "path": "boxfile.yml",
    "content": "run.config:\n  engine: ruby\n  engine.config:\n    runtime: ruby-2.5\n\n  extra_packages:\n    # basic servers:\n    - nginx\n    - nodejs\n\n    # for images:\n    - ImageMagick\n    - jemalloc\n\n    # for videos:\n    - ffmpeg3\n\n    # to prep the .env file:\n    - gettext-tools\n\n    # for node-gyp, used in the asset compilation process:\n    - python-2\n\n    # i18n:\n    - libidn\n\n  cache_dirs:\n    - node_modules\n\n  extra_path_dirs:\n    - node_modules/.bin\n\n  build_triggers:\n    - .ruby-version\n    - Gemfile\n    - Gemfile.lock\n    - package.json\n    - yarn.lock\n\n  extra_steps:\n    - cp .env.nanobox .env\n    - yarn\n\n  fs_watch: true\n\n\ndeploy.config:\n  extra_steps:\n    - NODE_ENV=production bundle exec rake assets:precompile\n  transform:\n    - \"envsubst < /app/.env.nanobox > /app/.env.production\"\n    - |-\n        if [ -z \"$LOCAL_DOMAIN\" ]\n        then\n          . /app/.env.production\n          export LOCAL_DOMAIN\n        fi\n        erb /app/nanobox/nginx-web.conf.erb > /app/nanobox/nginx-web.conf\n        erb /app/nanobox/nginx-stream.conf.erb > /app/nanobox/nginx-stream.conf\n    - touch /app/log/production.log\n  before_live:\n    web.web:\n      - bundle exec rake db:migrate:setup\n      - |-\n          if [[ \"${ES_ENABLED}\" != \"false\" ]]\n          then\n            bin/tootctl search deploy\n          fi\n      - bin/tootctl cache clear\n\n\nweb.web:\n  start:\n    nginx: nginx -c /app/nanobox/nginx-web.conf\n    rails: bundle exec puma -C /app/config/puma.rb\n\n  routes:\n    - '/'\n\n  writable_dirs:\n    - tmp\n\n  log_watch:\n    rails: 'log/production.log'\n\n  network_dirs:\n    data.storage:\n      - public/system\n\n\nweb.stream:\n  start:\n    nginx: nginx -c /app/nanobox/nginx-stream.conf\n    node: yarn run start\n\n  routes:\n    - '/api/v1/streaming*'\n    # Somehow we're getting requests for scheme://domain//api/v1/streaming* - match those, too\n    - '//api/v1/streaming*'\n\n  writable_dirs:\n    - tmp\n\n\nworker.sidekiq:\n  start:\n    default: bundle exec sidekiq -c 5 -q default -L /app/log/sidekiq.log\n    mailers: bundle exec sidekiq -c 5 -q mailers -L /app/log/sidekiq.log\n    pull: bundle exec sidekiq -c 5 -q pull -L /app/log/sidekiq.log\n    push: bundle exec sidekiq -c 5 -q push -L /app/log/sidekiq.log\n\n  writable_dirs:\n    - tmp\n\n  log_watch:\n    rails: 'log/production.log'\n    sidekiq: 'log/sidekiq.log'\n\n  network_dirs:\n    data.storage:\n      - public/system\n\n\ndata.db:\n  image: nanobox/postgresql:9.6\n\n  cron:\n    - id: backup\n      schedule: '0 3 * * *'\n      command: |\n        PGPASSWORD=${DATA_DB_PASS} pg_dump -U ${DATA_DB_USER} -w -Fc -O gonano |\n        gzip |\n        curl -k -H \"X-AUTH-TOKEN: ${WAREHOUSE_DATA_HOARDER_TOKEN}\" https://${WAREHOUSE_DATA_HOARDER_HOST}:7410/blobs/backup-${HOSTNAME}-$(date -u +%Y-%m-%d.%H-%M-%S).sql.gz -X POST -T - >&2\n        curl -k -s -H \"X-AUTH-TOKEN: ${WAREHOUSE_DATA_HOARDER_TOKEN}\" https://${WAREHOUSE_DATA_HOARDER_HOST}:7410/blobs/ |\n        sed 's/,/\\n/g' |\n        grep ${HOSTNAME} |\n        sort |\n        head -n-${BACKUP_COUNT:-1} |\n        sed 's/.*: \\?\"\\(.*\\)\".*/\\1/' |\n        while read file\n        do\n          curl -k -H \"X-AUTH-TOKEN: ${WAREHOUSE_DATA_HOARDER_TOKEN}\" https://${WAREHOUSE_DATA_HOARDER_HOST}:7410/blobs/${file} -X DELETE\n        done\n\n\ndata.elastic:\n  image: nanobox/elasticsearch:5\n\n  cron:\n    - id: backup\n      schedule: '0 3 * * *'\n      command: |\n        id=$(cat /proc/sys/kernel/random/uuid)\n        curl -X PUT -H \"Content-Type: application/json\" \"127.0.0.1:9200/_snapshot/${id}\" -d \"{\\\"type\\\": \\\"fs\\\",\\\"settings\\\": {\\\"location\\\": \\\"/var/tmp/${id}\\\",\\\"compress\\\": true}}\"\n        curl -X PUT -H \"Content-Type: application/json\" \"127.0.0.1:9200/_snapshot/${id}/backup?wait_for_completion=true&pretty\"\n        tar -cz -C \"/var/tmp/${id}\" . |\n        curl -k -H \"X-AUTH-TOKEN: ${WAREHOUSE_DATA_HOARDER_TOKEN}\" https://${WAREHOUSE_DATA_HOARDER_HOST}:7410/blobs/backup-${HOSTNAME}-$(date -u +%Y-%m-%d.%H-%M-%S).tgz -X POST -T - >&2\n        curl -X DELETE -H \"Content-Type: application/json\" \"127.0.0.1:9200/_snapshot/${id}\"\n        rm -rf \"/var/tmp/${id}\"\n        curl -k -s -H \"X-AUTH-TOKEN: ${WAREHOUSE_DATA_HOARDER_TOKEN}\" https://${WAREHOUSE_DATA_HOARDER_HOST}:7410/blobs/ |\n        sed 's/,/\\n/g' |\n        grep ${HOSTNAME} |\n        sort |\n        head -n-${BACKUP_COUNT:-1} |\n        sed 's/.*: \\?\"\\(.*\\)\".*/\\1/' |\n        while read file\n        do\n          curl -k -H \"X-AUTH-TOKEN: ${WAREHOUSE_DATA_HOARDER_TOKEN}\" https://${WAREHOUSE_DATA_HOARDER_HOST}:7410/blobs/${file} -X DELETE\n        done\n\n\ndata.redis:\n  image: nanobox/redis:4.0\n\n  cron:\n    - id: backup\n      schedule: '0 3 * * *'\n      command: |\n        curl -k -H \"X-AUTH-TOKEN: ${WAREHOUSE_DATA_HOARDER_TOKEN}\" https://${WAREHOUSE_DATA_HOARDER_HOST}:7410/blobs/backup-${HOSTNAME}-$(date -u +%Y-%m-%d.%H-%M-%S).rdb -X POST -T /data/var/db/redis/dump.rdb >&2\n        curl -k -s -H \"X-AUTH-TOKEN: ${WAREHOUSE_DATA_HOARDER_TOKEN}\" https://${WAREHOUSE_DATA_HOARDER_HOST}:7410/blobs/ |\n        sed 's/,/\\n/g' |\n        grep ${HOSTNAME} |\n        sort |\n        head -n-${BACKUP_COUNT:-1} |\n        sed 's/.*: \\?\"\\(.*\\)\".*/\\1/' |\n        while read file\n        do\n          curl -k -H \"X-AUTH-TOKEN: ${WAREHOUSE_DATA_HOARDER_TOKEN}\" https://${WAREHOUSE_DATA_HOARDER_HOST}:7410/blobs/${file} -X DELETE\n        done\n\n\ndata.storage:\n  image: nanobox/unfs:0.9\n\n  cron:\n    - id: backup\n      schedule: '0 3 * * *'\n      command: |\n        tar cz -C /data/var/db/unfs/ . |\n        curl -k -H \"X-AUTH-TOKEN: ${WAREHOUSE_DATA_HOARDER_TOKEN}\" https://${WAREHOUSE_DATA_HOARDER_HOST}:7410/blobs/backup-${HOSTNAME}-$(date -u +%Y-%m-%d.%H-%M-%S).tgz -X POST -T - >&2\n        curl -k -s -H \"X-AUTH-TOKEN: ${WAREHOUSE_DATA_HOARDER_TOKEN}\" https://${WAREHOUSE_DATA_HOARDER_HOST}:7410/blobs/ |\n        sed 's/,/\\n/g' |\n        grep ${HOSTNAME} |\n        sort |\n        head -n-${BACKUP_COUNT:-1} |\n        sed 's/.*: \\?\"\\(.*\\)\".*/\\1/' |\n        while read file\n        do\n          curl -k -H \"X-AUTH-TOKEN: ${WAREHOUSE_DATA_HOARDER_TOKEN}\" https://${WAREHOUSE_DATA_HOARDER_HOST}:7410/blobs/${file} -X DELETE\n        done\n"
  },
  {
    "path": "config/application.rb",
    "content": "require_relative 'boot'\n\nrequire 'rails/all'\n\n# Require the gems listed in Gemfile, including any gems\n# you've limited to :test, :development, or :production.\nBundler.require(*Rails.groups)\n\nrequire_relative '../app/lib/exceptions'\nrequire_relative '../lib/paperclip/lazy_thumbnail'\nrequire_relative '../lib/paperclip/gif_transcoder'\nrequire_relative '../lib/paperclip/video_transcoder'\nrequire_relative '../lib/mastodon/snowflake'\nrequire_relative '../lib/mastodon/version'\nrequire_relative '../lib/florence/version'\nrequire_relative '../lib/devise/ldap_authenticatable'\n\nDotenv::Railtie.load\n\nBundler.require(:pam_authentication) if ENV['PAM_ENABLED'] == 'true'\n\nrequire_relative '../lib/mastodon/redis_config'\n\nmodule Mastodon\n  class Application < Rails::Application\n    # Initialize configuration defaults for originally generated Rails version.\n    config.load_defaults 5.2\n\n    # Settings in config/environments/* take precedence over those specified here.\n    # Application configuration should go into files in config/initializers\n    # -- all .rb files in that directory are automatically loaded.\n\n    # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.\n    # Run \"rake -D time\" for a list of tasks for finding time zone names. Default is UTC.\n    # config.time_zone = 'Central Time (US & Canada)'\n\n    # All translations from config/locales/*.rb,yml are auto loaded.\n    # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]\n    config.i18n.available_locales = [\n      :en,\n      :ar,\n      :ast,\n      :bg,\n      :bn,\n      :ca,\n      :co,\n      :cs,\n      :cy,\n      :da,\n      :de,\n      :el,\n      :eo,\n      :es,\n      :eu,\n      :fa,\n      :fi,\n      :fr,\n      :ga,\n      :gl,\n      :he,\n      :hi,\n      :hr,\n      :hu,\n      :hy,\n      :id,\n      :io,\n      :it,\n      :ja,\n      :ka,\n      :kk,\n      :ko,\n      :lt,\n      :lv,\n      :ms,\n      :nl,\n      :no,\n      :oc,\n      :pl,\n      :pt,\n      :'pt-BR',\n      :ro,\n      :ru,\n      :sk,\n      :sl,\n      :sq,\n      :sr,\n      :'sr-Latn',\n      :sv,\n      :ta,\n      :te,\n      :th,\n      :tr,\n      :uk,\n      :'zh-CN',\n      :'zh-HK',\n      :'zh-TW',\n    ]\n\n    config.i18n.default_locale = ENV['DEFAULT_LOCALE']&.to_sym\n\n    unless config.i18n.available_locales.include?(config.i18n.default_locale)\n      config.i18n.default_locale = :en\n    end\n\n    # config.paths.add File.join('app', 'api'), glob: File.join('**', '*.rb')\n    # config.autoload_paths += Dir[Rails.root.join('app', 'api', '*')]\n\n    config.active_job.queue_adapter = :sidekiq\n\n    config.middleware.use Rack::Attack\n    config.middleware.use Rack::Deflater\n\n    config.to_prepare do\n      Doorkeeper::AuthorizationsController.layout 'modal'\n      Doorkeeper::AuthorizedApplicationsController.layout 'admin'\n      Doorkeeper::Application.send :include, ApplicationExtension\n    end\n  end\nend\n"
  },
  {
    "path": "config/boot.rb",
    "content": "ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)\n\nrequire 'bundler/setup' # Set up gems listed in the Gemfile.\nrequire 'bootsnap' # Speed up boot time by caching expensive operations.\n\nBootsnap.setup(\n  cache_dir:            File.expand_path('../tmp/cache', __dir__),\n  development_mode:     ENV.fetch('RAILS_ENV', 'development') == 'development',\n  load_path_cache:      true,\n  autoload_paths_cache: true,\n  disable_trace:        false,\n  compile_cache_iseq:   false,\n  compile_cache_yaml:   false\n)\n"
  },
  {
    "path": "config/brakeman.ignore",
    "content": "{\n  \"ignored_warnings\": [\n    {\n      \"warning_type\": \"Mass Assignment\",\n      \"warning_code\": 105,\n      \"fingerprint\": \"0117d2be5947ea4e4fbed9c15f23c6615b12c6892973411820c83d079808819d\",\n      \"check_name\": \"PermitAttributes\",\n      \"message\": \"Potentially dangerous key allowed for mass assignment\",\n      \"file\": \"app/controllers/api/v1/search_controller.rb\",\n      \"line\": 30,\n      \"link\": \"https://brakemanscanner.org/docs/warning_types/mass_assignment/\",\n      \"code\": \"params.permit(:type, :offset, :min_id, :max_id, :account_id)\",\n      \"render_path\": null,\n      \"location\": {\n        \"type\": \"method\",\n        \"class\": \"Api::V1::SearchController\",\n        \"method\": \"search_params\"\n      },\n      \"user_input\": \":account_id\",\n      \"confidence\": \"High\",\n      \"note\": \"\"\n    },\n    {\n      \"warning_type\": \"SQL Injection\",\n      \"warning_code\": 0,\n      \"fingerprint\": \"04dbbc249b989db2e0119bbb0f59c9818e12889d2b97c529cdc0b1526002ba4b\",\n      \"check_name\": \"SQL\",\n      \"message\": \"Possible SQL injection\",\n      \"file\": \"app/models/report.rb\",\n      \"line\": 90,\n      \"link\": \"https://brakemanscanner.org/docs/warning_types/sql_injection/\",\n      \"code\": \"Admin::ActionLog.from(\\\"(#{[Admin::ActionLog.where(:target_type => \\\"Report\\\", :target_id => id, :created_at => ((created_at..updated_at))).unscope(:order), Admin::ActionLog.where(:target_type => \\\"Account\\\", :target_id => target_account_id, :created_at => ((created_at..updated_at))).unscope(:order), Admin::ActionLog.where(:target_type => \\\"Status\\\", :target_id => status_ids, :created_at => ((created_at..updated_at))).unscope(:order)].map do\\n \\\"(#{query.to_sql})\\\"\\n end.join(\\\" UNION ALL \\\")}) AS admin_action_logs\\\")\",\n      \"render_path\": null,\n      \"location\": {\n        \"type\": \"method\",\n        \"class\": \"Report\",\n        \"method\": \"history\"\n      },\n      \"user_input\": \"Admin::ActionLog.where(:target_type => \\\"Status\\\", :target_id => status_ids, :created_at => ((created_at..updated_at))).unscope(:order)\",\n      \"confidence\": \"High\",\n      \"note\": \"\"\n    },\n    {\n      \"warning_type\": \"SQL Injection\",\n      \"warning_code\": 0,\n      \"fingerprint\": \"19df3740b8d02a9fe0eb52c939b4b87d3a2a591162a6adfa8d64e9c26aeebe6d\",\n      \"check_name\": \"SQL\",\n      \"message\": \"Possible SQL injection\",\n      \"file\": \"app/models/status.rb\",\n      \"line\": 87,\n      \"link\": \"https://brakemanscanner.org/docs/warning_types/sql_injection/\",\n      \"code\": \"result.joins(\\\"INNER JOIN statuses_tags t#{id} ON t#{id}.status_id = statuses.id AND t#{id}.tag_id = #{id}\\\")\",\n      \"render_path\": null,\n      \"location\": {\n        \"type\": \"method\",\n        \"class\": \"Status\",\n        \"method\": null\n      },\n      \"user_input\": \"id\",\n      \"confidence\": \"Weak\",\n      \"note\": \"\"\n    },\n    {\n      \"warning_type\": \"Mass Assignment\",\n      \"warning_code\": 105,\n      \"fingerprint\": \"28d81cc22580ef76e912b077b245f353499aa27b3826476667224c00227af2a9\",\n      \"check_name\": \"PermitAttributes\",\n      \"message\": \"Potentially dangerous key allowed for mass assignment\",\n      \"file\": \"app/controllers/admin/reports_controller.rb\",\n      \"line\": 56,\n      \"link\": \"https://brakemanscanner.org/docs/warning_types/mass_assignment/\",\n      \"code\": \"params.permit(:account_id, :resolved, :target_account_id)\",\n      \"render_path\": null,\n      \"location\": {\n        \"type\": \"method\",\n        \"class\": \"Admin::ReportsController\",\n        \"method\": \"filter_params\"\n      },\n      \"user_input\": \":account_id\",\n      \"confidence\": \"High\",\n      \"note\": \"\"\n    },\n    {\n      \"warning_type\": \"Dynamic Render Path\",\n      \"warning_code\": 15,\n      \"fingerprint\": \"4b6a895e2805578d03ceedbe1d469cc75a0c759eba093722523edb4b8683c873\",\n      \"check_name\": \"Render\",\n      \"message\": \"Render path contains parameter value\",\n      \"file\": \"app/views/admin/action_logs/index.html.haml\",\n      \"line\": 4,\n      \"link\": \"https://brakemanscanner.org/docs/warning_types/dynamic_render_path/\",\n      \"code\": \"render(action => Admin::ActionLog.page(params[:page]), {})\",\n      \"render_path\": [{\"type\":\"controller\",\"class\":\"Admin::ActionLogsController\",\"method\":\"index\",\"line\":7,\"file\":\"app/controllers/admin/action_logs_controller.rb\",\"rendered\":{\"name\":\"admin/action_logs/index\",\"file\":\"/home/eugr/Projects/mastodon/app/views/admin/action_logs/index.html.haml\"}}],\n      \"location\": {\n        \"type\": \"template\",\n        \"template\": \"admin/action_logs/index\"\n      },\n      \"user_input\": \"params[:page]\",\n      \"confidence\": \"Weak\",\n      \"note\": \"\"\n    },\n    {\n      \"warning_type\": \"Redirect\",\n      \"warning_code\": 18,\n      \"fingerprint\": \"5fad11cd67f905fab9b1d5739d01384a1748ebe78c5af5ac31518201925265a7\",\n      \"check_name\": \"Redirect\",\n      \"message\": \"Possible unprotected redirect\",\n      \"file\": \"app/controllers/remote_interaction_controller.rb\",\n      \"line\": 21,\n      \"link\": \"https://brakemanscanner.org/docs/warning_types/redirect/\",\n      \"code\": \"redirect_to(RemoteFollow.new(resource_params).interact_address_for(Status.find(params[:id])))\",\n      \"render_path\": null,\n      \"location\": {\n        \"type\": \"method\",\n        \"class\": \"RemoteInteractionController\",\n        \"method\": \"create\"\n      },\n      \"user_input\": \"RemoteFollow.new(resource_params).interact_address_for(Status.find(params[:id]))\",\n      \"confidence\": \"High\",\n      \"note\": \"\"\n    },\n    {\n      \"warning_type\": \"Dynamic Render Path\",\n      \"warning_code\": 15,\n      \"fingerprint\": \"67afc0d5f7775fa5bd91d1912e1b5505aeedef61876347546fa20f92fd6915e6\",\n      \"check_name\": \"Render\",\n      \"message\": \"Render path contains parameter value\",\n      \"file\": \"app/views/stream_entries/embed.html.haml\",\n      \"line\": 3,\n      \"link\": \"https://brakemanscanner.org/docs/warning_types/dynamic_render_path/\",\n      \"code\": \"render(action => \\\"stream_entries/#{Account.find_local!(params[:account_username]).statuses.find(params[:id]).stream_entry.activity_type.downcase}\\\", { Account.find_local!(params[:account_username]).statuses.find(params[:id]).stream_entry.activity_type.downcase.to_sym => Account.find_local!(params[:account_username]).statuses.find(params[:id]).stream_entry.activity, :centered => true, :autoplay => ActiveModel::Type::Boolean.new.cast(params[:autoplay]) })\",\n      \"render_path\": [{\"type\":\"controller\",\"class\":\"StatusesController\",\"method\":\"embed\",\"line\":63,\"file\":\"app/controllers/statuses_controller.rb\",\"rendered\":{\"name\":\"stream_entries/embed\",\"file\":\"/home/eugr/Projects/mastodon/app/views/stream_entries/embed.html.haml\"}}],\n      \"location\": {\n        \"type\": \"template\",\n        \"template\": \"stream_entries/embed\"\n      },\n      \"user_input\": \"params[:id]\",\n      \"confidence\": \"Weak\",\n      \"note\": \"\"\n    },\n    {\n      \"warning_type\": \"SQL Injection\",\n      \"warning_code\": 0,\n      \"fingerprint\": \"6f075c1484908e3ec9bed21ab7cf3c7866be8da3881485d1c82e13093aefcbd7\",\n      \"check_name\": \"SQL\",\n      \"message\": \"Possible SQL injection\",\n      \"file\": \"app/models/status.rb\",\n      \"line\": 92,\n      \"link\": \"https://brakemanscanner.org/docs/warning_types/sql_injection/\",\n      \"code\": \"result.joins(\\\"LEFT OUTER JOIN statuses_tags t#{id} ON t#{id}.status_id = statuses.id AND t#{id}.tag_id = #{id}\\\")\",\n      \"render_path\": null,\n      \"location\": {\n        \"type\": \"method\",\n        \"class\": \"Status\",\n        \"method\": null\n      },\n      \"user_input\": \"id\",\n      \"confidence\": \"Weak\",\n      \"note\": \"\"\n    },\n    {\n      \"warning_type\": \"Dynamic Render Path\",\n      \"warning_code\": 15,\n      \"fingerprint\": \"8d843713d99e8403f7992f3e72251b633817cf9076ffcbbad5613859d2bbc127\",\n      \"check_name\": \"Render\",\n      \"message\": \"Render path contains parameter value\",\n      \"file\": \"app/views/admin/custom_emojis/index.html.haml\",\n      \"line\": 45,\n      \"link\": \"https://brakemanscanner.org/docs/warning_types/dynamic_render_path/\",\n      \"code\": \"render(action => filtered_custom_emojis.eager_load(:local_counterpart).page(params[:page]), {})\",\n      \"render_path\": [{\"type\":\"controller\",\"class\":\"Admin::CustomEmojisController\",\"method\":\"index\",\"line\":11,\"file\":\"app/controllers/admin/custom_emojis_controller.rb\",\"rendered\":{\"name\":\"admin/custom_emojis/index\",\"file\":\"/home/eugr/Projects/mastodon/app/views/admin/custom_emojis/index.html.haml\"}}],\n      \"location\": {\n        \"type\": \"template\",\n        \"template\": \"admin/custom_emojis/index\"\n      },\n      \"user_input\": \"params[:page]\",\n      \"confidence\": \"Weak\",\n      \"note\": \"\"\n    },\n    {\n      \"warning_type\": \"SQL Injection\",\n      \"warning_code\": 0,\n      \"fingerprint\": \"9ccb9ba6a6947400e187d515e0bf719d22993d37cfc123c824d7fafa6caa9ac3\",\n      \"check_name\": \"SQL\",\n      \"message\": \"Possible SQL injection\",\n      \"file\": \"lib/mastodon/snowflake.rb\",\n      \"line\": 87,\n      \"link\": \"https://brakemanscanner.org/docs/warning_types/sql_injection/\",\n      \"code\": \"connection.execute(\\\"        CREATE OR REPLACE FUNCTION timestamp_id(table_name text)\\\\n        RETURNS bigint AS\\\\n        $$\\\\n          DECLARE\\\\n            time_part bigint;\\\\n            sequence_base bigint;\\\\n            tail bigint;\\\\n          BEGIN\\\\n            time_part := (\\\\n              -- Get the time in milliseconds\\\\n              ((date_part('epoch', now()) * 1000))::bigint\\\\n              -- And shift it over two bytes\\\\n              << 16);\\\\n\\\\n            sequence_base := (\\\\n              'x' ||\\\\n              -- Take the first two bytes (four hex characters)\\\\n              substr(\\\\n                -- Of the MD5 hash of the data we documented\\\\n                md5(table_name ||\\\\n                  '#{SecureRandom.hex(16)}' ||\\\\n                  time_part::text\\\\n                ),\\\\n                1, 4\\\\n              )\\\\n            -- And turn it into a bigint\\\\n            )::bit(16)::bigint;\\\\n\\\\n            -- Finally, add our sequence number to our base, and chop\\\\n            -- it to the last two bytes\\\\n            tail := (\\\\n              (sequence_base + nextval(table_name || '_id_seq'))\\\\n              & 65535);\\\\n\\\\n            -- Return the time part and the sequence part. OR appears\\\\n            -- faster here than addition, but they're equivalent:\\\\n            -- time_part has no trailing two bytes, and tail is only\\\\n            -- the last two bytes.\\\\n            RETURN time_part | tail;\\\\n          END\\\\n        $$ LANGUAGE plpgsql VOLATILE;\\\\n\\\")\",\n      \"render_path\": null,\n      \"location\": {\n        \"type\": \"method\",\n        \"class\": \"Mastodon::Snowflake\",\n        \"method\": \"define_timestamp_id\"\n      },\n      \"user_input\": \"SecureRandom.hex(16)\",\n      \"confidence\": \"Medium\",\n      \"note\": \"\"\n    },\n    {\n      \"warning_type\": \"Dynamic Render Path\",\n      \"warning_code\": 15,\n      \"fingerprint\": \"9f31d941f3910dba2e9bfcd81aef4513249bd24c02d0f98e13ad44fdeeccd0e8\",\n      \"check_name\": \"Render\",\n      \"message\": \"Render path contains parameter value\",\n      \"file\": \"app/views/admin/accounts/index.html.haml\",\n      \"line\": 47,\n      \"link\": \"https://brakemanscanner.org/docs/warning_types/dynamic_render_path/\",\n      \"code\": \"render(action => filtered_accounts.page(params[:page]), {})\",\n      \"render_path\": [{\"type\":\"controller\",\"class\":\"Admin::AccountsController\",\"method\":\"index\",\"line\":12,\"file\":\"app/controllers/admin/accounts_controller.rb\",\"rendered\":{\"name\":\"admin/accounts/index\",\"file\":\"/home/eugr/Projects/mastodon/app/views/admin/accounts/index.html.haml\"}}],\n      \"location\": {\n        \"type\": \"template\",\n        \"template\": \"admin/accounts/index\"\n      },\n      \"user_input\": \"params[:page]\",\n      \"confidence\": \"Weak\",\n      \"note\": \"\"\n    },\n    {\n      \"warning_type\": \"Redirect\",\n      \"warning_code\": 18,\n      \"fingerprint\": \"ba699ddcc6552c422c4ecd50d2cd217f616a2446659e185a50b05a0f2dad8d33\",\n      \"check_name\": \"Redirect\",\n      \"message\": \"Possible unprotected redirect\",\n      \"file\": \"app/controllers/media_controller.rb\",\n      \"line\": 14,\n      \"link\": \"https://brakemanscanner.org/docs/warning_types/redirect/\",\n      \"code\": \"redirect_to(MediaAttachment.attached.find_by!(:shortcode => ((params[:id] or params[:medium_id]))).file.url(:original))\",\n      \"render_path\": null,\n      \"location\": {\n        \"type\": \"method\",\n        \"class\": \"MediaController\",\n        \"method\": \"show\"\n      },\n      \"user_input\": \"MediaAttachment.attached.find_by!(:shortcode => ((params[:id] or params[:medium_id]))).file.url(:original)\",\n      \"confidence\": \"High\",\n      \"note\": \"\"\n    },\n    {\n      \"warning_type\": \"Redirect\",\n      \"warning_code\": 18,\n      \"fingerprint\": \"bb7e94e60af41decb811bb32171f1b27e9bf3f4d01e9e511127362e22510eb11\",\n      \"check_name\": \"Redirect\",\n      \"message\": \"Possible unprotected redirect\",\n      \"file\": \"app/controllers/remote_follow_controller.rb\",\n      \"line\": 19,\n      \"link\": \"https://brakemanscanner.org/docs/warning_types/redirect/\",\n      \"code\": \"redirect_to(RemoteFollow.new(resource_params).subscribe_address_for(Account.find_local!(params[:account_username])))\",\n      \"render_path\": null,\n      \"location\": {\n        \"type\": \"method\",\n        \"class\": \"RemoteFollowController\",\n        \"method\": \"create\"\n      },\n      \"user_input\": \"RemoteFollow.new(resource_params).subscribe_address_for(Account.find_local!(params[:account_username]))\",\n      \"confidence\": \"High\",\n      \"note\": \"\"\n    },\n    {\n      \"warning_type\": \"Mass Assignment\",\n      \"warning_code\": 105,\n      \"fingerprint\": \"e867661b2c9812bc8b75a5df12b28e2a53ab97015de0638b4e732fe442561b28\",\n      \"check_name\": \"PermitAttributes\",\n      \"message\": \"Potentially dangerous key allowed for mass assignment\",\n      \"file\": \"app/controllers/api/v1/reports_controller.rb\",\n      \"line\": 36,\n      \"link\": \"https://brakemanscanner.org/docs/warning_types/mass_assignment/\",\n      \"code\": \"params.permit(:account_id, :comment, :forward, :status_ids => ([]))\",\n      \"render_path\": null,\n      \"location\": {\n        \"type\": \"method\",\n        \"class\": \"Api::V1::ReportsController\",\n        \"method\": \"report_params\"\n      },\n      \"user_input\": \":account_id\",\n      \"confidence\": \"High\",\n      \"note\": \"\"\n    },\n    {\n      \"warning_type\": \"Dynamic Render Path\",\n      \"warning_code\": 15,\n      \"fingerprint\": \"fbd0fc59adb5c6d44b60e02debb31d3af11719f534c9881e21435bbff87404d6\",\n      \"check_name\": \"Render\",\n      \"message\": \"Render path contains parameter value\",\n      \"file\": \"app/views/stream_entries/show.html.haml\",\n      \"line\": 23,\n      \"link\": \"https://brakemanscanner.org/docs/warning_types/dynamic_render_path/\",\n      \"code\": \"render(partial => \\\"stream_entries/#{Account.find_local!(params[:account_username]).statuses.find(params[:id]).stream_entry.activity_type.downcase}\\\", { :locals => ({ Account.find_local!(params[:account_username]).statuses.find(params[:id]).stream_entry.activity_type.downcase.to_sym => Account.find_local!(params[:account_username]).statuses.find(params[:id]).stream_entry.activity, :include_threads => true }) })\",\n      \"render_path\": [{\"type\":\"controller\",\"class\":\"StatusesController\",\"method\":\"show\",\"line\":34,\"file\":\"app/controllers/statuses_controller.rb\",\"rendered\":{\"name\":\"stream_entries/show\",\"file\":\"/home/eugr/Projects/mastodon/app/views/stream_entries/show.html.haml\"}}],\n      \"location\": {\n        \"type\": \"template\",\n        \"template\": \"stream_entries/show\"\n      },\n      \"user_input\": \"params[:id]\",\n      \"confidence\": \"Weak\",\n      \"note\": \"\"\n    }\n  ],\n  \"updated\": \"2019-02-21 02:30:29 +0100\",\n  \"brakeman_version\": \"4.4.0\"\n}\n"
  },
  {
    "path": "config/database.yml",
    "content": "default: &default\n  adapter: postgresql\n  pool: <%= ENV[\"DB_POOL\"] || ENV['MAX_THREADS'] || 5 %>\n  timeout: 5000\n  encoding: unicode\n  sslmode: <%= ENV['DB_SSLMODE'] || \"prefer\" %>\n\ndevelopment:\n  <<: *default\n  database: <%= ENV['DB_NAME'] || 'mastodon_development' %>\n  username: <%= ENV['DB_USER'] %>\n  password: <%= ENV['DB_PASS'] %>\n  host: <%= ENV['DB_HOST'] %>\n  port: <%= ENV['DB_PORT'] %>\n\n# Warning: The database defined as \"test\" will be erased and\n# re-generated from your development database when you run \"rake\".\n# Do not set this db to the same as development or production.\ntest:\n  <<: *default\n  database: <%= ENV['DB_NAME'] || 'mastodon' %>_test<%= ENV['TEST_ENV_NUMBER'] %>\n  username: <%= ENV['DB_USER'] %>\n  password: <%= ENV['DB_PASS'] %>\n  host: <%= ENV['DB_HOST'] %>\n  port: <%= ENV['DB_PORT'] %>\n\nproduction:\n  <<: *default\n  database: <%= ENV['DB_NAME'] || 'mastodon_production' %>\n  username: <%= ENV['DB_USER'] || 'mastodon' %>\n  password: <%= ENV['DB_PASS'] || '' %>\n  host: <%= ENV['DB_HOST'] || 'localhost' %>\n  port: <%= ENV['DB_PORT'] || 5432 %>\n  prepared_statements: <%= ENV['PREPARED_STATEMENTS'] || 'true' %>\n\n"
  },
  {
    "path": "config/deploy.rb",
    "content": "# frozen_string_literal: true\n\nlock '3.11.0'\n\nset :repo_url, ENV.fetch('REPO', 'https://github.com/florence-social/mastodon-fork.git')\nset :branch, ENV.fetch('BRANCH', 'master')\n\nset :application, 'mastodon'\nset :rbenv_type, :user\nset :rbenv_ruby, File.read('.ruby-version').strip\nset :migration_role, :app\n\nappend :linked_files, '.env.production', 'public/robots.txt'\nappend :linked_dirs, 'vendor/bundle', 'node_modules', 'public/system'\n"
  },
  {
    "path": "config/environment.rb",
    "content": "# Load the Rails application.\nrequire_relative 'application'\n\n# Initialize the Rails application.\nRails.application.initialize!\n\nActiveRecord::SchemaDumper.ignore_tables = ['deprecated_preview_cards']\n"
  },
  {
    "path": "config/environments/development.rb",
    "content": "Rails.application.configure do\n  # Settings specified here will take precedence over those in config/application.rb.\n\n  # In the development environment your application's code is reloaded on\n  # every request. This slows down response time but is perfect for development\n  # since you don't have to restart the web server when you make code changes.\n  config.cache_classes = false\n\n  # Do not eager load code on boot.\n  config.eager_load = false\n\n  # Show full error reports.\n  config.consider_all_requests_local = true\n\n  # Enable/disable caching. By default caching is disabled.\n  # Run rails dev:cache to toggle caching.\n  if Rails.root.join('tmp/caching-dev.txt').exist?\n    config.action_controller.perform_caching = true\n\n    config.cache_store = :redis_store, ENV['REDIS_URL'], REDIS_CACHE_PARAMS\n\n    config.public_file_server.headers = {\n      'Cache-Control' => \"public, max-age=#{2.days.to_i}\",\n    }\n  else\n    config.action_controller.perform_caching = false\n\n    config.cache_store = :null_store\n  end\n\n  ActiveSupport::Logger.new(STDOUT).tap do |logger|\n    logger.formatter = config.log_formatter\n    config.logger = ActiveSupport::TaggedLogging.new(logger)\n  end\n\n  # Generate random VAPID keys\n  vapid_key = Webpush.generate_key\n  config.x.vapid_private_key = vapid_key.private_key\n  config.x.vapid_public_key = vapid_key.public_key\n\n  # Don't care if the mailer can't send.\n  config.action_mailer.raise_delivery_errors = false\n\n  config.action_mailer.perform_caching = false\n\n  # Print deprecation notices to the Rails logger.\n  config.active_support.deprecation = :log\n\n  # Raise an error on page load if there are pending migrations.\n  config.active_record.migration_error = :page_load\n\n  # Debug mode disables concatenation and preprocessing of assets.\n  # This option may cause significant delays in view rendering with a large\n  # number of complex assets.\n  config.assets.debug = true\n\n  # Suppress logger output for asset requests.\n  config.assets.quiet = true\n\n  # Adds additional error checking when serving assets at runtime.\n  # Checks for improperly declared sprockets dependencies.\n  # Raises helpful error messages.\n  config.assets.raise_runtime_errors = true\n\n  # Raises error for missing translations\n  # config.action_view.raise_on_missing_translations = true\n\n  # Use an evented file watcher to asynchronously detect changes in source code,\n  # routes, locales, etc. This feature depends on the listen gem.\n  # config.file_watcher = ActiveSupport::EventedFileUpdateChecker\n\n  config.action_mailer.default_options = { from: 'notifications@localhost' }\n\n  # If using a Heroku, Vagrant or generic remote development environment,\n  # use letter_opener_web, accessible at  /letter_opener.\n  # Otherwise, use letter_opener, which launches a browser window to view sent mail.\n  config.action_mailer.delivery_method = (ENV['HEROKU'] || ENV['VAGRANT'] || ENV['REMOTE_DEV']) ? :letter_opener_web : :letter_opener\n\n  config.after_initialize do\n    Bullet.enable        = true\n    Bullet.bullet_logger = true\n    Bullet.rails_logger  = false\n\n    Bullet.add_whitelist type: :n_plus_one_query, class_name: 'User', association: :account\n  end\n\n  config.x.otp_secret = ENV.fetch('OTP_SECRET', '1fc2b87989afa6351912abeebe31ffc5c476ead9bf8b3d74cbc4a302c7b69a45b40b1bbef3506ddad73e942e15ed5ca4b402bf9a66423626051104f4b5f05109')\nend\n\nActiveRecordQueryTrace.enabled = ENV['QUERY_TRACE_ENABLED'] == 'true'\n\nmodule PrivateAddressCheck\n  def self.private_address?(*)\n    false\n  end\nend\n"
  },
  {
    "path": "config/environments/production.rb",
    "content": "Rails.application.configure do\n  # Settings specified here will take precedence over those in config/application.rb.\n\n  # Code is not reloaded between requests.\n  config.cache_classes = true\n\n  # Eager load code on boot. This eager loads most of Rails and\n  # your application in memory, allowing both threaded web servers\n  # and those relying on copy on write to perform better.\n  # Rake tasks automatically ignore this option for performance.\n  config.eager_load = true\n\n  # Full error reports are disabled and caching is turned on.\n  config.consider_all_requests_local       = false\n  config.action_controller.perform_caching = true\n  config.action_controller.asset_host      = ENV['CDN_HOST'] if ENV['CDN_HOST'].present?\n\n  # Ensures that a master key has been made available in either ENV[\"RAILS_MASTER_KEY\"]\n  # or in config/master.key. This key is used to decrypt credentials (and other encrypted files).\n  # config.require_master_key = true\n\n  # Disable serving static files from the `/public` folder by default since\n  # Apache or NGINX already handles this.\n  config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?\n\n  ActiveSupport::Logger.new(STDOUT).tap do |logger|\n    logger.formatter = config.log_formatter\n    config.logger = ActiveSupport::TaggedLogging.new(logger)\n  end\n\n  # Compress JavaScripts and CSS.\n  # config.assets.js_compressor = Uglifier.new(mangle: false)\n  # config.assets.css_compressor = :sass\n\n  # Do not fallback to assets pipeline if a precompiled asset is missed.\n  config.assets.compile = false\n\n  # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb\n\n  # Specifies the header that your server uses for sending files.\n  # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache\n  config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX\n\n  # Allow to specify public IP of reverse proxy if it's needed\n  config.action_dispatch.trusted_proxies = ENV['TRUSTED_PROXY_IP'].split.map { |item| IPAddr.new(item) } if ENV['TRUSTED_PROXY_IP'].present?\n\n  # Use the lowest log level to ensure availability of diagnostic information\n  # when problems arise.\n  config.log_level = ENV.fetch('RAILS_LOG_LEVEL', 'info').to_sym\n\n  # Prepend all log lines with the following tags.\n  config.log_tags = [:request_id]\n\n  # Use a different cache store in production.\n  config.cache_store = :redis_store, ENV['CACHE_REDIS_URL'], REDIS_CACHE_PARAMS\n\n  # Ignore bad email addresses and do not raise email delivery errors.\n  # Set this to true and configure the email server for immediate delivery to raise delivery errors.\n  # config.action_mailer.raise_delivery_errors = false\n\n  # Enable locale fallbacks for I18n (makes lookups for any locale fall back to\n  # English when a translation cannot be found).\n  config.i18n.fallbacks = [:en]\n\n  # Send deprecation notices to registered listeners.\n  config.active_support.deprecation = :notify\n\n  # Use default logging formatter so that PID and timestamp are not suppressed.\n  config.log_formatter = ::Logger::Formatter.new\n\n  # Better log formatting\n  config.lograge.enabled = true\n\n  # Do not dump schema after migrations.\n  config.active_record.dump_schema_after_migration = false\n\n  config.action_mailer.perform_caching = false\n\n  # E-mails\n  config.action_mailer.default_options = { from: ENV.fetch('SMTP_FROM_ADDRESS', 'notifications@localhost') }\n\n  config.action_mailer.smtp_settings = {\n    :port                 => ENV['SMTP_PORT'],\n    :address              => ENV['SMTP_SERVER'],\n    :user_name            => ENV['SMTP_LOGIN'].presence,\n    :password             => ENV['SMTP_PASSWORD'].presence,\n    :domain               => ENV['SMTP_DOMAIN'] || ENV['LOCAL_DOMAIN'],\n    :authentication       => ENV['SMTP_AUTH_METHOD'] == 'none' ? nil : ENV['SMTP_AUTH_METHOD'] || :plain,\n    :ca_file              => ENV['SMTP_CA_FILE'].presence,\n    :openssl_verify_mode  => ENV['SMTP_OPENSSL_VERIFY_MODE'],\n    :enable_starttls_auto => ENV['SMTP_ENABLE_STARTTLS_AUTO'] || true,\n    :tls                  => ENV['SMTP_TLS'].presence,\n  }\n\n  config.action_mailer.delivery_method = ENV.fetch('SMTP_DELIVERY_METHOD', 'smtp').to_sym\n\n  config.action_dispatch.default_headers = {\n    'Server'                 => 'Mastodon',\n    'X-Frame-Options'        => 'DENY',\n    'X-Content-Type-Options' => 'nosniff',\n    'X-XSS-Protection'       => '1; mode=block',\n  }\n\n  config.x.otp_secret = ENV.fetch('OTP_SECRET')\nend\n"
  },
  {
    "path": "config/environments/test.rb",
    "content": "Rails.application.configure do\n  # Settings specified here will take precedence over those in config/application.rb.\n\n  # The test environment is used exclusively to run your application's\n  # test suite. You never need to work with it otherwise. Remember that\n  # your test database is \"scratch space\" for the test suite and is wiped\n  # and recreated between test runs. Don't rely on the data there!\n  config.cache_classes = true\n\n  # Do not eager load code on boot. This avoids loading your whole application\n  # just for the purpose of running a single test. If you are using a tool that\n  # preloads Rails for running tests, you may have to set it to true.\n  config.eager_load = false\n\n  # Configure public file server for tests with Cache-Control for performance.\n  config.public_file_server.enabled = true\n  config.public_file_server.headers = {\n    'Cache-Control' => \"public, max-age=#{1.hour.to_i}\"\n  }\n  config.assets.digest = false\n\n  # Show full error reports and disable caching.\n  config.consider_all_requests_local       = true\n  config.action_controller.perform_caching = false\n\n  # The default store, file_store is shared by processes parallelly executed\n  # and should not be used.\n  config.cache_store = :memory_store\n\n  # Raise exceptions instead of rendering exception templates.\n  config.action_dispatch.show_exceptions = false\n\n  # Disable request forgery protection in test environment.\n  config.action_controller.allow_forgery_protection = false\n  config.action_mailer.perform_caching = false\n\n  config.action_mailer.default_options = { from: 'notifications@localhost' }\n\n  # Tell Action Mailer not to deliver emails to the real world.\n  # The :test delivery method accumulates sent emails in the\n  # ActionMailer::Base.deliveries array.\n  config.action_mailer.delivery_method = :test\n\n  # Print deprecation notices to the stderr.\n  config.active_support.deprecation = :stderr\n\n  config.x.otp_secret = '100c7faeef00caa29242f6b04156742bf76065771fd4117990c4282b8748ff3d99f8fdae97c982ab5bd2e6756a159121377cce4421f4a8ecd2d67bd7749a3fb4'\n\n  # Generate random VAPID keys\n  vapid_key = Webpush.generate_key\n  config.x.vapid_private_key = vapid_key.private_key\n  config.x.vapid_public_key = vapid_key.public_key\n\n  # Raises error for missing translations\n  # config.action_view.raise_on_missing_translations = true\n\n  config.i18n.default_locale = :en\n  config.i18n.fallbacks = true\nend\n\nPaperclip::Attachment.default_options[:path] = \"#{Rails.root}/spec/test_files/:class/:id_partition/:style.:extension\"\n\n# set fake_data for pam, don't do real calls, just use fake data\nif ENV['PAM_ENABLED'] == 'true'\n  Rpam2.fake_data =\n    {\n      usernames: Set['pam_user1', 'pam_user2'],\n      servicenames: Set['pam_test', 'pam_test_controlled'],\n      password: '123456',\n      env: { email: 'pam@example.com' }\n    }\nend\n"
  },
  {
    "path": "config/i18n-tasks.yml",
    "content": "# i18n-tasks finds and manages missing and unused translations: https://github.com/glebm/i18n-tasks\n\n# The \"main\" locale.\nbase_locale: en\ndata:\n  read:\n    - config/locales/%{locale}.yml\n    - config/locales/**/*.%{locale}.yml\n\n  write:\n    - ['{devise, simple_form, doorkeeper}.*', 'config/locales/\\1.%{locale}.yml']\n    - config/locales/%{locale}.yml\n\n  yaml:\n    write:\n      line_width: -1\n\nsearch:\n  paths:\n   - app/\n   - config/navigation.rb\n\n  relative_roots:\n    - app/controllers\n    - app/helpers\n    - app/mailers\n    - app/views\n\n  exclude:\n    - app/assets/images\n    - app/assets/fonts\n    - app/assets/videos\n\nignore_missing:\n  - 'activemodel.errors.*'\n  - 'activerecord.attributes.*'\n  - 'activerecord.errors.*'\n  - '{pagination,doorkeeper}.*'\n  - '{date,datetime,time,number}.*'\n  - 'errors.messages.*'\n  - 'activerecord.errors.models.doorkeeper/*'\n  - 'sessions.{browsers,platforms}.*'\n  - 'terms.body_html'\n  - 'application_mailer.salutation'\n  - 'errors.500'\n  - 'auth.providers.*'\n\nignore_unused:\n  - 'activemodel.errors.*'\n  - 'activerecord.attributes.*'\n  - 'activerecord.errors.*'\n  - '{devise,pagination,doorkeeper}.*'\n  - '{date,datetime,time,number}.*'\n  - 'simple_form.{yes,no,recommended}'\n  - 'simple_form.{placeholders,hints,labels}.*'\n  - 'simple_form.{error_notification,required}.:'\n  - 'errors.messages.*'\n  - 'activerecord.errors.models.doorkeeper/*'\n  - 'errors.429'\n  - 'admin.accounts.roles.*'\n  - 'admin.action_logs.actions.*'\n  - 'statuses.attached.*'\n"
  },
  {
    "path": "config/initializers/0_post_deployment_migrations.rb",
    "content": "# Post deployment migrations are included by default. This file must be loaded\n# before other initializers as Rails may otherwise memoize a list of migrations\n# excluding the post deployment migrations.\n\nunless ENV['SKIP_POST_DEPLOYMENT_MIGRATIONS']\n  Rails.application.config.paths['db'].each do |db_path|\n    path = Rails.root.join(db_path, 'post_migrate').to_s\n\n    Rails.application.config.paths['db/migrate'] << path\n\n    # Rails memoizes migrations at certain points where it won't read the above\n    # path just yet. As such we must also update the following list of paths.\n    ActiveRecord::Migrator.migrations_paths << path\n  end\nend\n"
  },
  {
    "path": "config/initializers/1_hosts.rb",
    "content": "# frozen_string_literal: true\n\nport     = ENV.fetch('PORT') { 3000 }\nhost     = ENV.fetch('LOCAL_DOMAIN') { \"localhost:#{port}\" }\nweb_host = ENV.fetch('WEB_DOMAIN') { host }\n\nalternate_domains = ENV.fetch('ALTERNATE_DOMAINS') { '' }\n\nRails.application.configure do\n  https = Rails.env.production? || ENV['LOCAL_HTTPS'] == 'true'\n\n  config.x.local_domain = host\n  config.x.web_domain   = web_host\n  config.x.use_https    = https\n  config.x.use_s3       = ENV['S3_ENABLED'] == 'true'\n  config.x.use_swift    = ENV['SWIFT_ENABLED'] == 'true'\n\n  config.x.alternate_domains = alternate_domains.split(/\\s*,\\s*/)\n\n  config.action_mailer.default_url_options = { host: web_host, protocol: https ? 'https://' : 'http://', trailing_slash: false }\n\n  config.x.streaming_api_base_url = ENV.fetch('STREAMING_API_BASE_URL') do\n    if Rails.env.production?\n      \"ws#{https ? 's' : ''}://#{web_host}\"\n    else\n      \"ws://#{ENV['REMOTE_DEV'] == 'true' ? host.split(':').first : 'localhost'}:4000\"\n    end\n  end\nend\n"
  },
  {
    "path": "config/initializers/active_model_serializers.rb",
    "content": "ActiveModelSerializers.config.tap do |config|\n  config.default_includes = '**'\nend\n\nActiveSupport::Notifications.unsubscribe(ActiveModelSerializers::Logging::RENDER_EVENT)\n\nclass ActiveModel::Serializer::Reflection\n  # We monkey-patch this method so that when we include associations in a serializer,\n  # the nested serializers can send information about used contexts upwards back to\n  # the root. We do this via instance_options because the nesting can be dynamic.\n  def build_association(parent_serializer, parent_serializer_options, include_slice = {})\n    serializer = options[:serializer]\n\n    parent_serializer_options.merge!(named_contexts: serializer._named_contexts, context_extensions: serializer._context_extensions) if serializer.respond_to?(:_named_contexts)\n\n    association_options = {\n      parent_serializer: parent_serializer,\n      parent_serializer_options: parent_serializer_options,\n      include_slice: include_slice,\n    }\n\n    ActiveModel::Serializer::Association.new(self, association_options)\n  end\nend\n"
  },
  {
    "path": "config/initializers/application_controller_renderer.rb",
    "content": "# Be sure to restart your server when you modify this file.\n\n# ApplicationController.renderer.defaults.merge!(\n#   http_host: 'example.org',\n#   https: false\n# )\n"
  },
  {
    "path": "config/initializers/assets.rb",
    "content": "# Be sure to restart your server when you modify this file.\n\n# Version of your assets, change this if you want to expire all your assets.\nRails.application.config.assets.version = '1.0'\n\n# Add additional assets to the asset load path\n# Rails.application.config.assets.paths << 'node_modules'\n\n# Precompile additional assets.\n# application.js, application.css, and all non-JS/CSS in app/assets folder are already added.\n# Rails.application.config.assets.precompile += %w()\n\nRails.application.config.assets.initialize_on_precompile = true\n"
  },
  {
    "path": "config/initializers/backtrace_silencers.rb",
    "content": "# Be sure to restart your server when you modify this file.\n\n# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.\n# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }\n\n# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.\n# Rails.backtrace_cleaner.remove_silencers!\n"
  },
  {
    "path": "config/initializers/blacklists.rb",
    "content": "# frozen_string_literal: true\n\nRails.application.configure do\n  config.x.email_domains_blacklist = ENV.fetch('EMAIL_DOMAIN_BLACKLIST') { 'mvrht.com' }\n  config.x.email_domains_whitelist = ENV.fetch('EMAIL_DOMAIN_WHITELIST') { '' }\nend\n"
  },
  {
    "path": "config/initializers/chewy.rb",
    "content": "enabled         = ENV['ES_ENABLED'] == 'true'\nhost            = ENV.fetch('ES_HOST') { 'localhost' }\nport            = ENV.fetch('ES_PORT') { 9200 }\nfallback_prefix = ENV.fetch('REDIS_NAMESPACE') { nil }\nprefix          = ENV.fetch('ES_PREFIX') { fallback_prefix }\n\nChewy.settings = {\n  host: \"#{host}:#{port}\",\n  prefix: prefix,\n  enabled: enabled,\n  journal: false,\n  sidekiq: { queue: 'pull' },\n}\n\nChewy.root_strategy    = enabled ? :sidekiq : :bypass\nChewy.request_strategy = enabled ? :sidekiq : :bypass\n\nmodule Chewy\n  class << self\n    def enabled?\n      settings[:enabled]\n    end\n  end\nend\n"
  },
  {
    "path": "config/initializers/content_security_policy.rb",
    "content": "# Define an application-wide content security policy\n# For further information see the following documentation\n# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy\n\nbase_host     = Rails.configuration.x.web_domain\nassets_host   = Rails.configuration.action_controller.asset_host\nassets_host ||= \"http#{Rails.configuration.x.use_https ? 's' : ''}://#{base_host}\"\n\nRails.application.config.content_security_policy do |p|\n  p.base_uri        :none\n  p.default_src     :none\n  p.frame_ancestors :none\n  p.font_src        :self, assets_host\n  p.img_src         :self, :https, :data, :blob, assets_host\n  p.style_src       :self, :unsafe_inline, assets_host\n  p.media_src       :self, :https, :data, assets_host\n  p.frame_src       :self, :https\n  p.manifest_src    :self, assets_host\n\n  if Rails.env.development?\n    webpacker_urls = %w(ws http).map { |protocol| \"#{protocol}#{Webpacker.dev_server.https? ? 's' : ''}://#{Webpacker.dev_server.host_with_port}\" }\n\n    p.connect_src :self, :blob, assets_host, Rails.configuration.x.streaming_api_base_url, *webpacker_urls\n    p.script_src  :self, :unsafe_inline, :unsafe_eval, assets_host\n  else\n    p.connect_src :self, :blob, assets_host, Rails.configuration.x.streaming_api_base_url\n    p.script_src  :self, assets_host\n  end\nend\n\n# Report CSP violations to a specified URI\n# For further information see the following documentation:\n# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only\n# Rails.application.config.content_security_policy_report_only = true\n"
  },
  {
    "path": "config/initializers/cookies_serializer.rb",
    "content": "# Be sure to restart your server when you modify this file.\n\n# Specify a serializer for the signed and encrypted cookie jars.\n# Valid options are :json, :marshal, and :hybrid.\nRails.application.config.action_dispatch.cookies_serializer = :json\n"
  },
  {
    "path": "config/initializers/cors.rb",
    "content": "# Be sure to restart your server when you modify this file.\n\n# Avoid CORS issues when API is called from the frontend app.\n# Handle Cross-Origin Resource Sharing (CORS) in order to accept cross-origin AJAX requests.\n\n# Read more: https://github.com/cyu/rack-cors\n\nRails.application.config.middleware.insert_before 0, Rack::Cors do\n  allow do\n    origins '*'\n\n    resource '/.well-known/*',\n      headers: :any,\n      methods: [:get],\n      credentials: false\n    resource '/@:username',\n      headers: :any,\n      methods: [:get],\n      credentials: false\n    resource '/users/:username',\n      headers: :any,\n      methods: [:get],\n      credentials: false\n    resource '/api/*',\n      headers: :any,\n      methods: [:post, :put, :delete, :get, :patch, :options],\n      credentials: false,\n      expose: ['Link', 'X-RateLimit-Reset', 'X-RateLimit-Limit', 'X-RateLimit-Remaining', 'X-Request-Id']\n    resource '/oauth/token',\n      headers: :any,\n      methods: [:post],\n      credentials: false\n  end\nend\n"
  },
  {
    "path": "config/initializers/delivery_job.rb",
    "content": "ActionMailer::DeliveryJob.class_eval do\n  discard_on ActiveJob::DeserializationError\nend\n"
  },
  {
    "path": "config/initializers/devise.rb",
    "content": "Warden::Manager.after_set_user except: :fetch do |user, warden|\n  if user.session_active?(warden.cookies.signed['_session_id'] || warden.raw_session['auth_id'])\n    session_id = warden.cookies.signed['_session_id'] || warden.raw_session['auth_id']\n  else\n    session_id = user.activate_session(warden.request)\n  end\n\n  warden.cookies.signed['_session_id'] = {\n    value: session_id,\n    expires: 1.year.from_now,\n    httponly: true,\n    secure: (Rails.env.production? || ENV['LOCAL_HTTPS'] == 'true'),\n  }\nend\n\nWarden::Manager.after_fetch do |user, warden|\n  if user.session_active?(warden.cookies.signed['_session_id'] || warden.raw_session['auth_id'])\n    warden.cookies.signed['_session_id'] = {\n      value: warden.cookies.signed['_session_id'] || warden.raw_session['auth_id'],\n      expires: 1.year.from_now,\n      httponly: true,\n      secure: (Rails.env.production? || ENV['LOCAL_HTTPS'] == 'true'),\n    }\n  else\n    warden.logout\n    throw :warden, message: :unauthenticated\n  end\nend\n\nWarden::Manager.before_logout do |_, warden|\n  SessionActivation.deactivate warden.cookies.signed['_session_id']\n  warden.cookies.delete('_session_id')\nend\n\nmodule Devise\n  mattr_accessor :pam_authentication\n  @@pam_authentication = false\n  mattr_accessor :pam_controlled_service\n  @@pam_controlled_service = nil\n\n  mattr_accessor :check_at_sign\n  @@check_at_sign = false\n\n  mattr_accessor :ldap_authentication\n  @@ldap_authentication = false\n  mattr_accessor :ldap_host\n  @@ldap_host = nil\n  mattr_accessor :ldap_port\n  @@ldap_port = nil\n  mattr_accessor :ldap_method\n  @@ldap_method = nil\n  mattr_accessor :ldap_base\n  @@ldap_base = nil\n  mattr_accessor :ldap_uid\n  @@ldap_uid = nil\n  mattr_accessor :ldap_bind_dn\n  @@ldap_bind_dn = nil\n  mattr_accessor :ldap_password\n  @@ldap_password = nil\n  mattr_accessor :ldap_tls_no_verify\n  @@ldap_tls_no_verify = false\n  mattr_accessor :ldap_search_filter\n  @@ldap_search_filter = nil\n\n  class Strategies::PamAuthenticatable\n    def valid?\n      super && ::Devise.pam_authentication\n    end\n  end\nend\n\nDevise.setup do |config|\n  config.warden do |manager|\n    manager.default_strategies(scope: :user).unshift :ldap_authenticatable if Devise.ldap_authentication\n    manager.default_strategies(scope: :user).unshift :pam_authenticatable  if Devise.pam_authentication\n    manager.default_strategies(scope: :user).unshift :two_factor_authenticatable\n    manager.default_strategies(scope: :user).unshift :two_factor_backupable\n  end\n\n  # The secret key used by Devise. Devise uses this key to generate\n  # random tokens. Changing this key will render invalid all existing\n  # confirmation, reset password and unlock tokens in the database.\n  # Devise will use the `secret_key_base` on Rails 4+ applications as its `secret_key`\n  # by default. You can change it below and use your own secret key.\n  # config.secret_key = '2f86974c4dd7735170fd70fbf399f7a477ffd635ef240d07a22cf4bd7cd13dbae17c4383a2996d0c1e79a991ec18a91a17424c53e4771adb75a8b21904bd1403'\n\n  # ==> Mailer Configuration\n  # Configure the e-mail address which will be shown in Devise::Mailer,\n  # note that it will be overwritten if you use your own mailer class\n  # with default \"from\" parameter.\n  # config.mailer_sender = ENV['SMTP_FROM_ADDRESS'] || 'notifications@localhost'\n\n  # Configure the class responsible to send e-mails.\n  config.mailer = 'UserMailer'\n\n  # ==> ORM configuration\n  # Load and configure the ORM. Supports :active_record (default) and\n  # :mongoid (bson_ext recommended) by default. Other ORMs may be\n  # available as additional gems.\n  require 'devise/orm/active_record'\n\n  # ==> Configuration for any authentication mechanism\n  # Configure which keys are used when authenticating a user. The default is\n  # just :email. You can configure it to use [:username, :subdomain], so for\n  # authenticating a user, both parameters are required. Remember that those\n  # parameters are used only when authenticating and not when retrieving from\n  # session. If you need permissions, you should implement that in a before filter.\n  # You can also supply a hash where the value is a boolean determining whether\n  # or not authentication should be aborted when the value is not present.\n  # config.authentication_keys = [:email]\n\n  # Configure parameters from the request object used for authentication. Each entry\n  # given should be a request method and it will automatically be passed to the\n  # find_for_authentication method and considered in your model lookup. For instance,\n  # if you set :request_keys to [:subdomain], :subdomain will be used on authentication.\n  # The same considerations mentioned for authentication_keys also apply to request_keys.\n  # config.request_keys = []\n\n  # Configure which authentication keys should be case-insensitive.\n  # These keys will be downcased upon creating or modifying a user and when used\n  # to authenticate or find a user. Default is :email.\n  config.case_insensitive_keys = [:email]\n\n  # Configure which authentication keys should have whitespace stripped.\n  # These keys will have whitespace before and after removed upon creating or\n  # modifying a user and when used to authenticate or find a user. Default is :email.\n  config.strip_whitespace_keys = [:email]\n\n  # Tell if authentication through request.params is enabled. True by default.\n  # It can be set to an array that will enable params authentication only for the\n  # given strategies, for example, `config.params_authenticatable = [:database]` will\n  # enable it only for database (email + password) authentication.\n  # config.params_authenticatable = true\n\n  # Tell if authentication through HTTP Auth is enabled. False by default.\n  # It can be set to an array that will enable http authentication only for the\n  # given strategies, for example, `config.http_authenticatable = [:database]` will\n  # enable it only for database authentication. The supported strategies are:\n  # :database      = Support basic authentication with authentication key + password\n  config.http_authenticatable = [:pam, :database]\n\n  # If 401 status code should be returned for AJAX requests. True by default.\n  # config.http_authenticatable_on_xhr = true\n\n  # The realm used in Http Basic Authentication. 'Application' by default.\n  # config.http_authentication_realm = 'Application'\n\n  # It will change confirmation, password recovery and other workflows\n  # to behave the same regardless if the e-mail provided was right or wrong.\n  # Does not affect registerable.\n  # See : https://github.com/plataformatec/devise/wiki/How-To:-Using-paranoid-mode,-avoid-user-enumeration-on-registerable\n  config.paranoid = true\n\n  # By default Devise will store the user in session. You can skip storage for\n  # particular strategies by setting this option.\n  # Notice that if you are skipping storage for all authentication paths, you\n  # may want to disable generating routes to Devise's sessions controller by\n  # passing skip: :sessions to `devise_for` in your config/routes.rb\n  config.skip_session_storage = [:http_auth]\n\n  # By default, Devise cleans up the CSRF token on authentication to\n  # avoid CSRF token fixation attacks. This means that, when using AJAX\n  # requests for sign in and sign up, you need to get a new CSRF token\n  # from the server. You can disable this option at your own risk.\n  # config.clean_up_csrf_token_on_authentication = true\n\n  # ==> Configuration for :database_authenticatable\n  # For bcrypt, this is the cost for hashing the password and defaults to 10. If\n  # using other encryptors, it sets how many times you want the password re-encrypted.\n  #\n  # Limiting the stretches to just one in testing will increase the performance of\n  # your test suite dramatically. However, it is STRONGLY RECOMMENDED to not use\n  # a value less than 10 in other environments. Note that, for bcrypt (the default\n  # encryptor), the cost increases exponentially with the number of stretches (e.g.\n  # a value of 20 is already extremely slow: approx. 60 seconds for 1 calculation).\n  config.stretches = Rails.env.test? ? 1 : 10\n\n  # Setup a pepper to generate the encrypted password.\n  # config.pepper = '104d16705f794923e77c5e5167b52452d00646dc952a2d30b541c24086e647012c7b9625f253c51912e455981e503446772973d5f1638631196c819d7137fad4'\n\n  # Send a notification to the original email when the user's email is changed.\n  config.send_email_changed_notification = true\n\n  # Send a notification email when the user's password is changed\n  config.send_password_change_notification = true\n\n  # ==> Configuration for :confirmable\n  # A period that the user is allowed to access the website even without\n  # confirming their account. For instance, if set to 2.days, the user will be\n  # able to access the website for two days without confirming their account,\n  # access will be blocked just in the third day. Default is 0.days, meaning\n  # the user cannot access the website without confirming their account.\n  # config.allow_unconfirmed_access_for = 2.days\n\n  # A period that the user is allowed to confirm their account before their\n  # token becomes invalid. For example, if set to 3.days, the user can confirm\n  # their account within 3 days after the mail was sent, but on the fourth day\n  # their account can't be confirmed with the token any more.\n  # Default is nil, meaning there is no restriction on how long a user can take\n  # before confirming their account.\n  config.confirm_within = 2.days\n\n  # If true, requires any email changes to be confirmed (exactly the same way as\n  # initial account confirmation) to be applied. Requires additional unconfirmed_email\n  # db field (see migrations). Until confirmed, new email is stored in\n  # unconfirmed_email column, and copied to email column on successful confirmation.\n  config.reconfirmable = true\n\n  # Defines which key will be used when confirming an account\n  # config.confirmation_keys = [:email]\n\n  # ==> Configuration for :rememberable\n  # The time the user will be remembered without asking for credentials again.\n  config.remember_for = 1.year\n\n  # Invalidates all the remember me tokens when the user signs out.\n  config.expire_all_remember_me_on_sign_out = true\n\n  # If true, extends the user's remember period when remembered via cookie.\n  # config.extend_remember_period = false\n\n  # Options to be passed to the created cookie. For instance, you can set\n  # secure: true in order to force SSL only cookies.\n  config.rememberable_options = { secure: true }\n\n  # ==> Configuration for :validatable\n  # Range for password length.\n  config.password_length = 8..72\n\n  # Email regex used to validate email formats. It simply asserts that\n  # one (and only one) @ exists in the given string. This is mainly\n  # to give user feedback and not to assert the e-mail validity.\n  # config.email_regexp = /\\A[^@]+@[^@]+\\z/\n\n  # ==> Configuration for :timeoutable\n  # The time you want to timeout the user session without activity. After this\n  # time the user will be asked for credentials again. Default is 30 minutes.\n  # config.timeout_in = 30.minutes\n\n  # ==> Configuration for :lockable\n  # Defines which strategy will be used to lock an account.\n  # :failed_attempts = Locks an account after a number of failed attempts to sign in.\n  # :none            = No lock strategy. You should handle locking by yourself.\n  # config.lock_strategy = :failed_attempts\n\n  # Defines which key will be used when locking and unlocking an account\n  # config.unlock_keys = [:email]\n\n  # Defines which strategy will be used to unlock an account.\n  # :email = Sends an unlock link to the user email\n  # :time  = Re-enables login after a certain amount of time (see :unlock_in below)\n  # :both  = Enables both strategies\n  # :none  = No unlock strategy. You should handle unlocking by yourself.\n  # config.unlock_strategy = :both\n\n  # Number of authentication tries before locking an account if lock_strategy\n  # is failed attempts.\n  # config.maximum_attempts = 20\n\n  # Time interval to unlock the account if :time is enabled as unlock_strategy.\n  # config.unlock_in = 1.hour\n\n  # Warn on the last attempt before the account is locked.\n  # config.last_attempt_warning = true\n\n  # ==> Configuration for :recoverable\n  #\n  # Defines which key will be used when recovering the password for an account\n  # config.reset_password_keys = [:email]\n\n  # Time interval you can reset your password with a reset password key.\n  # Don't put a too small interval or your users won't have the time to\n  # change their passwords.\n  config.reset_password_within = 6.hours\n\n  # When set to false, does not sign a user in automatically after their password is\n  # reset. Defaults to true, so a user is signed in automatically after a reset.\n  config.sign_in_after_reset_password = false\n\n  # ==> Configuration for :encryptable\n  # Allow you to use another encryption algorithm besides bcrypt (default). You can use\n  # :sha1, :sha512 or encryptors from others authentication tools as :clearance_sha1,\n  # :authlogic_sha512 (then you should set stretches above to 20 for default behavior)\n  # and :restful_authentication_sha1 (then you should set stretches to 10, and copy\n  # REST_AUTH_SITE_KEY to pepper).\n  #\n  # Require the `devise-encryptable` gem when using anything other than bcrypt\n  # config.encryptor = :sha512\n\n  # ==> Scopes configuration\n  # Turn scoped views on. Before rendering \"sessions/new\", it will first check for\n  # \"users/sessions/new\". It's turned off by default because it's slower if you\n  # are using only default views.\n  # config.scoped_views = false\n\n  # Configure the default scope given to Warden. By default it's the first\n  # devise role declared in your routes (usually :user).\n  # config.default_scope = :user\n\n  # Set this configuration to false if you want /users/sign_out to sign out\n  # only the current scope. By default, Devise signs out all scopes.\n  # config.sign_out_all_scopes = true\n\n  # ==> Navigation configuration\n  # Lists the formats that should be treated as navigational. Formats like\n  # :html, should redirect to the sign in page when the user does not have\n  # access, but formats like :xml or :json, should return 401.\n  #\n  # If you have any extra navigational formats, like :iphone or :mobile, you\n  # should add them to the navigational formats lists.\n  #\n  # The \"*/*\" below is required to match Internet Explorer requests.\n  # config.navigational_formats = ['*/*', :html]\n\n  # The default HTTP method used to sign out a resource. Default is :delete.\n  config.sign_out_via = :delete\n\n  # ==> OmniAuth\n  # Add a new OmniAuth provider. Check the wiki for more information on setting\n  # up on your models and hooks.\n  # config.omniauth :github, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo'\n\n  # ==> Warden configuration\n  # If you want to use other strategies, that are not supported by Devise, or\n  # change the failure app, you can configure them inside the config.warden block.\n  #\n  # config.warden do |manager|\n  #   manager.intercept_401 = false\n  #   manager.default_strategies(scope: :user).unshift :some_external_strategy\n  # end\n\n  # ==> Mountable engine configurations\n  # When using Devise inside an engine, let's call it `MyEngine`, and this engine\n  # is mountable, there are some extra configurations to be taken into account.\n  # The following options are available, assuming the engine is mounted as:\n  #\n  #     mount MyEngine, at: '/my_engine'\n  #\n  # The router that invoked `devise_for`, in the example above, would be:\n  # config.router_name = :my_engine\n  #\n  # When using OmniAuth, Devise cannot automatically set OmniAuth path,\n  # so you need to do it manually. For the users scope, it would be:\n  # config.omniauth_path_prefix = '/my_engine/users/auth'\n\n  if ENV['PAM_ENABLED'] == 'true'\n    config.pam_authentication     = true\n    config.usernamefield          = nil\n    config.emailfield             = 'email'\n    config.check_at_sign          = true\n    config.pam_default_suffix     = ENV.fetch('PAM_EMAIL_DOMAIN') { ENV['LOCAL_DOMAIN'] }\n    config.pam_default_service    = ENV.fetch('PAM_DEFAULT_SERVICE') { 'rpam' }\n    config.pam_controlled_service = ENV.fetch('PAM_CONTROLLED_SERVICE') { nil }\n  end\n\n  if ENV['LDAP_ENABLED'] == 'true'\n    config.ldap_authentication = true\n    config.check_at_sign       = true\n    config.ldap_host           = ENV.fetch('LDAP_HOST', 'localhost')\n    config.ldap_port           = ENV.fetch('LDAP_PORT', 389).to_i\n    config.ldap_method         = ENV.fetch('LDAP_METHOD', :simple_tls).to_sym\n    config.ldap_base           = ENV.fetch('LDAP_BASE')\n    config.ldap_bind_dn        = ENV.fetch('LDAP_BIND_DN')\n    config.ldap_password       = ENV.fetch('LDAP_PASSWORD')\n    config.ldap_uid            = ENV.fetch('LDAP_UID', 'cn')\n    config.ldap_tls_no_verify  = ENV['LDAP_TLS_NO_VERIFY'] == 'true'\n    config.ldap_search_filter  = ENV.fetch('LDAP_SEARCH_FILTER', '%{uid}=%{email}')\n  end\nend\n"
  },
  {
    "path": "config/initializers/doorkeeper.rb",
    "content": "Doorkeeper.configure do\n  # Change the ORM that doorkeeper will use (needs plugins)\n  orm :active_record\n\n  # This block will be called to check whether the resource owner is authenticated or not.\n  resource_owner_authenticator do\n    current_user || redirect_to(new_user_session_url)\n  end\n\n  resource_owner_from_credentials do |_routes|\n    user = User.find_by(email: request.params[:username])\n    user if !user&.otp_required_for_login? && user&.valid_password?(request.params[:password])\n  end\n\n  # If you want to restrict access to the web interface for adding oauth authorized applications, you need to declare the block below.\n  admin_authenticator do\n    current_user&.admin? || redirect_to(new_user_session_url)\n  end\n\n  # Authorization Code expiration time (default 10 minutes).\n  # authorization_code_expires_in 10.minutes\n\n  # Access token expiration time (default 2 hours).\n  # If you want to disable expiration, set this to nil.\n  access_token_expires_in nil\n\n  # Assign a custom TTL for implicit grants.\n  # custom_access_token_expires_in do |oauth_client|\n  #   oauth_client.application.additional_settings.implicit_oauth_expiration\n  # end\n\n  # Use a custom class for generating the access token.\n  # https://github.com/doorkeeper-gem/doorkeeper#custom-access-token-generator\n  # access_token_generator \"::Doorkeeper::JWT\"\n\n  # The controller Doorkeeper::ApplicationController inherits from.\n  # Defaults to ActionController::Base.\n  # https://github.com/doorkeeper-gem/doorkeeper#custom-base-controller\n  base_controller 'ApplicationController'\n\n  # Reuse access token for the same resource owner within an application (disabled by default)\n  # Rationale: https://github.com/doorkeeper-gem/doorkeeper/issues/383\n  reuse_access_token\n\n  # Issue access tokens with refresh token (disabled by default)\n  # use_refresh_token\n\n  # Provide support for an owner to be assigned to each registered application (disabled by default)\n  # Optional parameter :confirmation => true (default false) if you want to enforce ownership of\n  # a registered application\n  # Note: you must also run the rails g doorkeeper:application_owner generator to provide the necessary support\n  enable_application_owner\n\n  # Define access token scopes for your provider\n  # For more information go to\n  # https://github.com/doorkeeper-gem/doorkeeper/wiki/Using-Scopes\n  default_scopes  :read\n  optional_scopes :write,\n                  :'write:accounts',\n                  :'write:blocks',\n                  :'write:conversations',\n                  :'write:favourites',\n                  :'write:filters',\n                  :'write:follows',\n                  :'write:lists',\n                  :'write:media',\n                  :'write:mutes',\n                  :'write:notifications',\n                  :'write:reports',\n                  :'write:statuses',\n                  :read,\n                  :'read:accounts',\n                  :'read:blocks',\n                  :'read:favourites',\n                  :'read:filters',\n                  :'read:follows',\n                  :'read:lists',\n                  :'read:mutes',\n                  :'read:notifications',\n                  :'read:search',\n                  :'read:statuses',\n                  :follow,\n                  :push\n\n  # Change the way client credentials are retrieved from the request object.\n  # By default it retrieves first from the `HTTP_AUTHORIZATION` header, then\n  # falls back to the `:client_id` and `:client_secret` params from the `params` object.\n  # Check out the wiki for more information on customization\n  # client_credentials :from_basic, :from_params\n\n  # Change the way access token is authenticated from the request object.\n  # By default it retrieves first from the `HTTP_AUTHORIZATION` header, then\n  # falls back to the `:access_token` or `:bearer_token` params from the `params` object.\n  # Check out the wiki for more information on customization\n  # access_token_methods :from_bearer_authorization, :from_access_token_param, :from_bearer_param\n\n  # Change the native redirect uri for client apps\n  # When clients register with the following redirect uri, they won't be redirected to any server and the authorization code will be displayed within the provider\n  # The value can be any string. Use nil to disable this feature. When disabled, clients must provide a valid URL\n  # (Similar behaviour: https://developers.google.com/accounts/docs/OAuth2InstalledApp#choosingredirecturi)\n  #\n  # native_redirect_uri 'urn:ietf:wg:oauth:2.0:oob'\n\n  # Forces the usage of the HTTPS protocol in non-native redirect uris (enabled\n  # by default in non-development environments). OAuth2 delegates security in\n  # communication to the HTTPS protocol so it is wise to keep this enabled.\n  #\n  force_ssl_in_redirect_uri false\n\n  # Specify what grant flows are enabled in array of Strings. The valid\n  # strings and the flows they enable are:\n  #\n  # \"authorization_code\" => Authorization Code Grant Flow\n  # \"implicit\"           => Implicit Grant Flow\n  # \"password\"           => Resource Owner Password Credentials Grant Flow\n  # \"client_credentials\" => Client Credentials Grant Flow\n  #\n  # If not specified, Doorkeeper enables authorization_code and\n  # client_credentials.\n  #\n  # implicit and password grant flows have risks that you should understand\n  # before enabling:\n  #   http://tools.ietf.org/html/rfc6819#section-4.4.2\n  #   http://tools.ietf.org/html/rfc6819#section-4.4.3\n  #\n\n  grant_flows %w(authorization_code password client_credentials)\n\n  # Under some circumstances you might want to have applications auto-approved,\n  # so that the user skips the authorization step.\n  # For example if dealing with a trusted application.\n  skip_authorization do |resource_owner, client|\n    client.application.superapp?\n  end\n\n  # WWW-Authenticate Realm (default \"Doorkeeper\").\n  # realm \"Doorkeeper\"\nend\n"
  },
  {
    "path": "config/initializers/fast_blank.rb",
    "content": "if String.method_defined?(:blank_as?)\n  class String\n    alias_method :blank?, :blank_as?\n  end\nend\n"
  },
  {
    "path": "config/initializers/ffmpeg.rb",
    "content": "if ENV['FFMPEG_BINARY'].present?\n    FFMPEG.ffmpeg_binary = ENV['FFMPEG_BINARY']\nend\n"
  },
  {
    "path": "config/initializers/filter_parameter_logging.rb",
    "content": "# Be sure to restart your server when you modify this file.\n\n# Configure sensitive parameters which will be filtered from the log file.\nRails.application.config.filter_parameters += [:password, :private_key, :public_key, :otp_attempt]\n"
  },
  {
    "path": "config/initializers/http_client_proxy.rb",
    "content": "Rails.application.configure do\n  config.x.http_client_proxy = {}\n  if ENV['http_proxy'].present?\n    proxy = URI.parse(ENV['http_proxy'])\n    raise \"Unsupported proxy type: #{proxy.scheme}\" unless %w(http https).include? proxy.scheme\n    raise \"No proxy host\" unless proxy.host\n\n    host = proxy.host\n    host = host[1...-1] if host[0] == '[' # for IPv6 address\n    config.x.http_client_proxy[:proxy] = { proxy_address: host, proxy_port: proxy.port, proxy_username: proxy.user, proxy_password: proxy.password }.compact\n  end\n\n  config.x.access_to_hidden_service = ENV['ALLOW_ACCESS_TO_HIDDEN_SERVICE'] == 'true'\nend\n\nmodule Goldfinger\n  def self.finger(uri, opts = {})\n    to_hidden = /\\.(onion|i2p)(:\\d+)?$/.match(uri)\n    raise Mastodon::HostValidationError, 'Instance does not support hidden service connections' if !Rails.configuration.x.access_to_hidden_service && to_hidden\n    opts = { ssl: !to_hidden, headers: {} }.merge(Rails.configuration.x.http_client_proxy).merge(opts)\n    opts[:headers]['User-Agent'] ||= Mastodon::Version.user_agent\n    Goldfinger::Client.new(uri, opts).finger\n  end\nend\n"
  },
  {
    "path": "config/initializers/httplog.rb",
    "content": "HttpLog.configure do |config|\n  config.logger = Rails.logger\n  config.color = { color: :yellow }\n  config.compact_log = true\nend\n"
  },
  {
    "path": "config/initializers/inflections.rb",
    "content": "# Be sure to restart your server when you modify this file.\n\n# Add new inflection rules using the following format. Inflections\n# are locale specific, and you may define rules for as many different\n# locales as you wish. All of these examples are active by default:\n# ActiveSupport::Inflector.inflections(:en) do |inflect|\n#   inflect.plural /^(ox)$/i, '\\1en'\n#   inflect.singular /^(ox)en/i, '\\1'\n#   inflect.irregular 'person', 'people'\n#   inflect.uncountable %w( fish sheep )\n# end\n\nActiveSupport::Inflector.inflections(:en) do |inflect|\n  inflect.acronym 'StatsD'\n  inflect.acronym 'OEmbed'\n  inflect.acronym 'OStatus'\n  inflect.acronym 'ActivityPub'\n  inflect.acronym 'PubSubHubbub'\n  inflect.acronym 'ActivityStreams'\n  inflect.acronym 'JsonLd'\nend\n"
  },
  {
    "path": "config/initializers/instrumentation.rb",
    "content": "# frozen_string_literal: true\n\ninstrumentation_hostname = ENV.fetch('INSTRUMENTATION_HOSTNAME') { 'localhost' }\n\nActiveSupport::Notifications.subscribe(/process_action.action_controller/) do |*args|\n  event      = ActiveSupport::Notifications::Event.new(*args)\n  controller = event.payload[:controller]\n  action     = event.payload[:action]\n  format     = event.payload[:format] || 'all'\n  format     = 'all' if format == '*/*'\n  status     = event.payload[:status]\n  key        = \"#{controller}.#{action}.#{format}.#{instrumentation_hostname}\"\n\n  ActiveSupport::Notifications.instrument :performance, action: :measure, measurement: \"#{key}.total_duration\", value: event.duration\n  ActiveSupport::Notifications.instrument :performance, action: :measure, measurement: \"#{key}.db_time\", value: event.payload[:db_runtime]\n  ActiveSupport::Notifications.instrument :performance, action: :measure, measurement: \"#{key}.view_time\", value: event.payload[:view_runtime]\n  ActiveSupport::Notifications.instrument :performance, measurement: \"#{key}.status.#{status}\"\nend\n"
  },
  {
    "path": "config/initializers/json_ld.rb",
    "content": "# frozen_string_literal: true\n\nrequire_relative '../../lib/json_ld/security'\n"
  },
  {
    "path": "config/initializers/kaminari_config.rb",
    "content": "# frozen_string_literal: true\n\nKaminari.configure do |config|\n  config.default_per_page = 40\n  config.window = 1\n  config.outer_window = 1\nend\n"
  },
  {
    "path": "config/initializers/mime_types.rb",
    "content": "# Be sure to restart your server when you modify this file.\n\nMime::Type.register 'application/json', :json, %w(text/x-json application/jsonrequest application/jrd+json application/activity+json application/ld+json)\nMime::Type.register 'text/xml',         :xml,  %w(application/xml application/atom+xml application/xrd+xml)\n"
  },
  {
    "path": "config/initializers/oj.rb",
    "content": "Oj.default_options = { mode: :compat, time_format: :ruby, use_to_json: true }\n"
  },
  {
    "path": "config/initializers/omniauth.rb",
    "content": "OmniAuth.config.allowed_request_methods = [:post]\n\nRails.application.config.middleware.use OmniAuth::Builder do\n  # Vanilla omniauth stategies\nend\n\nDevise.setup do |config|\n  # Devise omniauth strategies\n  options = {}\n  options[:redirect_at_sign_in] = ENV['OAUTH_REDIRECT_AT_SIGN_IN'] == 'true'\n\n  # CAS strategy\n  if ENV['CAS_ENABLED'] == 'true'\n    cas_options = options\n    cas_options[:url] = ENV['CAS_URL'] if ENV['CAS_URL']\n    cas_options[:host] = ENV['CAS_HOST'] if ENV['CAS_HOST']\n    cas_options[:port] = ENV['CAS_PORT'] if ENV['CAS_PORT']\n    cas_options[:ssl] = ENV['CAS_SSL'] == 'true' if ENV['CAS_SSL']\n    cas_options[:service_validate_url] = ENV['CAS_VALIDATE_URL'] if ENV['CAS_VALIDATE_URL']\n    cas_options[:callback_url] = ENV['CAS_CALLBACK_URL'] if ENV['CAS_CALLBACK_URL']\n    cas_options[:logout_url] = ENV['CAS_LOGOUT_URL'] if ENV['CAS_LOGOUT_URL']\n    cas_options[:login_url] = ENV['CAS_LOGIN_URL'] if ENV['CAS_LOGIN_URL']\n    cas_options[:uid_field] = ENV['CAS_UID_FIELD'] || 'user' if ENV['CAS_UID_FIELD']\n    cas_options[:ca_path] = ENV['CAS_CA_PATH'] if ENV['CAS_CA_PATH']\n    cas_options[:disable_ssl_verification] = ENV['CAS_DISABLE_SSL_VERIFICATION'] == 'true'\n    cas_options[:uid_key] = ENV['CAS_UID_KEY'] || 'user'\n    cas_options[:name_key] = ENV['CAS_NAME_KEY'] || 'name'\n    cas_options[:email_key] = ENV['CAS_EMAIL_KEY'] || 'email'\n    cas_options[:nickname_key] = ENV['CAS_NICKNAME_KEY'] || 'nickname'\n    cas_options[:first_name_key] = ENV['CAS_FIRST_NAME_KEY'] || 'firstname'\n    cas_options[:last_name_key] = ENV['CAS_LAST_NAME_KEY'] || 'lastname'\n    cas_options[:location_key] = ENV['CAS_LOCATION_KEY'] || 'location'\n    cas_options[:image_key] = ENV['CAS_IMAGE_KEY'] || 'image'\n    cas_options[:phone_key] = ENV['CAS_PHONE_KEY'] || 'phone'\n    config.omniauth :cas, cas_options\n  end\n\n  # SAML strategy\n  if ENV['SAML_ENABLED'] == 'true'\n    saml_options = options\n    saml_options[:assertion_consumer_service_url] = ENV['SAML_ACS_URL'] if ENV['SAML_ACS_URL']\n    saml_options[:issuer] = ENV['SAML_ISSUER'] if ENV['SAML_ISSUER']\n    saml_options[:idp_sso_target_url] = ENV['SAML_IDP_SSO_TARGET_URL'] if ENV['SAML_IDP_SSO_TARGET_URL']\n    saml_options[:idp_sso_target_url_runtime_params] = ENV['SAML_IDP_SSO_TARGET_PARAMS'] if ENV['SAML_IDP_SSO_TARGET_PARAMS'] # FIXME: Should be parsable Hash\n    saml_options[:idp_cert] = ENV['SAML_IDP_CERT'] if ENV['SAML_IDP_CERT']\n    saml_options[:idp_cert_fingerprint] = ENV['SAML_IDP_CERT_FINGERPRINT'] if ENV['SAML_IDP_CERT_FINGERPRINT']\n    saml_options[:idp_cert_fingerprint_validator] = ENV['SAML_IDP_CERT_FINGERPRINT_VALIDATOR'] if ENV['SAML_IDP_CERT_FINGERPRINT_VALIDATOR'] # FIXME: Should be Lambda { |fingerprint| }\n    saml_options[:name_identifier_format] = ENV['SAML_NAME_IDENTIFIER_FORMAT'] if ENV['SAML_NAME_IDENTIFIER_FORMAT']\n    saml_options[:request_attributes] = {}\n    saml_options[:certificate] = ENV['SAML_CERT'] if ENV['SAML_CERT']\n    saml_options[:private_key] = ENV['SAML_PRIVATE_KEY'] if ENV['SAML_PRIVATE_KEY']\n    saml_options[:security] = {}\n    saml_options[:security][:want_assertions_signed] = ENV['SAML_SECURITY_WANT_ASSERTION_SIGNED'] == 'true'\n    saml_options[:security][:want_assertions_encrypted] = ENV['SAML_SECURITY_WANT_ASSERTION_ENCRYPTED'] == 'true'\n    saml_options[:security][:assume_email_is_verified] = ENV['SAML_SECURITY_ASSUME_EMAIL_IS_VERIFIED'] == 'true'\n    saml_options[:attribute_statements] = {}\n    saml_options[:attribute_statements][:uid] = [ENV['SAML_ATTRIBUTES_STATEMENTS_UID']] if ENV['SAML_ATTRIBUTES_STATEMENTS_UID']\n    saml_options[:attribute_statements][:email] = [ENV['SAML_ATTRIBUTES_STATEMENTS_EMAIL']] if ENV['SAML_ATTRIBUTES_STATEMENTS_EMAIL']\n    saml_options[:attribute_statements][:full_name] = [ENV['SAML_ATTRIBUTES_STATEMENTS_FULL_NAME']] if ENV['SAML_ATTRIBUTES_STATEMENTS_FULL_NAME']\n    saml_options[:attribute_statements][:first_name] = [ENV['SAML_ATTRIBUTES_STATEMENTS_FIRST_NAME']] if ENV['SAML_ATTRIBUTES_STATEMENTS_FIRST_NAME']\n    saml_options[:attribute_statements][:last_name] = [ENV['SAML_ATTRIBUTES_STATEMENTS_LAST_NAME']] if ENV['SAML_ATTRIBUTES_STATEMENTS_LAST_NAME']\n    saml_options[:attribute_statements][:verified] = [ENV['SAML_ATTRIBUTES_STATEMENTS_VERIFIED']] if ENV['SAML_ATTRIBUTES_STATEMENTS_VERIFIED']\n    saml_options[:attribute_statements][:verified_email] = [ENV['SAML_ATTRIBUTES_STATEMENTS_VERIFIED_EMAIL']] if ENV['SAML_ATTRIBUTES_STATEMENTS_VERIFIED_EMAIL']\n    saml_options[:uid_attribute] = ENV['SAML_UID_ATTRIBUTE'] if ENV['SAML_UID_ATTRIBUTE']\n    config.omniauth :saml, saml_options\n  end\nend\n"
  },
  {
    "path": "config/initializers/open_uri_redirection.rb",
    "content": "require 'open-uri'\n\nmodule OpenURI\n  def self.redirectable?(uri1, uri2) # :nodoc:\n    uri1.scheme.casecmp(uri2.scheme).zero? ||\n      (/\\A(?:http|https|ftp)\\z/i =~ uri1.scheme && /\\A(?:http|https|ftp)\\z/i =~ uri2.scheme)\n  end\nend\n"
  },
  {
    "path": "config/initializers/pagination.rb",
    "content": ""
  },
  {
    "path": "config/initializers/paperclip.rb",
    "content": "# frozen_string_literal: true\n\nPaperclip.options[:read_timeout] = 60\n\nPaperclip.interpolates :filename do |attachment, style|\n  return attachment.original_filename if style == :original\n  [basename(attachment, style), extension(attachment, style)].delete_if(&:blank?).join('.')\nend\n\nPaperclip::Attachment.default_options.merge!(\n  use_timestamp: false,\n  path: ':class/:attachment/:id_partition/:style/:filename',\n  storage: :fog\n)\n\nif ENV['S3_ENABLED'] == 'true'\n  require 'aws-sdk-s3'\n\n  s3_region   = ENV.fetch('S3_REGION')   { 'us-east-1' }\n  s3_protocol = ENV.fetch('S3_PROTOCOL') { 'https' }\n  s3_hostname = ENV.fetch('S3_HOSTNAME') { \"s3-#{s3_region}.amazonaws.com\" }\n\n  Paperclip::Attachment.default_options.merge!(\n    storage: :s3,\n    s3_protocol: s3_protocol,\n    s3_host_name: s3_hostname,\n    s3_headers: {\n      'Cache-Control' => 'public, max-age=315576000, immutable',\n    },\n    s3_permissions: ENV.fetch('S3_PERMISSION') { 'public-read' },\n    s3_region: s3_region,\n    s3_credentials: {\n      bucket: ENV['S3_BUCKET'],\n      access_key_id: ENV['AWS_ACCESS_KEY_ID'],\n      secret_access_key: ENV['AWS_SECRET_ACCESS_KEY'],\n    },\n    s3_options: {\n      signature_version: ENV.fetch('S3_SIGNATURE_VERSION') { 'v4' },\n      http_open_timeout: 5,\n      http_read_timeout: 5,\n      http_idle_timeout: 5,\n    }\n  )\n\n  if ENV.has_key?('S3_ENDPOINT')\n    Paperclip::Attachment.default_options[:s3_options].merge!(\n      endpoint: ENV['S3_ENDPOINT'],\n      force_path_style: true\n    )\n    Paperclip::Attachment.default_options[:url] = ':s3_path_url'\n  end\n\n  if ENV.has_key?('S3_ALIAS_HOST') || ENV.has_key?('S3_CLOUDFRONT_HOST')\n    Paperclip::Attachment.default_options.merge!(\n      url: ':s3_alias_url',\n      s3_host_alias: ENV['S3_ALIAS_HOST'] || ENV['S3_CLOUDFRONT_HOST']\n    )\n  end\nelsif ENV['SWIFT_ENABLED'] == 'true'\n  require 'fog/openstack'\n\n  Paperclip::Attachment.default_options.merge!(\n    fog_credentials: {\n      provider: 'OpenStack',\n      openstack_username: ENV['SWIFT_USERNAME'],\n      openstack_project_id: ENV['SWIFT_PROJECT_ID'],\n      openstack_project_name: ENV['SWIFT_TENANT'],\n      openstack_tenant: ENV['SWIFT_TENANT'], # Some OpenStack-v2 ignores project_name but needs tenant\n      openstack_api_key: ENV['SWIFT_PASSWORD'],\n      openstack_auth_url: ENV['SWIFT_AUTH_URL'],\n      openstack_domain_name: ENV.fetch('SWIFT_DOMAIN_NAME') { 'default' },\n      openstack_region: ENV['SWIFT_REGION'],\n      openstack_cache_ttl: ENV.fetch('SWIFT_CACHE_TTL') { 60 },\n    },\n    fog_directory: ENV['SWIFT_CONTAINER'],\n    fog_host: ENV['SWIFT_OBJECT_URL'],\n    fog_public: true\n  )\nelse\n  Paperclip::Attachment.default_options.merge!(\n    storage: :filesystem,\n    use_timestamp: true,\n    path: (ENV['PAPERCLIP_ROOT_PATH'] || ':rails_root/public/system') + '/:class/:attachment/:id_partition/:style/:filename',\n    url: (ENV['PAPERCLIP_ROOT_URL'] || '/system') + '/:class/:attachment/:id_partition/:style/:filename',\n  )\nend\n"
  },
  {
    "path": "config/initializers/premailer_rails.rb",
    "content": "require_relative '../../lib/mastodon/premailer_webpack_strategy'\n\nPremailer::Rails.config.merge!(remove_ids: true,\n                               adapter: :nokogiri,\n                               generate_text_part: false,\n                               strategies: [PremailerWebpackStrategy])\n"
  },
  {
    "path": "config/initializers/rack_attack.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'doorkeeper/grape/authorization_decorator'\n\nclass Rack::Attack\n  class Request\n    def authenticated_token\n      return @token if defined?(@token)\n\n      @token = Doorkeeper::OAuth::Token.authenticate(\n        Doorkeeper::Grape::AuthorizationDecorator.new(self),\n        *Doorkeeper.configuration.access_token_methods\n      )\n    end\n\n    def remote_ip\n      @remote_ip ||= (@env[\"action_dispatch.remote_ip\"] || ip).to_s\n    end\n\n    def authenticated_user_id\n      authenticated_token&.resource_owner_id\n    end\n\n    def unauthenticated?\n      !authenticated_user_id\n    end\n\n    def api_request?\n      path.start_with?('/api')\n    end\n\n    def web_request?\n      !api_request?\n    end\n\n    def paging_request?\n      params['page'].present? || params['min_id'].present? || params['max_id'].present? || params['since_id'].present?\n    end\n  end\n\n  PROTECTED_PATHS = %w(\n    /auth/sign_in\n    /auth\n    /auth/password\n  ).freeze\n\n  PROTECTED_PATHS_REGEX = Regexp.union(PROTECTED_PATHS.map { |path| /\\A#{Regexp.escape(path)}/ })\n\n  # Always allow requests from localhost\n  # (blocklist & throttles are skipped)\n  Rack::Attack.safelist('allow from localhost') do |req|\n    # Requests are allowed if the return value is truthy\n    req.remote_ip == '127.0.0.1' || req.remote_ip == '::1'\n  end\n\n  throttle('throttle_authenticated_api', limit: 300, period: 5.minutes) do |req|\n    req.authenticated_user_id if req.api_request?\n  end\n\n  throttle('throttle_unauthenticated_api', limit: 300, period: 5.minutes) do |req|\n    req.remote_ip if req.api_request? && req.unauthenticated?\n  end\n\n  throttle('throttle_api_media', limit: 30, period: 30.minutes) do |req|\n    req.authenticated_user_id if req.post? && req.path.start_with?('/api/v1/media')\n  end\n\n  throttle('throttle_media_proxy', limit: 30, period: 30.minutes) do |req|\n    req.remote_ip if req.path.start_with?('/media_proxy')\n  end\n\n  throttle('throttle_api_sign_up', limit: 5, period: 30.minutes) do |req|\n    req.remote_ip if req.post? && req.path == '/api/v1/accounts'\n  end\n\n  # Throttle paging, as it is mainly used for public pages and AP collections\n  throttle('throttle_authenticated_paging', limit: 300, period: 15.minutes) do |req|\n    req.authenticated_user_id if req.paging_request?\n  end\n\n  throttle('throttle_unauthenticated_paging', limit: 300, period: 15.minutes) do |req|\n    req.remote_ip if req.paging_request? && req.unauthenticated?\n  end\n\n  API_DELETE_REBLOG_REGEX = /\\A\\/api\\/v1\\/statuses\\/[\\d]+\\/unreblog/.freeze\n  API_DELETE_STATUS_REGEX = /\\A\\/api\\/v1\\/statuses\\/[\\d]+/.freeze\n\n  throttle('throttle_api_delete', limit: 30, period: 30.minutes) do |req|\n    req.authenticated_user_id if (req.post? && req.path =~ API_DELETE_REBLOG_REGEX) || (req.delete? && req.path =~ API_DELETE_STATUS_REGEX)\n  end\n\n  throttle('protected_paths', limit: 25, period: 5.minutes) do |req|\n    req.remote_ip if req.post? && req.path =~ PROTECTED_PATHS_REGEX\n  end\n\n  self.throttled_response = lambda do |env|\n    now        = Time.now.utc\n    match_data = env['rack.attack.match_data']\n\n    headers = {\n      'Content-Type'          => 'application/json',\n      'X-RateLimit-Limit'     => match_data[:limit].to_s,\n      'X-RateLimit-Remaining' => '0',\n      'X-RateLimit-Reset'     => (now + (match_data[:period] - now.to_i % match_data[:period])).iso8601(6),\n    }\n\n    [429, headers, [{ error: I18n.t('errors.429') }.to_json]]\n  end\nend\n"
  },
  {
    "path": "config/initializers/rack_attack_logging.rb",
    "content": "ActiveSupport::Notifications.subscribe(/rack_attack/) do |_name, _start, _finish, _request_id, payload|\n  req = payload[:request]\n\n  next unless [:throttle, :blacklist].include? req.env['rack.attack.match_type']\n  Rails.logger.info(\"Rate limit hit (#{req.env['rack.attack.match_type']}): #{req.ip} #{req.request_method} #{req.fullpath}\")\nend\n"
  },
  {
    "path": "config/initializers/redis.rb",
    "content": "# frozen_string_literal: true\n\nredis_connection = Redis.new(\n  url: ENV['REDIS_URL'],\n  driver: :hiredis\n)\n\nnamespace = ENV.fetch('REDIS_NAMESPACE') { nil }\n\nif namespace\n  Redis.current = Redis::Namespace.new(namespace, redis: redis_connection)\nelse\n  Redis.current = redis_connection\nend\n"
  },
  {
    "path": "config/initializers/session_activations.rb",
    "content": "# frozen_string_literal: true\n\nRails.application.configure do\n  config.x.max_session_activations = ENV['MAX_SESSION_ACTIVATIONS'] || 10\nend\n"
  },
  {
    "path": "config/initializers/session_store.rb",
    "content": "# Be sure to restart your server when you modify this file.\n\nRails.application.config.session_store :cookie_store, key: '_mastodon_session', secure: (Rails.env.production? || ENV['LOCAL_HTTPS'] == 'true')\n"
  },
  {
    "path": "config/initializers/sidekiq.rb",
    "content": "# frozen_string_literal: true\n\nnamespace    = ENV.fetch('REDIS_NAMESPACE') { nil }\nredis_params = { url: ENV['REDIS_URL'] }\n\nif namespace\n  redis_params[:namespace] = namespace\nend\n\nSidekiq.configure_server do |config|\n  config.redis = redis_params\n\n  config.server_middleware do |chain|\n    chain.add SidekiqErrorHandler\n  end\nend\n\nSidekiq.configure_client do |config|\n  config.redis = redis_params\nend\n\nSidekiq::Logging.logger.level = ::Logger.const_get(ENV.fetch('RAILS_LOG_LEVEL', 'info').upcase.to_s)\n"
  },
  {
    "path": "config/initializers/simple_form.rb",
    "content": "# Use this setup block to configure all options available in SimpleForm.\n\nmodule AppendComponent\n  def append(wrapper_options = nil)\n    @append ||= begin\n      options[:append].to_s.html_safe if options[:append].present?\n    end\n  end\nend\n\nmodule RecommendedComponent\n  def recommended(wrapper_options = nil)\n    return unless options[:recommended]\n    options[:label_text] = ->(raw_label_text, _required_label_text, _label_present) { safe_join([raw_label_text, ' ', content_tag(:span, I18n.t('simple_form.recommended'), class: 'recommended')]) }\n    nil\n  end\nend\n\nSimpleForm.include_component(AppendComponent)\nSimpleForm.include_component(RecommendedComponent)\n\nSimpleForm.setup do |config|\n  # Wrappers are used by the form builder to generate a\n  # complete input. You can remove any component from the\n  # wrapper, change the order or even add your own to the\n  # stack. The options given below are used to wrap the\n  # whole input.\n  config.wrappers :default, class: :input, hint_class: :field_with_hint, error_class: :field_with_errors do |b|\n    ## Extensions enabled by default\n    # Any of these extensions can be disabled for a\n    # given input by passing: `f.input EXTENSION_NAME => false`.\n    # You can make any of these extensions optional by\n    # renaming `b.use` to `b.optional`.\n\n    # Determines whether to use HTML5 (:email, :url, ...)\n    # and required attributes\n    b.use :html5\n\n    # Calculates placeholders automatically from I18n\n    # You can also pass a string as f.input placeholder: \"Placeholder\"\n    b.use :placeholder\n\n    ## Optional extensions\n    # They are disabled unless you pass `f.input EXTENSION_NAME => true`\n    # to the input. If so, they will retrieve the values from the model\n    # if any exists. If you want to enable any of those\n    # extensions by default, you can change `b.optional` to `b.use`.\n\n    # Calculates maxlength from length validations for string inputs\n    b.optional :maxlength\n\n    # Calculates pattern from format validations for string inputs\n    b.optional :pattern\n\n    # Calculates min and max from length validations for numeric inputs\n    b.optional :min_max\n\n    # Calculates readonly automatically from readonly attributes\n    b.optional :readonly\n\n    ## Inputs\n    b.use :input\n    b.use :hint,  wrap_with: { tag: :span, class: :hint }\n    b.use :error, wrap_with: { tag: :span, class: :error }\n\n    ## full_messages_for\n    # If you want to display the full error message for the attribute, you can\n    # use the component :full_error, like:\n    #\n    # b.use :full_error, wrap_with: { tag: :span, class: :error }\n  end\n\n  config.wrappers :with_label, class: [:input, :with_label], hint_class: :field_with_hint, error_class: :field_with_errors do |b|\n    b.use :html5\n\n    b.wrapper tag: :div, class: :label_input do |ba|\n      ba.optional :recommended\n      ba.use :label\n\n      ba.wrapper tag: :div, class: :label_input__wrapper do |bb|\n        bb.use :input\n        bb.optional :append, wrap_with: { tag: :div, class: 'label_input__append' }\n      end\n    end\n\n    b.use :hint,  wrap_with: { tag: :span, class: :hint }\n    b.use :error, wrap_with: { tag: :span, class: :error }\n  end\n\n  config.wrappers :with_floating_label, class: [:input, :with_floating_label], hint_class: :field_with_hint, error_class: :field_with_errors do |b|\n    b.use :html5\n    b.use :label_input, wrap_with: { tag: :div, class: :label_input }\n    b.use :hint,  wrap_with: { tag: :span, class: :hint }\n    b.use :error, wrap_with: { tag: :span, class: :error }\n  end\n\n  config.wrappers :with_block_label, class: [:input, :with_block_label], hint_class: :field_with_hint, error_class: :field_with_errors do |b|\n    b.use :html5\n    b.use :label\n    b.use :hint, wrap_with: { tag: :span, class: :hint }\n    b.use :input\n    b.use :error, wrap_with: { tag: :span, class: :error }\n  end\n\n  # The default wrapper to be used by the FormBuilder.\n  config.default_wrapper = :default\n\n  # Define the way to render check boxes / radio buttons with labels.\n  # Defaults to :nested for bootstrap config.\n  #   inline: input + label\n  #   nested: label > input\n  config.boolean_style = :nested\n\n  # Default class for buttons\n  config.button_class = 'btn'\n\n  # Method used to tidy up errors. Specify any Rails Array method.\n  # :first lists the first message for each field.\n  # Use :to_sentence to list all errors for each field.\n  # config.error_method = :first\n\n  # Default tag used for error notification helper.\n  config.error_notification_tag = :div\n\n  # CSS class to add for error notification helper.\n  config.error_notification_class = 'error_notification'\n\n  # ID to add for error notification helper.\n  # config.error_notification_id = nil\n\n  # Series of attempts to detect a default label method for collection.\n  # config.collection_label_methods = [ :to_label, :name, :title, :to_s ]\n\n  # Series of attempts to detect a default value method for collection.\n  # config.collection_value_methods = [ :id, :to_s ]\n\n  # You can wrap a collection of radio/check boxes in a pre-defined tag, defaulting to none.\n  # config.collection_wrapper_tag = nil\n\n  # You can define the class to use on all collection wrappers. Defaulting to none.\n  # config.collection_wrapper_class = nil\n\n  # You can wrap each item in a collection of radio/check boxes with a tag,\n  # defaulting to :span.\n  # config.item_wrapper_tag = :span\n\n  # You can define a class to use in all item wrappers. Defaulting to none.\n  # config.item_wrapper_class = nil\n\n  # How the label text should be generated altogether with the required text.\n  config.label_text = lambda { |label, required, explicit_label| \"#{label} #{required}\" }\n\n  # You can define the class to use on all labels. Default is nil.\n  # config.label_class = nil\n\n  # You can define the default class to be used on forms. Can be overridden\n  # with `html: { :class }`. Defaulting to none.\n  # config.default_form_class = nil\n\n  # You can define which elements should obtain additional classes\n  # config.generate_additional_classes_for = [:wrapper, :label, :input]\n\n  # Whether attributes are required by default (or not). Default is true.\n  # config.required_by_default = true\n\n  # Tell browsers whether to use the native HTML5 validations (novalidate form option).\n  # These validations are enabled in SimpleForm's internal config but disabled by default\n  # in this configuration, which is recommended due to some quirks from different browsers.\n  # To stop SimpleForm from generating the novalidate option, enabling the HTML5 validations,\n  # change this configuration to true.\n  config.browser_validations = false\n\n  # Collection of methods to detect if a file type was given.\n  # config.file_methods = [ :mounted_as, :file?, :public_filename ]\n\n  # Custom mappings for input types. This should be a hash containing a regexp\n  # to match as key, and the input type that will be used when the field name\n  # matches the regexp as value.\n  # config.input_mappings = { /count/ => :integer }\n\n  # Custom wrappers for input types. This should be a hash containing an input\n  # type as key and the wrapper that will be used for all inputs with specified type.\n  # config.wrapper_mappings = { string: :prepend }\n\n  # Namespaces where SimpleForm should look for custom input classes that\n  # override default inputs.\n  # config.custom_inputs_namespaces << \"CustomInputs\"\n\n  # Default priority for time_zone inputs.\n  # config.time_zone_priority = nil\n\n  # Default priority for country inputs.\n  # config.country_priority = nil\n\n  # When false, do not use translations for labels.\n  # config.translate_labels = true\n\n  # Automatically discover new inputs in Rails' autoload path.\n  # config.inputs_discovery = true\n\n  # Cache SimpleForm inputs discovery\n  # config.cache_discovery = !Rails.env.development?\n\n  # Default class for inputs\n  # config.input_class = nil\n\n  # Define the default class of the input wrapper of the boolean input.\n  config.boolean_label_class = 'checkbox'\n\n  # Defines if the default input wrapper class should be included in radio\n  # collection wrappers.\n  # config.include_default_input_wrapper_class = true\n\n  # Defines which i18n scope will be used in Simple Form.\n  # config.i18n_scope = 'simple_form'\nend\n"
  },
  {
    "path": "config/initializers/single_user_mode.rb",
    "content": "# frozen_string_literal: true\n\nRails.application.configure do\n  config.x.single_user_mode = ENV['SINGLE_USER_MODE'] == 'true'\nend\n"
  },
  {
    "path": "config/initializers/statsd.rb",
    "content": "# frozen_string_literal: true\n\nif ENV['STATSD_ADDR'].present?\n  host, port = ENV['STATSD_ADDR'].split(':')\n\n  statsd = ::Statsd.new(host, port)\n  statsd.namespace = ENV.fetch('STATSD_NAMESPACE') { ['Mastodon', Rails.env].join('.') }\n\n  ::NSA.inform_statsd(statsd) do |informant|\n    informant.collect(:action_controller, :web)\n    informant.collect(:active_record, :db)\n    informant.collect(:active_support_cache, :cache)\n    informant.collect(:sidekiq, :sidekiq)\n  end\nend\n"
  },
  {
    "path": "config/initializers/stoplight.rb",
    "content": "require 'stoplight'\n\nStoplight::Light.default_data_store = Stoplight::DataStore::Redis.new(Redis.current)\nStoplight::Light.default_notifiers  = [Stoplight::Notifier::Logger.new(Rails.logger)]\n"
  },
  {
    "path": "config/initializers/strong_migrations.rb",
    "content": "# frozen_string_literal: true\n\nStrongMigrations.start_after = 20170924022025\n"
  },
  {
    "path": "config/initializers/suppress_csrf_warnings.rb",
    "content": "# frozen_string_literal: true\n\nActionController::Base.log_warning_on_csrf_failure = false\n"
  },
  {
    "path": "config/initializers/trusted_proxies.rb",
    "content": "module Rack\n  class Request\n    def trusted_proxy?(ip)\n      if Rails.application.config.action_dispatch.trusted_proxies.nil?\n        super\n      else\n        Rails.application.config.action_dispatch.trusted_proxies.any? { |proxy| proxy === ip }\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "config/initializers/twitter_regex.rb",
    "content": "module Twitter\n  class Regex\n    REGEXEN[:valid_general_url_path_chars] = /[^\\p{White_Space}<>\\(\\)\\?]/iou\n    REGEXEN[:valid_url_path_ending_chars] = /[^\\p{White_Space}\\(\\)\\?!\\*\"'「」<>;:=\\,\\.\\$%\\[\\]~&\\|@]|(?:#{REGEXEN[:valid_url_balanced_parens]})/iou\n    REGEXEN[:valid_url_balanced_parens] = /\n      \\(\n        (?:\n          #{REGEXEN[:valid_general_url_path_chars]}+\n          |\n          # allow one nested level of balanced parentheses\n          (?:\n            #{REGEXEN[:valid_general_url_path_chars]}*\n            \\(\n              #{REGEXEN[:valid_general_url_path_chars]}+\n            \\)\n            #{REGEXEN[:valid_general_url_path_chars]}*\n          )\n        )\n      \\)\n    /iox\n    REGEXEN[:valid_url_path] = /(?:\n      (?:\n        #{REGEXEN[:valid_general_url_path_chars]}*\n        (?:#{REGEXEN[:valid_url_balanced_parens]} #{REGEXEN[:valid_general_url_path_chars]}*)*\n        #{REGEXEN[:valid_url_path_ending_chars]}\n      )|(?:#{REGEXEN[:valid_general_url_path_chars]}+\\/)\n    )/iox\n    REGEXEN[:valid_url] = %r{\n      (                                                                                     #   $1 total match\n        (#{REGEXEN[:valid_url_preceding_chars]})                                            #   $2 Preceding character\n        (                                                                                   #   $3 URL\n          ((https?|dat|dweb|ipfs|ipns|ssb|gopher):\\/\\/)?                                    #   $4 Protocol (optional)\n          (#{REGEXEN[:valid_domain]})                                                       #   $5 Domain(s)\n          (?::(#{REGEXEN[:valid_port_number]}))?                                            #   $6 Port number (optional)\n          (/#{REGEXEN[:valid_url_path]}*)?                                                  #   $7 URL Path and anchor\n          (\\?#{REGEXEN[:valid_url_query_chars]}*#{REGEXEN[:valid_url_query_ending_chars]})? #   $8 Query String\n        )\n      )\n    }iox\n  end\nend\n"
  },
  {
    "path": "config/initializers/vapid.rb",
    "content": "# frozen_string_literal: true\n\nRails.application.configure do\n  # You can generate the keys using the following command (first is the private key, second is the public one)\n  # You should only generate this once per instance. If you later decide to change it, all push subscription will\n  # be invalidated, requiring the users to access the website again to resubscribe.\n  #\n  # Generate with `rake mastodon:webpush:generate_vapid_key` task (`docker-compose run --rm web rake mastodon:webpush:generate_vapid_key` if you use docker compose)\n  #\n  # For more information visit https://rossta.net/blog/using-the-web-push-api-with-vapid.html\n\n  if Rails.env.production?\n    config.x.vapid_private_key = ENV['VAPID_PRIVATE_KEY']\n    config.x.vapid_public_key = ENV['VAPID_PUBLIC_KEY']\n  end\nend\n"
  },
  {
    "path": "config/initializers/wrap_parameters.rb",
    "content": "# Be sure to restart your server when you modify this file.\n\n# This file contains settings for ActionController::ParamsWrapper which\n# is enabled by default.\n\n# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.\nActiveSupport.on_load(:action_controller) do\n  wrap_parameters format: [:json]\nend\n\n# To enable root element in JSON for ActiveRecord objects.\n# ActiveSupport.on_load(:active_record) do\n#   self.include_root_in_json = true\n# end\n"
  },
  {
    "path": "config/locales/activerecord.ar.yml",
    "content": "---\nar:\n  activerecord:\n    attributes:\n      poll:\n        expires_at: آخر أجل\n        options: الخيارات\n    errors:\n      models:\n        account:\n          attributes:\n            username:\n              invalid: فقط حروف و أرقام و سطور سفلية\n        status:\n          attributes:\n            reblog:\n              taken: المنشور موجود مِن قبل\n"
  },
  {
    "path": "config/locales/activerecord.ast.yml",
    "content": "---\nast:\n  activerecord:\n    errors:\n      models:\n        account:\n          attributes:\n            username:\n              invalid: namái lletres, númberos y guiones baxos\n"
  },
  {
    "path": "config/locales/activerecord.bg.yml",
    "content": "bg:\n"
  },
  {
    "path": "config/locales/activerecord.bn.yml",
    "content": "bn:\n"
  },
  {
    "path": "config/locales/activerecord.ca.yml",
    "content": "---\nca:\n  activerecord:\n    attributes:\n      poll:\n        expires_at: Data límit\n        options: Opcions\n    errors:\n      models:\n        account:\n          attributes:\n            username:\n              invalid: només lletres, números i subratllats\n        status:\n          attributes:\n            reblog:\n              taken: de l'estat ja existeix\n"
  },
  {
    "path": "config/locales/activerecord.co.yml",
    "content": "---\nco:\n  activerecord:\n    attributes:\n      poll:\n        expires_at: Fine\n        options: Scelte\n    errors:\n      models:\n        account:\n          attributes:\n            username:\n              invalid: solu lettere, numeri è liniette basse\n        status:\n          attributes:\n            reblog:\n              taken: di u statutu esista digià\n"
  },
  {
    "path": "config/locales/activerecord.cs.yml",
    "content": "---\ncs:\n  activerecord:\n    attributes:\n      poll:\n        expires_at: Uzávěrka\n        options: Volby\n    errors:\n      models:\n        account:\n          attributes:\n            username:\n              invalid: pouze písmena, číslice a podtržítka\n        status:\n          attributes:\n            reblog:\n              taken: příspěvku již existuje\n"
  },
  {
    "path": "config/locales/activerecord.cy.yml",
    "content": "---\ncy:\n  activerecord:\n    errors:\n      models:\n        account:\n          attributes:\n            username:\n              invalid: dim ond llythrennau, rhifau a tanlinellau\n        status:\n          attributes:\n            reblog:\n              taken: o'r statws yn bodoli'n barod\n"
  },
  {
    "path": "config/locales/activerecord.da.yml",
    "content": "---\nda:\n  activerecord:\n    errors:\n      models:\n        account:\n          attributes:\n            username:\n              invalid: kun tal, bogstaver og understreger\n        status:\n          attributes:\n            reblog:\n              taken: af allerede eksisterende status\n"
  },
  {
    "path": "config/locales/activerecord.de.yml",
    "content": "---\nde:\n  activerecord:\n    attributes:\n      poll:\n        expires_at: Frist\n        options: Wahlmöglichkeiten\n    errors:\n      models:\n        account:\n          attributes:\n            username:\n              invalid: nur Buchstaben, Ziffern und Unterstriche\n        status:\n          attributes:\n            reblog:\n              taken: des Beitrags existiert schon\n"
  },
  {
    "path": "config/locales/activerecord.el.yml",
    "content": "---\nel:\n  activerecord:\n    attributes:\n      poll:\n        expires_at: Προθεσμία\n        options: Επιλογές\n    errors:\n      models:\n        account:\n          attributes:\n            username:\n              invalid: μόνο γράμματα, αριθμοί και κάτω παύλες\n        status:\n          attributes:\n            reblog:\n              taken: της κατάστασης ήδη υπάρχει\n"
  },
  {
    "path": "config/locales/activerecord.en.yml",
    "content": "---\nen:\n  activerecord:\n    attributes:\n      poll:\n        expires_at: Deadline\n        options: Choices\n    errors:\n      models:\n        account:\n          attributes:\n            username:\n              invalid: only letters, numbers and underscores\n        status:\n          attributes:\n            reblog:\n              taken: of status already exists\n"
  },
  {
    "path": "config/locales/activerecord.eo.yml",
    "content": "---\neo:\n  activerecord:\n    attributes:\n      poll:\n        expires_at: Limdato\n        options: Elektoj\n    errors:\n      models:\n        account:\n          attributes:\n            username:\n              invalid: nur leteroj, ciferoj kaj substrekoj\n        status:\n          attributes:\n            reblog:\n              taken: de statuso jam ekzistas\n"
  },
  {
    "path": "config/locales/activerecord.es.yml",
    "content": "---\nes:\n  activerecord:\n    attributes:\n      poll:\n        expires_at: Vencimiento\n        options: Opciones\n    errors:\n      models:\n        account:\n          attributes:\n            username:\n              invalid: sólo letras, números y guiones bajos\n        status:\n          attributes:\n            reblog:\n              taken: del estado ya existe\n"
  },
  {
    "path": "config/locales/activerecord.eu.yml",
    "content": "---\neu:\n  activerecord:\n    attributes:\n      poll:\n        expires_at: Epemuga\n        options: Aukerak\n    errors:\n      models:\n        account:\n          attributes:\n            username:\n              invalid: letrak, zenbakiak eta gidoi baxuak besterik ez\n        status:\n          attributes:\n            reblog:\n              taken: mezu honentzat bazegoen aurretik\n"
  },
  {
    "path": "config/locales/activerecord.fa.yml",
    "content": "---\nfa:\n  activerecord:\n    errors:\n      models:\n        account:\n          attributes:\n            username:\n              invalid: تنها حروف، اعداد، و زیرخط\n        status:\n          attributes:\n            reblog:\n              taken: نوشته‌ها وجود دارند\n"
  },
  {
    "path": "config/locales/activerecord.fi.yml",
    "content": "fi:\n"
  },
  {
    "path": "config/locales/activerecord.fr.yml",
    "content": "---\nfr:\n  activerecord:\n    attributes:\n      poll:\n        expires_at: Date butoir\n        options: Choix\n    errors:\n      models:\n        account:\n          attributes:\n            username:\n              invalid: seulement des lettres, des nombres et des tirets bas\n        status:\n          attributes:\n            reblog:\n              taken: du statut existe déjà\n"
  },
  {
    "path": "config/locales/activerecord.gl.yml",
    "content": "---\ngl:\n  activerecord:\n    attributes:\n      poll:\n        expires_at: Caducidade\n        options: Opcións\n    errors:\n      models:\n        account:\n          attributes:\n            username:\n              invalid: só letras, números e liñas baixas\n        status:\n          attributes:\n            reblog:\n              taken: do estado xa existe\n"
  },
  {
    "path": "config/locales/activerecord.he.yml",
    "content": "---\nhe:\n  activerecord:\n    errors:\n      models:\n        account:\n          attributes:\n            username:\n              invalid: ספרות, אותיות לטיניות וקו תחתי בלבד\n        status:\n          attributes:\n            reblog:\n              taken: של החצרוץ כבר קיים\n"
  },
  {
    "path": "config/locales/activerecord.hr.yml",
    "content": "hr:\n"
  },
  {
    "path": "config/locales/activerecord.hu.yml",
    "content": "hu:\n"
  },
  {
    "path": "config/locales/activerecord.hy.yml",
    "content": "hy:\n"
  },
  {
    "path": "config/locales/activerecord.id.yml",
    "content": "---\nid:\n  activerecord:\n    errors:\n      models:\n        account:\n          attributes:\n            username:\n              invalid: hanya boleh berisi huruf, angka, dan underscore\n        status:\n          attributes:\n            reblog:\n              taken: status sudah ada\n"
  },
  {
    "path": "config/locales/activerecord.io.yml",
    "content": "io:\n"
  },
  {
    "path": "config/locales/activerecord.it.yml",
    "content": "---\nit:\n  activerecord:\n    errors:\n      models:\n        account:\n          attributes:\n            username:\n              invalid: solo lettere, numeri e trattino basso\n        status:\n          attributes:\n            reblog:\n              taken: dello stato esiste già\n"
  },
  {
    "path": "config/locales/activerecord.ja.yml",
    "content": "---\nja:\n  activerecord:\n    attributes:\n      poll:\n        expires_at: 期限\n        options: 項目\n    errors:\n      models:\n        account:\n          attributes:\n            username:\n              invalid: アルファベット・数字・アンダーバーの組み合わせで入力してください\n        status:\n          attributes:\n            reblog:\n              taken: は既にブーストされています\n"
  },
  {
    "path": "config/locales/activerecord.ka.yml",
    "content": "---\nka:\n  activerecord:\n    errors:\n      models:\n        account:\n          attributes:\n            username:\n              invalid: მხოლოდ ასოები, ციფრები და \"ქვედა-ტირე\"\n        status:\n          attributes:\n            reblog:\n              taken: სტატუსის უკვე არსებობს\n"
  },
  {
    "path": "config/locales/activerecord.kk.yml",
    "content": "---\nkk:\n  activerecord:\n    attributes:\n      poll:\n        expires_at: Дедлайн\n        options: Таңдаулар\n    errors:\n      models:\n        account:\n          attributes:\n            username:\n              invalid: тек әріптер, сандар және асты сызылған таңбалар\n        status:\n          attributes:\n            reblog:\n              taken: жазбасы бұрыннан бар\n"
  },
  {
    "path": "config/locales/activerecord.ko.yml",
    "content": "---\nko:\n  activerecord:\n    attributes:\n      poll:\n        expires_at: 마감 기한\n        options: 선택\n    errors:\n      models:\n        account:\n          attributes:\n            username:\n              invalid: 영문자, 숫자, _만 사용 가능\n        status:\n          attributes:\n            reblog:\n              taken: 이미 게시물이 존재합니다\n"
  },
  {
    "path": "config/locales/activerecord.lt.yml",
    "content": "lt:\n"
  },
  {
    "path": "config/locales/activerecord.lv.yml",
    "content": "lv:\n"
  },
  {
    "path": "config/locales/activerecord.ms.yml",
    "content": "ms:\n"
  },
  {
    "path": "config/locales/activerecord.nl.yml",
    "content": "---\nnl:\n  activerecord:\n    attributes:\n      poll:\n        expires_at: Deadline\n        options: Keuzes\n    errors:\n      models:\n        account:\n          attributes:\n            username:\n              invalid: alleen letters, nummers en underscores\n        status:\n          attributes:\n            reblog:\n              taken: van toot bestaat al\n"
  },
  {
    "path": "config/locales/activerecord.no.yml",
    "content": "---\n'no':\n  activerecord:\n    errors:\n      models:\n        account:\n          attributes:\n            username:\n              invalid: bare bokstaver, tall og understreker\n        status:\n          attributes:\n            reblog:\n              taken: av status eksisterer allerede\n"
  },
  {
    "path": "config/locales/activerecord.oc.yml",
    "content": "---\noc:\n  activerecord:\n    attributes:\n      poll:\n        expires_at: Data limita\n        options: Opcions\n    errors:\n      models:\n        account:\n          attributes:\n            username:\n              invalid: solament letras, nombres e tirets basses\n        status:\n          attributes:\n            reblog:\n              taken: de l’estatut existís ja\n"
  },
  {
    "path": "config/locales/activerecord.pl.yml",
    "content": "---\npl:\n  activerecord:\n    attributes:\n      poll:\n        expires_at: Ostateczny termin\n        options: Opcje\n    errors:\n      models:\n        account:\n          attributes:\n            username:\n              invalid: może składać się tylko z liter, cyfr i podkreślników\n        status:\n          attributes:\n            reblog:\n              taken: status już istnieje\n"
  },
  {
    "path": "config/locales/activerecord.pt-BR.yml",
    "content": "---\npt-BR:\n  activerecord:\n    attributes:\n      poll:\n        expires_at: Expira em\n        options: Escolhas\n    errors:\n      models:\n        account:\n          attributes:\n            username:\n              invalid: apenas letras, números e underscores\n        status:\n          attributes:\n            reblog:\n              taken: do status já existe\n"
  },
  {
    "path": "config/locales/activerecord.pt.yml",
    "content": "---\npt:\n  activerecord:\n    errors:\n      models:\n        account:\n          attributes:\n            username:\n              invalid: apenas letras, números e underscores\n        status:\n          attributes:\n            reblog:\n              taken: do status já existe\n"
  },
  {
    "path": "config/locales/activerecord.ro.yml",
    "content": "ro:\n"
  },
  {
    "path": "config/locales/activerecord.ru.yml",
    "content": "---\nru:\n  activerecord:\n    attributes:\n      poll:\n        expires_at: Крайний срок\n        options: Варианты\n    errors:\n      models:\n        account:\n          attributes:\n            username:\n              invalid: только буквы, цифры и символ подчёркивания\n        status:\n          attributes:\n            reblog:\n              taken: статуса уже существует\n"
  },
  {
    "path": "config/locales/activerecord.sk.yml",
    "content": "---\nsk:\n  activerecord:\n    attributes:\n      poll:\n        expires_at: Trvá do\n        options: Voľby\n    errors:\n      models:\n        account:\n          attributes:\n            username:\n              invalid: iba písmená, číslice a podčiarkovníky\n        status:\n          attributes:\n            reblog:\n              taken: príspevku už existuje\n"
  },
  {
    "path": "config/locales/activerecord.sl.yml",
    "content": "---\nsl:\n  activerecord:\n    errors:\n      models:\n        account:\n          attributes:\n            username:\n              invalid: samo črke, številke in podčrtaji\n        status:\n          attributes:\n            reblog:\n              taken: od statusa že obstajajo\n"
  },
  {
    "path": "config/locales/activerecord.sq.yml",
    "content": "---\nsq:\n  activerecord:\n    errors:\n      models:\n        account:\n          attributes:\n            username:\n              invalid: vetëm shkronja, numra dhe nënvija\n        status:\n          attributes:\n            reblog:\n              taken: e gjendjes ekziston tashmë\n"
  },
  {
    "path": "config/locales/activerecord.sr-Latn.yml",
    "content": "---\nsr-Latn:\n  activerecord:\n    errors:\n      models:\n        account:\n          attributes:\n            username:\n              invalid: samo slova, brojevi i donje crte\n        status:\n          attributes:\n            reblog:\n              taken: statusa već postoji\n"
  },
  {
    "path": "config/locales/activerecord.sr.yml",
    "content": "---\nsr:\n  activerecord:\n    errors:\n      models:\n        account:\n          attributes:\n            username:\n              invalid: само слова, бројеви и доње црте\n        status:\n          attributes:\n            reblog:\n              taken: статуса већ постоји\n"
  },
  {
    "path": "config/locales/activerecord.sv.yml",
    "content": "---\nsv:\n  activerecord:\n    errors:\n      models:\n        account:\n          attributes:\n            username:\n              invalid: enbart bokstäver, siffror och understreck\n"
  },
  {
    "path": "config/locales/activerecord.ta.yml",
    "content": "ta:\n"
  },
  {
    "path": "config/locales/activerecord.te.yml",
    "content": "te:\n"
  },
  {
    "path": "config/locales/activerecord.th.yml",
    "content": "---\nth:\n  activerecord:\n    errors:\n      models:\n        account:\n          attributes:\n            username:\n              invalid: ตัวอักษร, ตัวเลข และขีดล่างเท่านั้น\n        status:\n          attributes:\n            reblog:\n              taken: มีสถานะอยู่แล้ว\n"
  },
  {
    "path": "config/locales/activerecord.tr.yml",
    "content": "---\ntr:\n  activerecord:\n    errors:\n      models:\n        account:\n          attributes:\n            username:\n              invalid: sadece harfler, sayılar ve alt çizgiler\n        status:\n          attributes:\n            reblog:\n              taken: durum zaten var\n"
  },
  {
    "path": "config/locales/activerecord.uk.yml",
    "content": "---\nuk:\n  activerecord:\n    errors:\n      models:\n        account:\n          attributes:\n            username:\n              invalid: тільки букви, цифри та нижні підкреслювання\n        status:\n          attributes:\n            reblog:\n              taken: статусу вже існує\n"
  },
  {
    "path": "config/locales/activerecord.zh-CN.yml",
    "content": "---\nzh-CN:\n  activerecord:\n    attributes:\n      poll:\n        expires_at: 截止时间\n        options: 选项\n    errors:\n      models:\n        account:\n          attributes:\n            username:\n              invalid: 只能使用字母、数字和下划线\n        status:\n          attributes:\n            reblog:\n              taken: 已经被转嘟过\n"
  },
  {
    "path": "config/locales/activerecord.zh-HK.yml",
    "content": "---\nzh-HK:\n  activerecord:\n    errors:\n      models:\n        account:\n          attributes:\n            username:\n              invalid: 只能使用字母、數字和下劃線\n        status:\n          attributes:\n            reblog:\n              taken: 已經被轉推過\n"
  },
  {
    "path": "config/locales/activerecord.zh-TW.yml",
    "content": "zh-TW:\n"
  },
  {
    "path": "config/locales/activerecord.zh_Hant.yml",
    "content": "zh_Hant:\n  activerecord:\n    attributes:\n      status:\n        owned_poll: 投票\n    errors:\n      models:\n        account:\n          attributes:\n            username:\n              invalid: 只允許使用字母、數字和底線\n        status:\n          attributes:\n            reblog:\n              taken: 的嘟文已經存在\n"
  },
  {
    "path": "config/locales/ar.yml",
    "content": "---\nar:\n  about:\n    about_hashtag_html: هذه تبويقات متاحة للجمهور تحتوي على الكلمات الدلالية <strong>#%{hashtag}</strong>. يمكنك التفاعل معها إن كان لديك حساب في أي مكان على الفديفرس.\n    about_mastodon_html: ماستدون شبكة اجتماعية مبنية على أسُس بروتوكولات برمجيات الويب الحرة و مفتوحة المصدر. و هو لامركزي تمامًا كالبريد الإلكتروني.\n    about_this: عن مثيل الخادوم هذا\n    active_count_after: نشط\n    administered_by: 'يُديره:'\n    api: واجهة برمجة التطبيقات\n    apps: تطبيقات الأجهزة المحمولة\n    contact: للتواصل معنا\n    contact_missing: لم يتم تعيينه\n    contact_unavailable: غير متوفر\n    discover_users: اكتشف مستخدِمين\n    documentation: الدليل\n    extended_description_html: |\n      <h3>مكان جيد للقواعد</h3>\n      <p>لم يتم بعد إدخال الوصف الطويل.</p>\n    generic_description: \"%{domain} هو سيرفر من بين سيرفرات الشبكة\"\n    get_apps: جرّب تطبيقا على الموبايل\n    hosted_on: ماستدون مُستضاف على %{domain}\n    learn_more: تعلم المزيد\n    privacy_policy: سياسة الخصوصية\n    see_whats_happening: اطّلع على ما يجري\n    server_stats: 'إحصائيات الخادم:'\n    source_code: الشفرة المصدرية\n    status_count_after:\n      few: منشورات\n      many: منشورات\n      one: منشور\n      other: منشورات\n      two: منشورات\n      zero: منشورات\n    status_count_before: نشروا\n    tagline: اتبع أصدقائك وصديقاتك واكتشف آخرين وأخريات\n    terms: شروط الخدمة\n    user_count_after:\n      few: مستخدمين\n      many: مستخدمين\n      one: مستخدم\n      other: مستخدمين\n      two: مستخدمين\n      zero: مستخدمين\n    user_count_before: يستضيف\n    what_is_mastodon: ما هو ماستدون ؟\n  accounts:\n    choices_html: 'توصيات %{name}:'\n    follow: اتبع\n    followers:\n      few: متابِعون\n      many: متابِعون\n      one: متابِع\n      other: متابِعون\n      two: متابِعون\n      zero: متابِعون\n    following: مُتابَع\n    joined: انضم·ت في %{date}\n    last_active: آخر نشاط\n    link_verified_on: تم التحقق مِن مالك هذا الرابط بتاريخ %{date}\n    media: الوسائط\n    moved_html: \"%{name} إنتقلَ إلى %{new_profile_link} :\"\n    network_hidden: إنّ المعطيات غير متوفرة\n    nothing_here: لا يوجد أي شيء هنا!\n    people_followed_by: الأشخاص الذين يتبعهم %{name}\n    people_who_follow: الأشخاص الذين يتبعون %{name}\n    pin_errors:\n      following: يجب أن تكون مِن متابعي حساب الشخص الذي تريد إبرازه\n    posts:\n      few: تبويقات\n      many: تبويقات\n      one: تبويق\n      other: تبويقات\n      two: تبويقات\n      zero: تبويقات\n    posts_tab_heading: تبويقات\n    posts_with_replies: التبويقات و الردود\n    reserved_username: اسم المستخدم محجوز\n    roles:\n      admin: المدير\n      bot: روبوت\n      moderator: مُشرِف\n    unavailable: الحساب غير متوفر\n    unfollow: إلغاء المتابعة\n  admin:\n    account_actions:\n      action: تنفيذ الإجراء\n      title: اتخاذ إجراء إشراف على %{acct}\n    account_moderation_notes:\n      create: اترك ملاحظة\n      created_msg: تم إنشاء ملاحظة الإشراف بنجاح!\n      delete: حذف\n      destroyed_msg: تم تدمير ملاحظة الإشراف بنجاح!\n    accounts:\n      approve: صادِق عليه\n      approve_all: الموافقة على الكل\n      are_you_sure: متأكد ؟\n      avatar: الصورة الرمزية\n      by_domain: النطاق\n      change_email:\n        changed_msg: تم تعديل عنوان البريد الإلكتروني الخاص بالحساب بنجاح!\n        current_email: عنوان البريد الإلكتروني الحالي\n        label: تعديل عنوان البريد الإلكتروني\n        new_email: عنوان البريد الإلكتروني الجديد\n        submit: تعديل عنوان البريد الإلكتروني\n        title: تعديل عنوان البريد الإلكتروني الخاص بـ %{username}\n      confirm: تأكيد\n      confirmed: مؤكَّد\n      confirming: التأكد\n      deleted: تمت إزالته\n      demote: إنزال الرُتبة الوظيفية\n      disable: تعطيل\n      disable_two_factor_authentication: تعطيل المصادقة بخطوتين\n      disabled: معطَّل\n      display_name: عرض الاسم\n      domain: النطاق\n      edit: تعديل\n      email: البريد الإلكتروني\n      email_status: حالة البريد الإلكتروني\n      enable: تفعيل\n      enabled: مفعَّل\n      feed_url: عنوان رابط التغذية\n      followers: المتابِعون\n      followers_url: عنوان رابط المتابِعين\n      follows: يتابع\n      header: الرأسية\n      inbox_url: رابط صندوق الوارد\n      invited_by: تمت دعوته مِن طرف\n      ip: عنوان الإيبي\n      joined: انضم\n      location:\n        all: الكل\n        local: المحلي\n        remote: عن بُعد\n        title: الموقع\n      login_status: وضع الدخول\n      media_attachments: الوسائط المرفقة\n      memorialize: تحويل الحساب إلى صفحة ذكرى\n      moderation:\n        active: نشِط\n        all: الكل\n        pending: قيد المراجعة\n        silenced: تم كتمه\n        suspended: مُجَمَّد\n        title: الإشراف\n      moderation_notes: ملاحظات الإشراف\n      most_recent_activity: آخر نشاط حديث\n      most_recent_ip: أحدث عنوان إيبي\n      no_account_selected: لم يطرأ أي تغيير على أي حساب بما أنه لم يتم اختيار أي واحد\n      no_limits_imposed: مِن دون حدود مشروطة\n      not_subscribed: غير مشترك\n      outbox_url: رابط صندوق الصادر\n      pending: في انتظار المراجعة\n      perform_full_suspension: تعليق الحساب\n      profile_url: رابط الملف الشخصي\n      promote: ترقية\n      protocol: البروتوكول\n      public: عمومي\n      push_subscription_expires: انتهاء الاشتراك ”PuSH“\n      redownload: تحديث الصفحة الشخصية\n      reject: ارفض\n      reject_all: ارفض الكل\n      remove_avatar: حذف الصورة الرمزية\n      remove_header: حذف الرأسية\n      resend_confirmation:\n        already_confirmed: هذا المستخدم مؤكد بالفعل\n        send: أعد إرسال رسالة البريد الإلكتروني الخاصة بالتأكيد\n        success: تم إرسال رسالة التأكيد بنجاح!\n      reset: إعادة التعيين\n      reset_password: إعادة ضبط كلمة السر\n      resubscribe: إعادة الاشتراك\n      role: الصلاحيات\n      roles:\n        admin: مدير\n        moderator: مشرف\n        staff: الفريق\n        user: مستخدِم\n      salmon_url: عنوان رابط سالمون Salmon\n      search: البحث\n      shared_inbox_url: رابط الصندوق المُشترَك للبريد الوارد\n      show:\n        created_reports: البلاغات التي أنشأها هذا الحساب\n        targeted_reports: الشكاوى التي أُنشِأت مِن طرف الآخَرين\n      silence: كتم\n      silenced: تم كتمه\n      statuses: المنشورات\n      subscribe: اشترك\n      suspended: تم تعليقه\n      time_in_queue: في قائمة الانتظار %{time}\n      title: الحسابات\n      unconfirmed_email: البريد الإلكتروني غير مؤكد\n      undo_silenced: رفع الصمت\n      undo_suspension: إلغاء تعليق الحساب\n      unsubscribe: إلغاء الاشتراك\n      username: اسم المستخدم\n      warn: تحذير\n      web: الويب\n    action_logs:\n      actions:\n        assigned_to_self_report: قام %{name} بتعيين التقرير %{target} لأنفسهم\n        change_email_user: غيّر %{name} عنوان البريد الإلكتروني للمستخدم %{target}\n        confirm_user: \"%{name} قد قام بتأكيد عنوان البريد الإلكتروني لـ %{target}\"\n        create_account_warning: قام %{name} بإرسال تحذير إلى %{target}\n        create_custom_emoji: \"%{name} قام برفع إيموجي جديد %{target}\"\n        create_domain_block: \"%{name} قام بحجب نطاق %{target}\"\n        create_email_domain_block: \"%{name} قد قام بحظر نطاق البريد الإلكتروني %{target}\"\n        demote_user: \"%{name} قد قام بإنزال الرتبة الوظيفية لـ %{target}\"\n        destroy_custom_emoji: قام %{name} بحذف الإيموجي %{target}\n        destroy_domain_block: \"%{name} قام بإلغاء الحجب عن النطاق %{target}\"\n        destroy_email_domain_block: قام %{name} بإضافة نطاق البريد الإلكتروني %{target} إلى اللائحة البيضاء\n        destroy_status: لقد قام %{name} بحذف منشور %{target}\n        disable_2fa_user: \"%{name} لقد قام بتعطيل ميزة المصادقة بخطوتين للمستخدم %{target}\"\n        disable_custom_emoji: \"%{name} قام بتعطيل الإيموجي %{target}\"\n        disable_user: \"%{name} لقد قام بتعطيل تسجيل الدخول للمستخدِم %{target}\"\n        enable_custom_emoji: \"%{name} قام بتنشيط الإيموجي %{target}\"\n        enable_user: لقد قام %{name} بتنشيط تسجيل الدخول للمستخدِم %{target}\n        memorialize_account: لقد قام %{name} بتحويل حساب %{target} إلى صفحة تذكارية\n        promote_user: \"%{name} قام بترقية المستخدم %{target}\"\n        remove_avatar_user: تمت إزالة %{name} الصورة الرمزية %{target}\n        reopen_report: تمت إعادة فتح الشكوى %{name} %{target}\n        reset_password_user: \"%{name} لقد قام بإعادة تعيين الكلمة السرية الخاصة بـ %{target}\"\n        resolve_report: قام %{name} بحل الشكوى %{target}\n        silence_account: لقد قام %{name} بكتم حساب %{target}\n        suspend_account: لقد قام %{name} بتعليق حساب %{target}\n        unassigned_report: \"%{name} تقرير غير معتمد %{target}\"\n        unsilence_account: لقد قام %{name} بإلغاء الكتم عن حساب %{target}\n        unsuspend_account: لقد قام %{name} بإلغاء التعليق المفروض على حساب %{target}\n        update_custom_emoji: \"%{name} قام بتحديث الإيموجي %{target}\"\n        update_status: لقد قام %{name} بتحديث منشور %{target}\n      deleted_status: \"(منشور محذوف)\"\n      title: سِجلّ التفتيش و المعاينة\n    custom_emojis:\n      by_domain: النطاق\n      copied_msg: تم إنشاء نسخة محلية للإيموجي بنجاح\n      copy: نسخ\n      copy_failed_msg: فشلت عملية إنشاء نسخة محلية لهذا الإيموجي\n      created_msg: تم إنشاء الإيموجي بنجاح!\n      delete: حذف\n      destroyed_msg: تمت عملية تدمير الإيموجي بنجاح!\n      disable: تعطيل\n      disabled_msg: تمت عملية تعطيل ذلك الإيموجي بنجاح\n      emoji: إيموجي\n      enable: تفعيل\n      enabled_msg: تم تنشيط ذاك الإيموجي بنجاح\n      image_hint: ملف PNG إلى غاية حجم 50 ك.ب\n      listed: مُدرَج\n      new:\n        title: إضافة إيموجي خاص جديد\n      overwrite: إعادة الكتابة\n      shortcode: الترميز المُصَغّر\n      shortcode_hint: على الأقل حرفين، و فقط رموز أبجدية عددية و أسطر سفلية\n      title: الإيموجي الخاصة\n      unlisted: غير مدرج\n      update_failed_msg: تعذرت عملية تحديث ذاك الإيموجي\n      updated_msg: تم تحديث الإيموجي بنجاح!\n      upload: رفع\n    dashboard:\n      backlog: الأعمال المتراكمة\n      config: الإعداد\n      feature_deletions: الحسابات المحذوفة\n      feature_invites: روابط الدعوات\n      feature_profile_directory: دليل الحسابات\n      feature_registrations: التسجيلات\n      feature_relay: المُرحّل الفديرالي\n      feature_timeline_preview: معاينة الخيط الزمني\n      features: الميّزات\n      hidden_service: الفيديرالية مع الخدمات الخفية\n      open_reports: فتح الشكاوى\n      recent_users: أحدث المستخدِمين\n      search: البحث النصي الكامل\n      single_user_mode: وضع المستخدِم الأوحد\n      software: البرنامج\n      space: المساحة المستخدَمة\n      title: لوح المراقبة\n      total_users: إجمالي المستخدِمين\n      trends: المؤشرات\n      week_interactions: تفاعُلات هذا الأسبوع\n      week_users_active: نشط هذا الأسبوع\n      week_users_new: مستخدِمين هذا الأسبوع\n    domain_blocks:\n      add_new: إضافة حجب جديد لنطاق\n      created_msg: إنّ حجب النطاق حيز التشغيل\n      destroyed_msg: تم إلغاء الحجب المفروض على النطاق\n      domain: النطاق\n      new:\n        create: إنشاء حظر\n        hint: لن تمنع كتلة المجال إنشاء إدخالات حساب في قاعدة البيانات ، ولكنها ستطبق طرق الإشراف المحددة بأثر رجعي وتلقائي على هذه الحسابات.\n        severity:\n          desc_html: \"<strong>Silence</strong> سيجعل مشاركات الحساب غير مرئية لأي شخص لا يتبعها. <strong>Suspend</strong> سيزيل كل محتوى الحساب ووسائطه وبيانات ملفه الشخصي. Use <strong>None</strong>  إذا كنت تريد فقط رفض ملفات الوسائط.\"\n          noop: لا شيء\n          silence: كتم\n          suspend: تعليق\n        title: حجب نطاق جديد\n      reject_media: رفض ملفات الوسائط\n      reject_media_hint: يزيل ملفات الوسائط المخزنة محليًا ويرفض تنزيل أي ملفات في المستقبل. غير ذي صلة للتعليق\n      reject_reports: رفض التقارير\n      severity:\n        silence: تم كتمه\n        suspend: تم تعليقه\n      show:\n        affected_accounts:\n          few: \"%{count} حسابات معنية في قاعدة البيانات\"\n          many: \"%{count} حسابات معنية في قاعدة البيانات\"\n          one: حساب واحد معني في قاعدة البيانات\n          other: \"%{count} حسابات معنية في قاعدة البيانات\"\n          two: \"%{count} حسابات معنية في قاعدة البيانات\"\n          zero: \"%{count} حسابات معنية في قاعدة البيانات\"\n        retroactive:\n          silence: إلغاء الكتم عن كافة الحسابات المتواجدة على هذا النطاق\n          suspend: إلغاء التعليق المفروض على كافة حسابات هذا النطاق\n        title: رفع حظر النطاق عن %{domain}\n        undo: إلغاء\n      undo: إلغاء حجب النطاق\n    email_domain_blocks:\n      add_new: إضافة\n      created_msg: لقد دخل حظر نطاق البريد الإلكتروني حيّز الخدمة\n      delete: حذف\n      destroyed_msg: تم حذف نطاق البريد الإلكتروني من اللائحة السوداء بنجاح\n      domain: النطاق\n      new:\n        create: إضافة نطاق\n        title: إضافة نطاق بريد جديد إلى اللائحة السوداء\n      title: القائمة السوداء للبريد الإلكتروني\n    followers:\n      back_to_account: العودة إلى الحساب\n      title: \"%{acct} مُتابِعون\"\n    instances:\n      by_domain: النطاق\n      delivery_available: التسليم متوفر\n      known_accounts:\n        few: \"%{count} حسابات معروفة\"\n        many: \"%{count} حسابات معروفة\"\n        one: حساب معروف %{count}\n        other: \"%{count} حسابات معروفة\"\n        two: \"%{count} حسابات معروفة\"\n        zero: \"%{count} حسابات معروفة\"\n      moderation:\n        all: كافتها\n        limited: محدود\n        title: الإشراف\n      title: الفديرالية\n      total_blocked_by_us: المحجوبة مِن طرفنا\n      total_followed_by_them: يُتابِعونها\n      total_followed_by_us: التي نُتابِعها\n      total_reported: تقارير عنهم\n      total_storage: الوسائط المُرفَقة\n    invites:\n      deactivate_all: تعطيلها كافة\n      filter:\n        all: الكل\n        available: المتوفرة\n        expired: المنتهي صلاحيتها\n        title: التصفية\n      title: الدعوات\n    pending_accounts:\n      title: الحسابات المعلقة (%{count})\n    relays:\n      add_new: إضافة مُرحّل جديد\n      delete: حذف\n      disable: تعطيل\n      disabled: مُعطَّل\n      enable: تشغيل\n      enable_hint: عندما تقوم بتنشيط هذه الميزة، سوف يشترك خادومكم في جميع التبويقات القادمة مِن هذا المُرحِّل و سيشرع كذلك بإرسال كافة التبويقات العمومية إليه.\n      enabled: مُشغَّل\n      inbox_url: رابط المُرحّل\n      pending: في انتظار تسريح المُرحِّل\n      save_and_enable: حفظ وتشغيل\n      setup: إعداد اتصال بمُرحّل\n      status: الحالة\n      title: المُرحّلات\n    report_notes:\n      created_msg: تم إنشاء ملاحظة الشكوى بنجاح!\n      destroyed_msg: تم حذف ملاحظة الشكوى بنجاح!\n    reports:\n      account:\n        note: ملحوظة\n        report: تقرير\n      action_taken_by: تم اتخاذ الإجراء مِن طرف\n      are_you_sure: هل أنت متأكد ؟\n      assign_to_self: عين لي\n      assigned: تعين رئيس\n      comment:\n        none: لا شيء\n      created_at: ذكرت\n      mark_as_resolved: اعتبار الشكوى كمحلولة\n      mark_as_unresolved: علم كغير محلولة\n      notes:\n        create: اضف ملاحظة\n        create_and_resolve: الحل مع ملاحظة\n        create_and_unresolve: إعادة فتح مع ملاحظة\n        delete: حذف\n        placeholder: قم بوصف الإجراءات التي تم اتخاذها أو أي تحديثات أخرى ذات علاقة...\n      reopen: إعادة فتح الشكوى\n      report: 'الشكوى #%{id}'\n      reported_account: حساب مُبلّغ عنه\n      reported_by: أبلغ عنه من طرف\n      resolved: معالجة\n      resolved_msg: تم حل تقرير بنجاح!\n      status: الحالة\n      title: الشكاوى\n      unassign: إلغاء تعيين\n      unresolved: غير معالجة\n      updated_at: محدث\n    settings:\n      activity_api_enabled:\n        desc_html: عدد المنشورات المحلية و المستخدمين الناشطين و التسجيلات الأسبوعية الجديدة\n        title: نشر مُجمل الإحصائيات عن نشاط المستخدمين\n      bootstrap_timeline_accounts:\n        desc_html: افصل بين أسماء المستخدمين المتعددة بواسطة الفاصلة. استعمل الحسابات المحلية والمفتوحة فقط. الافتراضي عندما تكون فارغة كل المسؤولين المحليين.\n        title: الاشتراكات الافتراضية للمستخدمين الجدد\n      contact_information:\n        email: البريد الإلكتروني المهني\n        username: الاتصال بالمستخدِم\n      custom_css:\n        desc_html: يقوم بتغيير المظهر بواسطة سي أس أس يُحمَّل على كافة الصفحات\n        title: سي أس أس مخصص\n      hero:\n        desc_html: معروض على الصفحة الأولى. لا يقل عن 600 × 100 بكسل. عند عدم التعيين ، تعود الصورة إلى النسخة المصغرة على سبيل المثال\n        title: الصورة الرأسية\n      peers_api_enabled:\n        desc_html: أسماء النطاقات التي التقى بها مثيل الخادوم على البيئة الموحَّدة فديفرس\n        title: نشر عدد مثيلات الخوادم التي تم مصادفتها\n      preview_sensitive_media:\n        desc_html: روابط المُعَاينة على مواقع الويب الأخرى ستقوم بعرض صُوَر مصغّرة حتى و إن كانت الوسائط حساسة\n        title: إظهار الصور الحساسة في مُعاينات أوبن غراف\n      profile_directory:\n        desc_html: السماح للمستخدمين الكشف عن حساباتهم\n        title: تفعيل سجل الملفات الشخصية\n      registrations:\n        closed_message:\n          desc_html: يتم عرضه على الصفحة الرئيسية عندما يتم غلق تسجيل الحسابات الجديدة. يمكنكم إستخدام علامات الأيتش تي أم أل HTML\n          title: رسالة التسجيلات المقفلة\n        deletion:\n          desc_html: السماح لأي مستخدم إغلاق حسابه\n          title: السماح بحذف الحسابات\n        min_invite_role:\n          disabled: لا أحد\n          title: المستخدِمون المصرح لهم لإرسال الدعوات\n      registrations_mode:\n        modes:\n          none: لا أحد يمكنه إنشاء حساب\n          open: يمكن للجميع إنشاء حساب\n        title: طريقة إنشاء الحسابات\n      show_known_fediverse_at_about_page:\n        title: إظهار الفديفرس الموحَّد في خيط المُعايَنة\n      show_staff_badge:\n        desc_html: عرض شارة الموظفين على صفحة المستخدم\n        title: إظهار شارة الموظفين\n      site_description:\n        desc_html: فقرة تمهيدية على الصفحة الأولى. صف ميزات خادوم ماستدون هذا و ما يميّزه عن الآخرين. يمكنك استخدام علامات HTML ، ولا سيما <code>&lt;a&gt;</code> و <code>&lt;em&gt;</code>.\n        title: وصف مثيل الخادوم\n      site_description_extended:\n        desc_html: مكان جيد لمدونة قواعد السلوك والقواعد والإرشادات وغيرها من الأمور التي تحدد حالتك. يمكنك استخدام علامات HTML\n        title: الوصف المُفصّل للموقع\n      site_short_description:\n        desc_html: يتم عرضه في لوحة جانبية و في البيانات الوصفية. قم بوصف ماستدون و ما يميز هذا السيرفر عن الآخرين في فقرة موجزة. إن تركت الحقل فارغا فسوف يتم عرض الوصف الافتراضي لمثيل الخادوم.\n        title: مقدمة وصفية قصيرة عن مثيل الخادوم\n      site_terms:\n        desc_html: يمكنك كتابة سياسة الخصوصية الخاصة بك ، شروط الخدمة أو غيرها من القوانين. يمكنك استخدام علامات HTML\n        title: شروط الخدمة المخصصة\n      site_title: اسم مثيل الخادم\n      thumbnail:\n        desc_html: يستخدم للعروض السابقة عبر Open Graph و API. 1200x630px موصى به\n        title: الصورة الرمزية المصغرة لمثيل الخادوم\n      timeline_preview:\n        desc_html: عرض الخيط العمومي على صفحة الاستقبال\n        title: مُعاينة الخيط العام\n      title: إعدادات الموقع\n    statuses:\n      back_to_account: العودة إلى صفحة الحساب\n      batch:\n        delete: حذف\n        nsfw_off: تعيينه كمنشور غير حساس\n        nsfw_on: تعيينه كمنشور حساس\n      failed_to_execute: خطأ في التفعيل\n      media:\n        title: الوسائط\n      no_media: لا تحتوي على وسائط\n      no_status_selected: لم يطرأ أي تغيير على أي منشور بما أنه لم يتم اختيار أي واحد\n      title: منشورات الحساب\n      with_media: تحتوي على وسائط\n    subscriptions:\n      callback_url: عاود الاتصال بالعنوان\n      confirmed: مؤكَّد\n      expires_in: تنتهي مدة صلاحيتها في\n      last_delivery: آخر إيداع\n      topic: الموضوع\n    tags:\n      accounts: الحسابات\n      hidden: المخفية\n      hide: الإخفاء عن سجل الحسابات\n      name: الوسم\n      title: الوسوم\n      unhide: إظهاره في سجل حسابات المستخدمين\n      visible: ظاهر\n    title: الإدارة\n    warning_presets:\n      add_new: إضافة واحد جديد\n      delete: حذف\n      edit: تعديل\n      edit_preset: تعديل نموذج التحذير\n      title: إدارة نماذج التحذير\n  admin_mailer:\n    new_pending_account:\n      subject: حساب جديد في انتظار مراجعة على %{instance} (%{username})\n    new_report:\n      body: قام %{reporter} بالإبلاغ عن %{target}\n      body_remote: أبلغ شخص ما من %{domain} عن %{target}\n      subject: تقرير جديد ل%{instance} (#%{id})\n  appearance:\n    advanced_web_interface: واجهة الويب المتقدمة\n    confirmation_dialogs: نوافذ التأكيد\n    sensitive_content: محتوى حساس\n  application_mailer:\n    notification_preferences: تعديل خيارات البريد الإلكتروني\n    salutation: \"%{name}،\"\n    settings: 'تغيير تفضيلات البريد الإلكتروني: %{link}'\n    view_profile: عرض الملف الشخصي\n    view_status: عرض المنشور\n  applications:\n    created: تم إنشاء التطبيق بنجاح\n    destroyed: تم حذف التطبيق بنجاح\n    invalid_url: إن الرابط المقدم غير صالح\n    regenerate_token: إعادة توليد رمز النفاذ\n    token_regenerated: تم إعادة إنشاء الرمز الوصول بنجاح\n    warning: كن حذرا مع هذه البيانات. لا تقم أبدا بمشاركتها مع الآخَرين!\n    your_token: رمز نفاذك\n  auth:\n    apply_for_account: اطلب دعوة\n    change_password: الكلمة السرية\n    checkbox_agreement_html: أوافق على <a href=\"%{rules_path}\" target=\"_blank\">قواعد الخادم</a> و <a href=\"%{terms_path}\" target=\"_blank\">شروط الخدمة</a>\n    confirm_email: تأكيد عنوان البريد الإلكتروني\n    delete_account: حذف حساب\n    delete_account_html: إن كنت ترغب في حذف حسابك يُمكنك <a href=\"%{path}\">المواصلة هنا</a>. سوف يُطلَبُ منك التأكيد قبل الحذف.\n    didnt_get_confirmation: لم تتلق تعليمات التأكيد ؟\n    forgot_password: نسيت كلمة المرور ؟\n    invalid_reset_password_token: رمز إعادة تعيين كلمة المرور غير صالح أو منتهي الصلاحية. يرجى طلب واحد جديد.\n    login: تسجيل الدخول\n    logout: خروج\n    migrate_account: الانتقال إلى حساب آخر\n    migrate_account_html: إن كنت ترغب في تحويل هذا الحساب نحو حساب آخَر، يُمكِنُك <a href=\"%{path}\">إعداده هنا</a>.\n    or_log_in_with: أو قم بتسجيل الدخول بواسطة\n    providers:\n      cas: CAS\n      saml: SAML\n    register: إنشاء حساب\n    registration_closed: لا يقبل %{instance} استقبال أعضاء جدد\n    resend_confirmation: إعادة إرسال تعليمات التأكيد\n    reset_password: إعادة تعيين كلمة المرور\n    security: الأمان\n    set_new_password: إدخال كلمة مرور جديدة\n    trouble_logging_in: هل صادفتكم مشكلة في الولوج؟\n  authorize_follow:\n    already_following: أنت تتابع بالفعل هذا الحساب\n    error: يا للأسف، وقع هناك خطأ إثر عملية البحث عن الحساب عن بعد\n    follow: اتبع\n    follow_request: 'لقد قمت بإرسال طلب متابعة إلى:'\n    following: 'مرحى! أنت الآن تتبع:'\n    post_follow:\n      close: أو يمكنك إغلاق هذه النافذة.\n      return: عرض الملف الشخصي للمستخدم\n      web: واصل إلى الويب\n    title: إتباع %{acct}\n  datetime:\n    distance_in_words:\n      about_x_hours: \"%{count}سا\"\n      about_x_months: \"%{count} شهر\"\n      about_x_years: \"%{count} سنة\"\n      almost_x_years: \"%{count} سنوات\"\n      half_a_minute: الآن\n      less_than_x_minutes: \"%{count} د\"\n      less_than_x_seconds: الآن\n      over_x_years: \"%{count} سنين\"\n      x_days: \"%{count} أيام\"\n      x_minutes: \"%{count}د\"\n      x_months: \"%{count} شه\"\n      x_seconds: \"%{count}ث\"\n  deletes:\n    bad_password_msg: محاولة جيدة يا هاكرز ! كلمة السر خاطئة\n    confirm_password: قم بإدخال كلمتك السرية الحالية للتحقق من هويتك\n    proceed: حذف حساب\n    success_msg: تم حذف حسابك بنجاح\n    warning_title: توافر المحتوى المنشور و المبعثَر\n  directories:\n    directory: سِجلّ الحسابات\n    enabled: إنّ حسابك الآن ضمن فهرس المستخدِمين.\n    explanation: استكشف مستخدِمين آخرين حسب المواضيع التي تهمهم\n    explore_mastodon: استكشف %{title}\n    people:\n      few: \"%{count} شخص\"\n      many: \"%{count} شخص\"\n      one: \"%{count} شخص\"\n      other: \"%{count} شخص\"\n      two: \"%{count} شخص\"\n      zero: \"%{count} شخص\"\n  errors:\n    '403': ليس لك الصلاحيات الكافية لعرض هذه الصفحة.\n    '404': إنّ الصفحة التي تبحث عنها لا وجود لها أصلا.\n    '410': إنّ الصفحة التي تبحث عنها لم تعد موجودة.\n    '422':\n      content: فشل التحقق الآمن. ربما منعتَ كعكات الكوكيز؟\n      title: فشِل التحقق الآمن\n    '429': طلبات كثيرة جدا\n    '500':\n      content: نحن متأسفون، لقد حدث خطأ ما مِن جانبنا.\n      title: هذه الصفحة خاطئة\n    noscript_html: يرجى تفعيل الجافا سكريبت لاستخدام تطبيق الويب لماستدون، أو عِوض ذلك قوموا بتجريب إحدى <a href=\"%{apps_path}\">التطبيقات الأصلية</a> الدّاعمة لماستدون على منصّتكم.\n  existing_username_validator:\n    not_found_multiple: تعذر العثور على %{usernames}\n  exports:\n    archive_takeout:\n      date: التاريخ\n      download: تنزيل نسخة لحسابك\n      hint_html: بإمكانك طلب نسخة كاملة لـ <strong>كافة تبويقاتك و الوسائط التي قمت بنشرها</strong>. البيانات المُصدَّرة ستكون محفوظة على شكل نسق ActivityPub و باستطاعتك قراءتها بأي برنامج يدعم هذا النسق. يُمكنك طلب نسخة كل 7 أيام.\n      in_progress: عملية جمع نسخة لبيانات حسابك جارية...\n      request: طلب نسخة لحسابك\n      size: الحجم\n    blocks: قمت بحظر\n    csv: CSV\n    domain_blocks: النطاقات المحظورة\n    follows: أنت تتبع\n    lists: القوائم\n    mutes: قُمتَ بكتم\n    storage: ذاكرة التخزين\n  featured_tags:\n    add_new: إضافة واحد\n  filters:\n    contexts:\n      home: الخيط الزمني الرئيسي\n      notifications: الإخطارات\n      public: الخيوط الزمنية العامة\n      thread: المحادثات\n    edit:\n      title: تعديل عامل التصفية\n    errors:\n      invalid_context: لم تقم بتحديد أي مجال أو أنّ المجال غير صالح\n      invalid_irreversible: إلّا مجالات الإشعارات و الخيط الرئيسي معنية بالتصفية اللارجعية\n    index:\n      delete: إزالة\n      title: عوامل التصفية\n    new:\n      title: إضافة عامل تصفية جديد\n  footer:\n    developers: المطورون\n    more: المزيد…\n    resources: الموارد\n  generic:\n    all: الكل\n    changes_saved_msg: تم حفظ التعديلات بنجاح!\n    copy: نسخ\n    order_by: ترتيب بحسب\n    save_changes: حفظ التغييرات\n    validation_errors:\n      few: هناك شيء ما ليس على ما يرام! يُرجى مراجعة الأخطاء الـ %{count} أدناه\n      many: هناك شيء ما ليس على ما يرام! يُرجى مراجعة الأخطاء الـ %{count} أدناه\n      one: هناك شيء ما ليس على ما يرام! يُرجى مراجعة الخطأ أدناه\n      other: هناك شيء ما ليس على ما يرام! يُرجى مراجعة الأخطاء الـ %{count} أدناه\n      two: هناك شيء ما ليس على ما يرام! يُرجى مراجعة الأخطاء الـ %{count} أدناه\n      zero: هناك شيء ما ليس على ما يرام! يُرجى مراجعة الأخطاء الـ %{count} أدناه\n  identity_proofs:\n    active: نشط\n    authorize: نعم ، قم بترخيصه\n    authorize_connection_prompt: هل تريد ترخيص هذا الاتصال المشفّر؟\n    i_am_html: أنا %{username} على %{service}.\n    identity: الهوية\n    inactive: ليس نشطا\n    publicize_checkbox: 'وقم بتبويق هذا:'\n    publicize_toot: 'متحقق منه! أنا %{username} على %{service}: %{url}'\n    status: حالة التحقق\n    view_proof: عرض الدليل\n  imports:\n    modes:\n      merge: دمج\n      merge_long: الإبقاء علي التسجيلات الحالية وإضافة الجديدة\n      overwrite: إعادة الكتابة\n      overwrite_long: استبدال التسجيلات الحالية بالجديدة\n    preface: بإمكانك استيراد بيانات قد قُمتَ بتصديرها مِن مثيل خادوم آخَر، كقوائم المستخدِمين الذين كنتَ تتابِعهم أو قُمتَ بحظرهم.\n    success: تم تحميل بياناتك بنجاح وسيتم معالجتها في الوقت المناسب\n    types:\n      blocking: قائمة المحظورين\n      domain_blocking: قائمة النطاقات المحظورة\n      following: قائمة المستخدمين المتبوعين\n      muting: قائمة الكتم\n    upload: تحميل\n  in_memoriam_html: في ذكرى.\n  invites:\n    delete: تعطيل\n    expired: انتهت صلاحيتها\n    expires_in:\n      '1800': 30 دقيقة\n      '21600': 6 ساعات\n      '3600': ساعة\n      '43200': 12 ساعة\n      '604800': أسبوع\n      '86400': يوم واحد\n    expires_in_prompt: أبدا\n    generate: توليد\n    invited_by: 'تمت دعوتك من طرف:'\n    max_uses:\n      few: \"%{count} استخدامات\"\n      many: \"%{count} استخدامات\"\n      one: استخدام واحد\n      other: \"%{count} استخدامات\"\n      two: \"%{count} استخدامات\"\n      zero: \"%{count} استخدامات\"\n    max_uses_prompt: بلا حدود\n    prompt: توليد و مشاركة روابط للسماح للآخَرين بالنفاذ إلى مثيل الخادوم هذا\n    table:\n      expires_at: تنتهي مدة صلاحيتها في\n      uses: عدد الاستخدامات\n    title: دعوة أشخاص\n  lists:\n    errors:\n      limit: لقد بلغت الحد الأقصى للقوائم\n  media_attachments:\n    validations:\n      images_and_video: ليس بالإمكان إرفاق فيديو في منشور يحتوي مسبقا على صور\n      too_many: لا يمكن إرفاق أكثر من 4 ملفات\n  migrations:\n    acct: username@domain للحساب الجديد\n    currently_redirecting: 'تم تحويل رابط ملفك الشخصي إلى:'\n    proceed: حفظ\n    updated_msg: تم تحديث إعدادات ترحيل حسابك بنجاح!\n  moderation:\n    title: الإشراف\n  notification_mailer:\n    digest:\n      action: معاينة كافة الإشعارات\n      body: هذا هو مُلَخَّص الرسائل التي فاتتك وذلك منذ آخر زيارة لك في %{since}\n      mention: \"%{name} أشار إليك في:\"\n      new_followers_summary:\n        few: رائع، لقد قام بمتابَعتك %{count} مُتابِعون جُدد أثناء فترة غيابك عن ماستدون!\n        many: رائع، لقد قام بمتابَعتك %{count} مُتابِعون جُدد أثناء فترة غيابك عن ماستدون!\n        one: و لقد تحصّلتَ كذلك على مُتابِع آخَر بينما كنتَ غائبًا! هذا شيء رائع!\n        other: رائع، لقد قام بمتابَعتك %{count} مُتابِعون جُدد أثناء فترة غيابك عن ماستدون!\n        two: رائع، لقد قام بمتابَعتك %{count} مُتابِعون جُدد أثناء فترة غيابك عن ماستدون!\n        zero: رائع، لقد قام بمتابَعتك %{count} مُتابِعون جُدد أثناء فترة غيابك عن ماستدون!\n      subject:\n        few: \"%{count} إشعارات جديدة منذ آخر زيارة لك إلى \\U0001F418\"\n        many: \"%{count} إشعارات جديدة منذ آخر زيارة لك إلى \\U0001F418\"\n        one: \"إشعار واحد 1 منذ آخر زيارة لك لـ \\U0001F418\"\n        other: \"%{count} إشعارات جديدة منذ آخر زيارة لك إلى \\U0001F418\"\n        two: \"%{count} إشعارات جديدة منذ آخر زيارة لك إلى \\U0001F418\"\n        zero: \"%{count} إشعارات جديدة منذ آخر زيارة لك إلى \\U0001F418\"\n      title: أثناء فترة غيابك...\n    favourite:\n      body: 'أُعجب %{name} بمنشورك:'\n      subject: أُعجِب %{name} بمنشورك\n      title: مفضّلة جديدة\n    follow:\n      body: \"%{name} من متتبعيك الآن!\"\n      subject: \"%{name} من متتبعيك الآن\"\n      title: متابِع جديد\n    follow_request:\n      action: إدارة طلبات المتابَعة\n      body: طلب %{name} متابعتك\n      subject: 'متابع مُعلّق : %{name}'\n      title: طلب متابَعة جديد\n    mention:\n      action: الرد\n      body: 'أشار إليك %{name} في :'\n      subject: لقد قام %{name} بذِكرك\n      title: إشارة جديدة\n    reblog:\n      body: 'قام %{name} بترقية منشورك :'\n      subject: قام %{name} بترقية منشورك\n      title: ترقية جديدة\n  number:\n    human:\n      decimal_units:\n        format: \"%n%u\"\n        units:\n          billion: بل\n          million: ملي\n          quadrillion: كواد\n          thousand: ألف\n          trillion: ترل\n  pagination:\n    newer: الأحدَث\n    next: التالي\n    older: الأقدَم\n    prev: السابق\n    truncate: و\n  polls:\n    errors:\n      already_voted: لقد قمت بالتصويت على استطلاع الرأي هذا مِن قبل\n      duplicate_options: يحتوي على عناصر مكررة\n      duration_too_short: مبكّر جدا\n      expired: لقد انتهى استطلاع الرأي\n  preferences:\n    other: إعدادات أخرى\n    posting_defaults: التفضيلات الافتراضية لنشر التبويقات\n    public_timelines: الخيوط الزمنية العامة\n  relationships:\n    activity: نشاط الحساب\n    dormant: في سبات\n    last_active: آخر نشاط\n    most_recent: الأحدث\n    moved: هاجر\n    primary: رئيسي\n    relationship: العلاقة\n    remove_selected_domains: احذف كافة المتابِعين القادمين مِن النطاقات المختارة\n    remove_selected_followers: احذف المتابِعين الذين قمت باختيارهم\n    remove_selected_follows: الغي متابعة المستخدمين الذين اخترتهم\n    status: حالة الحساب\n  remote_follow:\n    acct: قم بإدخال عنوان حسابك username@domain الذي من خلاله تود النشاط\n    missing_resource: تعذر العثور على رابط التحويل المطلوب الخاص بحسابك\n    no_account_html: أليس عندك حساب بعدُ ؟ يُمْكنك <a href='%{sign_up_path}' target='_blank'>التسجيل مِن هنا</a>\n    proceed: أكمل المتابعة\n    prompt: 'إنك بصدد متابعة:'\n  remote_interaction:\n    favourite:\n      proceed: المواصلة إلى المفضلة\n      prompt: 'ترغب في إضافة هذا التبويق إلى مفضلتك:'\n    reblog:\n      proceed: المواصلة إلى الترقية\n      prompt: 'ترغب في ترقية هذا التبويق:'\n    reply:\n      proceed: المواصلة إلى الرد\n      prompt: 'ترغب في الرد على هذا التبويق:'\n  remote_unfollow:\n    error: خطأ\n    title: العنوان\n    unfollowed: غير متابَع\n  sessions:\n    activity: آخر نشاط\n    browser: المتصفح\n    browsers:\n      alipay: أليباي\n      blackberry: بلاك بيري\n      chrome: كروم\n      edge: مايكروسوفت إيدج\n      electron: إلكترون\n      firefox: فايرفكس\n      generic: متصفح مجهول\n      ie: إنترنت إكسبلورر\n      micro_messenger: مايكرو ميسنجر\n      nokia: متصفح Nokia S40 Ovi\n      opera: أوبرا\n      otter: أوتر\n      phantom_js: فانتوم جي آس\n      qq: متصفح كيوكيو\n      safari: سفاري\n      uc_browser: متصفح يوسي براوزر\n      weibo: وايبو\n    current_session: الجلسة الحالية\n    description: \"%{browser} على %{platform}\"\n    explanation: ها هي قائمة مُتصفِّحات الويب التي تستخدِم حاليًا حساب ماستدون الخاص بك.\n    ip: عنوان الإيبي\n    platforms:\n      adobe_air: أدوبي إيير\n      android: أندرويد\n      blackberry: بلاك بيري\n      chrome_os: نظام كروم أواس\n      firefox_os: نظام فايرفكس أواس\n      ios: نظام آي أواس\n      linux: لينكس\n      mac: ماك\n      other: نظام مجهول\n      windows: ويندوز\n      windows_mobile: ويندوز موبايل\n      windows_phone: ويندوز فون\n    revoke: إبطال\n    revoke_success: تم إبطال الجلسة بنجاح\n    title: الجلسات\n  settings:\n    account: الحساب\n    account_settings: إعدادات الحساب\n    appearance: المظهر\n    authorized_apps: التطبيقات المرخص لها\n    back: عودة إلى ماستدون\n    delete: حذف الحسابات\n    development: التطوير\n    edit_profile: تعديل الملف الشخصي\n    export: تصدير البيانات\n    featured_tags: الوسوم الشائعة\n    identity_proofs: دلائل الهوية\n    import: استيراد\n    import_and_export: استيراد وتصدير\n    migrate: تهجير الحساب\n    notifications: الإخطارات\n    preferences: التفضيلات\n    profile: الملف الشخصي\n    relationships: المتابِعون والمتابَعون\n    two_factor_authentication: المُصادقة بخُطوَتَيْن\n  statuses:\n    attached:\n      description: 'مُرفَق: %{attached}'\n      image:\n        few: \"%{count} صور\"\n        many: \"%{count} صور\"\n        one: صورة %{count}\n        other: \"%{count} صور\"\n        two: \"%{count} صورة\"\n        zero: \"%{count} صورة\"\n      video:\n        few: \"%{count} فيديوهات\"\n        many: \"%{count} فيديوهات\"\n        one: فيديو %{count}\n        other: \"%{count} فيديوهات\"\n        two: \"%{count} فيديوهات\"\n        zero: \"%{count} فيديوهات\"\n    boosted_from_html: تم إعادة ترقيته مِن %{acct_link}\n    content_warning: 'تحذير عن المحتوى: %{warning}'\n    disallowed_hashtags:\n      few: 'يحتوي على وسوم غير مسموح بها: %{tags}'\n      many: 'يحتوي على وسوم غير مسموح بها: %{tags}'\n      one: 'يحتوي على وسم غير مسموح به: %{tags}'\n      other: 'يحتوي على وسوم غير مسموح بها: %{tags}'\n      two: 'يحتوي على وسوم غير مسموح بها: %{tags}'\n      zero: 'يحتوي على وسوم غير مسموح بها: %{tags}'\n    language_detection: اكتشاف اللغة تلقائيا\n    open_in_web: افتح في الويب\n    over_character_limit: تم تجاوز حد الـ %{max} حرف المسموح بها\n    pin_errors:\n      limit: لقد بلغت الحد الأقصى للتبويقات المدبسة\n      ownership: لا يمكن تدبيس تبويق نشره شخص آخر\n      private: لا يمكن تدبيس تبويق لم يُنشر للعامة\n      reblog: لا يمكن تثبيت ترقية\n    poll:\n      vote: صوّت\n    show_more: أظهر المزيد\n    sign_in_to_participate: قم بتسجيل الدخول للمشاركة في هذه المحادثة\n    title: '%{name}: \"%{quote}\"'\n    visibilities:\n      private: اعرض فقط لمتتبعيك\n      private_long: إعرضه لمتتبعيك فقط\n      public: للعامة\n      public_long: يمكن للجميع رؤيته\n      unlisted: غير مُدرَج\n      unlisted_long: يُمكن لأيٍ كان رُؤيتَه و لكن لن يُعرَض على الخيوط العامة\n  stream_entries:\n    pinned: تبويق مثبّت\n    reblogged: رقّاه\n    sensitive_content: محتوى حساس\n  terms:\n    title: شروط الخدمة وسياسة الخصوصية على %{instance}\n  themes:\n    contrast: ماستدون (تباين عالٍ)\n    default: ماستدون (داكن)\n    mastodon-light: ماستدون (فاتح)\n  two_factor_authentication:\n    code_hint: قم بإدخال الرمز المُوَلّد عبر تطبيق المصادقة للتأكيد\n    description_html: في حال تفعيل <strong>المصادقة بخطوتين </strong>، فتسجيل الدخول يتطلب منك أن يكون بحوزتك هاتفك النقال قصد توليد الرمز الذي سيتم إدخاله.\n    disable: تعطيل\n    enable: تفعيل\n    enabled: نظام المصادقة بخطوتين مُفعَّل\n    enabled_success: تم تفعيل المصادقة بخطوتين بنجاح\n    generate_recovery_codes: توليد رموز الاسترجاع\n    instructions_html: \"<strong>قم بمسح رمز الكيو آر عبر Google Authenticator أو أي تطبيق TOTP على جهازك</strong>. من الآن فصاعدا سوف يقوم ذاك التطبيق بتوليد رموز يجب عليك إدخالها عند تسجيل الدخول.\"\n    lost_recovery_codes: تُمكّنك رموز الاسترجاع الاحتياطية مِن استرجاع النفاذ إلى حسابك في حالة فقدان جهازك المحمول. إن ضاعت منك هذه الرموز فبإمكانك إعادة توليدها مِن هنا و إبطال الرموز القديمة.\n    manual_instructions: 'في حالة تعذّر مسح رمز الكيو آر أو طُلب منك إدخال يدوي، يُمْكِنك إدخال هذا النص السري على التطبيق:'\n    recovery_codes: النسخ الاحتياطي لرموز الاسترجاع\n    recovery_codes_regenerated: تم إعادة توليد رموز الاسترجاع الاحتياطية بنجاح\n    setup: تنشيط\n    wrong_code: الرمز الذي أدخلته غير صالح! تحقق من صحة الوقت على الخادم و الجهاز؟\n  user_mailer:\n    backup_ready:\n      explanation: لقد قمت بطلب نسخة كاملة لحسابك على ماستدون. إنها متوفرة الآن للتنزيل!\n      subject: نسخة بيانات حسابك جاهزة للتنزيل\n      title: المغادرة بأرشيف الحساب\n    warning:\n      review_server_policies: مراجعة شروط السيرفر\n      subject:\n        disable: تم تجميد حسابك %{acct}\n        none: تحذير إلى %{acct}\n        suspend: لقد تم تعليق حسابك %{acct}\n      title:\n        disable: الحساب مُجمَّد\n        none: تحذير\n        suspend: الحساب مُعلَّق\n    welcome:\n      edit_profile_action: تهيئة الملف الشخصي\n      edit_profile_step: يُمكنك·كي تخصيص ملفك الشخصي عن طريق تحميل صورة رمزية ورأسية و بتعديل اسمك·كي العلني وأكثر. و إن أردت·تي معاينة المتابِعين و المتابعات الجُدد قبيل السماح لهم·ن بمتابَعتك فيمكنك·كي تأمين حسابك·كي.\n      explanation: ها هي بعض النصائح قبل بداية الاستخدام\n      final_action: اشرَع في النشر\n      final_step: |-\n        يمكنك الشروع في النشر في الحين! حتى و إن لم كنت لا تمتلك متابِعين بعدُ، يمكن للآخرين الإطلاع على منشوراتك الموجهة للجمهور على الخيط المحلي أو إن قمت باستخدام وسوم.\n        ابدأ بتقديم نفسك باستعمال وسم #introductions.\n      full_handle: عنوانك الكامل\n      full_handle_hint: هذا هو ما يجب تقديمه لأصدقائك قصد أن يكون بإمكانهم متابَعتك أو مُراسَلتك حتى و إن كانت حساباتهم على خوادم أخرى.\n      review_preferences_action: تعديل التفضيلات\n      subject: أهلًا بك على ماستدون\n      tip_federated_timeline: الخيط الزمني الفديرالي هو بمثابة شبه نظرة شاملة على شبكة ماستدون. غير أنه لا يشمل إلا على الأشخاص المتابَعين مِن طرف جيرانك و جاراتك، لذا فهذا الخيط لا يعكس كافة الشبكة برُمّتها.\n      tip_following: أنت تتبع تلقائيا مديري و مديرات الخادم. للعثور على أشخاص مميزين أو قد تهمك حساباتهم بإمكانك الإطلاع على الخيوط المحلية و كذا الفدرالية.\n      tip_local_timeline: الخيط الزمني المحلي هو بمثابة نظرة سريعة على الأشخاص المتواجدين على %{instance} يمكن اعتبارهم كجيرانك وجاراتك الأقرب إليك!\n      tips: نصائح\n      title: أهلاً بك، %{name}!\n  users:\n    follow_limit_reached: لا يمكنك متابعة أكثر مِن %{limit} أشخاص\n    invalid_email: عنوان البريد الإلكتروني غير صالح\n    invalid_otp_token: رمز المصادقة بخطوتين غير صالح\n    otp_lost_help_html: إن فقدتَهُما ، يمكنك الاتصال بـ %{email}\n    seamless_external_login: لقد قمت بتسجيل الدخول عبر خدمة خارجية، إنّ إعدادات الكلمة السرية و البريد الإلكتروني غير متوفرة.\n    signed_in_as: 'تم تسجيل دخولك بصفة:'\n  verification:\n    verification: التحقق\n"
  },
  {
    "path": "config/locales/ast.yml",
    "content": "---\nast:\n  about:\n    about_mastodon_html: Mastodon ye una rede social basada en protocolos abiertos y software de códigu llibre. Ye descentralizada, como'l corréu electrónicu.\n    about_this: Tocante a\n    administered_by: 'Alministráu por:'\n    contact: Contautu\n    contact_missing: Nun s'afitó\n    contact_unavailable: N/D\n    documentation: Documentación\n    extended_description_html: |\n      <h3>Un llugar bonu pa les regles</h3>\n      <p>Entá nun se configuró la descripción estendida.</p>\n    hosted_on: Mastodon ta agospiáu en %{domain}\n    learn_more: Deprendi más\n    source_code: Códigu fonte\n    status_count_before: Que crearon\n    terms: Términos del serviciu\n    user_count_after:\n      one: usuariu\n      other: usuarios\n    user_count_before: Ye'l llar de\n    what_is_mastodon: \"¿Qué ye Mastodon?\"\n  accounts:\n    followers:\n      one: Xente que te sigue\n      other: Siguidores\n    joined: Xunióse en %{date}\n    moved_html: \"%{name} mudóse a %{new_profile_link}:\"\n    network_hidden: Esta información nun ta disponible\n    nothing_here: \"¡Equí nun hai nada!\"\n    people_followed_by: Persones a les que sigue %{name}\n    people_who_follow: Persones que siguen a %{name}\n    posts_with_replies: Toots y rempuestes\n    reserved_username: El nome d'usuariu ta acutáu\n    roles:\n      bot: Robó\n  admin:\n    accounts:\n      are_you_sure: \"¿De xuru?\"\n      by_domain: Dominiu\n      domain: Dominiu\n      email: Corréu\n      followers: Siguidores\n      location:\n        local: Llocal\n        title: Allugamientu\n      protocol: Protocolu\n      resend_confirmation:\n        already_confirmed: Esti usuariu yá ta confirmáu\n      role: Permisos\n      roles:\n        admin: Alministrador\n        moderator: Llendador\n        user: Usuariu\n      statuses: Estaos\n      title: Cuentes\n      username: Nome d'usuariu\n    action_logs:\n      actions:\n        create_domain_block: \"%{name} bloquió'l dominiu %{target}\"\n        disable_custom_emoji: \"%{name} desactivó'l fustaxe %{target}\"\n        disable_user: \"%{name} desactivó l'aniciu de sesión del usuariu %{target}\"\n    custom_emojis:\n      by_domain: Dominiu\n      copy_failed_msg: Nun pudo facese una copia llocal d'esi fustaxe\n      emoji: Fustaxe\n      update_failed_msg: Nun pudo anovase esi fustaxe\n    dashboard:\n      config: Configuración\n      feature_registrations: Rexistros\n      features: Carauterístiques\n      hidden_service: Federación con servicios anubríos\n      recent_users: Usuarios recientes\n      total_users: usuarios en total\n      week_interactions: interaiciones d'esta selmana\n      week_users_new: usuarios d'esta selmana\n    domain_blocks:\n      domain: Dominiu\n    email_domain_blocks:\n      domain: Dominiu\n    instances:\n      title: Instancies conocíes\n    invites:\n      filter:\n        available: Disponible\n        expired: Caducó\n      title: Invitaciones\n    relays:\n      save_and_enable: Guardar y activar\n    reports:\n      are_you_sure: \"¿De xuru?\"\n      status: Estáu\n    settings:\n      registrations:\n        min_invite_role:\n          disabled: Naide\n      site_description:\n        title: Descipción de la instancia\n      site_title: Nome de la instancia\n      title: Axustes del sitiu\n    statuses:\n      failed_to_execute: Fallu al executar\n    title: Alministración\n  admin_mailer:\n    new_report:\n      body_remote: Daquién dende %{domain} informó de %{target}\n  applications:\n    invalid_url: La URL apurrida nun ye válida\n    warning: Ten curiáu con estos datos, ¡enxamás nun los compartas con naide!\n  auth:\n    change_password: Contraseña\n    delete_account: Desaniciu de la cuenta\n    delete_account_html: Si deseyes desaniciar la to cuenta, pues <a href=\"%{path}\">siguir equí</a>. Va pidísete la confirmación.\n    forgot_password: \"¿Escaeciesti la contraseña?\"\n    login: Aniciar sesión\n    migrate_account: Mudase a otra cuenta\n    migrate_account_html: Si deseyes redirixir esta cuenta a otra, pues <a href=\"%{path}\"> configuralo equí</a>.\n    register: Rexistrase\n    security: Seguranza\n  authorize_follow:\n    already_following: Yá tas siguiendo a esta cuenta\n    error: Desafortunadamente, hebo un fallu guetando la cuenta remota\n    follow_request: 'Unviesti una solicitú de siguimientu a:'\n    post_follow:\n      close: O pues zarrar esta ventana.\n      return: Amosar el perfil del usuariu\n      web: Dir a la web\n  datetime:\n    distance_in_words:\n      half_a_minute: Púramente agora\n      less_than_x_seconds: Púramente agora\n  deletes:\n    bad_password_msg: \"¡Bon intentu, crackers! Contraseña incorreuta\"\n    confirm_password: Introduz la contraseña pa verificar la to identidá\n  directories:\n    people:\n      one: \"%{count} persona\"\n      other: \"%{count} persones\"\n  errors:\n    '403': Nun tienes permisu pa ver esta páxina.\n    '404': La páxina que tabes guetando nun esiste.\n    '410': La páxina que tabes guetando yá nun esiste.\n    '422':\n      content: Falló la verificación de seguranza. ¿Tas bloquiando les cookies?\n      title: Falló la verificación de seguranza\n    '429': Ficiéronse milenta solicitúes\n    '500': \n  exports:\n    archive_takeout:\n      date: Data\n      hint_html: Pues solicitar un archivu colos tos <strong>toots y ficheros xubíos</strong>. Los datos esportaos van tar nel formatu ActivityPub, llexible pa cualesquier software que seya compatible. Pues solicitar un archivu cada 7 díes.\n      request: Solicitar l'archivu\n      size: Tamañu\n    blocks: Xente que bloquiesti\n    follows: Xente que sigues\n    mutes: Xente que silenciesti\n  filters:\n    contexts:\n      notifications: Avisos\n      public: Llinies temporales públiques\n      thread: Conversaciones\n    index:\n      title: Peñeres\n    new:\n      title: Amestar una peñera nueva\n  generic:\n    changes_saved_msg: \"¡Los cambeos guardáronse con ésitu!\"\n    save_changes: Guardar cambeos\n  imports:\n    preface: Pues importar los datos qu'esportares dende otra instancia, como por exemplu la llista de persones que bloquiares o tubieres siguiendo.\n    types:\n      blocking: Llista de xente bloquiao\n      following: Llista de siguidores\n      muting: Llista de xente silenciao\n    upload: Xubir\n  invites:\n    delete: Desactivar\n    expired: Caducó\n    expires_in:\n      '1800': 30 minutos\n      '21600': 6 hores\n      '3600': 1 hora\n      '43200': 12 hores\n      '604800': 1 selmana\n      '86400': 1 día\n    expires_in_prompt: Enxamás\n    invited_by: 'Convidóte:'\n    max_uses:\n      one: 1 usu\n      other: \"%{count} usos\"\n    table:\n      expires_at: Data de caducidá\n      uses: Usos\n  lists:\n    errors:\n      limit: Algamesti la cantidá máxima de llistes\n  media_attachments:\n    validations:\n      images_and_video: Nun pue axuntase un videu a un estáu que yá contién imáxenes\n      too_many: Nun puen axuntase más de 4 ficheros\n  migrations:\n    acct: nome_usuariu@dominiu de la cuenta nueva\n    proceed: Guardar\n  notification_mailer:\n    digest:\n      body: Equí hai un resume de los mensaxes que nun viesti dende la última visita'l %{since}\n      mention: \"%{name} mentóte en:\"\n    follow:\n      body: \"¡Agora %{name} ta siguiéndote!\"\n      title: Siguidor nuevu\n    follow_request:\n      body: \"%{name} solicitó siguite\"\n      title: Petición nueva de siguimientu\n    mention:\n      body: \"%{name} mentóte en:\"\n      subject: \"%{name} mentóte\"\n      title: Mención nueva\n    reblog:\n      body: \"%{name} compartió'l to estáu:\"\n      subject: \"%{name} compartió'l to estáu\"\n      title: Compartición nueva de toot\n  pagination:\n    next: Siguiente\n  remote_follow:\n    acct: Introduz el nome_usuariu@dominiu dende'l que lo quies facer\n    no_account_html: \"¿Nun tienes una cuenta? Pues <a href='%{sign_up_path}' target='_blank'>rexistrate equí</a>\"\n    proceed: Siguir\n    prompt: 'Vas siguir a:'\n  remote_unfollow:\n    error: Fallu\n  sessions:\n    browser: Restolador\n    browsers:\n      generic: Restolador desconocíu\n    current_session: Sesión actual\n    description: \"%{browser} en %{platform}\"\n    platforms:\n      other: plataforma desconocida\n    title: Sesiones\n  settings:\n    authorized_apps: Aplicaciones autorizaes\n    back: Volver a Mastodon\n    edit_profile: Edición del perfil\n    export: Esportación de datos\n    import: Importación\n    notifications: Avisos\n    preferences: Preferencies\n    two_factor_authentication: Autenticación en dos pasos\n  statuses:\n    attached:\n      image:\n        one: \"%{count} imaxe\"\n        other: \"%{count} imáxenes\"\n      video:\n        one: \"%{count} videu\"\n        other: \"%{count} vídeos\"\n    boosted_from_html: Compartióse'l toot dende %{acct_link}\n    language_detection: Deteutala automáticamente\n    pin_errors:\n      limit: Yá fixesti'l númberu máxiumu de toots\n      ownership: Nun pue fixase'l toot d'otra persona\n      private: Nun puen fixase los toots que nun seyan públicos\n      reblog: Nun pue fixase un toot compartíu\n    show_more: Amosar más\n    title: \"%{name}: «%{quote}»\"\n    visibilities:\n      private: Namái siguidores\n  stream_entries:\n    reblogged: compartióse\n    sensitive_content: Conteníu sensible\n  themes:\n    default: Mastodon\n  two_factor_authentication:\n    code_hint: Introduz el códigu xeneráu pola aplicación autenticadora pa confirmar\n    disable: Desactivar\n    enabled: L'autenticación en dos pasos ta activada\n    enabled_success: L'autenticación en dos pasos activóse con ésitu\n    generate_recovery_codes: Xenerar códigos de recuperación\n    lost_recovery_codes: Los códigos de recuperación permítente recuperar l'accesu a la cuenta si pierdes el teléfonu. Si tamién pierdes esos códigos, pues xeneralos de nueves equí. Los códigos de recuperación vieyos van invalidase.\n    manual_instructions: 'Si nun pues escaniar el códigu QR y precises introducilu a mano, equí ta''l secretu en testu planu:'\n    recovery_codes: Códigos de recuperación\n    recovery_codes_regenerated: Los códigos de recuperación rexeneráronse con ésitu\n  user_mailer:\n    welcome:\n      full_handle_hint: Esto ye lo que-yos diríes a los collacios pa que puean unviate mensaxes o siguite dende otra instancia.\n      subject: Afáyate en Mastodon\n      tips: Conseyos\n  users:\n    invalid_email: La direición de corréu nun ye válida\n    seamless_external_login: Aniciesti sesión pente un serviciu esternu, polo que los axustes de la contraseña y corréu nun tán disponibles.\n  verification:\n    verification: Verificación\n"
  },
  {
    "path": "config/locales/bg.yml",
    "content": "---\nbg:\n  about:\n    about_mastodon_html: Mastodon е <em>безплатен</em> сървър с <em>отворен код</em> за социални мрежи. Като <em>децентрализирана</em> алтернатива на комерсиалните платформи, той позволява избягването на риска от монополизация на твоята комуникация от единични компании. Изберете си сървър, на който се доверявате, и ще можете да контактувате с всички останали. Всеки може да пусне Mastodon и лесно да вземе участие в <em>социалната мрежа</em>.\n    about_this: За тази инстанция\n    contact: За контакти\n    source_code: Програмен код\n    status_count_before: Написали\n    user_count_before: Дом на\n  accounts:\n    follow: Последвай\n    following: Следва\n    nothing_here: Тук няма никого!\n    people_followed_by: Хора, които %{name} следва\n    people_who_follow: Хора, които следват %{name}\n    unfollow: Не следвай\n  application_mailer:\n    settings: 'Промяна на предпочитанията за e-mail: %{link}'\n    view: 'Преглед:'\n  applications:\n    invalid_url: Предоставеният URL е невалиден\n  auth:\n    didnt_get_confirmation: Не получих инструкции за потвърждение\n    forgot_password: Забравих си паролата\n    login: Влизане\n    logout: Излизане\n    register: Регистрация\n    resend_confirmation: Изпрати отново инструкции за потвърждение\n    reset_password: Подновяване на паролата\n    security: Идентификационни данни\n    set_new_password: Задай нова парола\n  authorize_follow:\n    error: Възникна грешка в откриването на потребителя\n    follow: Последвай\n    title: Последвай %{acct}\n  datetime:\n    distance_in_words:\n      about_x_hours: \"%{count} ч.\"\n      about_x_months: \"%{count} м.\"\n      about_x_years: \"%{count} г.\"\n      almost_x_years: \"%{count} г.\"\n      half_a_minute: Току-що\n      less_than_x_minutes: \"%{count} мин.\"\n      less_than_x_seconds: Току-що\n      over_x_years: \"%{count} г\"\n      x_days: \"%{count} дни\"\n      x_minutes: \"%{count} мин\"\n      x_months: \"%{count} м\"\n      x_seconds: \"%{count} сек\"\n  errors:\n    '403': You don't have permission to view this page.\n    '404': The page you are looking for isn't here.\n    '410': The page you were looking for doesn't exist here anymore.\n    '422': \n    '429': Throttled\n    '500': \n  exports:\n    blocks: Вашите блокирания\n    follows: Вашите следвания\n    storage: Съхранение на мултимедия\n  generic:\n    changes_saved_msg: Успешно запазване на промените!\n    save_changes: Запази промените\n  imports:\n    preface: Можеш да импортираш някои данни, като например всички хора, които следваш или блокираш в акаунта си на тази инстанция, от файлове, създадени чрез експорт в друга инстанция.\n    success: Твоите данни бяха успешно качени и ще бъдат обработени впоследствие\n    types:\n      blocking: Списък на блокираните\n      following: Списък на последователите\n    upload: Качване\n  invites:\n    expires_in:\n      '1800': 30 minutes\n      '21600': 6 hours\n      '3600': 1 hour\n      '43200': 12 hours\n      '604800': 1 week\n      '86400': 1 day\n  media_attachments:\n    validations:\n      images_and_video: Не мога да прикача видеоклип към публикация, която вече съдържа изображения\n      too_many: Не мога да прикача повече от 4 файла\n  notification_mailer:\n    digest:\n      body: Ето кратко резюме на нещата, които се случиха от последното ти посещение на %{since}\n      mention: \"%{name} те спомена в:\"\n      new_followers_summary:\n        one: Имаш един нов последовател! Ура!\n        other: Имаш %{count} нови последователи! Изумително!\n      subject:\n        one: \"1 ново известие от последното ти посещение \\U0001F418\"\n        other: \"%{count} нови известия от последното ти посещение \\U0001F418\"\n    favourite:\n      body: 'Публикацията ти беше харесана от %{name}:'\n      subject: \"%{name} хареса твоята публикация\"\n    follow:\n      body: \"%{name} те последва!\"\n      subject: \"%{name} те последва\"\n    follow_request:\n      body: \"%{name} помоли за разрешение да те последва\"\n      subject: 'Чакащ последовател: %{name}'\n    mention:\n      body: \"%{name} те спомена в:\"\n      subject: \"%{name} те спомена\"\n    reblog:\n      body: 'Твоята публикация беше споделена от %{name}:'\n      subject: \"%{name} сподели публикацията ти\"\n  pagination:\n    next: Напред\n    prev: Назад\n  remote_follow:\n    acct: Въведи потребителско_име@домейн, от които искаш да следваш\n    missing_resource: Неуспешно търсене на нужния URL за пренасочване за твоя акаунт\n    proceed: Започни следване\n    prompt: 'Ще последваш:'\n  settings:\n    authorized_apps: Упълномощени приложения\n    back: Обратно към Mastodon\n    edit_profile: Редактирай профила си\n    export: Експортиране на данни\n    import: Импортиране\n    preferences: Предпочитания\n    two_factor_authentication: Двустепенно удостоверяване\n  statuses:\n    open_in_web: Отвори в уеб\n    over_character_limit: прехвърлен лимит от %{max} символа\n    show_more: Покажи повече\n    visibilities:\n      private: Покажи само на последователите си\n      public: Публично\n      unlisted: Публично, но не показвай в публичния канал\n  stream_entries:\n    reblogged: споделено\n    sensitive_content: Деликатно съдържание\n  time:\n    formats:\n      default: \"%d %b, %Y, %H:%M\"\n  two_factor_authentication:\n    description_html: При активация на <strong>двустепенно удостоверяване</strong>, за да влезеш в приложението, ще трябва да използваш телефона си. През него ще се генерира код, който да въвеждаш при влизане.\n    disable: Деактивирай\n    enable: Активирай\n    instructions_html: \"<strong>Сканирай този QR код с Google Authenticator или подобно приложение от своя телефон</strong>. Oтсега нататък, това приложение ще генерира код, който ще трябва да въвеждаш при всяко влизане.\"\n  users:\n    invalid_email: E-mail адресът е невалиден\n    invalid_otp_token: Невалиден код\n"
  },
  {
    "path": "config/locales/bn.yml",
    "content": "---\nbn:\n  about:\n    about_hashtag_html: এগুলো প্রকাশ্য লেখা যার হ্যাশট্যাগ <strong>#%{hashtag}</strong>। আপনি এগুলোর ব্যবহার বা সাথে যুক্ত হতে পারবেন যদি আপনার যুক্তবিশ্বের কোথাও নিবন্ধন থেকে থাকে।\n    about_mastodon_html: মাস্টাডন উন্মুক্ত ইন্টারনেটজালের নিয়ম এবং স্বাধীন ও মুক্ত উৎসের সফটওয়্যারের ভিত্তিতে তৈরী একটি সামাজিক যোগাযোগ মাধ্যম। এটি ইমেইলের মত বিকেন্দ্রীভূত।\n    about_this: কি\n    active_count_after: চালু\n    active_footnote: মাসিক সক্রিয় ব্যবহারকারী\n    administered_by: 'পরিচালনা করছেন:'\n    api: সফটওয়্যার তৈরীর নিয়ম (API)\n    apps: মোবাইল অ্যাপ\n    apps_platforms: মাস্টাডন আইওএস, এন্ড্রোইড বা অন্য মাধ্যমে ব্যবহার করুন\n    browse_directory: একটি ব্যবহারকারীদের তালিকা দেখুন এবং পছন্দ অনুসারে খুজুন\n    browse_public_posts: মাস্টাডনে নতুন প্রকাশ্য লেখাগুলো সরাসরি দেখুন\n    contact: যোগাযোগ\n    contact_missing: নেই\n    contact_unavailable: প্রযোজ্য নয়\n    discover_users: ব্যবহারকারীদের দেখুন\n    documentation: ব্যবহারবিলি\n    extended_description_html: |\n      <h3>নিয়মের জন্য উপযুক্ত জায়গা</h3>\n      <p>বিস্তারিত বিবরণ এখনো যুক্ত করা হয়নি</p>\n    federation_hint_html: \"%{instance}তে একটা নিবন্ধন থাকলে আপনি যেকোনো মাস্টাডন বা এধরণের অন্যান্য সার্ভারের মানুষের সাথে যুক্ত হতে পারবেন ।\"\n    generic_description: নেটওয়ার্কের ভেতরে %{domain} একটি সার্ভার\n    get_apps: মোবাইল এপ্প একটা ব্যবহার করতে পারেন\n    hosted_on: এই মাস্টাডনটি আছে %{domain} এ\n    learn_more: বিস্তারিত জানুন\n    privacy_policy: গোপনীয়তা নীতি\n    see_whats_happening: কী কী হচ্ছে দেখুন\n    server_stats: 'সার্ভারের অবস্থা:'\n    source_code: আসল তৈরীপত্র\n    status_count_after:\n      one: অবস্থা\n      other: স্থিতিগুলি\n    status_count_before: কে লিখেছে\n    tagline: পরিচিতজনদের সাথে যুক্ত হন এবং নতুনদের সাথে পরিচিত হন\n    terms: ব্যবহারের শর্তাবলী\n    user_count_after:\n      one: ব্যবহারকারী\n      other: জনের\n    user_count_before: বাসা\n    what_is_mastodon: মাস্টাডনটি কি ?\n  accounts:\n    choices_html: \"%{name} বাছাই:\"\n    follow: যুক্ত\n    followers:\n      one: যুক্ত আছে\n      other: যারা যুক্ত হয়েছে\n    following: যুক্ত করা\n    joined: যোগদান হয় %{date}\n    last_active: শেষ সক্রিয় ছিল\n    link_verified_on: এই লিংকের মালিকানা শেষ চেক করা হয়  %{date} তারিখে\n    media: ছবি বা ভিডিও\n    moved_html: \"%{name} চলে গেছে %{new_profile_link} তে:\"\n    network_hidden: এই তথ্যটি নেই\n    nothing_here: এখানে কিছুই নেই!\n    people_followed_by: \"%{name} যাদেরকে অনুসরণ করে\"\n    people_who_follow: যারা %{name} কে অনুসরণ করে\n    pin_errors:\n      following: সমর্থন করতে অনুসরণ থাকা লাগবে\n    posts:\n      one: লেখা\n      other: লেখাগুলো\n    posts_tab_heading: লেখাগুলো\n    posts_with_replies: লেখা এবং মতামত\n    reserved_username: নামটি সংরক্ষিত\n    roles:\n      admin: পরিচালক\n      bot: রোবট\n      moderator: পরিচালক\n    unavailable: প্রোফাইল অনুপলব্ধ\n    unfollow: অনুসরণ বাদ\n  admin:\n    account_actions:\n      action: করা\n      title: 'প্রশাসনা করুন এর উপর : %{acct}'\n    account_moderation_notes:\n      create: কিছু লিখুন\n      created_msg: প্রশাসনবস্তুত লেখাটি সঠিকভাবে তৈরী হয়েছে!\n      delete: মুছে ফেলা\n      destroyed_msg: প্রশাসনবস্তুত লেখাটি সঠিকভাবে মুছে ফেলা হয়েছে!\n    accounts:\n      approve: অনুমোদন দিন\n      approve_all: প্রত্যেক কে অনুমতি দিন\n      are_you_sure: আপনি কি নিশ্চিত ?\n      avatar: অবতার\n      by_domain: ওয়েবসাইট/কার্যক্ষেত্র\n      change_email:\n        changed_msg: নিবন্ধনের ইমেইল সঠিকভাবে পরিবর্তন হয়েছে!\n        current_email: এখনকার ইমেইল\n        label: ইমেইল পরিবর্তন\n        new_email: নতুন ইমেইল\n        submit: ইমেইল পরিবর্তন\n        title: \"%{username} এর ইমেইল পরিবর্তন\"\n      confirm: নিশ্চিত করুন\n      confirmed: নিশ্চিত হয়েছে\n      confirming: নিশ্চিত করা হচ্ছে\n      deleted: মুছে ফেলা হয়েছে\n      demote: নিচের পদে দিন\n      disable: বন্ধ করুন\n      disable_two_factor_authentication: দুই পদ্ধতির প্রমাণীকরণ(2FA) বন্ধ করুন\n      disabled: বন্ধ করা হয়েছে\n      display_name: দেখানোর জন্য নাম\n      domain: ওয়েবসাইট/কার্যক্ষেত্র\n      edit: বদলান\n      email: ইমেইল\n      email_status: ইমেইলের অবস্থা\n      enable: চালু করুন\n      enabled: চালু করুন\n      feed_url: সম্মিলিত(feed) লিংক\n      followers: অনুসরকারীরা\n      followers_url: অনুসরণকারীদের লিংক\n      follows: অনুসরণ করে\n      header: শিরোলেখা\n      inbox_url: চিঠি পাওয়ার বক্স লিংক\n      invited_by: আমন্ত্রণ করেছে\n      ip: আইপি(IP)\n      joined: যোগ দিয়েছে\n      location:\n        all: সব\n        local: স্থানীয়\n        remote: দূরবর্তী\n        title: জায়গা\n      login_status: নিবন্ধনধারীভাবে প্রবেশের অবস্থা\n      media_attachments: ছবি/ভিডিও যুক্ত\n      memorialize: স্মরণিকা বানান\n      moderation:\n        active: চালু\n        all: সব\n        pending: অপেক্ষিত আছে\n        silenced: নীরব করা হয়েছে\n        suspended: স্থগিত করা হয়েছে\n        title: প্রশাসনা\n      moderation_notes: প্রশাসনের কিছু লেখা\n      most_recent_activity: সর্বশেষ কার্যক্রম\n      most_recent_ip: সর্বশেষ আইপি(IP)\n      no_limits_imposed: কোন সীমা আরোপ করা নেই\n      not_subscribed: সাবস্ক্রাইব নেই\n      outbox_url: চিঠি পাঠানোর বাক্স লিংক\n      pending: পয্র্যবেক্ষণের অপেক্ষায় আছে\n      perform_full_suspension: বাতিল করা\n  errors:\n    '403': You don't have permission to view this page.\n    '404': The page you are looking for isn't here.\n    '410': The page you were looking for doesn't exist here anymore.\n    '422': \n    '429': Throttled\n    '500': \n  invites:\n    expires_in:\n      '1800': 30 minutes\n      '21600': 6 hours\n      '3600': 1 hour\n      '43200': 12 hours\n      '604800': 1 week\n      '86400': 1 day\n  verification:\n    verification: সত্যতা নির্ধারণ\n"
  },
  {
    "path": "config/locales/ca.yml",
    "content": "---\nca:\n  about:\n    about_hashtag_html: Aquests són toots públics etiquetats amb <strong>#%{hashtag}</strong>. Pots interactuar amb ells si tens un compte a qualsevol lloc del fediverse.\n    about_mastodon_html: Mastodon és una xarxa social basada en protocols web oberts i en programari lliure i de codi obert. Està descentralitzat com el correu electrònic.\n    about_this: Quant a\n    active_count_after: actiu\n    active_footnote: Usuaris actius mensuals (UAM)\n    administered_by: 'Administrat per:'\n    api: API\n    apps: Apps mòbils\n    apps_platforms: Utilitza Mastodon des de iOS, Android i altres plataformes\n    browse_directory: Navega per el directori de perfils i filtra segons interessos\n    browse_public_posts: Navega per una transmissió en directe de publicacions públiques a Mastodon\n    contact: Contacte\n    contact_missing: No configurat\n    contact_unavailable: N/D\n    discover_users: Descobreix usuaris\n    documentation: Documentació\n    extended_description_html: |\n      <h3>Un bon lloc per les regles</h3>\n      <p>Encara no s'ha configurat la descripció ampliada.</p>\n    federation_hint_html: Amb un compte de %{instance} podràs seguir persones de qualsevol servidor Mastodon i altres.\n    generic_description: \"%{domain} és un servidor a la xarxa\"\n    get_apps: Prova una aplicació mòbil\n    hosted_on: Mastodon allotjat a %{domain}\n    learn_more: Més informació\n    privacy_policy: Política de privacitat\n    see_whats_happening: Mira què està passant\n    server_stats: 'Estadístiques del servidor:'\n    source_code: Codi font\n    status_count_after:\n      one: toot\n      other: toots\n    status_count_before: Que han escrit\n    tagline: Segueix els teus amics i descobreix-ne de nous\n    terms: Termes del servei\n    user_count_after:\n      one: usuari\n      other: usuaris\n    user_count_before: Tenim\n    what_is_mastodon: Què és Mastodon?\n  accounts:\n    choices_html: 'Eleccions de %{name}:'\n    follow: Segueix\n    followers:\n      one: Seguidor\n      other: Seguidors\n    following: Seguint\n    joined: Unit des de %{date}\n    last_active: darrer actiu\n    link_verified_on: La propietat d'aquest enllaç s'ha verificat el %{date}\n    media: Mèdia\n    moved_html: \"%{name} s'ha mogut a %{new_profile_link}:\"\n    network_hidden: Aquesta informació no està disponible\n    nothing_here: No hi ha res aquí!\n    people_followed_by: Usuaris seguits per %{name}\n    people_who_follow: Usuaris que segueixen %{name}\n    pin_errors:\n      following: Has d'estar seguint la persona que vulguis avalar\n    posts:\n      one: Toot\n      other: Toots\n    posts_tab_heading: Toots\n    posts_with_replies: Toots i respostes\n    reserved_username: El nom d'usuari està reservat\n    roles:\n      admin: Administrador\n      bot: Bot\n      moderator: Moderador\n    unavailable: Perfil inaccessible\n    unfollow: Deixa de seguir\n  admin:\n    account_actions:\n      action: Realitzar acció\n      title: Fer l'acció de moderació a %{acct}\n    account_moderation_notes:\n      create: Crea nota\n      created_msg: La nota de moderació s'ha creat correctament!\n      delete: Suprimeix\n      destroyed_msg: Nota de moderació destruïda amb èxit!\n    accounts:\n      approve: Aprova\n      approve_all: Aprova'ls tots\n      are_you_sure: N'estàs segur?\n      avatar: Avatar\n      by_domain: Domini\n      change_email:\n        changed_msg: El correu electrònic del compte s'ha canviat correctament!\n        current_email: Correu electrònic actual\n        label: Canviar l'adreça de correu\n        new_email: Nova adreça de correu\n        submit: Canviar adreça de correu\n        title: Canviar adreça de correu de %{username}\n      confirm: Confirma\n      confirmed: Confirmat\n      confirming: Confirmant\n      deleted: Esborrats\n      demote: Degrada\n      disable: Inhabilita\n      disable_two_factor_authentication: Desactiva 2FA\n      disabled: Inhabilitat\n      display_name: Nom de visualització\n      domain: Domini\n      edit: Edita\n      email: Correu electrònic\n      email_status: Estat del correu electrònic\n      enable: Habilita\n      enabled: Habilitat\n      feed_url: URL del canal\n      followers: Seguidors\n      followers_url: URL dels seguidors\n      follows: Segueix\n      header: Capçalera\n      inbox_url: URL de la safata d'entrada\n      invited_by: Convidat per\n      ip: IP\n      joined: Unit\n      location:\n        all: Tot\n        local: Local\n        remote: Remot\n        title: Localització\n      login_status: Estat d'accés\n      media_attachments: Adjunts multimèdia\n      memorialize: Converteix-lo en memorial\n      moderation:\n        active: Actiu\n        all: Tot\n        pending: Pendent\n        silenced: Silenciat\n        suspended: Suspès\n        title: Moderació\n      moderation_notes: Notes de moderació\n      most_recent_activity: Activitat més recent\n      most_recent_ip: IP més recent\n      no_account_selected: No s'han canviat els comptes perque no s'han seleccionat\n      no_limits_imposed: Sense límits imposats\n      not_subscribed: No subscrit\n      outbox_url: URL de la bústia de sortida\n      pending: Revisió pendent\n      perform_full_suspension: Suspèn\n      profile_url: URL del perfil\n      promote: Promociona\n      protocol: Protocol\n      public: Públic\n      push_subscription_expires: La subscripció PuSH expira\n      redownload: Actualitza el perfil\n      reject: Rebutja\n      reject_all: Rebutja'ls tots\n      remove_avatar: Eliminar avatar\n      remove_header: Treu la capçalera\n      resend_confirmation:\n        already_confirmed: Aquest usuari ja està confirmat\n        send: Reenviar el correu electrònic de confirmació\n        success: Correu electrònic de confirmació enviat amb èxit!\n      reset: Reinicialitza\n      reset_password: Restableix la contrasenya\n      resubscribe: Torna a subscriure\n      role: Permisos\n      roles:\n        admin: Administrador\n        moderator: Moderador\n        staff: Personal\n        user: Usuari\n      salmon_url: URL Salmon\n      search: Cerca\n      shared_inbox_url: URL de la safata d'entrada compartida\n      show:\n        created_reports: Informes creats\n        targeted_reports: Informes realitzats per altres\n      silence: Silenci\n      silenced: Silenciat\n      statuses: Estats\n      subscribe: Subscriu\n      suspended: Suspès\n      time_in_queue: Esperant en la cua %{time}\n      title: Comptes\n      unconfirmed_email: Correu electrònic sense confirmar\n      undo_silenced: Deixa de silenciar\n      undo_suspension: Desfés la suspensió\n      unsubscribe: Cancel·la la subscripció\n      username: Nom d'usuari\n      warn: Avís\n      web: Web\n    action_logs:\n      actions:\n        assigned_to_self_report: \"%{name} han assignat l'informe %{target} a ells mateixos\"\n        change_email_user: \"%{name} ha canviat l'adreça de correu electrònic del usuari %{target}\"\n        confirm_user: \"%{name} ha confirmat l'adreça de correu electrònic de l'usuari %{target}\"\n        create_account_warning: \"%{name} ha enviat un avís a %{target}\"\n        create_custom_emoji: \"%{name} ha pujat un nou emoji %{target}\"\n        create_domain_block: \"%{name} ha blocat el domini %{target}\"\n        create_email_domain_block: \"%{name} ha afegit a la llista negra el domini del correu electrònic %{target}\"\n        demote_user: \"%{name} ha degradat l'usuari %{target}\"\n        destroy_custom_emoji: \"%{name} ha destruït l'emoji %{target}\"\n        destroy_domain_block: \"%{name} ha desblocat el domini %{target}\"\n        destroy_email_domain_block: \"%{name} ha afegit a la llista negra el domini de correu electrònic %{target}\"\n        destroy_status: \"%{name} eliminat l'estat per %{target}\"\n        disable_2fa_user: \"%{name} ha desactivat el requisit de dos factors per a l'usuari %{target}\"\n        disable_custom_emoji: \"%{name} ha desactivat l'emoji %{target}\"\n        disable_user: \"%{name} ha desactivat l'accés per a l'usuari %{target}\"\n        enable_custom_emoji: \"%{name} ha activat l'emoji %{target}\"\n        enable_user: \"%{name} ha activat l'accés per a l'usuari %{target}\"\n        memorialize_account: \"%{name} ha convertit el compte %{target} en una pàgina de memorial\"\n        promote_user: \"%{name} ha promogut l'usuari %{target}\"\n        remove_avatar_user: \"%{name} ha eliminat l'avatar de %{target}\"\n        reopen_report: \"%{name} ha reobert l'informe %{target}\"\n        reset_password_user: \"%{name} ha restablert la contrasenya de l'usuari %{target}\"\n        resolve_report: \"%{name} ha resolt l'informe %{target}\"\n        silence_account: \"%{name} ha silenciat el compte de %{target}\"\n        suspend_account: \"%{name} ha suspès el compte de %{target}\"\n        unassigned_report: \"%{name} ha des-assignat l'informe %{target}\"\n        unsilence_account: \"%{name} ha silenciat el compte de %{target}\"\n        unsuspend_account: \"%{name} ha llevat la suspensió del compte de %{target}\"\n        update_custom_emoji: \"%{name} ha actualitzat l'emoji %{target}\"\n        update_status: \"%{name} estat actualitzat per %{target}\"\n      deleted_status: \"(toot suprimit)\"\n      title: Registre d'auditoria\n    custom_emojis:\n      by_domain: Domini\n      copied_msg: S'ha creat correctament la còpia local de l'emoji\n      copy: Copia\n      copy_failed_msg: No s'ha pogut fer una còpia local d'aquest emoji\n      created_msg: Emoji creat amb èxit!\n      delete: Suprimeix\n      destroyed_msg: Emojo s'ha destruït amb èxit!\n      disable: Inhabilita\n      disabled_msg: S'ha inhabilitat l'emoji amb èxit\n      emoji: Emoji\n      enable: Habilita\n      enabled_msg: S'ha habilitat amb èxit emoji\n      image_hint: PNG de fins a 50 KB\n      listed: Enumerat\n      new:\n        title: Afegeix emoji personalitzat nou\n      overwrite: Sobreescriure\n      shortcode: Codi curt\n      shortcode_hint: Com a mínim 2 caràcters, només caràcters alfanumèrics i guions baixos\n      title: Emojis personalitzats\n      unlisted: Sense classificar\n      update_failed_msg: No s'ha pogut actualitzar aquest emoji\n      updated_msg: Emoji s'ha actualitzat correctament!\n      upload: Carrega\n    dashboard:\n      backlog: treballs en espera\n      config: Configuració\n      feature_deletions: Supressions del compte\n      feature_invites: Enllaços de convits\n      feature_profile_directory: Directori de perfils\n      feature_registrations: Registres\n      feature_relay: Relay de la Federació\n      feature_timeline_preview: Vista previa de línia de temps\n      features: Característiques\n      hidden_service: Federació amb serveis ocults\n      open_reports: informes oberts\n      recent_users: Usuaris recents\n      search: Cerca de text complet\n      single_user_mode: Mode d'usuari únic\n      software: Programari\n      space: Ús d’espai\n      title: Panell\n      total_users: usuaris en total\n      trends: Tendències\n      week_interactions: interaccions d'aquesta setmana\n      week_users_active: usuaris actius aquesta setmana\n      week_users_new: nous usuaris aquest setmana\n    domain_blocks:\n      add_new: Afegir nou bloqueig de domini\n      created_msg: El bloqueig de domini ara s'està processant\n      destroyed_msg: El bloqueig de domini s'ha desfet\n      domain: Domini\n      existing_domain_block_html: Ja has imposat uns limits més estrictes a %{name}, l'hauries de <a href=\"%{unblock_url}\">desbloquejar-lo</a> primer.\n      new:\n        create: Crea un bloqueig\n        hint: El bloqueig de domini no impedirà la creació de nous comptes en la base de dades, però s'aplicaran de manera retroactiva mètodes de moderació específics sobre aquests comptes.\n        severity:\n          desc_html: \"<strong>Silenci</strong> farà les publicacions del compte invisibles a tothom que no l'estigui seguint. <strong>La suspensió</strong> eliminarà tots els continguts, multimèdia i les dades del perfil del compte. Usa <strong>Cap</strong> si només vols rebutjar el fitxers multimèdia.\"\n          noop: Cap\n          silence: Silenci\n          suspend: Suspensió\n        title: Bloqueig de domini nou\n      reject_media: Rebutja els fitxers multimèdia\n      reject_media_hint: Elimina els fitxers multimèdia emmagatzemats localment i impedeix baixar-ne cap en el futur. Irrellevant en les suspensions\n      reject_reports: Rebutja informes\n      reject_reports_hint: Ignora tots els informes procedents d'aquest domini. No és rellevant per a les suspensions\n      rejecting_media: rebutjant els fitxers multimèdia\n      rejecting_reports: rebutjant els informes\n      severity:\n        silence: silenciat\n        suspend: suspès\n      show:\n        affected_accounts:\n          one: Un compte afectat en la base de dades\n          other: \"%{count} comptes afectats en la base de dades\"\n        retroactive:\n          silence: Desfés el silenci a tots els comptes existents d'aquest domini\n          suspend: Desfés la suspensió de tots els comptes d'aquest domini\n        title: Desfés el bloqueig de domini de %{domain}\n        undo: Desfés\n      undo: Desfés el bloqueig del domini\n    email_domain_blocks:\n      add_new: Afegir nou\n      created_msg: S'ha creat el bloc de domini de correu electrònic\n      delete: Suprimeix\n      destroyed_msg: S'ha eliminat correctament el bloc del domini de correu\n      domain: Domini\n      new:\n        create: Afegeix un domini\n        title: Nova adreça de correu en la llista negra\n      title: Llista negra de correus electrònics\n    followers:\n      back_to_account: Tornar al compte\n      title: Seguidors de %{acct}\n    instances:\n      by_domain: Domini\n      delivery_available: El lliurament està disponible\n      known_accounts:\n        one: \"%{count} compte conegut\"\n        other: \"%{count} comptes coneguts\"\n      moderation:\n        all: Totes\n        limited: Limitades\n        title: Moderació\n      title: Federació\n      total_blocked_by_us: Bloquejats per nosaltres\n      total_followed_by_them: Seguits per ells\n      total_followed_by_us: Seguits per nosaltres\n      total_reported: Informes sobre ells\n      total_storage: Adjunts multimèdia\n    invites:\n      deactivate_all: Desactiva-ho tot\n      filter:\n        all: Totes\n        available: Disponible\n        expired: Caducat\n        title: Filtre\n      title: Convida\n    pending_accounts:\n      title: Comptes pendents (%{count})\n    relays:\n      add_new: Afegiu un nou relay\n      delete: Esborra\n      description_html: Un <strong>relay de federació</strong> és un servidor intermediari que intercanvia grans volums de toots públics entre servidors que es subscriuen i publiquen en ell. <strong>Pot ajudar a servidors petits i mitjans a descobrir contingut del fedivers</strong>, no fent necessari que els usuaris locals manualment segueixin altres persones de servidors remots.\n      disable: Inhabilita\n      disabled: Desactivat\n      enable: Activat\n      enable_hint: Una vegada habilitat el teu servidor es subscriurà a tots els toots públics d'aquest relay i començarà a enviar-hi tots els toots públics d'aquest servidor.\n      enabled: Activat\n      inbox_url: URL del Relay\n      pending: S'està esperant l'aprovació del relay\n      save_and_enable: Desa i activa\n      setup: Configura una connexió de relay\n      status: Estat\n      title: Relays\n    report_notes:\n      created_msg: La nota del informe s'ha creat correctament!\n      destroyed_msg: La nota del informe s'ha esborrat correctament!\n    reports:\n      account:\n        note: nota\n        report: informe\n      action_taken_by: Mesures adoptades per\n      are_you_sure: N'estàs segur?\n      assign_to_self: Assignar-me\n      assigned: Moderador assignat\n      comment:\n        none: Cap\n      created_at: Reportat\n      mark_as_resolved: Marca com a resolt\n      mark_as_unresolved: Marcar sense resoldre\n      notes:\n        create: Afegir nota\n        create_and_resolve: Resoldre amb nota\n        create_and_unresolve: Reobrir amb nota\n        delete: Esborrar\n        placeholder: Descriu les accions que s'han pres o qualsevol altra actualització relacionada…\n      reopen: Reobrir informe\n      report: 'Informe #%{id}'\n      reported_account: Compte reportat\n      reported_by: Reportat per\n      resolved: Resolt\n      resolved_msg: Informe resolt amb èxit!\n      status: Estat\n      title: Informes\n      unassign: Treure assignació\n      unresolved: No resolt\n      updated_at: Actualitzat\n    settings:\n      activity_api_enabled:\n        desc_html: Compte d'estatus publicats localment, usuaris actius i registres nous en períodes setmanals\n        title: Publica estadístiques agregades sobre l'activitat de l'usuari\n      bootstrap_timeline_accounts:\n        desc_html: Separa diversos noms d'usuari amb comes. Només funcionaran els comptes locals i desblocats. El valor predeterminat quan està buit és tots els administradors locals.\n        title: El seguiment per defecte per als usuaris nous\n      contact_information:\n        email: Introdueix una adreça de correu electrònic pública\n        username: Nom d'usuari del contacte\n      custom_css:\n        desc_html: Modifica l'aspecte amb CSS carregat a cada pàgina\n        title: CSS personalitzat\n      hero:\n        desc_html: Es mostra en pàgina frontal. Recomanat al menys 600x100px. Si no es configura es mostrarà el del servidor\n        title: Imatge d’heroi\n      mascot:\n        desc_html: Es mostra a diverses pàgines. Es recomana com a mínim 293 × 205px. Si no està configurat, torna a la mascota predeterminada\n        title: Imatge de la mascota\n      peers_api_enabled:\n        desc_html: Els noms de domini que aquest servidor ha trobat al fedivers\n        title: Publica la llista de servidors descoberts\n      preview_sensitive_media:\n        desc_html: Les visualitzacions prèvies d'enllaços d'altres llocs web mostraran una miniatura encara que els mitjans de comunicació estiguin marcats com a sensibles\n        title: Mostra els mitjans sensibles a les previsualitzacions d'OpenGraph\n      profile_directory:\n        desc_html: Permet als usuaris ser descoberts\n        title: Habilita el directori de perfils\n      registrations:\n        closed_message:\n          desc_html: Apareix en la primera pàgina quan es tanquen els registres. Pots utilitzar etiquetes HTML\n          title: Missatge de registre tancat\n        deletion:\n          desc_html: Permet a qualsevol usuari d'esborrar el seu compte\n          title: Obre la supressió del compte\n        min_invite_role:\n          disabled: Ningú\n          title: Permet les invitacions de\n      registrations_mode:\n        modes:\n          approved: Es requereix l’aprovació per registrar-se\n          none: Ningú no pot registrar-se\n          open: Qualsevol pot registrar-se\n        title: Mode de registres\n      show_known_fediverse_at_about_page:\n        desc_html: Quan s'activa, mostrarà tots els toots de tot el fedivers conegut en vista prèvia. En cas contrari, només es mostraran toots locals.\n        title: Mostra el fedivers conegut en vista prèvia de la línia de temps\n      show_staff_badge:\n        desc_html: Mostra una insígnia de personal en la pàgina d'usuari\n        title: Mostra insígnia de personal\n      site_description:\n        desc_html: Paràgraf introductori a la pàgina principal i en etiquetes meta. Pots utilitzar etiquetes HTML, en particular <code>&lt;a&gt;</code> i <code>&lt;em&gt;</code>.\n        title: Descripció del servidor\n      site_description_extended:\n        desc_html: Un bon lloc per al codi de conducta, regles, directrius i altres coses que distingeixen el teu servidor. Pots utilitzar etiquetes HTML\n        title: Descripció ampliada del lloc\n      site_short_description:\n        desc_html: Es mostra a la barra lateral i a metaetiquetes. Descriu en un únic paràgraf què és Mastodon i què fa que aquest servidor sigui especial. Si està buit, s'estableix per defecte la descripció del servidor.\n        title: Descripció curta del servidor\n      site_terms:\n        desc_html: Pots escriure la teva pròpia política de privadesa, els termes del servei o d'altres normes legals. Pots utilitzar etiquetes HTML\n        title: Termes del servei personalitzats\n      site_title: Nom del servidor\n      thumbnail:\n        desc_html: S'utilitza per obtenir visualitzacions prèvies a través d'OpenGraph i API. Es recomana 1200x630px\n        title: Miniatura del servidor\n      timeline_preview:\n        desc_html: Mostra la línia de temps pública a la pàgina inicial\n        title: Vista prèvia de la línia de temps\n      title: Configuració del lloc\n    statuses:\n      back_to_account: Torna a la pàgina del compte\n      batch:\n        delete: Suprimeix\n        nsfw_off: Marcar com a no sensible\n        nsfw_on: Marcar com a sensible\n      failed_to_execute: No s'ha pogut executar\n      media:\n        title: Contingut multimèdia\n      no_media: Sense contingut multimèdia\n      no_status_selected: No s’han canviat els estatus perquè cap no ha estat seleccionat\n      title: Estats del compte\n      with_media: Amb contingut multimèdia\n    subscriptions:\n      callback_url: URL de retorn\n      confirmed: Confirmat\n      expires_in: Expira en\n      last_delivery: Últim lliurament\n      title: WebSub\n      topic: Tema\n    tags:\n      accounts: Comptes\n      hidden: Amagat\n      hide: Ocult del directori\n      name: Etiqueta\n      title: Etiquetes\n      unhide: Mostra en el directori\n      visible: Visible\n    title: Administració\n    warning_presets:\n      add_new: Afegir nou\n      delete: Esborra\n      edit: Edita\n      edit_preset: Edita l'avís predeterminat\n      title: Gestiona les configuracions predefinides dels avisos\n  admin_mailer:\n    new_pending_account:\n      body: A continuació trobaràs els detalls del compte nou. Pots aprovar o rebutjar aquest registre.\n      subject: Nou compte per a revisar a %{instance} (%{username})\n    new_report:\n      body: \"%{reporter} ha informat de %{target}\"\n      body_remote: Algú des de el domini %{domain} ha informat sobre %{target}\n      subject: Informe nou per a %{instance} (#%{id})\n  appearance:\n    advanced_web_interface: Interfície web avançada\n    advanced_web_interface_hint: 'Si vols fer ús de tota l''amplada de la teva pantalla, l''interfície web avançada et permet configurar diverses columnes per a veure molta més informació al mateix temps: Inici, notificacions, línia de temps federada i qualsevol número de llistes i etiquetes.'\n    animations_and_accessibility: Animacions i accessibilitat\n    confirmation_dialogs: Diàlegs de confirmació\n    sensitive_content: Contingut sensible\n  application_mailer:\n    notification_preferences: Canvia les preferències de correu\n    salutation: \"%{name},\"\n    settings: 'Canvia les preferències de correu: %{link}'\n    view: 'Visualització:'\n    view_profile: Mostra el perfil\n    view_status: Mostra l'estat\n  applications:\n    created: L'aplicació s'ha creat correctament\n    destroyed: L'aplicació s'ha suprimit correctament\n    invalid_url: L'URL proporcionat no és correcte\n    regenerate_token: Torna a generar l'identificador d'accés\n    token_regenerated: L'identificador d'accés s'ha generat correctament\n    warning: Aneu amb compte amb aquestes dades. No les compartiu mai amb ningú!\n    your_token: El teu identificador d'accés\n  auth:\n    apply_for_account: Demana una invitació\n    change_password: Contrasenya\n    checkbox_agreement_html: Estic d'acord amb les <a href=\"%{rules_path}\" target=\"_blank\">normes del servidor</a> i <a href=\"%{terms_path}\" target=\"_blank\"> els termes del servei</a>\n    confirm_email: Confirmar correu electrònic\n    delete_account: Suprimeix el compte\n    delete_account_html: Si vols suprimir el compte pots <a href=\"%{path}\">fer-ho aquí</a>. Se't demanarà confirmació.\n    didnt_get_confirmation: No has rebut el correu de confirmació?\n    forgot_password: Has oblidat la contrasenya?\n    invalid_reset_password_token: L'enllaç de restabliment de la contrasenya no és vàlid o ha caducat. Torna-ho a provar.\n    login: Inicia sessió\n    logout: Tanca sessió\n    migrate_account: Mou a un compte diferent\n    migrate_account_html: Si vols redirigir aquest compte a un altre diferent, el pots <a href=\"%{path}\">configurar aquí</a>.\n    or_log_in_with: O inicia sessió amb\n    providers:\n      cas: CAS\n      saml: SAML\n    register: Registre\n    registration_closed: \"%{instance} no accepta nous membres\"\n    resend_confirmation: Torna a enviar el correu de confirmació\n    reset_password: Restableix la contrasenya\n    security: Seguretat\n    set_new_password: Estableix una contrasenya nova\n    trouble_logging_in: Problemes per iniciar la sessió?\n  authorize_follow:\n    already_following: Ja estàs seguint aquest compte\n    error: Malauradament, ha ocorregut un error cercant el compte remot\n    follow: Segueix\n    follow_request: 'Has enviat una sol·licitud de seguiment a:'\n    following: 'Perfecte! Ara segueixes:'\n    post_follow:\n      close: O bé, pots tancar aquesta finestra.\n      return: Mostra el perfil de l'usuari\n      web: Vés a la web\n    title: Segueix %{acct}\n  datetime:\n    distance_in_words:\n      about_x_hours: \"%{count} h\"\n      about_x_months: \"%{count} mesos\"\n      about_x_years: \"%{count} anys\"\n      almost_x_years: \"%{count}anys\"\n      half_a_minute: Ara mateix\n      less_than_x_minutes: fa %{count} minuts\n      less_than_x_seconds: Ara mateix\n      over_x_years: \"%{count} anys\"\n      x_days: \"%{count} dies\"\n      x_minutes: \"%{count} min\"\n      x_months: \"%{count} mesos\"\n      x_seconds: \"%{count} s\"\n  deletes:\n    bad_password_msg: Bon intent hackers! La contrasenya no és correcta\n    confirm_password: Introdueix la contrasenya actual per a verificar la identitat\n    description_html: Això eliminarà de forma <strong>irreversible i permanent</strong> el contingut del teu compte i el desactivarà. El teu nom d'usuari romandrà reservat per evitar que algú volgués fer-se passar per tu.\n    proceed: Suprimeix el compte\n    success_msg: El compte s'ha eliminat correctament\n    warning_html: Només és garantida l'eliminació del contingut d'aquest servidor en particular. El contingut que s'ha compartit àmpliament deixa petjades. Els servidors fora de línia i els que ja no estan subscrits no actualitzaran les seves bases de dades.\n    warning_title: Disponibilitat de contingut disseminat\n  directories:\n    directory: Directori de perfils\n    enabled: Actualment estàs inclòs al directori.\n    enabled_but_waiting: Has optat per aparèixer al directori però encara no tens el nombre mínim de seguidors (%{min_followers}) per ser-hi.\n    explanation: Descobreix usuaris segons els seus interessos\n    explore_mastodon: Explora %{title}\n    how_to_enable: Actualment no tens activat ser al directori. Pots optar-hi a continuació. Utilitza etiquetes en el teu text bio per incloure't sota etiquetes especifiques!\n    people:\n      one: \"%{count} persona\"\n      other: \"%{count} gent\"\n  errors:\n    '403': No tens permís per a veure aquesta pàgina.\n    '404': La pàgina que estàs cercant no és aquí.\n    '410': La pàgina que estàs cercant ja no existeix.\n    '422':\n      content: La verificació de seguretat ha fallat. Tens les galetes blocades?\n      title: La verificació de seguretat ha fallat\n    '429': Estrangulat\n    '500':\n      content: Ho sentim, però alguna cosa ha fallat a la nostra banda.\n      title: Aquesta pàgina no es correcta\n    noscript_html: Per a utilitzar Mastodon, activa el JavaScript. També pots provar una de les <a href=\"%{apps_path}\"> aplicacions natives</a> de Mastodon per a la vostra plataforma.\n  existing_username_validator:\n    not_found: no s'ha pogut trobar cap usuari local amb aquest nom d'usuari\n    not_found_multiple: no s'ha pogut trobar %{usernames}\n  exports:\n    archive_takeout:\n      date: Data\n      download: Descarrega l’arxiu\n      hint_html: Pots sol·licitar un arxiu dels teus <strong>toots i dels fitxers multimèdia pujats</strong>. Les dades exportades tindran el format ActivityPub, llegible per qualsevol programari compatible. Pots sol·licitar un arxiu cada 7 dies.\n      in_progress: Compilant el teu arxiu...\n      request: Sol·licita el teu arxiu\n      size: Tamany\n    blocks: Persones que has blocat\n    csv: CSV\n    domain_blocks: Bloquejos de dominis\n    follows: Persones que segueixes\n    lists: Llistes\n    mutes: Persones silenciades\n    storage: Emmagatzematge\n  featured_tags:\n    add_new: Afegir nova\n    errors:\n      limit: Ja has mostrat la quantitat màxima d'etiquetes\n  filters:\n    contexts:\n      home: Línia de temps Inici\n      notifications: Notificacions\n      public: Línies de temps públiques\n      thread: Converses\n    edit:\n      title: Editar filtre\n    errors:\n      invalid_context: Cap o el context proporcionat no és vàlid\n      invalid_irreversible: El filtratge irreversible només funciona amb el contextos inici o notificacions\n    index:\n      delete: Esborra\n      title: Filtres\n    new:\n      title: Afegir nou filtre\n  footer:\n    developers: Desenvolupadors\n    more: Més…\n    resources: Recursos\n  generic:\n    all: Tot\n    changes_saved_msg: Els canvis s'han desat correctament!\n    copy: Copia\n    order_by: Ordena per\n    save_changes: Desa els canvis\n    validation_errors:\n      one: Alguna cosa no va bé! Si us plau, revisa l'error\n      other: Alguna cosa no va bé! Si us plau, revisa %{count} errors més a baix\n  html_validator:\n    invalid_markup: 'conté HTML markup no vàlid: %{error}'\n  identity_proofs:\n    active: Actiu\n    authorize: Sí, autoritza\n    authorize_connection_prompt: Autoritzar aquesta connexió criptogràfica?\n    errors:\n      failed: Ha fallat la connexió criptogràfica. Torna-ho a provar des de %{provider}.\n      keybase:\n        invalid_token: Els tokens de Keybase són hashs de signatures i han de tenir 66 caràcters hexadecimals\n        verification_failed: Keybase no reconeix aquest token com a signatura del usuari de Keybase %{kb_username}. Si us plau prova des de Keybase.\n      wrong_user: No es pot crear una prova per a %{proving} mentre es connectava com a %{current}. Inicia sessió com a %{proving} i prova de nou.\n    explanation_html: Aquí pots connectar criptogràficament les teves altres identitats com ara el teu perfil de Keybase. Això permet que altres persones t'envïin missatges xifrats i confiar en el contingut que els hi envies.\n    i_am_html: Sóc %{username} a %{service}.\n    identity: Identitat\n    inactive: Inactiu\n    publicize_checkbox: 'I tooteja això:'\n    publicize_toot: 'Està provat! Sóc %{username} a %{service}: %{url}'\n    status: Estat de verificació\n    view_proof: Veure la prova\n  imports:\n    modes:\n      merge: Fusionar\n      merge_long: Mantenir els registres existents i afegir-ne de nous\n      overwrite: Sobreescriu\n      overwrite_long: Reemplaça els registres actuals amb els nous\n    preface: Pots importar algunes les dades que has exportat des d'un altre servidor, com ara el llistat de les persones que estàs seguint o bloquejant.\n    success: Les dades s'han rebut correctament i es processaran en breu\n    types:\n      blocking: Llista de blocats\n      domain_blocking: Llistat de dominis bloquejats\n      following: Llista de seguits\n      muting: Llista de silenciats\n    upload: Carregar\n  in_memoriam_html: En Memòria.\n  invites:\n    delete: Desactivar\n    expired: Caducat\n    expires_in:\n      '1800': 30 minuts\n      '21600': 6 hores\n      '3600': 1 hora\n      '43200': 12 hores\n      '604800': 1 setmana\n      '86400': 1 dia\n    expires_in_prompt: Mai\n    generate: Genera\n    invited_by: 'Has estat invitat per:'\n    max_uses:\n      one: 1 ús\n      other: \"%{count} usos\"\n    max_uses_prompt: Sense limit\n    prompt: Genera i comparteix enllaços amb altres persones per donar accés a aquest servidor\n    table:\n      expires_at: Caduca\n      uses: Usos\n    title: Convida persones\n  lists:\n    errors:\n      limit: Has assolit la quantitat màxima de llistes\n  media_attachments:\n    validations:\n      images_and_video: No es pot adjuntar un vídeo a una publicació que ja contingui imatges\n      too_many: No es poden adjuntar més de 4 fitxers\n  migrations:\n    acct: usuari@domini del nou compte\n    currently_redirecting: 'El teu perfil està configurat com a redirecció a:'\n    proceed: Desa\n    updated_msg: La configuració de la migració del compte s'ha actualitzat correctament!\n  moderation:\n    title: Moderació\n  notification_mailer:\n    digest:\n      action: Veure totes les notificacions\n      body: Un resum del que et vas perdre desde la darrera visita el %{since}\n      mention: \"%{name} t'ha mencionat en:\"\n      new_followers_summary:\n        one: A més, has adquirit un nou seguidor durant la teva absència! Visca!\n        other: A més, has adquirit %{count} nous seguidors mentre estaves fora! Increïble!\n      subject:\n        one: \"1 notificació nova des de la darrera visita \\U0001F418\"\n        other: \"%{count} notificacions noves des de la darrera visita \\U0001F418\"\n      title: Durant la teva absència…\n    favourite:\n      body: \"%{name} ha marcat com a favorit el teu estat:\"\n      subject: \"%{name} ha marcat com a favorit el teu estat\"\n      title: Favorit nou\n    follow:\n      body: \"%{name} t'està seguint!\"\n      subject: \"%{name} t'està seguint\"\n      title: Seguidor nou\n    follow_request:\n      action: Gestiona les sol·licituds de seguiment\n      body: \"%{name} ha sol·licitat seguir-te\"\n      subject: 'Seguidor pendent: %{name}'\n      title: Nova sol·licitud de seguiment\n    mention:\n      action: Respon\n      body: \"%{name} t'ha mencionat en:\"\n      subject: \"%{name} t'ha mencionat\"\n      title: Menció nova\n    reblog:\n      body: \"%{name} ha impulsat el teu estat:\"\n      subject: \"%{name} ha impulsat el teu estat\"\n      title: Nou impuls\n  number:\n    human:\n      decimal_units:\n        format: \"%n%u\"\n        units:\n          billion: B\n          million: M\n          quadrillion: Q\n          thousand: m\n          trillion: T\n  pagination:\n    newer: Més recent\n    next: Endavant\n    older: Més vell\n    prev: Enrere\n    truncate: \"&hellip;\"\n  polls:\n    errors:\n      already_voted: Ja has votat en aquesta enquesta\n      duplicate_options: conté opcions duplicades\n      duration_too_long: està massa lluny en el futur\n      duration_too_short: és massa aviat\n      expired: L'enquesta ja ha finalitzat\n      over_character_limit: no pot ser superior a %{max} caràcters cadascun\n      too_few_options: ha de tenir més d'una opció\n      too_many_options: no pot contenir més de %{max} opcions\n  preferences:\n    other: Altre\n    posting_defaults: Valors predeterminats de publicació\n    public_timelines: Línies de temps públiques\n  relationships:\n    activity: Activitat del compte\n    dormant: Inactiu\n    last_active: Darrer actiu\n    most_recent: Més recent\n    moved: Mogut\n    mutual: Mútua\n    primary: Primari\n    relationship: Relació\n    remove_selected_domains: Elimina tots els seguidors dels dominis seleccionats\n    remove_selected_followers: Elimina els seguidors seleccionats\n    remove_selected_follows: Deixa de seguir als usuaris seleccionats\n    status: Estat del compte\n  remote_follow:\n    acct: Escriu el teu usuari@domini des del qual vols seguir\n    missing_resource: No s'ha pogut trobar la URL de redirecció necessaria per al compte\n    no_account_html: No tens cap compte? Pots <a href='%{sign_up_path}' target='_blank'>registrar-te aquí</a>\n    proceed: Comença a seguir\n    prompt: 'Seguiràs a:'\n    reason_html: \"<strong>Per què és necessari aquest pas?</strong> <code>%{instance}</code> pot ser que no sigui el servidor on estàs registrat per tant primer hem de redirigir-te al teu servidor.\"\n  remote_interaction:\n    favourite:\n      proceed: Procedir a afavorir\n      prompt: 'Vols marcar com a favorit aquest toot:'\n    reblog:\n      proceed: Procedir a impulsar\n      prompt: 'Vols impulsar aquest toot:'\n    reply:\n      proceed: Procedir a respondre\n      prompt: 'Vols respondre a aquest toot:'\n  remote_unfollow:\n    error: Error\n    title: Títol\n    unfollowed: Sense seguir\n  scheduled_statuses:\n    over_daily_limit: Has superat el límit de %{limit} toots programats per a aquell dia\n    over_total_limit: Has superat el limit de %{limit} toots programats\n    too_soon: La data programada ha de ser futura\n  sessions:\n    activity: Última activitat\n    browser: Navegador\n    browsers:\n      alipay: Alipay\n      blackberry: Blackberry\n      chrome: Chrome\n      edge: Microsoft Edge\n      electron: Electron\n      firefox: Firefox\n      generic: Navegador desconegut\n      ie: Internet Explorer\n      micro_messenger: MicroMessenger\n      nokia: Nokia S40 Ovi Browser\n      opera: Opera\n      otter: Otter\n      phantom_js: PhantomJS\n      qq: QQ Browser\n      safari: Safari\n      uc_browser: UCBrowser\n      weibo: Weibo\n    current_session: Sessió actual\n    description: \"%{browser} de %{platform}\"\n    explanation: Aquests són els navegadors web que actualment han iniciat la sessió amb el teu compte de Mastodon.\n    ip: IP\n    platforms:\n      adobe_air: Adobe Air\n      android: Android\n      blackberry: Blackberry\n      chrome_os: ChromeOS\n      firefox_os: Firefox OS\n      ios: iOS\n      linux: Linux\n      mac: Mac\n      other: plataforma desconeguda\n      windows: Windows\n      windows_mobile: Windows Mobile\n      windows_phone: Windows Phone\n    revoke: Revoca\n    revoke_success: S'ha revocat la sessió amb èxit\n    title: Sessions\n  settings:\n    account: Compte\n    account_settings: Ajustos del compte\n    appearance: Aparènça\n    authorized_apps: Aplicacions autoritzades\n    back: Torna a Mastodon\n    delete: Eliminació del compte\n    development: Desenvolupament\n    edit_profile: Editar perfil\n    export: Exportar dades\n    featured_tags: Etiquetes destacades\n    identity_proofs: Proves d'identitat\n    import: Importar\n    import_and_export: Importar i exportar\n    migrate: Migració del compte\n    notifications: Notificacions\n    preferences: Preferències\n    profile: Perfil\n    relationships: Seguits i seguidors\n    two_factor_authentication: Autenticació de dos factors\n  statuses:\n    attached:\n      description: 'Adjunt: %{attached}'\n      image:\n        one: \"%{count} imatge\"\n        other: \"%{count} imatges\"\n      video:\n        one: \"%{count} vídeo\"\n        other: \"%{count} vídeos\"\n    boosted_from_html: Impulsat des de %{acct_link}\n    content_warning: 'Avís de contingut: %{warning}'\n    disallowed_hashtags:\n      one: 'conté una etiqueta no permesa: %{tags}'\n      other: 'conté les etiquetes no permeses: %{tags}'\n    language_detection: Detecta automàticament el llenguatge\n    open_in_web: Obre en la web\n    over_character_limit: Límit de caràcters de %{max} superat\n    pin_errors:\n      limit: Ja has fixat el màxim nombre de toots\n      ownership: No es pot fixar el toot d'algú altre\n      private: No es pot fixar el toot no públic\n      reblog: No es pot fixar un impuls\n    poll:\n      total_votes:\n        one: \"%{count} vot\"\n        other: \"%{count} vots\"\n      vote: Vota\n    show_more: Mostrar més\n    sign_in_to_participate: Inicia la sessió per participar a la conversa\n    title: '%{name}: \"%{quote}\"'\n    visibilities:\n      private: Només seguidors\n      private_long: Mostra només als seguidors\n      public: Públic\n      public_long: Tothom pot veure-ho\n      unlisted: No llistat\n      unlisted_long: Tothom ho pot veure, però no es mostra en la història federada\n  stream_entries:\n    pinned: Toot fixat\n    reblogged: ha impulsat\n    sensitive_content: Contingut sensible\n  terms:\n    body_html: |\n      <h2>Política de Privacitat</h2>\n      <h3 id=\"collect\">Quina informació recollim?</h3>\n\n      <ul>\n      <li><em>Informació bàsica del compte</em>: Si et registres en aquest servidor, se´t pot demanar que introdueixis un nom d'usuari, una adreça de correu electrònic i una contrasenya. També pots introduir informació de perfil addicional, com ara un nom de visualització i una biografia, i carregar una imatge de perfil i de capçalera. El nom d'usuari, el nom de visualització, la biografia, la imatge de perfil i la imatge de capçalera sempre apareixen públicament.</li>\n      <li><em>Publicacions, seguiment i altra informació pública</em>: La llista de persones que segueixes s'enumeren públicament i el mateix passa amb els teus seguidors. Quan envies un missatge, la data i l'hora s'emmagatzemen, així com l'aplicació que va enviar el missatge. Els missatges poden contenir multimèdia, com ara imatges i vídeos. Els toots públics i no llistats estan disponibles públicament. En quan tinguis un toot en el teu perfil, aquest també és informació pública. Les teves entrades es lliuren als teus seguidors que en alguns casos significa que es lliuren a diferents servidors en els quals s'hi emmagatzemen còpies. Quan suprimeixes publicacions, també es lliuraran als teus seguidors. L'acció d'impulsar o marcar com a favorit una publicació sempre és pública.</li>\n      <li><em>Toots directes i per a només seguidors</em>: Totes les publicacions s'emmagatzemen i processen al servidor. Els toots per a només seguidors només es lliuren als teus seguidors i als usuaris que s'esmenten en ells i els toots directes només es lliuren als usuaris esmentats. En alguns casos, significa que es lliuren a diferents servidors i s'hi emmagatzemen còpies. Fem un esforç de bona fe per limitar l'accés a aquestes publicacions només a les persones autoritzades, però és possible que altres servidors no ho facin. Per tant, és important revisar els servidors als quals pertanyen els teus seguidors. Pots canviar la opció de aprovar o rebutjar els nous seguidors manualment a la configuració. <em>Tingues en compte que els operadors del servidor i qualsevol servidor receptor poden visualitzar aquests missatges</em> i els destinataris poden fer una captura de pantalla, copiar-los o tornar-los a compartir. <em>No comparteixis cap informació perillosa a Mastodon.</em></li>\n      <li><em>IPs i altres metadades</em>: Quan inicies sessió registrem l'adreça IP en que l'has iniciat, així com el nom de l'aplicació o navegador. Totes les sessions registrades estan disponibles per a la teva revisió i revocació a la configuració. L'última adreça IP utilitzada s'emmagatzema durant un màxim de 12 mesos. També podrem conservar els registres que inclouen l'adreça IP de cada sol·licitud al nostre servidor.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"use\">Per a què utilitzem la teva informació?</h3>\n\n      <p>Qualsevol de la informació que recopilem de tu es pot utilitzar de la manera següent:</p>\n\n      <ul>\n      <li>Per proporcionar la funcionalitat bàsica de Mastodon. Només pots interactuar amb el contingut d'altres persones i publicar el teu propi contingut quan hàgis iniciat la sessió. Per exemple, pots seguir altres persones per veure les publicacions combinades a la teva pròpia línia de temps personalitzada.</li>\n      <li>Per ajudar a la moderació de la comunitat, per exemple comparar la teva adreça IP amb altres conegudes per determinar l'evasió de prohibicions o altres infraccions.</li>\n      <li>L'adreça electrònica que ens proporciones pot utilitzar-se per enviar-te informació, notificacions sobre altres persones que interactuen amb el teu contingut o t'envien missatges, i per respondre a les consultes i / o altres sol·licituds o preguntes.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"protect\">Com protegim la teva informació</h3>\n\n      <p>Implementem diverses mesures per mantenir la seguretat quan introdueixes, envies o accedeixes a la teva informació personal. Entre altres mesures, la sessió del teu navegador així com el trànsit entre les teves aplicacions i l'API estan protegides amb SSL i la teva contrasenya es codifica utilitzant un algoritme de direcció única. Pots habilitar l'autenticació de dos factors per a garantir l'accés segur al teu compte.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"data-retention\">Quina és la nostra política de retenció de dades?</h3>\n\n      <p>Farem un esforç de bona fe per:</p>\n\n      <ul>\n      <li>Conservar els registres del servidor que continguin l'adreça IP de totes les sol·licituds que rebi, tenint em compte que aquests registres es mantenen no més de 90 dies.</li>\n      <li>Conservar les adreces IP associades als usuaris registrats no més de 12 mesos.</li>\n      </ul>\n\n      <p>Pots sol·licitar i descarregar un arxiu del teu contingut incloses les publicacions, els fitxers adjunts multimèdia, la imatge de perfil i la imatge de capçalera.</p>\n\n      <p>Pots eliminar el teu compte de forma irreversible en qualsevol moment.</p>\n\n      <hr class=\"spacer\"/>\n\n      <h3 id=\"cookies\">Utilitzem cookies?</h3>\n\n      <p>Sí. Les cookies són petits fitxers que un lloc o el proveïdor de serveis transfereix al disc dur del teu ordinador a través del navegador web (si ho permet). Aquestes galetes permeten al lloc reconèixer el teu navegador i, si tens un compte registrat, associar-lo al teu compte registrat.</p>\n\n      <p>Utilitzem cookies per entendre i guardar les teves preferències per a futures visites.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"disclose\">Revelem informació a terceres parts?</h3>\n\n      <p>No venem, comercialitzem ni transmetem a tercers la teva informació d'identificació personal. Això no inclou tercers de confiança que ens ajuden a operar el nostre lloc, a dur a terme el nostre servei o a servir-te, sempre que aquestes parts acceptin mantenir confidencial aquesta informació. També podem publicar la teva informació quan creiem que l'alliberament és apropiat per complir amb la llei, fer complir les polítiques del nostre lloc o protegir els nostres drets o altres drets, propietat o seguretat.</p>\n\n      <p>Els altres servidors de la teva xarxa poden descarregar contingut públic. Els teus toots públics i per a només seguidors es lliuren als servidors on resideixen els teus seguidors i els missatges directes s'envien als servidors dels destinataris, sempre que aquests seguidors o destinataris resideixin en un servidor diferent d'aquest.</p>\n\n      <p>Quan autoritzes una aplicació a utilitzar el teu compte, segons l'abast dels permisos que aprovis, pot accedir a la teva informació de perfil pública, a la teva llista de seguits, als teus seguidors, a les teves llistes, a totes les teves publicacions i als teus favorits. Les aplicacions mai no poden accedir a la teva adreça de correu electrònic o contrasenya.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"children\">Ús del lloc dels nens</h3>\n\n      <p>Si el servidor és a EU o EEA: el nostre lloc, productes i serveis estan dirigits a persones que tenen almenys 16 anys. Si tens menys de 16 anys, seguint els requisits del GDPR (<a href=\"https://ca.wikipedia.org/wiki/Reglament_General_de_Protecció_de_Dades\">Reglament General de Protecció de Dades</a>) no utilitzis aquest lloc.</p>\n\n      <p>Si aquest servidor es troba als EUA: el nostre lloc, productes i serveis estan dirigits a persones que tenen almenys 13 anys. Si tens menys de 13 anys, segons els requisits de COPPA (<a href=\"https://en.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act\">Children's Online Privacy Protection Act</a>) no utilitzis aquest lloc.</p>\n\n      <p>Els requisits legals poden ser diferents si aquest servidor està en una altra jurisdicció.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"changes\">Canvis a la nostra política de privacitat</h3>\n\n      <p>Si decidim canviar la nostra política de privadesa, publicarem aquests canvis en aquesta pàgina.</p>\n\n      <p>Aquest document és CC-BY-SA. Actualitzat per darrera vegada el 7 de Març del 2018.</p>\n\n      <p>Originalment adaptat des del <a href=\"https://github.com/discourse/discourse\">Discourse privacy policy</a>.</p>\n    title: \"%{instance} Condicions del servei i política de privadesa\"\n  themes:\n    contrast: Mastodon (Alt contrast)\n    default: Mastodon (Fosc)\n    mastodon-light: Mastodon (Clar)\n  time:\n    formats:\n      default: \"%b %d, %Y, %H:%M\"\n      month: \"%b %Y\"\n  two_factor_authentication:\n    code_hint: Introdueix el codi generat per l'aplicació autenticadora per a confirmar\n    description_html: Si habilites l'<strong>autenticació de dos factors</strong>, et caldrà tenir el teu telèfon, que generarà tokens per a que puguis iniciar sessió.\n    disable: Desactiva\n    enable: Activa\n    enabled: Autenticació de dos factors activada\n    enabled_success: Autenticació de dos factors activada correctament\n    generate_recovery_codes: Genera codis de recuperació\n    instructions_html: \"<strong>Escaneja aquest codi QR desde Google Authenticator o una aplicació similar del teu telèfon</strong>. Desde ara, aquesta aplicació generarà tokens que tens que ingresar quan volguis iniciar sessió.\"\n    lost_recovery_codes: Els codis de recuperació et permeten recuperar l'accés al teu compte si perds el telèfon. Si has perdut els codis de recuperació els pots tornar a generar aquí. Els codis de recuperació anteriors s'anul·laran.\n    manual_instructions: 'Si no pots escanejar el codi QR code i necessites introduir-lo manualment, aquí tens el secret en text pla:'\n    recovery_codes: Codis de recuperació de còpia de seguretat\n    recovery_codes_regenerated: Codis de recuperació regenerats amb èxit\n    recovery_instructions_html: Si mai perds l'accéss al teu telèfon pots utilitzar un dels codis de recuperació a continuació per a recuperar l'accés al teu compte. <strong>Cal mantenir els codis de recuperació en lloc segur</strong>. Per exemple, imprimint-los i guardar-los amb altres documents importants.\n    setup: Establir\n    wrong_code: El codi introduït no és vàlid! És correcta l'hora del servidor i del dispositiu?\n  user_mailer:\n    backup_ready:\n      explanation: Has sol·licitat una copia completa del teu compte Mastodon. Ara ja està a punt per descàrrega!\n      subject: El teu arxiu està preparat per a descàrrega\n      title: Recollida del arxiu\n    warning:\n      explanation:\n        disable: Mentre el teu compte estigui congelat les dades romandran intactes però no pots dur a terme cap acció fins que no estigui desbloquejat.\n        silence: Mentre el teu compte estigui limitat només les persones que ja et segueixen veuen les teves dades en aquest servidor i pots ser exclòs de diverses llistes públiques. No obstant això, d'altres encara poden seguir-te manualment.\n        suspend: El teu compte s'ha suspès i tots els teus toots i fitxers multimèdia penjats s'han eliminat irreversiblement d'aquest servidor i dels servidors on tenies seguidors.\n      review_server_policies: Revisa les polítiques del servidor\n      subject:\n        disable: S'ha congelat el teu compte %{acct}\n        none: Avís per a %{acct}\n        silence: El teu compte %{acct} ha estat limitat\n        suspend: S'ha suspès el teu compte %{acct}\n      title:\n        disable: Compte congelat\n        none: Avís\n        silence: Compte limitat\n        suspend: Compte suspès\n    welcome:\n      edit_profile_action: Configurar perfil\n      edit_profile_step: Pots personalitzar el teu perfil penjant un avatar, un encapçalament, canviant el teu nom de visualització i molt més. Si prefereixes revisar els seguidors nous abans de que et puguin seguir, pots blocar el teu compte.\n      explanation: Aquests són alguns consells per a començar\n      final_action: Comença a publicar\n      final_step: 'Comença a publicar! Fins i tot sense seguidors, els altres poden veure els teus missatges públics, per exemple, a la línia de temps local i a les etiquetes (\"hashtags\"). És possible que vulguis presentar-te amb l''etiqueta #introductions.'\n      full_handle: El teu nom d'usuari sencer\n      full_handle_hint: Això és el que has de dir als teus amics perquè puguin enviar-te missatges o seguir-te des d'un altre servidor.\n      review_preferences_action: Canviar preferències\n      review_preferences_step: Assegura't d'establir les teves preferències, com ara els correus electrònics que vols rebre o el nivell de privadesa per defecte que t'agradaria que tinguin les teves entrades. Si no tens malaltia de moviment, pots optar per habilitar la reproducció automàtica de GIF.\n      subject: Benvingut/da a Mastodon\n      tip_federated_timeline: La línia de temps federada és el cabal principal de la xarxa Mastodon. Però només inclou les persones a les quals els teus veïns estan subscrits, de manera que no està complet.\n      tip_following: Per defecte segueixes als administradors del servidor. Per trobar més persones interessants, consulta les línies de temps local i federada.\n      tip_local_timeline: La línia de temps local és la vista del flux de publicacions dels usuaris de %{instance}. Aquests usuaris són els teus veïns més propers!\n      tip_mobile_webapp: Si el teu navegador del mòbil t'ofereix afegir Mastodon a la teva pantalla d'inici, podràs rebre notificacions \"push\". Es comporta com una aplicació nativa en molts aspectes!\n      tips: Consells\n      title: Benvingut a bord, %{name}!\n  users:\n    follow_limit_reached: No pots seguir més de %{limit} persones\n    invalid_email: L'adreça de correu no és correcta\n    invalid_otp_token: El codi de dos factors no és correcte\n    otp_lost_help_html: Si has perdut l'accés a tots dos pots contactar per %{email}\n    seamless_external_login: Has iniciat sessió via un servei extern per tant els ajustos de contrasenya i correu electrònic no estan disponibles.\n    signed_in_as: 'Sessió iniciada com a:'\n  verification:\n    explanation_html: 'Pots <strong>verificar-te com a propietari dels enllaços a les metadades del teu perfil</strong>. Per això, el lloc web enllaçat ha de contenir un enllaç al teu perfil de Mastodon. El vincle <strong>ha de</strong> tenir l''atribut <code>rel=\"me\"</code>. El contingut del text de l''enllaç no importa. Aquí tens un exemple:'\n    verification: Verificació\n"
  },
  {
    "path": "config/locales/co.yml",
    "content": "---\nco:\n  about:\n    about_hashtag_html: Quessi sò statuti pubblichi taggati cù <strong>#%{hashtag}</strong>. Pudete interagisce cù elli sì voi avete un contu in qualche parte di u fediverse.\n    about_mastodon_html: Mastodon ghjè una rete suciale custruita incù prutucolli web aperti è lugiziali liberi. Hè decentralizatu cumu l’e-mail.\n    about_this: À prupositu\n    active_count_after: attivi\n    active_footnote: Utilizatori Attivi Mensili (UAM)\n    administered_by: 'Amministratu da:'\n    api: API\n    apps: Applicazione per u telefuninu\n    apps_platforms: Utilizà Mastodon dapoi à iOS, Android è altre piattaforme\n    browse_directory: Navigà un'annuariu di i prufili è filtra per interessi\n    browse_public_posts: Navigà un flussu di i statuti publichi nant'à Mastodon\n    contact: Cuntattu\n    contact_missing: Mancante\n    contact_unavailable: Micca dispunibule\n    discover_users: Scopre utilizatori\n    documentation: Ducumentazione\n    extended_description_html: |\n      <h3>Una bona piazza per e regule</h3>\n      <p>A descrizzione stesa ùn hè micca stata riempiuta.</p>\n    federation_hint_html: Cù un contu nant'à %{instance} puderete siguità ghjente da tutti i servori Mastodon è ancu più d'altri.\n    generic_description: \"%{domain} hè un servore di a rete\"\n    get_apps: Pruvà un'applicazione di telefuninu\n    hosted_on: Mastodon allughjatu nant’à %{domain}\n    learn_more: Amparà di più\n    privacy_policy: Pulitica di vita privata\n    see_whats_happening: Vede cio chì si passa\n    server_stats: 'Statistiche di u servore:'\n    source_code: Codice di fonte\n    status_count_after:\n      one: statutu\n      other: statuti\n    status_count_before: chì anu pubblicatu\n    tagline: Siguità amichi è scopre ancu di più altri\n    terms: Cundizione di u serviziu\n    user_count_after:\n      one: utilizatore\n      other: utilizatori\n    user_count_before: Ci sò\n    what_is_mastodon: Quale hè Mastodon?\n  accounts:\n    choices_html: \"%{name} ricumanda:\"\n    follow: Siguità\n    followers:\n      one: Abbunatu·a\n      other: Abbunati\n    following: Abbunamenti\n    joined: Quì dapoi %{date}\n    last_active: ultima attività\n    link_verified_on: A pruprietà d'issu ligame hè stata verificata u %{date}\n    media: Media\n    moved_html: \"%{name} hà cambiatu di contu, avà hè nant’à %{new_profile_link}:\"\n    network_hidden: St'infurmazione ùn hè micca dispunibule\n    nothing_here: Ùn c’hè nunda quì!\n    people_followed_by: Seguitati da %{name}\n    people_who_follow: Seguitanu %{name}\n    pin_errors:\n      following: Duvete digià siguità a persona che vulete ricumandà\n    posts:\n      one: Statutu\n      other: Statuti\n    posts_tab_heading: Statuti\n    posts_with_replies: Statuti è risposte\n    reserved_username: Stu cugnome hè riservatu\n    roles:\n      admin: Amministratore\n      bot: Bot\n      moderator: Muderatore\n    unavailable: Prufile micca dispunibule\n    unfollow: Ùn siguità più\n  admin:\n    account_actions:\n      action: Realizà un'azzione\n      title: Realizà un'azzione di muderazione nant'à %{acct}\n    account_moderation_notes:\n      create: Creà\n      created_msg: Nota di muderazione creata!\n      delete: Toglie\n      destroyed_msg: Nota di muderazione sguassata!\n    accounts:\n      approve: Appruvà\n      approve_all: Appruvà tuttu\n      are_you_sure: Site sicuru·a?\n      avatar: Ritrattu di prufile\n      by_domain: Duminiu\n      change_email:\n        changed_msg: Email di u contu cambiatu!\n        current_email: E-mail attuale\n        label: Mudificà l’e-mail\n        new_email: Novu e-mail\n        submit: Cambià l'e-mail\n        title: Mudificà l’e-mail di %{username}\n      confirm: Cunfirmà\n      confirmed: Cunfirmata\n      confirming: Cunfirmazione\n      deleted: Sguassatu\n      demote: Ritrugradà\n      disable: Disattivà\n      disable_two_factor_authentication: Disattivà l’identificazione à 2 fattori\n      disabled: Disattivatu\n      display_name: Nome pubblicu\n      domain: Duminiu\n      edit: Mudificà\n      email: E-mail\n      email_status: Statutu di l’e-mail\n      enable: Attivà\n      enabled: Attivatu\n      feed_url: URL di u flussu\n      followers: Abbunati\n      followers_url: URL di l’abbunati\n      follows: Abbunamenti\n      header: Intistatura\n      inbox_url: URL di l’inbox\n      invited_by: Invitatu da\n      ip: IP\n      joined: Ghjuntu\n      location:\n        all: Tutti\n        local: Lucale\n        remote: D’altrò\n        title: Lucalizazione\n      login_status: Statutu di cunnessione\n      media_attachments: Media aghjunti\n      memorialize: Trasfurmà in mimuriale\n      moderation:\n        active: Attivu\n        all: Tutti\n        pending: In attesa\n        silenced: Silenzati\n        suspended: Suspesi\n        title: Muderazione\n      moderation_notes: Note di muderazione\n      most_recent_activity: Attività più ricente\n      most_recent_ip: IP più ricente\n      no_account_selected: Nisun contu hè statu cambiatu postu ch'ùn c'eranu micca selezziunati\n      no_limits_imposed: Nisuna limita imposta\n      not_subscribed: Micca abbunatu\n      outbox_url: URL di l’outbox\n      pending: In attesa di rivista\n      perform_full_suspension: Suspende\n      profile_url: URL di u prufile\n      promote: Prumove\n      protocol: Prutucollu\n      public: Pubblicu\n      push_subscription_expires: Spirata di l’abbunamentu PuSH\n      redownload: Mette à ghjornu u prufile\n      reject: Righjittà\n      reject_all: Righjittà tutti\n      remove_avatar: Toglie l’avatar\n      remove_header: Toglie l'intistatura\n      resend_confirmation:\n        already_confirmed: St’utilizatore hè digià cunfirmatu\n        send: Rimandà un’e-mail di cunfirmazione\n        success: L’e-mail di cunfirmazione hè statu mandatu!\n      reset: Riinizializà\n      reset_password: Riinizializà a chjave d’accessu\n      resubscribe: Riabbunassi\n      role: Auturizazione\n      roles:\n        admin: Amministratore\n        moderator: Muderatore\n        staff: Squadra\n        user: Utilizatore\n      salmon_url: URL di Salmon\n      search: Cercà\n      shared_inbox_url: URL di l’inbox spartuta\n      show:\n        created_reports: Signalamenti fatti\n        targeted_reports: Signalatu da l'altri\n      silence: Silenzà\n      silenced: Silenzatu\n      statuses: Statuti\n      subscribe: Abbunassi\n      suspended: Suspesu\n      time_in_queue: 'Attesa in fila: %{time}'\n      title: Conti\n      unconfirmed_email: E-mail micca cunfirmatu\n      undo_silenced: Ùn silenzà più\n      undo_suspension: Ùn suspende più\n      unsubscribe: Disabbunassi\n      username: Cugnome\n      warn: Averte\n      web: Web\n    action_logs:\n      actions:\n        assigned_to_self_report: \"%{name} s’hè assignatu u signalamentu %{target}\"\n        change_email_user: \"%{name} hà cambiatu l’indirizzu e-mail di %{target}\"\n        confirm_user: \"%{name} hà cunfirmatu l’indirizzu e-mail di %{target}\"\n        create_account_warning: \"%{name} hà mandatu un'avertimentu à %{target}\"\n        create_custom_emoji: \"%{name} hà caricatu una nov’emoji %{target}\"\n        create_domain_block: \"%{name} hà bluccatu u duminiu %{target}\"\n        create_email_domain_block: \"%{name} hà messu u duminiu e-mail %{target} nant’a lista nera\"\n        demote_user: \"%{name} hà ritrugradatu l’utilizatore %{target}\"\n        destroy_custom_emoji: \"%{name} hà sguassatu l'emoji %{target}\"\n        destroy_domain_block: \"%{name} hà sbluccatu u duminiu %{target}\"\n        destroy_email_domain_block: \"%{name} hà messu u duminiu e-mail %{target} nant’a lista bianca\"\n        destroy_status: \"%{name} hà toltu u statutu di %{target}\"\n        disable_2fa_user: \"%{name} hà disattivatu l’identificazione à dui fattori per %{target}\"\n        disable_custom_emoji: \"%{name} hà disattivatu l’emoji %{target}\"\n        disable_user: \"%{name} hà disattivatu a cunnessione per %{target}\"\n        enable_custom_emoji: \"%{name} hà attivatu l’emoji %{target}\"\n        enable_user: \"%{name} hà attivatu a cunnessione per %{target}\"\n        memorialize_account: \"%{name} hà trasfurmatu u contu di %{target} in una pagina mimuriale\"\n        promote_user: \"%{name} hà prumossu %{target}\"\n        remove_avatar_user: \"%{name} hà toltu u ritrattu di %{target}\"\n        reopen_report: \"%{name} hà riapertu u signalamentu %{target}\"\n        reset_password_user: \"%{name} hà riinizializatu a chjave d’accessu di %{target}\"\n        resolve_report: \"%{name} hà chjosu u signalamentu %{target}\"\n        silence_account: \"%{name} hà silenzatu u contu di %{target}\"\n        suspend_account: \"%{name} hà suspesu u contu di %{target}\"\n        unassigned_report: \"%{name} hà disassignatu u signalamentu %{target}\"\n        unsilence_account: \"%{name} hà fattu che u contu di %{target} ùn hè più silenzatu\"\n        unsuspend_account: \"%{name} hà fattu che u contu di %{target} ùn hè più suspesu\"\n        update_custom_emoji: \"%{name} hà messu à ghjornu l’emoji %{target}\"\n        update_status: \"%{name} hà cambiatu u statutu di %{target}\"\n      deleted_status: \"(statutu sguassatu)\"\n      title: Ghjurnale d’audit\n    custom_emojis:\n      by_domain: Duminiu\n      copied_msg: Copia lucale di l’emoji creata\n      copy: Cupià\n      copy_failed_msg: Ùn s’hè micca pussutu creà una copia di l’emoji\n      created_msg: L’emoji hè stata creata!\n      delete: Toglie\n      destroyed_msg: L’emoji hè stata tolta!\n      disable: Disattivà\n      disabled_msg: L’emoji hè stata disattivata\n      emoji: Emoji\n      enable: Attivà\n      enabled_msg: L’emoji hè stata attivata\n      image_hint: PNG di 50Ko o menu\n      listed: Listata\n      new:\n        title: Aghjustà una nov’emoji\n      overwrite: Soprascrive\n      shortcode: Accorta\n      shortcode_hint: 2 caratteri o più, solu lettere, numeri è liniette basse\n      title: Emoji parsunalizate\n      unlisted: Micca listata\n      update_failed_msg: Ùn s’hè micca pussutu mette à ghjornu l’emoji\n      updated_msg: L’emoji hè stata messa à ghjornu!\n      upload: Caricà\n    dashboard:\n      backlog: travagli in attesa\n      config: Cunfigurazione\n      feature_deletions: Sguassamenti di conti\n      feature_invites: Ligami d'invitazione\n      feature_profile_directory: Annuariu di i prufili\n      feature_registrations: Arregistramenti\n      feature_relay: Ripetitore di federazione\n      feature_timeline_preview: Vista di a linea pubblica\n      features: Funziunalità\n      hidden_service: Federazione cù servizii piattati\n      open_reports: signalamenti aperti\n      recent_users: Utilizatori ricenti\n      search: Ricerca di testu sanu\n      single_user_mode: Modu utilizatore unicu\n      software: Lugiziale\n      space: Usu di u spaziu\n      title: Quatru di strumenti\n      total_users: utilizatori in tutale\n      trends: Tindenze\n      week_interactions: interazzione sta settimana\n      week_users_active: attivi sta settimana\n      week_users_new: utilizatori sta settimana\n    domain_blocks:\n      add_new: Aghjustà novu blucchime di duminiu\n      created_msg: U blucchime di u duminiu hè attivu\n      destroyed_msg: U blucchime di u duminiu ùn hè più attivu\n      domain: Duminiu\n      existing_domain_block_html: Avete digià impostu limite più strette nant'à %{name}, duvete <a href=\"%{unblock_url}\">sbluccallu</a> primu.\n      new:\n        create: Creà un blucchime\n        hint: U blucchime di duminiu ùn impedirà micca a creazione di conti indè a database, mà metudi di muderazione specifiche saranu applicati.\n        severity:\n          desc_html: Cù <strong>Silenzà</strong>, solu l’abbunati di u contu viderenu i so missaghji. <strong>Suspende</strong> sguassarà tutti i cuntenuti è dati di u contu. Utilizate <strong>Nisuna</strong> s’è voi vulete solu righjittà fugliali media.\n          noop: Nisuna\n          silence: Silenzà\n          suspend: Suspende\n        title: Novu blucchime di duminiu\n      reject_media: Righjittà i fugliali media\n      reject_media_hint: Sguassa tutti i media caricati è ricusa caricamenti futuri. Inutile per una suspensione\n      reject_reports: Righjittà i rapporti\n      reject_reports_hint: Ignurà tutti i signalamenti chì venenu d'issu duminiu. Senz'oghjettu pè e suspensione\n      rejecting_media: righjettu di i fugliali media\n      rejecting_reports: righjettu di i signalamenti\n      severity:\n        silence: silenzatu\n        suspend: suspesu\n      show:\n        affected_accounts:\n          one: Un contu tuccatu indè a database\n          other: \"%{count} conti tuccati indè a database\"\n        retroactive:\n          silence: Ùn silenzà più i conti affettati di stu duminiu\n          suspend: Ùn suspende più i conti affettati di stu duminiu\n        title: Ùn bluccà più u duminiu %{domain}\n        undo: Annullà\n      undo: Annullà u blucchime di duminiu\n    email_domain_blocks:\n      add_new: Aghjustà\n      created_msg: U blucchime di u duminiu d’e-mail hè attivu\n      delete: Toglie\n      destroyed_msg: U blucchime di u duminiu d’e-mail ùn hè più attivu\n      domain: Duminiu\n      new:\n        create: Creà un blucchime\n        title: Nova iscrizzione nant’a lista nera e-mail\n      title: Lista nera e-mail\n    followers:\n      back_to_account: Rivene à u Contu\n      title: Abbunati à %{acct}\n    instances:\n      by_domain: Duminiu\n      delivery_available: Rimessa dispunibule\n      known_accounts:\n        one: \"%{count} contu cunnisciutu\"\n        other: \"%{count} conti cunnisciuti\"\n      moderation:\n        all: Tuttu\n        limited: Limitatu\n        title: Muderazione\n      title: Federazione\n      total_blocked_by_us: Bluccati da noi\n      total_followed_by_them: Siguitati da elli\n      total_followed_by_us: Siguitati da noi\n      total_reported: Rapporti nant'à elli\n      total_storage: Media aghjunti\n    invites:\n      deactivate_all: Disattivà tuttu\n      filter:\n        all: Tuttu\n        available: Dispunibuli\n        expired: Spirati\n        title: Filtrà\n      title: Invitazione\n    pending_accounts:\n      title: Conti in attesa (%{count})\n    relays:\n      add_new: Aghjustà un ripetitore\n      delete: Sguassà\n      description_html: Un <strong>ripetitore di federazione</strong> ghjè un servore intermediariu chì manda statuti pubblichi trà l'istanze abbunate. <strong>Pò aiutà l'istanze chjuche è mezane à scuprì u cuntinutu di u fediverse</strong> senza chì l'utilizatori appianu bisognu di seguità tutti i conti di l'altri servori.\n      disable: Disattivà\n      disabled: Disattivatu\n      enable: Attivà\n      enable_hint: Quandu sarà attivatu, u vostru servore hà da seguità i statuti pubblichi di u ripetitore, è mandarà i so statuti pubblichi quallà.\n      enabled: Attivatu\n      inbox_url: URL di u ripetitore\n      pending: In attesa di l'apprubazione di u ripetitore\n      save_and_enable: Salvà è attivà\n      setup: Creà una cunnessione cù un ripetitore\n      status: Statutu\n      title: Ripetitori\n    report_notes:\n      created_msg: Nota di signalamentu creata!\n      destroyed_msg: Nota di signalamentu sguassata!\n    reports:\n      account:\n        note: nota\n        report: palisà\n      action_taken_by: Intervenzione di\n      are_you_sure: Site sicuru·a?\n      assign_to_self: Assignallu à mè\n      assigned: Muderatore assignatu\n      comment:\n        none: Nisunu\n      created_at: Palisatu\n      mark_as_resolved: Indicà cum’è chjosu\n      mark_as_unresolved: Indicà cum’è sempre apertu\n      notes:\n        create: Aghjunghje una nota\n        create_and_resolve: Chjude cù una nota\n        create_and_unresolve: Riapre cù una nota\n        delete: Toglie\n        placeholder: Per parlà di l’azzione pigliate, o altre messe à ghjornu nant’à u signalamentu…\n      reopen: Riapre u signalamentu\n      report: 'Signalamente #%{id}'\n      reported_account: Contu palisatu\n      reported_by: Palisatu da\n      resolved: Scioltu è chjosu\n      resolved_msg: Signalamentu scioltu!\n      status: Statutu\n      title: Signalamenti\n      unassign: Disassignà\n      unresolved: Micca sciolti\n      updated_at: Messi à ghjornu\n    settings:\n      activity_api_enabled:\n        desc_html: Numeri di statuti creati quì, utilizatori attivi, è arregistramenti novi tutte e settimane\n        title: Pubblicà statistiche nant’à l’attività di l’utilizatori\n      bootstrap_timeline_accounts:\n        desc_html: Cugnomi separati cù virgule. Solu pussibule cù conti lucali è pubblichi. Quandu a lista hè viota, tutti l’amministratori lucali saranu selezziunati.\n        title: Abbunamenti predefiniti per l’utilizatori novi\n      contact_information:\n        email: E-mail prufissiunale\n        username: Identificatore di cuntattu\n      custom_css:\n        desc_html: Mudificà l'apparenza cù CSS caricatu nant'à ogni pagina\n        title: CSS persunalizatu\n      hero:\n        desc_html: Affissatu nant’a pagina d’accolta. Ricumandemu almenu 600x100px. S’ellu ùn hè micca definiti, a vignetta di u servore sarà usata\n        title: Ritrattu di cuprendula\n      mascot:\n        desc_html: Affissata nant'à parechje pagine. Almenu 293x205px ricumandatu. S'ella hè lasciata viota, a mascotta predefinita sarà utilizata\n        title: Ritrattu di a mascotta\n      peers_api_enabled:\n        desc_html: Indirizzi web stu servore hà vistu indè u fediverse\n        title: Pubblicà a lista di servori cunnisciuti\n      preview_sensitive_media:\n        desc_html: E priviste di i ligami nant'à l'altri siti mustreranu una vignetta ancu s'ellu hè marcatu cum'è sensibile u media\n        title: Vede media sensibili in e viste OpenGraph\n      profile_directory:\n        desc_html: Auturizà a scuperta di l'utilizatori\n        title: Attivà l'annuariu di i prufili\n      registrations:\n        closed_message:\n          desc_html: Affissatu nant’a pagina d’accolta quandu l’arregistramenti sò chjosi. Pudete fà usu di u furmattu HTML\n          title: Missaghju per l’arregistramenti chjosi\n        deletion:\n          desc_html: Auturizà tuttu u mondu à sguassà u so propiu contu\n          title: Auturizà à sguassà i conti\n        min_invite_role:\n          disabled: Nisunu\n          title: Auturizà l’invitazione da\n      registrations_mode:\n        modes:\n          approved: Apprubazione necessaria per arregistrassi\n          none: Nimu ùn pò arregistrassi\n          open: Tutt'ognunu pò arregistrassi\n        title: Modu d'arregistramenti\n      show_known_fediverse_at_about_page:\n        desc_html: Quandu ghjè selezziunatu, statuti di tuttu l’istanze cunnisciute saranu affissati indè a vista di e linee. Altrimente soli i statuti lucali saranu mustrati.\n        title: Vedde tuttu u fediverse cunnisciutu nant’a vista di e linee\n      show_staff_badge:\n        desc_html: Mustrerà un badge Squadra nant’à un prufile d’utilizatore\n        title: Mustrà un badge staff\n      site_description:\n        desc_html: Paragrafu di prisentazione nant’a pagina d’accolta. Parlate di cio chì rende stu servore speziale, o d'altre cose impurtante. Pudete fà usu di marchi HTML, in particulare <code>&lt;a&gt;</code> è <code>&lt;em&gt;</code>.\n        title: Discrizzione di u servore\n      site_description_extended:\n        desc_html: Una bona piazza per e regule, infurmazione è altre cose chì l’utilizatori duverìanu sapè. Pudete fà usu di marchi HTML\n        title: Discrizzione stesa di u situ\n      site_short_description:\n        desc_html: Mustratu indè a barra laterala è i tag meta. Spiegate quale hè Mastodon è ciò chì rende u vostru servore speciale in un paragrafu. S'ella hè lasciata viota, a discrizzione di u servore sarà utilizata.\n        title: Descrizzione corta di u servore\n      site_terms:\n        desc_html: Quì pudete scrive e vostre regule di cunfidenzialità, cundizione d’usu o altre menzione legale. Pudete fà usu di marchi HTML\n        title: Termini persunalizati\n      site_title: Nome di u servore\n      thumbnail:\n        desc_html: Utilizatu per viste cù OpenGraph è l’API. Ricumandemu 1200x630px\n        title: Vignetta di u servore\n      timeline_preview:\n        desc_html: Vede a linea pubblica nant’a pagina d’accolta\n        title: Vista di e linee\n      title: Parametri di u situ\n    statuses:\n      back_to_account: Ritornu à a pagina di u contu\n      batch:\n        delete: Toglie\n        nsfw_off: Indicà cum’è micca sensibile\n        nsfw_on: Indicà cum’è sensibile\n      failed_to_execute: Esecuzione impussibule\n      media:\n        title: Media\n      no_media: Nisun media\n      no_status_selected: I statuti ùn sò micca stati mudificati perchè manc'unu era selezziunatu\n      title: Statutu di u contu\n      with_media: Cù media\n    subscriptions:\n      callback_url: URL di richjama\n      confirmed: Cunfirmatu\n      expires_in: Spira in\n      last_delivery: Ultima arricata\n      title: WebSub\n      topic: Sughjettu\n    tags:\n      accounts: Conti\n      hidden: Piattatu\n      hide: Piattà di l'annuariu\n      name: Hashtag\n      title: Hashtag\n      unhide: Mustrà in l'annuariu\n      visible: Visibile\n    title: Amministrazione\n    warning_presets:\n      add_new: Aghjustà nova\n      delete: Sguassà\n      edit: Cambià\n      edit_preset: Cambià a preselezzione d'avertimentu\n      title: Amministrà e preselezzione d'avertimentu\n  admin_mailer:\n    new_pending_account:\n      body: I ditagli di u novu contu sò quì sottu. Pudete appruvà o righjittà a dumanda.\n      subject: Novu contu in attesa di rivista nant'à %{instance} (%{username})\n    new_report:\n      body: \"%{reporter} hà palisatu %{target}\"\n      body_remote: Qualch’unu da %{domain} hà palisatu %{target}\n      subject: Novu signalamentu nant’à %{instance} (#%{id})\n  appearance:\n    advanced_web_interface: Interfaccia web avanzata\n    advanced_web_interface_hint: 'S''è voi vulete fà usu di a larghezza sana di u vostru screnu, l''interfaccia web avanzata vi permette di cunfigurà parechje culonne sfarente per vede tutta l''infurmazione chì vulete vede in listessu tempu: Accolta, nutificazione, linea pubblica, è tutti l''hashtag è liste chì vulete.'\n    animations_and_accessibility: Animazione è accessibilità\n    confirmation_dialogs: Pop-up di cunfirmazione\n    sensitive_content: Cuntinutu sensibile\n  application_mailer:\n    notification_preferences: Cambià e priferenze e-mail\n    salutation: \"%{name},\"\n    settings: 'Cambià e priferenze e-mail: %{link}'\n    view: 'Vede:'\n    view_profile: Vede u prufile\n    view_status: Vede u statutu\n  applications:\n    created: Applicazione creata\n    destroyed: Applicazione sguassata\n    invalid_url: L’URL ch’è stata pruvista ùn hè valida\n    regenerate_token: Creà un’altra fiscia d’accessu\n    token_regenerated: A fiscia d’accessu hè stata rigenerata\n    warning: Abbadate à quessi dati. Ùn i date à nisunu!\n    your_token: Rigenerà a fiscia d’accessu\n  auth:\n    apply_for_account: Dumandà un'invitazione\n    change_password: Chjave d’accessu\n    checkbox_agreement_html: Sò d'accunsentu cù e <a href=\"%{rules_path}\" target=\"_blank\">regule di u servore</a> è i <a href=\"%{terms_path}\" target=\"_blank\">termini di u serviziu</a>\n    confirm_email: Cunfirmà l’e-mail\n    delete_account: Sguassà u contu\n    delete_account_html: S’è voi vulete toglie u vostru contu <a href=\"%{path}\">ghjè quì</a>. Duverete cunfirmà a vostra scelta.\n    didnt_get_confirmation: Ùn avete micca ricevutu l’istruzione di cunfirmazione?\n    forgot_password: Chjave scurdata?\n    invalid_reset_password_token: U ligame di riinizializazione di a chjave d’accessu hè spiratu o ùn hè micca validu. Pudete dumandà un'altru ligame.\n    login: Cunnettassi\n    logout: Scunnettassi\n    migrate_account: Cambià di contu\n    migrate_account_html: S’è voi vulete riindirizà stu contu versu un’altru, <a href=\"%{path}\">ghjè pussibule quì</a>.\n    or_log_in_with: O cunnettatevi cù\n    providers:\n      cas: CAS\n      saml: SAML\n    register: Arregistrassi\n    registration_closed: \"%{instance} ùn accetta micca novi socii\"\n    resend_confirmation: Rimandà l’istruzzioni di cunfirmazione\n    reset_password: Cambià a chjave d’accessu\n    security: Sicurità\n    set_new_password: Creà una nova chjave d’accessu\n    trouble_logging_in: Difficultà per cunnettavi?\n  authorize_follow:\n    already_following: Site digià abbunatu·a à stu contu\n    error: Peccatu, c’hè statu un prublemu ricercandu u contu\n    follow: Siguità\n    follow_request: 'Avete dumandatu di siguità:'\n    following: 'Eccu! Avà seguitate:'\n    post_follow:\n      close: O pudete ancu chjude sta finestra.\n      return: Vede u prufile di l’utilizatore\n      web: Andà à l’interfaccia web\n    title: Siguità %{acct}\n  datetime:\n    distance_in_words:\n      about_x_hours: \"%{count}o\"\n      about_x_months: \"%{count}Me\"\n      about_x_years: \"%{count}A\"\n      almost_x_years: \"%{count}A\"\n      half_a_minute: Avà\n      less_than_x_minutes: \"%{count}m\"\n      less_than_x_seconds: Avà\n      over_x_years: \"%{count}A\"\n      x_days: \"%{count}ghj\"\n      x_minutes: \"%{count}m\"\n      x_months: \"%{count}Me\"\n      x_seconds: \"%{count}s\"\n  deletes:\n    bad_password_msg: È nò! Sta chjave ùn hè curretta\n    confirm_password: Entrate a vostra chjave d’accessu attuale per verificà a vostra identità\n    description_html: U contu sarà deattivatu è u cuntenutu sarà sguassatu di manera <strong>permanente è irreversibile</strong>. Ùn sarà micca pussibule piglià stu cugnome torna per evità l’impusture.\n    proceed: Sguassà u contu\n    success_msg: U vostru contu hè statu sguassatu\n    warning_html: Pudete esse sicuru·a solu chì u cuntenutu sarà sguassatu di stu servore. S’ellu hè statu spartutu in altrò, sarà forse sempre quallà. I servori scunettati è quelli ch'ùn sò più abbunati à e vostre pubblicazione ùn anu micca da mette à ghjornu e so database.\n    warning_title: Dispunibilità di i cuntenuti sparsi\n  directories:\n    directory: Annuariu di i prufili\n    enabled: Site inscrittu·a indè l'annuariu.\n    enabled_but_waiting: Avete sceltu d'esse inscrittu·a indè l'annuariu, mà ùn avete micca ancu u numeru minimale d'abbunati (%{min_followers}) per esse listatu·a.\n    explanation: Scopre utilizatori à partesi di i so centri d'interessu\n    explore_mastodon: Scopre à %{title}\n    how_to_enable: Ùn site micca ancu inscrittu·a indè l'annuariu. Pudete inscrive vi quì sottu. Utilizate qualchi hashtag indè a vostra biugrafia per esse listatu·a indè tag specifichi!\n    people:\n      one: \"%{count} persona\"\n      other: \"%{count} persone\"\n  errors:\n    '403': Ùn site micca auturizatu·a à vede sta pagina.\n    '404': Sta pagina ùn esiste micca quì.\n    '410': Sta pagina ùn esiste più quì.\n    '422':\n      content: C’hè statu un prublemu cù a verificazione di sicurità. Forse bluccate cookies?\n      title: Fiascu di verificazione\n    '429': Limitatu dop’à troppu richieste\n    '500':\n      content: Scusate, mà c’hè statu un prublemu cù u nostru servore.\n      title: Sta pagina ùn hè curretta\n    noscript_html: Mastodon nant’à u web hà bisognu di JavaScript per funziunà. Pudete ancu pruvà <a href=\"%{apps_path}\">l’applicazione native</a> per a vostra piattaforma.\n  existing_username_validator:\n    not_found: ùn si pudeva micca truvà un'utilizatore lucale cù stu cugnome\n    not_found_multiple: ùn si pudeva micca truvà %{usernames}\n  exports:\n    archive_takeout:\n      date: Data\n      download: Scaricà l’archiviu\n      hint_html: Pudete dumandà un’archiviu di i vostri <strong>statuti è media caricati</strong>. I dati saranu in u furmattu ActivityPub è pudarenu esse letti da tutti i lugiziali chì u supportanu. Pudete richiede un'archiviu ogni 7 ghjorni.\n      in_progress: Cumpilazione di l’archiviu...\n      request: Dumandà u vostr’archiviu\n      size: Pesu\n    blocks: Bluccate\n    csv: CSV\n    domain_blocks: Blucchime di duminiu\n    follows: Seguitate\n    lists: Liste\n    mutes: Piattate\n    storage: I vostri media\n  featured_tags:\n    add_new: Aghjustà novu\n    errors:\n      limit: Avete digià messu in mostra u numeru massimale di hashtag\n  filters:\n    contexts:\n      home: Accolta\n      notifications: Nutificazione\n      public: Linee pubbliche\n      thread: Cunversazione\n    edit:\n      title: Mudificà u filtru\n    errors:\n      invalid_context: Micca abbastanza cuntestu\n      invalid_irreversible: A filtrazione irreversibile marchja solu per l'accolta è e nutificazione\n    index:\n      delete: Toglie\n      title: Filtri\n    new:\n      title: Aghjustà un novu filtru\n  footer:\n    developers: Sviluppatori\n    more: Di più…\n    resources: Risorze\n  generic:\n    all: Tuttu\n    changes_saved_msg: Cambiamenti salvati!\n    copy: Cupià\n    order_by: Urdinà da\n    save_changes: Salvà e mudificazione\n    validation_errors:\n      one: Qualcosa ùn và bè! Verificate u prublemu quì sottu\n      other: Qualcosa ùn và bè! Verificate %{count} prublemi quì sottu\n  html_validator:\n    invalid_markup: 'cuntene codice HTML invalidu: %{error}'\n  identity_proofs:\n    active: Attiva\n    authorize: Ié, auturizà\n    authorize_connection_prompt: Auturizà sta cunnessione crittograffica?\n    errors:\n      failed: A cunnessione crittograffica s'hè fiascata. Ripruvate da %{provider}.\n      keybase:\n        invalid_token: E fiscie Keybase sò hash di firme è duvenu fà 66 caratteri esadecimali (0-9 A-F)\n        verification_failed: Keybase ùn ricunosce micca sta fiscia cum'una firma di l'utilizatore Keybase %{kb_username}. Ripruvate da Keybase.\n      wrong_user: Ùn si pò micca creà una prova per %{proving} mentre chì site cunnettatu·a cum'è %{current}. Cunnettatevi cum'è %{proving} è ripruvate.\n    explanation_html: Quì pudete cunnettà crittografficamente e vostre altre identità, cum'è per esempiu un prufile Keybase. Quessu permette à d'altre persone di mandà vi missaghji crittati, è d'affiducià i cuntinuti chì mandate.\n    i_am_html: Sò %{username} nant'à %{service}.\n    identity: Identità\n    inactive: Inattiva\n    publicize_checkbox: 'È mandà stu statutu:'\n    publicize_toot: 'Hè pruvata! Sò %{username} nant’à %{service}: %{url}'\n    status: Statutu di a verificazione\n    view_proof: Vede a prova\n  imports:\n    modes:\n      merge: Unisce\n      merge_long: Cunservà i dati esistenti è aghjustà i novi\n      overwrite: Soprascrive\n      overwrite_long: Rimpiazzà i dati esistenti cù i novi\n    preface: Pudete impurtà certi dati, cumu e persone chì seguitate o bluccate nant’à u vostru contu, nant’à stu servore à partesi di fugliali creati nant’à un’altru.\n    success: I vostri dati sò stati impurtati è saranu trattati da quì à pocu\n    types:\n      blocking: Persone chì bluccate\n      domain_blocking: Lista di blucchimi di duminiu\n      following: Persone chì seguitate\n      muting: Persone chì piattate\n    upload: Impurtà\n  in_memoriam_html: In mimoria.\n  invites:\n    delete: Disattivà\n    expired: Spirata\n    expires_in:\n      '1800': 30 minuti\n      '21600': 6 ore\n      '3600': 1 ora\n      '43200': 12 ore\n      '604800': 1 settimana\n      '86400': 1 ghjornu\n    expires_in_prompt: Mai\n    generate: Creà\n    invited_by: 'Site statu·a invitatu·a da:'\n    max_uses:\n      one: 1 usu\n      other: \"%{count} usi\"\n    max_uses_prompt: Micca limita\n    prompt: Create è spartete ligami cù altre parsone per dà accessu à u servore\n    table:\n      expires_at: Spira\n      uses: Utiliza\n    title: Invità ghjente\n  lists:\n    errors:\n      limit: Ùn pudete più creà altre liste\n  media_attachments:\n    validations:\n      images_and_video: Ùn si pò micca aghjunghje un filmettu à un statutu chì hà digià ritratti\n      too_many: Ùn si pò micca aghjunghje più di 4 fugliali\n  migrations:\n    acct: cugnome@duminiu di u novu contu\n    currently_redirecting: 'U vostru prufile riindiriza tuttu versu à:'\n    proceed: Salvà\n    updated_msg: I paramettri di migrazione sò stati messi à ghjornu!\n  moderation:\n    title: Muderazione\n  notification_mailer:\n    digest:\n      action: Vede tutte e nutificazione\n      body: Eccu cio ch’avete mancatu dapoi à a vostr’ultima visita u %{since}\n      mention: \"%{name} v’hà mintuvatu·a in:\"\n      new_followers_summary:\n        one: Avete ancu un’abbunatu novu!\n        other: Avete ancu %{count} abbunati novi!\n      subject:\n        one: \"Una nutificazione nova dapoi à a vostr’ultima visita \\U0001F418\"\n        other: \"%{count} nutificazione nove dapoi à a vostr’ultima visita \\U0001F418\"\n      title: Dapoi l’ultima volta…\n    favourite:\n      body: \"%{name} hà aghjuntu u vostru statutu à i so favuriti :\"\n      subject: \"%{name} hà messu u vostru post in i so favuriti\"\n      title: Novu favuritu\n    follow:\n      body: \"%{name} s’hè abbunatu à u vostru contu !\"\n      subject: \"%{name} vi seguita\"\n      title: Abbunatu novu\n    follow_request:\n      action: Vede e dumande d’abbunamentu\n      body: \"%{name} vole abbunassi à u vostru contu\"\n      subject: 'Dumanda d’abbunamentu: %{name}'\n      title: Nova dumanda d’abbunamentu\n    mention:\n      action: Risposta\n      body: \"%{name} v’hà mintuvatu·a indè :\"\n      subject: \"%{name} v’hà mintuvatu·a\"\n      title: Nova menzione\n    reblog:\n      body: 'U vostru statutu hè statu spartutu da %{name}:'\n      subject: \"%{name} hà spartutu u vostru statutu\"\n      title: Nova spartera\n  number:\n    human:\n      decimal_units:\n        format: \"%n%u\"\n        units:\n          billion: G\n          million: M\n          quadrillion: P\n          thousand: K\n          trillion: T\n  pagination:\n    newer: Più ricente\n    next: Dopu\n    older: Più vechju\n    prev: Nanzu\n    truncate: \"&hellip;\"\n  polls:\n    errors:\n      already_voted: Avete digià vutatu nant'à stu scandagliu\n      duplicate_options: cuntene uzzione doppie\n      duration_too_long: hè troppu luntanu indè u futuru\n      duration_too_short: hè troppu prossimu\n      expired: U scandagliu hè digià finitu\n      over_character_limit: ùn ponu micca esse più longhi chè %{max} caratteri\n      too_few_options: deve avè più d'un'uzzione\n      too_many_options: ùn pò micca avè più di %{max} uzzione\n  preferences:\n    other: Altre\n    posting_defaults: Paramettri predefiniti\n    public_timelines: Linee pubbliche\n  relationships:\n    activity: Attività di u contu\n    dormant: Inattivu\n    last_active: Ultima attività\n    most_recent: Più ricente\n    moved: Spiazzatu\n    mutual: Mutuale\n    primary: Primariu\n    relationship: Rilazione\n    remove_selected_domains: Toglie tutti l'abbunati da i dumini selezziunati\n    remove_selected_followers: Toglie l'abbunati selezziunati\n    remove_selected_follows: Ùn siguità più l'utilizatori selezziunati\n    status: Statutu di u contu\n  remote_follow:\n    acct: Entrate u vostru cugnome@istanza da induve vulete siguità stu contu\n    missing_resource: Ùn avemu pussutu à truvà l’indirizzu di ridirezzione\n    no_account_html: Ùn avete micca un contu? Pudete <a href='%{sign_up_path}' target='_blank'>arregistravi quì</a>\n    proceed: Cuntinuà per siguità\n    prompt: 'Avete da siguità:'\n    reason_html: \"<strong>Perchè hè necessaria sta tappa?</strong> <code>%{instance}</code> ùn hè forse micca u servore induve site arregistratu·a, allora primu duvemu riindirizzavi à u vostru servore.\"\n  remote_interaction:\n    favourite:\n      proceed: Cuntinuà per favurisce\n      prompt: 'Vulete aghjustà stu statutu à i vostri favuriti:'\n    reblog:\n      proceed: Cuntinuà per sparte\n      prompt: 'Vulete sparte stu statutu:'\n    reply:\n      proceed: Cuntinuà per risponde\n      prompt: 'Vulete risponde à stu statutu:'\n  remote_unfollow:\n    error: Errore\n    title: Titulu\n    unfollowed: Disabbunatu\n  scheduled_statuses:\n    over_daily_limit: Avete trapassatu a limita di %{limit} statuti planificati per stu ghjornu\n    over_total_limit: Avete trapassatu a limita di %{limit} statuti planificati\n    too_soon: A data deve esse indè u futuru\n  sessions:\n    activity: Ultima attività\n    browser: Navigatore\n    browsers:\n      alipay: Alipay\n      blackberry: Blackberry\n      chrome: Chrome\n      edge: Microsoft Edge\n      electron: Electron\n      firefox: Firefox\n      generic: Navigatore scunnisciutu\n      ie: Internet Explorer\n      micro_messenger: MicroMessenger\n      nokia: Nokia S40 Ovi Browser\n      opera: Opera\n      otter: Otter\n      phantom_js: PhantomJS\n      qq: QQ Browser\n      safari: Safari\n      uc_browser: UCBrowser\n      weibo: Weibo\n    current_session: Sessione attuale\n    description: \"%{browser} nant’à %{platform}\"\n    explanation: Quessi sò i navigatori cunnettati à u vostru contu Mastodon.\n    ip: IP\n    platforms:\n      adobe_air: Adobe Air\n      android: Android\n      blackberry: Blackberry\n      chrome_os: ChromeOS\n      firefox_os: Firefox OS\n      ios: iOS\n      linux: Linux\n      mac: Mac\n      other: piattaforma scunnisciuta\n      windows: Windows\n      windows_mobile: Windows Mobile\n      windows_phone: Windows Phone\n    revoke: Rivucà\n    revoke_success: Sessione rivucata\n    title: Sessioni\n  settings:\n    account: Contu\n    account_settings: Parametri di u contu\n    appearance: Apparenza\n    authorized_apps: Applicazione auturizate\n    back: Ritornu nant’à Mastodon\n    delete: Suppressione di u contu\n    development: Sviluppu\n    edit_profile: Mudificà u prufile\n    export: Spurtazione d’infurmazione\n    featured_tags: Hashtag in vista\n    identity_proofs: Prove d'identità\n    import: Impurtazione\n    import_and_export: Impurtazione è spurtazione\n    migrate: Migrazione di u contu\n    notifications: Nutificazione\n    preferences: Priferenze\n    profile: Prufile\n    relationships: Abbunamenti è abbunati\n    two_factor_authentication: Identificazione à dui fattori\n  statuses:\n    attached:\n      description: 'Aghjuntu: %{attached}'\n      image:\n        one: \"%{count} ritrattu\"\n        other: \"%{count} ritratti\"\n      video:\n        one: \"%{count} filmettu\"\n        other: \"%{count} filmetti\"\n    boosted_from_html: Spartutu dapoi à %{acct_link}\n    content_warning: 'Avertimentu: %{warning}'\n    disallowed_hashtags:\n      one: 'cuntene l’hashtag disattivatu: %{tags}'\n      other: 'cuntene l’hashtag disattivati: %{tags}'\n    language_detection: Truvà a lingua autumaticamente\n    open_in_web: Apre nant’à u web\n    over_character_limit: Site sopr’à a limita di %{max} caratteri\n    pin_errors:\n      limit: Avete digià puntarulatu u numeru massimale di statuti\n      ownership: Pudete puntarulà solu unu di i vostri propii statuti\n      private: Ùn pudete micca puntarulà un statutu ch’ùn hè micca pubblicu\n      reblog: Ùn pudete micca puntarulà una spartera\n    poll:\n      total_votes:\n        one: \"%{count} votu\"\n        other: \"%{count} voti\"\n      vote: Vutà\n    show_more: Vede di più\n    sign_in_to_participate: Cunnettatevi per participà à a cunversazione\n    title: '%{name}: \"%{quote}\"'\n    visibilities:\n      private: Solu per l’abbunati\n      private_long: Mustrà solu à l’abbunati\n      public: Pubblicu\n      public_long: Tuttu u mondu pò vede\n      unlisted: Micca listatu\n      unlisted_long: Tuttu u mondu pò vede, mà micca indè e linee pubbliche\n  stream_entries:\n    pinned: Statutu puntarulatu\n    reblogged: hà spartutu\n    sensitive_content: Cuntenutu sensibile\n  terms:\n    body_html: |\n      <h2>Politique de confidentialité</h2>\n      <h3 id=\"collect\">Quelles informations collectons-nous ?</h3>\n\n      <ul>\n      <li><em>Informations de base sur votre compte</em> : Si vous vous inscrivez sur ce serveur, il vous sera demandé de rentrer un identifiant, une adresse électronique et un mot de passe. Vous pourrez également ajouter des informations additionnelles sur votre profil, telles qu’un nom public et une biographie, ainsi que téléverser une image de profil et une image d’en-tête. Vos identifiant, nom public, biographie, image de profil et image d’en-tête seront toujours affichés publiquement.</li>\n      <li><em>Posts, liste d’abonnements et autres informations publiques</em> : La liste de vos abonnements ainsi que la liste de vos abonné·e·s sont publiques. Quand vous postez un message, la date et l’heure d’envoi ainsi que le nom de l’application utilisée pour sa transmission sont enregistré·e·s. Des médias, tels que des images ou des vidéos, peuvent être joints aux messages. Les posts publics et non listés sont affichés publiquement. Quand vous mettez en avant un post sur votre profil, ce post est également affiché publiquement. Vos messages sont délivrés à vos abonné·e·s, ce qui, dans certains cas, signifie qu’ils sont délivrés à des serveurs tiers et que ces derniers en stockent une copie. Quand vous supprimer un post, il est probable que vos abonné·e·s en soient informé·e·s. Partager un message ou le marquer comme favori est toujours une action publique.</li>\n      <li><em>Posts directs et abonné·e·s uniquement</em> : Tous les posts sont stockés et traités par le serveur. Les messages abonné·e·s uniquement ne sont transmis qu’à vos abonné·e·s et aux personnes mentionnées dans le corps du message, tandis que les messages directs ne sont transmis qu’aux personnes mentionnées. Dans certains cas, cela signifie qu’ils sont délivrés à des serveurs tiers et que ces derniers en stockent une copie. Nous faisons un effort de bonne fois pour en limiter l’accès uniquement aux personnes autorisées, mais ce n’est pas nécessairement le cas des autres serveurs. Il est donc très important que vous vérifiiez les serveurs auxquels appartiennent vos abonné·e·s. Il vous est possible d’activer une option dans les paramètres afin d’approuver et de rejeter manuellement les nouveaux·lles abonné·e·s. <em>Gardez s’il-vous-plaît en mémoire que les opérateur·rice·s du serveur ainsi que celles et ceux de n’importe quel serveur récepteur peuvent voir ces messages</em> et qu’il est possible pour les destinataires de faire des captures d’écran, de copier et plus généralement de repartager ces messages. <em>Ne partager aucune information sensible à l’aide de Mastodon.</em></li>\n      <li><em>IP et autres métadonnées</em> : Quand vous vous connectez, nous enregistrons votre adresse IP ainsi que le nom de votre navigateur web. Toutes les sessions enregistrées peuvent être consultées dans les paramètres, afin que vous puissiez les surveiller et éventuellement les révoquer. La dernière adresse IP utilisée est conservée pour une durée de 12 mois. Nous sommes également susceptibles de conserver les journaux du serveur, ce qui inclut l’adresse IP de chaque requête reçue.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"use\">Que faisons-nous des informations que nous collectons ?</h3>\n\n      <p>Toutes les informations que nous collectons sur vous peuvent être utilisées d’une des manières suivantes :</p>\n\n      <ul>\n      <li>Pour vous fournir les fonctionnalités de base de Mastodon. Vous ne pouvez interagir avec le contenu des autres et poster votre propre contenu que lorsque vous êtes connecté·e. Par exemple, vous pouvez vous abonner à plusieurs autres comptes pour voir l’ensemble de leurs posts dans votre fil d’accueil personnalisé.</li>\n      <li>Pour aider à la modération de la communauté, par exemple, comparer votre adresse IP à d’autres afin de déterminer si un bannissement a été contourné ou si une autre violation aux règles a été commise.</li>\n      <li>L’adresse électronique que vous nous avez fournie peut être utilisée pour vous envoyez des informations, des notifications lorsque d’autres personnes interagissent avec votre contenu ou vous envoient des messages, pour répondre à des demandes de votre part ainsi que pour tout autres requêtes ou questions.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"protect\">Comment protégeons-nous vos informations ?</h3>\n\n      <p>Nous mettons en œuvre une variété de mesures de sécurité afin de garantir la sécurité de vos informations personnelles quand vous les saisissez, les soumettez et les consultez. Entre autres choses, votre session de navigation ainsi que le trafic entre votre application et l’API sont sécurisés à l’aide de TLS tandis que votre mot de passe est haché en utilisant un puissant algorithme à sens unique. Vous pouvez également activer l’authentification à deux facteurs pour sécuriser encore plus l’accès à votre compte.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"data-retention\">Quelle est notre politique de conservation des données ?</h3>\n\n      <p>Nous ferons un effort de bonne foi :</p>\n\n      <ul>\n      <li>Pour ne pas conserver plus de 90 jours les journaux systèmes contenant les adresses IP de toutes les requêtes reçues par ce serveur.</li>\n      <li>Pour ne pas conserver plus de 12 mois les adresses IP associées aux utilisateur·ice·s enregistré·e·s.</li>\n      </ul>\n\n      <p>Vous pouvez demander une archive de votre contenu, incluant vos posts, vos médias joints, votre image de profil et votre image d’en-tête.</p>\n\n      <p>Vous pouvez, à n’importe quel moment, supprimer votre compte de manière définitive.</p>\n\n      <hr class=\"spacer\"/>\n\n      <h3 id=\"cookies\">Utilisons-nous des témoins de connexion ?</h3>\n\n      <p>Oui. Les témoins de connexion sont de petits fichiers qu’un site ou un service transféres sur le disque dur de votre ordinateur via votre navigateur web (si vous l’avez autorisé). Ces témoins permettent au site de reconnaître votre navigateur et de, dans le cas où vous possédez un compte, de vous associer avec ce dernier.</p>\n\n      <p>Nous utilisons les témoins de connexion comme un moyen de comprendre et de nous souvenir de vos préférences pour vos prochaines visites.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"disclose\">Divulguons-nous des informations à des tierces parties ?</h3>\n\n      <p>Nous ne vendons, n’échangeons ou ne transférons d’une quelque manière que soit des informations permettant de vous identifier personnellement. Cela n’inclut pas les tierces parties de confiance qui nous aident à opérer ce site, à conduire nos activités commerciales ou à vous servir, tant qu’elles acceptent de garder ces informations confidentielles. Nous sommes également susceptibles de partager vos informations quand nous pensons que c’est nécessaire pour nous conformer à la loi, pour appliquer les politiques de notre site ainsi que pour défendre nos droits, notre propriété, notre sécurité et celles et ceux d’autres personnes.</p>\n\n      <p>Votre contenu public peut être téléchargé par d’autres serveurs du réseau. Dans le cas où vos abonné·e·s et vos destinataires résideraient sur des serveurs différents du vôtre, vos posts publics et abonné·e·s uniquement peuvent être délivrés vers les serveurs de vos abonné·e·s tandis que vos messages directs sont délivrés aux serveurs de vos destinataires.</p>\n\n      <p>Quand vous autorisez une application à utiliser votre compte, en fonction de l’étendue des permissions que vous approuvez, il est possible qu’elle puisse accéder aux informations publiques de votre profil, votre liste d’abonnements, votre liste d’abonné·e·s, vos listes, tout vos posts et vos favoris. Les applications ne peuvent en aucun cas accéder à votre adresse électronique et à votre mot de passe.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"children\">Utilisation de ce site par les enfants</h3>\n\n      <p>Si ce serveur est situé dans dans l’UE ou l’EEE : Notre site, produits et services sont tous destinés à des personnes âgées de 16 ans ou plus. Si vous avez moins de 16 ans, en application du RGPD (<a href=\"https://fr.wikipedia.org/wiki/R%C3%A8glement_g%C3%A9n%C3%A9ral_sur_la_protection_des_donn%C3%A9es\">Règlement Général sur la Protection des Données</a>), merci de ne pas utiliser ce site.</p>\n\n      <p>Si ce serveur est situé dans aux États-Unis d’Amérique : Notre site, produits et services sont tous destinés à des personnes âgées de 13 ans ou plus. Si vous avez moins de 13 ans, en application du COPPA (<a href=\"https://fr.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act\">Children's Online Privacy Protection Act</a>), merci de ne pas utiliser ce site.</p>\n\n      <p>Les exigences légales peuvent être différentes si ce serveur se trouve dans une autre juridiction.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"changes\">Modifications de notre politique de confidentialité</h3>\n\n      <p>Dans le cas où nous déciderions de changer notre politique de confidentialité, nous posterons les modifications sur cette page.</p>\n\n      <p>Ce document est publié sous lincence CC-BY-SA. Il a été mis à jours pour la dernière fois le 7 mars 2018.</p>\n\n      <p>Originellement adapté de la <a href=\"https://github.com/discourse/discourse\">politique de confidentialité de Discourse</a>.</p>\n    title: Termini d’usu è di cunfidenzialità per %{instance}\n  themes:\n    contrast: Mastodon (Cuntrastu altu)\n    default: Mastodon (Scuru)\n    mastodon-light: Mastodon (Chjaru)\n  time:\n    formats:\n      default: \"%d %b %Y, %H:%M\"\n      month: \"%b %Y\"\n  two_factor_authentication:\n    code_hint: Entrate u codice generatu da l’applicazione per cunfirmà\n    description_html: S’ella hè attivata <strong>l’identificazione à dui fattori</strong>, duvete avè u vostru telefuninu pè ottene un codice di cunnezzione.\n    disable: Disattivà\n    enable: Attivà\n    enabled: Identificazione à dui fattori attivata\n    enabled_success: L’identificazione à dui fattori hè stata attivata\n    generate_recovery_codes: Creà codici di ricuperazione\n    instructions_html: \"<strong>Scanate stu QR code cù Google Authenticator, Authy o qualcosa cusì nant’à u vostru telefuninu</strong>. St’applicazione hà da creà codici da entrà ogni volta chì vi cunnettate.\"\n    lost_recovery_codes: I codici di ricuperazione à usu unicu vi permettenu di sempre avè accessu à u vostru contu s’è voi avete persu u vostru telefuninu. S’elli sò ancu persi, pudete creà codici novi quì. I vechji codici ùn marchjeranu più.\n    manual_instructions: 'S’ellu ùn hè micca pussibule scanà u QR code, pudete entre sta chjave sicreta:'\n    recovery_codes: Codici di ricuperazione\n    recovery_codes_regenerated: Codici di ricuperazione ricreati\n    recovery_instructions_html: Pudete fà usu di i codici quì sottu per sempre avè accessu à u vostru contu s’ellu hè statu persu u vostru telefuninu. <strong>Guardateli in una piazza sicura</strong>. Per esempiu, stampati è cunservati cù altri ducumenti impurtanti.\n    setup: Installà\n    wrong_code: U codice ùn hè micca currettu! Site sicuru che l’ora di u telefuninu è di u servore sò esatte?\n  user_mailer:\n    backup_ready:\n      explanation: Avete dumandatu un’archiviu cumpletu di u vostru contu Mastodon. Avà hè prontu per scaricà!\n      subject: U vostru archiviu hè prontu à scaricà\n      title: Archiviu prontu\n    warning:\n      explanation:\n        disable: Quandu u vostru contu hè ghjacciatu, i vostri dati stannu intatti, mà ùn pudete fà nunda fin'à ch'ellu sia sbluccatu.\n        silence: Quandu u vostru contu hè limitatu, solu quelli chì sò digià abbunati à u vostru contu viderenu i vostri statuti nant'à quessu servore, è puderete esse esclusu·a di parechje liste pubbliche. Però, altri conti puderenu sempre seguitavi.\n        suspend: U vostru contu hè statu suspesu, è tutti i vo statuti è fugliali media caricati sò stati sguassati di manera irreversibile di stu servore, è di i servori induve aviate abbunati.\n      review_server_policies: Leghje e pulitiche di u servore\n      subject:\n        disable: U vostru contu %{acct} hè statu ghjacciatu\n        none: Avertimentu pè %{acct}\n        silence: U vostru contu %{acct} hè statu limitatu\n        suspend: U vostru contu %{acct} hè statu suspesu\n      title:\n        disable: Contu ghjacciatu\n        none: Avertimentu\n        silence: Contu limitatu\n        suspend: Contu suspesu\n    welcome:\n      edit_profile_action: Cunfigurazione di u prufile\n      edit_profile_step: Pudete persunalizà u vostru prufile cù un ritrattu di prufile o di cuprendula, un nome pubblicu persunalizatu, etc. Pudete ancu rende u contu privatu per duvè cunfirmà ogni dumanda d’abbunamentu.\n      explanation: Eccu alcune idee per principià\n      final_action: Principià à pustà\n      final_step: 'Andemu! Ancu senza abbunati i vostri missaghji pubblichi puderanu esse visti da altre persone, per esempiu nant’a linea lucale è l’hashtag. Pudete ancu prisintavi nant’à u hashtag #introductions.'\n      full_handle: U vostru identificatore cumplettu\n      full_handle_hint: Quessu ghjè cio chì direte à i vostri amichi per circavi, abbunassi à u vostru contu da altrò, o mandà missaghji.\n      review_preferences_action: Mudificà e priferenze\n      review_preferences_step: Quì pudete adattà u cumpurtamentu di Mastodon à e vostre priferenze, cum’è l’email che vulete riceve, u nivellu di cunfidenzialità predefinitu di i vostri statuti, o u cumpurtamentu di i GIF animati.\n      subject: Benvenutu·a nant’à Mastodon\n      tip_federated_timeline: A linea pubblica glubale mostra i statuti da altre istanze nant’a rete Mastodon, mà ùn hè micca cumpleta perchè ci sò soli i conti à quelli sò abbunati membri di a vostr’istanza.\n      tip_following: Site digià abbunatu·a à l’amministratori di u vostru servore. Per truvà d’altre parsone da siguità, pudete pruvà e linee pubbliche.\n      tip_local_timeline: A linea pubblica lucale ghjè una vista crunulogica di i statuti di a ghjente nant’à %{instance}. Quessi sò i vostri cunvicini!\n      tip_mobile_webapp: Pudete aghjunghje Mastodon à a pagina d’accolta di u vostru navigatore di telefuninu per riceve nutificazione, cum’un applicazione!\n      tips: Cunsiglii\n      title: Benvenutu·a, %{name}!\n  users:\n    follow_limit_reached: Ùn pidete seguità più di %{limit} conti\n    invalid_email: L’indirizzu e-mail ùn hè currettu\n    invalid_otp_token: U codice d’identificazione ùn hè currettu\n    otp_lost_help_html: S’è voi avete persu i dui, pudete cuntattà %{email}\n    seamless_external_login: Site cunnettatu·a dapoi un serviziu esternu, allora i parametri di chjave d’accessu è d’indirizzu e-mail ùn so micca dispunibili.\n    signed_in_as: 'Cunnettatu·a cum’è:'\n  verification:\n    explanation_html: 'Pudete <strong>verificavi cum''è u pruprietariu di i ligami in i metadati di u vostru prufile</strong>. Per quessa, u vostru situ deve avè un ligame versu a vostra pagina Mastodon. U ligame <strong>deve</strong> avè un''attributu <code>rel=\"me\"</code>. U cuntenutu di u testu di u ligame ùn hè micca impurtante. Eccu un''esempiu:'\n    verification: Verificazione\n"
  },
  {
    "path": "config/locales/cs.yml",
    "content": "---\ncs:\n  about:\n    about_hashtag_html: Tohle jsou veřejné tooty označené hashtagem <strong>#%{hashtag}</strong>. Pokud máte účet kdekoliv ve fedivesmíru, můžete s nimi interagovat.\n    about_mastodon_html: Mastodon je sociální síť založená na otevřených webových protokolech a svobodném, otevřeném softwaru. Je decentralizovaná jako e-mail.\n    about_this: O tomto serveru\n    active_count_after: aktivních\n    active_footnote: Měsíční aktivní uživatelé (MAU)\n    administered_by: 'Server spravuje:'\n    api: API\n    apps: Mobilní aplikace\n    apps_platforms: Používejte Mastodon z iOS, Androidu a jiných platforem\n    browse_directory: Prozkoumejte adresář profilů a filtrujte dle zájmů\n    browse_public_posts: Prozkoumejte živý proud veřejných příspěvků na Mastodonu\n    contact: Kontakt\n    contact_missing: Nenastaveno\n    contact_unavailable: Neuvedeno\n    discover_users: Objevujte uživatele\n    documentation: Dokumentace\n    extended_description_html: |\n      <h3>Dobré místo pro pravidla</h3>\n      <p>Rozšířený popis ještě nebyl nastaven.</p>\n    federation_hint_html: S účtem na %{instance} můžete sledovat lidi na jakémkoliv serveru Mastodon a jiných službách.\n    generic_description: \"%{domain} je jedním ze serverů v síti\"\n    get_apps: Vyzkoušejte mobilní aplikaci\n    hosted_on: Mastodon na adrese %{domain}\n    learn_more: Zjistit více\n    privacy_policy: Zásady soukromí\n    see_whats_happening: Podívejte se, co se děje\n    server_stats: 'Statistika serveru:'\n    source_code: Zdrojový kód\n    status_count_after:\n      few: příspěvky\n      many: příspěvků\n      one: příspěvek\n      other: příspěvků\n    status_count_before: Kteří napsali\n    tagline: Sledujte své přátele a objevujte nové\n    terms: Podmínky používání\n    user_count_after:\n      few: uživatelé\n      many: uživatelů\n      one: uživatel\n      other: uživatelů\n    user_count_before: Domov\n    what_is_mastodon: Co je Mastodon?\n  accounts:\n    choices_html: 'Volby uživatele %{name}:'\n    follow: Sledovat\n    followers:\n      few: Sledující\n      many: Sledujících\n      one: Sledující\n      other: Sledujících\n    following: Sledovaných\n    joined: Připojil/a se v %{date}\n    last_active: naposledy aktivní\n    link_verified_on: Vlastnictví tohoto odkazu bylo zkontrolováno %{date}\n    media: Média\n    moved_html: \"%{name} se přesunul/a na %{new_profile_link}:\"\n    network_hidden: Tato informace není k dispozici\n    nothing_here: Tady nic není!\n    people_followed_by: Lidé, které sleduje %{name}\n    people_who_follow: Lidé, kteří sledují uživatele %{name}\n    pin_errors:\n      following: Musíte již sledovat osobu, kterou chcete podpořit\n    posts:\n      few: Tooty\n      many: Tootů\n      one: Toot\n      other: Tootů\n    posts_tab_heading: Tooty\n    posts_with_replies: Tooty a odpovědi\n    reserved_username: Toto uživatelské jméno je rezervováno\n    roles:\n      admin: Administrátor\n      bot: Robot\n      moderator: Moderátor\n    unavailable: Profil nedostupný\n    unfollow: Přestat sledovat\n  admin:\n    account_actions:\n      action: Vykonat akci\n      title: Vykonat moderátorskou akci pro účet %{acct}\n    account_moderation_notes:\n      create: Zanechat poznámku\n      created_msg: Moderátorská poznámka byla úspěšně vytvořena!\n      delete: Smazat\n      destroyed_msg: Moderátorská poznámka byla úspěšně zničena!\n    accounts:\n      approve: Schválit\n      approve_all: Schválit vše\n      are_you_sure: Jste si jistý/á?\n      avatar: Avatar\n      by_domain: Doména\n      change_email:\n        changed_msg: E-mail k tomuto účtu byl úspěšně změněn!\n        current_email: Současný e-mail\n        label: Změnit e-mail\n        new_email: Nový e-mail\n        submit: Změnit e-mail\n        title: Změnit e-mail uživateli %{username}\n      confirm: Potvrdit\n      confirmed: Potvrzeno\n      confirming: Potvrzuji\n      deleted: Smazáno\n      demote: Degradovat\n      disable: Zablokovat\n      disable_two_factor_authentication: Zakázat 2FA\n      disabled: Blokováno\n      display_name: Zobrazované jméno\n      domain: Doména\n      edit: Upravit\n      email: E-mail\n      email_status: Stav e-mailu\n      enable: Povolit\n      enabled: Povoleno\n      feed_url: URL proudu\n      followers: Sledující\n      followers_url: URL sledujících\n      follows: Sledovaní\n      header: Záhlaví\n      inbox_url: URL příchozí schránky\n      invited_by: Pozván/a uživatelem\n      ip: IP adresa\n      joined: Připojil/a se\n      location:\n        all: Všechny\n        local: Místní\n        remote: Vzdálené\n        title: Umístění\n      login_status: Stav přihlášení\n      media_attachments: Mediální přílohy\n      memorialize: Změnit na „in memoriam“\n      moderation:\n        active: Aktivní\n        all: Vše\n        pending: Čekající\n        silenced: Utišen/a\n        suspended: Pozastaven/a\n        title: Moderování\n      moderation_notes: Moderátorské poznámky\n      most_recent_activity: Nejnovější aktivita\n      most_recent_ip: Nejnovější IP\n      no_account_selected: Nebyl změněn žádný účet, neboť žádný nebyl zvolen\n      no_limits_imposed: Nejsou nastavena žádná omezení\n      not_subscribed: Neodebírá\n      outbox_url: URL odchozí schránky\n      pending: Čeká na posouzení\n      perform_full_suspension: Pozastavit\n      profile_url: URL profilu\n      promote: Povýšit\n      protocol: Protokol\n      public: Veřejný\n      push_subscription_expires: Odebírání PuSH expiruje\n      redownload: Obnovit profil\n      reject: Zamítnout\n      reject_all: Zamítnout vše\n      remove_avatar: Odstranit avatar\n      remove_header: Odstranit záhlaví\n      resend_confirmation:\n        already_confirmed: Tento uživatel je již potvrzen\n        send: Znovu odeslat potvrzovací e-mail\n        success: Potvrzovací e-mail byl úspěšně odeslán!\n      reset: Obnovit\n      reset_password: Obnovit heslo\n      resubscribe: Znovu odebírat\n      role: Oprávnění\n      roles:\n        admin: Administrátor\n        moderator: Moderátor\n        staff: Člen personálu\n        user: Uživatel\n      salmon_url: URL Salmon\n      search: Hledat\n      shared_inbox_url: URL sdílené příchozí schránky\n      show:\n        created_reports: Vytvořená nahlášení\n        targeted_reports: Nahlášeni ostatními\n      silence: Utišit\n      silenced: Utišen/a\n      statuses: Tooty\n      subscribe: Odebírat\n      suspended: Pozastaven/a\n      time_in_queue: Čeká ve frontě %{time}\n      title: Účty\n      unconfirmed_email: Nepotvrzený e-mail\n      undo_silenced: Zrušit utišení\n      undo_suspension: Zrušit pozastavení\n      unsubscribe: Přestat odebírat\n      username: Uživatelské jméno\n      warn: Varovat\n      web: Web\n    action_logs:\n      actions:\n        assigned_to_self_report: \"%{name} přidělil/a hlášení %{target} sobě\"\n        change_email_user: \"%{name} změnil/a e-mailovou adresu uživatele %{target}\"\n        confirm_user: \"%{name} potvrdil/a e-mailovou adresu uživatele %{target}\"\n        create_account_warning: \"%{name} poslal/a varování uživateli %{target}\"\n        create_custom_emoji: \"%{name} nahrál/a nové emoji %{target}\"\n        create_domain_block: \"%{name} zablokoval/a doménu %{target}\"\n        create_email_domain_block: \"%{name} přidal/a e-mailovou doménu %{target} na černou listinu\"\n        demote_user: \"%{name} degradoval/a uživatele %{target}\"\n        destroy_custom_emoji: \"%{name} zničil/a emoji %{target}\"\n        destroy_domain_block: \"%{name} odblokoval/a doménu %{target}\"\n        destroy_email_domain_block: \"%{name} odebral/a e-mailovou doménu %{target} z černé listiny\"\n        destroy_status: \"%{name} odstranil/a toot uživatele %{target}\"\n        disable_2fa_user: \"%{name} vypnul/a dvoufázové ověřování pro uživatele %{target}\"\n        disable_custom_emoji: \"%{name} zakázal/a emoji %{target}\"\n        disable_user: \"%{name} zakázal/a přihlašování pro uživatele %{target}\"\n        enable_custom_emoji: \"%{name} povolil/a emoji %{target}\"\n        enable_user: \"%{name} povolil/a přihlašování pro uživatele %{target}\"\n        memorialize_account: \"%{name} změnil/a účet %{target} na stránku „in memoriam“\"\n        promote_user: \"%{name} povýšil/a uživatele %{target}\"\n        remove_avatar_user: \"%{name} odstranil/a avatar uživatele %{target}\"\n        reopen_report: \"%{name} znovuotevřel/a nahlášení %{target}\"\n        reset_password_user: \"%{name} obnovil/a heslo uživatele %{target}\"\n        resolve_report: \"%{name} vyřešil/a nahlášení %{target}\"\n        silence_account: \"%{name} utišil/a účet uživatele %{target}\"\n        suspend_account: \"%{name} pozastavil/a účet uživatele %{target}\"\n        unassigned_report: \"%{name} odebral/a nahlášení %{target}\"\n        unsilence_account: \"%{name} odtišil/a účet uživatele %{target}\"\n        unsuspend_account: \"%{name} zrušil/a pozastavení účtu uživatele %{target}\"\n        update_custom_emoji: \"%{name} aktualizoval/a emoji %{target}\"\n        update_status: \"%{name} aktualizoval/a toot uživatele %{target}\"\n      deleted_status: \"(smazaný toot)\"\n      title: Záznam auditu\n    custom_emojis:\n      by_domain: Doména\n      copied_msg: Místní kopie emoji byla úspěšně vytvořena\n      copy: Kopírovat\n      copy_failed_msg: Nebylo možné vytvořit místní kopii tohoto emoji\n      created_msg: Emoji úspěšně vytvořeno!\n      delete: Smazat\n      destroyed_msg: Emoji úspěšně zničeno!\n      disable: Zakázat\n      disabled_msg: Emoji bylo úspěšně zakázáno\n      emoji: Emoji\n      enable: Povolit\n      enabled_msg: Emoji bylo úspěšně povoleno\n      image_hint: PNG až do 50 KB\n      listed: Uvedeno\n      new:\n        title: Přidat nové vlastní emoji\n      overwrite: Přepsat\n      shortcode: Zkratka\n      shortcode_hint: Alespoň 2 znaky, pouze alfanumerické znaky a podtržítka\n      title: Vlastní emoji\n      unlisted: Neuvedeno\n      update_failed_msg: Nebylo možné aktualizovat toto emoji\n      updated_msg: Emoji úspěšně aktualizováno!\n      upload: Nahrát\n    dashboard:\n      backlog: opožděné úlohy\n      config: Konfigurace\n      feature_deletions: Smazání účtů\n      feature_invites: Odkazy pozvánek\n      feature_profile_directory: Adresář profilů\n      feature_registrations: Registrace\n      feature_relay: Federovací most\n      feature_timeline_preview: Náhled časové osy\n      features: Vlastnosti\n      hidden_service: Federace se skrytými službami\n      open_reports: otevřená hlášení\n      recent_users: Nedávní uživatelé\n      search: Fulltextové vyhledávání\n      single_user_mode: Režim jednoho uživatele\n      software: Software\n      space: Využití prostoru\n      title: Přehled\n      total_users: uživatelů celkem\n      trends: Trendy\n      week_interactions: interakcí tento týden\n      week_users_active: aktivních tento týden\n      week_users_new: uživatelů tento týden\n    domain_blocks:\n      add_new: Přidat novou blokaci domény\n      created_msg: Blokace domény se právě vyřizuje\n      destroyed_msg: Blokace domény byla zrušena\n      domain: Doména\n      existing_domain_block_html: Pro účet %{name} jste již nastavil/a přísnější omezení, musíte jej nejdříve <a href=\"%{unblock_url}\">odblokovat</a>.\n      new:\n        create: Vytvořit blokaci\n        hint: Blokace domény nezakáže vytváření záznamů účtů v databázi, ale bude na tyto účty zpětně a automaticky aplikovat specifické metody moderování.\n        severity:\n          desc_html: Funkce <strong>Utišit</strong> zneviditelní příspěvky z účtu komukoliv, kdo jej nesleduje. Funkce <strong>Pozastavit</strong> odstraní všechen obsah, média a profilová data účtu. Pro pouhé odmítnutí mediálních souborů použijte funkci <strong>Žádné</strong>.\n          noop: Žádné\n          silence: Utišit\n          suspend: Pozastavit\n        title: Nová doménová blokace\n      reject_media: Odmítat mediální soubory\n      reject_media_hint: Odstraní lokálně uložené mediální soubory a odmítne jejich stahování v budoucnosti. Nepodstatné pro pozastavení\n      reject_reports: Odmítat nahlášení\n      reject_reports_hint: Ignorovat všechna nahlášení pocházející z této domény. Nepodstatné pro pozastavení\n      rejecting_media: odmítají se mediální soubory\n      rejecting_reports: odmítají se nahlášení\n      severity:\n        silence: utišeno\n        suspend: pozastaveno\n      show:\n        affected_accounts:\n          few: \"%{count} účty v databázi byly ovlivněny\"\n          many: \"%{count} účtů v databázi bylo ovlivněno\"\n          one: Jeden účet v databázi byl ovlivněn\n          other: \"%{count} účtů v databázi bylo ovlivněno\"\n        retroactive:\n          silence: Odtišit existující ovlivněné účty z této domény\n          suspend: Zrušit pozastavení existujících ovlivněných účtů z této domény\n        title: Zrušit blokaci domény %{domain}\n        undo: Odvolat\n      undo: Odvolat blokaci domény\n    email_domain_blocks:\n      add_new: Přidat nový\n      created_msg: E-mailová doména úspěšně přidána na černou listinu\n      delete: Smazat\n      destroyed_msg: E-mailová doména úspěšně odstraněna z černé listiny\n      domain: Doména\n      new:\n        create: Přidat doménu\n        title: Nová položka pro černou listinu e-mailů\n      title: Černá listina e-mailů\n    followers:\n      back_to_account: Zpět na účet\n      title: Sledující uživatele %{acct}\n    instances:\n      by_domain: Doména\n      delivery_available: Doručení je k dispozici\n      known_accounts:\n        few: \"%{count} známé účty\"\n        many: \"%{count} známých účtů\"\n        one: \"%{count} známý účet\"\n        other: \"%{count} známých účtů\"\n      moderation:\n        all: Všechny\n        limited: Omezené\n        title: Moderování\n      title: Federace\n      total_blocked_by_us: Blokované námi\n      total_followed_by_them: Sledované jimi\n      total_followed_by_us: Sledované námi\n      total_reported: Nahlášení o nich\n      total_storage: Mediální přílohy\n    invites:\n      deactivate_all: Deaktivovat vše\n      filter:\n        all: Všechny\n        available: Dostupné\n        expired: Vypršelé\n        title: Filtrovat\n      title: Pozvánky\n    pending_accounts:\n      title: Čekající účty (%{count})\n    relays:\n      add_new: Přidat nový most\n      delete: Smazat\n      description_html: \"<strong>Federovací most</strong> je přechodný server, který vyměňuje velká množství veřejných tootů mezi servery, které z něj odebírají a publikují na něj. <strong>Může pomoci malým a středně velkým serverům objevovat obsah z fedivesmíru</strong>, což by jinak vyžadovalo, aby místní uživatelé manuálně sledovali jiné lidi na vzdálených serverech.\"\n      disable: Zakázat\n      disabled: Zakázáno\n      enable: Povolit\n      enable_hint: Je-li tohle povoleno, začne váš server odebírat všechny veřejné tooty z tohoto mostu a odesílat na něj své vlastní veřejné tooty.\n      enabled: Povoleno\n      inbox_url: URL mostu\n      pending: Čekám na souhlas mostu\n      save_and_enable: Uložit a povolit\n      setup: Nastavit připojení k mostu\n      status: Stav\n      title: Mosty\n    report_notes:\n      created_msg: Poznámka o nahlášení úspěšně vytvořena!\n      destroyed_msg: Poznámka o nahlášení úspěšně smazána!\n    reports:\n      account:\n        note: poznámka\n        report: nahlášení\n      action_taken_by: Akci vykonal/a\n      are_you_sure: Jste si jistý/á?\n      assign_to_self: Přidělit ke mně\n      assigned: Přiřazený moderátor\n      comment:\n        none: Žádné\n      created_at: Nahlášené\n      mark_as_resolved: Označit jako vyřešené\n      mark_as_unresolved: Označit jako nevyřešené\n      notes:\n        create: Přidat poznámku\n        create_and_resolve: Vyřešit s poznámkou\n        create_and_unresolve: Znovu otevřít s poznámkou\n        delete: Smazat\n        placeholder: Popište, jaké akce byly vykonány, nebo jakékoliv jiné související aktuality…\n      reopen: Znovu otevřít nahlášení\n      report: 'Nahlásit #%{id}'\n      reported_account: Nahlášený účet\n      reported_by: Nahlášeno uživatelem\n      resolved: Vyřešeno\n      resolved_msg: Nahlášení úspěšně vyřešeno!\n      status: Stav\n      title: Nahlášení\n      unassign: Odebrat\n      unresolved: Nevyřešeno\n      updated_at: Aktualizováno\n    settings:\n      activity_api_enabled:\n        desc_html: Počty lokálně publikovaných tootů, aktivních uživatelů a nových registrací, v týdenních intervalech\n        title: Publikovat hromadné statistiky o uživatelské aktivitě\n      bootstrap_timeline_accounts:\n        desc_html: Je-li uživatelských jmen více, oddělujte je čárkami. Lze zadat pouze místní a odemknuté účty. Je-li tohle prázdné, jsou výchozí hodnotou všichni místní administrátoři.\n        title: Výchozí sledovaní pro nové uživatele\n      contact_information:\n        email: Pracovní e-mail\n        username: Uživatelské jméno pro kontaktování\n      custom_css:\n        desc_html: Pozměnit vzhled pomocí šablony CSS načtené na každé stránce\n        title: Vlastní CSS\n      hero:\n        desc_html: Zobrazuje se na hlavní stránce. Doporučuje se rozlišení alespoň 600x100 px. Pokud toto není nastaveno, bude zobrazena miniatura serveru\n        title: Hlavní obrázek\n      mascot:\n        desc_html: Zobrazuje se na hlavní stránce. Doporučuje se rozlišení alespoň 293x205 px. Pokud toto není nastaveno, bude zobrazen výchozí maskot\n        title: Obrázek maskota\n      peers_api_enabled:\n        desc_html: Domény, na které tento server narazil ve fedivesmíru\n        title: Zveřejnit seznam objevených serverů\n      preview_sensitive_media:\n        desc_html: Náhledy odkazů na jiných stránkách budou zobrazeny i pokud jsou media označena jako citlivá\n        title: Zobrazovat v náhledech OpenGraph i citlivá média\n      profile_directory:\n        desc_html: Dovolit uživatelům být objevitelní\n        title: Povolit adresář profilů\n      registrations:\n        closed_message:\n          desc_html: Zobrazí se na hlavní stránce, jsou-li registrace uzavřeny. Můžete použít i HTML značky\n          title: Zpráva o uzavřených registracích\n        deletion:\n          desc_html: Dovolit každému smazání svého účtu\n          title: Zpřístupnit smazání účtu\n        min_invite_role:\n          disabled: Nikdo\n          title: Povolit pozvánky od\n      registrations_mode:\n        modes:\n          approved: Pro registraci je vyžadováno schválení\n          none: Nikdo se nemůže registrovat\n          open: Kdokoliv se může registrovat\n        title: Režim registrací\n      show_known_fediverse_at_about_page:\n        desc_html: Je-li tohle zapnuto, zobrazí se v náhledu tooty z celého známého fedivesmíru. Jinak budou zobrazeny pouze místní tooty.\n        title: Zobrazit na náhledu časové osy celý známý fedivesmír\n      show_staff_badge:\n        desc_html: Zobrazit na stránce uživatele odznak člena personálu\n        title: Zobrazit odznak personálu\n      site_description:\n        desc_html: Úvodní odstavec v API. Popište, díky čemu je tento server Mastodon zvláštní, a cokoliv jiného, co je důležité. Můžete zde používat HTML značky, hlavně <code>&lt;a&gt;</code> a <code>&lt;em&gt;</code>.\n        title: Popis serveru\n      site_description_extended:\n        desc_html: Dobré místo pro vaše pravidla, pokyny a jiné věci, které váš server odlišují od ostatních. Lze použít HTML značky\n        title: Vlastní rozšířené informace\n      site_short_description:\n        desc_html: Zobrazen v postranním panelu a meta značkách. Popište, co je Mastodon a díky čemu je tento server zvláštní v jediném odstavci.\n        title: Krátký popis serveru\n      site_terms:\n        desc_html: Můžete si napsat vlastní zásady soukromí, podmínky používání či jiné legality. Můžete použít HTML značky\n        title: Vlastní podmínky používání\n      site_title: Název serveru\n      thumbnail:\n        desc_html: Používáno pro náhledy přes OpenGraph a API. Doporučuje se rozlišení 1200x630px\n        title: Miniatura serveru\n      timeline_preview:\n        desc_html: Zobrazit na hlavní straně veřejnou časovou osu\n        title: Náhled časové osy\n      title: Nastavení stránky\n    statuses:\n      back_to_account: Zpět na stránku účtu\n      batch:\n        delete: Smazat\n        nsfw_off: Označit, že není citlivý\n        nsfw_on: Označit jako citlivý\n      failed_to_execute: Nepodařilo se vykonat\n      media:\n        title: Média\n      no_media: Žádná média\n      no_status_selected: Nebyly změněny žádné tooty, neboť žádné nebyly vybrány\n      title: Tooty účtu\n      with_media: S médii\n    subscriptions:\n      callback_url: Zpáteční URL\n      confirmed: Potvrzeno\n      expires_in: Vyprší v\n      last_delivery: Poslední doručení\n      title: WebSub\n      topic: Téma\n    tags:\n      accounts: Účty\n      hidden: Skryté\n      hide: Skrýt z adresáře\n      name: Hashtag\n      title: Hashtagy\n      unhide: Zobrazit v adresáři\n      visible: Viditelné\n    title: Administrace\n    warning_presets:\n      add_new: Přidat nové\n      delete: Smazat\n      edit: Upravit\n      edit_preset: Upravit předlohu pro varování\n      title: Spravovat předlohy pro varování\n  admin_mailer:\n    new_pending_account:\n      body: Detaily nového účtu jsou uvedeny níže. Můžete tento požadavek schválit nebo zamítnout.\n      subject: Nový účet čekající na posouzení na %{instance} (%{username})\n    new_report:\n      body: \"%{reporter} nahlásil/a uživatele %{target}\"\n      body_remote: Někdo z %{domain} nahlásil uživatele %{target}\n      subject: Nové nahlášení pro %{instance} (#%{id})\n  appearance:\n    advanced_web_interface: Pokročilé webové rozhraní\n    advanced_web_interface_hint: 'Chcete-li využít celé šířky vaší obrazovky, dovolí vám pokročilé webové rozhraní nastavit si mnoho různých sloupců, takže můžete vidět ve stejnou chvíli tolik informací, kolik chcete: domovskou časovou osu, oznámení, federovanou časovou osu a libovolný počet seznamů a hashtagů.'\n    animations_and_accessibility: Animace a přístupnost\n    confirmation_dialogs: Potvrzovací dialogy\n    sensitive_content: Citlivý obsah\n  application_mailer:\n    notification_preferences: Změnit volby e-mailu\n    salutation: \"%{name},\"\n    settings: 'Změnit volby e-mailu: %{link}'\n    view: 'Zobrazit:'\n    view_profile: Zobrazit profil\n    view_status: Zobrazit toot\n  applications:\n    created: Aplikace úspěšně vytvořena\n    destroyed: Aplikace úspěšně smazána\n    invalid_url: Zadaná adresa URL je neplatná\n    regenerate_token: Znovu vygenerovat přístupový token\n    token_regenerated: Přístupový token byl úspěšně vygenerován\n    warning: Buďte s těmito daty velmi opatrní. Nikdy je s nikým nesdílejte!\n    your_token: Váš přístupový token\n  auth:\n    apply_for_account: Vyžádat si pozvánku\n    change_password: Heslo\n    checkbox_agreement_html: Souhlasím s <a href=\"%{rules_path}\" target=\"_blank\">pravidly serveru</a> a <a href=\"%{terms_path}\" target=\"_blank\">podmínkami používání</a>\n    confirm_email: Potvrdit e-mail\n    delete_account: Odstranit účet\n    delete_account_html: Chcete-li odstranit svůj účet, <a href=\"%{path}\">pokračujte zde</a>. Budete požádán/a o potvrzení.\n    didnt_get_confirmation: Neobdržel/a jste pokyny pro potvrzení?\n    forgot_password: Zapomněl/a jste heslo?\n    invalid_reset_password_token: Token pro obnovení hesla je buď neplatný, nebo vypršel. Prosím vyžádejte si nový.\n    login: Přihlásit\n    logout: Odhlásit\n    migrate_account: Přesunout se na jiný účet\n    migrate_account_html: Chcete-li přesměrovat tento účet na jiný, můžete to <a href=\"%{path}\">nastavit zde</a>.\n    or_log_in_with: Nebo se přihlaste pomocí\n    providers:\n      cas: CAS\n      saml: SAML\n    register: Registrovat\n    registration_closed: \"%{instance} nepřijímá nové členy\"\n    resend_confirmation: Znovu odeslat pokyny pro potvrzení\n    reset_password: Obnovit heslo\n    security: Zabezpečení\n    set_new_password: Nastavit nové heslo\n    trouble_logging_in: Problémy s přihlašováním?\n  authorize_follow:\n    already_following: Tento účet již sledujete\n    error: Při hledání vzdáleného účtu bohužel nastala chyba\n    follow: Sledovat\n    follow_request: 'Poslal/a jste požadavek o sledování uživateli:'\n    following: 'Podařilo se! Nyní sledujete uživatele:'\n    post_follow:\n      close: Nebo můžete toto okno klidně zavřít.\n      return: Zobrazit profil uživatele\n      web: Přejít na web\n    title: Sledovat uživatele %{acct}\n  datetime:\n    distance_in_words:\n      about_x_hours: \"%{count} hod\"\n      about_x_months: \"%{count} měsíců\"\n      about_x_years: \"%{count} let\"\n      almost_x_years: \"%{count} let\"\n      half_a_minute: Právě teď\n      less_than_x_minutes: \"%{count} min\"\n      less_than_x_seconds: Právě teď\n      over_x_years: \"%{count} let\"\n      x_days: \"%{count} dní\"\n      x_minutes: \"%{count} min\"\n      x_months: \"%{count} mesíců\"\n      x_seconds: \"%{count} s\"\n  deletes:\n    bad_password_msg: Dobrý pokus, hackeři! Nesprávné heslo\n    confirm_password: Zadejte svoje současné heslo pro ověření vaší identity\n    description_html: Tímto <strong>trvale a nenávratně</strong> odstraníte obsah z vašeho účtu a deaktivujete ho. Vaše uživatelské jméno zůstane rezervované pro zabránění budoucím napodobováním.\n    proceed: Odstranit účet\n    success_msg: Váš účet byl úspěšně odstraněn\n    warning_html: Pouze vymazání obsahu z tohoto konkrétního serveru je zaručeno. Obsah, který byl široce sdílen, po sobě pravděpodobně zanechá stopy. U offline serverů a serverů, které vaše aktualizace již neodebírají, nebudou databáze aktualizovány.\n    warning_title: Dostupnost rozšířeného obsahu\n  directories:\n    directory: Adresář profilů\n    enabled: Aktuálně jste v adresáři uveden/a.\n    enabled_but_waiting: Přihlásil/a jste se k uvedení v adresáři, ale ještě nemáte minimální počet sledujících (%{min_followers}) pro uvedení.\n    explanation: Objevujte uživatele podle jejich zájmů\n    explore_mastodon: Prozkoumejte %{title}\n    how_to_enable: Aktuálně nejste přihlášen/a do adresáře. Přihlásit se můžete níže. Použijte ve svém popisu profilu hashtagy, abyste mohl/a být uveden/a pod konkrétními hashtagy!\n    people:\n      few: \"%{count} lidé\"\n      many: \"%{count} lidí\"\n      one: \"%{count} člověk\"\n      other: \"%{count} lidí\"\n  errors:\n    '403': Nemáte povolení zobrazit tuto stránku.\n    '404': Stránka, kterou hledáte, tu není.\n    '410': Stránka, kterou hledáte, tu již neexistuje.\n    '422':\n      content: Bezpečnostní ověření selhalo. Neblokujete cookies?\n      title: Bezpečnostní ověření selhalo\n    '429': Příliš mnoho požadavků\n    '500':\n      content: Omlouváme se, ale něco se u nás pokazilo.\n      title: Tato stránka není správná\n    noscript_html: Pro použití webové aplikace Mastodon prosím povolte JavaScript. Nebo zkuste jednu z <a href=\"%{apps_path}\">nativních aplikací</a> pro Mastodon pro vaši platformu.\n  existing_username_validator:\n    not_found: nelze najít místního uživatele s tímto uživatelským jménem\n    not_found_multiple: nelze najít %{usernames}\n  exports:\n    archive_takeout:\n      date: Datum\n      download: Stáhnout svůj archiv\n      hint_html: Můžete si vyžádat archiv vašich <strong>tootů a nahraných médií</strong>. Exportovaná data budou ve formátu ActivityPub a budou čitelná kterýmkoliv kompatibilním softwarem. Archiv si můžete vyžádat každých 7 dní.\n      in_progress: Kompiluji váš archiv…\n      request: Vyžádat svůj archiv\n      size: Velikost\n    blocks: Blokujete\n    csv: CSV\n    domain_blocks: Blokace domén\n    follows: Sledujete\n    lists: Seznamy\n    mutes: Skryl/a jste\n    storage: Paměť médií\n  featured_tags:\n    add_new: Přidat nový\n    errors:\n      limit: Již jste zvýraznil/a maximální počet hashtagů\n  filters:\n    contexts:\n      home: Domovská časová osa\n      notifications: Oznámení\n      public: Veřejné časové osy\n      thread: Konverzace\n    edit:\n      title: Upravit filtr\n    errors:\n      invalid_context: Nebylo poskytnuto nic, nebo má neplatný kontext\n      invalid_irreversible: Nezvratné filtrování funguje pouze v souvislosti s domovskou osou či oznámeními\n    index:\n      delete: Smazat\n      title: Filtry\n    new:\n      title: Přidat nový filtr\n  footer:\n    developers: Vývojáři\n    more: Více…\n    resources: Zdroje\n  generic:\n    all: Všechny\n    changes_saved_msg: Změny byly úspěšně uloženy!\n    copy: Kopírovat\n    order_by: Seřadit od\n    save_changes: Uložit změny\n    validation_errors:\n      few: Něco ještě není úplně v pořádku! Prosím zkontrolujte %{count} chyby níže\n      many: Něco ještě není úplně v pořádku! Prosím zkontrolujte %{count} chyb níže\n      one: Něco ještě není úplně v pořádku! Prosím zkontrolujte chybu níže\n      other: Něco ještě není úplně v pořádku! Prosím zkontrolujte %{count} chyb níže\n  html_validator:\n    invalid_markup: 'obsahuje neplatný HTML kód: %{error}'\n  identity_proofs:\n    active: Aktivní\n    authorize: Ano, autorizovat\n    authorize_connection_prompt: Autorizovat toto kryptografické spojení?\n    errors:\n      failed: Kryptografické spojení selhalo. Prosím zkuste to znovu z %{provider}.\n      keybase:\n        invalid_token: Tokeny Keybase jsou hashe podpisů a musí být 66 znaků dlouhé\n        verification_failed: Keybase nerozpoznává tento token jako podpis uživatele %{kb_username} na Keybase. Prosím zkuste to znovu z Keybase.\n      wrong_user: Nelze vytvořit důkaz pro uživatele %{proving}, zatímco jste přihlášen/a jako %{current}. Přihlaste se jako %{proving} a zkuste to znovu.\n    explanation_html: Zde můžete kryptograficky připojit vaše ostatní identity, například profil Keybase. To dovolí jiným lidem vám posílat šifrované zprávy a důvěřovat obsahu, který jim pošlete.\n    i_am_html: Na %{service} jsem %{username}.\n    identity: Identita\n    inactive: Neaktivní\n    publicize_checkbox: 'A tootnout tohle:'\n    publicize_toot: 'Je to dokázáno! Na %{service} jsem %{username}: %{url}'\n    status: Stav ověření\n    view_proof: Zobrazit důkaz\n  imports:\n    modes:\n      merge: Sloučit\n      merge_long: Ponechat existující záznamy a přidat nové\n      overwrite: Přepsat\n      overwrite_long: Nahradit aktuální záznamy novými\n    preface: Můžete importovat data, která jste exportoval/a z jiného serveru, jako například seznam lidí, které sledujete či blokujete.\n    success: Vaše data byla úspěšně nahrána a nyní budou zpracována v daný čas\n    types:\n      blocking: Seznam blokovaných\n      domain_blocking: Seznam blokovaných domén\n      following: Seznam sledovaných\n      muting: Seznam ignorovaných\n    upload: Nahrát\n  in_memoriam_html: Navždy budeme vzpomínat.\n  invites:\n    delete: Deaktivovat\n    expired: Vypršelé\n    expires_in:\n      '1800': 30 minut\n      '21600': 6 hodin\n      '3600': 1 hodinu\n      '43200': 12 hodin\n      '604800': 1 týden\n      '86400': 1 den\n    expires_in_prompt: Nikdy\n    generate: Vygenerovat\n    invited_by: 'Byl/a jste pozván/a uživatelem:'\n    max_uses:\n      few: \"%{count} použití\"\n      many: \"%{count} použití\"\n      one: 1 použití\n      other: \"%{count} použití\"\n    max_uses_prompt: Bez limitu\n    prompt: Vygenerujte a sdílejte s ostatními odkazy a umožněte jim přístup na tento server\n    table:\n      expires_at: Vyprší\n      uses: Použití\n    title: Pozvat lidi\n  lists:\n    errors:\n      limit: Dosáhl/a jste maximálního počtu seznamů\n  media_attachments:\n    validations:\n      images_and_video: K tootu, který již obsahuje obrázky, nelze připojit video\n      too_many: Nelze připojit více než 4 soubory\n  migrations:\n    acct: přezdívka@doména nového účtu\n    currently_redirecting: 'Váš profil má nastaveno přesměrování na:'\n    proceed: Uložit\n    updated_msg: Vaše nastavení přesunutí účtu bylo úspěšně aktualizováno!\n  moderation:\n    title: Moderování\n  notification_mailer:\n    digest:\n      action: Zobrazit všechna oznámení\n      body: Zde najdete stručný souhrn zpráv, které jste zmeškal/a od vaší poslední návštěvy %{since}\n      mention: \"%{name} vás zmínil/a v:\"\n      new_followers_summary:\n        few: Navíc jste získal/a %{count} nové sledující, zatímco jste byl/a pryč! Skvělé!\n        many: Navíc jste získal/a %{count} nových sledujících, zatímco jste byl/a pryč! Úžasné!\n        one: Navíc jste získal/a jednoho nového sledujícího, zatímco jste byl/a pryč! Hurá!\n        other: Navíc jste získal/a %{count} nových sledujících, zatímco jste byl/a pryč! Úžasné!\n      subject:\n        few: \"%{count} nová oznámení od vaší poslední návštěvy \\U0001F418\"\n        many: \"%{count} nových oznámení od vaší poslední návštěvy \\U0001F418\"\n        one: \"1 nové oznámení od vaší poslední návštěvy \\U0001F418\"\n        other: \"%{count} nových oznámení od vaší poslední návštěvy \\U0001F418\"\n      title: Ve vaší nepřítomnosti…\n    favourite:\n      body: 'Váš toot si oblíbil/a %{name}:'\n      subject: \"%{name} si oblíbil/a váš toot\"\n      title: Nové oblíbení\n    follow:\n      body: \"%{name} vás nyní sleduje!\"\n      subject: \"%{name} vás nyní sleduje\"\n      title: Nový sledující\n    follow_request:\n      action: Spravovat požadavky o sledování\n      body: \"%{name} požádal/a o povolení vás sledovat\"\n      subject: 'Čekající sledující: %{name}'\n      title: Nový požadavek o sledování\n    mention:\n      action: Odpovědět\n      body: 'Byl/a jste zmíněn/a uživatelem %{name} v:'\n      subject: Byl/a jste zmíněn/a uživatelem %{name}\n      title: Nová zmínka\n    reblog:\n      body: 'Váš toot byl boostnutý uživatelem %{name}:'\n      subject: \"%{name} boostnul/a váš toot\"\n      title: Nový boost\n  number:\n    human:\n      decimal_units:\n        format: \"%n %u\"\n        units:\n          billion: mld\n          million: mil\n          quadrillion: bld\n          thousand: tis\n          trillion: bil\n  pagination:\n    newer: Novější\n    next: Další\n    older: Starší\n    prev: Před\n    truncate: \"&hellip;\"\n  polls:\n    errors:\n      already_voted: V této anketě jste již hlasoval/a\n      duplicate_options: obsahuje duplicitní položky\n      duration_too_long: je příliš daleko v budoucnosti\n      duration_too_short: je příliš brzy\n      expired: Anketa již skončila\n      over_character_limit: nesmí být každá delší než %{max} znaků\n      too_few_options: musí mít více než jednu položku\n      too_many_options: nesmí obsahovat více než %{max} položky\n  preferences:\n    other: Ostatní\n    posting_defaults: Výchozí možnosti psaní\n    public_timelines: Veřejné časové osy\n  relationships:\n    activity: Aktivita účtu\n    dormant: Nečinné\n    last_active: Naposledy aktivních\n    most_recent: Naposledy přidaných\n    moved: Přesunuté\n    mutual: Vzájemné\n    primary: Primární\n    relationship: Vztah\n    remove_selected_domains: Odstranit všechny sledující ze zvolených domén\n    remove_selected_followers: Odstranit zvolené sledující\n    remove_selected_follows: Přestat sledovat zvolené uživatele\n    status: Stav účtu\n  remote_follow:\n    acct: Napište svou přezdívku@doménu, ze které chcete jednat\n    missing_resource: Nemůžeme najít požadované přesměrovací URL pro váš účet\n    no_account_html: Ještě nemáte účet? Můžete se <a href='%{sign_up_path}' target='_blank'>registrovat zde</a>\n    proceed: Pokračovat ke sledování\n    prompt: 'Budete sledovat:'\n    reason_html: \"<strong>Proč je tento krok nutný?</strong> <code>%{instance}</code> nemusí být serverem, na kterém jste registrován/a, proto vás musíme nejdříve přesměrovat na váš domovský server.\"\n  remote_interaction:\n    favourite:\n      proceed: Pokračovat k oblíbení\n      prompt: 'Chcete si oblíbit tento toot:'\n    reblog:\n      proceed: Pokračovat k boostnutí\n      prompt: 'Chcete boostnout tento toot:'\n    reply:\n      proceed: Pokračovat k odpovězení\n      prompt: 'Chcete odpovědět na tento toot:'\n  remote_unfollow:\n    error: Chyba\n    title: Nadpis\n    unfollowed: Už nesledujete\n  scheduled_statuses:\n    over_daily_limit: Překročil/a jste limit %{limit} plánovaných tootů pro tento den\n    over_total_limit: Překročil/a jste limit %{limit} plánovaných tootů\n    too_soon: Plánované datum musí být v budoucnosti\n  sessions:\n    activity: Nejnovější aktivita\n    browser: Prohlížeč\n    browsers:\n      alipay: Alipay\n      blackberry: Blackberry\n      chrome: Chrome\n      edge: Microsoft Edge\n      electron: Electron\n      firefox: Firefox\n      generic: Neznámý prohlížeč\n      ie: Internet Explorer\n      micro_messenger: MicroMessenger\n      nokia: Nokia S40 Ovi Browser\n      opera: Opera\n      otter: Otter\n      phantom_js: PhantomJS\n      qq: QQ Browser\n      safari: Safari\n      uc_browser: UCBrowser\n      weibo: Weibo\n    current_session: Aktuální relace\n    description: \"%{browser} na %{platform}\"\n    explanation: Tohle jsou webové prohlížeče aktuálně přihlášené na váš účet Mastodon.\n    ip: IP adresa\n    platforms:\n      adobe_air: Adobe Air\n      android: Androidu\n      blackberry: Blackberry\n      chrome_os: Chrome OS\n      firefox_os: Firefox OS\n      ios: iOS\n      linux: Linuxu\n      mac: Macu\n      other: neznámé platformě\n      windows: Windows\n      windows_mobile: Windows Mobile\n      windows_phone: Windows Phone\n    revoke: Zamítnout\n    revoke_success: Relace úspěšně zamítnuta\n    title: Relace\n  settings:\n    account: Účet\n    account_settings: Nastavení účtu\n    appearance: Vzhled\n    authorized_apps: Autorizované aplikace\n    back: Zpět na Mastodon\n    delete: Smazání účtu\n    development: Vývoj\n    edit_profile: Upravit profil\n    export: Export dat\n    featured_tags: Zvýrazněné hashtagy\n    identity_proofs: Důkazy identity\n    import: Import\n    import_and_export: Import a export\n    migrate: Přesunutí účtu\n    notifications: Oznámení\n    preferences: Předvolby\n    profile: Profil\n    relationships: Sledovaní a sledující\n    two_factor_authentication: Dvoufázové ověřování\n  statuses:\n    attached:\n      description: 'Přiloženo: %{attached}'\n      image:\n        few: \"%{count} obrázky\"\n        many: \"%{count} obrázků\"\n        one: \"%{count} obrázek\"\n        other: \"%{count} obrázků\"\n      video:\n        few: \"%{count} videa\"\n        many: \"%{count} videí\"\n        one: \"%{count} video\"\n        other: \"%{count} videí\"\n    boosted_from_html: Boostnuto z %{acct_link}\n    content_warning: 'Varování o obsahu: %{warning}'\n    disallowed_hashtags:\n      few: 'obsahoval nepovolené hashtagy: %{tags}'\n      many: 'obsahoval nepovolené hashtagy: %{tags}'\n      one: 'obsahoval nepovolený hashtag: %{tags}'\n      other: 'obsahoval nepovolené hashtagy: %{tags}'\n    language_detection: Zjistit jazyk automaticky\n    open_in_web: Otevřít na webu\n    over_character_limit: limit %{max} znaků byl překročen\n    pin_errors:\n      limit: Už jste si připnul/a maximální počet tootů\n      ownership: Nelze připnout toot někoho jiného\n      private: Nelze připnout neveřejné tooty\n      reblog: Nelze připnout boost\n    poll:\n      total_votes:\n        few: \"%{count} hlasy\"\n        many: \"%{count} hlasů\"\n        one: \"%{count} hlas\"\n        other: \"%{count} hlasů\"\n      vote: Hlasovat\n    show_more: Zobrazit více\n    sign_in_to_participate: Chcete-li se účastnit této konverzace, přihlaste se\n    title: \"%{name}: „%{quote}“\"\n    visibilities:\n      private: Pouze pro sledující\n      private_long: Zobrazit pouze sledujícím\n      public: Veřejné\n      public_long: Všichni mohou vidět\n      unlisted: Neuvedené\n      unlisted_long: Všichni mohou vidět, ale nebudou zahrnuty ve veřejných časových osách\n  stream_entries:\n    pinned: Připnutý toot\n    reblogged: boostnul/a\n    sensitive_content: Citlivý obsah\n  terms:\n    body_html: |\n      <h2>Zásady soukromí</h2>\n      <h3 id=\"collect\">Jaké informace sbíráme?</h3>\n\n      <ul>\n      <li><em>Základní informace o účtu</em>: Pokud se na tomto serveru zaregistrujete, můžeme vás požádat o zadání uživatelského jména, e-mailové adresy a hesla. Můžete také zadat dodatečné profilové informace, jako například zobrazované jméno a krátký životopis, a nahrát si profilovou fotografii a obrázek záhlaví. Uživatelské i zobrazované jméno, životopis, profilová fotografie a obrázek záhlaví jsou vždy uvedeny veřejně.</li>\n      <li><em>Příspěvky, sledující a další veřejné informace</em>: Seznam lidí, které sledujete, je uveden veřejně, totéž platí i pro vaše sledující. Když sem nahrajete zprávu, bude uloženo datum a čas, společně s aplikací, ze které jste zprávu odeslali. Zprávy mohou obsahovat mediální přílohy, jako jsou obrázky a videa. Veřejné a neuvedené příspěvky jsou dostupné veřejně. Pokud na vašem profilu uvedete příspěvek, je to také veřejně dostupná informace. Vaše příspěvky jsou doručeny vašim sledujícím, což v některých případech znamená, že budou doručeny na různé servery, na kterých budou ukládány kopie. Pokud příspěvky smažete, bude tohle taktéž doručeno vašim sledujícím. Akce znovusdílení nebo oblíbení jiného příspěvku je vždy veřejná.</li>\n      <li><em>Příspěvky přímé a pouze pro sledující</em>: Všechny příspěvky jsou uloženy a zpracovány na serveru. Příspěvky pouze pro sledující jsou doručeny vašim sledujícím a uživatelům v nich zmíněným a přímé příspěvky jsou doručeny pouze uživatelům v nich zmíněným. V některých případech tohle znamená, že budou doručeny na různé servery, na kterých budou ukládány kopie. Upřímně se snažíme omezit přístup k těmto příspěvkům pouze na autorizované uživatele, ovšem jiné servery tak nemusejí učinit. Proto je důležité posoudit servery, ke kterým vaši sledující patří. V nastavení si můžete zapnout volbu pro manuální schvalování či odmítnutí nových sledujících. <em>Prosím mějte na paměti, že operátoři tohoto serveru a kteréhokoliv přijímacího serveru mohou tyto zprávy vidět</em> a příjemci mohou vytvořit jejich snímek, zkopírovat je, nebo je jinak sdílet. <em>Nesdílejte přes Mastodon jakékoliv nebezpečné informace.</em></li>\n      <li><em>IP adresy a další metadata</em>: Když se přihlásíte, zaznamenáváme IP adresu, ze které se přihlašujete, jakožto i název vašeho webového prohlížeče. Všechny vaše webové relace jsou v nastavení přístupné k vašemu posouzení a odvolání. Nejpozdější IP adresa použita je uložena maximálně do 12 měsíců. Můžeme také uchovávat serverové záznamy, které obsahují IP adresy každého požadavku odeslaného na náš server.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"use\">Na co používáme vaše informace?</h3>\n\n      <p>Jakékoliv informace, které sbíráme, mohou být použity následujícími způsoby:</p>\n\n      <ul>\n      <li>K poskytnutí základních funkcí Mastodonu. Interagovat s obsahem od jiných lidí a přispívat svým vlastním obsahem můžete pouze, pokud jste přihlášeni. Můžete například sledovat jiné lidi a zobrazit si jejich kombinované příspěvky ve vaší vlastní personalizované časové ose.</li>\n      <li>Pro pomoc moderování komunity, například porovnáním vaší IP adresy s dalšími známými adresami pro určení vyhýbání se zákazům či jiných přestupků.</li>\n      <li>E-mailová adresa, kterou nám poskytnete, může být použita pro zasílání informací, oznámení o interakcích jiných uživatelů s vaším obsahem nebo přijatých zprávách a k odpovědím na dotazy a/nebo další požadavky či otázky.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"protect\">Jak vaše informace chráníme?</h3>\n\n      <p>Implenentujeme různá bezpečnostní opatření pro udržování bezpečnosti vašich osobních dat, když zadáváte, odesíláte, či přistupujete k vašim osobním datům. Mimo jiné je vaše relace v prohlížeči, jakož i provoz mezi vašimi aplikacemi a API, zabezpečena pomocí SSL, a vaše heslo je hashováno pomocí silného jednosměrného algoritmu. Pro větší zabezpečení vašeho účtu můžete povolit dvoufázové ověřování.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"data-retention\">Jaké jsou naše zásady o uchovávání údajů?</h3>\n\n      <p>Budeme se upřímně snažit:</p>\n\n      <ul>\n      <li>Uchovávat serverové záznamy obsahující IP adresy všech požadavků pro tento server, pokud se takové záznamy uchovávají, maximálně 90 dní.</li>\n      <li>Uchovávat IP adresy související s registrovanými uživateli maximálně 12 měsíců.</li>\n      </ul>\n\n      <p>Kdykoliv si můžete vyžádat a stáhnout archiv vašeho obsahu, včetně vašich příspěvků, mediálních příloh, profilové fotografie a obrázku záhlaví.</p>\n\n      <p>Kdykoliv můžete nenávratně smazat váš účet.</p>\n\n      <hr class=\"spacer\"/>\n\n      <h3 id=\"cookies\">Používáme cookies?</h3>\n\n      <p>Ano. Cookies jsou malé soubory, které stránka nebo její poskytovatel uloží na pevný disk vašeho počítače (pokud to dovolíte). Tyto cookies umožňují stránce rozpoznat váš prohlížeč, a pokud máte registrovaný účet, přidružit ho s vaším registrovaným účtem.</p>\n\n      <p>Používáme cookies pro pochopení a ukládání vašich předvoleb pro budoucí návštěvy.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"disclose\">Zveřejňujeme jakékoliv informace třetím stranám?</h3>\n\n      <p>Vaše osobně identifikovatelné informace neprodáváme, neobchodujeme s nimi, ani je nijak nepřenášíme vnějším stranám. Do tohoto se nepočítají důvěryhodné třetí strany, které nám pomáhají provozovat naši stránku, podnikat, nebo vás obsluhovat, pokud tyto strany souhlasí se zachováním důvěrnosti těchto informací. Můžeme také uvolnit vaše informace, pokud věříme, že je to nutné pro soulad se zákonem, prosazování našich zásad, nebo ochranu práv, majetku, či bezpečnost nás či ostatních.</p>\n\n      <p>Váš veřejný obsah může být stažen jinými servery na síti. Vaše příspěvky veřejné a pouze pro sledující budou doručeny na servery vašich sledujících a přímé zprávy budou doručeny na servery příjemců, pokud jsou tito sledující nebo příjemci zaregistrováni na jiném serveru, než je tento.</p>\n\n      <p>Když autorizujete aplikaci, aby používala váš účet, může, v závislosti na rozsahu oprávnění, které jí udělíte, přistupovat k vašim veřejným profilovým informacím, seznamu lidí, které sledujete, vašim sledujícím, vašim seznamům, všem vašim příspěvkům a příspěvkům, které jste si oblíbili. Aplikace nikdy nemohou získat vaši e-mailovou adresu či heslo.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"children\">Používání stránky dětmi</h3>\n\n      <p>Pokud se tento server nachází v EU nebo EHP: Naše stránka, produkty a služby jsou všechny směřovány na lidi, kterým je alespoň 16 let. Pokud je vám méně než 16, dle požadavků nařízení GDPR (<a href=\"https://cs.wikipedia.org/wiki/Obecn%C3%A9_na%C5%99%C3%ADzen%C3%AD_o_ochran%C4%9B_osobn%C3%ADch_%C3%BAdaj%C5%AF\">Obecné nařízení o ochraně osobních údajů</a>) tuto stránku nepoužívejte.</p>\n\n      <p>Pokud se tento server nachází v USA: Naše stránka, produkty a služby jsou všechny směřovány na lidi, kterým je alespoň 13 let. Pokud je vám méně než 13, dle požadavků zákona COPPA (<a href=\"https://cs.wikipedia.org/wiki/Children%27s_online_privacy_protection_act\">Children's Online Privacy Protection Act</a>) tuto stránku nepoužívejte.</p>\n\n      <p>Právní požadavky mohou být jiné, pokud se tento server nachází v jiné jurisdikci.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"changes\">Změny v našich zásadách soukromí</h3>\n\n      <p>Rozhodneme-li se naše zásady soukromí změnit, zveřejníme tyto změny na této stránce.</p>\n\n      <p>Tento dokument je dostupný pod licencí CC-BY-SA. Byl naposledy aktualizován 7. března 2018.</p>\n\n      <p>Původně adaptováno ze <a href=\"https://github.com/discourse/discourse\">zásad soukromí Discourse</a>.</p>\n    title: Podmínky používání a zásady soukromí %{instance}\n  themes:\n    contrast: Mastodon (vysoký kontrast)\n    default: Mastodon (tmavý)\n    mastodon-light: Mastodon (světlý)\n  time:\n    formats:\n      default: \"%d. %b %Y, %H:%M\"\n      month: \"%b %Y\"\n  two_factor_authentication:\n    code_hint: Pro potvrzení zadejte kód vygenerovaný vaší ověřovací aplikací\n    description_html: Povolíte-li <strong>dvoufázové ověřování</strong>, budete při přihlášení potřebovat telefon, který vám vygeneruje přístupové tokeny, které musíte zadat.\n    disable: Zakázat\n    enable: Povolit\n    enabled: Dvoufázové ověřování je povoleno\n    enabled_success: Dvoufázové ověřování bylo úspěšně povoleno\n    generate_recovery_codes: Vygenerovat záložní kódy\n    instructions_html: \"<strong>Naskenujte tento QR kód Google Authenticatorem nebo jinou TOTP aplikací na vašem telefonu</strong>. Od teď bude tato aplikace generovat tokeny, které budete muset zadat při přihlášení.\"\n    lost_recovery_codes: Záložní kódy vám dovolí dostat se k vašemu účtu, pokud ztratíte telefon. Ztratíte-li záložní kódy, můžete je zde znovu vygenerovat. Vaše staré záložní kódy budou zneplatněny.\n    manual_instructions: 'Nemůžete-li oskenovat QR kód a je potřeba ho zadat ručně, zde je tajemství v prostém textu:'\n    recovery_codes: Záložní kódy pro obnovu\n    recovery_codes_regenerated: Záložní kódy byly úspěšně znovu vygenerovány\n    recovery_instructions_html: Ztratíte-li někdy přístup k vašemu telefonu, můžete k získání přístupu k účtu použít jeden ze záložních kódů. <strong>Uchovávejte tyto kódy v bezpečí</strong>. Můžete si je například vytisknout a uložit je mezi jiné důležité dokumenty.\n    setup: Nastavit\n    wrong_code: Zadaný kód byl neplatný! Je čas na serveru a na zařízení správný?\n  user_mailer:\n    backup_ready:\n      explanation: Vyžádal/a jste si úplnou zálohu svého účtu Mastodon. Nyní je připravena ke stažení!\n      subject: Váš archiv je připraven ke stažení\n      title: Stažení archivu\n    warning:\n      explanation:\n        disable: Zatímco je váš účet zmražen, zůstávají data vašeho účtu nedotčená, ale nemůžete vykonávat žádné akce, dokud nebude odemčen.\n        silence: Zatímco je váš účet omezen, mohou vaše tooty na tomto serveru vidět pouze lidé, kteří váš již sledují, a můžete být vyloučen/a z různých veřejných výpisů. Ostatní vás však pořád mohou manuálně sledovat.\n        suspend: Váš účet byl pozastaven a všechny vaše tooty a vaše nahrané mediální soubory byly nenávratně odstraněny z tohoto serveru a serverů, na kterých jste měl/a sledující.\n      review_server_policies: Posoudit politiku serveru\n      subject:\n        disable: Váš účet %{acct} byl zmražen\n        none: Varování pro uživatele %{acct}\n        silence: Váš účet %{acct} byl omezen\n        suspend: Váš účet %{acct} byl pozastaven\n      title:\n        disable: Účet zmražen\n        none: Varování\n        silence: Účet omezen\n        suspend: Účet pozastaven\n    welcome:\n      edit_profile_action: Nastavit profil\n      edit_profile_step: Můžete si přizpůsobit svůj profil nahráním avataru a obrázku záhlaví, změnou zobrazovaného jména a dalších. Chcete-li posoudit nové sledující předtím, než vás mohou sledovat, můžete svůj účet uzamknout.\n      explanation: Zde je pár tipů na začátek\n      final_action: Začít psát\n      final_step: 'Začněte psát! I když nemáte sledující, mohou vaše zprávy vidět jiní lidé, například na místní časové ose a v hashtazích. Můžete se ostatním představit pomocí hashtagu #introductions.'\n      full_handle: Vaše celá adresa profilu\n      full_handle_hint: Tohle je, co byste řekl/a svým přátelům, aby vám mohli posílat zprávy nebo vás sledovat z jiného serveru.\n      review_preferences_action: Změnit nastavení\n      review_preferences_step: Nezapomeňte si nastavit své volby, například jaké e-maily chcete přijímat či jak soukromé mají být vaše příspěvky ve výchozím stavu. Nemáte-li epilepsii, můžete si nastavit automatické přehrávání obrázků GIF.\n      subject: Vítejte na Mastodonu\n      tip_federated_timeline: Federovaná časová osa je náhled celé sítě Mastodon. Zahrnuje ovšem pouze lidi, které sledují vaši sousedé, takže není úplná.\n      tip_following: Administrátora/y serveru sledujete automaticky. Chcete-li najít další zajímavé lidi, podívejte se na místní a federované časové osy.\n      tip_local_timeline: Místní časová osa je náhled lidí na %{instance}. Tohle jsou vaši nejbližší sousedé!\n      tip_mobile_webapp: Pokud vám váš mobilní prohlížeč nabídne přidat si Mastodon na vaši domovskou obrazovku, můžete dostávat oznámení. V mnoha ohledech to funguje jako nativní aplikace!\n      tips: Tipy\n      title: Vítejte na palubě, %{name}!\n  users:\n    follow_limit_reached: Nemůžete sledovat více než %{limit} lidí\n    invalid_email: E-mailová adresa je neplatná\n    invalid_otp_token: Neplatný kód pro dvoufázové ověřování\n    otp_lost_help_html: Pokud jste ztratil/a přístup k oběma, můžete se spojit %{email}\n    seamless_external_login: Jste přihlášen/a přes externí službu, nastavení hesla a e-mailu proto nejsou dostupná.\n    signed_in_as: 'Přihlášen/a jako:'\n  verification:\n    explanation_html: 'Můžete se <strong>ověřit jako vlastník odkazů v metadatech profilu</strong>. Pro tento účel musí stránka v odkazu obsahovat odkaz zpět na váš profil na Mastodonu. Odkaz zpět <strong>musí</strong> mít atribut <code>rel=\"me\"</code>. Na textu odkazu nezáleží. Zde je příklad:'\n    verification: Ověření\n"
  },
  {
    "path": "config/locales/cy.yml",
    "content": "---\ncy:\n  about:\n    about_hashtag_html: Dyma dŵtiau cyhoeddus wedi eu tagio gyda <strong>#%{hashtag}</strong>. Gallwch ryngweithio gyda nhw os oes gennych gyfrif yn unrhyw le yn y ffeddysawd.\n    about_mastodon_html: Mae Mastodon yn rwydwaith cymdeithasol sy'n seiliedig ar brotocolau gwe a meddalwedd cod agored rhad ac am ddim. Yn debyg i e-bost mae'n ddatganoledig.\n    about_this: Ynghylch\n    active_count_after: yn weithredol\n    active_footnote: Defnyddwyr Gweithredol Misol (DGM)\n    administered_by: 'Gweinyddir gan:'\n    api: API\n    apps: Apiau symudol\n    apps_platforms: Defnyddio Mastodon o iOS, Android a phlatfformau eraill\n    browse_directory: Pori cyfeiriadur proffil a hidlo wrth diddordebau\n    browse_public_posts: Pori ffrwd byw o byst cyhoeddus ar Fastodon\n    contact: Cyswllt\n    contact_missing: Heb ei osod\n    contact_unavailable: Ddim yn berthnasol\n    discover_users: Darganfod defnyddwyr\n    documentation: Dogfennaeth\n    extended_description_html: |\n      <h3>Lle da ar gyfer rheolau</h3>\n      <p>Nid yw'r disgrifiad estynedig wedi ei osod eto.</p>\n    federation_hint_html: Gyda cyfrif ar %{instance}, gallwch dilyn pobl ar unrhyw gweinydd Mastodon, a thu hwnt.\n    generic_description: Mae %{domain} yn un gweinydd yn y rhwydwaith\n    get_apps: Rhowch gynnig ar ap dyfeis symudol\n    hosted_on: Mastodon wedi ei weinyddu ar %{domain}\n    learn_more: Dysu mwy\n    privacy_policy: Polisi preifatrwydd\n    see_whats_happening: Gweld beth sy'n digwydd\n    server_stats: 'Ystadegau gweinydd:'\n    source_code: Cod ffynhonnell\n    status_count_after:\n      few: statwsau\n      many: statwsau\n      one: statws\n      other: statwsau\n      two: statwsau\n      zero: statwsau\n    status_count_before: Ysgriffennwyd gan\n    tagline: Dilyn ffrindiau a darganfod rhai newydd\n    terms: Telerau gwasanaeth\n    user_count_after:\n      few: defnyddwyr\n      many: defnyddwyr\n      one: defnyddiwr\n      other: defnyddwyr\n      two: defnyddwyr\n      zero: defnyddwyr\n    user_count_before: Cartref i\n    what_is_mastodon: Beth yw Mastodon?\n  accounts:\n    choices_html: 'Dewisiadau %{name}:'\n    follow: Dilynwch\n    followers:\n      few: Dilynwyr\n      many: Dilynwyr\n      one: Dilynwr\n      other: Dilynwyr\n      two: Dilynwyr\n      zero: Dilynwyr\n    following: Yn dilyn\n    joined: Ymunodd %{date}\n    last_active: diweddaraf\n    link_verified_on: Gwiriwyd perchnogaeth y ddolen yma ar %{date}\n    media: Cyfryngau\n    moved_html: 'Mae %{name} wedi symud i %{new_profile_link}:'\n    network_hidden: Nid yw'r wybodaeth hyn ar gael\n    nothing_here: Does dim byd yma!\n    people_followed_by: Pobl y mae %{name} yn ei ddilyn\n    people_who_follow: Pobl sy'n dilyn %{name}\n    pin_errors:\n      following: Rhaid i ti fod yn dilyn y person yr ydych am ei gymeradwyo yn barod\n    posts:\n      few: Tŵtiau\n      many: Tŵtiau\n      one: Tŵt\n      other: Tŵtiau\n      two: Tŵtiau\n      zero: Tŵtiau\n    posts_tab_heading: Tŵtiau\n    posts_with_replies: Tŵtiau ac atebion\n    reserved_username: Mae'r enw defnyddiwr ar gadw\n    roles:\n      admin: Gweinyddwr\n      bot: Bot\n      moderator: Safonwr\n    unavailable: Proffil ddim ar gael\n    unfollow: Dad-ddilyn\n  admin:\n    account_actions:\n      action: Cyflawni gweithred\n      title: Perfformio gweithrediad goruwchwylio ar %{acct}\n    account_moderation_notes:\n      create: Gadael nodyn\n      created_msg: Crewyd nodyn goruwchwylio yn llwyddiannus!\n      delete: Dileu\n      destroyed_msg: Dinistrwyd nodyn goruwchwylio yn llwyddiannus!\n    accounts:\n      approve: Cymeradwyo\n      approve_all: Cymeradwyo pob un\n      are_you_sure: Ydych chi'n siŵr?\n      avatar: Afatar\n      by_domain: Parth\n      change_email:\n        changed_msg: E-bost cyfrif wedi ei newid yn llwyddiannus!\n        current_email: E-bost Cyfredol\n        label: Newid E-bost\n        new_email: E-bost Newydd\n        submit: Newid E-bost\n        title: Newid E-bost i %{username}\n      confirm: Cadarnhau\n      confirmed: Cadarnhawyd\n      confirming: Cadarnhau\n      deleted: Wedi dileu\n      demote: Diraddio\n      disable: Diffodd\n      disable_two_factor_authentication: Diffodd 2FA\n      disabled: Wedi ei ddiffodd\n      display_name: Enw arddangos\n      domain: Parth\n      edit: Golygu\n      email: E-bost\n      email_status: Statws E-bost\n      enable: Galluogi\n      enabled: Wedi ei alluogi\n      feed_url: Ffrwd URL\n      followers: Dilynwyr\n      followers_url: URL Dilynwyr\n      follows: Yn dilyn\n      header: Pennawd\n      inbox_url: URL Mewnflwch\n      invited_by: Gwahoddwyd gan\n      ip: IP\n      joined: Ymunodd\n      location:\n        all: Popeth\n        local: Lleol\n        remote: Pell\n        title: Lleoliad\n      login_status: Statws mewngofnodi\n      media_attachments: Atodiadau\n      memorialize: Troi yn gofeb\n      moderation:\n        active: Yn weithredol\n        all: Popeth\n        pending: Yn aros\n        silenced: Wedi ei dawelu\n        suspended: Wedi ei atal\n        title: Goruwchwyliad\n      moderation_notes: Nodiadau goruwchwylio\n      most_recent_activity: Gweithgarwch diweddaraf\n      most_recent_ip: IP diweddaraf\n      no_account_selected: Ni newidwyd dim cyfrif achos ni ddewiswyd dim un\n      no_limits_imposed: Dim terfynau wedi'i gosod\n      not_subscribed: Heb danysgrifio\n      outbox_url: Allflwch URL\n      pending: Yn aros am adolygiad\n      perform_full_suspension: Atal\n      profile_url: URL proffil\n      promote: Hyrwyddo\n      protocol: Protocol\n      public: Cyhoeddus\n      push_subscription_expires: Tanysgrifiad PuSH yn dod i ben\n      redownload: Adnewyddu proffil\n      reject: Gwrthod\n      reject_all: Gwrthod pob un\n      remove_avatar: Dileu afatar\n      remove_header: Dileu pennawd\n      resend_confirmation:\n        already_confirmed: Mae'r defnyddiwr hwn wedi ei gadarnhau yn barod\n        send: Ailanfonwch e-bost cadarnhad\n        success: E-bost cadarnhau wedi ei anfon yn llwyddiannus!\n      reset: Ailosod\n      reset_password: Ailosod cyfrinair\n      resubscribe: Aildanysgrifio\n      role: Caniatâd\n      roles:\n        admin: Gweinyddwr\n        moderator: Aroglygydd\n        staff: Staff\n        user: Defnyddiwr\n      salmon_url: URL Eog\n      search: Chwilio\n      shared_inbox_url: URL Mewnflwch wedi ei rannu\n      show:\n        created_reports: Adroddiadau a wnaed\n        targeted_reports: Adroddwyd gan eraill\n      silence: Tawelu\n      silenced: Tawelwyd\n      statuses: Statysau\n      subscribe: Tanysgrifio\n      suspended: Ataliwyd\n      time_in_queue: Yn aros yn y rhestr am %{time}\n      title: Cyfrifon\n      unconfirmed_email: E-bost heb ei gadarnhau\n      undo_silenced: Dadwneud tawelu\n      undo_suspension: Dadwneud ataliad\n      unsubscribe: Dad-danysgrifio\n      username: Enw defnyddiwr\n      warn: Rhybuddio\n      web: Gwe\n    action_logs:\n      actions:\n        assigned_to_self_report: Aseiniodd %{name} adroddiad %{target} i'w hunan\n        change_email_user: Newidodd %{name} gyfeiriad e-bost y defnyddiwr %{target}\n        confirm_user: Cadarnhaodd %{name} gyfeiriad e-bost y defnyddiwr %{target}\n        create_account_warning: Anfonwyd rhybudd i %{target} gan %{name}\n        create_custom_emoji: Uwchlwythodd %{name} emoji newydd %{target}\n        create_domain_block: Blociodd %{name} y parth %{target}\n        create_email_domain_block: Cosbrestrwyd parth e-bost %{target} gan %{name}\n        demote_user: Diraddiodd %{name} y defnyddiwr %{target}\n        destroy_custom_emoji: Dinistriodd %{name} emoji %{target}\n        destroy_domain_block: Dadflociodd %{name} y parth %{target}\n        destroy_email_domain_block: Gwynrestrodd %{name} parth e-bost %{target}\n        destroy_status: Cafodd %{name} wared ar statws gan %{target}\n        disable_2fa_user: Diffoddodd %{name} ar ofyniad dau gam ar gyfer y defnyddiwr %{target}\n        disable_custom_emoji: Diffoddodd %{name} emoji %{target}\n        disable_user: Diffoddodd %{name} mewngofnodi ar gyfer y defnyddiwr %{target}\n        enable_custom_emoji: Galluogodd %{name} emoji %{target}\n        enable_user: Galluogodd %{name} mewngofnodi ar gyfer y defnyddiwr %{target}\n        memorialize_account: Newidodd %{name} gyfrif %{target} i dudalen goffau\n        promote_user: Dyrchafodd %{name} y defnyddiwr %{target}\n        remove_avatar_user: Cafodd %{name} wared ar afatar %{target}\n        reopen_report: Ailagorodd %{name} adroddiad %{target}\n        reset_password_user: Ailosododd %{name} gyfrinair y defnyddiwr %{target}\n        resolve_report: Datrusodd %{name} adroddiad %{target}\n        silence_account: Tawelodd %{name} gyfrif %{target}\n        suspend_account: Ataliodd %{name} gyfrif %{target}\n        unassigned_report: Dadbenododd %{name} adroddiad %{target}\n        unsilence_account: Terfynodd %{name} dawelu cyfrif %{target}\n        unsuspend_account: Terfynodd %{name} yr ataliad ar gyfrif %{target}\n        update_custom_emoji: Diweddarodd %{name} emoji %{target}\n        update_status: Diweddarodd %{name} statws gan %{target}\n      deleted_status: \"(statws wedi ei ddileu)\"\n      title: Log archwilio\n    custom_emojis:\n      by_domain: Parth\n      copied_msg: Llwyddwyd i greu copi lleol o'r emoji\n      copy: Copïo\n      copy_failed_msg: Methwyd i greu copi lleol o'r emoji hwnnw\n      created_msg: Llwyddwyd i greu emoji!\n      delete: Dileu\n      destroyed_msg: Llwyddwyd i ddinistrio emojo!\n      disable: Diffodd\n      disabled_msg: Llwyddwyd i ddiffodd yr emoji hwnnw\n      emoji: Emoji\n      enable: Galluogi\n      enabled_msg: Llwyddwyd i alluogi yr emoji hwnnw\n      image_hint: PNG hyd at 50KB\n      listed: Rhestredig\n      new:\n        title: Ychwanegu emoji personol newydd\n      overwrite: Trosysgrifio\n      shortcode: Byrgod\n      shortcode_hint: O leiaf 2 nodyn, dim ond nodau alffaniwmerig a tanlinellau\n      title: Emoji unigryw\n      unlisted: Heb eu rhestru\n      update_failed_msg: Methwyd a diweddaru'r emoji hwnnw\n      updated_msg: Llwyddwyd i ddiweddaru'r emoji!\n      upload: Uwchlwytho\n    dashboard:\n      backlog: tasgau heb eu cwblhau\n      config: Cyfluniad\n      feature_deletions: Dileadau cyfrif\n      feature_invites: Dolenni gwahodd\n      feature_profile_directory: Cyfeiriadur proffil\n      feature_registrations: Cofrestriadau\n      feature_relay: Relái ffederasiwn\n      feature_timeline_preview: Rhagolwg o'r ffrwd\n      features: Nodweddion\n      hidden_service: Ffederasiwn a gwasanaethau cudd\n      open_reports: adroddiadau agored\n      recent_users: Defnyddwyr diweddar\n      search: Chwilio testun llawn\n      single_user_mode: Modd un defnyddiwr\n      software: Meddalwedd\n      space: Defnydd o ofod\n      title: Dangosfwrdd\n      total_users: cyfanswm defnyddwyr\n      trends: Tueddiadau\n      week_interactions: ymadweithiau yr wythnos hon\n      week_users_active: gweithredol yr wythnos hon\n      week_users_new: defnyddwyr yr wythnos hon\n    domain_blocks:\n      add_new: Ychwanegu bloc parth newydd\n      created_msg: Mae'r bloc parth nawr yn cael ei brosesu\n      destroyed_msg: Mae'r bloc parth wedi ei ddadwneud\n      domain: Parth\n      existing_domain_block_html: Rydych yn barod wedi gosod cyfyngau fwy llym ar %{name}, mae rhaid i chi ei <a href=\"%{unblock_url}\">ddadblocio</a> yn gyntaf.\n      new:\n        create: Creu bloc\n        hint: Ni fydd y bloc parth yn atal cread cofnodion cyfrif yn y bas data, ond mi fydd yn gosod dulliau goruwchwylio penodol ôl-weithredol ac awtomatig ar y cyfrifau hynny.\n        severity:\n          desc_html: Mae <strong>Tawelu</strong> yn gwneud twtiau y cyfrif yn anweledig i unrhyw un nad yw'n dilyn y cyfrif. Mae <strong>Atal</strong> yn cael gwared ar holl gynnwys, cyfryngau a data proffil y cyfrif. Defnyddiwch <strong>Dim</strong> os ydych chi ond am wrthod dogfennau cyfryngau.\n          noop: Dim\n          silence: Tawelwch\n          suspend: Atal\n        title: Blocio parth newydd\n      reject_media: Gwrthod dogfennau cyfryngau\n      reject_media_hint: Dileu dogfennau cyfryngau wedi eu cadw yn lleol ac yn gwrthod i lawrlwytho unrhyw rai yn y dyfodol. Amherthnasol i ataliadau\n      reject_reports: Gwrthod adroddiadau\n      reject_reports_hint: Anwybyddu'r holl adroddiadau sy'n dod o'r parth hwn. Amherthnasol i ataliadau\n      rejecting_media: Yn gwrthod ffeiliau cyfryngau\n      rejecting_reports: Yn gwrthod adroddiadau\n      severity:\n        silence: tawelu\n        suspend: ataliedig\n      show:\n        affected_accounts:\n          few: Effeithiwyd ar %{count} gyfrifon\n          many: Effeithiwyd ar %{count} gyfrifon\n          one: Effeithiwyd ar un cyfrif\n          other: Effeithiwyd ar %{count} gyfrifon\n          two: Effeithiwyd ar %{count} gyfrifon\n          zero: Effeithiwyd ar %{count} gyfrifon\n        retroactive:\n          silence: Dad-dawelu pob cyfri presennol o'r parth hwn\n          suspend: Dad-atal pob cyfrif o'r parth hwn sy'n bodoli\n        title: Dadwneud blocio parth ar gyfer %{domain}\n        undo: Dadwneud\n      undo: Dadwneud bloc parth\n    email_domain_blocks:\n      add_new: Ychwanegu\n      created_msg: Llwyddwyd i ychwanegu parth e-bost i'r gosbrestr\n      delete: Dileu\n      destroyed_msg: Llwyddwyd i ddileu parth e-bost o'r gosbrestr\n      domain: Parth\n      new:\n        create: Ychwanegu parth\n        title: Cofnod newydd yng nghosbrestr e-byst\n      title: Cosbrestr e-bost\n    followers:\n      back_to_account: Nôl i'r gyfrif\n      title: Dilynwyr %{acct}\n    instances:\n      by_domain: Parth\n      delivery_available: Mae'r cyflenwad ar gael\n      known_accounts:\n        few: \"%{count} cyfrifon hysbys\"\n        many: \"%{count} cyfrifon hysbys\"\n        one: \"%{count} cyfrif hysbys\"\n        other: \"%{count} cyfrifon hysbys\"\n        two: \"%{count} cyfrifon hysbys\"\n        zero: \"%{count} cyfrifon hysbys\"\n      moderation:\n        all: Pob\n        limited: Gyfyngedig\n        title: Goruwchwyliad\n      title: Ffederasiwn\n      total_blocked_by_us: Wedi'i bloc gan ni\n      total_followed_by_them: Yn dilyn ganynt\n      total_followed_by_us: Yn dilyn ganom ni\n      total_reported: Adroddiadau amdanynt\n      total_storage: Atodiadau cyfryngau\n    invites:\n      deactivate_all: Diffodd pob un\n      filter:\n        all: Pob\n        available: Ar gael\n        expired: Wedi dod i ben\n        title: Hidlo\n      title: Gwahoddiadau\n    pending_accounts:\n      title: Cyfrifau yn aros (%{count})\n    relays:\n      add_new: Ychwanegau relái newydd\n      delete: Dileu\n      description_html: Mae <strong>relái ffederasiwn</strong> yn weinydd ganol sy'n cyfnewid niferoedd ucheol o dŵtiau cyhoeddus rhwng gweinyddwyr sydd wedi tanysgrifio ac yn cyhoeddi iddo. <strong>Gall helpu weinyddwyr bach a cymhedrol eu maint i ddarganfod cynnwys o'r ffedysawd</strong>, fel arall bydd gofyn ara ddefnyddwyr lleol yn dilyn unigolion ar weinyddwyr eraill a llaw.\n      disable: Diffodd\n      disabled: Wedi'i ddiffodd\n      enable: Galluogi\n      enable_hint: Unwaith y bydd wedi ei alluogi, bydd eich gweinydd yn tanysgrifio i holl dŵtiau cyhoeddus o'r relai hwn, ac yn dechrau anfon tŵtiau y gweinydd hwn ato.\n      enabled: Wedi ei alluogi\n      inbox_url: URL relái\n      pending: Aros am gymeradywaeth i'r relái\n      save_and_enable: Cadw a galluogi\n      setup: Sefydlu cysylltiad relái\n      status: Statws\n      title: Cyfnewidwyr\n    report_notes:\n      created_msg: Llwyddwyd i greu nodyn adroddiad!\n      destroyed_msg: Llwyddwyd i ddileu nodyn adroddiad!\n    reports:\n      account:\n        note: nodyn\n        report: adroddiad\n      action_taken_by: Gwnaethpwyd hyn gan\n      are_you_sure: Ydych chi'n sicr?\n      assign_to_self: Aseinio i mi\n      assigned: Arolygwr wedi'i aseinio\n      comment:\n        none: Dim\n      created_at: Adroddwyd\n      mark_as_resolved: Nodi fel wedi'i ddatrys\n      mark_as_unresolved: Nodi fel heb ei ddatrys\n      notes:\n        create: Ychwanegu nodyn\n        create_and_resolve: Datrys gyda nodyn\n        create_and_unresolve: Ailagor gyda nodyn\n        delete: Dileu\n        placeholder: Disgrifiwch pa weithredoedd sydd wedi eu cymryd, neu unrhyw ddiweddariadau eraill...\n      reopen: Ailagor adroddiad\n      report: 'Adroddiad #%{id}'\n      reported_account: Cyfrif wedi ei adrodd\n      reported_by: Adroddwyd gan\n      resolved: Wedi ei ddatrys\n      resolved_msg: Llwyddwyd i ddatrys yr adroddiad!\n      status: Statws\n      title: Adroddiadau\n      unassign: Dadneilltuo\n      unresolved: Heb ei ddatrys\n      updated_at: Diweddarwyd\n    settings:\n      activity_api_enabled:\n        desc_html: Niferoedd o statysau wedi eu postio'n lleol, defnyddwyr gweithredol, a cofrestradau newydd mewn bwcedi wythnosol\n        title: Cyhoeddi ystatedgau cyfangronedig am weithgaredd defnyddwyr\n      bootstrap_timeline_accounts:\n        desc_html: Gwahanu sawl enw defnyddiwr a coma. Dim ond cyfrifoedd lleol a cyfrifoedd heb eu cloi fydd yn gweithio. Tra bod yn aros yn wag yr hyn sy'n rhagosodedig yw'r holl weinyddwyr lleol.\n        title: Dilyn diofyn i ddefnyddwyr newydd\n      contact_information:\n        email: E-bost busnes\n        username: Enw defnyddiwr cyswllt\n      custom_css:\n        desc_html: Addasu gwedd gyda CSS wedi lwytho ar bob tudalen\n        title: CSS wedi'i addasu\n      hero:\n        desc_html: Yn cael ei arddangos ar y dudadlen flaen. Awgrymir 600x100px oleia. Pan nad yw wedi ei osod, mae'n ymddangos fel mân-lun yr achos\n        title: Delwedd arwr\n      mascot:\n        desc_html: I'w arddangos ar nifer o dudalennau. Awgrymir 293x205px o leiaf. Pan nad yw wedi ei osod, cwympo nôl i'r mascot rhagosodedig\n        title: Llun mascot\n      peers_api_enabled:\n        desc_html: Enwau parth y mae'r achos hwn wedi dod ar ei draws yn y ffedysawd\n        title: Cyhoeddi rhestr o achosion dargynfyddiedig\n      preview_sensitive_media:\n        desc_html: Bydd rhagolygon ar wefannau eraill yn dangos ciplun hyd yn oed os oes na gyfryngau wedi eu marcio'n sensitif\n        title: Dangos cyfryngau sensitif mewn rhagolygon OpenGraph\n      profile_directory:\n        desc_html: Caniatáu i ddefnyddwyr gael eu gweld\n        title: Galluogi cyfeiriadur proffil\n      registrations:\n        closed_message:\n          desc_html: I'w arddangos ar y dudalen flaen wedi i gofrestru cau. Mae modd defnyddio tagiau HTML\n          title: Neges gofrestru caeëdig\n        deletion:\n          desc_html: Caniatau i unrhywun i ddileu eu cyfrif\n          title: Agor dileu cyfrif\n        min_invite_role:\n          disabled: Neb\n          title: Caniatau gwahoddiadau gan\n      registrations_mode:\n        modes:\n          approved: Mae angen cymeradwyaeth ar gyfer cofrestru\n          none: Ni all unrhyw un cofrestru\n          open: Gall unrhyw un cofrestru\n        title: Modd cofrestriadau\n      show_known_fediverse_at_about_page:\n        desc_html: Wedi'i ddewis, bydd yn dangos rhagolwg o dŵtiau o'r holl ffedysawd. Fel arall bydd ond yn dangos tŵtiau lleol.\n        title: Dangos ffedysawd hysbys ar ragolwg y ffrwd\n      show_staff_badge:\n        desc_html: Dangos bathodyn staff ar dudalen defnyddiwr\n        title: Dangos bathodyn staff\n      site_description:\n        desc_html: Paragraff agoriadol ar y dudalen flaen. Disgrifiwch yr hyn sy'n arbennig am y gweinydd Mastodon hwn ac unrhywbeth arall o bwys. Mae modd defnyddio tagiau HTML <code>&lt;a&gt;</code> a <code>&lt;em&gt;</code>.\n        title: Disgrifiad achos\n      site_description_extended:\n        desc_html: Lle da ar gyfer eich cod ymddygiad, rheolau, canllawiau a phethau eraill sy'n gwneud eich achos yn whanol. Mae modd i chi ddefnyddio tagiau HTML\n        title: Gwybodaeth bellach wedi ei addasu\n      site_short_description:\n        desc_html: Yn cael ei ddangos yn bar ar yr ochr a tagiau meto. Digrifiwch beth yw Mastodon a beth sy'n gwneud y gweinydd hwn mewn un paragraff. Os yn wag, wedi ei ragosod i ddangos i disgrifiad yr achos.\n        title: Disgrifiad byr o'r achos\n      site_terms:\n        desc_html: Mae modd i chi ysgrifennu polisi preifatrwydd, termau gwasanaeth a cyfreitheg arall eich hun. Mae modd defnyddio tagiau HTML\n        title: Termau gwasanaeth wedi eu haddasu\n      site_title: Enw'r achos\n      thumbnail:\n        desc_html: Ceith ei ddefnyddio ar gyfer rhagolygon drwy OpenGraph a'r API. Argymhellir 1200x630px\n        title: Mân-lun yr achos\n      timeline_preview:\n        desc_html: Dangos ffrwd gyhoeddus ar y dudalen lanio\n        title: Rhagolwg o'r ffrwd\n      title: Gosodiadau'r wefan\n    statuses:\n      back_to_account: Yn ôl i dudalen y cyfrif\n      batch:\n        delete: Dileu\n        nsfw_off: Marcio fel nad yw'n sensitif\n        nsfw_on: Marcio'n sensitif\n      failed_to_execute: Methwyd a gweithredu\n      media:\n        title: Cyfryngau\n      no_media: Dim cyfryngau\n      no_status_selected: Ni newidwyd dim statws achos ni ddewiswyd dim un\n      title: Statysau cyfrif\n      with_media: A chyfryngau\n    subscriptions:\n      callback_url: URL galw-nôl\n      confirmed: Wedi'i gadarnhau\n      expires_in: Dod i ben ymhen\n      last_delivery: Danfoniad diwethaf\n      title: WebSub\n      topic: Pwnc\n    tags:\n      accounts: Cyfrifon\n      hidden: Cudd\n      hide: Cuddio o gyfeiriadur\n      name: Hashnod\n      title: Hashnodau\n      unhide: Dangoswch yn y cyfeiriadur\n      visible: Gweladwy\n    title: Gweinyddiaeth\n    warning_presets:\n      add_new: Ychwanegu newydd\n      delete: Dileu\n      edit: Golygu\n      edit_preset: Golygu rhagosodiad rhybudd\n      title: Rheoli rhagosodiadau rhybudd\n  admin_mailer:\n    new_pending_account:\n      body: Mae manylion y cyfrif newydd yn isod. Gallwch cymeradwyo neu wrthod y ceisiad hon.\n      subject: Cyfrif newydd i fynu ar gyfer adolygiad ar %{instance} (%{username})\n    new_report:\n      body: Mae %{reporter} wedi cwyno am %{target}\n      body_remote: Mae rhywun o %{domain} wedi cwyno am %{target}\n      subject: Cwyn newydd am %{instance} (#%{id})\n  appearance:\n    advanced_web_interface: Rhyngwyneb gwe uwch\n    advanced_web_interface_hint: 'Os hoffech gwneud defnydd o gyd o''ch lled sgrin, mae''r rhyngwyneb gwe uwch yn gadael i chi ffurfweddu sawl colofn wahanol i weld cymaint o wybodaeth â hoffech: Catref, hysbysiadau, ffrwd y ffedysawd, unrhyw nifer o rhestrau ac hashnodau.'\n    animations_and_accessibility: Animeiddiau ac hygyrchedd\n    confirmation_dialogs: Deialog cadarnhau\n    sensitive_content: Cynnwys sensitif\n  application_mailer:\n    notification_preferences: Newid gosodiadau e-bost\n    salutation: \"%{name},\"\n    settings: 'Newid gosodiadau e-bost: %{link}'\n    view: 'Gweld:'\n    view_profile: Gweld proffil\n    view_status: Gweld statws\n  applications:\n    created: Cais wedi ei greu'n llwyddiannus\n    destroyed: Cais wedi ei ddileu'n llwyddiannus\n    invalid_url: Mae'r URL a ddarparwyd yn annilys\n    regenerate_token: Adfywio tocyn mynediad\n    token_regenerated: Adfywiwyd y tocyn mynediad yn llwyddiannus\n    warning: Byddwch yn ofalus a'r data hyn. Peidiwch a'i rannu byth!\n    your_token: Eich tocyn mynediad\n  auth:\n    apply_for_account: Gofyn am wahoddiad\n    change_password: Cyfrinair\n    checkbox_agreement_html: Rydw i'n cytuno i'r <a href=\"%{rules_path}\" target=\"_blank\">rheolau'r gweinydd</a> a'r <a href=\"%{terms_path}\" target=\"_blank\">telerau gwasanaeth</a>\n    confirm_email: Cadarnhau e-bost\n    delete_account: Dileu cyfrif\n    delete_account_html: Os hoffech chi ddileu eich cyfrif, mae modd <a href=\"%{path}\">parhau yma</a>. Bydd gofyn i chi gadarnhau.\n    didnt_get_confirmation: Heb dderbyn cyfarwyddiadau cadarnhau?\n    forgot_password: Wedi anghofio'ch cyfrinair?\n    invalid_reset_password_token: Tocyn ailosod cyfrinair yn annilys neu wedi dod i ben. Gwnewch gais am un newydd os gwelwch yn dda.\n    login: Mewngofnodi\n    logout: Allgofnodi\n    migrate_account: Symud i gyfrif gwahanol\n    migrate_account_html: Os hoffech chi ailgyfeirio'r cyfrif hwn at un gwahanol, mae modd <a href=\"%{path}\">ei ffurfweddu yma</a>.\n    or_log_in_with: Neu logiwch mewn a\n    providers:\n      cas: CAS\n      saml: SAML\n    register: Cofrestru\n    registration_closed: Nid yw %{instance} yn derbyn aelodau newydd\n    resend_confirmation: Ailanfon cyfarwyddiadau cadarnhau\n    reset_password: Ailosod cyfrinair\n    security: Diogelwch\n    set_new_password: Gosod cyfrinair newydd\n    trouble_logging_in: Trafferdd mewngofnodi?\n  authorize_follow:\n    already_following: Yr ydych yn dilyn y cyfrif hwn yn barod\n    error: Yn anffodus, roedd gwall tra'n edrych am y cyfrif anghysbell\n    follow: Dilyn\n    follow_request: 'Yr ydych wedi anfon cais dilyn at:'\n    following: 'Llwyddiant! Yr ydych yn awr yn dilyn:'\n    post_follow:\n      close: Neu, gallwch gau'r ffenest hon.\n      return: Dangos proffil y defnyddiwr\n      web: I'r wê\n    title: Dilyn %{acct}\n  datetime:\n    distance_in_words:\n      about_x_hours: \"%{count}awr\"\n      about_x_months: \"%{count}mis\"\n      about_x_years: \"%{count}blwyddyn\"\n      almost_x_years: \"%{count}blwyddyn\"\n      half_a_minute: Newydd fod\n      less_than_x_minutes: \"%{count}munud\"\n      less_than_x_seconds: Newydd fod\n      over_x_years: \"%{count}blwyddyn\"\n      x_days: \"%{count}dydd\"\n      x_minutes: \"%{count}munud\"\n      x_months: \"%{count}mis\"\n      x_seconds: \"%{count}eiliad\"\n  deletes:\n    bad_password_msg: Go dda, hacwyr! Cyfrinair anghywir\n    confirm_password: Mewnbynnwch eich cyfrinair presennol i gadarnhau mai chi sydd yno\n    description_html: Bydd hyn yn cael gwared ar gynnwys o'ch cyfrif <strong>am byth heb fodd i'w adfer</strong> ac yn diffodd y cyfrif. Caiff eich eich enw defnyddiwr ei gadw i atal unrhyw ddynwarediadau yn y dyfodol.\n    proceed: Dileu cyfrif\n    success_msg: Llwyddwyd i ddileu eich cyfrif\n    warning_html: Dim ond dileu cynnwys o'r achos hwn ellid bod yn sicr ei fod wedi ei ddileu. Mae cynnwys sydd wedi ei rannu'n eang yn debygol o adael olion. Ni fydd gweinyddwyr all-lein a gweinyddwyr sydd wedi dad-danysgrifio o'ch diwedderiadau ddim yn diweddaru eu cronfeydd data.\n    warning_title: Argaeledd cynnwys wedi'i rannu\n  directories:\n    directory: Cyfeiriadur proffil\n    enabled: Rydych chi wedi'ch rhestru yn y cyfeiriadur ar hyn o bryd.\n    enabled_but_waiting: Rydych wedi dewis i chi gael eich rhestru yn y cyfeiriadur, ond nid oes gennych y nifer lleiaf o ddilynwyr (%{min_followers}) i'w rhestru eto.\n    explanation: Darganfod defnyddwyr yn seiliedig ar eu diddordebau\n    explore_mastodon: Archwilio %{title}\n    how_to_enable: Ar hyn o bryd nid ydych chi wedi dewis y cyfeiriadur. Gallwch ddewis i mewn isod. Defnyddiwch hashnodau yn eich bio-destun i'w restru dan hashnodau penodol!\n  errors:\n    '403': Nid oes gennych ganiatad i weld y dudalen hon.\n    '404': Nid yw'r dudalen yr oeddech yn chwilio amdani'n bodoli.\n    '410': Nid yw'r dudalen yr oeddech yn chwilio amdani'n bodoli mwyach.\n    '422':\n      content: Methwyd i ddilysu diogelwch. A ydych chi'n blocio cwcîs?\n      title: Methwyd i ddilysu diogelwch\n    '429': Wedi'i arafu\n    '500':\n      content: Mae'n ddrwg gennym ni, ond fe aeth rhywbeth o'i le ar ein rhan ni.\n      title: Nid yw'r dudalen hon yn gywir\n    noscript_html: I ddefnyddio ap gwe Mastodon, galluogwch JavaScript os gwlwch yn dda. Fel arall, gallwch drio un o'r <a href=\"%{apps_path}\">apiau cynhenid</a> ar gyfer Mastodon ar eich platfform.\n  existing_username_validator:\n    not_found: ni ddarganfwyd defnyddiwr lleol gyda'r enw cyfrif hynny\n    not_found_multiple: ni ddarganfwyd %{usernames}\n  exports:\n    archive_takeout:\n      date: Dyddiad\n      download: Lawrlwytho eich archif\n      hint_html: Mae modd gwneud cais am archif o'ch <strong>twtiau a'ch cyfryngau</strong>. Bydd y data sy'n cael ei allforio ar fformat ActivityPub, a ellir ei ddarllen gyda unrhyw feddalwaedd sy'n cydymffurfio. Mae modd gwneud cais am archif bob 7 diwrnod.\n      in_progress: Cyfansoddi eich archif...\n      request: Gwneud cais am eich archif\n      size: Maint\n    blocks: Yr ydych yn blocio\n    csv: CSV\n    domain_blocks: Blociau parth\n    follows: Yr ydych yn dilyn\n    lists: Rhestrau\n    mutes: Yr ydych yn tawelu\n    storage: Storio cyfryngau\n  featured_tags:\n    add_new: Ychwanegu\n    errors:\n      limit: Yr ydych yn barod wedi cynnwys yr uchafswm o hashnodau\n  filters:\n    contexts:\n      home: Ffrwd gartref\n      notifications: Hysbysiadau\n      public: Ffrwd gyhoeddus\n      thread: Sgyrsiau\n    edit:\n      title: Golygu hidlydd\n    errors:\n      invalid_context: Dim cyd-destun neu cyd-destun annilys wedi ei ddarparu\n      invalid_irreversible: Mae hidlo anadferadwy ond yn gweithio yng nghyd-destun cartref neu hysbysiadau\n    index:\n      delete: Dileu\n      title: Hidlyddion\n    new:\n      title: Ychwanegu hidlydd newydd\n  footer:\n    developers: Datblygwyr\n    more: Mwy…\n    resources: Adnoddau\n  generic:\n    all: Popeth\n    changes_saved_msg: Llwyddwyd i gadw y newidiadau!\n    copy: Copïo\n    order_by: Trefnu wrth\n    save_changes: Cadw newidiadau\n    validation_errors:\n      few: Mae rhywbeth o'i le o hyd! Edrychwch ar y %{count} gwall isod os gwelwch yn dda\n      many: Mae rhywbeth o'i le o hyd! Edrychwch ar y %{count} gwall isod os gwelwch yn dda\n      one: Mae rhywbeth o'i le o hyd! Edrychwch ar y gwall isod os gwelwch yn dda\n      other: Mae rhywbeth o'i le o hyd! Edrychwch ar y %{count} gwall isod os gwelwch yn dda\n      two: Mae rhywbeth o'i le o hyd! Edrychwch ar y %{count} gwall isod os gwelwch yn dda\n      zero: Mae rhywbeth o'i le o hyd! Edrychwch ar y %{count} gwall isod os gwelwch yn dda\n  html_validator:\n    invalid_markup: 'yn cynnwys marciad HTML annilys: %{error}'\n  identity_proofs:\n    active: Yn weithredol\n    authorize: Ie, awdurdodi\n    authorize_connection_prompt: Awdurdodi y cysylltiad cryptograffig hon?\n    errors:\n      failed: Methwyd y cysylltiad cryptograffig. Ceisiwch eto o %{provider}, os gwelwch yn dda.\n      keybase:\n        invalid_token: Mae tocynnau keybase yn hashiau o llofnodau ac mae rhaid iddynt bod yn 66 cymeriadau hecs\n        verification_failed: Nid yw Keybase yn adnabod y tocyn hyn fel llofnod defnyddiwr Keybase %{kb_username}. Cesiwch eto o Keybase, os gwelwch yn dda.\n      wrong_user: Ni all greu prawf ar gyfer %{proving} tra wedi mewngofnodi fel %{current}. Mewngofnodi fel %{proving} a cheisiwch eto.\n    explanation_html: Fama gallwch cysylltu i'ch hunanieithau arall yn cryptograffig, er enghraifft proffil Keybase. Mae hyn yn gadael pobl arall i anfon chi negeseuon amgryptiedig a ymddiried mewn cynnwys rydych yn eich anfon iddynt.\n    i_am_html: Rydw i'n %{username} ar %{service}.\n    identity: Hunaniaeth\n    inactive: Anweithgar\n    publicize_checkbox: 'A thŵtiwch hon:'\n    publicize_toot: 'Wedi profi! Rydw i''n %{username} ar %{service}: %{url}'\n    status: Statws gwirio\n    view_proof: Gweld prawf\n  imports:\n    modes:\n      merge: Cyfuno\n      merge_long: Cadw'r cofnodau presennol ac ychwanegu rhai newydd\n      overwrite: Trosysgrifio\n      overwrite_long: Disodli cofnodau bresennol gyda'r cofnodau newydd\n    preface: Mae modd mewnforio data yr ydych wedi allforio o achos arall, megis rhestr o bobl yr ydych yn ei ddilyn neu yn blocio.\n    success: Uwchlwythwyd eich data yn llwyddiannus ac fe fydd yn cael ei brosesu mewn da bryd\n    types:\n      blocking: Rhestr blocio\n      domain_blocking: Rhestr rhwystro parth\n      following: Rhestr dilyn\n      muting: Rhestr tawelu\n    upload: Uwchlwytho\n  in_memoriam_html: Mewn Cofiad.\n  invites:\n    delete: Dadactifadu\n    expired: Wedi darfod\n    expires_in:\n      '1800': 30 munud\n      '21600': 6 awr\n      '3600': 1 awr\n      '43200': 12 awr\n      '604800': 1 wythnos\n      '86400': 1 dydd\n    expires_in_prompt: Byth\n    generate: Cynhyrchu\n    invited_by: 'Cawsoch eich gwahodd gan:'\n    max_uses:\n      few: \"%{count} defnydd\"\n      many: \"%{count} defnydd\"\n      one: 1 iws\n      other: \"%{count} defnydd\"\n      two: \"%{count} defnydd\"\n      zero: \"%{count} defnydd\"\n    max_uses_prompt: Dim terfyn\n    prompt: Cynhyrchwch a rhannwch ddolenni gyda eraill i ganiatau mynediad i'r achos hwn\n    table:\n      expires_at: Darfod ar\n      uses: Defnyddiau\n    title: Gwahodd pobl\n  lists:\n    errors:\n      limit: Yr ydych wedi cyrraedd uchafswm nifer y rhestrau posib\n  media_attachments:\n    validations:\n      images_and_video: Ni ellir ychwanegu fideo at statws sy'n cynnwys delweddau'n barod\n      too_many: Ni ellir ychwanegu mwy na 4 dogfen\n  migrations:\n    acct: enwdefnyddiwr@parth y cyfrif newydd\n    currently_redirecting: 'Mae eich proffil wedi ei osod i ailgyfeirio i:'\n    proceed: Cadw\n    updated_msg: Diweddarwyd gosodiad mudo eich cyfrif yn llwyddiannus!\n  moderation:\n    title: Goruwchwyliad\n  notification_mailer:\n    digest:\n      action: Gweld holl hysbysiadau\n      body: Dyma grynodeb byr o'r holl negeseuon golloch chi ers eich ymweliad diwethaf ar %{since}\n      mention: 'Soniodd %{name} amdanoch chi:'\n      new_followers_summary:\n        few: Hefyd, rydych wedi ennill %{count} dilynwr newydd tra eich bod i ffwrdd! Hwrê!\n        many: Hefyd, rydych wedi ennill %{count} dilynwr newydd tra eich bod i ffwrdd! Hwrê!\n        one: Yr ydych wedi ennill dilynwr newydd tra eich bod i ffwrdd! Hwrê!\n        other: Hefyd, rydych wedi ennill %{count} dilynwr newydd tra eich bod i ffwrdd! Hwrê!\n        two: Hefyd, rydych wedi ennill %{count} dilynwr newydd tra eich bod i ffwrdd! Hwrê!\n        zero: Hefyd, rydych wedi ennill %{count} dilynwr newydd tra eich bod i ffwrdd! Hwrê!\n      subject:\n        few: \"%{count} hysbysiad newydd ers eich ymweliad diwethaf\"\n        many: \"%{count} hysbysiad newydd ers eich ymweliad diwethaf\"\n        one: 1 hysbysiad newydd ers eich ymweliad diwethaf\n        other: \"%{count} hysbysiad newydd ers eich ymweliad diwethaf\"\n        two: \"%{count} hysbysiad newydd ers eich ymweliad diwethaf\"\n        zero: \"%{count} hysbysiad newydd ers eich ymweliad diwethaf\"\n      title: Yn eich absenoldeb...\n    favourite:\n      body: 'Cafodd eich statws ei hoffi gan %{name}:'\n      subject: Hoffodd %{name} eich statws\n      title: Ffefryn newydd\n    follow:\n      body: Mae %{name} bellach yn eich dilyn!\n      subject: Mae %{name} bellach yn eich dilyn\n      title: Dilynwr newydd\n    follow_request:\n      action: Rheoli ceisiadau dilyn\n      body: Mae %{name} wedi gwneud cais i'ch dilyn\n      subject: 'Dilynwr yn aros: %{name}'\n      title: Cais dilynwr newydd\n    mention:\n      action: Ateb\n      body: 'Caswoch eich sôn amdano gan %{name} yn:'\n      subject: Cawsoch eich sôn amdano gan %{name}\n      title: Crywbylliad newydd\n    reblog:\n      body: 'Cafodd eich statws ei fŵstio gan %{name}:'\n      subject: Bŵstiodd %{name} eich statws\n      title: Hwb newydd\n  number:\n    human:\n      decimal_units:\n        format: \"%n%u\"\n        units:\n          billion: Biliwn\n          million: Miliwn\n          quadrillion: Cwadriliwn\n          thousand: Mil\n          trillion: Triliwn\n  pagination:\n    newer: Diweddarach\n    next: Nesaf\n    older: Hŷn\n    prev: Blaenorol\n    truncate: \"&hellip;\"\n  polls:\n    errors:\n      already_voted: Rydych chi barod wedi pleidleisio ar y pleidlais hon\n      duplicate_options: yn cynnwys eitemau dyblyg\n      duration_too_long: yn rhy bell yn y dyfodol\n      duration_too_short: yn rhy fuan\n      expired: Mae'r pleidlais wedi gorffen yn barod\n      over_character_limit: ni all fod yn hirach na %{max} cymeriad yr un\n      too_few_options: rhaid cael fwy nag un eitem\n      too_many_options: ni all cynnwys fwy na %{max} o eitemau\n  preferences:\n    other: Arall\n    posting_defaults: Rhagosodiadau postio\n    public_timelines: Ffrydau gyhoeddus\n  relationships:\n    activity: Gweithgareddau cyfrif\n    dormant: Segur\n    last_active: Gweithred ddiwethaf\n    most_recent: Yn diweddaraf\n    moved: Wedi symud\n    mutual: Cydfuddiannol\n    primary: Cynradd\n    relationship: Perthynas\n    remove_selected_domains: Tynnu pob dilynydd o'r parthau dewisiedig\n    remove_selected_followers: Tynnu'r dilynydd dewisiedig\n    remove_selected_follows: Dad-ddilyn y defnyddwyr dewisiedig\n    status: Statws cyfrif\n  remote_follow:\n    acct: Mewnbynnwch eich enwdefnyddiwr@parth yr ydych eisiau gweithredu ohonno\n    missing_resource: Ni ellir canfod yr URL ailgyferio angenrheidiol i'ch cyfrif\n    no_account_html: Heb gyfrif? Mae modd i chi <a href='%{sign_up_path}' target='_blank'>gofrestru yma</a>\n    proceed: Ymlaen i ddilyn\n    prompt: 'Yr ydych am ddilyn:'\n  remote_unfollow:\n    error: Gwall\n    title: Teitl\n    unfollowed: Dad-ddilynwyd\n  sessions:\n    activity: Gweithgaredd ddiwethaf\n    browser: Porwr\n    browsers:\n      generic: Porwr anhysbys\n      nokia: Porwr Nokia S40 Ovi\n      qq: Porwr QQ\n    current_session: Sesiwn cyfredol\n    description: \"%{browser} ar %{platform}\"\n    explanation: Dyma'r porwyr gwê sydd wedi mewngofnodi i'ch cyfrif Mastododon ar hyn o bryd.\n    platforms:\n      other: platfform anhysbys\n    revoke: Diddymu\n    revoke_success: Sesiwn wedi ei ddiddymu yn llwyddiannus\n    title: Sesiynau\n  settings:\n    authorized_apps: Apiau awdurdodedig\n    back: Yn ôl i Mastodon\n    delete: Dileu cyfrif\n    development: Datblygu\n    edit_profile: Golygu proffil\n    export: Allforio data\n    import: Mewnforio\n    migrate: Mudo cyfrif\n    notifications: Hysbysiadau\n    preferences: Dewisiadau\n    two_factor_authentication: Awdurdodi dau-gam\n  statuses:\n    attached:\n      description: 'Ynghlwm: %{attached}'\n      image:\n        few: \"%{count} o luniau\"\n        many: \"%{count} o luniau\"\n        one: \"%{count} llun\"\n        other: \"%{count} o luniau\"\n        two: \"%{count} o luniau\"\n        zero: \"%{count} o luniau\"\n      video:\n        few: \"%{count} fideo\"\n        many: \"%{count} fideo\"\n        one: \"%{count} fideo\"\n        other: \"%{count} fideo\"\n        two: \"%{count} fideo\"\n        zero: \"%{count} fideo\"\n    boosted_from_html: Wedi ei fŵstio %{acct_link}\n    content_warning: 'Rhybudd cynnwys: %{warning}'\n    disallowed_hashtags:\n      few: 'yn cynnwys yr hashnod gwaharddedig: %{tags}'\n      many: 'yn cynnwys yr hashnod gwaharddedig: %{tags}'\n      one: 'yn cynnwys hashnod gwaharddedig: %{tags}'\n      other: 'yn cynnwys yr hashnod gwaharddedig: %{tags}'\n      two: 'yn cynnwys yr hashnod gwaharddedig: %{tags}'\n      zero: 'yn cynnwys yr hashnod gwaharddedig: %{tags}'\n    language_detection: Canfod iaith yn awtomataidd\n    open_in_web: Agor yn y wê\n    over_character_limit: wedi mynd heibio'r uchafswm nodyn o %{max}\n    pin_errors:\n      limit: Yr ydych wedi pinio yr uchafswm posib o dŵtiau\n      ownership: Ni ellir pinio tŵt rhywun arall\n      private: Ni ellir pinio tŵt nad yw'n gyhoeddus\n      reblog: Ni ellir pinio bŵstiau\n    show_more: Dangos mwy\n    sign_in_to_participate: Mengofnodwch i gymryd rhan yn y sgwrs\n    visibilities:\n      private: Dilynwyr yn unig\n      private_long: Dangos i ddilynwyr yn unig\n      public: Cyhoeddus\n      public_long: Gall pawb weld\n      unlisted: Heb ei restru\n      unlisted_long: Gall pawb weld, ond heb ei restru ar ffrydiau cyhoeddus\n  stream_entries:\n    pinned: Tŵt wedi'i binio\n    reblogged: hybwyd\n    sensitive_content: Cynnwys sensitif\n  terms:\n    body_html: |\n      <h2>Polisi Preifatrwydd</h2>\n      <h3 id=\"collect\">Pa wybodaeth ydyn ni'n ei gasglu?</h3>\n\n      <ul>\n      <li><em>Gwybodaeth cyfrif sylfaenol</em>: Os ydych yn cofrestru ar y gweinydd hwn, mae'n bosib y byddwch yn cael eich gofyn i fewnbynnu enw defnyddiwr, cyfeiriad e-bost a chyfrinair. Mae modd i chi hefyd fewnbynnu gwybodaeth ychwanegol megis enw arddangos a bywgraffiad ac uwchlwytho llun proffil a llun pennawd. Mae'r enw defnyddiwr, enw arddangos, bywgraffiad, llun proffil a'r llun pennawd wedi eu rhestru'n gyhoeddus bob tro.</li>\n      <li><em>Postio, dilyn a gwybodaeth gyhoeddus arall</em>: Mae'r rhestr o bobl yr ydych yn dilyn wedi ei restru'n gyhoeddus, mae'r un peth yn wir am eich dilynwyr. Pan yr ydych yn mewnosod neges, mae'r dyddiad a'r amser yn cael ei gofnodi ynghyd a'r rhaglen y wnaethoch anfon y neges ohonni. Gall negeseuon gynnwys atodiadau cyfryngau, megis lluniau neu fideo. Mae negeseuon cyhoeddus a negeseuon heb eu rhestru ar gael yn gyhoeddus. Pan yr ydych yn nodweddu neges ar eich proffil, mae hynny hefyd yn wybodaeth sydd ar gael yn gyhoeddus. Mae eich negeseuon yn cael eu hanfon i'ch dilynwyr, mewn rhai achosion mae hyn yn golygu eu bod yn cael eu hanfon i amryw o weinyddwyr ac fe fydd copiau yn cael eu cadw yno. Pan yr ydych yn dileu negeseuon, mae hyn hefyd yn cael ei hanfon i'ch dilynwyr. Mae'r weithred o rannu neu hoffi neges arall yn gyhoeddus bob tro.</li>\n      <li><em>Negeseuon uniongyrchol a dilynwyr yn unig</em>: Mae pob neges yn cael eu cadw a'u prosesu ar y gweinydd. Mae negeseuon dilynwyr yn unig yn cael eu hanfon i'ch dilynwyr a'r defnyddwyr sy'n cael eu crybwyll ynddynt tra bod negeseuon uniongyrchol yn cael eu hanfon at rheini sy'n cael crybwyll ynddynt yn unig. Mewn rhai achostion golyga hyn eu bod yn cael eu hanfon i weinyddwyr gwahanol a'u cadw yno. yr ydym yn gnweud ymgais ewyllys da i gyfyngu'r mynediad at y negeseuon yna i bobl ac awdurdod yn unig, ond mae'n bosib y bydd gweinyddwyr eraill yn methu a gwneud hyn. Mae'n bwysig felly i chi fod yn wyliadwrus o ba weinyddwyr y mae eich dilynwyr yn perthyn iddynt. Mae modd i chi osod y dewis i ganiatau a gwrthod dilynwyr newydd a llaw yn y gosodiadau. <em>Cofiwch gall gweithredwyr y gweinydd ac unrhyw weinydd derbyn weld unrhyw negeseuon o'r fath</em>, ac fe all y derbynwyr gymryd sgrinlin, copïo neu drwy ddulliau eraill rannu rhain. <em>Peidiwch a rhannu unrhyw wybodaeth beryglus dros Mastodon.</em></li>\n      <li><em>IPs a mathau eraill o metadata</em>: Pan yr ydych yn mewngofnodi, yr ydym yn cofnodi y cyfeiriad IP yr ydych yn mewngofnodi ohonno, ynghyd a enw eich rhaglen pori. Mae pob un sesiwn mewngofnodi ar gael i chi adolygu a gwrthod yn y gosodiadau. Mae'r cyfeiriad IP diweddaraf yn cael ei storio hyd at 12 mis. Mae'n bosib y byddwn hefyd yn cadw cofnodion gweinydd sy'n cynnwys y cyfeiriad IP am bob cais sy'n cael ei wneud i'n gweinydd.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"use\">Beth ydym yn defnyddio eich gywbodaeth ar ei gyfer?</h3>\n\n      <p>Gall unrhyw wybodaeth yr ydym yn ei gasglu oddi wrthych gael ei ddefnyddio yn y ffyrdd canlynol:</p>\n\n      <ul>\n      <li>I ddarparu prif weithgaredd Mastodon. Gallwch ond rhyngweithio a chynnwys pobl eraill pan yr ydych wedi'ch mewngofnodi. Er enghraifft, gallwch ddilyn pobl eraill i weld eu negeseuon wedi cyfuno ar ffrwd gartref bersonol.</li>\n      <li>I helpu gyda goruwchwylio'r gymuned, er enghraifft drwy gymharu eich cyfeiriad IP gyda rhai eraill hysbys er mwyn sefydlu ymgais i geisio hepgor gwaharddiad neu droseddau eraill.</li>\n      <li>Gall y cyfeiriad e-bost yr ydych yn ei ddarparu gael ei ddefnyddio i anfon gwybodaeth atoch, hsybysiadau am bobl eraill yn rhyngweithio a'ch cynnwys neu'n anfon negeseuon atoch a/neu geisiadau neu gwestiynnau eraill.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"protect\">Sut ydym yn amddiffyn eich gwybodaeth?</h3>\n\n      <p>Mae gennym amryw o fesurau diogelwch er mwyn cynnal diogelwch eich gwybodaeth bersonol pan yr ydych yn mewnosod, cyflwyno neu'n cael mynediad at eich gwybodaeth bersonol. Ymysg pethau eraill, mae sesiwn eich porwr, ynghyd a'r traffig rhwng eich rhaglenni a'r API wedi eu diogelu gan SSL, ac mae'ch cyfrinair yn cael ei stwnshio drwy ddefnyddio algorithm cryf un-ffordd. Gallwch alluogi dilysu dau-gam er mwyn cryfhau diogelwch mynediad i'ch cyfrif ymhellach.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"data-retention\">Beth yw ein polisi cadw data?</h3>\n\n      <p>Gwnawn ymdrech ewyllys da i:</p>\n\n      <ul>\n      <li>Gadw cofnod gweinydd yn cynnwys y cyfeiriad IP o bob cais i'r gweinydd hwn, i'r graddau y mae cofnodion o'r fath yn cael eu cadw, am ddim mwy na 90 diwrnod.</li>\n      <li>Gadw cyfeiriadau IP a chysylltiad i ddefnyddwyr cofrestredig am ddim mwy na 12 mis.</li>\n      </ul>\n\n      <p>Mae modd i chi wneud cais am, a lawrlwytho archif o'ch cynnwys, gan gynnwys eich tŵtiau, atodiadau cyfryngau, llun proffil a llun pennawd.</p>\n\n      <p>Mae modd i chi ddileu eich cyfrif heb ei adfer ar unrhyw bryd</p>\n\n      <hr class=\"spacer\"/>\n\n      <h3 id=\"cookies\">Ydyn ni'n defnyddio cwcis?</h3>\n\n      <p>Ydyn. Dogfennau bach sy'n cael eu trosglwyddo i ddisg galed eich cyfrifiadur drwy eich porwr gan wefan neu wasanaeth yw cwcis (os ydych yn eu caniatau). Galluoga'r cwcis hyn i'r wefan i adnabod eich porwr ac, os oes gennych gyfrif wedi ei gofrestru, ei gysylltu gyda'r cyfrif yr ydych wedi ei gofrestru.</p>\n\n      <p>Rydym yn defnyddio cwcis i ddeall a chadw eich dewisiadau ar gyfer ymweliadau yn y dyfodol.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"disclose\">Ydyn ni'n datgelu unrhyw wybodaeth i bartïoedd allanol?</h3>\n\n      <p>Nid ydym yn gwerthu, cyfnewid neu mewn unrhyw ddull yn trosglwyddo i bartïoedd allanol eich gwybodaeth bersonol. Nid yw hyn yn cynnwys trydydd partïon yr ydym yn ymddiried ynddynt sy'n ein cynorthwyo i weithredu ein gwefan, cynnal ein busnes neu'ch gwasanaethu chi, cyhyd a bod y partïoedd hynny yn cytuno i gadw'r wybodaeth yma'n gyfrinachol. Mae'n bosib i ni ryddhau eich gwybodaeth pan yr ydym yn credu fod ei ryddhau yn briodol er mwyn cydymffurfio a'r gyfraith, gorfodi ein polisiau, neu i amddiffyn hawliau, eiddo neu diogelwch eraill.</p>\n\n      <p>Gall eich cynnwys cyhoeddus gael ei lawrlwytho gan weinyddwyr eraill yn y rhwydwaith. Mae eich tŵtiau cyhoeddus a'r rhai dilynwyr yn unig yn cael eu hanfon i'r gweinyddwyr sy'n lletya eich dilynwyr, tra bod negeseuon uniongrychol yn cael eu hanfon at weinyddwyr y derbynwyr, cyn belled a fod y dilynwyr neu'r derbynwyr hynny yn bodoli ar weinydd gwahanol i'r un hwn.</p>\n\n      <p>Pan yr ydych yn caniatau y rhaglen hwn i ddefnyddio'ch cyfrif, yn dibynnu ar sgôp yr hyn yr ydych yn caniatau, gallai gael mynediad at eich gwybodaeth proffil cyhoeddus, eich rhestr dilynwyr, eich dilynwyr, eich rhestrau, eich holl dŵtiau a'ch ffefrynnau. Ni all rhaglenni byth gael mynediad at eich cyfeiriad e-bost na chwaith eich cyfrinair.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"children\">Defnydd o'r wefan gan blant</h3>\n\n      <p>Os yw'r gweinydd hwn yn yr UE neu'r EEA: Mae ein gwefan, ein nwyddau a'n gwasanaethau oll wedi eu cyfeirio at bobl sydd dros 16 mlwydd oed. Os ydych o dan 16, yn ôl gofyniad y GDPR (<a href=\"https://en.wikipedia.org/wiki/General_Data_Protection_Regulation\">General Data Protection Regulation</a>) peidiwch a defnyddio'r wefan hon.</p>\n\n      <p>Os yw'r gweinydd hwn yn UDA: Mae ein gwefan, ein nwyddau a'n gwasanaethau oll wedi eu cyfeirio at bobl sydd dros 13 mlwydd oed oleiaf. Os ydych o dan 13 mlwydd oed, yn ôl gofyniad COPPA (<a href=\"https://en.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act\">Children's Online Privacy Protection Act</a>) peidiwch a defnyddio'r wefan hon.</p>\n\n      <p>Mae gofynion y gyfraith yn gallu bod yn wahanol os yw'r gweinydd hwn mewn awdurdodaeth wahanol.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"changes\">Newidiadau i'n Polisi Preifatrwydd</h3>\n\n      <p>Os ydyn yn penderfynnu i newid ein polisi preifatrwydd, fe wnawn ni roi'r newidiadau hynny ar y dudalen hon.</p>\n\n      <p>Mae'r ddogfen hon yn CC-BY-SA. Cafodd ei ddiweddaru diwethaf ar y 7fed o Fawrth, 2018.</p>\n\n      <p>Cafodd ei addasu yn wreiddiol o'r<a href=\"https://github.com/discourse/discourse\">Polisi preifatrwydd disgwrs</a>.</p>\n    title: \"%{instance} Termau Gwasanaeth a Polisi Preifatrwydd\"\n  themes:\n    contrast: Mastodon (Cyferbyniad uchel)\n    default: Mastodon (Tywyll)\n    mastodon-light: Mastodon (golau)\n  two_factor_authentication:\n    code_hint: Mewnbynwch y côd a grewyd gan eich ap dilysu i gadarnhau\n    description_html: Os ydych yn galluogi <strong>awdurdodi dau-gam</strong>, bydd mewngofnodi yn gofyn i chi fod a'ch ffôn gerllaw er mwyn cynhyrchu tocyn i chi gael mewnbynnu.\n    disable: Diffodd\n    enable: Galluogi\n    enabled: Awdurdodi dau-gam wedi'i alluogi\n    enabled_success: Awdurdodi dau-gam wedi'i alluogi'n llwyddiannus\n    generate_recovery_codes: Cynhyrchu côdau adfer\n    instructions_html: \"<strong>Sganiwch y côd QR yn Google Authenticator neu ap TOTP tebyg ar eich ffôn</strong>. O hyn ymlaen, bydd yr ap hwnnw yn cynhyrchu tocynnau y bydd rhaid i chi fewnbynnu tra'n mewngofnodi.\"\n    lost_recovery_codes: Mae côdau adfer yn caniatau i chi gael mynediad i'ch cyfrif eto os ydych yn colli'ch ffôn. Os ydych wedi colli eich côdau adfer, mae modd i chi gynhyrchu nhw eto yma. Bydd eich hen gôdau wedyn yn annilys.\n    manual_instructions: 'Os nad ydych yn gallu sganio côd QR ac angen ei fewnbynnu a llaw, dyma''r gyfrinach testun-plaen:'\n    recovery_codes: Creu copi wrth gefn o gôdau adfywio\n    recovery_codes_regenerated: Llwyddwyd i ail greu côdau adfywio\n    recovery_instructions_html: Os ydych byth yn colli mynediad i'ch ffôn, mae modd i chi ddefnyddio un o'r côdau adfywio isod i ennill mynediad i'ch cyfrif eto. <strong>Cadwch y côdau adfywio yn saff</strong>. Er enghraifft, gallwch eu argraffu a'u cadw gyda dogfennau eraill pwysig.\n    setup: Sefydlu\n    wrong_code: Roedd y cod y mewnbynnwyd yn annilys! A yw'r amser gweinydd ac amser dyfais yn gywir?\n  user_mailer:\n    backup_ready:\n      explanation: Fe wnaethoch chi gais am gopi wrth gefn llawn o'ch cyfrif Mastodon. Mae nawr yn barod i'w lawrlwytho!\n      subject: Mae eich archif yn barod i'w lawrlwytho\n      title: Allfudo archif\n    warning:\n      explanation:\n        disable: Er bod eich cyfrif wedi'i rewi, mae eich data cyfrif yn parhau i fod yn gyfan, ond ni allwch chi berfformio unrhyw gamau nes ei ddatgloi.\n      review_server_policies: Adolygu polisïau'r gweinydd\n      subject:\n        disable: Mae'ch cyfrif %{acct} wedi'i rewi\n        none: Rhybudd am %{acct}\n        silence: Mae'ch cyfrif %{acct} wedi bod yn gyfyngedig\n        suspend: Mae'ch cyfrif %{acct} wedi'i atal\n      title:\n        disable: Cyfrif wedi'i rewi\n        none: Rhybudd\n        silence: Cyfrif cyfyngedig\n        suspend: Cyfrif wedi'i rewi\n    welcome:\n      edit_profile_action: Sefydlu proffil\n      edit_profile_step: Mae modd i chi addasu eich proffil drwy uwchlwytho afatar, pennawd, drwy newid eich enw arddangos a mwy. Os hoffech chi adolygu dilynwyr newydd cyn iddynt gael caniatad i'ch dilyn, mae modd i chi gloi eich cyfrif.\n      explanation: Dyma ambell nodyn i'ch helpu i ddechrau\n      final_action: Dechrau postio\n      final_step: 'Dechrau postio! Hyd yn oed heb ddilynwyr mae''n bosib i eraill weld eich negeseuon cyhoeddus, er enghraifft at y ffrwd leol ac mewn hashnodau. Mae''n bosib yr hoffech hi gyflwyno''ch hun ar yr hashnod #introductions.'\n      full_handle: Eich enw llawn\n      full_handle_hint: Dyma'r hyn y bysech yn dweud wrth eich ffrindiau er mwyn iddyn nhw gael anfon neges atoch o achos arall.\n      review_preferences_action: Newid dewisiadau\n      review_preferences_step: Gwnewch yn siŵr i chi osod eich dewisiadau, megis pa e-byst hoffech eu derbyn, neu ba lefel preifatrwydd hoffech eich tŵtiau ragosod i. Os nad oes gennych salwch symud, gallwch ddewis i ganiatau chwarae GIFs yn awtomatig.\n      subject: Croeso i Mastodon\n      tip_federated_timeline: Mae'r ffrwd ffederasiwn yn olwg firehose o'r rhwydwaith Mastodon. Ond mae ond yn cynnwys y bobl mae eich cymdogion wedi ymrestru iddynt, felly nid yw'n gyflawn.\n      tip_following: Rydych yn dilyn goruwchwyliwr eich gweinydd yn ddiofyn. I ganfod pobl mwy diddorol, edrychwch ar y ffrydiau lleol a'r rhai wedi ei ffedereiddio.\n      tip_local_timeline: Mae'r ffrwd leol yn olwg firehose o bobl ar %{instance}. Dyma eich cymdogion agosaf!\n      tip_mobile_webapp: Os yw eich porwr gwe yn cynnig i ch ychwanegu Mastodon i'ch sgrîn gartref, mae modd i chi dderbyn hysbysiadau push. Mewn sawl modd mae'n gweithio fel ap cynhenid!\n      tips: Awgrymiadau\n      title: Croeso, %{name}!\n  users:\n    follow_limit_reached: Nid oes modd i chi ddilyn mwy na %{limit} o bobl\n    invalid_email: Mae'r cyfeiriad e-bost hwn yn annilys\n    invalid_otp_token: Côd dau-ffactor annilys\n    otp_lost_help_html: Os colloch chi fynediad i'r ddau, mae modd i chi gysylltu a %{email}\n    seamless_external_login: Yr ydych wedi'ch mewngofnodi drwy wasanaeth allanol, felly nid yw gosodiadau cyfrinair ac e-bost ar gael.\n    signed_in_as: 'Wedi mewngofnodi fel:'\n  verification:\n    explanation_html: 'Mae modd i chi <strong>ddilysu eich hun fel perchenog y dolenni yn metadata eich proffil</strong>. Rhaid i''r wefan a dolen iddi gynnwys dolen yn ôl i''ch proffil Mastodon. <strong>Rhaid</strong> i''r ddolen yn ôl gael nodwedd <code>rel=\"fi\"</code>. Nid oes ots beth yw cynnwys testun y ddolen. Dyma enghraifft:'\n    verification: Dilysu\n"
  },
  {
    "path": "config/locales/da.yml",
    "content": "---\nda:\n  about:\n    about_hashtag_html: Disse er offentlige trut der indeholder tagget <strong>#%{hashtag}</strong>. Du kan interagere med dem hvis du har en konto hvor som helst i fediverset.\n    about_mastodon_html: Mastodon er et socialt netværk der er baseret på åbne web protokoller og frit, open-source source software. Der er decentraliseret ligesom e-mail tjenester.\n    about_this: Om\n    administered_by: 'Administreret af:'\n    apps: Apps til mobilen\n    apps_platforms: Brug Mastodon på iOS, Android og andre platformer\n    contact: Kontakt\n    contact_missing: Ikke sat\n    contact_unavailable: Ikke tilgængeligt\n    documentation: Dokumentation\n    extended_description_html: |\n      <h3>Et godt sted for regler</h3>\n      <p>Den udvidede beskrivelse er endnu ikke blevet opsat.</p>\n    generic_description: \"%{domain} er en server i netværket\"\n    hosted_on: Mostodon hostet på %{domain}\n    learn_more: Lær mere\n    privacy_policy: Privatlivspolitik\n    source_code: Kildekode\n    status_count_before: Som har skrevet\n    terms: Vilkår for service\n    user_count_after:\n      one: bruger\n      other: brugere\n    user_count_before: Hjem til\n    what_is_mastodon: Hvad er Mastodon?\n  accounts:\n    choices_html: \"%{name}s valg:\"\n    follow: Følg\n    followers:\n      one: Følger\n      other: Følgere\n    following: Følger\n    joined: Tilmeldt den %{date}\n    link_verified_on: Ejerskabet af dette link blev tjekket den %{date}\n    media: Medier\n    moved_html: \"%{name} er flyttet til %{new_profile_link}:\"\n    network_hidden: Denne information er ikke tilgængelig\n    nothing_here: Der er intet her!\n    people_followed_by: Folk som %{name} følger\n    people_who_follow: Folk der følger %{name}\n    pin_errors:\n      following: Du er nødt til at følge den person du ønsker at støtte\n    posts:\n      one: Trut\n      other: Trut\n    posts_tab_heading: Trut\n    posts_with_replies: Trut og svar\n    reserved_username: Brugernavnet er allerede taget\n    roles:\n      admin: Administrator\n      bot: Robot\n      moderator: Moderator\n    unfollow: Følg ikke længere\n  admin:\n    account_actions:\n      action: Udfør handling\n    account_moderation_notes:\n      create: Læg en note\n      created_msg: Moderator notat succesfuldt oprettet!\n      delete: Slet\n      destroyed_msg: Moderator notat succesfuldt destrueret!\n    accounts:\n      are_you_sure: Er du sikker?\n      avatar: Profilbillede\n      by_domain: Domæne\n      change_email:\n        changed_msg: Email til konto succesfuldt ændret!\n        current_email: Nuværende email\n        label: Ændre email\n        new_email: Ny email\n        submit: Ændre email\n        title: Ændre email for %{username}\n      confirm: Bekræft\n      confirmed: Bekræftet\n      confirming: Bekræfter\n      demote: Degrader\n      disable: Deaktiver\n      disable_two_factor_authentication: Deaktiver 2FA\n      disabled: Deaktiveret\n      display_name: Visningsnavn\n      domain: Domæne\n      edit: Rediger\n      enable: Aktiver\n      enabled: Aktiveret\n      feed_url: Link til feed\n      followers: Følgere\n      followers_url: Link til følgere\n      follows: Følger\n      inbox_url: Link til indbakke\n      ip: IP-adresse\n      location:\n        all: Alle\n        local: Lokalt\n        remote: Fjernt\n        title: Placering\n      login_status: Status på login\n      media_attachments: Medie bilag\n      memorialize: Omdan til et memoriam\n      moderation:\n        all: Alle\n        silenced: Dæmpet\n        suspended: Udelukket\n        title: Moderasion\n      moderation_notes: Moderator notater\n      most_recent_activity: Seneste aktivitet\n      most_recent_ip: Senest IP\n      not_subscribed: Ikke abonneret\n      outbox_url: Link til udgående\n      perform_full_suspension: Udeluk\n      profile_url: Link til profil\n      promote: Forfrem\n      protocol: Protokol\n      public: Offentligt\n      push_subscription_expires: PuSH abonnement udløber\n      redownload: Opdater profil\n      remove_avatar: Fjern profilbillede\n      resend_confirmation:\n        already_confirmed: Denne bruger er allerede blevet bekræftet\n        send: Gensend bekræftelsesmail\n        success: Bekræftelsesmail sendt succesfuldt!\n      reset: Nulstil\n      reset_password: Nulstil kodeord\n      resubscribe: Abonner igen\n      role: Tilladelser\n      roles:\n        admin: Admin\n        moderator: Mod\n        staff: Personale\n        user: Bruger\n      salmon_url: Salmon-URL\n      search: Søg\n      shared_inbox_url: Link til delt indbakke\n      show:\n        created_reports: Anmeldelser oprettet\n        targeted_reports: Anmeldelser fra andre\n      silence: Dæmp\n      silenced: Dæmpet\n      statuses: Statusser\n      subscribe: Abonner\n      suspended: Udelukket\n      title: Konti\n      unconfirmed_email: Ikke-bekræftet email\n      undo_silenced: Fortryd dæmpning\n      undo_suspension: Fortryd udelukkelse\n      unsubscribe: Abonner ikke længere\n      username: Brugernavn\n    action_logs:\n      actions:\n        assigned_to_self_report: \"%{name} tildelte anmeldelsen %{target} til sig selv\"\n        change_email_user: \"%{name} ændrede email adressen for brugeren %{target}\"\n        confirm_user: \"%{name} bekræftede %{target}s email adresse\"\n        create_custom_emoji: \"%{name} uploadede humørikonet %{target}\"\n        create_domain_block: \"%{name} blokerede domænet %{target}\"\n        create_email_domain_block: \"%{name} sortlistede email domænet %{target}\"\n        demote_user: \"%{name} degraderede %{target}\"\n        destroy_domain_block: \"%{name} fjernede blokeringen af domænet %{target}\"\n        destroy_email_domain_block: \"%{name} hvid-listede email domænet %{target}\"\n        destroy_status: \"%{name} fjernede statussen fra %{target}\"\n        disable_2fa_user: \"%{name} deaktiverede to faktor kravet for brugeren %{target}\"\n        disable_custom_emoji: \"%{name} deaktiverede humørikonet %{target}\"\n        disable_user: \"%{name} deaktiverede login for brugeren %{target}\"\n        enable_custom_emoji: \"%{name} aktiverede humørikonet %{target}\"\n        enable_user: \"%{name} aktiverede login for brugeren %{target}\"\n        memorialize_account: \"%{name} omdannede %{target}s konto til en mindeside\"\n        promote_user: \"%{name} forfremmede brugeren %{target}\"\n        remove_avatar_user: \"%{name} fjernede %{target}s profilbillede\"\n        reopen_report: \"%{name} genåbnede anmeldelsen %{target}\"\n        reset_password_user: \"%{name} nulstillede kodeordet for brugeren %{target}\"\n        resolve_report: \"%{name} løste anmeldelsen %{target}\"\n        silence_account: \"%{name} dæmpede %{target}s konto\"\n        suspend_account: \"%{name} udelukkede %{target}s konto\"\n        unassigned_report: \"%{name} fjernede tildelingen af rapporten %{target}\"\n        unsilence_account: \"%{name} fjernede dæmpningen fra %{target}s konto\"\n        unsuspend_account: \"%{name} fjernede udelukkelsen fra %{target}s konto\"\n        update_custom_emoji: \"%{name} opdaterede humørikonet %{target}\"\n        update_status: \"%{name} opdaterede status for %{target}\"\n      deleted_status: \"(slettet status)\"\n      title: Revisionslog\n    custom_emojis:\n      by_domain: Domæne\n      copied_msg: Succesfuldt oprettede en lokal kopi af humørikonet\n      copy: Kopier\n      copy_failed_msg: Kunne ikke oprette en lokal kopi af dette humørikon\n      created_msg: Humørikon succesfuldt oprettet!\n      delete: Slet\n      destroyed_msg: Emojo succesfuldt destrueret!\n      disable: Deaktiver\n      disabled_msg: Succesfuldt deaktiverede det humørikon\n      emoji: Humørikon\n      enable: Aktiver\n      enabled_msg: Succesfuldt aktiverede det humørikon\n      image_hint: PNG op til 50KB\n      listed: Listet\n      new:\n        title: Tilføj nyt brugerdefineret humørikon\n      overwrite: Overskriv\n      shortcode: Kortkode\n      shortcode_hint: Mindst 2 tegn, kun alfabetiske tegn og understreger\n      title: Brugerdefinerede humørikoner\n      unlisted: Ikke listet\n      update_failed_msg: Kunne ikke opdatere det humørikon\n      updated_msg: Humørikon succesfuldt opdateret!\n      upload: Læg op\n    dashboard:\n      backlog: ophobede jobs\n      config: Konfiguration\n      feature_deletions: Konto sletninger\n      feature_invites: Invitations links\n      feature_registrations: Registreringer\n      feature_relay: Føderations relæ\n      features: Funktioner\n      hidden_service: Føderation med skjulte tjenester\n      open_reports: åbne anmeldelser\n      recent_users: Seneste brugere\n      search: Søg på fuld tekst\n      single_user_mode: Enkelt bruger mode\n      space: Brugt lagerplads\n      title: Betjeningspanel\n      total_users: samlede antal brugere\n      trends: Tendenser\n      week_interactions: interaktioner denne uge\n      week_users_active: aktive denne uge\n      week_users_new: brugere denne uge\n    domain_blocks:\n      add_new: Tilføj ny domain block\n      created_msg: Domæne blokade bliver nu behandlet\n      destroyed_msg: Domæne blokade er blevet annulleret\n      domain: Domæne\n      new:\n        create: Opret blokering\n        hint: Domæne blokeringen vil ikke forhindre oprettelse af konto opslag i databasen, men vil retroaktivt og automatisk benytte specifikke moderator metoder på disse konti.\n        severity:\n          desc_html: \"<strong>Dæmp</strong> vil gøre denne kontos opslag usynlige til alle der ikke følger dem. <strong>Udeluk</strong> vil fjerne al kontoens indhold, medie og profildata. Brug <strong>Ingen</strong> hvis du bare ønsker at afvise medie filer.\"\n          noop: Ingen\n          silence: Dæmp\n          suspend: Udeluk\n        title: Ny domæne blokering\n      reject_media: Afvis medie filer\n      reject_media_hint: Fjerner lokalt lagrede multimedie filer og nægter at hente nogen i fremtiden. Irrelevant for udelukkelser\n      reject_reports: Afvis anmeldelser\n      show:\n        affected_accounts:\n          one: En konto i databasen påvirket\n          other: \"%{count} konti i databasen påvirket\"\n        retroactive:\n          silence: Fjern dæmpningen af alle eksisterende konti fra dette domæne\n          suspend: Fjern udelukkelsen af alle eksisterende konti fra dette domæne\n        title: Annuller domæne blokeringen for domænet %{domain}\n        undo: Fortryd\n      undo: Fortryd domain block\n    email_domain_blocks:\n      add_new: Tilføj ny\n      created_msg: Tilføjede succesfuldt email domænet til sortliste\n      delete: Slet\n      destroyed_msg: Fjernede succesfuldt email domænet fra sortliste\n      domain: Domæne\n      new:\n        create: Tilføj domæne\n        title: Ny email blokade opslag\n      title: Email sortliste\n    followers:\n      back_to_account: Tilbage til konto\n    instances:\n      title: Førderation\n    invites:\n      deactivate_all: Deaktiver alle\n      filter:\n        all: Alle\n        available: Tilgængelig\n        expired: Udløbet\n        title: Filtre\n      title: Invitationer\n    relays:\n      add_new: Tilføj nyt relay\n      delete: Slet\n      description_html: Et <strong>federation relay</strong> er en mellemleds server der udveksler store mængder af offentlige trut mellem servere der abonnerer på og offentliggør til det. <strong>Det kan hjælpe små og mellemstore servere opdage indhold fra fediverset</strong>, hvilket der ellers ville kræve at lokale brugere manuelt følger andre folk på fjerne servere.\n      disable: Deaktiver\n      disabled: Deaktiveret\n      enable: Aktiver\n      enable_hint: Når dette er aktiveret, vil serveren abonnere på alle offentlige trut fra dette relay, og vil begynde at sende offentlige trut fra denne server dertil.\n      enabled: Aktiveret\n      inbox_url: Link til relay\n      pending: Venter på godkendelse fra relæet\n      save_and_enable: Gem og aktiver\n      setup: Opsæt en videresendelses forbindelse\n      title: Videresendelser\n    report_notes:\n      created_msg: Anmeldelse note blev oprettet!\n      destroyed_msg: Anmeldelse note blev slettet!\n    reports:\n      account:\n        note: notat\n        report: anmeld\n      action_taken_by: Handling udført af\n      are_you_sure: Er du sikker?\n      assign_to_self: Tildel til mig\n      assigned: Tildelt moderator\n      comment:\n        none: Ingen\n      created_at: Anmeldt\n      mark_as_resolved: Marker som værende løst\n      mark_as_unresolved: Marker som værende uløst\n      notes:\n        create: Tilføj notat\n        create_and_resolve: Løs med notat\n        create_and_unresolve: Genåbne med notat\n        delete: Slet\n        placeholder: Beskriv hvilke handlinger der er blevet udført, eller andre relevante opdateringer...\n      reopen: Genåben anmeldelse\n      report: 'Anmeldelse #%{id}'\n      reported_account: Anmeldt konto\n      reported_by: Anmeldt af\n      resolved: Løst\n      resolved_msg: Anmeldelse er sat til at være løst!\n      title: Anmeldelser\n      unassign: Utildel\n      unresolved: Uløst\n      updated_at: Opdateret\n    settings:\n      activity_api_enabled:\n        desc_html: Antal af lokalt opslåede statusser, aktive brugere, og nye registreringer i ugentlige opdelinger\n        title: Offentliggør samlede statistikker vedrørende brugeraktivitet\n      bootstrap_timeline_accounts:\n        desc_html: Opdel flere brugernavne ved hjælp af komma. Kun lokale og ulåste konti vil virke. Standard hvis tom er alle lokale administratorer.\n        title: Standard følger for nye brugere\n      contact_information:\n        email: Forretnings email\n        username: Kontakt brugernavn\n      custom_css:\n        desc_html: Ændre udseendet med CSS indlæst på hver side\n        title: Brugerdefineret CSS\n      hero:\n        desc_html: Vist på forsiden. Mindst 600x100px anbefales. Hvis ikke sat, vil dette falde tilbage til billedet fra serveren\n        title: Billede af helt\n      peers_api_enabled:\n        desc_html: Domæne navne denne server er stødt på i fediverset\n        title: Udgiv liste over opdagede server\n      preview_sensitive_media:\n        desc_html: Forhåndsvisninger af links på andre websider vil vise et miniaturebillede selv hvis mediet er markeret som følsomt\n        title: Vis følsomt medie i OpenGraph forhåndsvisninger\n      registrations:\n        closed_message:\n          desc_html: Vist på forsiden når registreringer er lukkede. Du kan bruge HTML tags\n          title: Besked for lukkede registreringer\n        deletion:\n          desc_html: Tillad alle at slette deres konto\n          title: Åben konto sletning\n        min_invite_role:\n          disabled: Ingen\n          title: Tillad invitationer af\n      show_known_fediverse_at_about_page:\n        desc_html: Når slået til, vil det vise trut fra hele det kendte fedivers på forhåndsvisning. Ellers vil det kun vise lokale trut.\n        title: Vis kendte fedivers på tidslinje forhåndsvisning\n      show_staff_badge:\n        desc_html: Vis personale emblem på en brugerside\n        title: Vis personale emblem\n      site_description:\n        desc_html: Introduktions afsnit på forsiden. Beskriv hvad der gør denne Mastodon server speciel og alt andet vigtigt. Du kan bruge HTML tags, især <code>&lt;a&gt;</code> og <code>&lt;em&gt;</code>.\n        title: Beskrivelse af serveren\n      site_description_extended:\n        desc_html: Et godt sted for placering af adfærdskodes, regler, retningslinjer og andre ting der gør din server unik. Du kan bruge HTML tags\n        title: Brugerdefineret udvidet information\n      site_short_description:\n        desc_html: Vist på sidelinjen og meta tags. Beskriv hvad Mastodon er og hvad der gør denne server speciel i et enkelt afsnit. Hvis tomt, vil standard være beskrivelsen af serveren.\n        title: Kort beskrivelse af serveren\n      site_terms:\n        desc_html: Du kan skrive din egen privatlivpolitik, servicevilkår, eller lignende. Du kan bruge HTML tags\n        title: Brugerdefineret servicevilkår\n      site_title: Navn af serveren\n      thumbnail:\n        desc_html: Brugt til forhåndsvisninger via OpenGraph og API. 1200x630px anbefales\n        title: Miniaturebillede for serveren\n      timeline_preview:\n        desc_html: Vis offentlig tidslinje på landingssiden\n        title: Tidslinje forhåndsvisning\n      title: Indstillinger for side\n    statuses:\n      back_to_account: Tilbage til kontosiden\n      batch:\n        delete: Slet\n        nsfw_off: Marker som værende ikke følsomt\n        nsfw_on: Marker som værende følsomt\n      failed_to_execute: Udførelsen kunne ikke lade sig gøre\n      media:\n        title: Multimedier\n      no_media: Ingen multimedier\n      no_status_selected: Ingen statusser blev ændret eller ingen blev valgt\n      title: Konto statusser\n      with_media: Med multimedier\n    subscriptions:\n      callback_url: Callback-URL\n      confirmed: Bekræftet\n      expires_in: Udløber om\n      last_delivery: Sidste levering\n      title: Websub\n      topic: Emne\n    tags:\n      accounts: Kontoer\n      hidden: Skjult\n  admin_mailer:\n    new_report:\n      body: \"%{reporter} har anmeldt %{target}\"\n      body_remote: Nogen fra %{domain} har anmeldt %{target}\n      subject: Ny anmeldelse for %{instance} (#%{id})\n  application_mailer:\n    notification_preferences: Ændre email præferencer\n    settings: 'Ændre email præferencer: %{link}'\n    view: 'Se:'\n    view_profile: Se profil\n    view_status: Se status\n  applications:\n    created: Applikation blev oprettet\n    destroyed: Applikation er blevet slettet\n    invalid_url: Det angivne URL er ugyldigt\n    regenerate_token: Regenerer adgangs token\n    token_regenerated: Adgangs token blev regenereret\n    warning: Vær meget forsigtig med disse data. Del dem aldrig med nogen!\n    your_token: Din adgangs token\n  auth:\n    change_password: Kodeord\n    confirm_email: Bekræft email\n    delete_account: Slet konto\n    delete_account_html: Hvis du ønsker at slette din konto, kan du <a href=\"%{path}\">gøre det her</a>. Du vil blive bedt om bekræftelse.\n    didnt_get_confirmation: Har du endnu ikke modtaget instrukser for bekræftelse?\n    forgot_password: Glemt dit kodeord?\n    invalid_reset_password_token: Adgangskode nulstillings token er ugyldig eller udløbet. Anmod venligst om en ny.\n    login: Log ind\n    logout: Log ud\n    migrate_account: Flyt til en anden konto\n    migrate_account_html: Hvis du ønsker at omdirigere denne konto til en anden, kan du <a href=\"%{path}\">gøre det her</a>.\n    or_log_in_with: Eller log in med\n    register: Opret dig\n    resend_confirmation: Gensend bekræftelses instrukser\n    reset_password: Nulstil kodeord\n    security: Sikkerhed\n    set_new_password: Sæt et nyt kodeord\n  authorize_follow:\n    already_following: Du følger allerede denne konto\n    error: Der opstod desværre en fejl under søgningen af denne fjerne konto\n    follow: Følg\n    follow_request: 'Du har anmodet om at følge:'\n    following: 'Succes! Du følger nu:'\n    post_follow:\n      close: Du kan også bare lukke dette vindue.\n      return: Vis brugerens profil\n      web: Gå til web\n    title: Følg %{acct}\n  datetime:\n    distance_in_words:\n      about_x_hours: \"%{count}t\"\n      about_x_months: \"%{count} måneder\"\n      about_x_years: \"%{count}år\"\n      almost_x_years: \"%{count}år\"\n      half_a_minute: Lige nu\n      less_than_x_seconds: Lige nu\n      over_x_years: \"%{count}år\"\n      x_months: \"%{count}md\"\n  deletes:\n    bad_password_msg: Godt forsøg, hackere! Forkert kodeord\n    confirm_password: Indtast dit nuværende kodeord for at bekræfte din identitet\n    description_html: Dette vil <strong>permanent, uigenkaldeligt</strong> fjerne indhold fra din konto samt deaktivere den. Dit brugernavn vil forblive reserveret for at forhindre fremtidige efterligninger.\n    proceed: Slet konto\n    success_msg: Din konto er nu blevet slettet\n    warning_html: Kun sletning af indhold fra denne specifikke server er garanteret. Indhold der er blevet delt rundt omkring vil sandsynligvis efterlade spor. Offline servere og servere der ikke længere abonnerer på dine opdateringer vil ikke opdatere deres databaser.\n    warning_title: Tilgængelighed af delt indhold\n  errors:\n    '403': Du har ikke tilladelse til at se denne side.\n    '404': Den side du leder efter findes ikke.\n    '410': Den side du leder efter findes ikke mere.\n    '422':\n      content: Sikkerhedsbekræftelse mislykkedes. Blokerer du cookies?\n      title: Sikkerheds godkendelse mislykkedes\n    '429': Droslet\n    '500':\n      content: Beklager men der gik noget galt i vores ende.\n      title: Siden er ikke korrekt\n    noscript_html: For at bruge Mastodon web applikationen, aktiver JavaScript. Alternativt kan du prøve en af disse <a href=\"%{apps_path}\">apps</a> til Mastodon for din platform.\n  exports:\n    archive_takeout:\n      date: Dato\n      download: Hent dit arkiv\n      hint_html: Du kan anmode om et arkiv af dine <strong>trut og oplagt medie</strong>. Den eksporterede data vil være i ActivityPub formattet, læseligt af enhvert kompatibel program. Du kan anmode om et arkiv en gang om ugen.\n      in_progress: Udarbejder dit arkiv...\n      request: Anmod om dit arkiv\n      size: Størrelse\n    blocks: Du blokerer\n    follows: Du følger\n    mutes: Du dæmper\n    storage: Medie lager\n  filters:\n    contexts:\n      home: Hjemme tidslinje\n      notifications: Notifikationer\n      public: Offentlig tidslinje\n      thread: Samtaler\n    edit:\n      title: Rediger filter\n    errors:\n      invalid_context: Ingen eller ugyldig kontekst angivet\n      invalid_irreversible: Uigenkaldelig filtrering virker kun med hjem eller notifikations kontekst\n    index:\n      delete: Slet\n      title: Filtrer\n    new:\n      title: Tilføj nyt filter\n  footer:\n    developers: Udviklere\n    more: Mere…\n    resources: Ressourcer\n  generic:\n    changes_saved_msg: Ændringerne blev gemt!\n    copy: Kopier\n    save_changes: Gem ændringer\n    validation_errors:\n      one: Der er noget der ikke er helt som det bør være! Tag lige et kig på følgende fejl forneden\n      other: Der er noget der ikke er helt som det bør være! Tag lige et kig på følgende %{count} fejl forneden\n  imports:\n    preface: Du kan importere data du har eksporteret fra en anden server, så som en liste over folk du følger eller blokerer.\n    success: Dine data blev succesfuldt uploaded og vil nu blive behandlet hurtigst muligt\n    types:\n      blocking: Blokeringsliste\n      following: Følgningsliste\n      muting: Liste over dæmpninger\n    upload: Læg op\n  in_memoriam_html: Til minde om.\n  invites:\n    delete: Deaktiver\n    expired: Udløbet\n    expires_in:\n      '1800': 30 minutter\n      '21600': 6 timer\n      '3600': 1 time\n      '43200': 12 timer\n      '604800': 1 uge\n      '86400': 1 dag\n    expires_in_prompt: Aldrig\n    generate: Generer\n    invited_by: 'Du er blevet inviteret af:'\n    max_uses:\n      one: 1 benyttelse\n      other: \"%{count} benyttelser\"\n    max_uses_prompt: Ubegrænset\n    prompt: Generer og del links med andre for at give dem adgang til denne server\n    table:\n      expires_at: Udløber\n      uses: Benyttelser\n    title: Inviter folk\n  lists:\n    errors:\n      limit: Du har nået det højeste antal lister\n  media_attachments:\n    validations:\n      images_and_video: Kan ikke vedhæfte en video til en status der allerede har billeder\n      too_many: Kan ikke vedhæfte mere en 4 filer\n  migrations:\n    acct: username@domain af den nye konto\n    currently_redirecting: 'Din profil er sat til at henvise til:'\n    proceed: Gem\n    updated_msg: Dine konti migrærings indstillinger blev opdateret!\n  moderation:\n    title: Moderatering\n  notification_mailer:\n    digest:\n      action: Se alle notifikationer\n      body: Her er en kort gennemgang af de beskeder du gik glip af siden dit sidste besøg den %{since}\n      mention: \"%{name} nævnte dig i:\"\n      new_followers_summary:\n        one: Du har også fået dig en ny følger mens du var væk! Sådan!\n        other: Du har også fået %{count} nye følgere mens du var væk! Fantastisk!\n      subject:\n        one: \"1 ny notifikation siden du sidst var her \\U0001F418\"\n        other: \"%{count} nye notifikationer siden du sidst var her \\U0001F418\"\n      title: Mens du var væk...\n    favourite:\n      body: 'Din status blev favoriseret af %{name}:'\n      subject: \"%{name} favoriserede din status\"\n      title: Ny favorit\n    follow:\n      body: \"%{name} følger dig nu!\"\n      subject: \"%{name} følger dig nu\"\n      title: Ny følger\n    follow_request:\n      action: Håndter følgeranmodninger\n      body: \"%{name} har anmodet om at følge dig\"\n      subject: 'Følger afventer: %{name}'\n      title: Ny følgeranmodning\n    mention:\n      action: Svar\n      body: 'Du blev nævnt af %{name} i:'\n      subject: Du blev nævnt af %{name}\n      title: Ny omtale\n    reblog:\n      body: 'Din status blev fremhævet af %{name}:'\n      subject: \"%{name} fremhævede din status\"\n      title: Ny fremhævelse\n  number:\n    human:\n      decimal_units:\n        units:\n          billion: mia.\n          million: mio.\n  pagination:\n    newer: Nyere\n    next: Næste\n    older: Ældre\n    prev: Forrige\n    truncate: \"...&hellip;\"\n  preferences:\n    other: Andet\n  remote_follow:\n    acct: Indtast dit brugernavn@domæne du vil handle fra\n    missing_resource: Kunne ikke finde det påkrævede omdirigerings link for din konto\n    no_account_html: Har du ikke en konto? Du kan <a href='%{sign_up_path}' target='_blank'>oprette dig her</a>\n    proceed: Fortsæt for at følge\n    prompt: 'Du er ved at følge:'\n  remote_unfollow:\n    error: Fejl\n    title: Titel\n    unfollowed: Følger ikke længere\n  sessions:\n    activity: Sidste aktivitet\n    browsers:\n      alipay: Ali-pay\n      blackberry: Blackberry OS\n      chrome: Google Chrome\n      edge: Microsoft edge\n      electron: Elektron\n      firefox: Mozilla Firefox\n      generic: Ukendt browser\n      ie: IE\n      micro_messenger: Micromessenger\n      nokia: Nokia S40 ovi browser\n      opera: Opera browser\n      otter: Odder\n      phantom_js: FantomJS\n      qq: QQ browser\n      safari: Apple Safari\n      uc_browser: UCbrowser\n      weibo: Weibo browser\n    current_session: Nuværrende session\n    description: \"%{browser} på %{platform}\"\n    explanation: Disse er de web browsere der på nuværende tidspunkt er logget ind på din Mastodon konto.\n    platforms:\n      adobe_air: Adobe air\n      blackberry: Blackberry OS\n      chrome_os: Chromeos\n      firefox_os: Firefox Os\n      mac: Mac.\n      other: ukendt platform\n      windows: Microsoft windows\n      windows_mobile: Windows mobil\n      windows_phone: Windows fon\n    revoke: Tilbagekald\n    revoke_success: Sessionen blev tilbagekaldt\n    title: Sessioner\n  settings:\n    authorized_apps: Godkendte apps\n    back: Tilbage til Mastodon\n    delete: Sletning af konto\n    development: Udvikling\n    edit_profile: Rediger profil\n    export: Data eksportering\n    import: Importer\n    migrate: Konto migrering\n    notifications: Notifikationer\n    preferences: Præferencer\n    two_factor_authentication: To-faktor godkendelse\n  statuses:\n    attached:\n      description: 'Vedhæftede: %{attached}'\n      image:\n        one: \"%{count} billede\"\n        other: \"%{count} billeder\"\n    boosted_from_html: Fremhævet fra %{acct_link}\n    content_warning: 'Advarsel om indhold: %{warning}'\n    disallowed_hashtags:\n      one: 'indeholdte et ikke tilladt hashtag: %{tags}'\n      other: 'indeholdte de ikke tilladte hashtags: %{tags}'\n    language_detection: Opfang automatisk sprog\n    open_in_web: Åbn i browser\n    over_character_limit: grænsen på %{max} tegn er overskredet\n    pin_errors:\n      limit: Du har allerede fastgjort det maksimale antal trut\n      ownership: Du kan ikke fastgøre en anden persons trut\n      private: Ikke offentlige trut kan ikke blive fastgjort\n      reblog: Fremhævede trut kan ikke fastgøres\n    show_more: Vis mere\n    sign_in_to_participate: Log ind for at deltage i samtalen\n    visibilities:\n      private: Kun-følgere\n      private_long: Vis kun til følgere\n      public: Offentlig\n      public_long: Alle kan se\n      unlisted: Ikke listet\n      unlisted_long: Alle kan se, men vil ikke være listet på offentlige tidslinjer\n  stream_entries:\n    pinned: Fastgjort trut\n    reblogged: fremhævede\n    sensitive_content: Følsomt indhold\n  terms:\n    body_html: \"<p><h2> Privatlivspolitik </h2> \\n<h3 id=\\\"collect\\\">Hvilke information indsamler vi?</h3> \\n\\n<ul>\\n  <li><em>Grundlæggende kontoinformation </em>: Hvis du registrerer dig på denne server, bliver du måske bedt om at indtaste et brugernavn, en e-mail-adresse og et kodeord. Du kan også indtaste yderligere profiloplysninger, såsom et visningsnavn og biografi, og uploade et profilbillede og headerbillede. Brugernavnet, visningsnavnet, biografien, profilbilledet og hovedbilledet vises altid offentligt. </li> \\n  <li> <em>Stillinger, følgende og andre offentlige oplysninger </em>: Listen over personer du følger er offentliggjort, det samme gælder for dine tilhængere. Når du sender en besked, gemmes datoen og klokkeslættet såvel som det program, du sendte beskeden fra. Meddelelser kan indeholde medievedhæftninger, som f.eks. Billeder og videoer. Offentlige og unoterede indlæg er offentligt tilgængelige. Når du har et indlæg på din profil, er det også offentligt tilgængelig information. Dine indlæg leveres til dine tilhængere, i nogle tilfælde betyder det, at de leveres til forskellige servere, og der gemmes kopier der. Når du sletter indlæg, leveres det også til dine tilhængere. Handlingen med reblogging eller favorisering af et andet indlæg er altid offentligt. </li>\\n  <li><em> Direkte og efterfølger-kun indlæg </ em>: Alle indlæg gemmes og behandles på serveren. Følgere-kun indlæg leveres til dine tilhængere og brugere, der er nævnt i dem, og direkte indlæg leveres kun til brugere nævnt i dem. I nogle tilfælde betyder det, at de leveres til forskellige servere, og der gemmes kopier der. Vi gør en god tro for at begrænse adgangen til disse stillinger kun til autoriserede personer, men andre servere kan undlade at gøre det. Derfor er det vigtigt at gennemgå de servere, dine tilhængere tilhører. Du kan skifte en mulighed for at godkende og afvise nye følgere manuelt i indstillingerne. <em> Vær opmærksom på, at operatørerne af serveren og enhver modtagende server muligvis kan se sådanne meddelelser </em>, og at modtagere muligvis skærmbilleder, kopierer eller på anden vis deler dem igen. <em> Del ikke nogen farlig information over Mastodon. </em> </li>\\n  <li> <em> IP'er og andre metadata </em>: Når du logger ind, registrerer vi den IP-adresse, du logger ind fra, samt navnet på din browser-applikation. Alle indloggede sessioner er tilgængelige til din anmeldelse og tilbagekaldelse i indstillingerne. Den seneste anvendte IP-adresse gemmes i op til 12 måneder. Vi kan også beholde serverlogfiler, som indeholder IP-adressen til hver anmodning til vores server. </li>\\n</ul>\\n\\n<hr class=\\\"spacer\\\" />\\n\\n<h3 id=\\\"use\\\">Hvad bruger vi dine oplysninger til? </h3>\\n\\n<p> Enhver af de oplysninger, vi indsamler fra dig, kan bruges på følgende måder: </p>\\n\\n<ul>\\n  <li> At levere kernen funktionalitet Mastodon. Du kan kun interagere med andres indhold og indsende dit eget indhold, når du er logget ind. Du kan f.eks. Følge andre personer for at se deres kombinerede indlæg på din egen personlige tidslinje. </li>\\n  <li> For at hjælpe moderering af samfundet, f.eks. sammenligning af din IP-adresse med andre kendte, for at bestemme forbud mod unddragelse eller andre overtrædelser. </li>\\n  <li> Den e-mail-adresse, du angiver, kan bruges til at sende dig oplysninger, meddelelser om andre personer, der interagerer med dit indhold eller sender dig beskeder, og for at svare på henvendelser og / eller andre forespørgsler eller spørgsmål. </li>\\n</ul>\\n\\n<hr class=\\\"spacer\\\" />\\n\\n<h3 id=\\\"protect\\\">Hvordan beskytter vi dine oplysninger? </h3>\\n\\n<p> Vi implementerer en række sikkerhedsforanstaltninger for at opretholde sikkerheden for dine personlige oplysninger, når du indtaster, indsender eller har adgang til dine personlige oplysninger. Bl.a. er din browsersession samt trafikken mellem dine applikationer og API'en sikret med SSL, og din adgangskode er hashed ved hjælp af en stærk envejsalgoritme. Du kan muligvis aktivere tofaktors godkendelse for yderligere at sikre adgang til din konto. </p>\\n\\n<hr class=\\\"spacer\\\" />\\n\\n<h3 id=\\\"data-retention\\\"> Hvad er vores data retention politik? </h3>\\n\\n<p> Vi vil gøre en god tro indsats for at: </p>\\n\\n<ul>\\n  <li> Behold serverlogfiler, der indeholder IP-adressen på alle anmodninger til denne server, for så vidt som sådanne logfiler holdes, ikke mere end 90 dage. </li>\\n  <li> Behold de IP-adresser, der er forbundet med registrerede brugere, ikke mere end 12 måneder. </li>\\n</ul>\\n\\n<p> Du kan anmode om og downloade et arkiv af dit indhold, herunder dine indlæg, medievedhæftninger, profilbillede og headerbillede. </p>\\n\\n<p> Du kan til enhver tid slette din konto. </p>\\n\\n<hr class=\\\"spacer\\\" />\\n\\n<h3 id=\\\"cookies\\\"> Bruger vi cookies? </h3>\\n\\n<p> Ja. Cookies er små filer, som et websted eller dets tjenesteudbyder overfører til din computers harddisk via din webbrowser (hvis du tillader det). Disse cookies gør det muligt for webstedet at genkende din browser og, hvis du har en registreret konto, associerer den med din registrerede konto. </p>\\n\\n<p> Vi bruger cookies til at forstå og gemme dine præferencer til fremtidige besøg. </p>\\n\\n<hr class=\\\"spacer\\\" />\\n\\n<h3 id=\\\"disclose\\\"> Viser vi nogen information til eksterne parter? </h3>\\n\\n<p> Vi sælger ikke, handler eller på anden måde overfører dine personlige identificerbare oplysninger til eksterne parter. Dette omfatter ikke tillid til tredjeparter, der hjælper os med at drive vores hjemmeside, udføre vores forretning eller servicere dig, så længe parterne er enige om at holde disse oplysninger fortrolige. Vi kan også frigive dine oplysninger, når vi mener, at udgivelsen er hensigtsmæssig for at overholde loven, håndhæve vores webstedspolitikker eller beskytte vores eller andre rettigheder, ejendom eller sikkerhed. </p>\\n\\n<p> Dit offentlige indhold kan downloades af andre servere i netværket. Dine offentlige og efterfølger-kun indlæg leveres til de servere, hvor dine tilhængere er bosat, og direkte meddelelser leveres til modtagerens servere, for så vidt som disse tilhængere eller modtagere opholder sig på en anden server end dette. </p>\\n\\n<p> Når du autoriserer et program til at bruge din konto, afhænger det af omfanget af tilladelser, du godkender, det kan få adgang til dine offentlige profiloplysninger, din følgende liste, dine tilhængere, dine lister, alle dine indlæg og dine favoritter. Applikationer kan aldrig få adgang til din e-mail-adresse eller adgangskode. </p>\\n\\n<hr class=\\\"spacer\\\" />\\n\\n<h3 id=\\\"children\\\"> Bebyggelse af børn </h3>\\n\\n<p> Hvis denne server er i EU eller EØS: Vores websted, produkter og tjenester er alle rettet mod personer, der er mindst 16 år gamle. Hvis du er under 16 år, skal du ikke bruge dette websted efter kravene i GDPR (<a href=\\\"https://en.wikipedia.org/wiki/General_Data_Protection_Regulation\\\"> Generel databeskyttelsesforordning </a>). . </p>\\n\\n<p> Hvis denne server er i USA: Vores websted, produkter og tjenester er alle rettet mod personer, der er mindst 13 år. Hvis du er under 13 år, skal du ikke bruge kravene i COPPA (<a href=\\\"https://en.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act\\\"> Børns online beskyttelse af personlige oplysninger </a>) dette websted. </p>\\n\\n<p> Lovkrav kan være anderledes, hvis denne server er i en anden jurisdiktion. </p>\\n\\n<hr class = \\\"spacer\\\" />\\n\\n<h3 id=\\\"changes\\\"> Ændringer i vores privatlivspolitik </h3>\\n\\n<p> Hvis vi beslutter os for at ændre vores privatlivspolitik, vil vi sende disse ændringer på denne side. </p>\\n\\n<p> Dette dokument er CC-BY-SA. Det blev senest opdateret 7. marts 2018. </p>\\n\\n<p> Oprindelig tilpasset fra <a href=\\\"https://github.com/discourse/discourse\\\"> Discourse privacy policy </a>.</p>\\n\"\n    title: Vilkår og privatlivpolitik for %{instance}\n  themes:\n    contrast: Mastodon (Høj kontrast)\n    default: Mastodont (Mørk)\n    mastodon-light: Mastodon (Lys)\n  two_factor_authentication:\n    code_hint: Indtast koden der er genereret af din app for at bekræfte\n    description_html: Hvis du aktiverer <strong>to-faktor godkendelse</strong>, vil du være nødt til at være i besiddelse af din telefon, der genererer tokens som du skal indtaste, når du logger ind.\n    disable: Deaktiver\n    enable: Aktiver\n    enabled: To-faktor godkendelse er aktiveret\n    enabled_success: To-faktor godkendelse succesfuldt aktiveret\n    generate_recovery_codes: Generer gendannelseskoder\n    instructions_html: \"<strong>Scan denne QR kode i Google Autehnticator eller lignende TOTP app på din telefon</strong>. Fra nu af vil den app generere koder som du vil være nødt til at indtaste når du logger ind.\"\n    lost_recovery_codes: Gendannelseskoder vil lade dig få adgang til din konto hvis du mister din telefon. Hvis du har mistet dine gendannelseskoder, kan du regenerere dem her. Dine gamle gendannelseskoder vil blive ugyldige.\n    manual_instructions: 'Hvis du ikke kan scanne QR koden er er nødt til at skrive koden ind manuelt, kan er din almindelig tekst secret:'\n    recovery_codes: Reserve koder\n    recovery_codes_regenerated: Reserve koder blev succesfuldt regenereret\n    recovery_instructions_html: Hvis du nogensinde mister adgang til din telefon, kan du bruge en af genoprettelses koderne forneden for at få adgang til din konto. <strong>Gem gendannelses koderne et sikkert sted</strong>. Foreksempel kan du printe dem ud og gemme dem sammen med andre vigtige dokumenter.\n    setup: Sæt op\n    wrong_code: Den indtastede kode var ugyldig! Er serverens tid og enhedens tid korrekte?\n  user_mailer:\n    backup_ready:\n      explanation: Din anmodning for fuld backup af din Mastodon konto. Den er nu klar til at blive hentet!\n      subject: Dit arkiv er klar til at blive hentet ned\n      title: Udpluk af arkiv\n    welcome:\n      edit_profile_action: Opsæt profil\n      edit_profile_step: Du kan skræddersy din profil ved at uploade et profilbillede, overskrift, ændre dit visningsnavn og mere. Hvis du kunne tænke dig at gennemse nye følgere før de må følge dig, kan du låse din konto.\n      explanation: Her er nogle råd til at starte med\n      final_action: Kom igang med at poste\n      final_step: 'Start med at skrive opslag! Selv uden følgere vil dine offentlige beskeder kunne ses af andre, foreksempel på den lokale tidslinje og i hashtags. Måske kunne du tænke dig at introducere dig selv på #introductions hashtagget.'\n      full_handle: Dit fulde brugernavn\n      full_handle_hint: Dette er hvad du vil fortælle dine venner så de kan sende dig beskeder eller følge dig fra andre server.\n      review_preferences_action: Ændre præferencer\n      review_preferences_step: Vær sikker på at sætte dine præferencer, så som hvilke emails du kunne tænke dig at modtage, eller hvilket niveau af privatliv der skal være standard for dine opslag. Hvis du kunne tænke dig ikke at blive køresyg, kan du vælge at aktivere automatisk afspilning af GIFfer.\n      subject: Velkommen til Mastodon\n      tip_federated_timeline: Den delte tidslinje er et brandslange agtigt indblik over Mastodon netværket. Men det inkluderer kun folk dine naboer abonnerer på, så den er ikke fuldendt.\n      tip_following: Du følger som standard administratoren(e) for den server du er på. For at finde flere folk, tjek både den lokale og fælles tidslinje.\n      tip_local_timeline: Den lokale tidslinje er et have af folk i %{instance}. Disse er dine umiddelbare naboer!\n      tip_mobile_webapp: Hvis din mobil browser tilbyder dig at tilføje Mastodon til din hjemmeskærm, kan du modtage push meddelelser. Dette opfører sig på mange måder ligesom en almindelig app!\n      tips: Råd\n      title: Velkommen ombord, %{name}!\n  users:\n    invalid_email: E-mail adressen er ugyldig\n    invalid_otp_token: Ugyldig to-faktor kode\n    otp_lost_help_html: Hvis du har mistet adgang til begge, kan du få kontakt via %{email}\n    seamless_external_login: Du er logget ind via en ekstern service, så er kodeord og e-mail indstillinger ikke tilgængelige.\n    signed_in_as: 'Logget ind som:'\n"
  },
  {
    "path": "config/locales/de.yml",
    "content": "---\nde:\n  about:\n    about_hashtag_html: Das sind öffentliche Beiträge, die mit <strong>#%{hashtag}</strong> getaggt wurden. Wenn du irgendwo im Fediversum ein Konto besitzt, kannst du mit ihnen interagieren.\n    about_mastodon_html: Mastodon ist ein soziales Netzwerk. Es basiert auf offenen Web-Protokollen und freier, quelloffener Software. Es ist dezentral (so wie E-Mail!).\n    about_this: Über diesen Server\n    active_count_after: aktiv\n    active_footnote: Monatlich Aktive Nutzer_innen (MAU)\n    administered_by: 'Betrieben von:'\n    api: API\n    apps: Mobile Apps\n    apps_platforms: Benutze Mastodon auf iOS, Android und anderen Plattformen\n    browse_directory: Durchsuche das Profilverzeichnis und filtere nach Interessen\n    browse_public_posts: Stöbere durch öffentliche Beiträge auf Mastodon\n    contact: Kontakt\n    contact_missing: Nicht angegeben\n    contact_unavailable: Nicht verfügbar\n    discover_users: Benutzer_innen entdecken\n    documentation: Dokumentation\n    extended_description_html: |\n      <h3>Ein hervorragender Ort für Regeln</h3>\n      <p>Die erweiterte Beschreibung wurde von dem Administrator noch nicht eingestellt.</p>\n    federation_hint_html: Mit einem Konto auf %{instance} wirst du in der Lage sein Nutzer_innen auf beliebigen Mastodon-Servern und darüber hinaus zu folgen.\n    generic_description: \"%{domain} ist ein Server im Fediversum\"\n    get_apps: Versuche eine mobile App\n    hosted_on: Mastodon, gehostet auf %{domain}\n    learn_more: Mehr erfahren\n    privacy_policy: Datenschutzerklärung\n    see_whats_happening: Finde heraus, was gerade in der Welt los ist\n    server_stats: 'Serverstatistiken:'\n    source_code: Quellcode\n    status_count_after:\n      one: Beitrag\n      other: Beiträge\n    status_count_before: mit\n    tagline: Finde deine Freunde und entdecke neue\n    terms: Nutzungsbedingungen\n    user_count_after:\n      one: Profil\n      other: Profile\n    user_count_before: Hostet\n    what_is_mastodon: Was ist Mastodon?\n  accounts:\n    choices_html: \"%{name} empfiehlt:\"\n    follow: Folgen\n    followers:\n      one: Folger_innen\n      other: Folger_innen\n    following: Folgt\n    joined: Beigetreten am %{date}\n    last_active: zuletzt aktiv\n    link_verified_on: Besitz des Links wurde überprüft am %{date}\n    media: Medien\n    moved_html: \"%{name} ist auf %{new_profile_link} umgezogen:\"\n    network_hidden: Diese Informationen sind nicht verfügbar\n    nothing_here: Hier gibt es nichts!\n    people_followed_by: Profile, denen %{name} folgt\n    people_who_follow: Profile, die %{name} folgen\n    pin_errors:\n      following: Du musst dieser Person bereits folgen, um sie empfehlen zu können\n    posts:\n      one: Beitrag\n      other: Beiträge\n    posts_tab_heading: Beiträge\n    posts_with_replies: Beiträge mit Antworten\n    reserved_username: Dieser Profilname ist belegt\n    roles:\n      admin: Administrator\n      bot: Bot\n      moderator: Moderator\n    unavailable: Profil nicht verfügbar\n    unfollow: Entfolgen\n  admin:\n    account_actions:\n      action: Aktion ausführen\n      title: Moderationsaktion auf %{acct} ausführen\n    account_moderation_notes:\n      create: Notiz erstellen\n      created_msg: Moderationsnotiz erfolgreich erstellt!\n      delete: Löschen\n      destroyed_msg: Moderationsnotiz erfolgreich gelöscht!\n    accounts:\n      approve: Akzeptieren\n      approve_all: Alle akzeptieren\n      are_you_sure: Bist du sicher?\n      avatar: Profilbild\n      by_domain: Domain\n      change_email:\n        changed_msg: E-Mail-Adresse des Kontos erfolgreich geändert!\n        current_email: Aktuelle E-Mail-Adresse\n        label: E-Mail-Adresse ändern\n        new_email: Neue E-Mail-Adresse\n        submit: E-Mail-Adresse ändern\n        title: E-Mail-Adresse für %{username} ändern\n      confirm: Bestätigen\n      confirmed: Bestätigt\n      confirming: Bestätigung\n      deleted: Gelöscht\n      demote: Degradieren\n      disable: Ausschalten\n      disable_two_factor_authentication: 2FA abschalten\n      disabled: Ausgeschaltet\n      display_name: Anzeigename\n      domain: Domain\n      edit: Bearbeiten\n      email: E-Mail\n      email_status: E-Mail-Status\n      enable: Freischalten\n      enabled: Freigegeben\n      feed_url: Feed-URL\n      followers: Folger_innen\n      followers_url: URL der Folger_innen\n      follows: Folgt\n      header: Titelbild\n      inbox_url: Posteingangs-URL\n      invited_by: Eingeladen von\n      ip: IP-Adresse\n      joined: Beigetreten\n      location:\n        all: Alle\n        local: Lokal\n        remote: Fern\n        title: Ursprung\n      login_status: Loginstatus\n      media_attachments: Dateien\n      memorialize: In Gedenkmal verwandeln\n      moderation:\n        active: Aktiv\n        all: Alle\n        pending: In Warteschlange\n        silenced: Stummgeschaltet\n        suspended: Gesperrt\n        title: Moderation\n      moderation_notes: Moderationsnotizen\n      most_recent_activity: Letzte Aktivität\n      most_recent_ip: Letzte IP-Adresse\n      no_account_selected: Keine Konten wurden geändert, da keine ausgewählt wurden\n      no_limits_imposed: Keine Beschränkungen\n      not_subscribed: Nicht abonniert\n      outbox_url: Postausgangs-URL\n      pending: In Warteschlange\n      perform_full_suspension: Verbannen\n      profile_url: Profil-URL\n      promote: Befördern\n      protocol: Protokoll\n      public: Öffentlich\n      push_subscription_expires: PuSH-Abonnement läuft aus\n      redownload: Profil neu laden\n      reject: Ablehnen\n      reject_all: Alle ablehnen\n      remove_avatar: Profilbild entfernen\n      remove_header: Titelbild entfernen\n      resend_confirmation:\n        already_confirmed: Diese_r Benutzer_in wurde bereits bestätigt\n        send: Bestätigungs-E-Mail erneut senden\n        success: Bestätigungs-E-Mail erfolgreich gesendet!\n      reset: Zurücksetzen\n      reset_password: Passwort zurücksetzen\n      resubscribe: Wieder abonnieren\n      role: Berechtigungen\n      roles:\n        admin: Administrator\n        moderator: Moderator_in\n        staff: Mitarbeiter\n        user: Nutzer\n      salmon_url: Salmon-URL\n      search: Suche\n      shared_inbox_url: Geteilte Posteingang-URL\n      show:\n        created_reports: Erstellte Meldungen\n        targeted_reports: Von anderen gemeldet\n      silence: Stummschalten\n      silenced: Stummgeschaltet\n      statuses: Beiträge\n      subscribe: Abonnieren\n      suspended: Verbannt\n      time_in_queue: \"%{time} in der Warteschlange\"\n      title: Konten\n      unconfirmed_email: Unbestätigte E-Mail-Adresse\n      undo_silenced: Stummschaltung aufheben\n      undo_suspension: Verbannung aufheben\n      unsubscribe: Abbestellen\n      username: Profilname\n      warn: Warnen\n      web: Web\n    action_logs:\n      actions:\n        assigned_to_self_report: \"%{name} hat sich die Meldung %{target} selbst zugewiesen\"\n        change_email_user: \"%{name} hat die E-Mail-Adresse des Nutzers %{target} geändert\"\n        confirm_user: \"%{name} hat die E-Mail-Adresse von %{target} bestätigt\"\n        create_account_warning: \"%{name} hat eine Warnung an %{target} gesendet\"\n        create_custom_emoji: \"%{name} hat neues Emoji %{target} hochgeladen\"\n        create_domain_block: \"%{name} hat die Domain %{target} blockiert\"\n        create_email_domain_block: \"%{name} hat die E-Mail-Domain %{target} geblacklistet\"\n        demote_user: \"%{name} stufte Benutzer_in %{target} herunter\"\n        destroy_custom_emoji: \"%{name} zerstörte Emoji %{target}\"\n        destroy_domain_block: \"%{name} hat die Domain %{target} entblockt\"\n        destroy_email_domain_block: \"%{name} hat die E-Mail-Domain %{target} gewhitelistet\"\n        destroy_status: \"%{name} hat einen Beitrag von %{target} entfernt\"\n        disable_2fa_user: \"%{name} hat Zwei-Faktor-Anforderung für Benutzer_in %{target} deaktiviert\"\n        disable_custom_emoji: \"%{name} hat das %{target} Emoji deaktiviert\"\n        disable_user: \"%{name} hat Zugang von Benutzer_in %{target} deaktiviert\"\n        enable_custom_emoji: \"%{name} hat das %{target} Emoji aktiviert\"\n        enable_user: \"%{name} hat Zugang von Benutzer_in %{target} aktiviert\"\n        memorialize_account: \"%{name} hat das Konto von %{target} in eine Gedenkseite umgewandelt\"\n        promote_user: \"%{name} hat %{target} befördert\"\n        remove_avatar_user: \"%{name} hat das Profilbild von %{target} entfernt\"\n        reopen_report: \"%{name} hat die Meldung %{target} wieder geöffnet\"\n        reset_password_user: \"%{name} hat das Passwort von %{target} zurückgesetzt\"\n        resolve_report: \"%{name} hat die Meldung %{target} bearbeitet\"\n        silence_account: \"%{name} hat das Konto von %{target} stummgeschaltet\"\n        suspend_account: \"%{name} hat das Konto von %{target} verbannt\"\n        unassigned_report: \"%{name} hat die Zuweisung der Meldung %{target} entfernt\"\n        unsilence_account: \"%{name} hat die Stummschaltung von %{target} aufgehoben\"\n        unsuspend_account: \"%{name} hat die Verbannung von %{target} aufgehoben\"\n        update_custom_emoji: \"%{name} hat das %{target} Emoji geändert\"\n        update_status: \"%{name} hat einen Beitrag von %{target} aktualisiert\"\n      deleted_status: \"(gelöschter Beitrag)\"\n      title: Überprüfungsprotokoll\n    custom_emojis:\n      by_domain: Domain\n      copied_msg: Eine lokale Kopie des Emojis wurde erstellt\n      copy: Kopieren\n      copy_failed_msg: Es konnte keine lokale Kopie des Emojis erstellt werden\n      created_msg: Emoji erstellt!\n      delete: Löschen\n      destroyed_msg: Emoji gelöscht!\n      disable: Deaktivieren\n      disabled_msg: Das Emoji wurde deaktiviert\n      emoji: Emoji\n      enable: Aktivieren\n      enabled_msg: Das Emoji wurde aktiviert\n      image_hint: PNG bis zu 50 kB\n      listed: Gelistet\n      new:\n        title: Eigenes Emoji hinzufügen\n      overwrite: Überschreiben\n      shortcode: Kürzel\n      shortcode_hint: Mindestens 2 Zeichen, nur Buchstaben, Ziffern und Unterstriche\n      title: Eigene Emojis\n      unlisted: Ungelistet\n      update_failed_msg: Konnte dieses Emoji nicht aktualisieren\n      updated_msg: Emoji erfolgreich aktualisiert!\n      upload: Hochladen\n    dashboard:\n      backlog: Rückständige Jobs\n      config: Konfiguration\n      feature_deletions: Kontolöschung\n      feature_invites: Einladungen\n      feature_profile_directory: Profilverzeichnis\n      feature_registrations: Offene Anmeldung\n      feature_relay: Föderationsrelais\n      feature_timeline_preview: Zeitleistenvorschau\n      features: Funktionen\n      hidden_service: Föderation mit versteckten Diensten\n      open_reports: Ausstehende Meldungen\n      recent_users: Neueste Nutzer\n      search: Volltextsuche\n      single_user_mode: Einzelnutzermodus\n      software: Software\n      space: Speicherverbrauch\n      title: Übersicht\n      total_users: Benutzer_innen insgesamt\n      trends: Trends\n      week_interactions: Interaktionen diese Woche\n      week_users_active: Aktiv diese Woche\n      week_users_new: Benutzer_innen diese Woche\n    domain_blocks:\n      add_new: Neue Domainblockade hinzufügen\n      created_msg: Die Domain-Blockade wird nun durchgeführt\n      destroyed_msg: Die Domain-Blockade wurde rückgängig gemacht\n      domain: Domain\n      existing_domain_block_html: Es gibt schon eine Blockade für %{name}, diese muss erst <a href=\"%{unblock_url}\">aufgehoben</a> werden.\n      new:\n        create: Blockade einrichten\n        hint: Die Domain-Blockade wird nicht verhindern, dass Konteneinträge in der Datenbank erstellt werden. Aber es werden rückwirkend und automatisch alle Moderationsmethoden auf diese Konten angewendet.\n        severity:\n          desc_html: \"<strong>Stummschaltung</strong> wird die Beiträge dieses Kontos für alle, die ihm nicht folgen, unsichtbar machen. Eine <strong>Sperre</strong> wird alle Beiträge, Medien und Profildaten dieses Kontos entfernen. Verwende <strong>Kein,</strong> um nur Mediendateien abzulehnen.\"\n          noop: Kein\n          silence: Stummschaltung\n          suspend: Sperre\n        title: Neue Domain-Blockade\n      reject_media: Mediendateien ablehnen\n      reject_media_hint: Entfernt lokal gespeicherte Mediendateien und verhindert deren künftiges Herunterladen. Für Sperren irrelevant\n      reject_reports: Meldungen ablehnen\n      reject_reports_hint: Ignoriere alle Meldungen von dieser Domain. Irrelevant für Sperrungen\n      rejecting_media: Mediendateien werden nicht gespeichert\n      rejecting_reports: Meldungen werden ignoriert\n      severity:\n        silence: stummgeschaltet\n        suspend: gesperrt\n      show:\n        affected_accounts:\n          one: Ein Konto in der Datenbank betroffen\n          other: \"%{count} Konten in der Datenbank betroffen\"\n        retroactive:\n          silence: Alle existierenden Konten dieser Domain nicht mehr stummschalten\n          suspend: Alle existierenden Konten dieser Domain entsperren\n        title: Domain-Blockade für %{domain} zurücknehmen\n        undo: Zurücknehmen\n      undo: Domainblockade zurücknehmen\n    email_domain_blocks:\n      add_new: Neue hinzufügen\n      created_msg: E-Mail-Domain-Blockade erfolgreich erstellt\n      delete: Löschen\n      destroyed_msg: E-Mail-Domain-Blockade erfolgreich gelöscht\n      domain: Domain\n      new:\n        create: Blockade erstellen\n        title: Neue E-Mail-Domain-Blockade\n      title: E-Mail-Domain-Blockade\n    followers:\n      back_to_account: Zurück zum Konto\n      title: \"%{acct}'s Folger_innen\"\n    instances:\n      by_domain: Domain\n      delivery_available: Zustellung funktioniert\n      known_accounts:\n        one: \"%{count} bekanntes Konto\"\n        other: \"%{count} bekannte Konten\"\n      moderation:\n        all: Alle\n        limited: Beschränkt\n        title: Moderation\n      title: Föderation\n      total_blocked_by_us: Von uns blockiert\n      total_followed_by_them: Gefolgt von denen\n      total_followed_by_us: Gefolgt von uns\n      total_reported: Beschwerden über sie\n      total_storage: Medienanhänge\n    invites:\n      deactivate_all: Alle deaktivieren\n      filter:\n        all: Alle\n        available: Verfügbar\n        expired: Ausgelaufen\n        title: Filter\n      title: Einladungen\n    pending_accounts:\n      title: Ausstehende Konten (%{count})\n    relays:\n      add_new: Neues Relay hinzufügen\n      delete: Löschen\n      description_html: Ein <strong>Föderierungsrelay</strong> ist ein vermittelnder Server, der eine große Anzahl öffentlicher Beiträge zwischen Servern austauscht, die es abonnieren und zu ihm veröffentlichen.<strong> Es kann kleinen und mittleren Servern dabei helfen, Inhalte des Fediverse zu entdecken</strong>, was andernfalls das manuelle Folgen anderer Leute auf entfernten Servern durch lokale Nutzer erfordern würde.\n      disable: Ausschalten\n      disabled: Ausgeschaltet\n      enable: Einschalten\n      enable_hint: Sobald aktiviert wird dein Server alle öffentlichen Beiträge dieses Relays abonnieren und wird alle öffentlichen Beiträge dieses Servers an es senden.\n      enabled: Eingeschaltet\n      inbox_url: Relay-URL\n      pending: Warte auf Zustimmung des Relays\n      save_and_enable: Speichern und aktivieren\n      setup: Relaisverbindung einrichten\n      status: Zustand\n      title: Relais\n    report_notes:\n      created_msg: Meldungs-Kommentar erfolgreich erstellt!\n      destroyed_msg: Meldungs-Kommentar erfolgreich gelöscht!\n    reports:\n      account:\n        note: Notiz\n        report: Meldung\n      action_taken_by: Maßnahme ergriffen durch\n      are_you_sure: Bist du dir sicher?\n      assign_to_self: Mir zuweisen\n      assigned: Zugewiesener Moderator\n      comment:\n        none: Kein\n      created_at: Gemeldet\n      mark_as_resolved: Als gelöst markieren\n      mark_as_unresolved: Als ungelöst markieren\n      notes:\n        create: Kommentar hinzufügen\n        create_and_resolve: Mit Kommentar lösen\n        create_and_unresolve: Mit Kommentar wieder öffnen\n        delete: Löschen\n        placeholder: Beschreibe, welche Maßnahmen ergriffen wurden oder irgendwelche andere Neuigkeiten…\n      reopen: Meldung wieder eröffnen\n      report: 'Meldung #%{id}'\n      reported_account: Gemeldetes Konto\n      reported_by: Gemeldet von\n      resolved: Gelöst\n      resolved_msg: Meldung erfolgreich gelöst!\n      status: Zustand\n      title: Meldungen\n      unassign: Zuweisung entfernen\n      unresolved: Ungelöst\n      updated_at: Aktualisiert\n    settings:\n      activity_api_enabled:\n        desc_html: Anzahl der lokal geposteten Beiträge, aktiven Nutzern und neuen Registrierungen in wöchentlichen Zusammenfassungen\n        title: Veröffentliche gesamte Statistiken über Benutzeraktivitäten\n      bootstrap_timeline_accounts:\n        desc_html: Mehrere Profilnamen durch Kommata trennen. Funktioniert nur mit lokalen und nicht gesperrten Konten. Standardwert bei freigelassenem Feld sind alle lokalen Admins.\n        title: Konten, denen Neu-Angemeldete automatisch folgen\n      contact_information:\n        email: Öffentliche E-Mail-Adresse\n        username: Profilname für die Kontaktaufnahme\n      custom_css:\n        desc_html: Verändere das Aussehen mit CSS, dass auf jeder Seite geladen wird\n        title: Benutzerdefiniertes CSS\n      hero:\n        desc_html: Wird auf der Startseite angezeigt. Mindestens 600x100px sind empfohlen. Wenn es nicht gesetzt wurde, wird das Server-Thumbnail dafür verwendet\n        title: Bild für Einstiegsseite\n      mascot:\n        desc_html: Angezeigt auf mehreren Seiten. Mehr als 293x205px empfohlen. Wenn es nicht gesetzt wurde wird es auf das Standard-Maskottchen zurückfallen\n        title: Maskottchen-Bild\n      peers_api_enabled:\n        desc_html: Domain-Namen, die der Server im Fediversum gefunden hat\n        title: Veröffentliche entdeckte Server durch die API\n      preview_sensitive_media:\n        desc_html: Linkvorschauen auf anderen Webseiten werden ein Vorschaubild anzeigen, obwohl die Medien als heikel gekennzeichnet sind\n        title: Heikle Medien im OpenGraph-Vorschau anzeigen\n      profile_directory:\n        desc_html: Erlaube Benutzer auffindbar zu sein\n        title: Aktiviere Profilverzeichnis\n      registrations:\n        closed_message:\n          desc_html: Wird auf der Einstiegsseite gezeigt, wenn die Anmeldung geschlossen ist. Du kannst HTML-Tags nutzen\n          title: Nachricht über geschlossene Registrierung\n        deletion:\n          desc_html: Allen erlauben, ihr Konto eigenmächtig zu löschen\n          title: Kontolöschung erlauben\n        min_invite_role:\n          disabled: Niemand\n          title: Einladungen erlauben von\n      registrations_mode:\n        modes:\n          approved: Zustimmung benötigt zur Registrierung\n          none: Niemand kann sich registrieren\n          open: Jeder kann sich registrieren\n        title: Registrierungsmodus\n      show_known_fediverse_at_about_page:\n        desc_html: Wenn aktiviert, wird es alle Beiträge aus dem bereits bekannten Teil des Fediversums auf der Startseite anzeigen. Andernfalls werden lokale Beitrage des Servers angezeigt.\n        title: Zeige eine öffentliche Zeitleiste auf der Einstiegsseite\n      show_staff_badge:\n        desc_html: Zeige Mitarbeiter-Badge auf Benutzerseite\n        title: Zeige Mitarbeiter-Badge\n      site_description:\n        desc_html: Einleitungsabschnitt auf der Frontseite. Beschreibe, was diesen Mastodon-Server ausmacht. Du kannst HTML-Tags benutzen, insbesondere <code>&lt;a&gt;</code> und <code>&lt;em&gt;</code>.\n        title: Beschreibung des Servers\n      site_description_extended:\n        desc_html: Bietet sich für Verhaltenskodizes, Regeln, Richtlinien und weiteres an, was deinen Server auszeichnet. Du kannst HTML-Tags benutzen\n        title: Erweiterte Beschreibung des Servers\n      site_short_description:\n        desc_html: Wird angezeigt in der Seitenleiste und in Meta-Tags. Beschreibe in einem einzigen Abschnitt, was Mastodon ist und was diesen Server von anderen unterscheidet. Falls leer, wird die Server-Beschreibung verwendet.\n        title: Kurze Beschreibung des Servers\n      site_terms:\n        desc_html: Hier kannst du deine eigenen Geschäftsbedingungen, Datenschutzerklärung und anderes rechtlich Relevante eintragen. Du kannst HTML-Tags nutzen\n        title: Benutzerdefinierte Geschäftsbedingungen\n      site_title: Name des Servers\n      thumbnail:\n        desc_html: Wird für die Vorschau via OpenGraph und API verwendet. 1200×630 px wird empfohlen\n        title: Vorschaubild des Servers\n      timeline_preview:\n        desc_html: Auf der Einstiegsseite die öffentliche Zeitleiste anzeigen\n        title: Zeitleisten-Vorschau\n      title: Server-Einstellungen\n    statuses:\n      back_to_account: Zurück zum Konto\n      batch:\n        delete: Löschen\n        nsfw_off: Als nicht heikel markieren\n        nsfw_on: Als heikel markieren\n      failed_to_execute: Ausführen fehlgeschlagen\n      media:\n        title: Medien\n      no_media: Keine Medien\n      no_status_selected: Keine Beiträge wurden geändert, weil keine ausgewählt wurden\n      title: Beiträge des Kontos\n      with_media: Mit Medien\n    subscriptions:\n      callback_url: Callback-URL\n      confirmed: Bestätigt\n      expires_in: Verfällt in\n      last_delivery: Letzte Zustellung\n      title: WebSub\n      topic: Thema\n    tags:\n      accounts: Konten\n      hidden: Versteckt\n      hide: Vom Profilverzeichnis verstecken\n      name: Hashtag\n      title: Hashtags\n      unhide: Zeige in Verzeichnis\n      visible: Sichtbar\n    title: Administration\n    warning_presets:\n      add_new: Neu hinzufügen\n      delete: Löschen\n      edit: Bearbeiten\n      edit_preset: Warnungsvorlage bearbeiten\n      title: Warnungsvorlagen verwalten\n  admin_mailer:\n    new_pending_account:\n      body: Die Details von diesem neuem Konto sind unten. Du kannst die Anfrage akzeptieren oder ablehnen.\n      subject: Neues Konto zur Überprüfung auf %{instance} verfügbar (%{username})\n    new_report:\n      body: \"%{reporter} hat %{target} gemeldet\"\n      body_remote: Jemand von %{domain} hat %{target} gemeldet\n      subject: Neue Meldung auf %{instance} (#%{id})\n  appearance:\n    advanced_web_interface: Fortgeschrittene Benutzeroberfläche\n    advanced_web_interface_hint: Wenn du mehr aus deiner Bildschirmbreite herausholen möchtest, erlaubt dir die fortgeschrittene Benutzeroberfläche viele unterschiedliche Spalten auf einmal zu sehen, wie z.B. deine Startseite, Benachrichtigungen, das gesamte bekannte Netz, deine Listen und beliebige Hashtags.\n    animations_and_accessibility: Animationen und Barrierefreiheit\n    confirmation_dialogs: Bestätigungsfenster\n    sensitive_content: Heikle Inhalte\n  application_mailer:\n    notification_preferences: Ändere E-Mail-Einstellungen\n    salutation: \"%{name},\"\n    settings: 'E-Mail-Einstellungen ändern: %{link}'\n    view: 'Ansehen:'\n    view_profile: Zeige Profil\n    view_status: Beitrag öffnen\n  applications:\n    created: Anwendung erfolgreich erstellt\n    destroyed: Anwendung erfolgreich gelöscht\n    invalid_url: Die angegebene URL ist ungültig\n    regenerate_token: Zugangs-Token neu erstellen\n    token_regenerated: Zugangs-Token neu erstellt\n    warning: Sei mit diesen Daten sehr vorsichtig. Teile sie mit niemandem!\n    your_token: Dein Zugangs-Token\n  auth:\n    apply_for_account: Eine Einladung anfragen\n    change_password: Passwort\n    checkbox_agreement_html: Ich akzeptiere die <a href=\"%{rules_path}\" target=\"_blank\">Server-Regeln</a> und die <a href=\"%{terms_path}\" target=\"_blank\">Nutzungsbedingungen</a>\n    confirm_email: E-Mail bestätigen\n    delete_account: Konto löschen\n    delete_account_html: Falls du dein Konto löschen willst, kannst du <a href=\"%{path}\">hier damit fortfahren</a>. Du wirst um Bestätigung gebeten werden.\n    didnt_get_confirmation: Keine Bestätigungs-Mail erhalten?\n    forgot_password: Passwort vergessen?\n    invalid_reset_password_token: Das Token zum Zurücksetzen des Passworts ist ungültig oder abgelaufen. Bitte fordere ein neues an.\n    login: Anmelden\n    logout: Abmelden\n    migrate_account: Ziehe zu einem anderen Konto um\n    migrate_account_html: Wenn du wünschst, dieses Konto zu einem anderen umzuziehen, kannst du <a href=\"%{path}\">dies hier einstellen</a>.\n    or_log_in_with: Oder anmelden mit\n    providers:\n      cas: CAS\n      saml: SAML\n    register: Registrieren\n    registration_closed: \"%{instance} akzeptiert keine neuen Mitglieder\"\n    resend_confirmation: Bestätigungs-Mail erneut versenden\n    reset_password: Passwort zurücksetzen\n    security: Sicherheit\n    set_new_password: Neues Passwort setzen\n    trouble_logging_in: Schwierigkeiten beim Anmelden?\n  authorize_follow:\n    already_following: Du folgst diesem Konto bereits\n    error: Das Remote-Konto konnte nicht geladen werden\n    follow: Folgen\n    follow_request: 'Du hast eine Folgeanfrage gesendet an:'\n    following: 'Erfolg! Du folgst nun:'\n    post_follow:\n      close: Oder du schließt einfach dieses Fenster.\n      return: Zeige das Profil\n      web: In der Benutzeroberfläche öffnen\n    title: \"%{acct} folgen\"\n  datetime:\n    distance_in_words:\n      about_x_hours: \"%{count}h\"\n      about_x_months: \"%{count}mo\"\n      about_x_years: \"%{count}y\"\n      almost_x_years: \"%{count}y\"\n      half_a_minute: Gerade eben\n      less_than_x_minutes: \"%{count}m\"\n      less_than_x_seconds: Gerade eben\n      over_x_years: \"%{count}J\"\n      x_days: \"%{count}T\"\n      x_minutes: \"%{count}m\"\n      x_months: \"%{count}mo\"\n      x_seconds: \"%{count}s\"\n  deletes:\n    bad_password_msg: Falsches Passwort\n    confirm_password: Gib dein derzeitiges Passwort ein, um deine Identität zu bestätigen\n    description_html: Hiermit wird <strong>dauerhaft und unwiederbringlich</strong> der Inhalt deines Kontos gelöscht und dein Konto deaktiviert. Dein Profilname wird reserviert, um künftige Imitationen zu verhindern.\n    proceed: Konto löschen\n    success_msg: Dein Konto wurde erfolgreich gelöscht\n    warning_html: Wir können nur dafür garantieren, dass die Inhalte auf diesem einen Server gelöscht werden. Bei Inhalten, die weit verbreitet wurden, ist es wahrscheinlich, dass Spuren bleiben werden. Server, die offline sind oder keine Benachrichtigungen von deinem Konto mehr empfangen, werden ihre Datenbanken nicht bereinigen.\n    warning_title: Verfügbarkeit verstreuter Inhalte\n  directories:\n    directory: Profilverzeichnis\n    enabled: Du bist gerade in dem Verzeichnis gelistet.\n    enabled_but_waiting: Du bist damit einverstanden im Verzeichnis aufgelistet zu werden, aber du hast noch nicht genug Folger_innen (%{min_followers}).\n    explanation: Entdecke Benutzer_innen basierend auf deren Interessen\n    explore_mastodon: Entdecke %{title}\n    how_to_enable: Du hast dich gerade nicht dazu entschieden im Verzeichnis gelistet zu werden. Du kannst dich unten dafür eintragen. Benutze Hashtags in deiner Profilbeschreibung, um unter spezifischen Hashtags gelistet zu werden!\n    people:\n      one: \"%{count} Person\"\n      other: \"%{count} Leute\"\n  errors:\n    '403': Dir fehlt die Befugnis, diese Seite sehen zu können.\n    '404': Die Seite nach der du gesucht hast wurde nicht gefunden.\n    '410': Die Seite nach der du gesucht hast existiert hier nicht mehr.\n    '422':\n      content: Sicherheitsüberprüfung fehlgeschlagen. Blockierst du Cookies?\n      title: Sicherheitsüberprüfung fehlgeschlagen\n    '429': Du wurdest gedrosselt\n    '500':\n      content: Bitte verzeih, etwas ist bei uns schief gegangen.\n      title: Diese Seite ist kaputt\n    noscript_html: Bitte aktiviere JavaScript, um die Mastodon-Web-Anwendung zu verwenden. Alternativ kannst du auch eine der <a href=\"%{apps_path}\">nativen Mastodon-Anwendungen</a> für deine Plattform probieren.\n  existing_username_validator:\n    not_found: kann lokalen Benutzer nicht mit diesem Nuternamen finden\n    not_found_multiple: kann %{usernames} nicht finden\n  exports:\n    archive_takeout:\n      date: Datum\n      download: Dein Archiv herunterladen\n      hint_html: Du kannst ein Archiv deiner <strong>Beiträge und hochgeladenen Medien</strong> anfragen. Die exportierten Daten werden in dem ActivityPub-Format gespeichert, welches mit jeder Software lesbar ist die das Format unterstützt. Du kannst alle 7 Tage ein Archiv anfordern.\n      in_progress: Stelle dein Archiv zusammen...\n      request: Dein Archiv anfragen\n      size: Größe\n    blocks: Du hast blockiert\n    csv: CSV\n    domain_blocks: Domainblockaden\n    follows: Du folgst\n    lists: Listen\n    mutes: Du hast stummgeschaltet\n    storage: Medienspeicher\n  featured_tags:\n    add_new: Neu hinzufügen\n    errors:\n      limit: Du hast bereits die maximale Anzahl an empfohlenen Hashtags erreicht\n  filters:\n    contexts:\n      home: Startseite\n      notifications: Benachrichtigungen\n      public: Öffentliche Zeitleisten\n      thread: Gespräche\n    edit:\n      title: Filter bearbeiten\n    errors:\n      invalid_context: Ungültiger oder fehlender Kontext übergeben\n      invalid_irreversible: Unwiderrufliche Filterung funktioniert nur mit Heim- oder Benachrichtigungskontext\n    index:\n      delete: Löschen\n      title: Filter\n    new:\n      title: Neuen Filter hinzufügen\n  footer:\n    developers: Entwickler\n    more: Mehr…\n    resources: Ressourcen\n  generic:\n    all: Alle\n    changes_saved_msg: Änderungen gespeichert!\n    copy: Kopieren\n    order_by: Sortieren nach\n    save_changes: Änderungen speichern\n    validation_errors:\n      one: Etwas ist noch nicht ganz richtig! Bitte korrigiere den Fehler\n      other: Etwas ist noch nicht ganz richtig! Bitte korrigiere %{count} Fehler\n  html_validator:\n    invalid_markup: 'enthält ungültiges HTML-Markup: %{error}'\n  identity_proofs:\n    active: Aktiv\n    authorize: Ja, autorisieren\n    authorize_connection_prompt: Diese kryptographische Verbindung autorisieren?\n    errors:\n      failed: Die kryptographische Verbindung ist fehlgeschlagen. Bitte versuche es nochmal von %{provider}.\n      keybase:\n        invalid_token: Keybase-Tokens sind Hashsignaturen und müssen 66 Hexadezimalzeichen lang sein\n        verification_failed: Keybase nimmt dieses Token nicht als Signatur für Keybase-Benutzer %{kb_username} an. Bitte versuche es nochmal über Keybase.\n      wrong_user: Kann keinen Beweis für %{proving} erstellen während du als %{current} angemeldet bist. Melde dich als %{proving} an und versuche es noch einmal.\n    explanation_html: Hier kannst du kryptographisch deine anderen Identitäten wie dein Keybase-Profil verbinden. Dadurch können andere Leute dir verschlüsselte Nachrichten senden und dem Inhalt, den sie dir senden, vertrauen.\n    i_am_html: Ich bin %{username} auf %{service}.\n    identity: Identität\n    inactive: Inaktiv\n    publicize_checkbox: 'Und poste das:'\n    publicize_toot: 'Es ist offiziell! Ich bin %{username} auf %{service}: %{url}'\n    status: Verifizierungsstatus\n    view_proof: Zeige Nachweis\n  imports:\n    modes:\n      merge: Zusammenführen\n      merge_long: Behalte existierende Datensätze und füge neue hinzu\n      overwrite: Überschreiben\n      overwrite_long: Ersetze aktuelle Datensätze mit neuen\n    preface: Daten, die du aus einem anderen Server exportiert hast, kannst du hier importieren. Beispielsweise die Liste derjenigen, denen du folgst oder die du blockiert hast.\n    success: Deine Daten wurden erfolgreich hochgeladen und werden in Kürze verarbeitet\n    types:\n      blocking: Blockierliste\n      domain_blocking: Domain-Blockliste\n      following: Folgeliste\n      muting: Stummschaltungsliste\n    upload: Hochladen\n  in_memoriam_html: In Gedenken.\n  invites:\n    delete: Deaktivieren\n    expired: Abgelaufen\n    expires_in:\n      '1800': 30 Minuten\n      '21600': 6 Stunden\n      '3600': 1 Stunde\n      '43200': 12 Stunden\n      '604800': 1 Woche\n      '86400': 1 Tag\n    expires_in_prompt: Nie\n    generate: Generieren\n    invited_by: 'Du wurdest eingeladen von:'\n    max_uses:\n      one: 1 mal verwendet\n      other: \"%{count} mal verwendet\"\n    max_uses_prompt: Kein Limit\n    prompt: Generiere und teile Links um Zugang zu diesem Server zu geben\n    table:\n      expires_at: Läuft ab\n      uses: Verwendungen\n    title: Leute einladen\n  lists:\n    errors:\n      limit: Du hast die maximale Anzahl an Listen erreicht\n  media_attachments:\n    validations:\n      images_and_video: Es kann kein Video an einen Beitrag, der bereits Bilder enthält, angehängt werden\n      too_many: Es können nicht mehr als 4 Dateien angehängt werden\n  migrations:\n    acct: benutzername@domain des neuen Kontos\n    currently_redirecting: 'Deine Profilweiterleitung wurde gesetzt auf:'\n    proceed: Speichern\n    updated_msg: Deine Konto-Migrationseinstellungen wurden erfolgreich aktualisiert!\n  moderation:\n    title: Moderation\n  notification_mailer:\n    digest:\n      action: Zeige alle Benachrichtigungen\n      body: Hier ist eine kurze Zusammenfassung der Nachrichten, die du seit deinem letzten Besuch am %{since} verpasst hast\n      mention: \"%{name} hat dich erwähnt:\"\n      new_followers_summary:\n        one: Außerdem ist dir seit du weg warst ein weiteres Wesen gefolgt! Juhu!\n        other: Außerdem sind dir seit du weg warst %{count} weitere Wesen gefolgt! Großartig!\n      subject:\n        one: \"1 neue Mitteilung seit deinem letzten Besuch \\U0001F418\"\n        other: \"%{count} neue Mitteilungen seit deinem letzten Besuch \\U0001F418\"\n      title: In deiner Abwesenheit...\n    favourite:\n      body: 'Dein Beitrag wurde von %{name} favorisiert:'\n      subject: \"%{name} hat deinen Beitrag favorisiert\"\n      title: Neue Favorisierung\n    follow:\n      body: \"%{name} folgt dir jetzt!\"\n      subject: \"%{name} folgt dir jetzt\"\n      title: Neuer Follower\n    follow_request:\n      action: Verwalte Folge-Anfragen\n      body: \"%{name} möchte dir folgen\"\n      subject: 'Ausstehender Follower: %{name}'\n      title: Neue Folge-Anfrage\n    mention:\n      action: Antworten\n      body: \"%{name} hat dich erwähnt:\"\n      subject: \"%{name} hat dich erwähnt\"\n      title: Neue Erwähnung\n    reblog:\n      body: \"%{name} hat deinen Beitrag geteilt:\"\n      subject: \"%{name} hat deinen Beitrag geteilt\"\n      title: Dein Beitrag wurde geteilt\n  number:\n    human:\n      decimal_units:\n        format: \"%n%u\"\n        units:\n          billion: B\n          million: M\n          quadrillion: Q\n          thousand: K\n          trillion: T\n  pagination:\n    newer: Neuer\n    next: Vorwärts\n    older: Älter\n    prev: Zurück\n    truncate: \"&hellip;\"\n  polls:\n    errors:\n      already_voted: Du hast bereits für diese Umfrage abgestimmt\n      duplicate_options: enthält doppelte Einträge\n      duration_too_long: ist zu weit in der Zukunft\n      duration_too_short: ist zu früh\n      expired: Die Umfrage ist bereits vorbei\n      over_character_limit: kann nicht länger als jeweils %{max} Zeichen sein\n      too_few_options: muss mindestens einen Eintrag haben\n      too_many_options: kann nicht mehr als %{max} Einträge beinhalten\n  preferences:\n    other: Weiteres\n    posting_defaults: Standardeinstellungen für Beiträge\n    public_timelines: Öffentliche Zeitleisten\n  relationships:\n    activity: Kontoaktivität\n    dormant: Inaktiv\n    last_active: Zuletzt aktiv\n    most_recent: Neuste\n    moved: Umgezogen\n    mutual: Bekannt\n    primary: Primär\n    relationship: Beziehung\n    remove_selected_domains: Entferne alle Follower von den ausgewählten Domains\n    remove_selected_followers: Entferne ausgewählte Follower\n    remove_selected_follows: Entfolge ausgewählte Benutzer\n    status: Kontostatus\n  remote_follow:\n    acct: Profilname@Domain, von wo aus du dieser Person folgen möchtest\n    missing_resource: Die erforderliche Weiterleitungs-URL für dein Konto konnte nicht gefunden werden\n    no_account_html: Noch kein Konto? Du kannst dich <a href='%{sign_up_path}' target='_blank'>hier anmelden</a>\n    proceed: Weiter\n    prompt: 'Du wirst dieser Person folgen:'\n    reason_html: \"<strong>Warum ist dieser Schritt erforderlich?</strong><code>%{instance}</code> ist möglicherweise nicht der Server auf dem du registriert bist, also müssen wir dich erst auf deinen Heimserver weiterleiten.\"\n  remote_interaction:\n    favourite:\n      proceed: Fortfahren zum Favorisieren\n      prompt: 'Du möchtest diesen Beitrag favorisieren:'\n    reblog:\n      proceed: Fortfahren zum Teilen\n      prompt: 'Du möchtest diesen Beitrag teilen:'\n    reply:\n      proceed: Fortfahren zum Antworten\n      prompt: 'Du möchtest auf diesen Beitrag antworten:'\n  remote_unfollow:\n    error: Fehler\n    title: Titel\n    unfollowed: Entfolgt\n  scheduled_statuses:\n    over_daily_limit: Du hast das Limit für geplante Beiträge, dass %{limit} beträgt, für heute erreicht\n    over_total_limit: Du hast das Limit für geplante Beiträge, dass %{limit} beträgt, erreicht\n    too_soon: Das geplante Datum muss in der Zukunft liegen\n  sessions:\n    activity: Letzte Aktivität\n    browser: Browser\n    browsers:\n      alipay: Alipay\n      blackberry: Blackberry\n      chrome: Chrome\n      edge: Microsoft Edge\n      electron: Electron\n      firefox: Firefox\n      generic: Unbekannter Browser\n      ie: Internet Explorer\n      micro_messenger: MicroMessenger\n      nokia: Nokia S40 Ovi Browser\n      opera: Opera\n      otter: Otter\n      phantom_js: PhantomJS\n      qq: QQ Browser\n      safari: Safari\n      uc_browser: UCBrowser\n      weibo: Weibo\n    current_session: Aktuelle Sitzung\n    description: \"%{browser} auf %{platform}\"\n    explanation: Dies sind die Webbrowser, die derzeit in deinem Mastodon-Konto eingeloggt sind.\n    ip: IP-Adresse\n    platforms:\n      adobe_air: Adobe Air\n      android: Android\n      blackberry: Blackberry\n      chrome_os: ChromeOS\n      firefox_os: Firefox OS\n      ios: iOS\n      linux: Linux\n      mac: Mac\n      other: unbekannte Plattform\n      windows: Windows\n      windows_mobile: Windows Mobile\n      windows_phone: Windows Phone\n    revoke: Schließen\n    revoke_success: Sitzung erfolgreich geschlossen\n    title: Sitzungen\n  settings:\n    account: Konto\n    account_settings: Konto & Sicherheit\n    appearance: Aussehen\n    authorized_apps: Autorisierte Anwendungen\n    back: Zurück zu Mastodon\n    delete: Konto löschen\n    development: Entwicklung\n    edit_profile: Profil bearbeiten\n    export: Datenexport\n    featured_tags: Empfohlene Hashtags\n    identity_proofs: Identitätsnachweise\n    import: Datenimport\n    import_and_export: Importieren und Exportieren\n    migrate: Konto-Umzug\n    notifications: Benachrichtigungen\n    preferences: Einstellungen\n    profile: Profil\n    relationships: Folger_innen und Gefolgte\n    two_factor_authentication: Zwei-Faktor-Auth\n  statuses:\n    attached:\n      description: 'Angehängt: %{attached}'\n      image:\n        one: \"%{count} Bild\"\n        other: \"%{count} Bilder\"\n      video:\n        one: \"%{count} Video\"\n        other: \"%{count} Videos\"\n    boosted_from_html: Geteilt von %{acct_link}\n    content_warning: 'Inhaltswarnung: %{warning}'\n    disallowed_hashtags:\n      one: 'enthält einen verbotenen Hashtag: %{tags}'\n      other: 'enthält verbotene Hashtags: %{tags}'\n    language_detection: Sprache automatisch erkennen\n    open_in_web: Im Web öffnen\n    over_character_limit: Zeichenlimit von %{max} überschritten\n    pin_errors:\n      limit: Du hast bereits die maximale Anzahl an Beiträgen angeheftet\n      ownership: Du kannst nur eigene Beiträge anheften\n      private: Du kannst nur öffentliche Beiträge anheften\n      reblog: Du kannst keine geteilten Beiträge anheften\n    poll:\n      total_votes:\n        one: \"%{count} Stimme\"\n        other: \"%{count} Stimmen\"\n      vote: Abstimmen\n    show_more: Mehr anzeigen\n    sign_in_to_participate: Melde dich an, um an der Konversation teilzuhaben\n    title: '%{name}: \"%{quote}\"'\n    visibilities:\n      private: Nur Folgende\n      private_long: Nur für Folgende sichtbar\n      public: Öffentlich\n      public_long: Für alle sichtbar\n      unlisted: Nicht gelistet\n      unlisted_long: Für alle sichtbar, aber nicht in öffentlichen Zeitleisten aufgelistet\n  stream_entries:\n    pinned: Angehefteter Beitrag\n    reblogged: teilte\n    sensitive_content: Heikle Inhalte\n  terms:\n    body_html: |\n      <h2>Datenschutzerklärung</h2>\n      <h3 id=\"collect\">Welche Informationen sammeln wir?</h3>\n\n      <ul>\n      <li><em>Grundlegende Kontoinformationen</em>: Wenn du dich auf diesem Server registrierst, wirst du darum gebeten, einen Benutzer:innen-Namen, eine E-Mail-Adresse und ein Passwort einzugeben. Du kannst auch zusätzliche Profilinformationen wie etwa einen Anzeigenamen oder eine Biografie eingeben und ein Profilbild oder ein Headerbild hochladen. Der Benutzer:innen-Name, der Anzeigename, die Biografie, das Profilbild und das Headerbild werden immer öffentlich angezeigt.</li>\n      <li><em>Beiträge, Folge- und andere öffentliche Informationen</em>: Die Liste der Leute, denen du folgst, wird öffentlich gezeigt, das gleiche gilt für deine Folgenden (Follower). Sobald du eine Nachricht übermittelst, wird das Datum und die Uhrzeit gemeinsam mit der Information, welche Anwendung du dafür verwendet hast, gespeichert. Nachricht können Medienanhänge enthalten, etwa Bilder und Videos. Öffentliche und ungelistete Beiträge sind öffentlich verfügbar. Sobald du einen Beitrag auf deinem Profil anpinnst, sind dies auch öffentlich verfügbare Informationen. Deine Beiträge werden an deine Folgenden ausgeliefert, was in manchen Fällen bedeutet, dass sie an andere Server ausgeliefert werden und dort Kopien gespeichert werden. Sobald du Beiträge löschst, wird dies ebenso an deine Follower ausgeliefert. Die Handlungen des Teilens und Favorisieren eines anderen Beitrages ist immer öffentlich.</li>\n      <li><em>Direkte und \"Nur Folgende\"-Beiträge</em>: Alle Beiträge werden auf dem Server gespeichert und verarbeitet. \"Nur Folgende\"-Beiträge werden an deine Folgenden und an Benutzer:innen, die du in ihnen erwähnst, ausgeliefert, direkte Beiträge nur an in ihnen erwähnte Benutzer:innen. In manchen Fällen bedeutet dass, dass sie an andere Server ausgeliefert werden und dort Kopien gespeichert werden. Wir bemühen uns nach bestem Wissen und Gewissen, den Zugriff auf diese Beiträge auf nur autorisierte Personen einzuschränken, jedoch könnten andere Server dabei scheitern. Deswegen ist es wichtig, die Server, zu denen deine Folgenden gehören, zu überprüfen. Du kannst eine Option in den Einstellungen umschalten, um neue Folgenden manuell anzunehmen oder abzuweisen. <em>Bitte beachte, dass die Betreiber des Server und jedes empfangenden Servers solche Nachrichten anschauen könnten</em> und dass Empfänger von diesen eine Bildschirmkopie erstellen könnten, sie kopieren oder anderweitig weiterverteilen könnten. <em>Teile nicht irgendwelche gefährlichen Informationen über Mastodon.</em></li>\n      <li><em>Internet Protocol-Adressen (IP-Adressen) und andere Metadaten</em>: Sobald du dich anmeldest, erfassen wir sowohl die IP-Adresse, von der aus du dich anmeldest, als auch den Namen deine Browseranwendung. Alle angemeldeten Sitzungen (Sessions) sind für deine Überprüfung und Widerruf in den Einstellungen verfügbar. Die letzte verwendete IP-Adresse wird bis zu 12 Monate lang gespeichert. Wir könnten auch Serverprotokoll behalten, welche die IP-Adresse von jeder Anfrage an unseren Server enthalten.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"use\">Für was verwenden wir deine Informationen?</h3>\n\n      <p>Jede der von dir gesammelten Information kann in den folgenden Weisen verwendet werden:</p>\n\n      <ul>\n      <li>Um die Kernfunktionalität von Mastodon bereitzustellen. Du kannst du mit dem Inhalt anderer Leute interagieren und deine eigenen Inhalte beitragen, wenn du angemeldet bist. Zum Beispiel kannst du anderen folgen, um deren kombinierten Beiträge in deine personalisierten Start-Timeline zu sehen.</li>\n      <li>Um Moderation der Community zu ermöglichen, zum Beispiel beim Vergleichen deiner IP-Adresse mit anderen bekannten, um Verbotsumgehung oder andere Vergehen festzustellen.</li>\n      <li>Die E-Mail-Adresse, die du bereitstellst, kann dazu verwendet werden, dir Informationen, Benachrichtigungen über andere Leute, die mit deinen Inhalten interagieren oder dir Nachrichten senden, und auf Anfragen, Wünsche und/oder Fragen zu antworten.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"protect\">Wie beschützen wir deine Informationen?</h3>\n\n      <p>Wir implementieren eine Reihe von Sicherheitsmaßnahmen, um die Sicherheit deiner persönlichen Information sicherzustellen, wenn du persönliche Informationen eingibst, übermittelst oder auf sie zugreifst. Neben anderen Dingen, wird sowohl deine Browsersitzung, als auch der Datenverkehr zwischen deinen Anwendungen und der Programmierschnittstelle (API) mit SSL gesichert, dein Passwort wird mit einem starken Einwegalgorithmus gehasht. Du kannst Zwei-Faktor-Authentifizierung aktivieren, um den Zugriff auf dein Konto zusätzlich abzusichern.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"data-retention\">Was ist unsere Datenspeicherungsrichtlinie?</h3>\n\n      <p>Wir werden mit bestem Wissen und Gewissen:</p>\n\n      <ul>\n      <li>Serverprotokolle, die IP-Adressen von allen deinen Anfragen an diesen Server, falls solche Protokolle behalten werden, für nicht mehr als 90 Tage behalten.</li>\n      <li>registrierten Benutzer:innen zugeordnete IP-Adressen nicht länger als 12 Monate behalten.</li>\n      </ul>\n\n      <p>Du kannst ein Archiv deines Inhalts anfordern und herunterladen, inkludierend deiner Beiträge, Medienanhänge, Profilbilder und Headerbilder.</p>\n\n      <p>Es ist in den meisten Fällen möglich dein Konto jederzeit eigenmächtig unwiderruflich zu löschen.</p>\n\n      <hr class=\"spacer\"/>\n\n      <h3 id=\"cookies\">Verwenden wir Cookies?</h3>\n\n      <p>Ja. Cookies sind kleine Dateien, die eine Webseite oder ihr Serviceanbieter über deinen Webbrowser (sofern er es erlaubt) auf die Festplatte deines Computers überträgt. Diese Cookies ermöglichen es der Seite deinen Browser wiederzuerkennen und, sofern du ein registriertes Konto hast, diesen mit deinem registrierten Konto zu verknüpfen.</p>\n\n      <p>Wir verwenden Cookies, um deine Einstellungen zu verstehen und für zukünftige Besuche zu speichern.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"disclose\">Offenbaren wir Informationen an Dritte?</h3>\n\n      <p>Wir verkaufen nicht, handeln nicht mit oder übertragen deine persönlich identifizierbaren Informationen nicht an Dritte. Dies beinhaltet nicht Dritte, die vertrauenswürdig sind und uns beim Betreiben unserer Seite, Leiten unseres Geschäftes oder dabei, die Dienste für dich bereitzustellen, unterstützen, sofern diese Dritte zustimmen, diese Informationen vertraulich zu halten. Wir können auch Informationen freigeben, wenn wir glauben, dass Freigabe angemessen ist, um dem Gesetz zu entsprechen, unsere Seitenrichtlinien durchzusetzen oder unsere Rechte, Eigentum und/oder Sicherheit oder die anderer zu beschützen.</p>\n\n      <p>Dein öffentlicher Inhalt kann durch andere Server im Netzwerk heruntergeladen werden. Deine öffentlichen und \"Nur Folgende\"-Beiträge werden an die Server ausgeliefert, bei denen sich deine Folgenden befinden und direkte Nachrichten werden an die Server des Empfängers ausgeliefert, falls diese Folgenden oder Empfänger sich auf einem anderen Server als diesen befinden.</p>\n\n      <p>Wenn du eine Anwendung autorisierst, dein Konto zu benutzen, kann diese – abhängig von den von dir genehmigten Befugnissen – auf deine öffentlichen Profilinformationen, deine Folgt- und Folgende-Liste, deine Listen, alle deine Beiträge und deine Favoriten zugreifen. Anwendungen können nie auf deine E-Mail-Adresse oder dein Passwort zugreifen</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"children\">Webseitenbenutzung durch Kinder</h3>\n\n      <p>Wenn sich dieser Server in der EU oder im Europäischen Wirtschaftsraum befindet: Unsere Website, Produkte und Dienstleistungen sind alle an Leute gerichtet, die mindestens 16 Jahre als sind. Wenn du unter 16 bist, darfst du nach den Bestimmungen der DSGVO (<a href=\"https://de.wikipedia.org/wiki/Datenschutz-Grundverordnung\">Datenschutz-Grundverordnung</a>) diese Webseite nicht benutzen.</p>\n\n      <p>Wenn sich dieser Server in den USA befindet: Unsere Webseite, Produkte und Dienstleistungen sind alle an Leute gerichtet, die mindestens 13 Jahre alt sind. Wenn du unter 13 bist, darfst du nach den Bestimmungen des COPPA (<a href=\"https://de.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act\">Children's Online Privacy Protection Act, dt. \"Gesetz zum Schutz der Privatsphäre von Kindern im Internet\"</a>) diese Webseite nicht benutzen.</p>\n\n      <p>Gesetzesvorschriften können unterschiedlich sein, wenn sich dieser Server in anderer Gerichtsbarkeit befindet.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"changes\">Änderung an unserer Datenschutzerklärung</h3>\n\n      <p>Wenn wir uns entscheiden, Änderungen an unserer Datenschutzerklärung vorzunehmen, werden wir diese Änderungen auf dieser Seite bekannt gegeben.</p>\n\n      <p>Dies ist eine Übersetzung, Irrtümer und Übersetzungsfehler vorbehalten. Im Zweifelsfall gilt die englische Originalversion.</p>\n\n      <p>Dieses Dokument ist CC-BY-SA. Es wurde zuletzt aktualisiert am 7. März 2018.</p>\n\n      <p>Ursprünglich übernommen von der <a href=\"https://github.com/discourse/discourse\">Discourse-Datenschutzerklärung</a>.</p>\n    title: \"%{instance} Nutzungsbedingungen und Datenschutzerklärung\"\n  themes:\n    contrast: Mastodon (Hoher Kontrast)\n    default: Mastodon (Dunkel)\n    mastodon-light: Mastodon (Hell)\n  time:\n    formats:\n      default: \"%d.%m.%Y %H:%M\"\n      month: \"%b %Y\"\n  two_factor_authentication:\n    code_hint: Gib zur Bestätigung den Code ein, den deine Authenticator-App generiert hat\n    description_html: Wenn du <strong>Zwei-Faktor-Authentifizierung (2FA)</strong> aktivierst, wirst du dein Telefon zum Anmelden benötigen. Darauf werden Sicherheitscodes erzeugt, die du bei der Anmeldung eingeben musst.\n    disable: Deaktivieren\n    enable: Aktivieren\n    enabled: Zwei-Faktor-Authentisierung ist aktiviert\n    enabled_success: Zwei-Faktor-Authentisierung erfolgreich aktiviert\n    generate_recovery_codes: Wiederherstellungscodes generieren\n    instructions_html: \"<strong>Lies diesen QR-Code mit Google Authenticator oder einer ähnlichen TOTP-App auf deinem Telefon ein.</strong> Von nun an wird diese App Tokens generieren, die du beim Anmelden eingeben musst.\"\n    lost_recovery_codes: Wiederherstellungscodes erlauben dir, wieder den Zugang zu deinem Konto zu erlangen, falls du dein Telefon verlieren solltest. Wenn du deine Wiederherstellungscodes verloren hast, kannst du sie hier neu generieren. Deine alten Wiederherstellungscodes werden damit ungültig gemacht.\n    manual_instructions: 'Wenn du den QR-Code nicht einlesen kannst und ihn manuell eingeben musst, ist hier das Klartext-Geheimnis:'\n    recovery_codes: Wiederherstellungs-Codes sichern\n    recovery_codes_regenerated: Wiederherstellungscodes erfolgreich neu generiert\n    recovery_instructions_html: Wenn du den Zugang zu deinem Telefon verlieren solltest, kannst du einen untenstehenden Wiederherstellungscode benutzen, um wieder auf dein Konto zugreifen zu können. <strong>Bewahre die Wiederherstellungscodes gut auf.</strong> Du könntest sie beispielsweise ausdrucken und bei deinen restlichen wichtigen Dokumenten aufbewahren.\n    setup: Einrichten\n    wrong_code: Der eingegebene Code war ungültig! Stimmen Serverzeit und Gerätezeit?\n  user_mailer:\n    backup_ready:\n      explanation: Du hast ein vollständiges Backup von deinem Mastodon-Konto angefragt. Es kann jetzt heruntergeladen werden!\n      subject: Dein Archiv ist bereit zum Download\n      title: Archiv-Download\n    warning:\n      explanation:\n        disable: Solange dein Konto eingefroren ist, sind deine Benutzerdaten intakt; aber du kannst nichts tun, bis dein Konto entsperrt wurde.\n        silence: Solange dein Konto limitiert ist, können nur die Leute, die dir bereits folgen, deine Beiträge auf dem Server sehen und es könnte sein, dass du von verschiedenen öffentlichen Listungen ausgeschlossen wirst. Andererseits können andere dir manuell folgen.\n        suspend: Dein Konto wurde gesperrt und alle deine Beiträge und hochgeladenen Medien wurden unwiderruflich vom Server und anderen Servern, bei denen du Folgende hattest, gelöscht.\n      review_server_policies: Serverrichtlinien ansehen\n      subject:\n        disable: Dein Konto %{acct} wurde eingefroren\n        none: Warnung für %{acct}\n        silence: Dein Konto %{acct} wurde limitiert\n        suspend: Dein Konto %{acct} wurde gesperrt\n      title:\n        disable: Konto eingefroren\n        none: Warnung\n        silence: Konto limitiert\n        suspend: Konto gesperrt\n    welcome:\n      edit_profile_action: Profil einstellen\n      edit_profile_step: Du kannst dein Profil anpassen, indem du einen Avatar oder ein Titelbild hochlädst oder deinen Anzeigenamen änderst und mehr. Wenn du deine Folgenden vorher überprüfen möchtest, bevor sie dir folgen können, dann kannst du dein Profil sperren.\n      explanation: Hier sind ein paar Tipps, um loszulegen\n      final_action: Fang an zu posten\n      final_step: 'Fang an zu posten! Selbst ohne Follower werden deine öffentlichen Beitrage von anderen gesehen, zum Beispiel auf der lokalen Zeitleiste oder in Hashtags. Vielleicht möchtest du dich vorstellen mit dem #introductions-Hashtag.'\n      full_handle: Dein vollständiger Benutzername\n      full_handle_hint: Dies ist was du deinen Freunden sagen kannst, damit sie dich anschreiben oder von einem anderen Server folgen können.\n      review_preferences_action: Einstellungen ändern\n      review_preferences_step: Stelle sicher, dass du deine Einstellungen einstellst, wie zum Beispiel welche E-Mails du gerne erhalten möchtest oder was für Privatsphäreneinstellungen voreingestellt werden sollten. Wenn dir beim Ansehen von GIFs nicht schwindelig wird, dann kannst du auch das automatische Abspielen dieser aktivieren.\n      subject: Willkommen bei Mastodon\n      tip_federated_timeline: Die föderierte Zeitleiste ist die sehr große Ansicht vom Mastodon-Netzwerk. Sie enthält aber auch nur Leute, denen du und deine Nachbarn folgen, sie ist also nicht komplett.\n      tip_following: Du folgst standardmäßig deinen Server-Admin(s). Um mehr interessante Leute zu finden, kannst du die lokale oder öffentliche Zeitleiste durchsuchen.\n      tip_local_timeline: Die lokale Zeitleiste ist eine Ansicht aller Leute auf %{instance}. Diese sind deine Nachbarn!\n      tip_mobile_webapp: Wenn dein mobiler Browser dir anbietet Mastodon zu deinem Startbildschirm hinzuzufügen, dann kannst du Benachrichtigungen erhalten. Es verhält sich wie eine native App in vielen Wegen!\n      tips: Tipps\n      title: Willkommen an Bord, %{name}!\n  users:\n    follow_limit_reached: Du kannst nicht mehr als %{limit} Leuten folgen\n    invalid_email: Ungültige E-Mail-Adresse\n    invalid_otp_token: Ungültiger Zwei-Faktor-Authentisierungs-Code\n    otp_lost_help_html: Wenn Du beides nicht mehr weißt, melde Dich bei uns unter der E-Mailadresse %{email}\n    seamless_external_login: Du bist angemeldet über einen Drittanbieter-Dienst, weswegen Passwort- und E-Maileinstellungen nicht verfügbar sind.\n    signed_in_as: 'Angemeldet als:'\n  verification:\n    explanation_html: 'Du kannst <strong>bestätigen, dass die Links in deinen Profil-Metadaten dir gehören</strong>. Dafür muss die verlinkte Website einen Link zurück auf dein Mastodon-Profil enthalten. Dieser Link <strong>muss</strong> ein <code>rel=\"me\"</code>-Attribut enthalten. Der Linktext ist dabei egal. Hier ist ein Beispiel:'\n    verification: Verifizierung\n"
  },
  {
    "path": "config/locales/devise.ar.yml",
    "content": "---\nar:\n  devise:\n    confirmations:\n      confirmed: تم تأكيد عنوان بريدك الإلكتروني.\n      send_instructions: سوف تتلقى بعد بضع دقائق رسالةً إلكترونيةً تضم تعليمات التأكيد. إن لم تتلق الرسالة، الرجاء التحقق من إنها ليست ضمن ملف الرسائل غير المرغوب فيها.\n      send_paranoid_instructions: إن كان عنوان بريدك الإلكتروني موجودا في قاعدة بياناتنا سوف تتلقّى الإرشادات اللازمة لتأكيده خلال بضع دقائق. يُرجى الإطلاع على الرسائل المتلقاة في البريد غير المرغوب فيه أيضا للتحقق من تلقي الرسالة.\n    failure:\n      already_authenticated: لقد تم تسجيل دخولك من قبل.\n      inactive: لم يتم تنشيط حسابك بعد.\n      invalid: \"%{authentication_keys} أو كلمة سر خاطئة.\"\n      last_attempt: بإمكانك إعادة المحاولة مرة واحدة قبل أن يتم قفل حسابك.\n      locked: إن حسابك مقفل.\n      not_found_in_database: \"%{authentication_keys} أو كلمة سر خاطئة.\"\n      pending: إنّ حسابك في انتظار مراجعة.\n      timeout: لقد انتهت مدة صلاحية جلستك. قم بتسجيل الدخول من جديد للمواصلة.\n      unauthenticated: يجب عليك تسجيل الدخول أو إنشاء حساب قبل المواصلة.\n      unconfirmed: يجب عليك تأكيد عنوان بريدك الإلكتروني قبل المواصلة.\n    mailer:\n      confirmation_instructions:\n        action: للتحقق من عنوان البريد الإلكتروني\n        action_with_app: تأكيد ثم العودة إلى %{app}\n        explanation: لقد قمت بإنشاء حساب على %{host} بواسطة عنوان البريد الإلكتروني الحالي. إنك على بعد خطوات قليلة من تفعليه. إن لم تكن من طلب ذلك، يرجى ألّا تولي اهتماما بهذه الرسالة.\n        extra_html: ندعوك إلى الإطلاع على <a href=\"%{terms_path}\">القواعد الخاصة بمثيل الخادوم هذا</a> and <a href=\"%{policy_path}\">و شروط الخدمة الخاصة بنا</a>.\n        subject: 'ماستدون: تعليمات التأكيد لمثيل الخادوم %{instance}'\n        title: للتحقق من عنوان البريد الإلكتروني\n      email_changed:\n        explanation: 'لقد تم تغيير عنوان البريد الإلكتروني الخاص بحسابك إلى :'\n        extra: إن لم تقم شخصيًا بتعديل عنوان بريدك الإلكتروني ، ذلك يعني أنّ شخصا آخر قد نَفِذَ إلى حسابك. فالرجاء قم بتعديل كلمتك السرية في الحال أو قم بالإتصال بمدير مثيل الخادوم إن كنت غير قادر على استعمال حسابك.\n        subject: 'ماستدون: تم استبدال عنوان بريدك الإلكتروني'\n        title: عنوان البريد الإلكتروني الجديد\n      password_change:\n        explanation: تم تغيير كلمة السر الخاصة بحسابك.\n        extra: إن لم تقم شخصيًا بتعديل كلمتك السرية، ذلك يعني أنّ شخصا آخر قد سيطر على حسابك. فالرجاء قم بتعديل كلمتك السرية في الحال أو قم بالاتصال بمدير مثيل الخادوم إن كنت غير قادر على استعمال حسابك.\n        subject: 'ماستدون: تم تغيير كلمة المرور'\n        title: تم تغيير كلمة السر\n      reconfirmation_instructions:\n        explanation: ندعوك لتأكيد العنوان الجديد قصد تعديله في بريدك.\n        extra: إن لم تكن صاحب هذا الطلب ، يُرجى عدم إعارة الاهتمام لهذه الرسالة. فعنوان البريد الإلكتروني المتعلق بحساب ماستدون سوف يبقى هو مِن غير أي تعديل إلّا و فقط إن قمت بالنقر على الرابط أعلاه قصد تعديله.\n        subject: 'ماستدون: تأكيد كلمة السر الخاصة بـ %{instance}'\n        title: التحقق من عنوان البريد الإلكتروني\n      reset_password_instructions:\n        action: تغيير كلمة السر\n        explanation: لقد قمت بطلب تغيير كلمة السر الخاصة بحسابك.\n        extra: إن لم تكن صاحب هذا الطلب ، يُرجى عدم إعارة الاهتمام لهذه الرسالة. فكلِمَتُك السرية تبقى هي مِن غير أي تعديل إلّا و فقط إن قمت بالنقر على الرابط أعلاه قصد إنشاء كلمة سرية جديدة.\n        subject: 'ماستدون: تعليمات استعادة كلمة المرور'\n        title: إعادة تعيين كلمة السر\n      unlock_instructions:\n        subject: 'ماستدون: تعليمات فك القفل'\n    omniauth_callbacks:\n      failure: تعذرت المصادقة من %{kind} بسبب \"%{reason}\".\n      success: تمت المصادقة بنجاح عبر حساب %{kind}.\n    passwords:\n      no_token: ليس بإمكانك النفاذ إلى هذه الصفحة إن لم تقم بالنقر على الرابط المتواجد في الرسالة الإلكترونية. الرجاء التحقق مِن أنك قمت بإدخال عنوان الرابط كاملا كما هو مذكور في رسالة إعادة تعيين الكلمة السرية.\n      send_instructions: إن كان عنوان بريدك الإلكتروني ضمن قاعدة بياناتنا، فسوف تتلقّى في غضون دقائق رابطا يُمكّنُك مِن استعادة كلمتك السرية على عنوان علبة البريد الإلكتروني الخاصة بك. إن لم تجد هذه الرسالة، يرجى تفقد مجلّد البريد المزعج.\n      send_paranoid_instructions: إن كان عنوان بريدك الإلكتروني ضمن قاعدة بياناتنا، فسوف تتلقّى في غضون دقائق رابطا يُمكّنُك مِن استعادة كلمتك السرية على عنوان علبة البريد الإلكتروني الخاصة بك. إن لم تجد هذه الرسالة، يرجى تفقد مجلّد البريد المزعج.\n      updated: تم تغيير كلمة المرور بنجاح. أنت مسجل الآن.\n      updated_not_active: تم تغيير كلمة المرور بنجاح.\n    registrations:\n      destroyed: إلى اللقاء! لقد تم إلغاء حسابك. نتمنى أن نراك مجددا.\n      signed_up: أهلا وسهلا! تم تسجيل دخولك بنجاح.\n      signed_up_but_inactive: لقد تمت عملية إنشاء حسابك بنجاح إلاّ أنه لا يمكننا تسجيل دخولك إلاّ بعد قيامك بتفعيله.\n      signed_up_but_locked: لقد تم تسجيل حسابك بنجاح إلّا أنه لا يمكنك تسجيل الدخول لأن حسابك مجمد.\n      signed_up_but_unconfirmed: لقد تم إرسال رسالة تحتوي على رابط للتفعيل إلى عنوان بريدك الإلكتروني. بالضغط على الرابط سوف يتم تفعيل حسابك. لذا يُرجى إلقاء نظرة على ملف الرسائل غير المرغوب فيها إنْ لم تَعثُر على الرسالة السالفة الذِكر.\n      update_needs_confirmation: لقد قمت بتحديث حسابك بنجاح إلا أنه يجب علينا التأكد من صحة عنوان بريدك الإلكتروني الجديد. يرجى الإطلاع على بريدك و اتباع الرابط الذي تلقيتَه لتأكيد عنوان بريدك الإلكتروني الجديد. إن لم تتلقى تلك الرسالة ، ندعوك إلى تفقُّد مجلد البريد المزعج.\n      updated: تم تحديث حسابك بنجاح.\n    sessions:\n      already_signed_out: تم تسجيل خروجك بنجاح.\n      signed_in: تم تسجيل دخولك بنجاح.\n      signed_out: تم تسجيل خروجك بنجاح.\n    unlocks:\n      send_instructions: سوف تتلقى خلال بضع دقائق رسالة إلكترونية تحتوي على التعليمات اللازمة لفك القفل عن حسابك. إن لم تتلقى تلك الرسالة ، ندعوك إلى تفقُّد مجلد البريد المزعج.\n      send_paranoid_instructions: إن كان حسابك موجود فعليًا فسوف تتلقى في غضون دقائق رسالة إلكترونية تحتوي على تعليمات تدُلُّك على كيفية فك القفل عن حسابك. إن لم تتلقى تلك الرسالة ، ندعوك إلى تفقُّد مجلد البريد المزعج.\n      unlocked: لقد تمت عملية إلغاء تجميد حسابك بنجاح. للمواصلة ، يُرجى تسجيل الدخول.\n  errors:\n    messages:\n      already_confirmed: قمت بتأكيده من قبل ، يرجى إعادة محاولة تسجيل الدخول\n      confirmation_period_expired: يجب التأكد منه قبل انقضاء مدة %{period}، يرجى إعادة طلب جديد\n      expired: انتهت مدة صلاحيته، الرجاء طلب واحد جديد\n      not_found: لا يوجد\n      not_locked: ليس مقفلاً\n      not_saved:\n        few: \"%{count} أخطاء منعت هذا %{resource} من الحفظ:\"\n        many: \"%{count} أخطاء منعت هذا %{resource} من الحفظ:\"\n        one: 'خطأ واحد منع هذا %{resource} من الحفظ:'\n        other: \"%{count} أخطاء منعت هذا %{resource} من الحفظ:\"\n        two: 'أخطاء منعت هذا %{resource} من الحفظ:'\n        zero: \"%{count} أخطاء منعت هذا %{resource} من الحفظ:\"\n"
  },
  {
    "path": "config/locales/devise.ast.yml",
    "content": "---\nast:\n  devise:\n    failure:\n      already_authenticated: Yá aniciesti sesión.\n      inactive: Entá nun s'activó la cuenta.\n      last_attempt: Tienes un intentu más enantes de bloquiar la cuenta.\n      locked: La cuenta ta bloquiada.\n      timeout: La sesión caducó. Volvi aniciar sesión pa siguir, por favor.\n      unauthenticated: Precises aniciar sesión o rexistrate enantes de siguir.\n    mailer:\n      confirmation_instructions:\n        explanation: Creesti una cuenta en %{host} con esta direición de corréu. Tas a un clic d'activala. Si nun fuisti tu, inora esti corréu.\n      email_changed:\n        title: Direición de corréu nueva\n      reset_password_instructions:\n        explanation: Solicitesti una contraseña nueva pa la cuenta.\n        extra: Si nun solicitesti esto, inora esti corréu. La contraseña nun va camudar hasta que nun accedas al enllaz d'enriba y crees una nueva.\n    registrations:\n      signed_up: \"¡Afáyate! Rexistréstite con ésitu.\"\n      signed_up_but_unconfirmed: Unvióse un mensaxe de confirmación a la direición de corréu. Sigui l'enllaz p'activar la cuenta. Comprueba la carpeta Puxarra si nun recibiesti esti corréu, por favor.\n      updated: La cuenta anovóse con ésitu.\n    unlocks:\n      send_instructions: Nunos minutos vas recibir un corréu coles instrucciones pa cómo desbloquiar la cuenta. Comprueba la carpeta Puxarra si nun lu recibiesti.\n      send_paranoid_instructions: Si esiste la cuenta, nun momentu vas recibir un corréu coles instrucciones pa cómo desbloquiala. Comprueba la carpeta Puxarra si nun recibiesti esti corréu.\n      unlocked: La cuenta desbloquióse con ésitu. Anicia sesión pa siguir, por favor.\n  errors:\n    messages:\n      already_confirmed: yá se confirmó, volvi aniciar sesión\n      not_found: nun s'alcontró\n"
  },
  {
    "path": "config/locales/devise.bg.yml",
    "content": "---\nbg:\n  devise:\n    confirmations:\n      confirmed: Твоят профил беше успешно потвърден. Влизането в профила е успешно.\n      send_instructions: Ще получиш писмо с инструкции как да потвърдиш своя профил до няколко минути.\n      send_paranoid_instructions: Ако твоят имейл адрес съществува в базата ни, ще получиш там инструкции как да потвърдиш своя профил.\n    failure:\n      already_authenticated: Вече си вътре в профила си.\n      inactive: Профилът ти все още не е активиран.\n      invalid: Невалиден %{authentication_keys}.\n      last_attempt: Разполагаш с още един опит преди профилът ти да бъде заключен.\n      locked: Профилът ти е заключен.\n      not_found_in_database: Невалиден %{authentication_keys}.\n      timeout: Сесията ти изтече, моля влез отново, за да продължиш.\n      unauthenticated: Преди да продължиш, трябва да влезеш в профила си или да се регистрираш.\n      unconfirmed: Преди да продължиш, трябва да потвърдиш регистрацията си.\n    mailer:\n      confirmation_instructions:\n        subject: 'Mastodon: Инструкции за потвърждаване %{instance}'\n      password_change:\n        subject: 'Mastodon: Паролата е променена'\n      reset_password_instructions:\n        subject: Инструкции за смяна на паролата\n      unlock_instructions:\n        subject: Инструкции за отключване\n    omniauth_callbacks:\n      failure: Не успяхме да те упълномощим чрез %{kind}, защото \"%{reason}\".\n      success: Успешно упълномощаване чрез %{kind} профил.\n    passwords:\n      no_token: Може да достъпваш тази страница само от имейл за промяна на паролата. Ако тази страница е отворена от такъв имейл, увери се, че използваш целия URL-адрес, който сме ти изпратили.\n      send_instructions: Ще получиш писмо с инструкции как да промениш паролата си до няколко минути.\n      send_paranoid_instructions: Ако твоят имейл адрес съществува в базата ни, ще получиш там инструкции за промяна на своята парола.\n      updated: Паролата ти беше променена успешно. Влизането в профила е успешно.\n      updated_not_active: Паролата ти беше променена успешно.\n    registrations:\n      destroyed: Довиждане! Твоят профил беше успешно изтрит. Надяваме се скоро да те видим отново.\n      signed_up: Привет! Регистрирацията ти е успешна.\n      signed_up_but_inactive: Регистрирацията ти е успешна. Въпреки това, не можеш да влезеш в профила си, защото той все още не е потвърден.\n      signed_up_but_locked: Регистрирацията ти е успешна. Въпреки това, не можеш да влезеш в профила си, защото той е заключен.\n      signed_up_but_unconfirmed: Писмо с връзка за потвърждаване на профила ти беше изпратено на твоя имейл адрес. Моля, отвори връзката, за да активираш своя профил.\n      update_needs_confirmation: Профилът ти е успешно променен, но ние трябва да проверим твоя нов имейл адрес. Моля, провери пощата си и отвори връзката за потвърждаване на новия адрес.\n      updated: Профилът ти е успешно променен.\n    sessions:\n      already_signed_out: Успешно излизане от профила.\n      signed_in: Успешно влизане.\n      signed_out: Успешно излизане.\n    unlocks:\n      send_instructions: Ще получиш писмо с инструкции как да отключиш профила си до няколко минути.\n      send_paranoid_instructions: Ако твоят профил съществува в базата ни, на своя имейл адрес ще получиш инструкции за отключването му до няколко минути.\n      unlocked: Твоят профил беше отключен успешно. За да продължиш, влез в него.\n  errors:\n    messages:\n      already_confirmed: е вече потвърден, моля опитай да влезеш в профила си с него\n      confirmation_period_expired: трябва да се потвърди в рамките на %{period}, моля направи нова заявка за потвърждение\n      expired: е изтекъл, моля заяви нов\n      not_found: не е намерен\n      not_locked: не бе заключен\n      not_saved:\n        one: 'Една грешка попречи този %{resource} да бъде записан:'\n        other: \"%{count} грешки попречиха този %{resource} да бъде записан:\"\n"
  },
  {
    "path": "config/locales/devise.bn.yml",
    "content": "bn:\n"
  },
  {
    "path": "config/locales/devise.ca.yml",
    "content": "---\nca:\n  devise:\n    confirmations:\n      confirmed: L'adreça de correu s'ha confirmat correctament.\n      send_instructions: \"En pocs minuts rebràs un correu electrònic amb instruccions sobre com confirmar l'adreça de correu. \\nSi us plau verifica la carpeta de corrreu brossa si no has rebut aquest correu.\"\n      send_paranoid_instructions: |-\n        Si l'adreça de correu electrònic existeix en la nostra base de dades, en pocs minuts rebràs un correu electrònic amb instruccions sobre com confirmar l'adreça de correu.\n        Si us plau verifica la carpeta de corrreu brossa si no has rebut aquest correu.\n    failure:\n      already_authenticated: Ja estàs registrat.\n      inactive: El teu compte encara no s'ha activat.\n      invalid: \"%{authentication_keys} o contrasenya no són vàlids.\"\n      last_attempt: Tens un intent més, abans que es bloqueji el compte.\n      locked: El compte s'ha bloquejat.\n      not_found_in_database: \"%{authentication_keys} o contrasenya no són vàlids.\"\n      pending: El teu compte encara està en revisió.\n      timeout: La sessió ha expirat. Inicia sessió una altra vegada per a continuar.\n      unauthenticated: Cal iniciar sessió o registrar-se abans de continuar.\n      unconfirmed: Has de confirmar l'adreça de correu electrònic abans de continuar.\n    mailer:\n      confirmation_instructions:\n        action: Verifica l'adreça de correu\n        action_with_app: Confirma i torna a %{app}\n        explanation: Has creat un compte a %{host} amb aquesta adreça de correu electrònic. Estàs a un sol clic de l'activació. Si no fos així, ignora aquest correu electrònic.\n        explanation_when_pending: Has sol·licitat una invitació a %{host} amb aquesta adreça de correu electrònic. Un cop confirmis la teva adreça de correu electrònic revisarem la teva sol·licitud. No es pot iniciar la sessió fins llavors. Si la teva sol·licitud és rebutjada les teves dades s’eliminaran, de manera que no s’exigirà cap altra acció. Si no has estat tu qui ha fet aquest sol·licitud si us plau ignora aquest correu electrònic.\n        extra_html: Si us plau consulta també <a href=\"%{terms_path}\"> les regles del servidor</a> i <a href=\"%{policy_path}\"> les nostres condicions de servei</a>.\n        subject: 'Mastodon: Instruccions de confirmació %{instance}'\n        title: Verifica l'adreça de correu\n      email_changed:\n        explanation: 'L''adreça de correu del teu compte s''està canviant a:'\n        extra: Si no has canviat el teu correu electrònic és probable que algú hagi accedit al teu compte. Si us plau, canvia la contrasenya immediatament o posa't en contacte amb l'administrador del servidor si no pots accedir al teu compte.\n        subject: 'Mastodon: s''ha canviat l''adreça electrònica'\n        title: Adreça de correu electrònic nova\n      password_change:\n        explanation: S'ha canviat la contrasenya del teu compte.\n        extra: Si no has canviat el teu correu electrònic, és probable que algú hagi accedit al teu compte. Si us plau, canvia la contrasenya immediatament o posa't en contacte amb l'administrador del servidor si no pots accedir al teu compte.\n        subject: 'Mastodon: Contrasenya canviada'\n        title: Contrasenya canviada\n      reconfirmation_instructions:\n        explanation: Confirma la nova adreça per canviar el teu correu electrònic.\n        extra: Si no has iniciat aquest canvi, ignora aquest correu electrònic. L'adreça electrònica del compte de Mastodon no canviarà fins que accedeixis a l'enllaç de dalt.\n        subject: 'Mastodon: Confirma el correu electrònic per a %{instance}'\n        title: Verifica l'adreça de correu electrònic\n      reset_password_instructions:\n        action: Canviar contrasenya\n        explanation: Has sol·licitat una contrasenya nova per al teu compte.\n        extra: Si no ho has sol·licitat, ignora aquest correu electrònic. La teva contrasenya no canviarà fins que accedeixis a l'enllaç de dalt i creis un de nou.\n        subject: 'Mastodon: Instruccions per a reiniciar contrassenya'\n        title: Contrasenya restablerta\n      unlock_instructions:\n        subject: 'Mastodon: Instruccions per a desblocar'\n    omniauth_callbacks:\n      failure: No podem autentificar-te desde %{kind} degut a \"%{reason}\".\n      success: Autentificat amb èxit des del compte %{kind}.\n    passwords:\n      no_token: No pots accedir a aquesta pàgina sense provenir des del correu de restabliment de la contrasenya. Si vens des del correu de restabliment de contrasenya, assegura't que estàs emprant l'adreça completa proporcionada.\n      send_instructions: Rebràs un correu electrònic amb instruccions sobre com reiniciar la contrasenya en pocs minuts.\n      send_paranoid_instructions: Si el seu correu electrònic existeix en la nostra base de dades, rebràs un enllaç de restabliment de contrasenya en l'adreça de correu en pocs minuts.\n      updated: La contrassenya s'ha canviat correctament. Ara ja estàs registrat.\n      updated_not_active: La contrassenya s'ha canviat correctament.\n    registrations:\n      destroyed: Adéu! el compte s'ha cancel·lat amb èxit. Desitgem veure't de nou aviat.\n      signed_up: Benvingut! T'has registrat amb èxit.\n      signed_up_but_inactive: T´has registrat amb èxit. No obstant, no podem identificar-te perquè el compte encara no s'ha activat.\n      signed_up_but_locked: T´has registrat amb èxit. No obstant, no podem identificar-te perquè el compte està blocat.\n      signed_up_but_pending: S'ha enviat un missatge amb un enllaç de confirmació a la teva adreça de correu electrònic. Després de que hagis fet clic a l'enllaç, revisarem la teva sol·licitud. Se't notificarà si s'aprova.\n      signed_up_but_unconfirmed: Un missatge amb un enllaç de confirmació ha estat enviat per correu electrònic. Si us plau segueixi l'enllaç per activar el seu compte.\n      update_needs_confirmation: Ha actualitzat el seu compte amb èxit, però necessitem verificar la nova adreça de correu. Si us plau comprovi el correu i segueixi l'enllaç per confirmar la nova adreça de correu.\n      updated: El seu compte ha estat actualitzat amb èxit.\n    sessions:\n      already_signed_out: Has tancat la sessió amb èxit.\n      signed_in: T'has registrat amb èxit.\n      signed_out: Has tancat la sessió amb èxit.\n    unlocks:\n      send_instructions: Rebràs un correu electrònic amb instruccions sobre com desblocar el compte en pocs minuts.\n      send_paranoid_instructions: Si el compte existeix, rebràs un correu electrònic amb instruccions sobre com desblocar-lo en pocs minuts.\n      unlocked: El compte s'ha blocat correctament. Inicia sessió per a continuar.\n  errors:\n    messages:\n      already_confirmed: ja està confirmat. Intenta d'iniciar sessió\n      confirmation_period_expired: calia fer la confirmació dins de %{period}, torna a sol·licitar-la\n      expired: ha expirat, demana'n una altra\n      not_found: no s'ha trobat\n      not_locked: no està blocada\n      not_saved:\n        one: '1 error ha impedit desar aquest %{resource}:'\n        other: \"%{count} errors hab impedit desar aquest %{resource}:\"\n"
  },
  {
    "path": "config/locales/devise.co.yml",
    "content": "---\nco:\n  devise:\n    confirmations:\n      confirmed: U vostru indirizzu email hè statu cunfirmatu.\n      send_instructions: Avete da riceve un’email cù l’istruzzione di cunfirmazione in qualchì minuta. Pensate à verificà u cartulare di spam s’ellu ùn c’hè nunda.\n      send_paranoid_instructions: S’ellu esiste u vostru indirizzu email in a database, avete da riceve l’istruzzione pè cunfirmà u vostru contu in qualchì minuta. Pensate à verificà u cartulare di spam s’ellu ùn c’hè nunda.\n    failure:\n      already_authenticated: Site digià cunnettatu·a.\n      inactive: U vostru contu ùn hè ancu attivatu.\n      invalid: L’ %{authentication_keys} o a chjave d’accessu ùn sò curretti.\n      last_attempt: Avete un’ultimu tintativu nanzu chì u vostru contu sia chjosu.\n      locked: U vostru contu hè chjosu.\n      not_found_in_database: L’ %{authentication_keys} o a chjave d’accessu ùn sò curretti.\n      pending: U vostru contu hè sempre in corsu di rivista.\n      timeout: A vostra sezzione hè spirata. Ricunnettatevi pè cuntinuà.\n      unauthenticated: Cunnettatevi o arregistratevi pè cuntinuà.\n      unconfirmed: Duvete cunfirmà u vostru contu pè cuntinuà.\n    mailer:\n      confirmation_instructions:\n        action: Verificà l’indirizzu email\n        action_with_app: Cunfirmà è rivene à %{app}\n        explanation: Avete creatu un contu nant’à %{host} cù st’indirizzu email. Pudete attivallu cù un clic, o ignurà quessu missaghji s’ellu un era micca voi.\n        explanation_when_pending: Avete dumandatu un'invitazione à %{host}, cù st'indirizzu e-mail. Una volta ch'ellu hè cunfirmatu, avemu da dà un'ochjata à a vostra dumanda. Ùn pudete micca cunnettavi nanz'à quessa. S'ella hè righjittata a vostra dumanda, i vostri dati saranu sguassati è ùn duverete fà nund'altru. S'ellu ùn era micca voi, pudete ignurà quess'e-mail.\n        extra_html: Pensate à leghje <a href=\"%{terms_path}\">e regule di u servore</a> è <a href=\"%{policy_path}\">i termini d’usu</a>.\n        subject: 'Mastodon: Istruzzione di cunfirmazione per %{instance}'\n        title: Verificà l’indirizzu email\n      email_changed:\n        explanation: 'L’indirizzu email di u vostru contu hè stata cambiata per:'\n        extra: S’ellu un era micca voi ch’avete cambiatu u vostru email, qualch’un’altru hà accessu à u vostru contu. Duvete cambià a vostra chjave d’accessu o cuntattà l’amministratore di u servore s’ellu ùn hè più pussibule di cunnettavi.\n        subject: 'Mastodon: Email cambiatu'\n        title: Novu indirizzu email\n      password_change:\n        explanation: A chjave d’accessu per u vostru contu hè stata cambiata.\n        extra: S’ellu un era micca voi ch’avete cambiatu a vostra chjave d’accessu, qualch’un’altru hà accessu à u vostru contu. Duvete cambià a vostra chjave d’accessu o cuntattà l’amministratore di u servore s’ellu ùn hè più pussibule di cunnettavi.\n        subject: 'Mastodon: Chjave d’accessu cambiata'\n        title: Chjave cambiata\n      reconfirmation_instructions:\n        explanation: Cunfirmà u novu indirizzu per cambià l’email.\n        extra: S’ellu ùn era micca voi, ignurate stu missaghju. L’email ùn cambiarà micca s’è voi ùn cliccate micca u ligame.\n        subject: 'Mastodon: Cunfirmà l’email per %{instance}'\n        title: Verificà indirizzu email\n      reset_password_instructions:\n        action: Cambià a chjave d’accessu\n        explanation: Avete dumandatu una nova chjave d’accessu per u vostru contu.\n        extra: S’ellu ùn era micca voi, ignurate stu missaghju. A chjave d’accessu ùn cambiarà micca s’è voi ùn cliccate micca u ligame.\n        subject: 'Mastodon: Cambià a chjave d’accessu'\n        title: Cambià a chjave\n      unlock_instructions:\n        subject: 'Mastodon: Riapre u contu'\n    omniauth_callbacks:\n      failure: Ùn pudemu micca cunnettavi da %{kind} perchè \"%{reason}\".\n      success: Vi site cunnettatu·a da %{kind}.\n    passwords:\n      no_token: Ùn pudete micca vede sta pagina senza vene d’un e-mail di cambiamentu di chjave d’accessu. S’è voi venite quì dapoi st’e-mail, assicuratevi ch’avete utilizatu l’indirizzu URL cumpletu.\n      send_instructions: Avete da riceve l’istruzzione di cambiamentu di a chjave d’accessu in qualchì minuta.\n      send_paranoid_instructions: S’ellu esiste u vostr’e-mail in a database, avete da riceve un ligame di reinizialisazione.\n      updated: A vostra chjave d’accessu hè stata cambiata, è site cunnettatu·a.\n      updated_not_active: A vostra chjave d’accessu hè stata cambiata.\n    registrations:\n      destroyed: Avvedeci! U vostru contu hè statu sguassatu. Speremu di vi rivede da prestu.\n      signed_up: Benvinutu! Site cunnettatu·a.\n      signed_up_but_inactive: Site arregistratu·a, mà ùn pudete micca cunnettavi perchè u vostru contu deve esse attivatu.\n      signed_up_but_locked: Site arregistratu·a, mà ùn pudete micca cunnettavi perchè u vostru contu hè chjosu.\n      signed_up_but_pending: Un missaghju cù un ligame di cunfirmazione hè statu mandatu à u vostr'indirizzu e-mail. Dop'à avè cliccatu u ligame, avemu da rivede a vostra dumanda - sarete nutificatu·a s'ella hè appruvata.\n      signed_up_but_unconfirmed: Un missaghju cù un ligame di cunfirmazione hè statu mandatu à u vostru indirizzu e-mail. Aprite stu ligame pè attivà u vostru contu. Pensate à verificà u cartulare di spam s’ellu ùn c’hè nunda.\n      update_needs_confirmation: U vostru contu hè statu messu à ghjornu mà duvemu verificà u vostru novu e-mail. Un missaghju cù un ligame di cunfirmazione hè statu mandatu. Pensate à verificà u cartulare di spam s’ellu ùn c’hè nunda.\n      updated: U vostru contu hè statu messu à ghjornu.\n    sessions:\n      already_signed_out: Scunnettatu·a.\n      signed_in: Cunnettatu·a.\n      signed_out: Scunnettatu·a.\n    unlocks:\n      send_instructions: Avete da riceve un’e-mail cù l’istruzzione pè riapre u vostru contu in qualchì minuta.\n      send_paranoid_instructions: S’ellu esiste u vostru contu, avete da riceve un’e-mail dù l’istruzzione pè riapre u vostru contu.\n      unlocked: U vostru contu hè statu riapertu, pudete cunnettavi pè cuntinuà.\n  errors:\n    messages:\n      already_confirmed: hè digià cunfirmatu, pudete pruvà à cunnettà vi\n      confirmation_period_expired: deve esse cunfirmatu nanz’à %{period}, duvete fà un’altra dumanda\n      expired: hè spiratu, duvete fà un’altra dumanda\n      not_found: ùn hè micca statu trovu\n      not_locked: ùn era micca chjosu\n      not_saved:\n        one: 'Un prublemu hà impeditu a cunservazione di stu (sta) %{resource}:'\n        other: \"%{count} prublemi anu impeditu a cunservazione di stu (sta) %{resource} :\"\n"
  },
  {
    "path": "config/locales/devise.cs.yml",
    "content": "---\ncs:\n  devise:\n    confirmations:\n      confirmed: Vaše e-mailová adresa byla úspěšně ověřena.\n      send_instructions: Za několik minut obdržíte e-mail s instrukcemi pro potvrzení vašeho účtu. Pokud tento e-mail neobdržíte, prosím zkontrolujte si složku „spam“.\n      send_paranoid_instructions: Pokud vaše e-mailová adresa existuje v naší databázi, obdržíte za několik minut e-mail s instrukcemi pro potvrzení vaší e-mailové adresy. Pokud tento e-mail neobdržíte, prosím zkontrolujte si složku „spam“.\n    failure:\n      already_authenticated: Již jste přihlášen/a.\n      inactive: Váš účet ještě není aktivován.\n      invalid: Neplatný %{authentication_keys} nebo heslo.\n      last_attempt: Máte ještě jeden pokus, než bude váš účet uzamčen.\n      locked: Váš účet je uzamčen.\n      not_found_in_database: Neplatné %{authentication_keys} nebo heslo.\n      pending: Váš účet je stále posuzován.\n      timeout: Vaše relace vypršela. Pro pokračování se prosím přihlaste znovu.\n      unauthenticated: Před pokračováním se musíte přihlásit nebo registrovat.\n      unconfirmed: Před pokračováním musíte potvrdit svůj e-mail.\n    mailer:\n      confirmation_instructions:\n        action: Potvrdit e-mailovou adresu\n        action_with_app: Potvrdit a navrátit se do %{app}\n        explanation: S touto e-mailovou adresou jste si vytvořil/a účet na %{host}. K jeho aktivaci vám zbývá jedno kliknutí. Pokud jste to nebyl/a vy, prosím ignorujte tento e-mail.\n        explanation_when_pending: S touto e-mailovou adresou jste si vyžádal/a pozvánku na %{host}. Jakmile svou e-mailovou adresu potvrdíte, posoudíme váš poadavek. Do té doby se nemůžete přihlásit. Pokud bude váš požadavek zamítnut, budou vaše data odstraněna, takže od vás nebude vyžadována žádná další akce. Pokud jste to nebyl/a vy, prosím ignorujte tento e-mail.\n        extra_html: Prosím podívejte se také na <a href=\"%{terms_path}\">pravidla tohoto serveru</a> a <a href=\"%{policy_path}\">naše podmínky používání</a>.\n        subject: 'Mastodon: Potvrzovací instrukce pro %{instance}'\n        title: Potvrďte e-mailovou adresu\n      email_changed:\n        explanation: 'E-mailová adresa vašeho účtu byla změněna na:'\n        extra: Pokud jste si e-mail nezměnil/a, je pravděpodobné, že někdo jiný získal přístup k vašemu účtu. Prosím změňte si okamžitě heslo, nebo, pokud se nemůžete na účet přihlásit, kontaktujte administrátora serveru.\n        subject: 'Mastodon: E-mail byl změněn'\n        title: Nová e-mailová adresa\n      password_change:\n        explanation: Heslo k vašemu účtu bylo změněno.\n        extra: Pokud jste si heslo nezměnil/a, je pravděpodobné, že někdo jiný získal přístup k vašemu účtu. Prosím změňte si okamžitě heslo, nebo, pokud se nemůžete na účet přihlásit, kontaktujte administrátora serveru.\n        subject: 'Mastodon: Heslo bylo změněno'\n        title: Heslo bylo změněno\n      reconfirmation_instructions:\n        explanation: Potvrďte novou adresu pro změnu e-mailu.\n        extra: Pokud jste tuto změnu nevyžádal/a vy, prosím ignorujte tento e-mail. E-mailová adresa nebude změněna, dokud nepřejdete na výše uvedenou adresu.\n        subject: 'Mastodon: Potvrďte e-mail pro %{instance}'\n        title: Ověřit e-mailovou adresu\n      reset_password_instructions:\n        action: Změnit heslo\n        explanation: Vyžádal/a jste si pro svůj účet nové heslo.\n        extra: Pokud jste tohle nevyžádal/a, prosím ignorujte tento e-mail. Vaše heslo nebude změněno, dokud nepřejdete na výše uvedenou adresu a nevytvoříte si nové.\n        subject: 'Mastodon: Instrukce pro obnovení hesla'\n        title: Obnovení hesla\n      unlock_instructions:\n        subject: 'Mastodon: Instrukce pro odemčení účtu'\n    omniauth_callbacks:\n      failure: Nelze vás ověřit z %{kind}, protože „%{reason}“.\n      success: Úspěšně ověřeno z účtu %{kind}.\n    passwords:\n      no_token: Tuto stránku nemůžete navštívit, pokud nepřicházíte z e-mailu pro obnovení hesla. Pokud z něj přicházíte, ujistěte se, že jste použil/a celé URL z e-mailu.\n      send_instructions: Pokud vaše e-mailová adresa existuje v naší databázi, obdržíte za několik minut ve vašem e-mailu odkaz pro obnovení hesla. Pokud tento e-mail neobdržíte, prosím zkontrolujte si složku „spam“.\n      send_paranoid_instructions: Pokud vaše e-mailová adresa existuje v naší databázi, obdržíte za několik minut ve vašem e-mailu odkaz pro obnovení hesla. Pokud tento e-mail neobdržíte, prosím zkontrolujte si složku „spam“.\n      updated: Vaše heslo bylo úspěšně změněno. Nyní jste přihlášen/a.\n      updated_not_active: Vaše heslo bylo úspěšně změněno.\n    registrations:\n      destroyed: Sbohem! Váš účet byl úspěšně zrušen. Doufáme, že vás opět brzy uvidíme.\n      signed_up: Vítejte! Registroval/a jste se úspěšně.\n      signed_up_but_inactive: Registroval/a jste se úspěšně. Nemohli jsme vás však přihlásit, protože váš účet ještě není aktivován.\n      signed_up_but_locked: Registroval/a jste se úspěšně. Nemohli jsme vás však přihlásit, protože váš účet je uzamčen.\n      signed_up_but_pending: Na vaši e-mailovou adresu byla poslána zpráva s potvrzovacím odkazem. Poté, co kliknete na odkaz, posoudíme váš požadavek. Pokud bude schválen, budete informován/a.\n      signed_up_but_unconfirmed: Na vaši e-mailovou adresu byla poslána zpráva s potvrzovacím odkazem. Pro aktivaci účtu přejděte na danou adresu. Pokud jste tento e-mail neobdržel/a, prosím zkontrolujte si složku spam.\n      update_needs_confirmation: Váš účet byl úspěšně aktualizován, ale je potřeba ověřit vaši novou e-mailovou adresu. Pokud tento e-mail neobdržíte, prosím zkontrolujte si složku „spam“.\n      updated: Váš účet byl úspěšně aktualizován.\n    sessions:\n      already_signed_out: Odhlášení proběhlo úspěšně.\n      signed_in: Přihlášení proběhlo úspěšně.\n      signed_out: Odhlášení proběhlo úspěšně.\n    unlocks:\n      send_instructions: Za několik minut obdržíte e-mail s instrukcemi pro odemčení vašeho účtu. Pokud tento e-mail neobdržíte, prosím zkontrolujte si složku „spam“.\n      send_paranoid_instructions: Pokud váš účet existuje, obdržíte za několik minut e-mail s instrukcemi pro odemčení vašeho účtu. Pokud tento e-mail neobdržíte, prosím zkontrolujte si složku „spam“.\n      unlocked: Váš účet byl úspěšně odemčen. Pro pokračování se prosím přihlaste.\n  errors:\n    messages:\n      already_confirmed: byl již potvrzen, prosím zkuste se přihlásit\n      confirmation_period_expired: musí být potvrzen do %{period}, prosím vyžádejte si nový\n      expired: vypršel, prosím vyžádejte si nový\n      not_found: nenalezen\n      not_locked: nebyl uzamčen\n      not_saved:\n        few: \"%{count} chyby zabránily uložení tohoto %{resource}:\"\n        many: \"%{count} chyb zabránilo uložení tohoto %{resource}:\"\n        one: '1 chyba zabránila uložení tohoto %{resource}:'\n        other: \"%{count} chyb zabránilo uložení tohoto %{resource}:\"\n"
  },
  {
    "path": "config/locales/devise.cy.yml",
    "content": "---\ncy:\n  devise:\n    confirmations:\n      confirmed: Mae eich cyfeiriad e-bost wedi ei gadarnhau yn llwyddiannus.\n      send_instructions: Byddwch yn derbyn e-bost a chyfarwyddiadau am sut i gadarnhau eich cyfeiriad e-bost mewn rhai munudau. Os na dderbynioch chi'r e-bost hwn, edrychwch yn eich ffolder sbam os gwelwch yn dda.\n      send_paranoid_instructions: Os yw eich cyfeiriad e-bost yn bodoli yn ein bas data, byddwch yn derbyn e-bost a chyfarwyddiadau am sut i gadarnhau eich cyfeiriad ebost mewn rhai munudau. Os na dderbynioch chi'r e-bost hwn, edrychwch yn eich ffolder sbam os gwelwch yn dda.\n    failure:\n      already_authenticated: Yr ydych wedi mewngofnodi yn barod.\n      inactive: Nid yw eich cyfrif yn weithredol eto.\n      invalid: \"%{authentication_keys} neu gyfrinair annilys.\"\n      last_attempt: Mae gennych un cyfle arall cyn i'ch cyfrif gael ei gloi.\n      locked: Mae eich cyfrif wedi ei gloi.\n      not_found_in_database: \"%{authentication_keys} neu gyfrinair annilys.\"\n      timeout: Mae eich sesiwn wedi dod i ben. Mewngofnodwch eto i barhau.\n      unauthenticated: Mae angen i chi fewngofnodi neu gofrestru cyn parhau.\n      unconfirmed: Mae rhaid i chi gadarnhau eich cyfeiriad e-bost cyn parhau.\n    mailer:\n      confirmation_instructions:\n        action: Gwiriwch eich cyfeiriad e-bost\n        action_with_app: Cadarnhau a dychwelyd i %{app}\n        explanation: Yr ydych wedi creu cyfrif ar %{host} gyda'r cyfrif e-bost hwn. Dim ond un clic sydd angen i'w wneud yn weithredol. Os nad chi oedd hyn, anwybyddwch yr e-bost hwn os gwelwch yn dda.\n        extra_html: Gwnewch yn siŵr i edrych ar <a href=\"%{terms_path}\">reolau'r achos</a> a <a href=\"%{policy_path}\">ein telerau gwasanaeth</a>.\n        subject: 'Mastodon: Canllawiau cadarnhau i %{instance}'\n        title: Gwirio cyfeiriad e-bost\n      email_changed:\n        explanation: 'Mae''r cyfeiriad e-bost ar gyfer eich cyfrif yn cael ei newid i:'\n        extra: Os na wnaethoch chi newid eich e-bost, mae'n debygol fod rhywun wedi cael mynediad i'ch cyfrif. Newidwch eich cyfrinair yn syth os gwelwch yn dda neu cysylltwch a gweinydd yr achos os ydych wedi'ch cloi allan o'ch cyfrif.\n        subject: 'Mastodon: Newidwyd e-bost'\n        title: Cyfeiriad e-bost newydd\n      password_change:\n        explanation: Newidwyd cyfrinair eich cyfrif.\n        extra: Os na wnaethoch chi newid eich e-bost, mae'n debygol fod rhywun wedi cael mynediad i'ch cyfrif. Newidwch eich cyfrinair yn syth os gwelwch yn dda neu cysylltwch a gweinydd yr achos os ydych wedi'ch cloi allan o'ch cyfrif.\n        subject: 'Mastodon: Newidwyd Cyfrinair'\n        title: Newidwyd cyfrinair\n      reconfirmation_instructions:\n        explanation: Cadarnhewch y cyferiad newydd i newid eich e-bost.\n        extra: Os nad chi wnaeth y newid hwn, anwybyddwch yr e-bost hwn os gwelwch yn dda. Ni fydd y cyfeiriad e-bost ar gyfer y cyfrif Mastodon yn newid nes eich bod yn mynd at y ddolen uchod.\n        subject: 'Mastodon: Cadarnhewch e-bost i %{instance}'\n        title: Gwirio cyfeiriad e-bost\n      reset_password_instructions:\n        action: Newid cyfrinair\n        explanation: Gofynnoch am gyfrinair newydd i'ch cyfrif.\n        extra: Os na wnaethoch gais am hyn, anwybyddwch yr e-bost hwn os gwelwch yn dda. Ni fydd eich cyfrinair yn newid nes i chi fynd at y ddolen uchod a chreu un newydd.\n        subject: 'Mastodon: Ailosod cyfarwyddiadau cyfrinair'\n        title: Ailosod cyfrinair\n      unlock_instructions:\n        subject: 'Mastodon: Cyfarwyddiadau datgloi'\n    omniauth_callbacks:\n      failure: Methu eich dilysu o %{kind} oherwydd \"%{reason}\".\n      success: Dilyswyd yn llwyddiannus o gyfrif %{kind}.\n    passwords:\n      no_token: Nid oes modd cael mynediad i'r dudalen hon heb ddod drwy e-bost ailosod cyfrinair. Os ydych yn dod o e-bost ailosod cyfrinair, gwnewch yn siŵr y defnyddioch chi'r URL a ddarparwyd yn ei gyfanrwydd.\n      send_instructions: Os yw eich cyfeiriad e-bost yn bresennol yn ein bas data, mi fyddwch yn derbyn dolen yn eich blwch e-bost ymhen cwpl o funudau. Os nad ydych yn derbyn yr e-bost hwn, edrychwch yn eich ffolder spam os gwelwch yn dda.\n      send_paranoid_instructions: Os yw eich cyfeiriad e-bost yn bresennol yn ein bas data, mi fyddwch yn derbyn dolen yn eich blwch e-bost ymhen cwpl o funudau. Os nad ydych yn derbyn yr e-bost hwn, edrychwch yn eich ffolder spam os gwelwch yn dda.\n      updated: Mae eich cyfrinair wedi ei newid yn llwyddiannus. Yr ydych wedi mewngofnodi.\n      updated_not_active: Mae eich cyfrinair wedi ei newid yn llwyddiannus.\n    registrations:\n      destroyed: Hwyl fawr! Mae eich cyfrif wedi ei ganslo'n llwyddiannus. Gobeithiwn eich gweld chi eto'n fuan.\n      signed_up: Croeso! Rydych wedi cofrestru'n llwyddiannus.\n      signed_up_but_inactive: Yr ydych wedi cofrestru'n llwyddiannus. Fodd bynnag, ni allwn eich mewngofnodi achos nid yw eich cyfrif wedi ei actifadu eto.\n      signed_up_but_locked: Yr ydych wedi cofrestru'n llwyddiannus. Fodd bynnag, ni allwn eich mewngofnodi achos fod eich cyfrif wedi ei gloi.\n      signed_up_but_unconfirmed: Mae neges gyda dolen cadarnhau wedi ei anfon i'ch cyfeiriad e-bost. Dilynwch y ddolen er mwyn actifadu eich cyfrif. Edrychwch yn eich ffolder sbam os na dderbynioch chi'r e-bost hwn os gwelwch yn dda.\n      update_needs_confirmation: Rydych wedi diweddaru eich cyfrif yn llwyddiannus, ond mae angen i ni wirio'ch cyfeiriad e-bost newydd. Edrychwch ar eich e-byst a dilynwch y ddolen gadarnhau er mwyn cadarnhau eich cyfeiriad e-bost newydd. Edrychwch ar eich ffolder sbam os na dderbynioch chi yr e-bost hwn.\n      updated: Mae eich cyfrif wedi ei ddiweddaru yn llwyddiannus.\n    sessions:\n      already_signed_out: Allgofnodwyd yn llwyddiannus.\n      signed_in: Mewngofnodwyd yn llwyddiannus.\n      signed_out: Allgofnodwyd yn llwyddiannus.\n    unlocks:\n      send_instructions: Mi fyddwch yn derbyn e-bost a chyfarwyddiadau ynghylch sut i ddatgloi eich cyfrif ymhen cwpl o funudau. Edrychwch yn eich ffolder sbam os na dderbynioch chi'r e-bost hwn os gwelwch yn dda.\n      send_paranoid_instructions: Os yw eich cyfrif yn bodoli, mi fyddwch yn derbyn e-bost a cyfarwyddiadau o sut i ddatgloi eich cyfrif ymhen cwpl o funudau. Edrychwch yn eich ffolder sbam os na dderbynioch chi'r e-bost hwn os gwelwch yn dda.\n      unlocked: Mae eich cyfrif wedi ei ddatgloi'n llwyddiannus. Mewngofnodwch i barhau.\n  errors:\n    messages:\n      already_confirmed: wedi ei gadarnhau yn barod, ymgeisiwch fewngofnodi\n      confirmation_period_expired: angen ei gadarnhau o fewn %{period}, gwnewch gais am un newydd os gwelwch yn dda\n      expired: wedi dod i ben, gwnewch gais am un newydd os gwelwch yn dda\n      not_found: heb ei ganfod\n      not_locked: heb ei gloi\n      not_saved:\n        few: 'Gwaharddwyd yr %{resource} rhag cael ei arbed oherwydd %{count} gwall:'\n        many: 'Gwaharddwyd yr %{resource} rhag cael ei arbed oherwydd %{count} gwall:'\n        one: 'Gwaharddwyd yr %{resource} rhag cael ei arbed oherwydd 1 gwall:'\n        other: 'Gwaharddwyd yr %{resource} rhag cael ei arbed oherwydd %{count} gwall:'\n        two: 'Gwaharddwyd yr %{resource} rhag cael ei arbed oherwydd %{count} gwall:'\n        zero: 'Gwaharddwyd yr %{resource} rhag cael ei arbed oherwydd %{count} gwall:'\n"
  },
  {
    "path": "config/locales/devise.da.yml",
    "content": "---\nda:\n  devise:\n    confirmations:\n      confirmed: Din email adresse er blevet succesfuldt bekræftet.\n      send_instructions: Du vil modtage en mail med instrukser for hvordan du bekræfter din email adresse om få minutter. Tjek venligst din spam mappe hvis du ikke har modtaget denne email.\n      send_paranoid_instructions: Hvis din email adresse allerede findes i vores database, vil du modtage en email med instrukser for hvordan du bekræfter din email adresse om få minutter. Tjek gerne din spam mappe hvis du ikke modtager denne email.\n    failure:\n      already_authenticated: Du er allerede logget ind.\n      inactive: Din konto er endnu ikke aktiveret.\n      invalid: Ugyldig %{authentication_keys} eller ugyldigt kodeord.\n      last_attempt: Du har et forsøg tilbage før din konto låses.\n      locked: Din konto er låst.\n      not_found_in_database: Ugyldig %{authentication_keys} eller ugyldigt kodeord.\n      timeout: Din session er udløbet. Log venligst ind igen for at fortsætte.\n      unauthenticated: Du er nødt til at logge ind eller oprette dig for at fortsætte.\n      unconfirmed: Du er nødt til at bekræfte din email adresse for at fortsætte.\n    mailer:\n      confirmation_instructions:\n        action: Bekræft email adresse\n        action_with_app: Bekræft og vend tilbage til %{app}\n        explanation: Du har oprettet en konto på %{host} med denne email adresse. Du er et klik fra at aktivere din konto. Hvis du ikke har oprettet dig, ignorer venligst denne email.\n        extra_html: Tjek også <a href=\"%{terms_path}\">reglerne for serveren</a> og <a href=\"%{policy_path}\">vores betingelser</a>.\n        subject: 'Mastodon: Bekræftelses instrukser for %{instance}'\n        title: Bekræft email adresse\n      email_changed:\n        explanation: 'Email adressen for din konto bliver ændret til:'\n        extra: Hvis du ikke har ændret din email adresse er det muligt, at nogen har fået adgang til din konto. Venligst ændre dit kodeord med det samme eller kontakt administratoren på serveren hvis du er låst ude af din konto.\n        subject: 'Mastodon: Email ændret'\n        title: Ny email adresse\n      password_change:\n        explanation: Kodeordet for din konto er blevet ændret.\n        extra: Hvis du ikke har ændret dit kodeord er det muligt, at nogen har fået adgang til din konto. Venligst ændre dit kodeord med det samme eller kontakt administratoren på serveren hvis du er låst ude af din konto.\n        subject: 'Mastodon: Kodeord ændret'\n        title: Kodeordet er blevet ændret\n      reconfirmation_instructions:\n        explanation: Bekræft den nye adresse for at ændre din email.\n        extra: Hvis denne ændring ikke blev foretaget af dig, ignorer denne email. Email adressen for denne Mastodon konto vil ikke blive ændret før du følger linket foroven.\n        subject: 'Mastodon: Bekræft email for %{instance}'\n        title: Bekræft email adresse\n      reset_password_instructions:\n        action: Ændre kodeord\n        explanation: Du anmodede om en ny adgangskode for din konto.\n        extra: Hvis du ikke har anmodet om dette, ignorer denne email. Din adgangskode vil ikke blive ændret før du har fulgt linket foroven og oprettet en ny.\n        subject: 'Mastodon: Instrukser for nulstilling af adgangskode'\n        title: Kodeordet er blevet nulstillet\n      unlock_instructions:\n        subject: 'Mastodon: Instruktioner for oplåsning'\n    omniauth_callbacks:\n      failure: Kunne ikke godkende dig fra %{kind} fordi \"%{reason}\".\n      success: Godkendelse fra %{kind} konto lykkedes.\n    passwords:\n      no_token: Du kan ikke tilgå denne side uden at komme fra en email om nulstilling af adgangskode. Hvis du kommer fra en email om nulstilling af adgangskode, tjek om du brugte det fulde link der blev angivet.\n      send_instructions: Hvis din email adresse allerede findes i vores database, vil du modtage et link til nulstilling af adgangskode til din email adresse om få minutter. Tjek din spam mappe hvis du ikke har modtaget denne email.\n      send_paranoid_instructions: Hvis din email adresse allerede findes i vores database, vil du modtage et link til nulstilling af adgangskode til din email adresse om få minutter. Tjek din spam mappe hvis du ikke har modtaget denne email.\n      updated: Din adgangskode er nu blevet ændret. Du er nu logget ind.\n      updated_not_active: Din adgangskode blev ændret.\n    registrations:\n      destroyed: Farvel! Din konto er nu annulleret. Vi håber snart at se dig igen.\n      signed_up: Velkommen! Du har nu tilmeldt dig.\n      signed_up_but_inactive: Du har nu oprettet dig. Vi kunne dog ikke logge dig ind da din konto endnu ikke er aktiveret.\n      signed_up_but_locked: Du har nu oprettet dig. Vi kunne dog ikke logge dig ind da din konto er låst.\n      signed_up_but_unconfirmed: En besked med et bekræftelses link er nu blevet sendt til din email adresse. Følg linket for at aktivere din konti. Tjek din spam mappe hvis du ikke har modtaget denne email.\n      update_needs_confirmation: Du har succesfuldt opdateret din konto, men vi er nødt til at bekræfte din email adresse. Tjek venligst din email og følg bekræftelses linket for at bekræfte din nye email adresse. Tjek venligst din spam mappe hvis du ikke har modtaget denne email.\n      updated: Din konto er nu blevet opdateret.\n    sessions:\n      already_signed_out: Du er nu logget ud.\n      signed_in: Du er nu logget ind.\n      signed_out: Du er nu logget ud.\n    unlocks:\n      send_instructions: Du vil modtage en email med instrukser for hvordan du låser op for din konto om nogle få minutter. Venligst tjek din spam mappe hvis du ikke har modtaget denne email.\n      send_paranoid_instructions: Hvis din konto findes, vil du modtage en email med instrukser for hvordan du låser op for den om få minutter. Tjek venligst din spam mappe hvis du ikke har modtaget denne mail.\n      unlocked: Din konto er succesfuldt blevet låst op. Log venligst ind for at fortsætte.\n  errors:\n    messages:\n      already_confirmed: er allerede blevet bekræftet, prøv venligst at logge ind\n      confirmation_period_expired: skal bekræftes indenfor %{period}, anmod venligst om en ny\n      expired: er udløbet, anmod venligst en ny\n      not_found: ikke fundet\n      not_locked: blev ikke låst\n      not_saved:\n        one: '1 fejl forhindrede denne %{resource} fra at blive gemt:'\n        other: \"%{count} fejl forhindrede denne %{resource} fra at blive gemt:\"\n"
  },
  {
    "path": "config/locales/devise.de.yml",
    "content": "---\nde:\n  devise:\n    confirmations:\n      confirmed: Deine E-Mail-Adresse wurde bestätigt.\n      send_instructions: Du wirst in wenigen Minuten eine E-Mail erhalten. Darin wird erklärt, wie du deine E-Mail-Adresse bestätigen kannst. Schau bitte auch in deinem Spam-Ordner nach, wenn du diese E-Mail nicht erhalten hast.\n      send_paranoid_instructions: Falls deine E-Mail-Adresse in unserer Datenbank hinterlegt ist, wirst du in wenigen Minuten eine E-Mail erhalten. Darin wird erklärt, wie du deine E-Mail-Adresse bestätigen kannst. Schau bitte auch in deinem Spam-Ordner nach, wenn du diese E-Mail nicht erhalten hast.\n    failure:\n      already_authenticated: Du bist bereits angemeldet.\n      inactive: Dein Konto wurde noch nicht aktiviert.\n      invalid: \"%{authentication_keys} oder Passwort ungültig.\"\n      last_attempt: Du hast noch einen Versuch, bevor dein Konto gesperrt wird.\n      locked: Dein Konto ist gesperrt.\n      not_found_in_database: \"%{authentication_keys} oder Passwort ungültig.\"\n      pending: Dein Konto wird immer noch überprüft.\n      timeout: Deine Sitzung ist abgelaufen. Bitte melde dich erneut an, um fortzufahren.\n      unauthenticated: Du musst dich anmelden oder registrieren, bevor du fortfahren kannst.\n      unconfirmed: Du musst deine E-Mail-Adresse bestätigen, bevor du fortfahren kannst.\n    mailer:\n      confirmation_instructions:\n        action: E-Mail-Adresse verifizieren\n        action_with_app: Bestätigen und zu %{app} zurückkehren\n        explanation: Du hast einen Account auf %{host} mit dieser E-Mail-Adresse erstellt. Du bist nun einen Klick entfernt vor der Aktivierung. Wenn du das nicht warst, kannst du diese E-Mail ignorieren.\n        explanation_when_pending: Du hast dich für eine Einladung bei %{host} mit dieser E-Mailadresse beworben. Sobald du deine E-Mailadresse bestätigst werden wir deine Anfrage überprüfen. Du kannst dich in dieser Zeit nicht anmelden. Wenn deine Anfrage abgelehnt wird, werden deine Daten entfernt, also wird keine weitere Handlung benötigt. Wenn du das nicht warst kannst du diese E-Mail ignorieren.\n        extra_html: Bitte lies auch die <a href=\"%{terms_path}\">Regeln des Servers</a> und <a href=\"%{policy_path}\">unsere Nutzungsbedingungen</a>.\n        subject: 'Mastodon: Bestätigung deines Kontos bei %{instance}'\n        title: Verifiziere E-Mail-Adresse\n      email_changed:\n        explanation: 'Die E-Mail-Adresse deines Accounts wird geändert zu:'\n        extra: Wenn du deine E-Mail-Adresse nicht geändert hast, dann kann es vermutlich sein, dass jemand Zugriff zu deinem Account erhalten hat. Bitte ändere sofort dein Passwort oder kontaktiere den Administrator des Servers, wenn du dich ausgesperrt hast.\n        subject: 'Mastodon: E-Mail-Adresse geändert'\n        title: Neue E-Mail-Adresse\n      password_change:\n        explanation: Das Passwort für deinen Account wurde geändert.\n        extra: Wenn du dein Passwort nicht geändert hast, dann kann es vermutlich sein, dass jemand Zugriff zu deinem Account erhalten hat. Bitte ändere sofort dein Passwort oder kontaktiere den Administrator des Servers, wenn du dich ausgesperrt hast.\n        subject: 'Mastodon: Passwort geändert'\n        title: Passwort geändert\n      reconfirmation_instructions:\n        explanation: Bestätige deine neue E-Mail-Adresse, um sie zu ändern.\n        extra: Wenn diese Änderung nicht von dir angestoßen wurde, dann solltest du diese E-Mail ignorieren. Die E-Mail-Adresse für deinen Mastodon-Account wird sich nicht ändern, bis du den obigen Link anklickst.\n        subject: 'Mastodon: Bestätige E-Mail-Adresse für %{instance}'\n        title: Verifiziere E-Mail-Adresse\n      reset_password_instructions:\n        action: Ändere Passwort\n        explanation: Du hast ein neues Passwort für deinen Account angefragt.\n        extra: Wenn du diese Anfrage nicht gestellt hast, solltest du diese E-Mail ignorieren. Dein Passwort wird sich nicht ändern solange du den obigen Link anklickst und ein neues erstellst.\n        subject: 'Mastodon: Passwort zurücksetzen'\n        title: Passwort zurücksetzen\n      unlock_instructions:\n        subject: 'Mastodon: Konto entsperren'\n    omniauth_callbacks:\n      failure: Du konntest nicht mit deinem %{kind}-Konto angemeldet werden, weil »%{reason}«.\n      success: Du hast dich erfolgreich mit deinem %{kind}-Konto angemeldet.\n    passwords:\n      no_token: Du kannst diese Seite nur über den Link aus der E-Mail zum Passwort-Zurücksetzen aufrufen. Wenn du einen solchen Link aufgerufen hast, stelle bitte sicher, dass du die vollständige Adresse aufrufst.\n      send_instructions: Du erhältst in wenigen Minuten eine E-Mail. Darin wird erklärt, wie du dein Passwort zurücksetzen kannst.\n      send_paranoid_instructions: Falls deine E-Mail-Adresse in unserer Datenbank hinterlegt ist, erhältst du in wenigen Minuten eine E-Mail. Darin wird erklärt, wie du dein Passwort zurücksetzen kannst.\n      updated: Dein Passwort wurde geändert. Du bist jetzt angemeldet.\n      updated_not_active: Dein Passwort wurde geändert.\n    registrations:\n      destroyed: Dein Konto wurde gelöscht.\n      signed_up: Willkommen! Du hast dich erfolgreich registriert.\n      signed_up_but_inactive: Du hast dich erfolgreich registriert. Wir konnten dich noch nicht anmelden, da dein Konto inaktiv ist.\n      signed_up_but_locked: Du hast dich erfolgreich registriert. Wir konnten dich noch nicht anmelden, da dein Konto gesperrt ist.\n      signed_up_but_pending: Eine Nachricht mit einem Bestätigungslink wurde an dich per E-Mail geschickt. Nachdem du diesen Link angeklickt hast werden wir deine Anfrage überprüfen. Du wirst benachrichtigt falls die Anfrage angenommen wurde.\n      signed_up_but_unconfirmed: Du hast dich erfolgreich registriert. Wir konnten dich noch nicht anmelden, da dein Konto noch nicht bestätigt ist. Du erhältst in Kürze eine E-Mail. Darin ist erklärt, wie du dein Konto freischalten kannst.\n      update_needs_confirmation: Deine Daten wurden aktualisiert, aber du musst deine neue E-Mail-Adresse bestätigen. Du erhältst in wenigen Minuten eine E-Mail. Darin ist erklärt, wie du die Änderung deiner E-Mail-Adresse abschließen kannst.\n      updated: Deine Daten wurden aktualisiert.\n    sessions:\n      already_signed_out: Erfolgreich abgemeldet.\n      signed_in: Erfolgreich angemeldet.\n      signed_out: Erfolgreich abgemeldet.\n    unlocks:\n      send_instructions: Du erhältst in wenigen Minuten eine E-Mail. Darin wird erklärt, wie du dein Konto entsperren kannst.\n      send_paranoid_instructions: Falls deine E-Mail-Adresse in unserer Datenbank hinterlegt ist, erhältst du in wenigen Minuten eine E-Mail. Darin wird erklärt, wie du dein Konto entsperren kannst.\n      unlocked: Dein Konto wurde entsperrt. Du bist jetzt angemeldet.\n  errors:\n    messages:\n      already_confirmed: wurde bereits bestätigt, bitte versuche dich anzumelden\n      confirmation_period_expired: muss innerhalb %{period} bestätigt werden, bitte fordere einen neuen Link an\n      expired: ist abgelaufen, bitte neu anfordern\n      not_found: nicht gefunden\n      not_locked: ist nicht gesperrt\n      not_saved:\n        one: '1 Fehler hat verhindert, dass %{resource} gespeichert wurde:'\n        other: \"%{count} Fehler verhinderten, dass %{resource} gespeichert wurde:\"\n"
  },
  {
    "path": "config/locales/devise.el.yml",
    "content": "---\nel:\n  devise:\n    confirmations:\n      confirmed: Η διεύθυνση email σου επιβεβαιώθηκε με επιτυχία.\n      send_instructions: Σε μερικά λεπτά θα λάβεις ένα email με οδηγίες για την επιβεβαίωση της διεύθυνσης email σου. Παρακαλούμε έλεγξε το φάκελο με τα ανεπιθύμητα αν δεν το έχεις λάβει.\n      send_paranoid_instructions: Αν η διεύθυνση email σου υπάρχει στη βάση μας, θα λάβεις σε μερικά λεπτά ένα email με οδηγίες επιβεβαίωσης της διεύθυνσής σου. Παρακαλούμε έλεγξε το φάκελο με τα ανεπιθύμητα αν δεν το έχεις λάβει.\n    failure:\n      already_authenticated: Έχεις ήδη συνδεθεί.\n      inactive: Ο λογαριασμός σου δεν έχει ενεργοποιηθεί ακόμα.\n      invalid: Λάθος %{authentication_keys} ή συνθηματικό.\n      last_attempt: Έχεις μια ακόμα προσπάθεια πριν κλειδωθεί ο λογαριασμός σου.\n      locked: Ο λογαριασμός σου κλειδώθηκε.\n      not_found_in_database: Λάθος %{authentication_keys} ή συνθηματικό.\n      pending: Εκκρεμεί η έγκριση του λογαριασμού σου.\n      timeout: Η τρέχουσα σύνδεσή σου έληξε. Παρακαλούμε συνδέσου ξανά για να συνεχίσεις.\n      unauthenticated: Πρέπει να συνδεθείς ή να εγγραφείς για να συνεχίσεις.\n      unconfirmed: Πρέπει να επιβεβαιώσεις τη διεύθυνση email σου για να συνεχίσεις.\n    mailer:\n      confirmation_instructions:\n        action: Επιβεβαίωσε διεύθυνση email\n        action_with_app: Επιβεβαίωση και επιστροφή στο %{app}\n        explanation: Δημιούργησες έναν λογαριασμό στο %{host} με αυτή τη διεύθυνση email. Με ένα κλικ θα τον ενεργοποιήσεις. Αν δεν το έκανες εσύ, παρακαλούμε αγνόησε αυτό το email.\n        explanation_when_pending: Έχεις υποβάλλει αίτηση πρόσκλησης στο %{host} με αυτή την ηλεκτρονική διεύθυνση email. Μόλις επιβεβαιώσεις το email σου, θα ελέγξουμε την αίτηση σου. Μέχρι τότε δε θα μπορεις να συνδεθείς. Αν απορριφθεί η αίτησή σου, τα στοιχεία σου θα αφαιρεθούν, άρα δε θα χρειαστεί να κάνεις κάτι επιπλέον. Αν δεν υπέβαλες εσύ την αίτηση, αγνόησε αυτό το email.\n        extra_html: Παρακαλούμε να διαβάσεις <a href=\"%{terms_path}\">του κανόνες αυτού του κόμβου</a> και <a href=\"%{policy_path}\">τους όρους χρήσης της υπηρεσίας μας</a>.\n        subject: 'Mastodon: Οδηγίες επιβεβαίωσης για %{instance}'\n        title: Επιβεβαίωσε διεύθυνση email\n      email_changed:\n        explanation: 'Αλλάζεις τη διεύθυνση email για τον λογαριασμό σου στην:'\n        extra: Αν δεν άλλαξες εσύ το email σου, ίσως κάποιος να έχει αποκτήσει πρόσβαση στο λογαριασμό σου. Παρακαλούμε άλλαξε το συνθηματικό σου άμεσα ή επικοινώνησε με τον διαχειριστή του κόμβου σου αν έχεις κλειδωθεί απ' έξω.\n        subject: 'Mastodon: Αλλαγή διεύθυνσης email'\n        title: Νέα διεύθυνση email\n      password_change:\n        explanation: Το συνθηματικό του λογαριασμού σου άλλαξε.\n        extra: Αν δεν άλλαξες εσύ το συνθηματικό σου, ίσως κάποιος να έχει αποκτήσει πρόσβαση στο λογαριασμό σου. Παρακαλούμε άλλαξε το συνθηματικό σου άμεσα ή επικοινώνησε με τον διαχειριστή του κόμβου σου αν έχεις κλειδωθεί απ' έξω.\n        subject: 'Mastodon: Αλλαγή συνθηματικού'\n        title: Αλλαγή συνθηματικού\n      reconfirmation_instructions:\n        explanation: Επιβεβαίωσε τη νέα διεύθυνση για να αλλάξεις το email σου.\n        extra: Αν δεν ζήτησες εσύ αυτή την αλλαγή, παρακαλούμε αγνόησε αυτό το email. Η διεύθυνση email για τον λογαριασμό σου στο Mastodon δεν θα αλλάξει μέχρι να επισκεφτείς τον παραπάνω σύνδεσμο.\n        subject: 'Mastodon: Επιβεβαίωση email για %{instance}'\n        title: Επιβεβαίωση διεύθυνσης email\n      reset_password_instructions:\n        action: Αλλαγή συνθηματικού\n        explanation: Ζήτησες ένα νέο συνθηματικό για τον λογαριασμό σου.\n        extra: Αν δεν ζήτησες εσύ αυτή την αλλαγή, παρακαλούμε αγνόησε αυτό το email. Το συνθηματικό σου δεν θα αλλάξει μέχρι να επισκεφτείς τον παραπάνω σύνδεσμο και να δημιουργήσεις ένα καινούριο.\n        subject: 'Mastodon: Οδηγίες επαναφοράς συνθηματικού'\n        title: Επαναφορά συνθηματικού\n      unlock_instructions:\n        subject: 'Mastodon: Οδηγίες ξεκλειδώματος'\n    omniauth_callbacks:\n      failure: Δεν μπόρεσαμε να σε πιστοποιήσουμε μέσω %{kind} γιατί \"%{reason}\".\n      success: Επιτυχημένη πιστοποίηση μέσω %{kind} λογαριασμού.\n    passwords:\n      no_token: Δεν μπορείς να επισκεφτείς αυτή τη σελίδα αν δεν έρχεσαι από email επαναφοράς συνθηματικού. Αν όντως έρχεσαι από email επαναφοράς συνθηματικού, σιγουρέψου πως χρησιμοποίησες το πλήρες URL που σου στάλθηκε.\n      send_instructions: Αν η email διεύθυνσή σου υπάρχει ήδη στη βάση μας, θα λάβεις σύντομα έναν σύνδεσμο ανάκτησης συνθηματικού. Παρακαλούμε έλεγξε το φάκελο με τα ανεπιθύμητα μηνύματα σου αν δεν το λάβεις.\n      send_paranoid_instructions: Αν η email διεύθυνσή σου υπάρχει ήδη στη βάση μας, θα λάβεις σύντομα έναν σύνδεσμο ανάκτησης συνθηματικού. Παρακαλούμε έλεγξε το φάκελο με τα ανεπιθύμητα μηνύματα σου αν δεν το λάβεις.\n      updated: Το συνθηματικό σου άλλαξε. Πλέον έχεις συνδεθεί.\n      updated_not_active: Το συνθηματικό σου άλλαξε.\n    registrations:\n      destroyed: Στο καλό! Ο λογαριασμός σου ακυρώθηκε με επιτυχία. Ελπίζουμε να σε ξαναδούμε σύντομα.\n      signed_up: Καλώς ήρθες! Εγγράφηκες με επιτυχία.\n      signed_up_but_inactive: Εγγράφηκες με επιτυχία. Όμως δε μπορέσαμε να σε συνδέσουμε γιατί ο λογαριασμός σου δεν έχει ενεργοποιηθεί ακόμα.\n      signed_up_but_locked: Εγγράφηκες με επιτυχία. Όμως δε μπορέσαμε να σε συνδέσουμε γιατί ο λογαριασμός σου είναι κλειδωμένος.\n      signed_up_but_pending: Στάλθηκε στο email σου μήνυμα με ένα σύνδεσμο επιβεβαίωσης. Μόλις τον ακολουθήσεις θα ελέγξουμε την αίτηση σου. Θα ειδοποιήσεις εάν γίνει δεκτή.\n      signed_up_but_unconfirmed: Σου στείλαμε ένα μήνυμα με σύνδεσμο επιβεβαίωσης στη διεύθυνση email σου. Παρακαλούμε ακολούθησε το σύνδεσμο για να ενεργοποιήσεις το λογαριασμό σου. Παρακαλούμε έλεγξε το φάκελο με τα ανεπιθύμητα μηνύματα σου αν δεν το λάβεις.\n      update_needs_confirmation: Ενημέρωσες το λογαριασμό σου με επιτυχία αλλά χρειαζόμαστε να επιβεβαιώσουμε τη νέα διεύθυνση email σου. Παρακαλούμε έλεγξε τα email σου και ακολούθησε το σύνδεσμο για να την επιβεβαιώσεις. Παρακαλούμε έλεγξε το φάκελο με τα ανεπιθύμητα μηνύματα σου αν δεν το λάβεις.\n      updated: Ο λογαριασμός σου επιβεβαιώθηκε με επιτυχία.\n    sessions:\n      already_signed_out: Αποσυνδέθηκες με επιτυχία.\n      signed_in: Συνδέθηκες με επιτυχία.\n      signed_out: Αποσυνδέθηκες με επιτυχία.\n    unlocks:\n      send_instructions: Σε μερικά λεπτά θα λάβεις ένα email με οδηγίες για το πως να ξεκλειδώσεις το λογαριασμό σου. Παρακαλούμε έλεγξε το φάκελο με τα ανεπιθύμητα μηνύματα σου αν δεν το λάβεις.\n      send_paranoid_instructions: Αν ο λογαριασμός σου υπάρχει, σε μερικά λεπτά θα λάβεις ένα email με οδηγίες για το πως να τον ξεκλειδώσεις. Παρακαλούμε έλεγξε το φάκελο με τα ανεπιθύμητα μηνύματα σου αν δεν το λάβεις.\n      unlocked: Ο λογαριασμός σου ξεκλειδώθηκε με επιτυχία. Παρακαλούμε συνδέσου για να συνεχίσεις.\n  errors:\n    messages:\n      already_confirmed: έχει ήδη επιβεβαιωθεί, προσπάθησε να συνδεθείς\n      confirmation_period_expired: πρέπει να επιβεβαιωθεί εντός %{period}, παρακαλούμε αιτηθείτε το ξανά\n      expired: έληξε, παρακαλούμε ζητήστε ένα νέο\n      not_found: δε βρέθηκε\n      not_locked: δεν ήταν κλειδωμένος\n      not_saved:\n        one: '1 σφάλμα απέτρεψε αυτό το %{resource} να αποθηκευτεί:'\n        other: \"%{count} σφάλματα απέτρεψαν το %{resource} να αποθηκευτεί:\"\n"
  },
  {
    "path": "config/locales/devise.en.yml",
    "content": "---\nen:\n  devise:\n    confirmations:\n      confirmed: Your email address has been successfully confirmed.\n      send_instructions: You will receive an email with instructions for how to confirm your email address in a few minutes. Please check your spam folder if you didn't receive this email.\n      send_paranoid_instructions: If your email address exists in our database, you will receive an email with instructions for how to confirm your email address in a few minutes. Please check your spam folder if you didn't receive this email.\n    failure:\n      already_authenticated: You are already signed in.\n      inactive: Your account is not activated yet.\n      invalid: Invalid %{authentication_keys} or password.\n      last_attempt: You have one more attempt before your account is locked.\n      locked: Your account is locked.\n      not_found_in_database: Invalid %{authentication_keys} or password.\n      pending: Your account is still under review.\n      timeout: Your session expired. Please sign in again to continue.\n      unauthenticated: You need to sign in or sign up before continuing.\n      unconfirmed: You have to confirm your email address before continuing.\n    mailer:\n      confirmation_instructions:\n        action: Verify email address\n        action_with_app: Confirm and return to %{app}\n        explanation: You have created an account on %{host} with this email address. You are one click away from activating it. If this wasn't you, please ignore this email.\n        explanation_when_pending: You applied for an invite to %{host} with this email address. Once you confirm your e-mail address, we will review your application. You can't login until then. If your application is rejected, your data will be removed, so no further action will be required from you. If this wasn't you, please ignore this email.\n        extra_html: Please also check out <a href=\"%{terms_path}\">the rules of the server</a> and <a href=\"%{policy_path}\">our terms of service</a>.\n        subject: 'Mastodon: Confirmation instructions for %{instance}'\n        title: Verify email address\n      email_changed:\n        explanation: 'The email address for your account is being changed to:'\n        extra: If you did not change your email, it is likely that someone has gained access to your account. Please change your password immediately or contact the server admin if you're locked out of your account.\n        subject: 'Mastodon: Email changed'\n        title: New email address\n      password_change:\n        explanation: The password for your account has been changed.\n        extra: If you did not change your password, it is likely that someone has gained access to your account. Please change your password immediately or contact the server admin if you're locked out of your account.\n        subject: 'Mastodon: Password changed'\n        title: Password changed\n      reconfirmation_instructions:\n        explanation: Confirm the new address to change your email.\n        extra: If this change wasn't initiated by you, please ignore this email. The email address for the Mastodon account won't change until you access the link above.\n        subject: 'Mastodon: Confirm email for %{instance}'\n        title: Verify email address\n      reset_password_instructions:\n        action: Change password\n        explanation: You requested a new password for your account.\n        extra: If you didn't request this, please ignore this email. Your password won't change until you access the link above and create a new one.\n        subject: 'Mastodon: Reset password instructions'\n        title: Password reset\n      unlock_instructions:\n        subject: 'Mastodon: Unlock instructions'\n    omniauth_callbacks:\n      failure: Could not authenticate you from %{kind} because \"%{reason}\".\n      success: Successfully authenticated from %{kind} account.\n    passwords:\n      no_token: You can't access this page without coming from a password reset email. If you do come from a password reset email, please make sure you used the full URL provided.\n      send_instructions: If your email address exists in our database, you will receive a password recovery link at your email address in a few minutes. Please check your spam folder if you didn't receive this email.\n      send_paranoid_instructions: If your email address exists in our database, you will receive a password recovery link at your email address in a few minutes. Please check your spam folder if you didn't receive this email.\n      updated: Your password has been changed successfully. You are now signed in.\n      updated_not_active: Your password has been changed successfully.\n    registrations:\n      destroyed: Bye! Your account has been successfully cancelled. We hope to see you again soon.\n      signed_up: Welcome! You have signed up successfully.\n      signed_up_but_inactive: You have signed up successfully. However, we could not sign you in because your account is not yet activated.\n      signed_up_but_locked: You have signed up successfully. However, we could not sign you in because your account is locked.\n      signed_up_but_pending: A message with a confirmation link has been sent to your email address. After you click the link, we will review your application. You will be notified if it is approved.\n      signed_up_but_unconfirmed: A message with a confirmation link has been sent to your email address. Please follow the link to activate your account. Please check your spam folder if you didn't receive this email.\n      update_needs_confirmation: You updated your account successfully, but we need to verify your new email address. Please check your email and follow the confirm link to confirm your new email address. Please check your spam folder if you didn't receive this email.\n      updated: Your account has been updated successfully.\n    sessions:\n      already_signed_out: Signed out successfully.\n      signed_in: Signed in successfully.\n      signed_out: Signed out successfully.\n    unlocks:\n      send_instructions: You will receive an email with instructions for how to unlock your account in a few minutes. Please check your spam folder if you didn't receive this email.\n      send_paranoid_instructions: If your account exists, you will receive an email with instructions for how to unlock it in a few minutes. Please check your spam folder if you didn't receive this email.\n      unlocked: Your account has been unlocked successfully. Please sign in to continue.\n  errors:\n    messages:\n      already_confirmed: was already confirmed, please try signing in\n      confirmation_period_expired: needs to be confirmed within %{period}, please request a new one\n      expired: has expired, please request a new one\n      not_found: not found\n      not_locked: was not locked\n      not_saved:\n        one: '1 error prohibited this %{resource} from being saved:'\n        other: \"%{count} errors prohibited this %{resource} from being saved:\"\n"
  },
  {
    "path": "config/locales/devise.eo.yml",
    "content": "---\neo:\n  devise:\n    confirmations:\n      confirmed: Via retadreso estis sukcese konfirmita.\n      send_instructions: Vi ricevos retmesaĝon kun instrukcioj por konfirmi vian retadreson ene de kelkaj minutoj. Bonvolu kontroli vian spamujon se vi ne ricevis ĉi tiun retmesaĝon.\n      send_paranoid_instructions: Se via retadreso ekzistas en nia datumbazo, vi ricevos retmesaĝon kun instrukcioj por konfirmi vian retadreson ene de kelkaj minutoj. Bonvolu kontroli vian spamujon se vi ne ricevis ĉi tiun retmesaĝon.\n    failure:\n      already_authenticated: Vi jam ensalutis.\n      inactive: Via konto ankoraŭ ne estas konfirmita.\n      invalid: Nevalida %{authentication_keys} aŭ pasvorto.\n      last_attempt: Vi ankoraŭ povas provi unufoje antaŭ ol via konto estos ŝlosita.\n      locked: Via konto estas ŝlosita.\n      not_found_in_database: Nevalida %{authentication_keys} aŭ pasvorto.\n      pending: Via konto ankoraŭ estas kontrolanta.\n      timeout: Via seanco eksvalidiĝis. Bonvolu ensaluti denove por daŭrigi.\n      unauthenticated: Vi devas ensaluti aŭ registriĝi antaŭ ol daŭrigi.\n      unconfirmed: Vi devas konfirmi vian retadreson antaŭ ol daŭrigi.\n    mailer:\n      confirmation_instructions:\n        action: Konfirmi retadreson\n        action_with_app: Konfirmi kaj reveni al %{app}\n        explanation: Vi kreis konton en %{host} per ĉi tiu retadreso. Nur klako restas por aktivigi ĝin. Se tio ne estis vi, bonvolu ignori ĉi tiun retmesaĝon.\n        explanation_when_pending: Vi petis inviton al %{host} per ĉi tiu retpoŝta adreso. Kiam vi konfirmas vian retpoŝtan adreson, ni revizios vian kandidatiĝon. Vi ne povas ensaluti ĝis tiam. Se via kandidatiĝo estas rifuzita, viaj datumoj estos forigitaj, do neniu alia ago estos postulita de vi. Se tio ne estis vi, bonvolu ignori ĉi tiun retpoŝton.\n        extra_html: Bonvolu rigardi <a href=\"%{terms_path}\">la regulojn de la servilo</a> kaj <a href=\"%{policy_path}\">niajn uzkondiĉojn</a>.\n        subject: 'Mastodon: Konfirmaj instrukcioj por %{instance}'\n        title: Konfirmi retadreson\n      email_changed:\n        explanation: 'La retadreso de via konto ŝanĝiĝas al:'\n        extra: Se vi ne volis ŝanĝi vian retadreson, iu verŝajne aliris al via konto. Bonvolu tuj ŝanĝi vian pasvorton aŭ kontakti la administranton de la servilo, se vi estas blokita ekster via konto.\n        subject: 'Mastodon: Retadreso ŝanĝita'\n        title: Nova retadreso\n      password_change:\n        explanation: La pasvorto de via konto estis ŝanĝita.\n        extra: Se vi ne ŝanĝis vian pasvorton, iu verŝajne aliris al via konto. Bonvolu ŝanĝi vian pasvorton tuj aŭ kontakti la administranton de la servilo, se vi estas blokita ekster via konto.\n        subject: 'Mastodon: Pasvorto ŝanĝita'\n        title: Pasvorto ŝanĝita\n      reconfirmation_instructions:\n        explanation: Retajpu la novan adreson por ŝanĝi vian retadreson.\n        extra: Se ĉi tiu ŝanĝo ne estis komencita de vi, bonvolu ignori ĉi tiun retmesaĝon. La retadreso por la Mastodon-konto ne ŝanĝiĝos se vi ne aliras la supran ligilon.\n        subject: 'Mastodon: Konfirmi retadreson por %{instance}'\n        title: Kontrolu retadreson\n      reset_password_instructions:\n        action: Ŝanĝi pasvorton\n        explanation: Vi petis novan pasvorton por via konto.\n        extra: Se vi ne petis ĉi tion, bonvolu ignori ĉi tiun retmesaĝon. Via pasvorto ne ŝanĝiĝos se vi ne aliras la supran ligilon kaj kreas novan.\n        subject: 'Mastodon: Instrukcioj por ŝanĝi pasvorton'\n        title: Pasvorto restarigita\n      unlock_instructions:\n        subject: 'Mastodon: Instrukcioj por malŝlosi'\n    omniauth_callbacks:\n      failure: 'Ni ne povis aŭtentigi vin per %{kind}: ''%{reason}''.'\n      success: Aŭtentigita sukcese per %{kind}.\n    passwords:\n      no_token: Vi ne povas aliri al ĉi tiu paĝo alimaniere ol per retmesaĝo por ŝanĝi pasvorton. Se vi venas de tia retmesaĝo, bonvolu certiĝi, ke vi uzas la tutan URL-on donitan.\n      send_instructions: Se via retadreso ekzistas en nia datumbazo, vi ricevos ligilon por havi novan pasvorton ĉe via retadreso ene de kelkaj minutoj. Bonvolu kontroli vian spamujon se vi ne ricevis ĉi tiun retmesaĝon.\n      send_paranoid_instructions: Se via retadreso ekzistas en nia datumbazo, vi ricevos ligilon por havi novan pasvorton ĉe via retadreso ene de kelkaj minutoj. Bonvolu kontroli vian spamujon se vi ne ricevis ĉi tiun retmesaĝon.\n      updated: Via pasvorto estis sukcese ŝanĝita. Vi nun estas ensalutinta.\n      updated_not_active: Via pasvorto estis sukcese ŝanĝita.\n    registrations:\n      destroyed: Ĝis! Via konto estis sukcese forigita. Ni esperas revidi vin baldaŭ.\n      signed_up: Bonvenon! Vi sukcese registriĝis.\n      signed_up_but_inactive: Vi sukcese registriĝis. Tamen, ni ne povis ensalutigi vin, ĉar via konto ankoraŭ ne estas konfirmita.\n      signed_up_but_locked: Vi sukcese registriĝis. Tamen, ni ne povis ensalutigi vin, ĉar via konto estas ŝlosita.\n      signed_up_but_pending: Mesaĝo kun konfirma ligilo estis sendita al via retpoŝta adreso. Post kiam vi alklakis la ligilon, ni revizios vian kandidatiĝon. Vi estos sciigita se ĝi estas aprobita.\n      signed_up_but_unconfirmed: Retmesaĝo kun konfirma ligilo estis sendita al via retadreso. Bonvolu sekvi la ligilon por aktivigi vian konton. Bonvolu kontroli vian spamujon, se vi ne ricevis ĉi tiun retmesaĝon.\n      update_needs_confirmation: Vi sukcese ĝisdatigis vian konton, sed ni bezonas kontroli vian novan retadreson. Bonvolu kontroli viajn retmesaĝojn kaj sekvi la konfirman ligilon por konfirmi vian novan retadreson. Bonvolu kontroli vian spamujon, se vi ne ricevis ĉi tiun retmesaĝon.\n      updated: Via konto estis sukcese ĝisdatigita.\n    sessions:\n      already_signed_out: Sukcese elsalutis.\n      signed_in: Sukcese ensalutis.\n      signed_out: Sukcese elsalutis.\n    unlocks:\n      send_instructions: Vi ricevos retmesaĝon kun instrukcioj por malŝlosi vian konton ene de kelkaj minutoj. Bonvolu kontroli vian spamujon, se vi ne ricevis ĉi tiun retmesaĝon.\n      send_paranoid_instructions: Se via konto ekzistas, vi ricevos retmesaĝon kun instrukcioj por malŝlosi ĝin ene de kelkaj minutoj. Bonvolu kontroli vian spamujon se vi ne ricevis ĉi tiun retmesaĝon.\n      unlocked: Via konto estis sukcese malŝlosita. Bonvolu ensaluti por daŭrigi.\n  errors:\n    messages:\n      already_confirmed: jam estis konfirmita, bonvolu provi ensaluti\n      confirmation_period_expired: devas esti konfirmita ene de %{period}, bonvolu peti denove\n      expired: eksvalidiĝis, bonvolu peti denove\n      not_found: ne estis trovita\n      not_locked: ne estis ŝlosita\n      not_saved:\n        one: '1 eraro malpermesis al ĉi tiu %{resource} esti konservita:'\n        other: \"%{count} eraroj malpermesis al ĉi tiu %{resource} esti konservita:\"\n"
  },
  {
    "path": "config/locales/devise.es.yml",
    "content": "---\nes:\n  devise:\n    confirmations:\n      confirmed: Su direccion de email ha sido confirmada con exito.\n      send_instructions: Recibirá un correo electrónico con instrucciones sobre cómo confirmar su dirección de correo en pocos minutos.\n      send_paranoid_instructions: Si su dirección de correo electrónico existe en nuestra base de datos, recibirá un correo electrónico con instrucciones sobre cómo confirmar su dirección de correo en pocos minutos.\n    failure:\n      already_authenticated: Usted ya está registrado.\n      inactive: Su cuenta todavía no está activa.\n      invalid: Inválido %{authentication_keys} o contraseña.\n      last_attempt: Tiene un intento más antes de que su cuenta sea bloqueada.\n      locked: Su cuenta está bloqueada.\n      not_found_in_database: Inválido %{authentication_keys} o contraseña.\n      pending: Su cuenta aun se encuentra bajo revisión.\n      timeout: Su sesión ha expirado. Por favor inicie sesión de nuevo para continuar.\n      unauthenticated: Necesita iniciar sesión o registrarse antes de continuar.\n      unconfirmed: Tiene que confirmar su dirección de correo electrónico antes de continuar.\n    mailer:\n      confirmation_instructions:\n        action: Verificar dirección de correo electrónico\n        action_with_app: Confirmar y regresar a %{app}\n        explanation: Has creado una cuenta en %{host} con esta dirección de correo electrónico. Estas a un clic de activarla. Si no fue usted, por favor ignore este correo electrónico.\n        explanation_when_pending: Usted ha solicitado una invitación a %{host} con esta dirección de correo electrónico. Una vez que confirme su dirección de correo electrónico, revisaremos su aplicación. No puede iniciar sesión hasta que su aplicación sea revisada. Si su solicitud está rechazada, sus datos serán eliminados, así que no será necesaria ninguna acción adicional por ti. Si no fuera usted, por favor ignore este correo electrónico.\n        extra_html: Por favor revise <a href=\"%{terms_path}\">las reglas de la instancia</a> y <a href=\"%{policy_path}\">nuestros términos de servicio</a>.\n        subject: 'Mastodon: Instrucciones de confirmación para %{instance}'\n        title: Verificar dirección de correo electrónico\n      email_changed:\n        explanation: 'El correo electrónico para su cuenta esta siendo cambiada a:'\n        extra: Si usted no ha cambiado su correo electrónico, es probable que alguien haya conseguido acceso a su cuenta. Por favor cambie su contraseña inmediatamente o contacte al administrador de la instancia si usted no puede iniciar sesión.\n        subject: 'Mastodon: Correo electrónico cambiado'\n        title: Nueva dirección de correo electrónico\n      password_change:\n        explanation: La contraseña de su cuenta a sido cambiada.\n        extra: Si usted no a cambiado su contraseña. es probable que alguien a conseguido acceso a su cuenta. Por favor cambie su contraseña inmediatamente o contacte a el administrador de la instancia si usted esta bloqueado de su cuenta.\n        subject: 'Mastodon: Contraseña cambiada'\n        title: Contraseña cambiada\n      reconfirmation_instructions:\n        explanation: Confirme la nueva dirección para cambiar su coreo electrónico.\n        extra: Si no iniciaste este cambio, por favor ignora este correo. Esta dirección de correo para la cuenta de Mastodon no cambiará hasta que accedas al vinculo arriba.\n        subject: 'Mastodon: Confirme correo electrónico para %{instance}'\n        title: Verifique dirección de correo electrónico\n      reset_password_instructions:\n        action: Cambiar contraseña\n        explanation: Solicitaste una nueva contraseña para tu cuenta.\n        extra: Si no solicitaste esto, por favor ignora este correo. Tu contraseña no cambiará hasta que tu accedas al vinculo arriba y crees una nueva.\n        subject: 'Mastodon: Instrucciones para reiniciar contraseña'\n        title: Reiniciar contraseña\n      unlock_instructions:\n        subject: 'Mastodon: Instrucciones para desbloquear'\n    omniauth_callbacks:\n      failure: No podemos autentificarle desde %{kind} debido a \"%{reason}\".\n      success: Autentificado con éxito desde la cuenta %{kind} .\n    passwords:\n      no_token: No puede acceder a esta página sin provenir desde el correo de reinicio de contraseña. Si viene desde el correo de reinicio de contraseña, por favor asegúrese que está utilizando la dirección completa proporcionada.\n      send_instructions: Recibirá un correo electrónico con instrucciones sobre cómo reiniciar su contraseña en pocos minutos.\n      send_paranoid_instructions: Si su correo electrónico existe en nuestra base de datos, recibirá un enlace de recuperación de contraseña en su dirección de correo en pocos minutos.\n      updated: Su contraseña ha sido cambiada con éxito. Ahora ya está registrado.\n      updated_not_active: Su contraseña ha sido cambiada con éxito.\n    registrations:\n      destroyed: \"¡Adios! Su cuenta ha sido cancelada con éxito. Esperamos verle pronto de nuevo.\"\n      signed_up: \"¡Bienvenido! Se ha registrado con éxito.\"\n      signed_up_but_inactive: Se ha registrado con éxito. Sin embargo, no podemos identificarle porque su cuenta no ha sido activada todavía.\n      signed_up_but_locked: Se ha registrado con éxito. Sin embargo, no podemos identificarle porque su cuenta está bloqueada.\n      signed_up_but_pending: Un mensaje con un enlace de confirmacion ha sido enviado a su direccion de email. Luego de clickear el link revisaremos su aplicacion. Seras notificado si es aprovada.\n      signed_up_but_unconfirmed: Un mensaje con un enlace de confirmación ha sido enviado a su correo electrónico. Por favor siga el enlace para activar su cuenta.\n      update_needs_confirmation: Ha actualizado su cuenta con éxito, pero necesitamos verificar su nueva dirección de correo. Por favor compruebe su correo y siga el enlace para confirmar su nueva dirección de correo.\n      updated: su cuenta ha sido actualizada con éxito.\n    sessions:\n      already_signed_out: Cerró sesión con éxito.\n      signed_in: Se registró con éxito.\n      signed_out: Cerró sesión con éxito.\n    unlocks:\n      send_instructions: Recibirá un correo electrónico con instrucciones sobre cómo desbloquear su cuenta en pocos minutos.\n      send_paranoid_instructions: Si su cuenta existe, recibirá un correo electrónico con instrucciones sobre cómo desbloquearla en pocos minutos.\n      unlocked: Su cuenta ha sido desbloqueada con éxito. Por favor inicie sesión para continuar.\n  errors:\n    messages:\n      already_confirmed: ya fue confirmado, por favor intente iniciar sesión\n      confirmation_period_expired: necesita ser confirmado dentro de %{period}, por favor pida una nueva\n      expired: ha expirado, por favor pida una nueva\n      not_found: no encontrado\n      not_locked: no fue bloqueada\n      not_saved:\n        one: '1 error prohibió este %{resource} de ser guardado:'\n        other: \"%{count} errores prohibieron este %{resource} de ser guardado:\"\n"
  },
  {
    "path": "config/locales/devise.eu.yml",
    "content": "---\neu:\n  devise:\n    confirmations:\n      confirmed: Zure e-mail helbidea ongi baieztatu da.\n      send_instructions: E-mail mezu bat jasoko duzu minutu batzuk barru zure e-mail helbidea baieztatzeko argibideekin. Egiaztatu zure spam karpeta ez baduzu e-mail hau jasotzen.\n      send_paranoid_instructions: Zure e-mail helbidea aurretik gure datu-basean bazegoen, e-mail mezu bat jasoko duzu minutu batzuk barru zure e-mail helbidea baieztatzeko argibideekin. Egiaztatu zure spam karpeta ez baduzu e-mail hau jasotzen.\n    failure:\n      already_authenticated: Saioa hasi duzu jada.\n      inactive: Zure kontua ez dago oraindik aktibo.\n      invalid: Baliogabeko %{authentication_keys} edo pasahitza.\n      last_attempt: Saiakera bat geratzen zaizu zure kontua giltzapetu aurretik.\n      locked: Zure kontua giltzapetuta dago.\n      not_found_in_database: Baliogabeko %{authentication_keys} edo pasahitza.\n      pending: Zure kontua oraindik berrikusteke dago.\n      timeout: Zure saioa iraungitu da. Hasi saioa berriro jarraitzeko.\n      unauthenticated: Saioa hasi edo izena eman behar duzu jarraitu aurretik.\n      unconfirmed: Zure e-mail helbidea baieztatu behar duzu jarraitu aurretik.\n    mailer:\n      confirmation_instructions:\n        action: Baieztatu e-mail helbidea\n        action_with_app: Berretsi eta itzuli %{app} aplikaziora\n        explanation: Kontu bat sortu duzu %{host} ostalarian e-mail helbide honekin. Aktibatzeko klik bat falta zaizu. Ez baduzu zuk sortu, ez egin ezer e-mail honekin.\n        explanation_when_pending: \"%{host} instantziara gonbidatua izatea eskatu duzu e-mail helbide honekin. Behin zure e-mail helbidea berresten duzula, zure eskaera berrikusiko da. Ezin duzu aurretik saioa hasi. Zure eskaera ukatuko balitz, zure datuak ezabatuko lirateke, eta ez zenuke beste ezer egiteko beharrik. Hau ez bazara zu izan, ezikusi e-mail hau.\"\n        extra_html: Egiaztatu <a href=\"%{terms_path}\">zerbitzariaren arauak</a> eta <a href=\"%{policy_path}\">zerbitzuaren erabilera baldintzak</a>.\n        subject: 'Mastodon: %{instance} instantziaren argibideak baieztapenerako'\n        title: Baieztatu e-mail helbidea\n      email_changed:\n        explanation: 'Zure kontuaren e-mail helbidea honetara aldatuko da:'\n        extra: Ez baduzu e-mail helbidea aldatu, agian baten bat zure kontura sartzea lortu du. Aldatu zure pasahitza berehala edo jarri zerbitzariko administratzailearekin kontaktuan zure kontura sartzerik ez baduzu.\n        subject: 'Mastodon: E-mail helbidea aldatuta'\n        title: E-mail helbide berria\n      password_change:\n        explanation: Zure kontuaren pasahitza aldatu da.\n        extra: Ez baduzu pasahitza aldatu, agian baten bat zure kontura sartzea lortu du. Aldatu zure pasahitza berehala edo jarri zerbitzariko administratzailearekin kontaktuan zure kontura sartzerik ez baduzu.\n        subject: 'Mastodon: Pasahitza aldatuta'\n        title: Pasahitza aldatuta\n      reconfirmation_instructions:\n        explanation: Baieztatu helbide berria zure e-maila aldatzeko.\n        extra: Aldaketa hau ez baduzu zuk eskatu, ezikusi e-mail hau. Mastodon kontuaren e-mail helbidea ez da aldatuko goiko estekan sartzen ez bazara.\n        subject: 'Mastodon: Baieztatu %{instance} instantziarako e-mail helbidea'\n        title: Baieztatu e-mail helbidea\n      reset_password_instructions:\n        action: Aldatu pasahitza\n        explanation: Pasahitza berria eskatu duzu zure konturako.\n        extra: Ez baduzu hau eskatu, mesedez ezikusi e-mail hau. Zure pasahitza ez da aldatuko goiko estekara sartu eta berri bat sortzen ez baduzu.\n        subject: 'Mastodon: Pasahitza berrezartzeko argibideak'\n        title: Pasahitza berrezartzea\n      unlock_instructions:\n        subject: 'Mastodon: Desblokeatzeko argibideak'\n    omniauth_callbacks:\n      failure: Ezin izan zaizu %{kind} motatik autentifikatu arrazoia \"%{reason}\" dela.\n      success: Ongi egin da autentifikazioa %{kind}  kontuarekin.\n    passwords:\n      no_token: Ezin zara orri honetara sartu ez bazatoz pasahitza aldatzeko e-mail batetik. Pasahitza aldatzeko e-mail batetik bazatoz egiaztatu emandako URL osoa erabiltzen duzula mesedez.\n      send_instructions: Zure e-mail helbidea gure datu-basean badago, pasahitza berreskuratzeko esteka bat duen e-mail bat jasoko duzu minutu gutxi barru. Egiaztatu spam karpeta e-mail hau jasotzen ez baduzu.\n      send_paranoid_instructions: Zure e-mail helbidea gure datu-basean badago, pasahitza berreskuratzeko esteka bat duen e-mail bat jasoko duzu minutu gutxi barru. Egiaztatu spam karpeta e-mail hau jasotzen ez baduzu.\n      updated: Zure pasahitza ongi aldatu da. Saioa hasi duzu.\n      updated_not_active: Zure pasahitza ongi aldatu da.\n    registrations:\n      destroyed: Agur! Zure kontua ongi ezeztatu da. Ea laster berriro ikusten garen.\n      signed_up: Ongi etorri! Ongi hasi duzu saioa.\n      signed_up_but_inactive: Ongi eman duzu izena. Hala ere, ezin duzu saioa hasi zure kontua oraindik ez dagoelako aktibatuta.\n      signed_up_but_locked: Ongi eman duzu izena. Hala ere, ezin duzu saioa hasi zure kontua giltzapetuta dagoelako.\n      signed_up_but_pending: Berrespen esteka bat duen mezu bat bidali da zure e-mail helbidera. Behin esteka sakatzen duzula, zure eskaera berrikusiko da. Onartzen bada jakinaraziko zaizu.\n      signed_up_but_unconfirmed: Baieztapen esteka bat duen e-mail bidali zaizu. Jarraitu esteka zure kontua aktibatzeko. Egiaztatu spam karpeta ez baduzu e-mail hau jaso.\n      update_needs_confirmation: Zure kontua ongi eguneratu duzu, baina zure email helbide berria egiaztatu behar dugu. Baieztapen esteka bat duen e-mail bidali zaizu, jarraitu esteka zure e-mal helbide berria baieztatzeko. Egiaztatu spam karpeta ez baduzu e-mail hau jaso.\n      updated: Zure kontua ongi eguneratu da.\n    sessions:\n      already_signed_out: Ongi amaitu duzu saioa.\n      signed_in: Ongi hasi duzu saioa.\n      signed_out: Ongi amaitu duzu saioa.\n    unlocks:\n      send_instructions: Kontua desblokeatzeko argibideak dituen e-mail jasoko duzu minutu gutxi barru. Egiaztatu spam karpeta ez baduzu e-mail hau jaso.\n      send_paranoid_instructions: Zure kontua existitzen bada, hau desblokeatzeko argibideak dituen e-mail bat jasoko duzu minutu gutxi barru. Egiaztatu spam karpeta ez baduzu mezu hau jasotzen.\n      unlocked: Zure kontua ongi desblokeatu da. Hasi saioa jarraitzeko.\n  errors:\n    messages:\n      already_confirmed: ba<zegoen baieztatuta, saiatu saioa hasten\n      confirmation_period_expired: baieztapena %{period} barruan egin behar zen, eskatu berri bat mesedez\n      expired: iraungitua, eskatu beste bat\n      not_found: ez da aurkitu\n      not_locked: ez zegoen giltzapetuta\n      not_saved:\n        one: 'Errore batek %{resource} hau gordetzea eragotzi du:'\n        other: \"%{count} errorek %{resource} hau gordetzea eragotzi dute:\"\n"
  },
  {
    "path": "config/locales/devise.fa.yml",
    "content": "---\nfa:\n  devise:\n    confirmations:\n      confirmed: نشانی ایمیل شما با موفقیت تأیید شد.\n      send_instructions: تا دقایقی دیگر ایمیلی خواهید گرفت که به شما می‌گوید چگونه باید نشانی ایمیل خود را تأیید کنید.\n      send_paranoid_instructions: اگر ایمیل شما در پایگاه دادهٔ ما موجود باشد، تا دقایقی دیگر ایمیلی خواهید گرفت که به شما می‌گوید چگونه باید نشانی ایمیل خود را تأیید کنید.\n    failure:\n      already_authenticated: شما الان هم وارد سیستم هستید.\n      inactive: حساب شما هنوز فعال نشده است.\n      invalid: خطای %{authentication_keys} یا رمز نامعتبر.\n      last_attempt: پیش از آن که حساب شما قفل شود، یک فرصت دیگر دارید.\n      locked: حساب شما قفل شده است.\n      not_found_in_database: خطای %{authentication_keys} یا رمز نامعتبر.\n      pending: حساب شما همچنان در دست بررسی است.\n      timeout: مهلت این ورود شما به سر رسید. برای ادامه، دوباره وارد شوید.\n      unauthenticated: برای ادامه باید وارد شوید یا ثبت نام کنید.\n      unconfirmed: برای ادامه باید نشانی ایمیل خود را تأیید کنید.\n    mailer:\n      confirmation_instructions:\n        action: تأیید نشانی ایمیل\n        action_with_app: تأیید و بازگشت به %{app}\n        explanation: شما با این نشانی ایمیل حسابی در %{host} باز کرده‌اید. با یک کلیک می‌توانید این حساب را فعال کنید. اگر شما چنین کاری نکردید، لطفاً این ایمیل را نادیده بگیرید.\n        explanation_when_pending: شما با این نشانی ایمیل برای %{host} درخواست دعوت‌نامه داده‌اید. اگر ایمیل خود را تأیید کنید، ما درخواست شما را بررسی خواهیم کرد. تا وقتی بررسی تمام نشده، شما نمی‌توانید به حساب خود وارد شوید. اگر درخواست شما رد شود، ما اطلاعاتی را که از شما داریم پاک خواهیم کرد پس نیازی به کاری از سمت شما نخواهد بود. اگر شما چنین درخواستی نداده‌اید، لطفاً این ایمیل را نادیده بگیرید.\n        extra_html: لطفاً همچنین <a href=\"%{terms_path}\">قانون‌های این سرور</a> و <a href=\"%{policy_path}\">شرایط کاربری</a> آن را ببینید.\n        subject: 'ماستدون: راهنمایی برای تأیید %{instance}'\n        title: تأیید نشانی ایمیل\n      email_changed:\n        explanation: 'نشانی ایمیل حساب شما تغییر می‌کند به:'\n        extra: اگر شما ایمیل خود را عوض نکردید، شاید کسی به حساب شما دسترسی پیدا کرده است. در این صورت لطفاً هر چه زودتر رمز حسابتان را عوض کنید. اگر رمزتان دیگر کار نمی‌کند، لطفاً با مدیر سرور تماس بگیرید.\n        subject: 'ماستدون: نشانی ایمیل عوض شد'\n        title: نشانی ایمیل تازه\n      password_change:\n        explanation: رمز حساب شما تغییر کرد.\n        extra: اگر شما رمز حسابتان را تغییر ندادید، شاید کسی به حساب شما دسترسی پیدا کرده است. در این صورت لطفاً هر چه زودتر رمز حسابتان را عوض کنید. اگر رمزتان دیگر کار نمی‌کند، لطفاً با مدیر سرور تماس بگیرید.\n        subject: 'ماستدون: رمزتان عوض شد'\n        title: رمزتان عوض شد\n      reconfirmation_instructions:\n        explanation: نشانی تازه را تأیید کنید تا ایمیل‌تان عوض شود.\n        extra: اگر شما باعث این تغییر نبودید، لطفاً این ایمیل را نادیده بگیرید. تا زمانی که شما پیوند بالا را باز نکنید، نشانی ایمیل مربوط به حساب شما عوض نخواهد شد.\n        subject: 'ماستدون: تأیید ایمیل برای %{instance}'\n        title: تأیید نشانی ایمیل\n      reset_password_instructions:\n        action: تغییر رمز\n        explanation: شما رمز تازه‌ای برای حسابتان درخواست کردید.\n        extra: اگر شما چنین درخواستی نکردید، لطفاً این ایمیل را نادیده بگیرید. تا زمانی که شما پیوند بالا را باز نکنید و رمز تازه‌ای نسازید، رمز شما عوض نخواهد شد.\n        subject: 'ماستدون: راهنمایی برای بازنشانی رمز'\n        title: بازنشانی رمز\n      unlock_instructions:\n        subject: 'ماستدون: راهنمایی برای بازکردن قفل'\n    omniauth_callbacks:\n      failure: تصدیق اعتبار شما از راه %{kind} انجام نشد زیرا \"%{reason}\".\n      success: تصدیق اعتبار شما از %{kind} با موفقیت انجام شد.\n    passwords:\n      no_token: این صفحه را تنها از راه یک ایمیل بازنشانی رمز می‌شود دید. اگر از چنین ایمیلی می‌آیید، لطفاً مطمئن شوید که نشانی موجود در ایمیل را کامل به کار برده‌اید.\n      send_instructions: اگر ایمیل شما در پایگاه دادهٔ ما موجود باشد، تا دقایقی دیگر یک ایمیل بازیابی رمز دریافت خواهید کرد.\n      send_paranoid_instructions: اگر ایمیل شما در پایگاه دادهٔ ما موجود باشد، تا دقایقی دیگر یک ایمیل بازیابی رمز دریافت خواهید کرد.\n      updated: رمز شما با موفقیت تغییر کرد. شما الان وارد سیستم هستید.\n      updated_not_active: رمز شما با موفقیت تغییر کرد.\n    registrations:\n      destroyed: بدرود! حساب شما با موفقیت لغو شد. امیدواریم دوباره شما را ببینیم.\n      signed_up: خوش آمدید! شما با موفقیت ثبت نام کردید.\n      signed_up_but_inactive: خوش آمدید! شما با موفقیت ثبت نام کردید. ولی هنوز وارد سیستم نیستید زیرا حساب شما هنوز فعال نیست.\n      signed_up_but_locked: خوش آمدید! شما با موفقیت ثبت نام کردید. ولی هنوز وارد سیستم نیستید زیرا حساب شما قفل شده است.\n      signed_up_but_pending: پیغامی که دارای یک پیوند برای تأیید است به نشانی ایمیل شما فرستاده شده. پس از این‌که پیوند را باز کردید، ما درخواست شما را بررسی خواهیم کرد. اگر درخواست شما پذیرفته شود، به شما خواهیم گفت.\n      signed_up_but_unconfirmed: یک پیغام برای تأیید به نشانی ایمیل شما فرستاده شده. لطفاً پیوند موجود در ایمیل را دنبال کنید تا حسابتان فعال شود.\n      update_needs_confirmation: شما با موفقیت حسابتان را به‌روز کردید، ولی لازم است که ما نشانی ایمیل تازهٔ شما را تأیید کنیم. لطفاً ایمیل خود را ببینید و پیوند موجود در ایمیل را دنبال کنید تا تا نشانی ایمیل تازهٔ شما تأیید شود.\n      updated: حساب شما با موفقبت به‌روز شد.\n    sessions:\n      already_signed_out: با موفقیت خارج شدید.\n      signed_in: با موفقیت وارد شدید.\n      signed_out: با موفقیت خارج شدید.\n    unlocks:\n      send_instructions: تا دقایقی دیگر ایمیلی خواهید گرفت که به شما می‌گوید چگونه باید قفل حساب خود را باز کنید.\n      send_paranoid_instructions: اگر حساب شما موجود باشد، تا دقایقی دیگر ایمیلی خواهید گرفت که به شما می‌گوید چگونه باید قفل آن را باز کنید.\n      unlocked: قفل حساب شما با موفقیت باز شد. لطفاً برای ادامه وارد سیستم شوید.\n  errors:\n    messages:\n      already_confirmed: تأیید شده، لطفاً وارد شوید\n      confirmation_period_expired: باید ظرف %{period} تأیید شود، لطفاً دوباره درخواست دهید\n      expired: مهلتش به سر رسید، لطفاً دوباره درخواست دهید\n      not_found: پیدا نشد\n      not_locked: قفل نبود\n      not_saved:\n        one: 'خطایی نگذاشت که این %{resource} ذخیره شود:'\n        other: 'به خاطر %{count} خطا، این %{resource} ذخیره نشد:'\n"
  },
  {
    "path": "config/locales/devise.fi.yml",
    "content": "---\nfi:\n  devise:\n    confirmations:\n      confirmed: Sähköpostiosoitteen vahvistus onnistui.\n      send_instructions: Saat kohta sähköpostitse ohjeet, kuinka vahvistat sähköpostiosoitteen. Jos et saa viestiä, tarkista roskapostikansio.\n      send_paranoid_instructions: Jos sähköpostiosoite on tietokannassamme, saat pian ohjeet, kuinka vahvistat osoitteen. Jos et saa viestiä, tarkista roskapostikansio.\n    failure:\n      already_authenticated: Olet jo kirjautunut sisään.\n      inactive: Tiliäsi ei ole vielä aktivoitu.\n      invalid: Virheellinen %{authentication_keys} tai salasana.\n      last_attempt: Voit yrittää enää kerran, ennen kuin tili lukitaan.\n      locked: Tili on lukittu.\n      not_found_in_database: Virheellinen %{authentication_keys} tai salasana.\n      timeout: Istunto on umpeutunut. Jatka kirjautumalla sisään.\n      unauthenticated: Kirjaudu sisään tai rekisteröidy, jos haluat jatkaa.\n      unconfirmed: Vahvista sähköpostiosoitteesi, ennen kuin jatkat.\n    mailer:\n      confirmation_instructions:\n        action: Vahvista sähköpostiosoite\n        action_with_app: Vahvista ja palaa %{app}\n        explanation: Olet luonut tilin palvelimelle %{host} käyttäen tätä sähköpostiosoitetta. Aktivoi tili yhdellä klikkauksella. Jos et luonut tiliä itse, voit jättää tämän viestin huomiotta.\n        extra_html: Katso myös <a href=\"%{terms_path}\">instanssin säännöt</a> ja <a href=\"%{policy_path}\">käyttöehdot</a>.\n        subject: 'Mastodon: Vahvistusohjeet - %{instance}'\n        title: Vahvista sähköpostiosoite\n      email_changed:\n        explanation: 'Tilin sähköpostiosoitteeksi vaihdetaan:'\n        extra: Jos et vaihtanut sähköpostiosoitettasi, joku muu on todennäköisesti päässyt käyttämään tiliäsi. Vaihda salasanasi viipymättä. Jos et pääse kirjautumaan tilillesi, ota yhteyttä instanssin ylläpitäjään.\n        subject: 'Mastodon: Sähköpostiosoite vaihdettu'\n        title: Uusi sähköpostiosoite\n      password_change:\n        explanation: Tilin salasana on vaihdettu.\n        extra: Jos et vaihtanut salasanaasi, joku muu on todennäköisesti päässyt käyttämään tiliäsi. Vaihda salasanasi viipymättä. Jos et pääse kirjautumaan tilillesi, ota yhteyttä instanssin ylläpitäjään.\n        subject: 'Mastodon: Salasana vaihdettu'\n        title: Salasana vaihdettu\n      reconfirmation_instructions:\n        explanation: Vahvista uusi sähköpostiosoite, niin muutos astuu voimaan.\n        extra: Jos et tehnyt muutosta itse, voit jättää tämän viestin huomiotta. Mastodon-tilin sähköpostiosoitetta ei vaihdeta, ennen kuin klikkaat yllä olevaa linkkiä.\n        subject: 'Mastodon: Vahvista sähköpostiosoite - %{instance}'\n        title: Vahvista sähköpostiosoite\n      reset_password_instructions:\n        action: Vaihda salasana\n        explanation: Pyysit tilillesi uuden salasanan.\n        extra: Jos et tehnyt pyyntöä itse, voit jättää tämän viestin huomiotta. Salasanaasi ei vaihdeta, ennen kuin klikkaat yllä olevaa linkkiä ja luot uuden salasanan.\n        subject: 'Mastodon: Ohjeet salasanan vaihtoon'\n        title: Salasanan vaihto\n      unlock_instructions:\n        subject: 'Mastodon: Ohjeet lukituksen poistoon'\n    omniauth_callbacks:\n      failure: Tunnistautuminen lähteestä %{kind} ei onnistunut, koska \"%{reason}\".\n      success: Tunnistautuminen tililtä %{kind} onnistui.\n    passwords:\n      no_token: Tälle sivulle pääsee vain salasananvaihtoviestin kautta. Jos tiedät tulevasi salasananvaihtoviestin kautta, varmista, että käytät koko viestissä mainittua URL-osoitetta.\n      send_instructions: Jos sähköpostiosoite on tietokannassamme, siihen lähetetään pian linkki salasanan vaihtoon. Jos et saa viestiä, tarkista roskapostikansio.\n      send_paranoid_instructions: Jos sähköpostiosoite on tietokannassamme, siihen lähetetään pian linkki salasanan vaihtoon. Jos et saa viestiä, tarkista roskapostikansio.\n      updated: Salasanan vaihto onnistui. Olet nyt kirjautunut sisään.\n      updated_not_active: Salasanan vaihto onnistui.\n    registrations:\n      destroyed: Tilisi on poistettu. Näkemiin ja tervetuloa uudelleen!\n      signed_up: Tervetuloa! Rekisteröityminen onnistui.\n      signed_up_but_inactive: Rekisteröityminen onnistui. Emme kuitenkaan voi kirjata sinua sisään, sillä tiliäsi ei ole vielä aktivoitu.\n      signed_up_but_locked: Rekisteröityminen onnistui. Emme kuitenkaan voi kirjata sinua sisään, sillä tilisi on lukittu.\n      signed_up_but_unconfirmed: Sähköpostiosoitteeseesi on lähetetty vahvistuslinkki. Aktivoi tili seuraamalla linkkiä. Jos et saanut viestiä, tarkista roskapostikansio.\n      update_needs_confirmation: Tilin päivitys onnistui, mutta uusi sähköpostiosoite on vahvistettava. Tarkista sähköpostisi ja vahvista uusi sähköpostiosoite seuraamalla vahvistuslinkkiä. Jos et saanut viestiä, tarkista roskapostikansio.\n      updated: Tilin päivitys onnistui.\n    sessions:\n      already_signed_out: Uloskirjautuminen onnistui.\n      signed_in: Sisäänkirjautuminen onnistui.\n      signed_out: Uloskirjautuminen onnistui.\n    unlocks:\n      send_instructions: Saat pian sähköpostitse ohjeet tilin lukituksen poistoon. Jos et saanut viestiä, tarkista roskapostikansio.\n      send_paranoid_instructions: Jos tili on olemassa, saat pian sähköpostitse ohjeet tilin lukituksen poistoon. Jos et saanut viestiä, tarkista roskapostikansio.\n      unlocked: Tilin lukituksen poisto onnistui. Jatka kirjautumalla sisään.\n  errors:\n    messages:\n      already_confirmed: on jo vahvistettu. Yritä kirjautua sisään\n      confirmation_period_expired: on vahvistettava %{period} sisällä. Pyydä uusi\n      expired: on vanhentunut. Pyydä uusi\n      not_found: ei löydy\n      not_locked: ei ollut lukittu\n      not_saved:\n        one: '1 virhe esti kohteen %{resource} tallennuksen:'\n        other: \"%{count} virhettä esti kohteen %{resource} tallennuksen:\"\n"
  },
  {
    "path": "config/locales/devise.fr.yml",
    "content": "---\nfr:\n  devise:\n    confirmations:\n      confirmed: Votre compte a été validé.\n      send_instructions: Vous allez recevoir les instructions nécessaires à la confirmation de votre compte dans quelques minutes. Veuillez, dans le cas où vous ne recevriez pas ce message, vérifier votre dossier d’indésirables.\n      send_paranoid_instructions: Si votre adresse électronique existe dans notre base de données, vous allez bientôt recevoir un courriel contenant les instructions de confirmation de votre compte. Veuillez, dans le cas où vous ne recevriez pas ce message, vérifier votre dossier d’indésirables.\n    failure:\n      already_authenticated: Vous êtes déjà connecté⋅e.\n      inactive: Votre compte n’est pas encore activé.\n      invalid: \"%{authentication_keys} ou mot de passe invalide.\"\n      last_attempt: Vous avez droit à une tentative avant que votre compte ne soit verrouillé.\n      locked: Votre compte est verrouillé.\n      not_found_in_database: \"%{authentication_keys} ou mot de passe invalide.\"\n      pending: Votre compte est toujours en cours d'approbation.\n      timeout: Votre session a expiré. Veuillez vous reconnecter pour continuer.\n      unauthenticated: Vous devez vous connecter ou vous inscrire pour continuer.\n      unconfirmed: Vous devez valider votre compte pour continuer.\n    mailer:\n      confirmation_instructions:\n        action: Vérifier l’adresse courriel\n        action_with_app: Confirmer et retourner à %{app}\n        explanation: Vous avez créé un compte sur %{host} avec cette adresse courriel. Vous êtes à un clic de l’activer. Si ce n’était pas vous, veuillez ignorer ce courriel.\n        explanation_when_pending: Vous avez demandé à vous inscrire à %{host} avec cette adresse courriel. Une fois que vous aurez confirmé cette adresse, nous étudierons votre demande. Vous ne pourrez pas vous connecté d'ici-là. Si votre demande est refusée, vos données seront supprimées du serveur, aucune action supplémentaire de votre part n'est donc requise. Si vous n'êtes pas à l'origine de cette demande, veuillez ignorer ce courriel.\n        extra_html: Merci de consultez également <a href=\"%{terms_path}\">les règles du serveur</a> et <a href=\"%{policy_path}\">nos conditions d’utilisation</a>.\n        subject: 'Mastodon : Merci de confirmer votre inscription sur %{instance}'\n        title: Vérifier l’adresse courriel\n      email_changed:\n        explanation: 'L’adresse courriel de votre compte est en cours de modification pour devenir :'\n        extra: Si vous n’avez pas changé votre adresse courriel, il est probable que quelqu’un ait eu accès à votre compte. Veuillez changer votre mot de passe immédiatement ou contacter l’administrateur·rice du serveur si vous êtes bloqué·e hors de votre compte.\n        subject: 'Mastodon : Courriel modifié'\n        title: Nouvelle adresse courriel\n      password_change:\n        explanation: Le mot de passe de votre compte a été changé.\n        extra: Si vous n’avez pas changé votre mot de passe, il est probable que quelqu’un ait eu accès à votre compte. Veuillez changer votre mot de passe immédiatement ou contacter l’administrateur·rice du serveur si vous êtes bloqué·e hors de votre compte.\n        subject: 'Mastodon : Votre mot de passe a été modifié avec succès'\n        title: Mot de passe modifié\n      reconfirmation_instructions:\n        explanation: Confirmez la nouvelle adresse pour changer votre courriel.\n        extra: Si ce changement n’a pas été initié par vous, veuillez ignorer ce courriel. L’adresse courriel du compte Mastodon ne changera pas tant que vous n’aurez pas cliqué sur le lien ci-dessus.\n        subject: 'Mastodon : Confirmez l’adresse pour %{instance}'\n        title: Vérifier l’adresse courriel\n      reset_password_instructions:\n        action: Modifier le mot de passe\n        explanation: Vous avez demandé un nouveau mot de passe pour votre compte.\n        extra: Si vous ne l’avez pas demandé, veuillez ignorer ce courriel. Votre mot de passe ne changera pas tant que vous n’aurez pas cliqué sur le lien ci-dessus et que vous n’en aurez pas créé un nouveau.\n        subject: 'Mastodon : Instructions pour changer votre mot de passe'\n        title: Réinitialisation du mot de passe\n      unlock_instructions:\n        subject: 'Mastodon : Instructions pour déverrouiller votre compte'\n    omniauth_callbacks:\n      failure: 'Nous n’avons pas pu vous authentifier via %{kind} : ''%{reason}''.'\n      success: Authentifié avec succès via %{kind}.\n    passwords:\n      no_token: Vous ne pouvez accéder à cette page sans passer par un courriel de réinitialisation de mot de passe. Si vous êtes passé⋅e par un courriel de ce type, assurez-vous d’utiliser l’URL complète.\n      send_instructions: Vous allez recevoir les instructions de réinitialisation du mot de passe dans quelques instants. Veuillez, dans le cas où vous ne recevriez pas ce message, vérifier votre dossier d’indésirables.\n      send_paranoid_instructions: Si votre adresse électronique existe dans notre base de données, vous allez recevoir un lien de réinitialisation par courriel. Veuillez, dans le cas où vous ne recevriez pas ce message, vérifier votre dossier d’indésirables.\n      updated: Votre mot de passe a été modifié avec succès, vous êtes maintenant connecté⋅e.\n      updated_not_active: Votre mot de passe a été modifié avec succès.\n    registrations:\n      destroyed: Au revoir ! Votre compte a été supprimé avec succès. Nous espérons vous revoir bientôt.\n      signed_up: Bienvenue ! Vous êtes connecté⋅e.\n      signed_up_but_inactive: Vous êtes bien enregistré⋅e. Vous ne pouvez cependant pas vous connecter car votre compte n’est pas encore activé.\n      signed_up_but_locked: Vous êtes bien enregistré⋅e. Vous ne pouvez cependant pas vous connecter car votre compte est verrouillé.\n      signed_up_but_pending: Un message avec un lien de confirmation a été envoyé à votre adresse courriel. Après avoir cliqué sur le lien, nous étudierons votre demande. Vous serez informé·e si elle a été approuvée.\n      signed_up_but_unconfirmed: Un message contenant un lien de confirmation a été envoyé à votre adresse courriel. Ouvrez ce lien pour activer votre compte. Veuillez vérifier votre dossier d'indésirables si vous ne recevez pas le courriel.\n      update_needs_confirmation: Votre compte a bien été mis à jour, mais nous devons vérifier votre nouvelle adresse courriel. Merci de vérifier vos courriels et de cliquer sur le lien de confirmation pour finaliser la validation de votre nouvelle adresse. Si vous n'avez pas reçu le courriel, vérifiez votre dossier d'indésirables.\n      updated: Votre compte a été modifié avec succès.\n    sessions:\n      already_signed_out: Déconnecté·e.\n      signed_in: Connecté·e.\n      signed_out: Déconnecté·e.\n    unlocks:\n      send_instructions: Vous allez recevoir les instructions nécessaires au déverrouillage de votre compte dans quelques instants. Veuillez, dans le cas où vous ne recevriez pas ce message, vérifier votre dossier d’indésirables.\n      send_paranoid_instructions: Si votre compte existe, vous allez bientôt recevoir un courriel contenant les instructions pour le déverrouiller. Veuillez, dans le cas où vous ne recevriez pas ce message, vérifier votre dossier d’indésirables.\n      unlocked: Votre compte a été déverrouillé avec succès, vous êtes maintenant connecté⋅e.\n  errors:\n    messages:\n      already_confirmed: a déjà été validée, veuillez essayer de vous connecter\n      confirmation_period_expired: à confirmer dans les %{period}, merci de faire une nouvelle demande\n      expired: a expiré, merci d’en faire une nouvelle demande\n      not_found: n’a pas été trouvé⋅e\n      not_locked: n’était pas verrouillé⋅e\n      not_saved:\n        one: 'Une erreur a empêché ce(tte) %{resource} d’être sauvegardé⋅e :'\n        other: \"%{count} erreurs ont empêché %{resource} d’être sauvegardé⋅e :\"\n"
  },
  {
    "path": "config/locales/devise.gl.yml",
    "content": "---\ngl:\n  devise:\n    confirmations:\n      confirmed: O seu enderezo de email foi confirmado con éxito.\n      send_instructions: Nuns minutos recibirá un correo electrónico con instruccións sobre como confirmar o seu enderezo de correo.  Comprobe por favor o cartafol de spam se non recibe este correo.\n      send_paranoid_instructions: Si o seu enderezo existe na nosa base de datos, recibirá nuns minutos un correo con instruccións sobre como confirmar o enderezo de correo. Por favor comprobe o cartafol de spam si non recibe este correo.\n    failure:\n      already_authenticated: Xa está conectada.\n      inactive: A súa conta aínda non foi activada.\n      invalid: Contrasinal ou %{authentication_keys} non válidos.\n      last_attempt: Quédalle un intento antes de que a conta sexa bloqueada.\n      locked: A súa conta foi bloqueada.\n      not_found_in_database: Contrasinal ou %{authentication_keys} non válidos.\n      pending: A súa conta está en proceso de revisión.\n      timeout: Caducou a sesión. Por favor conéctese de novo para seguir.\n      unauthenticated: Precisa rexistrarse ou conectarse para continuar.\n      unconfirmed: Debe confirmar o seu enderezo de correo antes de continuar.\n    mailer:\n      confirmation_instructions:\n        action: Validar enderezo de correo-e\n        action_with_app: Confirmar e voltar a %{app}\n        explanation: Creou unha conta en %{host} con este enderezo de correo. Está a punto de activalo, si non foi vostede quen fixo a petición, por favor ignore este correo.\n        explanation_when_pending: Vostede solicitou un convite para %{host} con este enderezo de correo. Unha vez confirme o enderezo de correo revisaremos a solicitude. Non pode conectarse ata entón. Si a solicitude fose rexeitada, os seus datos eliminaranse, así que non precisaría facer nada máis. Se non fixo vostede unha solicitude por favor ignore este correo.\n        extra_html: Por favor, lea tamén <a href=\"%{terms_path}\">as normas do sevidor</a> e <a href=\"%{policy_path}\">os termos do servizo</a>.\n        subject: 'Mastodon: Instruccións de confirmación para %{instance}'\n        title: Verificar enderezo de correo-e\n      email_changed:\n        explanation: 'O seu enderezo de correo para esta conta foi cambiado a:'\n        extra: Se non fixo a petición de cambio de correo-e é probable que alguén obtivese acceso a súa conta. Por favor, cambie o contrasinal inmediatamente ou contacte coa administración do servidor se non ten acceso a súa conta.\n        subject: 'Mastodon: email cambiado'\n        title: Novo enderezo de correo\n      password_change:\n        explanation: Cambiouse o contrasinal da súa conta.\n        extra: Se non cambiou o contrasinal, é probable que alguén obtivese acceso a súa conta. Por favor cambie o contrasinal inmediatamente ou contacte coa administración do servidor se non ten acceso a súa conta.\n        subject: 'Mastodon: contrasinal cambiado'\n        title: Contrainal cambiado\n      reconfirmation_instructions:\n        explanation: Confirme o novo enderezo para cambiar o correo-e.\n        extra: Si vostede non fixo esta petición, ignore este correo por favor. Este enderezo de correo-e para a conta Mastodon non cambiará ate que acceda a ligazón superior.\n        subject: 'Mastodon: Confirme email para %{instance}'\n        title: Verificación do enderezo de correo-e\n      reset_password_instructions:\n        action: Cambiar contrasinal\n        explanation: Solicitou un novo contrasinal para a súa conta.\n        extra: Si non fixo esta solicitude, por favor ignore este correo. O seu contrasinal non cambiará ate que acceda a ligazón superior e cree unha nova.\n        subject: 'Mastodon: Instruccións para restablecer o contrasinal'\n        title: Restablecer contrasinal\n      unlock_instructions:\n        subject: 'Mastodon: Instruccións para desbloquear'\n    omniauth_callbacks:\n      failure: Non podemos autenticala desde %{kind} porque \"%{reason}\".\n      success: Autenticouse con éxito desde a conta %{kind}.\n    passwords:\n      no_token: Non pode acceder a esta páxina vindo desde un correo de restablecemento de contrasinal. Si vostede chega desde un correo de restablecemento de contrasinal, por favor asegúrese de que utiliza o URL completo proporcionado.\n      send_instructions: Si o seu enderezo de correo existe na nosa base de datos,  nuns minutos recibirá unha ligazón para recuperar o contrasinal. Por favor comprobe o seu cartafol de spam si non recibe este correo.\n      send_paranoid_instructions: Si o seu enderezo de correo existe na nosa base de datos, recibirá nuns minutos unha ligazón para recuperar o contrasinal. Por favor comprobe o seu cartafol de spam si non recibe este correo.\n      updated: Cambiou o contrasinal con éxito. Agora xa está conectada.\n      updated_not_active: Cambiouse o seu contrasinal correctamente.\n    registrations:\n      destroyed: Adeus! A súa conta cancelouse con éxito. Agardamos vela de novo.\n      signed_up: Ben vida! Rexistrouse con éxito.\n      signed_up_but_inactive: Rexistrouse correctamente. Porén, aínda non podemos conectala porque a súa conta aínda non foi activada.\n      signed_up_but_locked: Rexistrouse correctamente. Porén, non podemos conectala porque a conta está bloqueada.\n      signed_up_but_pending: Enviouselle unha mensaxe de correo que contén unha ligazón de confirmación. Tras pulsar na ligazón, revisaremos a súa solicitude. Notificarémoslle se está aprobada.\n      signed_up_but_unconfirmed: Foi enviada unha mensaxe con unha ligazón de confirmación ao seu enderezo electrónico. Por favor siga a ligazón para activar a súa conta. Por favor comprobe o cartafol de spam si non recibe este correo.\n      update_needs_confirmation: Actualizou a súa conta correctamente, pero precisamos verificar o seu enderezo. Por favor comprobe o seu email e siga a ligazón de confirmación para confirmar o seu novo enderezo. Por favor comprobe o cartafol de spam si non recibe este correo.\n      updated: A súa conta foi actualizada correctamente.\n    sessions:\n      already_signed_out: Desconectouse con éxito.\n      signed_in: Conectouse correctamente.\n      signed_out: Desconectouse correctamente.\n    unlocks:\n      send_instructions: Recibirá nuns minutos un correo con instrucións sobre como desbloquear a súa conta. Por favor comprobe o cartafol de spam si non recibe este correo.\n      send_paranoid_instructions: Si a conta existe, recibirá un correo nuns minutos sobre como desbloquear a súa conta. Por favor comprobe o cartafol de spam si non recibe este correo.\n      unlocked: A súa conta foi desbloqueada correctamente. Por favor, conéctese para continuar.\n  errors:\n    messages:\n      already_confirmed: xa foi confirmada, por favor intente conectarse\n      confirmation_period_expired: precisa ser confirmada en %{period}, por favor solicite unha nova\n      expired: caducou, por favor solicite unha nova\n      not_found: non se atopou\n      not_locked: non foi bloqueada\n      not_saved:\n        one: '1 erro evitou que %{resource} fose gardada:'\n        other: \"%{count} erros evitaron que %{resource} fose gardada:\"\n"
  },
  {
    "path": "config/locales/devise.he.yml",
    "content": "---\nhe:\n  devise:\n    confirmations:\n      confirmed: כתובת הדוא\"ל אומתה בהצלחה.\n      send_instructions: נשלח אליך דוא\"ל עם הוראות לאימות כתובת הדוא\"ל שאמור להתקבל בדקות הקרובות. יש לבדוק את תיבת הספאם ליתר בטחון אם ההודעה לא הגיעה תוך דקות ספורות.\n      send_paranoid_instructions: אם כתובת הדוא\"ל שלך קיימת במסד הנתונים, יתקבל בדקות הקרובות דוא\"ל עם הוראות לאימות כתובתך. יש לבדוק את תיבת הספאם ליתר בטחון אם ההודעה לא הגיעה תוך דקות ספורות.\n    failure:\n      already_authenticated: חשבון זה כבר מחובר.\n      inactive: חשבון זה טרם הופעל.\n      invalid: \"%{authentication_keys} או סיסמא לא נכונים.\"\n      last_attempt: יש לך עוד ניסיון אחד לפני נעילת החשבון.\n      locked: חשבון זה נעול.\n      not_found_in_database: \"%{authentication_keys} או סיסמא לא נכונים.\"\n      timeout: פג תוקף השהיה בחשבון. נא להכנס מחדש על מנת להמשיך.\n      unauthenticated: יש להרשם או להכנס לחשבון על מנת להמשיך.\n      unconfirmed: יש לאמת את כתובת הדוא\"ל על מנת להמשיך.\n    mailer:\n      confirmation_instructions:\n        subject: 'מסטודון: הוראות אימות %{instance}'\n      password_change:\n        subject: 'מסטודון: הסיסמא שונתה'\n      reset_password_instructions:\n        subject: 'מסטודון: הוראות לאיפוס סיסמא'\n      unlock_instructions:\n        subject: 'מסטודון: הוראות לביטול נעילה'\n    omniauth_callbacks:\n      failure: 'לא ניתן לאמת את חשבונך מ־%{kind} מהסיבה: \"%{reason}\".'\n      success: נכשל אימות מחשבון %{kind}.\n    passwords:\n      no_token: לא ניתן לגשת לעמוד זה, אלא מדוא\"ל איפוס סיסמא. אם לא הגעת מדוא\"ל איפוס סיסמא, יש לוודא שכתובת הקישורית הוקלדה בשלמותה.\n      send_instructions: בדקות הקרובות יתקבל דוא\"ל עם הוראות לאיפוס סיסמתך. יש לבדוק את תיבת הספאם ליתר בטחון אם ההודעה לא הגיעה תוך דקות ספורות.\n      send_paranoid_instructions: אם כתובת הדוא\"ל שלך קיימת במסד הנתונים, יתקבל בדקות הקרובות דוא\"ל עם הוראות לאחזור סיסמא. יש לבדוק את תיבת הספאם ליתר בטחון אם ההודעה לא הגיעה תוך דקות ספורות.\n      updated: סיסמתך שונתה בהצלחה. הינך כעת במצב מחובר.\n      updated_not_active: סיסמתך שונתה בהצלחה.\n    registrations:\n      destroyed: בייוש! חשבונך בוטל בהצלחה. אנחנו מקווים לראות אותך שוב בקרוב.\n      signed_up: ברוכים הבאים! נרשמת בהצלחה.\n      signed_up_but_inactive: נרשמת בהצלחה. למרות זאת לא הצליחה הכניסה לחשבון מאחר וחשבונך עוד לא הופעל.\n      signed_up_but_locked: נרשמת בהצלחה. למרות זאת לא הצליחה הכניסה לחשבון מאחר וחשבונך נעול.\n      signed_up_but_unconfirmed: דוא\"ל עם קישורית לאימות נשלך לכתובתך. נא לעקוב אחר הקישורית על מנת להפעיל את החשבון. יש לבדוק את תיבת הספאם ליתר בטחון אם ההודעה לא הגיעה תוך דקות ספורות.\n      update_needs_confirmation: עדכת את חשבונך בהצלחה, אך יש צורך לאמת את כתובת הדוא\"ל החדשה שלך. נא לבדוק בחשבון הדוא\"ל לקבלת קישורית אימות על מנת לאמת את הכתובת החדשה. יש לבדוק את תיבת הספאם ליתר בטחון אם ההודעה לא הגיעה תוך דקות ספורות.\n      updated: חשבונך עודכן בהצלחה.\n    sessions:\n      already_signed_out: יצאת מהחשבון בהצלחה.\n      signed_in: נכנסת לחשבון בהצלחה.\n      signed_out: יצאת מהחשבון בהצלחה.\n    unlocks:\n      send_instructions: בדקות הקרובות ישלח אליך דוא\"ל עם הוראות לביטול נעילת החשבון. יש לבדוק את תיבת הספאם ליתר בטחון אם ההודעה לא הגיעה תוך דקות ספורות.\n      send_paranoid_instructions: אם חשבונך קיים, בדקות הקרובות ישלח אליך דוא\"ל עם הוראות לביטול נעילת החשבון. יש לבדוק את תיבת הספאם ליתר בטחון אם ההודעה לא הגיעה תוך דקות ספורות.\n      unlocked: נעילת חשבונך בוטלה בהצלחה. נא להכנס לחשבון על מנת להמשיך.\n  errors:\n    messages:\n      already_confirmed: כבר אושר. נא לנסות להכנס לחשבון\n      confirmation_period_expired: האישור צריך להתקבל תוך %{period}, נא לבקש חדש\n      expired: פג תוקפו. נא לבקש חדש\n      not_found: לא נמצא\n      not_locked: לא היה נעול\n"
  },
  {
    "path": "config/locales/devise.hr.yml",
    "content": "---\nhr:\n  devise:\n    confirmations:\n      confirmed: Tvoja email adresa je uspješno potvrđena.\n      send_instructions: Primit ćeš email sa uputama kako potvrditi  svoju email adresu za nekoliko minuta.\n      send_paranoid_instructions: Ako tvoja email adresa postoji u našoj bazi podataka, primit ćeš email sa uputama kako ju potvrditi za nekoliko minuta.\n    mailer:\n      confirmation_instructions:\n        subject: 'Mastodon: Upute za potvrđivanje %{instance}'\n      email_changed:\n        subject: 'Mastodon: Email adresa je promijenjena'\n        title: Nova email adresa\n      password_change:\n        subject: 'Mastodon: Lozinka je promijenjena'\n      reset_password_instructions:\n        subject: 'Mastodon: Upute za resetiranje lozinke'\n      unlock_instructions:\n        subject: 'Mastodon: Upute za otključavanje'\n    omniauth_callbacks:\n      failure: Ne možemo te autentificirati sa %{kind} zbog \"%{reason}\".\n      success: Uspješno autentificiran sa %{kind} računa.\n    passwords:\n      no_token: Ne možeš pristupiti ovoj stranici bez dolaženja sa emaila za resetiranje lozinke. Ako dolaziš sa tog emaila, pazi da koristiš potpuni link koji ti je dan.\n      send_instructions: Primit ćeš email sa uputama kako resetirati svoju lozinku za nekoliko minuta.\n      send_paranoid_instructions: Ako tvoja email adresa postoji u našoj bazi podataka, primit ćeš link za povrat lozinke na svoju email adresu za nekoliko minuta.\n      updated: Tvoja lozinka je uspješno izmijenjena. Sada si prijavljen.\n      updated_not_active: Toja lozinka je uspješno izmijenjena.\n    registrations:\n      destroyed: Zbogom! Tvoj račun je uspješno otkazan. Nadamo se da ćemo te vidjeti ponovo.\n      signed_up: Dobro došao! Uspješno si se prijavio.\n      signed_up_but_inactive: Uspješno si se registrirao. No, ne možeš se prijaviti, jer ti račun još nije aktiviran.\n      signed_up_but_locked: Uspješno si se registrirao. No, ne možeš se prijaviti jer je tvoj račun zaključan.\n      signed_up_but_unconfirmed: Poruka sa linkom za potvrđivanje je poslana na tvoju email adresu. Molimo, slijedi link kako bi tvoj račun bio aktiviran.\n      update_needs_confirmation: Tvoj račun je uspješno ažuriran, ali trebamo provjeriti tvoju novu email adresu. Molimo, provjeri svoj email i slijedi link za potvrđivanje kako bi tvoja nova email adresa bila potvrđena.\n      updated: Tvoj račun je uspješno ažuriran.\n    sessions:\n      already_signed_out: Uspješno si odjavljen.\n      signed_in: Uspješno si prijavljen.\n      signed_out: Uspješno si odjavljen.\n    unlocks:\n      send_instructions: Primit ćeš email sa uputama kako otključati svoj račun za nekoliko minuta.\n      send_paranoid_instructions: Ako tvoj račun postoji, primit ćeš email sa uputama kako ga otključati za nekoliko minuta.\n      unlocked: Tvoj račun je uspješno otključan. Prijavi se kako bi nastavio.\n  errors:\n    messages:\n      already_confirmed: je već potvrđen, pokušaj se prijaviti\n      confirmation_period_expired: mora biti potvrđen u roku od %{period}, molimo zatraži novi\n      expired: je istekao, zatraži novu\n      not_found: nije nađen\n      not_locked: nije zaključan\n"
  },
  {
    "path": "config/locales/devise.hu.yml",
    "content": "---\nhu:\n  devise:\n    confirmations:\n      confirmed: Az e-mail címed sikeresen meg lett erősítve.\n      send_instructions: Pár percen belül kapni fogsz egy e-mailt az e-mail címed megerősítéséhez szükséges lépésekről.\n      send_paranoid_instructions: Ha az e-mail címed létezik az adatbázisunkban, pár percen belül kapni fogsz egy e-mailt az e-mail címed megerősítéséhez szükséges lépésekről.\n    failure:\n      already_authenticated: Már bejelentkeztél.\n      inactive: Fiókod még nem lett aktiválva.\n      invalid: Helytelen %{authentication_keys} vagy jelszó.\n      last_attempt: Már csak egy próbálkozásod maradt mielőtt a fiókod lezárásra kerül.\n      locked: Fiókod le van zárva.\n      not_found_in_database: Helytelen %{authentication_keys} vagy jelszó.\n      timeout: A munkamenet lejárt. Jelentkezz be újra a folytatáshoz.\n      unauthenticated: A folytatás előtt be kell jelentkezned.\n      unconfirmed: A folytatás előtt meg kell erősítened az e-mail címed.\n    mailer:\n      confirmation_instructions:\n        action: Erősítsd meg az e-mail címedet\n        explanation: Ezzel az e-mail címmel kezdeményeztek regisztrációt a(z) %{host} oldalon. Csak egy kattintás, és a felhasználói fiókdat aktiváljuk. Ha a regisztrációt nem te kezdeményezted, kérjük tekintsd ezt az e-mailt tárgytalannak.\n        extra_html: Kérjük tekintsd át a <a href=\"%{terms_path}\">az instancia szabályzatát</a> és <a href=\"%{policy_path}\">a felhasználási feltételeket</a>.\n        subject: 'Mastodon: Megerősítési lépések %{instance}'\n        title: E-mail cím megerősítése\n      email_changed:\n        explanation: 'A fiókodhoz tartozó e-mail címet az alábbira módosítod:'\n        extra: Ha nem te kezdeményezted a fiókodhoz tartozó e-mail cím módosítását, valaki hozzáférhetett a fiókodhoz. Legjobb, ha azonnal megváltoztatod a jelszavadat; ha nem férsz hozzá a fiókodhoz, vedd fel a kapcsolatot az instanciád adminisztrátorával.\n        subject: 'Mastodon: a fiókodhoz tartozó e-mail címet megváltoztattuk'\n        title: Új e-mail cím\n      password_change:\n        explanation: A fiókodhoz tartozó jelszót megváltoztattuk.\n        extra: Ha nem te kezdeményezted a fiókodhoz tartozó jelszó módosítását, valaki hozzáférhetett a fiókodhoz. Legjobb, ha azonnal megváltoztatod a jelszavadat; ha nem férsz hozzá a fiókodhoz, vedd fel a kapcsolatot az instanciád adminisztrátorával.\n        subject: 'Mastodon: Jelszó megváltoztatva'\n        title: Sikeres jelszó-módosítás\n      reconfirmation_instructions:\n        explanation: Az e-mail cím megváltoztatásához meg kell erősítened az új címet.\n        extra: Amennyiben nem te kezdeményezted a módosítást, kérjük tekintsd ezt az e-mailt tárgytalannak. A Mastodon fiókodhoz tartozó e-mail címed változatlan marad mindaddig, amíg rá nem kattintasz a fenti linkre.\n        subject: 'Mastodon: erősítsd meg a(z) %{instance} instanciához tartozó e-mail címed'\n        title: E-mail cím megerősítése\n      reset_password_instructions:\n        action: Jelszó módosítása\n        explanation: A fiókodhoz tartozó jelszó módosítását kezdeményezted.\n        extra: Amennyiben nem te kezdeményezted a módosítást, kérjük tekintsd ezt az e-mailt tárgytalannak. A Mastodon fiókodhoz tartozó jelszavad változatlan marad mindaddig, amíg újat nem hozol létre a fenti linkre kattintva.\n        subject: 'Mastodon: Jelszó visszaállítási lépések'\n        title: Jelszó visszaállítása\n      unlock_instructions:\n        subject: 'Mastodon: Feloldási lépések'\n    omniauth_callbacks:\n      failure: \"%{kind} nem hitelesíthető, mert %{reason}.\"\n      success: Sikeres hitelesítés %{kind} fiókról.\n    passwords:\n      no_token: Nem férhetsz hozzá az oldalhoz jelszó visszaállító e-mail nélkül. Ha egy jelszó visszaállító e-mail hozott ide, ellenőrizd, hogy a megadott teljes URL-t használd.\n      send_instructions: Pár percen belül kapni fogsz egy e-mailt arról, hogy hogyan tudod visszaállítani a jelszavadat.\n      send_paranoid_instructions: Ha létezik az e-mail cím, pár percen belül kapni fogsz egy e-mailt arról, hogy hogyan tudod visszaállítani a jelszavadat.\n      updated: Jelszavad sikeresen frissült. Bejelentkeztél.\n      updated_not_active: Jelszavad sikeresen meg lett változtatva.\n    registrations:\n      destroyed: Viszlát! A fiókod sikeresen törölve. Reméljük hamarosan viszontláthatunk.\n      signed_up: Üdvözlünk! Sikeresen regisztráltál.\n      signed_up_but_inactive: Sikeresen regisztráltál. Ennek ellenére nem tudunk beléptetni, ugyanis a fiókod még nem lett aktiválva.\n      signed_up_but_locked: Sikeresen regisztráltál. Ennek ellenére nem tudunk beléptetni, ugyanis a fiókod le lett zárva.\n      signed_up_but_unconfirmed: Egy üzenet a megerősítési linkkel kiküldésre került az e-mail címedre. Kérjük használd a linket a fiókod aktiválásához.\n      update_needs_confirmation: Sikeresen frissítetted a fiókodat, de szükségünk van az e-mail címed megerősítésére. Kérlek ellenőrizd az e-mailedet és kövesd a levélben szereplő megerősítési linket az e-mail címed megerősítéséhez.\n      updated: Fiókod frissítése sikeres.\n    sessions:\n      already_signed_out: Sikeres kijelenkezés.\n      signed_in: Sikeres bejelentkezés.\n      signed_out: Sikeres kijelentkezés.\n    unlocks:\n      send_instructions: Pár percen belül egy e-mailt fogsz kapni a feloldáshoz szükséges lépésekkel.\n      send_paranoid_instructions: Ha a fiókod létezik, pár percen belül egy e-mailt fogsz kapni a feloldáshoz szükséges lépésekkel.\n      unlocked: A fiókod sikeresen fel lett oldva. Jelentkezz be a folytatáshoz.\n  errors:\n    messages:\n      already_confirmed: már meg lett erősítve, kérjük jelentkezz be\n      confirmation_period_expired: \"%{period} belül kellett megerősíteni, kérjük igényelj újat\"\n      expired: lejárt, kérjük igényelj újat\n      not_found: nem található\n      not_locked: nincs lezárva\n      not_saved:\n        one: '1 hiba megakadályozta %{resource} mentését:'\n        other: \"%{count} számú hiba megakadályozta %{resource} mentését:\"\n"
  },
  {
    "path": "config/locales/devise.hy.yml",
    "content": "hy:\n"
  },
  {
    "path": "config/locales/devise.id.yml",
    "content": "---\nid:\n  devise:\n    confirmations:\n      confirmed: Alamat email anda berhasil dikonfirmasi.\n      send_instructions: Anda akan menerima email berisi instruksi untuk mengkonfirmasi alamat email anda dalam beberapa menit.\n      send_paranoid_instructions: Jika email anda sudah ada dalam database kami, Anda akan menerima email berisi instruksi untuk mengkonfirmasi alamat email anda dalam beberapa menit.\n    failure:\n      already_authenticated: Anda sudak masuk.\n      inactive: Akun anda masih belum diaktifkan.\n      invalid: Ada %{authentication_keys} atau kata sandi yang tidak cocok.\n      last_attempt: Anda memiliki beberapa kali mencoba sebelum akun anda dikunci.\n      locked: Akun anda dikunci.\n      not_found_in_database: Ada %{authentication_keys} atau kata sandi yang tidak cocok.\n      timeout: Sesi anda telah berakhir. Silahkan coba masuk lagi.\n      unauthenticated: Anda harus masuk atau mendaftar terlebih dahulu.\n      unconfirmed: Anda harus mengkonfirmasi alamat email terlebih dahulu.\n    mailer:\n      confirmation_instructions:\n        subject: 'Mastodon: Petunjuk mengkonfirmasi untuk %{instance}'\n      password_change:\n        subject: 'Mastodon: Kata sandi telah diubah'\n      reset_password_instructions:\n        subject: 'Mastodon: Petunjuk mereset kata sandi'\n      unlock_instructions:\n        subject: 'Mastodon: Petunjuk membuka'\n    omniauth_callbacks:\n      failure: Tidak dapat mengautentikasi anda dari %{kind} karena \"%{reason}\".\n      success: Autentikasi dari akun %{kind} berhasil dilakukan.\n    passwords:\n      no_token: Anda tidak dapat mengakses halaman ini jika tidak berasal dari email berisi reset kata sandi. Jika anda datang dari email berisi reset kata sandi, mohon masukkan URL selengkapnya.\n      send_instructions: Jika alamat email anda telah ada dalam database kami, anda akan menerima sebuah link pemulihan kata sandi pada alamat email anda dalam beberapa menit.\n      send_paranoid_instructions: Jika alamat email anda telah ada dalam database kami, anda akan menerima sebuah link pemulihan kata sandi pada alamat email anda dalam beberapa menit.\n      updated: Kata sandi anda berhasil diubah. Anda telah masuk sekarang.\n      updated_not_active: Kata sandi anda berhasil diubah.\n    registrations:\n      destroyed: Selamat tinggal! Akun anda berhasil dibatalkan. Kami harap berjumpa lagi dengan anda dilain waktu.\n      signed_up: Selamat datang! Pendaftaran anda berhasil.\n      signed_up_but_inactive: Anda berhasil melakukan pendaftaran. Tetapi kami tidak dapat memasukkan anda karena akun anda belum diaktifkan.\n      signed_up_but_locked: Anda berhasil melakukan pendaftaran. Tetapi kami tidak dapat memasukkan anda karena akun anda dikunci.\n      signed_up_but_unconfirmed: Sebuah pesan berisi link konfirmasi telah dikirim ke alamat email anda. Silakan ikuti link tersebut untuk mengaktifkan akun anda.\n      update_needs_confirmation: Akun anda telah berhasil diubah, tetapi kami harus memverifikasi alamat email anda yang baru. Mohon cek email anda dan ikuti link untuk mengkonfirmasi alamat email anda yang baru.\n      updated: Akun anda berhasil diubah.\n    sessions:\n      already_signed_out: Berhasil logout.\n      signed_in: Berhasil masuk.\n      signed_out: Berhasil keluar.\n    unlocks:\n      send_instructions: Anda akan menerima sebuah email berisi petunjuk bagaimana cara membuka akun anda dalam beberapa menit.\n      send_paranoid_instructions: Jika akun anda telah terdaftar, anda akan menerima email berisi petunjuk cara membuka akun anda dalam beberapa menit.\n      unlocked: Akun anda berhasil dibuka. Silakan masuk untuk melanjutkan.\n  errors:\n    messages:\n      already_confirmed: sudah dikonfirmasikan, silakan coba masuk\n      confirmation_period_expired: harus dikonfirmasi dalam %{period}, silakan buat permintaan baru\n      expired: sudah kadaluarsa, silakan buat permintaan baru\n      not_found: tidak ditemukan\n      not_locked: tidak dikunci\n      not_saved:\n        other: \"%{count} error yang membuat %{resource} ini tidak dapat disimpan:\"\n"
  },
  {
    "path": "config/locales/devise.io.yml",
    "content": "---\nio:\n  devise:\n    confirmations:\n      confirmed: Tua konto konfirmesas.\n      send_instructions: Tu recevos instrucioni por konfirmar tua konto pos kelka minuti.\n      send_paranoid_instructions: Se tua retpost-adreso existas en nia datumbazo, tu balde revecos retpost-mesajo, qua kontenas la instrucioni por konfirmar tua konto.\n    failure:\n      already_authenticated: Tu ya esas enirinta.\n      inactive: Tua konto ankore ne konfirmesas.\n      invalid: Nejusta %{authentication_keys}.\n      last_attempt: Tu ankore povas probar unfoye ante ke tua konto esos extingita.\n      locked: Tua konto esas extingita.\n      not_found_in_database: Nejusta %{authentication_keys}.\n      timeout: Tua kunsido expiris. Voluntez rienirar por durar.\n      unauthenticated: Tu devas enirar o membreskar por durar.\n      unconfirmed: Tu devas konfirmar tua konto por durar.\n    mailer:\n      confirmation_instructions:\n        subject: Instrucioni por konfirmar %{instance}\n      password_change:\n        subject: Tua pasvorto chanjesis senprobleme.\n      reset_password_instructions:\n        subject: Instrucioni por chanjar la pasvorto\n      unlock_instructions:\n        subject: Instructioni por riacendar la konto\n    omniauth_callbacks:\n      failure: 'Ni ne povis autentikigar tu per %{kind}: ''%{reason}''.'\n      success: Autentikigita senprobleme per %{kind}.\n    passwords:\n      no_token: Tu ne povas irar a ta pagino per altra voyo kam retpost-mesajo por chanjar pasvorto. Se tu venas de tala retpost-mesajo, kontrolez ke tu uzis la tota URL.\n      send_instructions: Tu recevos retpost-mesajo kun instrucioni por chanjar tua pasvorto pos kelka minuti.\n      send_paranoid_instructions: Se tua retpost-adreso existas en nia datumbazo, tu recevos ligilo por chanjar tua pasvorto per retpost-mesajo.\n      updated_not_active: Tua pasvorto redaktesis senprobleme.\n    registrations:\n      destroyed: Til! Tua konto efacesis senprobleme. Ni esperas rividar tu balde.\n      signed_up: Bonveno! Tu membreskis senprobleme.\n      signed_up_but_inactive: Tu bone membreskis, ma tu ankore ne povas enirar pro ke tua konto ne konfirmesis.\n      signed_up_but_locked: Tu bone membreskis, ma tu ne povas enirar pro ke tua konto extingesis.\n      signed_up_but_unconfirmed: Retpost-mesajo kun tua ligilo por konfirmar tua konto sendesis a tua retpost-adreso. Voluntez uzar ta ligilo por konfirmar tua konto.\n      update_needs_confirmation: Tu vone aktualigis tua konto, ma ni bezonas kontrolar tua nova retpost-adreso. Voluntez kontrolar tua retpost-mesaji ed uzar la ligilo por konfirmar tua nova retpost-adreso.\n      updated: Tua konto aktualigesis senprobleme.\n    sessions:\n      already_signed_out: Ekirinta.\n      signed_in: Enirinta.\n      signed_out: Ekirinta.\n    unlocks:\n      send_instructions: Tu recevos retpost-mesajo kun instrucioni por riacendar tua konto pos kelka minuti.\n      send_paranoid_instructions: Se tua retpost-adreso existas en nia datumbazo, tu recevos ligilo por riacendar tua konto per retpost-meajo.\n      unlocked: Tua konto riacendesis senprobleme, tu nun esas enirinta.\n  errors:\n    messages:\n      already_confirmed: ja konfirmesis, voluntez probar enirar\n      confirmation_period_expired: devas konfirmesar en %{period}, voluntez iterar\n      expired: expiris, voluntez repetar\n      not_found: ne trovesis\n      not_locked: ne extingesis\n      not_saved:\n        one: '1 eroro impedis a ta %{resource} konservesar:'\n        other: \"%{count} erori impedis a ta %{resource} konservesar:\"\n"
  },
  {
    "path": "config/locales/devise.it.yml",
    "content": "---\nit:\n  devise:\n    confirmations:\n      confirmed: Il tuo indirizzo email è stato confermato con successo.\n      send_instructions: Riceverai in pochi minuti una email con istruzioni per confermare il tuo account al tuo indirizzo email.\n      send_paranoid_instructions: Se il tuo indirizzo email è presente nel nostro database, riceverai in pochi minuti una email con istruzioni per confermare il tuo account al tuo indirizzo email.\n    failure:\n      already_authenticated: Hai già effettuato l'accesso.\n      inactive: Non hai ancora attivato il tuo account.\n      invalid: \"%{authentication_keys} o password invalida.\"\n      last_attempt: Hai un altro tentativo prima che il tuo account venga bloccato.\n      locked: Il tuo account è stato bloccato.\n      not_found_in_database: \"%{authentication_keys} o password invalida.\"\n      timeout: La tua sessione è terminata. Per favore, effettua l'accesso o registrati per continuare.\n      unauthenticated: Devi effettuare l'accesso o registrarti per continuare.\n      unconfirmed: Devi confermare il tuo indirizzo email per continuare.\n    mailer:\n      confirmation_instructions:\n        action: Verifica indirizzo email\n        action_with_app: Conferma e torna a %{app}\n        explanation: Hai creato un account su %{host} con questo indirizzo email. Sei lonatno solo un clic dall'attivarlo. Se non sei stato tu, per favore ignora questa email.\n        extra_html: Per favore controlla<a href=\"%{terms_path}\">le regole del server</a> e <a href=\"%{policy_path}\">i nostri termini di servizio</a>.\n        subject: 'Mastodon: Istruzioni di conferma per %{instance}'\n        title: Verifica indirizzo email\n      email_changed:\n        explanation: 'L''indirizzo email del tuo account sta per essere cambiato in:'\n        extra: Se non hai cambiato la tua email, è probabile che qualcuno abbia ottenuto l'accesso al tuo account. Cambia immediatamente la tua password e contatta l'amministratore del server se non puoi più accedere al tuo account.\n        subject: 'Mastodon: Email cambiata'\n        title: Nuovo indirizzo email\n      password_change:\n        explanation: La password del tuo account è stata cambiata.\n        extra: Se non hai cambiato la password, è probabile che qualcuno abbia ottenuto l'accesso al tuo account. Cambia immediatamente la tua password e contatta l'amministratore del server non puoi più accedere al tuo account.\n        subject: 'Mastodon: Password modificata'\n        title: Password cambiata\n      reconfirmation_instructions:\n        explanation: Conferma il nuovo indirizzo per cambiare la tua email.\n        extra: Se questo cambiamento non è stato chiesto da te, ignora questa email. L'indirizzo email per l'account Mastodon non verrà cambiato finché non accedi dal link qui sopra.\n        subject: 'Mastodon: Email di conferma per %{instance}'\n        title: Verifica indirizzo email\n      reset_password_instructions:\n        action: Cambia password\n        explanation: Hai richiesto una nuova password per il tuo account.\n        extra: Se questo cambiamento non è stato chiesto da te, ignora questa email. La tua password non verrà cambiata finché non accedi tramite il link qui sopra e ne crei una nuova.\n        subject: 'Mastodon: Istruzioni per il reset della password'\n        title: Ripristino password\n      unlock_instructions:\n        subject: 'Mastodon: Istruzioni di sblocco'\n    omniauth_callbacks:\n      failure: Impossibile autenticarti da %{kind} perché \"%{reason}\".\n      success: Autenticato con successo con account %{kind}.\n    passwords:\n      no_token: Non puoi accedere a questa pagina senza essere stato reindirizzato da una mail di reset password. Se arrivi da una mail di reset password, per favore controlla di aver copiato per intero l'URL fornito.\n      send_instructions: Se la tua mail è presente nel nostro database, riceverai in pochi minuti un link per recuperare la tua password al tuo indirizzo mail.\n      send_paranoid_instructions: Se la tua mail è presente nel nostro database, riceverai in pochi minuti un link per recuperare la tua password al tuo indirizzo mail.\n      updated: La tua password è stata modificata con successo. Abbiamo già effettuato l'accesso per te.\n      updated_not_active: La tua password è stata modificata con successo.\n    registrations:\n      destroyed: Addio! Il tuo account è stato cancellato. Speriamo di rivederti presto.\n      signed_up: Benvenuto! Ti sei registrato con successo.\n      signed_up_but_inactive: Ti sei registrato con successo. Purtroppo però non possiamo farti accedere perché non hai ancora attivato il tuo account.\n      signed_up_but_locked: Ti sei registrato con successo. Purtroppo però non possiamo farti accedere perché il tuo account è bloccato.\n      signed_up_but_unconfirmed: Un messaggio con un link di conferma è stato inviato al tuo indirizzo email. Per favore, visita il link per attivare il tuo account.\n      update_needs_confirmation: Hai aggiornato correttamente il tuo account, ma abbiamo bisogno di verificare il tuo nuovo indirizzo email. Per favore, controlla la posta in arrivo e visita il link di conferma per verificare il tuo indirizzo email.\n      updated: Il tuo account è stato aggiornato con successo.\n    sessions:\n      already_signed_out: Sei uscito correttamente dal tuo account.\n      signed_in: Accesso eseguito correttamente.\n      signed_out: Sei uscito correttamente dal tuo account.\n    unlocks:\n      send_instructions: Riceverai in pochi minuti una email con istruzioni su come sbloccare il tuo account.\n      send_paranoid_instructions: Se il tuo account esiste, riceverai in pochi minuti una email con istruzioni su come sbloccarlo.\n      unlocked: Il tuo account è stato sbloccato con successo. Per favore, esegui l'accesso per continuare.\n  errors:\n    messages:\n      already_confirmed: era già stata confermata; per favore, prova ad eseguire l'accesso\n      confirmation_period_expired: deve essere confermata entro %{period}; per favore, richiedine una nuova\n      expired: è terminata; per favore, richiedine una nuova\n      not_found: non trovato\n      not_locked: non era stato bloccato\n      not_saved:\n        one: '1 errore ha impedito che %{resource} venisse salvato:'\n        other: \"%{count} errori hanno impedito che %{resource} venisse salvato:\"\n"
  },
  {
    "path": "config/locales/devise.ja.yml",
    "content": "---\nja:\n  devise:\n    confirmations:\n      confirmed: メールアドレスの確認が正常に完了しました。\n      send_instructions: まもなくメールアドレスの確認の方法が記載されたメールが送信されます。\n      send_paranoid_instructions: もしあなたのメールアドレスが登録されていれば、まもなくメールアドレスの確認の方法が記載されたメールが送信されます。\n    failure:\n      already_authenticated: 既にログイン済みです。\n      inactive: あなたのアカウントはまだ有効化されていません。\n      invalid: \"%{authentication_keys}かパスワードが誤っています。\"\n      last_attempt: あと1回失敗するとアカウントがロックされます。\n      locked: アカウントはロックされました。\n      not_found_in_database: \"%{authentication_keys}かパスワードが誤っています。\"\n      pending: あなたのアカウントはまだ承認待ちです。\n      timeout: セッションの有効期限が切れました。続行するには再度ログインしてください。\n      unauthenticated: 続行するにはログインするか、アカウントを作成してください。\n      unconfirmed: 続行するにはメールアドレスを確認する必要があります。\n    mailer:\n      confirmation_instructions:\n        action: メールアドレスの確認\n        action_with_app: 確認し %{app} に戻る\n        explanation: このメールアドレスで%{host}にアカウントを作成しました。有効にするまであと一歩です。もし心当たりがない場合、申し訳ありませんがこのメールを無視してください。\n        explanation_when_pending: このメールアドレスで%{host}への登録を申請しました。あなたがメールアドレスを確認したら、サーバー管理者が申請を審査します。それまでログインできません。申請が却下された場合、あなたのデータは削除されますので以降の操作は必要ありません。もし心当たりがない場合、申し訳ありませんがこのメールを無視してください。\n        extra_html: また <a href=\"%{terms_path}\">サーバーのルール</a> と <a href=\"%{policy_path}\">利用規約</a> もお読みください。\n        subject: 'Mastodon: メールアドレスの確認 %{instance}'\n        title: メールアドレスの確認\n      email_changed:\n        explanation: 'アカウントのメールアドレスは以下のように変更されます:'\n        extra: メールアドレスの変更を行っていない場合、他の誰かがあなたのアカウントにアクセスした可能性があります。すぐにパスワードを変更するか、アカウントがロックされている場合はサーバー管理者に連絡してください。\n        subject: 'Mastodon: メールアドレスの変更'\n        title: 新しいメールアドレス\n      password_change:\n        explanation: パスワードが変更されました。\n        extra: パスワードの変更を行っていない場合、他の誰かがあなたのアカウントにアクセスした可能性があります。すぐにパスワードを変更するか、アカウントがロックされている場合はサーバー管理者に連絡してください。\n        subject: 'Mastodon: パスワードが変更されました'\n        title: パスワードの変更\n      reconfirmation_instructions:\n        explanation: メールアドレスを変更するため新しいアドレスを確認してください。\n        extra: この変更に心当たりがない場合、このメールを無視してください。上記リンク先にアクセスするまでアカウントのメールアドレスは変更されません。\n        subject: 'Mastodon: %{instance}のメールを確認する'\n        title: メールアドレスの確認\n      reset_password_instructions:\n        action: パスワードの変更\n        explanation: あなたのアカウントに対しパスワードの再発行が要求されました。\n        extra: この要求に心当たりがない場合、このメールを無視してください。上記リンク先にアクセスし新しいものを作成するまでパスワードは変更されません。\n        subject: 'Mastodon: パスワード再発行'\n        title: パスワード再発行\n      unlock_instructions:\n        subject: 'Mastodon: アカウントのロックの解除'\n    omniauth_callbacks:\n      failure: \"%{reason}によって%{kind}からのアクセスを認証できませんでした。\"\n      success: \"%{kind}からのアクセスは正常に認証されました。\"\n    passwords:\n      no_token: パスワード再発行のメール以外からこのページにアクセスすることはできません。 パスワード再発行のメールからアクセスしたのにもかかわらずこのメッセージが表示される場合は、アクセスしたURLが間違っていないか確認してください。\n      send_instructions: パスワード再発行の方法が記載されたメールが間もなく送信されます。\n      send_paranoid_instructions: メールアドレスが登録済みであれば、パスワードをリセットするリンクが記載されたメールがあなたのメールアドレスに送信されます。\n      updated: パスワードは正常に更新されました。なお、既にログイン済みです。\n      updated_not_active: パスワードは正常に更新されました。\n    registrations:\n      destroyed: アカウントの作成はキャンセルされました。またのご利用をお待ちしています。\n      signed_up: アカウントの作成が完了しました。Mastodonへようこそ。\n      signed_up_but_inactive: アカウントの作成が完了しました。しかし、アカウントが有効化されていないためログインできませんでした。\n      signed_up_but_locked: アカウントの作成が完了しました。しかし、アカウントがロックされているためログインできませんでした。\n      signed_up_but_pending: メールアドレスの確認用のリンクが入力したメールアドレスに送信されました。リンクをクリックした後、あなたの申請を審査します。承認されると通知されます。\n      signed_up_but_unconfirmed: メールアドレスの確認用のリンクが入力したメールアドレスに送信されました。メール内のリンクをクリックしてアカウントを有効化してください。\n      update_needs_confirmation: アカウント情報の更新に成功しました。しかし、メールアドレスの確認が必要です。送信されたメール内のリンクをクリックしてメールアドレスを確認してください。\n      updated: アカウント情報の更新に成功しました。\n    sessions:\n      already_signed_out: 既にログアウトしています。\n      signed_in: ログインしました。\n      signed_out: ログアウトしました。\n    unlocks:\n      send_instructions: まもなくアカウントのロックを解除するための方法を記載したメールが送信されます。\n      send_paranoid_instructions: もしアカウントが存在すれば、まもなくアカウントのロックを解除するための方法を記載したメールが送信されます。\n      unlocked: アカウントロックは正常に解除されました。続行するにはログインしてください。\n  errors:\n    messages:\n      already_confirmed: は確認されました。ログインを試してください\n      confirmation_period_expired: \"%{period}以内に確認が必要です。再度試してください\"\n      expired: は期限切れです。再度試してください\n      not_found: 見つかりません\n      not_locked: ロックされていません\n      not_saved:\n        other: \"%{count}個のエラーが発生したため、%{resource}の保存に失敗しました:\"\n"
  },
  {
    "path": "config/locales/devise.ka.yml",
    "content": "---\nka:\n  devise:\n    confirmations:\n      confirmed: თქვენი ელ-ფოსტის მისამართი წარმატებით დამოწმდა.\n      send_instructions: თქვენ მიიღებთ ელ-ფოსტას ინსტრუქციებით თუ როგორც დაამოწმოთ თქვენი ელ-ფოსტის მისამართი რამდენიმე წუთში. გთხოვთ შეხედოთ თქვენი სპამის ფოლდერს თუ არ მიიღებთ ამ წერილს.\n      send_paranoid_instructions: თუ თქვენი ელ-ფოსტა არსებობს ჩვენს მონაცემთა ბაზაში, თქვენ მიიღებთ ელ-ფოსტას ინსტრუქციებით თუ როგორც დაამოწმოთ თქვენი ელ-ფოსტის მისამართი რამდენიმე წუთში. გთხოვთ შეხედოთ თქვენი სპამის ფოლდერს თუ არ მიიღებთ ამ წერილს.\n    failure:\n      already_authenticated: უკვე შესული ხართ.\n      inactive: თქვენი ანგარიში ჯერ არაა აქტივირებული.\n      invalid: არასწორი %{authentication_keys} ან პაროლი.\n      last_attempt: თქვენი ანგარიშის ჩაკეტვამდე დაგრჩათ კიდევ ერთი მცდელობა.\n      locked: თქვენი ანგარიში ჩაიკეტა.\n      not_found_in_database: არასწორი %{authentication_keys} ან პაროლი.\n      timeout: თქვენს სესიას გაუვიდა ვადა. გთხოვთ შედით ახლიდან რომ გააგრძელოთ.\n      unauthenticated: გაგრძელებამდე საჭიროა შეხვიდეთ ან დარეგისტრირდეთ.\n      unconfirmed: გაგრძელებამდე საჭიროა დაამოწმოთ თქვენი ელ-ფოსტა.\n    mailer:\n      confirmation_instructions:\n        action: დაამოწმეთ ელ-ფოსტის მისამართი\n        explanation: თქვენ ამ ელ-ფოსტის მისამართი ანგარიში შექმენით %{host}-ზე. დარჩა ერთი დაწკაპუნება მის აქტივაციამდე. თუ ეს თქვენ არ იყავით, გთხოვთ არ მიაქციოთ ყურადღება ამ წერილს.\n        extra_html: გთხოვთ ასევე გაეცნოთ <a href=\"%{terms_path}\">ინსტანციის წესებს</a> და <a href=\"%{policy_path}\">ჩვენს კონფინდენციალურობის პოლიტიკას</a>.\n        subject: 'მასტოდონი: დამოწმების ინსტრუქციები %{instance}-თვის'\n        title: ელ-ფოსტის მისამართის დამოწმება\n      email_changed:\n        explanation: 'თქვენი ანგარიშის ელ-ფოსტის მისამართი იცვლება შემდეგზე:'\n        extra: თუ თქვენ არ შეგიცვლიათ თქვენი ელ-ფოსტის მისამართი, როგორც ჩანს სხვამ ხელთ იგდო თქვენი ანგარიში. გთოხვთ შეცვალოთ თქვენი პაროლი რაც შეიძლება მალე, ან დაუკავშირდეთ ინსტანციის ადმინისტრატორს თუ თქვენი ანგარიში ჩაიკეტა.\n        subject: 'მასტოდონი: ელ-ფოსტა შეიცვალა'\n        title: ახალი ელ-ფოსტის მისამართი\n      password_change:\n        explanation: თქვენი ანგარიშის პაროლი შეიცვალა.\n        extra: თუ თქვენ არ შეგიცვლიათ პაროლი, როგორც ჩანს სხვამ ხელთ იგდო თქვენი ანგარიში. გთოხვთ შეცვალოთ თქვენი პაროლი რაც შეიძლება მალე, ან დაუკავშირდეთ ინსტანციის ადმინისტრატორს თუ თქვენი ანგარიში ჩაიკეტა.\n        subject: 'მასტოდონი: პაროლი შეიცვალა'\n        title: პაროლი შეიცვალა\n      reconfirmation_instructions:\n        explanation: დაამოწმეთ ახალი ელ-ფოსტის მისამართი ცვლილებისთვის.\n        extra: თუ თქვენ არ გამოიწვიეთ ეს ცვლილება, გთხოვთ არ მიაქციოთ ყურადღება ამ წერილს. მასტოდონის ელ-ფოსტის მისამართი არ შეიცვლება სანამ არ გადახვალთ ზემოთ მოცემულ ბმულზე.\n        subject: 'მასტოდონი: დაამოწმეთ ელ-ფოსტის მისამართი %{instance}-თვის'\n        title: დაამოწმეთ ელ-ფოსტის მისამართი\n      reset_password_instructions:\n        action: შეცვალეთ პაროლი\n        explanation: თქვენ მოითხოვეთ ახალი პაროლი თქვენი ანგარიშისთვის.\n        extra: თუ ეს თქვენ არ მოგითხოვიათ, გთხოვთ არ მიაქციოთ ყურადღება ამ წერილს. თქვენი პაროლი არ შეიცვლება, სანამ არ გადახვალთ ზემოთ მოცემულ ბმულზე.\n        subject: 'მასტოდონი: პაროლის განახლების ინსტრუქცეიბი'\n        title: პაროლის განახლება\n      unlock_instructions:\n        subject: 'მასტოდონი: ჩაკეტვის მოხსნის ინსტრუქციები'\n    omniauth_callbacks:\n      failure: 'ვერ მოხდა აუტენტიფიკაცია %{kind}-თან. მიზეზი: \"%{reason}\".'\n      success: წარმატებით შედგა აუტენტიფიკაცია %{kind} ანგარიშთან.\n    passwords:\n      no_token: ამ გვერდზე წვდომა ვერ გექნებათ თუ არ მოდიხართ პაროლის აღდგენის ელ-ფოსტის წერილიდან. თუ მოდიხართ პაროლის აღგენის წერილიდან, დაამოწმეთ რომ გადადიხართ სრულ ურლ-ზე.\n      send_instructions: თუ თქვენი ელ-ფოსტა არსებობს ჩვენს მონაცემთა ბაზაში, თქვენ მიიღებთ ელ-ფოსტაზე წერილს პაროლის განახლების ბმულით, რამდენიმე წუთში. გთხოვთ შეხედოთ თქვენი სპამის ფოლდერს თუ არ მიიღებთ ამ წერილს.\n      send_paranoid_instructions: თუ თქვენი ელ-ფოსტა არსებობს ჩვენს მონაცემთა ბაზაში, თქვენ მიიღებთ ელ-ფოსტაზე წერილს პაროლის განახლების ბმულით, რამდენიმე წუთში. გთხოვთ შეხედოთ თქვენი სპამის ფოლდერს თუ არ მიიღებთ ამ წერილს.\n      updated: თქვენი პაროლი წარმატებით შეიცვალა. ახლა შესული ხართ.\n      updated_not_active: თქვენი პაროლი წარმატებით შეიცვალა.\n    registrations:\n      destroyed: ნახვამდის! თქვენი ანგარიში წარმატებით გაუქმდა. იმედი გვაქვს ისევ შევხვდებით.\n      signed_up: გამარჯობა! თქვენ წარმატებით დარეგისტრირდით.\n      signed_up_but_inactive: თქვენ წარმატებით დარეგისტრირდით. თუმცა, ავტორიზაცია ვერ შედგა, თქვენი ანგარიში ჯერ არაა გააქტიურებული.\n      signed_up_but_locked: თქვენ წარმატებით დარეგისტრირდით. თუმცა, აცტორიზაცია ვერ შედგა, თქვენი ანგარიში ჩაკეტილია.\n      signed_up_but_unconfirmed: წერილი დამოწმების ბმულით თქვენს ელ-ფოსტაზე გამოგზავნილია. გთხოვთ გაჰყევით ბმულს, რათა გაააქტიუროთ ანგარიში. გთხოვთ შეხედოთ თქვენი სპამის ფოლდერს თუ არ მიიღებთ ამ წერილს.\n      update_needs_confirmation: თქვენი ანგარიში წარმატებით განახლდა, მაგრამ გვესაჭიროება თქვენი ელ-ფოსტის მისამართის დამოწმება. შეამოწმეთ ელ-ფოსტა და დასამოწმებლად გადადით მიღებულ ბმულზე. გთხოვთ შეხედოთ თქვენი სპამის ფოლდერს თუ არ მიიღებთ ამ წერილს.\n      updated: თქვენი ანგარიში წარმატებით განახლდა.\n    sessions:\n      already_signed_out: წარმატებით გახვედით.\n      signed_in: წარმატებით შეხვედით.\n      signed_out: წარმატებით გახვედით.\n    unlocks:\n      send_instructions: წერილს, ინსტრუქციებით თუ როგორ მოხსნათ ჩაკეტვა თქვენს ანგარიშს, მიიღებთ რამდენიმე წუთში. გთხოვთ შეხედოთ თქვენი სპამის ფოლდერს თუ არ მიიღებთ ამ წერილს.\n      send_paranoid_instructions: თუ თქვენი ელ-ფოსტა არსებობს ჩვენს მონაცემთა ბაზაში, თქვენ მიიღებთ ელ-ფოსტაზე წერილს ჩაკეტვის მოხნის ინსტრუქციებით. გთხოვთ შეხედოთ თქვენი სპამის ფოლდერს თუ არ მიიღებთ ამ წერილს.\n      unlocked: თქვენს ანგარიშს ჩაკეტვა წარმატებით მოეხსნა. გაგრძელებისთვის, გთხოვთ გაიაროთ ავტორიზაცია.\n  errors:\n    messages:\n      already_confirmed: უკვე დამოწმდა, გთხოვთ სცადოთ ავტორიზაციის გავლა\n      confirmation_period_expired: საჭიროებს დამოწმებას პერიოდში %{period}, გთხოვთ მოითხოვოთ ახლიდან\n      expired: გაუვიდა ვადა, გთხოვთ მოითხოვოთ ახალი\n      not_found: ვერ იქნა ნაპოვნი\n      not_locked: არ ჩაკეტილა\n      not_saved:\n        one: \"%{resource} ვერ დამახსოვრდა ერთი შეცდომის გამო:\"\n        other: \"%{resource} ვერ დამახსოვრდა %{count} შეცდომის გამო:\"\n"
  },
  {
    "path": "config/locales/devise.kk.yml",
    "content": "---\nkk:\n  devise:\n    confirmations:\n      confirmed: Сіздің email адресіңіз сәтті құпталды.\n      send_instructions: Email адресіңізге бірнеше минут ішінде қалай растау керегі туралы нұсқау бар хат келеді. Бұл хат егер келмесе, спам құтысын тексеріңіз.\n      send_paranoid_instructions: Email адресіңіз біздің дерекқорымызда болса, бірнеше минут ішінде растау туралы нұсқау бар хат аласыз. Бұл хатты алмасаңыз, спам құтысын тексеріңіз.\n    failure:\n      already_authenticated: Сіз кіріп тұрсыз.\n      inactive: Аккаунтыңыз әлі құпталмаған.\n      invalid: Қате %{authentication_keys} немесе құпиясөз.\n      last_attempt: Аккаунтыңыз құлыпталғанға дейін тағы бір әрекет жасаңыз.\n      locked: Аккаунтыңыз құлыпталған.\n      not_found_in_database: Қате %{authentication_keys} немесе құпиясөз.\n      timeout: Сессияңыз аяқталды. Қайтадан кіріңіз жалғастыру үшін.\n      unauthenticated: Жалғастыру үшін тіркеліңіз немесе логиніңізбен кіріңіз.\n      unconfirmed: Жалғастыру үшін email адресіңізді құптауыңыз керек.\n    mailer:\n      confirmation_instructions:\n        action: Email адресіңізді растаңыз\n        action_with_app: Растау және оралу - %{app}\n        explanation: Сіз %{host} сайтына тіркелгенсіз осы email адресімен. Активация жасауға бір адам қалды. Егер тіркелмеген болсаңыз, бұл хатты елемеңіз.\n        extra_html: Сондай-ақ <a href=\"%{terms_path}\">шарттар мен ережелерді</a> және <a href=\"%{policy_path}\">құпиялылық саясатын</a> оқыңыз.\n        subject: 'Mastodon: Растау туралы нұсқаулық %{instance}'\n        title: Email адресін растау\n      email_changed:\n        explanation: 'Сіздің email адресіңіз өзгертілейін деп жатыр:'\n        extra: Егер сіз электрондық поштаңызды өзгертпеген болсаңыз, онда біреу сіздің аккаунтыңызға қол жеткізді. Аккаунтыңыздан шыққан жағдайда дереу құпия сөзіңізді өзгертіңіз немесе сервер әкімшісіне хабарласыңыз.\n        subject: 'Mastodon: Email өзгертілді'\n        title: Жаңа email адрес\n      password_change:\n        explanation: Аккаунтыңыздағы құпиясөз өзгертілді.\n        extra: Егер сіз электрондық поштаңызды өзгертпеген болсаңыз, онда біреу сіздің аккаунтыңызға қол жеткізді. Аккаунтыңыздан шыққан жағдайда дереу құпия сөзіңізді өзгертіңіз немесе сервер әкімшісіне хабарласыңыз.\n        subject: 'Mastodon: Құпиясөз өзгертілді'\n        title: Құпиясөз өзгертілді\n      reconfirmation_instructions:\n        explanation: Email адресіңізді өзгерту үшін растаңыз.\n        extra: Егер сіз бұл өзгерісті жасамаған болсаңыз, бұл хатты елемеңіз. Mastodon тіркелгісінің электрондық пошта мекенжайы жоғарыдағы сілтемеге кірмейінше өзгермейді.\n        subject: 'Mastodon:  %{instance} үшін email растаңыз'\n        title: Еmail адресін растаңыз\n      reset_password_instructions:\n        action: Құпиясөз өзгерту\n        explanation: Аккаунтыңыз үшін жаңа құпиясөз сұраттыңыз.\n        extra: Егер сіз мұны сұрамаған болсаңыз, бұл хатты елемеңіз. Жоғарыдағы сілтемені ашып, жаңасын жасағанша құпия сөзіңіз өзгермейді.\n        subject: 'Mastodon: Құпиясөзді қалпына келтіру нұсқаулықтары'\n        title: Құпиясөзді қалпына келтіру\n      unlock_instructions:\n        subject: 'Mastodon: Құлыптан шешу нұсқаулықтары'\n    omniauth_callbacks:\n      failure: Сізді аутентификациялау мүмкін болмады %{kind} себебі \"%{reason}\".\n      success: \"%{kind} аккаунтынан сәтті аутентификация.\"\n    passwords:\n      no_token: Бұл бетке құпиясөзді қалпына келтіру электрондық поштасынан шықпай кіре алмайсыз. Құпия сөзді қалпына келтіру электрондық поштасынан шықсаңыз, берілген толық URL мекенжайын пайдаланғаныңызды тексеріңіз.\n      send_instructions: Электрондық пошта мекенжайыңыз біздің дерекқорымызда болса, бірнеше минут ішінде құпия сөзді қалпына келтіру сілтемесін аласыз. Бұл хат келмеген болса, спам құтысын тексеріңіз.\n      send_paranoid_instructions: Электрондық пошта мекенжайыңыз біздің дерекқорымызда болса, бірнеше минут ішінде құпия сөзді қалпына келтіру сілтемесін аласыз. Бұл хат келмеген болса, спам құтысын тексеріңіз.\n      updated: Құпиясөзіңіз сәтті өзгертілді. Сіз енді кірдіңіз.\n      updated_not_active: Құпиясөзіңіз сәтті өзгертілді.\n    registrations:\n      destroyed: Сау! Аккаунтыңыз тоқтатылды. Қайтадан ораласыз деп сенеміз.\n      signed_up: Қош келдіңіз! Тіркелу сәтті өтті.\n      signed_up_but_inactive: Тіркелу сәтті аяқталды. Дегенмен, аккаунтыңыз әлі белсендірілмегендіктен, сізге сайтқа кіру мүмкін болмайды.\n      signed_up_but_locked: Тіркелу сәтті аяқталды. Дегенмен, аккаунтыңыз құлыпталғандықтан, сізге сайтқа кіру мүмкін болмайды.\n      signed_up_but_unconfirmed: Растау сілтемесі бар хат электрондық поштаыңызға жіберілді. Аккаунтыңызды белсендіру үшін сілтеме бойынша өтіңіз. Бұл хат келмесе, спам құтысын тексеріңіз.\n      update_needs_confirmation: Аккаунтыыызды сәтті жаңарттыңыз, бірақ жаңа электрондық поштаны тексеру қажет. Электрондық поштаңызды тексеріп, жаңа электрондық пошта мекенжайыңызды растаңыз. Бұл электрондық поштаны алмасаңыз, спам қалтаңызды тексеріңіз.\n      updated: Аккаунтыңыз сәтті жаңартылды.\n    sessions:\n      already_signed_out: Сәтті шықтыңыз.\n      signed_in: Сәтті кірдіңіз.\n      signed_out: Шығу сәтті орындалды.\n    unlocks:\n      send_instructions: Бірнеше минуттан кейін аккаунтыңыздың құлпын ашу туралы нұсқаулар бар хат аласыз. Бұл хаттыы алмасаңыз, спам құтысын тексеріңіз.\n      send_paranoid_instructions: Егер тіркелгіңіз бар болса, оны бірнеше минуттан кейін құлыптан босату туралы нұсқаулар бар хат аласыз. Бұл хат келмесе, спам құтысын тексеріңіз.\n      unlocked: Аккаунтыңыз сәтті шешілді құлыптан. Жалғастыру үшін кіріңіз.\n  errors:\n    messages:\n      already_confirmed: әлдеқашан расталған, логинмен кіре беріңіз\n      confirmation_period_expired: \"%{period} ішінде расталуы қажет, жаңасын сұратыңыз\"\n      expired: уақыты өтіп кетті, жаңасын сұратыңыз\n      not_found: табылмады\n      not_locked: құлыпталмады\n      not_saved:\n        one: '1 тыйым салынған қате %{resource} сақталды:'\n        other: \"%{count} тыйым салынған қате %{resource} сақталды:\"\n"
  },
  {
    "path": "config/locales/devise.ko.yml",
    "content": "---\nko:\n  devise:\n    confirmations:\n      confirmed: 이메일이 성공적으로 확인 되었습니다.\n      send_instructions: 몇 분 이내로 확인 이메일이 발송 됩니다. 이메일을 받지 못 한 경우, 스팸 폴더를 확인하세요.\n      send_paranoid_instructions: 당신의 이메일이 우리의 DB에 있을 경우 몇 분 이내로 확인 메일이 발송 됩니다. 이메일을 받지 못 한 경우, 스팸 폴더를 확인하세요.\n    failure:\n      already_authenticated: 이미 로그인 된 상태입니다.\n      inactive: 계정이 활성화 되지 않았습니다.\n      invalid: 올바르지 않은 %{authentication_keys} 혹은 패스워드입니다.\n      last_attempt: 계정이 잠기기까지 한 번의 시도가 남았습니다.\n      locked: 계정이 잠겼습니다.\n      not_found_in_database: 올바르지 않은 %{authentication_keys} 혹은 패스워드입니다.\n      pending: 계정이 아직 심사 중입니다.\n      timeout: 세션이 만료 되었습니다. 다시 로그인 해 주세요.\n      unauthenticated: 계속 하려면 로그인을 해야 합니다.\n      unconfirmed: 계속 하려면 이메일을 확인 받아야 합니다.\n    mailer:\n      confirmation_instructions:\n        action: 이메일 확인\n        action_with_app: 확인하고 %{app}으로 돌아가기\n        explanation: 당신은 %{host}에서 이 이메일로 가입하셨습니다. 클릭만 하시면 계정이 활성화 됩니다. 만약 당신이 가입한 게 아니라면 이 메일을 무시해 주세요.\n        explanation_when_pending: 당신은 %{host}에 가입 요청을 하셨습니다. 이 이메일이 확인 되면 우리가 가입 요청을 리뷰하고 승인할 수 있습니다. 그 전까지는 로그인을 할 수 없습니다. 당신의 가입 요청이 거부 될 경우 당신에 대한 정보는 모두 삭제 되며 따로 요청 할 필요는 없습니다. 만약 당신이 가입 요청을 한 게 아니라면 이 메일을 무시해 주세요.\n        extra_html: <a href=\"%{terms_path}\">서버의 룰</a>과 <a href=\"%{policy_path}\">이용 약관</a>도 확인해 주세요.\n        subject: '마스토돈: %{instance}에 대한 확인 메일'\n        title: 이메일 주소 확인\n      email_changed:\n        explanation: '당신의 계정에 대한 이메일이 다음과 같이 바뀌려고 합니다:'\n        extra: 만약 당신이 메일을 바꾸지 않았다면 누군가가 당신의 계정에 대한 접근 권한을 얻은 것입니다. 즉시 패스워드를 바꾼 후, 계정이 잠겼다면 서버의 관리자에게 연락 하세요.\n        subject: '마스토돈: 이메일이 변경 되었습니다'\n        title: 새 이메일 주소\n      password_change:\n        explanation: 당신의 계정 패스워드가 변경되었습니다.\n        extra: 만약 패스워드 변경을 하지 않았다면 누군가가 당신의 계정에 대한 접근 권한을 얻은 것입니다. 즉시 패스워드를 바꾼 후, 계정이 잠겼다면 서버의 관리자에게 연락 하세요.\n        subject: '마스토돈: 패스워드가 변경 되었습니다'\n        title: 패스워드가 변경 되었습니다\n      reconfirmation_instructions:\n        explanation: 이메일 주소를 바꾸려면 새 이메일 주소를 확인해야 합니다.\n        extra: 당신이 시도한 것이 아니라면 이 메일을 무시해 주세요. 위 링크를 클릭하지 않으면 이메일 변경은 일어나지 않습니다.\n        subject: '마스토돈: %{instance}에 대한 이메일 확인'\n        title: 이메일 주소 확인\n      reset_password_instructions:\n        action: 패스워드 변경\n        explanation: 계정에 대한 패스워드 변경을 요청하였습니다.\n        extra: 만약 당신이 시도한 것이 아니라면 이 메일을 무시해 주세요. 위 링크를 클릭해 패스워드를 새로 설정하기 전까지는 패스워드가 바뀌지 않습니다.\n        subject: '마스토돈: 패스워드 재설정 방법'\n        title: 패스워드 재설정\n      unlock_instructions:\n        subject: '마스토돈: 잠금 해제 방법'\n    omniauth_callbacks:\n      failure: '\"%{reason}\" 때문에 당신을 %{kind}에서 인증할 수 없습니다.'\n      success: 성공적으로 %{kind} 계정을 인증 했습니다.\n    passwords:\n      no_token: 패스워드 재설정 이메일을 거치지 않고는 여기에 올 수 없습니다. 만약 패스워드 재설정 메일에서 온 것이라면 URL이 맞는지 확인해 주세요.\n      send_instructions: 당신의 이메일 주소가 우리의 DB에 있아면 패스워드 복구 링크가 몇 분 이내에 메일로 발송 됩니다. 만약 메일을 받지 못 하신 경우 스팸 폴더를 확인해 주세요.\n      send_paranoid_instructions: 당신의 이메일 주소가 우리의 DB에 있아면 패스워드 복구 링크가 몇 분 이내에 메일로 발송 됩니다. 만약 메일을 받지 못 하신 경우 스팸 폴더를 확인해 주세요.\n      updated: 패스워드가 재설정 되었습니다. 로그인 되었습니다.\n      updated_not_active: 패스워드가 성공적으로 변경 되었습니다.\n    registrations:\n      destroyed: 안녕히 가세요! 계정이 성공적으로 제거되었습니다. 다시 만나기를 희망합니다.\n      signed_up: 안녕하세요! 성공적으로 가입했습니다.\n      signed_up_but_inactive: 성공적으로 가입 했습니다. 그러나, 계정이 활성화 되지 않았기 때문에 아직 로그인 할 수 없습니다.\n      signed_up_but_locked: 성공적으로 가입 했습니다. 그러나, 계정이 잠겨있기 때문에 아직 로그인 할 수 없습니다.\n      signed_up_but_pending: 확인 링크를 포함한 메일이 발송 되었습니다. 링크를 클릭한 이후, 우리가 당신의 신청양식을 검토합니다. 승인이 되면 알림을 발송합니다.\n      signed_up_but_unconfirmed: 확인 링크를 포함한 메일이 발송 되었습니다. 링크를 클릭해 계정을 활성화 하세요. 메일을 받지 못 하신 경우 스팸 폴더를 확인해 주세요.\n      update_needs_confirmation: 계정 정보를 업데이트 했습니다. 하지만 새 이메일 주소에 대한 확인이 필요합니다. 이메일을 확인 한 후 링크를 통해 새 이메일을 확인 하세요. 메일을 받지 못 하신 경우 스팸 폴더를 확인해 주세요.\n      updated: 계정 정보가 성공적으로 업데이트 되었습니다.\n    sessions:\n      already_signed_out: 로그아웃 되었습니다.\n      signed_in: 로그인 되었습니다.\n      signed_out: 로그아웃 되었습니다.\n    unlocks:\n      send_instructions: 몇 분 이내로 계정 잠금 해제에 대한 안내 메일이 발송 됩니다. 메일을 받지 못 하신 경우 스팸 폴더를 확인해 주세요.\n      send_paranoid_instructions: 계정이 존재한다면 몇 분 이내로 계정 잠금 해제에 대한 안내 메일이 발송 됩니다. 메일을 받지 못 하신 경우 스팸 폴더를 확인해 주세요.\n      unlocked: 계정이 성공적으로 잠금 해제 되었습니다. 계속 하려면 로그인 하세요.\n  errors:\n    messages:\n      already_confirmed: 이미 확인 되었습니다, 로그인 하세요\n      confirmation_period_expired: \"%{period} 안에 확인을 해야 합니다, 새로 요청하세요\"\n      expired: 만료되었습니다, 새로 요청하세요\n      not_found: 찾을 수 없습니다\n      not_locked: 잠기지 않았습니다\n      not_saved:\n        other: \"%{count}개의 에러로 인해 %{resource}가 저장 될 수 없습니다:\"\n"
  },
  {
    "path": "config/locales/devise.lt.yml",
    "content": "lt:\n"
  },
  {
    "path": "config/locales/devise.lv.yml",
    "content": "lv:\n"
  },
  {
    "path": "config/locales/devise.ms.yml",
    "content": "ms:\n"
  },
  {
    "path": "config/locales/devise.nl.yml",
    "content": "---\nnl:\n  devise:\n    confirmations:\n      confirmed: Jouw account is bevestigd.\n      send_instructions: Je ontvangt via e-mail instructies hoe je jouw account kunt bevestigen. Kijk tussen je spam wanneer niks werd ontvangen.\n      send_paranoid_instructions: Als jouw e-mailadres in de database staat, ontvang je via e-mail instructies hoe je jouw account kunt bevestigen. Kijk tussen je spam wanneer niks werd ontvangen.\n    failure:\n      already_authenticated: Je bent al ingelogd.\n      inactive: Jouw account is nog niet geactiveerd.\n      invalid: \"%{authentication_keys} of wachtwoord ongeldig.\"\n      last_attempt: Je hebt nog één poging over voordat jouw account wordt opgeschort.\n      locked: Jouw account is opgeschort.\n      not_found_in_database: \"%{authentication_keys} of wachtwoord ongeldig.\"\n      pending: Jouw account moet nog steeds worden beoordeeld.\n      timeout: Jouw sessie is verlopen, log opnieuw in.\n      unauthenticated: Je dient in te loggen of te registreren.\n      unconfirmed: Je dient eerst jouw account te bevestigen.\n    mailer:\n      confirmation_instructions:\n        action: E-mailadres verifiëren\n        action_with_app: Bevestigen en naar %{app} teruggaan\n        explanation: Je hebt een account op %{host} aangemaakt en met één klik kun je deze activeren. Wanneer jij dit account niet hebt aangemaakt, mag je deze e-mail negeren.\n        explanation_when_pending: Je vroeg met dit e-mailadres een uitnodiging aan voor %{host}. Nadat je jouw e-mailadres hebt bevestigd, beoordelen we jouw aanvraag. Je kunt tot dan nog niet inloggen. Wanneer jouw aanvraag wordt afgekeurd, worden jouw gegevens verwijderd en hoef je daarna verder niets meer te doen. Wanneer jij dit niet was, kun je deze e-mail negeren.\n        extra_html: Bekijk ook de <a href=\"%{terms_path}\">regels van de Mastodonserver</a> en <a href=\"%{policy_path}\">onze gebruiksvoorwaarden</a>.\n        subject: 'Mastodon: E-mail bevestigen voor %{instance}'\n        title: E-mailadres verifiëren\n      email_changed:\n        explanation: 'Het e-mailadres van jouw account is gewijzigd naar:'\n        extra: Wanneer jij jouw e-mailadres niet hebt gewijzigd, heeft iemand zich waarschijnlijk toegang tot jouw account verschaft. Verander onmiddellijk jouw wachtwoord of neem contact op met de beheerder van jouw Mastodonserver wanneer je niet meer kunt inloggen.\n        subject: 'Mastodon: E-mailadres is veranderd'\n        title: Nieuw e-mailadres\n      password_change:\n        explanation: Het wachtwoord van dit account is gewijzigd.\n        extra: Wanneer jij jouw wachtwoord niet hebt gewijzigd, heeft iemand zich waarschijnlijk toegang tot jouw account verschaft. Verander onmiddellijk jouw wachtwoord of neem contact op met de beheerder van jouw Mastodonserver wanneer je niet meer kunt inloggen.\n        subject: 'Mastodon: Wachtwoord veranderd'\n        title: Wachtwoord gewijzigd\n      reconfirmation_instructions:\n        explanation: Bevestig jouw nieuw e-mailadres om deze te wijzigen.\n        extra: Wanneer jij deze wijziging niet hebt uitgevoerd, mag je deze e-mail negeren. Het e-mailadres van jouw Mastodonaccount wordt pas daadwerkelijk gewijzigd totdat je de link hierboven aanklikt.\n        subject: 'Mastodon: Bevestig het e-mailadres voor %{instance}'\n        title: E-mailadres verifiëren\n      reset_password_instructions:\n        action: Wachtwoord wijzigen\n        explanation: Jij hebt een nieuw wachtwoord voor jouw account aangevraagd.\n        extra: Wanneer jij dit niet hebt aangevraagd, mag je deze e-mail negeren. Jouw wachtwoord wordt pas gewijzigd nadat je de link hierboven hebt aangeklikt en een nieuw wachtwoord aanmaakt.\n        subject: 'Mastodon: Wachtwoord opnieuw instellen'\n        title: Wachtwoord opnieuw instellen\n      unlock_instructions:\n        subject: 'Mastodon: Instructies om opschorten account ongedaan te maken'\n    omniauth_callbacks:\n      failure: Kon je niet inloggen met jouw %{kind} account, omdat \"%{reason}\".\n      success: Succesvol met jouw %{kind} account ingelogd.\n    passwords:\n      no_token: Je kunt deze pagina niet benaderen zonder dat je een e-mail om je wachtwoord opnieuw in te stellen hebt ontvangen.\n      send_instructions: Je ontvangt via e-mail instructies hoe je jouw wachtwoord opnieuw moet instellen. Kijk tussen je spam wanneer niks werd ontvangen.\n      send_paranoid_instructions: Als jouw e-mailadres in de database staat, ontvang je via e-mail instructies hoe je jouw wachtwoord opnieuw kunt instellen. Kijk tussen je spam wanneer niks werd ontvangen.\n      updated: Jouw wachtwoord is gewijzigd. Je bent nu ingelogd.\n      updated_not_active: Jouw wachtwoord is gewijzigd.\n    registrations:\n      destroyed: Jouw account is succesvol verwijderd. Wellicht tot ziens.\n      signed_up: Je bent geregistreerd.\n      signed_up_but_inactive: Je bent geregistreerd. Je kon alleen niet automatisch ingelogd worden omdat jouw account nog niet geactiveerd is.\n      signed_up_but_locked: Je bent ingeschreven. Je kon alleen niet automatisch ingelogd worden omdat jouw account is opgeschort.\n      signed_up_but_pending: Er is een bericht met een bevestigingslink naar jouw e-mailadres verzonden. Nadat je op deze link hebt geklikt nemen we jouw aanvraag in behandeling. Je wordt op de hoogte gesteld wanneer deze wordt goedgekeurd.\n      signed_up_but_unconfirmed: Je ontvangt via e-mail instructies hoe je jouw account kunt activeren. Kijk tussen je spam wanneer niks werd ontvangen.\n      update_needs_confirmation: Je hebt je e-mailadres succesvol gewijzigd, maar we moeten je nieuwe mailadres nog bevestigen. Controleer jouw e-mail en klik op de link in de mail om jouw e-mailadres te bevestigen. Kijk tussen je spam wanneer niks werd ontvangen.\n      updated: Jouw accountgegevens zijn opgeslagen.\n    sessions:\n      already_signed_out: Succesvol uitgelogd.\n      signed_in: Je bent succesvol ingelogd.\n      signed_out: Je bent succesvol uitgelogd.\n    unlocks:\n      send_instructions: Je ontvangt via e-mail instructies hoe je het opschorten van jouw account ongedaan kunt maken. Kijk tussen je spam wanneer niks werd ontvangen.\n      send_paranoid_instructions: Als jouw e-mailadres in de database staat, ontvang je via e-mail instructies hoe je het opschorten van jouw account ongedaan kunt maken. Kijk tussen je spam wanneer niks werd ontvangen.\n      unlocked: Jouw account is niet meer opgeschort. Je kunt nu weer inloggen.\n  errors:\n    messages:\n      already_confirmed: is reeds bevestigd\n      confirmation_period_expired: moet worden bevestigd binnen %{period}, probeer het nog een keer\n      expired: is verlopen, vraag een nieuwe aan\n      not_found: niet gevonden\n      not_locked: is niet opgeschort\n      not_saved:\n        one: '1 fout verhinderde het opslaan van deze %{resource}:'\n        other: \"%{count} fouten verhinderden het opslaan van deze %{resource}:\"\n"
  },
  {
    "path": "config/locales/devise.no.yml",
    "content": "---\n'no':\n  devise:\n    confirmations:\n      confirmed: E-postaddressen din er blitt bekreftet.\n      send_instructions: Du vil motta en e-post med instruksjoner for bekreftelse om noen få minutter.\n      send_paranoid_instructions: Hvis din e-postaddresse finnes i vår database vil du motta en e-post med instruksjoner for bekreftelse om noen få minutter.\n    failure:\n      already_authenticated: Du er allerede innlogget.\n      inactive: Din konto er ikke blitt aktivert ennå.\n      invalid: Ugyldig %{authentication_keys} eller passord.\n      last_attempt: Du har ett forsøk igjen før kontoen din låses.\n      locked: Din konto er låst.\n      not_found_in_database: Ugyldig %{authentication_keys} eller passord.\n      timeout: Økten din løp ut på tid. Logg inn på nytt for å fortsette.\n      unauthenticated: Du må logge inn eller registrere deg før du kan fortsette.\n      unconfirmed: Du må bekrefte e-postadressen din før du kan fortsette.\n    mailer:\n      confirmation_instructions:\n        action: Bekreft e-postadresse\n        explanation: Du har laget en konto på %{host} med denne e-postadressen. Du er ett klikk unna å aktivere den. Hvis dette ikke var deg, vennligst se bort fra denne e-posten.\n        extra_html: Vennligst også sjekk ut <a href=\"%{terms_path}\">instansens regler </a> og <a href=\"%{policy_path}\">våre bruksvilkår</a>.\n        subject: 'Mastodon: Instruksjoner for å bekrefte e-postadresse %{instance}'\n        title: Bekreft e-postadresse\n      email_changed:\n        explanation: 'E-postadressen til din konto endres til:'\n        extra: Hvis du ikke endret din e-postadresse, er det sannsynlig at noen har fått tilgang til din konto. Vennligst endre ditt passord umiddelbart eller kontakt instansens administrator dersom du er utestengt fra kontoen din.\n        subject: 'Mastadon: E-postadresse endret'\n        title: Ny e-postadresse\n      password_change:\n        explanation: Passordet til din konto har blitt endret.\n        extra: Hvis du ikke endret ditt passord, er det sannsynlig at noen har fått tilgang til din konto. Vennligst endre ditt passord umiddelbart eller kontakt instansens administrator dersom du er utestengt fra kontoen din.\n        subject: 'Mastodon: Passord endret'\n        title: Passord endret\n      reconfirmation_instructions:\n        explanation: Din nye e-postadresse må bekreftes for å bli endret.\n        extra: Se bort fra denne e-posten dersom du ikke gjorde denne endringen. E-postadressen for Mastadon-kontoen blir ikke endret før du trykker på lenken over.\n        subject: 'Mastodon: Bekreft e-postadresse for %{instance}'\n        title: Bekreft e-postadresse\n      reset_password_instructions:\n        action: Endre passord\n        explanation: Du ba om et nytt passord for din konto.\n        extra: Se bort fra denne e-posten dersom du ikke ba om dette. Ditt passord blir ikke endret før du trykker på lenken over og lager et nytt.\n        subject: 'Mastodon: Hvordan nullstille passord'\n        title: Nullstill passord\n      unlock_instructions:\n        subject: 'Mastodon: Instruksjoner for å gjenåpne konto'\n    omniauth_callbacks:\n      failure: Kunne ikke autentisere deg fra %{kind} fordi \"%{reason}\".\n      success: Vellykket autentisering fra %{kind}.\n    passwords:\n      no_token: Du har ingen tilgang til denne siden hvis ikke klikket på en e-post om nullstilling av passord. Hvis du kommer fra en sådan bør du dobbelsjekke at du limte inn hele URLen.\n      send_instructions: Du vil motta en e-post med instruksjoner om nullstilling av passord om noen få minutter.\n      send_paranoid_instructions: Hvis e-postadressen din finnes i databasen vår vil du motta en e-post med instruksjoner om nullstilling av passord om noen få minutter.\n      updated: Passordet ditt er endret. Du er nå logget inn.\n      updated_not_active: Passordet ditt er endret.\n    registrations:\n      destroyed: Adjø! Kontoen din er slettet. På gjensyn.\n      signed_up: Velkommen! Registreringen var vellykket.\n      signed_up_but_inactive: Registreringen var vellykket. Vi kunne dessverre ikke logge deg inn fordi kontoen din ennå ikke har blitt aktivert.\n      signed_up_but_locked: Registreringen var vellykket. Vi kunne dessverre ikke logge deg inn fordi kontoen din har blitt låst.\n      signed_up_but_unconfirmed: En e-post med en bekreftelseslenke har blitt sendt til din innboks. Klikk på lenken i e-posten for å aktivere kontoen din.\n      update_needs_confirmation: Du har oppdatert kontoen din, men vi må bekrefte din nye e-postadresse. Sjekk e-posten din og følg bekreftelseslenken for å bekrefte din nye e-postadresse.\n      updated: Kontoen din ble oppdatert.\n    sessions:\n      already_signed_out: Logget ut.\n      signed_in: Logget inn.\n      signed_out: Logget ut.\n    unlocks:\n      send_instructions: Du vil motta en e-post med instruksjoner for å åpne kontoen din om noen få minutter.\n      send_paranoid_instructions: Hvis kontoen din eksisterer vil du motta en e-post med instruksjoner for å åpne kontoen din om noen få minutter.\n      unlocked: Kontoen din ble åpnet uten problemer. Logg på for å fortsette.\n  errors:\n    messages:\n      already_confirmed: har allerede blitt bekreftet, prøv å logge på istedet\n      confirmation_period_expired: må bekreftes innen %{period}. Spør om en ny e-post for bekreftelse istedet\n      expired: har utløpt, spør om en ny en istedet\n      not_found: ikke funnet\n      not_locked: var ikke låst\n      not_saved:\n        one: '1 feil hindret denne %{resource} i å bli lagret:'\n        other: \"%{count} feil hindret denne %{resource} i å bli lagret:\"\n"
  },
  {
    "path": "config/locales/devise.oc.yml",
    "content": "---\noc:\n  devise:\n    confirmations:\n      confirmed: Vòstra adreça de corrièl es ben estada validada.\n      send_instructions: Recebretz un corrièl per vos indicar çò que cal far per confirmar vòstra adreça de corrièl dins una estona. Mercés de verificar tanben vòstre dorsièr de corrièls indesirables.\n      send_paranoid_instructions: Se vòstra adreça existís dins nòstra basa de donadas, recebretz un corrièl per vos indicar çò que cal far per confirmar vòstra adreça de corrièl dins una estona. Mercés de verificar tanben vòstre dorsièr de corrièls indesirables.\n    failure:\n      already_authenticated: Sètz ja connectat.\n      inactive: Vòstre compte es pas encara activat.\n      invalid: \"%{authentication_keys} invalida.\"\n      last_attempt: Vos demòra un ensag abans que vòstre compte siasque blocat.\n      locked: Vòstre compte es blocat.\n      not_found_in_database: \"%{authentication_keys} invalida.\"\n      pending: Vòstre compte es encara en aprobacion.\n      timeout: Vòstra session a expirat. Mercés de vos tornar connectar per contunhar.\n      unauthenticated: Vos cal vos connectar o marcar abans de contunhar.\n      unconfirmed: Vos cal confirmar vòstra adreça de corrièl abans de contunhar.\n    mailer:\n      confirmation_instructions:\n        action: Verificar l’adreça de corrièl\n        action_with_app: Confirmar e tornar a %{app}\n        explanation: Venètz de crear un compte sus %{host} amb aquesta adreça de corrièl. Vos manca pas qu’un clic per l’activar. S’èra pas vosautre mercés de far pas cas a aqueste messatge.\n        explanation_when_pending: Avètz demandat una invitacion a %{host} amb aquesta adreça electronica. Un còp que confirmetz vòstra adreça electronica revisarem vòstra demanda. Se pòt iniciar la session fins alara. Se vòstra demanda es pas acceptada vòstras donadas seràn suprimidas, de manièra que caldrà pas cap d’autra accion. S’èra pas vos qu’avètz fach la demanda, se vos plai ignoratz aqueste corrièl.\n        extra_html: Pensatz tanben de gaitar <a href=\"%{terms_path}\">las règlas del servidor</a> e <a href=\"%{policy_path}\">nòstres tèrmes e condicions d’utilizacion</a>.\n        subject: 'Mastodon : consignas de confirmacion per %{instance}'\n        title: Verificatz l’adreça de corrièl\n      email_changed:\n        explanation: 'L’adreça per aqueste compte es ara :'\n        extra: S’avètz pas demandat aqueste cambiament d’adreça, poiriá arribar que qualqu’un mai aguèsse agut accès a vòstre compte. Mercés de cambiar sulpic vòstre senhal o de contactar vòstre administrator de servidor se l’accès a vòstre compte vos es barrat.\n        subject: 'Mastodon : corrièl cambiat'\n        title: Nòva adreça de corrièl\n      password_change:\n        explanation: Lo senhal per vòstre compte a cambiat.\n        extra: S’avètz pas demandat aqueste cambiament de senhal, poiriá arribar que qualqu’un mai aguèsse agut accès a vòstre compte. Mercés de cambiar sulpic vòstre senhal o de contactar vòstre administrator de servidor se l’accès a vòstre compte vos es barrat.\n        subject: Mastodon : senhal cambiat\n        title: Senhal cambiat\n      reconfirmation_instructions:\n        explanation: Confirmar la nòva adreça per cambiar lo corrièl.\n        extra: S’avètz pas res demandat, fasquètz pas cas a aqueste corrièl. Vòstre corrièl per Mastodon cambiarà pas se clicatz pas lo ligam dessús.\n        subject: 'Mastodon : confirmatz l’adreça per %{instance}'\n        title: Verificatz l’adreça de corrièl\n      reset_password_instructions:\n        action: Cambiament de senhal\n        explanation: Avètz demandat un nòu senhal per vòstre compte.\n        extra: S’avètz pas res demandat, fasquètz pas cas a aqueste corrièl. Vòstre senhal cambiarà pas se clicatz pas lo ligam e que ne causissètz pas un novèl.\n        subject: Mastodon : consignas per reïnicializar lo senhal\n        title: Reïnicializacion del senhal\n      unlock_instructions:\n        subject: Mastodon : consignas de desblocatge\n    omniauth_callbacks:\n      failure: Fracàs al moment de vos autentificar de %{kind} perque \"%{reason}\".\n      success: Sètz ben autentificat dempuèi lo compte %{kind}.\n    passwords:\n      no_token: Podètz pas accedir a aquesta pagina sens venir d’un corriel de reïnicializacion de senhal. S’es lo cas, mercés de verificar qu’avètz ben utilizat l’URL donada de manièra complèta.\n      send_instructions: Recebretz un corrièl amb las consignas per reïnicializar vòstre senhal dins una estona. Mercés de verificar tanben vòstre dorsièr de corrièls indesirables.\n      send_paranoid_instructions: Se vòstra adreça de corrièl existís dins nòstra basa de donadas, recebretz un ligam per reïnicializar vòstre senhal dins una estona. Mercés de verificar tanben vòstre dorsièr de corrièls indesirables.\n      updated: Vòstre senhal es ben estat cambiat. Sètz ara connectat.\n      updated_not_active: Vòstre senhal es ben estat cambiat.\n    registrations:\n      destroyed: Adieu-siatz ! Vòstra inscripcion es estada anullada amb succès. Esperem vos tornar veire lèu.\n      signed_up: La benvenguda ! Sètz ben marcat al malhum.\n      signed_up_but_inactive: Sètz ben marcat. Pasmens, avèm pas pogut vos connectar perque vòstre compte es pas encara validat.\n      signed_up_but_locked: Sètz ben marcat. Pasmens, avèm pas pogut vos connectar perque vòstre compte es pas encara blocat.\n      signed_up_but_pending: Un messatge amb un ligam de confirmacion es estat enviat a vòstra adreça electronica. Aprèp aver clicat lo ligam, revisarem vòstra demanda. Seretz avisat se’s aprovada.\n      signed_up_but_unconfirmed: Un messatge amb un ligam de confirmacion es estat enviat a vòstra adreça de corrièl. Clicatz sul ligam per activar vòstre compte. Mercés de verificar tanben vòstre dorsièr de corrièls indesirables.\n      update_needs_confirmation: Avètz ben mes a jorn vòstre compte, mai nos cal verificar vòstra nòva adreça de corrièl. Mercés de verificar vòstres messatges e clicar sul ligam de confirmacion per confirmar vòstra nòva adreça de corrièl. Mercés de verificar tanben vòstre dorsièr de corrièls indesirables.\n      updated: Vòstre compte es estat mes a jorn amb succès.\n    sessions:\n      already_signed_out: Desconnectat amb succès.\n      signed_in: Connectat amb succès.\n      signed_out: Desconnectat amb succès.\n    unlocks:\n      send_instructions: Recebretz un corrièl amb las consignas per o desblocar dins una estona. Mercés de verificar tanben vòstre dorsièr de corrièls indesirables.\n      send_paranoid_instructions: Se vòstre compte existís recebretz un corrièl amb las consignas per o desblocar dins una estona. Mercés de verificar tanben vòstre dorsièr de corrièls indesirables.\n      unlocked: Vòstre compte es estat desblocat amb succès. Mercés de vos connectar per contunhar.\n  errors:\n    messages:\n      already_confirmed: es ja estat confirmat, mercés d’ensejar de vos connectar\n      confirmation_period_expired: a d’èsser confirmat dins %{period}, mercés de tornar demandar\n      expired: a expirat, mercés de demandar un nòu\n      not_found: pas trobat\n      not_locked: èra pas blocat\n      not_saved:\n        one: '1 error defend aquesta %{resource} d’èsser salvagardada :'\n        other: \"%{count} errors defendon aquesta %{resource} d’èsser salvagardadas :\"\n"
  },
  {
    "path": "config/locales/devise.pl.yml",
    "content": "---\npl:\n  devise:\n    confirmations:\n      confirmed: Twój adres e-mail został poprawnie zweryfikowany.\n      send_instructions: W ciągu kilku minut otrzymasz wiadomosć e-mail z instrukcją jak potwierdzić Twój adres e-mail. Jeżeli nie otrzymano wiadomości, sprawdź folder ze spamem.\n      send_paranoid_instructions: Jeśli Twój adres e-mail już istnieje w naszej bazie danych, w ciągu kilku minut otrzymasz wiadomość e-mail z instrukcją jak potwierdzić Twój adres e-mail. Jeżeli nie otrzymano wiadomości, sprawdź folder ze spamem.\n    failure:\n      already_authenticated: Jesteś już zalogowany(-a).\n      inactive: Twoje konto nie zostało jeszcze aktywowane.\n      invalid: Nieprawidłowy %{authentication_keys} lub hasło.\n      last_attempt: Masz jeszcze jedną próbę; Twoje konto zostanie zablokowane jeśli się nie powiedzie.\n      locked: Twoje konto zostało zablokowane.\n      not_found_in_database: Nieprawidłowy %{authentication_keys} lub hasło.\n      pending: Twoje konto oczekuje na przegląd.\n      timeout: Twoja sesja wygasła. Zaloguj się ponownie, aby kontynuować..\n      unauthenticated: Zapisz się lub zaloguj, aby kontynuować.\n      unconfirmed: Zweryfikuj adres e-mail, aby kontynuować.\n    mailer:\n      confirmation_instructions:\n        action: Zweryfikuj adres e-mail\n        action_with_app: Potwierdź i wróć do %{app}\n        explanation: Utworzyłeś(-aś) konto na %{host} podając ten adres e-mail. Jedno kliknięcie dzieli Cię od aktywacji tego konta. Jeżeli to nie Ty, zignoruj ten e-mail.\n        explanation_when_pending: Poprosiłeś(-aś) o zaproszenie na %{host} używajac tego adresu e-mail. Kiedy potwierdzisz swój adres e-mail, przejrzymy Twoje podanie. Do tego czasu nie możesz się zalogować. Jeżeli Twoje podanie zostanie odrzucone, Twoje dane zostaną usunięte i nie będziesz musiał(-a) podejmować żadnych dodatkowych działań. Jeżeli to nie Ty, zignoruj ten e-mail.\n        extra_html: Przeczytaj też <a href=\"%{terms_path}\">regulamin serwera</a> i <a href=\"%{policy_path}\">nasze zasady użytkowania</a>.\n        subject: 'Mastodon: Instrukcje weryfikacji adresu e-mail na %{instance}'\n        title: Zweryfikuj adres e-mail\n      email_changed:\n        explanation: 'Adres e-mail dla Twojego konta zostanie zmieniony na:'\n        extra: Jeżeli nie próbowałeś(-aś) zmienić adresu e-mail, prawdopodobnie ktoś uzyskał dostęp do Twojego konta. Zmień natychmiastowo hasło lub skontaktuj się z administratorem serwera, jeżeli nie masz dostępu do konta.\n        subject: 'Mastodon: Zmieniono adres e-mail'\n        title: Nowy adres e-mail\n      password_change:\n        explanation: Hasło do Twojego konta zostało zmienione.\n        extra: Jeżeli nie zmieniałeś(-aś) hasła, prawdopodobnie ktoś uzyskał dostęp do Twojego konta. Zmień hasło natychmiastowo lub skontaktuj się z administratorem serwera, jeżeli nie masz dostępu do konta.\n        subject: 'Mastodon: Zmieniono hasło'\n        title: Zmieniono hasło\n      reconfirmation_instructions:\n        explanation: Potwierdź nowy adres aby zmienić e-mail.\n        extra: Jeżeli nie próbowałeś(-aś) zmienić e-maila, zignoruj tą wiadomość. Adres e-mail przypisany do konta Mastodona nie ulegnie zmianie, jeżeli nie użyjesz powyższego odnośniku.\n        subject: 'Mastodon: Potwierdź adres e-mail na %{instance}'\n        title: Zweryfikuj adres e-mail\n      reset_password_instructions:\n        action: Zmień hasło\n        explanation: Próbowałeś(-aś) uzyskać nowe hasło do swojego konta.\n        extra: Jeżeli to nie Ty, zignoruj tą wiadomość. Twoje hasło nie ulegnie zmianie, jeżeli nie wykorzystasz powyższego odnośnika i nie utworzysz nowego hasła.\n        subject: 'Mastodon: Instrukcje ustawienia nowego hasła'\n        title: Przywracanie hasła\n      unlock_instructions:\n        subject: 'Mastodon: Instrukcje odblokowania konta'\n    omniauth_callbacks:\n      failure: 'Uwierzytelnienie przez %{kind} nie powiodło się, ponieważ: \"%{reason}\".'\n      success: Uwierzytelnienie przez %{kind} powiodło się.\n    passwords:\n      no_token: Dostęp do tej strony możliwy jest wyłącznie za pomocą odnośnika z e-maila z instrukcjami ustawienia nowego hasła. Jeśli skorzystałeś(-aś) z takiego odnośnika, upewnij się, że został wykorzystany/skopiowany cały odnośnik.\n      send_instructions: W ciągu kilku minut otrzymasz wiadomość e-mail z instrukcją ustawienia nowego hasła. Jeżeli nie otrzymano wiadomości, sprawdź folder ze spamem.\n      send_paranoid_instructions: Jeśli Twój adres e-mail już istnieje w naszej bazie danych, w ciągu kilku minut otrzymasz wiadomość e-mail zawierającą odnośnik pozwalający na ustawienie nowego hasła. Jeżeli nie otrzymano wiadomości, sprawdź folder ze spamem.\n      updated: Twoje hasło zostało zmienione. Jesteś zalogowany(-a).\n      updated_not_active: Twoje hasło zostało zmienione.\n    registrations:\n      destroyed: Do zobaczenia! Twoje konto zostało zawieszone. Mamy jednak nadzieję, że do nas wrócisz.\n      signed_up: Witamy! Twoje konto zostało utworzone.\n      signed_up_but_inactive: Twoje konto zostało utworzone. Nie mogliśmy Cię jednak zalogować, ponieważ konto nie zostało jeszcze aktywowane.\n      signed_up_but_locked: Twoje konto zostało utworzone. Nie mogliśmy Cię jednak zalogować, ponieważ konto jest zablokowane.\n      signed_up_but_pending: Na Twój adres e-mail została wysłana wiadomosć z odnośnikiem potwierdzającym. Po kliknięciu w odnośnik, przejrzymy Twoje podanie. Zostaniesz poinformowany(-a), gdy zostanie ono przyjęte.\n      signed_up_but_unconfirmed: Na Twój adres e-mail została wysłana wiadomosć z odnośnikiem potwierdzającym. Kliknij w odnośnik, aby aktywować konto. Jeżeli nie otrzymano wiadomości, sprawdź folder ze spamem.\n      update_needs_confirmation: Konto zostało zaktualizowane, musimy jednak zweryfikować Twój nowy adres e-mail. Została na niego wysłana wiadomość z odnośnikiem potwierdzającym. Jeżeli nie otrzymano wiadomości, sprawdź folder ze spamem.\n      updated: Konto zostało zaktualizowane.\n    sessions:\n      already_signed_out: Zostałeś(-aś) wylogowany(-a).\n      signed_in: Zostałeś(-aś) zalogowany(-a).\n      signed_out: Zostałeś(-aś) wylogowany(-a).\n    unlocks:\n      send_instructions: W ciągu kilku minut otrzymasz wiadomość e-mail z instrukcjami odblokowania konta. Jeżeli nie otrzymano wiadomości, sprawdź folder ze spamem.\n      send_paranoid_instructions: Jeśli Twoje konto istnieje, instrukcje odblokowania go otrzymasz w wiadomości e-mail w ciągu kilku minut. Jeżeli nie otrzymano wiadomości, sprawdź folder ze spamem.\n      unlocked: Twoje konto zostało odblokowane. Zaloguj się, aby kontynuować.\n  errors:\n    messages:\n      already_confirmed: był już potwierdzony, spróbuj się zalogować\n      confirmation_period_expired: musi być potwierdzony w ciągu %{period}, poproś o nowe potwierdzenie\n      expired: wygasło, poproś o nowe\n      not_found: nie znaleziono\n      not_locked: było zablokowane\n      not_saved:\n        few: 'Błędy (%{count}) uniemożliwiły zapisanie tego %{resource}:'\n        many: 'Błędy (%{count}) uniemożliwiły zapisanie tego %{resource}:'\n        one: '1 błąd nie uniemożliwił zapisanie %{resource}:'\n        other: 'Błędy (%{count}) uniemożliwiły zapisanie tego %{resource}:'\n"
  },
  {
    "path": "config/locales/devise.pt-BR.yml",
    "content": "---\npt-BR:\n  devise:\n    confirmations:\n      confirmed: O seu endereço de e-mail foi confirmado.\n      send_instructions: Você receberá uma mensagem em sua caixa de entrada com instruções sobre como confirmar o seu endereço de e-mail dentro de alguns minutos. Por favor, cheque a sua pasta de spam caso não tenha recebido esta mensagem.\n      send_paranoid_instructions: Se o seu endereço de e-mail já existir em nossa base de dados, você receberá uma mensagem em sua caixa de entrada com instruções sobre confirmá-lo dentro de alguns minutos. Por favor, cheque a sua pasta de spam caso não tenha recebido esta mensagem.\n    failure:\n      already_authenticated: A sua sessão já está aberta.\n      inactive: A sua contra ainda não está ativada.\n      invalid: \"%{authentication_keys} ou senha inválida.\"\n      last_attempt: Você tem apenas mais uma tentativa sobrando antes que a sua conta seja bloqueada.\n      locked: A sua conta está bloqueada.\n      not_found_in_database: \"%{authentication_keys} ou senha inválida.\"\n      pending: Sua conta ainda está sendo revisada.\n      timeout: A sua sessão expirou. Por favor, entre novamente para continuar.\n      unauthenticated: Você precisa entrar ou cadastrar-se antes de continuar.\n      unconfirmed: Você precisa confirmar o seu endereço de e-mail antes de continuar.\n    mailer:\n      confirmation_instructions:\n        action: Verificar endereço de e-mail\n        action_with_app: Confirmar e voltar para %{app}\n        explanation: Você criou uma conta em %{host} com esse endereço de e-mail. Você está a um clique de ativá-la. Se não foi você, por favor ignore esse e-mail.\n        explanation_when_pending: Você pediu um convite para %{host} com esse endereço de email. Assim que você confirmar o seu endereço de e-mail, iremos revisar o seu pedido. Você não poderá fazer login até então. Se sua aplicação for rejeitada, seus dados serão removidos e nenhuma ação será necessária da sua parte. Se você não pediu por isso, por favor ignore esse e-mail.\n        extra_html: Por favor confira também <a href=\"%{terms_path}\">as regras da instância</a> e <a href=\"%{policy_path}\">nossos termos de serviço</a>.\n        subject: 'Mastodon: Instruções de confirmação para %{instance}'\n        title: Verifique o endereço de e-mail\n      email_changed:\n        explanation: 'O e-mail associado à sua conta será mudado para:'\n        extra: Se você não mudou seu e-mail é possível que alguém tenha conseguido acesso à sua conta. Por favor mude sua senha imediatamente ou entre em contato com um administrador da sua instância se você ficou sem acesso à sua conta.\n        subject: 'Mastodon: Email alterado'\n        title: Novo endereço de e-mail\n      password_change:\n        explanation: A senha da sua conta foi mudada.\n        extra: Se você não mudou a sua senha, é possível que alguém tenha conseguido acesso à sua conta. Por favor mude sua senha imediatamente ou entre em contato com um administrador da sua instância se você ficou sem acesso à sua conta.\n        subject: 'Mastodon: Senha modificada'\n        title: Senha alterada\n      reconfirmation_instructions:\n        explanation: Confirme o seu novo endereço para mudar seu e-mail.\n        extra: Se essa mudança não foi iniciada por você, por favor ignore esse e-mail. O endereço de e-mail para essa conta do Mastodon não irá mudar até que você acesse o link acima.\n        subject: 'Mastodon: Confirmar emai para %{instance}'\n        title: Verificar o endereço de e-mail\n      reset_password_instructions:\n        action: Mudar a senha\n        explanation: Você pediu uma nova senha para sua conta.\n        extra: Se você não fez esse pedido, por favor ignore esse e-mail. Sua senha não irá mudar até que você acesse o link acima e crie uma nova.\n        subject: 'Mastodon: Instruções para mudança de senha'\n        title: Redefinir a senha\n      unlock_instructions:\n        subject: 'Mastodon: Instruções de desbloqueio'\n    omniauth_callbacks:\n      failure: Não foi possível autenticá-lo como %{kind} porque \"%{reason}\".\n      success: Autenticado com sucesso como %{kind}.\n    passwords:\n      no_token: Você não pode acessar esta página se não tiver vindo de uma mensagem de mudança de senha. Se este for o caso, por favor verifique se a URL utilizada está completa.\n      send_instructions: Se o seu endereço de e-mail já estiver cadastrado em nossa base de dados, você receberá uma mensagem com um link para realizar a mudança de senha em alguns minutos. Por favor, cheque a sua pasta de spam caso não tenha recebido esta mensagem.\n      send_paranoid_instructions: Se o seu endereço de e-mail já estiver cadastrado em nossa base de dados, você receberá uma mensagem com um link para realizar a mudança de senha em alguns minutos. Por favor, cheque a sua pasta de spam caso não tenha recebido esta mensagem.\n      updated: A sua senha foi alterada. A sua sessão está aberta.\n      updated_not_active: A sua senha foi alterada.\n    registrations:\n      destroyed: Adeus! A sua conta foi cancelada. Esperamos vê-lo em breve.\n      signed_up: Bem vindo! A sua conta foi registrada com sucesso.\n      signed_up_but_inactive: A sua conta foi registrada. No entanto, não abrimos a sua sessão porque a sua conta ainda não foi ativada.\n      signed_up_but_locked: A sua conta foi registrada. No entanto, não abrimos a sua sessão porque a sua conta está bloqueada.\n      signed_up_but_pending: Uma mensagem com um link de confirmação foi enviada ao seu endereço de e-mail. Depois que você clicar no link, revisaremos seu pedido. Você será notificado se seu pedido for aprovado.\n      signed_up_but_unconfirmed: Uma mensagem com um link de confirmação foi enviada para o seu endereço de e-mail. Por favor, siga o link para ativar a sua conta e, caso não tenha recebido esta mensagem, cheque a sua pasta de spam.\n      update_needs_confirmation: Você mudou o seu endereço de e-mail ou a sua senha, mas é necessário confirmar a mudança. Por favor siga o link que foi enviado para o seu novo endereço de e-mail e, caso não tenha recebido esta mensagem, cheque a sua pasta de spam.\n      updated: A sua conta foi alterada com sucesso.\n    sessions:\n      already_signed_out: Sessão encerrada.\n      signed_in: Sessão iniciada.\n      signed_out: Sessão encerrada.\n    unlocks:\n      send_instructions: Você receberá uma mensagem com instruções para desbloquear a sua conta em alguns instantes. Por favor, cheque a sua pasta de spam caso não tenha recebido esta mensagem.\n      send_paranoid_instructions: Se a sua conta já existe, você receberá uma mensagem com instruções para desbloquear a sua conta em alguns instantes. Por favor, cheque a sua pasta de spam caso não tenha recebido esta mensagem.\n      unlocked: A sua conta foi desbloqueada com sucesso. Por favor inicie sessão para continuar.\n  errors:\n    messages:\n      already_confirmed: já foi confirmado, por favor tente iniciar sessão\n      confirmation_period_expired: precisa ser confirmada em até %{period}, por favor, solicite novo link de confirmação\n      expired: expirou, por favor solicite uma nova\n      not_found: não encontrado\n      not_locked: não está bloqueada\n      not_saved:\n        one: '1 erro impediu este %{resource} de ser salvo(a):'\n        other: \"%{count} erros impediram este %{resource} de ser salvo(a):\"\n"
  },
  {
    "path": "config/locales/devise.pt.yml",
    "content": "---\npt:\n  devise:\n    confirmations:\n      confirmed: O teu endereço de e-mail foi confirmado com sucesso.\n      send_instructions: Vais receber um email com as instruções para confirmar o teu endereço de email dentro de alguns minutos. Por favor, verifica a caixa de spam se não recebeste o e-mail.\n      send_paranoid_instructions: Se o teu endereço de email já existir na nossa base de dados, vais receber um email com as instruções de confirmação dentro de alguns minutos. Por favor, verifica a caixa de spam se não recebeste o e-mail.\n    failure:\n      already_authenticated: A tua sessão já está aberta.\n      inactive: A tua conta ainda não está ativada.\n      invalid: \"%{authentication_keys} ou palavra-passe inválida.\"\n      last_attempt: Tens mais uma tentativa antes de a tua conta ficar bloqueada.\n      locked: A tua conta está bloqueada.\n      not_found_in_database: \"%{authentication_keys} ou palavra-passe inválida.\"\n      timeout: A tua sessão expirou. Por favor, entra de novo para continuares.\n      unauthenticated: Precisas de entrar na tua conta ou de te registares antes de continuar.\n      unconfirmed: Tens de confirmar o teu endereço de email antes de continuar.\n    mailer:\n      confirmation_instructions:\n        action: Verificar o endereço de e-mail\n        action_with_app: Confirmar e regressar a %{app}\n        explanation: Criaste uma conta em %{host} com este endereço de e-mail. Estás a um clique de activá-la. Se não foste tu que fizeste este registo, por favor ignora esta mensagem.\n        extra_html: Por favor lê <a href=\"%{terms_path}\">as regras da instância</a> e os <a href=\"%{policy_path}\"> nossos termos de serviço</a>.\n        subject: 'Mastodon: Instruções de confirmação %{instance}'\n        title: Verificar o endereço de e-mail\n      email_changed:\n        explanation: 'O e-mail associado à tua conta será alterado para:'\n        extra: Se não alteraste o teu e-mail é possível que alguém tenha conseguido aceder à tua conta. Por favor muda a tua palavra-passe imediatamente ou entra em contato com um administrador do servidor se ficaste sem acesso à tua conta.\n        subject: 'Mastodon: Email alterado'\n        title: Novo endereço de e-mail\n      password_change:\n        explanation: A palavra-passe da tua conta foi alterada.\n        extra: Se não alteraste a tua palavra-passe, é possível que alguém tenha conseguido aceder à tua conta. Por favor muda a tua palavra-passe imediatamente ou entra em contato com um administrador do servidor se ficaste sem acesso à tua conta.\n        subject: 'Mastodon: Nova palavra-passe'\n        title: Palavra-passe alterada\n      reconfirmation_instructions:\n        explanation: Confirma o teu novo endereço para alterar o e-mail.\n        extra: Se esta mudança não foi iniciada por ti, por favor ignora este e-mail. O endereço de e-mail para a tua conta do Mastodon não irá mudar enquanto não acederes ao link acima.\n        subject: 'Mastodon: Confirmação de e-mail %{instance}'\n        title: Validar o endereço de e-mail\n      reset_password_instructions:\n        action: Alterar palavra-passe\n        explanation: Pediste a alteração da palavra-passe da tua conta.\n        extra: Se não fizeste este pedido, por favor ignora este e-mail. A tua palavra-passe não irá mudar se não acederes ao link acima e criares uma nova.\n        subject: 'Mastodon: Instruções para alterar a palavra-passe'\n        title: Solicitar nova palavra-passe\n      unlock_instructions:\n        subject: 'Mastodon: Instruções para desbloquear a tua conta'\n    omniauth_callbacks:\n      failure: Não foi possível autenticar %{kind} porque \"%{reason}\".\n      success: Autenticado com sucesso na conta %{kind}.\n    passwords:\n      no_token: Não pode aceder a esta página se não vier através do link enviado por email para alteração da sua palavra-passe. Se usaste esse link para chegar aqui, por favor verifica que o endereço URL actual é o mesmo do que foi enviado no email.\n      send_instructions: Vais receber um email com instruções para alterar a palavra-passe dentro de algns minutos.\n      send_paranoid_instructions: Se o teu endereço de email existe na nossa base de dados, vais receber um link para recuperar a palavra-passe dentro de alguns minutos.\n      updated: A tua palavra-passe foi alterada. Estás agora autenticado na tua conta.\n      updated_not_active: A tua palavra-passe foi alterada.\n    registrations:\n      destroyed: Adeus! A tua conta foi cancelada. Esperamos ver-te em breve.\n      signed_up: Bem-vindo! A tua conta foi registada com sucesso.\n      signed_up_but_inactive: A tua conta foi registada. No entanto ainda não está activa.\n      signed_up_but_locked: A tua conta foi registada. No entanto está bloqueada.\n      signed_up_but_unconfirmed: Uma mensagem com um link de confirmação foi enviada para o teu email. Por favor segue esse link para activar a tua conta.\n      update_needs_confirmation: Alteraste o teu endereço de email ou palavra-passe, mas é necessário confirmar essa alteração. Por favor vai ao teu email e segue link que te enviámos.\n      updated: A tua conta foi actualizada com sucesso.\n    sessions:\n      already_signed_out: Sessão encerrada.\n      signed_in: Sessão iniciada.\n      signed_out: Sessão encerrada.\n    unlocks:\n      send_instructions: Vais receber um email com instruções para desbloquear a tua conta dentro de alguns minutos.\n      send_paranoid_instructions: Se a tua conta existe, vais receber um email com instruções a detalhar como a desbloquear dentro de alguns minutos.\n      unlocked: A sua conta foi desbloqueada. Por favor inica uma nova sessão para continuar.\n  errors:\n    messages:\n      already_confirmed: já confirmado, por favor tente iniciar sessão\n      confirmation_period_expired: tem de ser confirmado durante %{period}, por favor tenta outra vez\n      expired: expirou, por favor tente outra vez\n      not_found: não encontrado\n      not_locked: não estava bloqueada\n      not_saved:\n        one: '1 erro impediu este %{resource} de ser guardado:'\n        other: \"%{count} erros impediram este %{resource} de ser guardado:\"\n"
  },
  {
    "path": "config/locales/devise.ro.yml",
    "content": "ro:\n"
  },
  {
    "path": "config/locales/devise.ru.yml",
    "content": "---\nru:\n  devise:\n    confirmations:\n      confirmed: Ваш адрес e-mail был успешно подтвержден.\n      send_instructions: Вы получите e-mail с инструкцией по подтверждению вашего адреса e-mail в течение нескольких минут.\n      send_paranoid_instructions: Если Ваш адрес e-mail есть в нашей базе данных, вы получите e-mail с инструкцией по подтверждению вашего адреса в течение нескольких минут.\n    failure:\n      already_authenticated: Вы уже авторизованы.\n      inactive: Ваш аккаунт еще не активирован.\n      invalid: Неверно введены %{authentication_keys} или пароль.\n      last_attempt: У Вас есть последняя попытка, после чего вход будет заблокирован.\n      locked: Ваш аккаунт заблокирован.\n      not_found_in_database: Неверно введены %{authentication_keys} или пароль.\n      pending: Ваша заявка на вступление всё ещё рассматривается.\n      timeout: Ваша сессия истекла. Пожалуйста, войдите снова, чтобы продолжить.\n      unauthenticated: Вам необходимо войти или зарегистрироваться.\n      unconfirmed: Вам необходимо подтвердить ваш адрес e-mail для продолжения.\n    mailer:\n      confirmation_instructions:\n        action: Подтвердите e-mail адрес\n        action_with_app: Подтвердить и вернуться в %{app}\n        explanation: Вы создали учётную запись на сайте %{host}, используя этот e-mail адрес. Остался лишь один шаг для активации. Если это были не вы, просто игнорируйте письмо.\n        explanation_when_pending: Вы подали заявку на %{host}, используя этот адрес e-mail. Как только вы его подтвердите, мы начнём изучать вашу заявку. До тех пор вы не сможете войти на сайт. Если ваша заявка будет отклонена, все данные будут автоматически удалены, от вас не потребуется никаких дополнительных действий. Если это были не вы, пожалуйста, проигнорируйте данное письмо.\n        extra_html: Пожалуйста, ознакомьтесь <a href=\"%{terms_path}\">правилами узла</a> and <a href=\"%{policy_path}\">условиями пользования Сервисом</a>.\n        subject: 'Mastodon: Инструкция по подтверждению на узле %{instance}'\n        title: Подтвердите e-mail адрес\n      email_changed:\n        explanation: 'E-mail адрес вашей учётной записи будет изменён на:'\n        extra: Если Вы не меняли адрес e-mail, возможно кто-то получил доступ к вашей учётной записи. Пожалуйста, срочно смените пароль или свяжитесь с администратором узла, если у вас нет доступа к учётной записи.\n        subject: 'Mastodon: Адрес e-mail изменён'\n        title: Новый адрес e-mail\n      password_change:\n        explanation: Пароль Вашей учётной записи был изменён.\n        extra: Если Вы не меняли пароль, возможно кто-то получил доступ к вашей учётной записи. Пожалуйста, срочно смените пароль или свяжитесь с администратором узла, если у вас нет доступа к учётной записи.\n        subject: 'Mastodon: Пароль изменен'\n        title: Пароль изменён\n      reconfirmation_instructions:\n        explanation: Подтвердите новый адрес для смены e-mail.\n        extra: Если смену e-mail инициировали не вы, пожалуйста, игнорируйте это письмо. Адрес e-mail для учётной записи Mastodon не будет изменён, пока вы не перейдёте по ссылке выше.\n        subject: 'Mastodon: Подтверждение e-mail для узла %{instance}'\n        title: Подтвердите e-mail адрес\n      reset_password_instructions:\n        action: Смена пароля\n        explanation: Вы запросили новый пароль для вашей учётной записи.\n        extra: Если это сделали не вы, пожалуйста, игнорируйте письмо. Ваш пароль не будет изменён, пока вы не перейдёте по ссылке выше и не создадите новый пароль.\n        subject: 'Mastodon: инструкция по смене пароля'\n        title: Сброс пароля\n      unlock_instructions:\n        subject: 'Mastodon: Инструкция по разблокировке'\n    omniauth_callbacks:\n      failure: Не получилось аутентифицировать вас с помощью %{kind} по следующей причине - \"%{reason}\".\n      success: Аутентификация с помощью аккаунта %{kind} прошла успешно.\n    passwords:\n      no_token: Вы можете получить доступ к этой странице, только перейдя по ссылке в e-mail для сброса пароля. Если вы действительно перешли по такой ссылке, пожалуйста, удостоверьтесь, что ссылка была введена полностью и без изменений.\n      send_instructions: Вы получите e-mail с инструкцией по сбросу пароля в течение нескольких минут.\n      send_paranoid_instructions: Если Ваш адрес e-mail есть в нашей базе данных, вы получите e-mail со ссылкой для сброса пароля в течение нескольких минут.\n      updated: Ваш пароль был успешно изменен. Вход выполнен.\n      updated_not_active: Ваш пароль был успешно изменен.\n    registrations:\n      destroyed: До свидания! Ваш аккаунт был успешно удален. Мы надеемся скоро увидеть вас снова.\n      signed_up: Добро пожаловать! Вы успешно зарегистрировались.\n      signed_up_but_inactive: Вы успешно зарегистрировались. Тем не менее, мы не можем авторизовать вас, поскольку ваш аккаунт еще не активирован.\n      signed_up_but_locked: Вы успешно зарегистрировались. Тем не менее, мы не можем авторизовать вас, поскольку ваш аккаунт заблокирован.\n      signed_up_but_pending: На ваш e-mail адрес было отправлено письмо с ссылкой для подтверждения. После перехода по ней, мы начнём рассматривать вашу заявку. В случае подтверждения, мы вас оповестим.\n      signed_up_but_unconfirmed: Сообщение со ссылкой для подтверждения было выслано на ваш адрес e-mail. Пожалуйста, пройдите по ссылке для активации вашего аккаунта.\n      update_needs_confirmation: Вы успешно обновили данные учётной записи, но нам нужно подтвердить ваш новый адрес e-mail. Пожалуйста, проверьте почту и перейдите по ссылке из письма для подтверждения вашего нового адреса.\n      updated: Ваш аккаунт был успешно обновлен.\n    sessions:\n      already_signed_out: Выход прошел успешно.\n      signed_in: Вход прошел успешно.\n      signed_out: Выход прошел успешно.\n    unlocks:\n      send_instructions: Вы получите e-mail с инструкцией по разблокировке вашего аккаунта в течение нескольких минут.\n      send_paranoid_instructions: Если Ваш аккаунт существует, вы получите e-mail с инструкцией по его разблокировке в течение нескольких минут.\n      unlocked: Ваш аккаунт был успешно разблокирован. пожалуйста, войдите для продолжения.\n  errors:\n    messages:\n      already_confirmed: уже подтвержден, пожалуйста, попробуйте войти\n      confirmation_period_expired: не был подтвержден в течение %{period}, пожалуйста, запросите новый\n      expired: истек, пожалуйста, запросите новый\n      not_found: не найден\n      not_locked: не был заблокирован\n      not_saved:\n        few: \"%{count} ошибки помешали сохранению этого %{resource}:\"\n        many: \"%{count} ошибок помешали сохранению этого %{resource}:\"\n        one: '1 ошибка помешала сохранению этого %{resource}:'\n        other: \"%{count} ошибок помешали сохранению этого %{resource}:\"\n"
  },
  {
    "path": "config/locales/devise.sk.yml",
    "content": "---\nsk:\n  devise:\n    confirmations:\n      confirmed: Tvoja emailová adresa bola úspešne overená.\n      send_instructions: O niekoľko minút obdržíš email s pokynmi ako potvrdiť svoj účet. Prosím, skontroluj si aj zložku spam, ak sa k tebe toto potvrdenie nedostalo.\n      send_paranoid_instructions: Ak sa tvoja emailová adresa nachádza v našej databázi, o niekoľko minút obdržíš email s pokynmi ako potvrdiť svoj účet. Prosím, skontroluj aj zložku spam, ak sa k tebe toto potvrdenie nedostalo.\n    failure:\n      already_authenticated: Už si prihlásený/á.\n      inactive: Tvoj účet ešte nebol potvrdený.\n      invalid: Nesprávny %{authentication_keys}, alebo heslo.\n      last_attempt: Máš posledný pokus pred zamknutím tvojho účtu.\n      locked: Tvoj účet je zamknutý.\n      not_found_in_database: Nesprávny %{authentication_keys}, alebo heslo.\n      pending: Tvoj účet je stále prehodnocovaný.\n      timeout: Tvoja aktívna sezóna vypršala. Pre pokračovanie sa prosím prihlás znovu.\n      unauthenticated: K pokračovaniu sa musíš zaregistrovať alebo prihlásiť.\n      unconfirmed: Pred pokračovaním musíš potvrdiť svoj email.\n    mailer:\n      confirmation_instructions:\n        action: Potvrď emailovú adresu\n        action_with_app: Potvrď a vráť sa na %{app}\n        explanation: S touto emailovou adresou si si vytvoril/a účet na %{host}. Si iba jeden klik od jeho aktivácie. Pokiaľ si to ale nebol/a ty, prosím ignoruj tento email.\n        extra_html: Prosím, pozri sa aj na <a href=\"%{terms_path}\"> pravidlá tohto servera,</a> a <a href=\"%{policy_path}\"> naše užívaťeľské podiemky</a>.\n        subject: 'Mastodon: Potvrdzovacie pokyny pre %{instance}'\n        title: Potvrď emailovú adresu\n      email_changed:\n        explanation: 'Emailová adresa tvojho účtu bude zmenená na:'\n        extra: Ak si nezmenil/a svoj email, je pravdepodobné, že niekto iný získal prístup k tvojmu účtu. Naliehavo preto prosím zmeň svoje heslo, alebo kontaktuj administrátora tohto serveru, pokiaľ si vymknutý/á zo svojho účtu.\n        subject: 'Mastodon: Emailová adresa bola zmenená'\n        title: Nová emailová adresa\n      password_change:\n        explanation: Heslo k tvojmu účtu bolo zmenené.\n        extra: Ak si heslo nezmenil/a, je pravdepodobné, že niekto iný získal prístup k tvojmu účtu. Naliehavo preto prosím zmeň svoje heslo, alebo kontaktuj administrátora tohto serveru, pokiaľ si vymknutý/á zo svojho účtu.\n        subject: 'Mastodon: Heslo bolo zmenené'\n        title: Heslo bolo zmenené\n      reconfirmation_instructions:\n        explanation: Potvrď novú emailovú adresu na ktorú chceš zmeniť svoj email.\n        extra: Pokiaľ si túto akciu nevyžiadal/a, prosím ignoruj tento email. Emailová adresa pre tvoj Mastodon účet totiž nebude zmenená pokiaľ nepostúpiš na adresu uvedenú vyššie.\n        subject: 'Mastodon: Potvrďenie emailu pre %{instance}'\n        title: Overiť emailovú adresu\n      reset_password_instructions:\n        action: Zmeň svoje heslo\n        explanation: Vyžiadal/a si si nové heslo pre svoj účet.\n        extra: Ak si túto akciu nevyžiadal/a, prosím ignoruj tento email. Tvoje heslo nebude zmenené pokiaľ nepostúpiš na adresu uvedenú vyššie a vytvoríš si nové.\n        subject: 'Mastodon: Pokyny pre obnovu hesla'\n        title: Nastav nové heslo\n      unlock_instructions:\n        subject: 'Mastodon: Pokyny na odomknutie účtu'\n    omniauth_callbacks:\n      failure: Nebolo možné ťa overiť z %{kind}, lebo \"%{reason}\".\n      success: Úspešné overenie z účtu %{kind}.\n    passwords:\n      no_token: Túto stránku nemôžeš navštíviť, ak neprichádzaš z emailu s pokynmi na obnovu hesla. Pokiaľ prichádzaš z tohto emailu, prosím uisti sa že si použil/a celú URL adresu z emailu.\n      send_instructions: Ak sa tvoja emailová adresa nachádza v databázi, tak o niekoľko minút obdržíš email s pokynmi ako nastaviť nové heslo. Ak máš pocit, že si email neobdržal/a, prosím skontroluj aj svoju spam zložku.\n      send_paranoid_instructions: Ak sa tvoja emailová adresa nachádza v databázi, za chvíľu obdržíš odkaz pre obnovu hesla na svoj email. Skontroluj ale prosím aj svoj spam, ak tento email nevidíš.\n      updated: Tvoje heslo bolo úspešne zmenené. Teraz si prihlásený/á.\n      updated_not_active: Tvoje heslo bolo úspešne zmenené.\n    registrations:\n      destroyed: Dovidenia! Tvoj účet bol úspešne zrušený. Dúfame ale, že ťa tu opäť niekedy uvidíme.\n      signed_up: Vitaj! Tvoja registrácia bola úspešná.\n      signed_up_but_inactive: Registrácia bola úspešná. Avšak, účet ešte nebol aktivovaný, takže ťa nemožno prihlásiť.\n      signed_up_but_locked: Registroval/a si sa úspešné. Avšak, tvoj účet je zamknutý, takže ťa nemožno prihlásiť.\n      signed_up_but_pending: Na tvoj email bola odoslaná správa s odkazom na potvrdenie. Po tom, čo naňho klikneš, bude tvoje uchádzanie posúdené. Budeš informovaný, ak sa tvoja požiadavka schváli.\n      signed_up_but_unconfirmed: Správa s odkazom na potvrdenie registrácie bola odoslaná na tvoj email. Pre aktváciu účtu, následuj prosím daný odkaz. Takisto ale skontroluj aj svoju spam zložku, pokiaľ sa ti zdá, že si tento email nedostal/a.\n      update_needs_confirmation: Účet bol úspešne pozmenený, ale ešte potrebujeme overiť tvoju novú emailovú adresu. Pre overenie prosím klikni na link v správe ktorú si dostal/a na email. Takisto ale skontroluj aj svoju spam zložku, ak sa ti zdá, že si tento email nedostal/a.\n      updated: Tvoj účet bol úspešne aktualizovaný.\n    sessions:\n      already_signed_out: Už si sa úspešne odhlásil/a.\n      signed_in: Prihlásil/a si sa úspešne.\n      signed_out: Odhlásil/a si sa úspešne.\n    unlocks:\n      send_instructions: O niekoľko minút obdržíš email s pokynmi, ako nastaviť nové heslo. Prosím, skontroluj ale aj svoju spam zložku, pokiaľ sa ti zdá, že si tento email nedostal/a.\n      send_paranoid_instructions: Ak tvoj účet existuje, o niekoľko minút obdržíš email s pokynmi ako si ho odomknúť. Prosím, skontroluj ale aj svoju spam zložku, pokiaľ sa ti zdá, že si tento email nedostal/a.\n      unlocked: Tvoj účet bol úspešne odomknutý. Pre pokračovanie sa prosím prihlás.\n  errors:\n    messages:\n      already_confirmed: bol už potvrdený, skús sa prihlásiť\n      confirmation_period_expired: musí byť potvrdený do %{period}, prosím požiadaj o nový\n      expired: vypŕšal, prosím, vyžiadaj si nový\n      not_found: nenájdený\n      not_locked: nebol zamknutý\n"
  },
  {
    "path": "config/locales/devise.sl.yml",
    "content": "---\nsl:\n  devise:\n    confirmations:\n      confirmed: Vaš e-poštni naslov je bil uspešno potrjen.\n      send_instructions: V nekaj minutah boste prejeli e-poštno sporočilo z navodili za potrditev vašega e-poštnega naslova. Če niste prejeli e-poštnega sporočila, preverite mapo neželena pošta.\n      send_paranoid_instructions: Če vaš e-poštni naslov obstaja v naši podatkovni bazi, boste v nekaj minutah prejeli e-poštno sporočilo z navodili za potrditev vašega e-poštnega naslova. Če niste prejeli e-poštnega sporočila, preverite mapo neželena pošta.\n    failure:\n      already_authenticated: Prijavljeni ste že.\n      inactive: Vaš račun še ni aktiviran.\n      invalid: Neveljavno %{authentication_keys} ali geslo.\n      last_attempt: Pred zaklepom računa imate še en poskus.\n      locked: Vaš račun je zaklenjen.\n      not_found_in_database: Neveljavno %{authentication_keys} ali geslo.\n      pending: Vaš račun je še vedno pod drobnogledom.\n      timeout: Vaša seja je potekla. Če želite nadaljevati, se znova prijavite.\n      unauthenticated: Pred nadaljevanjem se morate prijaviti ali vpisati.\n      unconfirmed: Pred nadaljevanjem morate potrditi svoj e-poštni naslov.\n    mailer:\n      confirmation_instructions:\n        action: Potrdi e-poštni naslov\n        action_with_app: Potrdi in se vrni v %{app}\n        explanation: S tem e-poštnim naslovom ste ustvarili račun na %{host}. Z enim samim klikom ga aktivirate. Če to niste bili vi, prosimo, prezrite to e-poštno sporočilo.\n        explanation_when_pending: S tem e-poštnim naslovom ste zaprosili za povabilo na %{host}. Ko potrdite svoj e-poštni naslov, bomo pregledali vašo prijavo. Do takrat se ne morete prijaviti. Če bo vaša prijava zavrnjena, bodo vaši podatki odstranjeni, zato ne bo potrebno nadaljnje ukrepanje. Če to niste bili vi, prezrite to e-poštno sporočilo.\n        extra_html: Preverite tudi <a href=\"%{terms_path}\">pravila vozlišča</a> in <a href=\"%{policy_path}\">naše pogoje storitve</a>.\n        subject: 'Mastodon: Navodila za potrditev za %{instance}'\n        title: Potrdi e-poštni naslov\n      email_changed:\n        explanation: 'E-poštni naslov za vaš račun je spremenjen na:'\n        extra: Če niste spremenili e-pošte, je verjetno, da je nekdo pridobil dostop do vašega računa. Prosim, zamenjajte geslo takoj. Če ste blokirani iz svojega računa  se obrnite na skrbnika vozlišča.\n        subject: 'Mastodon: E-pošta je spremenjena'\n        title: Novi e-poštni naslov\n      password_change:\n        explanation: Geslo za vaš račun je bilo spremenjeno.\n        extra: Če niste spremenili gesla, je verjetno, da je nekdo pridobil dostop do vašega računa. Prosim, zamenjajte geslo takoj. Če ste blokirani iz svojega računa  se obrnite na skrbnika vozlišča.\n        subject: 'Mastodon: Geslo je spremenjeno'\n        title: Geslo je spremenjeno\n      reconfirmation_instructions:\n        explanation: Potrdite novi naslov, da spremenite svoj e-poštni naslov.\n        extra: Če te spremembe niste sprožili, prezrite to e-poštno sporočilo. E-poštni naslov za račun Mastodon se ne bo spremenil, dokler ne kliknete na zgornjo povezavo.\n        subject: 'Mastodon: Potrdite e-pošto za %{instance}'\n        title: Potrdi e-poštni naslov\n      reset_password_instructions:\n        action: Spremeni geslo\n        explanation: Zahtevali ste novo geslo za svoj račun.\n        extra: Če tega niste zahtevali, prezrite to e-poštno sporočilo. Vaše geslo se ne bo spremenilo, dokler ne kliknete na zgornjo povezavo in ustvarite novega.\n        subject: 'Mastodon: Navodila za ponastavitev gesla'\n        title: Ponastavitev gesla\n      unlock_instructions:\n        subject: 'Mastodon: Odkleni navodila'\n    omniauth_callbacks:\n      failure: Overitev iz %{kind} ni možna zaradi \"%{reason}\".\n      success: Overitev iz računa %{kind} je bila uspešna.\n"
  },
  {
    "path": "config/locales/devise.sq.yml",
    "content": "---\nsq:\n  devise:\n    confirmations:\n      confirmed: Adresa juaj email u ripohua me sukses.\n      send_instructions: Brenda pak minutash, do të merrni një email me udhëzime se si të ripohoni adresën tuaj email. Ju lutemi, kontrolloni dosjen e mesazheve të padëshiruar, nëse nuk e morët këtë email.\n      send_paranoid_instructions: Nëse adresa juaj email gjendet në bazën tonë të të dhënave, brenda pak minutash, do të merrni një email me udhëzime se si të ripohoni adresën tuaj email. Ju lutemi, kontrolloni dosjen e mesazheve të padëshiruar, nëse nuk e morët këtë email.\n    failure:\n      already_authenticated: Jeni tashmë i futur.\n      inactive: Llogaria juaj s’është aktivizuar ende.\n      invalid: \"%{authentication_keys} ose fjalëkalim i pavlefshëm.\"\n      last_attempt: Mund të provoni edhe një herë, përpara se llogaria juaj të kyçet.\n      locked: Llogaria juaj është e kyçur.\n      not_found_in_database: \"%{authentication_keys} ose fjalëkalim i pavlefshëm.\"\n      timeout: Sesioni juaj ka skaduar. Ju lutemi, që të vazhdohet, ribëni hyrjen.\n      unauthenticated: Përpara se të vazhdohet më tej, lypset të bëni hyrjen ose të regjistroheni.\n      unconfirmed: Përpara se të vazhdohet, lypset të ripohoni adresën tuaj email.\n    mailer:\n      confirmation_instructions:\n        action: Verifikoni adresë email\n        action_with_app: Ripohojeni dhe kthehuni te %{app}\n        explanation: Keni krijuar një llogari te %{host}, me këtë adresë email. Jeni një klikim larg aktivizimit të saj. Nëse s’jeni ju, shpërfilleni këtë email.\n        extra_html: Ju lutemi, shihni edhe <a href=\"%{terms_path}\">rregullat e shërbyesit</a> dhe <a href=\"%{policy_path}\">kushtet tona të shërbimit</a>.\n        subject: 'Mastodon: Udhëzime ripohimi për %{instance}'\n        title: Verifikoni adresë email\n      email_changed:\n        explanation: 'Adresa email për llogarinë tuaj po ndryshohet në:'\n        extra: Nëse email-in tuaj nuk e ndryshuat ju, gjasat janë që dikush tjetër ka arritur të hyjë në llogarinë tuaj. Ju lutemi, ndryshoni menjëherë fjalëkalimin tuaj ose lidhuni me përgjegjësin e shërbyesit, nëse jeni kyçur jashtë llogarisë tuaj.\n        subject: 'Mastodon: Email-i u ndryshua'\n        title: Adresë email e re\n      password_change:\n        explanation: Fjalëkalimi për llogarinë tuaj u ndryshua.\n        extra: Nëse fjalëkalimin tuaj nuk e ndryshuat ju, gjasat janë që dikush tjetër ka arritur të hyjë në llogarinë tuaj. Ju lutemi, ndryshoni menjëherë fjalëkalimin tuaj ose lidhuni me përgjegjësin e shërbyesit, nëse jeni kyçur jashtë llogarisë tuaj.\n        subject: 'Mastodon: Fjalëkalimi u ndryshua'\n        title: Fjalëkalimi u ndryshua\n      reconfirmation_instructions:\n        explanation: Që të ndryshohet email-i juaj, ripohoni adresën e re.\n        extra: Nëse ky ndryshim s’qe filluar prej jush, ju lutemi, shpërfilleni këtë email. Adresa email për llogarinë Mastodon s’do të ndryshojë, para se të hyni në lidhjen më sipër.\n        subject: 'Mastodon: Ripohoni email-in për %{instance}'\n        title: Verifikoni adresë email\n      reset_password_instructions:\n        action: Ndryshoni fjalëkalimin\n        explanation: Kërkuat një fjalëkalim të ri për këtë llogari.\n        extra: Nëse këtë s’e kërkuat ju, ju lutemi, shpërfilleni këtë email. Fjalëkalimi juaj s’do të ndryshohet pa hyrë në lidhjen më sipër dhe krijimin e një të riu.\n        subject: 'Mastodon: Udhëzime ricaktimi fjalëkalimi'\n        title: Ricaktim fjalëkalimi\n      unlock_instructions:\n        subject: 'Mastodon: Udhëzime shkyçjeje'\n    omniauth_callbacks:\n      failure: S’u bë dot mirëfilltësimi juaj nga %{kind}, sepse \"%{reason}\".\n      success: Mirëfilltësimi nga llogaria %{kind} u bë me sukses.\n    passwords:\n      no_token: S’mund të hyni në këtë faqe paardhur nga një email ricaktimi fjalëkalimi. Nëse vini nga një email ricaktimi fjalëkalimi, ju lutemi, sigurohuni se përdorët URL-në e plotë dhënë për ju.\n      send_instructions: Nëse adresa juaj email gjendet në bazën tonë të të dhënave, brenda pak minutash, te adresa juaj email do të merrni një lidhje rimarrjeje fjalëkalimi. Ju lutemi, kontrolloni dosjen e mesazheve të padëshiruar, nëse nuk e morët këtë email.\n      send_paranoid_instructions: Nëse adresa juaj email gjendet në bazën tonë të të dhënave, brenda pak minutash, te adresa juaj email do të merrni një lidhje rimarrjeje fjalëkalimi. Ju lutemi, kontrolloni dosjen e mesazheve të padëshiruar, nëse nuk e morët këtë email.\n      updated: Fjalëkalimi juaj u ndryshua me sukses. Tani jeni i futur.\n      updated_not_active: Fjalëkalimi juaj u ndryshua me sukses.\n    registrations:\n      destroyed: Shëndet! Llogaria juaj u fshi me sukses. Shpresojmë t’ju rishohim së shpejti.\n      signed_up: Mirë se vini! U regjistruat me sukses.\n      signed_up_but_inactive: U regjistruat me sukses. Megjithatë, s’u bë dot hyrja juaj, ngaqë llogaria juaj s’është aktivizuar ende.\n      signed_up_but_locked: U regjistruat me sukses. Megjithatë, s’u bë dot hyrja juaj, ngaqë llogaria juaj është kyçur.\n      signed_up_but_unconfirmed: Te adresa juaj email u dërgua një mesazh me një lidhje ripohimi. Ju lutemi, që të aktivizoni llogarinë tuaj, ndiqni lidhjen. Ju lutemi, kontrolloni dosjen e mesazheve të padëshiruar, nëse nuk e morët këtë email.\n      update_needs_confirmation: E përditësuat me sukses llogarinë tuaj, por na duhet të verifikojmë adresën tuaj të re email. Ju lutemi, që të ripohoni adresën tuaj të re email, kontrolloni email-in tuaj dhe ndiqni lidhjen. Ju lutemi, kontrolloni dosjen e mesazheve të padëshiruar, nëse nuk e morët këtë email.\n      updated: Llogaria juaj u përditësua me sukses.\n    sessions:\n      already_signed_out: Dolët me sukses.\n      signed_in: Hytë me sukses.\n      signed_out: Dolët me sukses.\n    unlocks:\n      send_instructions: Brenda pak minutash, do të merrni një email me udhëzime se si të shkyçni llogarinë tuaj. Ju lutemi, kontrolloni dosjen e mesazheve të padëshiruar, nëse nuk e morët këtë email.\n      send_paranoid_instructions: Nëse llogaria juaj ekziston, brenda pak minutash, do të merrni një email me udhëzime se si të shkyçni llogarinë tuaj. Ju lutemi, kontrolloni dosjen e mesazheve të padëshiruar, nëse nuk e morët këtë email.\n      unlocked: Llogaria juaj u shkyç me sukses. Ju lutemi, që të vazhdohet, bëni hyrjen.\n  errors:\n    messages:\n      already_confirmed: qe e ripohuar tashmë, ju lutemi, provoni të bëni hyrjen\n      confirmation_period_expired: lyp të ripohohet brenda %{period}, ju lutemi, kërkoni një të ri\n      expired: ka skaduar, ju lutemi, kërkoni një të ri\n      not_found: s’u gjet\n      not_locked: s’qe kyçur\n      not_saved:\n        one: 'Ruajtjen e këtij %{resource} e pengoi 1 gabim:'\n        other: 'Ruajtjen e këtij %{resource} e penguan %{count} gabime:'\n"
  },
  {
    "path": "config/locales/devise.sr-Latn.yml",
    "content": "---\nsr-Latn:\n  devise:\n    confirmations:\n      confirmed: Adresa Vaše e-pošte je uspešno potvrđena.\n      send_instructions: U roku od nekoliko minuta primićete e-poštu sa uputstvom za potvrdu Vašeg naloga. Molimo proverite i spam fasciklu ako niste primili poruku.\n      send_paranoid_instructions: Ukoliko se adresa Vaše e-pošte nalazi u našoj bazi, u roku od nekoliko minuta primićete poruku sa uputstvom kako da potvrdite Vaš nalog. Molimo proverite i spam fasciklu ako niste primili poruku.\n    failure:\n      already_authenticated: Već ste prijavljeni.\n      inactive: Vaš nalog još nije aktiviran.\n      invalid: Neispravan %{authentication_keys} ili lozinka.\n      last_attempt: Imate još jedan pokušaj pre nego što Vaš nalog bude zaključan.\n      locked: Vaš nalog je zaključan.\n      not_found_in_database: Neispravan %{authentication_keys} ili lozinka.\n      timeout: Vreme trajanja Vaše sesije je isteklo. Za nastavak prijavite se ponovo.\n      unauthenticated: Za nastavak se morate prijaviti ili registrovati.\n      unconfirmed: Pre nastavka morate potvrditi svoj nalog.\n    mailer:\n      confirmation_instructions:\n        subject: 'Mastodont: Uputstvo za potvrdu korisničkog naloga na instanci %{instance}'\n      password_change:\n        subject: 'Mastodont: Lozinka promenjena'\n      reset_password_instructions:\n        subject: 'Mastodont: Uputstvo za resetovanje lozinke'\n      unlock_instructions:\n        subject: 'Mastodont: Uputstvo za otključavanje korisničkog naloga'\n    omniauth_callbacks:\n      failure: Nismo u mogućnosti autorizovati Vas sa %{kind} nalogom zbog \"%{reason}\".\n      success: Uspešna autorizacija sa %{kind} naloga.\n    passwords:\n      no_token: Ne možete pristupiti ovoj stranici ako niste pratili vezu u imejlu za resetovanje lozinke. Ukoliko ste pratili vezu za resetovanje lozinke u poruci, molimo Vas da proverite da li ste koristili punu adresu.\n      send_instructions: U roku od nekoliko minuta primitićete poruku sa uputstvom za promenu Vaše lozinke. Molimo proverite i spam fasciklu ako niste primili poruku.\n      send_paranoid_instructions: Ukoliko se adresa Vaše e-pošte nalazi u našoj bazi, u roku od nekoliko minuta primićete poruku sa uputstvom za promenu Vaše lozinke. Molimo proverite i spam fasciklu ako niste primili poruku.\n      updated: Vaša lozinka je uspešno promenjena. Sada ste prijavljeni.\n      updated_not_active: Vaša lozinka nije uspešno promenjena.\n    registrations:\n      destroyed: Ćao! Vaš nalog je uspešno obrisan. Nadamo se da ćete se uskoro vratiti.\n      signed_up: Dobrodošli! Uspešno ste se registrovali.\n      signed_up_but_inactive: Uspešno ste se registrovali. Nažalost ne možete se prijaviti zato što Vaš nalog još nije aktiviran.\n      signed_up_but_locked: Uspešno ste se registrovali. Nažalost ne možete se prijaviti zato što je Vaš nalog zaključan.\n      signed_up_but_unconfirmed: Poruka za potvrdu Vašeg naloga je poslata na Vašu imejl adresu. Kliknite na vezu u imejlu da potvrdite svoj nalog. Molimo proverite i spam fasciklu ako niste primili poruku.\n      update_needs_confirmation: Uspešno ste ažurirali svoj nalog, ali treba da potvrdimo novu adresu Vaše e-pošte. Molimo Vas da proverite e-poštu i pratite link za potvrdu nove adrese Vaše e-pošte.\n      updated: Vaš nalog je uspešno ažuriran.\n    sessions:\n      already_signed_out: Uspešno ste se odjavili.\n      signed_in: Uspešno ste se prijavili.\n      signed_out: Uspešno ste se odjavili.\n    unlocks:\n      send_instructions: U roku od nekoliko minuta primićete imejl sa uputstvom za otključavanje Vašeg naloga. Molimo proverite i spam fasciklu ako niste primili poruku.\n      send_paranoid_instructions: koliko se adresa Vaše e-pošte nalazi u našoj bazi, u roku od nekoliko minuta primićete poruku sa uputstvom kako da otključate Vaš nalog. Molimo proverite i spam fasciklu ako niste primili poruku.\n      unlocked: Vaš nalog je uspešno otključan. Molimo Vas da se prijavite da biste nastavili.\n  errors:\n    messages:\n      already_confirmed: je već potvrđen, molimo Vas da se prijavite\n      confirmation_period_expired: je trebao biti potvrđen tokom perioda %{period}, molimo Vas da zatražite novi\n      expired: je istekao, molimo Vas da zatražite novi\n      not_found: nije pronađeno\n      not_locked: nije zaključan\n      not_saved:\n        few: \"%{count} greške sprečavaju %{resource}a:\"\n        one: '1 greška sprečava %{resource}a:'\n        other: \"%{count} grešaka sprečavaju %{resource}a:\"\n"
  },
  {
    "path": "config/locales/devise.sr.yml",
    "content": "---\nsr:\n  devise:\n    confirmations:\n      confirmed: Адреса Ваше е-поште је успешно потврђена.\n      send_instructions: У року од неколико минута примићете е-пошту са упутством за потврду Вашег налога. Молимо проверите и спам фасциклу ако нисте примили поруку.\n      send_paranoid_instructions: Уколико се адреса Ваше е-поште налази у нашој бази, у року од неколико минута примићете поруку са упутством како да потврдите Ваш налог. Молимо проверите и спам фасциклу ако нисте примили поруку.\n    failure:\n      already_authenticated: Већ сте пријављени.\n      inactive: Ваш налог још није активиран.\n      invalid: Неисправан %{authentication_keys} или лозинка.\n      last_attempt: Имате још један покушај пре него што Ваш налог буде закључан.\n      locked: Ваш налог је закључан.\n      not_found_in_database: Неисправан %{authentication_keys} или лозинка.\n      timeout: Време трајања Ваше сесије је истекло. За наставак пријавите се поново.\n      unauthenticated: За наставак се морате пријавити или регистровати.\n      unconfirmed: Пре наставка морате потврдити свој налог.\n    mailer:\n      confirmation_instructions:\n        action: Потврдите адресу е-поште\n        action_with_app: Потврди и врати се на %{app}\n        explanation: Направили сте налог на %{host} са адресом ове е-поште. На један клик сте удаљени од активирања. Ако ово нисте ви, молимо игноришите ову е-пошту.\n        extra_html: Молимо да такође проверите <a href=\"%{terms_path}\"> правила ове инстанце и <a href=\"%{policy_path}\"> наше услове коришћења.\n        subject: 'Мастодонт: Упутство за потврду корисничког налога на инстанци %{instance}'\n        title: Потврдите адресу е-поште\n      email_changed:\n        explanation: 'Адреса ове е-поште за ваш налог ће бити промењена у:'\n        extra: Ако нисте променили вашу е-пошту, сасвим је могуће да је неко други добио приступ вашем налогу. Молимо промените лозинку одмах или контактирајте администратора инстанце ако сте закључани изван вашег налога.\n        subject: 'Мастодон: Е-пошта промењена'\n        title: Нова адреса е-поште\n      password_change:\n        explanation: Лозинка вашег налога је промењена.\n        extra: Ако нисте променили вашу е-пошту, сасвим је могуће да је неко други добио приступ вашем налогу. Молимо промените лозинку одмах или контактирајте администратора инстанце ако сте закључани изван вашег налога.\n        subject: 'Мастодонт: Лозинка промењена'\n        title: Лозинка промењена\n      reconfirmation_instructions:\n        explanation: Потврдите нову адресу да бисте променили е-пошту.\n        extra: Ако ова промена није иницирана са ваше стране, молимо игноришите ову е-пошту. Адреса е-пошта за овај Мастодон налог неће бити промењена док не приступите повезници/линку изнад.\n        subject: 'Мастодон: Потврдите е-пошту за %{instance}'\n        title: Потврдите адресу е-поште\n      reset_password_instructions:\n        action: Лозинка промењена\n        explanation: Затражили сте нову лозинку за ваш налог.\n        extra: Ако нисте затражили ово, молимо игноришите ову е-пошту. Ваша лозинка неће бити промењена док не приступите повезници/вези изнад и не направите нову.\n        subject: 'Мастодонт: Упутство за ресетовање лозинке'\n        title: Лозинка ресетована\n      unlock_instructions:\n        subject: 'Мастодонт: Упутство за откључавање корисничког налога'\n    omniauth_callbacks:\n      failure: Нисмо у могућности ауторизовати Вас са %{kind} налогом због \"%{reason}\".\n      success: Успешна ауторизација са %{kind} налога.\n    passwords:\n      no_token: Не можете приступити овој страници ако нисте пратили везу у имејлу за ресетовање лозинке. Уколико сте пратили везу за ресетовање лозинке у поруци, молимо Вас да проверите да ли сте користили пуну адресу.\n      send_instructions: У року од неколико минута примитићете поруку са упутством за промену Ваше лозинке. Молимо проверите и спам фасциклу ако нисте примили поруку.\n      send_paranoid_instructions: Уколико се адреса Ваше е-поште налази у нашој бази, у року од неколико минута примићете поруку са упутством за промену Ваше лозинке. Молимо проверите и спам фасциклу ако нисте примили поруку.\n      updated: Ваша лозинка је успешно промењена. Сада сте пријављени.\n      updated_not_active: Ваша лозинка није успешно промењена.\n    registrations:\n      destroyed: Ћао! Ваш налог је успешно обрисан. Надамо се да ћете се ускоро вратити.\n      signed_up: Добродошли! Успешно сте се регистровали.\n      signed_up_but_inactive: Успешно сте се регистровали. Нажалост не можете се пријавити зато што Ваш налог још није активиран.\n      signed_up_but_locked: Успешно сте се регистровали. Нажалост не можете се пријавити зато што је Ваш налог закључан.\n      signed_up_but_unconfirmed: Порука за потврду Вашег налога је послата на Вашу имејл адресу. Кликните на везу у имејлу да потврдите свој налог. Молимо проверите и спам фасциклу ако нисте примили поруку.\n      update_needs_confirmation: Uспешно сте ажурирали свој налог, али треба да потврдимо нову адресу Ваше е-поште. Молимо Вас да проверите е-пошту и пратите линк за потврду нове адресе Ваше е-поште.\n      updated: Ваш налог је успешно ажуриран.\n    sessions:\n      already_signed_out: Успешно сте се одјавили.\n      signed_in: Успешно сте се пријавили.\n      signed_out: Успешно сте се одјавили.\n    unlocks:\n      send_instructions: У року од неколико минута примићете имејл са упутством за откључавање Вашег налога. Молимо проверите и спам фасциклу ако нисте примили поруку.\n      send_paranoid_instructions: колико се адреса Ваше е-поште налази у нашој бази, у року од неколико минута примићете поруку са упутством како да откључате Ваш налог. Молимо проверите и спам фасциклу ако нисте примили поруку.\n      unlocked: Ваш налог је успешно откључан. Молимо Вас да се пријавите да бисте наставили.\n  errors:\n    messages:\n      already_confirmed: је већ потврђен, молимо Вас да се пријавите\n      confirmation_period_expired: је требао бити потврђен током периода %{period}, молимо Вас да затражите нови\n      expired: је истекао, молимо Вас да затражите нови\n      not_found: није пронађено\n      not_locked: није закључан\n      not_saved:\n        few: \"%{count} грешке спречавају %{resource}a:\"\n        one: '1 грешка спречава %{resource}а:'\n        other: \"%{count} грешака спречавају %{resource}a:\"\n"
  },
  {
    "path": "config/locales/devise.sv.yml",
    "content": "---\nsv:\n  devise:\n    confirmations:\n      confirmed: Din e-postadress har bekräftats.\n      send_instructions: Du kommer att få ett mail med instruktioner för hur du bekräftar din e-postadress om några minuter. Kontrollera din spammapp om du inte fick det här e-postmeddelandet.\n      send_paranoid_instructions: Om din e-postadress finns i vår databas får du ett mail med instruktioner för hur du bekräftar din e-postadress inom några minuter. Kontrollera din spammapp om du inte fick det här e-postmeddelandet.\n    failure:\n      already_authenticated: Du är redan inloggad.\n      inactive: Ditt konto är inte aktiverat än..\n      invalid: Ogiltigt %{authentication_keys} eller lösenord.\n      last_attempt: Du har ytterligare ett försök innan ditt konto blir låst.\n      locked: Ditt konto är låst.\n      not_found_in_database: Ogiltigt %{authentication_keys} eller lösenord.\n      timeout: Din session löpte ut. Vänligen logga in igen för att fortsätta.\n      unauthenticated: Du måste logga in eller registrera dig innan du fortsätter.\n      unconfirmed: Du måste bekräfta din e-postadress innan du fortsätter.\n    mailer:\n      confirmation_instructions:\n        action: Verifiera e-postadress\n        explanation: Du har skapat ett konto på %{host} med den här e-postadressen. Du är ett klick bort från att aktivera det. Om det inte var du ignorerar det här e-postmeddelandet.\n        extra_html: Kolla gärna också <a href=\"%{terms_path}\">instansens regler</a> och <a href=\"%{policy_path}\">våra användarvillkor</a>.\n        subject: 'Mastodon: Bekräftelsesinstruktioner för %{instance}'\n        title: Verifiera e-postadress\n      email_changed:\n        explanation: 'E-postadressen för ditt konto ändras till:'\n        extra: Om du inte ändrade din e-post är det troligt att någon har fått tillgång till ditt konto. Vänligen ändra ditt lösenord omedelbart eller kontakta instansadministratören om du är låst ur ditt konto.\n        subject: 'Mastodon: E-post ändrad'\n        title: Ny e-postadress\n      password_change:\n        explanation: Lösenordet för ditt konto har ändrats.\n        extra: Om du inte ändrade ditt lösenord är det troligt att någon har fått tillgång till ditt konto. Vänligen ändra ditt lösenord omedelbart eller kontakta instansadministratören om du är utelåst från ditt konto.\n        subject: 'Mastodon: Lösenord ändrat'\n        title: lösenordet ändrat\n      reconfirmation_instructions:\n        explanation: Bekräfta den nya adressen för att ändra din e-postadress.\n        extra: Om den här ändringen inte initierades av dig kan du ignorerar det här e-postmeddelandet. E-postadressen för Mastodon-kontot ändras inte förrän du kommer åt länken ovan.\n        subject: 'Mastodon: Bekräfta e-post för %{instance}'\n        title: Verifiera e-postadressen\n      reset_password_instructions:\n        action: Ändra lösenord\n        explanation: Du begärde ett nytt lösenord för ditt konto.\n        extra: Om du inte begärt detta kan du ignorerar det här e-postmeddelandet. Ditt lösenord ändras inte förrän du öppnar länken ovan och skapar ett nytt.\n        subject: 'Mastodon: Instruktioner för återställning av lösenord'\n        title: Lösenordsåterställning\n      unlock_instructions:\n        subject: 'Mastodon: Lås upp instruktioner'\n    omniauth_callbacks:\n      failure: Det gick inte att autentisera dig från %{kind} för \"%{reason}\".\n      success: Autentiserad från %{kind} konto.\n    passwords:\n      no_token: Du kan inte komma åt den här sidan utan att komma från ett e-postmeddelande för lösenordsåterställning. Om du kommer från ett lösenordsåterställt e-postmeddelande, var vänlig och se till att du använde hela webbadressen.\n      send_instructions: Om din e-postadress finns i vår databas, får du en länk för återställning av lösenord på din e-postadress om några minuter. Kontrollera din spammapp om du inte fick det här e-postmeddelandet.\n      send_paranoid_instructions: Om din e-postadress finns i vår databas, får du en länk för återställning av lösenord på din e-postadress om några minuter. Kontrollera din spammapp om du inte fick det här e-postmeddelandet.\n      updated: Ditt lösenord har ändrats framgångsrikt. Du är nu inloggad.\n      updated_not_active: Ditt lösenord har ändrats. Du är nu inloggad.\n    registrations:\n      destroyed: Adjö! Ditt konto har blivit nerstängt. Vi hoppas att vi ses snart igen.\n      signed_up: Välkommen! Du har nu registrerat dig.\n      signed_up_but_inactive: Du har nu registrerat dig. Vi kunde dock inte logga in dig eftersom ditt konto ännu inte är aktiverat.\n      signed_up_but_locked: Du har nu registrerat dig. Vi kunde dock inte logga in eftersom ditt konto är låst.\n      signed_up_but_unconfirmed: Ett meddelande med en bekräftelse länk har skickats till din e-postadress. Vänligen följ länken för att aktivera ditt konto. Kontrollera din spammapp om du inte fick det här e-postmeddelandet.\n      update_needs_confirmation: Du har uppdaterat ditt konto med framgång, men vi måste verifiera din nya e-postadress. Vänligen kolla din email och följ bekräfta länken för att bekräfta din nya e-postadress. Kontrollera din spammapp om du inte fick det här e-postmeddelandet.\n      updated: Ditt konto har uppdaterats utan problem.\n    sessions:\n      already_signed_out: Utloggad.\n      signed_in: Inloggad.\n      signed_out: Utloggad.\n    unlocks:\n      send_instructions: Du kommer att få ett mail med instruktioner om hur du låser upp ditt konto inom några minuter. Kontrollera din spammapp om du inte fick det här e-postmeddelandet.\n      send_paranoid_instructions: Om ditt konto finns, får du ett mail med instruktioner om hur du låser upp det på några minuter. Kontrollera din spammapp om du inte fick det här e-postmeddelandet.\n      unlocked: Ditt konto ha låsts upp. Vänligen logga in för att fortsätta.\n  errors:\n    messages:\n      already_confirmed: var redan bekräftad, var god försök att logga in\n      confirmation_period_expired: måste bekräftas inom %{period}, var god be om en ny\n      expired: har gått ut, vänligen be om en ny\n      not_found: hittades inte\n      not_locked: var inte låst\n      not_saved:\n        one: '1 fel förbjöd denna %{resource} att sparas:'\n        other: \"%{count} fel förbjöd dessa %{resource} från att sparas:\"\n"
  },
  {
    "path": "config/locales/devise.ta.yml",
    "content": "ta:\n"
  },
  {
    "path": "config/locales/devise.te.yml",
    "content": "te:\n"
  },
  {
    "path": "config/locales/devise.th.yml",
    "content": "---\nth:\n  devise:\n    confirmations:\n      send_instructions: You will receive an email with instructions for how to confirm your email address in a few minutes.\n      send_paranoid_instructions: If your email address exists in our database, you will receive an email with instructions for how to confirm your email address in a few minutes.\n    passwords:\n      send_instructions: If your email address exists in our database, you will receive a password recovery link at your email address in a few minutes.\n      send_paranoid_instructions: If your email address exists in our database, you will receive a password recovery link at your email address in a few minutes.\n    registrations:\n      signed_up_but_unconfirmed: A message with a confirmation link has been sent to your email address. Please follow the link to activate your account.\n      update_needs_confirmation: You updated your account successfully, but we need to verify your new email address. Please check your email and follow the confirm link to confirm your new email address.\n    unlocks:\n      send_instructions: You will receive an email with instructions for how to unlock your account in a few minutes.\n      send_paranoid_instructions: If your account exists, you will receive an email with instructions for how to unlock it in a few minutes.\n  errors:\n    messages:\n      not_found: ไม่พบ\n"
  },
  {
    "path": "config/locales/devise.tr.yml",
    "content": "---\ntr:\n  devise:\n    confirmations:\n      confirmed: E-posta adresiniz başarıyla onaylandı.\n      send_instructions: Birkaç dakika içinde e-posta adresinizi nasıl onaylayacağınıza ilişkin talimatları içeren bir e-posta alacaksınız. Bu e-postayı almadıysanız, lütfen spam klasörünüzü kontrol edin.\n      send_paranoid_instructions: E-posta adresiniz veritabanımızda varsa, e-posta adresinizi birkaç dakika içinde nasıl doğrulayacağınıza ilişkin talimatları içeren bir e-posta alacaksınız. Bu e-postayı almadıysanız, lütfen spam klasörünüzü kontrol edin.\n    failure:\n      already_authenticated: Zaten oturum açtınız.\n      inactive: Hesabınız henüz etkinleştirilmedi.\n      last_attempt: Hesabınız kilitlenmeden önce bir kez daha denemeniz gerekir.\n      locked: Hesabınız kilitli.\n    mailer:\n      confirmation_instructions:\n        action: E-posta adresinizi doğrulayın\n"
  },
  {
    "path": "config/locales/devise.uk.yml",
    "content": "---\nuk:\n  devise:\n    confirmations:\n      confirmed: Ваша поштова скринька була успішно підтверджена.\n      send_instructions: Ви отримаєте листа з інструкціями щодо підтвердження Вашої адреси через декілька хвилин.\n      send_paranoid_instructions: Якщо Ваша поштова скринька існує в нашій базі даних, то Ви отримаєте листа з інструкціями щодо підтвердження Вашої адреси через декілька хвилин.\n    failure:\n      already_authenticated: Ви вже увійшли.\n      inactive: Ваш акаунт ще не активований.\n      invalid: Неправильний %{authentication_keys} або пароль.\n      last_attempt: У вас є остання спроба, після якої вхід буде заблокований.\n      locked: Ваш акаунт заблокований.\n      not_found_in_database: Неправильний %{authentication_keys} або пароль.\n      timeout: Ваша сесія вичерпана. Будь ласка, зайдіть знову, щоб продовжити.\n      unauthenticated: Для продовження Вам потрібно увійти або зареєструватися.\n      unconfirmed: Для продовження Вам потрібно підтвердити Вашу поштову скриньку.\n    mailer:\n      confirmation_instructions:\n        subject: 'Mastodon: Інструкції для підтвердження %{instance}'\n      password_change:\n        subject: 'Mastodon: Ваш пароль змінений'\n      reset_password_instructions:\n        subject: 'Mastodon: Інструкції для скидання паролю'\n      unlock_instructions:\n        subject: 'Mastodon: Інструкції для розблокування'\n    omniauth_callbacks:\n      failure: Нам не вдалося аутентифікувати Вас з %{kind} через те, що \"%{reason}\".\n      success: Успішно аутентифіковано з акаунту %{kind}.\n    passwords:\n      no_token: Ви не можете отримати доступ до цієї сторінки без переходу за посиланням з листа з інструкціями. Якщо ви дійсно перейшли з цього листа, переконайтеся, що ви перейшли за повним посиланням.\n      send_instructions: Ви отримаєте листа з інструкціями щодо зміни паролю через декілька хвилин.\n      send_paranoid_instructions: Якщо Ваша поштова адреса існує у нашій базі даних, Ви отримаєте листа з інструкціями щодо зміни паролю через декілька хвилин.\n      updated: Ваш пароль було успішно змінено. Вхід виконано.\n      updated_not_active: Ваш пароль було успішно змінено.\n    registrations:\n      destroyed: До побачення! Ваш акаунт було успішно видалено. Сподіваємось, що Ви скоро повернетеся.\n      signed_up: Ласкаво просимо! Ви були успішно зареєстровані.\n      signed_up_but_inactive: Ви були успішно зареєстровані, але ми не можемо авторизувати вас, оскільки Ваш акаунт ще не активовано.\n      signed_up_but_locked: Ви були успішно зареєстровані, аале ми не можемо авторизувати вас, оскільки Ваш акаунт заблокований.\n      signed_up_but_unconfirmed: Повідомлення з посиланням на підтвердження будо відправлено на Вашу поштову скриньку. Будь ласка, перейдіть за посиланням, щоб активувати Ваш акаунт.\n      update_needs_confirmation: Ви успішно оновили Ваш акаунт, але нам потрібно підтвердити Вашу нову поштову адресу. Будь ласка, перевірте Вашу скриньку та перейдіть за посиланням, щоб активувати Вашу нову адресу.\n      updated: Ваш акаунт було успішно оновлено.\n    sessions:\n      already_signed_out: Ви вже вийшли з акаунту.\n      signed_in: Ви успішно увійшли в акаунт.\n      signed_out: Ви успішно вийшли з акаунту.\n    unlocks:\n      send_instructions: Ви отримаєте листа з інструкціями щодо розблокування Вашого акаунту через декілька хвилин.\n      send_paranoid_instructions: Якщо Ваш акаунт існує, Ви отримаєте листа з інструкціями щодо розблокування Вашого акаунту через декілька хвилин.\n      unlocked: Ваш акаунт було успішно активовано. Будь ласка, увійдіть, щоб продовжити.\n  errors:\n    messages:\n      already_confirmed: вже був підтверджений, будь ласка, спробуйте увійти\n      confirmation_period_expired: повинен бути підтверджений за %{period}, будь ласка, запросіть новий\n      expired: недійсний, будь ласка, запросіть новий\n      not_found: не знайдено\n      not_locked: не був заблокований\n      not_saved:\n        few: \"%{count} помилок не дало цьому %{resource} зберегтися:\"\n        many: \"%{count} помилок не дало цьому %{resource} зберегтися:\"\n        one: '1 помилка не дала цьому %{resource} зберегтися:'\n        other: \"%{count} помилок не дало цьому %{resource} зберегтися:\"\n"
  },
  {
    "path": "config/locales/devise.zh-CN.yml",
    "content": "---\nzh-CN:\n  devise:\n    confirmations:\n      confirmed: 成功验证你的邮箱地址。\n      send_instructions: 你的电子邮箱将在几分钟后收到一封确认邮件。如果没有，请检查你的垃圾邮箱。\n      send_paranoid_instructions: 如果你的邮箱存在于我们的数据库中，你将收到一封确认注册的邮件。如果没有，请检查你的垃圾邮箱。\n    failure:\n      already_authenticated: 你已经登录。\n      inactive: 你还没有激活帐户。\n      invalid: \"%{authentication_keys}或密码错误。\"\n      last_attempt: 你还有最后一次尝试机会，再次失败你的帐户将被锁定。\n      locked: 你的帐户已被锁定。\n      not_found_in_database: \"%{authentication_keys}或密码错误。\"\n      pending: 你的账户仍在审核中。\n      timeout: 你已登录超时，请重新登录。\n      unauthenticated: 继续操作前请注册或者登录。\n      unconfirmed: 继续操作前请先确认你的帐户。\n    mailer:\n      confirmation_instructions:\n        action: 验证电子邮件地址\n        action_with_app: 确认并返回%{app}\n        explanation: 你在 %{host} 上使用这个电子邮件地址创建了一个帐户。只需点击下面的链接，即可完成激活。如果你并没有创建过帐户，请忽略此邮件。\n        explanation_when_pending: 你用这个电子邮件申请了在 %{host} 注册。在确认电子邮件地址之后，我们会审核你的申请。在此之前，你不能登录。如果你的申请被驳回，你的数据会被移除，因此你无需再采取任何行动。如果申请人不是你，请忽略这封邮件。\n        extra_html: 请记得阅读<a href=\"%{terms_path}\">本服务器的相关规定</a>和<a href=\"%{policy_path}\">我们的使用条款</a>。\n        subject: Mastodon：确认 %{instance} 帐户信息\n        title: 验证电子邮件地址\n      email_changed:\n        explanation: 你的帐户的电子邮件地址即将变更为：\n        extra: 如果你并没有请求更改你的电子邮件地址，则他人很有可能已经入侵你的帐户。请立即更改你的密码；如果你已经无法访问你的帐户，请联系服务器管理员请求协助。\n        subject: Mastodon：电子邮件地址已被更改\n        title: 新电子邮件地址\n      password_change:\n        explanation: 你的帐户的密码已被更改。\n        extra: 如果你并没有请求更改你的密码，则他人很有可能已经入侵你的帐户。请立即更改你的密码；如果你已经无法访问你的帐户，请联系服务器的管理员请求协助。\n        subject: Mastodon：密码已被更改\n        title: 密码已被重置\n      reconfirmation_instructions:\n        explanation: 点击下面的链接来确认你的新电子邮件地址。\n        extra: 如果你并没有请求本次变更，请忽略此邮件。Mastodon 帐户的电子邮件地址只有在你点击上面的链接后才会更改。\n        subject: Mastodon：确认 %{instance} 电子邮件地址\n        title: 验证电子邮件地址\n      reset_password_instructions:\n        action: 更改密码\n        explanation: 点击下面的链接来更改帐户的密码。\n        extra: 如果你并没有请求本次变更，请忽略此邮件。你的密码只有在你点击上面的链接并输入新密码后才会更改。\n        subject: Mastodon：重置密码信息\n        title: 重置密码\n      unlock_instructions:\n        subject: Mastodon：帐户解锁信息\n    omniauth_callbacks:\n      failure: 由于%{reason}，无法从%{kind}获得授权。\n      success: 成功地从%{kind}获得授权。\n    passwords:\n      no_token: 你必须通过密码重置邮件才能访问这个页面。如果你确实如此，请确保你输入的 URL 是完整的。\n      send_instructions: 几分钟后，你将收到重置密码的电子邮件。如果没有，请检查你的垃圾邮箱。\n      send_paranoid_instructions: 如果你的邮箱存在于我们的数据库中，你将收到一封找回密码的邮件。如果没有，请检查你的垃圾邮箱。\n      updated: 你的密码已修改成功，你现在已登录。\n      updated_not_active: 你的密码已修改成功。\n    registrations:\n      destroyed: 再见！你的帐户已成功注销。我们希望很快可以再见到你。\n      signed_up: 欢迎！你已注册成功。\n      signed_up_but_inactive: 你已注册，但尚未激活帐户。\n      signed_up_but_locked: 你已注册，但帐户被锁定了。\n      signed_up_but_pending: 一封带有确认链接的邮件已经发送到了您的邮箱。 在您点击确认链接后，我们将会审核您的申请。审核通过后，我们将会通知您。\n      signed_up_but_unconfirmed: 一封带有确认链接的邮件已经发送至你的邮箱，请点击邮件中的链接以激活你的帐户。如果没有，请检查你的垃圾邮件。\n      update_needs_confirmation: 信息更新成功，但我们需要验证你的新电子邮件地址，请点击邮件中的链接以确认。如果没有，请检查你的垃圾邮箱。\n      updated: 帐户资料更新成功。\n    sessions:\n      already_signed_out: 已成功登出。\n      signed_in: 登录成功。\n      signed_out: 登出成功。\n    unlocks:\n      send_instructions: 几分钟后，你将收到一封解锁帐户的邮件。如果没有，请检查你的垃圾邮箱。\n      send_paranoid_instructions: 如果你的邮箱存在于我们的数据库中，你将收到一封解锁帐户的邮件。如果没有，请检查你的垃圾邮箱。\n      unlocked: 你的帐户已成功解锁。登录以继续。\n  errors:\n    messages:\n      already_confirmed: 已经确认成功，请尝试登录\n      confirmation_period_expired: 必须在 %{period}以内确认。请重新发起请求\n      expired: 已过期。请重新发起请求\n      not_found: 找不到\n      not_locked: 未被锁定\n      not_saved:\n        other: 发生 %{count} 个错误，导致%{resource}保存失败：\n"
  },
  {
    "path": "config/locales/devise.zh-HK.yml",
    "content": "---\nzh-HK:\n  devise:\n    confirmations:\n      confirmed: 你的電郵地址成功確認。\n      send_instructions: 你將會在幾分鐘內收到確認指示電郵，上面有確認你電郵地址的指示。\n      send_paranoid_instructions: 如果你的電郵地址已經存在於我們的資料庫，你將會在幾分鐘內收到電郵，確認你電郵地址的指示。\n    failure:\n      already_authenticated: 你之前已經登入了。\n      inactive: 您的帳號尚未啟用。\n      invalid: 不正確的 %{authentication_keys} 或密碼。\n      last_attempt: 若你再一次嘗試失敗，我們將鎖定你的帳號，以策安全。\n      locked: 你的帳號已被鎖定。\n      not_found_in_database: 不正確的 %{authentication_keys} 或密碼。\n      timeout: 你的登入階段已經過期，請重新登入以繼續使用。\n      unauthenticated: 你必須先登入或登記，以繼續使用。\n      unconfirmed: 你必須先確認電郵地址，繼續使用。\n    mailer:\n      confirmation_instructions:\n        action: 驗證電子郵件地址\n        explanation: 你在 %{host} 上使用這個電子郵件地址建立了一個帳戶。只需點擊下面的連結，即可啟用帳戶。如果你並沒有建立過帳戶，請忽略此郵件。\n        extra_html: 請記得閱讀本服務站的<a href=\"%{terms_path}\">相關規定</a>和<a href=\"%{policy_path}\">使用條款</a>。\n        subject: 'Mastodon: 確認電郵地址 %{instance}'\n        title: 驗證電子郵件地址\n      email_changed:\n        explanation: 你的帳戶的電子郵件地址即將變更為：\n        extra: 如果你沒有請求更改你的電子郵件地址，則他人很有可能已經入侵你的帳戶。請立即更改你的密碼；如果你已經無法訪問你的帳戶，請聯繫服務站的管理員請求協助。\n        subject: Mastodon：電子郵件地址已被更改\n        title: 新電子郵件地址\n      password_change:\n        explanation: 你的帳戶的密碼已被更改。\n        extra: 如果你沒有請求更改你的密碼，則他人很有可能已經入侵你的帳戶。請立即更改你的密碼；如果你已經無法訪問你的帳戶，請聯繫服務站的管理員請求協助。\n        subject: 'Mastodon: 更改密碼'\n        title: 密碼已被重設\n      reconfirmation_instructions:\n        explanation: 點擊下面的連結來確認你的新電子郵件地址。\n        extra: 如果你沒有請求本次變更，請忽略此郵件。 Mastodon 帳戶的電子郵件地址只有在你點擊上面的連結後才會更改。\n        subject: Mastodon：確認 %{instance} 電子郵件地址\n        title: 驗證電子郵件地址\n      reset_password_instructions:\n        action: 更改密碼\n        explanation: 點擊下面的連結來更改帳戶的密碼。\n        extra: 如果你沒有請求本次變更，請忽略此郵件。你的密碼只有在你點擊上面的連結並輸入新密碼後才會更改。\n        subject: 'Mastodon: 重設密碼'\n        title: 重設密碼\n      unlock_instructions:\n        subject: 'Mastodon: 解除用戶鎖定'\n    omniauth_callbacks:\n      failure: 無法以 %{kind} 登入你的用戶，原因是︰「%{reason}」。\n      success: 成功以 %{kind} 登入你的用戶。\n    passwords:\n      no_token: 你必須使用重設密碼電郵內的網址進入本頁。如果你確是使用電郵內的網址，請確認你用了完整的網址。\n      send_instructions: 你將在幾分鐘內收到重設密碼的電郵指示。\n      send_paranoid_instructions: 如果你的電郵地址已經存在於我們的資料庫，你將會在幾分鐘內收到重設密碼的電郵指示。\n      updated: 你的密碼已經更新，你現在正登入本站。\n      updated_not_active: 你的密碼已經更新。\n    registrations:\n      destroyed: 再見了！你的用戶已被取消，希望我們相有相見的機會吧。\n      signed_up: 歡迎你！你的登記已經成功。\n      signed_up_but_inactive: 你的登記已經成功，可是由於你的用戶還被被啟用，暫時還不能讓你登入。\n      signed_up_but_locked: 你的登記已經成功，可是由於你的用戶已被鎖定，我們無法讓你登入。\n      signed_up_but_unconfirmed: 一條確認連結已經電郵到你的郵址。請使用讓連結啟用你的用戶。\n      update_needs_confirmation: 你的用戶已經更新，但我們需要確認你的電郵地址。請打開你的郵箱，使用確認電郵的連結來確認的地郵址。\n      updated: 你的用戶已經成功更新。\n    sessions:\n      already_signed_out: 成功登出。\n      signed_in: 成功登入。\n      signed_out: 成功登出。\n    unlocks:\n      send_instructions: 你將在幾分鐘內收到解除用戶鎖定的電郵指示。\n      send_paranoid_instructions: 如果你的電郵地址已經存在於我們的資料庫，你將在幾分鐘內收到解除用戶鎖定的電郵指示。\n      unlocked: 你的用戶已經解鎖，請登入以繼續。\n  errors:\n    messages:\n      already_confirmed: 先前已經確認，請嘗試登入\n      confirmation_period_expired: 需要在 %{period} 之內確認。請重新申請\n      expired: 已經過期，請重新申請\n      not_found: 找不到\n      not_locked: 並未被鎖定\n      not_saved:\n        other: \"%{count} 個錯誤令 %{resource} 無法被儲存︰\"\n"
  },
  {
    "path": "config/locales/devise.zh-TW.yml",
    "content": "---\nzh-TW:\n  devise:\n    confirmations:\n      confirmed: 您的電子信箱位址已確認成功。\n      send_instructions: 幾分鐘後您將收到確認信件。若未收到此信件，請檢查垃圾郵件資料夾。\n      send_paranoid_instructions: 如果您的電子信箱存在於我們的資料庫，將會在幾分鐘內收到確認信。若未收到請檢查垃圾郵件資料夾。\n    failure:\n      already_authenticated: 您已登入。\n      inactive: 您的帳戶尚未啟用。\n      invalid: 無效的 %{authentication_keys} 或密碼。\n      last_attempt: 在帳號遭封鎖前您還有最後一次嘗試機會。\n      locked: 您的帳戶已被鎖定。\n      not_found_in_database: 無效的 %{authentication_keys} 或密碼。\n      pending: 您的帳戶仍在審核中。\n      timeout: 登入階段逾時。請重新登入以繼續。\n      unauthenticated: 您必須先登入或註冊以繼續使用。\n      unconfirmed: 您必須先確認電子信箱才能繼續使用。\n    mailer:\n      confirmation_instructions:\n        action: 驗證電子信箱位址\n        action_with_app: 確認並返回 %{app}\n        explanation: 您已經在 %{host} 上以此電子信箱位址建立了一支帳戶。您距離啟用它只剩一點之遙了。若這不是您，請忽略此信件。\n        explanation_when_pending: 您使用此電子信箱位址申請了 %{host} 的邀請。當您確認電子信箱後我們將審核您的申請，而直到核准前您都無法登入。當您的申請遭拒絕，您的資料將被移除而不必做後續動作。如果這不是您，請忽略此信件。\n        extra_html: 同時也請看看<a href=\"%{terms_path}\">該伺服器的規則</a>與<a href=\"%{policy_path}\">服務條款</a>。\n        subject: Mastodon：%{instance} 確認說明\n        title: 驗證電子信箱位址\n      email_changed:\n        explanation: 您帳戶的電子信箱位址將變更為：\n        extra: 若您未變更電子信箱，那麼很有可能是某人取得了你帳戶的存取權限。請立刻變更密碼，或當帳戶被鎖定時，請聯絡伺服器的管理員。\n        subject: Mastodon：已變更電子信箱\n        title: 新電子信箱位址\n      password_change:\n        explanation: 您帳戶的密碼已變更。\n        extra: 如果您未變更密碼，那麼很有可能是某人取得了帳戶的存取權限。請立刻變更密碼，或若帳戶被鎖定時，請聯絡伺服器的管理員。\n        subject: Mastodon：已變更密碼\n        title: 密碼已變更\n      reconfirmation_instructions:\n        explanation: 請確認新的電子信箱位址以變更。\n        extra: 若此次變更不是由您開啟的，請忽略此信件。Mastodon 帳戶的電子信箱位址在您存取上面的連結前不會變更。\n        subject: Mastodon：確認 %{instance} 的電子信箱位址\n        title: 驗證電子信箱位址\n      reset_password_instructions:\n        action: 變更密碼\n        explanation: 您已請求設定帳號的新密碼。\n        extra: 若您並未請求，請忽略此信件。您的密碼在存取上方連結並建立新連結前不會變更。\n        subject: Mastodon：重設密碼指引\n        title: 重設密碼\n      unlock_instructions:\n        subject: Mastodon：帳戶解鎖指引\n    omniauth_callbacks:\n      failure: 無法透過 %{kind} 認證是否為您，因為「%{reason}」。\n      success: 成功透過 %{kind} 登入帳戶。\n    passwords:\n      no_token: 您必須透過密碼重設信件才能存取此頁面。若確實如此，請確定輸入的網址是完整的。\n      send_instructions: 若電子信箱位址存在於資料庫，幾分鐘後您將在信箱中收到密碼復原連結。若未收到請檢查垃圾郵件資料夾。\n      send_paranoid_instructions: 若電子信箱位址存在於資料庫，幾分鐘後您將在信箱中收到密碼復原連結。若未收到請檢查垃圾郵件資料夾。\n      updated: 您的密碼已成功變更，現在已經登入。\n      updated_not_active: 您的密碼已成功變更。\n    registrations:\n      destroyed: 再見！您的帳戶已成功取消，期待再相逢。\n      signed_up: 歡迎！您已成功註冊。\n      signed_up_but_inactive: 您已註冊成功，但由於您的帳戶尚未啟用，我們暫時無法讓您登入。\n      signed_up_but_locked: 您已註冊成功，但由於您的帳戶已被鎖定，我們無法讓您登入。\n      signed_up_but_pending: 包含確認連結的訊息已寄到您的電子信箱。按下此連結後我們將審核您的申請。核准後將通知您。\n      signed_up_but_unconfirmed: 包含確認連結的訊息已寄到您的電子信箱。請前往連結以啟用帳號。若未收到請檢查垃圾郵件資料夾。\n      update_needs_confirmation: 已更新您的帳號，但仍需驗證您的新信箱。請檢查電子信箱並前往確認連結來確認新信箱位址。若未收到請檢查垃圾郵件資料夾。\n      updated: 您的帳戶已成功更新。\n    sessions:\n      already_signed_out: 已成功登出。\n      signed_in: 已成功登入。\n      signed_out: 已成功登出。\n    unlocks:\n      send_instructions: 幾分鐘後您將收到解鎖帳號的指引信件。若未收到請檢查垃圾郵件資料夾。\n      send_paranoid_instructions: 若此帳號存在，您將在幾分鐘後收到解鎖指引信件。若未收到請檢查垃圾郵件資料夾。\n      unlocked: 已解鎖您的帳戶，請登入繼續。\n  errors:\n    messages:\n      already_confirmed: 已經確認，請嘗試登入\n      confirmation_period_expired: 需要在 %{period} 內完成驗證。請重新申請\n      expired: 已經過期，請重新請求\n      not_found: 找不到\n      not_locked: 並未被鎖定\n      not_saved:\n        other: 因 %{count} 錯誤導致 %{resource} 無法儲存：\n"
  },
  {
    "path": "config/locales/doorkeeper.ar.yml",
    "content": "---\nar:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: التسمية\n        redirect_uri: عنوان التحويل\n        scopes: المجالات\n        website: تطبيق الويب\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              fragment_present: لا يجب أن يحتوي على كِسرة.\n              invalid_uri: يجب أن يكون رابطا صالحا.\n              relative_uri: يجب أن يكون رابطا مطلقا.\n              secured_uri: يجب أن يكون رابطا آمنا HTTPS/SSL.\n  doorkeeper:\n    applications:\n      buttons:\n        authorize: ترخيص\n        cancel: إلغاء\n        destroy: إبطال\n        edit: تعديل\n        submit: إرسال\n      confirmations:\n        destroy: متأكد ؟\n      edit:\n        title: تعديل التطبيق\n      form:\n        error: عفوا ! تحقق من خُلوّ الاستمارة من الأخطاء من فضلك\n      help:\n        native_redirect_uri: إستخدم %{native_redirect_uri} للاختبار و التجريب محليا\n        redirect_uri: إستخدم خطا واحدا لكل رابط\n        scopes: تقسيم المجالات بمسافات بيضاء. بدون تحديد قيمة يعني ذلك استخدام المجالات الإفتراضية.\n      index:\n        application: تطبيق\n        callback_url: رابط رد النداء\n        delete: حذف\n        name: التسمية\n        new: تطبيق جديد\n        scopes: المجالات\n        show: عرض\n        title: تطبيقاتك\n      new:\n        title: تطبيق جديد\n      show:\n        actions: الإجراءات\n        application_id: معرف التطبيق\n        callback_urls: روابط رد النداء\n        scopes: المجالات\n        secret: السر\n        title: 'تطبيق: %{name}'\n    authorizations:\n      buttons:\n        authorize: ترخيص\n        deny: رفض\n      error:\n        title: حدث هناك خطأ\n      new:\n        able_to: يُخوَّل لهذا التطبيق القيام بـ\n        prompt: طلبَ تطبيق %{client_name} تصريحا لاستعمال حسابك\n        title: إذن بالتصريح\n      show:\n        title: قم بنسخ رمز المصادقة و إلصاقه على التطبيق.\n    authorized_applications:\n      buttons:\n        revoke: إبطال التصريح\n      confirmations:\n        revoke: متأكد ؟\n      index:\n        application: التطبيق\n        created_at: صُرّح له في\n        date_format: \"%Y-%m-%d %H:%M:%S\"\n        scopes: المجالات\n        title: تطبيقاتك المرخص لها\n    errors:\n      messages:\n        access_denied: لقد رفض مالك المَورِدِ أو تصريح السيرفر طلبك.\n        invalid_client: فشلت المصادقة مع العميل لأنه العميل مجهول أو لغياب المصادقة ضمن العميل أو أنّ أسلوب المصادقة غير مدعومة.\n        invalid_grant: إنّ التصريح المقدَّم غير صالح، سواء انتهت مدة صلاحيته أو تم إلغاؤه أو أنه لا يتطابق مع عنوان إعادة التحويل في طلب التصريح أو أنّ هذا التصريح قد تم تقديمه لعميل آخر.\n        invalid_redirect_uri: إنّ عنوان إعادة التحويل غير صالح.\n        invalid_request: إنّ هذا الطلب يستلزم مؤشرا أو يحمل قيمة مُعامِل غير مدعومة أو فيه خلل ما.\n        invalid_resource_owner: إنّ المُعرِّفات التي قدّمها صاحب المورِد غير صحيحة أو أنه لا وجود لصاحب المورِد\n        invalid_scope: المجال المطلوب غير صحيح أو مجهول أو مُعبَّر عنه بشكل خاطئ.\n        invalid_token:\n          expired: انتهت فترة صلاحيته رمز المصادقة\n          revoked: تم إبطال رمز المصادقة\n          unknown: رمز المصادقة غير صالح\n        resource_owner_authenticator_not_configured: لقد أخفقت عملية البحث عن صاحب المَورِد لغياب الضبط في Doorkeeper.configure.resource_owner_authenticator.\n        server_error: لقد صادفَ خادوم التصريحات ظروفا غير مواتية، الأمر الذي مَنَعه مِن مواصلة دراسة الطلب.\n        temporarily_unavailable: تعذر على خادم التفويض معالجة الطلب و ذلك بسبب زيادة مؤقتة في التحميل أو عملية صيانة مبرمجة على الخادم.\n        unauthorized_client: لا يصرح للعميل بتنفيذ هذا الطلب باستخدام هذه الطريقة.\n        unsupported_grant_type: هذا النوع من منح التصريح غير معتمد في خادم الترخيص.\n        unsupported_response_type: لا يدعم خادم التصريح هذا النوع من الإجابات و الردود.\n    flash:\n      applications:\n        create:\n          notice: تم إنشاء التطبيق.\n        destroy:\n          notice: تم حذف التطبيق.\n        update:\n          notice: تم تحديث التطبيق.\n      authorized_applications:\n        destroy:\n          notice: تم إبطال التصريح المخول للتطبيق.\n    layouts:\n      admin:\n        nav:\n          applications: التطبيقات\n          oauth2_provider: مزود خدمة التصريح المفتوح OAuth2\n      application:\n        title: طلب تصريح مفتوح OAuth\n    scopes:\n      follow: تعديل علاقات الحساب\n      push: تلقي إشعاراتك\n      read: قراءة كافة بيانات حسابك\n      read:accounts: معاينة معلومات الحساب\n      read:blocks: رؤية الحسابات التي قمت بحجبها\n      read:favourites: رؤية مفضلاتك\n      read:filters: رؤية عوامل التصفية الخاصة بك\n      read:follows: رؤية متابِعيك\n      read:lists: رؤية قوائمك\n      read:mutes: رؤية الحسابات التي كَتمتَها\n      read:notifications: رؤية إشعاراتك الخاصة\n      read:reports: رؤية إبلاغاتك\n      read:search: البحث مكانك\n      read:statuses: رؤية كافة المنشورات\n      write: تغيير كافة بيانات حسابك\n      write:accounts: تعديل ملفك الشخصي\n      write:blocks: حجب الحسابات و النطاقات\n      write:favourites: الإعجاب بمنشورات\n      write:filters: إنشاء عوامل تصفية\n      write:follows: متابَعة الأشخاص\n      write:lists: إنشاء القوائم\n      write:media: إرسال الصور\n      write:mutes: كتم الأشخاص و المحادثات\n      write:notifications: مسح إشعاراتك\n      write:reports: الإبلاغ عن الأشخاص نيابة عنك\n      write:statuses: نشر منشورات\n"
  },
  {
    "path": "config/locales/doorkeeper.ast.yml",
    "content": "---\nast:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: Nome de l'aplicación\n        website: Sitiu web de l'aplicación\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              invalid_uri: ha ser una URI válida.\n              relative_uri: ha ser una URI absoluta.\n  doorkeeper:\n    applications:\n      buttons:\n        cancel: Encaboxar\n        destroy: Destruyir\n        edit: Editar\n        submit: Unviar\n      index:\n        name: Nome\n      show:\n        actions: Aiciones\n        title: 'Aplicación: %{name}'\n    authorizations:\n      error:\n        title: Asocedió un fallu\n      new:\n        able_to: Va ser a\n        prompt: L'aplicación %{client_name} solicitó l'accesu a la to cuenta\n      show:\n        title: Copia esti códigu d'autorización y apégalu na aplicación.\n    authorized_applications:\n      buttons:\n        revoke: Revocar\n      index:\n        date_format: \"%H:%M:%S %d-%m-%Y\"\n        title: Les aplicaciones qu'autoricesti\n    errors:\n      messages:\n        invalid_token:\n          expired: Caducó'l pase d'accesu\n          revoked: Revocóse'l pase d'accesu\n          unknown: El pase d'accesu nun ye válidu\n        unauthorized_client: El veceru nun ta autorizáu pa facer esta solicitú usando esti métodu.\n        unsupported_response_type: El sirvidor d'autorización nun sofita esta triba de rempuesta.\n    layouts:\n      admin:\n        nav:\n          applications: Aplicaciones\n          oauth2_provider: Fornidor d'OAuth2\n    scopes:\n      read:accounts: ver información de cuentes\n      read:blocks: ver quién bloquies\n      read:filters: ver les tos peñeres\n      read:follows: ver quién sigues\n      read:lists: ver les tos llistes\n      read:mutes: ver quién silencies\n      read:notifications: ver los tos avisos\n      read:statuses: ver tolos estaos\n      write: modificar los datos de la to cuenta\n      write:accounts: modificar el to perfil\n      write:blocks: bloquiar cuentes y dominios\n      write:filters: crear peñeres\n      write:follows: siguir a xente\n      write:lists: crear llistes\n      write:media: xubir ficheros de medios\n      write:mutes: silenciar xente y conversaciones\n      write:notifications: llimpiar los tos avisos\n      write:statuses: espublizar estaos\n"
  },
  {
    "path": "config/locales/doorkeeper.bg.yml",
    "content": "---\nbg:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: Име\n        redirect_uri: URI за пренасочване\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              fragment_present: не може да съдържа фрагмент.\n              invalid_uri: трябва да е валидно URI.\n              relative_uri: трябва да е абсолютно URI.\n              secured_uri: трябва да е HTTPS/SSL URI.\n  doorkeeper:\n    applications:\n      buttons:\n        authorize: Упълномощаване\n        cancel: Отказ\n        destroy: Унищожаване\n        edit: Редакция\n        submit: Изпращане\n      confirmations:\n        destroy: Потвърждаваш ли изтриването?\n      edit:\n        title: Редактиране на приложението\n      form:\n        error: О, не! Провери формата за възможни грешки\n      help:\n        native_redirect_uri: Изполвай %{native_redirect_uri} за локални тестове\n        redirect_uri: Използвай един ред за всяко URI\n        scopes: Разделяй диапазоните с интервал. Остави празно, за да използваш диапазона по подразбиране.\n      index:\n        callback_url: URL за обратно повикване\n        name: Име\n        new: Ново приложение\n        title: Твоите приложения\n      new:\n        title: Ново приложение\n      show:\n        actions: Действия\n        application_id: Идентификатор на приложението\n        callback_urls: URL-и за обратно повикване\n        scopes: Диапазони\n        secret: Тайна\n        title: 'Приложение: %{name}'\n    authorizations:\n      buttons:\n        authorize: Упълномощаване\n        deny: Отказ\n      error:\n        title: Възникна грешка\n      new:\n        able_to: Ще е възможно\n        prompt: Приложението %{client_name} заявява достъп до твоя акаунт\n        title: Изисква се упълномощаване\n    authorized_applications:\n      buttons:\n        revoke: Отмяна\n      confirmations:\n        revoke: Потвърждаваш ли отмяната?\n      index:\n        application: Приложение\n        created_at: Създадено на\n        scopes: Диапазони\n        title: Твоите упълномощени приложения\n    errors:\n      messages:\n        access_denied: Заявката беше отказана от собственика на ресурса или от сървъра за упълномощаване.\n        credential_flow_not_configured: Resource Owner Password Credentials предизвика грешка, заради това, че настройките за Doorkeeper.configure.resource_owner_from_credentials липсват.\n        invalid_client: Удостоверяването на клиента предизвика грешка, поради непознат клиент, липсващо клиентско удостоверяване, или заради това, че методът на удостоверяване не се поддържа.\n        invalid_grant: Предоставеното удостоверение за достъп е невалидно, изтекло, отхвърлено, не съвпада с пренасочващото URI, използвано в заявката за удостоверение, или е бил издадено от друг клиент.\n        invalid_redirect_uri: Наличното пренасочващо URI е невалидно.\n        invalid_request: Заявката е с липсващ задължителен параметър, включва стойност на параметъра, която не се поддържа, или е изкривена по друг начин.\n        invalid_resource_owner: Предоставените идентификационни данни на притежателя на ресурса са невалидни, или притежателят не може да бъде намерен.\n        invalid_scope: Заявеният диапазон е невалиден, неизвестен или изкривен.\n        invalid_token:\n          expired: Маркерът за достъп изтече\n          revoked: Маркерът за достъп беше отхвърлен\n          unknown: Маркерът за достъп е невалиден\n        resource_owner_authenticator_not_configured: Намирането на Resource Owner се провали поради липса на конфигурация на Doorkeeper.configure.resource_owner_authenticator.\n        server_error: Сървърът за удостоверяване попадна на неочаквано условие, което предотврати изпълнението на заявката.\n        temporarily_unavailable: Сървърът за удостоверяване не може да се справи със заявката в момента поради временно претоварване или профилактика на сървъра.\n        unauthorized_client: Клиентът не е удостоверен да изпълни заявката по този начин.\n        unsupported_grant_type: Типът на удостоврението за достъп не се поддържа от сървъра за удостоверяване.\n        unsupported_response_type: Удостоверяващият сървър не поддържа този тип отговор.\n    flash:\n      applications:\n        create:\n          notice: Приложението е създадено.\n        destroy:\n          notice: Приложението е изтрито.\n        update:\n          notice: Приложението е обновено.\n      authorized_applications:\n        destroy:\n          notice: Приложението е отказано.\n    layouts:\n      admin:\n        nav:\n          applications: Приложения\n          oauth2_provider: OAuth2 доставчик\n      application:\n        title: Нужно е упълномощаване по OAuth\n    scopes:\n      follow: следването, блокирането, деблокирането и отмяната на следването на акаунтите\n      read: четенето на данните от твоя акаунт\n      write: публикуването от твое име\n"
  },
  {
    "path": "config/locales/doorkeeper.bn.yml",
    "content": "bn:\n"
  },
  {
    "path": "config/locales/doorkeeper.ca.yml",
    "content": "---\nca:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: Nom de l'aplicació\n        redirect_uri: URI per a redirecció\n        scopes: Àmbits\n        website: Lloc web de l'aplicació\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              fragment_present: no pot contenir un fragment.\n              invalid_uri: ha de ser un URI válid.\n              relative_uri: ha de ser un URI absoluta.\n              secured_uri: ha de ser un URI HTTPS/SSL.\n  doorkeeper:\n    applications:\n      buttons:\n        authorize: Autoritza\n        cancel: Cancel⋅la\n        destroy: Destrueix\n        edit: Edita\n        submit: Envia\n      confirmations:\n        destroy: Estàs segur?\n      edit:\n        title: Edita l'aplicació\n      form:\n        error: Ep! Comprova el formulari per a possibles errors\n      help:\n        native_redirect_uri: Utilitza %{native_redirect_uri} per a proves locals\n        redirect_uri: Utilitza una línia per URI\n        scopes: Separa els àmbits amb espais. Deixa-ho en blanc per a utilitzar els àmbits per defecte.\n      index:\n        application: Aplicació\n        callback_url: URL de retorn\n        delete: Suprimeix\n        name: Nom\n        new: Aplicació nova\n        scopes: Àmbits\n        show: Mostra\n        title: Les teves aplicacions\n      new:\n        title: Aplicació nova\n      show:\n        actions: Accions\n        application_id: Id de l'aplicació\n        callback_urls: Callback URL\n        scopes: Àmbits\n        secret: Secret\n        title: 'Aplicació: %{name}'\n    authorizations:\n      buttons:\n        authorize: Autoritza\n        deny: Desautoritza\n      error:\n        title: S'a produit un error\n      new:\n        able_to: Serà capaç de\n        prompt: L'aplicació %{client_name} sol⋅licita tenir accés al teu compte\n        title: Cal autorizació\n      show:\n        title: Copia aquest coddi d'autorització i enganxa'l en l'aplicació.\n    authorized_applications:\n      buttons:\n        revoke: Revoca\n      confirmations:\n        revoke: Estàs segur?\n      index:\n        application: Aplicació\n        created_at: Creat el\n        date_format: \"%A-%m-%d %H:%M:%S\"\n        scopes: Àmbits\n        title: Les teves aplicacions autoritzades\n    errors:\n      messages:\n        access_denied: El propietari del recurs o servidor d'autorizació ha denegat la petició.\n        credential_flow_not_configured: Les credencials de contrasenya del propietari del recurs han fallat degut a que Doorkeeper.configure.resource_owner_from_credentials està sense configurar.\n        invalid_client: La autentificació del client ha fallat perquè és un client desconegut o no està inclòs l'autentificació del client o el mètode d'autenticació no està confirmat.\n        invalid_grant: La concessió d'autorizació oferida és invàlida, ha vençut, s'ha revocat, no coincideix amb l'URI de redirecció utilizada en la petició d'autorizació, o fou emesa per a un altre client.\n        invalid_redirect_uri: L'URI de redirecció inclòs no és vàlid.\n        invalid_request: En la petició manca un paràmetre necessari o inclou un valor de paràmetre no suportat o te un altre tipus de format incorrecte.\n        invalid_resource_owner: Les credencials del propietari del recurs proporcionat no son vàlides, o el propietari del recurs no pot ser trobat\n        invalid_scope: L'àmbit demanat és invàlid, desconegut o erroni.\n        invalid_token:\n          expired: L'identificador d'accés ha caducat\n          revoked: L'identificador d'accés fou revocat\n          unknown: L'identificador d'accés és invàlid\n        resource_owner_authenticator_not_configured: El propietari del recurs ha fallat perquè Doorkeeper.configure.resource_owner_authenticator està sense configurar.\n        server_error: El servidor de l'autorizació ha trobat unca condició inesperada que ha impedit complir la sol·licitud.\n        temporarily_unavailable: El servidor de l'autorizació és actualment incapaç de gestionar la petició degut a una sobrecàrrega temporal o una tasca de manteniment del servidor.\n        unauthorized_client: El client no està autoritzat a fer aquesta petició utilitzant aquest mètode.\n        unsupported_grant_type: El tipus de concessió d'autorització no està suportat pel servidor d'autorizació.\n        unsupported_response_type: El servidor d'autorizació no suporta aquest tipus de resposta.\n    flash:\n      applications:\n        create:\n          notice: Aplicació creada.\n        destroy:\n          notice: Aplicació eliminada.\n        update:\n          notice: Aplicació actualitzada.\n      authorized_applications:\n        destroy:\n          notice: Aplicació revocada.\n    layouts:\n      admin:\n        nav:\n          applications: Aplicacions\n          oauth2_provider: Proveïdor OAuth2\n      application:\n        title: OAuth autorització requerida\n    scopes:\n      follow: seguir, blocar, desblocar i deixar de seguir comptes\n      push: rebre notificacions push del teu compte\n      read: llegir les dades del teu compte\n      read:accounts: veure informació dels comptes\n      read:blocks: veure els teus bloqueijos\n      read:favourites: veure els teus favorits\n      read:filters: veure els teus filtres\n      read:follows: veure els teus seguiments\n      read:lists: veure les teves llistes\n      read:mutes: veure els teus silenciats\n      read:notifications: veure les teves notificacions\n      read:reports: veure els teus informes\n      read:search: cerca en nom teu\n      read:statuses: veure tots els toots\n      write: publicar en el teu nom\n      write:accounts: modifica el teu perfil\n      write:blocks: bloqueja comptes i dominis\n      write:favourites: afavoreix toots\n      write:filters: crear filtres\n      write:follows: seguir usuaris\n      write:lists: crear llistes\n      write:media: pujar fitxers multimèdia\n      write:mutes: silencia usuaris i converses\n      write:notifications: esborra les teves notificacions\n      write:reports: informe d’altres persones\n      write:statuses: publicar toots\n"
  },
  {
    "path": "config/locales/doorkeeper.co.yml",
    "content": "---\nco:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: Nome di l’applicazione\n        redirect_uri: URI di ridirezzione\n        scopes: Scopi\n        website: Situ di l’applicazione\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              fragment_present: ùn pò cuntene un pezzu.\n              invalid_uri: duve esse un’URI curretta.\n              relative_uri: duve esse un’URI assoluta.\n              secured_uri: duve esse un’URL HTTPS/SSL.\n  doorkeeper:\n    applications:\n      buttons:\n        authorize: Appruvà\n        cancel: Sguassà\n        destroy: Strughje\n        edit: Mudificà\n        submit: Mandà\n      confirmations:\n        destroy: Site sicuru·a?\n      edit:\n        title: Mudificà l’applicazione\n      form:\n        error: Uups! V’invitemu à verificà u vostru formulariu per vede s’elli ùn ci sò sbaglii\n      help:\n        native_redirect_uri: Utilizate %{native_redirect_uri} pè e prove lucale\n        redirect_uri: Utilizzate una linea per ogni URI\n        scopes: Separate i scopi cù spazii. Lasciate viotu per utilizzà i scopi predefiniti.\n      index:\n        application: Applicazione\n        callback_url: URL di richjama\n        delete: Toglie\n        name: Nome\n        new: Applicazione nova\n        scopes: Scopi\n        show: Vede\n        title: E vostre applicazione\n      new:\n        title: Applicazione nova\n      show:\n        actions: Azzioni\n        application_id: Chjave di u clientu\n        callback_urls: URL di richjama\n        scopes: Scopi\n        secret: Sicretu di u clientu\n        title: 'Applicazione : %{name}'\n    authorizations:\n      buttons:\n        authorize: Appruvà\n        deny: Ricusà\n      error:\n        title: C’hè statu un prublemu\n      new:\n        able_to: St’applicazione puderà\n        prompt: L’applicazione %{client_name} hà dumandatu d’avè accessu à u vostru contu\n        title: Permessu riquestu\n      show:\n        title: Codice d’auturizazione da cupià indè l’applicazione.\n    authorized_applications:\n      buttons:\n        revoke: Sguassà\n      confirmations:\n        revoke: Site sicuru·a?\n      index:\n        application: Applicazione\n        created_at: Auturizata u\n        date_format: \"%d-%m-%Y %H:%M:%S\"\n        scopes: Scopi\n        title: E vostre applicazione auturizate\n    errors:\n      messages:\n        access_denied: U pruprietariu di a risorsa o u servore d’autitinficazione hà ricusatu a dumanda.\n        credential_flow_not_configured: U flussu di l’identificazione di u pruprietariu di a risorsa hà fiascatu perchè Doorkeeper.configure.resource_owner_from_credentials ùn hè micca cunfiguratu.\n        invalid_client: L’autintificazione di u cliente hà fiascatu perchè u cliente ùn hè micca cunnisciutu, l’identificazione di u cliente ùn hè cumpresa, o u modu d’identificazione ùn marchja micca.\n        invalid_grant: L’accunsentu d’auturizazione furnitu ùn hè currettu, hè spiratu, sguassatu, ùn và micca cù l’indirizzu di ridirezzione usatu in a dumanda d’auturizazione, o hè statu emessu per un’altru cliente.\n        invalid_redirect_uri: L’URI di ridirezzione ùn hè curretta.\n        invalid_request: Ci manca un parametru riquestu indè a dumanda, cuntene un parametru ch’ùn esiste micca, o altru sbagliu di forma.\n        invalid_resource_owner: L’idintificanti di u pruprietariu di a risorsa ùn sò curretti, o u pruprietariu ùn pò micca esse trovu\n        invalid_scope: U scopu dumandatu ùn hè currettu, hè scunnisciutu, o altru sbagliu di forma.\n        invalid_token:\n          expired: A marca d’accessu hè spirata\n          revoked: A marca d’accessu hè stata rivucata\n          unknown: A marca d’accessu ùn hè curretta\n        resource_owner_authenticator_not_configured: Ùn c’hè micca pussutu ricercà u pruprietariu di a risorsa perchè Doorkeeper.configure.resource_owner_authenticator ùn hè micca cunfiguratu.\n        server_error: C’hè statu un prublemu cù u servore d’auturizazione.\n        temporarily_unavailable: U servore d’auturizazione ùn pò micca trattà a dumanda avà perchè hè sopraccaricatu o in mantenimentu.\n        unauthorized_client: U cliente ùn pò micca fà sta dumanda cusì.\n        unsupported_grant_type: Stu tippu d’accunsentu ùn marchja micca nant’à stu servore d’auturizazione.\n        unsupported_response_type: Sta risposta ùn marchja micca nant’à stu servore d’auturizazione.\n    flash:\n      applications:\n        create:\n          notice: Applicazione creata.\n        destroy:\n          notice: Applicazione sguassata.\n        update:\n          notice: Applicazione messa à ghjornu.\n      authorized_applications:\n        destroy:\n          notice: Applicazione sguassata.\n    layouts:\n      admin:\n        nav:\n          applications: Applicazione\n          oauth2_provider: Furnitore OAuth2\n      application:\n        title: Auturizazione OAuth riquestata\n    scopes:\n      follow: Mudificà rilazione trà i conti\n      push: Riceve e vostre nutificazione push\n      read: leghje tutte l’infurmazioni di u vostru contu\n      read:accounts: Vede l'infurmazione di i conti\n      read:blocks: vede i vostri blucchimi\n      read:favourites: vede i vostri favuriti\n      read:filters: vede i vostri filtri\n      read:follows: vede i vostri abbunamenti\n      read:lists: vede e vostre liste\n      read:mutes: vede i vostri piattati\n      read:notifications: vede e vostre nutificazione\n      read:reports: vede i vostri signalamenti\n      read:search: ricercà per voi\n      read:statuses: vede tutti i statuti\n      write: mudificà i dati di u vostru contu\n      write:accounts: mudificà u prufile\n      write:blocks: bluccà conti è dumini\n      write:favourites: aghjustà statuti à i favuriti\n      write:filters: creà filtri\n      write:follows: siguità conti\n      write:lists: creà liste\n      write:media: caricà fugliali media\n      write:mutes: piattà persone è cunversazione\n      write:notifications: sguassà e nutificazione\n      write:reports: palisà altre persone\n      write:statuses: pubblicà statuti\n"
  },
  {
    "path": "config/locales/doorkeeper.cs.yml",
    "content": "---\ncs:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: Název aplikace\n        redirect_uri: URI přesměrování\n        scopes: Rozsahy\n        website: Stránka aplikace\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              fragment_present: nesmí obsahovat fragment.\n              invalid_uri: musí být platné URI.\n              relative_uri: musí být apsolutní URI.\n              secured_uri: musí být URI HTTPS/SSL.\n  doorkeeper:\n    applications:\n      buttons:\n        authorize: Autorizovat\n        cancel: Zrušit\n        destroy: Zničit\n        edit: Upravit\n        submit: Odeslat\n      confirmations:\n        destroy: Jste si jistý/á?\n      edit:\n        title: Upravit aplikaci\n      form:\n        error: A jéje! Zkontrolujte svůj formulář kvůli případným chybám\n      help:\n        native_redirect_uri: Pro místní testy použijte %{native_redirect_uri}\n        redirect_uri: Jedno URI na každý řádek\n        scopes: Oddělujte rozsahy mezerami. Pro použití výchozích rozsahů zanechte prázdné.\n      index:\n        application: Aplikace\n        callback_url: Zpáteční URL\n        delete: Smazat\n        name: Název\n        new: Nová aplikace\n        scopes: Rozsahy\n        show: Zobrazit\n        title: Vaše aplikace\n      new:\n        title: Nová aplikace\n      show:\n        actions: Akce\n        application_id: Klientský klíč\n        callback_urls: Zpáteční URL\n        scopes: Rozsahy\n        secret: Klientské tajemství\n        title: 'Aplikace: %{name}'\n    authorizations:\n      buttons:\n        authorize: Autorizovat\n        deny: Zamítnout\n      error:\n        title: Vyskytla se chyba\n      new:\n        able_to: Bude moci\n        prompt: Aplikace %{client_name} vyžaduje přístup k vašemu účtu\n        title: Je vyžadována autorizace\n      show:\n        title: Zkopírujte tento autorizační kód a vložte ho do aplikace.\n    authorized_applications:\n      buttons:\n        revoke: Zamítnout\n      confirmations:\n        revoke: Jste si jistý/á?\n      index:\n        application: Aplikace\n        created_at: Autorizováno\n        date_format: \"%d. %m. %Y %H:%M:%S\"\n        scopes: Rozsahy\n        title: Vaše autorizované aplikace\n    errors:\n      messages:\n        access_denied: Vlastník zdroje či autorizační server zamítl požadavek.\n        credential_flow_not_configured: Proud Resource Owner Password Credentials selhal, protože Doorkeeper.configure.resource_owner_from_credentials nebylo nakonfigurováno.\n        invalid_client: Ověření klienta selhalo kvůli neznámému klientovi, chybějící klientské autentizaci či nepodporované autentizační metodě.\n        invalid_grant: Poskytnuté oprávnění je neplatné, vypršelé, zamítnuté, neshoduje se s URI přesměrování použitým v požadavku o autorizaci, nebo bylo uděleno jinému klientu.\n        invalid_redirect_uri: Přesměrovací URI není platné.\n        invalid_request: Požadavku chybí pžadovaný parametr, obsahuje nepodporovanou hodnotu parametru, či je jinak malformovaný.\n        invalid_resource_owner: Poskytnuté přihlašovací údaje vlastníka zdroje nejsou platné, nebo vlastník zdroje nemůže být nalezen\n        invalid_scope: Požadovaný rozsah je neplatný, neznámý, nebo malformovaný.\n        invalid_token:\n          expired: Přístupový token vypršel\n          revoked: Přístupový token byl zamítnut\n          unknown: Přístupový token je neplatný\n        resource_owner_authenticator_not_configured: Nález Resource Owner selhal, protože Doorkeeper.configure.resource_owner_authenticator nebylo nakonfigurováno.\n        server_error: Autorizační server se setkal s neočekávanou chybou, která mu zabránila ve vykonání požadavku.\n        temporarily_unavailable: Autorizační server vás nyní nemůže obsloužit kvůli dočasnému přetížení či údržbě serveru.\n        unauthorized_client: Klient není autorizován k vykonání tohoto požadavku touto metodou.\n        unsupported_grant_type: Tento typ oprávnění není podporován autorizačním serverem.\n        unsupported_response_type: Autorizační server nepodporuje tento typ odpovědi.\n    flash:\n      applications:\n        create:\n          notice: Aplikace vytvořena.\n        destroy:\n          notice: Aplikace smazána.\n        update:\n          notice: Aplikace aktualizována.\n      authorized_applications:\n        destroy:\n          notice: Aplikace zamítnuta.\n    layouts:\n      admin:\n        nav:\n          applications: Aplikace\n          oauth2_provider: Poskytovatel OAuth2\n      application:\n        title: Je požadována autorizace OAuth\n    scopes:\n      follow: upravovat vztahy mezi profily\n      push: přijímat vaše push oznámení\n      read: vidět všechna data vašeho účtu\n      read:accounts: vidět informace o účtech\n      read:blocks: vidět vaše blokace\n      read:favourites: vidět vaše oblíbení\n      read:filters: vidět vaše filtry\n      read:follows: vidět vaše sledování\n      read:lists: vidět vaše seznamy\n      read:mutes: vidět vaše skrytí\n      read:notifications: vidět vaše oznámení\n      read:reports: vidět vaše nahlášení\n      read:search: vyhledávat za vás\n      read:statuses: vidět všechny tooty\n      write: měnit všechna data vašeho účtu\n      write:accounts: měnit váš profil\n      write:blocks: blokovat účty a domény\n      write:favourites: oblibovat si tooty\n      write:filters: vytvářet filtry\n      write:follows: sledovat lidi\n      write:lists: vytvářet seznamy\n      write:media: nahrávat mediální soubory\n      write:mutes: skrývat lidi a konverzace\n      write:notifications: vymazávat vaše oznámení\n      write:reports: nahlašovat jiné uživatele\n      write:statuses: publikovat tooty\n"
  },
  {
    "path": "config/locales/doorkeeper.cy.yml",
    "content": "---\ncy:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: Enw rhaglen\n        redirect_uri: Ailgyfeirio URI\n        scopes: Rhinweddau\n        website: Gwefan cais\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              fragment_present: ni all gynnwys dernyn.\n              invalid_uri: rhaid iddo fod yn URI cyfredol.\n              relative_uri: rhaid iddo fod yn URI absoliwt.\n              secured_uri: rhaid iddo fod yn URI HTTPS/SSL.\n  doorkeeper:\n    applications:\n      buttons:\n        authorize: Awdurdodi\n        cancel: Diddymu\n        destroy: Dinistrio\n        edit: Golygu\n        submit: Cyflwyno\n      confirmations:\n        destroy: Ydych chi'n sicr?\n      edit:\n        title: Golygwch y rhaglen\n      form:\n        error: Wps! Gwiriwch eich ffurflen am gamgymeriadau posib\n      help:\n        native_redirect_uri: Defnyddiwch %{native_redirect_uri} ar gyfer profion lleol\n        redirect_uri: Defnyddiwch un llinell i bob URI\n        scopes: Gwahanwch rinweddau gyda gofodau. Gadewch yn wag i ddefnyddio y rhinweddau rhagosodiedig.\n      index:\n        application: Rhaglen\n        callback_url: URL galw-nôl\n        delete: Dileu\n        name: Enw\n        new: Rhaglen newydd\n        scopes: Rhinweddau\n        show: Dangoswch\n        title: Eich rhaglenni\n      new:\n        title: Rhaglen newydd\n      show:\n        actions: Gweithredoedd\n        application_id: Allwedd cleient\n        callback_urls: URLau galw-nôl\n        scopes: Rhinweddau\n        secret: Cyfrinach Cleient\n        title: 'Rhaglen: %{name}'\n    authorizations:\n      buttons:\n        authorize: Awdurdodi\n        deny: Gwrthod\n      error:\n        title: Mae rhywbeth wedi mynd o'i le\n      new:\n        able_to: Mi fydd a'r gallu i\n        prompt: Mae'r ap %{client_name} yn gofyn caniatad i gal mynediad i'ch cyfrif\n        title: Angen awdurdodi\n      show:\n        title: Copiwch y côd awdurdodi a gludiwch i'r rhaglen.\n    authorized_applications:\n      buttons:\n        revoke: Diddymu\n      confirmations:\n        revoke: Ydych chi'n sicr?\n      index:\n        application: Rhaglen\n        created_at: Awdurdodedig\n        scopes: Rhinweddau\n        title: Eich rhaglenni awdurdodedig\n    errors:\n      messages:\n        access_denied: Mae perchennog yr adnodd neu'r gweinydd awdurdodi wedi atal y cais.\n        credential_flow_not_configured: Llif meini prawf cyfrinair perchennog yr adnodd wedi methu achos fod Doorkeeper.configure.resource_owner_from_credentials heb ei ffurfweddu.\n        invalid_client: Methwyd dilysu cleient oherwydd cleient anhysbys, methiant i gynnwys dilysu cleient, neu defnydd o ddull dilysu nid yw'n cael ei gefnodi.\n        invalid_grant: Mae'r grant dilysu a ddarparwyd yn annilys, wedi dod i ben, wedi'i wrthod, ddim yn cyfateb a'r URI ailgyferio a ddefnyddiwyd yn y cais dilysu, neu wedi ei ddarparu i gleient arall.\n        invalid_redirect_uri: Nid yw'r uri ailgyfeirio cynnwysiedig yn gyfredol.\n        invalid_request: Nid yw'r cais yn cynnwys paramedr angenrheidiol, yn cynnwys paramader paramedr nad yw'n cael ei gefnogi, neu wedi ei gamffurfio mewn rhyw fodd arall.\n        invalid_resource_owner: Nid yw meini prawf perchennog yr adnodd yn ddilys, neu ni ellir canfod perchennog yr adnodd\n        invalid_scope: Mae'r sgôp a geisiwyd amdano yn annilys, anhysbys, neu'n gamffurfiedig.\n        invalid_token:\n          expired: Daeth y tocyn mynediad i ben\n          revoked: Gwrthodwyd y tocyn mynediad\n          unknown: Mae'r tocyn mynediad yn annilys\n        resource_owner_authenticator_not_configured: Methwyd canfod Perchenog Adnodd achos fod Doorkeeper.configure.resource_owner_authenticator heb ei gydffurfio.\n        server_error: Daeth y gweinydd awdurdodi ar draws gyflwr annisgwyl wnaeth ei atal rhag cyflawni'r cais.\n        temporarily_unavailable: Nid yw'r gweinydd awdurdodi yn gallu gweithredu y cais hwn ar hyn o bryd oherwydd gorlwytho dros dro neu gwaith cynnal a chadw ar y gweinydd hwn.\n        unauthorized_client: Nid yw'r cleient wedi ei awdurdodi i berfformio'r cais hwn yn defnyddio'r dull hwn.\n        unsupported_grant_type: Nid yw'r math o ganiatad awdurdodi yma'n cael ei gefnogi gan y gweinydd awdurdodi.\n        unsupported_response_type: Nid yw'r gweinydd awdurdodi yn cefnogi y math yma o ymateb.\n    flash:\n      applications:\n        create:\n          notice: Crewyd y rhaglen.\n        destroy:\n          notice: Dilëwyd y rhaglen.\n        update:\n          notice: Diweddarwyd y rhaglen.\n      authorized_applications:\n        destroy:\n          notice: Diddymwyd y cais.\n    layouts:\n      admin:\n        nav:\n          applications: Rhaglenni\n          oauth2_provider: Darparwr OAuth2\n      application:\n        title: Mae awdurdodiad OAuth yn ofynnol\n    scopes:\n      follow: addasu perthnasau cyfrif\n      push: derbyn eich hysbysiadau PUSH\n      read: darllen holl ddata eich cyfrif\n      read:accounts: gweld gwybodaeth y cyfrif\n      read:blocks: gweld eich blociau\n      read:favourites: gweld eich ffefrynnau\n      read:filters: gweld eich hidlwyr\n      read:follows: gweld eich dilynwyr\n      read:lists: gweld eich rhestrau\n      read:mutes: gweld y rheini wedi'i tewi\n      read:notifications: gweld eich hysbysiadau\n      read:reports: gweld eich adroddiadau\n      read:search: edrych ar eich rhan\n      read:statuses: gweld pob statws\n      write: addasu holl ddata eich cyfri\n      write:accounts: addasu eich proffil\n      write:blocks: blocio cyfrifon a parthau\n      write:favourites: hoff dŵtiau\n      write:filters: creu hidlwyr\n      write:follows: dilyn pobl\n      write:lists: creu rhestrau\n      write:media: uwchlwytho ffeiliau cyfryngau\n      write:mutes: tawelu pobl a sgyrsiau\n      write:notifications: clirio eich hysbysiadau\n      write:reports: adrodd pobl eraill\n      write:statuses: cyhoeddi tŵt\n"
  },
  {
    "path": "config/locales/doorkeeper.da.yml",
    "content": "---\nda:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: Navn på program\n        redirect_uri: Link\n        scopes: Områder\n        website: Webside for applikation\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              fragment_present: kan ikke indeholde et fragment.\n              invalid_uri: skal være et gyldigt URI.\n              relative_uri: skal være en absolut URI.\n              secured_uri: skal være en HTTPS/SSL URI.\n  doorkeeper:\n    applications:\n      buttons:\n        authorize: Godkend\n        cancel: Annuller\n        destroy: Destruer\n        edit: Rediger\n        submit: Indsend\n      confirmations:\n        destroy: Er du sikker?\n      edit:\n        title: Rediger applikation\n      form:\n        error: Ups! Tjek din form for mulige fejl\n      help:\n        native_redirect_uri: Brug %{native_redirect_uri} for lokale tests\n        redirect_uri: Brug en linje per URI\n        scopes: Adskil omfang med mellemrum. Lad være blankt for at bruge standard omfang.\n      index:\n        application: Applikation\n        callback_url: Callback-URL\n        delete: Slet\n        name: Navn\n        new: Ny applikation\n        scopes: Omfang\n        show: Vis\n        title: Dine applikationer\n      new:\n        title: Ny applikation\n      show:\n        actions: Handlinger\n        application_id: Klient nøgle\n        callback_urls: Callback-URLs\n        scopes: Omfang\n        secret: Secret\n        title: 'Applikation: %{name}'\n    authorizations:\n      buttons:\n        authorize: Godkend\n        deny: Afvis\n      error:\n        title: Der opstod en fejl\n      new:\n        able_to: Den vil være i stand til\n        prompt: Applikationen %{client_name} anmoder om adgang til din konto\n        title: Godkendelse påkræves\n      show:\n        title: Kopiere denne godkendelseskode og indsæt den i applikationen.\n    authorized_applications:\n      buttons:\n        revoke: Ophæv\n      confirmations:\n        revoke: Er du sikker?\n      index:\n        application: Applikation\n        created_at: Godkendt\n        scopes: Omfang\n        title: Dine godkendte applikationer\n    errors:\n      messages:\n        access_denied: Ejeren af ressourcen eller godkendelses serveren afviste anmodningen.\n        credential_flow_not_configured: Flytning af ressourceejers adgangskode mislykkedes grundet Doorkeeper.configure.resource_owner_from_credentials ikke er opsat.\n        invalid_client: Klient autentikationen mislykkedes grundet en ukendt klient, ingen klient autentikation fulgte med, eller en ikke-understøttet metode.\n        invalid_grant: Autoriseringen er ugyldig, udløbet, ophævet, passer ikke med den henvisnings URI der blev brugt i autoriserings anmodningen, eller blev givet til en anden klient.\n        invalid_redirect_uri: Ormdirigerings-uri'en der blev angivet er ikke gyldig.\n        invalid_request: Anmodningen mangler en parametre, inkluderer en ikke understøttet parametre værdi eller er på en eller anden måde deformeret.\n        invalid_resource_owner: De angivne ressource ejer kredentialer er ikke gyldige, eller ressource ejeren kunne ikke blive fundet\n        invalid_scope: Det anmodede omfang er ugyldigt, ukendt eller deformeret.\n        invalid_token:\n          expired: Adgangs-beviset er udløbet\n          revoked: Adgangs-beviset er blevet ophævet\n          unknown: Adgangs-beviset er ugyldigt\n        resource_owner_authenticator_not_configured: Ressource ejeren kunne ikke blive fundet grundet Doorkeeper.configure.resource_owner_authenticator ikke er konfigureret.\n        server_error: Autoriserings serveren blev mødt med en uventet betingelse der forhindrede den i at færdiggøre anmodningen.\n        temporarily_unavailable: Autoriserings serveren er på nuværende tidspunkt ikke i stand til at håndtere anmodningen grundet midlertidig overlast eller serveren er ved at blive opdateret.\n        unauthorized_client: Klienten er ikke godkendt til at udføre denne anmodning ved at bruge denne metode.\n        unsupported_grant_type: Autoriserings typen understøttes ikke af autoriserings serveren.\n        unsupported_response_type: Godkendelses serveren understøtter ikke denne type respons.\n    flash:\n      applications:\n        create:\n          notice: Applikationen blev oprettet.\n        destroy:\n          notice: Applikationen blev slettet.\n        update:\n          notice: Applikationen blev opdateret.\n      authorized_applications:\n        destroy:\n          notice: Applikationen blev ophævet.\n    layouts:\n      admin:\n        nav:\n          applications: Applikationer\n          oauth2_provider: OAuth Udbyder\n      application:\n        title: OAuth godkendelse påkrævet\n    scopes:\n      follow: ændre din kontos forhold\n      push: modtage dine push notifikationer\n      read: læse alle din kontos data\n      read:accounts: se konto oplysninger\n      read:blocks: se dine blokeringer\n      read:favourites: se dine favoritter\n      read:filters: se dine filtre\n      read:follows: se hvem du følger\n      read:lists: se dine lister\n      read:mutes: se dine dæmpninger\n      read:notifications: se dine notifikationer\n      read:reports: se dine anmeldelser\n      read:search: søge på dine vegne\n      read:statuses: se alle statusser\n      write: ændre din kontos data\n      write:accounts: ændre din profil\n      write:blocks: bloker konti og domæner\n      write:favourites: favoriser statusser\n      write:filters: opret filtre\n      write:follows: følg folk\n      write:lists: opret lister\n      write:media: upload multimedie filer\n      write:mutes: dæmp folk og samtaler\n      write:notifications: ryd dine notifikationer\n      write:reports: anmeld andre folk\n      write:statuses: udgiv statusser\n"
  },
  {
    "path": "config/locales/doorkeeper.de.yml",
    "content": "---\nde:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: Name der Anwendung\n        redirect_uri: Weiterleitungs-URI\n        scopes: Befugnisse\n        website: Website der Anwendung\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              fragment_present: darf kein Fragment enthalten.\n              invalid_uri: muss ein valider URI sein.\n              relative_uri: muss ein absoluter URI sein.\n              secured_uri: muss ein HTTPS-/SSL-URI sein.\n  doorkeeper:\n    applications:\n      buttons:\n        authorize: Autorisieren\n        cancel: Abbrechen\n        destroy: Löschen\n        edit: Bearbeiten\n        submit: Übertragen\n      confirmations:\n        destroy: Bist du sicher?\n      edit:\n        title: Anwendung bearbeiten\n      form:\n        error: Hoppla! Bitte überprüfe das Formular auf mögliche Fehler\n      help:\n        native_redirect_uri: \"%{native_redirect_uri} für lokale Tests benutzen\"\n        redirect_uri: Bitte benutze eine Zeile pro URI\n        scopes: Bitte die Befugnisse mit Leerzeichen trennen. Zur Verwendung der Standardwerte freilassen.\n      index:\n        application: Anwendung\n        callback_url: Callback-URL\n        delete: Löschen\n        name: Name\n        new: Neue Anwendung\n        scopes: Befugnisse\n        show: Zeigen\n        title: Deine Anwendungen\n      new:\n        title: Neue Anwendung\n      show:\n        actions: Aktionen\n        application_id: Client-Schlüssel\n        callback_urls: Callback-URLs\n        scopes: Befugnisse\n        secret: Client-Secret\n        title: 'Anwendung: %{name}'\n    authorizations:\n      buttons:\n        authorize: Autorisieren\n        deny: Verweigern\n      error:\n        title: Ein Fehler ist aufgetreten\n      new:\n        able_to: 'Es wird folgende Befugnisse haben:'\n        prompt: Die Anwendung %{client_name} verlangt Zugriff auf dein Konto\n        title: Autorisierung erforderlich\n      show:\n        title: Kopiere diesen Autorisierungs-Code und füge ihn in die Anwendung ein.\n    authorized_applications:\n      buttons:\n        revoke: Widerrufen\n      confirmations:\n        revoke: Bist du sicher?\n      index:\n        application: Anwendung\n        created_at: Autorisiert am\n        date_format: \"%d.%m.%Y %H:%M:%S\"\n        scopes: Befugnisse\n        title: Deine autorisierten Anwendungen\n    errors:\n      messages:\n        access_denied: Der »resource owner« oder der Autorisierungs-Server hat die Anfrage verweigert.\n        credential_flow_not_configured: Die Prozedur »Resource Owner Password Credentials« schlug fehl, da Doorkeeper.configure.resource_owner_from_credentials nicht konfiguriert ist.\n        invalid_client: 'Client-Authentifizierung ist fehlgeschlagen: Client unbekannt, keine Authentisierung mitgeliefert oder Authentisierungsmethode wird nicht unterstützt.'\n        invalid_grant: Die beigefügte Autorisierung ist ungültig, abgelaufen, wurde widerrufen, einem anderen Client ausgestellt oder der Weiterleitungs-URI stimmt nicht mit der Autorisierungs-Anfrage überein.\n        invalid_redirect_uri: Der beigefügte Weiterleitungs-URI ist ungültig.\n        invalid_request: Die Anfrage enthält ein nicht-unterstütztes Argument, ein Parameter fehlt, oder sie ist anderweitig fehlerhaft.\n        invalid_resource_owner: Die angegebenen Zugangsdaten für den Ressourcenbesitzer sind ungültig oder der Ressourcenbesitzer kann nicht gefunden werden\n        invalid_scope: Die angeforderte Befugnis ist ungültig, unbekannt oder fehlerhaft.\n        invalid_token:\n          expired: Der Zugriffs-Token ist abgelaufen\n          revoked: Der Zugriffs-Token wurde widerrufen\n          unknown: Der Zugriffs-Token ist ungültig\n        resource_owner_authenticator_not_configured: Die Prozedur »Resource Owner find« ist fehlgeschlagen, da Doorkeeper.configure.resource_owner_authenticator nicht konfiguriert ist.\n        server_error: Der Autorisierungs-Server hat ein unerwartetes Problem festgestellt und konnte die Anfrage nicht bearbeiten.\n        temporarily_unavailable: Der Autorisierungs-Server ist aufgrund von zwischenzeitlicher Überlastung oder Wartungsarbeiten derzeit nicht in der Lage, die Anfrage zu bearbeiten.\n        unauthorized_client: Der Client ist nicht dazu autorisiert, diese Anfrage mit dieser Methode auszuführen.\n        unsupported_grant_type: Der Autorisierungs-Typ wird nicht vom Autorisierungs-Server unterstützt.\n        unsupported_response_type: Der Autorisierungs-Server unterstützt diesen Antwort-Typ nicht.\n    flash:\n      applications:\n        create:\n          notice: Anwendung erstellt.\n        destroy:\n          notice: Anwendung gelöscht.\n        update:\n          notice: Anwendung aktualisiert.\n      authorized_applications:\n        destroy:\n          notice: Anwendung widerrufen.\n    layouts:\n      admin:\n        nav:\n          applications: Anwendungen\n          oauth2_provider: OAuth2-Anbieter\n      application:\n        title: OAuth-Autorisierung nötig\n    scopes:\n      follow: Kontenbeziehungen verändern\n      push: deine Push-Benachrichtigungen erhalten\n      read: all deine Daten lesen\n      read:accounts: deine Konteninformationen einsehen\n      read:blocks: deine Blockaden einsehen\n      read:favourites: deine Favoriten ansehen\n      read:filters: deine Filter ansehen\n      read:follows: sehen, wem du folgst\n      read:lists: deine Listen sehen\n      read:mutes: deine Stummschaltungen einsehen\n      read:notifications: deine Benachrichtigungen sehen\n      read:reports: deine Meldungen sehen\n      read:search: in deinem Namen suchen\n      read:statuses: alle Beiträge sehen\n      write: all deine Benutzerdaten verändern\n      write:accounts: dein Profil bearbeiten\n      write:blocks: Domains und Konten blockieren\n      write:favourites: Beiträge favorisieren\n      write:filters: Filter erstellen\n      write:follows: Leuten folgen\n      write:lists: Listen erstellen\n      write:media: Mediendateien hochladen\n      write:mutes: Leute und Konversationen stummschalten\n      write:notifications: deine Benachrichtigungen leeren\n      write:reports: andere Leute melden\n      write:statuses: Beiträge veröffentlichen\n"
  },
  {
    "path": "config/locales/doorkeeper.el.yml",
    "content": "---\nel:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: Όνομα εφαρμογής\n        redirect_uri: URI Ανακατεύθυνσης (Ενιαίο Αναγνωριστικό Πόρων)\n        scopes: Εύρος εφαρμογής\n        website: Ιστότοπος εφαρμογής\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              fragment_present: δεν μπορεί να περιέχει τμήμα διεύθυνσης.\n              invalid_uri: πρέπει να είναι έγκυρο URI (Ενιαίο Αναγνωριστικό Πόρων).\n              relative_uri: πρέπει να είναι απόλυτο URI (Ενιαίο Αναγνωριστικό Πόρων).\n              secured_uri: πρέπει να είναι HTTPS/SSL URI (Ενιαίο Αναγνωριστικό Πόρων).\n  doorkeeper:\n    applications:\n      buttons:\n        authorize: Ενέκρινε\n        cancel: Άκυρο\n        destroy: Καταστροφή\n        edit: Αλλαγή\n        submit: Υποβολή\n      confirmations:\n        destroy: Σίγουρα;\n      edit:\n        title: Αλλαγή εφαρμογής\n      form:\n        error: Ώπα! Έλεγξε τη φόρμα σου για πιθανά λάθη\n      help:\n        native_redirect_uri: Χρησιμοποίησε το %{native_redirect_uri} για τοπικές δοκιμές\n        redirect_uri: Χρησιμοποίησε μια γραμμή ανά URI\n        scopes: Διαχώρησε το κάθε εύρος εφαρμογής με κενά. Άστο κενό για χρήση των προεπιλεγμένων ευρών εφαρμογής.\n      index:\n        application: Εφαρμογή\n        callback_url: URL επιστροφής (Callback)\n        delete: Διαγραφή\n        name: Όνομα\n        new: Νέα εφαρμογή\n        scopes: Εύρος εφαρμογής\n        show: Εμφάνισε\n        title: Οι εφαρμογές σου\n      new:\n        title: Νέα εφαρμογή\n      show:\n        actions: Ενέργειες\n        application_id: Κλειδί πελάτη\n        callback_urls: URL επιστροφής (Callback)\n        scopes: Εύρος εφαρμογής\n        secret: Μυστικό πελάτη\n        title: 'Εφαρμογή: %{name}'\n    authorizations:\n      buttons:\n        authorize: Ενέκρινε\n        deny: Απόρριψε\n      error:\n        title: Εμφανίστηκε σφάλμα\n      new:\n        able_to: Θα μπορεί να\n        prompt: Η εφαρμογή %{client_name} ζητάει πρόσβαση στο λογαριασμό σου\n        title: Απαιτείται έγκριση\n      show:\n        title: Αντέγραψε αυτό τον κωδικό έγκρισης στην εφαρμογή.\n    authorized_applications:\n      buttons:\n        revoke: Ανακάλεσε\n      confirmations:\n        revoke: Σίγουρα;\n      index:\n        application: Εφαρμογή\n        created_at: Εγκεκριμένη\n        date_format: \"%H:%M:%S, %d/%m/%Y\"\n        scopes: Εύρος εφαρμογής\n        title: Οι εφαρμογές που έχεις εγκρίνει\n    errors:\n      messages:\n        access_denied: Ο ιδιοκτήτης του πόρου ή του παρόχου έγκρισης απέρριψε το αίτημα.\n        credential_flow_not_configured: Η ροή Resource Owner Password Credentials απέτυχε επειδή το Doorkeeper.configure.resource_owner_from_credentials δεν έχει ρυθμιστεί.\n        invalid_client: Η ταυτοποίηση του πελάτη απέτυχε είτε λόγω άγνωστου πελάτη, είτε λόγω έλλειψης ταυτοποιημένου πελάτη ή λόγω μη υποστηριζόμενης μεθόδου ταυτοποίησης.\n        invalid_grant: Η άδεια πιστοποίησης που δόθηκε είναι άκυρη, ληγμένη, έχει ανακληθεί, δεν συμφωνεί με το URI ανακατεύθυνσης που δόθηκε στο αίτημα πιστοποίησης ή εκδόθηκε προς άλλο πελάτη.\n        invalid_redirect_uri: Το URI ανακατεύθυνσης που δόθηκε δεν είναι έγκυρο.\n        invalid_request: Το αίτημα δεν έχει κάποια απαιτούμενη παράμετρο, περιέχει κάποια μη υποστηριζόμενη τιμή παραμέτρου ή είναι μη σωστά δομημένη.\n        invalid_resource_owner: Τα διαπιστευτήρια που έδωσε ο ιδιοκτήτης του πόρου δεν είναι έγκυρα, ή δεν βρέθηκε ο ιδιοκτήτης του πόρου\n        invalid_scope: Το αιτούμενο εύρος εφαρμογής είναι άκυρο, άγνωστο ή λάθος διατυπωμένο.\n        invalid_token:\n          expired: Το διακριτικό πρόσβασης έληξε\n          revoked: Το διακριτικό πρόσβασης ανακλήθηκε\n          unknown: Το διακριτικό πρόσβασης δεν είναι έγκυρο\n        resource_owner_authenticator_not_configured: Η αναζήτηση του ιδιοκτήτη του πόρου απέτυχε επειδή το Doorkeeper.configure.resource_owner_authenticator δεν έχει ρυθμιστεί.\n        server_error: Ο εξυπηρετητής έγκρισης (authorization server) αντιμετώπισε μια απροσδόκητη συνθήκη που τον απέτρεψε να ικανοποιήσει το αίτημα.\n        temporarily_unavailable: Ο εξυπηρετητής έγκρισης (authorization server) προς το παρόν δεν είναι διαθέσιμος να αναλάβει το αίτημα λόγω προσωρινής υπερφόρτωσης ή συντήρησής του.\n        unauthorized_client: Ο πελάτης δεν έχει άδεια να εκτελέσει αυτό το αίτημα χρησιμοποιώντας αυτή τη μέθοδο.\n        unsupported_grant_type: Το είδος άδειας έγκρισης δεν υποστηρίζεται από τον εξυπηρετητή έγκρισης (authorization server).\n        unsupported_response_type: Ο εξυπηρετητής έγκρισης (authorization server) δεν υποστηρίζει αυτό το είδος απάντησης.\n    flash:\n      applications:\n        create:\n          notice: Η εφαρμογή δημιουργήθηκε.\n        destroy:\n          notice: Η εφαρμογή διαγράφηκε.\n        update:\n          notice: Η εφαρμογή ενημερώθηκε.\n      authorized_applications:\n        destroy:\n          notice: Η εφαρμογή ανακλήθηκε.\n    layouts:\n      admin:\n        nav:\n          applications: Εφαρμογές\n          oauth2_provider: Πάροχος OAuth2\n      application:\n        title: Απαιτείται έγκριση OAuth\n    scopes:\n      follow: να αλλάζει τις σχέσεις με λογαριασμούς\n      push: να λαμβάνει τις ειδοποιήσεις σου\n      read: να διαβάζει όλα τα στοιχεία του λογαριασμού σου\n      read:accounts: να βλέπει τα στοιχεία λογαριασμών\n      read:blocks: να βλέπει τους αποκλεισμένους σου\n      read:favourites: να βλέπει τα αγαπημένα σου\n      read:filters: να βλέπει τα φίλτρα σου\n      read:follows: να βλέπει ποιους ακολουθείς\n      read:lists: να βλέπει τις λίστες σου\n      read:mutes: να βλέπει ποιους αποσιωπείς\n      read:notifications: να βλέπει τις ειδοποιήσεις σου\n      read:reports: να βλέπει τις καταγγελίες σου\n      read:search: να ψάχνει για εσένα\n      read:statuses: να βλέπει όλες τις δημοσιεύσεις σου\n      write: να αλλάζει όλα τα στοιχεία του λογαριασμού σου\n      write:accounts: να αλλάζει το προφίλ σου\n      write:blocks: να μπλοκάρει λογαριασμούς και τομείς\n      write:favourites: να σημειώνει δημοσιεύσεις ως αγαπημένες\n      write:filters: να δημιουργεί φίλτρα\n      write:follows: να ακολουθεί ανθρώπους\n      write:lists: να δημιουργεί λίστες\n      write:media: να ανεβάζει πολυμέσα\n      write:mutes: να αποσιωπεί ανθρώπους και συζητήσεις\n      write:notifications: να καθαρίζει τις ειδοποιήσεις σου\n      write:reports: να καταγγέλλει άλλους ανθρώπους\n      write:statuses: να κάνει δημοσιεύσεις\n"
  },
  {
    "path": "config/locales/doorkeeper.en.yml",
    "content": "---\nen:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: Application name\n        redirect_uri: Redirect URI\n        scopes: Scopes\n        website: Application website\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              fragment_present: cannot contain a fragment.\n              invalid_uri: must be a valid URI.\n              relative_uri: must be an absolute URI.\n              secured_uri: must be an HTTPS/SSL URI.\n  doorkeeper:\n    applications:\n      buttons:\n        authorize: Authorize\n        cancel: Cancel\n        destroy: Destroy\n        edit: Edit\n        submit: Submit\n      confirmations:\n        destroy: Are you sure?\n      edit:\n        title: Edit application\n      form:\n        error: Whoops! Check your form for possible errors\n      help:\n        native_redirect_uri: Use %{native_redirect_uri} for local tests\n        redirect_uri: Use one line per URI\n        scopes: Separate scopes with spaces. Leave blank to use the default scopes.\n      index:\n        application: Application\n        callback_url: Callback URL\n        delete: Delete\n        name: Name\n        new: New application\n        scopes: Scopes\n        show: Show\n        title: Your applications\n      new:\n        title: New application\n      show:\n        actions: Actions\n        application_id: Client key\n        callback_urls: Callback URLs\n        scopes: Scopes\n        secret: Client secret\n        title: 'Application: %{name}'\n    authorizations:\n      buttons:\n        authorize: Authorize\n        deny: Deny\n      error:\n        title: An error has occurred\n      new:\n        able_to: It will be able to\n        prompt: Application %{client_name} requests access to your account\n        title: Authorization required\n      show:\n        title: Copy this authorization code and paste it to the application.\n    authorized_applications:\n      buttons:\n        revoke: Revoke\n      confirmations:\n        revoke: Are you sure?\n      index:\n        application: Application\n        created_at: Authorized\n        date_format: \"%Y-%m-%d %H:%M:%S\"\n        scopes: Scopes\n        title: Your authorized applications\n    errors:\n      messages:\n        access_denied: The resource owner or authorization server denied the request.\n        credential_flow_not_configured: Resource Owner Password Credentials flow failed due to Doorkeeper.configure.resource_owner_from_credentials being unconfigured.\n        invalid_client: Client authentication failed due to unknown client, no client authentication included, or unsupported authentication method.\n        invalid_grant: The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client.\n        invalid_redirect_uri: The redirect uri included is not valid.\n        invalid_request: The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed.\n        invalid_resource_owner: The provided resource owner credentials are not valid, or resource owner cannot be found\n        invalid_scope: The requested scope is invalid, unknown, or malformed.\n        invalid_token:\n          expired: The access token expired\n          revoked: The access token was revoked\n          unknown: The access token is invalid\n        resource_owner_authenticator_not_configured: Resource Owner find failed due to Doorkeeper.configure.resource_owner_authenticator being unconfiged.\n        server_error: The authorization server encountered an unexpected condition which prevented it from fulfilling the request.\n        temporarily_unavailable: The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server.\n        unauthorized_client: The client is not authorized to perform this request using this method.\n        unsupported_grant_type: The authorization grant type is not supported by the authorization server.\n        unsupported_response_type: The authorization server does not support this response type.\n    flash:\n      applications:\n        create:\n          notice: Application created.\n        destroy:\n          notice: Application deleted.\n        update:\n          notice: Application updated.\n      authorized_applications:\n        destroy:\n          notice: Application revoked.\n    layouts:\n      admin:\n        nav:\n          applications: Applications\n          oauth2_provider: OAuth2 Provider\n      application:\n        title: OAuth authorization required\n    scopes:\n      follow: modify account relationships\n      push: receive your push notifications\n      read: read all your account's data\n      read:accounts: see accounts information\n      read:blocks: see your blocks\n      read:favourites: see your favourites\n      read:filters: see your filters\n      read:follows: see your follows\n      read:lists: see your lists\n      read:mutes: see your mutes\n      read:notifications: see your notifications\n      read:reports: see your reports\n      read:search: search on your behalf\n      read:statuses: see all statuses\n      write: modify all your account's data\n      write:accounts: modify your profile\n      write:blocks: block accounts and domains\n      write:favourites: favourite statuses\n      write:filters: create filters\n      write:follows: follow people\n      write:lists: create lists\n      write:media: upload media files\n      write:mutes: mute people and conversations\n      write:notifications: clear your notifications\n      write:reports: report other people\n      write:statuses: publish statuses\n"
  },
  {
    "path": "config/locales/doorkeeper.eo.yml",
    "content": "---\neo:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: Aplikaĵa nomo\n        redirect_uri: Plusenda URI\n        scopes: Ampleksoj\n        website: Aplikaĵa retejo\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              fragment_present: ne povas enhavi eron.\n              invalid_uri: devas esti valida URI.\n              relative_uri: devas esti absoluta URI.\n              secured_uri: devas esti HTTPS/SSL-a URI.\n  doorkeeper:\n    applications:\n      buttons:\n        authorize: Rajtigi\n        cancel: Nuligi\n        destroy: Detrui\n        edit: Redakti\n        submit: Sendi\n      confirmations:\n        destroy: Ĉu vi certas?\n      edit:\n        title: Redakti aplikaĵon\n      form:\n        error: Ups! Kontrolu vian formularon ĉu estas eraroj\n      help:\n        native_redirect_uri: Uzu %{native_redirect_uri} por lokaj provoj\n        redirect_uri: Uzu unu linion por ĉiu URI\n        scopes: Apartigu ampleksojn per spacetoj. Lasu malplena por uzi la dekomencajn ampleksojn.\n      index:\n        application: Aplikaĵo\n        callback_url: Revena URL\n        delete: Forigi\n        name: Nomo\n        new: Nova aplikaĵo\n        scopes: Ampleksoj\n        show: Montri\n        title: Viaj aplikaĵoj\n      new:\n        title: Nova aplikaĵo\n      show:\n        actions: Agoj\n        application_id: Klienta ŝlosilo\n        callback_urls: Revenaj URL-oj\n        scopes: Ampleksoj\n        secret: Klienta sekreto\n        title: 'Aplikaĵo: %{name}'\n    authorizations:\n      buttons:\n        authorize: Rajtigi\n        deny: Rifuzi\n      error:\n        title: Eraro okazis\n      new:\n        able_to: Ĝi povos\n        prompt: La aplikaĵo %{client_name} petas aliron al via konto\n        title: Rajtigo bezonata\n      show:\n        title: Kopiu ĉi tiun rajtigan kodon kaj gluu ĝin al la aplikaĵo.\n    authorized_applications:\n      buttons:\n        revoke: Malrajtigi\n      confirmations:\n        revoke: Ĉu vi certas?\n      index:\n        application: Aplikaĵo\n        created_at: Rajtigita\n        date_format: \"%Y-%m-%d %H:%M:%S\"\n        scopes: Ampleksoj\n        title: Viaj rajtigitaj aplikaĵoj\n    errors:\n      messages:\n        access_denied: La posedanto de la rimedo aŭ de la rajtiga servilo rifuzis vian peton.\n        credential_flow_not_configured: La sendado de la identigiloj de la posedanto de la rimedo malsukcesis ĉar Doorkeeper.configure.resource_owner_from_credentials ne estis agordita.\n        invalid_client: Klienta aŭtentigo malsukcesa pro nekonata kliento, neniu klienta aŭtentigo inkluzivita, aŭ nesubtenata aŭtentiga metodo.\n        invalid_grant: La rajtiga konsento ne estas valida, ne plu estas valida, estis forigita, ne kongruas kun la plusenda URI uzita en la aŭtentiga peto, aŭ estis sendita al alia kliento.\n        invalid_redirect_uri: La plusenda URI uzita ne estas valida.\n        invalid_request: Mankis al la peto nepra parametro, enhavas nesubtenatan parametran valoron, aŭ la peto simple estas misformita.\n        invalid_resource_owner: La donitaj identigiloj pri la posedanto de la rimedo ne estas validaj, aŭ tiu lasta ne povas esti trovita\n        invalid_scope: La petita amplekso estas nevalida, nekonata, aŭ misformita.\n        invalid_token:\n          expired: La alira ĵetono eksvalidiĝis\n          revoked: La alira ĵetono estis malvalidigita\n          unknown: La alira ĵetono estas nevalida\n        resource_owner_authenticator_not_configured: La posedanto de la rimedo ne povis esti trovita ĉar Doorkeeper.configure.resource_owner_authenticator ne estas agordita.\n        server_error: La rajtiga servilo renkontis neatenditan problemon, kiu malpermesis al ĝi plenumi la peton.\n        temporarily_unavailable: La rajtiga servilo ne povas nun plenumi la peton pro dumtempa troŝarĝo aŭ servila prizorgado.\n        unauthorized_client: Kliento ne rajtas fari ĉi tian peton per ĉi tiu metodo.\n        unsupported_grant_type: La tipo de la rajtiga konsento ne estas subtenata de la rajtiga servilo.\n        unsupported_response_type: La rajtiga servilo ne subtenas ĉi tian respondon.\n    flash:\n      applications:\n        create:\n          notice: Aplikaĵo kreita.\n        destroy:\n          notice: Aplikaĵo forigita.\n        update:\n          notice: Aplikaĵo ĝisdatigita.\n      authorized_applications:\n        destroy:\n          notice: Aplikaĵo malrajtigita.\n    layouts:\n      admin:\n        nav:\n          applications: Aplikaĵoj\n          oauth2_provider: OAuth2-provizanto\n      application:\n        title: OAuth-a rajtigo bezonata\n    scopes:\n      follow: ŝanĝi rilatojn al aliaj kontoj\n      push: ricevi viajn puŝ-sciigojn\n      read: legi ĉiujn datumojn de via konto\n      read:accounts: vidi la informojn de la konto\n      read:blocks: vidi viajn blokojn\n      read:favourites: vidi viajn stelumojn\n      read:filters: vidi viajn filtrilojn\n      read:follows: vidi viajn sekvatojn\n      read:lists: vidi viajn listojn\n      read:mutes: vidi viajn silentigojn\n      read:notifications: vidi viajn sciigojn\n      read:reports: vidi viajn signalojn\n      read:search: serĉi vianome\n      read:statuses: vidi ĉiujn mesaĝojn\n      write: ŝanĝi ĉiujn datumojn de via konto\n      write:accounts: ŝanĝi vian profilon\n      write:blocks: bloki kontojn kaj domajnojn\n      write:favourites: stelumitaj mesaĝoj\n      write:filters: krei filtrilojn\n      write:follows: sekvi homojn\n      write:lists: krei listojn\n      write:media: alŝuti aŭdovidaĵojn\n      write:mutes: silentigi homojn kaj konversaciojn\n      write:notifications: forigi viajn sciigojn\n      write:reports: signali aliajn homojn\n      write:statuses: publikigi mesaĝojn\n"
  },
  {
    "path": "config/locales/doorkeeper.es.yml",
    "content": "---\nes:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: Nombre de aplicación\n        redirect_uri: URI para redirección\n        scopes: Ámbitos\n        website: Sitio web\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              fragment_present: no puede contener un fragmento.\n              invalid_uri: debe ser un URI válido.\n              relative_uri: debe ser una URI absoluta.\n              secured_uri: debe ser un URI HTTPS/SSL.\n  doorkeeper:\n    applications:\n      buttons:\n        authorize: Autorizar\n        cancel: Cancelar\n        destroy: Destruir\n        edit: Editar\n        submit: Enviar\n      confirmations:\n        destroy: \"¿Está seguro?\"\n      edit:\n        title: Editar aplicación\n      form:\n        error: \"¡Uuups! Compruebe su formulario\"\n      help:\n        native_redirect_uri: Utilice %{native_redirect_uri} para pruebas locales\n        redirect_uri: Utilice una línea por URI\n        scopes: Separe los ámbitos con espacios. Déjelo en blanco para utilizar los ámbitos por defecto.\n      index:\n        application: Aplicación\n        callback_url: URL de callback\n        delete: Eliminar\n        name: Nombre\n        new: Nueva aplicación\n        scopes: Ámbitos\n        show: Mostrar\n        title: Sus aplicaciones\n      new:\n        title: Nueva aplicación\n      show:\n        actions: Acciones\n        application_id: Id de la aplicación\n        callback_urls: URLs de callback\n        scopes: Ámbitos\n        secret: Secreto\n        title: 'Aplicación: %{name}'\n    authorizations:\n      buttons:\n        authorize: Autorizar\n        deny: Desautorizar\n      error:\n        title: Ha ocurrido un error\n      new:\n        able_to: Será capaz de\n        prompt: La aplicación %{client_name} solicita tener acceso a su cuenta\n        title: Se requiere autorización\n      show:\n        title: Copia este código de autorización y pégalo en la aplicación.\n    authorized_applications:\n      buttons:\n        revoke: Revocar\n      confirmations:\n        revoke: \"¿Está seguro?\"\n      index:\n        application: Aplicación\n        created_at: Creado el\n        date_format: \"%A-%m-%d %H:%M:%S\"\n        scopes: Ámbitos\n        title: Sus aplicaciones autorizadas\n    errors:\n      messages:\n        access_denied: El propietario del recurso o servidor de autorización denegó la petición.\n        credential_flow_not_configured: Las credenciales de contraseña del propietario del recurso falló debido a que Doorkeeper.configure.resource_owner_from_credentials está sin configurar.\n        invalid_client: La autentificación del cliente falló debido o a que es un cliente desconocido o no está incluída la autentificación del cliente o el método de autentificación no está confirmado.\n        invalid_grant: La concesión de autorización ofrecida es inválida, venció, se revocó, no coincide con la URI de redirección utilizada en la petición de autorización, o fue emitida para otro cliente.\n        invalid_redirect_uri: La URI de redirección incluida no es válida.\n        invalid_request: En la petición falta un parámetro necesario o incluye un valor de parámetro no soportado o tiene otro tipo de formato incorrecto.\n        invalid_resource_owner: Las credenciales proporcionadas del propietario del recurso no son válidas, o el propietario del recurso no puede ser encontrado\n        invalid_scope: El ámbito pedido es inválido, desconocido o erróneo.\n        invalid_token:\n          expired: El autentificador de acceso expiró\n          revoked: El autentificador de acceso fue revocado\n          unknown: El autentificador de acceso es inválido\n        resource_owner_authenticator_not_configured: El propietario del recurso falló debido a que Doorkeeper.configure.resource_owner_authenticator está sin configurar.\n        server_error: El servidor de la autorización entontró una condición inesperada que le impidió cumplir con la solicitud.\n        temporarily_unavailable: El servidor de la autorización es actualmente incapaz de manejar la petición debido a una sobrecarga temporal o un trabajo de mantenimiento del servidor.\n        unauthorized_client: El cliente no está autorizado a realizar esta petición utilizando este método.\n        unsupported_grant_type: El tipo de concesión de autorización no está soportado por el servidor de autorización.\n        unsupported_response_type: El servidor de autorización no soporta este tipo de respuesta.\n    flash:\n      applications:\n        create:\n          notice: Aplicación creada.\n        destroy:\n          notice: Aplicación eliminada.\n        update:\n          notice: Aplicación actualizada.\n      authorized_applications:\n        destroy:\n          notice: Aplicación revocada.\n    layouts:\n      admin:\n        nav:\n          applications: Aplicaciones\n          oauth2_provider: Proveedor OAuth2\n      application:\n        title: OAuth autorización requerida\n    scopes:\n      follow: seguir, bloquear, desbloquear y dejar de seguir cuentas\n      read: leer los datos de tu cuenta\n      write: publicar en tu nombre\n      write:blocks: bloquear cuentas y dominios\n"
  },
  {
    "path": "config/locales/doorkeeper.eu.yml",
    "content": "---\neu:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: Aplikazioaren izena\n        redirect_uri: Birbideratu URIa\n        scopes: Esparruak\n        website: Aplikazioaren webgunea\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              fragment_present: ezin du zati bat eduki.\n              invalid_uri: baliozko URI bat izan behar du.\n              relative_uri: URI absolutu bat izan behar du.\n              secured_uri: HTTPS/SSL URI bat izan behar du.\n  doorkeeper:\n    applications:\n      buttons:\n        authorize: Baimendu\n        cancel: Utzi\n        destroy: Suntsitu\n        edit: Editatu\n        submit: Bidali\n      confirmations:\n        destroy: Ziur zaude?\n      edit:\n        title: Editatu aplikazioa\n      form:\n        error: Ene! Egiaztatu formularioan errorerik dagoen\n      help:\n        native_redirect_uri: Erabili %{native_redirect_uri} proba lokaletarako\n        redirect_uri: Erabili lerro bat URI bakoitzeko\n        scopes: Banandu esparruak espazioekin. Laga hutsik lehenetsitako esparruak erabiltzeko.\n      index:\n        application: Aplikazioa\n        callback_url: Itzulera URLa\n        delete: Ezabatu\n        name: Izena\n        new: Aplikazio berria\n        scopes: Esparruak\n        show: Erakutsi\n        title: Zure aplikazioak\n      new:\n        title: Aplikazio berria\n      show:\n        actions: Ekintzak\n        application_id: Bezeroaren gakoa\n        callback_urls: Itzulera URL-ak\n        scopes: Esparruak\n        secret: Bezeroaren sekretua\n        title: 'Aplikazioa: %{name}'\n    authorizations:\n      buttons:\n        authorize: Baimendu\n        deny: Ukatu\n      error:\n        title: Errore bat gertatu da\n      new:\n        able_to: Egin ahal izango du\n        prompt: \"%{client_name} aplikazioak zure kontua atzitzea eskatu du\"\n        title: Baimena behar da\n      show:\n        title: Kopiatu baimen kode hau eta itsatsi aplikazioan.\n    authorized_applications:\n      buttons:\n        revoke: Indargabetu\n      confirmations:\n        revoke: Ziur zaude?\n      index:\n        application: Aplikazioa\n        created_at: Baimenduta\n        date_format: \"%Y-%m-%d %H:%M:%S\"\n        scopes: Esparruak\n        title: Zuk baimendutako aplikazioak\n    errors:\n      messages:\n        access_denied: Baliabidearen jabeak edo baimenaren zerbitzariak eskaria ukatu du.\n        credential_flow_not_configured: Baliabidearen jabearen pasahitza kredentzialen fluxuak huts egin du Doorkeeper.configure.resource_owner_from_credentials konfiguratu gabe dagoelako.\n        invalid_client: Bezeroaren autentifikazioak huts egin du bezero ezezaguna delako, ez delako bezero autentifikazioa txertatu, edo autentifikazio metodoa ez delako onartzen.\n        invalid_grant: Emandako autorizatzea baliogabea da, iraungitu da, indargabetu da. ez dator bat autorizatze eskarian erabilitako URI-arekin, edo beste bezero batek sortu du.\n        invalid_redirect_uri: Sartutako birbideratze URI-a baliogabea da.\n        invalid_request: Eskaerak beharrezkoa den parametro bat falta du, onartu gabeko parametro-balio bat du, edo beste moduren batean gaizki osatua dago.\n        invalid_resource_owner: Emandako baliabidearen jabearen kredentzialak baliogabeak dira, edo baliabidearen jabea ez da aurkitu\n        invalid_scope: Eskatutako esparrua baliogabea da, ezezaguna, edo gaizki osatua dago.\n        invalid_token:\n          expired: Sarbide token-a iraungitu da\n          revoked: Sarbide token-a indargabetua izan da\n          unknown: Sarbide token-a baliogabea da\n        resource_owner_authenticator_not_configured: Baliabidearen jabearen bilaketak huts egin du Doorkeeper.configure.resource_owner_authenticator konfiguratu gabe dagoelako.\n        server_error: Autorizatze zerbitzariak eskaera betetzea eragotzi duen ustekabeko baldintza bat aurkitu du.\n        temporarily_unavailable: Autorizatze zerbitzariak ezin du orain eskaera bete  une batez zerbitzariak gainezka egin duelako edo mantentze lanetan dagoelako.\n        unauthorized_client: Bezeroak ez du eskaera hau metodo hau erabiliz egiteko baimenik.\n        unsupported_grant_type: Autorizatze mota ez da onartzen autorizatze zerbitzarian.\n        unsupported_response_type: Autorizatze zerbitzari honek ez du onartzen erantzun mota hau.\n    flash:\n      applications:\n        create:\n          notice: Aplikazioa sortuta.\n        destroy:\n          notice: Aplikazioa ezabatuta.\n        update:\n          notice: Aplikazioa eguneratuta.\n      authorized_applications:\n        destroy:\n          notice: Aplikazioa indargabetuta.\n    layouts:\n      admin:\n        nav:\n          applications: Aplikazioak\n          oauth2_provider: OAuth2 hornitzailea\n      application:\n        title: OAuth autorizazioa behar da\n    scopes:\n      follow: aldatu kontuaren erlazioak\n      push: jaso push jakinarazpenak\n      read: irakurri zure kontuko datu guztiak\n      read:accounts: ikusi kontuaren informazioa\n      read:blocks: ikusi zure blokeoak\n      read:favourites: ikusi zure gogokoak\n      read:filters: ikusi zure iragazkiak\n      read:follows: ikusi zuk jarraitutakoak\n      read:lists: ikusi zure zerrendak\n      read:mutes: ikusi zuk mutututakoak\n      read:notifications: ikusi zure jakinarazpenak\n      read:reports: ikusi zure salaketak\n      read:search: bilatu zure izenean\n      read:statuses: ikusi mezu guztiak\n      write: kontuaren datu guztiak aldatzea\n      write:accounts: zure profila aldatzea\n      write:blocks: kontuak eta domeinuak blokeatzea\n      write:favourites: gogoko mezuak\n      write:filters: sortu iragazkiak\n      write:follows: jarraitu jendea\n      write:lists: sortu zerrendak\n      write:media: igo multimedia fitxategiak\n      write:mutes: mututu pertsonak eta elkarrizketak\n      write:notifications: garbitu zure jakinarazpenak\n      write:reports: salatu beste jendea\n      write:statuses: argitaratu mezuak\n"
  },
  {
    "path": "config/locales/doorkeeper.fa.yml",
    "content": "---\nfa:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: نام برنامه\n        redirect_uri: نشانی تغییرمسیر\n        scopes: محدوده\n        website: وبگاه برنامه\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              fragment_present: نمی‌تواند چندتکه باشد.\n              invalid_uri: باید یک نشانی معتبر باشد.\n              relative_uri: باید یک نشانی مطلق باشد.\n              secured_uri: باید یک نشانی HTTPS/SSL باشد.\n  doorkeeper:\n    applications:\n      buttons:\n        authorize: اجازه دادن\n        cancel: لغو\n        destroy: پاک کردن\n        edit: ویرایش\n      confirmations:\n        destroy: آیا مطمئن هستید؟\n      edit:\n        title: ویرایش برنامه\n      form:\n        error: اوخ! ببینید چیزی را اشتباهی در فرم وارد نکرده‌اید؟\n      help:\n        native_redirect_uri: برای آزمایش‌های محلی %{native_redirect_uri} را به کار ببرید\n        redirect_uri: هر URI را در یک سطر جدا بنویسید\n        scopes: دامنه‌ها را با فاصلهٔ خالی از هم جدا کنید. برای به‌کاربردن دامنهٔ پیش‌فرض خالی بگذارید.\n      index:\n        application: برنامه\n        callback_url: نشانی Callback\n        delete: حذف\n        name: نام\n        new: برنامهٔ تازه\n        scopes: دامنه‌ها\n        show: نمایش\n        title: برنامه‌های شما\n      new:\n        title: برنامهٔ تازه\n      show:\n        application_id: کلید کلاینت\n        callback_urls: نشانی‌های Callabck\n        scopes: دامنه‌ها\n        secret: کد سری کلاینت\n        title: 'برنامه: %{name}'\n    authorizations:\n      buttons:\n        authorize: اجازه دادن\n        deny: لغو اجازه\n      error:\n        title: خطایی رخ داد\n      new:\n        able_to: اجازه خواهد داشت\n        prompt: برنامهٔ %{client_name} می‌خواهد به حساب شما دسترسی داشته باشد\n        title: نیاز به اجازه دادن\n      show:\n        title: این کد مجوز را کپی کرده و در برنامه وارد کنید.\n    authorized_applications:\n      buttons:\n        revoke: فسخ\n      confirmations:\n        revoke: آیا مطمئن هستید؟\n      index:\n        application: برنامه\n        created_at: مجازشده از\n        scopes: اجازه‌ها\n        title: برنامه‌های مجاز\n    errors:\n      messages:\n        access_denied: دارندهٔ منبع یا سرور اجازه دهنده درخواست را نپذیرفت.\n        invalid_token:\n          expired: کد دسترسی منقضی شده است\n          revoked: کد دسترسی فسخ شده است\n          unknown: کد دسترسی معتبر نیست\n        server_error: خطای پیش‌بینی‌نشده‌ای برای سرور اجازه‌دهنده رخ داد که جلوی اجرای این درخواست را گرفت.\n        temporarily_unavailable: سرور اجازه‌دهنده به دلیل بار زیاد یا تعمیرات سرور هم‌اینک نمی‌تواند درخواست شما را بررسی کند.\n    flash:\n      applications:\n        create:\n          notice: برنامه ساخته شد.\n        destroy:\n          notice: برنامه حذف شد.\n        update:\n          notice: برنامه به‌روز شد.\n      authorized_applications:\n        destroy:\n          notice: برنامه فسخ شد.\n    layouts:\n      admin:\n        nav:\n          applications: برنامه‌ها\n          oauth2_provider: فراهم‌کنندهٔ ورود دومرحله‌ای\n      application:\n        title: درخواست اجازهٔ OAuth\n    scopes:\n      follow: پیگیری، مسدودسازی، لغو مسدودسازی، و لغو پیگیری حساب‌ها\n      push: برای حساب خود اعلان‌های لحظه‌ای دریافت کنید\n      read: خواندن اطلاعات حساب شما\n      write: انتشار مطالب از طرف شما\n"
  },
  {
    "path": "config/locales/doorkeeper.fi.yml",
    "content": "---\nfi:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: Sovelluksen nimi\n        redirect_uri: Uudelleenohjauksen URI\n        scopes: Oikeudet\n        website: Sovelluksen verkkosivu\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              fragment_present: ei voi sisältää osia.\n              invalid_uri: on oltava kelvollinen URI.\n              relative_uri: on oltava täydellinen URI.\n              secured_uri: on oltava HTTPS/SSL-URI.\n  doorkeeper:\n    applications:\n      buttons:\n        authorize: Valtuuta\n        cancel: Peruuta\n        destroy: Tuhoa\n        edit: Muokkaa\n        submit: Lähetä\n      confirmations:\n        destroy: Oletko varma?\n      edit:\n        title: Muokkaa sovellusta\n      form:\n        error: Hups! Tarkista, että lomakkeessa ei ole virheitä\n      help:\n        native_redirect_uri: Käytä %{native_redirect_uri} paikallisiin testeihin\n        redirect_uri: Lisää jokainen URI omalle rivilleen\n        scopes: Erota oikeudet välilyönnein. Jos kenttä jätetään tyhjäksi, käytetään oletusoikeuksia.\n      index:\n        application: Sovellus\n        callback_url: Takaisinkutsu-URL\n        delete: Poista\n        name: Nimi\n        new: Uusi sovellus\n        scopes: Oikeudet\n        show: Näytä\n        title: Omat sovellukset\n      new:\n        title: Uusi sovellus\n      show:\n        actions: Toiminnot\n        application_id: Asiakasohjelman tunnus\n        callback_urls: Takaisinkutsu-URL:t\n        scopes: Oikeudet\n        secret: Asiakasohjelman salainen avain\n        title: 'Sovellus: %{name}'\n    authorizations:\n      buttons:\n        authorize: Valtuuta\n        deny: Evää\n      error:\n        title: Tapahtui virhe\n      new:\n        able_to: Se voi\n        prompt: Sovellus %{client_name} pyytää lupaa käyttää tiliäsi\n        title: Valtuutus vaaditaan\n      show:\n        title: Kopioi tämä valtuutuskoodi ja liitä se sovellukseen.\n    authorized_applications:\n      buttons:\n        revoke: Peru\n      confirmations:\n        revoke: Oletko varma?\n      index:\n        application: Sovellus\n        created_at: Valtuutettu\n        scopes: Oikeudet\n        title: Valtuutetut sovellukset\n    errors:\n      messages:\n        access_denied: Resurssin omistaja tai valtuutuspalvelin hylkäsi pyynnön.\n        credential_flow_not_configured: Resurssin omistajan salasana epäonnistui, koska asetusta Doorkeeper.configure.resource_owner_from_credentials ei ole konfiguroitu.\n        invalid_client: Asiakasohjelman valtuutus epäonnistui, koska asiakas on tuntematon, asiakkaan valtuutus ei ollut mukana tai valtuutustapaa ei tueta.\n        invalid_grant: Valtuutuslupa on virheellinen, umpeutunut, peruttu, valtuutuspyynnössä käytettyä uudelleenohjaus-URI:tä vastaamaton tai myönnetty toiselle asiakkaalle.\n        invalid_redirect_uri: Uudelleenohjaus-URI on virheellinen.\n        invalid_request: Pyynnöstä puuttuu vaadittu parametri, se sisältää tukemattoman parametriarvon tai on muulla tavoin väärin muotoiltu.\n        invalid_resource_owner: Annetut resurssin omistajan tunnnukset ovat virheelliset, tai resurssin omistajaa ei löydy\n        invalid_scope: Pyydetyt oikeudet ovat virheellisiä, tuntemattomia tai väärin muotoiltuja.\n        invalid_token:\n          expired: Käyttöoikeustunnus on vanhentunut\n          revoked: Käyttöoikeustunnus on peruttu\n          unknown: Käyttöoikeustunnus on virheellinen\n        resource_owner_authenticator_not_configured: Resurssin omistajaa ei löytynyt, koska asetusta Doorkeeper.configure.resource_owner_authenticator ei ole konfiguroitu.\n        server_error: Valtuutuspalvelin kohtasi odottamattoman virheen, joka esti pyynnön täyttämisen.\n        temporarily_unavailable: Valtuutuspalvelin ei voi tällä hetkellä käsitellä pyyntöä joko väliaikaisen ruuhkan tai huollon takia.\n        unauthorized_client: Asiakkaalla ei ole valtuuksia tehdä tätä pyyntöä tällä metodilla.\n        unsupported_grant_type: Valtuutuspalvelin ei tue tätä valtuutusluvan tyyppiä.\n        unsupported_response_type: Valtuutuspalvelin ei tue tätä vastauksen tyyppiä.\n    flash:\n      applications:\n        create:\n          notice: Sovellus luotu.\n        destroy:\n          notice: Sovellus poistettu.\n        update:\n          notice: Sovellus päivitetty.\n      authorized_applications:\n        destroy:\n          notice: Sovellus peruttu.\n    layouts:\n      admin:\n        nav:\n          applications: Sovellukset\n          oauth2_provider: OAuth2-palveluntarjoaja\n      application:\n        title: OAuth-valtuutus tarvitaan\n    scopes:\n      follow: seurata, estää, perua eston ja lopettaa tilien seuraaminen\n      read: lukea tilin tietoja\n      write: julkaista puolestasi\n"
  },
  {
    "path": "config/locales/doorkeeper.fr.yml",
    "content": "---\nfr:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: Nom\n        redirect_uri: L’URL de redirection\n        scopes: Étendues\n        website: Site web de l’application\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              fragment_present: ne peut contenir un fragment.\n              invalid_uri: doit être une URL valide.\n              relative_uri: doit être une URL absolue.\n              secured_uri: doit être une URL HTTP/SSL.\n  doorkeeper:\n    applications:\n      buttons:\n        authorize: Autoriser\n        cancel: Annuler\n        destroy: Détruire\n        edit: Modifier\n        submit: Envoyer\n      confirmations:\n        destroy: Êtes-vous certain·e ?\n      edit:\n        title: Modifier l’application\n      form:\n        error: Oups ! Vérifier votre formulaire pour des erreurs possibles\n      help:\n        native_redirect_uri: Utiliser %{native_redirect_uri} pour les tests locaux\n        redirect_uri: Utiliser une ligne par URL\n        scopes: Séparer les portées avec des espaces. Laisser vide pour utiliser les portées par défaut.\n      index:\n        application: Application\n        callback_url: URL de retour d’appel\n        delete: Effacer\n        name: Nom\n        new: Nouvelle application\n        scopes: Portées\n        show: Voir\n        title: Vos applications\n      new:\n        title: Nouvelle application\n      show:\n        actions: Actions\n        application_id: ID de l’application\n        callback_urls: URL du retour d’appel\n        scopes: Portées\n        secret: Secret\n        title: 'Application : %{name}'\n    authorizations:\n      buttons:\n        authorize: Autoriser\n        deny: Refuser\n      error:\n        title: Une erreur est survenue\n      new:\n        able_to: Cette application pourra\n        prompt: Autoriser %{client_name} à utiliser votre compte ?\n        title: Autorisation requise\n      show:\n        title: Copiez ce code d’autorisation et collez-le dans l’application.\n    authorized_applications:\n      buttons:\n        revoke: Annuler\n      confirmations:\n        revoke: Êtes-vous certain·e ?\n      index:\n        application: Application\n        created_at: Créé le\n        date_format: \"%d-%m-%Y %H:%M:%S\"\n        scopes: permissions\n        title: Vos applications autorisées\n    errors:\n      messages:\n        access_denied: Le propriétaire de la ressource ou le serveur d’autorisation a refusé la requête.\n        credential_flow_not_configured: Le flux des identifiants du mot de passe du propriétaire de la ressource a échoué car Doorkeeper.configure.resource_owner_from_credentials n’est pas configuré.\n        invalid_client: L’authentification du client a échoué à cause d’un client inconnu, d’aucune authentification de client incluse ou d’une méthode d’authentification non prise en charge.\n        invalid_grant: Le consentement d’autorisation accordé n’est pas valide, a expiré, est annulé, ne concorde pas avec l’URL de redirection utilisée dans la requête d’autorisation ou a été émis à un autre client.\n        invalid_redirect_uri: L’URL de redirection n’est pas valide.\n        invalid_request: La requête omet un paramètre requis, inclut une valeur de paramètre non prise en charge ou est autrement mal formée.\n        invalid_resource_owner: Les identifiants fournis par le propriétaire de la ressource ne sont pas valides ou le propriétaire de la ressource ne peut être trouvé\n        invalid_scope: La portée demandée n’est pas valide, est inconnue ou mal formée.\n        invalid_token:\n          expired: Le jeton d’accès a expiré\n          revoked: Le jeton d’accès a été révoqué\n          unknown: Le jeton d’accès n’est pas valide\n        resource_owner_authenticator_not_configured: La recherche du propriétaire de la ressource a échoué car Doorkeeper.configure.resource_owner_authenticator n’est pas configuré.\n        server_error: Le serveur d’autorisation a rencontré une condition inattendue l’empêchant de faire aboutir la requête.\n        temporarily_unavailable: Le serveur d’autorisation est actuellement incapable de traiter la requête à cause d’une surcharge ou d’une maintenance temporaire du serveur.\n        unauthorized_client: Le client n’est pas autorisé à effectuer cette requête à l’aide de cette méthode.\n        unsupported_grant_type: Le type de consentement d’autorisation n’est pas pris en charge par le serveur d’autorisation.\n        unsupported_response_type: Le serveur d’autorisation ne prend pas en charge ce type de réponse.\n    flash:\n      applications:\n        create:\n          notice: Application créée.\n        destroy:\n          notice: Application supprimée.\n        update:\n          notice: Application mise à jour.\n      authorized_applications:\n        destroy:\n          notice: Application annulée.\n    layouts:\n      admin:\n        nav:\n          applications: Applications\n          oauth2_provider: Fournisseur OAuth2\n      application:\n        title: Autorisation OAuth requise\n    scopes:\n      follow: modifier les relations avec les comptes\n      push: recevoir vos notifications\n      read: lire toutes les données de votre compte\n      read:accounts: voir les informations du compte\n      read:blocks: voir vos bloquages\n      read:favourites: voir vos favoris\n      read:filters: voir vos filtres\n      read:follows: voir vos suivis\n      read:lists: voir vos listes\n      read:mutes: voir vos masquages\n      read:notifications: voir vos notifications\n      read:reports: voir vos rapports\n      read:search: rechercher en votre nom\n      read:statuses: voir tous les statuts\n      write: modifier toutes les données de votre compte\n      write:accounts: modifier votre profil\n      write:blocks: bloquer des comptes et des domaines\n      write:favourites: statuts favoris\n      write:filters: créer des filtres\n      write:follows: suivre les gens\n      write:lists: créer des listes\n      write:media: téléverser des fichiers-média\n      write:mutes: masquer des gens et des conversations\n      write:notifications: nettoyer vos notifications\n      write:reports: rapporter d’autres personnes\n      write:statuses: publier des statuts\n"
  },
  {
    "path": "config/locales/doorkeeper.gl.yml",
    "content": "---\ngl:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: Nome do aplicativo\n        redirect_uri: URI a redireccionar\n        scopes: Permisos\n        website: Sitio web do aplicativo\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              fragment_present: non pode conter un fragmento.\n              invalid_uri: debe ser un URI válido.\n              relative_uri: debe ser un URI absoluto.\n              secured_uri: debe ser un URI HTTPS/SSL.\n  doorkeeper:\n    applications:\n      buttons:\n        authorize: Autorizar\n        cancel: Cancelar\n        destroy: Destruír\n        edit: Editar\n        submit: Enviar\n      confirmations:\n        destroy: Está segura?\n      edit:\n        title: Editar aplicativo\n      form:\n        error: Eeeeepa! Comprobe os posibles erros no formulario\n      help:\n        native_redirect_uri: Utilice %{native_redirect_uri} para probas locais\n        redirect_uri: Utilice unha liña por URI\n        scopes: Separar permisos con espazos. Deixar en blanco para utilizar os permisos por omisión.\n      index:\n        application: Aplicativo\n        callback_url: URL de chamada\n        delete: Eliminar\n        name: Nome\n        new: Novo aplicativo\n        scopes: Permisos\n        show: Mostrar\n        title: Os seus aplicativos\n      new:\n        title: Novo aplicativo\n      show:\n        actions: Accións\n        application_id: Chave do cliente\n        callback_urls: URLs de chamada\n        scopes: Permisos\n        secret: Chave secreta do cliente\n        title: 'Aplicativo: %{name}'\n    authorizations:\n      buttons:\n        authorize: Autorizar\n        deny: Denegar\n      error:\n        title: Algo fallou\n      new:\n        able_to: Poderá\n        prompt: O aplicativo %{client_name} solicita acceso a súa conta\n        title: Autorización necesaria\n      show:\n        title: Copie este código de autorización e pégueo no aplicativo.\n    authorized_applications:\n      buttons:\n        revoke: Retirar autorización\n      confirmations:\n        revoke: Está segura?\n      index:\n        application: Aplicativo\n        created_at: Autorizado\n        date_format: \"%d-%m-%Y %H:%M:%S\"\n        scopes: Permisos\n        title: Os seus aplicativos autorizados\n    errors:\n      messages:\n        access_denied: O propietario do recurso ou o servidor autorizado denegaron a petición.\n        credential_flow_not_configured: O fluxo do Contrasinal de Credenciais do Dono do Recurso  fallou debido a que Doorkeeper.configure.resource_owner_from_credentials non están configuradas.\n        invalid_client: A autenticación do cliente fallou debido a un cliente descoñecido, non se incluíu autenticación do cliente, ou o método de autenticación non está soportado.\n        invalid_grant: A validación da autorización proporcionada non é valida, caducou, foi rexeitada, non coincide a redirección URI utilizada na petición de autorización, ou foi proporcionada para outro cliente.\n        invalid_redirect_uri: A uri de redirección incluída non é válida.\n        invalid_request: A petición fáltalle un parámetro requerido, inclúe un valor de parámetro non soportado, ou de algún xeito non ten o formato axeitado.\n        invalid_resource_owner: As credenciais do dono do recurso proporcionadas non son válidas, ou o dono do recurso non pode ser atopado\n        invalid_scope: O permiso solicitado non é válido, descoñecido, ou mal formado.\n        invalid_token:\n          expired: O testemuño de acceso caducou\n          revoked: O testemuño de acceso foi rexeitado\n          unknown: O testemuño de acceso non é válido\n        resource_owner_authenticator_not_configured: O dono do recurso fallou debido a Doorkeeper.configure.resource_owner_authenticator non estar configurado.\n        server_error: O servidor de autorización atopou un problema non agardado que evitou completar a petición.\n        temporarily_unavailable: O servidor de autorización non pode atender a petición en este momento debido a unha sobrecarga puntual ou mantemento do servidor.\n        unauthorized_client: O cliente non está autorizado a realizar a petición utilizando este método.\n        unsupported_grant_type: O método para proporcionar autorización non está soportado polo servidor de autorización.\n        unsupported_response_type: O servidor de autorización non soporta este tipo de resposta.\n    flash:\n      applications:\n        create:\n          notice: Aplicativo creado.\n        destroy:\n          notice: Aplicativo eliminado.\n        update:\n          notice: Aplicativo actualizado.\n      authorized_applications:\n        destroy:\n          notice: Aplicativo rexeitado.\n    layouts:\n      admin:\n        nav:\n          applications: Aplicativos\n          oauth2_provider: Proveedor OAuth2\n      application:\n        title: Precisa autorización OAuth\n    scopes:\n      follow: modificar as relacións da conta\n      push: recibir notificacións push\n      read: ler todos os datos da súa conta\n      read:accounts: ver información das contas\n      read:blocks: ver a quen bloquea\n      read:favourites: ver as súas favoritas\n      read:filters: ver os seus filtros\n      read:follows: ver a quen segue\n      read:lists: ver as súas listas\n      read:mutes: ver a quen ten acalado\n      read:notifications: ver as notificacións\n      read:reports: ver os seus informes\n      read:search: buscar no seu nome\n      read:statuses: ver todos os estados\n      write: modificar todos os datos da súa conta\n      write:accounts: modificar o seu perfil\n      write:blocks: bloquear contas e dominios\n      write:favourites: estados favoritos\n      write:filters: crear filtros\n      write:follows: seguir usuarias\n      write:lists: crear listas\n      write:media: subir ficheiros de medios\n      write:mutes: acalar usuarias e conversas\n      write:notifications: eliminar as notificacións\n      write:reports: informe a outras usuarias\n      write:statuses: publicar estados\n"
  },
  {
    "path": "config/locales/doorkeeper.he.yml",
    "content": "---\nhe:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: שם\n        redirect_uri: קישורית הפניה\n        scopes: תחומים\n        website: אתר יישום\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              fragment_present: לא יכול להכיל מקטע.\n              invalid_uri: חייב להכיל קישורית בת-תוקף.\n              relative_uri: חייב להיות קישורית אבסולוטית.\n              secured_uri: חייב להיות קישורית מאובטחת מסוג HTTPS.\n  doorkeeper:\n    applications:\n      buttons:\n        authorize: אישור\n        cancel: ביטול\n        destroy: השמדה\n        edit: עריכה\n        submit: שליחה\n      confirmations:\n        destroy: בטוח?\n      edit:\n        title: עריכת ישום\n      form:\n        error: אופס! נא לבדוק את הטופס לשגיאות אפשריות\n      help:\n        native_redirect_uri: שימוש ב %{native_redirect_uri} לבדיקות מקומיות\n        redirect_uri: שימוש בשורה אחת לכל קישורית\n        scopes: יש להפריד תחומים בעזרת רווחים. נה להשאיר ריק על מנת להשתמש בתחום ברירת המחדל.\n      index:\n        application: יישום\n        callback_url: כתובת גישה חוזרת (Callback URL)\n        delete: למחוק\n        name: שם\n        new: ישום חדש\n        scopes: תחומים\n        show: להציג\n        title: ישומך\n      new:\n        title: ישום חדש\n      show:\n        actions: פעולות\n        application_id: זהות ישום\n        callback_urls: כתובות לקריאה חוזרת (Callback URLs)\n        scopes: תחומים\n        secret: סוד\n        title: 'ישום: %{name}'\n    authorizations:\n      buttons:\n        authorize: הרשאה\n        deny: מניעה\n      error:\n        title: התרחשה שגיאה\n      new:\n        able_to: יוכל\n        prompt: ישום %{client_name} מבקש גישה לחשבונך\n        title: נדרשת הרשאה\n      show:\n        title: יש להעתיק את קוד ההרשאה הזה ולהדביקו ביישום שביקש אותו.\n    authorized_applications:\n      buttons:\n        revoke: ביטול\n      confirmations:\n        revoke: בטוח?\n      index:\n        application: ישום\n        created_at: מאושר\n        scopes: תחומים\n        title: ישומיך המאושרים\n    errors:\n      messages:\n        access_denied: בעלי המשאב או שרת ההרשאה דחו את הבקשה.\n        credential_flow_not_configured: התהליך \"Resource Owner Password Credentials\" נכשל בשל חוסר בתצורת Doorkeeper.configure.resource_owner_from_credentials.\n        invalid_client: הרשאת הלקוח נכשלה עקב לקוח שאינו ידוע, חוסר בהרשאת לקוח או שיטת הרשאה שאינה נתמכת.\n        invalid_grant: חוזה ההרשאה המצורף אינו חוקי, אינו תקף, מבוטל, או שאינו מתאים לקישורית ההפניה שבשימוש על ידי בקשת ההרשאה, או שהופק על ידי לקוח אחר.\n        invalid_redirect_uri: קישורית ההפניה המצורפת אינה חוקית.\n        invalid_request: הבקשה חסרה פרמטר נדרש, מכילה פרמטר עם ערך שאיננו נתמך, או שתצורתה שגויה.\n        invalid_resource_owner: הרשאות בעלי המשאב שהוזנו אינן חוקיות, או שלא ניתן למצוא את בעלי המשאב\n        invalid_scope: התחום המבוקש אינו חוקי, אינו ידוע, או שתצורותו שגויה.\n        invalid_token:\n          expired: פג תוקף אסימון הגישה\n          revoked: בוטל תוקף אסימון הגישה\n          unknown: אסימון הגישה אינו חוקי\n        resource_owner_authenticator_not_configured: חיפוש בעלי המשאב נכשל מכיוון שתצורת Doorkeeper.configure.resource_owner_authenticator לא הושלמה.\n        server_error: שרת ההרשאות נתקל במצב בלתי צפוי, שמונע ממנו להשלים את הבקשה.\n        temporarily_unavailable: שרת ההרשאות לא מסוגל לטפל בבקשה בעת זו עקב עומס זמני או עקב תחזוקה של השרת.\n        unauthorized_client: הלקוח אינו מאושר להגיש בקשה זו בשיטה זו.\n        unsupported_grant_type: סוג חוזה הרשאה זה אינו נתמך על ידי שרת ההרשאות.\n        unsupported_response_type: שרת ההרשאות לא תומך בסוג תגובה זה.\n    flash:\n      applications:\n        create:\n          notice: הישום נוצר.\n        destroy:\n          notice: הישום נמחק.\n        update:\n          notice: הישום עודכן.\n      authorized_applications:\n        destroy:\n          notice: הישום בוטל.\n    layouts:\n      admin:\n        nav:\n          applications: ישומים\n          oauth2_provider: ספק OAuth2\n      application:\n        title: נדרשת הרשאת OAuth\n    scopes:\n      follow: לעקוב, לחסום, להסיר חסימה ולהפסיק לעקוב אחרי חשבונות\n      read: לקרוא את המידע שבחשבונך\n      write: להפיץ הודעות בשמך\n"
  },
  {
    "path": "config/locales/doorkeeper.hr.yml",
    "content": "---\nhr:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: Ime\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              fragment_present: ne može sadržavati fragment.\n              invalid_uri: mora biti valjan URI.\n              relative_uri: mora biti apsolutan URI.\n              secured_uri: mora biti HTTPS/SSL URI.\n  doorkeeper:\n    applications:\n      buttons:\n        authorize: Odobri\n        cancel: Otkaži\n        destroy: Uništi\n        edit: Uredi\n        submit: Pošalji\n      confirmations:\n        destroy: Jesi li siguran?\n      edit:\n        title: Uredi aplikaciju\n      form:\n        error: Ups! Provjeri svoju formu za moguće greške\n      help:\n        native_redirect_uri: Koristi %{native_redirect_uri} za lokalne testove\n        redirect_uri: Koristi jednu liniju po URI\n        scopes: Odvoji scopes sa razmacima. Ostavi prazninu kako bi koristio zadane scopes.\n      index:\n        name: Ime\n        new: Nova Aplikacija\n        title: Tvoje aplikacije\n      new:\n        title: Nova Aplikacija\n      show:\n        actions: Akcije\n        application_id: Id Aplikacije\n        callback_urls: Callback urls\n        secret: Tajna\n        title: 'Aplikacija: %{name}'\n    authorizations:\n      buttons:\n        authorize: Odobri\n        deny: Odbij\n      error:\n        title: Došlo je do greške\n      new:\n        able_to: Moći će\n        prompt: Aplikacija %{client_name} je zatražila pristup tvom računu\n        title: Traži se autorizacija\n    authorized_applications:\n      buttons:\n        revoke: Odbij\n      confirmations:\n        revoke: Jesi li siguran?\n      index:\n        application: Aplikacija\n        created_at: Ovlašeno\n        title: Tvoje autorizirane aplikacije\n    errors:\n      messages:\n        access_denied: Vlasnik resursa / autorizacijski server je odbio zahtjev.\n        invalid_client: Autentifikacija klijenta nije uspjela zbog nepoznatog klijenta, neuključene autentifikacije od strane klijenta, ili nepodržane metode autentifikacije.\n        invalid_redirect_uri: The redirect uri included nije valjan.\n        invalid_request: Zahtjevu nedostaje traženi parametar, uključuje nepodržanu vrijednost parametra, ili je na neki drugi način neispravno formiran.\n        invalid_resource_owner: The provided resource owner credentials nisu valjani, ili vlasnik resursa ne može biti nađen\n        invalid_scope: Traženi scope nije valjan, znan, ili je neispravno oblikovan.\n        invalid_token:\n          expired: Pristupni token je istekao\n          revoked: Pristupni token je odbijen\n          unknown: Pristupni token nije valjan\n        server_error: Autorizacijski server naišao je na neočekivani uvjet, što ga je onemogućilo da ispuni zahtjev.\n        temporarily_unavailable: Autorizacijski server trenutno nije u mogućnosti  izvesti zahtjev zbog privremenog preopterećenja ili održavanja servera.\n        unauthorized_client: Klijent nije ovlašten izvesti zahtjev koristeći ovu metodu.\n        unsupported_grant_type: The authorization grant tip nije podržan od autorizacijskog servera.\n        unsupported_response_type: Autorizacijski server ne podržava ovaj tip odgovora.\n    flash:\n      applications:\n        create:\n          notice: Aplikacija je stvorena.\n        destroy:\n          notice: Aplikacija je obrisana.\n        update:\n          notice: Aplikacija je ažurirana.\n      authorized_applications:\n        destroy:\n          notice: Aplikacija je odbijena.\n    layouts:\n      admin:\n        nav:\n          applications: Aplikacije\n      application:\n        title: Traži se OAuth autorizacija\n    scopes:\n      follow: slijediti, blokirati, deblokirati i prestati slijediti račune\n      read: čitati  podatke tvog računa\n      write: slati poruke u tvoje ime\n"
  },
  {
    "path": "config/locales/doorkeeper.hu.yml",
    "content": "---\nhu:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: Név\n        redirect_uri: Visszairányító URI\n        scopes: Hatáskör\n        website: Az alkalmazás weboldala\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              fragment_present: nem tartalmazhat töredéket.\n              invalid_uri: érvényes URI-nak kell lennie.\n              relative_uri: abszolút URI-nak kell lennie.\n              secured_uri: HTTPS/SSL URI-nak kell lennie.\n  doorkeeper:\n    applications:\n      buttons:\n        authorize: Engedélyezés\n        cancel: Mégsem\n        destroy: Törlés\n        edit: Szerkesztés\n        submit: Elküldés\n      confirmations:\n        destroy: Biztos vagy benne?\n      edit:\n        title: Alkalmazás szerkesztése\n      form:\n        error: Hoppá! Ellenőrizd az űrlapot az esetleges hibák miatt\n      help:\n        native_redirect_uri: Használj %{native_redirect_uri} a helyi tesztekhez\n        redirect_uri: Egy sor URI-nként\n        scopes: A nézeteket szóközzel válaszd el. Hagyd üresen az alapértelmezett nézetekhez.\n      index:\n        application: Alkalmazás\n        delete: Eltávolítás\n        name: Név\n        new: Új alkalmazás\n        scopes: Hatáskör\n        show: Mutat\n        title: Alkalmazásod\n      new:\n        title: Új alkalmazás\n      show:\n        actions: Műveletek\n        application_id: Alkalmazás azonosító\n        callback_urls: Callback urlek\n        scopes: Nézetek\n        secret: Titok\n        title: 'Alkalmazás: %{name}'\n    authorizations:\n      buttons:\n        authorize: Engedélyezés\n        deny: Tiltás\n      error:\n        title: Hiba történt\n      new:\n        able_to: Képes lesz\n        prompt: \"%{client_name} nevű alkalmazás engedélyt kér a fiókodhoz való hozzáféréshez.\"\n        title: Engedély szükséges\n    authorized_applications:\n      buttons:\n        revoke: Visszavonás\n      confirmations:\n        revoke: Biztos vagy benne?\n      index:\n        application: Alkalmazás\n        created_at: Készítve\n        scopes: Hatáskör\n        title: Engedélyezett alkalmazásaid\n    errors:\n      messages:\n        access_denied: Az erőforrás tulajdonosa vagy hitelesítő kiszolgálója megtakadta a kérést.\n        credential_flow_not_configured: Az erőforrás tulajdonos jelszóadatainak átadása megszakadt, mert a Doorkeeper.configure.resource_owner_from_credentials beállítatlan.\n        invalid_client: A kliens hitelesítése megszakadt, mert a ismeretlen a kliens, kliens nem küldött hitelesítést, vagy ismeretlen a kliens\n        invalid_grant: A biztosított hitelesítés érvénytelen, lejárt, visszavont, vagy nem egyezik a hitelesítéi kérésben használt URIval, vagy más kliensnek lett címezve.\n        invalid_redirect_uri: A redirect uri nem valós.\n        invalid_request: A kérésből hiányzik egy szükséges paraméter, nem támogatott paramétert tartalmaz, vagy egyéb módon hibás.\n        invalid_resource_owner: A biztosított erőforrás tulajdonosának hitelesítő adatai nem valósak, vagy az erőforrás tulajdonosa nem található.\n        invalid_scope: A kért nézet érvénytelen, ismeretlen, vagy hibás.\n        invalid_token:\n          expired: Hozzáférési kulcs lejárt\n          revoked: Hozzáférési kulcs vissza lett vonva\n          unknown: Hozzáférési kulcs érvénytelen\n        resource_owner_authenticator_not_configured: Erőforrás tulajdonos keresés megszakadt, ugyanis a Doorkeeper.configure.resource_owner_authenticator beállítatlan.\n        server_error: Hitelesítő szervert váratlan esemény érte, mely meggátolta a kérés teljesítését.\n        temporarily_unavailable: A hitelesítő szerver jelenleg nem tudja teljesíteni a kérést egy átmeneti túlterheltség vagy a kiszolgáló karbantartása miatt.\n        unauthorized_client: A kliens nincs feljogosítva a kérés teljesítésére.\n        unsupported_grant_type: A hitelesítés módja nem támogatott a hitelesítő kiszolgálón.\n        unsupported_response_type: A hitelesítő kiszolgáló nem támogatja ezt a választ.\n    flash:\n      applications:\n        create:\n          notice: Alkalmazás létrehozva.\n        destroy:\n          notice: Alkalmazás törölve.\n        update:\n          notice: Alkalmazás frissítve.\n      authorized_applications:\n        destroy:\n          notice: Alkalmazás visszavonva.\n    layouts:\n      admin:\n        nav:\n          applications: Alkalmazások\n          oauth2_provider: OAuth2 szolgáltató\n      application:\n        title: OAuth engedély szükséges\n    scopes:\n      follow: fiókok követése, blokkoláse, blokkolás feloldása és követés abbahagyása\n      read: fiókod adatainak olvasása\n      write: bejegyzés írása a nevedben\n"
  },
  {
    "path": "config/locales/doorkeeper.hy.yml",
    "content": "hy:\n"
  },
  {
    "path": "config/locales/doorkeeper.id.yml",
    "content": "---\nid:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: Nama aplikasi\n        redirect_uri: URI Pengalihan\n        scopes: Cakupan\n        website: Website aplikasi\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              fragment_present: tidak dapat mengandung sebuah pecahan.\n              invalid_uri: harus URI yang valid.\n              relative_uri: harus URI yang absolut.\n              secured_uri: harus berupa URI HTTPS/SSL.\n  doorkeeper:\n    applications:\n      buttons:\n        authorize: Otorisasi\n        cancel: Batal\n        destroy: Hapus\n        edit: Ubah\n        submit: Kirim\n      confirmations:\n        destroy: Apakah anda yakin?\n      edit:\n        title: Ubah aplikasi\n      form:\n        error: Oops! Cek kembali kemungkinan kesalahan pada formulir anda\n      help:\n        native_redirect_uri: Gunakan %{native_redirect_uri} sebagai tes lokal\n        redirect_uri: Gunakan satu baris per URI\n        scopes: Pisahkan scope dengan spasi. Biarkan kosong jika ingin menggunakan scope default.\n      index:\n        application: Aplikasi\n        callback_url: URL Callback\n        delete: Hapus\n        name: Nama\n        new: Aplikasi baru\n        scopes: Cakupan\n        show: Tampilkan\n        title: Aplikasi anda\n      new:\n        title: Aplikasi Baru\n      show:\n        actions: Aksi\n        application_id: Id Aplikasi\n        callback_urls: Url callback\n        scopes: Scope\n        secret: Rahasia\n        title: 'Aplikasi: %{name}'\n    authorizations:\n      buttons:\n        authorize: Izinkan\n        deny: Tolak\n      error:\n        title: Ada yang error\n      new:\n        able_to: Mempunyai akses untuk\n        prompt: Aplikasi %{client_name} meminta akses pada akun anda\n        title: Izin diperlukan\n    authorized_applications:\n      buttons:\n        revoke: Cabut izin\n      confirmations:\n        revoke: Anda yakin?\n      index:\n        application: Aplikasi\n        created_at: Diizinkan pada\n        scopes: Scope\n        title: Aplikasi yang anda izinkan\n    errors:\n      messages:\n        access_denied: Pemilik akun atau server otorisasi menolak permintaan.\n        credential_flow_not_configured: Aliran Resource Owner Password Credentials gagal dikarenakan Doorkeeper.configure.resource_owner_from_credentials tidak terkonfigurasi dengan benar.\n        invalid_client: Perizinan klien gagal karena klien tidak diketahui, tidak ada klien yang diizinkan, atau metode perizinan tidak didukung.\n        invalid_grant: Pemberian izin yang diberikan tidak valid, kadaluarsa, telah dicabut, atau tidak cocok dengan URI pengalihan yang digunakan pada permintaan izin, atau telah diberikan pada klien lain.\n        invalid_redirect_uri: Uri pengalihan tidak valid.\n        invalid_request: Permintaan ini tidak mempunyai parameter yang dibutuhkan, mengandung parameter yang tidak didukung, atau mungkin strukturnya tidak benar.\n        invalid_resource_owner: Identitas pemilik data yang diberikan tidak valid, atau pemilik data tidak ditemukan\n        invalid_scope: Scope yang diminta tidak valid, tidak diketahui, atau struktur tidak benar.\n        invalid_token:\n          expired: Token akses telah kadaluarsa\n          revoked: Token akses telah dicabut\n          unknown: Token akses tidak valid\n        resource_owner_authenticator_not_configured: Pencarian pemilik data gagal karena Doorkeeper.configure.resource_owner_authenticator tidak dikonfigurasi dengan benar.\n        server_error: Server otorisasi tidak bisa memenuhi permintaan karena terjadi sesuatu.\n        temporarily_unavailable: Server otorisasi saat ini tidak bisa menangani permintaan karena server sibuk atau sedang ada maintenance/perawatan.\n        unauthorized_client: Klien tidak memiliki izin untuk melakukan permintaan dengan metode ini.\n        unsupported_grant_type: Tipe izin tidak didukung oleh server otorisasi.\n        unsupported_response_type: Server otorisasi tidak mendukung tipe tanggapan/response seperti ini.\n    flash:\n      applications:\n        create:\n          notice: Aplikasi dibuat.\n        destroy:\n          notice: Aplikasi dihapus.\n        update:\n          notice: Aplikasi diubah.\n      authorized_applications:\n        destroy:\n          notice: Aplikasi dicabut.\n    layouts:\n      admin:\n        nav:\n          applications: Aplikasi\n          oauth2_provider: Penyedia OAuth2\n      application:\n        title: Otorisasi OAuth diperlukan\n    scopes:\n      follow: mengikuti, blokir, menghapus blokir, dan berhenti mengikuti akun\n      read: membaca data pada akun anda\n      write: memposting sebagai anda\n"
  },
  {
    "path": "config/locales/doorkeeper.io.yml",
    "content": "---\nio:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: Nomo\n        redirect_uri: URI di plussendo\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              fragment_present: ne povas kontenar fragmento.\n              invalid_uri: mustas esar valida URI.\n              relative_uri: mustas esar absoluta URI.\n              secured_uri: mustas esar URI HTTPS/SSL.\n  doorkeeper:\n    applications:\n      buttons:\n        authorize: Yurizar\n        cancel: Nuhiligar\n        destroy: Destruktar\n        edit: Redaktar\n        submit: Sendar\n      confirmations:\n        destroy: Ka tu esas certa?\n      edit:\n        title: Redaktar apliko\n      form:\n        error: Ups! Kontrolez tua formulario kad esas erori\n      help:\n        native_redirect_uri: Uzez %{native_redirect_uri} por lokala probi\n        redirect_uri: Uzez un lineo por singla URI\n      index:\n        new: New Application\n      new:\n        title: New Application\n      show:\n        application_id: Application Id\n        callback_urls: Callback urls\n        secret: Secret\n    scopes:\n      follow: follow, block, unblock and unfollow accounts\n      read: read your account's data\n      write: post on your behalf\n"
  },
  {
    "path": "config/locales/doorkeeper.it.yml",
    "content": "---\nit:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: Nome applicazione\n        redirect_uri: URI di reindirizzamento\n        scopes: Scopi\n        website: Sito web applicazione\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              fragment_present: non può contenere un frammento.\n              invalid_uri: deve essere un URI valido.\n              relative_uri: deve essere un URI assoluto.\n              secured_uri: deve essere un URI HTTPS/SSL.\n  doorkeeper:\n    applications:\n      buttons:\n        authorize: Autorizza\n        cancel: Annulla\n        destroy: Distruggi\n        edit: Modifica\n        submit: Invia\n      confirmations:\n        destroy: Sei sicuro?\n      edit:\n        title: Modifica applicazione\n      form:\n        error: Ooops! Controlla nel modulo la presenza di errori\n      help:\n        native_redirect_uri: Usa %{native_redirect_uri} per test locali\n        redirect_uri: Usa una riga per URI\n        scopes: Dividi gli scopes con spazi. Lascia vuoto per utilizzare gli scopes di default.\n      index:\n        application: Applicazione\n        delete: Elimina\n        name: Nome\n        new: Nuova applicazione\n        show: Mostra\n        title: Le tue applicazioni\n      new:\n        title: Nuova applicazione\n      show:\n        actions: Azioni\n        application_id: Id applicazione\n        callback_urls: Callback urls\n        scopes: Scopi\n        secret: Secret\n        title: 'Applicazione: %{name}'\n    authorizations:\n      buttons:\n        authorize: Autorizza\n        deny: Nega\n      error:\n        title: Si è verificato un errore\n      new:\n        able_to: Non sarà in grado di\n        prompt: L'applicazione %{client_name} richiede l'accesso al tuo account\n        title: Autorizzazione richiesta\n      show:\n        title: Copia questo codice di autorizzazione e incollalo nell'applicazione.\n    authorized_applications:\n      buttons:\n        revoke: Disabilita\n      confirmations:\n        revoke: Sei sicuro?\n      index:\n        application: Applicazione\n        created_at: Autorizzato\n        date_format: \"%d-%m-%Y %H:%M:%S\"\n        scopes: Scopi\n        title: Applicazioni autorizzate\n    errors:\n      messages:\n        access_denied: Il proprietario del servizio o il server di autorizzazione hanno rifiutato la richiesta.\n        credential_flow_not_configured: Il processo Resource Owner Password Credentials è fallito perché Doorkeeper.configure.resource_owner_from_credentials non è stato configurato.\n        invalid_client: Accesso al servizio fallito perché il servizio è sconosciuto, l'accesso al servizio non è stato incluso, o il metodo di accesso non è supportato.\n        invalid_grant: Il permesso d'autorizzazione è non valido, scaduto, disabilitato, non coincide con l'URI di reindirizzamento fornito nella richiesta di autorizzazione, o è stato rilasciato da un altro client.\n        invalid_redirect_uri: L'URI di reindirizzamento fornito non è valido.\n        invalid_request: La richiesta non contiene un parametro necessario, contiene un valore parametrico non supportato, o è altrimenti malformulata.\n        invalid_resource_owner: Le credenziali di accesso fornite per il proprietario non sono corrette, o il proprietario del servizio non è stato trovato\n        invalid_scope: Lo scope richiesto è invalido, sconosciuto, o malformulato.\n        invalid_token:\n          expired: Il token di accesso è scaduto\n          revoked: Il token di accesso è stato disabilitato\n          unknown: Il token di accesso non è valido\n        resource_owner_authenticator_not_configured: Impossibile trovare il proprietario del servizio perché Doorkeeper.configure.resource_owner_authenticator non è stato configurato.\n        server_error: Il server di autorizzazione ha riscontrato un errore imprevisto che non ha permesso di completare la tua richiesta.\n        temporarily_unavailable: Al momento il server di autorizzazione non può completare la tua richiesta a causa di un temporaneo sovraccarico o di manutenzione del server.\n        unauthorized_client: Il client non è autorizzato a eseguire questa operazione con questo metodo.\n        unsupported_grant_type: Questa modalità di trasmissione di autenticazione non è supportata da questo server.\n        unsupported_response_type: Il server autorizzatore non supporta questa modalità di risposta.\n    flash:\n      applications:\n        create:\n          notice: Applicazione creata.\n        destroy:\n          notice: Applicazione cancellata.\n        update:\n          notice: Applicazione aggiornata.\n      authorized_applications:\n        destroy:\n          notice: Applicazione disabilitata.\n    layouts:\n      admin:\n        nav:\n          applications: Applicazioni\n          oauth2_provider: Provider OAuth2\n      application:\n        title: Autorizzazione OAuth richiesta\n    scopes:\n      follow: modificare relazioni tra account\n      push: ricevere le tue notifiche push\n      read: leggere tutte le informazioni del tuo account\n      read:accounts: vedere informazioni sull'account\n      read:blocks: vedere i tuoi blocchi\n      read:favourites: vedere i tuoi preferiti\n      read:filters: vedere i tuoi filtri\n      read:follows: vedere i tuoi seguiti\n      read:lists: vedere le tue liste\n      read:mutes: vedere i tuoi silenziati\n      read:notifications: vedere le tue notifiche\n      read:reports: vedere i tuoi rapporti\n      read:search: fare ricerche per te\n      read:statuses: vedere tutti gli status\n      write: modificare tutti i dati del tuo account\n      write:accounts: modificare il tuo profilo\n      write:blocks: bloccare account e domini\n      write:favourites: segnare status come preferiti\n      write:filters: creare filtri\n      write:follows: seguire persone\n      write:lists: creare liste\n      write:media: caricare media\n      write:mutes: silenziare persone e conversazioni\n      write:notifications: cancellare le tue notifiche\n      write:reports: fare rapporto su altre persone\n      write:statuses: pubblicare status\n"
  },
  {
    "path": "config/locales/doorkeeper.ja.yml",
    "content": "---\nja:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: アプリの名前\n        redirect_uri: リダイレクトURI\n        scopes: アクセス権\n        website: アプリのウェブサイト\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              fragment_present: フラグメントを含めることはできません。\n              invalid_uri: 有効なURIである必要があります。\n              relative_uri: 絶対URIである必要があります。\n              secured_uri: URIはHTTPS/SSLである必要があります。\n  doorkeeper:\n    applications:\n      buttons:\n        authorize: 承認\n        cancel: キャンセル\n        destroy: 削除\n        edit: 編集\n        submit: 送信\n      confirmations:\n        destroy: 本当に削除しますか？\n      edit:\n        title: アプリの編集\n      form:\n        error: フォームにエラーが無いか確認してください\n      help:\n        native_redirect_uri: ローカルテストに %{native_redirect_uri} を使用\n        redirect_uri: 一行に一つのURLを入力してください\n        scopes: アクセス権は半角スペースで区切ることができます。 空白のままにするとデフォルトを使用します。\n      index:\n        application: アプリ\n        callback_url: コールバックURL\n        delete: 削除\n        name: 名前\n        new: 新規アプリ\n        scopes: アクセス権\n        show: 見る\n        title: アプリ\n      new:\n        title: 新規アプリ\n      show:\n        actions: アクション\n        application_id: クライアントキー\n        callback_urls: コールバックURL\n        scopes: アクセス権\n        secret: クライアントシークレット\n        title: 'アプリ: %{name}'\n    authorizations:\n      buttons:\n        authorize: 承認\n        deny: 拒否\n      error:\n        title: エラーが発生しました\n      new:\n        able_to: このアプリは以下のことができます\n        prompt: アプリ %{client_name} があなたのアカウントへのアクセスを要求しています\n        title: 認証が必要です\n      show:\n        title: 認証コードをコピーしてアプリに貼り付けて下さい。\n    authorized_applications:\n      buttons:\n        revoke: 取消\n      confirmations:\n        revoke: 本当に取り消しますか？\n      index:\n        application: アプリ名\n        created_at: 許可した日時\n        date_format: \"%Y年%m月%d日 %H時%M分%S秒\"\n        scopes: アクセス権\n        title: 認証済みアプリ\n    errors:\n      messages:\n        access_denied: リソースの所有者または認証サーバーが要求を拒否しました。\n        credential_flow_not_configured: リソース所有者のパスワード Doorkeeper.configure.resource_owner_from_credentials が設定されていないためクレデンシャルフローに失敗しました。\n        invalid_client: 不明なクライアントであるか、クライアント情報が含まれていない、またはサポートされていない認証方法のため、クライアントの認証に失敗しました。\n        invalid_grant: 指定された認証許可は無効であるか、期限切れ、取り消されている、リダイレクトURIの不一致、または別のクライアントに発行されています。\n        invalid_redirect_uri: 無効なリダイレクトURIが含まれています。\n        invalid_request: リクエストに必要なパラメータが欠けているか、サポートされていないパラメータが含まれている、または不正なフォーマットです。\n        invalid_resource_owner: 指定されたリソース所有者のクレデンシャルが無効であるか、リソース所有者が見つかりません\n        invalid_scope: 要求されたアクセス権は無効であるか、不明、または不正なフォーマットです。\n        invalid_token:\n          expired: アクセストークンの有効期限が切れています\n          revoked: アクセストークンは取り消されています\n          unknown: アクセストークンが無効です\n        resource_owner_authenticator_not_configured: Doorkeeper.configure.resource_owner_authenticator が設定されていないため、リソース所有者の検索に失敗しました。\n        server_error: 認証サーバーに予期せぬ例外が発生したため、リクエストを実行できなくなりました。\n        temporarily_unavailable: 現在、認証サーバーに一時的な過負荷が掛かっているか、またはメンテナンス中のため、リクエストを処理できません。\n        unauthorized_client: クライアントはこのメゾットで要求を実行する権限がありません。\n        unsupported_grant_type: 指定された認証許可タイプは認証サーバでサポートされていません。\n        unsupported_response_type: このレスポンスタイプは認証サーバでサポートされていません。\n    flash:\n      applications:\n        create:\n          notice: アプリが作成されました。\n        destroy:\n          notice: アプリが削除されました。\n        update:\n          notice: アプリが更新されました。\n      authorized_applications:\n        destroy:\n          notice: アプリが取り消されました。\n    layouts:\n      admin:\n        nav:\n          applications: アプリ\n          oauth2_provider: OAuth2プロバイダー\n      application:\n        title: OAuth認証\n    scopes:\n      follow: アカウントのつながりを変更\n      push: プッシュ通知の受信\n      read: アカウントのすべてのデータの読み取り\n      read:accounts: アカウント情報の読み取り\n      read:blocks: ブロックの読み取り\n      read:favourites: お気に入りの読み取り\n      read:filters: フィルターの読み取り\n      read:follows: フォローの読み取り\n      read:lists: リストの読み取り\n      read:mutes: ミュートの読み取り\n      read:notifications: 通知の読み取り\n      read:reports: 通報の読み取り\n      read:search: あなたの代わりに検索\n      read:statuses: すべてのトゥートの読み取り\n      write: アカウントのすべてのデータの変更\n      write:accounts: プロフィールの変更\n      write:blocks: ユーザーのブロックやドメインの非表示\n      write:favourites: トゥートのお気に入り登録\n      write:filters: フィルターの変更\n      write:follows: あなたの代わりにフォロー、アンフォロー\n      write:lists: リストの変更\n      write:media: メディアのアップロード\n      write:mutes: アカウントや会話のミュート\n      write:notifications: 通知の消去\n      write:reports: 通報の作成\n      write:statuses: トゥートの投稿\n"
  },
  {
    "path": "config/locales/doorkeeper.ka.yml",
    "content": "---\nka:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: აპლიკაციის სახელი\n        redirect_uri: გადამისამართების ური\n        scopes: ფარგლები\n        website: აპლიკაციის ვებ-საიტი\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              fragment_present: ვერ ექნება ფრაგმეტი.\n              invalid_uri: უნდა იყოს ვალიდური ური.\n              relative_uri: უნდა იყოს აბსოლუტური ური.\n              secured_uri: უნდა იყოს ჰტტპს/სსლ ური.\n  doorkeeper:\n    applications:\n      buttons:\n        authorize: ავტორიზაცია\n        cancel: უარყოფა\n        destroy: გაუქმება\n        edit: შეცვლა\n        submit: გაგრძელება\n      confirmations:\n        destroy: დარწმუნებული ხართ?\n      edit:\n        title: აპლიკაციის შეცვლა\n      form:\n        error: უპს! შესაძლო შეცდომებზე შეამოწმეთ თქვენი ფორმა\n      help:\n        native_redirect_uri: ლოკალური ტესტებისთვის მოიხმარეთ %{native_redirect_uri}\n        redirect_uri: გამოიყენეთ ერთი ხაზი თითო ური-სთვის\n        scopes: ფარგლები გამოჰყავით სიცარიელით. საწყისი ფარგლის გამოსაყენებლად დატოვეთ ცარიელი.\n      index:\n        application: აპლიკაცია\n        callback_url: ქოლბექ ურლ\n        delete: გაუქმება\n        name: სახელი\n        new: ახალი აპლიკაცია\n        scopes: ფარგლები\n        show: ჩვენება\n        title: თქვენი აპლიკაციები\n      new:\n        title: ახალი აპლიკაცია\n      show:\n        actions: მოქმედებები\n        application_id: კლიენტის გასაღები\n        callback_urls: ქოლბექ ურლები\n        scopes: ფარგლები\n        secret: კლიენტის სერვერი\n        title: 'აპლიკაცია: %{name}'\n    authorizations:\n      buttons:\n        authorize: ავტორიზაცია\n        deny: აკრძალვა\n      error:\n        title: წარმოიშვა შეცდომა\n      new:\n        able_to: ის შეძლებს\n        prompt: აპლიკაცია %{client_name} ითხოვს წვდომას თქვენს ანგარიშზე\n        title: საჭიროა ავტორიზაცია\n      show:\n        title: დააკოპირეთ ეს ავტორიზაციის კოდი და ჩასვით აპლიკაციაში.\n    authorized_applications:\n      buttons:\n        revoke: გაუქმება\n      confirmations:\n        revoke: დარწმუნებული ხართ?\n      index:\n        application: აპლიკაცია\n        created_at: ავტორიზებული\n        scopes: ფარგლები\n        title: თქვენი ავტორიზებული აპლიკაციები\n    errors:\n      messages:\n        access_denied: რესურსის მფლობელმა ან აუტორიზაციის სერვერმა აკრძალა ეს მოთხოვნა.\n        credential_flow_not_configured: რესურის მფლობელის პაროლის რწმუნებულებების ნაკადი ვერ შესრულდა არაკონფიგურირებული Doorkeeper.configure.resource_owner_from_credentials გამო.\n        invalid_client: ამოუცნობი კლიენტის გამო კლიენტ აუტენტიფიკაცია ვერ მოხერხდა, კლიენტის აუტენტიფიკაცია არ იყო თან დართული, ან მხარდაუჭერელი აუტენტიფიკაციის მეთოდი.\n        invalid_grant: მოწოდებული ავტორიზაციის გრანტი არასწორია, ვადაგასულია, გაუქმებულია არ ემთხვევა გადამისამართების ურის, რომელიც მოიხმარება ავტორიზაცის მოთხოვნაში, ან მიეცა სხვა კლიენტს.\n        invalid_redirect_uri: მითითებული გადამისამართების ური არაა ვალიდური.\n        invalid_request: მოთხოვნას აკლია აუცილებელი პარამეტრი, მოიცავს მხარდაუჭერელ პარამეტრის მნიშვნელობას, ან სხვაგვარად არაა გამართული.\n        invalid_resource_owner: მოწოდებული რესურსის მფლობელის რწმუნებულებები არაა ვალიდური, ან მფლობელის პონვა ვერ ხერხდება\n        invalid_scope: მოთხოვნილი ფარგალი არასწორია, ამოუცნობია ან არაა გამართული.\n        invalid_token:\n          expired: წვდომის ტოკენს გაუვიდა ვადა\n          revoked: წვდომის ტოკენი გაუქმდა\n          unknown: წვდომის ტოკენი არაა ვალიდური\n        resource_owner_authenticator_not_configured: რესურსის მფლობელის მოპოვება არ შედგა Doorkeeper.configure.resource_owner_authenticator კონფიგურაციის არ არსებობის გამო.\n        server_error: აუტორიზაციის სერვერს შეხვდა მოულოდნელი მდგომარეობა, რამაც ხელი შეუშალა მას აღესრულებინა მოთხონვა.\n        temporarily_unavailable: ავტორიზაციის სერვერი ამჟამად ვერ ახერხებს მოთხოვნის შემუშავებას დროებითი გადატვირთვის ან სერვერის შენარჩუნების გამო.\n        unauthorized_client: კლიენტი არაა ავტორიზებული შეასრულოს ეს მოთხოვნა ამ მეთოდით.\n        unsupported_grant_type: ავტორიზაციის გრანტის სახეობა არაა მხარდაჭერილი ავტორიზაციის სერვერის მიერ.\n        unsupported_response_type: ავტორიზაციის სერვერი არ უჭერს მხარს ამ პასუხის სახეობას.\n    flash:\n      applications:\n        create:\n          notice: აპლიკაცია შეიქმნა.\n        destroy:\n          notice: აპლიკაცია გაუქმდა.\n        update:\n          notice: აპლიკაცია განახლდა.\n      authorized_applications:\n        destroy:\n          notice: აპლიკაცია წაიშალა.\n    layouts:\n      admin:\n        nav:\n          applications: აპლიკაციები\n          oauth2_provider: ოუ-აუთ2 პროვაიდერი\n      application:\n        title: საჭიროა ოუ-აუთ ავტორიზაცია\n    scopes:\n      follow: შეცვალეთ ანგარიშის ურთიერთობები\n      push: მიიღეთ თქვენი ფუშ შეტყობინებები\n      read: წაიკითხოს მთელი თქვენი ანგარიშის მონაცემები\n      read:accounts: იხილოს ანგარიშის ინფორმაცია\n      read:blocks: იხილოს თქვენი ბლოკები\n      read:favourites: იხილოს თქვენი ფავორიტები\n      read:filters: იხილოს თქვენი ფილრები\n      read:follows: იხილოს თქვენი მიდევნებები\n      read:lists: იხილოს თქვენი სიები\n      read:mutes: იხილოს თქვენი გაჩუმებები\n      read:notifications: იხილოს თქვენი შეტყობინებები\n      read:reports: იხილოს თქვენი რეპორტები\n      read:search: მოძებნოს თქვენი სახელით\n      read:statuses: იხილოს ყველა სტატუსი\n      write: შეცვალოს მთელი თქვენი ანგარიშის მონაცემები\n      write:accounts: შეცვალოს თქვენი პროფილი\n      write:blocks: დაბლოკოს ანგარიშები და დომენები\n      write:favourites: ფავორიტი სტატუსები\n      write:filters: შექმნას ფილტრები\n      write:follows: გაყვეს ხალხს\n      write:lists: შექმნას სიები\n      write:media: ატვირთოს მედია ფაილები\n      write:mutes: გააგჩუმოს ადამიანები და საუბრები\n      write:notifications: გაასუფთავოს თქვენი შეტყობინებები\n      write:reports: დაარეპორტოს სხვა ადამიანები\n      write:statuses: გამოაქვეყნოს სტატუსები\n"
  },
  {
    "path": "config/locales/doorkeeper.kk.yml",
    "content": "---\nkk:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: Application аты\n        redirect_uri: Redirеct URI\n        scopes: Scopеs\n        website: Application сайты\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              fragment_present: cannot contain a frаgment.\n              invalid_uri: must be a vаlid URI.\n              relative_uri: must be an аbsolute URI.\n              secured_uri: must be аn HTTPS/SSL URI.\n  doorkeeper:\n    applications:\n      buttons:\n        authorize: Авторизация\n        cancel: Қайтып алу\n        destroy: Жою\n        edit: Түзету\n        submit: Жіберу\n      confirmations:\n        destroy: Шынымен бе?\n      edit:\n        title: Қосымшаны түзету\n      form:\n        error: Whoops! Check your form for pоssible errors\n      help:\n        native_redirect_uri: Use %{native_redirect_uri} fоr local tests\n        redirect_uri: Use one line pеr URI\n        scopes: Separate scopes with spаces. Leave blank to use the default scopes.\n      index:\n        application: Қосымша\n        callback_url: Callbаck URL\n        delete: Өшіру\n        name: Аты\n        new: Жаңа қосымша\n        scopes: Scopеs\n        show: Көрсету\n        title: Қосымшаларыңыз\n      new:\n        title: Жаңа қосымша\n      show:\n        actions: Әрекеттер\n        application_id: Client kеy\n        callback_urls: Callbаck URLs\n        scopes: Scopеs\n        secret: Client sеcret\n        title: 'Applicаtion: %{name}'\n    authorizations:\n      buttons:\n        authorize: Авторизация\n        deny: Қабылдамау\n      error:\n        title: Қате пайда болды\n      new:\n        able_to: It will be аble to\n        prompt: Application %{client_name} rеquests access to your account\n        title: Authorization rеquired\n      show:\n        title: Copy this authorization cоde and paste it to the application.\n    authorized_applications:\n      buttons:\n        revoke: Тыйым салу\n      confirmations:\n        revoke: Шынымен бе?\n      index:\n        application: Қосымша\n        created_at: Авторизацияланды\n        scopes: Scopеs\n        title: Your authorized applicаtions\n    errors:\n      messages:\n        access_denied: The resource owner or authоrization server denied the request.\n        credential_flow_not_configured: Resource Owner Password Credentials flow fаiled due to Doorkeeper.configure.resource_owner_from_credentials being unconfigured.\n        invalid_client: Client authentication failed due to unknоwn client, no client authentication included, or unsupported authentication method.\n        invalid_grant: The provided authorization grant is invаlid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client.\n        invalid_redirect_uri: The redirеct uri included is not valid.\n        invalid_request: The request is missing a required parameter, includes an unsupported parameter vаlue, or is otherwise malformed.\n        invalid_resource_owner: The provided resource owner credentials are not valid, or rеsource owner cannot be found\n        invalid_scope: The requested scope is invаlid, unknown, or malformed.\n        invalid_token:\n          expired: The access tokеn expired\n          revoked: The access tоken was revoked\n          unknown: The access tоken is invalid\n        resource_owner_authenticator_not_configured: Resource Owner find fаiled due to Doorkeeper.configure.resource_owner_authenticator being unconfiged.\n        server_error: The authorization server encоuntered an unexpected condition which prevented it from fulfilling the request.\n        temporarily_unavailable: The authorization server is currently unable to hаndle the request due to a temporary overloading or maintenance of the server.\n        unauthorized_client: The client is not authorized to perform this requеst using this method.\n        unsupported_grant_type: The authorization grant type is nоt supported by the authorization server.\n        unsupported_response_type: The authorization server does nоt support this response type.\n    flash:\n      applications:\n        create:\n          notice: Application crеated.\n        destroy:\n          notice: Application dеleted.\n        update:\n          notice: Application updаted.\n      authorized_applications:\n        destroy:\n          notice: Application revоked.\n    layouts:\n      admin:\n        nav:\n          applications: Applicatiоns\n          oauth2_provider: OAuth2 Prоvider\n      application:\n        title: OAuth authorizatiоn required\n    scopes:\n      follow: modify accоunt relationships\n      push: receive your push nоtifications\n      read: read all your accоunt's data\n      read:accounts: see accounts infоrmation\n      read:blocks: see your blоcks\n      read:favourites: see your favоurites\n      read:filters: see yоur filters\n      read:follows: see your follоws\n      read:lists: see yоur lists\n      read:mutes: see yоur mutes\n      read:notifications: see your nоtifications\n      read:reports: see your repоrts\n      read:search: search on yоur behalf\n      read:statuses: see all stаtuses\n      write: modify all your accоunt's data\n      write:accounts: modify your prоfile\n      write:blocks: block accounts and dоmains\n      write:favourites: favourite stаtuses\n      write:filters: creаte filters\n      write:follows: follow peоple\n      write:lists: creatе lists\n      write:media: upload mеdia files\n      write:mutes: mute pеople and conversations\n      write:notifications: clear yоur notifications\n      write:reports: report оther people\n      write:statuses: publish stаtuses\n"
  },
  {
    "path": "config/locales/doorkeeper.ko.yml",
    "content": "---\nko:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: 애플리케이션 이름\n        redirect_uri: 리디렉션 URI\n        scopes: 범위\n        website: 애플리케이션 웹사이트\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              fragment_present: fragment를 포함할 수 없습니다\n              invalid_uri: 올바른 URI여야 합니다.\n              relative_uri: 절대경로 URI여야 합니다\n              secured_uri: HTTPS/SSL URI여야 합니다.\n  doorkeeper:\n    applications:\n      buttons:\n        authorize: 승인\n        cancel: 취소\n        destroy: 제거\n        edit: 수정\n        submit: 제출\n      confirmations:\n        destroy: 확실합니까?\n      edit:\n        title: 애플리케이션 수정\n      form:\n        error: 이런! 에러를 확인하세요\n      help:\n        native_redirect_uri: \"%{native_redirect_uri}를 이용해 로컬 테스트를 할 수 있습니다\"\n        redirect_uri: 한 줄에 하나의 URI를 작성하세요\n        scopes: 스페이스로 범위를 구분하세요. 빈 칸으로 놔두면 기본 범위를 사용합니다.\n      index:\n        application: 애플리케이션\n        callback_url: 콜백 URL\n        delete: 삭제\n        name: 이름\n        new: 새 애플리케이션\n        scopes: 범위\n        show: 표시\n        title: 당신의 애플리케이션들\n      new:\n        title: 새 애플리케이션\n      show:\n        actions: 동작\n        application_id: 클라이언트 키\n        callback_urls: 콜백 URL\n        scopes: 범위\n        secret: 클라이언트 비밀키\n        title: '애플리케이션: %{name}'\n    authorizations:\n      buttons:\n        authorize: 승인\n        deny: 거부\n      error:\n        title: 에러가 발생하였습니다\n      new:\n        able_to: 다음과 같은 행동들이 가능합니다\n        prompt: \"%{client_name}이 당신의 계정에 접근 권한을 요청합니다\"\n        title: 승인 필요\n      show:\n        title: 이 승인 코드를 복사하여 애플리케이션에 붙여넣으세요\n    authorized_applications:\n      buttons:\n        revoke: 취소\n      confirmations:\n        revoke: 확실합니까?\n      index:\n        application: 애플리케이션\n        created_at: 승인 됨\n        date_format: \"%Y-%m-%d %H:%M:%S\"\n        scopes: 범위\n        title: 당신의 승인 된 애플리케이션들\n    errors:\n      messages:\n        access_denied: 리소스 소유자 또는 권한 부여 서버가 요청을 거부했습니다.\n        invalid_redirect_uri: 리디렉션 URI가 올바르지 않습니다\n        invalid_request: 요청에 필요한 매개변수가 없거나, 지원 되지 않는 매개변수가 있거나, 형식이 잘못되었습니다.\n        invalid_token:\n          expired: 액세스 토큰이 만료되었습니다.\n          revoked: 액세스 토큰이 취소되었습니다.\n          unknown: 액세스 토큰이 잘못되었습니다.\n    flash:\n      applications:\n        create:\n          notice: 애플리케이션이 생성 되었습니다.\n        destroy:\n          notice: 애플리케이션이 삭제 되었습니다.\n        update:\n          notice: 애플리케이션이 갱신 되었습니다.\n      authorized_applications:\n        destroy:\n          notice: 애플리케이션이 취소 되었습니다.\n    layouts:\n      admin:\n        nav:\n          applications: 애플리케이션\n          oauth2_provider: OAuth2 제공자\n      application:\n        title: OAuth 인증이 필요합니다\n    scopes:\n      follow: 계정의 관계를 수정\n      push: 푸시 알림을 받기\n      read: 계정의 모든 데이터를 읽기\n      read:accounts: 계정의 정보를 보기\n      read:blocks: 차단을 보기\n      read:favourites: 관심글을 보기\n      read:filters: 필터를 보기\n      read:follows: 팔로우를 보기\n      read:lists: 리스트를 보기\n      read:mutes: 뮤트를 보기\n      read:notifications: 알림 보기\n      read:reports: 신고 보기\n      read:search: 당신의 권한으로 검색\n      read:statuses: 게시물 모두 보기\n      write: 계정 정보 수정\n      write:accounts: 프로필 수정\n      write:blocks: 계정이나 도메인 차단\n      write:favourites: 관심글 지정\n      write:filters: 필터 만들기\n      write:follows: 사람을 팔로우\n      write:lists: 리스트 만들기\n      write:media: 미디어 파일 업로드\n      write:mutes: 사람이나 대화 뮤트\n      write:notifications: 알림 모두 지우기\n      write:reports: 다른 사람을 신고\n      write:statuses: 게시물 게시\n"
  },
  {
    "path": "config/locales/doorkeeper.lt.yml",
    "content": "lt:\n"
  },
  {
    "path": "config/locales/doorkeeper.lv.yml",
    "content": "lv:\n"
  },
  {
    "path": "config/locales/doorkeeper.ms.yml",
    "content": "ms:\n"
  },
  {
    "path": "config/locales/doorkeeper.nl.yml",
    "content": "---\nnl:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: Naam toepassing\n        redirect_uri: Redirect-URI\n        scopes: Toestemmingen\n        website: Website toepassing\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              fragment_present: kan geen fragment bevatten.\n              invalid_uri: moet een geldige URI zijn.\n              relative_uri: moet een absolute URI zijn.\n              secured_uri: moet een HTTPS/SSL URI zijn.\n  doorkeeper:\n    applications:\n      buttons:\n        authorize: Autoriseren\n        cancel: Annuleren\n        destroy: Verwijderen\n        edit: Bewerken\n        submit: Opslaan\n      confirmations:\n        destroy: Weet je het zeker?\n      edit:\n        title: Toepassing bewerken\n      form:\n        error: Oops! Controleer het formulier op fouten\n      help:\n        native_redirect_uri: Gebruik %{native_redirect_uri} voor lokale tests\n        redirect_uri: Gebruik één regel per URI\n        scopes: Toestemmingen met spaties van elkaar scheiden. Laat leeg om de standaardtoestemmingen te gebruiken.\n      index:\n        application: Toepassing\n        callback_url: Callback-URL\n        delete: Verwijderen\n        name: Naam\n        new: Nieuwe toepassing\n        scopes: Toestemmingen\n        show: Tonen\n        title: Jouw toepassingen\n      new:\n        title: Nieuwe toepassing\n      show:\n        actions: Acties\n        application_id: Client-key\n        callback_urls: Callback-URL's\n        scopes: Toestemmingen\n        secret: Client-secret\n        title: 'Toepassing: %{name}'\n    authorizations:\n      buttons:\n        authorize: Autoriseren\n        deny: Weigeren\n      error:\n        title: Er is een fout opgetreden\n      new:\n        able_to: Deze toepassing zal in staat zijn om\n        prompt: \"%{client_name} autoriseren om jouw account te gebruiken\"\n        title: Autorisatie vereist\n      show:\n        title: Kopieer deze autorisatiecode en plak het in de toepassing.\n    authorized_applications:\n      buttons:\n        revoke: Intrekken\n      confirmations:\n        revoke: Weet je het zeker?\n      index:\n        application: Toepassing\n        created_at: Aangemaakt op\n        date_format: \"%d-%m-%Y %H:%M:%S\"\n        scopes: Toestemmingen\n        title: Jouw geautoriseerde toepassingen\n    errors:\n      messages:\n        access_denied: De resource-eigenaar of autorisatie-server weigerde het verzoek.\n        credential_flow_not_configured: De wachtwoordgegevens-flow van de resource-eigenaar is mislukt omdat Doorkeeper.configure.resource_owner_from_credentials niet is ingesteld.\n        invalid_client: Clientverificatie is mislukt door een onbekende client, ontbrekende client-authenticatie of een niet ondersteunde authenticatie-methode.\n        invalid_grant: De verstrekte autorisatie is ongeldig, verlopen, ingetrokken, komt niet overeen met de redirect-URI die is opgegeven of werd uitgegeven aan een andere client.\n        invalid_redirect_uri: De opgegeven redirect-URI is ongeldig.\n        invalid_request: Het verzoek mist een vereiste parameter, bevat een niet ondersteunde parameterwaarde of is anderszins onjuist.\n        invalid_resource_owner: De verstrekte resource-eigenaargegevens zijn ongeldig of de resource-eigenaar kan niet worden gevonden\n        invalid_scope: De opgevraagde toestemming is ongeldig, onbekend of onjuist.\n        invalid_token:\n          expired: Toegangscode verlopen\n          revoked: Toegangscode ingetrokken\n          unknown: Toegangscode ongeldig\n        resource_owner_authenticator_not_configured: Het opzoeken van de resource-eigenaar is mislukt omdat Doorkeeper.configure.resource_owner_authenticator niet is ingesteld.\n        server_error: De autorisatieserver is is een onverwachte situatie tegengekomen die het verzoek verhinderde.\n        temporarily_unavailable: De autorisatieserver is momenteel niet in staat het verzoek te behandelen als gevolg van een tijdelijke overbelasting of onderhoud aan de server.\n        unauthorized_client: De client is niet bevoegd om dit verzoek op deze manier uit te voeren.\n        unsupported_grant_type: Het type autorisatie wordt niet door de autorisatieserver ondersteund.\n        unsupported_response_type: De autorisatieserver ondersteund dit antwoordtype niet.\n    flash:\n      applications:\n        create:\n          notice: Toepassing aangemaakt.\n        destroy:\n          notice: Toepassing verwijderd.\n        update:\n          notice: Toepassing bewerkt.\n      authorized_applications:\n        destroy:\n          notice: Toepassing ingetrokken.\n    layouts:\n      admin:\n        nav:\n          applications: Toepassingen\n          oauth2_provider: OAuth2-provider\n      application:\n        title: OAuth-autorisatie vereist\n    scopes:\n      follow: relaties tussen accounts bewerken\n      push: ontvang jouw pushmeldingen\n      read: alle gegevens van jouw account lezen\n      read:accounts: zie informatie accounts\n      read:blocks: zie jouw geblokkeerde gebruikers\n      read:favourites: zie jouw favorieten\n      read:filters: zie jouw filters\n      read:follows: zie de accounts die jij volgt\n      read:lists: zie jouw lijsten\n      read:mutes: zie jouw genegeerde gebruikers\n      read:notifications: zie jouw meldingen\n      read:reports: zie jouw gerapporteerde toots\n      read:search: namens jou zoeken\n      read:statuses: zie alle toots\n      write: alle gegevens van jouw account bewerken\n      write:accounts: jouw profiel bewerken\n      write:blocks: accounts en domeinen blokkeren\n      write:favourites: toots als favoriet markeren\n      write:filters: filters aanmaken\n      write:follows: mensen volgen\n      write:lists: lijsten aanmaken\n      write:media: mediabestanden uploaden\n      write:mutes: mensen en gesprekken negeren\n      write:notifications: meldingen verwijderen\n      write:reports: andere mensen rapporteren\n      write:statuses: toots publiceren\n"
  },
  {
    "path": "config/locales/doorkeeper.no.yml",
    "content": "---\n'no':\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: Navn\n        redirect_uri: Omdirigerings-URI\n        scopes: Omfang\n        website: Applikasjonsnettside\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              fragment_present: kan ikke inneholde ett fragment.\n              invalid_uri: må være en gyldig URI.\n              relative_uri: må være en absolutt URI.\n              secured_uri: må være en HTTPS/SSL URI.\n  doorkeeper:\n    applications:\n      buttons:\n        authorize: Autoriser\n        cancel: Avbryt\n        destroy: Ødelegg\n        edit: Rediger\n        submit: Send inn\n      confirmations:\n        destroy: Er du sikker?\n      edit:\n        title: Endre applikasjon\n      form:\n        error: Oops! Sjekk skjemaet ditt for mulige feil\n      help:\n        native_redirect_uri: Bruk %{native_redirect_uri} for lokale tester\n        redirect_uri: Bruk én linje per URI\n        scopes: Adskill omfang med mellomrom. La det være blankt for å bruke standard omfang.\n      index:\n        application: Applikasjon\n        callback_url: Callback-URL\n        delete: Fjern\n        name: Navn\n        new: Ny applikasjon\n        scopes: Omfang\n        show: Vis\n        title: Dine applikasjoner\n      new:\n        title: Nye applikasjoner\n      show:\n        actions: Operasjoner\n        application_id: Applikasjons-ID\n        callback_urls: Callback-URLer\n        scopes: Omfang\n        secret: Hemmelighet\n        title: 'Applikasjon: %{name}'\n    authorizations:\n      buttons:\n        authorize: Autorisér\n        deny: Avvis\n      error:\n        title: En feil oppstod\n      new:\n        able_to: Den vil ha mulighet til\n        prompt: Applikasjon %{client_name} spør om tilgang til din konto\n        title: Autorisasjon påkrevd\n      show:\n        title: Kopier denne koden og lim den inn i programmet.\n    authorized_applications:\n      buttons:\n        revoke: Opphev\n      confirmations:\n        revoke: Opphev?\n      index:\n        application: Applikasjon\n        created_at: Autorisert\n        scopes: Omfang\n        title: Dine autoriserte applikasjoner\n    errors:\n      messages:\n        access_denied: Ressurseieren eller autoriseringstjeneren avviste forespørslen.\n        credential_flow_not_configured: Ressurseiers passordflyt feilet fordi Doorkeeper.configure.resource_owner_from_credentials ikke var konfigurert.\n        invalid_client: Klientautentisering feilet på grunn av ukjent klient, ingen autentisering inkludert, eller autentiseringsmetode er ikke støttet.\n        invalid_grant: Autoriseringen er ugyldig, utløpt, opphevet, stemmer ikke overens med omdirigerings-URIen eller var utstedt til en annen klient.\n        invalid_redirect_uri: Den inkluderte omdirigerings-URLen er ikke gyldig.\n        invalid_request: Forespørslen mangler en eller flere parametere, inkluderte en parameter som ikke støttes eller har feil struktur.\n        invalid_resource_owner: Ressurseierens detaljer er ikke gyldige, eller så er det ikke mulig å finne eieren\n        invalid_scope: Det etterspurte omfanget er ugyldig, ukjent eller har feil struktur.\n        invalid_token:\n          expired: Tilgangsbeviset har utløpt\n          revoked: Tilgangsbeviset har blitt opphevet\n          unknown: Tilgangsbeviset er ugyldig\n        resource_owner_authenticator_not_configured: Ressurseier kunne ikke finnes fordi Doorkeeper.configure.resource_owner_authenticator ikke er konfigurert.\n        server_error: Autoriseringstjeneren støtte på en uventet hendelse som hindret den i å svare på forespørslen.\n        temporarily_unavailable: Autoriseringstjeneren kan ikke håndtere forespørslen grunnet en midlertidig overbelastning eller tjenervedlikehold.\n        unauthorized_client: Klienten har ikke autorisasjon for å utføre denne forespørslen med denne metoden.\n        unsupported_grant_type: Autorisasjonstildelingstypen er ikke støttet av denne autoriseringstjeneren.\n        unsupported_response_type: Autorisasjonsserveren støtter ikke denne typen av forespørsler.\n    flash:\n      applications:\n        create:\n          notice: Applikasjon opprettet.\n        destroy:\n          notice: Applikasjon slettet.\n        update:\n          notice: Applikasjon oppdatert.\n      authorized_applications:\n        destroy:\n          notice: Applikasjon opphevet.\n    layouts:\n      admin:\n        nav:\n          applications: Applikasjoner\n          oauth2_provider: OAuth2-tilbyder\n      application:\n        title: OAuth-autorisering påkrevet\n    scopes:\n      follow: følg, blokkér, avblokkér, avfølg brukere\n      read: lese dine data\n      write: poste på dine vegne\n"
  },
  {
    "path": "config/locales/doorkeeper.oc.yml",
    "content": "---\noc:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: Nom\n        redirect_uri: URL de redireccion\n        scopes: Encastres\n        website: Site de l’aplicacion\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              fragment_present: pòt pas conténer un tròç.\n              invalid_uri: deu èstre un URI valid.\n              relative_uri: deu èstre un URI absolut.\n              secured_uri: deu èstre un HTTPS/SSL URI.\n  doorkeeper:\n    applications:\n      buttons:\n        authorize: Autorizar\n        cancel: Anullar\n        destroy: Suprimir\n        edit: Modificar\n        submit: Mandar\n      confirmations:\n        destroy: Sètz segur ?\n      edit:\n        title: Modificar l’aplicacion\n      form:\n        error: Ops ! Verificatz vòstre formulari\n      help:\n        native_redirect_uri: Emplegatz %{native_redirect_uri} per d’ensages locales\n        redirect_uri: Utilizatz una linha per URI\n        scopes: Separatz los encastres amb d’espacis. Daissatz void per utilizar l’encastre per defaut.\n      index:\n        application: Aplicacion\n        callback_url: URL de rapèl\n        delete: Suprimir\n        name: Nom\n        new: Nòva aplicacion\n        scopes: Encastres\n        show: Veire\n        title: Vòstras aplicacions\n      new:\n        title: Nòva aplicacion\n      show:\n        actions: Accions\n        application_id: Id de l’aplicacion\n        callback_urls: urls de rapèls\n        scopes: Encastres\n        secret: Secret\n        title: Aplicacion : %{name}\n    authorizations:\n      buttons:\n        authorize: Autorizar\n        deny: Refusar\n      error:\n        title: I a agut un error\n      new:\n        able_to: Aquesta aplicacion poirà\n        prompt: L’aplicacion %{client_name} demanda l’accès al vòstre compte\n        title: Cal l’autorizacion\n      show:\n        title: Copiatz lo còdi d’autorizacion e pegatz-lo dins l’aplicacion.\n    authorized_applications:\n      buttons:\n        revoke: Revocar\n      confirmations:\n        revoke: Ne sètz segur ?\n      index:\n        application: Aplicacion\n        created_at: Creacion\n        date_format: \"%-d %b. de %Y %Ho%M %S\"\n        scopes: Encastres\n        title: Las vòstras aplicacions autorizadas\n    errors:\n      messages:\n        access_denied: Lo proprietari de la ressorça o lo servider d’autorizacion refusèt la demanda.\n        credential_flow_not_configured: Lo flux de qualificacion del senhal del proprietari de la ressorça capitèt pas pr’amor que Doorkeeper.configure.resource_owner_from_credentials es pas configurat.\n        invalid_client: L’autorizacion del client capitèt pas pr’amor que lo client es desconegut, l’autorizacion del client es pas enclús, o lo metòde d’autorizacion es pas suportat.\n        invalid_grant: L’acòrdi d’autorizacion donadat es pas valid, expirat, revocat, una redireccion URI utilizat en la demanda d’autorizacion no correspond, o a estat desliurat a un altre client.\n        invalid_redirect_uri: L’URL de redireccion es pas valida.\n        invalid_request: La demanda a un paramètre que li manca, a una valor qu’es pas suportada, o quicòm mal format.\n        invalid_resource_owner: La qualificacion del proprietari de la ressorça donada es pas valida, o lo proprietari de la ressorça es pas trobable\n        invalid_scope: L’encastre demandat es pas valid, o d’un marrit format.\n        invalid_token:\n          expired: Lo geton d’accès a expirat\n          revoked: Lo geton d’accès a estat revocat\n          unknown: Lo geton d’accès es pas valid\n        resource_owner_authenticator_not_configured: La recèrca del proprietari de la ressorça a pas capitat pr’amor que Doorkeeper.configure.resource_owner_authenticator es pas configurat.\n        server_error: Lo servider d’autorizacion trobèt una condicion que l’empachèt d’acomplir la demanda.\n        temporarily_unavailable: Lo servider d’autorizacion pòt actualament pas menar la demanda pr’amor que es temporalament subrecargat o es en mantenença.\n        unauthorized_client: Lo client es pas autorizat a far aquesta demanda en utlizant aqueste metòde.\n        unsupported_grant_type: Lo tipe de qualificacion de l’autorizacion es pas suportat pel servider d’autorizacion.\n        unsupported_response_type: Lo servider d’autorizacion supòrta pas aqueste tipe de responsa.\n    flash:\n      applications:\n        create:\n          notice: Aplicacion creada.\n        destroy:\n          notice: Aplicacion escafada.\n        update:\n          notice: Aplicacion mesa a jorn.\n      authorized_applications:\n        destroy:\n          notice: Aplicacion revocada.\n    layouts:\n      admin:\n        nav:\n          applications: Aplicacions\n          oauth2_provider: Provesidor OAuth\n      application:\n        title: Cal una autorizacion OAuth\n    scopes:\n      follow: modificar las relacions del compte\n      push: recebre vòstras notificacions push\n      read: legir totas las donadas de vòstre compte\n      read:accounts: veire las informacions del compte\n      read:blocks: veire vòstres blocatges\n      read:favourites: veire vòstres favorits\n      read:filters: veire vòstres filtres\n      read:follows: veire vòstres abonaments\n      read:lists: veire vòstras listas\n      read:mutes: veire qual rescondètz\n      read:notifications: veire vòstras notificacions\n      read:reports: veire vòstres senhalaments\n      read:search: recercar per vos\n      read:statuses: veire los estatuts\n      write: modificar totas las donadas de vòstre compte\n      write:accounts: modificar vòstre perfil\n      write:blocks: blocar de comptes e de domenis\n      write:favourites: metre en favorit\n      write:filters: crear de filtres\n      write:follows: sègre de monde\n      write:lists: crear de listas\n      write:media: mandar de fichièrs mèdias\n      write:mutes: rescondre de monde e de conversacions\n      write:notifications: escafar vòstras notificacions\n      write:reports: senhalar de monde\n      write:statuses: publicar d’estatuts\n"
  },
  {
    "path": "config/locales/doorkeeper.pl.yml",
    "content": "---\npl:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: Nazwa aplikacji\n        redirect_uri: URI przekierowania\n        scopes: Zakres\n        website: Strona aplikacji\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              fragment_present: nie może zawierać fragmentu.\n              invalid_uri: musi być poprawnym adresem URI.\n              relative_uri: musi być bezwzględnym adresem URI.\n              secured_uri: musi być bezpiecznym (HTTPS/TLS) adresem URI.\n  doorkeeper:\n    applications:\n      buttons:\n        authorize: Autoryzuj\n        cancel: Anuluj\n        destroy: Usuń\n        edit: Edytuj\n        submit: Wyślij\n      confirmations:\n        destroy: Czy na pewno?\n      edit:\n        title: Edytuj aplikację\n      form:\n        error: Ups! Sprawdź, czy formularz nie zawiera błędów\n      help:\n        native_redirect_uri: Użyj %{native_redirect_uri} do lokalnych testów\n        redirect_uri: Jeden adres na linię tekstu\n        scopes: Rozdziel zakresy (scopes) spacjami. Zostaw puste, aby użyć domyślnych zakresów.\n      index:\n        application: Aplikacja\n        callback_url: URL wywołania zwrotnego (callback)\n        delete: Usuń\n        name: Nazwa\n        new: Nowa aplikacja\n        scopes: Zakres\n        show: Pokaż\n        title: Twoje aplikacje\n      new:\n        title: Nowa aplikacja\n      show:\n        actions: Akcje\n        application_id: ID Aplikacji\n        callback_urls: Adresy wywołań zwrotnych\n        scopes: Zakresy (scopes)\n        secret: Sekret\n        title: 'Aplikacja: %{name}'\n    authorizations:\n      buttons:\n        authorize: Autoryzuj\n        deny: Odmów\n      error:\n        title: Wystapił błąd\n      new:\n        able_to: Uzyska\n        prompt: Aplikacja %{client_name} prosi o dostęp do Twojego konta\n        title: Wymagana jest autoryzacja\n      show:\n        title: Skopiuj kod uwierzytelniający i wklej go w aplikacji.\n    authorized_applications:\n      buttons:\n        revoke: Unieważnij\n      confirmations:\n        revoke: Czy na pewno?\n      index:\n        application: Aplikacja\n        created_at: Autoryzowana\n        date_format: \"%d.%m.%Y %H:%M:%S\"\n        scopes: Zakresy\n        title: Twoje autoryzowane aplikacje\n    errors:\n      messages:\n        access_denied: Właściciel zasobu lub serwer autoryzujący odrzuciły żądanie.\n        credential_flow_not_configured: Ścieżka \"Resource Owner Password Credentials\" zakończyła się błędem, ponieważ Doorkeeper.configure.resource_owner_from_credentials nie został skonfigurowany.\n        invalid_client: Autoryzacja klienta nie powiodła się z powodu nieznanego klienta, braku uwierzytelnienia klienta, lub niewspieranej metody uwierzytelniania.\n        invalid_grant: Grant uwierzytelnienia jest niepoprawny, przeterminowany, unieważniony, nie pasuje do URI przekierowwania użytego w żądaniu uwierzytelnienia, lub został wystawiony przez innego klienta.\n        invalid_redirect_uri: URI przekierowania jest nieprawidłowy.\n        invalid_request: 'Żądanie jest nieprawidłowe: brakujący parametr, niewspierana wartość parametru, lub inny błąd.'\n        invalid_resource_owner: Dostarczone dane uwierzytelniające właściciela zasobu są niepoprawne, lub właściciel zasobu nie może zostać znaleziony\n        invalid_scope: Zakres żądania jest niepoprawny, nieznany, lub błędnie zbudowany.\n        invalid_token:\n          expired: Token dostępowy wygasł\n          revoked: Token dostępowy został unieważniony\n          unknown: Token dostępowy jest błędny\n        resource_owner_authenticator_not_configured: Wyszukiwanie właściciela zasobu nie powiodło się, ponieważ Doorkeeper.configure.resource_owner_authenticator nie został skonfigurowany.\n        server_error: Serwer uwierzytelniający napotkał nieoczekiwane warunki, które uniemożliwiły obsłużenie żądania.\n        temporarily_unavailable: Serwer uwierzytelniający nie jest obecnie w stanie obsłużyć żądania z powodu tymczasowego przeciążenia lub prac konserwacyjnych.\n        unauthorized_client: Klient nie jest uprawniony do wykonania tego żądania przy pomocy tej metody.\n        unsupported_grant_type: Ten typ grantu uwierzytelniającego nie jest wspierany przez serwer uwierzytelniający.\n        unsupported_response_type: Serwer uwierzytelniający nie wspiera tego typu odpowiedzi.\n    flash:\n      applications:\n        create:\n          notice: Utworzono aplikację.\n        destroy:\n          notice: Usunięto aplikację.\n        update:\n          notice: Zaktualizowano aplikację.\n      authorized_applications:\n        destroy:\n          notice: Unieważniono aplikację.\n    layouts:\n      admin:\n        nav:\n          applications: Aplikacje\n          oauth2_provider: Dostawca OAuth2\n      application:\n        title: Uwierzytelnienie OAuth jest wymagane\n    scopes:\n      follow: możliwość śledzenia kont\n      push: otrzymywanie powiadomień push dla Twojego konta\n      read: możliwość odczytu wszystkich danych konta\n      read:accounts: dostęp do informacji o koncie\n      read:blocks: dostęp do listy blokowanych\n      read:favourites: dostęp do listy ulubionych\n      read:filters: dostęp do filtrów\n      read:follows: dostęp do listy śledzonych\n      read:lists: dostęp do Twoich list\n      read:mutes: dostęp do listy wyciszonych\n      read:notifications: możliwość odczytu powiadomień\n      read:reports: dostęp do Twoich zgłoszeń\n      read:search: wyświetlanie z Twojego konta\n      read:statuses: wyświetlanie wszystkich wpisów\n      write: możliwość modyfikowania wszystkich danych o koncie\n      write:accounts: możliwość modyfikowania informacji o koncie\n      write:blocks: możliwość blokowania domen i użytkowników\n      write:favourites: możliwość dodawnia wpisów do ulubionych\n      write:filters: możliwość tworzenia filtrów\n      write:follows: możliwość śledzenia ludzi\n      write:lists: możliwość tworzenia list\n      write:media: możliwość wysyłania zawartości multimedialnej\n      write:mutes: możliwość wyciszania ludzi i konwersacji\n      write:notifications: możliwość usuwania Twoich powiadomień\n      write:reports: możliwość zgłaszania wpisów\n      write:statuses: możliwość publikowania wpisów\n"
  },
  {
    "path": "config/locales/doorkeeper.pt-BR.yml",
    "content": "---\npt-BR:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: Nome do aplicativo\n        redirect_uri: URI de redirecionamento\n        scopes: Autorizações\n        website: Website do aplicativo\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              fragment_present: não pode conter um fragmento.\n              invalid_uri: precisa ser uma URI válida.\n              relative_uri: precisa ser uma URI absoluta.\n              secured_uri: precisa ser uma URI HTTPS/SSL.\n  doorkeeper:\n    applications:\n      buttons:\n        authorize: Autorizar\n        cancel: Cancelar\n        destroy: Destruir\n        edit: Editar\n        submit: Enviar\n      confirmations:\n        destroy: Você tem certeza?\n      edit:\n        title: Editar aplicativo\n      form:\n        error: Oops! Verifique o seu formulário para saber de possíveis erros\n      help:\n        native_redirect_uri: Use %{native_redirect_uri} para testes locais\n        redirect_uri: Use uma linha para cada URI\n        scopes: Separe autorizações com espaços. Deixe em branco para usar autorizações padrões.\n      index:\n        application: Aplicativos\n        callback_url: URL de retorno\n        delete: Excluir\n        name: Nome\n        new: Novo aplicativo\n        scopes: Autorizações\n        show: Mostrar\n        title: Seus aplicativos\n      new:\n        title: Novos aplicativos\n      show:\n        actions: Ações\n        application_id: Chave do cliente\n        callback_urls: URLs de retorno\n        scopes: Autorizações\n        secret: Segredo do cliente\n        title: 'Aplicativo: %{name}'\n    authorizations:\n      buttons:\n        authorize: Autorizar\n        deny: Negar\n      error:\n        title: Ocorreu um erro\n      new:\n        able_to: Será capaz de\n        prompt: O aplicativo %{client_name} solicita acesso à sua conta\n        title: Autorização necessária\n      show:\n        title: Copie este código de autorização e cole no aplicativo.\n    authorized_applications:\n      buttons:\n        revoke: Revogar\n      confirmations:\n        revoke: Você tem certeza?\n      index:\n        application: Aplicativos\n        created_at: Autorizados\n        date_format: \"%d-%m-%Y %H:%M:%S\"\n        scopes: Autorizações\n        title: Aplicativos autorizados\n    errors:\n      messages:\n        access_denied: O proprietário ou servidor de autorização negou a solicitação.\n        credential_flow_not_configured: Cadeira de Credenciais de Senha do Proprietário falhou porque Doorkeeper.configure.resource_owner_from_credentials não foram configuradas.\n        invalid_client: Autenticação do cliente falhou por causa de um cliente desconhecido, nenhum cliente de autenticação incluído ou método de autenticação não suportado.\n        invalid_grant: A garantia de autorização é inválida, expirou, foi revogada, não é equivalente à URI de redirecionamento usada da solicitação de autorização ou foi emitida por outro cliente.\n        invalid_redirect_uri: A URI de redirecionamento incluída não é válida.\n        invalid_request: A solicitação não possui um parâmetro obrigatório, inclui um valor não suportado ou está mal formatada.\n        invalid_resource_owner: As credenciais do proprietário informadas não são válidas ou o proprietário não pôde ser encontrado\n        invalid_scope: A autorização requirida é inválida, desconhecida ou está mal formatada.\n        invalid_token:\n          expired: O token de acesso expirou\n          revoked: O token de acesso foi revogado\n          unknown: O token de acesso é inválido\n        resource_owner_authenticator_not_configured: Procura pelo proprietário falhou porque Doorkeeper.configure.resource_owner_authenticator não foi configurado.\n        server_error: O servidor de autorização encontrou uma condição inesperada que preveniu a solicitação de ser respondida.\n        temporarily_unavailable: O servidor de autorização é incapaz de lidar com a solicitação no momento por causa d múltiplas requisições ou manutenção programada.\n        unauthorized_client: O cliente não possui autorização para performar esta solicitação usando este método.\n        unsupported_grant_type: O tipo de garantia de autorização não é suportada pelo servidor de autorização.\n        unsupported_response_type: O servidor de autorização não suporta este tipo de resposta.\n    flash:\n      applications:\n        create:\n          notice: Aplicativo criado.\n        destroy:\n          notice: Aplicativo deletado.\n        update:\n          notice: Aplicativo atualizado.\n      authorized_applications:\n        destroy:\n          notice: Aplicativo revogado.\n    layouts:\n      admin:\n        nav:\n          applications: Aplicativo\n          oauth2_provider: Provedor de OAuth2\n      application:\n        title: Autorização OAuth obrigatória\n    scopes:\n      follow: modificar as relações com outras contas\n      push: receber suas notificações push\n      read: ler todos os dados da sua conta\n      read:accounts: ver as informações da conta\n      read:blocks: ver seus bloqueios\n      read:favourites: ver seus favoritos\n      read:filters: ver seus filtros\n      read:follows: ver quem você segue\n      read:lists: ver suas listas\n      read:mutes: ver seus usuários silenciados\n      read:notifications: ver suas notificações\n      read:reports: ver suas denúncias\n      read:search: buscar em seu nome\n      read:statuses: ver todos os status\n      write: modificar todos os dados da sua conta\n      write:accounts: modificar seu perfil\n      write:blocks: bloquear contas e domínios\n      write:favourites: status favoritos\n      write:filters: criar filtros\n      write:follows: seguir pessoas\n      write:lists: criar listas\n      write:media: enviar arquivos de mídia\n      write:mutes: silenciar pessoas e conversas\n      write:notifications: limpar suas notificações\n      write:reports: reportar outras pessoas\n      write:statuses: publicar status\n"
  },
  {
    "path": "config/locales/doorkeeper.pt.yml",
    "content": "---\npt:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: Nome da Aplicação\n        redirect_uri: URL de redirecionamento\n        scopes: Autorizações\n        website: Site da Aplicação\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              fragment_present: não pode conter um fragmento.\n              invalid_uri: tem de ser um URI válido.\n              relative_uri: tem de ser um URI absoluto.\n              secured_uri: tem de ser um HTTPS/SSL URI.\n  doorkeeper:\n    applications:\n      buttons:\n        authorize: Autorizar\n        cancel: Cancelar\n        destroy: Destruir\n        edit: Editar\n        submit: Submeter\n      confirmations:\n        destroy: Tens a certeza?\n      edit:\n        title: Editar aplicação\n      form:\n        error: Oops! Verifica que o formulário não tem erros\n      help:\n        native_redirect_uri: Usa %{native_redirect_uri} para testes locais\n        redirect_uri: Utiliza uma linha por URI\n        scopes: Separa autorizações com espaços. Deixa em branco para usar autorizações predefinidas.\n      index:\n        application: Aplicações\n        callback_url: URL de retorno\n        delete: Eliminar\n        name: Nome\n        new: Nova Aplicação\n        scopes: Autorizações\n        show: Mostrar\n        title: As tuas aplicações\n      new:\n        title: Nova aplicação\n      show:\n        actions: Ações\n        application_id: Id de Aplicação\n        callback_urls: Callback urls\n        scopes: Autorizações\n        secret: Segredo\n        title: 'Aplicação: %{name}'\n    authorizations:\n      buttons:\n        authorize: Autorize\n        deny: Não autorize\n      error:\n        title: Ocorreu um erro\n      new:\n        able_to: Vai poder\n        prompt: Aplicação %{client_name} pede acesso à tua conta\n        title: Autorização é necessária\n      show:\n        title: Copiar o código desta autorização e colar na aplicação.\n    authorized_applications:\n      buttons:\n        revoke: Revogar\n      confirmations:\n        revoke: Tens a certeza?\n      index:\n        application: Aplicação\n        created_at: Criada em\n        scopes: Autorizações\n        title: As tuas aplicações autorizadas\n    errors:\n      messages:\n        access_denied: O proprietário do recurso ou servidor de autorização negou o pedido.\n        credential_flow_not_configured: As credenciais da palavra-passe do proprietário do recurso falhou devido a que Doorkeeper.configure.resource_owner_from_credentials não foram configuradas.\n        invalid_client: Autenticação do cliente falhou por causa de um cliente desconhecido, nenhum cliente de autenticação incluído ou método de autenticação não suportado.\n        invalid_grant: A concessão de autorização fornecida é inválida, expirou, foi revogada, não corresponde à URI de redirecionamento usada no pedido de autorização ou foi emitida para outro cliente.\n        invalid_redirect_uri: A URI de redirecionamento incluída não é válida.\n        invalid_request: A solicitação não possui um parâmetro requerido, inclui um valor  não suportado ou tem outro tipo de formato incorreto.\n        invalid_resource_owner: As credenciais do proprietário do recurso não são válidas ou o proprietário do recurso não pode ser encontrado\n        invalid_scope: O âmbito solicitado é inválido, desconhecido ou tem um formato incorreto.\n        invalid_token:\n          expired: O token de acesso expirou\n          revoked: O token de acesso foi revogado\n          unknown: O token de acesso é inválido\n        resource_owner_authenticator_not_configured: A procura pelo proprietário do recurso falhou porque Doorkeeper.configure.resource_owner_authenticator não foi configurado.\n        server_error: O servidor de autorização encontrou uma condição inesperada que impediu o cumprimento do pedido .\n        temporarily_unavailable: O servidor de autorização não é capaz de lidar com o pedido devido a uma sobrecarga ou mantenimento do servidor.\n        unauthorized_client: O cliente não está autorizado a realizar esta solicitação usando este método.\n        unsupported_grant_type: O tipo de concessão de autorização não é suportado pelo servidor de autorização.\n        unsupported_response_type: O servidor de autorização não suporta este tipo de resposta.\n    flash:\n      applications:\n        create:\n          notice: Aplicação criada.\n        destroy:\n          notice: Aplicação eliminada.\n        update:\n          notice: Aplicação alterada.\n      authorized_applications:\n        destroy:\n          notice: Aplicação revogada.\n    layouts:\n      admin:\n        nav:\n          applications: Aplicações\n          oauth2_provider: Fornecedor OAuth2\n      application:\n        title: Autorização OAuth necessária\n    scopes:\n      follow: siga, bloqueie, desbloqueie, e deixa de seguir contas\n      read: tenha acesso aos dados da tua conta\n      write: publique por ti\n"
  },
  {
    "path": "config/locales/doorkeeper.ro.yml",
    "content": "ro:\n"
  },
  {
    "path": "config/locales/doorkeeper.ru.yml",
    "content": "---\nru:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: Название\n        redirect_uri: URI перенаправления\n        scopes: Права\n        website: Веб-сайт приложения\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              fragment_present: не может содержать фрагмент.\n              invalid_uri: должен быть правильным URI.\n              relative_uri: должен быть абсолютным URI.\n              secured_uri: должен быть HTTPS/SSL URI.\n  doorkeeper:\n    applications:\n      buttons:\n        authorize: Авторизовать\n        cancel: Отменить\n        destroy: Удалить\n        edit: Изменить\n        submit: Принять\n      confirmations:\n        destroy: Вы уверены?\n      edit:\n        title: Изменить приложение\n      form:\n        error: Ой! Проверьте Вашу форму на возможные ошибки\n      help:\n        native_redirect_uri: Используйте %{native_redirect_uri} для локального тестирования\n        redirect_uri: Используйте по одной строке на URI\n        scopes: Разделяйте список разрешений пробелами. Оставьте незаполненным для использования разрешений по умолчанию.\n      index:\n        application: Приложение\n        callback_url: Callback URL\n        delete: Удалить\n        name: Название\n        new: Новое приложение\n        scopes: Права\n        show: Показывать\n        title: Ваши приложения\n      new:\n        title: Новое Приложение\n      show:\n        actions: Действия\n        application_id: Id приложения\n        callback_urls: Callback urls\n        scopes: Разрешения\n        secret: Секрет\n        title: 'Приложение: %{name}'\n    authorizations:\n      buttons:\n        authorize: Авторизовать\n        deny: Отказать\n      error:\n        title: Произошла ошибка\n      new:\n        able_to: Оно сможет\n        prompt: Приложение %{client_name} запрашивает доступ к Вашему аккаунту\n        title: Требуется авторизация\n      show:\n        title: Скопируйте этот код авторизации и вставьте его в приложении.\n    authorized_applications:\n      buttons:\n        revoke: Отозвать авторизацию\n      confirmations:\n        revoke: Вы уверены?\n      index:\n        application: Приложение\n        created_at: Авторизовано\n        date_format: \"%d.%m.%Y %H:%M:%S\"\n        scopes: Разрешения\n        title: Ваши авторизованные приложения\n    errors:\n      messages:\n        access_denied: Владелец ресурса или сервер авторизации ответил отказом на Ваш запрос.\n        credential_flow_not_configured: Поток с предоставлением клиенту пароля завершился неудачей, поскольку параметр Doorkeeper.configure.resource_owner_from_credentials не был сконфигурирован.\n        invalid_client: Клиентская аутентификация завершилась неудачей (неизвестный клиент, не включена клиентская аутентификация, или метод аутентификации не поддерживается.\n        invalid_grant: Предоставленный доступ некорректен, истек, отозван, не совпадает с URI перенаправления, использованным в запросе авторизации, или был выпущен для другого клиента.\n        invalid_redirect_uri: Включенный URI перенаправления некорректен.\n        invalid_request: В запросе не хватает обязательного параметра, присутствует неподдерживаемое значение параметра, либо он был сформирован неверно.\n        invalid_resource_owner: Предоставленные данные владельца ресурса некорректны, или владелец ресурса не может быть найден\n        invalid_scope: Запрошенное разрешение некорректно, неизвестно или неверно сформировано.\n        invalid_token:\n          expired: Токен доступа истек\n          revoked: Токен доступа был отменен\n          unknown: Токен доступа некорректен\n        resource_owner_authenticator_not_configured: Поиск владельца ресурса завершился неудачей, поскольку параметр Doorkeeper.configure.resource_owner_authenticator не был сконфигурирован.\n        server_error: Сервер авторизации встретился с неожиданной ошибкой, не позволившей ему выполнить запрос.\n        temporarily_unavailable: Сервер авторизации в данный момент не может выполнить запрос по причине временной перегрузки или профилактики.\n        unauthorized_client: Клиент не авторизован для выполнения этого запроса с использованием этого метода.\n        unsupported_grant_type: Тип авторизации не поддерживается сервером авторизации.\n        unsupported_response_type: Сервер авторизации не поддерживает этот тип ответа.\n    flash:\n      applications:\n        create:\n          notice: Приложение создано.\n        destroy:\n          notice: Приложение удалено.\n        update:\n          notice: Приложение обновлено.\n      authorized_applications:\n        destroy:\n          notice: Авторизация приложения отозвана.\n    layouts:\n      admin:\n        nav:\n          applications: Приложения\n          oauth2_provider: Провайдер OAuth2\n      application:\n        title: Требуется авторизация OAuth\n    scopes:\n      follow: подписываться, отписываться, блокировать и разблокировать аккаунты\n      push: принимать push-уведомления для Вашего аккаунта\n      read: читать данные Вашего аккаунта\n      read:accounts: видеть информацию об аккаунтах\n      read:blocks: видеть ваших заблокированных\n      read:favourites: видеть ваше избранное\n      read:filters: видеть ваши фильтры\n      read:follows: видеть, на кого вы подписаны\n      read:lists: видеть ваши списки\n      read:mutes: видеть список заглушенных\n      read:notifications: видеть ваши уведомления\n      read:reports: видеть ваши жалобы\n      read:search: использовать поиск\n      read:statuses: видеть все статусы\n      write: изменять все данные вашего аккаунта\n      write:accounts: редактировать ваш профиль\n      write:blocks: блокировать аккаунты и домены\n      write:favourites: отмечать статусы как избранные\n      write:filters: создавать фильтры\n      write:follows: подписываться на людей\n      write:lists: создавать списки\n      write:media: выкладывать медиаконтент\n      write:mutes: заглушать людей и обсуждения\n      write:notifications: очищать список уведомлений\n      write:reports: отправлять жалобы на других\n      write:statuses: публиковать статусы\n"
  },
  {
    "path": "config/locales/doorkeeper.sk.yml",
    "content": "---\nsk:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: Názov aplikácie\n        redirect_uri: Presmerovacia URI\n        scopes: Pôsobnosť\n        website: Webstránka aplikácie\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              fragment_present: nesmie obsahovať fragment.\n              invalid_uri: musí byť platná URI.\n              relative_uri: musí byť absolútna URI.\n              secured_uri: musí byť HTTPS/SSL URI.\n  doorkeeper:\n    applications:\n      buttons:\n        authorize: Overiť\n        cancel: Zrušiť\n        destroy: Zničiť\n        edit: Upraviť\n        submit: Poslať\n      confirmations:\n        destroy: Si si istý/á?\n      edit:\n        title: Upraviť aplikáciu\n      form:\n        error: No teda! Pozrite formulár pre prípadné chyby\n      help:\n        native_redirect_uri: Použite %{native_redirect_uri} pre lokálne testy\n        redirect_uri: Iba jedna URI na riadok\n        scopes: Oprávnenia oddeľujte medzerami. Nechajte prázdne pre štandardné oprávnenia.\n      index:\n        application: Aplikácia\n        callback_url: Návratová URL\n        delete: Zmazať\n        name: Názov\n        new: Nová aplikácia\n        scopes: Oprávnenia\n        show: Ukázať\n        title: Vaše aplikácie\n      new:\n        title: Nová aplikácia\n      show:\n        actions: Akcie\n        application_id: Kľúč klienta\n        callback_urls: Návratové URL adresy\n        scopes: Oprávnenia\n        secret: Tajné slovo klienta\n        title: 'Aplikácia: %{name}'\n    authorizations:\n      buttons:\n        authorize: Overiť\n        deny: Zamietni\n      error:\n        title: Nastala chyba\n      new:\n        able_to: Bude môcť\n        prompt: Aplikácia %{client_name} žiada prístup k vašemu účtu\n        title: Je potrebná autorizácia\n      show:\n        title: Skopíruj tento autorizačný kód a vlož ho do aplikácie.\n    authorized_applications:\n      buttons:\n        revoke: Zrušiť oprávnenie\n      confirmations:\n        revoke: Si si istý?\n      index:\n        application: Aplikácia\n        created_at: Autorizované\n        scopes: Oprávnenia\n        title: Vaše autorizované aplikácie\n    errors:\n      messages:\n        access_denied: Prístup zamietnutý.\n        credential_flow_not_configured: Resource Owner Password Credentials zlyhal lebo Doorkeeper.configure.resource_owner_from_credentials nebol nakonfigurovaný.\n        invalid_client: Overenie klienta zlyhalo. Neznámy klient, chýbajú údaje o klientovi alebo nepodporovaná metóda overovania.\n        invalid_grant: Poslané oprávnenie je neplatné, expirované, zrušené, nesúhlasí s presmerovacou URI použitou v autorizačnej požiadavke alebo bolo vydané niekomu inému.\n        invalid_redirect_uri: Presmerovacia URI je neplatná.\n        invalid_request: Požiadavke chýba povinný parameter alebo obsahuje nepodporovanú hodnotu niektorého parametra alebo je nejako inak poškodená.\n        invalid_resource_owner: Uvedené prihlasovacie údaje sú neplatné alebo nenájdené\n        invalid_scope: Požadovaný rozsah je neplatný, neznámy alebo poškodený.\n        invalid_token:\n          expired: Prístupový token expiroval\n          revoked: Prístupový token bol odňatý\n          unknown: Prístupový token je neplatný\n        resource_owner_authenticator_not_configured: Resource Owner zlyhal pretože Doorkeeper.configure.resource_owner_authenticator nebol nakonfigurovaný.\n        server_error: Nastala neočakávaná chyba na autorizačnom serveri ktorá zabránila vykonať požiadavku.\n        temporarily_unavailable: Autorizačný server ťa teraz nemôže obslúžiť, pretože prebieha údržba alebo je dočasne preťažený.\n        unauthorized_client: Klient nie je autorizovaný vykonať danú požiadavku takouto metódou.\n        unsupported_grant_type: Tento typ oprávnenia nie je podporovaný autorizačným serverom.\n        unsupported_response_type: Autorizačný server nepodporuje typ tejto odpovede.\n    flash:\n      applications:\n        create:\n          notice: Aplikácia vytvorená.\n        destroy:\n          notice: Aplikácia zmazaná.\n        update:\n          notice: Aplikácia aktualizovaná.\n      authorized_applications:\n        destroy:\n          notice: Oprávnenia aplikácie zrušené.\n    layouts:\n      admin:\n        nav:\n          applications: Aplikácie\n          oauth2_provider: Poskytovateľ OAuth2\n      application:\n        title: Požadovaná OAuth autorizácia\n    scopes:\n      follow: uprav vzťahy svojho účtu\n      push: dostávaj oboznámenia ohľadom tvojho účtu na obrazovku\n      read: prezri si všetky dáta ohľadom svojho účetu\n      read:accounts: prezri si informácie o účte\n      read:blocks: prezri svoje bloky\n      read:favourites: prezri svoje obľúbené\n      read:filters: prezri svoje filtrovanie\n      read:follows: prezri si svoje sledovania\n      read:lists: prezri si svoje zoznamy\n      read:mutes: prezri svoje utíšenia\n      read:notifications: zhliadni svoje oboznámenia\n      read:reports: prezri svoje reporty\n      read:search: vyhľadvávaj v rámci seba\n      read:statuses: zhliadni všetky príspevky\n      write: upraviť všetky dáta tvojho účtu\n      write:accounts: uprav svoj profil\n      write:blocks: blokuj účty a domény\n      write:favourites: obľúbené príspevky\n      write:filters: vytvor roztriedenie\n      write:follows: následuj ľudí\n      write:lists: vytvor listy\n      write:media: nahraj mediálne súbory\n      write:mutes: stíš diskusie, aj zapojených užívateľov\n      write:notifications: vyčisti oboznámenia\n      write:reports: nahlás iných užívateľov\n      write:statuses: publikuj príspevky\n"
  },
  {
    "path": "config/locales/doorkeeper.sl.yml",
    "content": "---\nsl:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: Ime programa\n"
  },
  {
    "path": "config/locales/doorkeeper.sq.yml",
    "content": "---\nsq:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: Emër aplikacioni\n        redirect_uri: URI Ridrejtimi\n        scopes: Fushëveprime\n        website: Sajt aplikacioni\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              fragment_present: s’mund të përmbajë një fragment.\n              invalid_uri: duhet të jetë një URI e vlefshme.\n              relative_uri: duhet të jetë një URI absolute.\n              secured_uri: duhet të jetë një URI HTTPS/SSL.\n  doorkeeper:\n    applications:\n      buttons:\n        authorize: Autorizoje\n        cancel: Anuloje\n        destroy: Asgjësoje\n        edit: Përpunoni\n        submit: Parashtroje\n      confirmations:\n        destroy: A jeni i sigurt?\n      edit:\n        title: Përpunoni aplikacion\n      form:\n        error: Oh! Kontrolloni formularin tuaj për gabime të mundshme\n      help:\n        native_redirect_uri: Përdor %{native_redirect_uri} për teste vendore\n        redirect_uri: Përdorni një URI për rresht\n        scopes: Ndajini fushëveprimet me hapësira. Që të përdoren fushëveprimet parazgjedhje, lëreni të zbrazët.\n      index:\n        application: Aplikacion\n        callback_url: URL Callback-u\n        delete: Fshije\n        name: Emër\n        new: Aplikacion i ri\n        scopes: Fushëveprime\n        show: Shfaqe\n        title: Aplikacionet tuaja\n      new:\n        title: Aplikacion i ri\n      show:\n        actions: Veprime\n        application_id: Kyç klienti\n        callback_urls: URL-ra Callback\n        scopes: Fushëveprime\n        secret: E fshehtë klienti\n        title: 'Aplikacion: %{name}'\n    authorizations:\n      buttons:\n        authorize: Autorizoje\n        deny: Mohoje\n      error:\n        title: Ndodhi një gabim\n      new:\n        able_to: Do të jetë në gjendje të\n        prompt: \"%{client_name} kërkesa hyrjeje aplikacionesh te llogaria juaj\"\n        title: Lypset autorizim\n      show:\n        title: Kopjojeni këtë kod autorizimi dhe ngjiteni te aplikacioni.\n    authorized_applications:\n      buttons:\n        revoke: Shfuqizoje\n      confirmations:\n        revoke: A jeni i sigurt?\n      index:\n        application: Aplikacion\n        created_at: I autorizuar\n        date_format: \"%d.%m.%Y, %H:%M:%S\"\n        scopes: Fushëveprime\n        title: Aplikacionet tuaja të autorizuara\n    errors:\n      messages:\n        access_denied: I zoti i burimit ose shërbyesi i autorizimit e hodhi poshtë kërkesën.\n        credential_flow_not_configured: Rrjedha e Kredencialeve të Fjalëkalimit të të Zotit të Burimit dështoi për shkak se Doorkeeper.configure.resource_owner_from_credentials është i paformësuar.\n        invalid_client: Mirëfilltësimi i klientit dështoi për shkak klienti të panjohur, mospërfshirjeje mirëfilltësimi klienti, ose metode të pambuluar mirëfilltësimi.\n        invalid_grant: Autorizimi i dhënë është i pavlefshëm, ka skaduar, është shfuqizuar, nuk përputhet me URI-n e ridrejtimit të përdorur te kërkesa e autorizimit, ose është emetuar për klient tjetër.\n        invalid_redirect_uri: URI e ridrejtimit s’është e vlefshme.\n        invalid_request: Kërkesës i mungon një parametër i domosdoshëm, përfshin një vlerë të pambuluar parametri, ose përndryshe është e keqformuar.\n        invalid_resource_owner: Kredencialet e dhëna për të zotin e burimit s’janë të vlefshme, ose s’gjendet i zoti i burimit\n        invalid_scope: Fushëveprimi i kërkuar është i pavlefshëm, i panjohur ose i keqformuar.\n        invalid_token:\n          expired: Token-i i hyrjeve skadoi\n          revoked: Token-i i hyrjeve u shfuqizua\n          unknown: Token-i i hyrjeve është i pavlefshëm\n        resource_owner_authenticator_not_configured: Gjetja e të Zotit të Burimit dështoi, ngaqë Doorkeeper.configure.resource_owner_authenticator s’është i formësuar.\n        server_error: Shërbyesi i autorizimit hasi një kusht të papritur, i cili e pengoi të plotësonte kërkesën.\n        temporarily_unavailable: Shërbyesi i mirëfilltësimeve hëpërhë s’është në gjendje të trajtojë kërkesën, për shkak të një mbingarkese të përkohshme ose ndonjë mirëmbajtjeje të shërbyesit.\n        unauthorized_client: Klienti s’është i autorizuar të kryejë këtë kërkesë duke përdorur këtë metodë.\n        unsupported_grant_type: Lloji i autorizimit të dhënë nuk mbulohet nga shërbyesi i autorizimeve.\n        unsupported_response_type: Shërbyesi i autorizimeve nuk e mbulon këtë lloj përgjigjeje.\n    flash:\n      applications:\n        create:\n          notice: Aplikacioni u krijua.\n        destroy:\n          notice: Aplikacioni u fshi.\n        update:\n          notice: Aplikacioni u përditësua.\n      authorized_applications:\n        destroy:\n          notice: Aplikacioni u shfuqizua.\n    layouts:\n      admin:\n        nav:\n          applications: Aplikacione\n          oauth2_provider: Furnizues OAuth2\n      application:\n        title: Lypset autorizim OAuth\n    scopes:\n      follow: të ndryshojë marrëdhënies llogarish\n      push: të marrë njoftime push për ju\n      read: të lexojë krejt të dhënat e llogarisë tuaj\n      read:accounts: të shohë të dhëna llogarish\n      read:blocks: të shohë blloqet tuaja\n      read:favourites: të shohë të parapëlqyerit tuaj\n      read:filters: të shohë filtrat tuaj\n      read:follows: të shohë ndjekësit tuaj\n      read:lists: të shohë listat tuaja\n      read:mutes: të shohë ç’keni heshtuar\n      read:notifications: të shohë njoftimet tuaja\n      read:reports: të shohë raportet tuaja\n      read:search: të bëjë kërkime në emrin tuaj\n      read:statuses: të shohë krejt gjendjet\n      write: të ndryshojë krejt të dhënat e llogarisë tuaj\n      write:accounts: të ndryshojë profilin tuaj\n      write:blocks: të bllokojë llogari dhe përkatësi\n      write:favourites: të parapëlqejë gjendje\n      write:filters: të krijojë filtra\n      write:follows: të ndjekë persona\n      write:lists: të krijojë lista\n      write:media: të ngarkojë kartela media\n      write:mutes: të heshtojë persona dhe biseda\n      write:notifications: të pastrojë njoftimet tuaja\n      write:reports: të raportojë persona të tjerë\n      write:statuses: të botojë gjendje\n"
  },
  {
    "path": "config/locales/doorkeeper.sr-Latn.yml",
    "content": "---\nsr-Latn:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: Ime aplikacije\n        redirect_uri: Adresa za preusmeravanje\n        scopes: Opseg važenja\n        website: Veb sajt aplikacije\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              fragment_present: ne može da sadrži fragment.\n              invalid_uri: mora biti ispravan URI.\n              relative_uri: mora biti apsolutni URI.\n              secured_uri: mora biti HTTPS/SSL URI.\n  doorkeeper:\n    applications:\n      buttons:\n        authorize: Autorizuj\n        cancel: Poništi\n        destroy: Uništi\n        edit: Izmeni\n        submit: Pošalji\n      confirmations:\n        destroy: Da li ste sigurni?\n      edit:\n        title: Izmeni aplikaciju\n      form:\n        error: Ops! Proverite formular za eventualne greške\n      help:\n        native_redirect_uri: Koristite %{native_redirect_uri} za lokalno testiranje\n        redirect_uri: Koristite jednu liniju po URI-ju\n        scopes: Odvojite opsege važenja sa belinama. Ostavite prazno za podrazumevane opsege važenja.\n      index:\n        application: Aplikacija\n        callback_url: Adresa za povratni poziv\n        delete: Obriši\n        name: Ime\n        new: Nova aplikacija\n        scopes: Opsezi važenja\n        show: Prikaži\n        title: Vaše aplikacije\n      new:\n        title: Nova aplikacija\n      show:\n        actions: Akcije\n        application_id: Klijentski ključ\n        callback_urls: Adrese za povratne pozive\n        scopes: Opseg važenja\n        secret: Klijentska tajna\n        title: 'Aplikacija: %{name}'\n    authorizations:\n      buttons:\n        authorize: Autorizuj se\n        deny: Odbij\n      error:\n        title: Dogodila se greška\n      new:\n        able_to: Biće u mogućnosti da\n        prompt: Aplikacija %{client_name} zahteva pristup Vašem nalogu\n        title: Potrebna autorizacija\n      show:\n        title: Kopirajte ovaj autorizacioni kod i nalepite ga u aplikaciju.\n    authorized_applications:\n      buttons:\n        revoke: Opozovi\n      confirmations:\n        revoke: Da li ste sigurni?\n      index:\n        application: Aplikacija\n        created_at: Autorizovana\n        date_format: \"%d.%m.%Y %H:%M:%S\"\n        scopes: Opsezi važenja\n        title: Vaše autorizovane aplikacije\n    errors:\n      messages:\n        access_denied: Vlasnik resursa ili autorizacioni server su odbili zahtev.\n        credential_flow_not_configured: Tok Resource Owner Password Credentials nije uspeo pošto je Doorkeeper.configure.resource_owner_from_credentials neiskonfigurisan.\n        invalid_client: Klijentska identifikacija nije uspela zbog nepoznatog klijenta, zato što klijent nije uključio identifikaciju ili zato što je iskorišćen nepodržani identifikacioni metod.\n        invalid_grant: Zadata identifikaciona dozvola je neispravna, istekla, opozvana, ne poklapa se sa adresom preusmeravanja ili je izdata nekog drugom klijentu.\n        invalid_redirect_uri: Uključena adresa preusmeravanja nije ispravna.\n        invalid_request: Obavezni parametar fali u zahtevu, zahtev uključuje nepodržanu vrednost parametra ili je parametar na neki drugi način pogrešan.\n        invalid_resource_owner: Zadati kredencijali vlasnika resursa nisu ispravni ili vlasnik resursa ne može biti nađen\n        invalid_scope: Zahtevani opseg važenja nije ispravan, nepoznat je ili je na neki drugi način pogrešan.\n        invalid_token:\n          expired: Pristupni token je istekao\n          revoked: Pristupni token je opozvan\n          unknown: Pristupni token nije ispravan\n        resource_owner_authenticator_not_configured: Greška u pronalaženju vlasnika resursa pošto Doorkeeper.configure.resource_owner_authenticator nije konfigurisan.\n        server_error: Identifikacioni server je naišao na neočekivanu situaciju zbog koje nije ispunio upućeni zahtev.\n        temporarily_unavailable: Identifikacioni server trenutno ne može da obradi zahtev jer je privremeno preopterećen ili je u režimu održavanja.\n        unauthorized_client: Klijent nije ovlašćen da izvrši ovaj zahtev ovim metodom.\n        unsupported_grant_type: Tip autorizacione dozvole nije podržan od strane autorizacionog servera.\n        unsupported_response_type: Autorizacioni server ne podržava ovaj tip odgovora.\n    flash:\n      applications:\n        create:\n          notice: Aplikacija napravljena.\n        destroy:\n          notice: Aplikacija obrisana.\n        update:\n          notice: Aplikacija ažurirana.\n      authorized_applications:\n        destroy:\n          notice: Aplikacija opozvana.\n    layouts:\n      admin:\n        nav:\n          applications: Aplikacije\n          oauth2_provider: OAuth2 provajder\n      application:\n        title: OAuth autorizacija potrebna\n    scopes:\n      follow: prati, blokira, odblokira i otprati naloge\n      read: čita podatke Vašeg naloga\n      write: objavljuje statuse u Vaše ime\n"
  },
  {
    "path": "config/locales/doorkeeper.sr.yml",
    "content": "---\nsr:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: Име апликације\n        redirect_uri: Адреса за преусмеравање\n        scopes: Опсег важења\n        website: Веб сајт апликације\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              fragment_present: не може да садржи фрагмент.\n              invalid_uri: мора бити исправан URI.\n              relative_uri: мора бити апсолутни URI.\n              secured_uri: мора бити HTTPS/SSL URI.\n  doorkeeper:\n    applications:\n      buttons:\n        authorize: Ауторизуј\n        cancel: Поништи\n        destroy: Уништи\n        edit: Измени\n        submit: Пошаљи\n      confirmations:\n        destroy: Да ли сте сигурни?\n      edit:\n        title: Измени апликацију\n      form:\n        error: Опс! Проверите формулар за евентуалне грешке\n      help:\n        native_redirect_uri: Користите %{native_redirect_uri} за локално тестирање\n        redirect_uri: Користите једну линију по URI-ју\n        scopes: Одвојите опсеге важења са белинама. Оставите празно за подразумеване опсеге важења.\n      index:\n        application: Апликација\n        callback_url: Адреса за повратни позив\n        delete: Обриши\n        name: Име\n        new: Нова апликација\n        scopes: Опсези важења\n        show: Прикажи\n        title: Ваше апликације\n      new:\n        title: Нова апликација\n      show:\n        actions: Акције\n        application_id: Клијентски кључ\n        callback_urls: Адресе за повратне позиве\n        scopes: Опсег важења\n        secret: Клијентска тајна\n        title: 'Апликација: %{name}'\n    authorizations:\n      buttons:\n        authorize: Ауторизуј се\n        deny: Одбиј\n      error:\n        title: Догодила се грешка\n      new:\n        able_to: Биће у могућности да\n        prompt: Апликација %{client_name} захтева приступ Вашем налогу\n        title: Потребна ауторизација\n      show:\n        title: Копирајте овај ауторизациони код и налепите га у апликацију.\n    authorized_applications:\n      buttons:\n        revoke: Опозови\n      confirmations:\n        revoke: Да ли сте сигурни?\n      index:\n        application: Апликација\n        created_at: Ауторизована\n        date_format: \"%d.%m.%Y %H:%M:%S\"\n        scopes: Опсези важења\n        title: Ваше ауторизоване апликације\n    errors:\n      messages:\n        access_denied: Власник ресурса или ауторизациони сервер су одбили захтев.\n        credential_flow_not_configured: Ток Resource Owner Password Credentials није успео пошто је Doorkeeper.configure.resource_owner_from_credentials неисконфигурисан.\n        invalid_client: Клијентска идентификација није успела због непознатог клијента, зато што клијент није укључио идентификацију или зато што је искоришћен неподржани идентификациони метод.\n        invalid_grant: Задата идентификациона дозвола је неисправна, истекла, опозвана, не поклапа се са адресом преусмеравања или је издата неког другом клијенту.\n        invalid_redirect_uri: Укључена адреса преусмеравања није исправна.\n        invalid_request: Обавезни параметар фали у захтеву, захтев укључује неподржану вредност параметра или је параметар на неки други начин погрешан.\n        invalid_resource_owner: Задати креденцијали власника ресурса нису исправни или власник ресурса не може бити нађен\n        invalid_scope: Захтевани опсег важења није исправан, непознат је или је на неки други начин погрешан.\n        invalid_token:\n          expired: Приступни токен је истекао\n          revoked: Приступни токен је опозван\n          unknown: Приступни токен није исправан\n        resource_owner_authenticator_not_configured: Грешка у проналажењу власника ресурса пошто Doorkeeper.configure.resource_owner_authenticator није конфигурисан.\n        server_error: Идентификациони сервер је наишао на неочекивану ситуацију због које није испунио упућени захтев.\n        temporarily_unavailable: Идентификациони сервер тренутно не може да обради захтев јер је привремено преоптерећен или је у режиму одржавања.\n        unauthorized_client: Клијент није овлашћен да изврши овај захтев овим методом.\n        unsupported_grant_type: Тип ауторизационе дозволе није подржан од стране ауторизационог сервера.\n        unsupported_response_type: Ауторизациони сервер не подржава овај тип одговора.\n    flash:\n      applications:\n        create:\n          notice: Апликација направљена.\n        destroy:\n          notice: Апликација обрисана.\n        update:\n          notice: Апликација ажурирана.\n      authorized_applications:\n        destroy:\n          notice: Апликација опозвана.\n    layouts:\n      admin:\n        nav:\n          applications: Апликације\n          oauth2_provider: OAuth2 провајдер\n      application:\n        title: OAuth ауторизација потребна\n    scopes:\n      follow: прати, блокира, одблокира и отпрати налоге\n      read: чита податке Вашег налога\n      write: објављује статусе у Ваше име\n"
  },
  {
    "path": "config/locales/doorkeeper.sv.yml",
    "content": "---\nsv:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: Applikationsnamn\n        redirect_uri: Omdirigera URI\n        scopes: Omfattning\n        website: Applikationswebbplats\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              fragment_present: kan inte innehålla ett fragment.\n              invalid_uri: måste vara en giltig URI.\n              relative_uri: måste vara en absolut URI.\n              secured_uri: måste vara en HTTPS/SSL URI.\n  doorkeeper:\n    applications:\n      buttons:\n        authorize: Godkänna\n        cancel: Ångra\n        destroy: Förstöra\n        edit: Redigera\n        submit: Skicka\n      confirmations:\n        destroy: Äre du säker?\n      edit:\n        title: Redigera applikation\n      form:\n        error: Hoppsan! Kontrollera i formuläret efter eventuella fel\n      help:\n        native_redirect_uri: Använd %{native_redirect_uri} för lokalt test\n        redirect_uri: Använd en per rad URI\n        scopes: Separera omfattningen med mellanslag. Lämna tomt för att använda standardomfattning.\n      index:\n        application: Applikation\n        callback_url: Återkalls URL\n        delete: Ta bort\n        name: Namn\n        new: Ny applikation\n        scopes: Omfattning\n        show: Visa\n        title: Dina applikationer\n      new:\n        title: Ny applikation\n      show:\n        actions: Handlingar\n        application_id: Klientnyckel\n        callback_urls: Återkalls URLs\n        scopes: Omfattning\n        secret: Kundhemlighet\n        title: 'Program: %{name}'\n    authorizations:\n      buttons:\n        authorize: Godkänna\n        deny: Neka\n      error:\n        title: Ett fel har uppstått\n      new:\n        able_to: Det kommer att kunna\n        prompt: Applikation %{client_name} begär tillgång till ditt konto\n        title: Godkännande krävs\n      show:\n        title: Kopiera denna behörighetskod och klistra in den i programmet.\n    authorized_applications:\n      buttons:\n        revoke: Återkalla\n      confirmations:\n        revoke: Är du säker?\n      index:\n        application: Applikation\n        created_at: Auktoriserad\n        scopes: Omfattning\n        title: Dina behöriga ansökningar\n    errors:\n      messages:\n        access_denied: Resursägaren eller behörighetsservern nekade begäran.\n        credential_flow_not_configured: Resurs Ägare Lösenord Credentials flöde misslyckades på grund av att Doorkeeper.configure.resource_owner_from_credentials är okonfigurerad.\n        invalid_client: Klientautentisering misslyckades på grund av okänd klient, ingen klientautentisering inkluderad eller icke godkänd autentiseringsmetod.\n        invalid_grant: Det beviljade godkännandetillskottet är ogiltigt, upphört, återkallat, matchar inte den omdirigering URI som användes i auktorisationsförfrågan eller har utfärdats till en annan klient.\n        invalid_redirect_uri: Den omdirigerade uri är inte giltig.\n        invalid_request: Förfrågan saknar en obligatorisk parameter, innehåller ett icke-stödt parametervärde eller är annars felaktigt.\n        invalid_resource_owner: De angivna resursägarnas referenser är inte giltiga, eller resursägare kan inte hittas\n        invalid_scope: Det begärda räckvidden är ogiltigt, okänt eller felaktigt.\n        invalid_token:\n          expired: The access token utgången\n          revoked: The access token är återkallad\n          unknown: The access token är ogiltig\n        resource_owner_authenticator_not_configured: Resursägaren hittade fel på grund av Doorkeeper.configure.resource_owner_authenticator är okonfigurerad.\n        server_error: Tillståndsservern stötte på ett oväntat villkor som hindrade det från att uppfylla förfrågan.\n        temporarily_unavailable: Autorisationsservern kan inte hantera begäran på grund av tillfällig överbelastning eller underhåll av servern.\n        unauthorized_client: Klienten är inte behörig att utföra denna förfrågan med den här metoden.\n        unsupported_grant_type: Typgodkännandet för godkännande beviljas inte av behörighetsservern.\n        unsupported_response_type: Autorisationsservern stöder inte den här svarstypen.\n    flash:\n      applications:\n        create:\n          notice: Applikation skapad.\n        destroy:\n          notice: Applikation borttagen.\n        update:\n          notice: Applikation uppdaterad.\n      authorized_applications:\n        destroy:\n          notice: Applikation återkallas.\n    layouts:\n      admin:\n        nav:\n          applications: Applikationer\n          oauth2_provider: OAuth2 leverantör\n      application:\n        title: OAuth-behörighet krävs\n    scopes:\n      follow: följa, blockera, ta bort blockerade och sluta följa konton\n      push: ta emot push aviseringar för ditt konto\n      read: läsa dina kontodata\n      write: posta åt dig\n"
  },
  {
    "path": "config/locales/doorkeeper.ta.yml",
    "content": "ta:\n"
  },
  {
    "path": "config/locales/doorkeeper.te.yml",
    "content": "te:\n"
  },
  {
    "path": "config/locales/doorkeeper.th.yml",
    "content": "---\nth:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: ชื่อ\n        redirect_uri: เปลี่ยนเส้นทาง URI\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              invalid_uri: ต้องใช้ URI ที่ถูกต้อง.\n              relative_uri: ต้องเป็น absolute URI.\n              secured_uri: ต้องใช้ HTTPS/SSL URI.\n  doorkeeper:\n    applications:\n      buttons:\n        cancel: ยกเลิก\n        destroy: ทำลาย\n        edit: แก้ไข\n      confirmations:\n        destroy: แน่ใจนะ?\n      edit:\n        title: แก้ไข แอ๊ฟพลิเคชั่น\n      help:\n        native_redirect_uri: ใช้ %{native_redirect_uri} สำหรับการทดสอบ\n        redirect_uri: ใช้บรรทัดละหนึ่ง URI\n      index:\n        name: ชื่อ\n        new: New Application\n      new:\n        title: New Application\n      show:\n        application_id: Application Id\n        callback_urls: Callback urls\n        secret: Secret\n    authorizations:\n      buttons:\n        authorize: อนุญาติ\n        deny: ไม่อนุญาติ\n    authorized_applications:\n      buttons:\n        revoke: ยกเลิกการอนุญาติ\n    scopes:\n      follow: follow, block, unblock and unfollow accounts\n      read: read your account's data\n      write: post on your behalf\n"
  },
  {
    "path": "config/locales/doorkeeper.tr.yml",
    "content": "---\ntr:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: Uygulama adı\n        website: Uygulama web sitesi\n  doorkeeper:\n    applications:\n      buttons:\n        authorize: Yetki ver\n        cancel: İptal et\n        destroy: Yok et\n        edit: Düzenle\n        submit: Gönder\n      confirmations:\n        destroy: Emin misiniz?\n      edit:\n        title: Uygulamayı düzenle\n"
  },
  {
    "path": "config/locales/doorkeeper.uk.yml",
    "content": "---\nuk:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: Ім'я\n        redirect_uri: URI перенаправлення\n        scopes: Рамки\n        website: Веб-сайт додатку\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              fragment_present: не може містити фрагмент.\n              invalid_uri: повинен бути дійсним URI.\n              relative_uri: повинен бути абсолютним URI.\n              secured_uri: повинен бути HTTPS/SSL URI.\n  doorkeeper:\n    applications:\n      buttons:\n        authorize: Авторизувати\n        cancel: Відмінити\n        destroy: Видалити\n        edit: Редагувати\n        submit: Прийняти\n      confirmations:\n        destroy: Ви впевнені?\n      edit:\n        title: Редагувати додаток\n      form:\n        error: Отакої! Перевірте свою форму на помилки\n      help:\n        native_redirect_uri: Використовуйте %{native_redirect_uri} для локальних тестувань\n        redirect_uri: Використовуйте одну стрічку на URI\n        scopes: Відділяйте області видимості пробілами. Залишайте порожніми, щоб використовувати області видимості за промовчуванням.\n      index:\n        callback_url: URL зворотнього виклику\n        name: Назва\n        new: Новий додаток\n        title: Ваші додатки\n      new:\n        title: Новий додаток\n      show:\n        actions: Дії\n        application_id: ID додатку\n        callback_urls: URL зворотніх викликів\n        scopes: Дозволи\n        secret: Таємниця\n        title: 'Додаток: %{name}'\n    authorizations:\n      buttons:\n        authorize: Авторизувати\n        deny: Відмовити\n      error:\n        title: Сталася помилка\n      new:\n        able_to: Він зможе\n        prompt: Податок %{client_name} просить доступу до вашого акаунту\n        title: Необхідна авторизація\n    authorized_applications:\n      buttons:\n        revoke: Відкликати авторизацію\n      confirmations:\n        revoke: Ви впевнені?\n      index:\n        application: Додаток\n        created_at: Авторизовано\n        date_format: \"%d-%m-%Y %H:%M:%S\"\n        scopes: Дозволи\n        title: Ваші авторизовані додатки\n    errors:\n      messages:\n        access_denied: Власник ресурсу або сервер авторизації відхилив Ваш запит.\n        credential_flow_not_configured: Не вдалося перевірити парольні дані клієнту через неналаштований параметр Doorkeeper.configure.resource_owner_from_credentials.\n        invalid_client: Не вдалося аутентифікувати клієнта (клієнт невідомий, аутентифікацію клієнта не увімкнено, або непідтримуваний метод аутентифікації).\n        invalid_grant: Наданий санкціонований дозвіл недійсний, прострочений, анульований, не відповідає URI перенаправлення, що використовується в запиті авторизації, або був виданий іншому клієнту.\n        invalid_redirect_uri: Включений URI перенаправлення не є дійсним.\n        invalid_request: У запиті відсутній обов'язковий параметр, міститься непідтримуване значення параметра, або він сформований неправильно.\n        invalid_resource_owner: Надані дані власника ресурсу не є дійсними, або власника ресурсу неможливо знайти\n        invalid_scope: Запитуваний дозвыд недійсний, невідомий, або неправильно сформований.\n        invalid_token:\n          expired: Токен доступу прострочено\n          revoked: Токен доступу було відкликано\n          unknown: Токен доступу недійсний\n        resource_owner_authenticator_not_configured: Не вдалося знайти власника ресурсу через неналаштований Doorkeeper.configure.resource_owner_authenticator.\n        server_error: Сервер авторизації зіткнувся з непередбачуваною умовою, яка не дозволяє йому виконати запит.\n        temporarily_unavailable: Сервер авторизації в даний момент не може обробити запит через тимчасове перевантаження або профілактику.\n        unauthorized_client: Клієнт не має права виконувати цей запит, використовуючи цей метод.\n        unsupported_grant_type: Тип авторизації не підтримується сервером авторизації.\n        unsupported_response_type: Сервер авторизації не підтримує цей тип відповіді.\n    flash:\n      applications:\n        create:\n          notice: Додаток створено.\n        destroy:\n          notice: Додаток видалено.\n        update:\n          notice: Додаток оновлено.\n      authorized_applications:\n        destroy:\n          notice: Авторизацію додатка відкликано.\n    layouts:\n      admin:\n        nav:\n          applications: Заявки\n          oauth2_provider: Постачальник OAuth2\n      application:\n        title: Необхідна авторизація OAuth\n    scopes:\n      follow: підписуватися, відписуватися, блокувати та розблоковувати акаунти\n      read: Читати дані Вашого акаунта\n      write: Публікувати від Вашого імені\n"
  },
  {
    "path": "config/locales/doorkeeper.zh-CN.yml",
    "content": "---\nzh-CN:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: 应用名称\n        redirect_uri: 重定向 URI\n        scopes: 权限范围\n        website: 应用网站\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              fragment_present: 不能包含网址片段（#）\n              invalid_uri: 必须是有效的 URL 格式\n              relative_uri: 必须是绝对的 URL 地址\n              secured_uri: 必须是 HTTPS/SSL 的 URL 地址\n  doorkeeper:\n    applications:\n      buttons:\n        authorize: 授权\n        cancel: 取消\n        destroy: 删除\n        edit: 编辑\n        submit: 提交\n      confirmations:\n        destroy: 确定要删除应用吗？\n      edit:\n        title: 修改应用\n      form:\n        error: 抱歉! 提交信息的时候遇到了下面的错误\n      help:\n        native_redirect_uri: 本地测试请使用 %{native_redirect_uri}\n        redirect_uri: 每行只能有一个 URL\n        scopes: 用空格分割权限范围，留空则使用默认设置\n      index:\n        application: 应用\n        callback_url: 回调 URL\n        delete: 删除\n        name: 名称\n        new: 创建新应用\n        scopes: 权限范围\n        show: 显示\n        title: 你的应用\n      new:\n        title: 创建新应用\n      show:\n        actions: 操作\n        application_id: 应用 ID\n        callback_urls: 回调 URL\n        scopes: 权限范围\n        secret: 应用密钥\n        title: 应用：%{name}\n    authorizations:\n      buttons:\n        authorize: 同意授权\n        deny: 拒绝授权\n      error:\n        title: 发生错误\n      new:\n        able_to: 此应用将能够\n        prompt: 授权 %{client_name} 使用你的帐户？\n        title: 需要授权\n      show:\n        title: 接下来请复制此处的授权代码并粘贴到应用中。\n    authorized_applications:\n      buttons:\n        revoke: 撤销授权\n      confirmations:\n        revoke: 确定要撤销对此应用的授权吗？\n      index:\n        application: 应用\n        created_at: 授权时间\n        scopes: 权限范围\n        title: 已授权的应用列表\n    errors:\n      messages:\n        access_denied: 资源所有者或服务器拒绝了请求\n        credential_flow_not_configured: 由于 Doorkeeper.configure.resource_owner_from_credentials 尚未配置，应用验证授权流程失败。\n        invalid_client: 由于应用信息未知、未提交认证信息或使用了不支持的认证方式，认证失败\n        invalid_grant: 授权方式无效、过期或已被撤销、与授权请求中的回调地址不一致，或使用了其他应用的回调地址\n        invalid_redirect_uri: 无效的登录回调地址\n        invalid_request: 请求缺少必要的参数，或者参数值、格式不正确\n        invalid_resource_owner: 资源所有者认证无效，或找不到所有者\n        invalid_scope: 请求的权限范围无效、未知或格式不正确\n        invalid_token:\n          expired: 访问令牌已过期\n          revoked: 访问令牌已被吊销\n          unknown: 访问令牌无效\n        resource_owner_authenticator_not_configured: 由于 Doorkeeper.configure.resource_owner_authenticator 尚未配置，查找资源所有者失败。\n        server_error: 服务器异常，无法处理请求\n        temporarily_unavailable: 服务器维护中或负载过高，暂时无法处理请求\n        unauthorized_client: 未授权的应用，请求无法执行\n        unsupported_grant_type: 服务器不支持此类型的授权方式\n        unsupported_response_type: 服务器不支持这种响应类型\n    flash:\n      applications:\n        create:\n          notice: 应用创建成功\n        destroy:\n          notice: 应用删除成功\n        update:\n          notice: 应用修改成功\n      authorized_applications:\n        destroy:\n          notice: 已成功撤销对此应用的授权\n    layouts:\n      admin:\n        nav:\n          applications: 应用\n          oauth2_provider: OAuth2 提供商\n      application:\n        title: 需要 OAuth 认证\n    scopes:\n      follow: 关注或屏蔽用户\n      push: 接收你的帐户的推送通知\n      read: 读取你的帐户数据\n      read:accounts: 查看账户信息\n      read:blocks: 查看你的屏蔽列表\n      read:favourites: 查看你的收藏\n      read:filters: 查看你的过滤器\n      read:follows: 查看你的关注\n      read:lists: 查看你的列表\n      read:mutes: 查看你的隐藏列表\n      read:notifications: 查看你的通知\n      read:reports: 查看你的举报\n      read:search: 以你的身份搜索\n      read:statuses: 查看所有嘟文\n      write: 修改你的账户数据\n      write:accounts: 修改你的个人资料\n      write:blocks: 屏蔽账户和域名\n      write:favourites: 收藏嘟文\n      write:filters: 创建过滤器\n      write:follows: 关注其他人\n      write:lists: 创建列表\n      write:media: 上传媒体文件\n      write:mutes: 隐藏用户和对话\n      write:notifications: 清除你的通知\n      write:reports: 举报他人\n      write:statuses: 发表嘟文\n"
  },
  {
    "path": "config/locales/doorkeeper.zh-HK.yml",
    "content": "---\nzh-HK:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: 名稱\n        redirect_uri: 轉接 URI\n        scopes: 權限範圍\n        website: 應用網站\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              fragment_present: URI 不可包含 \"#fragment\" 部份。\n              invalid_uri: 必需有正確的 URI。\n              relative_uri: 必需為完整 URI。\n              secured_uri: 必需使用有 HTTPS/SSL 加密的 URI。\n  doorkeeper:\n    applications:\n      buttons:\n        authorize: 認證\n        cancel: 取消\n        destroy: 移除\n        edit: 編輯\n        submit: 提交\n      confirmations:\n        destroy: 是否確定？\n      edit:\n        title: 編輯應用程式\n      form:\n        error: 噢！請檢查你表格的錯誤訊息\n      help:\n        native_redirect_uri: 使用 %{native_redirect_uri} 作局部測試\n        redirect_uri: 每行輸入一個 URI\n        scopes: 請用半形空格分開權限範圍 (scope)。留空表示使用預設的權限範圍。\n      index:\n        application: 應用\n        callback_url: 回傳網址\n        delete: 刪除\n        name: 名稱\n        new: 新增應用程式\n        scopes: 權限範圍\n        show: 顯示\n        title: 你的應用程式\n      new:\n        title: 新增應用程式\n      show:\n        actions: 操作\n        application_id: 應用程式 ID\n        callback_urls: 回傳網址\n        scopes: 權限範圍\n        secret: 密碼\n        title: 應用程式︰ %{name}\n    authorizations:\n      buttons:\n        authorize: 批准\n        deny: 拒絕\n      error:\n        title: 發生錯誤\n      new:\n        able_to: 要求獲取權限\n        prompt: 應用程式 %{client_name} 要求得到你用戶的部份權限\n        title: 需要用戶授權\n      show:\n        title: 請把這個授權碼複製到應用程式中。\n    authorized_applications:\n      buttons:\n        revoke: 取消授權\n      confirmations:\n        revoke: 是否確定要取消授權？\n      index:\n        application: 應用程式\n        created_at: 授權日期\n        scopes: 權限範圍\n        title: 已獲你授權的程用程式\n    errors:\n      messages:\n        access_denied: 資源擁有者或授權伺服器不接受請求。\n        credential_flow_not_configured: 資源擁有者密碼認證程序 (Resource Owner Password Credentials flow) 失敗，原因是 Doorkeeper.configure.resource_owner_from_credentials 沒有設定。\n        invalid_client: 用戶程式認證 (Client authentication) 失敗，原因是用戶程式未有登記、沒有指定用戶程式 (client)、或者使用了不支援的認證方法 (method)。\n        invalid_grant: 授權申請 (authorization grant) 不正確、過期、已被取消，或者無法對應授權請求 (authorization request) 內的轉接 URI，或者屬於別的用戶程式。\n        invalid_redirect_uri: 不正確的轉接網址。\n        invalid_request: 請求缺少了必要的參數、包含了不支援的參數、或者其他輸入錯誤。\n        invalid_resource_owner: 資源擁有者的登入資訊錯誤、或者無法找到該資源擁有者\n        invalid_scope: 請求的權限範圍 (scope) 不正確、未有定義、或者輸入錯誤。\n        invalid_token:\n          expired: access token 已經過期\n          revoked: access token 已被取消\n          unknown: access token 不正確\n        resource_owner_authenticator_not_configured: 無法找到資源擁有者，原因是 Doorkeeper.configure.resource_owner_authenticator 沒有設定。\n        server_error: 認證伺服器遇上未知狀況，令請求無法通過。\n        temporarily_unavailable: 認證伺服器由於臨時負荷過重或者維護，目前未能處理請求。\n        unauthorized_client: 用戶程式無權用此方法 (method) 請行這個請求。\n        unsupported_grant_type: 授權伺服器不支援這個授權類型 (grant type)。\n        unsupported_response_type: 授權伺服器不支援這個回應類型 (response type)。\n    flash:\n      applications:\n        create:\n          notice: 已新增應用程式。\n        destroy:\n          notice: 已刪除應用程式。\n        update:\n          notice: 已更新應用程式。\n      authorized_applications:\n        destroy:\n          notice: 已取消應用程式授權。\n    layouts:\n      admin:\n        nav:\n          applications: 應用程式\n          oauth2_provider: OAuth2 供應者\n      application:\n        title: 需要 OAuth 授權\n    scopes:\n      follow: 關注、封鎖、解除封鎖及取消關注用戶\n      push: 接收你的帳號的推送通知\n      read: 閱讀你的用戶資料\n      write: 以你的名義發佈文章\n"
  },
  {
    "path": "config/locales/doorkeeper.zh-TW.yml",
    "content": "---\nzh-TW:\n  activerecord:\n    attributes:\n      doorkeeper/application:\n        name: 名稱\n        redirect_uri: 重新導向 URI\n        scopes: 權限範圍\n        website: 應用程式網頁\n    errors:\n      models:\n        doorkeeper/application:\n          attributes:\n            redirect_uri:\n              fragment_present: 不能包含 fragment。\n              invalid_uri: 必需有正確的 URI.\n              relative_uri: 必需為絕對 URI.\n              secured_uri: 必需使用有 HTTPS/SSL 加密的 URI.\n  doorkeeper:\n    applications:\n      buttons:\n        authorize: 授權\n        cancel: 取消\n        destroy: 移除\n        edit: 編輯\n        submit: 送出\n      confirmations:\n        destroy: 您確定嗎？\n      edit:\n        title: 編輯應用程式\n      form:\n        error: 唉呦！請檢查表單錯誤訊息\n      help:\n        native_redirect_uri: 請使用 %{native_redirect_uri} 作測試\n        redirect_uri: 每行輸入一個 URI\n        scopes: 請用半形空格分開權限範圍 (scope)。留空表示使用預設的權限範圍。\n      index:\n        application: 應用程式\n        callback_url: 回傳網址\n        delete: 刪除\n        name: 名稱\n        new: 新增應用程式\n        scopes: 權限範圍\n        show: 顯示\n        title: 你的應用程式\n      new:\n        title: 新增應用程式\n      show:\n        actions: 動作\n        application_id: 應用程式 ID\n        callback_urls: 回傳網址\n        scopes: 權限範圍\n        secret: 密碼\n        title: 應用程式︰ %{name}\n    authorizations:\n      buttons:\n        authorize: 授權\n        deny: 拒絕\n      error:\n        title: 發生錯誤\n      new:\n        able_to: 要求取得權限\n        prompt: 應用程式 %{client_name} 要求取得您帳號的部份權限\n        title: 需要授權\n      show:\n        title: 複製此授權碼並貼上到應用程式中。\n    authorized_applications:\n      buttons:\n        revoke: 撤銷授權\n      confirmations:\n        revoke: 您確定要撤銷這個授權？\n      index:\n        application: 應用程式\n        created_at: 授權時間\n        scopes: 權限範圍\n        title: 已授權的應用程式\n    errors:\n      messages:\n        access_denied: 資源擁有者或認證伺服器不接受請求。\n        credential_flow_not_configured: 資源擁有者密碼認證程序失敗，由於 Doorkeeper.configure.resource_owner_from_credentials 沒有設定。\n        invalid_client: 客戶端驗證失敗，可能是未知的客戶端程式、未包含客戶端驗證、或使用了不支援的認證方法。\n        invalid_grant: 授權申請不正確、逾期、已被取消、與授權請求內的重新導向 URI 不符、或屬於別的客戶端程式。\n        invalid_redirect_uri: 不正確的重新導向網址。\n        invalid_request: 請求缺少必要的參數、包含不支援的參數、或其他輸入錯誤。\n        invalid_resource_owner: 資源擁有者的登入資訊錯誤、或無法找到該資源擁有者\n        invalid_scope: 請求的權限範圍無效、未定義、或輸入錯誤。\n        invalid_token:\n          expired: access token 已過期\n          revoked: access token 已被取消\n          unknown: access token 不正確\n        resource_owner_authenticator_not_configured: 無法找到資源擁有者，由於 Doorkeeper.configure.resource_owner_authenticator 沒有設定。\n        server_error: 認證伺服器發生未知錯誤。\n        temporarily_unavailable: 認證伺服器暫時無法使用。\n        unauthorized_client: 客戶端程式無權使用此方法進行請求。\n        unsupported_grant_type: 認證伺服器不支援這個授權類型。\n        unsupported_response_type: 認證伺服器不支援這個回應類型。\n    flash:\n      applications:\n        create:\n          notice: 已新增應用程式。\n        destroy:\n          notice: 已刪除應用程式。\n        update:\n          notice: 已更新應用程式。\n      authorized_applications:\n        destroy:\n          notice: 已撤銷應用程式授權。\n    layouts:\n      admin:\n        nav:\n          applications: 應用程式\n          oauth2_provider: OAuth2 供應者\n      application:\n        title: 需要 OAuth 授權\n    scopes:\n      follow: 關注、封鎖、解除封鎖及取消關注帳號\n      push: 接收你帳號的推送通知\n      read: 讀取您的帳號資料\n      write: 以您的名義發佈嘟文\n"
  },
  {
    "path": "config/locales/el.yml",
    "content": "---\nel:\n  about:\n    about_hashtag_html: Αυτά είναι κάποια από τα δημόσια τουτ σημειωμένα με <strong>#%{hashtag}</strong>. Μπορείς να αλληλεπιδράσεις με αυτά αν έχεις λογαριασμό οπουδήποτε στο fediverse.\n    about_mastodon_html: Το Mastodon είναι ένα κοινωνικό δίκτυο που βασίζεται σε ανοιχτά δικτυακά πρωτόκολλα και ελεύθερο λογισμικό ανοιχτού κώδικα. Είναι αποκεντρωμένο όπως το e-mail.\n    about_this: Σχετικά\n    active_count_after: ενεργοί\n    active_footnote: Μηνιαίοι Ενεργοί Χρήστες (ΜΕΧ)\n    administered_by: 'Διαχειριστής:'\n    api: API\n    apps: Εφαρμογές κινητών\n    apps_platforms: Χρησιμοποίησε το Mastodon από το iOS, το Android και αλλού\n    browse_directory: Ξεφύλλισε ένα κατάλογο χρηστών και φίλτραρε ανά ενδιαφέροντα\n    browse_public_posts: Κοίταξε μια ζωντανή ροή δημοσιεύσεων στο Mastodon\n    contact: Επικοινωνία\n    contact_missing: Δεν έχει οριστεί\n    contact_unavailable: Μ/Δ\n    discover_users: Ανακάλυψε χρήστες\n    documentation: Τεκμηρίωση\n    extended_description_html: |\n      <h3>Ένα καλό σημείο για κανόνες</h3>\n      <p>Η αναλυτική περιγραφή δεν έχει ακόμα οριστεί</p>\n    federation_hint_html: Με ένα λογαριασμό στο %{instance} θα μπορείς να ακολουθείς ανθρώπους σε οποιοδήποτε κόμβο στο Mastodon αλλά και αλλού.\n    generic_description: \"%{domain} είναι ένας εξυπηρετητής στο δίκτυο\"\n    get_apps: Δοκίμασε μια εφαρμογή κινητού\n    hosted_on: Το Mastodon φιλοξενείται στο %{domain}\n    learn_more: Μάθε περισσότερα\n    privacy_policy: Πολιτική απορρήτου\n    see_whats_happening: Μάθε τι συμβαίνει\n    server_stats: 'Στατιστικά κόμβου:'\n    source_code: Πηγαίος κώδικας\n    status_count_after:\n      one: δημοσίευση\n      other: δημοσιεύσεις\n    status_count_before: Που έγραψαν\n    tagline: Ακολούθησε τους γνωστούς σου και ανακάλυψε νέους ανθρώπους\n    terms: Όροι χρήσης\n    user_count_after:\n      one: χρήστης\n      other: χρήστες\n    user_count_before: Σπίτι για\n    what_is_mastodon: Τι είναι το Mastodon;\n  accounts:\n    choices_html: 'Επιλογές από %{name}:'\n    follow: Ακολούθησε\n    followers:\n      one: Ακόλουθος\n      other: Ακόλουθοι\n    following: Ακολουθεί\n    joined: Εγγράφηκε στις %{date}\n    last_active: τελευταία ενεργός/ή\n    link_verified_on: Η κυριότητα αυτού του συνδέσμου ελέγχθηκε στις %{date}\n    media: Πολυμέσα\n    moved_html: 'Ο/Η %{name} μετακόμισε στο %{new_profile_link}:'\n    network_hidden: Αυτή η πληροφορία δεν είναι διαθέσιμη\n    nothing_here: Δεν υπάρχει τίποτα εδώ!\n    people_followed_by: Χρήστες που ακολουθεί ο/η %{name}\n    people_who_follow: Χρήστες που ακολουθούν τον/την %{name}\n    pin_errors:\n      following: Πρέπει ήδη να ακολουθείς το άτομο που θέλεις να επιδοκιμάσεις\n    posts:\n      one: Τουτ\n      other: Τουτ\n    posts_tab_heading: Τουτ\n    posts_with_replies: Τουτ και απαντήσεις\n    reserved_username: Το όνομα χρήστη είναι κατειλημμένο\n    roles:\n      admin: Διαχειριστής\n      bot: Μποτ (αυτόματος λογαριασμός)\n      moderator: Μεσολαβητής\n    unavailable: Το προφίλ δεν είναι διαθέσιμο\n    unfollow: Διακοπή παρακολούθησης\n  admin:\n    account_actions:\n      action: Εκτέλεση ενέργειας\n      title: Εκτέλεση ενέργειας διαχείρισης στο %{acct}\n    account_moderation_notes:\n      create: Άφησε σημείωση\n      created_msg: Επιτυχής δημιουργία σημειώματος μεσολάβησης!\n      delete: Διαγραφή\n      destroyed_msg: Επιτυχής καταστροφή σημειώματος μεσολάβησης!\n    accounts:\n      approve: Έγκριση\n      approve_all: Έγκριση όλων\n      are_you_sure: Σίγουρα;\n      avatar: Αβατάρ\n      by_domain: Τομέας\n      change_email:\n        changed_msg: Επιτυχής αλλαγή email λογαριασμού!\n        current_email: Τρέχον email\n        label: Αλλαγή email\n        new_email: Νέο email\n        submit: Αλλαγή email\n        title: Αλλαγή email για %{username}\n      confirm: Επιβεβαίωση\n      confirmed: Επιβεβαιώθηκε\n      confirming: Προς επιβεβαίωση\n      deleted: Διαγραμμένοι\n      demote: Υποβίβαση\n      disable: Απενεργοποίηση\n      disable_two_factor_authentication: Απενεργοποίηση 2FA\n      disabled: Απενεργοποιημένο\n      display_name: Όνομα εμφάνισης\n      domain: Τομέας\n      edit: Αλλαγή\n      email: Email\n      email_status: Κατάσταση email\n      enable: Ενεργοποίηση\n      enabled: Ενεργοποιημένο\n      feed_url: URL ροής\n      followers: Ακόλουθοι\n      followers_url: URL ακολούθων\n      follows: Ακολουθεί\n      header: Επικεφαλίδα\n      inbox_url: URL εισερχομένων\n      invited_by: Προσκλήθηκε από\n      ip: IP\n      joined: Γράφτηκε\n      location:\n        all: Όλες\n        local: Τοπική\n        remote: Απομακρυσμένα\n        title: Τοποθεσία\n      login_status: Κατάσταση σύνδεσης\n      media_attachments: Συνημμένα πολυμέσα\n      memorialize: Μετατροπή σε νεκρολογία\n      moderation:\n        active: Ενεργός/ή\n        all: Όλα\n        pending: Εκκρεμούν\n        silenced: Αποσιωπημένα\n        suspended: Σε αναστολή\n        title: Μεσολάβηση\n      moderation_notes: Σημειώσεις μεσολάβησης\n      most_recent_activity: Πιο πρόσφατη δραστηριότητα\n      most_recent_ip: Πιο πρόσφατη IP\n      no_account_selected: Κανείς λογαριασμός δεν ενημερώθηκε αφού κανείς δεν ήταν επιλεγμένος\n      no_limits_imposed: Χωρίς όρια\n      not_subscribed: Άνευ συνδρομής\n      outbox_url: URL εξερχομένων\n      pending: Εκκρεμεί έγκριση\n      perform_full_suspension: Αναστολή\n      profile_url: URL προφίλ\n      promote: Προβίβασε\n      protocol: Πρωτόκολλο\n      public: Δημόσιο\n      push_subscription_expires: Η εγγραφή PuSH λήγει\n      redownload: Ανανέωση αβατάρ\n      reject: Απόρριψη\n      reject_all: Απόρριψη όλων\n      remove_avatar: Απομακρυσμένο αβατάρ\n      remove_header: Αφαίρεση επικεφαλίδας\n      resend_confirmation:\n        already_confirmed: Ήδη επιβεβαιωμένος χρήστης\n        send: Επανάληψη αποστολής email επιβεβαίωσης\n        success: Το email επιβεβαίωσης στάλθηκε επιτυχώς!\n      reset: Επαναφορά\n      reset_password: Επαναφορά συνθηματικού\n      resubscribe: Επανεγγραφή\n      role: Δικαιώματα\n      roles:\n        admin: Διαχειριστής\n        moderator: Συντονιστής\n        staff: Προσωπικό\n        user: Χρήστης\n      salmon_url: URL Salmon\n      search: Αναζήτηση\n      shared_inbox_url: URL κοινόχρηστων εισερχομένων\n      show:\n        created_reports: Αναφορές από αυτόν το λογαριασμό\n        targeted_reports: Αναφορές για αυτόν το λογαριασμό\n      silence: Αποσιώπησε\n      silenced: Αποσιωπημένοι\n      statuses: Καταστάσεις\n      subscribe: Εγγραφή\n      suspended: Σε αναστολή\n      time_in_queue: Σε αναμονή για %{time}\n      title: Λογαριασμοί\n      unconfirmed_email: Ανεπιβεβαίωτο email\n      undo_silenced: Αναίρεση αποσιώπησης\n      undo_suspension: Αναίρεση παύσης\n      unsubscribe: Κατάργηση εγγραφής\n      username: Όνομα χρήστη\n      warn: Προειδοποίηση\n      web: Διαδίκτυο\n    action_logs:\n      actions:\n        assigned_to_self_report: Ο/Η %{name} ανάθεσε την καταγγελία %{target} στον εαυτό του/της\n        change_email_user: Ο/Η %{name} άλλαξε τη διεύθυνση email του χρήστη %{target}\n        confirm_user: Ο/Η %{name} επιβεβαίωσε τη διεύθυνση email του χρήστη %{target}\n        create_account_warning: Ο/Η %{name} έστειλε προειδοποίηση προς %{target}\n        create_custom_emoji: Ο/Η %{name} ανέβασε νέο emoji %{target}\n        create_domain_block: Ο/Η %{name} μπλόκαρε τον τομέα %{target}\n        create_email_domain_block: Ο/Η %{name} έβαλε τον τομέα email %{target} σε μαύρη λίστα\n        demote_user: Ο/Η %{name} υποβίβασε το χρήστη %{target}\n        destroy_custom_emoji: Ο/Η %{name} κατέστρεψε το emoji %{target}\n        destroy_domain_block: Ο/Η %{name} ξεμπλόκαρε τον τομέα %{target}\n        destroy_email_domain_block: Ο/Η %{name} έβαλε τον τομέα email %{target} σε λευκή λίστα\n        destroy_status: Ο/Η %{name} αφαίρεσε την κατάσταση του/της %{target}\n        disable_2fa_user: Ο/Η %{name} απενεργοποίησε την απαίτηση δύο παραγόντων για το χρήστη %{target}\n        disable_custom_emoji: Ο/Η %{name} απενεργοποίησε το emoji %{target}\n        disable_user: Ο/Η %{name} απενεργοποίησε την είσοδο για το χρήστη %{target}\n        enable_custom_emoji: Ο/Η %{name} ενεργοποίησε το emoji %{target}\n        enable_user: Ο/Η %{name} ενεργοποίησε την είσοδο του χρήστη %{target}\n        memorialize_account: Ο/Η %{name} μετέτρεψε το λογαριασμό του/της %{target} σε σελίδα νεκρολογίας\n        promote_user: Ο/Η %{name} προβίβασε το χρήστη %{target}\n        remove_avatar_user: Ο/Η %{name} αφαίρεσε το αβατάρ του/της %{target}\n        reopen_report: Ο/Η %{name} ξανάνοιξε την καταγγελία %{target}\n        reset_password_user: Ο/Η %{name} επανέφερε το συνθηματικό του χρήστη %{target}\n        resolve_report: Ο/Η %{name} επέλυσε την καταγγελία %{target}\n        silence_account: Ο/Η %{name} αποσιώπησε το λογαριασμό του/της %{target}\n        suspend_account: Ο/Η %{name} έπαυσε το λογαριασμό του/της %{target}\n        unassigned_report: Ο/Η %{name} αποδέσμευσε την καταγγελία %{target}\n        unsilence_account: Ο/Η %{name} ήρε την αποσιώπηση του λογαριασμού του/της %{target}\n        unsuspend_account: Ο/Η %{name} ήρε την παύση του λογαριασμού του χρήστη %{target}\n        update_custom_emoji: Ο/Η %{name} ενημέρωσε το emoji %{target}\n        update_status: Ο/Η %{name} ενημέρωσε την κατάσταση του/της %{target}\n      deleted_status: \"(διαγραμμένη δημοσίευση)\"\n      title: Αρχείο ελέγχου\n    custom_emojis:\n      by_domain: Τομέας\n      copied_msg: Επιτυχής δημιουργία τοπικού αντίγραφου του emoji\n      copy: Αντιγραφή\n      copy_failed_msg: Αδυναμία δημιουργίας τοπικού αντίγραφου αυτού του emoji\n      created_msg: Επιτυχής δημιουργία του emoji!\n      delete: Διαγραφή\n      destroyed_msg: Επιτυχής καταστροφή του emojo!\n      disable: Απενεργοποίηση\n      disabled_msg: Επιτυχής απενεργοποίηση αυτού του emoji\n      emoji: Emoji\n      enable: Ενεργοποίηση\n      enabled_msg: Επιτυχής ενεργοποίηση αυτού του emoji\n      image_hint: PNG έως 50KB\n      listed: Αναφερθέντα\n      new:\n        title: Προσθήκη νέου προσαρμοσμένου emoji\n      overwrite: Αντικατάσταση\n      shortcode: Σύντομος κωδικός\n      shortcode_hint: Τουλάχιστον 2 χαρακτήρες, μόνο αλφαριθμητικοί και κάτω παύλες\n      title: Προσαρμοσμένα emoji\n      unlisted: Μη καταχωρημένα\n      update_failed_msg: Αδυναμία ενημέρωσης του emoji\n      updated_msg: Επιτυχής ενημέρωση του emoji!\n      upload: Ανέβασμα\n    dashboard:\n      backlog: χρονοκαθυστερημένες εργασίες\n      config: Διαμόρφωση\n      feature_deletions: Διαγραφή λογαριασμών\n      feature_invites: Σύνδεσμοι προσκλήσεων\n      feature_profile_directory: Κατάλογος χρηστών\n      feature_registrations: Εγγραφές\n      feature_relay: Ανταποκριτής ομοσπονδίας\n      feature_timeline_preview: Προεπισκόπιση ροής\n      features: Λειτουργίες\n      hidden_service: Ομοσπονδία με κρυμμένες υπηρεσίες\n      open_reports: ανοιχτές καταγγελίες\n      recent_users: Πρόσφατοι χρήστες\n      search: Αναζήτηση πλήρους κειμένου\n      single_user_mode: Λειτουργία μοναδιαίου χρήστη\n      software: Λογισμικό\n      space: Κατανάλωση χώρου\n      title: Ταμπλό\n      total_users: χρήστες συνολικά\n      trends: Τάσεις\n      week_interactions: αλληλεπιδράσεις αυτή την εβδομάδα\n      week_users_active: ενεργοί αυτή την εβδομάδα\n      week_users_new: χρήστες αυτή την εβδομάδα\n    domain_blocks:\n      add_new: Προσθήκη νέου\n      created_msg: Ο αποκλεισμός τομέα είναι υπό επεξεργασία\n      destroyed_msg: Ο αποκλεισμός τομέα άρθηκε\n      domain: Τομέας\n      existing_domain_block_html: Έχεις ήδη επιβάλλει αυστηρότερους περιορισμούς στο %{name}, πρώτα θα πρέπει να τους <a href=\"%{unblock_url}\">αναιρέσεις</a>.\n      new:\n        create: Δημιουργία αποκλεισμού\n        hint: Ο αποκλεισμός τομέα δεν θα αποτρέψει νέες καταχωρίσεις λογαριασμών στην βάση δεδομένων, αλλά θα εφαρμόσει αναδρομικά και αυτόματα συγκεκριμένες πολιτικές μεσολάβησης σε αυτούς τους λογαριασμούς.\n        severity:\n          desc_html: Η <strong>αποσιώπηση</strong> θα κάνει αόρατες τις δημοσιεύσεις ενός λογαριασμού σε όσους δεν τον ακολουθούν. Η <strong>αναστολή</strong> θα αφαιρέσει όλο το περιεχόμενο, τα πολυμέσα και τα στοιχεία προφίλ ενός λογαριασμού. Χρησιμοποίησε το <strong>κανένα</strong> αν θέλεις απλά να απορρίψεις τα αρχεία πολυμέσων.\n          noop: Κανένα\n          silence: Σίγαση\n          suspend: Αναστολή\n        title: Αποκλεισμός νέου τομέα\n      reject_media: Απόρριψη πολυμέσων\n      reject_media_hint: Αφαιρεί τα τοπικά αποθηκευμένα αρχεία πολυμέσων και αποτρέπει τη λήψη άλλων στο μέλλον. Δεν έχει σημασία για τις αναστολές\n      reject_reports: Απόρριψη καταγγελιών\n      reject_reports_hint: Αγνόηση όσων καταγγελιών προέρχονται από αυτό τον τομέα. Δεν σχετίζεται με τις παύσεις\n      rejecting_media: απορρίπτουν αρχεία πολυμέσων\n      rejecting_reports: απορρίπτουν καταγγελίες\n      severity:\n        silence: αποσιωπημένοι\n        suspend: ανεσταλμένοι\n      show:\n        affected_accounts:\n          one: Επηρεάζεται ένας λογαριασμός στη βάση δεδομένων\n          other: Επηρεάζονται %{count} λογαριασμοί στη βάση δεδομένων\n        retroactive:\n          silence: Αναίρεση αποσιώπησης όλων των λογαριασμός του τομέα\n          suspend: Αναίρεση αναστολής όλων των λογαριασμών του τομέα\n        title: Αναίρεση αποκλεισμού για τον τομέα %{domain}\n        undo: Αναίρεση\n      undo: Αναίρεση\n    email_domain_blocks:\n      add_new: Πρόσθεση νέου\n      created_msg: Επιτυχής πρόσθεση email τομέα σε μαύρη λίστα\n      delete: Διαγραφή\n      destroyed_msg: Επιτυχής διαγραφή email τομέα από τη μαύρη λίστα\n      domain: Τομέας\n      new:\n        create: Πρόσθεση τομέα\n        title: Νέα εγγραφή email στη μαύρη λίστα\n      title: Μαύρη λίστα email\n    followers:\n      back_to_account: Επιστροφή στον λογαριασμό\n      title: Ακόλουθοι του/της %{acct}\n    instances:\n      by_domain: Τομέας\n      delivery_available: Διαθέσιμη παράδοση\n      known_accounts:\n        one: \"%{count} γνωστός λογαριασμός\"\n        other: \"%{count} γνωστοί λογαριασμοί\"\n      moderation:\n        all: Όλα\n        limited: Περιορισμένα\n        title: Διαμεσολάβηση\n      title: Γνωστοί κόμβοι\n      total_blocked_by_us: Μπλοκάρονται από εμάς\n      total_followed_by_them: Ακολουθούνται από εκείνους\n      total_followed_by_us: Ακολουθούνται από εμάς\n      total_reported: Καταγγελίες προς εκείνους\n      total_storage: Συνημμένα πολυμέσα\n    invites:\n      deactivate_all: Απενεργοποίηση όλων\n      filter:\n        all: Όλες\n        available: Διαθέσιμες\n        expired: Ληγμένες\n        title: Φίλτρο\n      title: Προσκλήσεις\n    pending_accounts:\n      title: Λογαριασμοί σε αναμονή (%{count})\n    relays:\n      add_new: Πρόσθεσε νέο ανταποκριτή (relay)\n      delete: Διαγραφή\n      description_html: Ο <strong>ομοσπονδιακός ανταποκριτής</strong> είναι ένας ενδιάμεσος εξυπηρετητής (server) που ανταλλάσσει μεγάλους όγκους δημόσιων τουτ μεταξύ εξυπηρετητών που εγγράφονται και δημοσιεύουν σε αυτόν. <strong>Βοηθάει μικρούς και μεσαίους εξυπηρετητές να ανακαλύψουν περιεχόμενο στο fediverse</strong>, που υπό άλλες συνθήκες θα χρειαζόταν κάποιους τοπικούς χρήστες που να ακολουθούν χρήστες σε απομακρυσμένους εξυπηρετητές.\n      disable: Απενεργοποίηση\n      disabled: Απενεργοποιημένο\n      enable: Ενεργοποίηση\n      enable_hint: Μόλις ενεργοποιηθεί, ο εξυπηρετητής (server) σου θα εγγραφεί σε όλα τα δημόσια τουτ αυτού του ανταποκριτή (relay) και θα αρχίσει να προωθεί τα δικά του δημόσια τουτ σε αυτόν.\n      enabled: Ενεργοποιημένο\n      inbox_url: URL ανταποκριτή\n      pending: Περιμένοντας την έγκριση του ανταποκριτή\n      save_and_enable: Αποθήκευση και ενεργοποίηση\n      setup: Όρισε μια σύνδεση ανταπόκρισης\n      status: Κατάσταση\n      title: Ανταποκριτές\n    report_notes:\n      created_msg: Επιτυχής δημιουργία σημείωσης καταγγελίας!\n      destroyed_msg: Επιτυχής διαγραφή σημείωσης καταγγελίας!\n    reports:\n      account:\n        note: σημείωση\n        report: καταγγελία\n      action_taken_by: Ενέργεια από τον/την\n      are_you_sure: Σίγουρα;\n      assign_to_self: Ανάθεση σε μένα\n      assigned: Αρμόδιος συντονιστής\n      comment:\n        none: Κανένα\n      created_at: Καταγγέλθηκε\n      mark_as_resolved: Σημειωμένο ως επιλυμένο\n      mark_as_unresolved: Σημειωμένο ως ανεπίλυτο\n      notes:\n        create: Πρόσθεσε σημείωση\n        create_and_resolve: Επίλυσε με σημείωση\n        create_and_unresolve: Ξανάνοιξε με σημείωση\n        delete: Διαγραφή\n        placeholder: Περιέγραψε τις ενέργειες που έγιναν, ή οποιαδήποτε άλλη ενημέρωση...\n      reopen: Ξανάνοιξε την καταγγελία\n      report: 'Καταγγελία #%{id}'\n      reported_account: Αναφερόμενος λογαριασμός\n      reported_by: Αναφέρθηκε από\n      resolved: Επιλύθηκε\n      resolved_msg: Η καταγγελία επιλύθηκε επιτυχώς!\n      status: Κατάσταση\n      title: Αναφορές\n      unassign: Αποσύνδεση\n      unresolved: Άλυτη\n      updated_at: Ενημερωμένη\n    settings:\n      activity_api_enabled:\n        desc_html: Καταμέτρηση τοπικών δημοσιεύσεων, ενεργών χρηστών και νέων εγγραφών σε εβδομαδιαίες ομαδοποιήσεις\n        title: Δημοσίευση συγκεντρωτικών στατιστικών για τη δραστηριότητα χρηστών\n      bootstrap_timeline_accounts:\n        desc_html: Διαχωρίστε πολλαπλά ονόματα χρηστών με κόμματα. Λειτουργεί μόνο με τοπικούς και ανοιχτούς λογαριασμούς. Αν είναι κενό, περιλαμβάνει όλους τους τοπικούς διαχειριστές.\n        title: Προεπιλεγμένοι λογαριασμοί για παρακολούθηση από τους νέους χρήστες\n      contact_information:\n        email: Επαγγελματικό email\n        username: Όνομα χρήστη επικοινωνίας\n      custom_css:\n        desc_html: Τροποποίηση της εμφάνισης μέσω CSS που φορτώνεται σε κάθε σελίδα\n        title: Προσαρμοσμένο CSS\n      hero:\n        desc_html: Εμφανίζεται στην μπροστινή σελίδα. Συνίσταται τουλάχιστον 600x100px. Όταν λείπει, χρησιμοποιείται η μικρογραφία του κόμβου\n        title: Εικόνα ήρωα\n      mascot:\n        desc_html: Εμφάνιση σε πολλαπλές σελίδες. Προτεινόμενο 293x205px τουλάχιστον. Αν δεν έχει οριστεί, χρησιμοποιεί την προεπιλεγμένη μασκότ\n        title: Εικόνα μασκότ\n      peers_api_enabled:\n        desc_html: Ονόματα τομέων που αυτός ο κόμβος έχει ήδη συναντήσει στο fediverse\n        title: Δημοσίευση λίστας κόμβων που έχουν ανακαλυφθεί\n      preview_sensitive_media:\n        desc_html: Οι προεπισκοπήσεις συνδέσμων σε τρίτους ιστότοπους θα είναι ορατές ακόμα κι όταν το πολυμέσο έχει σημειωθεί ως ευαίσθητο\n        title: Εμφάνιση ευαίσθητων πολυμέσων στις προεπισκοπήσεις OpenGraph\n      profile_directory:\n        desc_html: Να επιτρέπεται η ανακάλυψη χρηστών\n        title: Ενεργοποίηση του καταλόγου χρηστών\n      registrations:\n        closed_message:\n          desc_html: Εμφανίζεται στην εισαγωγική σελίδα όταν οι εγγραφές είναι κλειστές. Μπορείς να χρησιμοποιήσεις HTML tags\n          title: Μήνυμα κλεισμένων εγγραφών\n        deletion:\n          desc_html: Επέτρεψε σε οποιονδήποτε να διαγράψει το λογαριασμό του/της\n          title: Άνοιξε τη διαγραφή λογαριασμού\n        min_invite_role:\n          disabled: Κανείς\n          title: Επέτρεψε προσκλήσεις από\n      registrations_mode:\n        modes:\n          approved: Απαιτείται έγκριση για εγγραφή\n          none: Δεν μπορεί να εγγραφεί κανείς\n          open: Μπορεί να εγγραφεί ο οποιοσδήποτε\n        title: Μέθοδος εγγραφής\n      show_known_fediverse_at_about_page:\n        desc_html: Όταν αντιστραφεί, θα δείχνει τα τουτ από όλο το γνωστό fediverse στην προεπισκόπηση. Διαφορετικά θα δείχνει μόνο τοπικά τουτ.\n        title: Εμφάνιση του γνωστού fediverse στην προεπισκόπηση ροής\n      show_staff_badge:\n        desc_html: Δείξε ένα σήμα προσωπικού στη σελίδα ενός χρήστη\n        title: Δείξε διακριτικό προσωπικού\n      site_description:\n        desc_html: Εισαγωγική παράγραφος στην αρχική σελίδα. Περιέγραψε τι κάνει αυτό τον διακομιστή Mastodon διαφορετικό και ό,τι άλλο ενδιαφέρον. Μπορείς να χρησιμοποιήσεις HTML tags, συγκεκριμένα <code>&lt; a&gt;</code> και <code> &lt; em&gt;</code>.\n        title: Περιγραφή κόμβου\n      site_description_extended:\n        desc_html: Ένα καλό μέρος για τον κώδικα δεοντολογίας, τους κανόνες, τις οδηγίες και ό,τι άλλο διαφοροποιεί τον κόμβο σου. Μπορείς να χρησιμοποιήσεις και κώδικα HTML\n        title: Προσαρμοσμένες εκτεταμένες πληροφορίες\n      site_short_description:\n        desc_html: Εμφανίζεται στην πλαϊνή μπάρα και στα meta tags. Περιέγραψε τι είναι το Mastodon και τι κάνει αυτό τον διακομιστή ιδιαίτερο σε μια παράγραφο. Αν μείνει κενό, θα χρησιμοποιήσει την προκαθορισμένη περιγραφή του κόμβου.\n        title: Σύντομη περιγραφή του κόμβου\n      site_terms:\n        desc_html: Μπορείς να γράψεις τη δική σου πολιτική απορρήτου, όρους χρήσης ή άλλους νομικούς όρους. Μπορείς να χρησιμοποιήσεις HTML tags\n        title: Προσαρμοσμένοι όροι χρήσης της υπηρεσίας\n      site_title: Όνομα κόμβου\n      thumbnail:\n        desc_html: Χρησιμοποιείται για προεπισκοπήσεις μέσω του OpenGraph και του API. Συστήνεται 1200x630px\n        title: Μικρογραφία κόμβου\n      timeline_preview:\n        desc_html: Εμφάνισε τη δημόσια ροή στην αρχική σελίδα\n        title: Προεπισκόπιση ροής\n      title: Ρυθμίσεις ιστότοπου\n    statuses:\n      back_to_account: Επιστροφή στη σελίδα λογαριασμού\n      batch:\n        delete: Διαγραφή\n        nsfw_off: Σημείωσε ως μη ευαίσθητο\n        nsfw_on: Σημείωσε ως ευαίσθητο\n      failed_to_execute: Αποτυχία εκτέλεσης\n      media:\n        title: Πολυμέσα\n      no_media: Χωρίς πολυμέσα\n      no_status_selected: Καμία δημοσίευση δεν άλλαξε αφού καμία δεν ήταν επιλεγμένη\n      title: Καταστάσεις λογαριασμού\n      with_media: Με πολυμέσα\n    subscriptions:\n      callback_url: URL επιστροφής (Callback)\n      confirmed: Επιβεβαιωμένες\n      expires_in: Λήγει σε\n      last_delivery: Τελευταία παράδοση\n      title: Πρωτόκολλο WebSub\n      topic: Θέμα\n    tags:\n      accounts: Λογαριασμοί\n      hidden: Κρυμμένες\n      hide: Απόκρυψη από κατάλογο\n      name: Ταμπέλα\n      title: Ταμπέλες\n      unhide: Εμφάνιση σε κατάλογο\n      visible: Εμφανείς\n    title: Διαχείριση\n    warning_presets:\n      add_new: Πρόσθεση νέου\n      delete: Διαγραφή\n      edit: Ενημέρωση\n      edit_preset: Ενημέρωση προκαθορισμένης προειδοποίησης\n      title: Διαχείριση προκαθορισμένων προειδοποιήσεων\n  admin_mailer:\n    new_pending_account:\n      body: Τα στοιχεία του νέου λογαριασμού είναι παρακάτω. Μπορείς να εγκρίνεις ή να απορρίψεις αυτή την αίτηση.\n      subject: Νέος λογαριασμός προς έγκριση στο %{instance} (%{username})\n    new_report:\n      body: Ο/Η %{reporter} κατήγγειλε τον/την %{target}\n      body_remote: Κάποιος/α από τον τομέα %{domain} κατήγγειλε τον/την %{target}\n      subject: Νέα καταγγελία για %{instance} (#%{id})\n  appearance:\n    advanced_web_interface: Προηγμένη λειτουργία χρήσης\n    advanced_web_interface_hint: 'Αν θέλεις να χρησιμοποιήσεις ολόκληρο το πλάτος της οθόνης σου, η προηγμένη λειτουργία χρήσης σου επιτρέπει να ορίσεις πολλαπλές κολώνες ώστε να βλέπεις ταυτόχρονα όση πληροφορία θέλεις: Την αρχική ροή, τις ειδοποιήσεις, την ομοσπονδιακή ροή και όσες λίστες και ταμπέλες θέλεις.'\n    animations_and_accessibility: Κίνηση και προσβασιμότητα\n    confirmation_dialogs: Ερωτήσεις επιβεβαίωσης\n    sensitive_content: Ευαίσθητο περιεχόμενο\n  application_mailer:\n    notification_preferences: Αλλαγή προτιμήσεων email\n    salutation: \"%{name},\"\n    settings: 'Άλλαξε τις προτιμήσεις email: %{link}'\n    view: 'Προβολή:'\n    view_profile: Προβολή προφίλ\n    view_status: Προβολή κατάστασης\n  applications:\n    created: Η εφαρμογή δημιουργήθηκε επιτυχώς\n    destroyed: Η εφαρμογή διαγράφηκε επιτυχώς\n    invalid_url: Το URL δεν είναι έγκυρο\n    regenerate_token: Αναδημιουργία του διακριτικού πρόσβασης (access token)\n    token_regenerated: Το διακριτικό πρόσβασης (access token) αναδημιουργήθηκε επιτυχώς\n    warning: Μεγάλη προσοχή με αυτά τα στοιχεία. Μην τα μοιραστείς ποτέ με κανέναν!\n    your_token: Το διακριτικό πρόσβασής σου (access token)\n  auth:\n    apply_for_account: Αίτηση πρόσκλησης\n    change_password: Συνθηματικό\n    checkbox_agreement_html: Συμφωνώ με τους <a href=\"%{rules_path}\" target=\"_blank\">κανονισμούς του κόμβου</a> και <a href=\"%{terms_path}\" target=\"_blank\">τους όρους χρήσης</a>\n    confirm_email: Επιβεβαίωση email\n    delete_account: Διαγραφή email\n    delete_account_html: Αν θέλεις να διαγράψεις το λογαριασμό σου, μπορείς <a href=\"%{path}\">να συνεχίσεις εδώ</a>. Θα σου ζητηθεί επιβεβαίωση.\n    didnt_get_confirmation: Δεν έλαβες τις οδηγίες επιβεβαίωσης;\n    forgot_password: Ξέχασες το συνθηματικό σου;\n    invalid_reset_password_token: Το διακριτικό επαναφοράς συνθηματικού είναι άκυρο ή ληγμένο. Παρακαλώ αιτήσου νέο.\n    login: Σύνδεση\n    logout: Αποσύνδεση\n    migrate_account: Μετακόμισε σε διαφορετικό λογαριασμό\n    migrate_account_html: Αν θέλεις να ανακατευθύνεις αυτό τον λογαριασμό σε έναν διαφορετικό, μπορείς να το <a href=\"%{path}\">διαμορφώσεις εδώ</a>.\n    or_log_in_with: Ή συνδέσου με\n    providers:\n      cas: Υπηρεσία Κεντρικής Πιστοποίησης (CAS)\n      saml: Πρωτόκολλο SAML\n    register: Εγγραφή\n    registration_closed: Το %{instance} δεν δέχεται νέα μέλη\n    resend_confirmation: Στείλε ξανά τις οδηγίες επιβεβαίωσης\n    reset_password: Επαναφορά συνθηματικού\n    security: Ασφάλεια\n    set_new_password: Ορισμός νέου συνθηματικού\n    trouble_logging_in: Πρόβλημα σύνδεσης;\n  authorize_follow:\n    already_following: Ήδη ακολουθείς αυτό το λογαριασμό\n    error: Δυστυχώς παρουσιάστηκε ένα σφάλμα κατά την αναζήτηση του απομακρυσμένου λογαριασμού\n    follow: Ακολούθησε\n    follow_request: 'Έστειλες αίτημα παρακολούθησης προς:'\n    following: 'Επιτυχία! Πλέον ακολουθείς τον/την:'\n    post_follow:\n      close: Ή, μπορείς απλά να κλείσεις αυτό το παράθυρο.\n      return: Δείξε το προφίλ του χρήστη\n      web: Πήγαινε στο δίκτυο\n    title: Ακολούθησε %{acct}\n  datetime:\n    distance_in_words:\n      about_x_hours: \"%{count}ω\"\n      about_x_months: \"%{count}μ\"\n      about_x_years: \"%{count}ε\"\n      almost_x_years: \"%{count}ε\"\n      half_a_minute: Μόλις τώρα\n      less_than_x_minutes: \"%{count}λ\"\n      less_than_x_seconds: Μόλις τώρα\n      over_x_years: \"%{count}ε\"\n      x_days: \"%{count}η\"\n      x_minutes: \"%{count}λ\"\n      x_months: \"%{count}μ\"\n      x_seconds: \"%{count}δ\"\n  deletes:\n    bad_password_msg: Καλή προσπάθεια χάκερς! Λάθος συνθηματικό\n    confirm_password: Γράψε το τρέχον συνθηματικό σου για να πιστοποιήσεις την ταυτότητά σου\n    description_html: Αυτό θα διαγράψει <strong>οριστικά και αμετάκλητα</strong> το περιεχόμενο του λογαριασμού σου και θα τον απενεργοποιήσει. Το όνομα χρήστη θα παραμείνει δεσμευμένο για να αποφευχθούν μελλοντικές πλαστοπροσωπίες.\n    proceed: Διαγραφή λογαριασμού\n    success_msg: Ο λογαριασμός σου διαγράφηκε με επιτυχία\n    warning_html: Μόνο η διαγραφή περιεχομένου από αυτό τον συγκεκριμένο κόμβο είναι εγγυημένη. Το περιεχόμενο που έχει διαμοιραστεί ευρέως είναι πιθανό να αφήσει ίχνη. Όσοι διακομιστές είναι εκτός σύνδεσης και όσοι έχουν διακόψει τη λήψη των ενημερώσεων του κόμβου σου, δε θα ενημερώσουν τις βάσεις δεδομένων τους.\n    warning_title: Διαθεσιμότητα ήδη διανεμημένου περιεχομένου\n  directories:\n    directory: Κατάλογος λογαριασμών\n    enabled: Περιλαμβάνεσαι στον κατάλογο.\n    enabled_but_waiting: Έχεις επιλέξει να εμφανίζεσαι στον κατάλογο μεν, αλλά ακόμα δεν έχεις τον ελάχιστο αριθμό ακόλουθων (%{min_followers}) που απαιτείται για να συμπεριληφθείς.\n    explanation: Βρες χρήστες βάσει των ενδιαφερόντων τους\n    explore_mastodon: Εξερεύνησε το %{title}\n    how_to_enable: Δεν έχεις επιλέξει να συμπεριληφθείς στον καταλογο. Μπορείς να επιλέξεις παρακάτω. Χρησιμοποίησε ταμπέλες στο κείμενο του βιογραφικού σου για να εμφανίζεσαι κάτω από συγκεκριμένες ταμπέλες!\n    people:\n      one: \"%{count} άτομο\"\n      other: \"%{count} άτομα\"\n  errors:\n    '403': Δεν έχεις δικαίωμα πρόσβασης σε αυτή τη σελίδα.\n    '404': Η σελίδα που ψάχνεις δεν υπάρχει.\n    '410': Η σελίδα που έψαχνες δεν υπάρχει πια εδώ.\n    '422':\n      content: Απέτυχε η επιβεβαίωση ασφαλείας. Μήπως μπλοκάρεις τα cookies;\n      title: Η επιβεβαίωση ασφαλείας απέτυχε\n    '429': Περιορισμένο\n    '500':\n      content: Λυπούμαστε, κάτι πήγε στραβά από τη δική μας μεριά.\n      title: Η σελίδα αυτή δεν είναι σωστή\n    noscript_html: Για να χρησιμοποιήσετε τη δικτυακή εφαρμογή του Mastodon, ενεργοποίησε την Javascript. Εναλλακτικά, δοκίμασε μια από τις <a href=\"%{apps_path}\">εφαρμογές</a> για το Mastodon στην πλατφόρμα σου.\n  existing_username_validator:\n    not_found: δεν βρέθηκε τοπικός χρήστης με αυτό το όνομα\n    not_found_multiple: δεν βρέθηκε %{usernames}\n  exports:\n    archive_takeout:\n      date: Ημερομηνία\n      download: Κατέβασε το αρχείο σου\n      hint_html: Μπορείς να αιτηθείς ένα αρχείο των <strong>τουτ και των ανεβασμένων πολυμέσων</strong> σου. Τα δεδομένα θα είναι σε μορφή ActivityPub, προσιτά από οποιοδήποτε συμβατό πρόγραμμα. Μπορείς να αιτηθείς αρχείο κάθε 7 μέρες.\n      in_progress: Συγκεντρώνουμε το αρχείο σου...\n      request: Αιτήσου το αρχείο σου\n      size: Μέγεθος\n    blocks: Μπλοκάρεις\n    csv: CSV\n    domain_blocks: Μπλοκαρίσματα κόμβων\n    follows: Ακολουθείς\n    lists: Λίστες\n    mutes: Αποσιωπάς\n    storage: Αποθήκευση πολυμέσων\n  featured_tags:\n    add_new: Προσθήκη νέας\n    errors:\n      limit: Έχεις ήδη προσθέσει το μέγιστο αριθμό ταμπελών\n  filters:\n    contexts:\n      home: Αρχική ροή\n      notifications: Ειδοποιήσεις\n      public: Δημόσιες ροές\n      thread: Συζητήσεις\n    edit:\n      title: Ενημέρωση φίλτρου\n    errors:\n      invalid_context: Έδωσες λάθος ή ανύπαρκτο πλαίσιο\n      invalid_irreversible: Τα μη αντιστρέψιμα φίλτρα δουλεύουν μόνο στα πλαίσια της αρχικής ροής και των ειδοποιήσεων\n    index:\n      delete: Διαγραφή\n      title: Φίλτρα\n    new:\n      title: Πρόσθεσε νέο φίλτρο\n  footer:\n    developers: Ανάπτυξη\n    more: Περισσότερα…\n    resources: Πόροι\n  generic:\n    all: Όλα\n    changes_saved_msg: Οι αλλαγές αποθηκεύτηκαν!\n    copy: Αντιγραφή\n    order_by: Ταξινόμηση κατά\n    save_changes: Αποθήκευσε τις αλλαγές\n    validation_errors:\n      one: Κάτι δεν είναι εντάξει ακόμα! Για κοίταξε το παρακάτω σφάλμα\n      other: Κάτι δεν είναι εντάξει ακόμα! Για κοίταξε τα παρακάτω %{count} σφάλματα\n  html_validator:\n    invalid_markup: 'περιέχει λάθος μορφοποίηση HTML: %{error}'\n  identity_proofs:\n    active: Ενεργή\n    authorize: Ναι, εξουσιοδότησε\n    authorize_connection_prompt: Εξουσιοδότηση αυτής της κρυπτογραφικής σύνδεσης;\n    errors:\n      failed: Η κρυπτογραφική σύνδεση απέτυχε. Παρακαλώ ξανά δοκίμασε μέσω %{provider}.\n      keybase:\n        invalid_token: Τα κλειδιά Keybase είναι κατακερματισμένες υπογραφές και πρέπει να έχουν μήκος 66 δεκαεξαδικών χαρακτήρων\n        verification_failed: Το Keybase δεν δέχτηκε αυτό το κλειδί ως υπογραφή του χρήστη %{kb_username}. Παρακαλούμε δοκίμασε μέσω Keybase.\n      wrong_user: Δεν επιτρέπεται να δημιουργηθεί ένα αποδεικτικό για %{proving} υπό τη σύνδεση ως %{current}. Συνδέσου ως %{proving} και δοκίμασε ξανά.\n    explanation_html: Εδώ μπορείς να συνδέσεις κρυπτογραφικά τις υπόλοιπες ταυτοτητές σου, όπως για παράδειγμα ένα προφίλ στο Keybase. Αυτό επιτρέπει σε άλλους ανθρώπους να σου στέλνουν κρυπτογραφημένα μηνύματα και να μπορούν να εμπιστευτούν το περιεχόμενο που τους στέλνεις εσύ.\n    i_am_html: Είμαι ο/η %{username} στην υπηρεσία %{service}.\n    identity: Ταυτότητα\n    inactive: Ανενεργή\n    publicize_checkbox: 'Και κάνε τουτ αυτό:'\n    publicize_toot: 'Αποδείχτηκε! Λέγομαι %{username} στο %{service}: %{url}'\n    status: Κατάσταση επαλήθευσης\n    view_proof: Εμφάνιση απόδειξης\n  imports:\n    modes:\n      merge: Συγχώνευση\n      merge_long: Διατήρηση των εγγράφων που υπάρχουν και προσθηκη των νέων\n      overwrite: Αντικατάσταση\n      overwrite_long: Αντικατάσταση των υπαρχόντων εγγράφων με τις καινούργιες\n    preface: Μπορείς να εισάγεις τα δεδομένα που έχεις εξάγει από άλλο κόμβο, όπως τη λίστα των ανθρώπων που ακολουθείς ή μπλοκάρεις.\n    success: Τα δεδομένα σου μεταφορτώθηκαν επιτυχώς και θα επεξεργαστούν εν καιρώ\n    types:\n      blocking: Λίστα αποκλεισμού\n      domain_blocking: Λίστα αποκλεισμένων τομέων\n      following: Λίστα ακολούθων\n      muting: Λίστα αποσιωπήσεων\n    upload: Ανέβασμα\n  in_memoriam_html: Εις μνήμην.\n  invites:\n    delete: Απενεργοποίησε\n    expired: Ληγμένη\n    expires_in:\n      '1800': 30 λεπτά\n      '21600': 6 ώρες\n      '3600': 1 ώρα\n      '43200': 12 ώρες\n      '604800': 1 εβδομάδα\n      '86400': 1 μέρα\n    expires_in_prompt: Ποτέ\n    generate: Δημιούργησε\n    invited_by: 'Σε προσκάλεσε ο/η:'\n    max_uses:\n      one: 1 χρήσης\n      other: \"%{count} χρήσεων\"\n    max_uses_prompt: Απεριόριστη\n    prompt: Φτιάξε και μοίρασε συνδέσμους με τρίτους για να δώσεις πρόσβαση σε αυτόν τον κόμβο\n    table:\n      expires_at: Λήγει\n      uses: Χρήσεις\n    title: Προσκάλεσε κόσμο\n  lists:\n    errors:\n      limit: Έχεις φτάσει το μέγιστο πλήθος επιτρεπτών λιστών\n  media_attachments:\n    validations:\n      images_and_video: Δεν γίνεται να προσθέσεις βίντεο σε ενημέρωση που ήδη περιέχει εικόνες\n      too_many: Δεν γίνεται να προσθέσεις περισσότερα από 4 αρχεία\n  migrations:\n    acct: ΌνομαΧρήστη@Τομέας του νέου λογαριασμού\n    currently_redirecting: 'Το προφίλ σου έχει ρυθμιστεί να ανακατευθύνει στο:'\n    proceed: Αποθήκευση\n    updated_msg: Οι ρυθμίσεις μετακόμισης του λογαριασμού σου ενημερώθηκαν!\n  moderation:\n    title: Συντονισμός\n  notification_mailer:\n    digest:\n      action: Δες όλες τις ειδοποιήσεις\n      body: Μια σύνοψη των μηνυμάτων που έχασες από την τελευταία επίσκεψή σου στις %{since}\n      mention: 'Ο/Η %{name} σε ανέφερε στις:'\n      new_followers_summary:\n        one: Επίσης, απέκτησες έναν νέο ακόλουθο ενώ ήσουν μακριά!\n        other: Επίσης, απέκτησες %{count} νέους ακόλουθους ενώ ήσουν μακριά! Εκπληκτικό!\n      subject:\n        one: \"1 νέα ειδοποίηση από την τελευταία επίσκεψή σου \\U0001F418\"\n        other: \"%{count} νέες ειδοποιήσεις από την τελευταία επίσκεψή σου \\U0001F418\"\n      title: Ενώ έλειπες...\n    favourite:\n      body: 'Η κατάστασή σου αγαπήθηκε από τον/την %{name}:'\n      subject: Ο/Η %{name} αγάπησε την κατάστασή σου\n      title: Νέο αγαπημένο\n    follow:\n      body: Ο/Η %{name} πλέον σε ακολουθεί!\n      subject: Ο/Η %{name} πλέον σε ακολουθεί\n      title: Νέος/α ακόλουθος\n    follow_request:\n      action: Διαχειρίσου τα αιτήματα παρακολούθησης\n      body: \"%{name} αιτήθηκε να σε ακολουθήσει\"\n      subject: 'Ακόλουθος που εκκρεμεί: %{name}'\n      title: Νέο αίτημα ακολούθησης\n    mention:\n      action: Απάντησε\n      body: 'Αναφέρθηκες από τον/την %{name} στο:'\n      subject: Αναφέρθηκες από τον/την %{name}\n      title: Νέα αναφορά\n    reblog:\n      body: 'Η κατάστασή σου προωθήθηκε από τον/την %{name}:'\n      subject: Ο/Η %{name} προώθησε την κατάστασή σου\n      title: Νέα προώθηση\n  number:\n    human:\n      decimal_units:\n        format: \"%n%u\"\n        units:\n          billion: δις.\n          million: εκ.\n          quadrillion: τετράκις.\n          thousand: χ.\n          trillion: τρις.\n  pagination:\n    newer: Νεότερο\n    next: Επόμενο\n    older: Παλιότερο\n    prev: Προηγούμενο\n    truncate: \"&hellip;\"\n  polls:\n    errors:\n      already_voted: Έχεις ήδη ψηφίσει σε αυτή την ψηφοφορία\n      duplicate_options: περιέχει επαναλαμβανόμενες επιλογές\n      duration_too_long: είναι πολύ μακριά στο μέλλον\n      duration_too_short: είναι πολύ σύντομα\n      expired: Η ψηφοφορία έχει ήδη λήξει\n      over_character_limit: δε μπορεί να υπερβαίνει τους %{max} χαρακτήρες έκαστη\n      too_few_options: πρέπει να έχει περισσότερες από μια επιλογές\n      too_many_options: δεν μπορεί να έχει περισσότερες από %{max} επιλογές\n  preferences:\n    other: Άλλο\n    posting_defaults: Προεπιλογές δημοσίευσης\n    public_timelines: Δημόσιες ροές\n  relationships:\n    activity: Δραστηριότητα λογαριασμού\n    dormant: Αδρανής\n    last_active: Τελευταία δραστηριότητα\n    most_recent: Πιο πρόσφατα\n    moved: Μετακόμισε\n    mutual: Αμοιβαίος\n    primary: Βασικός\n    relationship: Σχέση\n    remove_selected_domains: Αφαίρεση ακόλουθων που βρίσκονται στους επιλεγμένους κόμβους\n    remove_selected_followers: Αφαίρεση επιλεγμένων ακόλουθων\n    remove_selected_follows: Διακοπή παρακολούθησης επιλεγμένων χρηστών\n    status: Κατάσταση λογαριασμού\n  remote_follow:\n    acct: Γράψε το ΌνομαΧρήστη@τομέα από όπου θέλεις να εκτελέσεις την ενέργεια αυτή\n    missing_resource: Δεν βρέθηκε το απαιτούμενο URL ανακατεύθυνσης για το λογαριασμό σου\n    no_account_html: Δεν έχεις λογαριασμό; Μπορείς <a href='%{sign_up_path}' target='_blank'>να γραφτείς εδώ</a>\n    proceed: Συνέχισε για να ακολουθήσεις\n    prompt: 'Ετοιμάζεσαι να ακολουθήσεις:'\n    reason_html: \"<strong>Γιατί χρειάζεται αυτό το βήμα;</strong> Το <code>%{instance}</code> μπορεί να μην είναι ο κόμβος που έχεις γραφτεί, έτσι πρέπει να σε ανακατευθύνουμε στο δικό σου.\"\n  remote_interaction:\n    favourite:\n      proceed: Συνέχισε για σημείωση ως αγαπημένου\n      prompt: 'Θέλεις να σημειώσεις ως αγαπημένο αυτό το τουτ:'\n    reblog:\n      proceed: Συνέχισε για προώθηση\n      prompt: 'Θέλεις να προωθήσεις αυτό το τουτ:'\n    reply:\n      proceed: Συνέχισε για να απαντήσεις\n      prompt: 'Θέλεις να απαντήσεις σε αυτό το τουτ:'\n  remote_unfollow:\n    error: Σφάλμα\n    title: Τίτλος\n    unfollowed: Σταμάτησες να ακολουθείς\n  scheduled_statuses:\n    over_daily_limit: Έχεις υπερβεί το όριο των %{limit} προγραμματισμένων τουτ για εκείνη τη μέρα\n    over_total_limit: Έχεις υπερβεί το όριο των %{limit} προγραμματισμένων τουτ\n    too_soon: Η προγραμματισμένη ημερομηνία πρέπει να είναι στο μέλλον\n  sessions:\n    activity: Τελευταία δραστηριότητα\n    browser: Φυλλομετρητής (Browser)\n    browsers:\n      alipay: Alipay\n      blackberry: Blackberry\n      chrome: Chrome\n      edge: Microsoft Edge\n      electron: Electron\n      firefox: Firefox\n      generic: Άγνωστος φυλλομετρητής\n      ie: Internet Explorer\n      micro_messenger: MicroMessenger\n      nokia: Nokia S40 Ovi Browser\n      opera: Opera\n      otter: Otter\n      phantom_js: PhantomJS\n      qq: QQ Browser\n      safari: Safari\n      uc_browser: UCBrowser\n      weibo: Weibo\n    current_session: Τρέχουσα σύνδεση\n    description: \"%{browser} σε %{platform}\"\n    explanation: Αυτοί είναι οι φυλλομετρητές (browsers) που είναι συνδεδεμένοι στον λογαριασμό σου στο Mastodon αυτή τη στιγμή.\n    ip: IP\n    platforms:\n      adobe_air: Adobe Air\n      android: Android\n      blackberry: Blackberry\n      chrome_os: ChromeOS\n      firefox_os: Firefox OS\n      ios: iOS\n      linux: Linux\n      mac: Mac\n      other: άγνωστη πλατφόρμα\n      windows: Windows\n      windows_mobile: Windows Mobile\n      windows_phone: Windows Phone\n    revoke: Ανακάλεσε\n    revoke_success: Η σύνδεση ανακλήθηκε επιτυχώς\n    title: Σύνδεση\n  settings:\n    account: Λογαριασμός\n    account_settings: Ρυθμίσεις λογαριασμού\n    appearance: Εμφάνιση\n    authorized_apps: Εγκεκριμένες εφαρμογές\n    back: Πίσω στο Mastodon\n    delete: Διαγραφή λογαριασμού\n    development: Ανάπτυξη\n    edit_profile: Επεξεργασία προφίλ\n    export: Εξαγωγή δεδομένων\n    featured_tags: Χαρακτηριστικές ταμπέλες\n    identity_proofs: Αποδείξεις ταυτοτήτων\n    import: Εισαγωγή\n    import_and_export: Εισαγωγή & Εξαγωγή\n    migrate: Μετακόμιση λογαριασμού\n    notifications: Ειδοποιήσεις\n    preferences: Προτιμήσεις\n    profile: Προφίλ\n    relationships: Ακολουθεί και ακολουθείται\n    two_factor_authentication: Πιστοποίηση 2 παραγόντων (2FA)\n  statuses:\n    attached:\n      description: 'Συνημμένα: %{attached}'\n      image:\n        one: \"%{count} εικόνα\"\n        other: \"%{count} εικόνες\"\n      video:\n        one: \"%{count} βίντεο\"\n        other: \"%{count} βίντεο\"\n    boosted_from_html: Προωθήθηκε από %{acct_link}\n    content_warning: 'Προειδοποίηση περιεχομένου: %{warning}'\n    disallowed_hashtags:\n      one: 'περιέχει μη επιτρεπτή ταμπέλα: %{tags}'\n      other: 'περιέχει μη επιτρεπτές ταμπέλες: %{tags}'\n    language_detection: Αυτόματη αναγνώριση γλώσσας\n    open_in_web: Δες στο διαδίκτυο\n    over_character_limit: υπέρβαση μέγιστου ορίου %{max} χαρακτήρων\n    pin_errors:\n      limit: Έχεις ήδη καρφιτσώσει το μέγιστο αριθμό επιτρεπτών τουτ\n      ownership: Δεν μπορείς να καρφιτσώσεις μη δικό σου τουτ\n      private: Τα μη δημόσια τουτ δεν καρφιτσώνονται\n      reblog: Οι προωθήσεις δεν καρφιτσώνονται\n    poll:\n      total_votes:\n        one: \"%{count} ψήφος\"\n        other: \"%{count} ψήφοι\"\n      vote: Ψήφισε\n    show_more: Δείξε περισσότερα\n    sign_in_to_participate: Εγγράφου για να συμμετάσχεις στη συζήτηση\n    title: '%{name}: \"%{quote}\"'\n    visibilities:\n      private: Μόνο ακόλουθοι\n      private_long: Εμφάνιση μόνο σε ακόλουθους\n      public: Δημόσιο\n      public_long: Βλέπει οποιοσδήποτε\n      unlisted: Μη καταχωρημένο\n      unlisted_long: Βλέπει οποιοσδήποτε, αλλά δεν καταχωρείται στις δημόσιες ροές\n  stream_entries:\n    pinned: Καρφιτσωμένο τουτ\n    reblogged: προωθημένο\n    sensitive_content: Ευαίσθητο περιεχόμενο\n  terms:\n    body_html: |\n      <h2>Πολιτική Απορρήτου</h2>\n      <h3 id=\"collect\">Ποιες πληροφορίες συλλέγουμε;</h3>\n\n      <ul>\n      <li><em>Βασικά στοιχεία λογαριασμού</em>: Όταν εγγραφείς σε αυτό τον διακομιστή, μπορεί να σου ζητηθεί όνομα χρήστη, διεύθυνση email και ένας κωδικός. Μπορεί επίσης να εισάγεις επιπλέον πληροφορίες λογαριασμού όπως ένα όνομα λογαριασμού και σύντομο βιογραφικό και να ανεβάσεις εικόνα προφίλ και επικεφαλίδας. Το όνομα χρήστη, το όνομα λογαριασμού, το βιογραφικό και οι εικόνες προφίλ και επικεφαλίδας είναι πάντα δημόσια εμφανείς.</li>\n      <li><em>Δημοσιεύσεις, ακόλουθοι και λοιπά δημόσια στοιχεία</em>: Η λίστα των ανθρώπων που ακολουθείς εμφανίζεται δημόσια, το ίδιο και οι ακόλουθοί σου. Όταν υποβάλλεις ένα μήνυμα, η ημερομηνία και ώρα αποθηκεύονται καθώς και η εφαρμογή που χρησιμοποίησες για την υποβολή του. Τα μηνύματα μπορεί να περιέχουν συνημμένα πολυμέσα όπως εικόνες και βίντεο. Τα δημόσια και τα μη καταχωρημένα μηνύματα είναι δημόσια διαθέσιμα. Όταν προβάλεις μια δημοσίευση στο προφίλ σου, είναι και αυτό δημόσια διαθέσιμο. Οι δημοσιεύσεις σου παραδίδονται στους ακολούθους σου, σε κάποιες περιπτώσεις αυτό σημαίνει ότι παραδίδονται σε διαφορετικούς διακομιστές (servers) και αντίγραφά τους αποθηκεύονται σε αυτούς. Παρομοίως, όταν διαγράψεις δημοσιεύσεις, αυτό μεταφέρεται στους ακόλουθους σου. Η αναδημοσίευση και η σημείωση ως αγαπημένης μιας δημοσίευσης είναι πάντα δημόσια.</li>\n      <li><em>Προσωπικές δημοσιεύσεις και προς ακόλουθους</em>: Όλες οι δημοσιεύσεις αποθηκεύονται και επεξεργάζονται στον διακομιστή. Οι δημοσιεύσεις προς τους ακόλουθους παραδίδονται στους ακόλουθους σου και σε όσους χρήστες αναφέρονται σε αυτές. Σε κάποιες περιπτώσεις αυτό σημαίνει πως παραδίδονται σε διαφορετικούς διακομιστές και αντίγραφά τους αποθηκεύονται σε αυτούς. Καταβάλουμε ειλικρινή προσπάθεια περιορισμού πρόσβασης σε αυτές τις δημοσιεύσεις μόνο σε εγκεκριμένα άτομα, όμως διαφορετικοί διακομιστές μπορεί να μην το πετυχαίνουν αυτό. Για αυτό, είναι σημαντικό να ελέγχεις τους διακομιστές στους οποίους ανήκουν οι ακόλουθοί σου. Μπορείς να ενεργοποιήσεις την επιλογή χειροκίνητης αποδοχής ή απόρριψης των νέων ακόλουθών σου στις ρυθμίσεις. <em>Παρακαλούμε έχε υπόψιν σου πως οι διαχειριστές του διακομιστή και των αποδεκτών διακομιστών πιθανόν να κοιτάνε αυτά τα μηνύματα</em>, και πως οι τελικοί αποδέκτες μπορούν να αποθηκεύσουν την οθόνη, το μήνυμα ή να το αναμεταδώσουν με άλλους τρόπους. <em>Μην μοιράζεσαι επικύνδυνες πληροφορίες μέσω του Mastodon.</em></li>\n      <li><em>Διευθύνσεις IP και άλλα metadata</em>: Όταν συνδέεσαι, καταγράφουμε την διεύθυνση IP σου, καθώς και το όνομα της εφαρμογής του φυλλομετρητή σου (browser). Όλες οι τρέχουσες συνδέσεις στον λογαριασμό σου είναι διαθέσιμες προς ανασκόπηση στις ρυθμίσεις. Η πιο πρόσφατη διεύθυνση IP αποθηκεύεται για μέχρι 12 μήνες. Επίσης μπορεί να διατηρήσουμε ιστορικό του διακομιστή (log files) που να περιέχει την διεύθυνση ΙΡ κάθε κλήσης προς τον διακομιστή μας.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"use\">Πως χρησιμοποιούμε τις πληροφορίες σου;</h3>\n\n      <p>Οι πληροφορίες σου που συλλέγουμε μπορεί να χρησιμοποιηθούν με τους ακόλουθους τρόπους:</p>\n\n      <ul>\n      <li>Για να παρέχουμε την βασική λειτουργικότητα του Mastodon. Μπορείς να αλληλεπιδράσεις με τις δημοσιεύσεις άλλων και να κάνεις τις δικές σου μόνο αφού συνδεθείς. Για παράδειγμα, μπορείς να ακολουθήσεις άλλους χρήστες για να βλέπεις τις συνολικές δημοσιεύσεις τους στη δική σου, προσωπική αρχική ροή.</li>\n      <li>Για να διευκολύνουμε τη διαχείριση της κοινότητας, για παράδειγμα συγκρίνοντας τη δική σου διεύθυνση IP με άλλες γνωστές διευθύνσεις για να καθορίσουμε περιπτώσεις αποφυγής αποκλεισμού ή άλλων παραβάσεων.</li>\n      <li>Η διεύθυνση email που δίνεις μπορεί να χρησιμοποιηθεί για να σου στείλουμε πληροφορίες, ειδοποιήσεις για αλληλεπιδράσεις άλλων χρηστών με τις δημοσιεύσεις σου και να ανταποκριθούμε σε ερωτήματά σου.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"protect\">Πως προστατεύουμε τις πληροφορίες σου;</h3>\n\n      <p>Εφαρμόζουμε μια σειρά μεθόδων ασφαλείας για να διασφαλίσουμε τις προσωπικές πληροφορίες που εισάγεις, καταθέτεις ή κοιτάζεις. Μεταξύ άλλων, η σύνδεση του φυλλομετρητή σου καθώς και οι ανταλασσόμενες πληροφορίες μεταξύ των εφαρμογών σου και του API είναι κρυπτογραφημένες μέσω SSL και το συνθηματικό σου κωδικοποιείται με ισχυρό, μη αντιστρέψιμο αλγόριθμο. Μπορείς να ενεργοποιήσεις την ταυτοπόίηση 2 παραγόντων (2FA) για επιπλέον ασφαλή πρόσβαση στο λογαριασμό σου.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"data-retention\">Ποια είναι η πολιτική διατήρησης πληροφοριών μας;</h3>\n\n      <p>Καταβάλουμε κάθε δυνατή προσπάθεια να:</p>\n\n      <ul>\n      <li>Διατηρήσουμε αρχεία ενεργειών των διακομιστών (servers) για όλα τα αιτήματα σε αυτόν τον διακομιστή, και αυτά τα αρχεία διατηρούνται για μέγιστο χρόνο 90 ημερών.</li>\n      <li>Διατηρήσουμε τις διευθύνσεις IP που σχετίζονται με εγγεγραμμένους χρήστες για μέγιστο χρόνο 12 μηνών.</li>\n      </ul>\n\n      <p>Μπορείς να αιτηθείς και να αποθηκεύσεις τοπικά ένα αρχείο του περιεχομένου σου που περιλαμβάνει τις δημοσιεύσεις, τα συνημμένα πολυμέσα, την εικόνα προφίλ και την εικόνα επικεφαλίδας.</p>\n\n      <p>Μπορείς ανά πάσα στιγμή να διαγράψεις οριστικά και αμετάκλητα το λογαριασμό σου.</p>\n\n      <hr class=\"spacer\"/>\n\n      <h3 id=\"cookies\">Χρησιμοποιούμε cookies;</h3>\n\n      <p>Ναι. Τα cookies είναι μικρά αρχεία που ένας ιστοτοπος (site) ή πάροχος υπηρεσίας μεταφέρει στον σκληρό δίσκο του υπολογιστή μέσω του φυλλομετρητή (αν το επιτρέψεις). Τα cookies αυτά επιτρέπουν στον ιστότοπο να αναγνωρίζει τον φυλλομετρητή σου και, αν έχεις λογαριασμό, να τον συνδέσει με αυτόν.</p>\n\n      <p>Χρησιμοποιούμε τα cookies για να αναγνωρίσουμε και αποθηκεύσουμε τις προτιμήσεις σου για τις μελλοντικές σου επισκέψεις.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"disclose\">Αποκαλύπτουμε πληροφορίες σε τρίτους;</h3>\n\n      <p>Δεν πουλάμε, ανταλλάσσουμε ή με άλλο τρόπο μεταφέρουμε σε τρίτα μέρη πληροφορίες που σε προσωποποιούν. Αυτό δεν περιλαμβάνει αξιόπιστα τρίτα μέρη που μας βοηθούν να λειτουργούμε τον ιστότοπό μας, να διεξάγουμε τις εργασίες μας ή να σε εξυπηρετούμε, στο βαθμό που αυτά τα τρίτα μέρη συμφωνούν να διατηρούν αυτές τις πληροφορίες εμπιστευτικές. Επίσης μπορεί να μοιραστούμε τις πληροφορίες σου όταν θεωρήσουμε πως αυτό είναι σύμφωνο με τον νόμο, με την πολιτική του ιστότοπου μας ή διαφυλάσσει τα δικά μας δικαιώματα ή τρίτων, την ιδιοκτησία ή την ασφάλεια.</p>\n\n      <p>Το δημόσιο περιεχόμενο σου μπορεί να αποθηκευτεί από άλλους διακομιστές (servers) στο δίκτυο. Οι δημόσιες και οι προς ακόλουθους δημοσιεύσεις σου παραδίδονται στους διακομιστές των ακολούθων σου και τα προσωπικά μηνύματα στους διακομιστές των παραληπτών, όταν αυτοί βρίσκονται σε διαφορετικό διακομιστή.</p>\n\n      <p>Όταν επιτρέψεις σε μια εφαρμογή να χρησιμοποιήσει τον λογαριασμό σου, ανάλογα με το εύρος των δικαιωμάτων που εγκρίνεις, μπορεί να έχει πρόσβαση στις πληροφορίες του δημόσιου προφιλ σου, στη λίστα των ακολούθων σου, στους ακόλουθούς σου, στις λίστες σου, σε όλες τις δημοσιεύσεις σου και στα αγαπημένα σου. Οι εφαρμογές ποτέ δεν έχουν πρόσβαση στις διευθύνσεις email και στα συνθηματικά σου.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"children\">Χρήση από παιδιά</h3>\n\n      <p>Αν αυτός ο διακομιστής βρίσκεται στην ΕΕ (Ευρωπαϊκή Ένωση) ή στον ΕΟΧ (Ευρωπαϊκός Οικονομικός Χώρος): Ο ιστότοπός μας, τα προϊόντα και οι υπηρεσίες μας απευθύνονται σε άτομα ηλικίας άνω των 16. Αν είσαι κάτω των 16, σύμφωνα με τις απαιτήσεις του Γενικού Κανονισμού Προστασίας Δεδομένων \"GDPR\" (<a href=\"https://en.wikipedia.org/wiki/General_Data_Protection_Regulation\">General Data Protection Regulation</a>) μην χρησιμοποιήσεις αυτόν τον ιστότοπο.</p>\n\n      <p>Αν αυτός ο διακομιστής βρίσκεται στις ΗΠΑ: Ο ιστότοπός μας, τα προϊόντα και οι υπηρεσίες μας απευθύνονται σε άτομα ηλικίας τουλάχιστον 13 ετών. Αν είσαι κάτω των 13, σύμφωνα με τις απαιτήσεις του COPPA (<a href=\"https://en.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act\">Children's Online Privacy Protection Act</a>) μην χρησιμοποιήσεις αυτόν τον ιστότοπο.</p>\n\n      <p>Οι νομικές απαιτήσεις μπορεί να είναι διαφορετικές αν ο διακομιστής αυτός βρίσκεται σε άλλη δικαιοδοσία.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"changes\">Αλλαγές στην πολιτική απορρήτου μας</h3>\n\n      <p>Αν αποφασίσουμε να κάνουμε αλλαγές στην πολιτική απορρήτου μας, θα τις δηλώσουμε σε αυτήν εδώ τη σελίδα.</p>\n\n      <p>Η άδεια χρήσης αυτού του κειμένου είναι κατάCC-BY-SA. Ενημερώθηκε τελευταία φορά στις 7 Μαρτίου, 2018.</p>\n\n      <p>Οι παραπάνω όροι έχουν προσαρμοστεί από τους αντίστοιχους όρους του <a href=\"https://github.com/discourse/discourse\">Discourse</a>.</p>\n    title: Όροι Χρήσης και Πολιτική Απορρήτου του κόμβου %{instance}\n  themes:\n    contrast: Mastodon (Υψηλή αντίθεση)\n    default: Mastodon (Σκοτεινό)\n    mastodon-light: Mastodon (Ανοιχτόχρωμο)\n  time:\n    formats:\n      default: \"%b %d, %Y, %H:%M\"\n      month: \"%b %Y\"\n  two_factor_authentication:\n    code_hint: Βάλε τον κωδικό που δημιούργησε η εφαρμογή πιστοποίησής σου για επιβεβαίωση\n    description_html: Αν ενεργοποιήσεις την <strong>πιστοποίηση 2 παραγόντων (2FA)</strong>, για να συνδεθείς θα πρέπει να έχεις το τηλέφωνό σου, που θα σου δημιουργήσει κλειδιά εισόδου.\n    disable: Απενεργοποίησε\n    enable: Ενεργοποίησε\n    enabled: Η πιστοποίηση 2 παραγόντων (2FA) είναι ενεργοποιημένη\n    enabled_success: Η πιστοποίηση 2 παραγόντων (2FA) ενεργοποιήθηκε επιτυχώς\n    generate_recovery_codes: Δημιούργησε κωδικούς ανάκτησης\n    instructions_html: \"<strong>Σάρωσε αυτόν τον κωδικό QR με την εφαρμογή Google Authenticator ή κάποια άλλη αντίστοιχη στο τηλέφωνό σου</strong>. Από εδώ και στο εξής, η εφαρμογή αυτή θα δημιουργεί κλειδιά που θα πρέπει να εισάγεις όταν συνδέεσαι.\"\n    lost_recovery_codes: Οι κωδικοί ανάκτησης σου επιτρέπουν να ανακτήσεις ξανά πρόσβαση στον λογαριασμό σου αν χάσεις το τηλέφωνό σου. Αν έχεις χάσει τους κωδικούς ανάκτησης, μπορείς να τους δημιουργήσεις ξανά εδώ. Οι παλιοί κωδικοί σου θα ακυρωθούν.\n    manual_instructions: 'Αν δεν μπορείς να σαρώσεις τον κωδικό QR και χρειάζεσαι να τον εισάγεις χειροκίνητα, ορίστε η μυστική φράση σε μορφή κειμένου:'\n    recovery_codes: Εφεδρικοί κωδικοί ανάκτησης\n    recovery_codes_regenerated: Οι εφεδρικοί κωδικοί ανάκτησης δημιουργήθηκαν επιτυχώς\n    recovery_instructions_html: Αν ποτέ δεν έχεις πρόσβαση στο κινητό σου, μπορείς να χρησιμοποιήσεις έναν από τους παρακάτω κωδικούς ανάκτησης για να αποκτήσεις πρόσβαση στο λογαριασμό σου. <strong>Διαφύλαξε τους κωδικούς ανάκτησης</strong>. Για παράδειγμα, μπορείς να τους εκτυπώσεις και να τους φυλάξεις μαζί με άλλα σημαντικά σου έγγραφα.\n    setup: Στήσιμο\n    wrong_code: Ο κωδικός που έβαλες ήταν άκυρος! Τα ρολόγια στον διακομιστή και τη συσκευή είναι σωστά;\n  user_mailer:\n    backup_ready:\n      explanation: Ζήτησες ένα εφεδρικό αντίγραφο του λογαριασμού σου στο Mastodon. Είναι έτοιμο για κατέβασμα!\n      subject: Το εφεδρικό αντίγραφό σου είναι έτοιμο για κατέβασμα\n      title: Λήψη εφεδρικού αρχείου\n    warning:\n      explanation:\n        disable: Όσο ο λογαριασμός σου είναι παγωμένος, τα στοιχεία του παραμένουν άθικτα αλλά δεν μπορείς να κανείς καμία ενέργεια μέχρι να ξεκλειδωθείς.\n        silence: Όσο ο λογαριασμός σου είναι περιορισμένος, μόνο όσοι σε ακολουθούν ήδη θα βλέπουν τα τουτ σου σε αυτό τον κόμβο ενώ μπορεί να εξαιρεθείς από διάφορες δημόσιες απαριθμήσεις. Πάντως, θα μπορούν να σε ακολουθήσουν χειροκίνητα.\n        suspend: Ο λογαριασμός σου αναστάλθηκε μόνιμα, όλα τα τουτ και τα ανεβασμένα πολυμέσα σου διαγράφηκαν αμετάκλητα από αυτόν τον κόμβο και σε όσους άλλους είχες ακόλουθους.\n      review_server_policies: Αναθεώρηση πολιτικής του κόμβου\n      subject:\n        disable: Ο λογαριασμός σου %{acct} έχει παγώσει\n        none: Προειδοποίηση προς %{acct}\n        silence: Ο λογαριασμός σου %{acct} έχει περιοριστεί\n        suspend: Ο λογαριασμός σου %{acct} έχει ανασταλεί\n      title:\n        disable: Παγωμένος λογαριασμός\n        none: Προειδοποίηση\n        silence: Περιορισμένος λογαριασμός\n        suspend: Ανασταλμένος λογαριασμός\n    welcome:\n      edit_profile_action: Στήσιμο προφίλ\n      edit_profile_step: Μπορείς να προσαρμόσεις το προφίλ σου ανεβάζοντας μια εικόνα εμφάνισης & επικεφαλίδας, αλλάζοντας το εμφανιζόμενο όνομά σου και άλλα. Αν θες να ελέγχεις τους νέου σου ακόλουθους πριν αυτοί σε ακολουθήσουν, μπορείς να κλειδώσεις το λογαριασμό σου.\n      explanation: Μερικές συμβουλές για να ξεκινήσεις\n      final_action: Ξεκίνα τις δημοσιεύσεις\n      final_step: 'Ξεκίνα τις δημοσιεύσεις! Ακόμα και χωρίς ακόλουθους τα δημόσια μηνύματά σου μπορεί να τα δουν άλλοι, για παράδειγμα στην τοπική ροή και στις ετικέτες. Ίσως να θέλεις να κάνεις μια εισαγωγή του εαυτού σου με την ετικέτα #introductions.'\n      full_handle: Το πλήρες όνομά σου\n      full_handle_hint: Αυτό θα εδώ θα πεις στους φίλους σου για να σου μιλήσουν ή να σε ακολουθήσουν από άλλο κόμβο.\n      review_preferences_action: Αλλαγή προτιμήσεων\n      review_preferences_step: Σιγουρέψου πως έχεις ορίσει τις προτιμήσεις σου, όπως το ποια email θέλεις να λαμβάνεις, ή ποιο επίπεδο ιδιωτικότητας θέλεις να έχουν οι δημοσιεύσεις σου. Αν δεν σε πιάνει ναυτία, μπορείς να ενεργοποιήσεις την αυτόματη αναπαραγωγή των GIF.\n      subject: Καλώς ήρθες στο Mastodon\n      tip_federated_timeline: Η ομοσπονδιακή ροή είναι μια όψη πραγματικού χρόνου στο δίκτυο του Mastodon. Παρόλα αυτά, περιλαμβάνει μόνο όσους ακολουθούν οι γείτονές σου, άρα δεν είναι πλήρης.\n      tip_following: Ακολουθείς το διαχειριστή του διακομιστή σου αυτόματα. Για να βρεις περισσότερους ενδιαφέροντες ανθρώπους, έλεγξε την τοπική και την ομοσπονδιακή ροή.\n      tip_local_timeline: Η τοπική ροή είναι η όψη πραγματικού χρόνου των ανθρώπων στον κόμβο %{instance}. Αυτοί είναι οι άμεσοι γείτονές σου!\n      tip_mobile_webapp: Αν ο φυλλομετρητής (browser) στο κινητό σού σου επιτρέπει να προσθέσεις το Mastodon στην αρχική οθόνη της συσκευής, θα λαμβάνεις και ειδοποιήσεις μέσω push. Σε πολλά πράγματα λειτουργεί σαν κανονική εφαρμογή!\n      tips: Συμβουλές\n      title: Καλώς όρισες, %{name}!\n  users:\n    follow_limit_reached: Δεν μπορείς να ακολουθήσεις περισσότερα από %{limit} άτομα\n    invalid_email: Η διεύθυνση email είναι άκυρη\n    invalid_otp_token: Άκυρος κωδικός πιστοποίησης 2 παραγόντων (2FA)\n    otp_lost_help_html: Αν χάσεις και τα δύο, μπορείς να επικοινωνήσεις με τον/την %{email}\n    seamless_external_login: Επειδή έχεις συνδεθεί μέσω τρίτης υπηρεσίας, οι ρυθμίσεις συνθηματικού και email δεν είναι διαθέσιμες.\n    signed_in_as: 'Έχεις συνδεθεί ως:'\n  verification:\n    explanation_html: 'Μπορείς να <strong>πιστοποιήσεις τον εαυτό σου ως ιδιοκτήτη των συνδέσμων που εμφανίζεις στα μεταδεδομένα του προφίλ σου</strong>. Για να συμβεί αυτό, ο συνδεδεμένος ιστότοπος πρέπει να περιέχει ένα σύνδεσμο που να επιστρέφει προς το προφίλ σου στο Mastodon. Ο σύνδεσμος επιστροφής <strong>πρέπει</strong> περιέχει την ιδιότητα (attribute) <code>rel=\"me\"</code>. Το περιεχόμενο του κειμένου δεν έχει σημασία. Για παράδειγμα:'\n    verification: Πιστοποίηση\n"
  },
  {
    "path": "config/locales/en.yml",
    "content": "---\nen:\n  about:\n    about_hashtag_html: These are public toots tagged with <strong>#%{hashtag}</strong>. You can interact with them if you have an account anywhere in the fediverse.\n    about_mastodon_html: Mastodon is a social network based on open web protocols and free, open-source software. It is decentralized like e-mail.\n    about_this: About\n    active_count_after: active\n    active_footnote: Monthly Active Users (MAU)\n    administered_by: 'Administered by:'\n    api: API\n    apps: Mobile apps\n    apps_platforms: Use Mastodon from iOS, Android and other platforms\n    browse_directory: Browse a profile directory and filter by interests\n    browse_public_posts: Browse a live stream of public posts on Mastodon\n    contact: Contact\n    contact_missing: Not set\n    contact_unavailable: N/A\n    discover_users: Discover users\n    documentation: Documentation\n    extended_description_html: |\n      <h3>A good place for rules</h3>\n      <p>The extended description has not been set up yet.</p>\n    federation_hint_html: With an account on %{instance} you'll be able to follow people on any Mastodon server and beyond.\n    generic_description: \"%{domain} is one server in the network\"\n    get_apps: Try a mobile app\n    hosted_on: Mastodon hosted on %{domain}\n    learn_more: Learn more\n    privacy_policy: Privacy policy\n    see_whats_happening: See what's happening\n    server_stats: 'Server stats:'\n    source_code: Source code\n    status_count_after:\n      one: status\n      other: statuses\n    status_count_before: Who authored\n    tagline: Follow friends and discover new ones\n    terms: Terms of service\n    user_count_after:\n      one: user\n      other: users\n    user_count_before: Home to\n    what_is_mastodon: What is Mastodon?\n  accounts:\n    choices_html: \"%{name}'s choices:\"\n    follow: Follow\n    followers:\n      one: Follower\n      other: Followers\n    following: Following\n    joined: Joined %{date}\n    last_active: last active\n    link_verified_on: Ownership of this link was checked on %{date}\n    media: Media\n    moved_html: \"%{name} has moved to %{new_profile_link}:\"\n    network_hidden: This information is not available\n    nothing_here: There is nothing here!\n    people_followed_by: People whom %{name} follows\n    people_who_follow: People who follow %{name}\n    pin_errors:\n      following: You must be already following the person you want to endorse\n    posts:\n      one: Toot\n      other: Toots\n    posts_tab_heading: Toots\n    posts_with_replies: Toots and replies\n    reserved_username: The username is reserved\n    roles:\n      admin: Admin\n      bot: Bot\n      moderator: Mod\n    unavailable: Profile unavailable\n    unfollow: Unfollow\n  admin:\n    account_actions:\n      action: Perform action\n      title: Perform moderation action on %{acct}\n    account_moderation_notes:\n      create: Leave note\n      created_msg: Moderation note successfully created!\n      delete: Delete\n      destroyed_msg: Moderation note successfully destroyed!\n    accounts:\n      approve: Approve\n      approve_all: Approve all\n      are_you_sure: Are you sure?\n      avatar: Avatar\n      by_domain: Domain\n      change_email:\n        changed_msg: Account email successfully changed!\n        current_email: Current email\n        label: Change email\n        new_email: New email\n        submit: Change email\n        title: Change email for %{username}\n      confirm: Confirm\n      confirmed: Confirmed\n      confirming: Confirming\n      deleted: Deleted\n      demote: Demote\n      disable: Disable\n      disable_two_factor_authentication: Disable 2FA\n      disabled: Disabled\n      display_name: Display name\n      domain: Domain\n      edit: Edit\n      email: Email\n      email_status: Email status\n      enable: Enable\n      enabled: Enabled\n      feed_url: Feed URL\n      followers: Followers\n      followers_url: Followers URL\n      follows: Follows\n      header: Header\n      inbox_url: Inbox URL\n      invited_by: Invited by\n      ip: IP\n      joined: Joined\n      location:\n        all: All\n        local: Local\n        remote: Remote\n        title: Location\n      login_status: Login status\n      media_attachments: Media attachments\n      memorialize: Turn into memoriam\n      moderation:\n        active: Active\n        all: All\n        pending: Pending\n        silenced: Silenced\n        suspended: Suspended\n        title: Moderation\n      moderation_notes: Moderation notes\n      most_recent_activity: Most recent activity\n      most_recent_ip: Most recent IP\n      no_account_selected: No accounts were changed as none were selected\n      no_limits_imposed: No limits imposed\n      not_subscribed: Not subscribed\n      outbox_url: Outbox URL\n      pending: Pending review\n      perform_full_suspension: Suspend\n      profile_url: Profile URL\n      promote: Promote\n      protocol: Protocol\n      public: Public\n      push_subscription_expires: PuSH subscription expires\n      redownload: Refresh profile\n      reject: Reject\n      reject_all: Reject all\n      remove_avatar: Remove avatar\n      remove_header: Remove header\n      resend_confirmation:\n        already_confirmed: This user is already confirmed\n        send: Resend confirmation email\n        success: Confirmation email successfully sent!\n      reset: Reset\n      reset_password: Reset password\n      resubscribe: Resubscribe\n      role: Permissions\n      roles:\n        admin: Administrator\n        moderator: Moderator\n        staff: Staff\n        user: User\n      salmon_url: Salmon URL\n      search: Search\n      shared_inbox_url: Shared inbox URL\n      show:\n        created_reports: Made reports\n        targeted_reports: Reported by others\n      silence: Silence\n      silenced: Silenced\n      statuses: Statuses\n      subscribe: Subscribe\n      suspended: Suspended\n      time_in_queue: Waiting in queue %{time}\n      title: Accounts\n      unconfirmed_email: Unconfirmed email\n      undo_silenced: Undo silence\n      undo_suspension: Undo suspension\n      unsubscribe: Unsubscribe\n      username: Username\n      warn: Warn\n      web: Web\n    action_logs:\n      actions:\n        assigned_to_self_report: \"%{name} assigned report %{target} to themselves\"\n        change_email_user: \"%{name} changed the e-mail address of user %{target}\"\n        confirm_user: \"%{name} confirmed e-mail address of user %{target}\"\n        create_account_warning: \"%{name} sent a warning to %{target}\"\n        create_custom_emoji: \"%{name} uploaded new emoji %{target}\"\n        create_domain_block: \"%{name} blocked domain %{target}\"\n        create_email_domain_block: \"%{name} blacklisted e-mail domain %{target}\"\n        demote_user: \"%{name} demoted user %{target}\"\n        destroy_custom_emoji: \"%{name} destroyed emoji %{target}\"\n        destroy_domain_block: \"%{name} unblocked domain %{target}\"\n        destroy_email_domain_block: \"%{name} whitelisted e-mail domain %{target}\"\n        destroy_status: \"%{name} removed status by %{target}\"\n        disable_2fa_user: \"%{name} disabled two factor requirement for user %{target}\"\n        disable_custom_emoji: \"%{name} disabled emoji %{target}\"\n        disable_user: \"%{name} disabled login for user %{target}\"\n        enable_custom_emoji: \"%{name} enabled emoji %{target}\"\n        enable_user: \"%{name} enabled login for user %{target}\"\n        memorialize_account: \"%{name} turned %{target}'s account into a memoriam page\"\n        promote_user: \"%{name} promoted user %{target}\"\n        remove_avatar_user: \"%{name} removed %{target}'s avatar\"\n        reopen_report: \"%{name} reopened report %{target}\"\n        reset_password_user: \"%{name} reset password of user %{target}\"\n        resolve_report: \"%{name} resolved report %{target}\"\n        silence_account: \"%{name} silenced %{target}'s account\"\n        suspend_account: \"%{name} suspended %{target}'s account\"\n        unassigned_report: \"%{name} unassigned report %{target}\"\n        unsilence_account: \"%{name} unsilenced %{target}'s account\"\n        unsuspend_account: \"%{name} unsuspended %{target}'s account\"\n        update_custom_emoji: \"%{name} updated emoji %{target}\"\n        update_status: \"%{name} updated status by %{target}\"\n      deleted_status: \"(deleted status)\"\n      title: Audit log\n    custom_emojis:\n      by_domain: Domain\n      copied_msg: Successfully created local copy of the emoji\n      copy: Copy\n      copy_failed_msg: Could not make a local copy of that emoji\n      created_msg: Emoji successfully created!\n      delete: Delete\n      destroyed_msg: Emojo successfully destroyed!\n      disable: Disable\n      disabled_msg: Successfully disabled that emoji\n      emoji: Emoji\n      enable: Enable\n      enabled_msg: Successfully enabled that emoji\n      image_hint: PNG up to 50KB\n      listed: Listed\n      new:\n        title: Add new custom emoji\n      overwrite: Overwrite\n      shortcode: Shortcode\n      shortcode_hint: At least 2 characters, only alphanumeric characters and underscores\n      title: Custom emojis\n      unlisted: Unlisted\n      update_failed_msg: Could not update that emoji\n      updated_msg: Emoji successfully updated!\n      upload: Upload\n    dashboard:\n      backlog: backlogged jobs\n      config: Configuration\n      feature_deletions: Account deletions\n      feature_invites: Invite links\n      feature_profile_directory: Profile directory\n      feature_registrations: Registrations\n      feature_relay: Federation relay\n      feature_timeline_preview: Timeline preview\n      features: Features\n      hidden_service: Federation with hidden services\n      open_reports: open reports\n      recent_users: Recent users\n      search: Full-text search\n      single_user_mode: Single user mode\n      software: Software\n      space: Space usage\n      title: Dashboard\n      total_users: users in total\n      trends: Trends\n      week_interactions: interactions this week\n      week_users_active: active this week\n      week_users_new: users this week\n    domain_blocks:\n      add_new: Add new domain block\n      created_msg: Domain block is now being processed\n      destroyed_msg: Domain block has been undone\n      domain: Domain\n      existing_domain_block_html: You have already imposed stricter limits on %{name}, you need to <a href=\"%{unblock_url}\">unblock it</a> first.\n      new:\n        create: Create block\n        hint: The domain block will not prevent creation of account entries in the database, but will retroactively and automatically apply specific moderation methods on those accounts.\n        severity:\n          desc_html: \"<strong>Silence</strong> will make the account's posts invisible to anyone who isn't following them. <strong>Suspend</strong> will remove all of the account's content, media, and profile data. Use <strong>None</strong> if you just want to reject media files.\"\n          noop: None\n          silence: Silence\n          suspend: Suspend\n        title: New domain block\n      reject_media: Reject media files\n      reject_media_hint: Removes locally stored media files and refuses to download any in the future. Irrelevant for suspensions\n      reject_reports: Reject reports\n      reject_reports_hint: Ignore all reports coming from this domain. Irrelevant for suspensions\n      rejecting_media: rejecting media files\n      rejecting_reports: rejecting reports\n      severity:\n        silence: silenced\n        suspend: suspended\n      show:\n        affected_accounts:\n          one: One account in the database affected\n          other: \"%{count} accounts in the database affected\"\n        retroactive:\n          silence: Unsilence existing affected accounts from this domain\n          suspend: Unsuspend existing affected accounts from this domain\n        title: Undo domain block for %{domain}\n        undo: Undo\n      undo: Undo domain block\n    email_domain_blocks:\n      add_new: Add new\n      created_msg: Successfully added e-mail domain to blacklist\n      delete: Delete\n      destroyed_msg: Successfully deleted e-mail domain from blacklist\n      domain: Domain\n      new:\n        create: Add domain\n        title: New e-mail blacklist entry\n      title: E-mail blacklist\n    followers:\n      back_to_account: Back To Account\n      title: \"%{acct}'s Followers\"\n    instances:\n      by_domain: Domain\n      delivery_available: Delivery is available\n      known_accounts:\n        one: \"%{count} known account\"\n        other: \"%{count} known accounts\"\n      moderation:\n        all: All\n        limited: Limited\n        title: Moderation\n      title: Federation\n      total_blocked_by_us: Blocked by us\n      total_followed_by_them: Followed by them\n      total_followed_by_us: Followed by us\n      total_reported: Reports about them\n      total_storage: Media attachments\n    invites:\n      deactivate_all: Deactivate all\n      filter:\n        all: All\n        available: Available\n        expired: Expired\n        title: Filter\n      title: Invites\n    pending_accounts:\n      title: Pending accounts (%{count})\n    relays:\n      add_new: Add new relay\n      delete: Delete\n      description_html: A <strong>federation relay</strong> is an intermediary server that exchanges large volumes of public toots between servers that subscribe and publish to it. <strong>It can help small and medium servers discover content from the fediverse</strong>, which would otherwise require local users manually following other people on remote servers.\n      disable: Disable\n      disabled: Disabled\n      enable: Enable\n      enable_hint: Once enabled, your server will subscribe to all public toots from this relay, and will begin sending this server's public toots to it.\n      enabled: Enabled\n      inbox_url: Relay URL\n      pending: Waiting for relay's approval\n      save_and_enable: Save and enable\n      setup: Setup a relay connection\n      status: Status\n      title: Relays\n    report_notes:\n      created_msg: Report note successfully created!\n      destroyed_msg: Report note successfully deleted!\n    reports:\n      account:\n        note: note\n        report: report\n      action_taken_by: Action taken by\n      are_you_sure: Are you sure?\n      assign_to_self: Assign to me\n      assigned: Assigned moderator\n      comment:\n        none: None\n      created_at: Reported\n      mark_as_resolved: Mark as resolved\n      mark_as_unresolved: Mark as unresolved\n      notes:\n        create: Add note\n        create_and_resolve: Resolve with note\n        create_and_unresolve: Reopen with note\n        delete: Delete\n        placeholder: Describe what actions have been taken, or any other related updates...\n      reopen: Reopen report\n      report: 'Report #%{id}'\n      reported_account: Reported account\n      reported_by: Reported by\n      resolved: Resolved\n      resolved_msg: Report successfully resolved!\n      status: Status\n      title: Reports\n      unassign: Unassign\n      unresolved: Unresolved\n      updated_at: Updated\n    settings:\n      activity_api_enabled:\n        desc_html: Counts of locally posted statuses, active users, and new registrations in weekly buckets\n        title: Publish aggregate statistics about user activity\n      bootstrap_timeline_accounts:\n        desc_html: Separate multiple usernames by comma. Only local and unlocked accounts will work. Default when empty is all local admins.\n        title: Default follows for new users\n      contact_information:\n        email: Contact e-mail\n        username: Contact username\n      custom_css:\n        desc_html: Modify the look with CSS loaded on every page\n        title: Custom CSS\n      hero:\n        desc_html: Displayed on the frontpage. At least 600x100px recommended. When not set, falls back to server thumbnail\n        title: Cover image\n      mascot:\n        desc_html: Displayed on multiple pages. At least 293×205px recommended. When not set, falls back to default mascot\n        title: Mascot image\n      max_bio_chars:\n        desc_html: 'Maximum biography length in characters (default: 500)'\n        title: Max biography size\n      max_toot_chars:\n        desc_html: 'Maximum toot length in characters (default: 500)'\n        title: Max toot size\n      peers_api_enabled:\n        desc_html: Domain names this server has encountered in the fediverse\n        title: Publish list of discovered servers\n      preview_sensitive_media:\n        desc_html: Link previews on other websites will display a thumbnail even if the media is marked as sensitive\n        title: Show sensitive media in OpenGraph previews\n      profile_directory:\n        desc_html: Allow users to be discoverable\n        title: Enable profile directory\n      registrations:\n        closed_message:\n          desc_html: Displayed on frontpage when registrations are closed. You can use HTML tags\n          title: Closed registration message\n        deletion:\n          desc_html: Allow anyone to delete their account\n          title: Open account deletion\n        min_invite_role:\n          disabled: No one\n          title: Allow invitations by\n      registrations_mode:\n        modes:\n          approved: Approval required for sign up\n          none: Nobody can sign up\n          open: Anyone can sign up\n        title: Registrations mode\n      show_known_fediverse_at_about_page:\n        desc_html: When toggled, it will show toots from all the known fediverse on preview. Otherwise it will only show local toots.\n        title: Show known fediverse on timeline preview\n      show_staff_badge:\n        desc_html: Show a staff badge on a user page\n        title: Show staff badge\n      site_description:\n        desc_html: Introductory paragraph on the API. Describe what makes this Mastodon server special and anything else important. You can use HTML tags, in particular <code>&lt;a&gt;</code> and <code>&lt;em&gt;</code>.\n        title: Server description\n      site_description_extended:\n        desc_html: A good place for your code of conduct, rules, guidelines and other things that set your server apart. You can use HTML tags\n        title: Custom extended information\n      site_short_description:\n        desc_html: Displayed in sidebar and meta tags. Describe what Mastodon is and what makes this server special in a single paragraph.\n        title: Short server description\n      site_terms:\n        desc_html: You can write your own privacy policy, terms of service or other legalese. You can use HTML tags\n        title: Custom terms of service\n      site_title: Server name\n      thumbnail:\n        desc_html: Used for previews via OpenGraph and API. 1200x630px recommended\n        title: Server thumbnail\n      timeline_preview:\n        desc_html: Display public timeline on landing page\n        title: Timeline preview\n      title: Site settings\n    statuses:\n      back_to_account: Back to account page\n      batch:\n        delete: Delete\n        nsfw_off: Mark as not sensitive\n        nsfw_on: Mark as sensitive\n      failed_to_execute: Failed to execute\n      media:\n        title: Media\n      no_media: No media\n      no_status_selected: No statuses were changed as none were selected\n      title: Account statuses\n      with_media: With media\n    subscriptions:\n      callback_url: Callback URL\n      confirmed: Confirmed\n      expires_in: Expires in\n      last_delivery: Last delivery\n      title: WebSub\n      topic: Topic\n    tags:\n      accounts: Accounts\n      hidden: Hidden\n      hide: Hide from directory\n      name: Hashtag\n      title: Hashtags\n      unhide: Show in directory\n      visible: Visible\n    title: Administration\n    warning_presets:\n      add_new: Add new\n      delete: Delete\n      edit: Edit\n      edit_preset: Edit warning preset\n      title: Manage warning presets\n  admin_mailer:\n    new_pending_account:\n      body: The details of the new account are below. You can approve or reject this application.\n      subject: New account up for review on %{instance} (%{username})\n    new_report:\n      body: \"%{reporter} has reported %{target}\"\n      body_remote: Someone from %{domain} has reported %{target}\n      subject: New report for %{instance} (#%{id})\n  appearance:\n    advanced_web_interface: Advanced web interface\n    advanced_web_interface_hint: 'If you want to make use of your entire screen width, the advanced web interface allows you to configure many different columns to see as much information at the same time as you want: Home, notifications, federated timeline, any number of lists and hashtags.'\n    animations_and_accessibility: Animations and accessibility\n    confirmation_dialogs: Confirmation dialogs\n    sensitive_content: Sensitive content\n  application_mailer:\n    notification_preferences: Change e-mail preferences\n    salutation: \"%{name},\"\n    settings: 'Change e-mail preferences: %{link}'\n    view: 'View:'\n    view_profile: View profile\n    view_status: View status\n  applications:\n    created: Application successfully created\n    destroyed: Application successfully deleted\n    invalid_url: The provided URL is invalid\n    regenerate_token: Regenerate access token\n    token_regenerated: Access token successfully regenerated\n    warning: Be very careful with this data. Never share it with anyone!\n    your_token: Your access token\n  auth:\n    apply_for_account: Request an invite\n    change_password: Password\n    checkbox_agreement_html: I agree to the <a href=\"%{rules_path}\" target=\"_blank\">server rules</a> and <a href=\"%{terms_path}\" target=\"_blank\">terms of service</a>\n    confirm_email: Confirm email\n    delete_account: Delete account\n    delete_account_html: If you wish to delete your account, you can <a href=\"%{path}\">proceed here</a>. You will be asked for confirmation.\n    didnt_get_confirmation: Didn't receive confirmation instructions?\n    forgot_password: Forgot your password?\n    invalid_reset_password_token: Password reset token is invalid or expired. Please request a new one.\n    login: Log in\n    logout: Logout\n    migrate_account: Move to a different account\n    migrate_account_html: If you wish to redirect this account to a different one, you can <a href=\"%{path}\">configure it here</a>.\n    or_log_in_with: Or log in with\n    providers:\n      cas: CAS\n      saml: SAML\n    register: Sign up\n    registration_closed: \"%{instance} is not accepting new members\"\n    resend_confirmation: Resend confirmation instructions\n    reset_password: Reset password\n    security: Security\n    set_new_password: Set new password\n    trouble_logging_in: Trouble logging in?\n  authorize_follow:\n    already_following: You are already following this account\n    error: Unfortunately, there was an error looking up the remote account\n    follow: Follow\n    follow_request: 'You have sent a follow request to:'\n    following: 'Success! You are now following:'\n    post_follow:\n      close: Or, you can just close this window.\n      return: Show the user's profile\n      web: Go to web\n    title: Follow %{acct}\n  datetime:\n    distance_in_words:\n      about_x_hours: \"%{count}h\"\n      about_x_months: \"%{count}mo\"\n      about_x_years: \"%{count}y\"\n      almost_x_years: \"%{count}y\"\n      half_a_minute: Just now\n      less_than_x_minutes: \"%{count}m\"\n      less_than_x_seconds: Just now\n      over_x_years: \"%{count}y\"\n      x_days: \"%{count}d\"\n      x_minutes: \"%{count}m\"\n      x_months: \"%{count}mo\"\n      x_seconds: \"%{count}s\"\n  deletes:\n    bad_password_msg: Nice try, hackers! Incorrect password\n    confirm_password: Enter your current password to verify your identity\n    description_html: This will <strong>permanently, irreversibly</strong> remove content from your account and deactivate it. Your username will remain reserved to prevent future impersonations.\n    proceed: Delete account\n    success_msg: Your account was successfully deleted\n    warning_html: Only deletion of content from this particular server is guaranteed. Content that has been widely shared is likely to leave traces. Offline servers and servers that have unsubscribed from your updates will not update their databases.\n    warning_title: Disseminated content availability\n  directories:\n    directory: Profile directory\n    enabled: You are currently listed in the directory.\n    enabled_but_waiting: You have opted-in to be listed in the directory, but you do not have the minimum number of followers (%{min_followers}) to be listed yet.\n    explanation: Discover users based on their interests\n    explore_mastodon: Explore %{title}\n    how_to_enable: You are not currently opted-in to the directory. You can opt-in below. Use hashtags in your bio text to be listed under specific hashtags!\n    people:\n      one: \"%{count} person\"\n      other: \"%{count} people\"\n  errors:\n    '403': You don't have permission to view this page.\n    '404': The page you are looking for isn't here.\n    '410': The page you were looking for doesn't exist here anymore.\n    '422':\n      content: Security verification failed. Are you blocking cookies?\n      title: Security verification failed\n    '429': Throttled\n    '500':\n      content: We're sorry, but something went wrong on our end.\n      title: This page is not correct\n    noscript_html: To use the Mastodon web application, please enable JavaScript. Alternatively, try one of the <a href=\"%{apps_path}\">native apps</a> for Mastodon for your platform.\n  existing_username_validator:\n    not_found: could not find a local user with that username\n    not_found_multiple: could not find %{usernames}\n  exports:\n    archive_takeout:\n      date: Date\n      download: Download your archive\n      hint_html: You can request an archive of your <strong>toots and uploaded media</strong>. The exported data will be in the ActivityPub format, readable by any compliant software. You can request an archive every 7 days.\n      in_progress: Compiling your archive...\n      request: Request your archive\n      size: Size\n    blocks: You block\n    csv: CSV\n    domain_blocks: Domain blocks\n    follows: You follow\n    lists: Lists\n    mutes: You mute\n    storage: Media storage\n  featured_tags:\n    add_new: Add new\n    errors:\n      limit: You have already featured the maximum amount of hashtags\n  filters:\n    contexts:\n      home: Home timeline\n      notifications: Notifications\n      public: Public timelines\n      thread: Conversations\n    edit:\n      title: Edit filter\n    errors:\n      invalid_context: None or invalid context supplied\n      invalid_irreversible: Irreversible filtering only works with home or notifications context\n    index:\n      delete: Delete\n      title: Filters\n    new:\n      title: Add new filter\n  footer:\n    developers: Developers\n    more: More…\n    resources: Resources\n  generic:\n    all: All\n    changes_saved_msg: Changes successfully saved!\n    copy: Copy\n    order_by: Order by\n    save_changes: Save changes\n    validation_errors:\n      one: Something isn't quite right yet! Please review the error below\n      other: Something isn't quite right yet! Please review %{count} errors below\n  html_validator:\n    invalid_markup: 'contains invalid HTML markup: %{error}'\n  identity_proofs:\n    active: Active\n    authorize: Yes, authorize\n    authorize_connection_prompt: Authorize this cryptographic connection?\n    errors:\n      failed: The cryptographic connection failed. Please try again from %{provider}.\n      keybase:\n        invalid_token: Keybase tokens are hashes of signatures and must be 66 hex characters\n        verification_failed: Keybase does not recognize this token as a signature of Keybase user %{kb_username}. Please retry from Keybase.\n      wrong_user: Cannot create a proof for %{proving} while logged in as %{current}. Log in as %{proving} and try again.\n    explanation_html: Here you can cryptographically connect your other identities, such as a Keybase profile. This lets other people send you encrypted messages and trust content you send them.\n    i_am_html: I am %{username} on %{service}.\n    identity: Identity\n    inactive: Inactive\n    publicize_checkbox: 'And toot this:'\n    publicize_toot: 'It is proven! I am %{username} on %{service}: %{url}'\n    status: Verification status\n    view_proof: View proof\n  imports:\n    modes:\n      merge: Merge\n      merge_long: Keep existing records and add new ones\n      overwrite: Overwrite\n      overwrite_long: Replace current records with the new ones\n    preface: You can import data that you have exported from another server, such as a list of the people you are following or blocking.\n    success: Your data was successfully uploaded and will now be processed in due time\n    types:\n      blocking: Blocking list\n      domain_blocking: Domain blocking list\n      following: Following list\n      muting: Muting list\n    upload: Upload\n  in_memoriam_html: In Memoriam.\n  invites:\n    delete: Deactivate\n    expired: Expired\n    expires_in:\n      '1800': 30 minutes\n      '21600': 6 hours\n      '3600': 1 hour\n      '43200': 12 hours\n      '604800': 1 week\n      '86400': 1 day\n    expires_in_prompt: Never\n    generate: Generate\n    invited_by: 'You were invited by:'\n    max_uses:\n      one: 1 use\n      other: \"%{count} uses\"\n    max_uses_prompt: No limit\n    prompt: Generate and share links with others to grant access to this server\n    table:\n      expires_at: Expires\n      uses: Uses\n    title: Invite people\n  lists:\n    errors:\n      limit: You have reached the maximum amount of lists\n  media_attachments:\n    validations:\n      images_and_video: Cannot attach a video to a status that already contains images\n      too_many: Cannot attach more than 4 files\n  migrations:\n    acct: username@domain of the new account\n    currently_redirecting: 'Your profile is set to redirect to:'\n    proceed: Save\n    updated_msg: Your account migration setting successfully updated!\n  moderation:\n    title: Moderation\n  notification_mailer:\n    digest:\n      action: View all notifications\n      body: Here is a brief summary of the messages you missed since your last visit on %{since}\n      mention: \"%{name} mentioned you in:\"\n      new_followers_summary:\n        one: Also, you have acquired one new follower while being away! Yay!\n        other: Also, you have acquired %{count} new followers while being away! Amazing!\n      subject:\n        one: \"1 new notification since your last visit \\U0001F418\"\n        other: \"%{count} new notifications since your last visit \\U0001F418\"\n      title: In your absence...\n    favourite:\n      body: 'Your status was favourited by %{name}:'\n      subject: \"%{name} favourited your status\"\n      title: New favourite\n    follow:\n      body: \"%{name} is now following you!\"\n      subject: \"%{name} is now following you\"\n      title: New follower\n    follow_request:\n      action: Manage follow requests\n      body: \"%{name} has requested to follow you\"\n      subject: 'Pending follower: %{name}'\n      title: New follow request\n    mention:\n      action: Reply\n      body: 'You were mentioned by %{name} in:'\n      subject: You were mentioned by %{name}\n      title: New mention\n    reblog:\n      body: 'Your status was boosted by %{name}:'\n      subject: \"%{name} boosted your status\"\n      title: New boost\n  number:\n    human:\n      decimal_units:\n        format: \"%n%u\"\n        units:\n          billion: B\n          million: M\n          quadrillion: Q\n          thousand: K\n          trillion: T\n          unit: ''\n  pagination:\n    newer: Newer\n    next: Next\n    older: Older\n    prev: Prev\n    truncate: \"&hellip;\"\n  polls:\n    errors:\n      already_voted: You have already voted on this poll\n      duplicate_options: contain duplicate items\n      duration_too_long: is too far into the future\n      duration_too_short: is too soon\n      expired: The poll has already ended\n      over_character_limit: cannot be longer than %{max} characters each\n      too_few_options: must have more than one item\n      too_many_options: can't contain more than %{max} items\n  preferences:\n    other: Other\n    posting_defaults: Posting defaults\n    public_timelines: Public timelines\n  relationships:\n    activity: Account activity\n    dormant: Dormant\n    last_active: Last active\n    most_recent: Most recent\n    moved: Moved\n    mutual: Mutual\n    primary: Primary\n    relationship: Relationship\n    remove_selected_domains: Remove all followers from the selected domains\n    remove_selected_followers: Remove selected followers\n    remove_selected_follows: Unfollow selected users\n    status: Account status\n  remote_follow:\n    acct: Enter your username@domain you want to act from\n    missing_resource: Could not find the required redirect URL for your account\n    no_account_html: Don't have an account? You can <a href='%{sign_up_path}' target='_blank'>sign up here</a>\n    proceed: Proceed to follow\n    prompt: 'You are going to follow:'\n    reason_html: \"<strong>Why is this step necessary?</strong> <code>%{instance}</code> might not be the server where you are registered, so we need to redirect you to your home server first.\"\n  remote_interaction:\n    favourite:\n      proceed: Proceed to favourite\n      prompt: 'You want to favourite this toot:'\n    reblog:\n      proceed: Proceed to boost\n      prompt: 'You want to boost this toot:'\n    reply:\n      proceed: Proceed to reply\n      prompt: 'You want to reply to this toot:'\n  remote_unfollow:\n    error: Error\n    title: Title\n    unfollowed: Unfollowed\n  scheduled_statuses:\n    over_daily_limit: You have exceeded the limit of %{limit} scheduled toots for that day\n    over_total_limit: You have exceeded the limit of %{limit} scheduled toots\n    too_soon: The scheduled date must be in the future\n  sessions:\n    activity: Last activity\n    browser: Browser\n    browsers:\n      alipay: Alipay\n      blackberry: Blackberry\n      chrome: Chrome\n      edge: Microsoft Edge\n      electron: Electron\n      firefox: Firefox\n      generic: Unknown browser\n      ie: Internet Explorer\n      micro_messenger: MicroMessenger\n      nokia: Nokia S40 Ovi Browser\n      opera: Opera\n      otter: Otter\n      phantom_js: PhantomJS\n      qq: QQ Browser\n      safari: Safari\n      uc_browser: UCBrowser\n      weibo: Weibo\n    current_session: Current session\n    description: \"%{browser} on %{platform}\"\n    explanation: These are the web browsers currently logged in to your Mastodon account.\n    ip: IP\n    platforms:\n      adobe_air: Adobe Air\n      android: Android\n      blackberry: Blackberry\n      chrome_os: ChromeOS\n      firefox_os: Firefox OS\n      ios: iOS\n      linux: Linux\n      mac: Mac\n      other: unknown platform\n      windows: Windows\n      windows_mobile: Windows Mobile\n      windows_phone: Windows Phone\n    revoke: Revoke\n    revoke_success: Session successfully revoked\n    title: Sessions\n  settings:\n    account: Account\n    account_settings: Account settings\n    appearance: Appearance\n    authorized_apps: Authorized apps\n    back: Back to Mastodon\n    delete: Account deletion\n    development: Development\n    edit_profile: Edit profile\n    export: Data export\n    featured_tags: Featured hashtags\n    identity_proofs: Identity proofs\n    import: Import\n    import_and_export: Import and export\n    migrate: Account migration\n    notifications: Notifications\n    preferences: Preferences\n    profile: Profile\n    relationships: Follows and followers\n    two_factor_authentication: Two-factor Auth\n  statuses:\n    attached:\n      description: 'Attached: %{attached}'\n      image:\n        one: \"%{count} image\"\n        other: \"%{count} images\"\n      video:\n        one: \"%{count} video\"\n        other: \"%{count} videos\"\n    boosted_from_html: Boosted from %{acct_link}\n    content_warning: 'Content warning: %{warning}'\n    disallowed_hashtags:\n      one: 'contained a disallowed hashtag: %{tags}'\n      other: 'contained the disallowed hashtags: %{tags}'\n    language_detection: Automatically detect language\n    open_in_web: Open in web\n    over_character_limit: character limit of %{max} exceeded\n    pin_errors:\n      limit: You have already pinned the maximum number of toots\n      ownership: Someone else's toot cannot be pinned\n      private: Non-public toot cannot be pinned\n      reblog: A boost cannot be pinned\n    poll:\n      total_votes:\n        one: \"%{count} vote\"\n        other: \"%{count} votes\"\n      vote: Vote\n    show_more: Show more\n    sign_in_to_participate: Sign in to participate in the conversation\n    title: '%{name}: \"%{quote}\"'\n    visibilities:\n      private: Followers-only\n      private_long: Only show to followers\n      public: Public\n      public_long: Everyone can see\n      unlisted: Unlisted\n      unlisted_long: Everyone can see, but not listed on public timelines\n  stream_entries:\n    pinned: Pinned toot\n    reblogged: boosted\n    sensitive_content: Sensitive content\n  terms:\n    body_html: |\n      <h2>Privacy Policy</h2>\n      <h3 id=\"collect\">What information do we collect?</h3>\n\n      <ul>\n        <li><em>Basic account information</em>: If you register on this server, you may be asked to enter a username, an e-mail address and a password. You may also enter additional profile information such as a display name and biography, and upload a profile picture and header image. The username, display name, biography, profile picture and header image are always listed publicly.</li>\n        <li><em>Posts, following and other public information</em>: The list of people you follow is listed publicly, the same is true for your followers. When you submit a message, the date and time is stored as well as the application you submitted the message from. Messages may contain media attachments, such as pictures and videos. Public and unlisted posts are available publicly. When you feature a post on your profile, that is also publicly available information. Your posts are delivered to your followers, in some cases it means they are delivered to different servers and copies are stored there. When you delete posts, this is likewise delivered to your followers. The action of reblogging or favouriting another post is always public.</li>\n        <li><em>Direct and followers-only posts</em>: All posts are stored and processed on the server. Followers-only posts are delivered to your followers and users who are mentioned in them, and direct posts are delivered only to users mentioned in them. In some cases it means they are delivered to different servers and copies are stored there. We make a good faith effort to limit the access to those posts only to authorized persons, but other servers may fail to do so. Therefore it's important to review servers your followers belong to. You may toggle an option to approve and reject new followers manually in the settings. <em>Please keep in mind that the operators of the server and any receiving server may view such messages</em>, and that recipients may screenshot, copy or otherwise re-share them. <em>Do not share any dangerous information over Mastodon.</em></li>\n        <li><em>IPs and other metadata</em>: When you log in, we record the IP address you log in from, as well as the name of your browser application. All the logged in sessions are available for your review and revocation in the settings. The latest IP address used is stored for up to 12 months. We also may retain server logs which include the IP address of every request to our server.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"use\">What do we use your information for?</h3>\n\n      <p>Any of the information we collect from you may be used in the following ways:</p>\n\n      <ul>\n        <li>To provide the core functionality of Mastodon. You can only interact with other people's content and post your own content when you are logged in. For example, you may follow other people to view their combined posts in your own personalized home timeline.</li>\n        <li>To aid moderation of the community, for example comparing your IP address with other known ones to determine ban evasion or other violations.</li>\n        <li>The email address you provide may be used to send you information, notifications about other people interacting with your content or sending you messages, and to respond to inquiries, and/or other requests or questions.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"protect\">How do we protect your information?</h3>\n\n      <p>We implement a variety of security measures to maintain the safety of your personal information when you enter, submit, or access your personal information. Among other things, your browser session, as well as the traffic between your applications and the API, are secured with SSL, and your password is hashed using a strong one-way algorithm. You may enable two-factor authentication to further secure access to your account.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"data-retention\">What is our data retention policy?</h3>\n\n      <p>We will make a good faith effort to:</p>\n\n      <ul>\n        <li>Retain server logs containing the IP address of all requests to this server, in so far as such logs are kept, no more than 90 days.</li>\n        <li>Retain the IP addresses associated with registered users no more than 12 months.</li>\n      </ul>\n\n      <p>You can request and download an archive of your content, including your posts, media attachments, profile picture, and header image.</p>\n\n      <p>You may irreversibly delete your account at any time.</p>\n\n      <hr class=\"spacer\"/>\n\n      <h3 id=\"cookies\">Do we use cookies?</h3>\n\n      <p>Yes. Cookies are small files that a site or its service provider transfers to your computer's hard drive through your Web browser (if you allow). These cookies enable the site to recognize your browser and, if you have a registered account, associate it with your registered account.</p>\n\n      <p>We use cookies to understand and save your preferences for future visits.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"disclose\">Do we disclose any information to outside parties?</h3>\n\n      <p>We do not sell, trade, or otherwise transfer to outside parties your personally identifiable information. This does not include trusted third parties who assist us in operating our site, conducting our business, or servicing you, so long as those parties agree to keep this information confidential. We may also release your information when we believe release is appropriate to comply with the law, enforce our site policies, or protect ours or others rights, property, or safety.</p>\n\n      <p>Your public content may be downloaded by other servers in the network. Your public and followers-only posts are delivered to the servers where your followers reside, and direct messages are delivered to the servers of the recipients, in so far as those followers or recipients reside on a different server than this.</p>\n\n      <p>When you authorize an application to use your account, depending on the scope of permissions you approve, it may access your public profile information, your following list, your followers, your lists, all your posts, and your favourites. Applications can never access your e-mail address or password.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"children\">Site usage by children</h3>\n\n      <p>If this server is in the EU or the EEA: Our site, products and services are all directed to people who are at least 16 years old. If you are under the age of 16, per the requirements of the GDPR (<a href=\"https://en.wikipedia.org/wiki/General_Data_Protection_Regulation\">General Data Protection Regulation</a>) do not use this site.</p>\n\n      <p>If this server is in the USA: Our site, products and services are all directed to people who are at least 13 years old. If you are under the age of 13, per the requirements of COPPA (<a href=\"https://en.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act\">Children's Online Privacy Protection Act</a>) do not use this site.</p>\n\n      <p>Law requirements can be different if this server is in another jurisdiction.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"changes\">Changes to our Privacy Policy</h3>\n\n      <p>If we decide to change our privacy policy, we will post those changes on this page.</p>\n\n      <p>This document is CC-BY-SA. It was last updated March 7, 2018.</p>\n\n      <p>Originally adapted from the <a href=\"https://github.com/discourse/discourse\">Discourse privacy policy</a>.</p>\n    title: \"%{instance} Terms of Service and Privacy Policy\"\n  themes:\n    contrast: Mastodon (High contrast)\n    default: Mastodon (Dark)\n    mastodon-light: Mastodon (Light)\n  time:\n    formats:\n      default: \"%b %d, %Y, %H:%M\"\n      month: \"%b %Y\"\n  two_factor_authentication:\n    code_hint: Enter the code generated by your authenticator app to confirm\n    description_html: If you enable <strong>two-factor authentication</strong>, logging in will require you to be in possession of your phone, which will generate tokens for you to enter.\n    disable: Disable\n    enable: Enable\n    enabled: Two-factor authentication is enabled\n    enabled_success: Two-factor authentication successfully enabled\n    generate_recovery_codes: Generate recovery codes\n    instructions_html: \"<strong>Scan this QR code into Google Authenticator or a similiar TOTP app on your phone</strong>. From now on, that app will generate tokens that you will have to enter when logging in.\"\n    lost_recovery_codes: Recovery codes allow you to regain access to your account if you lose your phone. If you've lost your recovery codes, you can regenerate them here. Your old recovery codes will be invalidated.\n    manual_instructions: 'If you can''t scan the QR code and need to enter it manually, here is the plain-text secret:'\n    recovery_codes: Backup recovery codes\n    recovery_codes_regenerated: Recovery codes successfully regenerated\n    recovery_instructions_html: If you ever lose access to your phone, you can use one of the recovery codes below to regain access to your account. <strong>Keep the recovery codes safe</strong>. For example, you may print them and store them with other important documents.\n    setup: Set up\n    wrong_code: The entered code was invalid! Are server time and device time correct?\n  user_mailer:\n    backup_ready:\n      explanation: You requested a full backup of your Mastodon account. It's now ready for download!\n      subject: Your archive is ready for download\n      title: Archive takeout\n    warning:\n      explanation:\n        disable: While your account is frozen, your account data remains intact, but you cannot perform any actions until it is unlocked.\n        silence: While your account is limited, only people who are already following you will see your toots on this server, and you may be excluded from various public listings. However, others may still manually follow you.\n        suspend: Your account has been suspended, and all of your toots and your uploaded media files have been irreversibly removed from this server, and servers where you had followers.\n      review_server_policies: Review server policies\n      subject:\n        disable: Your account %{acct} has been frozen\n        none: Warning for %{acct}\n        silence: Your account %{acct} has been limited\n        suspend: Your account %{acct} has been suspended\n      title:\n        disable: Account frozen\n        none: Warning\n        silence: Account limited\n        suspend: Account suspended\n    welcome:\n      edit_profile_action: Setup profile\n      edit_profile_step: You can customize your profile by uploading an avatar, header, changing your display name and more. If you’d like to review new followers before they’re allowed to follow you, you can lock your account.\n      explanation: Here are some tips to get you started\n      final_action: Start posting\n      final_step: 'Start posting! Even without followers your public messages may be seen by others, for example on the local timeline and in hashtags. You may want to introduce yourself on the #introductions hashtag.'\n      full_handle: Your full handle\n      full_handle_hint: This is what you would tell your friends so they can message or follow you from another server.\n      review_preferences_action: Change preferences\n      review_preferences_step: Make sure to set your preferences, such as which emails you'd like to receive, or what privacy level you’d like your posts to default to. If you don’t have motion sickness, you could choose to enable GIF autoplay.\n      subject: Welcome to Mastodon\n      tip_federated_timeline: The federated timeline is a firehose view of the Mastodon network. But it only includes people your neighbours are subscribed to, so it's not complete.\n      tip_following: You follow your server's admin(s) by default. To find more interesting people, check the local and federated timelines.\n      tip_local_timeline: The local timeline is a firehose view of people on %{instance}. These are your immediate neighbours!\n      tip_mobile_webapp: If your mobile browser offers you to add Mastodon to your homescreen, you can receive push notifications. It acts like a native app in many ways!\n      tips: Tips\n      title: Welcome aboard, %{name}!\n  users:\n    follow_limit_reached: You cannot follow more than %{limit} people\n    invalid_email: The e-mail address is invalid\n    invalid_otp_token: Invalid two-factor code\n    otp_lost_help_html: If you lost access to both, you may get in touch with %{email}\n    seamless_external_login: You are logged in via an external service, so password and e-mail settings are not available.\n    signed_in_as: 'Signed in as:'\n  verification:\n    explanation_html: 'You can <strong>verify yourself as the owner of the links in your profile metadata</strong>. For that, the linked website must contain a link back to your Mastodon profile. The link back <strong>must</strong> have a <code>rel=\"me\"</code> attribute. The text content of the link does not matter. Here is an example:'\n    verification: Verification\n"
  },
  {
    "path": "config/locales/en_GB.yml",
    "content": "---\nen_GB:\n  about:\n    about_hashtag_html: These are public toots tagged with <strong>#%{hashtag}</strong>. You can interact with them if you have an account anywhere in the fediverse.\n    about_mastodon_html: Mastodon is a social network based on open web protocols and free, open-source software. It is decentralized like e-mail.\n    about_this: About\n    active_count_after: active\n    active_footnote: Monthly Active Users (MAU)\n    administered_by: 'Administered by:'\n    api: API\n    apps: Mobile apps\n    apps_platforms: Use Mastodon from iOS, Android and other platforms\n    browse_directory: Browse a profile directory and filter by interests\n    browse_public_posts: Browse a live stream of public posts on Mastodon\n    contact: Contact\n    contact_missing: Not set\n    contact_unavailable: N/A\n    discover_users: Discover users\n    documentation: Documentation\n    extended_description_html: |\n      <h3>1A good place for rules</h3>2\n      <p>3The extended description has not been set up yet.</p>4\n    federation_hint_html: With an account on %{instance} you'll be able to follow people on any Mastodon server and beyond.\n    generic_description: \"%{domain} is one server in the network\"\n    get_apps: Try a mobile app\n    hosted_on: Mastodon hosted on %{domain}\n    learn_more: Learn more\n    privacy_policy: Privacy policy\n    see_whats_happening: See what's happening\n    server_stats: 'Server stats:'\n    source_code: Source code\n    status_count_after:\n      one: status\n      other: statuses\n    status_count_before: Who authored\n    tagline: Follow friends and discover new ones\n    terms: Terms of service\n    user_count_after:\n      one: user\n      other: users\n    user_count_before: Home to\n    what_is_mastodon: What is Mastodon?\n  accounts:\n    choices_html: \"%{name}'s choices:\"\n    follow: Follow\n    followers:\n      one: Follower\n      other: Follower\n    following: Following\n    joined: Joined %{date}\n    last_active: last active\n    link_verified_on: Ownership of this link was checked on %{date}\n    media: Media\n    moved_html: \"%{name} has moved to %{new_profile_link}:\"\n    network_hidden: This information is not available\n    nothing_here: There is nothing here!\n    people_followed_by: People whom %{name} follows\n    people_who_follow: People who follow %{name}\n    pin_errors:\n      following: You must be already following the person you want to endorse\n    posts:\n      one: Toot\n      other: Toots\n    posts_tab_heading: Toots\n    posts_with_replies: Toots and replies\n    reserved_username: The username is reserved\n    roles:\n      admin: Admin\n      bot: Bot\n      moderator: Mod\n    unfollow: Unfollow\n  admin:\n    account_actions:\n      action: Perform action\n      title: Perform moderation action on %{acct}\n    account_moderation_notes:\n      create: Leave note\n      created_msg: Moderation note successfully created!\n      delete: Delete\n      destroyed_msg: Moderation note successfully destroyed!\n    accounts:\n      approve: Approve\n      are_you_sure: Are you sure?\n      avatar: Avatar\n      by_domain: Domain\n      change_email:\n        changed_msg: Account email successfully changed!\n        current_email: Current email\n        label: Change email\n        new_email: New email\n        submit: Change email\n        title: Change email for %{username}\n      confirm: Confirm\n      confirmed: Confirmed\n      confirming: Confirming\n      deleted: Deleted\n      demote: Demote\n      disable: Disable\n      disable_two_factor_authentication: Disable 2FA\n      disabled: Disabled\n      display_name: Display name\n      domain: Domain\n      edit: Edit\n      email: Email\n      email_status: Email status\n      enable: Enable\n      enabled: Enabled\n      feed_url: Feed URL\n      followers: Followers\n      followers_url: Followers URL\n      follows: Follows\n      header: Header\n      inbox_url: Inbox URL\n      invited_by: Invited by\n      ip: IP\n      joined: Joined\n      location:\n        all: All\n        local: Local\n        remote: Remote\n        title: Location\n      login_status: Login status\n      media_attachments: Media attachments\n      memorialize: Turn into memoriam\n      moderation:\n        active: Active\n        all: All\n        pending: Pending\n        silenced: Silenced\n        suspended: Suspended\n        title: Moderation\n      moderation_notes: Moderation notes\n      most_recent_activity: Most recent activity\n      most_recent_ip: Most recent IP\n      no_limits_imposed: No limits imposed\n      not_subscribed: Not subscribed\n      outbox_url: Outbox URL\n      pending: Pending review\n      perform_full_suspension: Suspend\n      profile_url: Profile URL\n      promote: Promote\n      protocol: Protocol\n      public: Public\n      push_subscription_expires: PuSH subscription expires\n      redownload: Refresh profile\n      reject: Reject\n      remove_avatar: Remove avatar\n      remove_header: Remove header\n      resend_confirmation:\n        already_confirmed: This user is already confirmed\n        send: Resend confirmation email\n        success: Confirmation email successfully sent!\n      reset: Reset\n      reset_password: Reset password\n      resubscribe: Resubscribe\n      role: Permissions\n      roles:\n        admin: Administrator\n        moderator: Moderator\n        staff: Staff\n        user: User\n      salmon_url: Salmon URL\n      search: Search\n      shared_inbox_url: Shared inbox URL\n      show:\n        created_reports: Made reports\n        targeted_reports: Reported by others\n      silence: Silence\n      silenced: Silenced\n      statuses: Statuses\n      subscribe: Subscribe\n      suspended: Suspended\n      title: Accounts\n      unconfirmed_email: Unconfirmed email\n      undo_silenced: Undo silence\n      undo_suspension: Undo suspension\n      unsubscribe: Unsubscribe\n      username: Username\n      warn: Warn\n      web: Web\n    action_logs:\n      actions:\n        assigned_to_self_report: \"%{name} assigned report %{target} to themselves\"\n        change_email_user: \"%{name} changed the e-mail address of user %{target}\"\n        confirm_user: \"%{name} confirmed e-mail address of user %{target}\"\n        create_account_warning: \"%{name} sent a warning to %{target}\"\n        create_custom_emoji: \"%{name} uploaded new emoji %{target}\"\n        create_domain_block: \"%{name} blocked domain %{target}\"\n        create_email_domain_block: \"%{name} blacklisted e-mail domain %{target}\"\n        demote_user: \"%{name} demoted user %{target}\"\n        destroy_custom_emoji: \"%{name} destroyed emoji %{target}\"\n        destroy_domain_block: \"%{name} unblocked domain %{target}\"\n        destroy_email_domain_block: \"%{name} whitelisted e-mail domain %{target}\"\n        destroy_status: \"%{name} removed status by %{target}\"\n        disable_2fa_user: \"%{name} disabled two factor requirement for user %{target}\"\n        disable_custom_emoji: \"%{name} disabled emoji %{target}\"\n        disable_user: \"%{name} disabled login for user %{target}\"\n        enable_custom_emoji: \"%{name} enabled emoji %{target}\"\n        enable_user: \"%{name} enabled login for user %{target}\"\n        memorialize_account: \"%{name} turned %{target}'s account into a memoriam page\"\n        promote_user: \"%{name} promoted user %{target}\"\n        remove_avatar_user: \"%{name} removed %{target}'s avatar\"\n        reopen_report: \"%{name} reopened report %{target}\"\n        reset_password_user: \"%{name} reset password of user %{target}\"\n        resolve_report: \"%{name} resolved report %{target}\"\n        silence_account: \"%{name} silenced %{target}'s account\"\n        suspend_account: \"%{name} suspended %{target}'s account\"\n        unassigned_report: \"%{name} unassigned report %{target}\"\n        unsilence_account: \"%{name} unsilenced %{target}'s account\"\n        unsuspend_account: \"%{name} unsuspended %{target}'s account\"\n        update_custom_emoji: \"%{name} updated emoji %{target}\"\n        update_status: \"%{name} updated status by %{target}\"\n      deleted_status: \"(deleted status)\"\n      title: Audit log\n    custom_emojis:\n      by_domain: Domain\n      copied_msg: Successfully created local copy of the emoji\n      copy: Copy\n      copy_failed_msg: Could not make a local copy of that emoji\n      created_msg: Emoji successfully created!\n      delete: Delete\n      destroyed_msg: Emojo successfully destroyed!\n      disable: Disable\n      disabled_msg: Successfully disabled that emoji\n      emoji: Emoji\n      enable: Enable\n      enabled_msg: Successfully enabled that emoji\n      image_hint: PNG up to 50KB\n      listed: Listed\n      new:\n        title: Add new custom emoji\n      overwrite: Overwrite\n      shortcode: Shortcode\n      shortcode_hint: At least 2 characters, only alphanumeric characters and underscores\n      title: Custom emojis\n      unlisted: Unlisted\n      update_failed_msg: Could not update that emoji\n      updated_msg: Emoji successfully updated!\n      upload: Upload\n    dashboard:\n      backlog: backlogged jobs\n      config: Configuration\n      feature_deletions: Account deletions\n      feature_invites: Invite links\n      feature_profile_directory: Profile directory\n      feature_registrations: Registrations\n      feature_relay: Federation relay\n      features: Features\n      hidden_service: Federation with hidden services\n      open_reports: open reports\n      recent_users: Recent users\n      search: Full-text search\n      single_user_mode: Single user mode\n      software: Software\n      space: Space usage\n      title: Dashboard\n      total_users: users in total\n      trends: Trends\n      week_interactions: interactions this week\n      week_users_active: active this week\n      week_users_new: users this week\n    domain_blocks:\n      add_new: Add new domain block\n      created_msg: Domain block is now being processed\n      destroyed_msg: Domain block has been undone\n      domain: Domain\n      new:\n        create: Create block\n        hint: The domain block will not prevent creation of account entries in the database, but will retroactively and automatically apply specific moderation methods on those accounts.\n        severity:\n          desc_html: \"<strong>Silence</strong> will make the account's posts invisible to anyone who isn't following them. <strong>Suspend</strong> will remove all of the account's content, media, and profile data. Use <strong>None</strong> if you just want to reject media files.\"\n          noop: None\n          silence: Silence\n          suspend: Suspend\n        title: New domain block\n      reject_media: Reject media files\n      reject_media_hint: Removes locally stored media files and refuses to download any in the future. Irrelevant for suspensions\n      reject_reports: Reject reports\n      reject_reports_hint: Ignore all reports coming from this domain. Irrelevant for suspensions\n      rejecting_media: rejecting media files\n      rejecting_reports: rejecting reports\n      severity:\n        silence: silenced\n        suspend: suspended\n      show:\n        affected_accounts:\n          one: One account in the database affected\n          other: \"%{count} accounts in the database affected\"\n        retroactive:\n          silence: Unsilence all existing accounts from this domain\n          suspend: Unsuspend all existing accounts from this domain\n        title: Undo domain block for %{domain}\n        undo: Undo\n      undo: Undo domain block\n    email_domain_blocks:\n      add_new: Add new\n      created_msg: Successfully added e-mail domain to blacklist\n      delete: Delete\n      destroyed_msg: Successfully deleted e-mail domain from blacklist\n      domain: Domain\n      new:\n        create: Add domain\n        title: New e-mail blacklist entry\n      title: E-mail blacklist\n    followers:\n      back_to_account: Back To Account\n      title: \"%{acct}'s Followers\"\n    instances:\n      by_domain: Domain\n      delivery_available: Delivery is available\n      known_accounts:\n        one: \"%{count} known account\"\n        other: \"%{count} known accounts\"\n      moderation:\n        all: All\n        limited: Limited\n        title: Moderation\n      title: Federation\n      total_blocked_by_us: Blocked by us\n      total_followed_by_them: Followed by them\n      total_followed_by_us: Followed by us\n      total_reported: Reports about them\n      total_storage: Media attachments\n    invites:\n      deactivate_all: Deactivate all\n      filter:\n        all: All\n        available: Available\n        expired: Expired\n        title: Filter\n      title: Invites\n    relays:\n      add_new: Add new relay\n      delete: Delete\n      description_html: A <strong>federation relay</strong> is an intermediary server that exchanges large volumes of public toots between servers that subscribe and publish to it. <strong>It can help small and medium servers discover content from the fediverse</strong>, which would otherwise require local users manually following other people on remote servers.\n      disable: Disable\n      disabled: Disabled\n      enable: Enable\n      enable_hint: Once enabled, your server will subscribe to all public toots from this relay, and will begin sending this server's public toots to it.\n      enabled: Enabled\n      inbox_url: Relay URL\n      pending: Waiting for relay's approval\n      save_and_enable: Save and enable\n      setup: Setup a relay connection\n      status: Status\n      title: Relays\n    report_notes:\n      created_msg: Report note successfully created!\n      destroyed_msg: Report note successfully deleted!\n    reports:\n      account:\n        note: note\n        report: report\n      action_taken_by: Action taken by\n      are_you_sure: Are you sure?\n      assign_to_self: Assign to me\n      assigned: Assigned moderator\n      comment:\n        none: None\n      created_at: Reported\n      mark_as_resolved: Mark as resolved\n      mark_as_unresolved: Mark as unresolved\n      notes:\n        create: Add note\n        create_and_resolve: Resolve with note\n        create_and_unresolve: Reopen with note\n        delete: Delete\n        placeholder: Describe what actions have been taken, or any other related updates...\n      reopen: Reopen report\n      report: 'Report #%{id}'\n      reported_account: Reported account\n      reported_by: Reported by\n      resolved: Resolved\n      resolved_msg: Report successfully resolved!\n      status: Status\n      title: Reports\n      unassign: Unassign\n      unresolved: Unresolved\n      updated_at: Updated\n    settings:\n      activity_api_enabled:\n        desc_html: Counts of locally posted statuses, active users, and new registrations in weekly buckets\n        title: Publish aggregate statistics about user activity\n      bootstrap_timeline_accounts:\n        desc_html: Separate multiple usernames by comma. Only local and unlocked accounts will work. Default when empty is all local admins.\n        title: Default follows for new users\n      contact_information:\n        email: Business e-mail\n        username: Contact username\n      custom_css:\n        desc_html: Modify the look with CSS loaded on every page\n        title: Custom CSS\n      hero:\n        desc_html: Displayed on the frontpage. At least 600x100px recommended. When not set, falls back to server thumbnail\n        title: Hero image\n      mascot:\n        desc_html: Displayed on multiple pages. At least 293×205px recommended. When not set, falls back to default mascot\n        title: Mascot image\n      peers_api_enabled:\n        desc_html: Domain names this server has encountered in the fediverse\n        title: Publish list of discovered servers\n      preview_sensitive_media:\n        desc_html: Link previews on other websites will display a thumbnail even if the media is marked as sensitive\n        title: Show sensitive media in OpenGraph previews\n      profile_directory:\n        desc_html: Allow users to be discoverable\n        title: Enable profile directory\n      registrations:\n        closed_message:\n          desc_html: Displayed on frontpage when registrations are closed. You can use HTML tags\n          title: Closed registration message\n        deletion:\n          desc_html: Allow anyone to delete their account\n          title: Open account deletion\n        min_invite_role:\n          disabled: No one\n          title: Allow invitations by\n      registrations_mode:\n        modes:\n          approved: Approval required for sign up\n          none: Nobody can sign up\n          open: Anyone can sign up\n        title: Registrations mode\n      show_known_fediverse_at_about_page:\n        desc_html: When toggled, it will show toots from all the known fediverse on preview. Otherwise it will only show local toots.\n        title: Show known fediverse on timeline preview\n      show_staff_badge:\n        desc_html: Show a staff badge on a user page\n        title: Show staff badge\n      site_description:\n        desc_html: Introductory paragraph on the frontpage. Describe what makes this Mastodon server special and anything else important. You can use HTML tags, in particular <code>&lt;a&gt;</code> and <code>&lt;em&gt;</code>.\n        title: Server description\n      site_description_extended:\n        desc_html: A good place for your code of conduct, rules, guidelines and other things that set your server apart. You can use HTML tags\n        title: Custom extended information\n      site_short_description:\n        desc_html: Displayed in sidebar and meta tags. Describe what Mastodon is and what makes this server special in a single paragraph. If empty, defaults to server description.\n        title: Short server description\n      site_terms:\n        desc_html: You can write your own privacy policy, terms of service or other legalese. You can use HTML tags\n        title: Custom terms of service\n      site_title: Server name\n      thumbnail:\n        desc_html: Used for previews via OpenGraph and API. 1200x630px recommended\n        title: Server thumbnail\n      timeline_preview:\n        desc_html: Display public timeline on landing page\n        title: Timeline preview\n      title: Site settings\n    statuses:\n      back_to_account: Back to account page\n      batch:\n        delete: Delete\n        nsfw_off: Mark as not sensitive\n        nsfw_on: Mark as sensitive\n      failed_to_execute: Failed to execute\n      media:\n        title: Media\n      no_media: No media\n      no_status_selected: No statuses were changed as none were selected\n      title: Account statuses\n      with_media: With media\n    subscriptions:\n      callback_url: Callback URL\n      confirmed: Confirmed\n      expires_in: Expires in\n      last_delivery: Last delivery\n      title: WebSub\n      topic: Topic\n    tags:\n      accounts: Accounts\n      hidden: Hidden\n      hide: Hide from directory\n      name: Hashtag\n      title: Hashtags\n      unhide: Show in directory\n      visible: Visible\n    title: Administration\n    warning_presets:\n      add_new: Add new\n      delete: Delete\n      edit: Edit\n      edit_preset: Edit warning preset\n      title: Manage warning presets\n  admin_mailer:\n    new_pending_account:\n      body: The details of the new account are below. You can approve or reject this application.\n      subject: New account up for review on %{instance} (%{username})\n    new_report:\n      body: \"%{reporter} has reported %{target}\"\n      body_remote: Someone from %{domain} has reported %{target}\n      subject: New report for %{instance} (#%{id})\n  application_mailer:\n    notification_preferences: Change e-mail preferences\n    salutation: \"%{name},\"\n    settings: 'Change e-mail preferences: %{link}'\n    view: 'View:'\n    view_profile: View Profile\n    view_status: View status\n  applications:\n    created: Application successfully created\n    destroyed: Application successfully deleted\n    invalid_url: The provided URL is invalid\n    regenerate_token: Regenerate access token\n    token_regenerated: Access token successfully regenerated\n    warning: Be very careful with this data. Never share it with anyone!\n    your_token: Your access token\n  auth:\n    apply_for_account: Request an invite\n    change_password: Password\n    checkbox_agreement_html: I agree to the <a href=\"%{rules_path}\" target=\"_blank\">server rules</a> and <a href=\"%{terms_path}\" target=\"_blank\">terms of service</a>\n    confirm_email: Confirm email\n    delete_account: Delete account\n    delete_account_html: If you wish to delete your account, you can <a href=\"%{path}\">proceed here</a>. You will be asked for confirmation.\n    didnt_get_confirmation: Didn't receive confirmation instructions?\n    forgot_password: Forgot your password?\n    invalid_reset_password_token: Password reset token is invalid or expired. Please request a new one.\n    login: Log in\n    logout: Logout\n    migrate_account: Move to a different account\n    migrate_account_html: If you wish to redirect this account to a different one, you can <a href=\"%{path}\">configure it here</a>.\n    or_log_in_with: Or log in with\n    providers:\n      cas: CAS\n      saml: SAML\n    register: Sign up\n    registration_closed: \"%{instance} is not accepting new members\"\n    resend_confirmation: Resend confirmation instructions\n    reset_password: Reset password\n    security: Security\n    set_new_password: Set new password\n    trouble_logging_in: Trouble logging in?\n  authorize_follow:\n    already_following: You are already following this account\n    error: Unfortunately, there was an error looking up the remote account\n    follow: Follow\n    follow_request: 'You have sent a follow request to:'\n    following: 'Success! You are now following:'\n    post_follow:\n      close: Or, you can just close this window.\n      return: Show the user's profile\n      web: Go to web\n    title: Follow %{acct}\n  datetime:\n    distance_in_words:\n      about_x_hours: \"%{count}h\"\n      about_x_months: \"%{count}mo\"\n      about_x_years: \"%{count}y\"\n      almost_x_years: \"%{count}y\"\n      half_a_minute: Just now\n      less_than_x_minutes: \"%{count}m\"\n      less_than_x_seconds: Just now\n      over_x_years: \"%{count}y\"\n      x_days: \"%{count}d\"\n      x_minutes: \"%{count}m\"\n      x_months: \"%{count}mo\"\n      x_seconds: \"%{count}s\"\n  deletes:\n    bad_password_msg: Nice try, hackers! Incorrect password\n    confirm_password: Enter your current password to verify your identity\n    description_html: This will <strong>permanently, irreversibly</strong> remove content from your account and deactivate it. Your username will remain reserved to prevent future impersonations.\n    proceed: Delete account\n    success_msg: Your account was successfully deleted\n    warning_html: Only deletion of content from this particular server is guaranteed. Content that has been widely shared is likely to leave traces. Offline servers and servers that have unsubscribed from your updates will not update their databases.\n    warning_title: Disseminated content availability\n  directories:\n    directory: Profile directory\n    enabled: You are currently listed in the directory.\n    enabled_but_waiting: You have opted-in to be listed in the directory, but you do not have the minimum number of followers (%{min_followers}) to be listed yet.\n    explanation: Discover users based on their interests\n    explore_mastodon: Explore %{title}\n    how_to_enable: You are not currently opted-in to the directory. You can opt-in below. Use hashtags in your bio text to be listed under specific hashtags!\n    people:\n      one: \"%{count} person\"\n      other: \"%{count} people\"\n  errors:\n    '403': You don't have permission to view this page.\n    '404': The page you are looking for isn't here.\n    '410': The page you were looking for doesn't exist here anymore.\n    '422':\n      content: Security verification failed. Are you blocking cookies?\n      title: Security verification failed\n    '429': Throttled\n    '500':\n      content: We're sorry, but something went wrong on our end.\n      title: This page is not correct\n    noscript_html: To use the Mastodon web application, please enable JavaScript. Alternatively, try one of the <a href=\"%{apps_path}\">native apps</a> for Mastodon for your platform.\n  exports:\n    archive_takeout:\n      date: Date\n      download: Download your archive\n      hint_html: You can request an archive of your <strong>toots and uploaded media</strong>. The exported data will be in the ActivityPub format, readable by any compliant software. You can request an archive every 7 days.\n      in_progress: Compiling your archive...\n      request: Request your archive\n      size: Size\n    blocks: You block\n    csv: CSV\n    domain_blocks: Domain blocks\n    follows: You follow\n    lists: Lists\n    mutes: You mute\n    storage: Media storage\n  featured_tags:\n    add_new: Add new\n    errors:\n      limit: You have already featured the maximum amount of hashtags\n  filters:\n    contexts:\n      home: Home timeline\n      notifications: Notifications\n      public: Public timelines\n      thread: Conversations\n    edit:\n      title: Edit filter\n    errors:\n      invalid_context: None or invalid context supplied\n      invalid_irreversible: Irreversible filtering only works with home or notifications context\n    index:\n      delete: Delete\n      title: Filters\n    new:\n      title: Add new filter\n  footer:\n    developers: Developers\n    more: More…\n    resources: Resources\n  generic:\n    all: All\n    changes_saved_msg: Changes successfully saved!\n    copy: Copy\n    save_changes: Save changes\n    validation_errors:\n      one: Something isn't quite right yet! Please review the error below\n      other: Something isn't quite right yet! Please review %{count} errors below\n  identity_proofs:\n    active: Active\n    authorize: Yes, authorize\n    authorize_connection_prompt: Authorize this cryptographic connection?\n    errors:\n      failed: The cryptographic connection failed. Please try again from %{provider}.\n      keybase:\n        invalid_token: Keybase tokens are hashes of signatures and must be 66 hex characters\n        verification_failed: Keybase does not recognize this token as a signature of Keybase user %{kb_username}. Please retry from Keybase.\n    explanation_html: Here you can cryptographically connect your other identities, such as a Keybase profile. This lets other people send you encrypted messages and trust content you send them.\n    i_am_html: I am %{username} on %{service}.\n    identity: Identity\n    inactive: Inactive\n    status: Verification status\n    view_proof: View proof\n  imports:\n    modes:\n      merge: Merge\n      merge_long: Keep existing records and add new ones\n      overwrite: Overwrite\n      overwrite_long: Replace current records with the new ones\n    preface: You can import data that you have exported from another server, such as a list of the people you are following or blocking.\n    success: Your data was successfully uploaded and will now be processed in due time\n    types:\n      blocking: Blocking list\n      domain_blocking: Domain blocking list\n      following: Following list\n      muting: Muting list\n    upload: Upload\n  in_memoriam_html: In Memoriam.\n  invites:\n    delete: Deactivate\n    expired: Expired\n    expires_in:\n      '1800': 30 minutes\n      '21600': 6 hours\n      '3600': 1 hour\n      '43200': 12 hours\n      '604800': 1 week\n      '86400': 1 day\n    expires_in_prompt: Never\n    generate: Generate\n    invited_by: 'You were invited by:'\n    max_uses:\n      one: 1 use\n      other: \"%{count} uses\"\n    max_uses_prompt: No limit\n    prompt: Generate and share links with others to grant access to this server\n    table:\n      expires_at: Expires\n      uses: Uses\n    title: Invite people\n  lists:\n    errors:\n      limit: You have reached the maximum amount of lists\n  media_attachments:\n    validations:\n      images_and_video: Cannot attach a video to a status that already contains images\n      too_many: Cannot attach more than 4 files\n  migrations:\n    acct: username@domain of the new account\n    currently_redirecting: 'Your profile is set to redirect to:'\n    proceed: Save\n    updated_msg: Your account migration setting successfully updated!\n  moderation:\n    title: Moderation\n  notification_mailer:\n    digest:\n      action: View all notifications\n      body: Here is a brief summary of the messages you missed since your last visit on %{since}\n      mention: \"%{name} mentioned you in:\"\n      new_followers_summary:\n        one: Also, you have acquired one new follower while being away! Yay!\n        other: Also, you have acquired %{count} new followers while being away! Amazing!\n      subject:\n        one: \"1 new notification since your last visit \\U0001F418\"\n        other: \"%{count} new notifications since your last visit \\U0001F418\"\n      title: In your absence...\n    favourite:\n      body: 'Your status was favourited by %{name}:'\n      subject: \"%{name} favourited your status\"\n      title: New favourite\n    follow:\n      body: \"%{name} is now following you!\"\n      subject: \"%{name} is now following you\"\n      title: New follower\n    follow_request:\n      action: Manage follow requests\n      body: \"%{name} has requested to follow you\"\n      subject: 'Pending follower: %{name}'\n      title: New follow request\n    mention:\n      action: Reply\n      body: 'You were mentioned by %{name} in:'\n      subject: You were mentioned by %{name}\n      title: New mention\n    reblog:\n      body: 'Your status was boosted by %{name}:'\n      subject: \"%{name} boosted your status\"\n      title: New boost\n  number:\n    human:\n      decimal_units:\n        format: \"%n%u\"\n        units:\n          billion: B\n          million: M\n          quadrillion: Q\n          thousand: K\n          trillion: T\n  pagination:\n    newer: Newer\n    next: Next\n    older: Older\n    prev: Prev\n    truncate: \"&hellip;\"\n  polls:\n    errors:\n      already_voted: You have already voted on this poll\n      duplicate_options: contain duplicate items\n      duration_too_long: is too far into the future\n      duration_too_short: is too soon\n      expired: The poll has already ended\n      over_character_limit: cannot be longer than %{max} characters each\n      too_few_options: must have more than one item\n      too_many_options: can't contain more than %{max} items\n  preferences:\n    other: Other\n  relationships:\n    activity: Account activity\n    dormant: Dormant\n    moved: Moved\n    mutual: Mutual\n    primary: Primary\n    relationship: Relationship\n    remove_selected_domains: Remove all followers from the selected domains\n    remove_selected_followers: Remove selected followers\n    remove_selected_follows: Unfollow selected users\n    status: Account status\n  remote_follow:\n    acct: Enter your username@domain you want to act from\n    missing_resource: Could not find the required redirect URL for your account\n    no_account_html: Don't have an account? You can <a href='%{sign_up_path}' target='_blank'>sign up here</a>\n    proceed: Proceed to follow\n    prompt: 'You are going to follow:'\n    reason_html: \"<strong>Why is this step necessary?</strong> <code>%{instance}</code> might not be the server where you are registered, so we need to redirect you to your home server first.\"\n  remote_interaction:\n    favourite:\n      proceed: Proceed to favourite\n      prompt: 'You want to favourite this toot:'\n    reblog:\n      proceed: Proceed to boost\n      prompt: 'You want to boost this toot:'\n    reply:\n      proceed: Proceed to reply\n      prompt: 'You want to reply to this toot:'\n  remote_unfollow:\n    error: Error\n    title: Title\n    unfollowed: Unfollowed\n  scheduled_statuses:\n    over_daily_limit: You have exceeded the limit of %{limit} scheduled toots for that day\n    over_total_limit: You have exceeded the limit of %{limit} scheduled toots\n    too_soon: The scheduled date must be in the future\n  sessions:\n    activity: Last activity\n    browser: Browser\n    browsers:\n      alipay: Alipay\n      blackberry: Blackberry\n      chrome: Chrome\n      edge: Microsoft Edge\n      electron: Electron\n      firefox: Firefox\n      generic: Unknown browser\n      ie: Internet Explorer\n      micro_messenger: MicroMessenger\n      nokia: Nokia S40 Ovi Browser\n      opera: Opera\n      otter: Otter\n      phantom_js: PhantomJS\n      qq: QQ Browser\n      safari: Safari\n      uc_browser: UCBrowser\n      weibo: Weibo\n    current_session: Current session\n    description: \"%{browser} on %{platform}\"\n    explanation: These are the web browsers currently logged in to your Mastodon account.\n    ip: IP\n    platforms:\n      adobe_air: Adobe Air\n      android: Android\n      blackberry: Blackberry\n      chrome_os: ChromeOS\n      firefox_os: Firefox OS\n      ios: iOS\n      linux: Linux\n      mac: Mac\n      other: unknown platform\n      windows: Windows\n      windows_mobile: Windows Mobile\n      windows_phone: Windows Phone\n    revoke: Revoke\n    revoke_success: Session successfully revoked\n    title: Sessions\n  settings:\n    authorized_apps: Authorized apps\n    back: Back to Mastodon\n    delete: Account deletion\n    development: Development\n    edit_profile: Edit profile\n    export: Data export\n    featured_tags: Featured hashtags\n    identity_proofs: Identity proofs\n    import: Import\n    migrate: Account migration\n    notifications: Notifications\n    preferences: Preferences\n    relationships: Follows and followers\n    two_factor_authentication: Two-factor Auth\n  statuses:\n    attached:\n      description: 'Attached: %{attached}'\n      image:\n        one: \"%{count} image\"\n        other: \"%{count} images\"\n      video:\n        one: \"%{count} video\"\n        other: \"%{count} videos\"\n    boosted_from_html: Boosted from %{acct_link}\n    content_warning: 'Content warning: %{warning}'\n    disallowed_hashtags:\n      one: 'contained a disallowed hashtag: %{tags}'\n      other: 'contained the disallowed hashtags: %{tags}'\n    language_detection: Automatically detect language\n    open_in_web: Open in web\n    over_character_limit: character limit of %{max} exceeded\n    pin_errors:\n      limit: You have already pinned the maximum number of toots\n      ownership: Someone else's toot cannot be pinned\n      private: Non-public toot cannot be pinned\n      reblog: A boost cannot be pinned\n    poll:\n      total_votes:\n        one: \"%{count} vote\"\n        other: \"%{count} votes\"\n      vote: Vote\n    show_more: Show more\n    sign_in_to_participate: Sign in to participate in the conversation\n    title: '%{name}: \"%{quote}\"'\n    visibilities:\n      private: Followers-only\n      private_long: Only show to followers\n      public: Public\n      public_long: Everyone can see\n      unlisted: Unlisted\n      unlisted_long: Everyone can see, but not listed on public timelines\n  stream_entries:\n    pinned: Pinned toot\n    reblogged: boosted\n    sensitive_content: Sensitive content\n  terms:\n    body_html: |\n      <h2>Privacy Policy</h2>\n      <h3 id=\"collect\">What information do we collect?</h3>\n\n      <ul>\n        <li><em>Basic account information</em>: If you register on this server, you may be asked to enter a username, an e-mail address and a password. You may also enter additional profile information such as a display name and biography, and upload a profile picture and header image. The username, display name, biography, profile picture and header image are always listed publicly.</li>\n        <li><em>Posts, following and other public information</em>: The list of people you follow is listed publicly, the same is true for your followers. When you submit a message, the date and time is stored as well as the application you submitted the message from. Messages may contain media attachments, such as pictures and videos. Public and unlisted posts are available publicly. When you feature a post on your profile, that is also publicly available information. Your posts are delivered to your followers, in some cases it means they are delivered to different servers and copies are stored there. When you delete posts, this is likewise delivered to your followers. The action of reblogging or favouriting another post is always public.</li>\n        <li><em>Direct and followers-only posts</em>: All posts are stored and processed on the server. Followers-only posts are delivered to your followers and users who are mentioned in them, and direct posts are delivered only to users mentioned in them. In some cases it means they are delivered to different servers and copies are stored there. We make a good faith effort to limit the access to those posts only to authorized persons, but other servers may fail to do so. Therefore it's important to review servers your followers belong to. You may toggle an option to approve and reject new followers manually in the settings. <em>Please keep in mind that the operators of the server and any receiving server may view such messages</em>, and that recipients may screenshot, copy or otherwise re-share them. <em>Do not share any dangerous information over Mastodon.</em></li>\n        <li><em>IPs and other metadata</em>: When you log in, we record the IP address you log in from, as well as the name of your browser application. All the logged in sessions are available for your review and revocation in the settings. The latest IP address used is stored for up to 12 months. We also may retain server logs which include the IP address of every request to our server.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"use\">What do we use your information for?</h3>\n\n      <p>Any of the information we collect from you may be used in the following ways:</p>\n\n      <ul>\n        <li>To provide the core functionality of Mastodon. You can only interact with other people's content and post your own content when you are logged in. For example, you may follow other people to view their combined posts in your own personalized home timeline.</li>\n        <li>To aid moderation of the community, for example comparing your IP address with other known ones to determine ban evasion or other violations.</li>\n        <li>The email address you provide may be used to send you information, notifications about other people interacting with your content or sending you messages, and to respond to inquiries, and/or other requests or questions.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"protect\">How do we protect your information?</h3>\n\n      <p>We implement a variety of security measures to maintain the safety of your personal information when you enter, submit, or access your personal information. Among other things, your browser session, as well as the traffic between your applications and the API, are secured with SSL, and your password is hashed using a strong one-way algorithm. You may enable two-factor authentication to further secure access to your account.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"data-retention\">What is our data retention policy?</h3>\n\n      <p>We will make a good faith effort to:</p>\n\n      <ul>\n        <li>Retain server logs containing the IP address of all requests to this server, in so far as such logs are kept, no more than 90 days.</li>\n        <li>Retain the IP addresses associated with registered users no more than 12 months.</li>\n      </ul>\n\n      <p>You can request and download an archive of your content, including your posts, media attachments, profile picture, and header image.</p>\n\n      <p>You may irreversibly delete your account at any time.</p>\n\n      <hr class=\"spacer\"/>\n\n      <h3 id=\"cookies\">Do we use cookies?</h3>\n\n      <p>Yes. Cookies are small files that a site or its service provider transfers to your computer's hard drive through your Web browser (if you allow). These cookies enable the site to recognize your browser and, if you have a registered account, associate it with your registered account.</p>\n\n      <p>We use cookies to understand and save your preferences for future visits.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"disclose\">Do we disclose any information to outside parties?</h3>\n\n      <p>We do not sell, trade, or otherwise transfer to outside parties your personally identifiable information. This does not include trusted third parties who assist us in operating our site, conducting our business, or servicing you, so long as those parties agree to keep this information confidential. We may also release your information when we believe release is appropriate to comply with the law, enforce our site policies, or protect ours or others rights, property, or safety.</p>\n\n      <p>Your public content may be downloaded by other servers in the network. Your public and followers-only posts are delivered to the servers where your followers reside, and direct messages are delivered to the servers of the recipients, in so far as those followers or recipients reside on a different server than this.</p>\n\n      <p>When you authorize an application to use your account, depending on the scope of permissions you approve, it may access your public profile information, your following list, your followers, your lists, all your posts, and your favourites. Applications can never access your e-mail address or password.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"children\">Site usage by children</h3>\n\n      <p>If this server is in the EU or the EEA: Our site, products and services are all directed to people who are at least 16 years old. If you are under the age of 16, per the requirements of the GDPR (<a href=\"https://en.wikipedia.org/wiki/General_Data_Protection_Regulation\">General Data Protection Regulation</a>) do not use this site.</p>\n\n      <p>If this server is in the USA: Our site, products and services are all directed to people who are at least 13 years old. If you are under the age of 13, per the requirements of COPPA (<a href=\"https://en.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act\">Children's Online Privacy Protection Act</a>) do not use this site.</p>\n\n      <p>Law requirements can be different if this server is in another jurisdiction.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"changes\">Changes to our Privacy Policy</h3>\n\n      <p>If we decide to change our privacy policy, we will post those changes on this page.</p>\n\n      <p>This document is CC-BY-SA. It was last updated March 7, 2018.</p>\n\n      <p>Originally adapted from the <a href=\"https://github.com/discourse/discourse\">Discourse privacy policy</a>.</p>\n    title: \"%{instance} Terms of Service and Privacy Policy\"\n  themes:\n    contrast: Mastodon (High contrast)\n    default: Mastodon (Dark)\n    mastodon-light: Mastodon (Light)\n  time:\n    formats:\n      default: \"%b %d, %Y, %H:%M\"\n      month: \"%b %Y\"\n  two_factor_authentication:\n    code_hint: Enter the code generated by your authenticator app to confirm\n    description_html: If you enable <strong>two-factor authentication</strong>, logging in will require you to be in possession of your phone, which will generate tokens for you to enter.\n    disable: Disable\n    enable: Enable\n    enabled: Two-factor authentication is enabled\n    enabled_success: Two-factor authentication successfully enabled\n    generate_recovery_codes: Generate recovery codes\n    instructions_html: \"<strong>Scan this QR code into Google Authenticator or a similiar TOTP app on your phone</strong>. From now on, that app will generate tokens that you will have to enter when logging in.\"\n    lost_recovery_codes: Recovery codes allow you to regain access to your account if you lose your phone. If you've lost your recovery codes, you can regenerate them here. Your old recovery codes will be invalidated.\n    manual_instructions: 'If you can''t scan the QR code and need to enter it manually, here is the plain-text secret:'\n    recovery_codes: Backup recovery codes\n    recovery_codes_regenerated: Recovery codes successfully regenerated\n    recovery_instructions_html: If you ever lose access to your phone, you can use one of the recovery codes below to regain access to your account. <strong>Keep the recovery codes safe</strong>. For example, you may print them and store them with other important documents.\n    setup: Set up\n    wrong_code: The entered code was invalid! Are server time and device time correct?\n  user_mailer:\n    backup_ready:\n      explanation: You requested a full backup of your Mastodon account. It's now ready for download!\n      subject: Your archive is ready for download\n      title: Archive takeout\n    warning:\n      explanation:\n        disable: While your account is frozen, your account data remains intact, but you cannot perform any actions until it is unlocked.\n        silence: While your account is limited, only people who are already following you will see your toots on this server, and you may be excluded from various public listings. However, others may still manually follow you.\n        suspend: Your account has been suspended, and all of your toots and your uploaded media files have been irreversibly removed from this server, and servers where you had followers.\n      review_server_policies: Review server policies\n      subject:\n        disable: Your account %{acct} has been frozen\n        none: Warning for %{acct}\n        silence: Your account %{acct} has been limited\n        suspend: Your account %{acct} has been suspended\n      title:\n        disable: Account frozen\n        none: Warning\n        silence: Account limited\n        suspend: Account suspended\n    welcome:\n      edit_profile_action: Setup profile\n      edit_profile_step: You can customize your profile by uploading an avatar, header, changing your display name and more. If you’d like to review new followers before they’re allowed to follow you, you can lock your account.\n      explanation: Here are some tips to get you started\n      final_action: Start posting\n      final_step: 'Start posting! Even without followers your public messages may be seen by others, for example on the local timeline and in hashtags. You may want to introduce yourself on the #introductions hashtag.'\n      full_handle: Your full handle\n      full_handle_hint: This is what you would tell your friends so they can message or follow you from another server.\n      review_preferences_action: Change preferences\n      review_preferences_step: Make sure to set your preferences, such as which emails you'd like to receive, or what privacy level you’d like your posts to default to. If you don’t have motion sickness, you could choose to enable GIF autoplay.\n      subject: Welcome to Mastodon\n      tip_federated_timeline: The federated timeline is a firehose view of the Mastodon network. But it only includes people your neighbours are subscribed to, so it's not complete.\n      tip_following: You follow your server's admin(s) by default. To find more interesting people, check the local and federated timelines.\n      tip_local_timeline: The local timeline is a firehose view of people on %{instance}. These are your immediate neighbours!\n      tip_mobile_webapp: If your mobile browser offers you to add Mastodon to your homescreen, you can receive push notifications. It acts like a native app in many ways!\n      tips: Tips\n      title: Welcome aboard, %{name}!\n  users:\n    follow_limit_reached: You cannot follow more than %{limit} people\n    invalid_email: The e-mail address is invalid\n    invalid_otp_token: Invalid two-factor code\n    otp_lost_help_html: If you lost access to both, you may get in touch with %{email}\n    seamless_external_login: You are logged in via an external service, so password and e-mail settings are not available.\n    signed_in_as: 'Signed in as:'\n  verification:\n    explanation_html: 'You can <strong>verify yourself as the owner of the links in your profile metadata</strong>. For that, the linked website must contain a link back to your Mastodon profile. The link back <strong>must</strong> have a <code>rel=\"me\"</code> attribute. The text content of the link does not matter. Here is an example:'\n    verification: Verification\n"
  },
  {
    "path": "config/locales/eo.yml",
    "content": "---\neo:\n  about:\n    about_hashtag_html: Ĉi tiuj estas la publikaj fajfoj markitaj per <strong>#%{hashtag}</strong>. Vi povas interagi kun ili se vi havas konton ie ajn en la fediverse.\n    about_mastodon_html: Mastodon estas socia reto bazita sur malfermitaj retaj protokoloj kaj sur libera malfermitkoda programo. Ĝi estas sencentra kiel retmesaĝoj.\n    about_this: Pri\n    active_count_after: aktiva\n    active_footnote: Monate Aktivaj Uzantoj (MAU)\n    administered_by: 'Administrata de:'\n    api: API\n    apps: Poŝtelefonaj aplikaĵoj\n    apps_platforms: Uzu Mastodon ĉe iOS, Android kaj aliajn platformojn\n    browse_directory: Esplori profilujo kaj filtri per interesoj\n    browse_public_posts: Vidi vivantan fluon de publikaj mesaĝoj al Mastodon\n    contact: Kontakti\n    contact_missing: Ne elektita\n    contact_unavailable: Ne disponebla\n    discover_users: Malkovri uzantojn\n    documentation: Dokumentado\n    extended_description_html: |\n      <h3>Bona loko por reguloj</h3>\n      <p>La detala priskribo ne estis elektita.</p>\n    federation_hint_html: Per konto ĉe %{instance}, vi povos sekvi homojn ĉe iu ajn Mastodon nodo kaj preter.\n    generic_description: \"%{domain} estas unu servilo en la reto\"\n    get_apps: Provu telefonan aplikaĵon\n    hosted_on: \"%{domain} estas nodo de Mastodon\"\n    learn_more: Lerni pli\n    privacy_policy: Privateca politiko\n    see_whats_happening: Vidi kio okazas\n    server_stats: Servo statuso\n    source_code: Fontkodo\n    status_count_after:\n      one: mesaĝo\n      other: mesaĝoj\n    status_count_before: Kie skribiĝis\n    tagline: Sekvi amikojn kaj trovi novan onin\n    terms: Uzkondiĉoj\n    user_count_after:\n      one: uzanto\n      other: uzantoj\n    user_count_before: Hejmo de\n    what_is_mastodon: Kio estas Mastodon?\n  accounts:\n    choices_html: 'Proponoj de %{name}:'\n    follow: Sekvi\n    followers:\n      one: Sekvanto\n      other: Sekvantoj\n    following: Sekvatoj\n    joined: Aliĝis je %{date}\n    last_active: laste aktiva\n    link_verified_on: Proprieto de ĉi tiu ligilo estis kontrolita je %{date}\n    media: Aŭdovidaĵoj\n    moved_html: \"%{name} moviĝis al %{new_profile_link}:\"\n    network_hidden: Tiu informo ne estas disponebla\n    nothing_here: Estas nenio ĉi tie!\n    people_followed_by: Sekvatoj de %{name}\n    people_who_follow: Sekvantoj de %{name}\n    pin_errors:\n      following: Vi devas sekvi la homon, kiun vi volas proponi\n    posts:\n      one: Mesaĝo\n      other: Mesaĝoj\n    posts_tab_heading: Mesaĝoj\n    posts_with_replies: Mesaĝoj kaj respondoj\n    reserved_username: La uzantnomo estas rezervita\n    roles:\n      admin: Administranto\n      bot: Roboto\n      moderator: Kontrolanto\n    unavailable: Profilo ne disponebla\n    unfollow: Ne plu sekvi\n  admin:\n    account_actions:\n      action: Plenumi agon\n      title: Plenumi kontrolan agon al %{acct}\n    account_moderation_notes:\n      create: Lasi noton\n      created_msg: Kontrola noto sukcese kreita!\n      delete: Forigi\n      destroyed_msg: Kontrola noto sukcese detruita!\n    accounts:\n      approve: Aprobi\n      approve_all: Aprobi ĉiujn\n      are_you_sure: Ĉu vi certas?\n      avatar: Profilbildo\n      by_domain: Domajno\n      change_email:\n        changed_msg: Konta retadreso sukcese ŝanĝita!\n        current_email: Nuna retadreso\n        label: Ŝanĝi retadreson\n        new_email: Nova retadreso\n        submit: Ŝanĝi retadreson\n        title: Ŝanĝi retadreson por %{username}\n      confirm: Konfirmi\n      confirmed: Konfirmita\n      confirming: Konfirmante\n      deleted: Forigita\n      demote: Degradi\n      disable: Malebligi\n      disable_two_factor_authentication: Malebligi 2FA\n      disabled: Malebligita\n      display_name: Montrata nomo\n      domain: Domajno\n      edit: Redakti\n      email: Retadreso\n      email_status: Retadreso Stato\n      enable: Ebligi\n      enabled: Ebligita\n      feed_url: URL de la fluo\n      followers: Sekvantoj\n      followers_url: URL de la sekvantoj\n      follows: Sekvatoj\n      header: Kapa bildo\n      inbox_url: Enira URL\n      invited_by: Invitita de\n      ip: IP\n      joined: Aliĝis\n      location:\n        all: Ĉio\n        local: Lokaj\n        remote: Foraj\n        title: Loko\n      login_status: Ensaluta stato\n      media_attachments: Ligitaj aŭdovidaĵoj\n      memorialize: Ŝanĝi al memoro\n      moderation:\n        active: Aktivaj\n        all: Ĉio\n        pending: Pritraktata\n        silenced: Silentigitaj\n        suspended: Haltigitaj\n        title: Kontrolado\n      moderation_notes: Kontrolaj notoj\n      most_recent_activity: Lasta ago\n      most_recent_ip: Lasta IP\n      no_account_selected: Neniu konto estis ŝanĝita ĉar neniu estis selektita\n      no_limits_imposed: Neniu limito trudita\n      not_subscribed: Ne abonita\n      outbox_url: Elira URL\n      pending: Pritraktata recenzo\n      perform_full_suspension: Haltigi\n      profile_url: Profila URL\n      promote: Plirangigi\n      protocol: Protokolo\n      public: Publika\n      push_subscription_expires: Eksvalidiĝo de la abono al PuSH\n      redownload: Aktualigi profilon\n      reject: Malakcepti\n      reject_all: Malaprobi ĉiujn\n      remove_avatar: Forigi profilbildon\n      remove_header: Forigi kapan bildon\n      resend_confirmation:\n        already_confirmed: Ĉi tiu uzanto jam estas konfirmita\n        send: Esend konfirmi retpoŝton\n        success: Konfirma retmesaĝo sukcese sendita!\n      reset: Restarigi\n      reset_password: Restarigi pasvorton\n      resubscribe: Reaboni\n      role: Permesoj\n      roles:\n        admin: Administranto\n        moderator: Kontrolanto\n        staff: Teamo\n        user: Uzanto\n      salmon_url: Salmon-URL\n      search: Serĉi\n      shared_inbox_url: URL de kunhavigita leterkesto\n      show:\n        created_reports: Kreitaj signaloj\n        targeted_reports: Signalitaj de aliaj\n      silence: Kaŝi\n      silenced: Silentigita\n      statuses: Mesaĝoj\n      subscribe: Aboni\n      suspended: Haltigita\n      title: Kontoj\n      unconfirmed_email: Nekonfirmita retadreso\n      undo_silenced: Malfari kaŝon\n      undo_suspension: Malfari haltigon\n      unsubscribe: Malaboni\n      username: Uzantnomo\n      warn: Averti\n      web: Reto\n    action_logs:\n      actions:\n        assigned_to_self_report: \"%{name} asignis signalon %{target} al si mem\"\n        change_email_user: \"%{name} ŝanĝis retadreson de uzanto %{target}\"\n        confirm_user: \"%{name} konfirmis retadreson de uzanto %{target}\"\n        create_account_warning: \"%{name} sendis averton al %{target}\"\n        create_custom_emoji: \"%{name} alŝutis novan emoĝion %{target}\"\n        create_domain_block: \"%{name} blokis domajnon %{target}\"\n        create_email_domain_block: \"%{name} metis en nigran liston domajnon %{target}\"\n        demote_user: \"%{name} degradis uzanton %{target}\"\n        destroy_custom_emoji: \"%{name} neniigis la emoĝion %{target}\"\n        destroy_domain_block: \"%{name} malblokis domajnon %{target}\"\n        destroy_email_domain_block: \"%{name} metis en blankan liston domajnon %{target}\"\n        destroy_status: \"%{name} forigis mesaĝojn de %{target}\"\n        disable_2fa_user: \"%{name} malebligis dufaktoran aŭtentigon por uzanto %{target}\"\n        disable_custom_emoji: \"%{name} malebligis emoĝion %{target}\"\n        disable_user: \"%{name} malebligis ensaluton por uzanto %{target}\"\n        enable_custom_emoji: \"%{name} ebligis emoĝion %{target}\"\n        enable_user: \"%{name} ebligis ensaluton por uzanto %{target}\"\n        memorialize_account: \"%{name} ŝanĝis la konton de %{target} al memora paĝo\"\n        promote_user: \"%{name} plirangigis uzanton %{target}\"\n        remove_avatar_user: \"%{name} forigis profilbildon de %{target}\"\n        reopen_report: \"%{name} remalfermis signalon %{target}\"\n        reset_password_user: \"%{name} restarigis pasvorton de uzanto %{target}\"\n        resolve_report: \"%{name} solvis signalon %{target}\"\n        silence_account: \"%{name} kaŝis la konton de %{target}\"\n        suspend_account: \"%{name} haltigis la konton de %{target}\"\n        unassigned_report: \"%{name} malasignis signalon %{target}\"\n        unsilence_account: \"%{name} malkaŝis la konton de %{target}\"\n        unsuspend_account: \"%{name} malhaltigis la konton de %{target}\"\n        update_custom_emoji: \"%{name} ĝisdatigis emoĝion %{target}\"\n        update_status: \"%{name} ĝisdatigis mesaĝon de %{target}\"\n      deleted_status: \"(forigita mesaĝo)\"\n      title: Kontrola protokolo\n    custom_emojis:\n      by_domain: Domajno\n      copied_msg: Loka kopio de la emoĝio sukcese kreita\n      copy: Kopii\n      copy_failed_msg: Fari lokan kopion de ĉi tiu emoĝio ne eblis\n      created_msg: Emoĝio sukcese kreita!\n      delete: Forigi\n      destroyed_msg: Emoĝio sukcese forigita!\n      disable: Malebligi\n      disabled_msg: Emoĝio sukcese malebligita\n      emoji: Emoĝio\n      enable: Ebligi\n      enabled_msg: Tiu emoĝio estis sukcese ebligita\n      image_hint: PNG ĝis 50KB\n      listed: Listigita\n      new:\n        title: Aldoni novan propran emoĝion\n      overwrite: Anstataŭigi\n      shortcode: Mallonga kodo\n      shortcode_hint: Almenaŭ 2 signoj, nur literoj, ciferoj kaj substrekoj\n      title: Propraj emoĝioj\n      unlisted: Nelistigita\n      update_failed_msg: Ĝisdatigi tiun emoĝion ne eblis\n      updated_msg: Emoĝio sukcese ĝisdatigita!\n      upload: Alŝuti\n    dashboard:\n      backlog: postigitaj taskoj\n      config: Agordado\n      feature_deletions: Forigo de kontoj\n      feature_invites: Invitaj ligiloj\n      feature_profile_directory: Profilujo\n      feature_registrations: Registriĝoj\n      feature_relay: Federacia ripetilo\n      feature_timeline_preview: Templinio antaŭvidi\n      features: Funkcioj\n      hidden_service: Federacio kun kaŝitaj servoj\n      open_reports: nefermitaj raportoj\n      recent_users: Lastatempaj uzantoj\n      search: Tutteksta serĉado\n      single_user_mode: Unuuzanta reĝimo\n      software: Programo\n      space: Memorspaca uzado\n      title: Kontrolpanelo\n      total_users: uzantoj sume\n      trends: Furoroj\n      week_interactions: interagoj tiusemajne\n      week_users_active: aktivaj tiusemajne\n      week_users_new: uzantoj tiusemajne\n    domain_blocks:\n      add_new: Aldoni novan\n      created_msg: Domajna blokado en traktado\n      destroyed_msg: Domajna blokado malfarita\n      domain: Domajno\n      new:\n        create: Krei blokadon\n        hint: La domajna blokado ne evitigos kreadon de novaj kontoj en la datumbazo, sed aplikos specifajn kontrolajn agojn sur ĉi tiujn kontojn aŭtomate kaj retroaktive.\n        severity:\n          desc_html: \"<strong>Kaŝi</strong> igos la mesaĝojn de la konto nevideblaj al tiuj, kiuj ne sekvas tiun. <strong>Haltigi</strong> forigos ĉiujn enhavojn, aŭdovidaĵojn kaj datumojn de la konto. Uzu <strong>Nenio</strong> se vi simple volas malakcepti aŭdovidaĵojn.\"\n          noop: Nenio\n          silence: Kaŝi\n          suspend: Haltigi\n        title: Nova domajna blokado\n      reject_media: Malakcepti aŭdovidajn dosierojn\n      reject_media_hint: Forigas aŭdovidaĵojn loke konservitajn kaj rifuzas alŝuti ajnan estonte. Senzorge pri haltigoj\n      reject_reports: Malakcepti raportojn\n      reject_reports_hint: Ignori ĉiujn raportojn el tiu domajno. Nur gravas por silentigoj\n      rejecting_media: aŭdovidaj dosieroj malakceptiĝas\n      rejecting_reports: raportoj malakceptiĝas\n      severity:\n        silence: silentigita\n        suspend: haltigita\n      show:\n        affected_accounts:\n          one: Unu konto en la datumbazo esta influita\n          other: \"%{count} kontoj en la datumbazo estas influitaj\"\n        retroactive:\n          silence: Malkaŝi ĉiujn kontojn, kiuj ekzistas en ĉi tiu domajno\n          suspend: Malhaltigi ĉiujn kontojn, kiuj ekzistas en ĉi tiu domajno\n        title: Malfari domajnan blokadon por %{domain}\n        undo: Malfari\n      undo: Malfari\n    email_domain_blocks:\n      add_new: Aldoni novan\n      created_msg: Retadreso sukcese aldonita al la nigra listo\n      delete: Forigi\n      destroyed_msg: Retadreso sukcese forigita de la nigra listo\n      domain: Domajno\n      new:\n        create: Aldoni domajnon\n        title: Nova blokado de retadresa domajno\n      title: Nigra listo de retadresaj domajnoj\n    followers:\n      back_to_account: Reen al la konto\n      title: Sekvantoj de %{acct}\n    instances:\n      by_domain: Domajno\n      delivery_available: Liverado disponeblas\n      known_accounts:\n        one: \"%{count} konata konto\"\n        other: \"%{count} konataj kontoj\"\n      moderation:\n        all: Ĉiuj\n        limited: Limigita\n        title: Kontrolo\n      title: Federacio\n      total_blocked_by_us: Blokitaj de ni\n      total_followed_by_them: Sekvataj de ili\n      total_followed_by_us: Sekvataj de ni\n      total_reported: Raportoj pri ili\n      total_storage: Aŭdovidaj kunsendaĵoj\n    invites:\n      deactivate_all: Malaktivigi ĉion\n      filter:\n        all: Ĉio\n        available: Disponebla\n        expired: Eksvalida\n        title: Filtri\n      title: Invitoj\n    relays:\n      add_new: Aldoni novan ripetilon\n      delete: Forigi\n      description_html: \"<strong>Fratara ripetilo</strong> estas survoja servilo, kiu interŝanĝas grandan kvanton de publikaj mesaĝoj inter serviloj, kiuj abonas kaj publikigas al ĝi. <strong>Ĝi povas helpi etajn kaj mezgrandajn servilojn malkovri enhavon de la fediverse</strong>, kio normale postulus al lokaj uzantoj mane sekvi homojn de foraj serviloj.\"\n      disable: Malebligi\n      disabled: Malebligita\n      enable: Ebligi\n      enable_hint: Post ebligo, via servilo abonos ĉiujn publikajn mesaĝojn de tiu ripetilo, kaj komencos sendi publikajn mesaĝojn de la servilo al ĝi.\n      enabled: Malebligita\n      inbox_url: URL de la ripetilo\n      pending: Atendante aprobon de la ripetilo\n      save_and_enable: Konservi kaj ebligi\n      setup: Agordi konekton al ripetilo\n      status: Stato\n      title: Ripetiloj\n    report_notes:\n      created_msg: Signala noto sukcese kreita!\n      destroyed_msg: Signala noto sukcese forigita!\n    reports:\n      account:\n        note: noto\n        report: signalo\n      action_taken_by: Ago farita de\n      are_you_sure: Ĉu vi certas?\n      assign_to_self: Asigni al mi\n      assigned: Asignita kontrolanto\n      comment:\n        none: Nenio\n      created_at: Signalita\n      mark_as_resolved: Marki solvita\n      mark_as_unresolved: Marki nesolvita\n      notes:\n        create: Aldoni noton\n        create_and_resolve: Solvi per noto\n        create_and_unresolve: Remalfermi per noto\n        delete: Forigi\n        placeholder: Priskribu faritajn agojn, aŭ ajnan novan informon pri tiu signalo…\n      reopen: Remalfermi signalon\n      report: 'Signalo #%{id}'\n      reported_account: Signalita konto\n      reported_by: Signalita de\n      resolved: Solvitaj\n      resolved_msg: Signalo sukcese solvita!\n      status: Mesaĝoj\n      title: Signaloj\n      unassign: Malasigni\n      unresolved: Nesolvitaj\n      updated_at: Ĝisdatigita\n    settings:\n      activity_api_enabled:\n        desc_html: Sumo de lokaj mesaĝoj, aktivaj uzantoj, kaj novaj registriĝoj laŭsemajne\n        title: Publikigi kunmetitajn statistikojn pri la uzanta agado\n      bootstrap_timeline_accounts:\n        desc_html: Disigi plurajn uzantnomojn per komo. Funkcios nur por lokaj neŝlositaj kontoj. Kiam malplena, la dekomenca valoro estas ĉiuj lokaj administrantoj.\n        title: Dekomencaj sekvadoj por novaj uzantoj\n      contact_information:\n        email: Publika retadreso\n        username: Kontakta uzantnomo\n      custom_css:\n        desc_html: Ŝanĝi la aspekton per CSS ŝargita en ĉiu pago\n        title: Propra CSS\n      hero:\n        desc_html: Montrata en la ĉefpaĝo. Almenaŭ 600x100px rekomendita. Kiam ne agordita, la bildeto de la servilo estos uzata\n        title: Kapbildo\n      mascot:\n        desc_html: Montrata en pluraj paĝoj. Rekomendataj estas almenaŭ 293x205px. Se ĉi tio ne estas agordita, la defaŭlta maskoto uziĝas\n        title: Maskota bildo\n      peers_api_enabled:\n        desc_html: Nomoj de domajnoj, kiujn ĉi tiu servilo renkontis en la federauniverso\n        title: Publikigi liston de malkovritaj serviloj\n      preview_sensitive_media:\n        desc_html: Antaŭvido de ligiloj en aliaj retejoj montros bildeton eĉ se la aŭdovidaĵo estas markita kiel tikla\n        title: Montri tiklajn aŭdovidaĵojn en la antaŭvidoj de OpenGraph\n      profile_directory:\n        desc_html: Permesi al uzantoj esti troveblaj\n        title: Ebligi la profilujon\n      registrations:\n        closed_message:\n          desc_html: Montrita sur la hejma paĝo kiam registriĝoj estas fermitaj. Vi povas uzi HTML-etikedojn\n          title: Mesaĝo pri fermitaj registriĝoj\n        deletion:\n          desc_html: Permesi al iu ajn forigi propran konton\n          title: Permesi forigi konton\n        min_invite_role:\n          disabled: Neniu\n          title: Permesi invitojn de\n      registrations_mode:\n        modes:\n          approved: Bezonas aprobi por aliĝi\n          none: Neniu povas aliĝi\n          open: Iu povas aliĝi\n        title: Registrado modo\n      show_known_fediverse_at_about_page:\n        desc_html: Kiam ŝaltita, ĝi montros mesaĝojn de la tuta konata fediverse antaŭvide. Aliokaze, ĝi montros nur lokajn mesaĝojn.\n        title: Montri konatan fediverse en tempolinia antaŭvido\n      show_staff_badge:\n        desc_html: Montri teaman insignon en paĝo de uzanto\n        title: Montri teaman insignon\n      site_description:\n        desc_html: Enkonduka alineo en la ĉefpaĝo. Priskribu la unikaĵojn de ĉi tiu nodo de Mastodon, kaj ĉiujn aliajn gravaĵojn. Vi povas uzi HTML-etikedojn, kiel <code>&lt;a&gt;</code> kaj <code>&lt;em&gt;</code>.\n        title: Priskribo de la servilo\n      site_description_extended:\n        desc_html: Bona loko por viaj sintenaj reguloj, aliaj reguloj, gvidlinioj kaj aliaj aferoj, kiuj apartigas vian serilon. Vi povas uzi HTML-etikedojn\n        title: Propraj detalaj informoj\n      site_short_description:\n        desc_html: Afiŝita en la flankpanelo kaj metadatumaj etikedoj. Priskribu kio estas Mastodon, kaj kio specialas en ĉi tiu nodo, per unu alineo. Se malplena, la priskribo de la servilo estos uzata.\n        title: Mallonga priskribo de la servilo\n      site_terms:\n        desc_html: Vi povas skribi vian propran privatecan politikon, viajn uzkondiĉojn aŭ aliajn leĝaĵojn. Vi povas uzi HTML-etikedojn\n        title: Propraj uzkondiĉoj\n      site_title: Nomo de la servilo\n      thumbnail:\n        desc_html: Uzata por antaŭvidoj per OpenGraph kaj per API. 1200x630px rekomendita\n        title: Bildeto de la servilo\n      timeline_preview:\n        desc_html: Montri publikan templinion en komenca paĝo\n        title: Tempolinia antaŭvido\n      title: Retejaj agordoj\n    statuses:\n      back_to_account: Reveni al konta paĝo\n      batch:\n        delete: Forigi\n        nsfw_off: Marki ne tikla\n        nsfw_on: Marki tikla\n      failed_to_execute: Ekigo malsukcesa\n      media:\n        title: Aŭdovidaĵoj\n      no_media: Neniu aŭdovidaĵo\n      no_status_selected: Neniu mesaĝo estis ŝanĝita ĉar neniu estis elektita\n      title: Mesaĝoj de la konto\n      with_media: Kun aŭdovidaĵoj\n    subscriptions:\n      callback_url: Revena URL\n      confirmed: Konfirmita\n      expires_in: Eksvalidiĝas je\n      last_delivery: Lasta livero\n      title: WebSub\n      topic: Temo\n    tags:\n      accounts: Kontoj\n      hidden: Kaŝitaj\n      hide: Kaŝi de la profilujo\n      name: Kradvorto\n      title: Kradvortoj\n      unhide: Montri en la profilujo\n      visible: Videblaj\n    title: Administrado\n    warning_presets:\n      add_new: Aldoni novan\n      delete: Forigi\n      edit: Redakti\n      edit_preset: Redakti avertan antaŭagordon\n      title: Administri avertajn antaŭagordojn\n  admin_mailer:\n    new_pending_account:\n      body: La detaloj de la nova konto estas sube. Vi povas aprobi aŭ Malakcepti ĉi kandidatiĝo.\n      subject: Nova konto atendas por recenzo en %{instance} (%{username})\n    new_report:\n      body: \"%{reporter} signalis %{target}\"\n      body_remote: Iu de %{domain} signalis %{target}\n      subject: Nova signalo por %{instance} (#%{id})\n  appearance:\n    advanced_web_interface: Altnivela retpaĝa interfaco\n    confirmation_dialogs: Konfirmaj dialogoj\n    sensitive_content: Tikla enhavo\n  application_mailer:\n    notification_preferences: Ŝanĝi retmesaĝajn preferojn\n    salutation: \"%{name},\"\n    settings: 'Ŝanĝi retmesaĝajn preferojn: %{link}'\n    view: 'Vidi:'\n    view_profile: Vidi profilon\n    view_status: Vidi mesaĝon\n  applications:\n    created: Aplikaĵo sukcese kreita\n    destroyed: Aplikaĵo sukcese forigita\n    invalid_url: La URL donita ne estas valida\n    regenerate_token: Rekrei aliran ĵetonon\n    token_regenerated: Alira ĵetono sukcese rekreita\n    warning: Estu tre atenta kun ĉi tiu datumo. Neniam diskonigu ĝin al iu ajn!\n    your_token: Via alira ĵetono\n  auth:\n    apply_for_account: Peti inviton\n    change_password: Pasvorto\n    checkbox_agreement_html: Mi samopinii al la <a href=\"%{rules_path}\" target=\"_blank\">Servo reguloj</a> kaj <a href=\"%{terms_path}\" target=\"_blank\">kondiĉo al servadon</a>\n    confirm_email: Konfirmi retadreson\n    delete_account: Forigi konton\n    delete_account_html: Se vi deziras forigi vian konton, vi povas <a href=\"%{path}\">fari tion ĉi tie</a>. Vi bezonos konfirmi vian peton.\n    didnt_get_confirmation: Ĉu vi ne ricevis la instrukciojn por konfirmi?\n    forgot_password: Pasvorto forgesita?\n    invalid_reset_password_token: Ĵetono por restarigi pasvorton nevalida aŭ eksvalida. Bonvolu peti novan.\n    login: Ensaluti\n    logout: Elsaluti\n    migrate_account: Movi al alia konto\n    migrate_account_html: Se vi deziras alidirekti ĉi tiun konton al alia, vi povas <a href=\"%{path}\">agordi ĝin ĉi tie</a>.\n    or_log_in_with: Aŭ ensaluti per\n    providers:\n      cas: CAS\n      saml: SAML\n    register: Registriĝi\n    registration_closed: \"%{instance} ne estas akcepti nova uzantojn\"\n    resend_confirmation: Resendi la instrukciojn por konfirmi\n    reset_password: Ŝanĝi pasvorton\n    security: Sekureco\n    set_new_password: Elekti novan pasvorton\n    trouble_logging_in: Ĝeni ensaluti?\n  authorize_follow:\n    already_following: Vi jam sekvas tiun konton\n    error: Bedaŭrinde, estis eraro en la serĉado de la fora konto\n    follow: Sekvi\n    follow_request: 'Vi sendis peton de sekvado al:'\n    following: 'Sukceson! Vi nun sekvas:'\n    post_follow:\n      close: Aŭ, vi povas simple fermi ĉi tiun fenestron.\n      return: Montri la profilon de la uzanto\n      web: Iri al reto\n    title: Sekvi %{acct}\n  datetime:\n    distance_in_words:\n      about_x_hours: \"%{count}h\"\n      about_x_months: \"%{count}mo\"\n      about_x_years: \"%{count}j\"\n      almost_x_years: \"%{count}j\"\n      half_a_minute: Ĵuse\n      less_than_x_minutes: \"%{count}m\"\n      less_than_x_seconds: Ĵuse\n      over_x_years: \"%{count}j\"\n      x_days: \"%{count}t\"\n      x_minutes: \"%{count}m\"\n      x_months: \"%{count}mo\"\n      x_seconds: \"%{count}s\"\n  deletes:\n    bad_password_msg: Malĝusta pasvorto\n    confirm_password: Enmetu vian nunan pasvorton por konfirmi vian identecon\n    description_html: Tio <strong>porĉiame kaj neŝanĝeble</strong> forigos la enhavon de via konto kaj malaktivigos ĝin. Via uzantnomo restos rezervita por eviti postajn trompojn pri identeco.\n    proceed: Forigi konton\n    success_msg: Via konto estis sukcese forigita\n    warning_html: La forigo de la enhavo estas certa nur por ĉi tiu aparta servilo. Enhavo, kiu estis disvastigita verŝajne lasos spurojn. Eksterretaj serviloj kaj serviloj, kiuj ne abonas viajn ĝisdatigojn ne ĝisdatigos siajn datumbazojn.\n    warning_title: Disponebleco de disvastigita enhavo\n  directories:\n    directory: Profilujo\n    enabled: Vi estas listigata en la profilujo.\n    enabled_but_waiting: Vi elektis esti listigata en la profilujo, sed vi ankoraŭ ne havas la minimuman kvanton da sekvantoj (%{min_followers}) por esti listigata.\n    explanation: Malkovru uzantojn per iliaj interesoj\n    explore_mastodon: Esplori %{title}\n    how_to_enable: Vi ankoraŭ ne donis permeson listigi vin en la profilujo. Vi povas doni permeson ĉi-sube. Uzu kradvortojn en via biografia teksto por esti listigata sub specifaj kradvortoj!\n    people:\n      one: \"%{count} persono\"\n      other: \"%{count} personoj\"\n  errors:\n    '403': Vi ne havas la rajton por vidi ĉi tiun paĝon.\n    '404': La paĝo ke kiun vi serĉas ne ekzistas ĉi tie.\n    '410': La paĝo, kiun vi serĉas, ne plu ekzistas ĉi tie.\n    '422':\n      content: Sekureca konfirmo malsukcesa. Ĉu vi blokas kuketojn?\n      title: Sekureca konfirmo malsukcesa\n    '429': Datumtrafiko limigita\n    '500':\n      content: Ni bedaŭras, io malsukcesis niaflanke.\n      title: Ĉi tiu paĝo ne estas ĝusta\n    noscript_html: |-\n      Por uzi la retan aplikaĵon de Mastodon, bonvolu ebligi JavaScript. Alimaniere, provu unu el la\n      <a href=\"%{apps_path}\">operaciumaj aplikaĵoj</a> por Mastodon por via platformo.\n  existing_username_validator:\n    not_found: Ne povas trovi lokaj uzanto kun tiu uzantnomo\n    not_found_multiple: Ne povas trovi %{usernames}\n  exports:\n    archive_takeout:\n      date: Dato\n      download: Elŝuti vian arkivon\n      hint_html: Vi povas peti arkivon de viaj <strong>mesaĝoj kaj alŝutitaj aŭdovidaĵoj</strong>. La eksportitaj datumoj estos en la formato ActivityPub, legebla de ajna konformema programo. Vi povas peti arkivon ĉiuseptage.\n      in_progress: Kunmetado de via arkivo…\n      request: Peti vian arkivon\n      size: Grandeco\n    blocks: Vi blokas\n    csv: CSV\n    domain_blocks: Blokoj de domajnoj\n    follows: Vi sekvas\n    lists: Listoj\n    mutes: Vi silentigas\n    storage: Aŭdovidaĵa konservado\n  featured_tags:\n    add_new: Aldoni novan\n    errors:\n      limit: Vi jam elstarigis la maksimuman kvanton da kradvortoj\n  filters:\n    contexts:\n      home: Hejma templinio\n      notifications: Sciigoj\n      public: Publika templinio\n      thread: Konversacioj\n    edit:\n      title: Ŝanĝi filtrilojn\n    errors:\n      invalid_context: Neniu aŭ nevalida kunteksto donita\n      invalid_irreversible: Nemalfarebla filtrado funkcias nur por hejma aŭ sciiga kuntekstoj\n    index:\n      delete: Forigi\n      title: Filtriloj\n    new:\n      title: Aldoni novan filtrilon\n  footer:\n    developers: Programistoj\n    more: Pli…\n    resources: Rimedoj\n  generic:\n    all: Ĉio\n    changes_saved_msg: Ŝanĝoj sukcese konservitaj!\n    copy: Kopii\n    order_by: Ordigi de\n    save_changes: Konservi ŝanĝojn\n    validation_errors:\n      one: Io mise okazis! Bonvolu konsulti la suban erar-raporton\n      other: Io mise okazis! Bonvolu konsulti la subajn %{count} erar-raportojn\n  html_validator:\n    invalid_markup: 'havas malvalida HTML markado: %{error}'\n  identity_proofs:\n    active: Aktiva\n    authorize: Jes, permesi\n    authorize_connection_prompt: Permesi ĉi tiu ĉifrikan conekton?\n    errors:\n      failed: La ĉifrika conekto nefaris. Peti provu denove el %{provider}.\n      keybase:\n        invalid_token: Keybase signo estas haŝoj de subskribo kaj devi 66 deksesuma leteroj\n        verification_failed: Keybase ne rekoni ĉi tiu signo kiel subskribo de Keybase uzanto %{kb_username}. Peti provu denove el Keybase.\n      wrong_user: Ne povas krei por %{proving} dum ensalutis kiel %{current}. Ensaluti kiel %{proving} kaj provu denove.\n    explanation_html: Ĉi tie vi povas ĉifrika konekti via alia identicoj, kiel Keybase profilon. ĉi tiu igi aliaj popoloj sendi al vi ĉifritaj mesaĝoj kaj fidi kontento vi sendi al ilin.\n    i_am_html: Mi estas %{username} en %{service}.\n    identity: Identeco\n    inactive: Malaktiva\n    publicize_checkbox: 'Kaj fajfi ĉi tio:'\n    publicize_toot: 'I estas pruvita! Mi estas %{username} sur %{service}: %{url}'\n    status: Confirmo statuso\n    view_proof: Vidi pruvo\n  imports:\n    modes:\n      merge: Kunigi\n      merge_long: Konservi ekzistajn registrojn kaj aldoni novajn\n      overwrite: Anstataŭigi\n      overwrite_long: Anstataŭigi la nunajn registrojn per la novaj\n    preface: Vi povas importi datumojn, kiujn vi eksportis el alia servilo, kiel liston de homoj, kiujn vi sekvas aŭ blokas.\n    success: Viaj datumoj estis sukcese alŝutitaj kaj estos traktitaj kiel planite\n    types:\n      blocking: Listo de blokitoj\n      domain_blocking: Listo de blokitaj domajnoj\n      following: Listo de sekvatoj\n      muting: Listo de silentigitoj\n    upload: Alŝuti\n  in_memoriam_html: Memore\n  invites:\n    delete: Malaktivigi\n    expired: Eksvalida\n    expires_in:\n      '1800': 30 minutoj\n      '21600': 6 horoj\n      '3600': 1 horo\n      '43200': 12 horoj\n      '604800': 1 semajno\n      '86400': 1 tago\n    expires_in_prompt: Neniam\n    generate: Krei\n    invited_by: 'Vi estis invitita de:'\n    max_uses:\n      one: 1 uzo\n      other: \"%{count} uzoj\"\n    max_uses_prompt: Neniu limo\n    prompt: Krei kaj diskonigi ligilojn al aliaj por doni aliron al ĉi tiu servilo\n    table:\n      expires_at: Eksvalidiĝas je\n      uses: Uzoj\n    title: Inviti homojn\n  lists:\n    errors:\n      limit: Vi atingis la maksimuman kvanton de listoj\n  media_attachments:\n    validations:\n      images_and_video: Aldoni videon al mesaĝo, kiu jam havas bildojn ne eblas\n      too_many: Aldoni pli ol 4 dosierojn ne eblas\n  migrations:\n    acct: uzantnomo@domajno de la nova konto\n    currently_redirecting: 'Via profilo alidirektos al:'\n    proceed: Konservi\n    updated_msg: Via agordo pri konta migrado estis sukcese ĝisdatigita!\n  moderation:\n    title: Kontrolado\n  notification_mailer:\n    digest:\n      action: Vidi ĉiujn sciigojn\n      body: Jen eta resumo de la mesaĝoj, kiujn vi mistrafis ekde via lasta vizito en %{since}\n      mention: \"%{name} menciis vin en:\"\n      new_followers_summary:\n        one: Ankaŭ, vi ekhavis novan sekvanton en via foresto! Jej!\n        other: Ankaŭ, vi ekhavis %{count} novajn sekvantojn en via foresto! Mirinde!\n      subject:\n        one: \"1 nova sciigo ekde via lasta vizito \\U0001F418\"\n        other: \"%{count} novaj sciigoj ekde via lasta vizito \\U0001F418\"\n      title: En via foresto…\n    favourite:\n      body: \"%{name} stelumis vian mesaĝon:\"\n      subject: \"%{name} stelumis vian mesaĝon\"\n      title: Nova stelumo\n    follow:\n      body: \"%{name} eksekvis vin!\"\n      subject: \"%{name} eksekvis vin\"\n      title: Nova sekvanto\n    follow_request:\n      action: Administri petojn de sekvado\n      body: \"%{name} petis sekvi vin\"\n      subject: \"%{name} petis sekvi vin\"\n      title: Nova peto de sekvado\n    mention:\n      action: Respondi\n      body: \"%{name} menciis vin en:\"\n      subject: \"%{name} menciis vin\"\n      title: Nova mencio\n    reblog:\n      body: \"%{name} diskonigis vian mesaĝon:\"\n      subject: \"%{name} diskonigis vian mesaĝon\"\n      title: Nova diskonigo\n  number:\n    human:\n      decimal_units:\n        format: \"%n%u\"\n        units:\n          billion: Md\n          million: Mn\n          quadrillion: Dd\n          thousand: m\n          trillion: Dn\n  pagination:\n    newer: Pli nova\n    next: Sekva\n    older: Malpli nova\n    prev: Antaŭa\n    truncate: \"&hellip;\"\n  polls:\n    errors:\n      already_voted: Vi jam voĉdonis al ĉi tiu enketa\n      duplicate_options: enhavas duoblaĵojn\n      duration_too_long: estas tro for en la estonteco\n      duration_too_short: estas tro frue\n      expired: La enketo jam finiĝis\n      over_character_limit: ne povas esti po pli longa ol %{max} signoj\n      too_few_options: devas enhavi pli da unu propono\n      too_many_options: ne povas enhavi pli da %{max} proponoj\n  preferences:\n    other: Aliaj aferoj\n  relationships:\n    dormant: Dormanta\n    last_active: Lasta aktiva\n    most_recent: Plej lasta\n    moved: Moviĝita\n    mutual: Reciproka\n    primary: Primara\n    relationship: Rilato\n    status: Statuso de la konto\n  remote_follow:\n    acct: Enmetu vian uzantnomo@domajno de kie vi volas agi\n    missing_resource: La URL de plusendado ne estis trovita\n    no_account_html: Ĉu vi ne havas konton? Vi povas <a href='%{sign_up_path}' target='_blank'>registriĝi tie</a>\n    proceed: Daŭrigi por eksekvi\n    prompt: 'Vi eksekvos:'\n    reason_html: \"<strong>Kial necesas ĉi tiu paŝo?</strong><code>%{instance}</code> povus ne esti la servilo, kie vi registriĝis, do ni unue bezonas alidirekti vin al via hejma servilo.\"\n  remote_interaction:\n    favourite:\n      proceed: Konfirmi la stelumon\n      prompt: 'Vi volas stelumi ĉi tiun mesaĝon:'\n    reblog:\n      proceed: Konfirmi la diskonigon\n      prompt: 'Vi volas diskonigi ĉi tiun mesaĝon:'\n    reply:\n      proceed: Konfirmi la respondon\n      prompt: 'Vi volas respondi al ĉi tiu mesaĝo:'\n  remote_unfollow:\n    error: Eraro\n    title: Titolo\n    unfollowed: Ne plu sekvita\n  scheduled_statuses:\n    over_daily_limit: Vi transpasis la limigon al %{limit} samtage planitaj mesaĝoj\n    over_total_limit: Vi transpasis la limigon al %{limit} planitaj mesaĝoj\n    too_soon: La planita dato devas esti en la estonteco\n  sessions:\n    activity: Lasta ago\n    browser: Retumilo\n    browsers:\n      alipay: Alipay\n      blackberry: Blackberry\n      chrome: Chrome\n      edge: Microsoft Edge\n      electron: Electron\n      firefox: Firefox\n      generic: Nekonata retumilo\n      ie: Internet Explorer\n      micro_messenger: MicroMessenger\n      nokia: Nokia S40 Ovi Browser\n      opera: Opera\n      otter: Otter\n      phantom_js: PhantomJS\n      qq: QQ Browser\n      safari: Safari\n      uc_browser: UCBrowser\n      weibo: Weibo\n    current_session: Nuna seanco\n    description: \"%{browser} en %{platform}\"\n    explanation: Ĉi tiuj estas la retumiloj nun ensalutintaj al via Mastodon-konto.\n    ip: IP\n    platforms:\n      adobe_air: Adobe Air\n      android: Android\n      blackberry: Blackberry\n      chrome_os: ChromeOS\n      firefox_os: Firefox OS\n      ios: iOS\n      linux: Linux\n      mac: Mac\n      other: nekonata platformo\n      windows: Windows\n      windows_mobile: Windows Mobile\n      windows_phone: Windows Phone\n    revoke: Malvalidigi\n    revoke_success: Seanco sukcese malvalidigita\n    title: Seancoj\n  settings:\n    account: Konto\n    account_settings: Agordoj de konto\n    appearance: Apero\n    authorized_apps: Rajtigitaj aplikaĵoj\n    back: Reveni al Mastodon\n    delete: Konta forigo\n    development: Evoluigado\n    edit_profile: Redakti profilon\n    export: Eksporti datumojn\n    featured_tags: Elstarigitaj kradvortoj\n    identity_proofs: Pruvo de identeco\n    import: Importi\n    import_and_export: Alporto kaj elporto\n    migrate: Konta migrado\n    notifications: Sciigoj\n    preferences: Preferoj\n    profile: Profilo\n    relationships: Sekvatoj kaj sekvantoj\n    two_factor_authentication: Dufaktora aŭtentigo\n  statuses:\n    attached:\n      description: 'Ligita: %{attached}'\n      image:\n        one: \"%{count} bildo\"\n        other: \"%{count} bildoj\"\n      video:\n        one: \"%{count} video\"\n        other: \"%{count} videoj\"\n    boosted_from_html: Diskonigita de %{acct_link}\n    content_warning: 'Enhava averto: %{warning}'\n    disallowed_hashtags:\n      one: 'enhavas malpermesitan kradvorton: %{tags}'\n      other: 'enhavis malpermesitan kradvorton: %{tags}'\n    language_detection: Aŭtomate detekti la lingvon\n    open_in_web: Malfermi retumile\n    over_character_limit: limo de %{max} signoj transpasita\n    pin_errors:\n      limit: Vi jam atingis la maksimuman nombron de alpinglitaj mesaĝoj\n      ownership: Mesaĝo de iu alia ne povas esti alpinglita\n      private: Mesaĝo nepublika ne povas esti alpinglita\n      reblog: Diskonigo ne povas esti alpinglita\n    poll:\n      total_votes:\n        one: \"%{count} voĉdono\"\n        other: \"%{count} voĉdonoj\"\n      vote: Voĉdoni\n    show_more: Montri pli\n    sign_in_to_participate: Ensaluti por partopreni en la konversacio\n    title: \"%{name}: “%{quote}”\"\n    visibilities:\n      private: Montri nur al sekvantoj\n      private_long: Montri nur al sekvantoj\n      public: Publika\n      public_long: Ĉiuj povas vidi\n      unlisted: Nelistigita\n      unlisted_long: Ĉiuj povas vidi, sed nelistigita en publikaj templinioj\n  stream_entries:\n    pinned: Alpinglita\n    reblogged: diskonigita\n    sensitive_content: Tikla enhavo\n  terms:\n    title: Uzkondiĉoj kaj privateca politiko de %{instance}\n  themes:\n    contrast: Mastodon (Forta kontrasto)\n    default: Mastodon (Malluma)\n    mastodon-light: Mastodon (Luma)\n  time:\n    formats:\n      default: \"%Y-%m-%d %H:%M\"\n      month: \"%b %Y\"\n  two_factor_authentication:\n    code_hint: Enmetu la kodon kreitan de via aŭtentiga aplikaĵo por konfirmi\n    description_html: Se vi ebligas <strong>dufaktoran aŭtentigon</strong>, vi bezonos vian poŝtelefonon por ensaluti, ĉar ĝi kreos nombrojn, kiujn vi devos enmeti.\n    disable: Malebligi\n    enable: Ebligi\n    enabled: Dufaktora aŭtentigo ebligita\n    enabled_success: Dufaktora aŭtentigo sukcese ebligita\n    generate_recovery_codes: Krei realirajn kodojn\n    instructions_html: \"<strong>Skanu ĉi tiun QR-kodon per Google Authenticator aŭ per simila aplikaĵo en via poŝtelefono</strong>. De tiam, la aplikaĵo kreos nombrojn, kiujn vi devos enmeti.\"\n    lost_recovery_codes: Realiraj kodoj permesas rehavi aliron al via konto se vi perdis vian telefonon. Se vi perdis viajn realirajn kodojn, vi povas rekrei ilin ĉi tie. Viaj malnovaj realiraj kodoj iĝos eksvalidaj.\n    manual_instructions: 'Se vi ne povas skani la QR-kodon kaj bezonas enmeti ĝin mane, jen la tut-teksta sekreto:'\n    recovery_codes: Realiraj kodoj\n    recovery_codes_regenerated: Realiraj kodoj sukcese rekreitaj\n    recovery_instructions_html: Se vi perdas aliron al via telefono, vi povas uzi unu el la subaj realiraj kodoj por rehavi aliron al via konto. <strong>Konservu realirajn kodojn sekure</strong>. Ekzemple, vi povas printi ilin kaj konservi ilin kun aliaj gravaj dokumentoj.\n    setup: Agordi\n    wrong_code: La enmetita kodo estis nevalida! Ĉu la servila tempo kaj la aparata tempo ĝustas?\n  user_mailer:\n    backup_ready:\n      explanation: Vi petis kompletan arkivon de via Mastodon-konto. Ĝi nun pretas por elŝutado!\n      subject: Via arkivo estas preta por elŝutado\n      title: Arkiva elŝuto\n    warning:\n      explanation:\n        disable: Dum via konto estas frostigita, via kontaj datumoj restas intaktaj, sed vi ne povas plenumi iujn agojn ĝis ĝi estas malhaltigita.\n        silence: Dum via konto estas limigita, nur tiuj, kiuj jam sekvas vin, vidos viajn mesaĝojn en ĉi tiu servilo, kaj vi povus esti ekskludita de diversaj publikaj listoj. Tamen, aliaj ankoraŭ povas mane sekvi vin.\n        suspend: Via konto estis haltigita, kaj ĉiuj el viaj mesaĝoj kaj alŝutitaj aŭdovidaj dosieroj estis nemalfareble forigitaj de ĉi tiu servilo, kaj de la serviloj, kie vi havis sekvantojn.\n      review_server_policies: Superrigardi servilajn politikojn\n      subject:\n        disable: Via konto %{acct} estas frostigita\n        none: Averto por %{acct}\n        silence: Via konto %{acct} estas limigita\n        suspend: Via konto %{acct} estas haltigita\n      title:\n        disable: Konto frostigita\n        none: Averto\n        silence: Konto limigita\n        suspend: Konto haltigita\n    welcome:\n      edit_profile_action: Agordi profilon\n      edit_profile_step: Vi povas proprigi vian profilon per alŝuto de profilbildo, fonbildo, ŝanĝo de via afiŝita nomo kaj pli. Se vi ŝatus kontroli novajn sekvantojn antaŭ ol ili rajtas sekvi vin, vi povas ŝlosi vian konton.\n      explanation: Jen kelkaj konsiloj por helpi vin komenci\n      final_action: Ekmesaĝi\n      final_step: 'Ekmesaĝu! Eĉ sen sekvantoj, viaj publikaj mesaĝoj povas esti vidataj de aliaj, ekzemple en la loka templinio kaj en la kradvortoj. Eble vi ŝatus prezenti vin per la kradvorto #introductions.'\n      full_handle: Via kompleta uzantnomo\n      full_handle_hint: Jen kion vi dirus al viaj amikoj, por ke ili mesaĝu aŭ sekvu vin de alia servilo.\n      review_preferences_action: Ŝanĝi preferojn\n      review_preferences_step: Estu certa ke vi agordis viajn preferojn, kiel kiujn retmesaĝojn vi ŝatus ricevi, aŭ kiun dekomencan privatecan nivelon vi ŝatus ke viaj mesaĝoj havu. Se tio ne ĝenas vin, vi povas ebligi aŭtomatan ekigon de GIF-oj.\n      subject: Bonvenon en Mastodon\n      tip_federated_timeline: La fratara templinio estas antaŭvido de la reto de Mastodon. Sed ĝi enhavas nur homojn, kiuj estas sekvataj de aliaj homoj de via nodo, do ĝi ne estas kompleta.\n      tip_following: Vi dekomence sekvas la administrantojn de via servilo. Por trovi pli da interesaj homoj, rigardu la lokan kaj frataran templiniojn.\n      tip_local_timeline: La loka templinio estas antaŭvido de la homoj en %{instance}. Ĉi tiuj estas viaj apudaj najbaroj!\n      tip_mobile_webapp: Se via telefona retumilo proponas al vi aldoni Mastodon al via hejma ekrano, vi povas ricevi puŝsciigojn. Tio multmaniere funkcias kiel operaciuma aplikaĵo!\n      tips: Konsiloj\n      title: Bonvenon, %{name}!\n  users:\n    follow_limit_reached: Vi ne povas sekvi pli da %{limit} homojn\n    invalid_email: La retadreso estas nevalida\n    invalid_otp_token: Nevalida kodo de dufaktora aŭtentigo\n    otp_lost_help_html: Se vi perdas aliron al ambaŭ, vi povas kontakti %{email}\n    seamless_external_login: Vi estas ensalutinta per ekstera servo, do pasvortaj kaj retadresaj agordoj ne estas disponeblaj.\n    signed_in_as: 'Ensalutinta kiel:'\n  verification:\n    explanation_html: 'Vi povas <strong>pruvi, ke vi estas la posedanto de la ligiloj en viaj profilaj metadatumoj</strong>. Por fari tion, la alligita retejo devas enhavi ligilon reen al via Mastodon-profilo. La religilo <strong>devas</strong> havi la atributon <code>rel=\"me\"</code>. Ne gravas la teksta enhavo de la religilo. Jen ekzemplo:'\n    verification: Kontrolo\n"
  },
  {
    "path": "config/locales/es.yml",
    "content": "---\nes:\n  about:\n    about_hashtag_html: Estos son toots públicos etiquetados con <strong>#%{hashtag}</strong>. Puedes interactuar con ellos si tienes una cuenta en cualquier parte del fediverso.\n    about_mastodon_html: Mastodon es un servidor de red social <em>libre y de código abierto</em>. Una alternativa <em>descentralizada</em> a plataformas comerciales, que evita el riesgo de que una única compañía monopolice su comunicación. Cualquiera puede ejecutar Mastodon y participar sin problemas en la <em>red social</em>.\n    about_this: Acerca de esta instancia\n    active_count_after: activos\n    active_footnote: Usuarios activos mensuales (MAU)\n    administered_by: 'Administrado por:'\n    api: API\n    apps: Aplicaciones móviles\n    apps_platforms: Usa Mastodon desde iOS, Android, y otras plataformas\n    browse_directory: Revisa un directorio de perfiles y filtra por intereses\n    browse_public_posts: Revisa una transmisión en vivo de publicaciones en Mastodon\n    contact: Contacto\n    contact_missing: No especificado\n    contact_unavailable: N/A\n    discover_users: Descubrir usuarios\n    documentation: Documentación\n    extended_description_html: |\n      <h3>Un buen lugar para las reglas</h3>\n      <p>La descripción extendida no se ha colocado aún.</p>\n    federation_hint_html: Con una cuenta en %{instance}, podrá seguir a gente en cualquier servidor de Mastodon y más alla.\n    generic_description: \"%{domain} es un servidor en la red\"\n    get_apps: Probar una aplicación móvil\n    hosted_on: Mastodon hosteado en %{domain}\n    learn_more: Aprende más\n    privacy_policy: Política de privacidad\n    see_whats_happening: Ver lo que está pasando\n    server_stats: 'Datos del servidor:'\n    source_code: Código fuente\n    status_count_after:\n      one: estado\n      other: estados\n    status_count_before: Qué han escrito\n    tagline: Seguir a amigos existentes y descubre nuevos\n    terms: Condiciones de servicio\n    user_count_after:\n      one: usuario\n      other: usuarios\n    user_count_before: Tenemos\n    what_is_mastodon: \"¿Qué es Mastodon?\"\n  accounts:\n    choices_html: 'Elecciones de %{name}:'\n    follow: Seguir\n    followers:\n      one: Seguidor\n      other: Seguidores\n    following: Siguiendo\n    joined: Se unió el %{date}\n    last_active: última conexión\n    link_verified_on: La propiedad de este vínculo fue verificada el %{date}\n    media: Archivos\n    moved_html: \"%{name} se ha trasladado a %{new_profile_link}:\"\n    network_hidden: Esta información no está disponible\n    nothing_here: \"¡No hay nada aquí!\"\n    people_followed_by: Usuarios a quien %{name} sigue\n    people_who_follow: Usuarios que siguen a %{name}\n    pin_errors:\n      following: Debes estar siguiendo a la persona a la que quieres aprobar\n    posts:\n      one: Toot\n      other: Toots\n    posts_tab_heading: Toots\n    posts_with_replies: Toots con respuestas\n    reserved_username: El nombre de usuario está reservado\n    roles:\n      admin: Administrador\n      bot: Robot\n      moderator: Moderador\n    unavailable: Perfil no disponible\n    unfollow: Dejar de seguir\n  admin:\n    account_actions:\n      action: Realizar acción\n      title: Moderar %{acct}\n    account_moderation_notes:\n      create: Crear\n      created_msg: \"¡Nota de moderación creada con éxito!\"\n      delete: Borrar\n      destroyed_msg: \"¡Nota de moderación destruida con éxito!\"\n    accounts:\n      approve: Aprobar\n      approve_all: Aprobar todos\n      are_you_sure: \"¿Estás seguro?\"\n      avatar: Avatar\n      by_domain: Dominio\n      change_email:\n        changed_msg: \"¡El correo electrónico se ha actualizado correctamente!\"\n        current_email: Correo electrónico actual\n        label: Cambiar el correo electrónico\n        new_email: Nuevo correo electrónico\n        submit: Cambiar el correo electrónico\n        title: Cambiar el correo electrónico de %{username}\n      confirm: Confirmar\n      confirmed: Confirmado\n      confirming: Confirmando\n      deleted: Borrado\n      demote: Degradar\n      disable: Deshabilitar\n      disable_two_factor_authentication: Desactivar autenticación de dos factores\n      disabled: Deshabilitada\n      display_name: Nombre\n      domain: Dominio\n      edit: Editar\n      email: E-mail\n      email_status: E-mail Status\n      enable: Habilitar\n      enabled: Habilitada\n      feed_url: URL de notificaciones\n      followers: Seguidores\n      followers_url: URL de los seguidores\n      follows: Sigue\n      header: Cabecera\n      inbox_url: URL de la bandeja de entrada\n      invited_by: Invitado por\n      ip: IP\n      joined: Se unió\n      location:\n        all: Todos\n        local: Local\n        remote: Remoto\n        title: Localización\n      login_status: Estado del login\n      media_attachments: Multimedia\n      memorialize: Convertir en memorial\n      moderation:\n        active: Activo\n        all: Todos\n        pending: Pendiente\n        silenced: Silenciados\n        suspended: Suspendidos\n        title: Moderación\n      moderation_notes: Notas de moderación\n      most_recent_activity: Actividad más reciente\n      most_recent_ip: IP más reciente\n      no_account_selected: Ninguna cuenta se cambió ya que ninguna fue seleccionada\n      no_limits_imposed: Sin límites impuestos\n      not_subscribed: No se está suscrito\n      outbox_url: URL de bandeja de salida\n      pending: Revisión pendiente\n      perform_full_suspension: Suspender\n      profile_url: URL del perfil\n      promote: Promocionar\n      protocol: Protocolo\n      public: Público\n      push_subscription_expires: Expiración de la suscripción PuSH\n      redownload: Refrescar avatar\n      reject: Rechazar\n      reject_all: Rechazar todos\n      remove_avatar: Eliminar el avatar\n      remove_header: Eliminar el encabezado\n      resend_confirmation:\n        already_confirmed: Este usuario ya está confirmado\n        send: Reenviar el correo electrónico de confirmación\n        success: \"¡Correo electrónico de confirmación enviado con éxito!\"\n      reset: Reiniciar\n      reset_password: Reiniciar contraseña\n      resubscribe: Re-suscribir\n      role: Permisos\n      roles:\n        admin: Administrador\n        moderator: Moderador\n        staff: Personal\n        user: Usuario\n      salmon_url: URL de salmón\n      search: Buscar\n      shared_inbox_url: URL de bandeja compartida\n      show:\n        created_reports: Denuncias hechas por esta cuenta\n        targeted_reports: Denuncias hechas sobre esta cuenta\n      silence: Silenciar\n      silenced: Silenciado\n      statuses: Estados\n      subscribe: Suscribir\n      suspended: Susependido\n      time_in_queue: Esperando en fila %{time}\n      title: Cuentas\n      unconfirmed_email: Correo electrónico sin confirmar\n      undo_silenced: Des-silenciar\n      undo_suspension: Des-suspender\n      unsubscribe: Desuscribir\n      username: Nombre de usuario\n      warn: Advertir\n      web: Web\n    action_logs:\n      actions:\n        assigned_to_self_report: \"%{name} se ha asignado la denuncia %{target} a sí mismo\"\n        change_email_user: \"%{name} ha cambiado la dirección de correo del usuario %{target}\"\n        confirm_user: \"%{name} confirmó la dirección de correo del usuario %{target}\"\n        create_account_warning: \"%{name} envió una advertencia a %{target}\"\n        create_custom_emoji: \"%{name} subió un nuevo emoji %{target}\"\n        create_domain_block: \"%{name} bloqueó el dominio %{target}\"\n        create_email_domain_block: \"%{name} puso en lista negra el dominio de correos %{target}\"\n        demote_user: \"%{name} degradó al usuario %{target}\"\n        destroy_custom_emoji: \"%{name} destruyó el emoji %{target}\"\n        destroy_domain_block: \"%{name} desbloqueó el dominio %{target}\"\n        destroy_email_domain_block: \"%{name} puso en lista blanca el dominio de correos %{target}\"\n        destroy_status: \"%{name} eliminó el estado de %{target}\"\n        disable_2fa_user: \"%{name} deshabilitó el requerimiento de dos factores para el usuario %{target}\"\n        disable_custom_emoji: \"%{name} deshabilitó el emoji %{target}\"\n        disable_user: \"%{name} deshabilitó el acceso del usuario %{target}\"\n        enable_custom_emoji: \"%{name} habilitó el emoji %{target}\"\n        enable_user: \"%{name} habilitó el acceso del usuario %{target}\"\n        memorialize_account: \"%{name} convirtió la cuenta de %{target} en una página de memorial\"\n        promote_user: \"%{name} promoción al usuario %{target}\"\n        remove_avatar_user: \"%{name} ha eliminado el avatar de %{target}\"\n        reopen_report: \"%{name} ha reabierto la denuncia %{target}\"\n        reset_password_user: \"%{name} restauró la contraseña del usuario %{target}\"\n        resolve_report: \"%{name} ha resuelto la denuncia %{target}\"\n        silence_account: \"%{name} silenció la cuenta de %{target}\"\n        suspend_account: \"%{name} suspendió la cuenta de %{target}\"\n        unassigned_report: \"%{name} ha desasignado la denuncia %{target}\"\n        unsilence_account: \"%{name} desactivó el silenciado de la cuenta de %{target}\"\n        unsuspend_account: \"%{name} desactivó la suspensión de la cuenta de %{target}\"\n        update_custom_emoji: \"%{name} actualizó el emoji %{target}\"\n        update_status: \"%{name} actualizó el estado de %{target}\"\n      deleted_status: \"(estado borrado)\"\n      title: Log de auditoría\n    custom_emojis:\n      by_domain: Dominio\n      copied_msg: Copia local del emoji creada con éxito\n      copy: Copiar\n      copy_failed_msg: No se pudo realizar una copia local de ese emoji\n      created_msg: \"¡Emoji creado con éxito!\"\n      delete: Borrar\n      destroyed_msg: \"¡Emojo destruido con éxito!\"\n      disable: Deshabilitar\n      disabled_msg: Se deshabilitó con éxito ese emoji\n      emoji: Emoji\n      enable: Habilitar\n      enabled_msg: Se habilitó con éxito ese emoji\n      image_hint: PNG de hasta 50KB\n      listed: Listados\n      new:\n        title: Añadir nuevo emoji personalizado\n      overwrite: Sobrescribir\n      shortcode: Código de atajo\n      shortcode_hint: Al menos 2 caracteres, solo caracteres alfanuméricos y guiones bajos\n      title: Emojis personalizados\n      unlisted: Sin listar\n      update_failed_msg: No se pudo actualizar ese emoji\n      updated_msg: \"¡Emoji actualizado con éxito!\"\n      upload: Subir\n    dashboard:\n      backlog: trabajos de backlog\n      config: Configuración\n      feature_deletions: Borrados de cuenta\n      feature_invites: Enlaces de invitación\n      feature_profile_directory: Directorio de perfiles\n      feature_registrations: Registros\n      feature_relay: Relés de federación\n      feature_timeline_preview: Vista previa de la cronología\n      features: Características\n      hidden_service: Federación con servicios ocultos\n      open_reports: denuncias abiertas\n      recent_users: Usuarios recientes\n      search: Búsqueda por texto completo\n      single_user_mode: Modo único usuario\n      software: Software\n      space: Uso de almacenamiento\n      title: Tablero\n      total_users: usuarios en total\n      trends: Tendencias\n      week_interactions: interacciones esta semana\n      week_users_active: activo esta semana\n      week_users_new: usuarios esta semana\n    domain_blocks:\n      add_new: Añadir nuevo\n      created_msg: El bloque de dominio está siendo procesado\n      destroyed_msg: El bloque de dominio se deshizo\n      domain: Dominio\n      existing_domain_block_html: Ya ha impuesto límites más estrictos a %{name}, necesita <a href=\"%{unblock_url}\">desbloquearlo</a> primero.\n      new:\n        create: Crear bloque\n        hint: El bloque de dominio no prevendrá la creación de entradas de cuenta en la base de datos, pero aplicará retroactiva y automáticamente métodos de moderación específica en dichas cuentas.\n        severity:\n          desc_html: \"<strong>Silenciar</strong> hará los posts de la cuenta invisibles a cualquiera que no lo esté siguiendo. <strong>Suspender</strong> eliminará todo el contenido, media, y datos del perfil. Usa <strong>Ninguno</strong> si solo quieres rechazar archivos multimedia.\"\n          noop: Ninguno\n          silence: Silenciar\n          suspend: Suspender\n        title: Nuevo bloque de dominio\n      reject_media: Rechazar archivos multimedia\n      reject_media_hint: Remueve localmente archivos multimedia almacenados para descargar cualquiera en el futuro. Irrelevante para suspensiones\n      reject_reports: Rechazar denuncias\n      reject_reports_hint: Ignorar todas las denuncias de este dominio. Irrelevante para suspensiones\n      rejecting_media: rechazando archivos multimedia\n      rejecting_reports: rechazando denuncias\n      severity:\n        silence: silenciado\n        suspend: suspendido\n      show:\n        affected_accounts:\n          one: Una cuenta en la base de datos afectada\n          other: \"%{count} cuentas en la base de datos afectadas\"\n        retroactive:\n          silence: Des-silenciar todas las cuentas existentes de este dominio\n          suspend: Des-suspender todas las cuentas existentes de este dominio\n        title: Deshacer bloque de dominio para %{domain}\n        undo: Deshacer\n      undo: Deshacer bloque de dominio\n    email_domain_blocks:\n      add_new: Añadir nuevo\n      created_msg: Dominio de correo añadido a la lista negra con éxito\n      delete: Borrar\n      destroyed_msg: Dominio de correo borrado de la lista negra con éxito\n      domain: Dominio\n      new:\n        create: Añadir dominio\n        title: Nueva entrada en la lista negra de correo\n      title: Lista negra de correo\n    followers:\n      back_to_account: Regresar A Cuenta\n      title: Seguidores de %{acct}\n    instances:\n      by_domain: Dominio\n      delivery_available: Distribución está disponible\n      known_accounts:\n        one: \"%{count} cuenta conocida\"\n        other: \"%{count} cuentas conocidas\"\n      moderation:\n        all: Todo\n        limited: Limitado\n        title: Moderación\n      title: Instancias conocidas\n      total_blocked_by_us: Bloqueado por nosotros\n      total_followed_by_them: Seguido por ellos\n      total_followed_by_us: Seguido por nosotros\n      total_reported: Denuncias sobre ellos\n      total_storage: Archivos adjuntos\n    invites:\n      deactivate_all: Desactivar todos\n      filter:\n        all: Todas\n        available: Disponibles\n        expired: Expiradas\n        title: Filtrar\n      title: Invitaciones\n    pending_accounts:\n      title: Cuentas pendientes (%{count})\n    relays:\n      add_new: Añadir nuevo relé\n      delete: Borrar\n      description_html: Un <strong>relé de federación</strong> es un servidor intermedio que intercambia grandes volúmenes de toots públicos entre servidores que se suscriben y publican en él. <strong>Puede ayudar a servidores pequeños y medianos a descubir contenido del fediverso</strong>, que de otra manera requeriría que los usuarios locales siguiesen a mano a personas de servidores remotos.\n      disable: Deshabilitar\n      disabled: Deshabilitado\n      enable: Habilitar\n      enable_hint: Una vez conectado, su servidor se suscribirá a todos los toots públicos de este relé, y comenzará a enviar los toots públicos de este servidor hacia él.\n      enabled: Habilitado\n      inbox_url: URL del relé\n      pending: Esperando la aprobación del relé\n      save_and_enable: Guardar y conectar\n      setup: Preparar una conexión de relé\n      status: Estado\n      title: Relés\n    report_notes:\n      created_msg: \"¡El registro de la denuncia se ha creado correctamente!\"\n      destroyed_msg: \"¡El registro de la denuncia se ha borrado correctamente!\"\n    reports:\n      account:\n        note: nota\n        report: denuncia\n      action_taken_by: Acción tomada por\n      are_you_sure: \"¿Estás seguro?\"\n      assign_to_self: Asignar a mí\n      assigned: Moderador asignado\n      comment:\n        none: Ninguno\n      created_at: Denunciado\n      mark_as_resolved: Marcar como resuelto\n      mark_as_unresolved: Marcar como no resuelto\n      notes:\n        create: Añadir una nota\n        create_and_resolve: Resolver con una nota\n        create_and_unresolve: Reabrir con una nota\n        delete: Eliminar\n        placeholder: Especificar qué acciones se han tomado o cualquier otra novedad respecto a esta denuncia…\n      reopen: Reabrir denuncia\n      report: 'Denunciar #%{id}'\n      reported_account: Cuenta denunciada\n      reported_by: Denunciado por\n      resolved: Resuelto\n      resolved_msg: \"¡La denuncia se ha resuelto correctamente!\"\n      status: Estado\n      title: Denuncias\n      unassign: Desasignar\n      unresolved: No resuelto\n      updated_at: Actualizado\n    settings:\n      activity_api_enabled:\n        desc_html: Conteo de estados publicados localmente, usuarios activos, y nuevos registros en periodos semanales\n        title: Publicar estadísticas agregado acerca de actividad de usuario\n      bootstrap_timeline_accounts:\n        desc_html: Separa con comas los nombres de usuario. Solo funcionará para cuentas locales desbloqueadas. Si se deja vacío, se tomará como valor por defecto a todos los administradores locales.\n        title: Seguimientos predeterminados para usuarios nuevos\n      contact_information:\n        email: Correo electrónico\n        username: Nombre de usuario\n      custom_css:\n        desc_html: Modificar el aspecto con CSS cargado en cada página\n        title: CSS personalizado\n      hero:\n        desc_html: Mostrado en la página principal. Recomendable al menos 600x100px. Por defecto se establece a la miniatura de la instancia\n        title: Imagen de portada\n      mascot:\n        desc_html: Mostrado en múltiples páginas. Se recomienda un tamaño mínimo de 293x205px. Cuando no se especifica, se muestra la mascota por defecto\n        title: Imagen de la mascota\n      max_bio_chars:\n        desc_html: 'Fijar longitud maxima de la biografía en carácteres (defecto: 500)'\n        title: Tamaño maximo de la biografía\n      max_toot_chars:\n        desc_html: 'Fijar longitud maxima de un toot en carácteres (defecto: 500)'\n        title: Tamaño maximo de un toot\n      peers_api_enabled:\n        desc_html: Nombres de dominio que esta instancia ha encontrado en el fediverso\n        title: Publicar lista de instancias descubiertas\n      preview_sensitive_media:\n        desc_html: Los enlaces de vistas previas en otras web mostrarán una miniatura incluso si el medio está marcado como contenido sensible\n        title: Mostrar contenido sensible en previews de OpenGraph\n      profile_directory:\n        desc_html: Permitir que los usuarios sean encontrables\n        title: Activar directorio de perfiles\n      registrations:\n        closed_message:\n          desc_html: Se muestra en la portada cuando los registros están cerrados. Puedes usar tags HTML\n          title: Mensaje de registro cerrado\n        deletion:\n          desc_html: Permite a cualquiera a eliminar su cuenta\n          title: Eliminación de cuenta abierta\n        min_invite_role:\n          disabled: Nadie\n          title: Permitir invitaciones de\n      registrations_mode:\n        modes:\n          approved: Aprobación requerida para registrarse\n          none: Nadie puede registrarse\n          open: Cualquiera puede registrarse\n        title: Modo de registraciones\n      show_known_fediverse_at_about_page:\n        desc_html: Cuando esté activado, se mostrarán toots de todo el fediverso conocido en la vista previa. En otro caso, se mostrarán solamente toots locales.\n        title: Mostrar fediverso conocido en la vista previa de la historia\n      show_staff_badge:\n        desc_html: Mostrar un parche de staff en la página de un usuario\n        title: Mostrar parche de staff\n      site_description:\n        desc_html: Párrafo introductorio en la portada y en meta tags. Puedes usar tags HTML, en particular <code>&lt;a&gt;</code> y <code>&lt;em&gt;</code>.\n        title: Descripción de instancia\n      site_description_extended:\n        desc_html: Un buen lugar para su código de conducta, reglas, guías y otras cosas que estén impuestas aparte en su instancia. Puedes usar tags HTML\n        title: Información extendida personalizada\n      site_short_description:\n        desc_html: Mostrado en la barra lateral y las etiquetas de metadatos. Describe lo que es Mastodon y qué hace especial a este servidor en un solo párrafo. si está vacío, pone por defecto la descripción de la instancia.\n        title: Descripción corta de la instancia\n      site_terms:\n        desc_html: Puedes escribir tus propias políticas de privacidad, términos de servicio u otras legalidades. Puedes usar tags HTML\n        title: Términos de servicio personalizados\n      site_title: Nombre de instancia\n      thumbnail:\n        desc_html: Se usa para muestras con OpenGraph y APIs. Se recomienda 1200x630px\n        title: Portada de instancia\n      timeline_preview:\n        desc_html: Mostrar cronología pública en la portada\n        title: Previsualización\n      title: Ajustes del sitio\n    statuses:\n      back_to_account: Volver a la cuenta\n      batch:\n        delete: Eliminar\n        nsfw_off: Marcar contenido como no sensible\n        nsfw_on: Marcar contenido como sensible\n      failed_to_execute: Falló al ejecutar\n      media:\n        title: Multimedia\n      no_media: No hay multimedia\n      no_status_selected: No se cambió ningún estado al no seleccionar ninguno\n      title: Estado de las cuentas\n      with_media: Con multimedia\n    subscriptions:\n      callback_url: URL del callback\n      confirmed: Confirmado\n      expires_in: Expira en\n      last_delivery: Última entrega\n      title: WebSub\n      topic: Tópico\n    tags:\n      accounts: Cuentas\n      hidden: Oculto\n      hide: Ocultar del directorio\n      name: Etiqueta\n      title: Etiquetas\n      unhide: Mostrar en el directorio\n      visible: Visible\n    title: Administración\n    warning_presets:\n      add_new: Añadir nuevo\n      delete: Borrar\n      edit: Editar\n      edit_preset: Editar preajuste de advertencia\n      title: Administrar preajuste de advertencia\n  admin_mailer:\n    new_pending_account:\n      body: Los detalles de la cuenta nueva estan abajo. Puedes aprobar o rechazar esta aplicación.\n      subject: Cuenta nueva para revisión en %{instance} (%{username})\n    new_report:\n      body: \"%{reporter} ha denunciado a %{target}\"\n      body_remote: Alguien de %{domain} a denunciado a %{target}\n      subject: Denuncia nueva para %{instance} (#%{id})\n  appearance:\n    advanced_web_interface: Interfaz avanzado\n    advanced_web_interface_hint: 'Si quiere usar todo el espacio de su pantalla, el interfaz avanzado le permite configurar muchas columnas diferentes para ver mucha información a la misma vez como quiera: Hogar, notificaciones, cronología federada, cualquier numero de listas y etiquetas.'\n    animations_and_accessibility: Animaciones y accesibilidad\n    confirmation_dialogs: Diálogos de confirmación\n    sensitive_content: Contenido sensible\n  application_mailer:\n    notification_preferences: Cambiar preferencias de correo electrónico\n    salutation: \"%{name},\"\n    settings: 'Cambiar preferencias de correo: %{link}'\n    view: 'Vista:'\n    view_profile: Ver perfil\n    view_status: Ver estado\n  applications:\n    created: Aplicación creada exitosamente\n    destroyed: Apicación eliminada exitosamente\n    invalid_url: La URL proporcionada es incorrecta\n    regenerate_token: Regenerar token de acceso\n    token_regenerated: Token de acceso regenerado exitosamente\n    warning: Ten mucho cuidado con estos datos. ¡No los compartas con nadie!\n    your_token: Su identificador de acceso\n  auth:\n    apply_for_account: Solicitar una invitación\n    change_password: Contraseña\n    checkbox_agreement_html: Acepto las <a href=\"%{rules_path}\" target=\"_blank\">reglas del servidor</a> y los <a href=\"%{terms_path}\" target=\"_blank\">términos de servicio</a>\n    confirm_email: Confirmar correo electrónico\n    delete_account: Borrar cuenta\n    delete_account_html: Si desea eliminar su cuenta, puede <a href=\"%{path}\">proceder aquí</a>. Será pedido de una confirmación.\n    didnt_get_confirmation: \"¿No recibió el correo de confirmación?\"\n    forgot_password: \"¿Olvidó su contraseña?\"\n    invalid_reset_password_token: El token de reinicio de contraseña es inválido o expiró. Por favor pide uno nuevo.\n    login: Iniciar sesión\n    logout: Cerrar sesión\n    migrate_account: Mudarse a otra cuenta\n    migrate_account_html: Si deseas redireccionar esta cuenta a otra distinta, puedes <a href=\"%{path}\">configurarlo aquí</a>.\n    or_log_in_with: O inicia sesión con\n    providers:\n      cas: CAS\n      saml: SAML\n    register: Registrarse\n    registration_closed: \"%{instance} no está aceptando nuevos miembros\"\n    resend_confirmation: Volver a enviar el correo de confirmación\n    reset_password: Restablecer contraseña\n    security: Cambiar contraseña\n    set_new_password: Establecer nueva contraseña\n    trouble_logging_in: \"¿Problemas iniciando la sesión?\"\n  authorize_follow:\n    already_following: Ya estás siguiendo a esta cuenta\n    error: Desafortunadamente, ha ocurrido un error buscando la cuenta remota\n    follow: Seguir\n    follow_request: 'Tienes una solicitud de seguimiento de:'\n    following: \"¡Éxito! Ahora estás siguiendo a:\"\n    post_follow:\n      close: O, puedes simplemente cerrar esta ventana.\n      return: Regresar al perfil del usuario\n      web: Ir al sitio web\n    title: Seguir a %{acct}\n  datetime:\n    distance_in_words:\n      about_x_hours: \"%{count}h\"\n      about_x_months: \"%{count}m\"\n      about_x_years: \"%{count}a\"\n      almost_x_years: \"%{count}a\"\n      half_a_minute: Justo ahora\n      less_than_x_minutes: \"%{count}min\"\n      less_than_x_seconds: Justo ahora\n      over_x_years: \"%{count}y\"\n      x_days: \"%{count}d\"\n      x_minutes: \"%{count}min\"\n      x_months: \"%{count}m\"\n      x_seconds: \"%{count}s\"\n  deletes:\n    bad_password_msg: \"¡Buen intento, hackers! Contraseña incorrecta\"\n    confirm_password: Ingrese su contraseña actual para demostrar su identidad\n    description_html: Esto eliminará el contenido de su cuenta y la desactivará <strong>permanente e irrevesiblemente</strong>. Su nombre de usuario quedará reservado para prevenir futuros robos de identidad.\n    proceed: Eliminar cuenta\n    success_msg: Su cuenta se eliminó con éxito\n    warning_html: Se garantiza únicamente la eliminación del contenido de esta instancia. El contenido que se haya compartido extensamente dejará sus huellas. Los servidores fuera de línea y los que se hayan desuscrito de tus actualizaciones ya no actualizarán sus bases de datos.\n    warning_title: Disponibilidad diseminada del contenido\n  directories:\n    directory: Directorio de perfiles\n    enabled: Usted está actualmente en el directorio.\n    enabled_but_waiting: Usted ha optado por estar en el directorio, pero no tiene el número mínimo de seguidores (%{min_followers}) para ser listado todavía.\n    explanation: Descubre usuarios por sus intereses\n    explore_mastodon: Explorar %{title}\n    how_to_enable: Actualmente no está registrado para el directorio. Puede optar abajo. ¡Use etiquetas en su biografía para aparecer bajo etiquetas especificas!\n    people:\n      one: \"%{count} persona\"\n      other: \"%{count} personas\"\n  errors:\n    '403': No tienes permiso para acceder a esta página.\n    '404': La página que estabas buscando no existe.\n    '410': La página que estabas buscando no existe más.\n    '422':\n      content: Verificación de seguridad fallida. ¿Estás bloqueando algunas cookies?\n      title: Verificación de seguridad fallida\n    '429': Asfixiado\n    '500':\n      content: Lo sentimos, algo ha funcionado mal por nuestra parte.\n      title: Esta página no es correcta\n    noscript_html: Para usar la aplicación web de Mastodon, por favor active JavaScript. Alternativamente, prueba alguna de las <a href=\"%{apps_path}\">aplicaciones nativas</a> para Mastodon para su plataforma.\n  existing_username_validator:\n    not_found: no se pudo encontrar un usuario local con ese nombre\n    not_found_multiple: no se pudo encontrar %{usernames}\n  exports:\n    archive_takeout:\n      date: Fecha\n      download: Descargar su archivo\n      hint_html: Puedes solicitar un archivo de tus <strong>toots y materiales subidos</strong>. Los datos exportados estarán en formato ActivityPub, legibles por cualquier software compatible.\n      in_progress: Recopilando su archivo...\n      request: Solicitar su archivo\n      size: Tamaño\n    blocks: Personas que has bloqueado\n    csv: CSV\n    domain_blocks: Bloques de dominio\n    follows: Personas que sigues\n    lists: Listas\n    mutes: Tienes en silencio\n    storage: Almacenamiento\n  featured_tags:\n    add_new: Añadir nuevo\n    errors:\n      limit: Ya ha alcanzado la cantidad máxima de etiquetas\n  filters:\n    contexts:\n      home: Cronología propia\n      notifications: Notificaciones\n      public: Cronología pública\n      thread: Conversaciones\n    edit:\n      title: Editar filtro\n    errors:\n      invalid_context: Se suminstró un contexto inválido o vacío\n      invalid_irreversible: El filtrado irreversible solo funciona con los contextos propios o de notificaciones\n    index:\n      delete: Borrar\n      title: Filtros\n    new:\n      title: Añadir un nuevo filtro\n  footer:\n    developers: Desarrolladores\n    more: Más…\n    resources: Recursos\n  generic:\n    all: Todo\n    changes_saved_msg: \"¡Cambios guardados con éxito!\"\n    copy: Copiar\n    order_by: Ordenar por\n    save_changes: Guardar cambios\n    validation_errors:\n      one: \"¡Algo no está bien! Por favor, revisa el error\"\n      other: \"¡Algo no está bien! Por favor, revise %{count} errores más abajo\"\n  html_validator:\n    invalid_markup: 'contiene marcado de HTML inválido: %{error}'\n  identity_proofs:\n    active: Activo\n    authorize: Sí, autorizar\n    authorize_connection_prompt: \"¿Autorizar esta conexión criptográfica?\"\n    errors:\n      failed: La conexión criptográfica falló. Por favor, inténtelo de nuevo desde %{provider}.\n      keybase:\n        invalid_token: Los identificadores de Keybase son resumenes criptográficos de firmas y deben ser 66 carácteres hexadecimales\n        verification_failed: Keybase no reconoce este identificador como una firma del usuario de Keybase %{kb_username}. Por favor, inténtelo de nuevo desde Keybase.\n      wrong_user: No se puede crear una prueba para %{proving} mientras conectado como %{current}. Conectese como %{proving} e intente de nuevo.\n    explanation_html: Aquí puede conectar criptograficamente a sus otras identidades, como un perfil de Keybase. Esto deja que otras personas les mande mensajes cifrados y confiar en el contenido que reciban de usted.\n    i_am_html: Soy %{username} en %{service}.\n    identity: Identidad\n    inactive: Inactivo\n    publicize_checkbox: 'E incluye esto:'\n    publicize_toot: \"¡Está comprobado! Soy %{username} en %{service}: %{url}\"\n    status: Estado de verificación\n    view_proof: Ver prueba\n  imports:\n    modes:\n      merge: Unir\n      merge_long: Mantener registros actuales y agregar nuevos\n      overwrite: Sobrescribir\n      overwrite_long: Reemplazar registros actuales con los nuevos\n    preface: Puede importar ciertos datos, como todas las personas que está siguiendo o bloqueando en su cuenta en esta instancia, desde archivos exportados de otra instancia.\n    success: Sus datos se han cargado correctamente y serán procesados en brevedad\n    types:\n      blocking: Lista de bloqueados\n      domain_blocking: Lista de dominios bloqueados\n      following: Lista de seguidos\n      muting: Lista de silenciados\n    upload: Subir\n  in_memoriam_html: En memoria.\n  invites:\n    delete: Desactivar\n    expired: Expiradas\n    expires_in:\n      '1800': 30 minutos\n      '21600': 6 horas\n      '3600': 1 hora\n      '43200': 12 horas\n      '604800': 1 semana\n      '86400': 1 día\n    expires_in_prompt: Nunca\n    generate: Generar\n    invited_by: 'Fuiste invitado por:'\n    max_uses:\n      one: 1 uso\n      other: \"%{count} usos\"\n    max_uses_prompt: Sin límite\n    prompt: Generar y compartir enlaces con otros para conceder acceso a este nodo\n    table:\n      expires_at: Expira\n      uses: Usos\n    title: Invitar gente\n  lists:\n    errors:\n      limit: Has alcanzado la cantidad máxima de listas\n  media_attachments:\n    validations:\n      images_and_video: No se puede adjuntar un video a un estado que ya contenga imágenes\n      too_many: No se pueden adjuntar más de 4 archivos\n  migrations:\n    acct: usuario@dominio de la nueva cuenta\n    currently_redirecting: 'Su perfil está redireccionado a:'\n    proceed: Guardar\n    updated_msg: \"¡La configuración de migración de su cuenta ha sido actualizada exitosamente!\"\n  moderation:\n    title: Moderación\n  notification_mailer:\n    digest:\n      action: Ver todas las notificaciones\n      body: Aquí hay un resumen de los mensajes que perdió desde su última visita el %{since}\n      mention: \"%{name} te ha mencionado en:\"\n      new_followers_summary:\n        one: \"¡Ademas, has adquirido un nuevo seguidor mientras no estabas! ¡Hurra!\"\n        other: \"¡Ademas, has adquirido %{count} nuevos seguidores mientras no estabas! ¡Genial!\"\n      subject:\n        one: \"1 nueva notificación desde su última visita \\U0001F418\"\n        other: \"%{count} nuevas notificaciones desde su última visita \\U0001F418\"\n      title: En su ausencia…\n    favourite:\n      body: 'Su estado fue marcado como favorito por %{name}:'\n      subject: \"%{name} marcó su estado como favorito\"\n      title: Nuevo favorito\n    follow:\n      body: \"¡%{name} te está siguiendo!\"\n      subject: \"%{name} te está siguiendo\"\n      title: Nuevo seguidor\n    follow_request:\n      action: Administrar solicitudes para seguir\n      body: \"%{name} ha solicitado seguirte\"\n      subject: 'Seguidor pendiente: %{name}'\n      title: Nueva solicitud para seguir\n    mention:\n      action: Responder\n      body: 'Fuiste mencionado por %{name} en:'\n      subject: Fuiste mencionado por %{name}\n      title: Nueva mención\n    reblog:\n      body: \"%{name} promovió su estado:\"\n      subject: \"%{name} promovió su estado\"\n      title: Nueva difusión\n  number:\n    human:\n      decimal_units:\n        format: \"%n%u\"\n        units:\n          billion: B\n          million: M\n          quadrillion: Q\n          thousand: K\n          trillion: T\n          unit: ''\n  pagination:\n    newer: Más nuevo\n    next: Próximo\n    older: Más antiguo\n    prev: Anterior\n    truncate: \"&hellip;\"\n  polls:\n    errors:\n      already_voted: Ya has votado en esta encuesta\n      duplicate_options: contiene opciones duplicadas\n      duration_too_long: es muy lejos en el futuro\n      duration_too_short: es muy pronto\n      expired: La encuesta ya se ha terminado\n      over_character_limit: no puede tener más de %{max} carácteres cada uno\n      too_few_options: debe tener mas de una opción\n      too_many_options: no puede tener mas de %{max} opciones\n  preferences:\n    other: Otros\n    posting_defaults: Condición base de publicación\n    public_timelines: Cronologías públicas\n  relationships:\n    activity: Actividad de cuenta\n    dormant: Latente\n    last_active: Última vez activo\n    most_recent: Más reciente\n    moved: Movido\n    mutual: Recíproco\n    primary: Primario\n    relationship: Relación\n    remove_selected_domains: Eliminar todos los seguidores de los dominios seleccionados\n    remove_selected_followers: Eliminar los seguidores seleccionados\n    remove_selected_follows: Dejar de seguir los usuarios seleccionados\n    status: Estado de cuenta\n  remote_follow:\n    acct: Ingrese su usuario@dominio desde donde quiere seguir\n    missing_resource: No se pudo encontrar la URL de redirección requerida para su cuenta\n    no_account_html: \"¿No tienes una cuenta? Puedes <a href='%{sign_up_path}' target='_blank'>registrarte aqui</a>\"\n    proceed: Proceder a seguir\n    prompt: 'Vas a seguir a:'\n    reason_html: \"<strong>¿Por qué es este paso necesario?</strong> Pueda que <code>%{instance}</code> no sea el servidor donde esté registrado, entonces necesitamos redirigirle a su servidor primero.\"\n  remote_interaction:\n    favourite:\n      proceed: Preceder a hacer un favorito\n      prompt: 'Quieres hacer este toot un favorito:'\n    reblog:\n      proceed: Preceder a promover\n      prompt: 'Quieres promover este toot:'\n    reply:\n      proceed: Preceder a responder\n      prompt: 'Quieres responder a este toot:'\n  remote_unfollow:\n    error: Error\n    title: Título\n    unfollowed: Dejó de seguir\n  scheduled_statuses:\n    over_daily_limit: Ha excedido el limite de %{limit} toots programados por ese día\n    over_total_limit: Ha excedido el limite de %{limit} toots programados\n    too_soon: La fecha programada debe de estar en el futuro\n  sessions:\n    activity: Última actividad\n    browser: Navegador\n    browsers:\n      alipay: Alipay\n      blackberry: Blackberry\n      chrome: Chrome\n      edge: Microsoft Edge\n      electron: Electron\n      firefox: Firefox\n      generic: Navegador desconocido\n      ie: Internet Explorer\n      micro_messenger: MicroMessenger\n      nokia: Nokia S40 Ovi Browser\n      opera: Opera\n      otter: Otter\n      phantom_js: PhantomJS\n      qq: QQ Browser\n      safari: Safari\n      uc_browser: UCBrowser\n      weibo: Weibo\n    current_session: Sesión actual\n    description: \"%{browser} en %{platform}\"\n    explanation: Estos son los navegadores web conectados actualmente en su cuenta de Mastodon.\n    ip: IP\n    platforms:\n      adobe_air: Adobe Air\n      android: Android\n      blackberry: Blackberry\n      chrome_os: ChromeOS\n      firefox_os: Firefox OS\n      ios: iOS\n      linux: Linux\n      mac: Mac\n      other: Plataforma desconocida\n      windows: Windows\n      windows_mobile: Windows Mobile\n      windows_phone: Windows Phone\n    revoke: Revocar\n    revoke_success: Sesión revocada exitosamente\n    title: Sesiones\n  settings:\n    account: Cuenta\n    account_settings: Configuraciones de la cuenta\n    appearance: Apariencia\n    authorized_apps: Aplicaciones autorizadas\n    back: Volver al inicio\n    delete: Borrar cuenta\n    development: Desarrollo\n    edit_profile: Editar perfil\n    export: Exportar información\n    featured_tags: Etiquetas destacadas\n    identity_proofs: Pruebas de identidad\n    import: Importar\n    import_and_export: Importar y exportar\n    migrate: Migración de cuenta\n    notifications: Notificaciones\n    preferences: Preferencias\n    profile: Perfil\n    relationships: Siguientes y seguidores\n    two_factor_authentication: Autenticación de dos factores\n  statuses:\n    attached:\n      description: 'Adjunto: %{attached}'\n      image:\n        one: \"%{count} imagen\"\n        other: \"%{count} imágenes\"\n      video:\n        one: \"%{count} vídeo\"\n        other: \"%{count} vídeos\"\n    boosted_from_html: Impulsado desde %{acct_link}\n    content_warning: 'Alerta de contenido: %{warning}'\n    disallowed_hashtags:\n      one: 'contenía una etiqueta no permitida: %{tags}'\n      other: 'contenía unas etiquetas no permitidas: %{tags}'\n    language_detection: Detección automática de idioma\n    open_in_web: Abrir en web\n    over_character_limit: Límite de caracteres de %{max} superado\n    pin_errors:\n      limit: Ya has fijado el número máximo de publicaciones\n      ownership: El toot de alguien más no puede fijarse\n      private: Los toots no-públicos no pueden fijarse\n      reblog: Un boost no puede fijarse\n    poll:\n      total_votes:\n        one: \"%{count} voto\"\n        other: \"%{count} votos\"\n      vote: Votar\n    show_more: Mostrar más\n    sign_in_to_participate: Regístrate para participar en la conversación\n    title: '%{name}: \"%{quote}\"'\n    visibilities:\n      private: Sólo mostrar a seguidores\n      private_long: Solo mostrar a tus seguidores\n      public: Público\n      public_long: Todos pueden ver\n      unlisted: Público, pero no mostrar en la historia federada\n      unlisted_long: Todos pueden ver, pero no está listado en las cronologías públicas\n  stream_entries:\n    pinned: Toot fijado\n    reblogged: promovió\n    sensitive_content: Contenido sensible\n  terms:\n    title: Términos del Servicio y Políticas de Privacidad de %{instance}\n  themes:\n    contrast: Alto contraste\n    default: Mastodon (oscuro)\n    mastodon-light: Mastodon (claro)\n  time:\n    formats:\n      default: \"%d de %b del %Y, %H:%M\"\n      month: \"%b %Y\"\n  two_factor_authentication:\n    code_hint: Ingrese el código generado por su aplicación de autenticación para confirmar\n    description_html: Si activa la <strong>autenticación de dos factores</strong>, se requerirá estar en posesión de su teléfono, lo que generará autentificadores para que usted pueda iniciar una sesión.\n    disable: Deshabilitar\n    enable: Habilitar\n    enabled: La autenticación de dos factores está activada\n    enabled_success: Verificación de dos factores activada exitosamente\n    generate_recovery_codes: generar códigos de recuperación\n    instructions_html: \"<strong>Escanea este código QR desde Google Authenticator o una aplicación similar en su teléfono</strong>. Desde ahora, esta aplicación va a generar tokens que tienes que ingresar cuando quieras iniciar sesión.\"\n    lost_recovery_codes: Los códigos de recuperación le permite obtener acceso a su cuenta si pierde su teléfono. Si ha perdido sus códigos de recuperación, puede regenerarlos aquí. Sus viejos códigos de recuperación se harán inválidos.\n    manual_instructions: 'Si no puedes escanear el código QR y necesitas introducirlo manualmente, este es el secreto en texto plano:'\n    recovery_codes: Hacer copias de seguridad de sus códigos de recuperación\n    recovery_codes_regenerated: Códigos de recuperación regenerados con éxito\n    recovery_instructions_html: Si pierde acceso a su teléfono, puede usar uno de los siguientes códigos de recuperación para obtener acceso a su cuenta. <strong>Mantenlos a salvo</strong>. Por ejemplo, puede imprimirlos y guardarlos con otros documentos importantes.\n    setup: Configurar\n    wrong_code: \"¡El código ingresado es inválido! ¿El dispositivo y tiempo del servidor están correctos?\"\n  user_mailer:\n    backup_ready:\n      explanation: Ha solicitado una copia completa de su cuenta de Mastodon. ¡Ya está preparada para descargar!\n      subject: Su archivo está preparado para descargar\n      title: Descargar archivo\n    warning:\n      explanation:\n        disable: Mientras su cuenta esta congelada sus datos quedan intactos, pero no puede hacer nada hasta que sea desbloqueada.\n        silence: Mientras su cuenta esté limitada, solo gente que ya le este siguiendo podran ver sus toots en este servidor, y puede que sea excluido de varias listados públicos. Sin embargo, otros pueden seguirle manualmente.\n        suspend: Su cuenta a sido suspendida, y todos sus toots y sus archivos de media subidos han sido irreversiblemente eliminado de este servidor, y de servidores donde tenía seguidores.\n      review_server_policies: Revisar políticas del servidor\n      subject:\n        disable: Su cuenta %{acct} a sido congelada\n        none: Advertencia para %{acct}\n        silence: Su cuenta %{acct} a sido limitada\n        suspend: Su cuenta %{acct} a sido suspendida\n      title:\n        disable: Cuenta congelada\n        none: Advertencia\n        silence: Cuenta limitada\n        suspend: Cuenta suspendida\n    welcome:\n      edit_profile_action: Configurar el perfil\n      edit_profile_step: Puedes personalizar su perfil subiendo un avatar, una cabecera, cambiando su nombre de usuario y más. Si quiere revisar sus nuevos seguidores antes de que se les permita seguirte, puede bloquear su cuenta.\n      explanation: Aquí hay algunos consejos para empezar\n      final_action: Empezar a publicar\n      final_step: \"¡Empieza a publicar! Incluso sin seguidores, sus mensajes públicos pueden ser vistos por otros, por ejemplo en la cronología local y con etiquetas. Podría introducirse con la etiqueta #introductions.\"\n      full_handle: Su sobrenombre completo\n      full_handle_hint: Esto es lo que le dirías a tus amigos para que ellos puedan enviarle mensajes o seguirle desde otra instancia.\n      review_preferences_action: Cambiar preferencias\n      review_preferences_step: Asegúrate de poner tus preferencias, como que correos te gustaría recibir, o que nivel de privacidad te gustaría que tus publicaciones tengan por defecto. Si no tiene cinetosis, podría activar la reproducción automática de GIFs.\n      subject: Bienvenido a Mastodon\n      tip_federated_timeline: La cronología federada es una vista de la red de Mastodon. Pero solo incluye gente que tus vecinos están siguiendo, así que no está completa.\n      tip_following: Sigue a sus administradores de servidor por defecto. Para encontrar más gente interesante, revisa las cronologías locales y federadas.\n      tip_local_timeline: La cronología local es una vista de la gente en %{instance}. Estos son sus vecinos inmediatos!\n      tip_mobile_webapp: Si el navegador de su dispositivo móvil ofrece agregar Mastodon a su página de inicio, puede recibir notificaciones. Actúa como una aplicación nativa en muchas formas!\n      tips: Consejos\n      title: \"¡Te damos la bienvenida a bordo, %{name}!\"\n  users:\n    follow_limit_reached: No puedes seguir a más de %{limit} personas\n    invalid_email: La dirección de correo es incorrecta\n    invalid_otp_token: Código de dos factores incorrecto\n    otp_lost_help_html: Si perdiste al acceso a ambos, puedes ponerte en contancto con %{email}\n    seamless_external_login: Has iniciado sesión desde un servicio externo, así que los ajustes de contraseña y correo no están disponibles.\n    signed_in_as: 'Sesión iniciada como:'\n  verification:\n    explanation_html: 'Puede <strong>verificarse a si mismo como el dueño de los enlaces en los metadatos de su perfil</strong>. Para eso, el sitio vinculado debe contener un vínculo a su perfil de Mastodon. El vínculo en su sitio <strong>debe</strong> tener un atributo <code>rel=\"me\"</code>. El texto del vínculo no importa. Aquí hay un ejemplo:'\n    verification: Verificación\n"
  },
  {
    "path": "config/locales/eu.yml",
    "content": "---\neu:\n  about:\n    about_hashtag_html: Hauek  <strong>#%{hashtag}</strong> traola duten toot publikoak dira. Fedibertsoko edozein kontu baduzu harremanetan jarri zaitezke.\n    about_mastodon_html: Mastodon web protokolo ireki eta libreak darabiltzan gizarte sare bat da. E-mail sarea bezala deszentralizatua da.\n    about_this: Honi buruz\n    active_count_after: aktiboa\n    active_footnote: Hilabeteko erabiltzaile aktiboak (HEA)\n    administered_by: 'Administratzailea(k):'\n    api: APIa\n    apps: Aplikazio mugikorrak\n    apps_platforms: Erabili Mastodon, iOS, Android eta beste plataformetatik\n    browse_directory: Arakatu profilen direktorio bat eta iragazi interesen arabera\n    browse_public_posts: Arakatu Mastodoneko mezu publikoen zuzeneko jario bat\n    contact: Kontaktua\n    contact_missing: Ezarri gabe\n    contact_unavailable: E/E\n    discover_users: Aurkitu erabiltzaileak\n    documentation: Dokumentazioa\n    extended_description_html: |\n      <h3>Arauentzako toki egoki bat</h3>\n      <p>Azalpen luzea ez da ezarri oraindik.</p>\n    federation_hint_html: \"%{instance} instantzian kontu bat izanda edozein Mastodon zerbitzariko jendea jarraitu ahal izango duzu, eta harago ere.\"\n    generic_description: \"%{domain} sareko zerbitzari bat da\"\n    get_apps: Probatu mugikorrerako aplikazio bat\n    hosted_on: Mastodon %{domain} domeinuan ostatatua\n    learn_more: Ikasi gehiago\n    privacy_policy: Pribatutasun politika\n    see_whats_happening: Ikusi zer gertatzen ari den\n    server_stats: 'Zerbitzariaren estatistikak:'\n    source_code: Iturburu kodea\n    status_count_after:\n      one: mezu\n      other: mezu\n    status_count_before: Hauek\n    tagline: Jarraitu lagunak eta egin berriak\n    terms: Erabilera baldintzak\n    user_count_after:\n      one: erabiltzaile\n      other: erabiltzaile\n    user_count_before: Hemen\n    what_is_mastodon: Zer da Mastodon?\n  accounts:\n    choices_html: \"%{name}(r)en aukerak:\"\n    follow: Jarraitu\n    followers:\n      one: Jarraitzaile\n      other: jarraitzaile\n    following: Jarraitzen\n    joined: \"%{date}(e)an elkartua\"\n    last_active: azkenekoz aktiboa\n    link_verified_on: 'Esteka honen jabetzaren egiaztaketa data: %{date}'\n    media: Multimedia\n    moved_html: \"%{name} hona lekualdatu da %{new_profile_link}:\"\n    network_hidden: Informazio hau ez dago eskuragarri\n    nothing_here: Ez dago ezer hemen!\n    people_followed_by: \"%{name}(e)k jarraitzen dituenak\"\n    people_who_follow: \"%{name} jarraitzen dutenak\"\n    pin_errors:\n      following: Onetsi nahi duzun pertsona aurretik jarraitu behar duzu\n    posts:\n      one: Toot\n      other: Tootak\n    posts_tab_heading: Tootak\n    posts_with_replies: Toot eta erantzunak\n    reserved_username: Erabiltzaile-izena erreserbatuta dago\n    roles:\n      admin: Administratzailea\n      bot: Bot-a\n      moderator: Moderatzailea\n    unavailable: Profila ez dago eskuragarri\n    unfollow: Utzi jarraitzeari\n  admin:\n    account_actions:\n      action: Burutu ekintza\n      title: Burutu moderazio ekintza %{acct} kontuan\n    account_moderation_notes:\n      create: Sortu oharra\n      created_msg: Moderazio oharra ongi sortu da!\n      delete: Ezabatu\n      destroyed_msg: Moderazio ohara ongi suntsitu da!\n    accounts:\n      approve: Onartu\n      approve_all: Onartu denak\n      are_you_sure: Ziur zaude?\n      avatar: Abatarra\n      by_domain: Domeinua\n      change_email:\n        changed_msg: e-mail kontua ongi aldatu da!\n        current_email: Uneko e-mail helbidea\n        label: Aldatu e-mail helbidea\n        new_email: E-mail berria\n        submit: Aldatu e-mail helbidea\n        title: Aldatu %{username}(r)en e-mail helbidea\n      confirm: Berretsi\n      confirmed: Berretsita\n      confirming: Berresten\n      deleted: Ezabatua\n      demote: Jaitsi mailaz\n      disable: Desgaitu\n      disable_two_factor_authentication: Desgaitu 2FA\n      disabled: Desgaituta\n      display_name: Pantaila-izena\n      domain: Domeinua\n      edit: Editatu\n      email: E-mail\n      email_status: Posta elektronikoaren egoera\n      enable: Gaitu\n      enabled: Gaituta\n      feed_url: Jarioaren URL-a\n      followers: Jarraitzaileak\n      followers_url: Jarraitzaileen URL-a\n      follows: Jarraitzen du\n      header: Goiburua\n      inbox_url: Sarrera ontziaren URL-a\n      invited_by: 'Honek gonbidatua:'\n      ip: IP-a\n      joined: Elkartuta\n      location:\n        all: Denak\n        local: Lokala\n        remote: Urrunekoa\n        title: Kokalekua\n      login_status: Saioaren egoera\n      media_attachments: Multimedia eranskinak\n      memorialize: Bihurtu memoriala\n      moderation:\n        active: Aktiboa\n        all: Denak\n        pending: Zain\n        silenced: Isilarazita\n        suspended: Kanporatua\n        title: Moderazioa\n      moderation_notes: Moderazio oharrak\n      most_recent_activity: Azken jarduera\n      most_recent_ip: Azken IP-a\n      no_account_selected: Ez da konturik aldatu ez delako bata bera hautatu\n      no_limits_imposed: Ez da mugarik ezarri\n      not_subscribed: Harpidetu gabe\n      outbox_url: Irteera ontziaren URL-a\n      pending: Berrikusketa egiteke\n      perform_full_suspension: Kanporatu\n      profile_url: Profilaren URL-a\n      promote: Sustatu\n      protocol: Protokoloa\n      public: Publikoa\n      push_subscription_expires: Push harpidetzaren iraugitzea\n      redownload: Freskatu profila\n      reject: Ukatu\n      reject_all: Ukatu denak\n      remove_avatar: Kendu abatarra\n      remove_header: Kendu goiburua\n      resend_confirmation:\n        already_confirmed: Erabiltzaile hau berretsita dago\n        send: Birbidali baieztapen e-maila\n        success: Baieztapen e-maila ongi bidali da!\n      reset: Berrezarri\n      reset_password: Berrezarri pasahitza\n      resubscribe: Berriro harpidetu\n      role: Baimenak\n      roles:\n        admin: Administratzailea\n        moderator: Moderatzailea\n        staff: Langilea\n        user: Erabiltzailea\n      salmon_url: Salmon URL-a\n      search: Bilatu\n      shared_inbox_url: Partekatutako sarrera ontziaren URL-a\n      show:\n        created_reports: Sortutako txostenak\n        targeted_reports: Besteen salaketak\n      silence: Isilarazi\n      silenced: Isilarazita\n      statuses: Mezuak\n      subscribe: Harpidetu\n      suspended: Kanporatuta\n      time_in_queue: Kolan zain %{time}\n      title: Kontuak\n      unconfirmed_email: Baieztatu gabeko e-mail helbidea\n      undo_silenced: Utzi isilarazteari\n      undo_suspension: Desegin kanporatzea\n      unsubscribe: Kendu harpidetza\n      username: Erabiltzaile-izena\n      warn: Abisatu\n      web: Weba\n    action_logs:\n      actions:\n        assigned_to_self_report: \"%{name}(e)k %{target} salaketa bere buruari esleitu dio\"\n        change_email_user: \"%{name}(e)k %{target}(r)en e-mail helbidea aldatu du\"\n        confirm_user: \"%{name}(e)k %{target}(r)en e-mail helbidea berretsi du\"\n        create_account_warning: \"%{name}-k abisua bidali dio %{target}-ri\"\n        create_custom_emoji: \"%{name}(e)k emoji berria kargatu du %{target}\"\n        create_domain_block: \"%{name}(e)k %{target} domeinua blokeatu du\"\n        create_email_domain_block: \"%{name}(e)k %{target} e-mail helbideen domeinua zerrenda beltzean sartu du\"\n        demote_user: \"%{name}(e)k %{target} mailaz jaitsi du\"\n        destroy_custom_emoji: \"%{name} erabiltzaileak %{target} emojia suntsitu du\"\n        destroy_domain_block: \"%{name}(e)k %{target} domeinua desblokeatu du\"\n        destroy_email_domain_block: \"%{name}(e)k %{target} e-mail helbideen domeinua zerrenda zurian sartu du\"\n        destroy_status: \"%{name}(e)k %{target}(e)n egoera kendu du\"\n        disable_2fa_user: \"%{name}(e)k %{target}(r)i bi faktoreetako eskaera kendu dio\"\n        disable_custom_emoji: \"%{name}(e)k %{target} emoji-a desgaitu du\"\n        disable_user: \"%{name}(e)k %{target}(r)en saioa desgaitu du\"\n        enable_custom_emoji: \"%{name}(e)k %{target} emoji-a gaitu du\"\n        enable_user: \"%{name}(e)k %{target} erabiltzailearen saioa gaitu du\"\n        memorialize_account: \"%{name}(e)k %{target}(r)en kontua memoriala bihurtu du\"\n        promote_user: \"%{name}(e)k %{target}(r)en kategoria igo du\"\n        remove_avatar_user: \"%{name}(e)k %{target}(r)en abatarra kendu du\"\n        reopen_report: \"%{name}(e)k %{target}(r)en salaketa berrireki du\"\n        reset_password_user: \"%{name}(e)k %{target}(r)en pasahitza berrezarri du\"\n        resolve_report: \"%{name}(e)k %{target}(r)en salaketa konpondu du\"\n        silence_account: \"%{name}(e)k %{target}(r)en kontua isilarazi du\"\n        suspend_account: \"%{name}(e)k %{target} kontua kanporatu du\"\n        unassigned_report: \"%{name}(e)k %{target} txotenaren esleipena atzera bota du\"\n        unsilence_account: \"%{name}(e)k %{target} isilarazteko agindua kendu du\"\n        unsuspend_account: \"%{name}(e)k %{target} kontuaren kanporaketa atzera bota du\"\n        update_custom_emoji: \"%{name}(e)k %{target} emoji-a eguneratu du\"\n        update_status: \"%{name} (e)k %{target}(r)en mezua aldatu du\"\n      deleted_status: \"(ezabatutako mezua)\"\n      title: Auditoria-egunkaria\n    custom_emojis:\n      by_domain: Domeinua\n      copied_msg: Ongi sortu da emoji-aren kopia lokala\n      copy: Kopiatu\n      copy_failed_msg: Ezin izan da emoji-aren kopia lokal bat sortu\n      created_msg: Emoji-a ongi sortu da!\n      delete: Ezabatu\n      destroyed_msg: Emoji-a ongi suntsitu da!\n      disable: Desgaitu\n      disabled_msg: Emoji-a ongi desgaitu da\n      emoji: Emojia\n      enable: Gaitu\n      enabled_msg: Emoji hori ongi gaitu da\n      image_hint: PNG gehienez 50KB\n      listed: Zerrendatua\n      new:\n        title: Gehitu emoji pertsonal berria\n      overwrite: Gainidatzi\n      shortcode: Laster-kodea\n      shortcode_hint: Gutxienez 2 karaktere, alfanumerikoak eta azpimarra  besterik ez\n      title: Emoji pertsonalak\n      unlisted: Zerrendatu gabea\n      update_failed_msg: Ezin izan da emoji hori eguneratu\n      updated_msg: Emoji-a ongi eguneratu da!\n      upload: Igo\n    dashboard:\n      backlog: aurreikusitako lanak\n      config: Konfigurazioa\n      feature_deletions: Kontu ezabaketak\n      feature_invites: Gonbidapen estekak\n      feature_profile_directory: Profil-direktorioa\n      feature_registrations: Izen emateak\n      feature_relay: Federazio haria\n      feature_timeline_preview: Denbora-lerroaren aurrebista\n      features: Ezaugarriak\n      hidden_service: Federazioa ezkutuko zerbitzuekin\n      open_reports: salaketa irekiak\n      recent_users: Azken erabiltzaileak\n      search: Testu osoko bilaketa\n      single_user_mode: Erabiltzaile bakarreko modua\n      software: Softwarea\n      space: Espazio erabilera\n      title: Kontrol panela\n      total_users: erabiltzaile guztira\n      trends: Joerak\n      week_interactions: interakzio aste honetan\n      week_users_active: aktibo aste honetan\n      week_users_new: erabiltzaile aste honetan\n    domain_blocks:\n      add_new: Gehitu domeinuaren blokeo berria\n      created_msg: Domeinuaren blokeoa orain prozesatzen ari da\n      destroyed_msg: Domeinuaren blokeoa desegin da\n      domain: Domeinua\n      existing_domain_block_html: '%{name} domeinuan muga zorrotzagoak ezarri dituzu jada, aurretik <a href=\"%{unblock_url}\">desblokeatu</a> beharko duzu.'\n      new:\n        create: Sortu blokeoa\n        hint: Domeinuaren blokeoak ez du eragotziko kontuen sarrerak sortzea datu-basean, baina automatikoki ezarriko zaizkie moderazio metodo bereziak iraganeko mezuetan ere.\n        severity:\n          desc_html: \"<strong>Isilarazi</strong>-k kontuko mezuak jarraitzaileek besterik ez ikustea eragingo du. <strong>Kanporatu</strong>-k kontuaren edukia, multimedia eta profileko datuak ezabatuko ditu. <strong>Bat ere ez</strong> nahi duzun guztia multimedia fitxategiak ukatzea bada.\"\n          noop: Bat ere ez\n          silence: Isilarazi\n          suspend: Kanporatu\n        title: Domeinuaren blokeo berria\n      reject_media: Ukatu multimedia fitxategiak\n      reject_media_hint: Lokalki gordetako multimedia fitxategiak ezabatzen ditu eta etorkizunean fitxategi berriak deskargatzeari uko egingo dio. Ez du garrantzirik kanporaketetan\n      reject_reports: Errefusatu salaketak\n      reject_reports_hint: Ezikusi domeinu honetatik jasotako salaketak. Kanporatzeentzako garrantzirik gabekoa\n      rejecting_media: errefusatu multimedia fitxategiak\n      rejecting_reports: txostenak errefusatzen\n      severity:\n        silence: isilarazia\n        suspend: kanporatua\n      show:\n        affected_accounts:\n          one: Datu-baseko kontu bati eragiten dio\n          other: Datu-baseko %{count} kontuei eragiten die\n        retroactive:\n          silence: Kendu isilarazteko agindua domeinu honetako kontu guztiei\n          suspend: Kendu kanporatzeko agindua domeinu honetako kontu guztiei\n        title: Desegin %{domain} domeinuko blokeoa\n        undo: Desegin\n      undo: Desegin domeinuaren blokeoa\n    email_domain_blocks:\n      add_new: Gehitu berria\n      created_msg: Ongi gehitu da e-mail helbidea domeinuen zerrenda beltzera\n      delete: Ezabatu\n      destroyed_msg: Ongi ezabatu da e-mail domeinua zerrenda beltzetik\n      domain: Domeinua\n      new:\n        create: Gehitu domeinua\n        title: Sarrera berria e-mail zerrenda beltzean\n      title: E-mail zerrenda beltza\n    followers:\n      back_to_account: Itzuli kontura\n      title: \"%{acct} kontuaren jarraitzaileak\"\n    instances:\n      by_domain: Domeinua\n      delivery_available: Bidalketa eskuragarri dago\n      known_accounts:\n        one: Kontu ezagun %{count}\n        other: \"%{count} kontu ezagun\"\n      moderation:\n        all: Denak\n        limited: Mugatua\n        title: Moderazioa\n      title: Federazioa\n      total_blocked_by_us: Guk blokeatuta\n      total_followed_by_them: Haiek jarraitua\n      total_followed_by_us: Guk jarraitua\n      total_reported: Heiei buruzko txostenak\n      total_storage: Multimedia eranskinak\n    invites:\n      deactivate_all: Desgaitu guztiak\n      filter:\n        all: Denak\n        available: Eskuragarri\n        expired: Iraungitua\n        title: Iragazi\n      title: Gonbidapenak\n    pending_accounts:\n      title: Zain dauden kontuak (%{count})\n    relays:\n      add_new: Gehitu hari berria\n      delete: Ezabatu\n      description_html: \"<strong>Federazio errele</strong> bat zerbitzari tartekari bat da, bertara harpidetutako eta bertan argitaratzen duten zerbitzarien artean toot publiko kopuru handiak banatzen ditu. <strong>Zerbitzari txiki eta ertainei Fedibertsoko edukia aurkitzen laguntzen die</strong>, bestela erabiltzaile lokalek eskuz jarraitu beharko lituzkete urruneko zerbitzarietako erabiltzaileak.\"\n      disable: Desgaitu\n      disabled: Desgaituta\n      enable: Gaitu\n      enable_hint: Behin gaituta, zure zerbitzaria errele honetako toot publiko guztietara harpidetuko da, eta zerbitzari honetako toot publikoak errelera bidaltzen hasiko da.\n      enabled: Gaituta\n      inbox_url: Errelearen URLa\n      pending: Erreleak onartzearen zain\n      save_and_enable: Gorde eta gaitu\n      setup: Ezarri errele konexio bat\n      status: Mezuak\n      title: Erreleak\n    report_notes:\n      created_msg: Salaketa oharra ongi sortu da!\n      destroyed_msg: Salaketa oharra ongi ezabatu da!\n    reports:\n      account:\n        note: oharra\n        report: salaketa\n      action_taken_by: Neurrien hartzailea\n      are_you_sure: Ziur zaude?\n      assign_to_self: Esleitu niri\n      assigned: Esleitutako moderatzailea\n      comment:\n        none: Bat ere ez\n      created_at: Salatua\n      mark_as_resolved: Markatu konpondutako gisa\n      mark_as_unresolved: Markatu konpondu gabeko gisa\n      notes:\n        create: Gehitu oharra\n        create_and_resolve: Konpondu ohar batekin\n        create_and_unresolve: Berrireki ohar batekin\n        delete: Ezabatu\n        placeholder: Azaldu hartutako neurriak, edo erlazioa duten bestelako berriak...\n      reopen: Berrireki salaketa\n      report: 'Salaketa #%{id}'\n      reported_account: Salatutako kontua\n      reported_by: Salatzailea\n      resolved: Konponduta\n      resolved_msg: Salaketa ongi konpondu da!\n      status: Mezua\n      title: Salaketak\n      unassign: Kendu esleipena\n      unresolved: Konpondu gabea\n      updated_at: Eguneratua\n    settings:\n      activity_api_enabled:\n        desc_html: Lokalki bidalitako mezu kopurua, erabiltzaile aktiboak, eta izen emate berriak asteko\n        title: Argitaratu erabiltzaile-jardueraren estatistikak\n      bootstrap_timeline_accounts:\n        desc_html: Banandu erabiltzaile-izenak koma bitartez. Giltzapetu gabeko kontu lokalekin dabil bakarrik. Hutsik dagoenean lehenetsitakoa admin lokal guztiak da.\n        title: Lehenetsitako jarraipena erabiltzaile berrientzat\n      contact_information:\n        email: Laneko e-mail helbidea\n        username: Kontaktuaren erabiltzaile-izena\n      custom_css:\n        desc_html: Aldatu itxura orri bakoitzean kargatutako CSS bidez\n        title: CSS pertsonala\n      hero:\n        desc_html: Azaleko orrian bistaratua. Gutxienez 600x100px aholkatzen da. Ezartzen ez bada, zerbitzariaren irudia hartuko du\n        title: Azaleko irudia\n      mascot:\n        desc_html: Hainbat orritan bistaratua. Gutxienez 293x205px aholkatzen da. Ezarri ezean lehenetsitako maskota erakutsiko da\n        title: Maskotaren irudia\n      peers_api_enabled:\n        desc_html: Zerbitzari honek fedibertsoan aurkitutako domeinu-izenak\n        title: Argitaratu aurkitutako zerbitzarien zerrenda\n      preview_sensitive_media:\n        desc_html: Beste webguneetako esteken aurrebistak iruditxoa izango du multimedia hunkigarri gisa markatzen bada ere\n        title: Erakutsi multimedia hunkigarria OpenGraph aurrebistetan\n      profile_directory:\n        desc_html: Baimendu erabiltzaileak aurkigarriak izatea\n        title: Gaitu profil-direktorioa\n      registrations:\n        closed_message:\n          desc_html: Azaleko orrian bistaratua izen ematea ixten denean. HTML etiketak erabili ditzakezu\n          title: Izen emate itxiaren mezua\n        deletion:\n          desc_html: Baimendu edonori bere kontua ezabatzea\n          title: Ireki kontu ezabaketa\n        min_invite_role:\n          disabled: Inor ez\n          title: Baimendu hauen gobidapenak\n      registrations_mode:\n        modes:\n          approved: Izena emateko onarpena behar da\n          none: Ezin du inork izena eman\n          open: Edonork eman dezake izena\n        title: Erregistratzeko modua\n      show_known_fediverse_at_about_page:\n        desc_html: Txandakatzean, fedibertsu ezagun osoko toot-ak bistaratuko ditu aurrebistan. Bestela, toot lokalak besterik ez ditu erakutsiko.\n        title: Erakutsi fedibertsu ezagun osoko denbora-lerroa aurrebistan\n      show_staff_badge:\n        desc_html: Erakutsi langile banda erabiltzailearen orrian\n        title: Erakutsi langile banda\n      site_description:\n        desc_html: Azaleko orrian agertuko den sarrera paragrafoa. Azaldu zerk egiten duen berezi Mastodon zerbitzari hau eta garrantzizko beste edozer. HTML etiketak erabili ditzakezu, zehazki <code>&lt;a&gt;</code> eta <code>&lt;em&gt;</code>.\n        title: Zerbitzariaren deskripzioa\n      site_description_extended:\n        desc_html: Zure jokabide-koderako  toki on bat, arauak, gidalerroak eta zure zerbitzari desberdin egiten duten bestelakoak. HTML etiketak erabili ditzakezu\n        title: Informazio hedatu pertsonalizatua\n      site_short_description:\n        desc_html: Albo-barra eta meta etiketetan bistaratua. Deskribatu zerk egiten duen Mastodon zerbitzari hau berezia paragrafo batean. Hutsik lagatzekotan lehenetsitako deskripzioa agertuko da.\n        title: Zerbitzariaren deskripzio laburra\n      site_terms:\n        desc_html: Zure pribatutasun politika, erabilera baldintzak eta bestelako testu legalak idatzi ditzakezu. HTML etiketak erabili ditzakezu\n        title: Erabilera baldintza pertsonalizatuak\n      site_title: Zerbitzariaren izena\n      thumbnail:\n        desc_html: Aurrebistetarako erabilia OpenGraph eta API bidez. 1200x630px aholkatzen da\n        title: Zerbitzariaren iruditxoa\n      timeline_preview:\n        desc_html: Bistaratu denbora-lerro publikoa hasiera orrian\n        title: Denbora-lerroaren aurrebista\n      title: Gunearen ezarpenak\n    statuses:\n      back_to_account: Atzera kontuaren orrira\n      batch:\n        delete: Ezabatu\n        nsfw_off: Markatu ez hunkigarri gisa\n        nsfw_on: Markatu hunkigarri gisa\n      failed_to_execute: Ezin izan da burutu\n      media:\n        title: Multimedia\n      no_media: Multimediarik ez\n      no_status_selected: Ez da mezurik aldatu ez delako mezurik aukeratu\n      title: Kontuaren mezuak\n      with_media: Multimediarekin\n    subscriptions:\n      callback_url: Itzulera URL-a\n      confirmed: Berretsita\n      expires_in: Iraungitzea\n      last_delivery: Azken bidalketa\n      title: WebSub\n      topic: Mintzagaia\n    tags:\n      accounts: Kontuak\n      hidden: Ezkutatuta\n      hide: Ezkutatu direktoriotik\n      name: Traola\n      title: Traolak\n      unhide: Erakutsi direktorioan\n      visible: Ikusgai\n    title: Administrazioa\n    warning_presets:\n      add_new: Gehitu berria\n      delete: Ezabatu\n      edit: Editatu\n      edit_preset: Editatu abisu aurre-ezarpena\n      title: Kudeatu abisu aurre-ezarpenak\n  admin_mailer:\n    new_pending_account:\n      body: Kontu berriaren xehetasunak azpian daude. Eskaera hau onartu edo ukatu dezakezu.\n      subject: Kontu berria berrikusteko %{instance} instantzian (%{username})\n    new_report:\n      body: \"%{reporter}(e)k %{target} salatu du\"\n      body_remote: \"%{domain} domeinuko norbaitek %{target} salatu du\"\n      subject: Salaketa berria %{instance} instantzian (#%{id})\n  appearance:\n    advanced_web_interface: Web interfaze aurreratua\n    advanced_web_interface_hint: 'Pantaila bere zabalera osoan erabili nahi baduzu, web interfaze aurreratuak hainbat zutabe desberdin konfiguratzea ahalbidetzen dizu, aldi berean nahi beste informazio ikusteko: Hasiera, jakinarazpenak, federatutako denbora-lerroa, edo nahi beste zerrenda eta traola.'\n    animations_and_accessibility: Animazioak eta irisgarritasuna\n    confirmation_dialogs: Berrespen dialogoak\n    sensitive_content: Eduki hunkigarria\n  application_mailer:\n    notification_preferences: Aldatu e-mail hobespenak\n    salutation: \"%{name},\"\n    settings: 'Aldatu e-mail hobespenak: %{link}'\n    view: 'Ikusi:'\n    view_profile: Ikusi profila\n    view_status: Ikusi mezua\n  applications:\n    created: Aplikazioa ongi sortu da\n    destroyed: Aplikazioa ongi ezabatu da\n    invalid_url: Emandako URL-a baliogabea da\n    regenerate_token: Birsortu sarbide token-a\n    token_regenerated: Sarbide token-a ongi birsortu da\n    warning: Kontuz datu hauekin, ez partekatu inoiz inorekin!\n    your_token: Zure sarbide token-a\n  auth:\n    apply_for_account: Eskatu gonbidapen bat\n    change_password: Pasahitza\n    checkbox_agreement_html: <a href=\"%{rules_path}\" target=\"_blank\">Zerbitzariaren arauak</a> eta <a href=\"%{terms_path}\" target=\"_blank\">erabilera baldintzak</a> onartzen ditut\n    confirm_email: Berretsi e-mail helbidea\n    delete_account: Ezabatu kontua\n    delete_account_html: Kontua ezabatu nahi baduzu, <a href=\"%{path}\">jarraitu hemen</a>. Berrestea eskatuko zaizu.\n    didnt_get_confirmation: Ez dituzu berresteko argibideak jaso?\n    forgot_password: Pasahitza ahaztu duzu?\n    invalid_reset_password_token: Pasahitza berrezartzeko token-a baliogabea da edo iraungitu du. Eskatu beste bat.\n    login: Hasi saioa\n    logout: Amaitu saioa\n    migrate_account: Lekualdatu beste kontu batera\n    migrate_account_html: Kontu hau beste batera birbideratu nahi baduzu, <a href=\"%{path}\">hemen konfiguratu</a> dezakezu.\n    or_log_in_with: Edo hasi saioa honekin\n    providers:\n      cas: CAS\n      saml: SAML\n    register: Eman izena\n    registration_closed: \"%{instance} instantziak ez ditu kide berriak onartzen\"\n    resend_confirmation: Birbidali berresteko argibideak\n    reset_password: Berrezarri pasahitza\n    security: Segurtasuna\n    set_new_password: Ezarri pasahitza berria\n    trouble_logging_in: Arazoak saioa hasteko?\n  authorize_follow:\n    already_following: Kontu hau aurretik jarraitzen duzu\n    error: Zoritxarrez, urruneko kontua bilatzean errore bat gertatu da\n    follow: Jarraitu\n    follow_request: 'Jarraitzeko eskari bat bidali duzu hona:'\n    following: 'Ongi! Orain jarraitzen duzu:'\n    post_follow:\n      close: Edo, leiho hau besterik gabe itxi dezakezu.\n      return: Erakutsi erabiltzailearen profila\n      web: Joan webera\n    title: Jarraitu %{acct}\n  datetime:\n    distance_in_words:\n      about_x_hours: \"%{count}o\"\n      about_x_months: \"%{count} hilabete\"\n      about_x_years: \"%{count} urte\"\n      almost_x_years: \"%{count} urte\"\n      half_a_minute: Oraintxe\n      less_than_x_minutes: \"%{count}m\"\n      less_than_x_seconds: Oraintxe\n      over_x_years: \"%{count} urte\"\n      x_days: \"%{count} egun\"\n      x_minutes: \"%{count}m\"\n      x_months: \"%{count} hilabete\"\n      x_seconds: \"%{count}s\"\n  deletes:\n    bad_password_msg: Saiakera ona hacker! Pasahitz okerra\n    confirm_password: Sartu zure oraingo pasahitza zure identitatea baieztatzeko\n    description_html: Honek <strong>behin betirako eta atzera egiteko aukera gabe</strong> zure kontuko edukia kendu eta hau desaktibatuko du. Zure erabiltzaile-izena erreserbatuko da etorkizunean inork zure itxurak ez egiteko.\n    proceed: Ezabatu kontua\n    success_msg: Zure kontua ongi ezabatu da\n    warning_html: Zerbitzari honetako edukiak ezabatzea besterik ezin da bermatu. Asko partekatu den edukiaren arrastoak geratzea izan liteke. Deskonektatuta dauden zerbitzariak edo zure eguneraketetatik harpidetza kendu duten zerbitzariek ez dituzte beraien datu-baseak eguneratuko.\n    warning_title: Sakabanatutako edukiaren eskuragarritasuna\n  directories:\n    directory: Profilen direktorioa\n    enabled: Direktorioan zerrendatuta zaude orain.\n    enabled_but_waiting: Direktorioan zerrendatuta izatea aukeratu duzu, baina ez duzu oraindik gutxieneko jarraitzaile kopurua (%{min_followers}) zerrendan agertzeko.\n    explanation: Deskubritu erabiltzaileak interesen arabera\n    explore_mastodon: Esploratu %{title}\n    how_to_enable: Ez duzu aukeratu direktorioan zerrendatua izatea aukeratu. Behean aukeratu dezakezu. Erabili traolak zure biografiaren testuan traola zehatzetan agertzeko!\n    people:\n      one: pertsona %{count}\n      other: \"%{count} pertsona\"\n  errors:\n    '403': Ez duzu orri hau ikusteko baimenik.\n    '404': Bilatu duzun orria ez dago hemen.\n    '410': Bilatu duzun orria ez dago hemen jada.\n    '422':\n      content: Segurtasun egiaztaketak huts egin du. Cookie-ak blokeatzen dituzu?\n      title: Segurtasun egiaztaketak huts egin du\n    '429': Itoa\n    '500':\n      content: Sentitzen dugu, zerbait okerra gertatu da gure aldean.\n      title: Orri hau ez da zuzena\n    noscript_html: Mastodon web aplikazioa erabiltzeko, gaitu JavaScript. Bestela, probatu Mastodon plataformarako <a href=\"%{apps_path}\">aplikazio natibo</a>ren bat.\n  existing_username_validator:\n    not_found: ezin izan da izen hori duen kide lokalik aurkitu\n    not_found_multiple: ezin izan dira aurkitu %{usernames}\n  exports:\n    archive_takeout:\n      date: Data\n      download: Deskargatu zure artxiboa\n      hint_html: Zure <strong>toot eta igotako multimedia</strong>ren artxibo bat eskatu dezakezu. Esportatutako datuak ActivityPub formatua izango dute, bateragarria den edozein programarekin irakurtzeko. Artxiboa 7 egunetan behin eska dezakezu.\n      in_progress: Zure artxiboa biltzen...\n      request: Eskatu zure artxiboa\n      size: Tamaina\n    blocks: Zuk blokeatutakoak\n    csv: CSV\n    domain_blocks: Domeinuen blokeoak\n    follows: Zuk jarraitutakoak\n    lists: Zerrendak\n    mutes: Zuk mututukoak\n    storage: Multimedia biltegiratzea\n  featured_tags:\n    add_new: Gehitu berria\n    errors:\n      limit: Gehienezko traola kopurua nabarmendu duzu jada\n  filters:\n    contexts:\n      home: Hasierako denbora-lerroa\n      notifications: Jakinarazpenak\n      public: Denbora-lerro publikoak\n      thread: Elkarrizketak\n    edit:\n      title: Editatu iragazkia\n    errors:\n      invalid_context: Testuinguru baliogabe edo hutsa eman da\n      invalid_irreversible: Behin betiko iragazketa hasiera edo jakinarazpenen testuinguruan besterik ez dabil\n    index:\n      delete: Ezabatu\n      title: Iragazkiak\n    new:\n      title: Gehitu iragazki berria\n  footer:\n    developers: Garatzaileak\n    more: Gehiago…\n    resources: Baliabideak\n  generic:\n    all: Denak\n    changes_saved_msg: Aldaketak ongi gorde dira!\n    copy: Kopiatu\n    order_by: Ordenatze-irizpidea\n    save_changes: Gorde aldaketak\n    validation_errors:\n      one: Zerbait ez dabil ongi! Egiaztatu beheko errorea mesedez\n      other: Zerbait ez dabil ongi! Egiaztatu beheko %{count}  erroreak mesedez\n  html_validator:\n    invalid_markup: 'HTML markaketa baliogabea du: %{error}'\n  identity_proofs:\n    active: Aktiboa\n    authorize: Bai, baimendu\n    authorize_connection_prompt: Baimendu zifratutako konexio hau?\n    errors:\n      failed: Zifratutako konexioak huts egin du. Saiatu berriro %{provider} hornitzailetik.\n      keybase:\n        invalid_token: Keybase-ko token-ak sinaduren hash-ak dira eta 66 hex karakterekoak izan beha dira\n        verification_failed: Keybase-k ez du token hau Keybase-ko %{kb_username} erabiltzailearen sinaduratzat onartzen. Saiatu berriro Keybase-tik.\n      wrong_user: Ezin izan da %{proving} erabiltzailearentzat froga sortu %{current} gisa saioa hasita. Hasi saioa %{proving} erabilita eta saiatu berriro.\n    explanation_html: Hemen modu zifratuan konektatu ditzakezu zure beste identitateak, esaterako Keybase profila. Honek beste jendeak zuri zifratutako mezuak bidaltzea ahalbidetzen du, eta zuk beraiei bidalitako edukia fidagarritzat jotzea.\n    i_am_html: \"%{username} erabiltzailea naiz %{service} zerbitzuan.\"\n    identity: Identitatea\n    inactive: Ez aktiboa\n    publicize_checkbox: 'Eta bidali toot hau:'\n    publicize_toot: 'Frogatua dago! %{username} erabiltzailea naiz %{service} zerbitzuan: %{url}'\n    status: Egiaztatze egoera\n    view_proof: Ikusi froga\n  imports:\n    modes:\n      merge: Bateratu\n      merge_long: Mantendu dauden erregistroak eta gehitu berriak\n      overwrite: Gainidatzi\n      overwrite_long: Ordeztu oraingo erregistroak berriekin\n    preface: Beste zerbitzari bateko datuak inportatu ditzakezu, esaterako jarraitzen duzun edo blokeatu duzun jendearen zerrenda.\n    success: Zure datuak ongi igo dira eta dagokionean prozesatuko dira\n    types:\n      blocking: Blokeatutakoen zerrenda\n      domain_blocking: Domeinuen blokeo zerrenda\n      following: Jarraitutakoen zerrenda\n      muting: Mutututakoen zerrenda\n    upload: Igo\n  in_memoriam_html: Memoriala.\n  invites:\n    delete: Desaktibatu\n    expired: Iraungitua\n    expires_in:\n      '1800': 30 minutu\n      '21600': 6 ordu\n      '3600': Ordu 1\n      '43200': 12 ordu\n      '604800': Astebete\n      '86400': Egun 1\n    expires_in_prompt: Inoiz ez\n    generate: Sortu\n    invited_by: 'Honek gonbidatu zaitu:'\n    max_uses:\n      one: Erabilera 1\n      other: \"%{count} erabilera\"\n    max_uses_prompt: Mugagabea\n    prompt: Sortu eta partekatu estekak zerbitzari honetara sarbidea emateko\n    table:\n      expires_at: Iraungitzea\n      uses: Erabilerak\n    title: Gonbidatu jendea\n  lists:\n    errors:\n      limit: Gehieneko zerrenda kopurura heldu zara\n  media_attachments:\n    validations:\n      images_and_video: Ezin da irudiak dituen mezu batean bideo bat erantsi\n      too_many: Ezin dira 4 fitxategi baino gehiago erantsi\n  migrations:\n    acct: Kontu berriaren erabiltzaile@domeinua\n    currently_redirecting: 'Zure profila hona birbideratzeko ezarri da:'\n    proceed: Gorde\n    updated_msg: Kontuaren migrazio-ezarpenak ongi eguneratu dira!\n  moderation:\n    title: Moderazioa\n  notification_mailer:\n    digest:\n      action: Ikusi jakinarazpen guztiak\n      body: Hona zure %{since}(e)ko azken bisitatik galdu dituzun mezuen laburpen bat\n      mention: \"%{name}(e)k aipatu zaitu:\"\n      new_followers_summary:\n        one: Kanpoan zeundela jarraitzaile berri bat gehitu zaizu!\n        other: Kanpoan zeundela %{count} jarraitzaile berri bat gehitu zaizkizu!\n      subject:\n        one: \"Jakinarazpen berri bat azken bisitatik \\U0001F418\"\n        other: \"%{count} jakinarazpen berri azken bisitatik \\U0001F418\"\n      title: Kanpoan zeundela...\n    favourite:\n      body: \"%{name}(e)k zure mezua gogoko du:\"\n      subject: \"%{name}(e)k zure mezua gogoko du\"\n      title: Gogoko berria\n    follow:\n      body: \"%{name}(e)k jarraitzen zaitu!\"\n      subject: \"%{name}(e)k jarraitzen zaitu\"\n      title: Jarraitzaile berria\n    follow_request:\n      action: Kudeatu jarraitzeko eskaerak\n      body: \"%{name}(e)k zu jarraitzeko eskaera egin du\"\n      subject: 'Onartzeke dagoen erabiltzailea: %{name}'\n      title: Jarraitzeko eskaera berria\n    mention:\n      action: Erantzun\n      body: \"%{name}(e)k aipatu zaitu:\"\n      subject: \"%{name}(e)k aipatu zaitu\"\n      title: Aipamen berria\n    reblog:\n      body: \"%{name}(e)k bultzada eman dio zure mezuari:\"\n      subject: \"%{name}(e)k bultzada eman dio zure mezuari\"\n      title: Bultzada berria\n  number:\n    human:\n      decimal_units:\n        format: \"%n%u\"\n        units:\n          billion: B\n          million: M\n          quadrillion: Q\n          thousand: K\n          trillion: T\n  pagination:\n    newer: Berriagoa\n    next: Hurrengoa\n    older: Zaharragoa\n    prev: Aurrekoa\n    truncate: \"&hellip;\"\n  polls:\n    errors:\n      already_voted: Inkesta honetan dagoeneko bozkatu duzu\n      duplicate_options: bikoiztutako elementuak ditu\n      duration_too_long: etorkizunean urrunegi dago\n      duration_too_short: goizegi da\n      expired: Inkesta amaitu da jada\n      over_character_limit: bakoitzak gehienez %{max} karaktere izan ditzake\n      too_few_options: elementu bat baino gehiago izan behar du\n      too_many_options: ezin ditu %{max} elementu baino gehiago izan\n  preferences:\n    other: Beste bat\n    posting_defaults: Bidalketarako lehenetsitakoak\n    public_timelines: Denbora-lerro publikoak\n  relationships:\n    activity: Kontuaren aktibitatea\n    dormant: Ez aktiboa\n    last_active: Azkenekoz aktiboa\n    most_recent: Azkenak\n    moved: Lekuz aldatua\n    mutual: Alde bikoa\n    primary: Primarioa\n    relationship: Erlazioa\n    remove_selected_domains: Kendu hautatutako domeinuetako jarraitzaile guztiak\n    remove_selected_followers: Kendu hautatutako jarraitzaileak\n    remove_selected_follows: Utzi hautatutako erabiltzaileak jarraitzeari\n    status: Kontuaren egoera\n  remote_follow:\n    acct: Sartu jarraitzeko erabili nahi duzun erabiltzaile@domeinua\n    missing_resource: Ezin izan da zure konturako behar den birbideratze URL-a\n    no_account_html: Ez duzu konturik? <a href='%{sign_up_path}' target='_blank'>Izena eman</a> dezakezu\n    proceed: Ekin jarraitzeari\n    prompt: 'Hau jarraituko duzu:'\n    reason_html: \"<strong>Zergaitik eman behar da urrats hau?</strong><code>%{instance}</code> agian ez da izena eman duzun zerbitzaria, eta zure hasiera-zerbitzarira eraman behar zaitugu aurretik.\"\n  remote_interaction:\n    favourite:\n      proceed: Bihurtu gogoko\n      prompt: 'Toot hau gogoko bihurtu nahi duzu:'\n    reblog:\n      proceed: Eman bultzada\n      prompt: 'Toot honi bultzada eman nahi diozu:'\n    reply:\n      proceed: Ekin erantzuteari\n      prompt: 'Toot honi erantzun nahi diozu:'\n  remote_unfollow:\n    error: Errorea\n    title: Izenburua\n    unfollowed: Jarraitzeari utzita\n  scheduled_statuses:\n    over_daily_limit: Egun horretarako programatutako toot kopuruaren muga gainditu duzu (%{limit})\n    over_total_limit: Programatutako toot kopuruaren muga gainditu duzu (%{limit})\n    too_soon: Programatutako data etorkizunean egon behar du\n  sessions:\n    activity: Azken jarduera\n    browser: Nabigatzailea\n    browsers:\n      alipay: Alipay\n      blackberry: Blackberry\n      chrome: Chrome\n      edge: Microsoft Edge\n      electron: Electron\n      firefox: Firefox\n      generic: Nabigatzaile ezezaguna\n      ie: Internet Explorer\n      micro_messenger: MicroMessenger\n      nokia: Nokia S40 Ovi nabigatzailea\n      opera: Opera\n      otter: Otter\n      phantom_js: PhantomJS\n      qq: QQ nabigatzailea\n      safari: Safari\n      uc_browser: UCBrowser\n      weibo: Weibo\n    current_session: Uneko saioa\n    description: \"%{browser} - %{platform}\"\n    explanation: Zure Mastodon kontuan saioa hasita duten nabigatzaileak daude.\n    ip: IP-a\n    platforms:\n      adobe_air: Adobe Air\n      android: Android\n      blackberry: Blackberry\n      chrome_os: ChromeOS\n      firefox_os: Firefox OS\n      ios: iOS\n      linux: Linux\n      mac: Mac\n      other: plataforma ezezaguna\n      windows: Windows\n      windows_mobile: Windows Mobile\n      windows_phone: Windows Phone\n    revoke: Indargabetu\n    revoke_success: Saioa ongi indargabetu da\n    title: Saioak\n  settings:\n    account: Kontua\n    account_settings: Kontuaren ezarpenak\n    appearance: Itxura\n    authorized_apps: Baimendutako aplikazioak\n    back: Itzuli Mastodon-era\n    delete: Kontuaren ezabaketa\n    development: Garapena\n    edit_profile: Aldatu profila\n    export: Datuen esportazioa\n    featured_tags: Nabarmendutako traolak\n    identity_proofs: Identitate frogak\n    import: Inportazioa\n    import_and_export: Inportatu eta esportatu\n    migrate: Kontuaren migrazioa\n    notifications: Jakinarazpenak\n    preferences: Hobespenak\n    profile: Profila\n    relationships: Jarraitutakoak eta jarraitzaileak\n    two_factor_authentication: Bi faktoreetako autentifikazioa\n  statuses:\n    attached:\n      description: 'Erantsita: %{attached}'\n      image:\n        one: irudi %{count}\n        other: \"%{count} irudi\"\n      video:\n        one: bideo %{count}\n        other: \"%{count} bideo\"\n    boosted_from_html: \"%{acct_link}(e)tik bultzatua\"\n    content_warning: 'Edukiaren abisua: %{warning}'\n    disallowed_hashtags:\n      one: 'debekatutako traola bat zuen: %{tags}'\n      other: 'debekatutako traola hauek zituen: %{tags}'\n    language_detection: Antzeman hizkuntza automatikoki\n    open_in_web: Ireki web-ean\n    over_character_limit: \"%{max}eko karaktere muga gaindituta\"\n    pin_errors:\n      limit: Gehienez finkatu daitekeen toot kopurua finkatu duzu jada\n      ownership: Ezin duzu beste norbaiten toot bat finkatu\n      private: Ezin dira publikoak ez diren toot-ak finkatu\n      reblog: Bultzada bat ezin da finkatu\n    poll:\n      total_votes:\n        one: Boto %{count}\n        other: \"%{count} boto\"\n      vote: Bozkatu\n    show_more: Erakutsi gehiago\n    sign_in_to_participate: Eman izena elkarrizketan parte hartzeko\n    title: '%{name}: \"%{quote}\"'\n    visibilities:\n      private: Jarraitzaileak besterik ez\n      private_long: Erakutsi jarraitzaileei besterik ez\n      public: Publikoa\n      public_long: Edonork ikusi dezake\n      unlisted: Zerrendatu gabea\n      unlisted_long: Edonork ikusi dezake, baina ez da denbora-lerro publikoetan agertzen\n  stream_entries:\n    pinned: Finkatutako toot-a\n    reblogged: \"(r)en bultzada\"\n    sensitive_content: 'Kontuz: Eduki hunkigarria'\n  terms:\n    body_html: |\n      <h2>Pribatutasun politika</h2>\n      <h3 id=\"collect\">Zer informazio biltzen dugu?</h3>\n\n      <ul>\n      <li><em>Kontuaren oinarrizko informazioa</em>: Zerbitzari honetan izena ematen baduzu, erabiltzaile-izena, e-mail helbidea eta pasahitza sartzea galdetu dakizuke.  Profilean bestelako informazioa sartu dezakezu esaterako pantaila.-izena eta biografia, eta profileko eta goiburuko irudiak igo ditzakezu. Erabiltzaile-izena, pantaiula-izena, biografia, profileko irudia eta goiburuko irudia beti dira publikoak.</li>\n      <li><em>Mezuak, jarraitzea eta beste informazioa</em>: Jarraitzen duzun jendearen zerrenda publikoa da, baita zure jarraitzaileena.  Mezu bat bidaltzean, data eta ordua eta mezua bidaltzeko erabilitako aplikazioa gordetzen dira. Mezuen eranskinak izan ditzakete, esaterako irudiak eta bideoak. Mezu publikoak eta zerrendatu gabeak publikoki ikusi daitezke. Zure profilean mezu bat sustatzen duzunean, informazio hori ere publikoki eskuragarri dago. Zure mezuak zure jarraitzaileei bidaltzen zaie, kasu batzuetan honek esan nahi du beste zerbitzari batzuetara bidaltzen dela eta han kopiak gordetzen dituzte. Mezuak ezabatzen dituzunean, hau zure jarraitzaileei bidaltzen zaie ere, beste mezu batzuk zabaltzea edo gogoko izatea beti da informazio publikoa.</li>\n      <li><em>Mezu zuzenak eta soilik jarraitzaileentzako mezuak</em>: Mezu guztiak zerbitzarian gorde eta prozesatzen dira. Soilik jarraitzaileentzako diren mezuak  zure jarraitzaileei bidaltzen zaie eta bertan aipatutako erabiltzaileei, mezu zuzenak soilik aipatutako erabiltzaileei bidaltzen zaie. Honek esan nahi du kasu batzuetan beste zerbitzari batzuetara bidaltzen dela mezua eta han kopiak gordetzen direla. Borondate oneko ahalegin bat egiten dugu mezuok soilik baimena duten pertsonek ikus ditzaten, baina beste zerbitzariek agian ez. Hortaz,  zure jarraitzaileen zerbitzaria zein den egiaztatzea garrantzitsua da.  Jarraitzaileak eskuz onartu eta ukatzeko aukera aldatu dezakezu. <em>Kontuan izan zerbitzariaren operadoreak eta mezua jasotzen duen edozein zerbitzarik operadoreek mezuok ikus ditzaketela</em> eta edonork atera dezakeela pantaila argazki bat, kopiatu edo beste modu batean partekatu.<em>Ez partekatu informazio arriskutsua Mastodon bidez.</em></li>\n      <li><em>IP-ak eta bestelako meta-datuak</em>: Saioa hasten duzunean, zure IP helbidea gordetzen dugu, eta erabiltzen duzun nabigatzaile edo aplikazioa. Hasitako saio guztiak zuk ikusteko mopduan daude eta ezarpenetan indargabetu ditzakezu. Erabilitako azken IP helbidea 12 hilabetez gordetzen da. Gure zerbitzariak jasotako eskari guztiak eta IP-a duten zerbitzariko egunkariak gorde genitzake.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"use\">Zertarako erabiltzen dugu zure informazioa?</h3>\n\n      <p>Biltzen dugun informazio guztia honela erabiltzen da:</p>\n\n      <ul>\n      <li>Mastodon zerbitzuko funtzio nagusietarako. Beste pertsonen edukiarekin harremanetan sartzeko edo zure edukia argitaratzeko saioa hasi behar duzu. Adibidez, beste pertsona batzuk jarraitu ditzakezu zure denbora-lerro pertsonalizatu bat izateko.</li>\n      <li>Komunitatearen moderazioari laguntzeko, esaterako zure IP-a ezagutzen ditugun beste batzuekin alderatu dezakegu, debekuak ekiditea edo bestelako arau-urraketak eragozteko.</li>\n      <li>Emandako e-mail helbidea informazioa bidaltzeko erabili genezake, beste pertsonek zure edukiekin harremanetan jartzean jakinarazteko, edo mezu bat bidaltzen dizutenean, galderak erantzutean eta bestelako eskari eta galderetarako.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"protect\">Nola babesten dugu zure informazioa?</h3>\n\n      <p>Hainbat segurtasun neurri hartzen ditugu zure informazio pertsonalaren segurtasuna babesteko, informazio pertsonala sartzen duzunean, bidaltzen duzunean edo atzitzen duzunean. Besteak beste zure nabigatzailearen saioa eta zure aplikazioen eta API-aren arteko trafikoa, SSL bidez babesten da, eta zure pasahitza alde bateko algoritmo sendo batekin hash-eatzen da. Bi faktoreetako autentifikazioa gaitu dezakezu zure kontuaren segurtasuna areagotzeko.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"data-retention\">Zein da gure datuak biltzeko politika?</h3>\n\n      <p>Borondate oneko ahalegina egingo dugu honetarako:</p>\n\n      <ul>\n      <li>Zerbitzari honetara egindako eskari guztien egunkaria IP helbidearekin, 90 egunez gehienez.</li>\n      <li>Izena eman duten erabiltzaileen eskariekin lotutako IP helbideak, 12 hilabetez gehienez..</li>\n      </ul>\n\n      <p>Zure edukiaren kopia duen artxibo bat eskatu eta deskargatu dezakezu, bertan mezuak multimedia eranskinak, profileko irudia eta goiburuko irudia daude.</p>\n\n      <p>Zure kontua behin betirako ezabatu dezakezu nahi duzunean.</p>\n\n      <hr class=\"spacer\"/>\n\n      <h3 id=\"cookies\">Cookie-ak erabiltzen ditugu?</h3>\n\n      <p>Bai. Cookie-ak gune edo zerbitzu hornitzaile baten zure ordenagailuko disko gogorrera bidaltzen dituen fitxategi txikiak dira (Zuk baimentzen baduzu). Cookie hauek guneari zure nabigatzailea identifikatzea, konturik duzun jakin, eta erregistratutako kontuarekin erlazionatzea ahalbidetzen diote.</p>\n\n      <p>Cookie-ak erabiltzen ditugu zure hobespenak ulertu eta hurrengo saioetarako gordetzeko</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"disclose\">Informazioa kanpoko inorekin partekatzen dugu?</h3>\n\n      <p>Ez dugu identifikatu zaitzakeen informazio pertsonala, saltzen, trukatzen edo kanpora bidaltzen. Salbuespena konfidatzako hiirugarrengoak dira, gunea martxan izaten laguntzen digutenak, negozioa aurrera eramateko aholkua ematen digutenak edo zuri zerbitzua ematen laguntzen digutenak, hauek informazioaren konfidentzialtasuna errespetatzea onartzen dutenean., Agian legearekin betetzeko beharrezkoa den informazioa ere eman genezake, gunearen politika indarrean jartzeko behar dena, edo gure eskubideak, jabetzak, edo segurtasuna babesteko beharrezkoa dena.</p>\n\n      <p>Zure eduki publikoak sareko beste zerbitzariek deskargatu dezakete. Zure mezu publikoak eta soilik jarraitzaileentzat diren mezuak zure jarraitzaileen zerbitzarietara bidaltzen dira, jarraitzaile edo hartzaile horiek beste zerbitzari batean badute kontua.</p>\n\n      <p>Aplikazio bati zure kontua erabiltzeko baimena ematen diozunean, onartutako baimen esparruaren arabera, zure profileko informazio publikoa atzitu lezake, zuk jarraitutakoen zerrenda, zure jarraitzaileen zerrenda, zure mezu guztiak eta zure gogokoak. Aplikazioen ezin dute inoiz zure e-mail helbidea edo pasahitza atzitu.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"children\">Umeek gunea erabiltzea</h3>\n\n      <p>Zerbitzari hau Europar Batasunean edo Europako Ekonomia-Eremuan badago: Gure gunea, produktua eta zerbitzuak 16 urte edo gehiago dituztenei zuzenduta daude. 16 urte baino gazteagoa bazara, GDPR legearen arabera ezin duzu gune hau erabili (<a href=\"https://en.wikipedia.org/wiki/General_Data_Protection_Regulation\">General Data Protection Regulation</a>) </p>\n\n      <p>Zerbitzari hau Amerikako Estatu Batuetan badago:  Gure gunea, produktua eta zerbitzuak 13 urte edo gehiago dituztenei zuzenduta daude. 13 urte baino gazteagoa bazara, COPPA legearen arabera ezin duzu gune hau erabili (<a href=\"https://en.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act\">Children's Online Privacy Protection Act</a>).</p>\n\n      <p>Zerbitzari hau beste eremu legal batean badago, legearen eskariak desberdinak izan daitezke.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"changes\">Aldaketak gure pribatutasun politikan</h3>\n\n      <p>Guire pribatutasun politika aldatzea erabakitzen badugu, aldaketak orri honetan argitaratuko ditugu.</p>\n\n      <p>Dokumentu honek CC-BY-SA lizentzia du. Eta azkenekoz 2019ko martxoak 7an eguneratu zen</p>\n\n      <p>Jatorrian <a href=\"https://github.com/discourse/discourse\">Discourse sarearen pribatutasun politikatik</a> moldatua.</p>\n    title: \"%{instance} instantziaren erabilera baldintzak eta pribatutasun politika\"\n  themes:\n    contrast: Mastodon (Kontraste altua)\n    default: Mastodon (Iluna)\n    mastodon-light: Mastodon (Argia)\n  time:\n    formats:\n      default: \"%Y(e)ko %b %d, %H:%M\"\n      month: \"%Y(e)ko %b\"\n  two_factor_authentication:\n    code_hint: Sartu zure autentifikazio aplikazioak sortutako kodea berresteko\n    description_html: \"<strong>Bi faktoreetako autentifikazioa</strong> gaitzen baduzu, saioa hasteko telefonoa eskura izan beharko duzu, honek zuk sartu behar dituzun kodeak sortuko dituelako.\"\n    disable: Desgaitu\n    enable: Gaitu\n    enabled: Bi faktoreetako autentifikazioa gaituta dago\n    enabled_success: Bi faktoreetako autentifikazioa ongi gaitu da\n    generate_recovery_codes: Sortu berreskuratze kodeak\n    instructions_html: \"<strong>Eskaneatu QR kode hau Google Authentiocator edo antzeko TOTTP aplikazio batekin zure telefonoan</strong>. Hortik aurrera, aplikazio horrek saioa hasteko sartu behar dituzun kodeak sortuko ditu.\"\n    lost_recovery_codes: Berreskuratze kodeek telefonoa galtzen baduzu kontura sarbidea berreskuratzea ahalbideko dizute. Berreskuratze kodeak galdu badituzu, hemen birsortu ditzakezu. Zure berreskuratze kode zaharrak indargabetuko dira,.\n    manual_instructions: 'Ezin baduzu QR kodea eskaneatu eta eskuz sartu behar baduzu, hona sekretua testu hutsean:'\n    recovery_codes: Berreskuratze kodeen babes-kopia\n    recovery_codes_regenerated: Berreskuratze kodeak ongi sortu dira\n    recovery_instructions_html: Zure telefonora sarbidea galtzen baduzu, beheko berreskuratze kode bat erabili dezakezu kontura berriro sartu ahal izateko. <strong>Gore barreskuratze kodeak toki seguruan</strong>. Adibidez inprimatu eta dokumentu garrantzitsuekin batera gorde.\n    setup: Ezarri\n    wrong_code: Sartutako kodea baliogabea da! Zerbitzariaren eta gailuaren erlojuak ondo ezarrita daude?\n  user_mailer:\n    backup_ready:\n      explanation: Zure Mastodon kontuaren babes-kopia osoa eskatu duzu. Deskargatzeko prest dago!\n      subject: Zure artxiboa deskargatzeko prest dago\n      title: Artxiboa jasotzea\n    warning:\n      explanation:\n        disable: Zure kontua izoztuta dagoen bitartean, zure kontua bere horretan dirau, baina ezin duzu ekintzarik burutu desblokeatzen den arte.\n        silence: Zure kontua murriztua dagoen bitartean, jada zu jarraitzen zaituztenak besterik ez dituzte zure Toot-ak ikusiko zerbitzari honetan, eta agian zerrenda publikoetatik kenduko zaizu. Hala ere besteek oraindik zu jarraitu zaitzakete.\n        suspend: Zure kontua kanporatua izan da, zure toot guztiak eta multimedia fitxategiak behin betiko ezabatu dira zerbitzari honetatik, eta zure jarraitzaileen zerbitzarietatik.\n      review_server_policies: Berrikusi zerbitzariko politikak\n      subject:\n        disable: Zure  %{acct} kontua izoztu da\n        none: \"%{acct} konturako abisua\"\n        silence: Zure  %{acct} kontua murriztu da\n        suspend: Zure %{acct} kontua kanporatua izan da\n      title:\n        disable: Kontu izoztua\n        none: Abisua\n        silence: Kontu murriztua\n        suspend: Kontu kanporatua\n    welcome:\n      edit_profile_action: Ezarri profila\n      edit_profile_step: Pertsonalizatu profila abatar bat igoz, goiburu bat, zure pantaila-izena aldatuz eta gehiago. Jarraitzaile berriak onartu aurretik gainbegiratu nahi badituzu, kontua giltzaperatu dezakezu.\n      explanation: Hona hasteko aholku batzuk\n      final_action: Hasi mezuak bidaltzen\n      final_step: 'Hasi argitaratzen! Jarraitzailerik ez baduzu ere zure mezu publikoak besteek ikusi ditzakete, esaterako denbora-lerro lokalean eta traoletan. Zure burua aurkeztu nahi baduzu #aurkezpenak traola erabili zenezake.'\n      full_handle: Zure erabiltzaile-izen osoa\n      full_handle_hint: Hau da lagunei esango zeniekeena beste zerbitzari batetik zu jarraitzeko edo zuri mezuak bidaltzeko.\n      review_preferences_action: Aldatu hobespenak\n      review_preferences_step: Ziurtatu hobespenak ezartzen dituzula, jaso nahi dituzu e-mail mezuak, lehenetsitako pribatutasuna mezu berrietarako. Mareatzen ez bazaitu GIF-ak automatikoki abiatzea ezarri dezakezu ere.\n      subject: Ongi etorri Mastodon-era\n      tip_federated_timeline: Federatutako denbora-lerroan Mastodon sarearen trafikoa ikusten da. Baina zure instantziako auzokideak jarraitutakoak besterik ez daude hor, ez da osoa.\n      tip_following: Lehenetsita zerbitzariko administratzailea jarraitzen duzu. Jende interesgarri gehiago aurkitzeko, egiaztatu denbora-lerro lokala eta federatua.\n      tip_local_timeline: Denbora-lerro lokalean %{instance} instantziako trafikoa ikusten da. Hauek zure instantziako auzokideak dira!\n      tip_mobile_webapp: Zure mugikorreko nabigatzaileak Mastodon hasiera pantailan gehitzea eskaintzen badizu, push jakinarazpenak jaso ditzakezu. Aplikazio natiboaren parekoa da zentzu askotan!\n      tips: Aholkuak\n      title: Ongi etorri, %{name}!\n  users:\n    follow_limit_reached: Ezin dituzu %{limit} pertsona baino gehiago jarraitu\n    invalid_email: E-mail helbidea baliogabea da\n    invalid_otp_token: Bi faktoreetako kode baliogabea\n    otp_lost_help_html: 'Bietara sarbidea galdu baduzu, jarri kontaktuan hemen: %{email}'\n    seamless_external_login: Kanpo zerbitzu baten bidez hasi duzu saioa, beraz pasahitza eta e-mail ezarpenak ez daude eskuragarri.\n    signed_in_as: 'Saioa honela hasita:'\n  verification:\n    explanation_html: 'Ezin duzu <strong>zure burua zure profileko metadatuen esteken jabe gisa egiaztatu</strong>. Horretarako, estekatutako webgunean zure Mastodon profilera daraman esteka bat egon behar du. Mastodonera daraman esteka horrek<strong>derrigorrez</strong> <code>rel=\"me\"</code> artibutua izan behar du . Estekaren testuak ez du axola. Hona adibide bat:'\n    verification: Egiaztaketa\n"
  },
  {
    "path": "config/locales/fa.yml",
    "content": "---\nfa:\n  about:\n    about_hashtag_html: این‌ها نوشته‌های عمومی هستند که برچسب (هشتگ) <strong>#%{hashtag}</strong> را دارند. اگر شما روی هر سروری حساب داشته باشید می‌توانید به این نوشته‌ها واکنش نشان دهید.\n    about_mastodon_html: ماستدون (Mastodon) یک شبکهٔ اجتماعی است که بر اساس پروتکل‌های آزاد وب و نرم‌افزارهای آزاد و کدباز ساخته شده است. این شبکه مانند ایمیل غیرمتمرکز است.\n    about_this: درباره\n    active_count_after: فعال\n    active_footnote: کاربران فعال در ماه گذشته\n    administered_by: 'با مدیریت:'\n    api: رابط برنامه‌نویسی کاربردی\n    apps: اپ‌های موبایل\n    apps_platforms: ماستدون را در iOS، اندروید، و سایر سیستم‌ها داشته باشید\n    browse_directory: در فهرست گزیدهٔ کاربران این سرور چرخی بزنید و کاربران را بر اساس علاقه‌مندی‌هایشان پیدا کنید\n    browse_public_posts: فهرست لحظه‌ای نوشته‌های عمومی در ماستدون را ببینید\n    contact: تماس\n    contact_missing: تعیین نشده\n    contact_unavailable: موجود نیست\n    discover_users: یافتن کاربران\n    documentation: مستندات\n    extended_description_html: |\n      <h3>جای خوبی برای قانون‌ها</h3>\n      <p>توضیحات تکمیلی نوشته نشده است.</p>\n    federation_hint_html: با داشتن حساب روی %{instance} می‌توانید کاربران همهٔ سرورهای دیگر ماستدون (و سایر شبکه‌های سازگار با آن) را پی بگیرید.\n    generic_description: \"%{domain} یک سرور روی شبکه است\"\n    get_apps: یک اپ موبایل را امتحان کنید\n    hosted_on: ماستدون، میزبانی‌شده روی %{domain}\n    learn_more: بیشتر بدانید\n    privacy_policy: سیاست رازداری\n    see_whats_happening: ببینید چه خبر است\n    server_stats: 'آمار سرور:'\n    source_code: کدهای منبع\n    status_count_after:\n      one: چیز نوشته‌اند\n      other: چیز نوشته‌اند\n    status_count_before: که در کنار هم\n    tagline: با دوستان خود در ارتباط باشید و دوستان تازه پیدا کنید\n    terms: شرایط کاربری\n    user_count_after:\n      one: کاربر\n      other: کاربر\n    user_count_before: دارای\n    what_is_mastodon: ماستدون چیست؟\n  accounts:\n    choices_html: 'انتخاب‌های %{name}:'\n    follow: پی بگیرید\n    followers:\n      one: پیگیر\n      other: پیگیر\n    following: پی می‌گیرد\n    joined: کاربر از %{date}\n    last_active: آخرین فعالیت\n    link_verified_on: مالکیت این نشانی در تاریخ %{date} بررسی شد\n    media: عکس و ویدیو\n    moved_html: \"%{name} حساب خود را به %{new_profile_link} منتقل کرده است:\"\n    network_hidden: این اطلاعات در دسترس نیست\n    nothing_here: این‌جا چیزی نیست!\n    people_followed_by: کسانی که %{name} پی می‌گیرد\n    people_who_follow: کسانی که %{name} را پی می‌گیرند\n    pin_errors:\n      following: شما باید پیگیر کاربری باشید که می‌خواهید ثابت کنید\n    posts:\n      one: بوق\n      other: بوق\n    posts_tab_heading: نوشته‌ها\n    posts_with_replies: نوشته‌ها و پاسخ‌ها\n    reserved_username: این نام کاربری در دسترس نیست\n    roles:\n      admin: مدیر\n      bot: ربات\n      moderator: ناظم\n    unfollow: پایان پیگیری\n  admin:\n    account_actions:\n      action: انجام تغییر\n      title: انجام تغییر مدیریتی روی %{acct}\n    account_moderation_notes:\n      create: افزودن یادداشت\n      created_msg: یادداشت مدیر با موفقیت ساخته شد!\n      delete: پاک کردن\n      destroyed_msg: یادداشت مدیر با موفقیت پاک شد!\n    accounts:\n      approve: پذیرفتن\n      approve_all: پذیرفتن همه\n      are_you_sure: آیا مطمئن هستید؟\n      avatar: تصویر نمایه\n      by_domain: دامین\n      change_email:\n        changed_msg: نشانی ایمیل این حساب با موفقیت تغییر کرد!\n        current_email: ایمیل کنونی\n        label: تغییر نشانی ایمیل\n        new_email: ایمیل تازه\n        submit: تغییر ایمیل\n        title: تغییر ایمیل برای %{username}\n      confirm: تأیید\n      confirmed: تأیید شد\n      confirming: تأیید\n      deleted: پاک‌شده\n      demote: تنزل‌دادن\n      disable: غیرفعال\n      disable_two_factor_authentication: غیرفعال‌سازی ورود دومرحله‌ای\n      disabled: غیرفعال\n      display_name: نمایش به نام\n      domain: دامین\n      edit: ویرایش\n      email: ایمیل\n      email_status: وضعیت ایمیل\n      enable: فعال\n      enabled: فعال\n      feed_url: نشانی فید\n      followers: پیگیران\n      followers_url: نشانی پیگیران\n      follows: پی می‌گیرد\n      header: زمینه\n      inbox_url: نشانی صندوق ورودی\n      invited_by: دعوت‌شده از طرف\n      joined: عضویت از\n      location:\n        all: همه\n        local: محلی\n        remote: غیرمستقیم\n        title: مکان\n      login_status: وضعیت ورود\n      media_attachments: ضمیمه‌های تصویری\n      memorialize: تبدیل به یادمان\n      moderation:\n        active: فعال\n        all: همه\n        pending: در انتظار\n        silenced: بی‌صدا شده\n        suspended: معلق شده\n        title: وضعیت\n      moderation_notes: یادداشت مدیر\n      most_recent_activity: آخرین فعالیت‌ها\n      most_recent_ip: آخرین IP ها\n      no_account_selected: هیچ حسابی تغییر نکرد زیرا حسابی انتخاب نشده بود\n      no_limits_imposed: بدون محدودیت\n      not_subscribed: عضو نیست\n      outbox_url: نشانی صندوق خروجی\n      pending: در انتظار بررسی\n      perform_full_suspension: تعلیق\n      profile_url: نشانی نمایه\n      promote: ترفیع‌دادن\n      protocol: پروتکل\n      public: عمومی\n      push_subscription_expires: عضویت از راه PuSH منقضی شد\n      redownload: به‌روزرسانی نمایه\n      reject: نپذیرفتن\n      reject_all: نپذیرفتن هیچکدام\n      remove_avatar: حذف تصویر نمایه\n      remove_header: برداشتن تصویر زمینه\n      resend_confirmation:\n        already_confirmed: این کاربر قبلا تایید شده است\n        send: ایمیل تایید را دوباره بفرستید\n        success: ایمیل تایید با موفقیت ارسال شد!\n      reset: بازنشانی\n      reset_password: بازنشانی رمز\n      resubscribe: اشتراک دوباره\n      role: اجازه‌ها\n      roles:\n        admin: مدیر\n        moderator: ناظم\n        staff: کارمند\n        user: کاربر\n      salmon_url: نشانی Salmon\n      search: جستجو\n      shared_inbox_url: نشانی صندوق ورودی مشترک\n      show:\n        created_reports: گزارش‌های ثبت کرده\n        targeted_reports: گزارش‌های دیگران\n      silence: بی‌صدا\n      silenced: بی‌صداشده\n      statuses: نوشته‌ها\n      subscribe: اشتراک\n      suspended: تعلیق‌شده\n      time_in_queue: در حال انتظار %{time}\n      title: حساب‌ها\n      unconfirmed_email: ایمیل تأییدنشده\n      undo_silenced: واگردانی بی‌صداکردن\n      undo_suspension: واگردانی تعلیق\n      unsubscribe: لغو اشتراک\n      username: نام کاربری\n      warn: هشدار\n      web: وب\n    action_logs:\n      actions:\n        assigned_to_self_report: \"%{name} رسیدگی به گزارش %{target} را به عهده گرفت\"\n        change_email_user: \"%{name} نشانی ایمیل کاربر %{target} را تغییر داد\"\n        confirm_user: \"%{name} نشانی ایمیل کاربر %{target} را تأیید کرد\"\n        create_account_warning: \"%{name} هشداری برای %{target} فرستاد\"\n        create_custom_emoji: \"%{name} شکلک تازهٔ %{target} را بارگذاشت\"\n        create_domain_block: \"%{name} دامین %{target} را مسدود کرد\"\n        create_email_domain_block: \"%{name} دامین ایمیل %{target} را مسدود کرد\"\n        demote_user: \"%{name} مقام کاربر %{target} را تنزل داد\"\n        destroy_custom_emoji: \"%{name} شکلک %{target} را حذف کرد\"\n        destroy_domain_block: \"%{name} دامین %{target} را باز کرد\"\n        destroy_email_domain_block: \"%{name} دامین ایمیل %{target} را باز کرد\"\n        destroy_status: \"%{name} نوشته‌ای از %{target} را پاک کرد\"\n        disable_2fa_user: \"%{name} اجبار ورود دومرحله‌ای را برای کاربر %{target} غیرفعال کرد\"\n        disable_custom_emoji: \"%{name} شکلک %{target} را غیرفعال کرد\"\n        disable_user: \"%{name} ورود را برای کاربر %{target} غیرفعال کرد\"\n        enable_custom_emoji: \"%{name} شکلک %{target} را فعال کرد\"\n        enable_user: \"%{name} ورود را برای کاربر %{target} فعال کرد\"\n        memorialize_account: \"%{name} حساب کاربر %{target} را تبدیل به صفحهٔ یادمان کرد\"\n        promote_user: \"%{name} کاربر %{target} را ترفیع داد\"\n        remove_avatar_user: \"%{name} تصویر نمایهٔ کاربر %{target} را حذف کرد\"\n        reopen_report: \"%{name} گزارش %{target} را دوباره به جریان انداخت\"\n        reset_password_user: \"%{name} رمز کاربر %{target} را بازنشاند\"\n        resolve_report: \"%{name} گزارش %{target} را رفع کرد\"\n        silence_account: \"%{name} حساب کاربر %{target} را خاموش (بی‌صدا) کرد\"\n        suspend_account: \"%{name} حساب کاربر %{target} را تعلیق کرد\"\n        unassigned_report: \"%{name} بررسی گزارش %{target} را متوقف کرد\"\n        unsilence_account: \"%{name} حساب کاربر %{target} را روشن (باصدا) کرد\"\n        unsuspend_account: \"%{name} حساب کاربر %{target} را از تعلیق خارج کرد\"\n        update_custom_emoji: \"%{name} شکلک %{target} را به‌روز کرد\"\n        update_status: \"%{name} نوشتهٔ %{target} را به‌روز کرد\"\n      deleted_status: \"(بوق پاک‌شده)\"\n      title: سیاههٔ بازرسی\n    custom_emojis:\n      by_domain: دامین\n      copied_msg: نسخهٔ محلی شکلک با موفقیت ساخته شد\n      copy: نسخه‌برداری\n      copy_failed_msg: نشد که نسخهٔ محلی این شکلک ساخته شود\n      created_msg: این شکلک با موفقیت ساخته شد!\n      delete: پاک کردن\n      destroyed_msg: این شکلک با موفقیت پاک شد!\n      disable: غیرفعال‌سازی\n      disabled_msg: این شکلک با موفقیت غیرفعال شد\n      emoji: شکلک\n      enable: فعال‌سازی\n      enabled_msg: این شکلک با موفقیت فعال شد\n      image_hint: پروندهٔ PNG حداکثر 50KB\n      listed: فهرست‌شده\n      new:\n        title: افزودن شکلک سفارشی\n      overwrite: بازنویسی\n      shortcode: کد کوتاه\n      shortcode_hint: دست‌کم ۲ نویسه و تنها شامل حروف، اعداد و زیرخط\n      title: شکلک‌های سفارشی\n      unlisted: فهرست‌نشده\n      update_failed_msg: این شکلک نتوانست به‌روز شود\n      updated_msg: شکلک با موفقیت به‌روز شد!\n      upload: بارگذاری\n    dashboard:\n      backlog: کارهای باقیمانده\n      config: پیکربندی\n      feature_deletions: حساب‌های حذف‌شده\n      feature_invites: دعوت‌نامه‌ها\n      feature_profile_directory: فهرست گزیدهٔ کاربران\n      feature_registrations: ثبت‌نام‌ها\n      feature_relay: رله\n      feature_timeline_preview: پیش‌نمایش نوشته‌ها\n      features: ویژگی‌ها\n      hidden_service: ارتباط میان‌سروری با سرویس‌های نهفته\n      open_reports: گزارش‌های فعال\n      recent_users: کاربران تازه\n      search: جستجوی متنی\n      single_user_mode: حالت تک‌کاربره\n      software: نرم‌افزار\n      space: فضای مصرف‌شده\n      title: ابزارهای مدیریت\n      total_users: شمار کاربران\n      trends: هشتگ‌های پرکاربرد\n      week_interactions: فعالیت‌ها در این هفته\n      week_users_active: کاربران فعال هفتهٔ اخیر\n      week_users_new: کاربران هفتهٔ اخیر\n    domain_blocks:\n      add_new: افزودن مسدودسازی دامین تازه\n      created_msg: مسدودکردن دامین در حال انجام است\n      destroyed_msg: مسدودکردن دامین واگردانده شد\n      domain: دامین\n      new:\n        create: مسدودسازی\n        hint: مسدودسازی دامین جلوی فهرست‌شدن حساب‌ها در پایگاه داده را نمی‌گیرد، بلکه به طور خودکار روش‌های مدیریتی را روی فعالیت‌های فعلی و گذشتهٔ آن حساب‌ها اعمال می‌کند.\n        severity:\n          desc_html: \"<strong>بی‌صداکردن</strong> یک حساب نوشته‌های آن را برای همه (به جز پیگیرانش) ناپدید می‌کند. <strong>معلق‌کردن</strong> حساب همهٔ نوشته‌ها، تصویرها، و اطلاعات حساب را پاک می‌کند. اگر فقط می‌خواهید جلوی تصویرها و ویدیوها را بگیرید <strong>هیچ</strong> را برگزینید.\"\n          noop: هیچ\n          silence: بی‌صداکردن\n          suspend: معلق‌کردن\n        title: مسدودسازی دامین دیگر\n      reject_media: نپذیرفتن پرونده‌های تصویری\n      reject_media_hint: تصویرهای ذخیره‌شده در این‌جا را پاک می‌کند و جلوی دریافت تصویرها را در آینده می‌گیرد. بی‌تأثیر برای معلق‌شده‌ها\n      reject_reports: نپذیرفتن گزارش‌ها\n      reject_reports_hint: گزارش‌هایی را که از این دامین می‌آید نادیده می‌گیرد. بی‌تأثیر برای معلق‌شده‌ها\n      rejecting_media: رسانه‌ها نادیده گرفته می‌شوند\n      rejecting_reports: گزارش‌ها نادیده گرفته می‌شوند\n      severity:\n        silence: بی‌صداشده\n        suspend: معلق‌شده\n      show:\n        affected_accounts:\n          one: روی یک حساب در پایگاه داده تأثیر گذاشت\n          other: روی %{count} حساب در پایگاه داده تأثیر گذاشت\n        retroactive:\n          silence: بی‌صداشدن همهٔ حساب‌های این دامین را لغو کن\n          suspend: معلق‌شدن همهٔ حساب‌های این دامین را لغو کن\n        title: واگردانی مسدودسازی دامنه برای %{domain}\n        undo: واگردانی\n      undo: واگردانی مسدودسازی دامین\n    email_domain_blocks:\n      add_new: افزودن تازه\n      created_msg: مسدودسازی دامین ایمیل با موفقیت ساخته شد\n      delete: پاک‌کردن\n      destroyed_msg: مسدودسازی دامین ایمیل با موفقیت پاک شد\n      domain: دامین\n      new:\n        create: ساختن مسدودسازی\n        title: مسدودسازی دامین ایمیل تازه\n      title: مسدودسازی دامین‌های ایمیل\n    followers:\n      back_to_account: بازگشت به حساب\n      title: پیگیران %{acct}\n    instances:\n      by_domain: دامین\n      delivery_available: پیام آماده است\n      known_accounts:\n        one: \"%{count} حساب شناخته‌شده\"\n        other: \"%{count} حساب شناخته‌شده\"\n      moderation:\n        all: همه\n        limited: محدود\n        title: مدیریت\n      title: ارتباط میان‌سروری\n      total_blocked_by_us: مسدودشده از طرف ما\n      total_followed_by_them: ما را پی می‌گیرند\n      total_followed_by_us: ما پیگیرشان هستیم\n      total_reported: گزارش درباره‌شان\n      total_storage: عکس‌ها و ویدیوها\n    invites:\n      deactivate_all: غیرفعال‌کردن همه\n      filter:\n        all: همه\n        available: در دسترس\n        expired: منقضی‌شده\n        title: فیلتر\n      title: دعوت‌ها\n    relays:\n      add_new: افزودن رلهٔ تازه\n      delete: حذف\n      description_html: یک <strong>رلهٔ میان‌سروری</strong> (federation relay) یک سرور میانجی است که حجم زیادی از بوق‌های عمومی را بین سرورهای گوناگونی که عضوش می‌شوند جابه‌جا می‌کند. <strong>رله‌ها به سرورهای کوچک و متوسط کمک می‌کنند تا مطالب عمومی بیشتری را بیابند.</strong> اگر رله نباشد، این مطالب عمومی تنها وقتی پیدا می‌شوند که کاربران محلی خودشان پیگیر کاربران روی سرورهای دیگر شوند.\n      disable: غیرفعال‌کردن\n      disabled: غیرفعال\n      enable: فعال‌سازی\n      enable_hint: اگر فعال باشد، سرور شما عضو همهٔ بوق‌های عمومی‌ای را که از این رله می‌آید می‌گیرد، و بوق‌های عمومی این سرور را به آن می‌فرستند.\n      enabled: فعال\n      inbox_url: نشانی رله\n      pending: در انتظار پذیرش رله\n      save_and_enable: ذخیره و فعال‌سازی\n      setup: پیوستن به رله‌ها\n      status: وضعیت\n      title: رله‌ها\n    report_notes:\n      created_msg: یادداشت گزارش با موفقیت ساخته شد!\n      destroyed_msg: یادداشت گزارش با موفقیت حذف شد!\n    reports:\n      account:\n        note: یادداشت\n        report: گزارش\n      action_taken_by: انجام‌دهنده\n      are_you_sure: آیا مطمئن هستید؟\n      assign_to_self: به عهدهٔ من بگذار\n      assigned: مدیر عهده‌دار\n      comment:\n        none: خالی\n      created_at: گزارش‌شده\n      mark_as_resolved: علامت‌گذاری به عنوان حل‌شده\n      mark_as_unresolved: علامت‌گذاری به عنوان حل‌نشده\n      notes:\n        create: افزودن یادداشت\n        create_and_resolve: حل کردن با یادداشت\n        create_and_unresolve: دوباره گشودن با یادداشت\n        delete: حذف\n        placeholder: کارهایی را که در این باره انجام شده، یا هر به‌روزرسانی دیگری را بنویسید...\n      reopen: دوباره به جریان بیندازید\n      report: 'گزارش #%{id}'\n      reported_account: حساب گزارش‌شده\n      reported_by: گزارش از طرف\n      resolved: حل‌شده\n      resolved_msg: گزارش با موفقیت حل شد!\n      status: نوشته\n      title: گزارش‌ها\n      unassign: پس‌گرفتن مسئولیت\n      unresolved: حل‌نشده\n      updated_at: به‌روز شد\n    settings:\n      activity_api_enabled:\n        desc_html: تعداد بوق‌های محلی، کاربران فعال، و کاربران تازه در هر هفته\n        title: انتشار آمار تجمیعی دربارهٔ فعالیت کاربران\n      bootstrap_timeline_accounts:\n        desc_html: نام‌های کاربری را با ویرگول از هم جدا کنید. تنها حساب‌های محلی و قفل‌نشده کار می‌کنند. اگر این‌جا را خالی بگذارید، به طور پیش‌فرض همهٔ مدیرهای این سرور پی‌گرفته خواهند شد.\n        title: پیگیری‌های پیش‌فرض برای کاربران تازه\n      contact_information:\n        email: ایمیل کاری\n        username: نام کاربری\n      custom_css:\n        desc_html: ظاهر ماستدون را با CSS-ای که در همهٔ صفحه‌ها جاسازی می‌شود تغییر دهید\n        title: سبک CSS سفارشی\n      hero:\n        desc_html: در صفحهٔ آغازین نمایش می‌یابد. دست‌کم ۶۰۰×۱۰۰ پیکسل توصیه می‌شود. اگر تعیین نشود، با تصویر بندانگشتی سرور جایگزین خواهد شد\n        title: تصویر سربرگ\n      mascot:\n        desc_html: در صفحه‌های گوناگونی نمایش می‌یابد. دست‌کم ۲۹۳×۲۰۵ پیکسل. اگر تعیین نشود، با تصویر پیش‌فرض جایگزین خواهد شد\n        title: تصویر نماد\n      peers_api_enabled:\n        desc_html: دامین‌هایی که این سرور به آن‌ها برخورده است\n        title: انتشار فهرست سرورهای یافته‌شده\n      preview_sensitive_media:\n        desc_html: پیوند به سایت‌های دیگر پیش‌نمایشی خواهد داشت که یک تصویر کوچک را نشان می‌دهد، حتی اگر نوشته به عنوان حساس علامت‌گذاری شده باشد\n        title: نمایش تصاویر حساسیت‌برانگیز در پیش‌نمایش‌های OpenGraph\n      profile_directory:\n        desc_html: به کاربران اجازه دهید تا بتوانند خود را روی فهرست گزیدهٔ کاربران این سرور نمایش دهند\n        title: فعال‌سازی فهرست گزیدهٔ کاربران\n      registrations:\n        closed_message:\n          desc_html: وقتی امکان ثبت نام روی سرور فعال نباشد در صفحهٔ اصلی نمایش می‌یابد<br>می‌توانید HTML بنویسید\n          title: پیغام برای فعال‌نبودن ثبت نام\n        deletion:\n          desc_html: هر کسی بتواند حساب خود را پاک کند\n          title: فعال‌سازی پاک‌کردن حساب\n        min_invite_role:\n          disabled: هیچ کس\n          title: اجازهٔ دعوت به\n      registrations_mode:\n        modes:\n          approved: ثبت نام نیازمند تأیید مدیران است\n          none: کسی نمی‌تواند ثبت نام کند\n          open: همه می‌توانند ثبت نام کنند\n        title: شرایط ثبت نام\n      show_known_fediverse_at_about_page:\n        desc_html: اگر انتخاب شود، بوق‌های همهٔ سرورهای دیگر نیز در پیش‌نمایش این سرور نمایش می‌یابد. وگرنه فقط بوق‌های محلی نشان داده می‌شوند.\n        title: نمایش سرورهای دیگر در پیش‌نمایش این سرور\n      show_staff_badge:\n        desc_html: نمایش علامت همکار روی صفحهٔ کاربر\n        title: نمایش علامت همکار\n      site_description:\n        desc_html: معرفی کوتاهی دربارهٔ رابط برنامه‌نویسی کاربردی. دربارهٔ این که چه چیزی دربارهٔ این سرور ماستدون ویژه است یا هر چیز مهم دیگری بنویسید. می‌توانید HTML بنویسید، به‌ویژه <code>&lt;a&gt;</code> و <code>&lt;em&gt;</code>.\n        title: دربارهٔ این سرور\n      site_description_extended:\n        desc_html: جای خوبی برای نوشتن سیاست‌های کاربری، قانون‌ها، راهنماها، و هر چیزی که ویژهٔ این سرور است. تگ‌های HTML هم مجاز است\n        title: اطلاعات تکمیلی سفارشی\n      site_short_description:\n        desc_html: روی نوار کناری و همچنین به عنوان فرادادهٔ صفحه‌ها نمایش می‌یابد. در یک بند توضیح دهید که ماستدون چیست و چرا این سرور با بقیه فرق دارد.\n        title: توضیح کوتاه دربارهٔ سرور\n      site_terms:\n        desc_html: می‌توانید سیاست رازداری، شرایط استفاده، یا سایر مسائل قانونی را به دلخواه خود بنویسید. تگ‌های HTML هم مجاز است\n        title: شرایط استفادهٔ سفارشی\n      site_title: نام سرور\n      thumbnail:\n        desc_html: برای دیدن با OpenGraph و رابط برنامه‌نویسی. وضوح پیشنهادی ۱۲۰۰×۶۳۰ پیکسل\n        title: تصویر کوچک سرور\n      timeline_preview:\n        desc_html: نوشته‌های عمومی این سرور را در صفحهٔ آغازین نشان دهید\n        title: پیش‌نمایش نوشته‌ها\n      title: تنظیمات سایت\n    statuses:\n      back_to_account: بازگشت به صفحهٔ حساب\n      batch:\n        delete: پاک‌کردن\n        nsfw_off: علامت‌زدن به عنوان غیرحساس\n        nsfw_on: علامت‌زدن به عنوان حساس\n      failed_to_execute: اجرا نشد\n      media:\n        title: رسانه\n      no_media: بدون عکس یا ویدیو\n      no_status_selected: هیچ بوقی تغییری نکرد زیرا هیچ‌کدام از آن‌ها انتخاب نشده بودند\n      title: نوشته‌های حساب\n      with_media: دارای عکس یا ویدیو\n    subscriptions:\n      callback_url: نشانی Callback\n      confirmed: تأییدشده\n      expires_in: مهلت انقضا\n      last_delivery: آخرین ارسال\n      topic: موضوع\n    tags:\n      accounts: حساب‌ها\n      hidden: پنهان‌شده\n      hide: در فهرست گزیدهٔ کاربران نشان نده\n      name: برچسب\n      title: برچسب‌ها\n      unhide: نمایش در فهرست گزیدهٔ کاربران\n      visible: نمایان\n    title: مدیریت سرور\n    warning_presets:\n      add_new: افزودن تازه\n      delete: زدودن\n      edit: ویرایش\n      edit_preset: ویرایش هشدار پیش‌فرض\n      title: مدیریت هشدارهای پیش‌فرض\n  admin_mailer:\n    new_pending_account:\n      body: جزئیات حساب تازه این‌جاست. شما می‌توانید آن را تأیید یا رد کنید.\n      subject: حساب تازه‌ای در %{instance} نیازمند بررسی است (%{username})\n    new_report:\n      body: کاربر %{reporter} کاربر %{target} را گزارش داد\n      body_remote: کسی از %{domain} گزارش %{target} را فرستاده\n      subject: گزارش تازه‌ای برای %{instance} (#%{id})\n  appearance:\n    advanced_web_interface: رابط کاربری پیشرفته\n    advanced_web_interface_hint: 'اگر می‌خواهید همهٔ فضای نمایشگر خود را به کار ببرید، می‌توانید به کمک رابط کاربری پیشرفته ستون‌های گوناگونی داشته باشید تا در یک نگاه همهٔ اطلاعاتی را که می‌خواهید ببینید: نوشته‌های دیگران، اعلان‌ها، فهرست نوشته‌های همه‌جا، و هر تعداد فهرست و برچسب که بخواهید.'\n    animations_and_accessibility: پویانمایی‌های و دسترسی‌پذیری\n    confirmation_dialogs: پیغام‌های تأیید\n    sensitive_content: محتوای حساس\n  application_mailer:\n    notification_preferences: تغییر ترجیحات ایمیل\n    salutation: \"%{name}،\"\n    settings: 'تغییر تنظیمات ایمیل: %{link}'\n    view: 'نمایش:'\n    view_profile: دیدن نمایه\n    view_status: دیدن نوشته‌ها\n  applications:\n    created: برنامه با موفقیت ساخته شد\n    destroyed: برنامه با موفقیت پاک شد\n    invalid_url: نشانی واردشده معتبر نیست\n    regenerate_token: دوباره‌سازی کد دسترسی\n    token_regenerated: کد دسترسی با موفقیت ساخته شد\n    warning: خیلی مواظب این اطلاعات باشید و آن را به هیچ کس ندهید!\n    your_token: کد دسترسی شما\n  auth:\n    apply_for_account: درخواست دعوت‌نامه\n    change_password: رمز\n    checkbox_agreement_html: من <a href=\"%{rules_path}\" target=\"_blank\">قانون‌های این سرور</a> و <a href=\"%{terms_path}\" target=\"_blank\">شرایط کاربری</a> را می‌پذیرم\n    confirm_email: تأیید ایمیل\n    delete_account: پاک‌کردن حساب\n    delete_account_html: اگر می‌خواهید حساب خود را پاک کنید، از <a href=\"%{path}\">این‌جا</a> پیش بروید. از شما درخواست تأیید خواهد شد.\n    didnt_get_confirmation: راهنمایی برای تأیید را دریافت نکردید؟\n    forgot_password: رمزتان را گم کرده‌اید؟\n    invalid_reset_password_token: کد بازنشانی رمز نامعتبر یا منقضی شده است. لطفاً کد دیگری درخواست کنید.\n    login: ورود\n    logout: خروج\n    migrate_account: نقل مکان به یک حساب دیگر\n    migrate_account_html: اگر می‌خواهید این حساب را به حساب دیگری منتقل کنید، <a href=\"%{path}\">این‌جا را کلیک کنید</a>.\n    or_log_in_with: یا ورود به وسیلهٔ\n    register: عضو شوید\n    registration_closed: سرور %{instance} عضو تازه‌ای نمی‌پذیرد\n    resend_confirmation: راهنمایی برای تأیید را دوباره بفرست\n    reset_password: بازنشانی رمز\n    security: امنیت\n    set_new_password: تعیین رمز تازه\n    trouble_logging_in: برای ورود مشکلی دارید؟\n  authorize_follow:\n    already_following: شما همین الان هم این حساب را پی‌می‌گیرید\n    error: متأسفانه حین یافتن آن حساب خطایی رخ داد\n    follow: پی بگیرید\n    follow_request: 'شما درخواست پیگیری فرستاده‌اید به:'\n    following: 'انجام شد! شما هم‌اینک پیگیر این کاربر هستید:'\n    post_follow:\n      close: یا این پنجره را ببندید.\n      return: نمایهٔ این کاربر را نشان بده\n      web: رفتن به وب\n    title: پیگیری %{acct}\n  datetime:\n    distance_in_words:\n      about_x_hours: \"%{count} ساعت\"\n      about_x_months: \"%{count} ماه\"\n      about_x_years: \"%{count} سال\"\n      almost_x_years: \"%{count} سال\"\n      half_a_minute: همین الان\n      less_than_x_minutes: \"%{count} دقیقه\"\n      less_than_x_seconds: همین الان\n      over_x_years: \"%{count} سال\"\n      x_days: \"%{count} روز\"\n      x_minutes: \"%{count} دقیقه\"\n      x_months: \"%{count} ماه\"\n      x_seconds: \"%{count} ثانیه\"\n  deletes:\n    bad_password_msg: هکر گرامی، رمزی که وارد کردید اشتباه است ؛)\n    confirm_password: رمز فعلی خود را وارد کنید تا معلوم شود که خود شمایید\n    description_html: این کار همهٔ محتوای حساب شما را <strong>برای همیشه و به‌طور بازگشت‌ناپذیری</strong> پاک کرده و حساب را غیرفعال می‌کند. نام کاربری شما برای جلوگیری از جعل هویت احتمالی در آینده از دسترس خارج خواهد شد.\n    proceed: پاک‌کردن حساب\n    success_msg: حساب شما با موفقیت پاک شد\n    warning_html: تنها پاک‌شدن محتوای حساب در این سرور خاص تضمین می‌شود. محتوایی که به گستردگی هم‌رسانی شده باشد ممکن است ردش همچنان باقی بماند. سرورهای آفلاین یا سرورهایی که دیگر مشترک شما نیستند پایگاه‌های دادهٔ خود را به‌روز نخواهند کرد.\n    warning_title: دسترس‌پذیری محتوای هم‌رسان‌شده\n  directories:\n    directory: فهرست گزیدهٔ کاربران\n    enabled: شما هم‌اینک در فهرست گزیدهٔ کاربران نمایش می‌یابید.\n    enabled_but_waiting: شما می‌خواهید در فهرست گزیدهٔ کاربران این سرور باشید، ولی تعداد پیگیران شما هنوز به مقدار لازم (%{min_followers}) نرسیده است.\n    explanation: کاربران این سرور را بر اساس علاقه‌مندی‌هایشان پیدا کنید\n    explore_mastodon: گشت و گذار در %{title}\n    how_to_enable: شما هنوز در فهرست گزیدهٔ کاربران این سرور نشان داده نمی‌شوید. این‌جا می‌توانید انتخابش کنید. اگر در بخش معرفی خود در نمایه‌تان برچسب (هشتگ) داشته باشد، نام شما هم برای آن هشتگ‌ها فهرست می‌شود!\n    people:\n      one: \"%{count} نفر\"\n      other: \"%{count} نفر\"\n  errors:\n    '403': شما اجازهٔ دیدن این صفحه را ندارید.\n    '404': صفحه‌ای که به دنبالش هستید این‌جا نیست.\n    '410': صفحه‌ای که به دنبالش بودید دیگر این‌جا وجود ندارد.\n    '422':\n      content: تأیید امنیتی انجام نشد. آیا مرورگر شما کوکی‌ها را مسدود می‌کند؟\n      title: تأیید امنیتی کار نکرد\n    '429': درخواست‌های بیش از حد\n    '500':\n      content: شرمنده، یک چیزی از سمت ما اشتباه شده.\n      title: این صفحه درست نیست\n    noscript_html: برای استفاده از نسخهٔ تحت وب ماستدون، لطفاً جاوااسکریپت را فعال کنید. یا به جایش می‌توانید <a href=\"%{apps_path}\">یک اپ ماستدون</a> را به‌کار ببرید.\n  existing_username_validator:\n    not_found: کاربری در این سرور با این نام کاربری پیدا نشد\n    not_found_multiple: \"%{usernames} پیدا نشد\"\n  exports:\n    archive_takeout:\n      date: تاریخ\n      download: بایگانی خود را باربگیرید\n      hint_html: شما می‌توانید بایگانی <strong>نوشته‌ها و پرونده‌های بارگذاری‌شدهٔ</strong> خود را درخواست کنید. داده‌های برون‌بری‌شده در قالب ActivityPub خواهند بود و همهٔ نرم‌افزارهای سازگار خواهند توانست آن را بخوانند. شما هر ۷ روز می‌توانید یک بار برای چنین بایگانی‌ای درخواست دهید.\n      in_progress: در حال ساختن بایگانی شما...\n      request: درخواست بایگانی داده‌هایتان\n      size: اندازه\n    blocks: حساب‌های مسدودشده\n    domain_blocks: دامین‌های مسدودشده\n    follows: حساب‌های پی‌گرفته\n    lists: فهرست‌ها\n    mutes: حساب‌های بی‌صداشده\n    storage: تصویرهای ذخیره‌شده\n  featured_tags:\n    add_new: افزودن تازه\n    errors:\n      limit: شما بیشترین تعداد مجاز برچسب‌ها را دارید\n  filters:\n    contexts:\n      home: خانه\n      notifications: اعلان‌ها\n      public: فهرست عمومی\n      thread: گفتگوها\n    edit:\n      title: ویرایش فیلتر\n    errors:\n      invalid_context: زمینه‌ای موجود نیست یا نامعتبر است\n      invalid_irreversible: فیلترهای برگشت‌ناپذیر تنها در زمینهٔ پیگیری‌ها یا اعلان‌ها کار می‌کنند\n    index:\n      delete: پاک‌کردن\n      title: فیلترها\n    new:\n      title: افزودن فیلتر تازه\n  footer:\n    developers: برنامه‌نویسان\n    more: بیشتر…\n    resources: منابع\n  generic:\n    all: همه\n    changes_saved_msg: تغییرات با موفقیت ذخیره شدند!\n    copy: رونوشت\n    order_by: مرتب‌سازی\n    save_changes: ذخیرهٔ تغییرات\n    validation_errors:\n      one: یک چیزی هنوز درست نیست! لطفاً خطاهای زیر را ببینید\n      other: یک چیزی هنوز درست نیست! لطفاً %{count} خطای زیر را ببینید\n  html_validator:\n    invalid_markup: 'دارای نشانه‌گذاری نامعتبر HTML است: %{error}'\n  identity_proofs:\n    active: فعال\n    authorize: بله، اجازه بده\n    authorize_connection_prompt: آیا اجازهٔ این ارتباط رمزگذاری را می‌دهید؟\n    errors:\n      failed: برقراری ارتباط  رمزگذاری شکست خورد. لطفاً دوباره از %{provider} تلاش کنید.\n      keybase:\n        invalid_token: کدهای Keybase چکیده (هش) امضاهای دیجیتال هستند و دست‌کم ۶۶ نویسه در مبنای ۱۶ دارند\n        verification_failed: این کد را Keybase به عنوان امضای دیجیتال کاربر %{kb_username} تأیید نمی‌کند. لطفاً دوباره از Keybase تلاش کنید.\n      wrong_user: نمی‌توان تأییدی برای %{proving} در حالی که به عنوان %{current} وارد شده‌اید. به عنوان %{proving} وارد شوید و دوباره تلاش کنید.\n    explanation_html: این‌جا می‌توانید به شناسه‌های دیگر خود مانند نمایهٔ Keybase خودتان به طور رمزنگارانه متصل شوید. با این کار دیگران می‌توانند به شما پیغام‌های رمزشده بفرستند و به چیزی که شما به آن‌ها می‌فرستید اعتماد کنند.\n    i_am_html: من %{username} روی %{service} هستم.\n    identity: شناسه\n    inactive: غیرفعال\n    publicize_checkbox: 'این را ببوقید:'\n    publicize_toot: 'تأیید شد! من %{username} روی %{service} هستم: %{url}'\n    status: وضعیت تأیید\n    view_proof: دیدن مدرک\n  imports:\n    modes:\n      merge: ادغام\n      merge_long: داده‌های فعلی را داشته باشید و داده‌های تازه‌ای بیفزایید\n      overwrite: بازنویسی\n      overwrite_long: داده‌های فعلی را پاک کنید و داده‌های تازه‌ای بیفزایید\n    preface: شما می‌توانید داده‌هایی از قبیل کاربرانی که پی می‌گرفتید یا مسدود می‌کردید را در حساب خود روی این سرور درون‌ریزی کنید. برای این کار پرونده‌هایی که از سرور دیگر برون‌سپاری کرده‌اید را به‌کار ببرید.\n    success: داده‌های شما با موفقیت بارگذاری شد و به زودی پردازش می‌شود\n    types:\n      blocking: فهرست مسدودشده‌ها\n      domain_blocking: فهرست دامین‌های مسدودشده\n      following: فهرست پی‌گیری‌ها\n      muting: فهرست بی‌صداشده‌ها\n    upload: بارگذاری\n  in_memoriam_html: به یادبود.\n  invites:\n    delete: غیرفعال‌سازی\n    expired: منقضی‌شده\n    expires_in:\n      '1800': ۳۰ دقیقه\n      '21600': ۶ ساعت\n      '3600': ۱ ساعت\n      '43200': ۱۲ ساعت\n      '604800': ۱ هفته\n      '86400': ۱ روز\n    expires_in_prompt: هیچ وقت\n    generate: ساختن\n    invited_by: 'دعوت‌کنندهٔ شما:'\n    max_uses:\n      one: ۱ بار\n      other: \"%{count} بار\"\n    max_uses_prompt: نامحدود\n    prompt: با ساختن و اشتراک‌گذاری یک پیوند، اجازهٔ دسترسی به این سرور را به دیگران بدهید\n    table:\n      expires_at: تاریخ انقضا\n      uses: استفاده‌ها\n    title: دعوت دیگران\n  lists:\n    errors:\n      limit: از این بیشتر نمی‌شود فهرست داشت\n  media_attachments:\n    validations:\n      images_and_video: نمی‌توان برای نوشته‌ای که تصویر دارد ویدیو بارگذاری کرد\n      too_many: نمی‌توان بیشتر از ۴ تصویر بارگذاری کرد\n  migrations:\n    acct: username@domain حساب تازه\n    currently_redirecting: 'نمایهٔ شما منتقل می‌شود به:'\n    proceed: ذخیره\n    updated_msg: تنظیمات نقل مکان حساب شما با موفقیت به‌روز شد!\n  moderation:\n    title: مدیریت کاربران\n  notification_mailer:\n    digest:\n      action: دیدن همهٔ اعلان‌ها\n      body: خلاصه‌ای از پیغام‌هایی که از زمان آخرین بازدید شما در %{since} فرستاده شد\n      mention: \"%{name} این‌جا از شما نام برد:\"\n      new_followers_summary:\n        one: در ضمن، وقتی که نبودید یک پیگیر تازه پیدا کردید! ای ول!\n        other: در ضمن، وقتی که نبودید %{count} پیگیر تازه پیدا کردید! چه عالی!\n      subject:\n        one: \"یک اعلان تازه از زمان آخرین بازدید شما \\U0001F418\"\n        other: \"%{count} اعلان تازه از زمان آخرین بازدید شما \\U0001F418\"\n      title: در مدتی که نبودید...\n    favourite:\n      body: \"%{name} این نوشتهٔ شما را پسندید:\"\n      subject: \"%{name} نوشتهٔ شما را پسندید\"\n      title: پسندیده‌شدن تازه\n    follow:\n      body: \"%{name} هم‌اینک پیگیر شماست!\"\n      subject: \"%{name} هم‌اینک پیگیر شماست\"\n      title: پیگیر تازه\n    follow_request:\n      action: مدیریت درخواست‌های پیگیری\n      body: \"%{name} می‌خواهد پیگیر نوشته‌های شما باشد\"\n      subject: 'منتظر پیگیری: %{name}'\n      title: درخواست پیگیری تازه\n    mention:\n      action: پاسخ\n      body: \"%{name} در این‌جا از شما نام برد:\"\n      subject: \"%{name} از شما نام برد\"\n      title: نام‌برده‌شدن تازه\n    reblog:\n      body: \"%{name} نوشتهٔ شما را بازبوقید:\"\n      subject: \"%{name} نوشتهٔ شما را بازبوقید\"\n      title: بازبوق تازه\n  pagination:\n    newer: تازه‌تر\n    next: بعدی\n    older: قدیمی‌تر\n    prev: قبلی\n  polls:\n    errors:\n      already_voted: شما قبلاً در این نظرسنجی رأی داده‌اید\n      duplicate_options: دارای موارد تکراری است\n      duration_too_long: در آیندهٔ خیلی دور است\n      duration_too_short: در آیندهٔ خیلی نزدیک است\n      expired: این نظرسنجی به پایان رسیده است\n      over_character_limit: هر کدام نمی‌تواند از %{max} نویسه طولانی‌تر باشد\n      too_few_options: حتماً باید بیش از یک گزینه داشته باشد\n      too_many_options: نمی‌تواند بیشتر از %{max} گزینه داشته باشد\n  preferences:\n    other: سایر تنظیمات\n  relationships:\n    activity: فعالیت حساب\n    dormant: غیرفعال\n    last_active: آخرین فعالیت\n    most_recent: تازه‌ترین\n    moved: منتقل‌شده\n    mutual: دوطرفه\n    primary: اصلی\n    relationship: رابطه\n    remove_selected_domains: همهٔ پیگیران از طرف این سرور را بردار\n    remove_selected_followers: پیگیران انتخاب‌شده را بردار\n    remove_selected_follows: به پیگیری از کاربران انتخاب‌شده پایان بده\n    status: وضعیت حساب\n  remote_follow:\n    acct: نشانی حساب username@domain خود را این‌جا بنویسید\n    missing_resource: نشانی اینترنتی برای رسیدن به حساب شما پیدا نشد\n    no_account_html: هنوز عضو نیستید؟ <a href='%{sign_up_path}' target='_blank'>این‌جا می‌توانید حساب باز کنید</a>\n    proceed: درخواست پیگیری\n    prompt: 'شما قرار است این حساب را پیگیری کنید:'\n    reason_html: \"<strong>چرا این مرحله لازم است؟</strong> ممکن است <code>%{instance}</code> سروری نباشد که شما روی آن حساب باز کرده‌اید، بنابراین ما باید پیش از هرچیز شما را به سرور خودتان منتقل کنیم.\"\n  remote_interaction:\n    favourite:\n      proceed: به سمت پسندیدن این بوق\n      prompt: 'شما می‌خواهید این بوق را بپسندید:'\n    reblog:\n      proceed: به سمت بازبوقیدن\n      prompt: 'شما می‌خواهید این بوق را بازببوقید:'\n    reply:\n      proceed: به سمت پاسخ‌دادن\n      prompt: 'شما می‌خواهید به این بوق پاسخ دهید:'\n  remote_unfollow:\n    error: خطا\n    title: عنوان\n    unfollowed: پایان پیگیری\n  scheduled_statuses:\n    over_daily_limit: شما از حد مجاز %{limit} بوق زمان‌بندی‌شده در آن روز فراتر رفته‌اید\n    over_total_limit: شما از حد مجاز %{limit} بوق زمان‌بندی‌شده فراتر رفته‌اید\n    too_soon: زمان تعیین‌شده باید در آینده باشد\n  sessions:\n    activity: آخرین فعالیت\n    browser: مرورگر\n    browsers:\n      generic: مرورگر ناشناخته\n    current_session: نشست فعلی\n    description: \"%{browser} روی %{platform}\"\n    explanation: مرورگرهای زیر هم‌اینک به حساب شما وارد شده‌اند.\n    platforms:\n      other: سیستم ناشناخته\n    revoke: لغو کردن\n    revoke_success: نشست با موفقیت لغو شد\n    title: نشست‌ها\n  settings:\n    account: حساب\n    account_settings: تنظیمات حساب\n    appearance: نما\n    authorized_apps: برنامه‌های مجاز\n    back: بازگشت به ماستدون\n    delete: پاک‌کردن حساب\n    development: فرابری\n    edit_profile: ویرایش نمایه\n    export: برون‌سپاری داده‌ها\n    featured_tags: برچسب‌های منتخب\n    identity_proofs: مدرک شناسه‌ها\n    import: درون‌ریزی\n    import_and_export: درون‌ریزی و برون‌بری\n    migrate: انتقال حساب\n    notifications: اعلان‌ها\n    preferences: ترجیحات\n    profile: نمایه\n    relationships: پیگیری‌ها و پیگیران\n    two_factor_authentication: ورود دومرحله‌ای\n  statuses:\n    attached:\n      description: 'پیوست‌شده: %{attached}'\n      image:\n        one: \"%{count} تصویر\"\n        other: \"%{count} تصویر\"\n      video:\n        one: \"%{count} ویدیو\"\n        other: \"%{count} ویدیو\"\n    boosted_from_html: بازبوقیده از طرف %{acct_link}\n    content_warning: 'هشدا محتوا: %{warning}'\n    disallowed_hashtags:\n      one: 'دارای هشتگ غیرمجاز: %{tags}'\n      other: 'دارای هشتگ‌های غیرمجاز: %{tags}'\n    language_detection: زبان نوشته خودبه‌خود شناخته شود\n    open_in_web: بازکردن در وب\n    over_character_limit: از حد مجاز %{max} حرف فراتر رفتید\n    pin_errors:\n      limit: از این بیشتر نمی‌شود نوشته‌های ثابت داشت\n      ownership: نوشته‌های دیگران را نمی‌توان ثابت کرد\n      private: نوشته‌های غیرعمومی را نمی‌توان ثابت کرد\n      reblog: بازبوق‌ها را نمی‌توان ثابت کرد\n    poll:\n      total_votes:\n        one: \"%{count} رأی\"\n        other: \"%{count} رأی\"\n      vote: رأی\n    show_more: نمایش\n    sign_in_to_participate: برای شرکت در گفتگو وارد حساب خود شوید\n    visibilities:\n      private: خصوصی\n      private_long: تنها پیگیران شما می‌بینند\n      public: عمومی\n      public_long: همه می‌توانند ببینند\n      unlisted: فهرست‌نشده\n      unlisted_long: عمومی، ولی در فهرست نوشته‌ها نمایش نمی‌یابد\n  stream_entries:\n    pinned: نوشته‌های ثابت\n    reblogged: بازبوقید\n    sensitive_content: محتوای حساس\n  terms:\n    body_html: |\n      <h2>سیاست رازداری</h2>\n      <h3 id=\"collect\">What information do we collect?</h3>\n\n      <ul>\n      <li><em>Basic account information</em>: If you register on this server, you may be asked to enter a username, an e-mail address and a password. You may also enter additional profile information such as a display name and biography, and upload a profile picture and header image. The username, display name, biography, profile picture and header image are always listed publicly.</li>\n      <li><em>Posts, following and other public information</em>: The list of people you follow is listed publicly, the same is true for your followers. When you submit a message, the date and time is stored as well as the application you submitted the message from. Messages may contain media attachments, such as pictures and videos. Public and unlisted posts are available publicly. When you feature a post on your profile, that is also publicly available information. Your posts are delivered to your followers, in some cases it means they are delivered to different servers and copies are stored there. When you delete posts, this is likewise delivered to your followers. The action of reblogging or favouriting another post is always public.</li>\n      <li><em>Direct and followers-only posts</em>: All posts are stored and processed on the server. Followers-only posts are delivered to your followers and users who are mentioned in them, and direct posts are delivered only to users mentioned in them. In some cases it means they are delivered to different servers and copies are stored there. We make a good faith effort to limit the access to those posts only to authorized persons, but other servers may fail to do so. Therefore it's important to review servers your followers belong to. You may toggle an option to approve and reject new followers manually in the settings. <em>Please keep in mind that the operators of the server and any receiving server may view such messages</em>, and that recipients may screenshot, copy or otherwise re-share them. <em>Do not share any dangerous information over Mastodon.</em></li>\n      <li><em>IPs and other metadata</em>: When you log in, we record the IP address you log in from, as well as the name of your browser application. All the logged in sessions are available for your review and revocation in the settings. The latest IP address used is stored for up to 12 months. We also may retain server logs which include the IP address of every request to our server.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"use\">What do we use your information for?</h3>\n\n      <p>Any of the information we collect from you may be used in the following ways:</p>\n\n      <ul>\n      <li>To provide the core functionality of Mastodon. You can only interact with other people's content and post your own content when you are logged in. For example, you may follow other people to view their combined posts in your own personalized home timeline.</li>\n      <li>To aid moderation of the community, for example comparing your IP address with other known ones to determine ban evasion or other violations.</li>\n      <li>The email address you provide may be used to send you information, notifications about other people interacting with your content or sending you messages, and to respond to inquiries, and/or other requests or questions.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"protect\">How do we protect your information?</h3>\n\n      <p>We implement a variety of security measures to maintain the safety of your personal information when you enter, submit, or access your personal information. Among other things, your browser session, as well as the traffic between your applications and the API, are secured with SSL, and your password is hashed using a strong one-way algorithm. You may enable two-factor authentication to further secure access to your account.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"data-retention\">What is our data retention policy?</h3>\n\n      <p>We will make a good faith effort to:</p>\n\n      <ul>\n      <li>Retain server logs containing the IP address of all requests to this server, in so far as such logs are kept, no more than 90 days.</li>\n      <li>Retain the IP addresses associated with registered users no more than 12 months.</li>\n      </ul>\n\n      <p>You can request and download an archive of your content, including your posts, media attachments, profile picture, and header image.</p>\n\n      <p>You may irreversibly delete your account at any time.</p>\n\n      <hr class=\"spacer\"/>\n\n      <h3 id=\"cookies\">Do we use cookies?</h3>\n\n      <p>Yes. Cookies are small files that a site or its service provider transfers to your computer's hard drive through your Web browser (if you allow). These cookies enable the site to recognize your browser and, if you have a registered account, associate it with your registered account.</p>\n\n      <p>We use cookies to understand and save your preferences for future visits.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"disclose\">Do we disclose any information to outside parties?</h3>\n\n      <p>We do not sell, trade, or otherwise transfer to outside parties your personally identifiable information. This does not include trusted third parties who assist us in operating our site, conducting our business, or servicing you, so long as those parties agree to keep this information confidential. We may also release your information when we believe release is appropriate to comply with the law, enforce our site policies, or protect ours or others rights, property, or safety.</p>\n\n      <p>Your public content may be downloaded by other servers in the network. Your public and followers-only posts are delivered to the servers where your followers reside, and direct messages are delivered to the servers of the recipients, in so far as those followers or recipients reside on a different server than this.</p>\n\n      <p>When you authorize an application to use your account, depending on the scope of permissions you approve, it may access your public profile information, your following list, your followers, your lists, all your posts, and your favourites. Applications can never access your e-mail address or password.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"children\">Site usage by children</h3>\n\n      <p>If this server is in the EU or the EEA: Our site, products and services are all directed to people who are at least 16 years old. If you are under the age of 16, per the requirements of the GDPR (<a href=\"https://en.wikipedia.org/wiki/General_Data_Protection_Regulation\">General Data Protection Regulation</a>) do not use this site.</p>\n\n      <p>If this server is in the USA: Our site, products and services are all directed to people who are at least 13 years old. If you are under the age of 13, per the requirements of COPPA (<a href=\"https://en.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act\">Children's Online Privacy Protection Act</a>) do not use this site.</p>\n\n      <p>Law requirements can be different if this server is in another jurisdiction.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"changes\">Changes to our Privacy Policy</h3>\n\n      <p>If we decide to change our privacy policy, we will post those changes on this page.</p>\n\n      <p>This document is CC-BY-SA. It was last updated March 7, 2018.</p>\n\n      <p>Originally adapted from the <a href=\"https://github.com/discourse/discourse\">Discourse privacy policy</a>.</p>\n    title: شرایط استفاده و سیاست رازداری %{instance}\n  themes:\n    contrast: ماستدون (کنتراست بالا)\n    default: ماستدون (تیره)\n    mastodon-light: ماستدون (روشن)\n  time:\n    formats:\n      default: \"%d %b %Y, %H:%M\"\n  two_factor_authentication:\n    code_hint: برای تأیید، کدی را که برنامهٔ تأییدکننده ساخته است وارد کنید\n    description_html: اگر <strong>ورود دومرحله‌ای</strong> را فعال کنید، برای ورود به سیستم به تلفن خود نیاز خواهید داشت تا برایتان یک کد موقتی بسازد.\n    disable: غیرفعال‌کردن\n    enable: فعال‌کردن\n    enabled: ورود دومرحله‌ای فعال است\n    enabled_success: ورود دومرحله‌ای با موفقیت فعال شد\n    generate_recovery_codes: ساخت کدهای بازیابی\n    instructions_html: \"<strong>این کد QR را با برنامهٔ Google Authenticator یا برنامه‌های TOTP مشابه اسکن کنید</strong>. از این به بعد، آن برنامه کدهایی موقتی خواهد ساخت که برای ورود باید آن‌ها را وارد کنید.\"\n    lost_recovery_codes: با کدهای بازیابی می‌توانید اگر تلفن خود را گم کردید به حساب خود دسترسی داشته باشید. اگر کدهای بازیابی خود را گم کردید، آن‌ها را این‌جا دوباره بسازید. کدهای بازیابی قبلی شما نامعتبر خواهند شد.\n    manual_instructions: 'اگر نمی‌توانید کدها را اسکن کنید و باید آن‌ها را دستی وارد کنید، متن کد امنیتی این‌جاست:'\n    recovery_codes: پشتیبان‌گیری از کدهای بازیابی\n    recovery_codes_regenerated: کدهای بازیابی با موفقیت ساخته شدند\n    recovery_instructions_html: اگر تلفن خود را گم کردید، می‌توانید با یکی از کدهای بازیابی زیر کنترل حساب خود را به دست بگیرید. <strong>این کدها را در جای امنی نگه دارید.</strong> مثلاً آن‌ها را چاپ کنید و کنار سایر مدارک مهم خود قرار دهید.\n    setup: راه اندازی\n    wrong_code: کدی که وارد کردید نامعتبر بود! آیا ساعت سرور و ساعت دستگاه شما درست تنظیم شده‌اند؟\n  user_mailer:\n    backup_ready:\n      explanation: شما یک نسخهٔ پشتیبان کامل از حساب خود را درخواست کردید. این پشتیبان الان آمادهٔ بارگیری است!\n      subject: بایگانی شما آمادهٔ دریافت است\n      title: گرفتن بایگانی\n    warning:\n      explanation:\n        disable: تا وقتی حساب شما متوقف باشد، داده‌های شما دست‌نخورده باقی می‌مانند، ولی تا وقتی که حسابتان باز نشده، نمی‌توانید هیچ کاری با آن بکنید.\n        silence: تا وقتی حساب شما محدود باشد، تنها کسانی که از قبل پیگیر شما بودند نوشته‌های شما در این سرور را می‌بینند و شما در فهرست‌های عمومی دیده نمی‌شوید. ولی دیگران همچنان می‌توانند به دلخواه خودشان پیگیر شما شوند.\n        suspend: حساب شما معلق شده است، و همهٔ نوشته‌ها و رسانه‌های تصویری شما به طور بازگشت‌ناپذیری پاک شده‌اند؛ چه از این سرور و چه از سرورهای دیگری که از آن‌ها پیگیر داشتید.\n      review_server_policies: مرور سیاست‌های این سرور\n      subject:\n        disable: حساب %{acct} شما متوقف شده است\n        none: هشدار برای %{acct}\n        silence: حساب %{acct} شما محدود شده است\n        suspend: حساب %{acct}  شما معلق شده است\n      title:\n        disable: حساب متوقف شده است\n        none: هشدار\n        silence: حساب محدود شده است\n        suspend: حساب معلق شده است\n    welcome:\n      edit_profile_action: تنظیم نمایه\n      edit_profile_step: 'شما می‌توانید نمایهٔ خود را به دلخواه خود تغییر دهید: می‌توانید تصویر نمایه، تصویر پس‌زمینه، نام، و چیزهای دیگری را تعیین کنید. اگر بخواهید، می‌توانید حساب خود را خصوصی کنید تا فقط کسانی که شما اجازه می‌دهید بتوانند پیگیر حساب شما شوند.'\n      explanation: نکته‌هایی که برای آغاز کار به شما کمک می‌کنند\n      final_action: چیزی منتشر کنید\n      final_step: 'چیزی بنویسید! حتی اگر الان کسی پیگیر شما نباشد، دیگران نوشته‌های عمومی شما را می‌بینند، مثلاً در فهرست نوشته‌های محلی و در هشتگ‌ها. شاید بخواهید با هشتگ #آشنایی خودتان را معرفی کنید.'\n      full_handle: نام کاربری کامل شما\n      full_handle_hint: این چیزی است که باید به دوستان خود بگویید تا بتوانند به شما پیغام بفرستند یا از سرورهای دیگر پیگیر شما شوند.\n      review_preferences_action: تغییر ترجیحات\n      review_preferences_step: با رفتن به صفحهٔ ترجیحات می‌توانید چیزهای گوناگونی را تنظیم کنید. مثلاً این که چه ایمیل‌های آگاه‌سازی‌ای به شما فرستاده شود، یا حریم خصوصی پیش‌فرض نوشته‌هایتان چه باشد. اگر بیماری سفر (حالت تهوع بر اثر دیدن اجسام متحرک) ندارید، می‌توانید پخش خودکار ویدیوها را فعال کنید.\n      subject: به ماستدون خوش آمدید\n      tip_federated_timeline: \"«فهرست نوشته‌های همه‌جا» نمایی از کل شبکهٔ بزرگ ماستدون به شما می‌دهد. البته این فهرست فقط افردای را نشان می‌دهد که هم‌سروری‌های شما آن‌ها را پیگیری می‌کنند، و بنابراین ممکن است کامل نباشد.\"\n      tip_following: شما به طور پیش‌فرض مدیر(های) سرور خود را پی می‌گیرید. برای یافتن افراد جالب دیگر، فهرست «نوشته‌های محلی» و «نوشته‌های همه‌جا» را ببینید.\n      tip_local_timeline: فهرست نوشته‌های محلی نمایی کلی از کاربران روی %{instance} را ارائه می‌دهد. این‌ها همسایه‌های شما هستند!\n      tip_mobile_webapp: اگر مرورگر موبایل شما امکان گذاشتن ماستدون روی صفحهٔ اصلی موبایل را به شما می‌دهد، این یعنی می‌توانید اعلان‌های خودکار ماستدون را دریافت کنید. با این کار ماستدون خیلی شبیه یک اپ معمولی موبایل می‌شود!\n      tips: نکته‌ها\n      title: خوش آمدید، کاربر %{name}!\n  users:\n    follow_limit_reached: شما نمی‌توانید بیش از %{limit} نفر را پی بگیرید\n    invalid_email: نشانی ایمیل نامعتبر است\n    invalid_otp_token: کد ورود دومرحله‌ای نامعتبر است\n    otp_lost_help_html: اگر شما دسترسی به هیچ‌کدامشان ندارید، باید با ایمیل %{email} تماس بگیرید\n    seamless_external_login: شما با یک سرویس خارج از مجموعه وارد شده‌اید، به همین دلیل تنظیمات ایمیل و رمز برای شما در دسترس نیست.\n    signed_in_as: 'واردشده به نام:'\n  verification:\n    explanation_html: 'شما می‌توانید <strong>خود را به عنوان مالک صفحه‌ای که در نمایه‌تان به آن پیوند داده‌اید تأیید کنید.</strong> برای این کار، صفحه‌ای که به آن پیوند داده‌اید، خودش باید پیوندی به نمایهٔ ماستدون شما داشته باشد. پیوند در آن صفحه <strong>باید</strong> عبارت <code>rel=\"me\"‎</code> را به عنوان attribute در خود داشته باشد. محتوای متن پیوند اهمتی ندارد. یک نمونه از چنین پیوندی:'\n    verification: تأیید\n"
  },
  {
    "path": "config/locales/fi.yml",
    "content": "---\nfi:\n  about:\n    about_hashtag_html: Nämä ovat hashtagilla <strong>#%{hashtag}</strong> merkittyjä julkisia tuuttauksia. Voit vastata niihin, jos sinulla on tili jossain päin fediversumia.\n    about_mastodon_html: Mastodon on sosiaalinen verkosto. Se on toteutettu avoimilla verkkoprotokollilla ja vapailla, avoimen lähdekoodin ohjelmistoilla, ja se toimii hajautetusti samaan tapaan kuin sähköposti.\n    about_this: Tietoja tästä palvelimesta\n    administered_by: 'Ylläpitäjä:'\n    apps: Mobiili sovellukset\n    contact: Ota yhteyttä\n    contact_missing: Ei asetettu\n    contact_unavailable: Ei saatavilla\n    documentation: Dokumentaatio\n    extended_description_html: |\n      <h3>Hyvä paikka säännöille</h3>\n      <p>Pidempää kuvausta ei ole vielä laadittu.</p>\n    generic_description: \"%{domain} on yksi verkostoon kuuluvista palvelimista\"\n    hosted_on: Mastodon palvelimella %{domain}\n    learn_more: Lisätietoja\n    privacy_policy: Tietosuojaseloste\n    source_code: Lähdekoodi\n    status_count_after:\n      one: tila\n      other: tilanne\n    status_count_before: He ovat luoneet\n    terms: Käyttöehdot\n    user_count_after:\n      one: käyttäjä\n      other: käyttäjät\n    user_count_before: Koti\n    what_is_mastodon: Mikä on Mastodon?\n  accounts:\n    choices_html: \"%{name} valinnat:\"\n    follow: Seuraa\n    followers:\n      one: Seuraaja\n      other: Seuraajat\n    following: Seuratut\n    joined: Liittynyt %{date}\n    last_active: viimeksi aktiivinen\n    link_verified_on: Tämän linkin omistus on tarkastettu %{date}\n    moved_html: \"%{name} on muuttanut osoitteeseen %{new_profile_link}:\"\n    network_hidden: Nämä tiedot eivät ole käytettävissä\n    nothing_here: Täällä ei ole mitään!\n    people_followed_by: Henkilöt, joita %{name} seuraa\n    people_who_follow: Käyttäjän %{name} seuraajat\n    pin_errors:\n      following: Sinun täytyy seurata henkilöä jota haluat tukea\n    posts_with_replies: Tuuttaukset ja vastaukset\n    reserved_username: Käyttäjänimi on varattu\n    roles:\n      admin: Ylläpitäjä\n      moderator: Moderaattori\n    unfollow: Lopeta seuraaminen\n  admin:\n    account_moderation_notes:\n      create: Luo\n      created_msg: Moderointimerkinnän luonti onnistui!\n      delete: Poista\n      destroyed_msg: Moderointimerkinnän poisto onnistui!\n    accounts:\n      are_you_sure: Oletko varma?\n      avatar: Profiilikuva\n      by_domain: Verkkotunnus\n      change_email:\n        changed_msg: Tilin sähköposti vaihdettu onnistuneesti!\n        current_email: Nykyinen sähköposti\n        label: Vaihda sähköposti\n        new_email: Uusi sähköposti\n        submit: Vaihda sähköposti\n        title: Vaihda sähköposti käyttäjälle %{username}\n      confirm: Vahvista\n      confirmed: Vahvistettu\n      confirming: Vahvistetaan\n      demote: Alenna\n      disable: Poista käytöstä\n      disable_two_factor_authentication: Poista 2FA käytöstä\n      disabled: Poistettu käytöstä\n      display_name: Nimimerkki\n      domain: Verkkotunnus\n      edit: Muokkaa\n      email: Sähköposti\n      email_status: Sähköpostin tila\n      enable: Ota käyttöön\n      enabled: Käytössä\n      feed_url: Syötteen osoite\n      followers: Seuraajat\n      followers_url: Seuraajien osoite\n      follows: Seuraa\n      inbox_url: Saapuvan postilaatikon osoite\n      location:\n        all: Kaikki\n        local: Paikalliset\n        remote: Etätilit\n        title: Sijainti\n      login_status: Sisäänkirjautumisen tila\n      media_attachments: Medialiitteet\n      memorialize: Muuta muistosivuksi\n      moderation:\n        all: Kaikki\n        silenced: Hiljennetty\n        suspended: Jäähyllä\n        title: Moderointi\n      moderation_notes: Moderointimerkinnät\n      most_recent_activity: Viimeisin toiminta\n      most_recent_ip: Viimeisin IP\n      not_subscribed: Ei tilaaja\n      outbox_url: Lähtevän postilaatikon osoite\n      perform_full_suspension: Siirrä kokonaan jäähylle\n      profile_url: Profiilin osoite\n      promote: Ylennä\n      protocol: Protokolla\n      public: Julkinen\n      push_subscription_expires: PuSH-tilaus vanhenee\n      redownload: Päivitä profiilikuva\n      remove_avatar: Poista profiilikuva\n      resend_confirmation:\n        already_confirmed: Tämä käyttäjä on jo vahvistettu\n        send: Lähetä varmistusviesti uudelleen\n        success: Vahvistusviesti onnistuneesti lähetetty!\n      reset: Palauta\n      reset_password: Palauta salasana\n      resubscribe: Tilaa uudelleen\n      role: Oikeudet\n      roles:\n        admin: Ylläpitäjä\n        moderator: Moderaattori\n        staff: Henkilöstö\n        user: Käyttäjä\n      salmon_url: Salmon-URL\n      search: Hae\n      shared_inbox_url: Jaetun saapuvan postilaatikon osoite\n      show:\n        created_reports: Tämän tilin luomat raportit\n        targeted_reports: Tästä tilistä tehdyt raportit\n      silence: Hiljennä\n      statuses: Tilat\n      subscribe: Tilaa\n      title: Tilit\n      unconfirmed_email: Sähköpostia ei vahvistettu\n      undo_silenced: Peru hiljennys\n      undo_suspension: Peru jäähy\n      unsubscribe: Lopeta tilaus\n      username: Käyttäjänimi\n    action_logs:\n      actions:\n        assigned_to_self_report: \"%{name} otti raportin %{target} tehtäväkseen\"\n        change_email_user: \"%{name} vaihtoi käyttäjän %{target} sähköpostiosoitteen\"\n        confirm_user: \"%{name} vahvisti käyttäjän %{target} sähköpostiosoitteen\"\n        create_custom_emoji: \"%{name} lähetti uuden emojin %{target}\"\n        create_domain_block: \"%{name} esti verkkotunnuksen %{target}\"\n        create_email_domain_block: \"%{name} lisäsi sähköpostiverkkotunnuksen %{target} estolistalle\"\n        demote_user: \"%{name} alensi käyttäjän %{target}\"\n        destroy_domain_block: \"%{name} poisti verkkotunnuksen %{target} eston\"\n        destroy_email_domain_block: \"%{name} lisäsi sähköpostiverkkotunnuksen %{target} sallittujen listalle\"\n        destroy_status: \"%{name} poisti käyttäjän %{target} tilan\"\n        disable_2fa_user: \"%{name} poisti käyttäjältä %{target} kaksivaiheisen todentamisen vaatimuksen\"\n        disable_custom_emoji: \"%{name} poisti emojin %{target} käytöstä\"\n        disable_user: \"%{name} poisti sisäänkirjautumisen käytöstä käyttäjältä %{target}\"\n        enable_custom_emoji: \"%{name} salli emojin %{target} käyttöön\"\n        enable_user: \"%{name} salli sisäänkirjautumisen käyttäjälle %{target}\"\n        memorialize_account: \"%{name} muutti käyttäjän %{target} tilin muistosivuksi\"\n        promote_user: \"%{name} ylensi käyttäjän %{target}\"\n        remove_avatar_user: \"%{name} poisti käyttäjän %{target} profiilikuvan\"\n        reopen_report: \"%{name} avasi uudelleen raportin %{target}\"\n        reset_password_user: \"%{name} palautti käyttäjän %{target} salasanan\"\n        resolve_report: \"%{name} hylkäsi raportin %{target}\"\n        silence_account: \"%{name} hiljensi käyttäjän %{target}\"\n        suspend_account: \"%{name} siirsi käyttäjän %{target} jäähylle\"\n        unsilence_account: \"%{name} poisti käyttäjän %{target} hiljennyksen\"\n        unsuspend_account: \"%{name} perui käyttäjän %{target} jäähyn\"\n        update_custom_emoji: \"%{name} päivitti emojin %{target}\"\n        update_status: \"%{name} päivitti käyttäjän %{target} tilan\"\n      title: Auditointiloki\n    custom_emojis:\n      by_domain: Verkkotunnus\n      copied_msg: Emojin paikallisen kopion luonti onnistui\n      copy: Kopioi\n      copy_failed_msg: Emojista ei voitu tehdä paikallista kopiota\n      created_msg: Emojin luonti onnistui!\n      delete: Poista\n      destroyed_msg: Emojon poisto onnistui!\n      disable: Poista käytöstä\n      disabled_msg: Emojin poisto käytöstä onnistui\n      enable: Ota käyttöön\n      enabled_msg: Emojin käyttöönotto onnistui\n      image_hint: PNG enintään 50 kt\n      listed: Listassa\n      new:\n        title: Lisää uusi mukautettu emoji\n      overwrite: Kirjoita yli\n      shortcode: Lyhennekoodi\n      shortcode_hint: Vähintään kaksi merkkiä, vain kirjaimia, numeroita ja alaviivoja\n      title: Mukautetut emojit\n      unlisted: Ei listassa\n      update_failed_msg: Emojin päivitys epäonnistui\n      updated_msg: Emojin päivitys onnistui!\n      upload: Lähetä\n    domain_blocks:\n      add_new: Lisää uusi\n      created_msg: Verkkotunnuksen estoa käsitellään\n      destroyed_msg: Verkkotunnuksen esto on peruttu\n      domain: Verkkotunnus\n      new:\n        create: Luo esto\n        hint: Verkkotunnuksen esto ei estä tilien luomista ja lisäämistä tietokantaan, mutta se soveltaa näihin tileihin automaattisesti määrättyjä moderointitoimia tilin luomisen jälkeen.\n        severity:\n          desc_html: \"<strong>Hiljennys</strong> estää tilin julkaisuja näkymästä muille kuin tilin seuraajille. <strong>Jäähy</strong> poistaa tilin kaiken sisällön, median ja profiilitiedot. Jos haluat vain hylätä mediatiedostot, valitse <strong>Ei mitään</strong>.\"\n          noop: Ei mitään\n          silence: Hiljennys\n          suspend: Jäähy\n        title: Uusi verkkotunnuksen esto\n      reject_media: Hylkää mediatiedostot\n      reject_media_hint: Poistaa paikallisesti tallennetut mediatiedostot eikä lataa niitä enää jatkossa. Ei merkitystä jäähyn kohdalla\n      show:\n        affected_accounts:\n          one: Vaikuttaa yhteen tiliin tietokannassa\n          other: Vaikuttaa %{count} tiliin tietokannassa\n        retroactive:\n          silence: Peru kaikkien tässä verkkotunnuksessa jo olemassa olevien tilien hiljennys\n          suspend: Peru kaikkien tässä verkkotunnuksessa jo olemassa olevien tilien jäähy\n        title: Peru verkkotunnuksen %{domain} esto\n        undo: Peru\n      undo: Peru\n    email_domain_blocks:\n      add_new: Lisää uusi\n      created_msg: Sähköpostiverkkotunnuksen lisäys estolistalle onnistui\n      delete: Poista\n      destroyed_msg: Sähköpostiverkkotunnuksen poisto estolistalta onnistui\n      domain: Verkkotunnus\n      new:\n        create: Lisää verkkotunnus\n        title: Uusi sähköpostiestolistan merkintä\n      title: Sähköpostiestolista\n    instances:\n      title: Tiedossa olevat instanssit\n    invites:\n      filter:\n        all: Kaikki\n        available: Saatavilla\n        expired: Vanhentunut\n        title: Suodata\n      title: Kutsut\n    report_notes:\n      created_msg: Muistiinpano onnistuneesti lisätty raporttiin!\n      destroyed_msg: Muistiinpano onnistuneesti poistettu raportista!\n    reports:\n      account:\n        note: muistiinpano\n        report: raportti\n      action_taken_by: Toimenpiteen tekijä\n      are_you_sure: Oletko varma?\n      assign_to_self: Ota tehtäväksi\n      comment:\n        none: Ei mitään\n      created_at: Raportoitu\n      mark_as_resolved: Merkitse ratkaistuksi\n      mark_as_unresolved: Merkitse ratkaisemattomaksi\n      notes:\n        create: Lisää muistiinpano\n        create_and_resolve: Ratkaise ja lisää muistiinpano\n        create_and_unresolve: Avaa uudelleen ja lisää muistiinpano\n        delete: Poista\n        placeholder: Kuvaile mitä toimia on tehty tai muita päivityksiä tähän raporttiin…\n      reopen: Avaa raportti uudestaan\n      report: Raportti nro %{id}\n      reported_account: Raportoitu tili\n      reported_by: Raportoija\n      resolved: Ratkaistut\n      resolved_msg: Raportti onnistuneesti ratkaistu!\n      status: Tila\n      title: Raportit\n      unresolved: Ratkaisemattomat\n      updated_at: Päivitetty\n    settings:\n      activity_api_enabled:\n        desc_html: Paikallisesti julkaistujen tilojen, aktiivisten käyttäjien ja uusien rekisteröintien määrät viikoittain\n        title: Julkaise koostetilastoja käyttäjien aktiivisuudesta\n      bootstrap_timeline_accounts:\n        desc_html: Erota käyttäjänimet pilkulla. Vain paikalliset ja lukitsemattomat tilit toimivat. Jos kenttä jätetään tyhjäksi, oletusarvona ovat kaikki paikalliset ylläpitäjät.\n        title: Uudet käyttäjät seuraavat oletuksena seuraavia tilejä\n      contact_information:\n        email: Työsähköposti\n        username: Yhteyshenkilön käyttäjänimi\n      hero:\n        desc_html: Näytetään etusivulla. Suosituskoko vähintään 600x100 pikseliä. Jos kuvaa ei aseteta, käytetään instanssin pikkukuvaa\n        title: Sankarin kuva\n      peers_api_enabled:\n        desc_html: Verkkotunnukset, jotka tämä instanssi on kohdannut fediversumissa\n        title: Julkaise löydettyjen instanssien luettelo\n      registrations:\n        closed_message:\n          desc_html: Näytetään etusivulla, kun rekisteröinti on suljettu. HTML-tagit käytössä\n          title: Viesti, kun rekisteröinti on suljettu\n        deletion:\n          desc_html: Salli jokaisen poistaa oma tilinsä\n          title: Avoin tilin poisto\n        min_invite_role:\n          disabled: Ei kukaan\n          title: Salli kutsut käyttäjältä\n      show_known_fediverse_at_about_page:\n        desc_html: Kun tämä on valittu, esikatselussa näytetään tuuttaukset kaikkialta tunnetusta fediversumista. Muutoin näytetään vain paikalliset tuuttaukset.\n        title: Näytä aikajanan esikatselussa koko tunnettu fediversumi\n      show_staff_badge:\n        desc_html: Näytä käyttäjäsivulla henkilöstömerkki\n        title: Näytä henkilöstömerkki\n      site_description:\n        desc_html: Esittelykappale etusivulla ja metatunnisteissa. HTML-tagit käytössä, tärkeimmät ovat <code>&lt;a&gt;</code> ja <code>&lt;em&gt;</code>.\n        title: Instanssin kuvaus\n      site_description_extended:\n        desc_html: Hyvä paikka käytösohjeille, säännöille, ohjeistuksille ja muille instanssin muista erottaville asioille. HTML-tagit käytössä\n        title: Omavalintaiset laajat tiedot\n      site_terms:\n        desc_html: Tähän voi kirjoittaa instanssin tietosuojakäytännöstä, käyttöehdoista ja sen sellaisista asioista. HTML-tagit käytössä\n        title: Omavalintaiset käyttöehdot\n      site_title: Instanssin nimi\n      thumbnail:\n        desc_html: Käytetään esikatseluissa OpenGraphin ja API:n kautta. Suosituskoko 1200x630 pikseliä\n        title: Instanssin pikkukuva\n      timeline_preview:\n        desc_html: Näytä julkinen aikajana aloitussivulla\n        title: Aikajanan esikatselu\n      title: Sivuston asetukset\n    statuses:\n      back_to_account: Takaisin tilin sivulle\n      batch:\n        delete: Poista\n        nsfw_off: NSFW POIS\n        nsfw_on: NSFW PÄÄLLÄ\n      failed_to_execute: Suoritus epäonnistui\n      no_media: Ei mediaa\n      title: Tilin tilat\n      with_media: Sisältää mediaa\n    subscriptions:\n      callback_url: Paluu-URL\n      confirmed: Vahvistettu\n      expires_in: Vanhenee\n      last_delivery: Viimeisin toimitus\n      topic: Aihe\n    title: Ylläpito\n  admin_mailer:\n    new_report:\n      body: \"%{reporter} on raportoinut kohteen %{target}\"\n      body_remote: Joku osoitteesta %{domain} on raportoinut kohteen %{target}\n      subject: Uusi raportti instanssista %{instance} (nro %{id})\n  application_mailer:\n    notification_preferences: Muuta sähköpostiasetuksia\n    settings: 'Muuta sähköpostiasetuksia: %{link}'\n    view: 'Näytä:'\n    view_profile: Näytä profiili\n    view_status: Näytä tila\n  applications:\n    created: Sovelluksen luonti onnistui\n    destroyed: Sovelluksen poisto onnistui\n    invalid_url: Annettu URL on virheellinen\n    regenerate_token: Luo pääsytunnus uudelleen\n    token_regenerated: Pääsytunnuksen uudelleenluonti onnistui\n    warning: Säilytä tietoa hyvin. Älä milloinkaan jaa sitä muille!\n    your_token: Pääsytunnus\n  auth:\n    change_password: Salasana\n    confirm_email: Vahvista sähköpostiosoite\n    delete_account: Poista tili\n    delete_account_html: Jos haluat poistaa tilisi, <a href=\"%{path}\">paina tästä</a>. Poisto on vahvistettava.\n    didnt_get_confirmation: Etkö saanut vahvistusohjeita?\n    forgot_password: Unohditko salasanasi?\n    invalid_reset_password_token: Salasananpalautustunnus on virheellinen tai vanhentunut. Pyydä uusi.\n    login: Kirjaudu sisään\n    logout: Kirjaudu ulos\n    migrate_account: Muuta toiseen tiliin\n    migrate_account_html: Jos haluat ohjata tämän tilin toiseen tiliin, voit <a href=\"%{path}\">asettaa toisen tilin tästä</a>.\n    or_log_in_with: Tai käytä kirjautumiseen\n    register: Rekisteröidy\n    resend_confirmation: Lähetä vahvistusohjeet uudestaan\n    reset_password: Palauta salasana\n    security: Tunnukset\n    set_new_password: Aseta uusi salasana\n  authorize_follow:\n    already_following: Sinä seuraat jo tätä tiliä\n    error: Valitettavasti etätilin haussa tapahtui virhe\n    follow: Seuraa\n    follow_request: 'Olet lähettänyt seuraamispyynnön käyttäjälle:'\n    following: 'Onnistui! Seuraat käyttäjää:'\n    post_follow:\n      close: Tai voit sulkea tämän ikkunan.\n      return: Palaa käyttäjän profiiliin\n      web: Siirry verkkosivulle\n    title: Seuraa käyttäjää %{acct}\n  datetime:\n    distance_in_words:\n      about_x_hours: \"%{count} h\"\n      about_x_months: \"%{count} kk\"\n      about_x_years: \"%{count} v\"\n      almost_x_years: \"%{count} v\"\n      half_a_minute: Nyt\n      less_than_x_minutes: \"%{count} m\"\n      less_than_x_seconds: Nyt\n      over_x_years: \"%{count} v\"\n      x_days: \"%{count} pv\"\n      x_minutes: \"%{count} m\"\n      x_months: \"%{count} kk\"\n      x_seconds: \"%{count} s\"\n  deletes:\n    bad_password_msg: Hyvä yritys, hakkerit! Väärä salasana\n    confirm_password: Tunnistaudu syöttämällä nykyinen salasanasi\n    description_html: Tämä poistaa <strong>pysyvästi ja peruuttamattomasti</strong> kaiken tilisi sisällön ja poistaa tilin käytöstä. Käyttäjänimesi pysyy varattuna, jotta identiteettiäsi ei myöhemmin varasteta.\n    proceed: Poista tili\n    success_msg: Tilin poisto onnistui\n    warning_html: Sisällön poistaminen taataan vain tämän instanssin osalta. Jos sisältöä on jaettu paljon, siitä todennäköisesti jää jälkiä. Palvelimet, joihin ei saada yhteyttä tai jotka ovat lopettaneet päivitystesi tilaamisen, eivät päivitä tietokantojaan.\n    warning_title: Sisällön saatavuustieto levitetty\n  errors:\n    '403': Sinulla ei ole lupaa nähdä tätä sivua.\n    '404': Etsimääsi sivua ei ole olemassa.\n    '410': Etsimääsi sivua ei ole enää olemassa.\n    '422':\n      content: Turvallisuusvahvistus epäonnistui. Oletko estänyt evästeet?\n      title: Turvallisuusvahvistus epäonnistui\n    '429': Rajoitettu\n    '500':\n      content: Valitettavasti jokin meni pieleen meidän päässämme.\n      title: Sivu ei ole oikein\n    noscript_html: Mastodon-selainsovelluksen käyttöön vaaditaan JavaScript. Voit vaihtoehtoisesti kokeilla jotakin omalle käyttöjärjestelmällesi tehtyä Mastodon<a href=\"%{apps_path}\">sovellusta</a>.\n  exports:\n    archive_takeout:\n      date: Päiväys\n      download: Lataa arkisto\n      hint_html: Voit pyytää arkistoa omista <strong>tuuttauksistasi ja mediastasi</strong>. Vientitiedot ovat ActivityPub-muodossa, ja ne voi lukea millä tahansa yhteensopivalla ohjelmalla.\n      in_progress: Arkistoa kootaan...\n      request: Pyydä arkisto\n      size: Koko\n    blocks: Estot\n    follows: Seurattavat\n    mutes: Mykistetyt\n    storage: Media-arkisto\n  generic:\n    changes_saved_msg: Muutosten tallennus onnistui!\n    save_changes: Tallenna muutokset\n    validation_errors:\n      one: Kaikki ei ole aivan oikein! Tarkasta alla oleva virhe\n      other: Kaikki ei ole aivan oikein! Tarkasta alla olevat %{count} virhettä\n  imports:\n    preface: Voit tuoda toisesta instanssista viemiäsi tietoja, kuten esimerkiksi seuraamiesi tai estämiesi henkilöiden listan.\n    success: Tietojen lähettäminen onnistui, ja ne käsitellään kohtapuoliin\n    types:\n      blocking: Estettyjen lista\n      following: Seurattujen lista\n      muting: Mykistettyjen lista\n    upload: Lähetä\n  in_memoriam_html: Muistoissamme.\n  invites:\n    delete: Poista käytöstä\n    expired: Vanhentunut\n    expires_in:\n      '1800': 30 minuuttia\n      '21600': 6 tuntia\n      '3600': 1 tunti\n      '43200': 12 tuntia\n      '604800': 1 viikko\n      '86400': 1 vuorokausi\n    expires_in_prompt: Ei koskaan\n    generate: Luo\n    max_uses:\n      one: kertakäyttöinen\n      other: \"%{count} käyttökertaa\"\n    max_uses_prompt: Ei rajoitusta\n    prompt: Luo linkkejä ja jaa niiden avulla muille pääsyoikeus tähän instanssiin\n    table:\n      expires_at: Vanhenee\n      uses: Käytetty\n    title: Kutsu ihmisiä\n  lists:\n    errors:\n      limit: Sinulla on jo suurin sallittu määrä listoja\n  media_attachments:\n    validations:\n      images_and_video: Videota ei voi liittää tilapäivitykseen, jossa on jo kuvia\n      too_many: Tiedostoja voi liittää enintään 4\n  migrations:\n    acct: uuden tilin käyttäjätunnus@verkkotunnus\n    currently_redirecting: 'Profiiliisi on asetettu uudelleenohjaus:'\n    proceed: Tallenna\n    updated_msg: Tilinsiirtoasetusten päivitys onnistui!\n  moderation:\n    title: Moderointi\n  notification_mailer:\n    digest:\n      action: Näytä kaikki ilmoitukset\n      body: Tässä lyhyt yhteenveto viime käyntisi (%{since}) jälkeen tulleista viesteistä\n      mention: \"%{name} mainitsi sinut:\"\n      new_followers_summary:\n        one: Olet myös saanut yhden uuden seuraajan! Juhuu!\n        other: Olet myös saanut %{count} uutta seuraajaa! Aivan mahtavaa!\n      subject:\n        one: \"1 uusi ilmoitus viime käyntisi jälkeen \\U0001F418\"\n        other: \"%{count} uutta ilmoitusta viime käyntisi jälkeen \\U0001F418\"\n      title: Poissaollessasi…\n    favourite:\n      body: \"%{name} tykkäsi tilastasi:\"\n      subject: \"%{name} tykkäsi tilastasi\"\n      title: Uusi tykkäys\n    follow:\n      body: \"%{name} seuraa nyt sinua!\"\n      subject: \"%{name} seuraa nyt sinua\"\n      title: Uusi seuraaja\n    follow_request:\n      action: Hallinnoi seuraamispyyntöjä\n      body: \"%{name} haluaa seurata sinua\"\n      subject: 'Odottava seuraamispyyntö: %{name}'\n      title: Uusi seuraamispyyntö\n    mention:\n      action: Vastaa\n      body: \"%{name} mainitsi sinut:\"\n      subject: \"%{name} mainitsi sinut\"\n      title: Uusi maininta\n    reblog:\n      body: \"%{name} buustasi tilaasi:\"\n      subject: \"%{name} boostasi tilaasi\"\n      title: Uusi buustaus\n  number:\n    human:\n      decimal_units:\n        format: \"%n %u\"\n        units:\n          billion: Mrd\n          quadrillion: Brd\n          thousand: k\n          trillion: B\n  pagination:\n    newer: Uudemmat\n    next: Seuraava\n    older: Vanhemmat\n    prev: Edellinen\n  preferences:\n    other: Muut\n  remote_follow:\n    acct: Syötä se käyttäjätunnus@verkkotunnus, josta haluat seurata\n    missing_resource: Vaadittavaa uudelleenohjaus-URL:ää tiliisi ei löytynyt\n    proceed: Siirry seuraamaan\n    prompt: 'Olet aikeissa seurata:'\n  remote_unfollow:\n    error: Virhe\n  sessions:\n    activity: Viimeisin toiminta\n    browser: Selain\n    browsers:\n      generic: Tuntematon selain\n      nokia: Nokia S40 Ovi -selain\n    current_session: Nykyinen istunto\n    description: \"%{browser}, %{platform}\"\n    explanation: Nämä verkkoselaimet ovat tällä hetkellä kirjautuneet Mastodon-tilillesi.\n    platforms:\n      other: tuntematon järjestelmä\n    revoke: Hylkää\n    revoke_success: Istunnon hylkäys onnistui\n    title: Istunnot\n  settings:\n    authorized_apps: Valtuutetut sovellukset\n    back: Takaisin Mastodoniin\n    delete: Tilin poisto\n    development: Kehittäminen\n    edit_profile: Muokkaa profiilia\n    export: Vie tietoja\n    import: Tuo\n    migrate: Tilin muutto muualle\n    notifications: Ilmoitukset\n    preferences: Ominaisuudet\n    two_factor_authentication: Kaksivaiheinen todentaminen\n  statuses:\n    attached:\n      description: 'Liitetty: %{attached}'\n      image:\n        one: \"%{count} kuva\"\n        other: \"%{count} kuvaa\"\n    content_warning: 'Sisältövaroitus: %{warning}'\n    disallowed_hashtags:\n      one: 'sisälsi aihetunnisteen jota ei sallita: %{tags}'\n      other: 'sisälsi aihetunnisteet joita ei sallita: %{tags}'\n    open_in_web: Avaa selaimessa\n    over_character_limit: merkkimäärän rajoitus %{max} ylitetty\n    pin_errors:\n      limit: Olet jo kiinnittänyt suurimman mahdollisen määrän tuuttauksia\n      ownership: Muiden tuuttauksia ei voi kiinnittää\n      private: Piilotettua tuuttausta ei voi kiinnittää\n      reblog: Buustausta ei voi kiinnittää\n    show_more: Näytä lisää\n    title: \"%{name}: ”%{quote}”\"\n    visibilities:\n      private: Vain seuraajille\n      private_long: Näytä vain seuraajille\n      public: Julkinen\n      public_long: Kaikki voivat nähdä\n      unlisted: Listaamaton julkinen\n      unlisted_long: Kaikki voivat nähdä, mutta ei näytetä julkisilla aikajanoilla\n  stream_entries:\n    pinned: Kiinnitetty tuuttaus\n    reblogged: buustasi\n    sensitive_content: Arkaluontoista sisältöä\n  terms:\n    title: \"%{instance}, käyttöehdot ja tietosuojakäytäntö\"\n  themes:\n    default: Mastodon\n  time:\n    formats:\n      default: \"%d.%m.%Y klo %H.%M\"\n  two_factor_authentication:\n    code_hint: Vahvista syöttämällä todentamissovelluksen generoima koodi\n    description_html: Jos otat käyttöön <strong>kaksivaiheisen todentamisen</strong>, kirjautumiseen vaaditaan puhelin, jolla voidaan luoda kirjautumistunnuksia.\n    disable: Poista käytöstä\n    enable: Ota käyttöön\n    enabled: Kaksivaiheinen todentaminen käytössä\n    enabled_success: Kaksivaiheisen todentamisen käyttöönotto onnistui\n    generate_recovery_codes: Luo palautuskoodit\n    instructions_html: \"<strong>Lue tämä QR-koodi puhelimen Google Authenticator- tai vastaavalla TOTP-sovelluksella</strong>. Sen jälkeen sovellus luo tunnuksia, joita tarvitset sisäänkirjautuessasi.\"\n    lost_recovery_codes: Palautuskoodien avulla voit käyttää tiliä, jos menetät puhelimesi. Jos olet hukannut palautuskoodit, voit luoda uudet tästä. Vanhat palautuskoodit poistetaan käytöstä.\n    manual_instructions: 'Jos et voi lukea QR-koodia ja haluat syöttää sen käsin, tässä on salainen koodi tekstinä:'\n    recovery_codes: Varapalautuskoodit\n    recovery_codes_regenerated: Uusien palautuskoodien luonti onnistui\n    recovery_instructions_html: Jos menetät puhelimesi, voit kirjautua tilillesi jollakin alla olevista palautuskoodeista. <strong>Pidä palautuskoodit hyvässä tallessa</strong>. Voit esimerkiksi tulostaa ne ja säilyttää muiden tärkeiden papereiden joukossa.\n    setup: Ota käyttöön\n    wrong_code: Annettu koodi oli virheellinen! Ovatko palvelimen aika ja laitteen aika oikein?\n  user_mailer:\n    backup_ready:\n      explanation: Pyysit täydellistä varmuuskopiota Mastodon-tilistäsi. Voit nyt ladata sen!\n      subject: Arkisto on valmiina ladattavaksi\n      title: Arkiston tallennus\n    welcome:\n      edit_profile_action: Aseta profiili\n      edit_profile_step: Voit mukauttaa profiiliasi lataamalla profiilikuvan ja otsakekuvan, muuttamalla näyttönimeäsi ym. Jos haluat hyväksyä uudet seuraajat ennen kuin he voivat seurata sinua, voit lukita tilisi.\n      explanation: Näillä vinkeillä pääset alkuun\n      final_action: Ala julkaista\n      final_step: 'Ala julkaista! Vaikkei sinulla olisi seuraajia, monet voivat nähdä julkiset viestisi esimerkiksi paikallisella aikajanalla ja hashtagien avulla. Kannattaa esittäytyä! Käytä hashtagia #introductions. (Jos haluat esittäytyä myös suomeksi, se kannattaa tehdä erillisessä tuuttauksessa ja käyttää hashtagia #esittely.).'\n      full_handle: Koko käyttäjätunnuksesi\n      full_handle_hint: Kerro tämä ystävillesi, niin he voivat lähettää sinulle viestejä tai löytää sinut toisen instanssin kautta.\n      review_preferences_action: Muuta asetuksia\n      review_preferences_step: Käy tarkistamassa, että asetukset ovat haluamallasi tavalla. Voit valita, missä tilanteissa haluat saada sähköpostia, mikä on julkaisujesi oletusnäkyvyys jne. Jos et saa helposti pahoinvointia, voit valita, että GIF-animaatiot toistetaan automaattisesti.\n      subject: Tervetuloa Mastodoniin\n      tip_federated_timeline: Yleinen aikajana näyttää sisältöä koko Mastodon-verkostosta. Siinä näkyvät kuitenkin vain ne henkilöt, joita oman instanssisi käyttäjät seuraavat. Siinä ei siis näytetä aivan kaikkea.\n      tip_following: Oletusarvoisesti seuraat oman palvelimesi ylläpitäjiä. Etsi lisää kiinnostavia ihmisiä paikalliselta ja yleiseltä aikajanalta.\n      tip_local_timeline: Paikallinen aikajana näyttää instanssin %{instance} käyttäjien julkaisut. He ovat naapureitasi!\n      tip_mobile_webapp: Jos voit lisätä Mastodonin mobiiliselaimen kautta aloitusnäytöllesi, voit vastaanottaa push-ilmoituksia. Toiminta vastaa monin tavoin tavanomaista sovellusta!\n      tips: Vinkkejä\n      title: Tervetuloa mukaan, %{name}!\n  users:\n    invalid_email: Virheellinen sähköpostiosoite\n    invalid_otp_token: Virheellinen kaksivaiheisen todentamisen koodi\n    otp_lost_help_html: Jos sinulla ei ole pääsyä kumpaankaan, voit ottaa yhteyttä osoitteeseen %{email}\n    seamless_external_login: Olet kirjautunut ulkoisen palvelun kautta, joten salasana- ja sähköpostiasetukset eivät ole käytettävissä.\n    signed_in_as: 'Kirjautunut henkilönä:'\n"
  },
  {
    "path": "config/locales/fr.yml",
    "content": "---\nfr:\n  about:\n    about_hashtag_html: Figurent ci-dessous les pouets tagués avec <strong>#%{hashtag}</strong>. Vous pouvez interagir avec eux si vous avez un compte n’importe où dans le Fediverse.\n    about_mastodon_html: Mastodon est un réseau social utilisant des formats ouverts et des logiciels libres. Comme le courriel, il est décentralisé.\n    about_this: À propos\n    active_count_after: actif·ve·s\n    active_footnote: Utilisateur·rice·s actif·ve·s mensuels (MAU)\n    administered_by: 'Administrée par :'\n    api: API\n    apps: Applications mobiles\n    apps_platforms: Utilisez Mastodon depuis iOS, Android et d’autres plates-formes\n    browse_directory: Parcourir l’annuaire des profils et filtrer par centres d’intérêt\n    browse_public_posts: Parcourir un flux en direct de messages publics sur Mastodon\n    contact: Contact\n    contact_missing: Manquant\n    contact_unavailable: Non disponible\n    discover_users: Découvrez des utilisateur·rice·s\n    documentation: Documentation\n    extended_description_html: |\n      <h3>Un bon endroit pour les règles</h3>\n      <p>La description étendue n’a pas été remplie.</p>\n    federation_hint_html: Avec un compte sur %{instance}, vous pourrez suivre les gens sur n’importe quel serveur Mastodon et au-delà.\n    generic_description: \"%{domain} est seulement un serveur du réseau\"\n    get_apps: Essayez une application mobile\n    hosted_on: Serveur Mastodon hébergée par %{domain}\n    learn_more: En savoir plus\n    privacy_policy: Politique de vie privée\n    see_whats_happening: Voir ce qui se passe\n    server_stats: 'Statistiques du serveur :'\n    source_code: Code source\n    status_count_after:\n      one: Statut\n      other: Statuts\n    status_count_before: Ayant publié\n    tagline: Suivez vos ami·e·s et découvrez en de nouveaux·elles\n    terms: Conditions d’utilisation\n    user_count_after:\n      one: utilisateur\n      other: utilisateurs\n    user_count_before: Abrite\n    what_is_mastodon: Qu’est-ce que Mastodon ?\n  accounts:\n    choices_html: \"%{name} recommande :\"\n    follow: Suivre\n    followers:\n      one: Abonné·e\n      other: Abonné⋅e⋅s\n    following: Abonnements\n    joined: Inscrit·e en %{date}\n    last_active: actif dernièrement\n    link_verified_on: La propriété de ce lien a été vérifiée le %{date}\n    media: Médias\n    moved_html: \"%{name} a changé de compte pour %{new_profile_link} :\"\n    network_hidden: Cette information n’est pas disponible\n    nothing_here: Rien à voir ici !\n    people_followed_by: Personnes suivies par %{name}\n    people_who_follow: Personnes qui suivent %{name}\n    pin_errors:\n      following: Vous devez être déjà abonné·e à la personne que vous désirez recommander\n    posts:\n      one: Pouet\n      other: Pouets\n    posts_tab_heading: Pouets\n    posts_with_replies: Statuts & réponses\n    reserved_username: Ce nom d’utilisateur⋅ice est réservé\n    roles:\n      admin: Admin\n      bot: Robot\n      moderator: Modérateur·trice\n    unavailable: Profil non disponible\n    unfollow: Ne plus suivre\n  admin:\n    account_actions:\n      action: Effectuer une action\n      title: Effectuer une action de modération sur %{acct}\n    account_moderation_notes:\n      create: Laisser un commentaire\n      created_msg: Note de modération créée avec succès !\n      delete: Supprimer\n      destroyed_msg: Note de modération supprimée avec succès !\n    accounts:\n      approve: Approuver\n      approve_all: Tout approuver\n      are_you_sure: Êtes-vous certain⋅e ?\n      avatar: Avatar\n      by_domain: Domaine\n      change_email:\n        changed_msg: Courriel du compte modifié avec succès !\n        current_email: Courriel actuel\n        label: Modifier le courriel\n        new_email: Nouveau courriel\n        submit: Modifier le courriel\n        title: Modifier le courriel pour %{username}\n      confirm: Confirmer\n      confirmed: Confirmé\n      confirming: Confirmation\n      deleted: Supprimé\n      demote: Rétrograder\n      disable: Désactiver\n      disable_two_factor_authentication: Désactiver l’authentification à deux facteurs\n      disabled: Désactivé\n      display_name: Nom affiché\n      domain: Domaine\n      edit: Éditer\n      email: Courriel\n      email_status: État de la messagerie\n      enable: Activer\n      enabled: Activé\n      feed_url: URL du flux\n      followers: Abonné⋅e⋅s\n      followers_url: URL des abonné·e·s\n      follows: Abonnements\n      header: Entête\n      inbox_url: URL d’entrée\n      invited_by: Invité par\n      ip: Adresse IP\n      joined: Inscrit·e depuis\n      location:\n        all: Tous\n        local: Local\n        remote: Distant\n        title: Situation\n      login_status: Statut de connexion\n      media_attachments: Fichiers médias\n      memorialize: Convertir en mémorial\n      moderation:\n        active: Actif\n        all: Tous\n        pending: En cours de traitement\n        silenced: Masqués\n        suspended: Suspendus\n        title: Modération\n      moderation_notes: Notes de modération\n      most_recent_activity: Dernière activité\n      most_recent_ip: Adresse IP la plus récente\n      no_account_selected: Aucun compte n’a été modifié, car aucun n’a été sélectionné\n      no_limits_imposed: Aucune limite imposée\n      not_subscribed: Non abonné\n      outbox_url: URL de sortie\n      pending: En attente d’approbation\n      perform_full_suspension: Suspendre\n      profile_url: URL du profil\n      promote: Promouvoir\n      protocol: Protocole\n      public: Publique\n      push_subscription_expires: Expiration de l’abonnement PuSH\n      redownload: Rafraîchir le profil\n      reject: Rejeter\n      reject_all: Tout rejeter\n      remove_avatar: Supprimer l’avatar\n      remove_header: Supprimer l’entête\n      resend_confirmation:\n        already_confirmed: Cet·te utilisateur·ice est déjà confirmé·e\n        send: Renvoyer un courriel de confirmation\n        success: Courriel de confirmation envoyé avec succès !\n      reset: Réinitialiser\n      reset_password: Réinitialiser le mot de passe\n      resubscribe: Se réabonner\n      role: Permissions\n      roles:\n        admin: Administrateur\n        moderator: Modérateur\n        staff: Équipe\n        user: Utilisateur\n      salmon_url: URL Salmon\n      search: Rechercher\n      shared_inbox_url: URL de la boite de réception partagée\n      show:\n        created_reports: Signalements faits\n        targeted_reports: Signalés par d’autres\n      silence: Masquer\n      silenced: Silencié\n      statuses: Statuts\n      subscribe: S’abonner\n      suspended: Suspendu\n      time_in_queue: En file d’attente %{time}\n      title: Comptes\n      unconfirmed_email: Courriel non-confirmé\n      undo_silenced: Démasquer\n      undo_suspension: Annuler la suspension\n      unsubscribe: Se désabonner\n      username: Nom d’utilisateur⋅ice\n      warn: Avertissement\n      web: Web\n    action_logs:\n      actions:\n        assigned_to_self_report: \"%{name} s’est assigné·e le signalement de %{target}\"\n        change_email_user: \"%{name} a modifié l’adresse de courriel de l’utilisateur·rice %{target}\"\n        confirm_user: \"%{name} adresse courriel confirmée de l’utilisateur·ice %{target}\"\n        create_account_warning: \"%{name} a envoyé une attention à %{target}\"\n        create_custom_emoji: \"%{name} a importé de nouveaux émojis %{target}\"\n        create_domain_block: \"%{name} a bloqué le domaine %{target}\"\n        create_email_domain_block: \"%{name} a mis le domaine du courriel %{target} sur liste noire\"\n        demote_user: \"%{name} a rétrogradé l’utilisateur·ice %{target}\"\n        destroy_custom_emoji: \"%{name} a détruit l’émoticône %{target}\"\n        destroy_domain_block: \"%{name} a débloqué le domaine %{target}\"\n        destroy_email_domain_block: \"%{name} a mis le domaine du courriel %{target} sur liste blanche\"\n        destroy_status: \"%{name} a enlevé le statut de %{target}\"\n        disable_2fa_user: \"%{name} a désactivé l’authentification à deux facteurs pour l’utilisateur·ice %{target}\"\n        disable_custom_emoji: \"%{name} a désactivé l’émoji %{target}\"\n        disable_user: \"%{name} a désactivé le login pour l’utilisateur·ice %{target}\"\n        enable_custom_emoji: \"%{name} a activé l’émoji %{target}\"\n        enable_user: \"%{name} a activé le login pour l’utilisateur·ice %{target}\"\n        memorialize_account: \"%{name} a transformé le compte de %{target} en une page de mémorial\"\n        promote_user: \"%{name} a promu l’utilisateur·ice %{target}\"\n        remove_avatar_user: \"%{name} a supprimé l’avatar de %{target}\"\n        reopen_report: \"%{name} a rouvert le signalement %{target}\"\n        reset_password_user: \"%{name} a réinitialisé le mot de passe de %{target}\"\n        resolve_report: \"%{name} a résolu le signalement %{target}\"\n        silence_account: \"%{name} a mis le compte %{target} en mode silence\"\n        suspend_account: \"%{name} a suspendu le compte %{target}\"\n        unassigned_report: \"%{name} a désassigné le signalement %{target}\"\n        unsilence_account: \"%{name} a mis fin au mode silence de %{target}\"\n        unsuspend_account: \"%{name} a réactivé le compte de %{target}\"\n        update_custom_emoji: \"%{name} a mis à jour l’émoji %{target}\"\n        update_status: \"%{name} a mis à jour le statut de %{target}\"\n      deleted_status: \"(statut supprimé)\"\n      title: Journal d’audit\n    custom_emojis:\n      by_domain: Domaine\n      copied_msg: Copie locale de l’émoji créée avec succès !\n      copy: Copier\n      copy_failed_msg: Impossible de faire une copie locale de cet émoji\n      created_msg: Émoji créé avec succès !\n      delete: Supprimer\n      destroyed_msg: Émoji supprimé avec succès !\n      disable: Désactiver\n      disabled_msg: Émoji désactivé avec succès !\n      emoji: Émoji\n      enable: Activer\n      enabled_msg: Émoji activé avec succès\n      image_hint: PNG de moins de 50 Ko\n      listed: Listé\n      new:\n        title: Ajouter un nouvel émoji personnalisé\n      overwrite: Réécrire\n      shortcode: Raccourci\n      shortcode_hint: Au moins deux caractères, seulement des caractères alphanumériques ou des tirets bas\n      title: Émojis personnalisés\n      unlisted: Délisté\n      update_failed_msg: N’a pas pu mettre à jour cet émoji\n      updated_msg: Émoji mis à jour avec succès !\n      upload: Téléverser\n    dashboard:\n      backlog: tâches en attente\n      config: Configuration\n      feature_deletions: Suppressions de comptes\n      feature_invites: Liens d’invitation\n      feature_profile_directory: Annuaire des profils\n      feature_registrations: Inscriptions\n      feature_relay: Relais de fédération\n      feature_timeline_preview: Aperçu du fil public\n      features: Fonctionnalités\n      hidden_service: Fédération avec des services cachés\n      open_reports: signalements non résolus\n      recent_users: Utilisateur·rice·s récent·e·s\n      search: Recherche plein texte\n      single_user_mode: Mode utilisateur·ice unique\n      software: Logiciel\n      space: Espace utilisé\n      title: Tableau de bord\n      total_users: utilisateur·rice·s au total\n      trends: Tendances\n      week_interactions: interactions cette semaine\n      week_users_active: actif·ve·s cette semaine\n      week_users_new: utilisateur·rice·s cette semaine\n    domain_blocks:\n      add_new: Ajouter un nouveau bloqueur de domaine\n      created_msg: Le blocage de domaine est désormais activé\n      destroyed_msg: Le blocage de domaine a été désactivé\n      domain: Domaine\n      existing_domain_block_html: Vous avez déjà imposé des limites plus strictes à %{name}, vous devez d’abord le <a href=\"%{unblock_url}\">débloquer</a>.\n      new:\n        create: Créer le blocage\n        hint: Le blocage de domaine n’empêchera pas la création de comptes dans la base de données, mais il appliquera automatiquement et rétrospectivement des méthodes de modération spécifiques sur ces comptes.\n        severity:\n          desc_html: \"<strong>Masqué</strong> rendra les messages des comptes concernés invisibles à ceux qui ne les suivent pas. <strong>Suspendre</strong> supprimera tout le contenu des comptes concernés, les médias, et les données du profil. Utilisez <strong>Aucune</strong> si vous voulez simplement rejeter les fichiers multimédia.\"\n          noop: Aucune\n          silence: Masqué\n          suspend: Suspendre\n        title: Nouveau blocage de domaine\n      reject_media: Fichiers média rejetés\n      reject_media_hint: Supprime localement les fichiers média stockés et refuse d’en télécharger ultérieurement. Ne concerne pas les suspensions\n      reject_reports: Rejeter les signalements\n      reject_reports_hint: Ignorez tous les signalements provenant de ce domaine. Ne concerne pas les suspensions\n      rejecting_media: rejet des fichiers multimédia\n      rejecting_reports: rejet des signalements\n      severity:\n        silence: silencié\n        suspend: suspendu\n      show:\n        affected_accounts:\n          one: Un compte affecté dans la base de données\n          other: \"%{count} comptes affectés dans la base de données\"\n        retroactive:\n          silence: Annuler le masquage sur tous les comptes existants pour ce domaine\n          suspend: Annuler la suspension sur tous les comptes existants pour ce domaine\n        title: Annuler le blocage de domaine pour %{domain}\n        undo: Annuler\n      undo: Annuler le bloqueur de domaine\n    email_domain_blocks:\n      add_new: Ajouter\n      created_msg: Le blocage de domaine de courriel est désormais activé\n      delete: Supprimer\n      destroyed_msg: Le blocage de domaine de courriel a été désactivé\n      domain: Domaine\n      new:\n        create: Créer le blocage\n        title: Nouveau blocage de domaine de courriel\n      title: Blocage de domaines de courriel\n    followers:\n      back_to_account: Retour au compte\n      title: Abonné⋅e⋅s de %{acct}\n    instances:\n      by_domain: Domaine\n      delivery_available: Livraison disponible\n      known_accounts:\n        one: \"%{count} compte connu\"\n        other: \"%{count} comptes connus\"\n      moderation:\n        all: Tout\n        limited: Limité\n        title: Modération\n      title: Fédération\n      total_blocked_by_us: Bloqués par nous\n      total_followed_by_them: Suivi par eux\n      total_followed_by_us: Suivi par nous\n      total_reported: Signalements à leurs propos\n      total_storage: Attachements de média\n    invites:\n      deactivate_all: Tout désactiver\n      filter:\n        all: Tout\n        available: Disponible\n        expired: Expiré\n        title: Filtre\n      title: Invitations\n    pending_accounts:\n      title: Comptes en attente (%{count})\n    relays:\n      add_new: Ajouter un nouveau relais\n      delete: Effacer\n      description_html: Un <strong>relai de fédération</strong> est un serveur intermédiaire qui échange de grandes quantités de pouets entre les serveurs qui publient dessus et ceux qui y sont abonnés. <strong>Il peut aider les petits et moyen serveurs à découvrir du contenu sur le fediverse</strong>, ce qui normalement nécessiterait que les membres locaux suivent des gens inscrits sur des serveurs distants.\n      disable: Désactiver\n      disabled: Désactivé\n      enable: Activé\n      enable_hint: Une fois activé, votre serveur souscrira à tous les pouets publics présents sur ce relais et y enverra ses propres pouets publics.\n      enabled: Activé\n      inbox_url: URL de relais\n      pending: En attente de l’approbation du relai\n      save_and_enable: Sauvegarder et activer\n      setup: Paramétrer une connexion de relais\n      status: Statut\n      title: Relais\n    report_notes:\n      created_msg: Note de signalement créée avec succès !\n      destroyed_msg: Note de signalement effacée avec succès !\n    reports:\n      account:\n        note: note\n        report: signaler\n      action_taken_by: Intervention de\n      are_you_sure: Êtes vous certain⋅e ?\n      assign_to_self: Me l’assigner\n      assigned: Modérateur assigné\n      comment:\n        none: Aucun\n      created_at: Signalé\n      mark_as_resolved: Marquer comme résolu\n      mark_as_unresolved: Marquer comme non-résolu\n      notes:\n        create: Ajouter une note\n        create_and_resolve: Résoudre avec une note\n        create_and_unresolve: Ré-ouvrir avec une note\n        delete: Effacer\n        placeholder: Décrivez quelles actions ont été prises, ou toute autre mise à jour…\n      reopen: Ré-ouvrir le signalement\n      report: 'Signalement #%{id}'\n      reported_account: Compte signalé\n      reported_by: Signalé par\n      resolved: Résolus\n      resolved_msg: Signalement résolu avec succès !\n      status: Statut\n      title: Signalements\n      unassign: Dés-assigner\n      unresolved: Non résolus\n      updated_at: Mis à jour\n    settings:\n      activity_api_enabled:\n        desc_html: Nombre de statuts affichés localement, d’utilisateur·ice·s actif·ve·s et de nouveaux enregistrements dans les registres hebdomadaires\n        title: Publier des statistiques agrégées sur l’activité des utilisateur·ice·s\n      bootstrap_timeline_accounts:\n        desc_html: Séparez les noms d’utilisateur·ice par des virgules. Ne fonctionne qu’avec des comptes locaux et non verrouillés. Si laissé vide, tous les administrateur⋅ice⋅s locaux sont sélectionné⋅e⋅s.\n        title: Abonnements par défaut pour les nouveaux·elles utilisateur·ice·s\n      contact_information:\n        email: Entrez une adresse courriel publique\n        username: Entrez un nom d’utilisateur⋅ice\n      custom_css:\n        desc_html: Modifier l’apparence avec une CSS chargée sur chaque page\n        title: CSS personnalisé\n      hero:\n        desc_html: Affichée sur la page d’accueil. Au moins 600x100px recommandé. Lorsqu’elle n’est pas définie, se rabat sur la vignette du serveur\n        title: Image d’en-tête\n      mascot:\n        desc_html: Affiché sur plusieurs pages. Au moins 293×205px recommandé. Lorsqu’il n’est pas défini, retombe à la mascotte par défaut\n        title: Image de la mascotte\n      max_bio_chars:\n        desc_html: Longeur maximale des biographies en nombre de charactères (500 par défaut)\n        title: Longeur maximale des biographies\n      max_toot_chars:\n        desc_html: Longeur maximale des pouets en nombre de charactères (500 par défaut)\n        title: Longeur maximale des pouets\n      peers_api_enabled:\n        desc_html: Noms des domaines que ce serveur a découvert dans le fediverse\n        title: Publier la liste des serveurs découverts\n      preview_sensitive_media:\n        desc_html: Les liens de prévisualisation sur les autres sites web afficheront une vignette même si le média est sensible\n        title: Afficher les médias sensibles dans les prévisualisations OpenGraph\n      profile_directory:\n        desc_html: Permettre aux utilisateurs d’être découverts\n        title: Activer l’annuaire des profils\n      registrations:\n        closed_message:\n          desc_html: Affiché sur la page d’accueil lorsque les inscriptions sont fermées<br>Vous pouvez utiliser des balises HTML\n          title: Message de fermeture des inscriptions\n        deletion:\n          desc_html: Permettre à tou·te·s les utilisateur·ice·s de supprimer leur compte\n          title: Autoriser les suppressions de compte\n        min_invite_role:\n          disabled: Personne\n          title: Autoriser les invitations par\n      registrations_mode:\n        modes:\n          approved: Approbation requise pour s’inscrire\n          none: Personne ne peut s’inscrire\n          open: N’importe qui peut s’inscrire\n        title: Mode d’enregistrement\n      show_known_fediverse_at_about_page:\n        desc_html: Lorsque l’option est activée, les pouets provenant de toutes les serveurs connues sont affichés dans la prévisualisation. Sinon, seuls les pouets locaux sont affichés.\n        title: Afficher le fediverse connu dans la prévisualisation du fil\n      show_staff_badge:\n        desc_html: Montrer un badge de responsable sur une page utilisateur·ice\n        title: Montrer un badge de responsable\n      site_description:\n        desc_html: Paragraphe introductif sur la page d’accueil. Décrivez ce qui rend spécifique ce serveur Mastodon et toute autre chose importante. Vous pouvez utiliser des balises HTML, en particulier <code>&lt;a&gt;</code> et <code>&lt;em&gt;</code>.\n        title: Description du serveur\n      site_description_extended:\n        desc_html: L’endroit idéal pour afficher votre code de conduite, les règles, les guides et autres choses qui rendent votre serveur différent. Vous pouvez utiliser des balises HTML\n        title: Description étendue du serveur\n      site_short_description:\n        desc_html: Affichée dans la barre latérale et dans les méta-tags. Décrivez ce qui rend spécifique ce serveur Mastodon en un seul paragraphe. Si laissée vide, la description du serveur sera affiché par défaut.\n        title: Description courte du serveur\n      site_terms:\n        desc_html: Affichée sur la page des conditions d’utilisation du site<br>Vous pouvez utiliser des balises HTML\n        title: Politique de confidentialité\n      site_title: Nom du serveur\n      thumbnail:\n        desc_html: Utilisée pour les prévisualisations via OpenGraph et l’API. 1200x630px recommandé\n        title: Vignette du serveur\n      timeline_preview:\n        desc_html: Afficher le fil public sur la page d’accueil\n        title: Prévisualisation du fil global\n      title: Paramètres du serveur\n    statuses:\n      back_to_account: Retour à la page du compte\n      batch:\n        delete: Supprimer\n        nsfw_off: Marquer comme non-sensible\n        nsfw_on: Marquer comme sensible\n      failed_to_execute: Erreur d’exécution\n      media:\n        title: Médias\n      no_media: Aucun média\n      no_status_selected: Aucun statut n’a été modifié car aucun n’a été sélectionné\n      title: État du compte\n      with_media: avec médias\n    subscriptions:\n      callback_url: URL de rappel\n      confirmed: Confirmé\n      expires_in: Expire dans\n      last_delivery: Dernière livraison\n      title: WebSub\n      topic: Sujet\n    tags:\n      accounts: Comptes\n      hidden: Masqué\n      hide: Masquer dans l’annuaire\n      name: Hashtag\n      title: Hashtags\n      unhide: Afficher dans l’annuaire\n      visible: Visible\n    title: Administration\n    warning_presets:\n      add_new: Ajouter un nouveau\n      delete: Effacer\n      edit: Éditer\n      edit_preset: Éditer la présélection d’avertissement\n      title: Gérer les présélections d’avertissement\n  admin_mailer:\n    new_pending_account:\n      body: Les détails du nouveau compte se trouvent ci-dessous. Vous pouvez approuver ou rejeter cette demande.\n      subject: Nouveau compte à examiner sur %{instance} (%{username})\n    new_report:\n      body: \"%{reporter} a signalé %{target}\"\n      body_remote: Quelqu’un de %{domain} a signalé %{target}\n      subject: Nouveau signalement sur %{instance} (#%{id})\n  appearance:\n    advanced_web_interface: Interface web avancée\n    advanced_web_interface_hint: 'Si vous voulez utiliser toute la largeur de votre écran, l’interface web avancée vous permet de configurer plusieurs colonnes différentes pour voir autant d’informations que vous le souhaitez en même temps : Accueil, notifications, fil public fédéré, un nombre illimité de listes et hashtags.'\n    animations_and_accessibility: Animations et accessibilité\n    confirmation_dialogs: Dialogues de confirmation\n    sensitive_content: Contenu sensible\n  application_mailer:\n    notification_preferences: Modifier les préférences de courriel\n    salutation: \"%{name},\"\n    settings: 'Changer les préférences courriel : %{link}'\n    view: 'Voir :'\n    view_profile: Voir le profil\n    view_status: Afficher le statut\n  applications:\n    created: Application créée avec succès\n    destroyed: Application supprimée avec succès\n    invalid_url: L’URL fournie est invalide\n    regenerate_token: Regénérer le jeton d’accès\n    token_regenerated: Jeton d’accès regénéré avec succès\n    warning: Soyez prudent⋅e avec ces données. Ne les partagez pas !\n    your_token: Votre jeton d’accès\n  auth:\n    apply_for_account: Demander une invitation\n    change_password: Mot de passe\n    checkbox_agreement_html: J’accepte les <a href=\"%{rules_path}\" target=\"_blank\">règles du serveur</a> et les <a href=\"%{terms_path}\" target=\"_blank\">conditions de service</a>\n    confirm_email: Confirmer mon adresse mail\n    delete_account: Supprimer le compte\n    delete_account_html: Si vous désirez supprimer votre compte, vous pouvez <a href=\"%{path}\">cliquer ici</a>. Il vous sera demandé de confirmer cette action.\n    didnt_get_confirmation: Vous n’avez pas reçu les consignes de confirmation ?\n    forgot_password: Mot de passe oublié ?\n    invalid_reset_password_token: Le lien de réinitialisation du mot de passe est invalide ou a expiré. Merci de réessayer.\n    login: Se connecter\n    logout: Se déconnecter\n    migrate_account: Déplacer vers un compte différent\n    migrate_account_html: Si vous voulez rediriger ce compte vers un autre, vous pouvez le <a href=\"%{path}\">configurer ici</a>.\n    or_log_in_with: Ou authentifiez-vous avec\n    providers:\n      cas: CAS\n      saml: SAML\n    register: S’inscrire\n    registration_closed: \"%{instance} n’accepte pas de nouveaux membres\"\n    resend_confirmation: Envoyer à nouveau les consignes de confirmation\n    reset_password: Réinitialiser le mot de passe\n    security: Sécurité\n    set_new_password: Définir le nouveau mot de passe\n    trouble_logging_in: Vous avez un problème pour vous connecter ?\n  authorize_follow:\n    already_following: Vous suivez déjà ce compte\n    error: Malheureusement, il y a eu une erreur en cherchant les détails du compte distant\n    follow: Suivre\n    follow_request: 'Vous avez demandé à suivre :'\n    following: 'Youpi ! Vous suivez maintenant  :'\n    post_follow:\n      close: Ou bien, vous pouvez fermer cette fenêtre.\n      return: Afficher le profil de l’utilisateur⋅ice\n      web: Retour à l’interface web\n    title: Suivre %{acct}\n  datetime:\n    distance_in_words:\n      about_x_hours: \"%{count} h\"\n      about_x_months: \"%{count} mois\"\n      about_x_years: \"%{count} an(s)\"\n      almost_x_years: \"%{count} an(s)\"\n      half_a_minute: À l’instant\n      less_than_x_minutes: \"%{count} min\"\n      less_than_x_seconds: À l’instant\n      over_x_years: \"%{count}an(s)\"\n      x_days: \"%{count} j\"\n      x_minutes: \"%{count} min\"\n      x_months: \"%{count} mois\"\n      x_seconds: \"%{count} s\"\n  deletes:\n    bad_password_msg: Bien essayé ! Mot de passe incorrect\n    confirm_password: Entrez votre mot de passe pour vérifier votre identité\n    description_html: Cela va supprimer votre compte et le désactiver de manière <strong>permanente et irréversible</strong>. Votre nom d’utilisateur⋅ice restera réservé afin d’éviter la confusion.\n    proceed: Supprimer compte\n    success_msg: Votre compte a été supprimé avec succès\n    warning_html: Seule la suppression du contenu depuis ce serveur est garantie. Le contenu qui a été partagé est susceptible de laisser des traces. Les serveurs hors-ligne ainsi que ceux n’étant plus abonnées à vos publications ne mettront pas leur base de données à jour.\n    warning_title: Disponibilité du contenu disséminé\n  directories:\n    directory: Annuaire des profils\n    enabled: Vous êtes actuellement listé dans l’annuaire.\n    enabled_but_waiting: Vous avez choisi d’être listé dans l’annuaire, mais vous n’avez pas encore le nombre minimum de suiveurs (%{min_followers}) pour y être inscrit.\n    explanation: Découvrir des utilisateurs en se basant sur leurs centres d’intérêt\n    explore_mastodon: Explorer %{title}\n    how_to_enable: Vous n’êtes pas encore inscrit dans l’annuaire. Vous pouvez vous inscrire ci-dessous. Utilisez des hashtags dans votre texte biographique pour être listé sous des hashtags spécifiques !\n    people:\n      one: \"%{count} personne\"\n      other: \"%{count} personne\"\n  errors:\n    '403': Vous n’avez pas accès à cette page.\n    '404': La page que vous recherchez n’existe pas.\n    '410': La page que vous recherchez n’existe plus.\n    '422':\n      content: Vérification de sécurité échouée. Bloquez-vous les cookies ?\n      title: Vérification de sécurité échouée\n    '429': Trop de requêtes émises dans un délai donné\n    '500':\n      content: Nous sommes désolé·e·s, mais quelque chose s’est mal passé de notre côté.\n      title: Cette page n’est pas correcte\n    noscript_html: Pour utiliser Mastodon, veuillez activer JavaScript. Sinon, essayez l’une des <a href=\"%{apps_path}\">applications natives</a> pour Mastodon pour votre plate-forme.\n  existing_username_validator:\n    not_found: n’a pas trouvé d’utilisateur·rice local·e avec ce nom\n    not_found_multiple: n’a pas trouvé %{usernames}\n  exports:\n    archive_takeout:\n      date: Date\n      download: Télécharger votre archive\n      hint_html: Vous pouvez demander une archive de vos <strong>pouets et médias téléversés</strong>. Les données exportées seront au format ActivityPub, lisible par tout logiciel compatible. Vous pouvez demander une archive tous les 7 jours.\n      in_progress: Création de votre archive…\n      request: Demandez vos archives\n      size: Taille\n    blocks: Vous bloquez\n    csv: CSV\n    domain_blocks: Bloqueurs de domaine\n    follows: Vous suivez\n    lists: Listes\n    mutes: Vous masquez\n    storage: Médias stockés\n  featured_tags:\n    add_new: Ajouter un nouvel hashtag\n    errors:\n      limit: Vous avez déjà mis en avant le nombre maximum de hashtags\n  filters:\n    contexts:\n      home: Accueil\n      notifications: Notifications\n      public: Fils publics\n      thread: Conversations\n    edit:\n      title: Éditer le filtre\n    errors:\n      invalid_context: Contexte invalide ou insuffisant\n      invalid_irreversible: Le filtrage irréversible ne fonctionne que pour l’accueil et les notifications\n    index:\n      delete: Effacer\n      title: Filtres\n    new:\n      title: Ajouter un nouveau filtre\n  footer:\n    developers: Développeurs\n    more: Davantage…\n    resources: Ressources\n  generic:\n    all: Tous\n    changes_saved_msg: Les modifications ont été enregistrées avec succès !\n    copy: Copier\n    order_by: Classer par\n    save_changes: Enregistrer les modifications\n    validation_errors:\n      one: Quelque chose ne va pas ! Vérifiez l’erreur ci-dessous\n      other: Certaines choses ne vont pas ! Vérifiez les %{count} erreurs ci-dessous\n  html_validator:\n    invalid_markup: 'contient un balisage HTML invalide: %{error}'\n  identity_proofs:\n    active: Actif\n    authorize: Oui, autoriser\n    authorize_connection_prompt: Autoriser cette connexion chiffrée ?\n    errors:\n      failed: La connexion chiffrée a échoué. Veuillez réessayer à partir de %{provider}.\n      keybase:\n        invalid_token: Les jetons Keybase sont des hachages de signatures et doivent comporter 66 caractères hexadécimaux\n        verification_failed: Keybase ne reconnaît pas ce jeton comme une signature de l’utilisateur Keybase %{kb_username}. Veuillez réessayer à partir de Keybase.\n      wrong_user: Impossible de créer une preuve pour %{proving} lorsque vous êtes connecté en tant que %{current}. Connectez-vous en tant que %{proving} et réessayez.\n    explanation_html: Ici, vous pouvez connecter de manière chiffrée vos autres identités, par exemple un profil Keybase. Cela permet à d’autres personnes de vous envoyer des messages chiffrés et de faire confiance au contenu que vous leur envoyez.\n    i_am_html: Je suis %{username} sur %{service}.\n    identity: Identité\n    inactive: Inactif\n    publicize_checkbox: 'Et le poueter:'\n    publicize_toot: 'C’est prouvé ! Je suis %{username} sur %{service}: %{url}'\n    status: Statut de vérification\n    view_proof: Voir la preuve\n  imports:\n    modes:\n      merge: Fusionner\n      merge_long: Garder les enregistrements existants et ajouter les nouveaux\n      overwrite: Réécrire\n      overwrite_long: Remplacer les enregistrements actuels par les nouveaux\n    preface: Vous pouvez importer certaines données que vous avez exporté d’un autre serveur, comme une liste des personnes que vous suivez ou bloquez sur votre compte.\n    success: Vos données ont été importées avec succès et seront traitées en temps et en heure\n    types:\n      blocking: Liste d’utilisateur⋅ice⋅s bloqué⋅e⋅s\n      domain_blocking: Liste des serveurs bloquées\n      following: Liste d’utilisateur⋅ice⋅s suivi⋅e⋅s\n      muting: Liste d’utilisateur⋅ice⋅s que vous masquez\n    upload: Importer\n  in_memoriam_html: En mémoire de.\n  invites:\n    delete: Désactiver\n    expired: Expiré\n    expires_in:\n      '1800': 30 minutes\n      '21600': 6 heures\n      '3600': 1 heure\n      '43200': 12 heures\n      '604800': 1 semaine\n      '86400': 1 jour\n    expires_in_prompt: Jamais\n    generate: Générer\n    invited_by: 'Vous avez été invité·e par :'\n    max_uses:\n      one: 1 usage\n      other: \"%{count} usages\"\n    max_uses_prompt: Pas de limite\n    prompt: Générer et partager des liens avec les autres pour donner accès à ce serveur\n    table:\n      expires_at: Expire\n      uses: Utilise\n    title: Inviter des gens\n  lists:\n    errors:\n      limit: Vous avez atteint le nombre maximum de listes\n  media_attachments:\n    validations:\n      images_and_video: Impossible de joindre une vidéo à un statut contenant déjà des images\n      too_many: Impossible de joindre plus de 4 fichiers\n  migrations:\n    acct: profil@domaine du nouveau compte\n    currently_redirecting: 'Votre profil va être redirigé vers :'\n    proceed: Enregistrer\n    updated_msg: Les paramètres de votre migration de compte ont été mis à jour avec succès !\n  moderation:\n    title: Modération\n  notification_mailer:\n    digest:\n      action: Voir toutes les notifications\n      body: Voici un bref résumé des messages que vous auriez raté depuis votre dernière visite le %{since}\n      mention: \"%{name} vous a mentionné⋅e dans :\"\n      new_followers_summary:\n        one: Vous avez un⋅e nouvel⋅le abonné⋅e ! Youpi !\n        other: Vous avez %{count} nouveaux⋅elles abonné⋅e·s ! Incroyable !\n      subject:\n        one: \"Une nouvelle notification depuis votre dernière visite \\U0001F418\"\n        other: \"%{count} nouvelles notifications depuis votre dernière visite \\U0001F418\"\n      title: Pendant votre absence…\n    favourite:\n      body: \"%{name} a ajouté votre pouet à ses favoris :\"\n      subject: \"%{name} a ajouté votre post à ses favoris\"\n      title: Nouveau favori\n    follow:\n      body: \"%{name} vous suit !\"\n      subject: \"%{name} vous suit\"\n      title: Nouvel·le abonné·e\n    follow_request:\n      action: Gérer les demandes d’abonnement\n      body: \"%{name} a demandé à vous suivre\"\n      subject: 'Abonné⋅es en attente : %{name}'\n      title: Nouvelle demande d’abonnement\n    mention:\n      action: Répondre\n      body: \"%{name} vous a mentionné⋅e dans :\"\n      subject: \"%{name} vous a mentionné·e\"\n      title: Nouvelle mention\n    reblog:\n      body: \"%{name} a partagé votre statut :\"\n      subject: \"%{name} a partagé votre statut\"\n      title: Nouveau partage\n  number:\n    human:\n      decimal_units:\n        format: \"%n%u\"\n        units:\n          billion: G\n          million: M\n          quadrillion: P\n          thousand: K\n          trillion: T\n  pagination:\n    newer: Plus récent\n    next: Suivant\n    older: Plus ancien\n    prev: Précédent\n    truncate: \"&hellip;\"\n  polls:\n    errors:\n      already_voted: Vous avez déjà voté sur ce sondage\n      duplicate_options: contient des doublons\n      duration_too_long: est trop loin dans le futur\n      duration_too_short: est trop tôt\n      expired: Ce sondage est déjà terminé\n      over_character_limit: ne peuvent être plus long que %{max} caractères chacun\n      too_few_options: doit avoir plus qu’une proposition\n      too_many_options: ne peut contenir plus que %{max} propositions\n  preferences:\n    other: Autre\n    posting_defaults: Paramètres par défaut des pouets\n    public_timelines: Fils publics\n  relationships:\n    activity: Activité du compte\n    dormant: Dormant\n    last_active: Dernière activité\n    most_recent: Plus récent\n    moved: Déménagé\n    mutual: Mutuel\n    primary: Primaire\n    relationship: Relation\n    remove_selected_domains: Supprimer tous les abonné·e·s des domaines sélectionnés\n    remove_selected_followers: Supprimer les abonné·e·s sélectionnés\n    remove_selected_follows: Cesser de suivre les utilisateur·rice·s sélectionné·e·s\n    status: Statut du compte\n  remote_follow:\n    acct: Entrez l’adresse profil@serveur depuis laquelle vous voulez vous abonner\n    missing_resource: L’URL de redirection n’a pas pu être trouvée\n    no_account_html: Vous n’avez pas de compte ? Vous pouvez <a href='%{sign_up_path}' target='_blank'>vous inscrire ici</a>\n    proceed: Confirmer l’abonnement\n    prompt: 'Vous allez suivre :'\n    reason_html: \"<strong>Pourquoi cette étape est-elle nécessaire?</strong> <code>%{instance}</code> pourrait ne pas être le serveur où vous vous êtes inscrit, et nous devons donc vous rediriger vers votre serveur de base en premier.\"\n  remote_interaction:\n    favourite:\n      proceed: Confirmer l’ajout aux favoris\n      prompt: 'Vous souhaitez mettre ce pouet en favori :'\n    reblog:\n      proceed: Confirmer le repartage\n      prompt: 'Vous souhaitez repartager ce pouet :'\n    reply:\n      proceed: Confirmer la réponse\n      prompt: 'Vous souhaitez répondre à ce pouet :'\n  remote_unfollow:\n    error: Erreur\n    title: Titre\n    unfollowed: Non-suivi\n  scheduled_statuses:\n    over_daily_limit: Vous avez dépassé la limite de %{limit} pouets planifiés pour ce jour\n    over_total_limit: Vous avez dépassé la limite de %{limit} pouets planifiés\n    too_soon: La date planifiée doit être dans le futur\n  sessions:\n    activity: Dernière activité\n    browser: Navigateur\n    browsers:\n      alipay: Alipay\n      blackberry: Blackberry\n      chrome: Chrome\n      edge: Microsoft Edge\n      electron: Electron\n      firefox: Firefox\n      generic: Navigateur inconnu\n      ie: Internet Explorer\n      micro_messenger: MicroMessenger\n      nokia: Nokia S40 Ovi Browser\n      opera: Opera\n      otter: Otter\n      phantom_js: PhantomJS\n      qq: QQ Browser\n      safari: Safari\n      uc_browser: UCBrowser\n      weibo: Weibo\n    current_session: Session courante\n    description: \"%{browser} sur %{platform}\"\n    explanation: Ceci est la liste des navigateurs actuellement connectés à votre compte Mastodon.\n    ip: Adresse IP\n    platforms:\n      adobe_air: Adobe Air\n      android: Android\n      blackberry: Blackberry\n      chrome_os: ChromeOS\n      firefox_os: Firefox OS\n      ios: iOS\n      linux: Linux\n      mac: Mac\n      other: système inconnu\n      windows: Windows\n      windows_mobile: Windows Mobile\n      windows_phone: Windows Phone\n    revoke: Révoquer\n    revoke_success: Session révoquée avec succès\n    title: Sessions\n  settings:\n    account: Compte\n    account_settings: Paramètres du compte\n    appearance: Apparence\n    authorized_apps: Applications autorisées\n    back: Retour vers Mastodon\n    delete: Suppression de compte\n    development: Développement\n    edit_profile: Modifier le profil\n    export: Export de données\n    featured_tags: Hashtags mis en avant\n    identity_proofs: Preuves d’identité\n    import: Import de données\n    import_and_export: Import et export\n    migrate: Migration de compte\n    notifications: Notifications\n    preferences: Préférences\n    profile: Profil\n    relationships: Abonnements et abonné·e·s\n    two_factor_authentication: Identification à deux facteurs\n  statuses:\n    attached:\n      description: 'Attaché : %{attached}'\n      image:\n        one: \"%{count} image\"\n        other: \"%{count} images\"\n      video:\n        one: \"%{count} vidéo\"\n        other: \"%{count} vidéos\"\n    boosted_from_html: Repartagé depuis %{acct_link}\n    content_warning: 'Avertissement sur le contenu : %{warning}'\n    disallowed_hashtags:\n      one: 'contient un hashtag désactivé : %{tags}'\n      other: 'contient les hashtags désactivés : %{tags}'\n    language_detection: Détecter automatiquement la langue\n    open_in_web: Ouvrir sur le web\n    over_character_limit: limite de caractères dépassée de %{max} caractères\n    pin_errors:\n      limit: Vous avez déjà épinglé le nombre maximum de pouets\n      ownership: Vous ne pouvez pas épingler un statut ne vous appartenant pas\n      private: Les statuts non-publics ne peuvent pas être épinglés\n      reblog: Un partage ne peut pas être épinglé\n    poll:\n      total_votes:\n        one: \"%{count} vote\"\n        other: \"%{count} votes\"\n      vote: Voter\n    show_more: Afficher plus\n    sign_in_to_participate: Inscrivez-vous pour prendre part à la conversation\n    title: '%{name} : \"%{quote}\"'\n    visibilities:\n      private: Abonné⋅e⋅s uniquement\n      private_long: Seul⋅e⋅s vos abonné⋅e⋅s verront vos statuts\n      public: Public\n      public_long: Tout le monde peut voir vos statuts\n      unlisted: Public sans être affiché sur le fil public\n      unlisted_long: Tout le monde peut voir vos statuts mais ils ne seront pas sur listés sur les fils publics\n  stream_entries:\n    pinned: Pouet épinglé\n    reblogged: a partagé\n    sensitive_content: Contenu sensible\n  terms:\n    body_html: |\n      <h2>Politique de confidentialité</h2>\n      <h3 id=\"collect\">Quelles informations collectons-nous ?</h3>\n\n      <ul>\n      <li><em>Informations de base sur votre compte</em> : Si vous vous inscrivez sur ce serveur, il vous sera demandé de rentrer un identifiant, une adresse électronique et un mot de passe. Vous pourrez également ajouter des informations additionnelles sur votre profil, telles qu’un nom public et une biographie, ainsi que téléverser une image de profil et une image d’en-tête. Vos identifiant, nom public, biographie, image de profil et image d’en-tête seront toujours affichés publiquement.</li>\n      <li><em>Posts, liste d’abonnements et autres informations publiques</em> : La liste de vos abonnements ainsi que la liste de vos abonné·e·s sont publiques. Quand vous postez un message, la date et l’heure d’envoi ainsi que le nom de l’application utilisée pour sa transmission sont enregistré·e·s. Des médias, tels que des images ou des vidéos, peuvent être joints aux messages. Les posts publics et non listés sont affichés publiquement. Quand vous mettez en avant un post sur votre profil, ce post est également affiché publiquement. Vos messages sont délivrés à vos abonné·e·s, ce qui, dans certains cas, signifie qu’ils sont délivrés à des serveurs tiers et que ces derniers en stockent une copie. Quand vous supprimer un post, il est probable que vos abonné·e·s en soient informé·e·s. Partager un message ou le marquer comme favori est toujours une action publique.</li>\n      <li><em>Posts directs et abonné·e·s uniquement</em> : Tous les posts sont stockés et traités par le serveur. Les messages abonné·e·s uniquement ne sont transmis qu’à vos abonné·e·s et aux personnes mentionnées dans le corps du message, tandis que les messages directs ne sont transmis qu’aux personnes mentionnées. Dans certains cas, cela signifie qu’ils sont délivrés à des serveurs tiers et que ces derniers en stockent une copie. Nous faisons un effort de bonne fois pour en limiter l’accès uniquement aux personnes autorisées, mais ce n’est pas nécessairement le cas des autres serveurs. Il est donc très important que vous vérifiiez les serveurs auxquels appartiennent vos abonné·e·s. Il vous est possible d’activer une option dans les paramètres afin d’approuver et de rejeter manuellement les nouveaux·lles abonné·e·s. <em>Gardez s’il-vous-plaît en mémoire que les opérateur·rice·s du serveur ainsi que celles et ceux de n’importe quel serveur récepteur peuvent voir ces messages</em> et qu’il est possible pour les destinataires de faire des captures d’écran, de copier et plus généralement de repartager ces messages. <em>Ne partager aucune information sensible à l’aide de Mastodon.</em></li>\n      <li><em>IP et autres métadonnées</em> : Quand vous vous connectez, nous enregistrons votre adresse IP ainsi que le nom de votre navigateur web. Toutes les sessions enregistrées peuvent être consultées dans les paramètres, afin que vous puissiez les surveiller et éventuellement les révoquer. La dernière adresse IP utilisée est conservée pour une durée de 12 mois. Nous sommes également susceptibles de conserver les journaux du serveur, ce qui inclut l’adresse IP de chaque requête reçue.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"use\">Que faisons-nous des informations que nous collectons ?</h3>\n\n      <p>Toutes les informations que nous collectons sur vous peuvent être utilisées d’une des manières suivantes :</p>\n\n      <ul>\n      <li>Pour vous fournir les fonctionnalités de base de Mastodon. Vous ne pouvez interagir avec le contenu des autres et poster votre propre contenu que lorsque vous êtes connecté·e. Par exemple, vous pouvez vous abonner à plusieurs autres comptes pour voir l’ensemble de leurs posts dans votre fil d’accueil personnalisé.</li>\n      <li>Pour aider à la modération de la communauté, par exemple, comparer votre adresse IP à d’autres afin de déterminer si un bannissement a été contourné ou si une autre violation aux règles a été commise.</li>\n      <li>L’adresse électronique que vous nous avez fournie peut être utilisée pour vous envoyez des informations, des notifications lorsque d’autres personnes interagissent avec votre contenu ou vous envoient des messages, pour répondre à des demandes de votre part ainsi que pour tout autres requêtes ou questions.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"protect\">Comment protégeons-nous vos informations ?</h3>\n\n      <p>Nous mettons en œuvre une variété de mesures de sécurité afin de garantir la sécurité de vos informations personnelles quand vous les saisissez, les soumettez et les consultez. Entre autres choses, votre session de navigation ainsi que le trafic entre votre application et l’API sont sécurisés à l’aide de TLS tandis que votre mot de passe est haché en utilisant un puissant algorithme à sens unique. Vous pouvez également activer l’authentification à deux facteurs pour sécuriser encore plus l’accès à votre compte.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"data-retention\">Quelle est notre politique de conservation des données ?</h3>\n\n      <p>Nous ferons un effort de bonne foi :</p>\n\n      <ul>\n      <li>Pour ne pas conserver plus de 90 jours les journaux systèmes contenant les adresses IP de toutes les requêtes reçues par ce serveur.</li>\n      <li>Pour ne pas conserver plus de 12 mois les adresses IP associées aux utilisateur·ice·s enregistré·e·s.</li>\n      </ul>\n\n      <p>Vous pouvez demander une archive de votre contenu, incluant vos posts, vos médias joints, votre image de profil et votre image d’en-tête.</p>\n\n      <p>Vous pouvez, à n’importe quel moment, supprimer votre compte de manière définitive.</p>\n\n      <hr class=\"spacer\"/>\n\n      <h3 id=\"cookies\">Utilisons-nous des témoins de connexion ?</h3>\n\n      <p>Oui. Les témoins de connexion sont de petits fichiers qu’un site ou un service transféres sur le disque dur de votre ordinateur via votre navigateur web (si vous l’avez autorisé). Ces témoins permettent au site de reconnaître votre navigateur et de, dans le cas où vous possédez un compte, de vous associer avec ce dernier.</p>\n\n      <p>Nous utilisons les témoins de connexion comme un moyen de comprendre et de nous souvenir de vos préférences pour vos prochaines visites.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"disclose\">Divulguons-nous des informations à des tierces parties ?</h3>\n\n      <p>Nous ne vendons, n’échangeons ou ne transférons d’une quelque manière que soit des informations permettant de vous identifier personnellement. Cela n’inclut pas les tierces parties de confiance qui nous aident à opérer ce site, à conduire nos activités commerciales ou à vous servir, tant qu’elles acceptent de garder ces informations confidentielles. Nous sommes également susceptibles de partager vos informations quand nous pensons que c’est nécessaire pour nous conformer à la loi, pour appliquer les politiques de notre site ainsi que pour défendre nos droits, notre propriété, notre sécurité et celles et ceux d’autres personnes.</p>\n\n      <p>Votre contenu public peut être téléchargé par d’autres serveurs du réseau. Dans le cas où vos abonné·e·s et vos destinataires résideraient sur des serveurs différents du vôtre, vos posts publics et abonné·e·s uniquement peuvent être délivrés vers les serveurs de vos abonné·e·s tandis que vos messages directs sont délivrés aux serveurs de vos destinataires.</p>\n\n      <p>Quand vous autorisez une application à utiliser votre compte, en fonction de l’étendue des permissions que vous approuvez, il est possible qu’elle puisse accéder aux informations publiques de votre profil, votre liste d’abonnements, votre liste d’abonné·e·s, vos listes, tout vos posts et vos favoris. Les applications ne peuvent en aucun cas accéder à votre adresse électronique et à votre mot de passe.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"children\">Utilisation de ce site par les enfants</h3>\n\n      <p>Si ce serveur est situé dans dans l’UE ou l’EEE : Notre site, produits et services sont tous destinés à des personnes âgées de 16 ans ou plus. Si vous avez moins de 16 ans, en application du RGPD (<a href=\"https://fr.wikipedia.org/wiki/R%C3%A8glement_g%C3%A9n%C3%A9ral_sur_la_protection_des_donn%C3%A9es\">Règlement Général sur la Protection des Données</a>), merci de ne pas utiliser ce site.</p>\n\n      <p>Si ce serveur est situé dans aux États-Unis d’Amérique : Notre site, produits et services sont tous destinés à des personnes âgées de 13 ans ou plus. Si vous avez moins de 13 ans, en application du COPPA (<a href=\"https://fr.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act\">Children's Online Privacy Protection Act</a>), merci de ne pas utiliser ce site.</p>\n\n      <p>Les exigences légales peuvent être différentes si ce serveur se trouve dans une autre juridiction.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"changes\">Modifications de notre politique de confidentialité</h3>\n\n      <p>Dans le cas où nous déciderions de changer notre politique de confidentialité, nous posterons les modifications sur cette page.</p>\n\n      <p>Ce document est publié sous lincence CC-BY-SA. Il a été mis à jours pour la dernière fois le 7 mars 2018.</p>\n\n      <p>Originellement adapté de la <a href=\"https://github.com/discourse/discourse\">politique de confidentialité de Discourse</a>.</p>\n    title: \"%{instance} Conditions d’utilisation et politique de confidentialité\"\n  themes:\n    contrast: Mastodon (Contraste élevé)\n    default: Mastodon (Sombre)\n    mastodon-light: Mastodon (Clair)\n  time:\n    formats:\n      default: \"%d %b %Y, %H:%M\"\n      month: \"%b %Y\"\n  two_factor_authentication:\n    code_hint: Entrez le code généré par votre application pour confirmer\n    description_html: Si vous activez <strong>l’identification à deux facteurs</strong>, vous devrez être en possession de votre téléphone afin de générer un code de connexion.\n    disable: Désactiver\n    enable: Activer\n    enabled: L’authentification à deux facteurs est activée\n    enabled_success: Identification à deux facteurs activée avec succès\n    generate_recovery_codes: Générer les codes de récupération\n    instructions_html: \"<strong>Scannez ce QR code grâce à Google Authenticator, Authy ou une application similaire sur votre téléphone</strong>. Désormais, cette application génèrera des jetons que vous devrez saisir à chaque connexion.\"\n    lost_recovery_codes: Les codes de récupération vous permettent de retrouver les accès à votre compte si vous perdez votre téléphone. Si vous perdez vos codes de récupération, vous pouvez les générer à nouveau ici. Vos anciens codes de récupération seront invalidés.\n    manual_instructions: 'Si vous ne pouvez pas scanner le code QR et devez l’entrer manuellement, voici le secret en texte-plein :'\n    recovery_codes: Codes de récupération\n    recovery_codes_regenerated: Codes de récupération régénérés avec succès\n    recovery_instructions_html: Si vous perdez l’accès à votre téléphone, vous pouvez utiliser un des codes de récupération ci-dessous pour retrouver l’accès à votre compte. <strong>Conservez les codes de récupération en sécurité</strong>. Par exemple, en les imprimant et en les stockant avec vos autres documents importants.\n    setup: Installer\n    wrong_code: Les codes entrés sont incorrects ! L’heure du serveur et celle de votre appareil sont-elles correctes ?\n  user_mailer:\n    backup_ready:\n      explanation: Vous avez demandé une sauvegarde complète de votre compte Mastodon. Elle est maintenant prête à être téléchargée !\n      subject: Votre archive est prête à être téléchargée\n      title: Récupération de l’archive\n    warning:\n      explanation:\n        disable: Lorsque votre compte est gelé, les données de votre compte demeurent intactes, mais vous ne pouvez effectuer aucune action jusqu’à ce qu’il soit débloqué.\n        silence: Lorsque votre compte est limité, seulement les utilisateurs qui vous suivent déjà verront vos pouets sur ce serveur, et vous pourriez être exclu de plusieurs listes publiques. Néanmoins, d’autres utilisateurs peuvent vous suivre manuellement.\n        suspend: Votre compte a été suspendu, et tous vos pouets et vos fichiers multimédia téléversés ont été supprimés irréversiblement de ce serveur, et des serveurs où vous aviez des abonné⋅e⋅s.\n      review_server_policies: Passer en revue les politiques du serveur\n      subject:\n        disable: Votre compte %{acct} a été gelé\n        none: Avertissement pour %{acct}\n        silence: Votre compte %{acct} a été limité\n        suspend: Votre compte %{acct} a été suspendu\n      title:\n        disable: Compte gelé\n        none: Avertissement\n        silence: Compte limité\n        suspend: Compte suspendu\n    welcome:\n      edit_profile_action: Configuration du profil\n      edit_profile_step: Vous pouvez personnaliser votre profil en téléchargeant un avatar, une image d’en-tête, en changeant votre pseudo et plus encore. Si vous souhaitez examiner les nouveaux·lles abonné·e·s avant qu’il·elle·s ne soient autorisé·e·s à vous suivre, vous pouvez verrouiller votre compte.\n      explanation: Voici quelques conseils pour vous aider à démarrer\n      final_action: Commencer à publier\n      final_step: 'Commencez à poster ! Même sans abonné·e·s, vos messages publics peuvent être vus par d’autres, par exemple sur le fil public local et dans les hashtags. Vous pouvez vous présenter sur le hashtag #introductions.'\n      full_handle: Votre identifiant complet\n      full_handle_hint: C’est ce que vous diriez à vos ami·e·s pour leur permettre de vous envoyer un message ou vous suivre à partir d’un autre serveur.\n      review_preferences_action: Modifier les préférences\n      review_preferences_step: Assurez-vous de définir vos préférences, telles que les courriels que vous aimeriez recevoir ou le niveau de confidentialité auquel vous aimeriez que vos messages soient soumis par défaut. Si vous n’avez pas le mal des transports, vous pouvez choisir d’activer la lecture automatique des GIF.\n      subject: Bienvenue sur Mastodon\n      tip_federated_timeline: La fil public global est une vue en direct du réseau Mastodon. Mais elle n’inclut que les personnes auxquelles vos voisin·es sont abonné·e·s, donc elle n’est pas complète.\n      tip_following: Vous suivez les administrateur·rice·s de votre serveur par défaut. Pour trouver d’autres personnes intéressantes, consultez les fils publics local et global.\n      tip_local_timeline: Le fil public local est une vue des personnes sur %{instance}. Ce sont vos voisines et voisins immédiats !\n      tip_mobile_webapp: Si votre navigateur mobile vous propose d’ajouter Mastodon à votre écran d’accueil, vous pouvez recevoir des notifications. Il agit comme une application native de bien des façons !\n      tips: Astuces\n      title: Bienvenue à bord, %{name} !\n  users:\n    follow_limit_reached: Vous ne pouvez pas suivre plus de %{limit} personnes\n    invalid_email: L’adresse courriel est invalide\n    invalid_otp_token: Le code d’authentification à deux facteurs est invalide\n    otp_lost_help_html: Si vous perdez accès aux deux, vous pouvez contacter %{email}\n    seamless_external_login: Vous êtes connecté via un service externe, donc les paramètres concernant le mot de passe et le courriel ne sont pas disponibles.\n    signed_in_as: 'Connecté·e en tant que :'\n  verification:\n    explanation_html: 'Vous pouvez <strong>vérifier vous-même que vous êtes le propriétaire des liens dans les métadonnées de votre profil</strong>. Pour cela, le site Web lié doit contenir un lien vers votre profil Mastodon. Le lien de retour <strong>doit</strong>avoir un attribut <code>rel=\"me\"</code>. Le contenu textuel du lien n’a pas d’importance. En voici un exemple :'\n    verification: Vérification\n"
  },
  {
    "path": "config/locales/ga.yml",
    "content": "---\nga:\n  about:\n    about_hashtag_html: Is toots phoiblí iad seo atá clibáilte le <strong>#%{hashtag}</strong>. Is féidir leat idirghníomhú leo má tá cuntas agat áit ar bith sa fediverse.\n"
  },
  {
    "path": "config/locales/gl.yml",
    "content": "---\ngl:\n  about:\n    about_hashtag_html: Estas son mensaxes públicas etiquetadas con <strong>#%{hashtag}</strong>. Pode interactuar con elas si ten unha conta nalgures do fediverso.\n    about_mastodon_html: Mastodon é unha rede social que se basea en protocolos web abertos e libres, software de código aberto. É descentralizada como o correo electrónico.\n    about_this: Sobre\n    active_count_after: activo\n    active_footnote: Usuarias Activas no Mes (UAM)\n    administered_by: 'Administrada por:'\n    api: API\n    apps: Apps móbiles\n    apps_platforms: Utilice Mastodon desde iOS, Android e outras plataformas\n    browse_directory: Navegue no directorio de perfís e filtre por intereses\n    browse_public_posts: Vexa o fluxo de comentarios públicos en Mastodon\n    contact: Contacto\n    contact_missing: Non establecido\n    contact_unavailable: N/A\n    discover_users: Descubra usuarias\n    documentation: Documentación\n    extended_description_html: |\n      <h3>Un bo lugar para regras</h3>\n      <p>A descrición extendida aínda non se proporcionou.</p>\n    federation_hint_html: Con unha conta en %{instance} poderá seguir a outras persoas en calquera dos servidores Mastodon e incluso máis.\n    generic_description: \"%{domain} é un servidor na rede\"\n    get_apps: Probe cunha app móbil\n    hosted_on: Mastodon aloxado en %{domain}\n    learn_more: Coñeza máis\n    privacy_policy: Política de intimidade\n    see_whats_happening: Mire o que acontece\n    server_stats: 'Estatísticas:'\n    source_code: Código fonte\n    status_count_after:\n      one: estado\n      other: estados\n    status_count_before: Que publicaron\n    tagline: Siga as amizades e faga outras novas\n    terms: Termos do servizo\n    user_count_after:\n      one: usuaria\n      other: usuarias\n    user_count_before: Fogar de\n    what_is_mastodon: Qué é Mastodon?\n  accounts:\n    choices_html: 'Eleccións de %{name}:'\n    follow: Seguir\n    followers:\n      one: Seguidora\n      other: Seguidoras\n    following: Seguindo\n    joined: Uneuse %{date}\n    last_active: última actividade\n    link_verified_on: A propiedade de esta ligazón foi comprobada en %{date}\n    media: Medios\n    moved_html: \"%{name} mudouse a %{new_profile_link}:\"\n    network_hidden: A información non está dispoñible\n    nothing_here: Nada por aquí!\n    people_followed_by: Personas que segue %{name}\n    people_who_follow: Personas que seguen a %{name}\n    pin_errors:\n      following: Debe seguir a persoa que intenta recomendar\n    posts:\n      one: Toot\n      other: Toots\n    posts_tab_heading: Toots\n    posts_with_replies: Toots e respostas\n    reserved_username: O nome de usuaria está reservado\n    roles:\n      admin: Admin\n      bot: Bot\n      moderator: Mod\n    unavailable: Perfil non dispoñible\n    unfollow: Deixar de seguir\n  admin:\n    account_actions:\n      action: Realizar acción\n      title: Realizar acción de moderación sobre %{acct}\n    account_moderation_notes:\n      create: Deixar nota\n      created_msg: Nota a moderación creada con éxito!\n      delete: Eliminar\n      destroyed_msg: Nota a moderación destruída con éxito!\n    accounts:\n      approve: Aprobar\n      approve_all: Aprobar todo\n      are_you_sure: Está segura?\n      avatar: Avatar\n      by_domain: Dominio\n      change_email:\n        changed_msg: Cambiouse correctamente o correo-e da conta!\n        current_email: Correo actual\n        label: Cambiar correo\n        new_email: Novo correo\n        submit: Cambiar correo\n        title: Cambiar o correo de %{username}\n      confirm: Confirmar\n      confirmed: Confirmado\n      confirming: Confirmar\n      deleted: Eliminado\n      demote: Degradar\n      disable: Deshabilitar\n      disable_two_factor_authentication: Deshabilitar 2FA\n      disabled: Deshabilitado\n      display_name: Mostrar nome\n      domain: Dominio\n      edit: Editar\n      email: Correo-e\n      email_status: Estado do correo\n      enable: Habilitar\n      enabled: Habilitado\n      feed_url: URL fonte\n      followers: Seguidoras\n      followers_url: URL das seguidoras\n      follows: Segue\n      header: Cabeceira\n      inbox_url: URL da Caixa de entrada\n      invited_by: Convidada por\n      ip: IP\n      joined: Uniuse\n      location:\n        all: Todo\n        local: Local\n        remote: Remoto\n        title: Lugar\n      login_status: Estado da conexión\n      media_attachments: Anexos de medios\n      memorialize: Convertir a lembranza\n      moderation:\n        active: Activa\n        all: Todo\n        pending: Pendente\n        silenced: Acalado\n        suspended: Suspendido\n        title: Moderación\n      moderation_notes: Notas de moderación\n      most_recent_activity: Actividade máis recente\n      most_recent_ip: IP máis recente\n      no_account_selected: Non cambiou nada xa que non tiña nada seleccionado\n      no_limits_imposed: Sen límites impostos\n      not_subscribed: Non suscrita\n      outbox_url: URL caixa de saída\n      pending: Pendente revisión\n      perform_full_suspension: Suspender\n      profile_url: URL do perfil\n      promote: Promocionar\n      protocol: Protocolo\n      public: Público\n      push_subscription_expires: A suscrición PuSH caduca\n      redownload: Actualizar perfil\n      reject: Rexeitar\n      reject_all: Rexeitar todo\n      remove_avatar: Eliminar avatar\n      remove_header: Eliminar cabeceira\n      resend_confirmation:\n        already_confirmed: Este usuario ya está confirmado\n        send: Reenviar el correo electrónico de confirmación\n        success: \"¡Correo electrónico de confirmación enviado con éxito!\"\n      reset: Restablecer\n      reset_password: Restablecer contrasinal\n      resubscribe: Voltar a suscribir\n      role: Permisos\n      roles:\n        admin: Administrador\n        moderator: Moderador\n        staff: Membresía\n        user: Usuaria\n      salmon_url: URL Salmon\n      search: Busca\n      shared_inbox_url: URL da caixa de entrada compartida\n      show:\n        created_reports: Informes creados\n        targeted_reports: Informes feitos por outros\n      silence: Acalar\n      silenced: Acalada\n      statuses: Estados\n      subscribe: Subscribir\n      suspended: Suspendida\n      time_in_queue: Agardando en cola %{time}\n      title: Contas\n      unconfirmed_email: Correo non confirmado\n      undo_silenced: Desfacer acalar\n      undo_suspension: Desfacer suspensión\n      unsubscribe: Non subscribir\n      username: Nome de usuaria\n      warn: Aviso\n      web: Web\n    action_logs:\n      actions:\n        assigned_to_self_report: \"%{name} asignou o informe %{target} a ela misma\"\n        change_email_user: \"%{name} cambiou o enderezo de correo-e da usuaria %{target}\"\n        confirm_user: \"%{name} comfirmou o enderezo de correo da usuaria %{target}\"\n        create_account_warning: \"%{name} enviou un aviso sobre %{target}\"\n        create_custom_emoji: \"%{name} subeu un novo emoji %{target}\"\n        create_domain_block: \"%{name} bloqueou o dominio %{target}\"\n        create_email_domain_block: \"%{name} engadeu a lista negra o dominio de correo %{target}\"\n        demote_user: \"%{name} degradou a usuaria %{target}\"\n        destroy_custom_emoji: \"%{name} destruíu emoji %{target}\"\n        destroy_domain_block: \"%{name} desbloqueou o dominio %{target}\"\n        destroy_email_domain_block: \"%{name} meteu na lista blanca de correo o dominio %{target}\"\n        destroy_status: \"%{name} eliminou o estado de %{target}\"\n        disable_2fa_user: \"%{name} deshabilitou o requerimento 2FA para usuaria %{target}\"\n        disable_custom_emoji: \"%{name} deshabilitou emoji %{target}\"\n        disable_user: \"%{name} deshabilitou a conexión para a usuaria  %{target}\"\n        enable_custom_emoji: \"%{name} habilitou emoji %{target}\"\n        enable_user: \"%{name} habilitou a conexión para a usuaria %{target}\"\n        memorialize_account: \"%{name} converteu a conta de  %{target} nunha páxina para a lembranza\"\n        promote_user: \"%{name} promoveu a usuaria %{target}\"\n        remove_avatar_user: \"%{name} eliminou o avatar de %{target}\"\n        reopen_report: \"%{name} voltou abrir informe  %{target}\"\n        reset_password_user: \"%{name} restableceu o contrasinal da usuaria %{target}\"\n        resolve_report: \"%{name} solucionou o informe %{target}\"\n        silence_account: \"%{name} acalou a conta de %{target}\"\n        suspend_account: \"%{name} suspendeu a conta de %{target}\"\n        unassigned_report: \"%{name} non asignou informe %{target}\"\n        unsilence_account: \"%{name} deulle voz a conta de %{target}\"\n        unsuspend_account: \"%{name} activou a conta de %{target}\"\n        update_custom_emoji: \"%{name} actualizou emoji %{target}\"\n        update_status: \"%{name} actualizou un estado de %{target}\"\n      deleted_status: \"(estado eliminado)\"\n      title: Rexistro de auditoría\n    custom_emojis:\n      by_domain: Dominio\n      copied_msg: Creouse con éxito unha copia local dos emoji\n      copy: Copiar\n      copy_failed_msg: Non se puido facer copia local de ese emoji\n      created_msg: Creou o emoji con satisfactoriamente!\n      delete: Eliminar\n      destroyed_msg: Emojo destruído satisfactoriamente!\n      disable: Deshabilitar\n      disabled_msg: Deshabilitouse correctamente ese emoji\n      emoji: Emoji\n      enable: Habilitar\n      enabled_msg: Habilitouse correctamente ese emoji\n      image_hint: PNG ate 50KB\n      listed: Listado\n      new:\n        title: Engadir novo emoji persoalizado\n      overwrite: Sobrescribir\n      shortcode: Código corto\n      shortcode_hint: Cando menos 2 caracteres, só caracteres alfanuméricos e subliñados\n      title: Emojis persoalizados\n      unlisted: Non listado\n      update_failed_msg: Non se puido actualizar ese emoji\n      updated_msg: Actualizouse correctamente o emoji!\n      upload: Subir\n    dashboard:\n      backlog: traballos respaldados\n      config: Axustes\n      feature_deletions: Borrado de contas\n      feature_invites: Ligazóns de convite\n      feature_profile_directory: Directorio do perfil\n      feature_registrations: Rexistros\n      feature_relay: Repetidores de federación\n      feature_timeline_preview: Vista previa da TL\n      features: Características\n      hidden_service: Federación con servizos ocultos\n      open_reports: informes abertos\n      recent_users: Usuarias recentes\n      search: Busca de texto completo\n      single_user_mode: Modo de usuario individual\n      software: Software\n      space: Uso de espazo\n      title: Taboleiro\n      total_users: total de usuarias\n      trends: Tendencias\n      week_interactions: interaccións en esta semana\n      week_users_active: activas estas semana\n      week_users_new: usuarias esta semana\n    domain_blocks:\n      add_new: Engadir novo bloqueo de dominio\n      created_msg: Estase a procesar o bloqueo do dominio\n      destroyed_msg: Desfixose a acción de bloqueo de dominio\n      domain: Dominio\n      existing_domain_block_html: Xa estableceu límites estrictos para %{name}, precisa <a href=\"%{unblock_url}\">desbloqueala</a> primeiro.\n      new:\n        create: Crear bloque\n        hint: O bloqueo do dominio non previrá a creación de entradas de contas na base de datos, pero aplicará de xeito retroactivo e automático regras específicas de moderación sobre esas contas.\n        severity:\n          desc_html: \"<strong>Silenciar</strong> fará invisibles as mensaxes das contas para calquera que non os siga. <strong>Suspender</strong> eliminará todo o contido das contas, ficheiros de medios, e datos de perfil. Utilice <strong>Ningún</strong> si só quere rexeitar ficheiros de medios.\"\n          noop: Ningún\n          silence: Silenciar\n          suspend: Suspender\n        title: Novo bloqueo de dominio\n      reject_media: Rexeitar ficheiros de medios\n      reject_media_hint: Eliminar ficheiros de medios almacenados localmente e rexeita descargalos no futuro. Irrelevante para as suspensións\n      reject_reports: Rexeitar informes\n      reject_reports_hint: Ignorar todos os informes procedentes de este dominio. Irrelevante para as suspensións\n      rejecting_media: rexeitando ficheiros de medios\n      rejecting_reports: rexeitando informes\n      severity:\n        silence: acalado\n        suspend: suspendido\n      show:\n        affected_accounts:\n          one: Afectoulle a unha conta na base de datos\n          other: Afectoulle a %{count} contas na base de datos\n        retroactive:\n          silence: Non silenciar todas as contas existentes de este dominio\n          suspend: Non suspender todas as contas existentes de este dominio\n        title: Desfacer o bloqueo de dominio para %{domain}\n        undo: Desfacer\n      undo: Desfacer bloqueo de dominio\n    email_domain_blocks:\n      add_new: Engadir novo\n      created_msg: Engadeuse correctamente o dominio de email a lista negra\n      delete: Eliminar\n      destroyed_msg: Eliminouse correctamente o dominio de e-mail da lista negra\n      domain: Dominio\n      new:\n        create: Engadir dominio\n        title: Nova entrada la lista negra de e-mail\n      title: Lista negra de E-mail\n    followers:\n      back_to_account: Voltar a Conta\n      title: Seguidoras de %{acct}\n    instances:\n      by_domain: Dominio\n      delivery_available: A entrega está dispoñible\n      known_accounts:\n        one: \"%{count} conta coñecida\"\n        other: \"%{count} contas coñecidas\"\n      moderation:\n        all: Todo\n        limited: Limitado\n        title: Moderación\n      title: Federación\n      total_blocked_by_us: Bloqueado por nós\n      total_followed_by_them: Seguidas por eles\n      total_followed_by_us: Seguidas por nós\n      total_reported: Informes sobre elas\n      total_storage: Anexos de medios\n    invites:\n      deactivate_all: Desactivar todo\n      filter:\n        all: Todo\n        available: Dispoñible\n        expired: Cadudado\n        title: Filtro\n      title: Convida\n    pending_accounts:\n      title: Contas pendentes (%{count})\n    relays:\n      add_new: Engadir un novo repetidor\n      delete: Eliminar\n      description_html: Un <strong>repetidor da federación</strong> é un servidor intermedio que intercambia grandes volumes de toots públicos entre servidores que se suscriban e publiquen nel. <strong>Pode axudar a servidores pequenos e medios a descubrir contido no fediverso</strong>, o que de outro xeito precisaría que as usuarias locais seguisen a outra xente en servidores remotos.\n      disable: Desactivar\n      disabled: Desactivada\n      enable: Activar\n      enable_hint: Unha vez activado, o seu servidor suscribirase a todos os toots públicos de este servidor, e tamén comezará a eviar a el os toots públicos do servidor.\n      enabled: Activada\n      inbox_url: URL do repetidor\n      pending: Agardando polo permiso do repetidor\n      save_and_enable: Gardar e activar\n      setup: Configurar a conexión ao repetidor\n      status: Estado\n      title: Repetidores\n    report_notes:\n      created_msg: Creouse correctamente a nota do informe!\n      destroyed_msg: Nota do informe eliminouse con éxito!\n    reports:\n      account:\n        note: nota\n        report: informe\n      action_taken_by: Acción tomada por\n      are_you_sure: Está segura?\n      assign_to_self: Asignarmo\n      assigned: Moderador asignado\n      comment:\n        none: Nada\n      created_at: Reportado\n      mark_as_resolved: Marcar como resolto\n      mark_as_unresolved: Marcar como non resolto\n      notes:\n        create: Engadir nota\n        create_and_resolve: Resolver con nota\n        create_and_unresolve: Voltar a abrir con nota\n        delete: Eliminar\n        placeholder: Describe qué medidas foron tomadas, ou calquer outra información relacionada...\n      reopen: Voltar a abrir o informe\n      report: 'Informe #%{id}'\n      reported_account: Conta reportada\n      reported_by: Reportada por\n      resolved: Resolto\n      resolved_msg: Resolveuse con éxito o informe!\n      status: Estado\n      title: Informes\n      unassign: Non asignar\n      unresolved: Non resolto\n      updated_at: Actualizado\n    settings:\n      activity_api_enabled:\n        desc_html: Conta de estados publicados localmente, usuarias activas, e novos rexistros por semana\n        title: Publicar estatísticas agregadas sobre a actividade da usuaria\n      bootstrap_timeline_accounts:\n        desc_html: Separar múltiples nomes de usuaria con vírgulas. Só funcionarán as contas locais non bloqueadas. Si baldeiro, por omisión son todos os local admin.\n        title: Seguimentos por omisión para novas usuarias\n      contact_information:\n        email: e-mail de traballo\n        username: Nome de usuaria de contacto\n      custom_css:\n        desc_html: Modificar o aspecto con CSS cargado en cada páxina\n        title: CSS persoalizado\n      hero:\n        desc_html: Mostrado na portada. Recoméndase 600x100px como mínimo. Se non se establece, mostrará a imaxe por omisión do servidor\n        title: Imáxe Heróe\n      mascot:\n        desc_html: Mostrado en varias páxinas. Recoméndase 293x205 como mínimo. Se non se establece publícase a mascota por omisión\n        title: Imaxe da mascota\n      peers_api_enabled:\n        desc_html: Nomes de dominio que este servidor atopou no fediverso\n        title: Publicar lista de servidores descubertos\n      preview_sensitive_media:\n        desc_html: A vista previa de ligazóns de outros sitios web mostrará unha imaxe incluso si os medios están marcados como sensibles\n        title: Mostrar medios sensibles con vista previa OpenGraph\n      profile_directory:\n        desc_html: Permitir que as usuarias poidan ser descubertas\n        title: Activar o directorio de perfil\n      registrations:\n        closed_message:\n          desc_html: Mostrado na páxina de portada cando o rexistro está pechado. Pode utilizar etiquetas HTML\n          title: Mensaxe de rexistro pechado\n        deletion:\n          desc_html: Permitirlle a calquera que elimine a súa conta\n          title: Abrir o borrado da conta\n        min_invite_role:\n          disabled: Ninguén\n          title: Permitir convites por\n      registrations_mode:\n        modes:\n          approved: Precisa aprobación para rexistrarse\n          none: Rexistro pechado\n          open: Rexistro aberto\n        title: Estado do rexistro\n      show_known_fediverse_at_about_page:\n        desc_html: Si activado, mostraralle os toots de todo o fediverso coñecido nunha vista previa. Si non só mostrará os toots locais.\n        title: Mostrar vista previa do fediverso na liña temporal\n      show_staff_badge:\n        desc_html: Mostrar unha insignia de membresía nunha páxina de usuaria\n        title: Mostrar insigna de membresía\n      site_description:\n        desc_html: Parágrafo de presentación na páxina principal. Describe o que fai especial a este servidor Mastodon e calquera outra ouca importante. Pode utilizar etiquetas HTML, en particular <code>&lt;a&gt;</code> e <code>&lt;em&gt;</code>.\n        title: Descrición do servidor\n      site_description_extended:\n        desc_html: Un bo lugar para o seu código de conducta, regras, guías e outras cousas que distingan ao seu servidor. Pode utilizar etiquetas HTML\n        title: Información extendida da persoalización\n      site_short_description:\n        desc_html: Mostrado na barra lateral e nas etiquetas meta. Describe o que é Mastodon e que fai especial a este servidor nun só parágrafo. Si está baldeiro, mostrará a descrición do servidor.\n        title: Descrición curta do servidor\n      site_terms:\n        desc_html: Pode escribir a súa propia política de intimidade, termos de servizo ou aclaracións legais. Pode utilizar etiquetas HTML\n        title: Termos de servizo persoalizados\n      site_title: Nome do servidor\n      thumbnail:\n        desc_html: Utilizado para vistas previsas vía OpenGraph e API. Recoméndase 1200x630px\n        title: Icona do servidor\n      timeline_preview:\n        desc_html: Mostrar liña de tempo pública na páxina de inicio\n        title: vista previa da liña temporal\n      title: Axustes do sitio\n    statuses:\n      back_to_account: Voltar a páxina da conta\n      batch:\n        delete: Eliminar\n        nsfw_off: Marcar como non sensible\n        nsfw_on: Marcar como sensible\n      failed_to_execute: Fallou a execución\n      media:\n        title: Medios\n      no_media: Sen medios\n      no_status_selected: Non se cambiou ningún estado xa que ningún foi seleccionado\n      title: Estados da conta\n      with_media: con medios\n    subscriptions:\n      callback_url: URL de chamada\n      confirmed: Confirmado\n      expires_in: Caduca en\n      last_delivery: Última entrega\n      title: WebSub\n      topic: Asunto\n    tags:\n      accounts: Contas\n      hidden: Ocultas\n      hide: Ocultar do directorio\n      name: Etiqueta\n      title: Etiquetas\n      unhide: Mostrar en directorio\n      visible: Visible\n    title: Administración\n    warning_presets:\n      add_new: Engadir novo\n      delete: Eliminar\n      edit: Editar\n      edit_preset: Editar aviso preestablecido\n      title: Xestionar avisos preestablecidos\n  admin_mailer:\n    new_pending_account:\n      body: Abaixo están os detalles da conta. Pode aprobar ou rexeitar esta solicitude.\n      subject: Hai unha conta nova para revisar en %{instance} (%{username})\n    new_report:\n      body: \"%{reporter} informou sobre %{target}\"\n      body_remote: Alguén desde %{domain} informou sobre %{target}\n      subject: Novo informe sobre %{instance} (#%{id})\n  appearance:\n    advanced_web_interface: Interface web avanzada\n    advanced_web_interface_hint: Se quere utilizar todo o ancho da súa pantalla, a interface web avanzada permítelle configurar diferentes columnas para ver tanta información como desexe. Inicio, notificacións, liña temporal federada, calquera número de listas e etiquetas.\n    animations_and_accessibility: Animacións e accesibilidade\n    confirmation_dialogs: Diálogos de confirmación\n    sensitive_content: Contido sensible\n  application_mailer:\n    notification_preferences: Cambiar os axustes de correo-e\n    salutation: \"%{name},\"\n    settings: 'Mudar as preferencias de e-mail: %{link}'\n    view: 'Vista:'\n    view_profile: Ver perfil\n    view_status: Ver estado\n  applications:\n    created: Creouse con éxito este aplicativo\n    destroyed: Eliminouse con éxito o aplicativo\n    invalid_url: A URL proporcionada non é válida\n    regenerate_token: Votar a xenerar o testemuño de acceso\n    token_regenerated: Rexenerouse con éxito o testemuño de acceso\n    warning: Teña moito tino con estos datos. Nunca os comparta con ninguén!\n    your_token: O seu testemuño de acceso\n  auth:\n    apply_for_account: Solicite un convite\n    change_password: Contrasinal\n    checkbox_agreement_html: Acepto as <a href=\"%{rules_path}\" target=\"_blank\">regras do servidor</a> e os <a href=\"%{terms_path}\" target=\"_blank\">termos do servizo</a>\n    confirm_email: Confirmar correo-e\n    delete_account: Eliminar conta\n    delete_account_html: Se desexa eliminar a súa conta, pode <a href=\"%{path}\">facelo aquí</a>. Pediráselle confirmación.\n    didnt_get_confirmation: Non recibeu as instruccións de confirmación?\n    forgot_password: Esqueceu o contrasinal?\n    invalid_reset_password_token: O testemuño para restablecer o contrasinal non é válido ou caducou. Por favor solicite un novo.\n    login: Conectar\n    logout: Desconectar\n    migrate_account: Mover a unha conta diferente\n    migrate_account_html: Se desexa redirixir esta conta hacia outra diferente, pode <a href=\"%{path}\">configuralo aquí</a>.\n    or_log_in_with: ou conectar con\n    providers:\n      cas: CAS\n      saml: SAML\n    register: Rexistro\n    registration_closed: \"%{instance} non está a aceptar novas usuarias\"\n    resend_confirmation: Voltar a enviar intruccións de confirmación\n    reset_password: Restablecer contrasinal\n    security: Seguridade\n    set_new_password: Establecer novo contrasinal\n    trouble_logging_in: Problemas para conectar?\n  authorize_follow:\n    already_following: Xa está a seguir esta conta\n    error: Desgraciadamente, algo fallou ao buscar a conta remota\n    follow: Seguir\n    follow_request: 'Enviou unha petición de seguimento a:'\n    following: 'Parabéns! Está a seguir a:'\n    post_follow:\n      close: Ou, pode pechar esta ventá.\n      return: Mostrar o perfil da usuaria\n      web: Ir a web\n    title: Seguir %{acct}\n  datetime:\n    distance_in_words:\n      about_x_hours: \"%{count}h\"\n      about_x_months: \"%{count}mes\"\n      about_x_years: \"%{count}a\"\n      almost_x_years: \"%{count}a\"\n      half_a_minute: Agora\n      less_than_x_minutes: \"%{count}m\"\n      less_than_x_seconds: Agora\n      over_x_years: \"%{count}a\"\n      x_days: \"%{count}d\"\n      x_minutes: \"%{count}m\"\n      x_months: \"%{count}mes\"\n      x_seconds: \"%{count}s\"\n  deletes:\n    bad_password_msg: Bo intento, hackers! Contrasinal incorrecto\n    confirm_password: Introduza o seu contrasinal para verificar a súa identidade\n    description_html: Esto eliminará de xeito <strong>permanente e irreversible</strong> o contido da súa conta e será desactivada. O seu nome de usuaria permanecerá reservado para evitar futuras confusións de identidades.\n    proceed: Eliminar conta\n    success_msg: A súa conta eliminouse correctamente\n    warning_html: Só se garantiza a eliminación de contido de este servidor. O contido que foi compartido con outras instancias é probable que deixe rastros. O servidores fora de liña e servidores que se desuscribiron das súas actualizacións non actualizarán as súas bases de datos.\n    warning_title: Dispoñibilidade do contido espallado\n  directories:\n    directory: Directorio de perfil\n    enabled: Vostede está actualmente na lista do directorio.\n    enabled_but_waiting: Vostede optou por ser incluída no directorio, mais por agora non ten o número mínimo de seguidoras (%{min_followers}) para aparecer.\n    explanation: Descubra usuarias según o seu interese\n    explore_mastodon: Explorar %{title}\n    how_to_enable: Actualmente non solicitou ser incluída no directorio, pode facelo abaixo. Utilice etiquetas no texto de biografía para ser incluída baixo etiquetas específicas!\n    people:\n      one: \"%{count} persoa\"\n      other: \"%{count} persoas\"\n  errors:\n    '403': Non ten permiso para ver esta páxina.\n    '404': A páxina que está a buscar non está aquí.\n    '410': A páxina que estaba a buscar xa non existe.\n    '422':\n      content: Fallou a verificación de seguridade. Está bloqueando as cookies?\n      title: Fallou a verficación de seguridade\n    '429': Acelerado\n    '500':\n      content: Sentímolo, pero algo do noso lado falloou.\n      title: Esta páxina non é correcta\n    noscript_html: Para utilizar a aplicación web de Mastodon debe habilitar JavaScript. De xeito alternativo, intente unha das <a href=\"%{apps_path}\">apps nativas</a> para Mastodon da súa plataforma.\n  existing_username_validator:\n    not_found: non se atopou unha usuaria local con ese alcume\n    not_found_multiple: non se atopou a %{usernames}\n  exports:\n    archive_takeout:\n      date: Data\n      download: Descargue o seu ficheiro\n      hint_html: Pode solicitar un ficheiro cos <strong>seus toots e ficheiros de medios</strong>. Os datos estarán en formato ActivityPub e son compatibles con calquer software que o siga. Pode solicitar un ficheiro cada 7 días.\n      in_progress: Xerando o seu ficheiro...\n      request: Solicite o ficheiro\n      size: Tamaño\n    blocks: A bloquear\n    csv: CSV\n    domain_blocks: Bloqueos de dominio\n    follows: A seguir\n    lists: Listas\n    mutes: Acalou\n    storage: Almacenamento de medios\n  featured_tags:\n    add_new: Engadir novo\n    errors:\n      limit: Xa acadou o número máximo de etiquetas\n  filters:\n    contexts:\n      home: Liña temporal inicial\n      notifications: Avisos\n      public: Liñas temporais públicas\n      thread: Conversas\n    edit:\n      title: Editar filtro\n    errors:\n      invalid_context: Non se proporcionou un contexto válido\n      invalid_irreversible: O filtrado non reversible só funciona con contexto de avisos ou Inicio\n    index:\n      delete: Eliminar\n      title: Filtros\n    new:\n      title: Engadir novo filtro\n  footer:\n    developers: Desenvolvedoras\n    more: Máis…\n    resources: Recursos\n  generic:\n    all: Todo\n    changes_saved_msg: Cambios gardados correctamente!!\n    copy: Copiar\n    order_by: Ordenar por\n    save_changes: Gardar cambios\n    validation_errors:\n      one: Algo non está ben de todo! Por favor revise abaixo o erro\n      other: Algo aínda non está ben! Por favor revise os %{count} erros abaixo\n  html_validator:\n    invalid_markup: 'contén etiquetas HTML non válidas: %{error}'\n  identity_proofs:\n    active: Activo\n    authorize: Si, autorizar\n    authorize_connection_prompt: Autorizar esta conexión criptográfica?\n    errors:\n      failed: Fallou a conexión criptográfica. Por favor inténteo de novo desde %{provider}.\n      keybase:\n        invalid_token: Os testemuños Keybase son hashes de firma e deben ter 66 caracteres hexadecimais\n        verification_failed: Keybase non recoñece este testemuño como firma da usuaria de Keybase %{kb_username}. Por favor inténteo desde Keybase.\n      wrong_user: Non se puido crear a proba para %{proving} mentras está conectada como %{current}. Conéctese como %{proving} e inténteo de novo.\n    explanation_html: Aquí pódese conectar criptográficamente as suas outras identidades, como a un perfil Keybase. Esto permitelle a outras persoas enviarlle mensaxes cifradas e confiar no contido que vostede lle envía.\n    i_am_html: Eu son %{username} en %{service}.\n    identity: Identidade\n    inactive: Inactiva\n    publicize_checkbox: 'E tootee esto:'\n    publicize_toot: 'Comprobado! Eu son %{username} en %{service}: %{url}'\n    status: Estado da validación\n    view_proof: Ver proba\n  imports:\n    modes:\n      merge: Fusionar\n      merge_long: Manter os rexistros actuais e engadir novos\n      overwrite: Sobreescribir\n      overwrite_long: Sustituír rexistros actuais cos novos\n    preface: Pode importar os datos que exportou de outro servidor, tales como a lista de usuarias que está a seguir ou bloquear.\n    success: Os seus datos foron correctamente subidos e serán procesados ao momento\n    types:\n      blocking: Lista de bloqueo\n      domain_blocking: Lista de bloqueo de dominios\n      following: Lista de seguimento\n      muting: Lista de usuarias acaladas\n    upload: Subir\n  in_memoriam_html: Lembranzas.\n  invites:\n    delete: Desactivar\n    expired: Caducou\n    expires_in:\n      '1800': 30 minutos\n      '21600': 6 horas\n      '3600': 1 hora\n      '43200': 12 horas\n      '604800': 1 semana\n      '86400': 1 día\n    expires_in_prompt: Nunca\n    generate: Xerar\n    invited_by: 'Vostede foi convidada por:'\n    max_uses:\n      one: 1 uso\n      other: \"%{count} usos\"\n    max_uses_prompt: Sen límite\n    prompt: Xerar e compartir ligazóns con outras para permitir acceso a este servidor\n    table:\n      expires_at: Caduca\n      uses: Usos\n    title: Convidar xente\n  lists:\n    errors:\n      limit: Acadou o número máximo de listas\n  media_attachments:\n    validations:\n      images_and_video: Non pode anexar un vídeo a un estado que xa contén imaxes\n      too_many: Non pode anexar máis de 4 ficheiros\n  migrations:\n    acct: nomeusuaria@dominio da nova conta\n    currently_redirecting: 'O seu perfil está listo para redirixir a:'\n    proceed: Gardar\n    updated_msg: O axuste de migración da conta actualizouse correctamente!\n  moderation:\n    title: Moderación\n  notification_mailer:\n    digest:\n      action: Ver todas as notificacións\n      body: Aquí ten un breve resumo das mensaxes publicadas desde a súa última visita en %{since}\n      mention: \"%{name} mencionouna en:\"\n      new_followers_summary:\n        one: Ademáis, ten unha nova seguidora desde entón! Ben!\n        other: Ademáis, obtivo %{count} novas seguidoras desde entón! Tremendo!\n      subject:\n        one: \"1 nova notificación desde a súa última visita \\U0001F418\"\n        other: \"%{count} novas notificacións desde a súa última visita \\U0001F418\"\n      title: Na súa ausencia...\n    favourite:\n      body: 'O seu estado foi marcado favorito por %{name}:'\n      subject: \"%{name} marcou favorito o seu estado\"\n      title: Nova favorita\n    follow:\n      body: \"%{name} agora está a seguila!\"\n      subject: \"%{name} agora está a seguila\"\n      title: Nova seguidora\n    follow_request:\n      action: Xestionar peticións de seguimento\n      body: \"%{name} solicitou poder seguila\"\n      subject: 'Seguidora pendente: %{name}'\n      title: Nova petición de seguimento\n    mention:\n      action: Respostar\n      body: 'Foi mencionada por %{name} en:'\n      subject: Vostede foi mencionada por %{name}\n      title: Nova mención\n    reblog:\n      body: 'O seu estado foi promocionado por %{name}:'\n      subject: \"%{name} promoveu o seu estado\"\n      title: Nova promoción\n  number:\n    human:\n      decimal_units:\n        format: \"%n%u\"\n        units:\n          billion: B\n          million: M\n          quadrillion: Q\n          thousand: K\n          trillion: T\n  pagination:\n    newer: Máis novo\n    next: Seguinte\n    older: Máis antigo\n    prev: Previo\n    truncate: \"&hellip;\"\n  polls:\n    errors:\n      already_voted: Xa votou en esta sondaxe\n      duplicate_options: contén elementos duplicados\n      duration_too_long: está moi lonxe no futuro\n      duration_too_short: é demasiado cedo\n      expired: A sondaxe rematou\n      over_character_limit: non poden ter máis de %{max} caracteres cada unha\n      too_few_options: debe ter máis de unha opción\n      too_many_options: non pode haber máis de %{max} opcións\n  preferences:\n    other: Outro\n    posting_defaults: Valores por omisión\n    public_timelines: Liñas temporais públicas\n  relationships:\n    activity: Actividade da conta\n    dormant: En repouso\n    last_active: Último activo\n    most_recent: Máis recente\n    moved: Movida\n    mutual: Mutuo\n    primary: Principal\n    relationship: Relación\n    remove_selected_domains: Eliminar todas as seguidoras dos dominios escollidos\n    remove_selected_followers: Eliminar as seguidoras escollidas\n    remove_selected_follows: Deixar de seguir as usuarias escollidas\n    status: Estado da conta\n  remote_follow:\n    acct: Introduza o seu usuaria@servidor desde onde quere interactuar\n    missing_resource: Non se puido atopar o URL de redirecionamento requerido para a súa conta\n    no_account_html: Non ten unha conta? Pode <a href='%{sign_up_path}' target='_blank'>rexistrarse aquí</a>\n    proceed: Proceda para seguir\n    prompt: 'Vostede vai seguir:'\n    reason_html: \"<strong>Por que é necesario este paso?</strong><code>%{instance}</code> podería non ser o servidor onde se rexistrou, así que precisamo redirixila primeiro ao seu servidor de orixe.\"\n  remote_interaction:\n    favourite:\n      proceed: Darlle a favorito\n      prompt: 'Vostede quere favorecer este toot:'\n    reblog:\n      proceed: Darlle a promocionar\n      prompt: 'Vostede quere promocionar este toot:'\n    reply:\n      proceed: Respostar\n      prompt: 'Vostede quere respostar a este toot:'\n  remote_unfollow:\n    error: Fallo\n    title: Título\n    unfollowed: Deixou de seguir\n  scheduled_statuses:\n    over_daily_limit: Excedeu o límite de %{limit} toots programados para ese día\n    over_total_limit: Excedeu o límite de %{limit} toots programados\n    too_soon: A data de programación debe estar no futuro\n  sessions:\n    activity: Última actividade\n    browser: Navegador\n    browsers:\n      alipay: Alipay\n      blackberry: Blackberry\n      chrome: Chrome\n      edge: Microsoft Edge\n      electron: Electron\n      firefox: Firefox\n      generic: Navegador descoñecido\n      ie: Internet Explorer\n      micro_messenger: MicroMessenger\n      nokia: Navegador Nokia S40 Ovi\n      opera: Opera\n      otter: Otter\n      phantom_js: PhantomJS\n      qq: Navegador QQ\n      safari: Safari\n      uc_browser: UCBrowser\n      weibo: Weibo\n    current_session: Sesión actual\n    description: \"%{browser} en %{platform}\"\n    explanation: Estos son os navegadores web nos que actualmente ten sesión aberta.\n    ip: IP\n    platforms:\n      adobe_air: Adobe Air\n      android: Android\n      blackberry: Blackberry\n      chrome_os: ChromeOS\n      firefox_os: Firefox OS\n      ios: iOS\n      linux: Linux\n      mac: Mac\n      other: plataforma descoñecida\n      windows: Windows\n      windows_mobile: Windows Mobile\n      windows_phone: Windows Phone\n    revoke: Revocar\n    revoke_success: A sesión revocouse con éxito\n    title: Sesións\n  settings:\n    account: Conta\n    account_settings: Axustes da conta\n    appearance: Aparencia\n    authorized_apps: Apps autorizadas\n    back: Voltar a Mastodon\n    delete: Eliminación da conta\n    development: Desenvolvemento\n    edit_profile: Editar perfil\n    export: Exportar datos\n    featured_tags: Etiquetas destacadas\n    identity_proofs: Probas de identidade\n    import: Importar\n    import_and_export: Importar e exportar\n    migrate: Migrar conta\n    notifications: Notificacións\n    preferences: Preferencias\n    profile: Perfil\n    relationships: Seguindo e seguidoras\n    two_factor_authentication: Validar Doble Factor\n  statuses:\n    attached:\n      description: 'Axenado: %{attached}'\n      image:\n        one: \"%{count} imaxe\"\n        other: \"%{count} imaxes\"\n      video:\n        one: \"%{count}  vídeo\"\n        other: \"%{count} vídeos\"\n    boosted_from_html: Promovida desde %{acct_link}\n    content_warning: 'Aviso sobre o contido: %{warning}'\n    disallowed_hashtags:\n      one: 'contiña unha etiqueta non permitida: %{tags}'\n      other: 'contiña etiquetas non permitidas: %{tags}'\n    language_detection: Detección automática do idioma\n    open_in_web: Abrir na web\n    over_character_limit: Excedeu o límite de caracteres %{max}\n    pin_errors:\n      limit: Xa fixou o número máximo permitido de mensaxes\n      ownership: Non pode fixar a mensaxe de outra usuaria\n      private: As mensaxes non-públicas non poden ser fixadas\n      reblog: Non se poden fixar as mensaxes promovidas\n    poll:\n      total_votes:\n        one: \"%{count} voto\"\n        other: \"%{count} votos\"\n      vote: Votar\n    show_more: Mostrar máis\n    sign_in_to_participate: Conéctese para participar na conversa\n    title: '%{name}: \"%{quote}\"'\n    visibilities:\n      private: Só seguidoras\n      private_long: Mostrar só as seguidoras\n      public: Público\n      public_long: Visible para calquera\n      unlisted: Non listado\n      unlisted_long: Visible para calquera, pero non listado en liñas de tempo públicas\n  stream_entries:\n    pinned: Mensaxe fixada\n    reblogged: promovida\n    sensitive_content: Contido sensible\n  terms:\n    body_html: |\n      <h2>Intimidade</h2>\n      <h3 id=\"collect\">Qué información recollemos?</h3>\n\n      <ul>\n      <li><em>Información básica da conta</em>: Si se rexistra en este servidor, pediráselle un nome de usuaria, un enderezo de correo electrónico e un contrasinal. De xeito adicional tamén poderá introducir información como un nome público e biografía, tamén subir unha fotografía de perfil e unha imaxe para a cabeceira. O nome de usuaria, o nome público, a biografía e as imaxes de perfil e cabeceira sempre se mostran publicamente.</li>\n      <li><em>Publicacións, seguimento e outra información pública</em>: O listado das persoas que segue é un listado público, o mesmo acontece coas súas seguidoras. Cando evía unha mensaxe, a data e hora gárdanse así como o aplicativo que utilizou para enviar a mensaxe. As publicacións poderían conter ficheiros de medios anexos, como fotografías e vídeos. As publicacións públicas e as non listadas están dispoñibles de xeito público. Cando destaca unha publicación no seu perfil tamén é pública. As publicacións son enviadas as súas seguidoras, en algúns casos pode acontecer que estén en diferentes servidores e gárdanse copias neles. Cando elemina unha publicación tamén se envía as súas seguidoras. A acción de voltar a publicar ou marcar como favorita outra publicación sempre é pública.</li>\n      <li><em>Mensaxes directas e só para seguidoras</em>: Todas as mensaxes gárdanse e procésanse no servidor. As mensaxes só para seguidoras son entregadas as súas seguidoras e as usuarias que son mencionadas en elas, e as mensaxes directas entréganse só as usuarias mencionadas en elas. En algúns casos esto implica que son entregadas a diferentes servidores e gárdanse copias alí. Facemos un esforzo sincero para limitar o acceso a esas publicacións só as persoas autorizadas, pero outros servidores poderían non ser tan escrupulosos. Polo tanto, é importante revisar os servidores onde se hospedan as súas seguidoras. Nos axustes pode activar a opción de aprovar ou rexeitar novas seguidoras de xeito manual.  <em>Teña en conta que a administración do servidor e todos os outros servidores implicados poden ver as mensaxes.</em>, e as destinatarias poderían facer capturas de pantalla, copiar e voltar a compartir as mensaxes. <em>Non comparta información comprometida en Mastodon.</em></li>\n      <li><em>IPs e outros metadatos</em>: Cando se conecta, gravamos o IP desde onde se conecta, así como o nome do aplicativo desde onde o fai. Todas as sesións conectadas están dispoñibles para revisar e revogar nos axustes. O último enderezo IP utilizado gárdase ate por 12 meses. Tamén poderiamos gardar informes do servidor que inclúan o enderezo IP de cada petición ao servidor.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"use\">De qué xeito utilizamos os seus datos?</h3>\n\n      <p>Toda a información que recollemos podería ser utilizada dos seguintes xeitos:</p>\n\n      <ul>\n      <li>Para proporcionar a funcionabiliade básica de Mastodon. Só pode interactuar co contido de outra xente e publicar o seu propio contido si está conectada. Por exemplo, podería seguir outra xente e ver as súas publicacións combinadas nunha liña temporal inicial persoalizada.</li>\n      <li>Para axudar a moderar a comunidade, por exemplo comparando o seu enderezo IP con outros coñecidos para evitar esquivar os rexeitamentos ou outras infraccións.</li>\n      <li>O endero de correo electrónico que nos proporciona podería ser utilizado para enviarlle información, notificacións sobre outra xente que interactúa cos seus contidos ou lle envía mensaxes, e para respostar a consultas, e/ou outras cuestións ou peticións.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"protect\">Cómo proxetemos os seus datos?</h3>\n\n      <p>Implementamos varias medidas de seguridade para protexer os seus datos personais cando introduce, envía ou accede a súa información persoal. Entre outras medidas, a súa sesión de navegación, así como o tráfico entre os seus aplicativos e o API están aseguradas mediante SSL, e o seu contrasinal está camuflado utilizando un algoritmo potente de unha sóa vía. Pode habilitar a autenticación de doble factor para protexer o acceso a súa conta aínda máis.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"data-retention\">Cal é a nosa política de retención de datos?</h3>\n\n      <p>Faremos un sincero esforzo en:</p>\n\n      <ul>\n      <li>Protexer informes do servidor que conteñan direccións IP das peticións ao servidor, ate a data estos informes gárdanse por non máis de 90 días.</li>\n      <li>Reter os enderezos IP asociados con usuarias rexistradas non máis de 12 meses.</li>\n      </ul>\n\n      <p>Pode solicitar e descargar un ficheiro cos seus contidos, incluíndo publicacións, anexos de medios, imaxes de perfil e imaxe da cabeceira.</p>\n\n      <p>En calquer momento pode eliminar de xeito irreversible a súa conta.</p>\n\n      <hr class=\"spacer\"/>\n\n      <h3 id=\"cookies\">Utilizamos testemuños?</h3>\n\n      <p>Si. Os testemuños son pequenos ficheiros que un sitio web ou o provedor de servizo transfiren ao disco duro da súa computadora a través do navegador web (si vostede o permite). Estos testemuños posibilitan ao sitio web recoñecer o seu navegador e, si ten unha conta rexistrada, asocialo con dita conta.</p>\n\n      <p>Utilizamos testemuños para comprender e gardar as súas preferencias para futuras visitas.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"disclose\">Entregamos algunha información a terceiras alleas?</h3>\n\n      <p>Non vendemos, negociamos ou transferimos de algún xeito a terceiras partes alleas a súa información identificativa persoal. Esto non inclúe terceiras partes de confianza que nos axudan a operar o sitio web, a xestionar a empresa, ou darlle servizo si esas partes aceptan manter esa información baixo confidencialidade. Poderiamos liberar esa información si cremos que eso da cumplimento axeitado a lei, reforza as políticas do noso sitio ou protexe os nosos, e de outros, dereitos, propiedade ou seguridade.</p>\n\n      <p>O seu contido público podería ser descargado por outros servidores na rede. As súas publicacións públicas e para só seguidoras son entregadas aos servidores onde residen as súas seguidoras na rede, e as mensaxes directas son entregadas aos servidores das destinatarias sempre que esas seguidoras ou destinatarios residan en servidores distintos de este.</p>\n\n      <p>Cado autoriza a este aplicativo a utilizar a súa conta, dependendo da amplitude dos permisos que autorice, podería acceder a información pública de perfil, ao listado de seguimento, as súas seguidoras, os seus listados, todas as súas publicacións, as publicacións favoritas. Os aplicativos non poden nunca acceder ao seu enderezo de correo nin ao seu contrasinal.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"children\">Utilización do sitio web por menores</h3>\n\n      <p>Si este servidor está na UE ou no EEE: a nosa web, productos e servizos están dirixidos a persoas de 16 ou máis anos. Si ten menos de 16 anos, a requerimento da GDPR (<a href=\"https://en.wikipedia.org/wiki/General_Data_Protection_Regulation\">General Data Protection Regulation</a>) non utilice esta web.</p>\n\n      <p>Si este servidor está nos EEUU: a nosa web, productos e servizos están dirixidos a persoas de 13 ou máis anos. Si non ten 13 anos de idade, a requerimento de COPPA (<a href=\"https://en.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act\">Children's Online Privacy Protection Act</a>) non utilice esta web.</p>\n\n      <p>Os requerimentos legais poden ser diferentes si este servidor está baixo outra xurisdición.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"changes\">Cambios na nosa política de intimidade</h3>\n\n      <p>Si decidimos cambiar a nosa política de intimidade publicaremos os cambios en esta páxina.</p>\n\n      <p>Este documento ten licenza CC-BY-SA. Actualizouse o 7 de Marzo de 2018.</p>\n\n      <p>Adaptado do orixinal <a href=\"https://github.com/discourse/discourse\">Discourse privacy policy</a>.</p>\n    title: \"%{instance} Termos do Servizo e Política de Intimidade\"\n  themes:\n    contrast: Mastodon (Alto contraste)\n    default: Mastodon (Escuro)\n    mastodon-light: Mastodon (Claro)\n  time:\n    formats:\n      default: \"%d %b, %Y, %H:%M\"\n      month: \"%b %Y\"\n  two_factor_authentication:\n    code_hint: Introducir o código xerado polo seu aplicativo de autenticación para confirmar\n    description_html: Si habilita a <strong>autenticación de doble factor</strong>, a conexión pediralle estar en posesión do seu teléfono, que xerará testemuños para poder entrar.\n    disable: Deshabilitar\n    enable: Habilitar\n    enabled: A autenticación de doble-factor está habilitada\n    enabled_success: Habilitouse con éxito a autenticación de doble-factor\n    generate_recovery_codes: Xerar códigos de recuperación\n    instructions_html: \"<strong>Escanee este código QR en Google Authenticator ou aplicativo TOTP similar no seu teléfono</strong>. Desde agora, este aplicativo xerará testemuños que vostede deberá introducir ao conectarse.\"\n    lost_recovery_codes: Os códigos de recuperación permítenlle recuperar o acceso a súa conta si perde o teléfono. Si perde os códigos de recuperación, pode restauralos aquí. Os seus códigos de recuperación anteriores serán invalidados.\n    manual_instructions: 'Si non pode escanear o código QR e precisa introducilo manualmente, aquí está o testemuño secreto en texto plano:'\n    recovery_codes: Códigos de recuperación do respaldo\n    recovery_codes_regenerated: Códigos de recuperación xerados correctamente\n    recovery_instructions_html: Si perdese o acceso ao seu teléfono, pode utilizar un dos códigos inferiores de recuperación para recuperar o acceso a súa conta. <strong>Garde os códigos en lugar seguro</strong>. Por exemplo, pode imprimilos e gardalos xunto con outros documentos importantes.\n    setup: Configurar\n    wrong_code: O código introducido non é válido! Son correctas as horas no dispositivo e o servidor?\n  user_mailer:\n    backup_ready:\n      explanation: Solicitou un respaldo completo da súa conta de Mastodon. Xa está listo para descargar!\n      subject: O seu ficheiro xa está listo para descargar\n      title: Leve o ficheiro\n    warning:\n      explanation:\n        disable: Cando a súa conta está conxelada, os datos permanecen intactos, pero non pode levar a fin accións ate que se desbloquea.\n        silence: Mentras a conta está limitada, só a xente que actualmente a segue verá os seus toots en este servidor, e vostede podería estar excluída de varias listas públicas. Porén, outras persoas poderíana seguila de xeito manual.\n        suspend: A súa conta foi suspendida, e todos os seus toots e medios subidos foron eliminados de este servidor de xeito irreversible, e dos servidores onde tivese seguidoras.\n      review_server_policies: Revisar políticas do servidor\n      subject:\n        disable: A súa conta %{acct} foi conxelada\n        none: Aviso para %{acct}\n        silence: A súa conta %{acct} foi limitada\n        suspend: A súa conta %{acct} foi suspendida\n      title:\n        disable: Conta conxelada\n        none: Aviso\n        silence: Conta limitada\n        suspend: Conta suspendida\n    welcome:\n      edit_profile_action: Configurar perfil\n      edit_profile_step: Vostede pode persoalizar o seu perfil subindo un avatar, cabeceira, cambiar o seu nome público e aínda máis. Si restrinxe a súa conta pode revisar a conta das personas que solicitan seguilas antes de permitirlles o acceso aos seus toots.\n      explanation: Aquí ten alunhas endereitas para ir aprendendo\n      final_action: Comece a publicar\n      final_step: 'Publique! Incluso sin seguidoras as súas mensaxes serán vistas por outras, por exemplo na liña temporal local e nas etiquetas. Podería presentarse no #fediverso utilizando a etiqueta #introductions.'\n      full_handle: O seu alcume completo\n      full_handle_hint: Esto é o que lle dirá aos seus amigos para que poidan seguila ou enviarlle mensaxes desde outro servidor.\n      review_preferences_action: Cambiar preferencias\n      review_preferences_step: Lembre establecer as preferencias, tales como qué correos-e lle querería recibir, ou o nivel de intimidade por omisión para as súas mensaxes. Se non lle molestan as imaxes con movemento, pode escoller que os GIF se reproduzan automáticamente.\n      subject: Benvida a Mastodon\n      tip_federated_timeline: A liña temporal federada é unha visión ampla da rede Mastodon. Pero so inclúe xente a que segue xente que vostede segue, así que non é completa.\n      tip_following: Por omisión vostede segue ao Admin do seu servidor. Para atopar máis xente interesante, mire nas liñas temporais local e federada.\n      tip_local_timeline: A liña temporal local é unha ollada xeral sobre a xente en %{instance}. Son as súas veciñas máis próximas!\n      tip_mobile_webapp: Si o navegador móbil lle ofrece engadir Mastodon a pantalla de inicio, pode recibir notificacións push. En moitos aspectos comportarase como un aplicativo nativo!\n      tips: Consellos\n      title: Benvida, %{name}!\n  users:\n    follow_limit_reached: Non pode seguir a máis de %{limit} persoas\n    invalid_email: O enderezo de correo non é válido\n    invalid_otp_token: Código de doble-factor non válido\n    otp_lost_help_html: Si perde o acceso a ambos, pode contactar con %{email}\n    seamless_external_login: Está conectado a través de un servizo externo, polo que os axustes de contrasinal e correo-e non están dispoñibles.\n    signed_in_as: 'Rexistrada como:'\n  verification:\n    explanation_html: 'Pode <strong>validarse a vostede mesma como a dona das ligazóns nos metadatos do seu perfil</strong>. Para esto, o sitio web ligado debe conter unha ligazón de retorno ao perfil de Mastodon. Esta ligazón de retorno <strong>ten que</strong> ter un atributo <code>rel=\"me\"</code>. O texto da ligazón non importa. Aquí ten un exemplo:'\n    verification: Validación\n"
  },
  {
    "path": "config/locales/he.yml",
    "content": "---\nhe:\n  about:\n    about_hashtag_html: אלו סטטוסים פומביים המתוייגים בתור<strong>#%{hashtag}</strong>. ניתן להגיב, להדהד או לחבב אותם אם יש לך חשבון בכל מקום בפדרציה.\n    about_mastodon_html: מסטודון היא רשת חברתית <em>חופשית, מבוססת תוכנה חופשית (\"קוד פתוח\")</em>. כאלטרנטיבה <em>בלתי ריכוזית</em> לפלטפרומות המסחריות, מסטודון מאפשרת להמנע מהסיכונים הנלווים להפקדת התקשורת שלך בידי חברה יחידה. שמת את מבטחך בשרת אחד &mdash; לא משנה במי בחרת, תמיד אפשר לדבר עם כל שאר המשתמשים. לכל מי שרוצה יש את האפשרות להקים שרת מסטודון עצמאי, ולהשתתף ב<em>רשת החברתית</em> באופן חלק.\n    about_this: אודות שרת זה\n    apps: יישומונים לנייד\n    contact: יצירת קשר\n    contact_missing: ללא הגדרה\n    contact_unavailable: לא רלוונטי/חסר\n    documentation: תיעוד\n    extended_description_html: |\n      <h3>מקום טוב לכללים</h3>\n      <p>התיאור המורחב טרם הוגדר.</p>\n    generic_description: \"%{domain} הוא שרת אחד בתוך הרשת\"\n    hosted_on: מסטודון שיושב בכתובת %{domain}\n    learn_more: מידע נוסף\n    source_code: קוד מקור\n    status_count_before: שכתבו\n    user_count_before: ביתם של\n    what_is_mastodon: מה זה מסטודון?\n  accounts:\n    follow: לעקוב\n    following: נעקבים\n    media: מדיה\n    moved_html: \"%{name} עבר(ה) אל %{new_profile_link}:\"\n    nothing_here: אין פה שום דבר!\n    people_followed_by: הנעקבים של %{name}\n    people_who_follow: העוקבים של %{name}\n    posts_with_replies: חצרוצים ותגובות\n    reserved_username: שם המשתמש שמור\n    roles:\n      admin: מנהל\n      moderator: מנחה\n    unfollow: הפסקת מעקב\n  admin:\n    account_moderation_notes:\n      create: ליצור\n      created_msg: הודעת מנחה נוצרה בהצלחה!\n      delete: למחוק\n      destroyed_msg: הודעת מנחה נמחקה בהצלחה!\n    accounts:\n      are_you_sure: בטוח?\n      by_domain: שם מתחם\n      confirm: אישור\n      confirmed: אושר\n      confirming: המאשר\n      demote: הורדה בדרגה\n      disable: לחסום\n      disable_two_factor_authentication: ביטול הזדהות דו-שלבית\n      disabled: נחסם\n      display_name: שם לתצוגה\n      domain: תחום\n      edit: עריכה\n      email: דוא\"ל\n      email_status: סטטוס דוא\"ל\n      enable: לאפשר\n      enabled: מאופשר\n      feed_url: כתובת פיד\n      followers: עוקבים\n      followers_url: כתובת עוקבים\n      follows: נעקבים\n      inbox_url: כתובת תיבה נכנסת\n      ip: כתובת IP\n      location:\n        all: הכל\n        local: מקומי\n        remote: מרחוק\n        title: מיקום\n      login_status: מצב חיבור\n      media_attachments: תוספות מדיה\n      memorialize: הפוך לדף זכרון\n      moderation:\n        all: הכל\n        silenced: מושתקים\n        suspended: מושהים\n        title: ניהול קהילה\n      moderation_notes: הודעות מנחה\n      most_recent_activity: פעילות עדכנית\n      most_recent_ip: כתובות אחרונות\n      not_subscribed: לא רשום\n      outbox_url: כתובת תיבת דואר יוצא\n      perform_full_suspension: ביצוע השעייה מלאה\n      profile_url: כתובת פרופיל\n      promote: להעלות בדרגה\n      protocol: פרטיכל\n      public: פומבי\n      push_subscription_expires: הרשמה להודעות בדחיפה פגה\n      redownload: לקריאה מחדש של האווטאר\n      resend_confirmation:\n        already_confirmed: משתמש זה כבר אושר\n        send: שלח מחדש דוא\"ל אימות\n        success: הודעת האימייל נשלחה בהצלחה!\n      reset: איפוס\n      reset_password: אתחול סיסמא\n      resubscribe: להרשם מחדש\n      role: הרשאות\n      roles:\n        admin: מנהל מערכת\n        moderator: מנחה דיונים\n        user: משתמש(ת)\n      salmon_url: כתובת סלמון\n      search: חיפוש\n      shared_inbox_url: תיבה משותפת לדואר נכנס\n      show:\n        created_reports: דיווחים מאת חשבון זה\n        targeted_reports: דיווחים נגד חשבון זה\n      silence: השתקה\n      statuses: הודעות\n      subscribe: הרשמה\n      title: חשבונות\n      undo_silenced: ביטול השתקה\n      undo_suspension: ביטול השעייה\n      unsubscribe: הפסקת הרשמה\n      username: שם משתמש\n      web: רשת\n    action_logs:\n      actions:\n        confirm_user: יש אישור מאת %{name} על כתובת הדוא\"ל של %{target}\n        create_custom_emoji: \"%{name} תרמה/תרם אמוג'י חדש %{target}\"\n        create_domain_block: \"%{name} חסמה/חסם את שם המתחם %{target}\"\n        create_email_domain_block: מתחם דוא\"ל %{target} הוסף לרשימה השחורה ע\"י %{name}\n        demote_user: '%{name} הורד(ה) בדרגה ע\"י %{target}'\n        destroy_domain_block: החסימה על מתחם %{target} הוסרה ע\"י %{name}\n        destroy_email_domain_block: מתחם דוא\"ל %{target} הוכנס לרשימה הלבנה ע\"י %{name}\n        destroy_status: ההודעה של  %{target} הוסרה ע\"י %{name}\n        disable_2fa_user: אימות דו שלבי של  %{target} הוסר ע\"י %{name}\n    domain_blocks:\n      add_new: הוספת חדש\n      created_msg: חסימת שרת בתהליך\n      destroyed_msg: חסימת שרת בוטלה\n      domain: שרת\n      new:\n        create: יצירת חסימה\n        hint: חסימת השרת לא תמנע יצירת רישומי חשבון במסד הנתונים, אבל תבצע פעולות ניהול קהילה מסוימות על חשבונות אלו אוטומטית ורטרואקטיבית.\n        severity:\n          desc_html: \"<strong>השתקה</strong> תחביא הודעות מחשבון זה לכל מי שלא עוקב אחריו. <strong>השעייה</strong> תסיר מהשרת את כל התוכן, מדיה ותכונות הפרופיל שמקושרות לחשבון זה. <strong>כלום</strong> כדי לחסום קבצי מדיה בלבד.\"\n          silence: השתקה\n          suspend: השעייה\n        title: חסימת שרת חדשה\n      reject_media: חסימת קבצי מדיה\n      reject_media_hint: מסירה קבצי מדיה השמורים מקומית ומונעת מהורדת קבצים נוספים בעתיד. לא רלוונטי להשעיות\n      show:\n        retroactive:\n          silence: הסרת השתקה מכל החשבונות על שרת זה\n          suspend: הסרת השעייה מכל החשבונות על שרת זה\n        title: ביטול חסימת שרת עבור %{domain}\n        undo: ביטול\n      undo: ביטול\n    instances:\n      title: שרתים מוכרים\n    reports:\n      are_you_sure: 100% על בטוח?\n      comment:\n        none: ללא\n      mark_as_resolved: סימון כפתור\n      report: 'דווח על #%{id}'\n      reported_account: חשבון מדווח\n      reported_by: דווח על ידי\n      resolved: פתור\n      status: הודעה\n      title: דיווחים\n      unresolved: לא פתור\n    settings:\n      contact_information:\n        email: נא להקליד כתובת דוא\"ל פומבית\n        username: נא להכניס שם משתמש\n      registrations:\n        closed_message:\n          desc_html: מוצג על הדף הראשי כאשר ההרשמות סגורות<br>ניתן להשתמש בתגיות HTML\n          title: מסר סגירת הרשמות\n      site_description:\n        desc_html: מוצג כפסקה על הדף הראשי ומשמש כתגית מטא. ניתן להשתמש בתגיות HTML, ובמיוחד ב־<code> &lt; a&gt; </code> ו־<code> &lt; em&gt; </code> .\n        title: תיאור האתר\n      site_description_extended:\n        desc_html: מוצג על עמוד המידע הנוסף<br>ניתן להשתמש בתגיות HTML\n        title: תיאור אתר מורחב\n      site_title: כותרת האתר\n      title: הגדרות אתר\n    subscriptions:\n      callback_url: קישורית Callback\n      confirmed: מאושר\n      expires_in: פג תוקף ב-\n      last_delivery: משלוח אחרון\n      title: מנוי WebSub\n      topic: נושא\n    title: ניהול\n  application_mailer:\n    settings: 'שינוי הגדרות דוא\"ל: %{link}'\n    view: 'תצוגה:'\n  applications:\n    invalid_url: כתובת הקישורית אינה חוקית\n  auth:\n    didnt_get_confirmation: לא התקבלו הוראות אימות?\n    forgot_password: הנשתכחה סיסמתך?\n    login: כניסה\n    logout: יציאה\n    register: הרשמה\n    resend_confirmation: שלח הוראות אימות בשנית\n    reset_password: איפוס סיסמא\n    security: החלפת סיסמא\n    set_new_password: שינוי סיסמא\n  authorize_follow:\n    error: למרבה הצער, היתה שגיאה בחיפוש החשבון המרוחק\n    follow: לעקוב\n    title: לעקוב אחרי %{acct}\n  datetime:\n    distance_in_words:\n      about_x_hours: \"%{count} שעות\"\n      about_x_months: \"%{count} חודשים\"\n      about_x_years: \"%{count} שנים\"\n      almost_x_years: \"%{count} שנים\"\n      half_a_minute: ממש הרגע\n      less_than_x_minutes: \"%{count} דקות\"\n      less_than_x_seconds: ממש עכשיו\n      over_x_years: \"%{count} שנים\"\n      x_days: \"%{count} ימים\"\n      x_minutes: \"%{count} דקות\"\n      x_months: \"%{count} חודשים\"\n      x_seconds: \"%{count} שניות\"\n  errors:\n    '403': חסרות לך הרשאות לצפיה בעמוד זה.\n    '404': הדף המבוקש לא קיים.\n    '410': הדף המבוקש כבר לא קיים.\n    '422':\n      content: בדיקת אבטחה נכשלה. החסמת עוגיותיך מפנינו?\n      title: בדיקת בטיחות נכשלה\n    '429': הוחנק\n    '500': \n  exports:\n    blocks: רשימת חסימות\n    follows: רשימת נעקבים\n    mutes: רשימת השתקות\n    storage: אחסון מדיה\n  generic:\n    changes_saved_msg: השינויים נשמרו בהצלחה!\n    save_changes: שמור שינויים\n  imports:\n    preface: ניתן ליבא מידע מסויים כגון כל הנעקבים או המשתמשים החסומים לתוך חשבונך על שרת זה, מתוך קבצים שנוצרו על ידי יצוא משרת אחר כגון רשימת הנעקבים והחסומים שלך.\n    success: כל המידע יובא בהצלחה, ויעובד בזמן הקרוב\n    types:\n      blocking: רשימת חסימות\n      following: רשימת נעקבים\n      muting: רשימת השתקות\n    upload: יבוא\n  invites:\n    expires_in:\n      '1800': 30 minutes\n      '21600': 6 hours\n      '3600': 1 hour\n      '43200': 12 hours\n      '604800': 1 week\n      '86400': 1 day\n  media_attachments:\n    validations:\n      images_and_video: לא ניתן להוסיף וידאו לחצרוץ שכבר מכיל תמונות\n      too_many: לא ניתן להוסיף יותר מארבעה קבצים\n  notification_mailer:\n    digest:\n      body: להלן סיכום זריז של הדברים שקרו על מאז ביקורך האחרון ב-%{since}\n      mention: \"%{name} פנה אליך ב:\"\n    favourite:\n      body: 'חצרוצך חובב על ידי %{name}:'\n      subject: חצרוצך חובב על ידי %{name}\n    follow:\n      body: \"%{name} עכשיו במעקב אחריך!\"\n      subject: \"%{name} עכשיו במעקב אחריך\"\n    follow_request:\n      body: התקבלה בקשת מעקב מ־%{name}\n      subject: 'בקשת מעקב בהמתנה: %{name}'\n    mention:\n      body: 'התקבלה פניה עבורך מאת %{name} ב:'\n      subject: התקבלה פניה עבורך מאת %{name}\n    reblog:\n      body: 'חצרוצך הודהד על ידי %{name}:'\n      subject: חצרוצך הודהד על ידי%{name}\n  pagination:\n    next: הבא\n    prev: הקודם\n  remote_follow:\n    acct: נא להקליד שם_משתמש@קהילה מהם ברצונך לעקוב\n    missing_resource: לא ניתן למצוא קישורית להפניה לחשבונך\n    proceed: להמשיך ולעקוב\n    prompt: 'לעקוב אחרי:'\n  settings:\n    authorized_apps: ישומים מאושרים\n    back: חזרה למסטודון\n    edit_profile: עריכת פרופיל\n    export: יצוא מידע\n    import: יבוא\n    preferences: העדפות\n    two_factor_authentication: אימות דו-שלבי\n  statuses:\n    open_in_web: פתח ברשת\n    over_character_limit: חריגה מגבול התווים של %{max}\n    show_more: עוד\n    visibilities:\n      private: לעוקבים בלבד\n      private_long: להצגה לעוקבים בלבד\n      public: פומבי\n      public_long: כולם יוכלו לקרוא\n      unlisted: מוסתר\n      unlisted_long: פומבי, אבל לא להצגה בפיד הציבורי\n  stream_entries:\n    reblogged: הודהד\n    sensitive_content: תוכן רגיש\n  time:\n    formats:\n      default: \"%d %b %Y, %H:%M\"\n  two_factor_authentication:\n    code_hint: לאישור, יש להקליד את הקוד שיוצר על ידי ישום האימות\n    description_html: לאחר הפעלת <strong>אימות דו-שלבי</strong>, ניתן יהיה להכנס רק כל עוד ברשותך טלפון, שייצר עבורך קודים שיאפשרו כניסה.\n    disable: כיבוי\n    enable: הפעלה\n    enabled_success: אימות דו-שלבי הופעל בהצלחה\n    generate_recovery_codes: ייצור קודי אחזור\n    instructions_html: \"<strong>יש לסרוק קוד QR זה בעזרת Google Authenticator או ישום TOTP דומה על טלפונך</strong>. מעתה ואילך, ישום זה יוכל ליצר קודים לשימוש לצורך כניסה.\"\n    lost_recovery_codes: קודי האחזור מאפשרים אחזור גישה לחשבון במידה ומכשירך אבד. במידה וקודי האחזור אבדו, ניתן לייצרם מחדש כאן. תוקף קודי האחזור הישנים יפוג.\n    manual_instructions: 'במידה ולא ניתן לסרוק את קוד ה-QR אלא יש צורך להקליד אותו ידנית, להלן סוד כמוס בלתי מוצפן:'\n    recovery_codes_regenerated: קודי האחזור יוצרו בהצלחה\n    recovery_instructions_html: במידה והגישה למכשירך תאבד, ניתן לייצר קודי אחזור למטה על מנת לאחזר גישה לחשבונך בכל עת. <strong>נא לשמור על קודי הגישה במקום בטוח</strong>. לדוגמא על ידי הדפסתם ושמירתם עם מסמכים חשובים אחרים, או שימוש בתוכנה ייעודית לניהול סיסמאות וסודות.\n    setup: הכנה\n    wrong_code: הקוד שהוזן שגוי! האם הזמן בשרת והזמן במכשירך נכונים?\n  users:\n    invalid_email: כתובת הדוא\"ל אינה חוקית\n    invalid_otp_token: קוד דו-שלבי שגוי\n"
  },
  {
    "path": "config/locales/hi.yml",
    "content": "{}\n"
  },
  {
    "path": "config/locales/hr.yml",
    "content": "---\nhr:\n  about:\n    about_mastodon_html: Mastodon je <em>besplatna, open-source</em> socijalna mreža. <em>Decentralizirana</em> alternativa komercijalnim platformama, izbjegava rizik toga da jedna tvrtka monopolizira vašu komunikaciju. Izaberite server kojem ćete vjerovati &mdash; koji god odabrali, moći ćete komunicirati sa svima ostalima. Bilo tko može imati svoju vlastitu Mastodon instancu i sudjelovati u <em>socijalnoj mreži</em> bez problema.\n    about_this: O ovoj instanci\n    contact: Kontakt\n    source_code: Izvorni kod\n    status_count_before: Tko je autor\n  accounts:\n    follow: Slijedi\n    following: Slijedim\n    nothing_here: Ovdje nema ničeg!\n    people_followed_by: Ljudi koje %{name} slijedi\n    people_who_follow: Ljudi koji slijede %{name}\n    unfollow: Prestani slijediti\n  application_mailer:\n    settings: 'Promijeni e-mail postavke: %{link}'\n    view: 'Vidi:'\n  applications:\n    invalid_url: Uneseni link nije valjan\n  auth:\n    didnt_get_confirmation: Niste primili instrukcije za potvrđivanje?\n    forgot_password: Zaboravljena lozinka?\n    login: Prijavi se\n    logout: Odjavi se\n    register: Registriraj se\n    resend_confirmation: Ponovo pošalji instrukcije za potvrđivanje\n    reset_password: Resetiraj lozinku\n    security: Vjerodajnica\n    set_new_password: Postavi novu lozinku\n  authorize_follow:\n    error: Nažalost, došlo je do greške looking up the remote račun\n    follow: Slijedi\n    title: Slijedi %{acct}\n  datetime:\n    distance_in_words:\n      about_x_hours: \"%{count}s\"\n      about_x_months: \"%{count}mj\"\n      about_x_years: \"%{count}g\"\n      almost_x_years: \"%{count}g\"\n      half_a_minute: upravo\n      less_than_x_seconds: upravo\n      over_x_years: \"%{count}g\"\n      x_months: \"%{count}mj\"\n      x_seconds: \"%{count}sek\"\n  errors:\n    '403': You don't have permission to view this page.\n    '404': The page you are looking for isn't here.\n    '410': The page you were looking for doesn't exist here anymore.\n    '422': \n    '429': Throttled\n    '500': \n  exports:\n    blocks: Blokirao si\n    follows: Slijediš\n    storage: Pohrana media zapisa\n  generic:\n    changes_saved_msg: Izmjene su uspješno sačuvane!\n    save_changes: Sačuvaj izmjene\n  imports:\n    preface: Možeš uvesti određene podatke kao što su svi ljudi koje slijediš ili blokiraš u svoj račun na ovoj instanci, sa fajlova kreiranih izvozom sa druge instance.\n    success: Tvoji podaci su uspješno uploadani i bit će obrađeni u dogledno vrijeme\n    types:\n      blocking: Lista blokiranih\n      following: Lista onih koje slijedim\n      muting: Lista utišanih\n  invites:\n    expires_in:\n      '1800': 30 minutes\n      '21600': 6 hours\n      '3600': 1 hour\n      '43200': 12 hours\n      '604800': 1 week\n      '86400': 1 day\n  notification_mailer:\n    digest:\n      body: Ovo je kratak sažetak propuštenog od tvog prošlog posjeta %{since}\n      mention: \"%{name} te je spomenuo:\"\n    favourite:\n      body: 'Tvoj status je %{name} označio kao omiljen:'\n      subject: \"%{name} je označio kao omiljen tvoj status\"\n    follow:\n      body: \"%{name} te sada slijedi!\"\n      subject: \"%{name} te sada slijedi\"\n    follow_request:\n      body: \"%{name} je zatražio da te slijedi\"\n      subject: 'Sljedbenik na čekanju: %{name}'\n    mention:\n      body: 'Spomenuo te je %{name} u:'\n      subject: Spomenuo te je %{name}\n    reblog:\n      body: 'Tvoj status je potaknut od %{name}:'\n      subject: \"%{name} je potakao tvoj status\"\n  pagination:\n    next: Sljedeći\n    prev: Prošli\n  remote_follow:\n    acct: Unesi svoje username@domain sa koje želiš slijediti\n    missing_resource: Traženi redirect link za tvoj račun nije mogao biti nađen\n    proceed: Nastavi slijediti\n    prompt: 'Slijediti ćeš:'\n  settings:\n    authorized_apps: Autorizirane aplikacije\n    back: Natrag na Mastodon\n    edit_profile: Uredi profil\n    export: Izvoz podataka\n    import: Uvezi\n    preferences: Postavke\n    two_factor_authentication: Dvo-faktorska Autentifikacija\n  statuses:\n    open_in_web: Otvori na webu\n    over_character_limit: prijeđen je limit od %{max} znakova\n    show_more: Prikaži više\n    visibilities:\n      private: Pokaži samo sljedbenicima\n      public: Javno\n      unlisted: Javno, no nemoj prikazati na javnom timelineu\n  stream_entries:\n    reblogged: potaknut\n    sensitive_content: Osjetljivi sadržaj\n  two_factor_authentication:\n    description_html: Ako omogućiš <strong>dvo-faktorsku autentifikaciju</strong>, prijavljivanje će zahtjevati da kod sebe imaš svoj mobitel, koji će generirati tokene koje ćeš unijeti.\n    disable: Onemogući\n    enable: Omogući\n    instructions_html: \"<strong>Skeniraj ovaj QR kod u Google Authenticator ili sličnu aplikaciju na svom telefonu</strong>. Od sada, ta aplikacija će generirati tokene koje ćeš unijeti pri prijavljivanju.\"\n  users:\n    invalid_email: E-mail adresa nije valjana\n    invalid_otp_token: Nevaljani dvo-faktorski kod\n"
  },
  {
    "path": "config/locales/hu.yml",
    "content": "---\nhu:\n  about:\n    about_hashtag_html: Ezek a <strong>#%{hashtag}</strong> címkével ellátott publikus tülkök. Reagálhatsz rájuk, ha már van felhasználói fiókod valahol a föderációban.\n    about_mastodon_html: Mastodon egy <em>szabad, nyílt forráskódú</em> szociális hálózati kiszolgálo. Egy <em>központosítatlan</em> alternatíva a kereskedelmi platformokra, elkerüli a kommunikációd monopolizációját veszélyét. Bárki futtathatja a Mastodon-t és részt vehet a <em>szociális hálózatban</em>.\n    about_this: Rólunk\n    contact: Kapcsolat\n    contact_missing: Nincs megadva\n    extended_description_html: |\n      <h3>Ez itt a szabályzat helye</h3>\n      <p>Még nem állítottál be bővebb leírást.</p>\n    generic_description: \"%{domain} csak egy a számtalan szerver közül a föderációban\"\n    hosted_on: \"%{domain} Mastodon instancia\"\n    learn_more: Tudj meg többet\n    source_code: Forráskód\n    status_count_before: eddig\n    user_count_before: Összesen\n    what_is_mastodon: Mi a Mastodon?\n  accounts:\n    follow: Követés\n    following: Követed őket\n    media: Média\n    moved_html: \"%{name} ide költözött: %{new_profile_link}\"\n    nothing_here: Nincs itt semmi!\n    people_followed_by: \"%{name} követett személyei\"\n    people_who_follow: \"%{name} követői\"\n    posts_with_replies: Tülkök és válaszok\n    reserved_username: Ez egy már lefoglalt felhasználónév\n    roles:\n      admin: Adminisztrátor\n      moderator: Moderátor\n    unfollow: Követés abbahagyása\n  admin:\n    account_moderation_notes:\n      create: Új bejegyzés\n      created_msg: Moderációs bejegyzés létrehozva!\n      delete: Törlés\n      destroyed_msg: Moderációs bejegyzés törölve!\n    accounts:\n      are_you_sure: Biztos vagy benne?\n      confirm: Megerősítés\n      confirmed: Megerősítve\n      confirming: Megerősítve\n      demote: Lefokozás\n      disable: Kikapcsolás\n      disable_two_factor_authentication: Kétlépcsős azonosítás kikapcsolása\n      disabled: Kikapcsolva\n      display_name: Megjelenített név\n      edit: Szerkesztés\n      email: E-mail\n      email_status: E-mail állapot\n      enable: Engedélyezés\n      enabled: Engedélyezve\n      feed_url: Hírcsatorna URL\n      followers: Követők\n      followers_url: Követők URL\n      follows: Követettek\n      inbox_url: Beérkezett üzenetek URL\n      location:\n        all: Összes\n        local: Helyi\n        remote: Távoli\n        title: Hely\n      login_status: Bejelentkezve\n      media_attachments: Média-csatolmányok\n      memorialize: Emlékállítás\n      moderation:\n        all: Összes\n        silenced: Némítva\n        suspended: Felfüggesztve\n        title: Moderáció\n      moderation_notes: Moderációs bejegyzés\n      most_recent_activity: Legutóbbi tevékenységek\n      most_recent_ip: Legutóbbi IP-cím\n      not_subscribed: Nincs feliratkozás\n      outbox_url: Kimenő üzenetek URL\n      perform_full_suspension: Teljes felfüggesztés\n      profile_url: Profil URL\n      promote: Előléptetés\n      protocol: Protokoll\n      public: Nyilvános\n      push_subscription_expires: A PuSH feliratkozás elévül\n      redownload: Profilkép frissítése\n      resend_confirmation:\n        already_confirmed: Ezt a felhasználót már megerősítették\n        send: Küldd újra a megerősítő email-t\n        success: A megerősítő e-mail sikeresen elküldve!\n      reset: Visszaállítás\n      reset_password: Jelszó visszaállítása\n      resubscribe: Feliratkozás ismét\n      role: Engedélyek\n      roles:\n        admin: Adminisztrátor\n        moderator: Moderátor\n        staff: Stáb\n        user: Felhasználó\n      search: Keresés\n      shared_inbox_url: Bejövő üzenetek URL keresése\n      show:\n        created_reports: Ezen fiók által létrehozott jelentések\n        targeted_reports: Jelentések ezzel a fiókkal kapcsolatban\n      silence: Némítás\n      statuses: Tülkök\n      subscribe: Feliratkozás\n      title: Fiókok\n      undo_silenced: Némítás visszavonása\n      undo_suspension: Felfüggesztés visszavonása\n      unsubscribe: Leiratkozás\n      username: Felhasználónév\n      web: Weboldal\n    action_logs:\n      actions:\n        confirm_user: \"%{name} megerősítette e-mail címét: %{target}\"\n        create_custom_emoji: \"%{name} új hangulatjelet töltött fel: %{target}\"\n        create_domain_block: \"%{name} letiltotta az alábbi domaint: %{target}\"\n        create_email_domain_block: \"%{name} feketelistára tette az alábbi e-mail domaint: %{target}\"\n        demote_user: \"%{name} lefokozta az alábbi felhasználót: %{target}\"\n        destroy_domain_block: \"%{name} engedélyezte az alábbi domaint: %{target}\"\n        destroy_email_domain_block: \"%{name} fehérlistára tette az alábbi e-mail domaint: %{target}\"\n        destroy_status: \"%{name} eltávolította az alábbi felhasználó tülkjét: %{target}\"\n        disable_2fa_user: \"%{name} kikapcsolta a kétlépcsős azonosítást %{target} felhasználó fiókján\"\n        disable_custom_emoji: \"%{name} letiltotta az alábbi hangulatjelet: %{target}\"\n        disable_user: \"%{name} letiltotta az alábbi felhasználó bejelentkezését: %{target}\"\n        enable_custom_emoji: \"%{name} engedélyezte az alábbi hangulatjelet: %{target}\"\n        enable_user: \"%{name} engedélyezte az alábbi felhasználó bejelentkezését: %{target}\"\n        memorialize_account: \"%{name} emléket állított az alábbi felhasználónak: %{target}\"\n        promote_user: \"%{name} előléptette az alábbi felhasználót: %{target}\"\n        reset_password_user: \"%{name} visszaállította az alábbi felhasználó jelszavát: %{target}\"\n        resolve_report: \"%{name} mellőzte az alábbi jelentést: %{target}\"\n        silence_account: \"%{name} lenémította %{target} felhasználói fiókját\"\n        suspend_account: \"%{name} felfüggesztette %{target} felhasználói fiókját\"\n        unsilence_account: \"%{name} feloldotta a némítást %{target} felhasználói fiókján\"\n        unsuspend_account: \"%{name} feloldotta %{target} felhasználói fiókjának felfüggesztését\"\n        update_custom_emoji: \"%{name} frissítette az alábbi hangulatjelet: %{target}\"\n        update_status: \"%{name} frissítette %{target} felhasználó tülkjét\"\n      title: Audit napló\n    custom_emojis:\n      copied_msg: Sikeresen létrehoztuk a hangulatjel helyi másolatát\n      copy: Másolás\n      copy_failed_msg: Hangulatjel helyi másolatának létrehozása sikertelen\n      created_msg: Hangulatjel létrehozva!\n      delete: Törlés\n      destroyed_msg: A hangulatjel törlése sikeres!\n      disable: Letiltás\n      disabled_msg: Hangulatjel letiltva\n      emoji: Hangulatjel\n      enable: Engedélyezés\n      enabled_msg: Hangulatjel engedélyezve\n      image_hint: PNG (maximális méret 50KB)\n      listed: Listázva\n      new:\n        title: Új egyedi hangulatjel hozzáadása\n      overwrite: Felülírás\n      shortcode_hint: Legalább két karakter, csak betűk, számok és alsóvonás\n      title: Egyedi hangulatjelek\n      unlisted: Nincs listázva\n      update_failed_msg: Nem sikerült frissíteni a hangulatjelet\n      updated_msg: Hangulatjel sikeresen frissítve!\n      upload: Feltöltés\n    domain_blocks:\n      add_new: Új hozzáadása\n      created_msg: A domain-tiltás feldolgozása folyamatban\n      destroyed_msg: A domain tiltása feloldva\n      new:\n        create: Tiltás létrehozása\n        hint: A domain-tiltás nem gátolja meg az új fiókok hozzáadását az abatbázishoz, de visszamenőlegesen és automatikusan aktivál bizonyos moderációs szabályokat ezen fiókok esetében.\n        severity:\n          desc_html: A <strong>Némítás</strong> elrejti az adott felhasználó tülkjeit mindenki elől, aki nem követi az adott felhasználót. A <strong>Felfüggesztés</strong> eltávolítja az adott felhasználó által létrehozott minden tartalmat, ide értve a médiafájlokat és a fiókadatokat is. Válaszd az <strong>Egyik sem</strong> opciót, ha csupán a médiafájlokat szeretnéd elutasítani.\n          noop: Egyik sem\n          silence: Némítás\n          suspend: Felfüggesztés\n        title: Új domain-tiltás\n      reject_media: Médiafájlok elutasítása\n      reject_media_hint: Eltávolítja a helyben tárolt médiafájlokat és a továbbiakban letiltja az új médiafájlok letöltését. Felfüggesztett fiókok esetében irreleváns opció\n      show:\n        affected_accounts:\n          one: Összesen egy fiók érintett az adatbázisban\n          other: Összesen %{count} fiók érintett az adatbázisban\n        retroactive:\n          silence: Minden felhasználó némításának feloldása ezen a domainen\n          suspend: Minden felhasználó felfüggesztésének feloldása ezen a domainen\n        title: \"%{domain} domain tiltásának feloldása\"\n        undo: Visszavonás\n      undo: Visszavonás\n    email_domain_blocks:\n      add_new: Új hozzáadása\n      created_msg: E-mail domain sikeresen hozzáadva a feketelistához\n      delete: Törlés\n      destroyed_msg: E-mail domain sikeresen eltávolítva a feketelistáról\n      new:\n        create: Domain hozzáadása\n        title: Új e-mail feketelista bejegyzés\n      title: E-mail feketelista\n    instances:\n      title: Nyilvántartott instanciák\n    invites:\n      filter:\n        all: Összes\n        available: Elérhető\n        expired: Elévült\n        title: Szűrő\n      title: Meghívások\n    reports:\n      action_taken_by: 'Kezelte:'\n      are_you_sure: Biztos vagy benne?\n      comment:\n        none: Egyik sem\n      mark_as_resolved: Megjelölés megoldottként\n      report: \"#%{id} számú jelentés\"\n      reported_account: Bejelentett fiók\n      reported_by: 'Jelentette:'\n      resolved: Megoldott\n      status: Állapot\n      title: Jelentések\n      unresolved: Megoldatlan\n    settings:\n      activity_api_enabled:\n        desc_html: Helyi tülkök, aktív felhasználók és új regisztrációk száma heti bontásban\n        title: Felhasználói aktivitás összesített statisztikájának publikussá tétele\n      bootstrap_timeline_accounts:\n        desc_html: Az egyes felhasználónevek vesszővel elválasztva. Csak helyi és aktivált fiókok esetében működik. Üresen (alapértelmezettként) minden helyi adminisztrátorra érvényes.\n        title: Alapértelmezett követések új felhasználók esetében\n      contact_information:\n        email: Kapcsolattartói e-mail cím\n        username: Kapcsolattartó felhasználóneve\n      peers_api_enabled:\n        desc_html: Domainek, amelyekkel ez az instancia kapcsolatban áll\n        title: Instanciák listájának közzététele, melyekkel ez a szerver kapcsolatban áll\n      registrations:\n        closed_message:\n          desc_html: Ez az üzenet jelenik meg a főoldalon, ha a regisztráció nem engedélyezett. HTML-tageket is használhatsz\n          title: Üzenet, ha a regisztráció nem engedélyezett\n        deletion:\n          desc_html: Engedélyezed a felhasználóknak, hogy töröljék fiókjukat\n          title: Fiók törlésének engedélyezése\n        min_invite_role:\n          disabled: Senkinek\n          title: Meghívások engedélyezése\n      show_staff_badge:\n        desc_html: Stáb-jelvény megjelenítése a felhasználó oldalán\n        title: Stáb-jelvény megjelenítése\n      site_description:\n        desc_html: 'Rövid bemutatkozás a főoldalon és a meta fejlécekben. Az alábbi HTML-tageket használhatod: <code>&lt;a&gt;</code> és <code>&lt;em&gt;</code>.'\n        title: Az instancia bemutatása\n      site_description_extended:\n        desc_html: Ide teheted például a közösségi és egyéb szabályzatot, útmutatókat és mindent, ami egyedivé teszi instanciádat. HTML-tageket is használhatsz\n        title: További egyedi információ\n      site_terms:\n        desc_html: Megírhatod saját adatkezelési szabályzatodat, felhasználási feltételeidet vagy más hasonló jellegű dokumentumodat. HTML-tageket is használhatsz\n        title: Egyedi felhasználási feltételek\n      site_title: Az instancia neve\n      thumbnail:\n        desc_html: Az OpenGraph és API előnézetekhez használjuk. Ajánlott mérete 1200x560 pixel\n        title: Az instancia bélyegképe\n      timeline_preview:\n        desc_html: Publikus időfolyam megjelenítése a főoldalon\n        title: Időfolyam előnézete\n      title: Oldal beállításai\n    statuses:\n      back_to_account: Vissza a fiók oldalára\n      batch:\n        delete: Törlés\n        nsfw_off: Szenzitív tartalom kikapcsolva\n        nsfw_on: Szenzitív tartalom bekapcsolva\n      failed_to_execute: Végrehajtás sikertelen\n      media:\n        title: Média\n      no_media: Nem található médiafájl\n      title: Felhasználó tülkjei\n      with_media: Médiafájlokkal\n    subscriptions:\n      confirmed: Megerősítve\n      expires_in: Elévül\n      last_delivery: Utolsó kézbesítés\n      topic: Téma\n    title: Karbantartás\n  admin_mailer:\n    new_report:\n      body: \"%{reporter} jelentette: %{target}\"\n      subject: 'Új jelentés az alábbi instancián: %{instance} (#%{id})'\n  application_mailer:\n    notification_preferences: E-mail beállítások módosítása\n    settings: 'E-mail beállítások módosítása: %{link}'\n    view: 'Megtekintés:'\n    view_profile: Profil megtekintése\n    view_status: Tülk megtekintése\n  applications:\n    created: Alkalmazás sikeresen létrehozva\n    destroyed: Alkalmazás sikeresen eltávolítva\n    invalid_url: A megadott URL nem megfelelő\n    regenerate_token: Hozzáférési kulcs újragenerálása\n    token_regenerated: Hozzáférési kulcs sikeresen újragenerálva\n    warning: Ez érzékeny adat. Soha ne oszd meg másokkal!\n    your_token: Hozzáférési kulcsod\n  auth:\n    delete_account: Felhasználói fiók törlése\n    delete_account_html: Felhasználói fiókod törléséhez <a href=\"%{path}\">kattints ide</a>. A rendszer újbóli megerősítést fog kérni.\n    didnt_get_confirmation: Nem kaptad meg a megerősítési lépéseket?\n    forgot_password: Elfelejtetted a jelszavad?\n    invalid_reset_password_token: A jelszó-visszaállítási kulcs nem megfelelő vagy lejárt. Kérlek generálj egy újat.\n    login: Bejelentkezés\n    logout: Kijelentkezés\n    migrate_account: Felhasználói fiók költöztetése\n    migrate_account_html: Ha szeretnéd átirányítani ezt a fiókodat egy másikra, a beállításokat <a href=\"%{path}\">itt találod meg</a>.\n    register: Regisztráció\n    resend_confirmation: Megerősítési lépések újraküldése\n    reset_password: Jelszó visszaállítása\n    security: Biztonság\n    set_new_password: Új jelszó beállítása\n  authorize_follow:\n    error: Hiba történt a távoli felhasználó keresésekor\n    follow: Követés\n    follow_request: 'Engedélyt kértél az alábbi felhasználó követésére:'\n    following: 'Siker! Mostantól követed az alábbi felhasználót:'\n    post_follow:\n      close: Akár be is zárhatod ezt az ablakot.\n      return: Visszatérés a felhasználó profiloldalára\n      web: Megtekintés a weben\n    title: \"%{acct} követése\"\n  datetime:\n    distance_in_words:\n      about_x_hours: \"%{count}ó\"\n      about_x_months: \"%{count}h\"\n      about_x_years: \"%{count}é\"\n      almost_x_years: \"%{count}é\"\n      half_a_minute: Épp most\n      less_than_x_minutes: \"%{count}p\"\n      less_than_x_seconds: Épp most\n      over_x_years: \"%{count}é\"\n      x_days: \"%{count}n\"\n      x_minutes: \"%{count}p\"\n      x_months: \"%{count}h\"\n      x_seconds: \"%{count}mp\"\n  deletes:\n    bad_password_msg: Haha, hekker! Helytelen jelszó\n    confirm_password: Személyazonosságod megerősítéséhez írd be a jelenlegi jelszavad\n    description_html: Ezzel <strong>véglegesen és visszafordíthatatlanul</strong> törlöd minden tartalmadat és deaktiválod a fiókodat. A felhasználónevedet megtartjuk, hogy megakadályozzuk a neveddel történő jövőbeni visszaélések lehetőségét.\n    proceed: Felhasználói fiók törlése\n    success_msg: Felhasználói fiókod sikeresen törölve lett\n    warning_html: Csak azt tudjuk garantálni, hogy az általad létrehozott tartalmat erről az instanciáról töröljük. Ha egyes tartalmaidat sokan megosztották, valószínűleg marad nyomuk a megosztások miatt. Nam fogjuk tudni frissíteni azon instanciák adatbázisát, amelyek nem kapcsolódnak a föderációhoz vagy amelyek leiratkoztak a tülkjeidről.\n    warning_title: Szórt tartalmak elérése\n  errors:\n    '403': Nincs jogosultságod az oldal megtekintéséhez.\n    '404': Az általad keresett oldal nem található.\n    '410': Az általad keresett oldal már nem létezik.\n    '422':\n      content: Megerősítés sikertelen. Nem tiltottad le esetleg a sütiket?\n      title: Megerősítés sikertelen\n    '429': Kampec\n    '500':\n      content: Sajnáljuk, valami hiba történt a mi oldalunkon.\n      title: Az oldal nem megfelelő\n    noscript_html: A Mastodon webalkalmazás használatához engedélyezned kell a JavaScriptet. A másik megoldás, hogy kipróbálod az egyik, a platformodnak megfelelő <a href=\"%{apps_path}\">alkalmazást</a>.\n  exports:\n    blocks: Tiltólistádon\n    follows: Követettjeid\n    mutes: Némításaid\n    storage: Médiatároló\n  generic:\n    changes_saved_msg: Változások sikeresen elmentve!\n    save_changes: Változások mentése\n    validation_errors:\n      one: Valami nincs rendjén! Kérlek tekintsd meg a hibát alant\n      other: Valami nincs rendjén! Kérlek tekintsd meg a %{count} darab hibát alant\n  imports:\n    preface: Itt importálhatod egy másik instanciáról lementett adataidat, például követettjeid és letiltott felhasználóid listáját.\n    success: Adataidat sikeresen feltöltöttük és feldolgozásukat megkezdtük\n    types:\n      blocking: Letiltottak listája\n      following: Követettjeid listája\n      muting: Némított felhasználók listája\n    upload: Feltöltés\n  invites:\n    delete: Visszavonás\n    expired: Lejárt\n    expires_in:\n      '1800': 30 perc\n      '21600': 6 óra\n      '3600': 1 óra\n      '43200': 12 óra\n      '604800': 1 week\n      '86400': 1 nap\n    expires_in_prompt: Soha\n    generate: Generálás\n    max_uses:\n      one: 1 felhasználás\n      other: \"%{count} felhasználás\"\n    max_uses_prompt: Nincs korlát\n    prompt: Az itt generált linkek megosztásával hívhatod meg ismerőseidet az instanciára\n    table:\n      expires_at: Lejárat\n      uses: Használat\n    title: Meghívások\n  lists:\n    errors:\n      limit: Elérted a hozzáadható listák maximális számát\n  media_attachments:\n    validations:\n      images_and_video: Nem csatolhatsz videót olyan tülkhöz, amelyhez már csatoltál képet\n      too_many: Maximum négy fájlt csatolhatsz a tülkhöz\n  migrations:\n    acct: Az új fiók felhasznalonev@domain formátumban\n    currently_redirecting: 'A profilod az alábbi fiókra van átirányítva:'\n    proceed: Mentés\n    updated_msg: Fiókod átirányítási beállítasait sikeresen mentettük!\n  moderation:\n    title: Moderáció\n  notification_mailer:\n    digest:\n      action: Összes értesítés megtekintése\n      body: Itt a legutóbbi látogatásod (%{since}) óta írott üzenetek rövid összefoglalása\n      mention: \"%{name} megemlített itt:\"\n      new_followers_summary:\n        one: Sőt, egy új követőd is lett, amióta nem jártál itt. Hurrá!\n        other: Sőt, %{count} új követőd is lett, amióta nem jártál itt. Hihetetlen!\n      subject:\n        one: \"Egy új értesítésed érkezett legutóbbi látogatásod óta \\U0001F418\"\n        other: \"%{count} új értesítésed érkezett legutóbbi látogatásod óta \\U0001F418\"\n      title: Amíg távol voltál…\n    favourite:\n      body: 'Az állapotodat kedvencnek jelölte %{name}:'\n      subject: \"%{name} kedvencnek jelölte az állapotod\"\n      title: Új kedvencnek jelölés\n    follow:\n      body: \"%{name} mostantól követ téged!\"\n      subject: \"%{name} mostantól követ téged\"\n      title: Új követő\n    follow_request:\n      action: Követési kérések kezelése\n      body: \"%{name} követni szeretne téged\"\n      subject: 'Jóváhagyásra vár: %{name}'\n      title: Új követési kérés\n    mention:\n      action: Válasz\n      body: \"%{name} megemlített téged:\"\n      subject: \"%{name} megemlített téged\"\n      title: Új említés\n    reblog:\n      body: 'Az állapotod reblogolta %{name}:'\n      subject: \"%{name} reblogolta az állapotod\"\n      title: Új reblog\n  pagination:\n    next: Következő\n    prev: Előző\n  preferences:\n    other: Egyéb\n  remote_follow:\n    acct: Írd be a felhasználódat, amelyről követni szeretnéd felhasznalonev@domain formátumban\n    missing_resource: A fiókodnál nem található a szükséges átirányítási URL\n    proceed: Tovább a követéshez\n    prompt: 'Őt tervezed követni:'\n  sessions:\n    activity: Legutóbbi tevékenység\n    browser: Böngésző\n    browsers:\n      generic: Ismeretlen böngésző\n      nokia: Nokia S40 Ovi Böngésző\n    current_session: Jelenlegi munkamenet\n    description: \"%{browser} az alábbi platformon: %{platform}\"\n    explanation: Jelenleg az alábbi böngészőkkel vagy bejelentkezve a fiókodba.\n    platforms:\n      other: ismeretlen platform\n    revoke: Visszavonás\n    revoke_success: Munkamenet sikeresen visszavonva\n    title: Munkamenetek\n  settings:\n    authorized_apps: Jóváhagyott alkalmazások\n    back: Vissza a Mastodonhoz\n    delete: Fiók törlése\n    development: Fejlesztőknek\n    edit_profile: Profil szerkesztése\n    export: Adatok exportálása\n    import: Importálás\n    migrate: Fiók átirányítása\n    notifications: Értesítések\n    preferences: Általános beállítások\n    two_factor_authentication: Kétlépcsős azonosítás\n  statuses:\n    open_in_web: Megnyitás a weben\n    over_character_limit: Túllépted a maximális %{max} karakteres keretet\n    pin_errors:\n      limit: Elérted a kitűzhető tülkök maximális számát\n      ownership: Nem tűzheted ki valaki más tülkjét\n      private: Csak publikus tülköt tűzhetsz ki\n      reblog: Reblogolt tülköt nem tudsz kitűzni\n    show_more: Mutass többet\n    visibilities:\n      private: Csak követőknek\n      private_long: A tülk csak követőidnek jelenik meg\n      public: Nyilvános\n      public_long: Bárki láthatja a tülköt\n      unlisted: Listázatlan\n      unlisted_long: Mindenki látja, de a nyilvános időfolyamokban nem jelenik meg\n  stream_entries:\n    pinned: Kitűzött tülk\n    reblogged: reblogolt\n    sensitive_content: Szenzitív tartalom\n  terms:\n    title: \"%{instance} Felhasználási feltételek és Adatkezelési nyilatkozat\"\n  themes:\n    default: Mastodon\n  time:\n    formats:\n      default: \"%Y %b %d, %H:%M\"\n  two_factor_authentication:\n    code_hint: Megerősítéshez írd be az alkalmazás által generált kódot\n    description_html: He engedélyezed a <strong>kétlépcsős azonosítást</strong>, a bejelentkezéshez szükséged lesz a teefonodre és egy alkalmazásra, amely hozzáférési kódot generál számodra.\n    disable: Kikapcsolás\n    enable: Engedélyezés\n    enabled: Kétlépcsős azonosítás engedélyezve\n    enabled_success: A kétlépcsős azonosítást sikeresen engedélyezted\n    generate_recovery_codes: Visszaállítási kódok generálása\n    instructions_html: \"<strong>Olvasd be ez a QR-kódot a telefonodon futó Google Authenticator (vagy egyéb TOTP) alkalmazással</strong>. A jövőben ez az alkalmazás fog számodra hozzáférési kódot generálni a belépéshez.\"\n    lost_recovery_codes: A visszaállítási kódok segítségével tudsz belépni, ha elveszítenéd a telefonod. Ha a visszaállítási kódjaidat hagytad el, itt generálhatsz újakat. A régi kódokat ebben az esetben érvénytelenítjük.\n    manual_instructions: 'Ha nem sikerült a QR-kód beolvasása, itt a szöveges kulcs, amelyet manuálisan kell begépelned:'\n    recovery_codes: Visszaállítási kódok biztonsági mentése\n    recovery_codes_regenerated: Visszaállítási kódok sikeresen újragenerálva\n    recovery_instructions_html: A visszaállítási kódok egyikének segítségével tudsz majd belépni, ha elveszítenéd a telefonod. <strong>Tartsd biztos helyen a visszaállítási kódjaid</strong>! Például nyomtasd ki őket és tárold a többi fontos iratoddal együtt.\n    setup: Beállítás\n    wrong_code: A beírt kód nem érvényes! A szerver órája és az eszközöd órája szinkronban jár?\n  user_mailer:\n    welcome:\n      edit_profile_action: Készítsd el profilod\n      edit_profile_step: 'Itt tudod egyedivé tenni a profilod: feltölthetsz profil- és borítóképet, megváltoztathatod a megjelenített neved és így tovább. Ha jóvá szeretnéd hagyni követőidet, mielőtt láthatják a tülkjeid, itt tudod a fiókodat zárttá tenni.'\n      explanation: Néhány tipp a kezdeti lépésekhez\n      final_action: Kezdj tülkölni\n      final_step: 'Kezdj tülkölni! Publikus üzeneteid még követők híján is megjelennek másoknak, például a helyi időfolyamban és a címkéknél. Kezdd például azzal, hogy bemutatkozol: használd a #bemutatkozas és az #introductions címkét a tülködben.'\n      full_handle: Teljes felhasználóneved\n      full_handle_hint: Ez az, amit megadhatsz másoknak, hogy üzenhessenek neked vagy követhessenek téged más instanciákról.\n      review_preferences_action: Beállítások módosítása\n      review_preferences_step: Tekintsd át beállításaidat, például hogy milyen értesítéseket kérsz emailben vagy hogy alapértelmezettként mi legyen a tülkjeid adatvédelmi beállítása. Ha nem vagy szédülős alkat, azt is engedélyezheted, hogy automatikusan lejátsszuk a GIF-eket.\n      subject: Üdvözöl a Mastodon\n      tip_federated_timeline: A nyilvános időfolyam a Mastodon ütőere, ahol minden tülk összefolyik. Nem teljes ugyan, mert csak azokat az emberek fogod látni, akiket instanciád többi felhasználója követ.\n      tip_following: Alapértelmezettként instanciád adminisztrátorait követed. Látogasd meg a helyi és a nyilvános időfolyamot, hogy más érdekes emberekre is rátalálj.\n      tip_local_timeline: A helyi időfolyam a saját instanciád (%{instance}) ütőere. Ezek a kedves emberek itt mind a szomszédaid!\n      tip_mobile_webapp: Ha a böngésződ lehetővé teszi, hogy kezdőképernyődhöz add a Mastodont, még értesítéseket is fogsz kapni &ndash; akárcsak egy igazi alkalmazás esetében!\n      tips: Tippek\n      title: Üdv a fedélzeten, %{name}!\n  users:\n    invalid_email: A megadott e-mail cím helytelen\n    invalid_otp_token: Érvénytelen ellenőrző kód\n    signed_in_as: Bejelentkezve mint\n"
  },
  {
    "path": "config/locales/hy.yml",
    "content": "---\nhy:\n  errors:\n    '403': You don't have permission to view this page.\n    '404': The page you are looking for isn't here.\n    '410': The page you were looking for doesn't exist here anymore.\n    '422': \n    '429': Throttled\n    '500': \n  invites:\n    expires_in:\n      '1800': 30 minutes\n      '21600': 6 hours\n      '3600': 1 hour\n      '43200': 12 hours\n      '604800': 1 week\n      '86400': 1 day\n"
  },
  {
    "path": "config/locales/id.yml",
    "content": "---\nid:\n  about:\n    about_hashtag_html: Ini adalah toot public yang ditandai dengan <strong>#%{hashtag}</strong>. Anda bisa berinteraksi dengan mereka jika anda memiliki akun dimanapun di fediverse.\n    about_mastodon_html: Mastodon adalah sebuah jejaring sosial <em>terbuka, open-source</em. Sebuah alternatif <em>desentralisasi</em> dari platform komersial, menjauhkan anda resiko dari sebuah perusahaan yang memonopoli komunikasi anda. Pilih server yang anda percayai &mdash; apapun yang anda pilih, anda tetap dapat berinteraksi dengan semua orang. Semua orang dapat menjalankan server Mastodon sendiri dan berpartisipasi dalam <em>jejaring sosial</em> dengan mudah.\n    about_this: Tentang server ini\n    administered_by: 'Dikelola oleh:'\n    apps: Aplikasi hp\n    contact: Kontak\n    contact_missing: Belum diset\n    contact_unavailable: Tidak Tersedia\n    documentation: Dokumentasi\n    extended_description_html: |\n      <h3>Tempat yang baik untuk peraturan</h3>\n      <p>Deskripsi lainnya belum diset.</p>\n    generic_description: \"%{domain} adalah satu server dalam jaringan\"\n    hosted_on: Mastodon dihosting di %{domain}\n    learn_more: Pelajari selengkapnya\n    privacy_policy: Kebijakan Privasi\n    source_code: Kode sumber\n    status_count_after:\n      other: status\n    status_count_before: Yang telah menulis\n    terms: Kebijakan layanan\n    user_count_after:\n      other: pengguna\n    user_count_before: Tempat bernaung bagi\n    what_is_mastodon: Apa itu Mastodon?\n  accounts:\n    follow: Ikuti\n    followers:\n      other: Pengikut\n    following: Mengikuti\n    joined: Bergabung pada %{date}\n    last_active: terakhir aktif\n    link_verified_on: Kepemilikan tautan ini telah dicek pada %{date}\n    moved_html: \"%{name} telah pindah ke %{new_profile_link}:\"\n    network_hidden: Informasi ini tidak tersedia\n    nothing_here: Tidak ada apapun disini!\n    people_followed_by: Orang yang diikuti %{name}\n    people_who_follow: Orang-orang yang mengikuti %{name}\n    pin_errors:\n      following: Anda harus mengikuti orang yang ingin anda endorse\n    posts:\n      other: Toot\n    posts_tab_heading: Toot\n    posts_with_replies: Toot dan balasan\n    reserved_username: Nama pengguna telah dipesan\n    roles:\n      moderator: Moderator\n    unfollow: Berhenti mengikuti\n  admin:\n    account_actions:\n      action: Lakukan aksi\n      title: Lakukan moderasi pada %{acct}\n    account_moderation_notes:\n      create: Beri catatan\n      created_msg: Catatan moderasi berhasil dibuat!\n      delete: Hapus\n      destroyed_msg: Catatan moderasi berhasil dihapus!\n    accounts:\n      are_you_sure: Anda yakin?\n      change_email:\n        changed_msg: Email akun ini berhasil diubah!\n        current_email: Email saat ini\n        label: Ganti email\n        new_email: Email baru\n        submit: Ganti email\n        title: Ganti email untuk %{username}\n      confirm: Konfirmasi\n      confirmed: Dikonfirmasi\n      confirming: Mengkonfirmasi\n      deleted: Terhapus\n      disable: Nonaktifkan\n      disable_two_factor_authentication: Nonaktifkan 2FA\n      disabled: Dinonaktifkan\n      display_name: Nama\n      edit: Ubah\n      email: E-mail\n      email_status: Status Email\n      enable: Aktifkan\n      enabled: Diaktifkan\n      feed_url: URL Feed\n      followers: Pengikut\n      followers_url: URL pengikut\n      follows: Mengikut\n      inbox_url: URL Kotak masuk\n      invited_by: Diundang oleh\n      joined: Bergabung\n      location:\n        all: Semua\n        local: Lokal\n        title: Lokasi\n      login_status: Status login\n      media_attachments: Lampiran media\n      memorialize: Ubah menjadi memoriam\n      moderation:\n        active: Aktif\n        all: Semua\n        silenced: Didiamkan\n        suspended: Disuspen\n        title: Moderasi\n      moderation_notes: Catatan moderasi\n      most_recent_activity: Aktivitas terbaru\n      most_recent_ip: IP terbaru\n      no_limits_imposed: Tidak ada batasan\n      not_subscribed: Tidak berlangganan\n      outbox_url: URL Kotak keluar\n      perform_full_suspension: Lakukan suspen penuh\n      profile_url: URL profil\n      promote: Promosikan\n      protocol: Protokol\n      public: Publik\n      push_subscription_expires: Langganan PuSH telah kadaluarsa\n      redownload: Muat ulang profil\n      remove_avatar: Hapus avatar\n      remove_header: Hapus header\n      resend_confirmation:\n        already_confirmed: Pengguna ini sudah dikonfirmasi\n        send: Kirim ulang email konfirmasi\n        success: Email konfirmasi berhasil dikirim!\n      reset_password: Reset kata sandi\n      resubscribe: Langganan ulang\n      role: Hak akses\n      roles:\n        staff: Staf\n        user: Pengguna\n      salmon_url: URL Salmon\n      search: Cari\n      show:\n        created_reports: Laporan yang dibuat oleh akun ini\n        targeted_reports: Laporan yang dibuat tentang akun ini\n      silence: Diam\n      silenced: Didiamkan\n      statuses: Status\n      subscribe: Langganan\n      suspended: Disuspen\n      title: Akun\n      unconfirmed_email: Email belum dikonfirmasi\n      undo_silenced: Undo mendiamkan\n      undo_suspension: Undo suspen\n      unsubscribe: Berhenti langganan\n      username: Nama pengguna\n      warn: Beri Peringatan\n    domain_blocks:\n      add_new: Tambah\n      created_msg: Pemblokiran domain sedang diproses\n      destroyed_msg: Pemblokiran domain telah dibatalkan\n      new:\n        create: Buat pemblokiran\n        hint: Pemblokiran domain tidak akan menghentikan pembuatan akun dalam database, tapi kami akan memberikan moderasi otomatis pada akun-akun tersebut.\n        severity:\n          desc_html: \"<strong>Pendiaman</strong> akan membuat semua postingan tidak dapat dilihat oleh semua orang yang tidak mengikutinya. <strong>Suspen</strong> akan menghapus semua konten, media, dan profil dari akun yang bersangkutan.\"\n          silence: Pendiaman\n          suspend: Suspen\n        title: Pemblokiran domain baru\n      reject_media: Tolak berkas media\n      reject_media_hint: Hapus file media yang tersimpan dan menolak semua unduhan nantinya. Tidak terpengaruh dengan suspen\n      show:\n        affected_accounts:\n          other: \"%{count} akun dalam database terpengaruh\"\n        retroactive:\n          silence: Hapus pendiaman terhadap akun pada domain ini\n          suspend: Hapus suspen terhadap akun pada domain ini\n        title: Hapus pemblokiran domain %{domain}\n    instances:\n      title: Server yang diketahui\n    reports:\n      comment:\n        none: Tidak ada\n      mark_as_resolved: Tandai telah diseleseikan\n      report: 'Laporkan #%{id}'\n      reported_account: Akun yang dilaporkan\n      reported_by: Dilaporkan oleh\n      resolved: Terseleseikan\n      title: Laporan\n      unresolved: Belum Terseleseikan\n    settings:\n      contact_information:\n        email: Masukkan alamat email\n        username: Masukkan nama pengguna\n      registrations:\n        closed_message:\n          desc_html: Ditampilkan pada halaman depan saat pendaftaran ditutup<br>Anda bisa menggunakan tag HTML\n          title: Pesan penutupan pendaftaran\n      site_description:\n        desc_html: Ditampilkan sebagai sebuah paragraf di halaman depan dan digunakan sebagai tag meta.<br>Anda bisa menggunakan tag HTML, khususnya <code>&lt;a&gt;</code> dan <code>&lt;em&gt;</code>.\n        title: Deskripsi situs\n      site_description_extended:\n        desc_html: Ditampilkan pada halaman informasi tambahan<br>Anda bisa menggunakan tag HTML\n        title: Deskripsi situs tambahan\n      site_title: Judul Situs\n      title: Pengaturan situs\n    subscriptions:\n      confirmed: Dikonfirmasi\n      expires_in: Kadaluarsa dalam\n      last_delivery: Terakhir dikirim\n      topic: Topik\n    title: Administrasi\n  application_mailer:\n    settings: 'Ubah pilihan email: %{link}'\n    view: 'Tampilan:'\n  applications:\n    invalid_url: URL tidak sesuai\n  auth:\n    didnt_get_confirmation: Tidak menerima petunjuk konfirmasi?\n    forgot_password: Lupa kata sandi?\n    login: Masuk\n    logout: Keluar\n    register: Daftar\n    resend_confirmation: Kirim ulang email konfirmasi\n    reset_password: Reset kata sandi\n    security: Identitas\n    set_new_password: Tentukan kata sandi baru\n  authorize_follow:\n    error: Sayangnya, ada error saat melihat akun remote\n    follow: Ikuti\n    title: Mengikuti %{acct}\n  datetime:\n    distance_in_words:\n      about_x_hours: \"%{count}j\"\n      about_x_months: \"%{count}bln\"\n      about_x_years: \"%{count}thn\"\n      almost_x_years: \"%{count}thn\"\n      half_a_minute: Baru saja\n      less_than_x_minutes: \"%{count}mnt\"\n      less_than_x_seconds: Baru saja\n      over_x_years: \"%{count}thn\"\n      x_days: \"%{count}hari\"\n      x_minutes: \"%{count}mnt\"\n      x_months: \"%{count}bln\"\n      x_seconds: \"%{count}dtk\"\n  errors:\n    '403': Anda tidak mempunyai izin untuk melihat halaman ini.\n    '404': Halaman yang anda cari tidak ditemukan\n    '410': Halaman yang anda cari sudah tidak dapat ditemukan lagi.\n    '422':\n      content: Verifikasi keamanan gagal. Apa anda memblokir cookie?\n      title: Verifikasi keamanan gagal\n    '429': Throttled\n    '500': \n  exports:\n    blocks: Anda blokir\n    follows: Anda ikuti\n    mutes: Anda bisukan\n    storage: Penyimpanan media\n  generic:\n    changes_saved_msg: Perubahan berhasil disimpan!\n    save_changes: Simpan perubahan\n  imports:\n    preface: Anda bisa mengimpor data tertentu seperti orang-orang yang anda ikuti atau anda blokir di server ini, dari file yang dibuat oleh fitur expor di server lain.\n    success: Data anda berhasil diupload dan akan diproses sesegera mungkin\n    types:\n      blocking: Daftar diblokir\n      following: Daftar diikuti\n      muting: Daftar didiamkan\n    upload: Unggah\n  invites:\n    expires_in:\n      '1800': 30 minutes\n      '21600': 6 hours\n      '3600': 1 hour\n      '43200': 12 hours\n      '604800': 1 week\n      '86400': 1 day\n  media_attachments:\n    validations:\n      images_and_video: Tidak bisa melampirkan video pada status yang telah memiliki gambar\n      too_many: Tidak dapat melampirkan lebih dari 4 file\n  notification_mailer:\n    digest:\n      body: Ini adalah ringkasan singkat yang anda lewatkan pada sejak kunjungan terakhir anda pada %{since}\n      mention: \"%{name} menyebut anda di:\"\n      new_followers_summary:\n        other: Anda mendapatkan %{count} pengikut baru! Luar biasa!\n      subject:\n        other: \"%{count} notifikasi baru sejak kunjungan terakhir anda pada \\U0001F418\"\n    favourite:\n      body: 'Status anda disukai oleh %{name}:'\n      subject: \"%{name} menyukai status anda\"\n    follow:\n      body: \"%{name} mengikuti anda!\"\n      subject: \"%{name} menjadi pengikut anda\"\n    follow_request:\n      body: \"%{name} meminta untuk mengikuti anda\"\n      subject: 'Pengikut menunggu: %{name}'\n    mention:\n      body: 'Anda disebut oleh %{name} pada:'\n      subject: Anda disebut oleh %{name}\n    reblog:\n      body: 'Status anda di-boost oleh %{name}:'\n      subject: \"%{name} mem-boost status anda\"\n  pagination:\n    next: Selanjutnya\n    prev: Sebelumnya\n  remote_follow:\n    acct: Masukkan namapengguna@domain yang akan anda ikuti\n    missing_resource: Tidak dapat menemukan URL redirect dari akun anda\n    proceed: Lanjutkan untuk mengikuti\n    prompt: 'Anda akan mengikuti:'\n  settings:\n    authorized_apps: Apl yang diizinkan\n    back: Kembali ke Mastodon\n    edit_profile: Ubah profil\n    export: Expor data\n    import: Impor\n    preferences: Pilihan\n    two_factor_authentication: Autentikasi Two-factor\n  statuses:\n    open_in_web: Buka di web\n    over_character_limit: melebihi %{max} karakter\n    show_more: Tampilkan selengkapnya\n    visibilities:\n      private: Khusus pengikut\n      private_long: Hanya tampilkan ke pengikut\n      public: Publik\n      public_long: Bisa dilihat semua orang\n      unlisted: Bisa dilihat semua orang, tapi tidak ditampilkan di linimasa publik\n  stream_entries:\n    reblogged: di-boost-kan\n    sensitive_content: Konten sensitif\n  time:\n    formats:\n      default: \"%d %b %Y, %H:%M\"\n  two_factor_authentication:\n    code_hint: Masukkan kode yang dibuat oleh app autentikator sebagai konfirmasi\n    description_html: Jika anda menaktifkan ototentikasi dua faktor, saat login anda harus menggunakan telepon anda  untuk membuat token supaya anda bisa masuk.\n    disable: Matikan\n    enable: Aktifkan\n    enabled_success: Ototentikasi dua faktor telah diaktifkan\n    generate_recovery_codes: Buat Kode Pemulihan\n    instructions_html: \"<strong>Pindai kode QR ini pada Otentikator Google anda atau aplikasi TOTP lainnya di telepon anda</strong>. Mulai sekarang, aplikasi tersebut akan membuat token yang bisa anda gunakan untuk login.\"\n    lost_recovery_codes: Kode pemulihan bisa anda gunakan untuk mendapatkan kembali akses pada akun anda jika anda kehilangan handphone anda. Jika anda kehilangan kode pemulihan, anda bisa membuatnya ulang disini. Kode pemulihan anda yang lama tidak akan bisa digunakan lagi.\n    manual_instructions: 'Jika anda tidak bisa memindai kode QR dan harus memasukkannya secara manual, ini dia kode yang harus dimasukkan:'\n    recovery_codes_regenerated: Kode Pemulihan berhasil dibuat ulang\n    recovery_instructions_html: Jika anda kehilangan akses pada handphone anda, anda bisa menggunakan kode pemulihan dibawah ini untuk mendapatkan kembali akses pada akun anda. Simpan kode pemulihan anda baik-baik, misalnya dengan mencetaknya atau menyimpannya bersama dokumen penting lainnya.\n    setup: Persiapan\n    wrong_code: Kode yang dimasukkan tidak cocok! Apa waktu server dan waktu di handphone sudah cocok?\n  users:\n    invalid_email: Alamat email tidak cocok\n    invalid_otp_token: Kode dua faktor tidak cocok\n"
  },
  {
    "path": "config/locales/io.yml",
    "content": "---\nio:\n  about:\n    about_mastodon_html: Mastodon esas <em>gratuita, apertitkodexa</em> sociala reto. Ol esas <em>sencentra</em> altra alternativo a komercala servadi. Ol evitigas, ke sola firmo guvernez tua tota komunikadol. Selektez servero, quan tu fidas. Irge qua esas tua selekto, tu povas komunikar kun omna altra uzeri. Irgu povas krear sua propra instaluro di Mastodon en sua servero, e partoprenar en la <em>sociala reto</em> tote glate.\n    about_this: Pri ta instaluro\n    contact: Kontaktar\n    source_code: Fontkodexo\n    status_count_before: Qua publikigis\n    user_count_before: Hemo di\n  accounts:\n    follow: Sequar\n    following: Sequati\n    nothing_here: Esas nulo hike!\n    people_followed_by: Sequati da %{name}\n    people_who_follow: Sequanti di %{name}\n    unfollow: Dessequar\n  admin:\n    accounts:\n      are_you_sure: Ka tu esas certa?\n      email: E-mail\n      perform_full_suspension: Perform full suspension\n      show:\n        created_reports: Reports created by this account\n        targeted_reports: Reports made about this account\n    domain_blocks:\n      add_new: Add new\n      new:\n        severity:\n          desc_html: \"<strong>Silence</strong> will make the account's posts invisible to anyone who isn't following them. <strong>Suspend</strong> will remove all of the account's content, media, and profile data.\"\n      show:\n        retroactive:\n          silence: Unsilence all existing accounts from this domain\n          suspend: Unsuspend all existing accounts from this domain\n      undo: Undo\n    instances:\n      title: Known Instances\n    settings:\n      contact_information:\n        email: Enter a public e-mail address\n        username: Enter a username\n      registrations:\n        closed_message:\n          desc_html: Displayed on frontpage when registrations are closed<br>You can use HTML tags\n      site_description:\n        desc_html: Displayed as a paragraph on the frontpage and used as a meta tag.<br>You can use HTML tags, in particular <code>&lt;a&gt;</code> and <code>&lt;em&gt;</code>.\n        title: Site description\n      site_description_extended:\n        desc_html: Displayed on extended information page<br>You can use HTML tags\n        title: Extended site description\n      site_title: Site title\n      title: Site Settings\n  application_mailer:\n    settings: 'Chanjar la retpost-mesajala preferi: %{link}'\n    view: 'Vidar:'\n  applications:\n    invalid_url: La URL donita ne esas valida\n  auth:\n    didnt_get_confirmation: Ka tu ne recevis la instrucioni por konfirmar?\n    forgot_password: Pasvorto obliviita?\n    login: Enirar\n    logout: Ekirar\n    register: Membreskar\n    resend_confirmation: Risendar la instrucioni por konfirmar\n    reset_password: Chanjar la pasvorto\n    security: Chanjar pasvorto\n    set_new_password: Selektar nova pasvorto\n  authorize_follow:\n    error: Regretinde, eventis eraro probante konsultar la fora konto\n    follow: Sequar\n    title: Sequar %{acct}\n  datetime:\n    distance_in_words:\n      half_a_minute: Jus\n      less_than_x_seconds: Jus\n  errors:\n    '403': You don't have permission to view this page.\n    '404': La pagino quan tu serchas ne existas.\n    '410': La pagino quan tu serchas ne plus existas.\n    '422': \n    '429': Throttled\n    '500': \n  exports:\n    blocks: Tu blokusas\n    follows: Tu sequas\n    storage: Konservado di kontenajo\n  generic:\n    changes_saved_msg: Chanji senprobleme konservita!\n    save_changes: Konservar la chanji\n    validation_errors:\n      one: Ulo ne eventis senprobleme! Voluntez konsultar la suba eror-raporto\n      other: Ulo ne eventis senprobleme! Voluntez konsultar la suba %{count} eror-raporti\n  imports:\n    preface: Tu povas importacar kelka datumi, tal quala listi de omna homi quin tu sequas o blokusas, a tua konto di ca instaluro, per dosiero exportacita de altra instaluro.\n    success: Tua datumi esis senprobleme importacita ed esos traktita quale projetita\n    types:\n      blocking: Listo de blokusiti\n      following: Listo de sequati\n    upload: Kargar\n  invites:\n    expires_in:\n      '1800': 30 minutes\n      '21600': 6 hours\n      '3600': 1 hour\n      '43200': 12 hours\n      '604800': 1 week\n      '86400': 1 day\n  notification_mailer:\n    digest:\n      body: Yen mikra rezumo di to, depos ke tu laste vizitis en %{since}\n      mention: \"%{name} mencionis tu en:\"\n      new_followers_summary:\n        one: Tu obtenis nova sequanto! Yey!\n        other: Tu obtenis %{count} nova sequanti! Astonive!\n      subject:\n        one: \"1 nova savigo depos tua lasta vizito \\U0001F418\"\n        other: \"%{count} nova savigi depos tua lasta vizito \\U0001F418\"\n    favourite:\n      body: \"%{name} favoris tua mesajo:\"\n      subject: \"%{name} favoris tua mesajo\"\n    follow:\n      body: \"%{name} sequeskas tu!\"\n      subject: \"%{name} sequeskas tu\"\n    follow_request:\n      body: \"%{name} demandis sequar tu\"\n      subject: \"%{name} demandis sequar tu\"\n    mention:\n      body: \"%{name} mencionis tu en:\"\n      subject: \"%{name} mencionis tu\"\n    reblog:\n      body: \"%{name} diskonocigis tua mesajo:\"\n      subject: \"%{name} diskonocigis tua mesajo\"\n  pagination:\n    next: Sequanta\n    prev: Preiranta\n  remote_follow:\n    acct: Enpozez tua uzernomo@instaluro de ube tu volas sequar ta uzero\n    missing_resource: La URL di plussendado ne povis esar trovita\n    proceed: Durar por plussendar\n    prompt: 'Tu sequeskos:'\n  settings:\n    authorized_apps: Yurizita apliki\n    back: Retro a Mastodon\n    edit_profile: Redaktar la profilo\n    export: Exportacar datumi\n    import: Importacar\n    preferences: Preferi\n    two_factor_authentication: Dufaktora autentikigo\n  statuses:\n    open_in_web: Apertar retnavigile\n    over_character_limit: limito de %{max} signi ecesita\n    show_more: Montrar plue\n    visibilities:\n      private: Montrar nur a sequanti\n      public: Publika\n      unlisted: Publika, ma ne aperos en publika tempolinei\n  stream_entries:\n    reblogged: diskonocigita\n    sensitive_content: Titiliva kontenajo\n  two_factor_authentication:\n    description_html: Se tu posibligas <strong>dufaktora autentikigo</strong>, tu bezonos tua poshtelefonilo por enirar, nam ol kreos nombri, quin tu devos enskribar.\n    disable: Extingar\n    enable: Acendar\n    generate_recovery_codes: Generate Recovery Codes\n    instructions_html: \"<strong>Skanez ta QR-kodexo per Google Authenticator o per simila apliko di tua poshtelefonilo</strong>. De lore, la apliko kreos nombri, quin tu devos enskribar.\"\n    recovery_instructions_html: If you ever lose access to your phone, you can use one of the recovery codes below to regain access to your account. Keep the recovery codes safe, for example by printing them and storing them with other important documents.\n  users:\n    invalid_email: La retpost-adreso ne esas valida\n    invalid_otp_token: La dufaktora autentikigila kodexo ne esas valida\n"
  },
  {
    "path": "config/locales/it.yml",
    "content": "---\nit:\n  about:\n    about_hashtag_html: Questi sono i toot pubblici etichettati con <strong>#%{hashtag}</strong>. Puoi interagire con loro se hai un account nel fediverse.\n    about_mastodon_html: Mastodon è un social network <em>gratuito e open-source</em>. Un'alternativa <em>decentralizzata</em> alle piattaforme commerciali che evita che una singola compagnia monopolizzi il tuo modo di comunicare. Scegli un server di cui ti fidi &mdash; qualunque sia la tua scelta, potrai interagire con chiunque altro. Chiunque può sviluppare un suo server Mastodon e partecipare alla vita del <em>social network</em>.\n    about_this: A proposito di questo server\n    active_count_after: attivo\n    active_footnote: Utenti Attivi Mensili (MAU)\n    administered_by: 'Amministrato da:'\n    apps: Applicazioni Mobile\n    apps_platforms: Usa Mastodon da iOS, Android e altre piattaforme\n    contact: Contatti\n    contact_missing: Non impostato\n    contact_unavailable: N/D\n    documentation: Documentazione\n    extended_description_html: |\n      <h3>Un buon posto per le regole</h3>\n      <p>La descrizione estesa non è ancora stata preparata.</p>\n    generic_description: \"%{domain} è un server nella rete\"\n    get_apps: Prova l'app per smartphone\n    hosted_on: Mastodon ospitato su %{domain}\n    learn_more: Scopri altro\n    privacy_policy: Politica della privacy\n    source_code: Codice sorgente\n    status_count_before: Che hanno pubblicato\n    tagline: Segui vecchi amici e trovane nuovi\n    terms: Termini di Servizio\n    user_count_after:\n      one: utente\n      other: utenti\n    user_count_before: Home di\n    what_is_mastodon: Che cos'è Mastodon?\n  accounts:\n    choices_html: 'Suggerimenti da %{name}:'\n    follow: Segui\n    followers:\n      one: Seguace\n      other: Seguaci\n    following: Segui\n    joined: Dal %{date}\n    last_active: ultima attività\n    link_verified_on: La proprietà di questo link è stata controllata il %{date}\n    moved_html: \"%{name} è stato spostato su %{new_profile_link}:\"\n    network_hidden: Questa informazione non e' disponibile\n    nothing_here: Qui non c'è nulla!\n    people_followed_by: Persone seguite da %{name}\n    people_who_follow: Persone che seguono %{name}\n    pin_errors:\n      following: Devi gia seguire la persona che vuoi promuovere\n    posts_tab_heading: Toot\n    posts_with_replies: Toot e risposte\n    reserved_username: Il nome utente è gia stato preso\n    roles:\n      admin: Amministratore\n      moderator: Moderatore\n    unfollow: Non seguire più\n  admin:\n    account_actions:\n      action: Esegui azione\n      title: Esegui azione di moderazione su %{acct}\n    account_moderation_notes:\n      create: Lascia nota\n      created_msg: Nota di moderazione creata con successo!\n      delete: Elimina\n      destroyed_msg: Nota di moderazione distrutta con successo!\n    accounts:\n      are_you_sure: Sei sicuro?\n      by_domain: Dominio\n      change_email:\n        changed_msg: Account email cambiato con successo!\n        current_email: Email corrente\n        label: Cambia email\n        new_email: Nuova email\n        submit: Cambia email\n        title: Cambia email per %{username}\n      confirm: Conferma\n      confirmed: Confermato\n      confirming: Confermando\n      deleted: Cancellato\n      demote: Declassa\n      disable: Disabilita\n      disable_two_factor_authentication: Disabilita 2FA\n      disabled: Disabilitato\n      display_name: Nome visualizzato\n      domain: Dominio\n      edit: Modifica\n      email_status: Stato email\n      enable: Abilita\n      enabled: Abilitato\n      feed_url: URL Feed\n      followers: Follower\n      followers_url: URL follower\n      follows: Segue\n      header: Intestazione\n      inbox_url: URL inbox\n      invited_by: Invitato da\n      joined: Unito\n      location:\n        all: Tutto\n        local: Locale\n        remote: Remoto\n        title: Luogo\n      login_status: Stato login\n      media_attachments: Media allegati\n      memorialize: Trasforma in memoriam\n      moderation:\n        active: Attivo\n        all: Tutto\n        silenced: Silenziati\n        suspended: Sospesi\n        title: Moderazione\n      moderation_notes: Note di moderazione\n      most_recent_activity: Attività più recenti\n      most_recent_ip: IP più recenti\n      no_limits_imposed: Nessun limite imposto\n      not_subscribed: Non sottoscritto\n      outbox_url: URL outbox\n      perform_full_suspension: Sospendi\n      profile_url: URL profilo\n      promote: Promuovi\n      protocol: Protocollo\n      public: Pubblico\n      push_subscription_expires: Sottoscrizione PuSH scaduta\n      redownload: Aggiorna avatar\n      remove_avatar: Rimuovi avatar\n      remove_header: Rimuovi intestazione\n      resend_confirmation:\n        already_confirmed: Questo utente è già confermato\n        send: Reinvia email di conferma\n        success: Email di conferma inviata con successo!\n      reset: Reimposta\n      reset_password: Reimposta password\n      resubscribe: Riscriversi\n      role: Permessi\n      roles:\n        admin: Amministratore\n        moderator: Moderatore\n        staff: Personale\n        user: Utente\n      salmon_url: URL Salmone\n      search: Cerca\n      shared_inbox_url: URL Inbox Condiviso\n      show:\n        created_reports: Rapporti creati da questo account\n        targeted_reports: Rapporti che riguardano questo account\n      silence: Silenzia\n      silenced: Silenziato\n      statuses: Stati\n      subscribe: Sottoscrivi\n      suspended: Sospeso\n      title: Account\n      unconfirmed_email: Email non confermata\n      undo_silenced: Rimuovi silenzia\n      undo_suspension: Rimuovi sospensione\n      unsubscribe: Annulla l'iscrizione\n      username: Nome utente\n      warn: Avverti\n    action_logs:\n      actions:\n        assigned_to_self_report: \"%{name} ha assegnato il rapporto %{target} a se stesso\"\n        change_email_user: \"%{name} ha cambiato l'indirizzo email per l'utente %{target}\"\n        confirm_user: \"%{name} ha confermato l'indirizzo email per l'utente %{target}\"\n        create_account_warning: \"%{name} ha mandato un avvertimento a %{target}\"\n        create_custom_emoji: \"%{name} ha caricato un nuovo emoji %{target}\"\n        create_domain_block: \"%{name} ha bloccato il dominio %{target}\"\n        create_email_domain_block: \"%{name} ha messo il dominio email %{target} nella blacklist\"\n        demote_user: \"%{name} ha degradato l'utente %{target}\"\n        destroy_custom_emoji: \"%{name} ha distrutto l'emoji %{target}\"\n        destroy_domain_block: \"%{name} ha sbloccato il dominio %{target}\"\n        destroy_email_domain_block: \"%{name}ha messo il dominio email %{target} nella whitelist\"\n        destroy_status: \"%{name} ha eliminato lo status di %{target}\"\n        disable_2fa_user: \"%{name} ha disabilitato l'obbligo dei due fattori per l'utente %{target}\"\n        disable_custom_emoji: \"%{name} ha disabilitato l'emoji %{target}\"\n        disable_user: \"%{name} ha disabilitato il login per l'utente %{target}\"\n        enable_custom_emoji: \"%{name} ha abilitato l'emoji %{target}\"\n        enable_user: \"%{name} ha abilitato il login per l'utente %{target}\"\n        memorialize_account: \"%{name} ha trasformato l'account di %{target} in una pagina in memoriam\"\n        promote_user: \"%{name} ha promosso l'utente %{target}\"\n        remove_avatar_user: \"%{name} ha eliminato l'avatar di %{target}\"\n        reopen_report: \"%{name} ha riaperto il rapporto %{target}\"\n        reset_password_user: \"%{name} ha reimpostato la password dell'utente %{target}\"\n        resolve_report: \"%{name} ha risolto il rapporto %{target}\"\n        silence_account: \"%{name} ha silenziato l'account di %{target}\"\n        suspend_account: \"%{name} ha sospeso l'account di %{target}\"\n        unassigned_report: \"%{name} report non assegnato %{target}\"\n        unsilence_account: \"%{name} ha de-silenziato l'account di %{target}\"\n        unsuspend_account: \"%{name} ha annullato la sospensione dell'account di %{target}\"\n        update_custom_emoji: \"%{name} ha aggiornato l'emoji %{target}\"\n        update_status: \"%{name} stato aggiornato da %{target}\"\n      deleted_status: \"(stato cancellato)\"\n    custom_emojis:\n      by_domain: Dominio\n      copied_msg: Creata con successo una copia locale dell'emoji\n      copy: Copia\n      copy_failed_msg: Impossibile creare una copia locale di questo emoji\n      created_msg: Emoji creato con successo!\n      delete: Elimina\n      destroyed_msg: Emoji distrutto con successo!\n      disable: Disabilita\n      disabled_msg: Questa emoji è stata disabilitata con successo\n      enable: Abilita\n      enabled_msg: Questa emoji è stata abilitata con successo\n      image_hint: PNG fino a 50 KB\n      listed: Elencato\n      new:\n        title: Aggiungi nuovo emoji personalizzato\n      overwrite: Sovrascrivi\n      shortcode_hint: Almeno due caratteri, solo caratteri alfanumerici e trattino basso\n      title: Emoji personalizzate\n      unlisted: Non elencato\n      update_failed_msg: Impossibile aggiornare questa emojii\n      updated_msg: Emoji aggiornata con successo!\n      upload: Carica\n    dashboard:\n      config: Configurazione\n      feature_deletions: Cancellazioni di account\n      feature_invites: Link di invito\n      feature_profile_directory: Directory dei profili\n      feature_registrations: Registrazioni\n      feature_relay: Ripetitore di federazione\n      features: Funzionalità\n      hidden_service: Federazione con servizi nascosti\n      open_reports: apri report\n      recent_users: Utenti Recenti\n      search: Ricerca testo intero\n      single_user_mode: Modalita utente singolo\n      space: Utilizzo dello spazio\n      total_users: utenti totali\n      trends: Tendenze\n      week_interactions: interazioni per questa settimana\n      week_users_active: attivi questa settimana\n      week_users_new: utenti questa settimana\n    domain_blocks:\n      add_new: Aggiungi nuovo\n      created_msg: Il blocco del dominio sta venendo processato\n      destroyed_msg: Il blocco del dominio è stato rimosso\n      domain: Dominio\n      new:\n        create: Crea blocco\n        hint: Il blocco dominio non previene la creazione di utenti nel database, ma applicherà automaticamente e retroattivamente metodi di moderazione specifici su quegli account.\n        severity:\n          desc_html: \"<strong>Silenzia</strong> rende i post di questo account invisibili a chiunque non lo stia seguendo. <strong>Sospendi</strong> elimina tutti i contenuti, media e dati del profilo dell'account. Usa <strong>Nessuno</strong> se vuoi solo bloccare i file media.\"\n          noop: Nessuno\n          silence: Silenzia\n          suspend: Sospendi\n        title: Nuovo blocco dominio\n      reject_media: Rifiuta file media\n      reject_media_hint: Rimuovi i file media salvati in locale e blocca i download futuri. Irrilevante per le sospensioni\n      reject_reports: Respingi rapporti\n      reject_reports_hint: Ignora tutti i rapporti provenienti da questo dominio. Irrilevante per sospensioni\n      severity:\n        silence: silenziato\n        suspend: sospeso\n      show:\n        affected_accounts:\n          one: Interessato un solo account nel database\n          other: Interessati %{count} account nel database\n        retroactive:\n          silence: De-silenzia tutti gli account esistenti da questo dominio\n          suspend: Annulla la sospensione di tutti gli account esistenti da questo dominio\n        title: Annulla il blocco del dominio per %{domain}\n        undo: Annulla\n      undo: Annulla\n    email_domain_blocks:\n      add_new: Aggiungi nuovo\n      created_msg: Dominio email aggiunto con successo alla lista nera\n      delete: Elimina\n      destroyed_msg: Dominio email cancellato con successo dalla lista nera\n      domain: Dominio\n      new:\n        create: Aggiungi dominio\n        title: Nuova voce della lista nera delle email\n      title: Lista nera email\n    followers:\n      back_to_account: Torna all'account\n      title: Seguaci di %{acct}\n    instances:\n      by_domain: Dominio\n      known_accounts:\n        one: \"%{count} account noto\"\n        other: \"%{count} account noti\"\n      moderation:\n        limited: Limitato\n        title: Moderazione\n      title: Istanze conosciute\n      total_blocked_by_us: Bloccato da noi\n      total_followed_by_them: Seguito da loro\n      total_followed_by_us: Seguito da noi\n      total_storage: Media allegati\n    invites:\n      deactivate_all: Disattiva tutto\n      filter:\n        all: Tutto\n        available: Disponibile\n        expired: Scaduto\n        title: Filtro\n      title: Inviti\n    relays:\n      add_new: Aggiungi ripetitore\n      delete: Cancella\n      description_html: Un <strong>ripetitore di federazione</strong> è un server che fa da intermediario e scambia grandi quantità di toot pubblici tra server che si collegano e pubblicano su di esso. <strong>Può aiutare server piccoli e medi a ottenere contenuti dal fediverse</strong>, che altrimenti riceverebbero solo se i loro utenti locali seguissero altre persone su server remoti.\n      disable: Disabilita\n      disabled: Disabilitato\n      enable: Abilita\n      enable_hint: Dopo l'attivazione, il vostro server riceverà tutti i toot pubblici da questo ripetitore, e inizierà a inviargli i suoi toot pubblici.\n      enabled: Abilitato\n      inbox_url: Url Relay\n      pending: In attesa dell'approvazione del ripetitore\n      save_and_enable: Salva e attiva\n      setup: Crea una connessione con un ripetitore\n      title: Ripetitori\n    report_notes:\n      created_msg: Nota rapporto creata!\n      destroyed_msg: Nota rapporto cancellata!\n    reports:\n      account:\n        report: rapporto\n      action_taken_by: Azione intrapresa da\n      are_you_sure: Sei sicuro?\n      assign_to_self: Assegna a me\n      assigned: Moderatore assegnato\n      comment:\n        none: Nessuno\n      created_at: Segnalato\n      mark_as_resolved: Segna come risolto\n      mark_as_unresolved: Segna come non risolto\n      notes:\n        create: Aggiungi nota\n        create_and_resolve: Risolvi con nota\n        create_and_unresolve: Riapri con nota\n        delete: Elimina\n        placeholder: Descrivi quali azioni sono state intraprese, o ogni altro aggiornamento rilevante...\n      reopen: Riapri rapporto\n      report: 'Rapporto #%{id}'\n      reported_account: Account segnalato\n      reported_by: Inviato da\n      resolved: Risolto\n      resolved_msg: Rapporto risolto!\n      status: Stato\n      title: Rapporti\n      unassign: Non assegnare\n      unresolved: Non risolto\n      updated_at: Aggiornato\n    settings:\n      activity_api_enabled:\n        desc_html: Conteggi degli status pubblicati localmente, degli utenti attivi e delle nuove registrazioni in gruppi settimanali\n        title: Pubblica statistiche aggregate circa l'attività dell'utente\n      bootstrap_timeline_accounts:\n        desc_html: Separa i nomi utente con virgola. Funziona solo con account locali e non bloccati. Quando vuoto, valido per tutti gli amministratori locali.\n        title: Seguiti predefiniti per i nuovi utenti\n      contact_information:\n        username: Nome utente del contatto\n      custom_css:\n        desc_html: Modifica l'aspetto con il CSS caricato in ogni pagina\n        title: CSS personalizzato\n      hero:\n        desc_html: Mostrata nella pagina iniziale. Almeno 600x100 px consigliati. Se non impostata, sarà usato il thumbnail del server\n        title: Immagine dell'eroe\n      mascot:\n        desc_html: Mostrata su più pagine. Almeno 293×205px consigliati. Se non impostata, sarò usata la mascotte predefinita\n        title: Immagine della mascotte\n      peers_api_enabled:\n        desc_html: Nomi di dominio che questo server ha incontrato nel fediverse\n        title: Pubblica elenco dei server scoperti\n      preview_sensitive_media:\n        desc_html: Le anteprime dei link su altri siti mostreranno un thumbnail anche se il media è segnato come sensibile\n        title: Mostra media sensibili nella anteprime OpenGraph\n      profile_directory:\n        desc_html: Permetti agli utenti di essere trovati\n        title: Attiva directory dei profili\n      registrations:\n        closed_message:\n          desc_html: Mostrato nella pagina iniziale quando le registrazioni sono chiuse. Puoi usare tag HTML\n          title: Messaggio per registrazioni chiuse\n        deletion:\n          desc_html: Consenti a chiunque di cancellare il proprio account\n          title: Apri la cancellazione dell'account\n        min_invite_role:\n          disabled: Nessuno\n          title: Permetti inviti da\n      show_known_fediverse_at_about_page:\n        desc_html: Quando attivato, mostra nell'anteprima i toot da tutte le istanze conosciute. Altrimenti mostra solo i toot locali.\n        title: Mostra la fediverse conosciuta nell'anteprima della timeline\n      show_staff_badge:\n        title: Mostra badge staff\n      site_description:\n        desc_html: Paragrafo introduttivo nella pagina iniziale. Descrive ciò che rende speciale questo server Mastodon e qualunque altra cosa sia importante dire. Potete usare marcatori HTML, in particolare <code>&lt;a&gt;</code> e <code>&lt;em&gt;</code>.\n        title: Descrizione del server\n      site_description_extended:\n        desc_html: Un posto adatto per pubblicare regole di comportamento, linee guida e altre cose specifiche del vostro server. Potete usare marcatori HTML\n        title: Informazioni estese personalizzate\n      site_short_description:\n        desc_html: Mostrato nella barra laterale e nei tag meta. Descrive in un paragrafo che cos'è Mastodon e che cosa rende questo server speciale. Se vuoto, sarà usata la descrizione predefinita del server.\n        title: Breve descrizione del server\n      site_terms:\n        desc_html: Potete scrivere la vostra politica sulla privacy, condizioni del servizio o altre informazioni legali. Potete usare tag HTML\n        title: Termini di servizio personalizzati\n      site_title: Nome del server\n      thumbnail:\n        desc_html: Usato per anteprime tramite OpenGraph e API. 1200x630px consigliati\n        title: Thumbnail del server\n      timeline_preview:\n        desc_html: Mostra la timeline pubblica sulla pagina iniziale\n        title: Anteprima timeline\n      title: Impostazioni sito\n    statuses:\n      back_to_account: Torna alla pagina dell'account\n      batch:\n        delete: Elimina\n        nsfw_off: Segna come non sensibile\n        nsfw_on: Segna come sensibile\n      failed_to_execute: Impossibile eseguire\n      no_media: Nessun media\n      no_status_selected: Nessun status è stato modificato perché nessuno era stato selezionato\n      title: Gli status dell'account\n      with_media: con media\n    subscriptions:\n      callback_url: URL Callback\n      confirmed: Confermato\n      expires_in: Scade in\n      topic: Argomento\n    tags:\n      accounts: Account\n      hidden: Nascosto\n      hide: Non mostrare nella directory\n      title: Hashtag\n      unhide: Mostra nella directory\n      visible: Visibile\n    title: Amministrazione\n    warning_presets:\n      add_new: Aggiungi nuovo\n      delete: Cancella\n      edit: Modifica\n      edit_preset: Modifica avviso predefinito\n      title: Gestisci avvisi predefiniti\n  application_mailer:\n    notification_preferences: Cambia preferenze email\n    settings: 'Cambia le impostazioni per le email: %{link}'\n    view: 'Guarda:'\n    view_profile: Mostra profilo\n    view_status: Mostra stati\n  applications:\n    created: Applicazione creata con successo\n    destroyed: Applicazione eliminata con successo\n    invalid_url: L'URL fornito non è valido\n    regenerate_token: Rigenera il token di accesso\n    token_regenerated: Token di accesso rigenerato\n    warning: Fa' molta attenzione con questi dati. Non fornirli mai a nessun altro!\n  auth:\n    confirm_email: Conferma email\n    delete_account: Elimina account\n    delete_account_html: Se desideri cancellare il tuo account, puoi <a href=\"%{path}\">farlo qui</a>. Ti sarà chiesta conferma.\n    didnt_get_confirmation: Non hai ricevuto le istruzioni di conferma?\n    forgot_password: Hai dimenticato la tua password?\n    login: Entra\n    logout: Esci da Mastodon\n    migrate_account: Sposta ad un account differente\n    migrate_account_html: Se vuoi che questo account sia reindirizzato a uno diverso, puoi <a href=\"%{path}\">configurarlo qui</a>.\n    or_log_in_with: Oppure accedi con\n    register: Iscriviti\n    resend_confirmation: Invia di nuovo le istruzioni di conferma\n    reset_password: Resetta la password\n    security: Credenziali\n    set_new_password: Imposta una nuova password\n  authorize_follow:\n    already_following: Stai già seguendo questo account\n    error: Sfortunatamente c'è stato un errore nel consultare l'account remoto\n    follow: Segui\n    follow_request: 'Hai mandato una richiesta di diventare seguace a:'\n    following: 'Accettato! Ora stai seguendo:'\n    post_follow:\n      close: Oppure puoi chiudere questa finestra.\n      return: Mostra il profilo dell'utente\n      web: Vai al web\n    title: Segui %{acct}\n  datetime:\n    distance_in_words:\n      about_x_hours: \"%{count} ore\"\n      about_x_months: \"%{count} mesi\"\n      about_x_years: \"%{count} anni\"\n      almost_x_years: \"%{count} anni\"\n      half_a_minute: Adesso\n      less_than_x_minutes: \"%{count} minuti\"\n      less_than_x_seconds: Adesso\n      over_x_years: \"%{count} anni\"\n      x_days: \"%{count} giorni\"\n      x_minutes: \"%{count} minuti\"\n      x_months: \"%{count} mesi\"\n      x_seconds: \"%{count} secondi\"\n  deletes:\n    bad_password_msg: Ci avete provato, hacker! Password errata\n    confirm_password: Inserisci la tua password attuale per verificare la tua identità\n    description_html: Questa azione eliminerà <strong>in modo permanente e irreversibile</strong> tutto il contenuto del tuo account e lo disattiverà. Il tuo nome utente resterà riservato per prevenire che qualcuno in futuro assuma la tua identità.\n    proceed: Cancella l'account\n    success_msg: Il tuo account è stato cancellato\n    warning_html: È garantita la cancellazione del contenuto solo da questo server. I contenuti che sono stati ampiamente condivisi probabilmente lasceranno delle tracce. I server offline e quelli che non ricevono più i tuoi aggiornamenti non aggiorneranno i loro database.\n  directories:\n    directory: Directory dei profili\n    enabled: Attualmente sei elencato nella directory.\n    enabled_but_waiting: Hai scelto di essere elencato nella directory, ma non hai ancora il numero minimo di seguaci (%{min_followers}) per comparire.\n    explanation: Scopri utenti in base ai loro interessi\n    explore_mastodon: Esplora %{title}\n    how_to_enable: Attualmente non hai scelto di comparire nella directory. Puoi farlo qui sotto. Se vuoi comparire sotto determinati hashtag, usali nel testo della tua biografia.\n    people:\n      one: \"%{count} persona\"\n      other: \"%{count} persone\"\n  errors:\n    '403': Non sei autorizzato a visualizzare questa pagina.\n    '404': La pagina che stavi cercando non esiste.\n    '410': La pagina che stavi cercando qui non esiste più.\n    '422':\n      content: Verifica di sicurezza non riuscita. Stai bloccando i cookies?\n      title: Verifica di sicurezza non riuscita\n    '429': Throttled\n    '500':\n      content: Siamo spiacenti, ma qualcosa non ha funzionato dal nostro lato.\n      title: Questa pagina non è corretta\n    noscript_html: Per usare l'interfaccia web di Mastodon dovi abilitare JavaScript. In alternativa puoi provare una delle <a href=\"%{apps_path}\">app native</a> per Mastodon per la tua piattaforma.\n  exports:\n    archive_takeout:\n      date: Data\n      download: Scarica il tuo archivio\n      hint_html: Puoi richiedere un archivio dei tuoi <strong>toot e media caricati</strong>. I dati esportati sono in formato ActivityPub, leggibili da qualunque software che segue questo standard. Puoi richiedere un archivio ogni 7 giorni.\n      in_progress: Creazione archivio...\n      request: Richiedi il tuo archivio\n      size: Dimensioni\n    blocks: Stai bloccando\n    domain_blocks: Blocchi di dominio\n    follows: Stai seguendo\n    lists: Liste\n    mutes: Stai silenziando\n    storage: Archiviazione media\n  featured_tags:\n    add_new: Aggiungi nuovo\n    errors:\n      limit: Hai già messo in evidenza il numero massimo di hashtag\n  filters:\n    contexts:\n      home: Timeline home\n      notifications: Notifiche\n      public: Timeline pubbliche\n      thread: Conversazioni\n    edit:\n      title: Modifica filtro\n    errors:\n      invalid_context: Contesto mancante o non valido\n    index:\n      delete: Cancella\n      title: Filtri\n    new:\n      title: Aggiungi filtro\n  footer:\n    developers: Sviluppatori\n    more: Altro…\n  generic:\n    changes_saved_msg: Modifiche effettuate con successo!\n    copy: Copia\n    save_changes: Salva modifiche\n    validation_errors:\n      one: Qualcosa ancora non va bene! Per favore, controlla l'errore qui sotto\n      other: Qualcosa ancora non va bene! Per favore, controlla i %{count} errori qui sotto\n  imports:\n    modes:\n      merge: Fondi\n      merge_long: Mantieni record esistenti e aggiungine di nuovi\n      overwrite: Sovrascrivi\n      overwrite_long: Sostituisci record attuali con quelli nuovi\n    preface: Puoi importare alcune informazioni, come le persone che segui o hai bloccato su questo server, da file creati da un'esportazione su un altro server.\n    success: Le tue impostazioni sono state importate correttamente e verranno applicate in breve tempo\n    types:\n      blocking: Lista dei bloccati\n      domain_blocking: Lista dei domini bloccati\n      following: Lista dei seguaci\n      muting: Lista dei silenziati\n    upload: Carica\n  invites:\n    delete: Disattiva\n    expired: Scaduto\n    expires_in:\n      '1800': 30 minuti\n      '21600': 6 ore\n      '3600': 1 ora\n      '43200': 12 ore\n      '604800': 1 settimana\n      '86400': 1 giorno\n    expires_in_prompt: Mai\n    generate: Genera\n    invited_by: 'Sei stato invitato da:'\n    max_uses:\n      one: un uso\n      other: \"%{count} utilizzi\"\n    max_uses_prompt: Nessun limite\n    prompt: Genera e condividi dei link con altri per concedere l'accesso a questo server\n    table:\n      expires_at: Scade\n      uses: Utilizzi\n    title: Invita persone\n  lists:\n    errors:\n      limit: Hai raggiunto il numero massimo di liste\n  media_attachments:\n    validations:\n      images_and_video: Impossibile allegare video a un post che contiene già immagini\n      too_many: Impossibile allegare più di 4 file\n  migrations:\n    acct: utente@dominio del nuovo account\n    currently_redirecting: 'Il tuo profilo sarà ridirezionato a:'\n    proceed: Salva\n    updated_msg: L'impostazione per la migrazione dell'account è sta aggiornata!\n  moderation:\n    title: Moderazione\n  notification_mailer:\n    digest:\n      action: Vedi tutte le notifiche\n      body: Ecco un breve riassunto di quello che ti sei perso dalla tua ultima visita del %{since}\n      mention: \"%{name} ti ha menzionato:\"\n      new_followers_summary:\n        one: E inoltre hai ricevuto un nuovo seguace mentre eri assente! Urrà!\n        other: Inoltre, hai acquisito %{count} nuovi seguaci mentre eri assente! Incredibile!\n      subject:\n        one: \"1 nuova notifica dalla tua ultima visita \\U0001F418\"\n        other: \"%{count} nuove notifiche dalla tua ultima visita \\U0001F418\"\n      title: In tua assenza…\n    favourite:\n      body: 'Il tuo status è stato apprezzato da %{name}:'\n      subject: \"%{name} ha apprezzato il tuo status\"\n      title: Nuovo preferito\n    follow:\n      body: \"%{name} ti sta seguendo!\"\n      subject: \"%{name} ti sta seguendo\"\n      title: Nuovo seguace\n    follow_request:\n      action: Gestisci richieste di essere seguito\n      body: \"%{name} ha chiesto di seguirti\"\n      subject: 'Seguace in sospeso: %{name}'\n      title: Nuova richiesta di essere seguito\n    mention:\n      action: Rispondi\n      body: 'Sei stato menzionato da %{name} su:'\n      subject: Sei stato menzionato da %{name}\n      title: Nuova menzione\n    reblog:\n      body: 'Il tuo status è stato condiviso da %{name}:'\n      subject: \"%{name} ha condiviso il tuo status\"\n      title: Nuova condivisione\n  pagination:\n    newer: Più recente\n    next: Avanti\n    older: Più vecchio\n    prev: Indietro\n  polls:\n    errors:\n      already_voted: Hai già votato in questo sondaggio\n      duration_too_long: è troppo lontano nel futuro\n      duration_too_short: è troppo presto\n      expired: Il sondaggio si è già concluso\n      over_character_limit: non possono essere più lunghi di %{max} caratteri ciascuno\n      too_few_options: deve avere più di un elemento\n      too_many_options: non può contenere più di %{max} elementi\n  preferences:\n    other: Altro\n  remote_follow:\n    acct: Inserisci il tuo username@dominio da cui vuoi seguire questo utente\n    missing_resource: Impossibile trovare l'URL di reindirizzamento richiesto per il tuo account\n    no_account_html: Non hai un account? Puoi <a href='%{sign_up_path}' target='_blank'>iscriverti qui</a>\n    proceed: Conferma\n    prompt: 'Stai per seguire:'\n  remote_interaction:\n    favourite:\n      proceed: Continua per segnare come apprezzato\n      prompt: 'Vuoi segnare questo toot come apprezzato:'\n    reblog:\n      proceed: Continua per condividere\n      prompt: 'Vuoi condividere questo toot:'\n    reply:\n      proceed: Continua per rispondere\n      prompt: 'Vuoi rispondere a questo toot:'\n  remote_unfollow:\n    error: Errore\n    title: Titolo\n    unfollowed: Non più seguito\n  scheduled_statuses:\n    over_daily_limit: Hai superato il limite di %{limit} toot programmati per questo giorno\n    over_total_limit: Hai superato il limite di %{limit} toot programmati\n    too_soon: La data di pubblicazione deve essere nel futuro\n  sessions:\n    activity: Ultima attività\n    browsers:\n      generic: Browser sconosciuto\n    current_session: Sessione corrente\n    description: \"%{browser} su %{platform}\"\n    explanation: Questi sono i browser da cui attualmente è avvenuto l'accesso al tuo account Mastodon.\n    platforms:\n      other: piattaforma sconosciuta\n    title: Sessioni\n  settings:\n    authorized_apps: Applicazioni autorizzate\n    back: Torna a Mastodon\n    delete: Cancellazione account\n    development: Sviluppo\n    edit_profile: Modifica profilo\n    export: Esporta impostazioni\n    featured_tags: Hashtag in evidenza\n    import: Importa\n    migrate: Migrazione dell'account\n    notifications: Notifiche\n    preferences: Preferenze\n    two_factor_authentication: Autenticazione a due fattori\n  statuses:\n    attached:\n      description: 'Allegato: %{attached}'\n      image:\n        one: \"%{count} immagine\"\n        other: \"%{count} immagini\"\n    boosted_from_html: Condiviso da %{acct_link}\n    disallowed_hashtags:\n      one: 'contiene un hashtag non permesso: %{tags}'\n      other: 'contiene gli hashtags non permessi: %{tags}'\n    language_detection: Individua lingua automaticamente\n    open_in_web: Apri sul Web\n    over_character_limit: Limite caratteri superato di %{max}\n    pin_errors:\n      limit: Hai già fissato in cima il massimo numero di toot\n      ownership: Non puoi fissare in cima un toot di qualcun altro\n      private: Un toot non pubblico non può essere fissato in cima\n      reblog: Un toot condiviso non può essere fissato in cima\n    poll:\n      total_votes:\n        one: \"%{count} voto\"\n        other: \"%{count} voti\"\n      vote: Vota\n    show_more: Mostra di più\n    sign_in_to_participate: Accedi per partecipare alla conversazione\n    visibilities:\n      private: Mostra solo ai tuoi seguaci\n      private_long: Mostra solo ai seguaci\n      public: Pubblico\n      public_long: Tutti lo possono vedere\n      unlisted: Pubblico, ma non visibile sulla timeline pubblica\n      unlisted_long: Tutti lo possono vedere, ma non compare nelle timeline pubbliche\n  stream_entries:\n    pinned: Toot fissato in cima\n    reblogged: condiviso\n    sensitive_content: Materiale sensibile\n  terms:\n    title: \"%{instance} Termini di servizio e politica della privacy\"\n  themes:\n    contrast: Mastodon (contrasto elevato)\n    default: Mastodon (scuro)\n    mastodon-light: Mastodon (chiaro)\n  two_factor_authentication:\n    code_hint: Inserisci il codice generato dalla tua app di autenticazione\n    description_html: Se abiliti <strong>l'autorizzazione a due fattori</strong>, entrare nel tuo account ti richiederà di avere vicino il tuo telefono, il quale ti genererà un codice per eseguire l'accesso.\n    disable: Disabilita\n    enable: Abilita\n    enabled: È abilitata l'autenticazione a due fattori\n    enabled_success: Autenticazione a due fattori attivata con successo\n    generate_recovery_codes: Genera codici di recupero\n    instructions_html: \"<strong>Scannerizza questo QR code con Google Authenticator o un'app TOTP simile sul tuo telefono</strong>. Da ora in poi, quell'applicazione genererà codici da inserire necessariamente per eseguire l'accesso.\"\n    lost_recovery_codes: I codici di recupero ti permettono di accedere al tuo account se perdi il telefono. Se hai perso i tuoi codici di recupero, puoi rigenerarli qui. Quelli vecchi saranno annullati.\n    manual_instructions: 'Se non puoi scannerizzare il QR code e hai bisogno di inserirlo manualmente, questo è il codice segreto in chiaro:'\n    recovery_codes: Codici di recupero del backup\n    recovery_codes_regenerated: I codici di recupero sono stati rigenerati\n    recovery_instructions_html: Se perdi il telefono, puoi usare uno dei codici di recupero qui sotto per riottenere l'accesso al tuo account. <strong>Conserva i codici di recupero in un posto sicuro</strong>. Ad esempio puoi stamparli e conservarli insieme ad altri documenti importanti.\n    setup: Configura\n    wrong_code: Il codice inserito non è corretto! Assicurati che l'orario del server e l'orario del dispositivo siano corretti.\n  user_mailer:\n    backup_ready:\n      explanation: Hai richiesto un backup completo del tuo account Mastodon. È pronto per essere scaricato!\n      subject: Il tuo archivio è pronto per essere scaricato\n      title: Esportazione archivio\n    welcome:\n      edit_profile_step: Puoi personalizzare il tuo profilo caricando un avatar, un'intestazione, modificando il tuo nome visualizzato e così via. Se vuoi controllare i tuoi nuovi seguaci prima di autorizzarli a seguirti, puoi bloccare il tuo account.\n      explanation: Ecco alcuni suggerimenti per iniziare\n      final_action: Inizia a postare\n      final_step: 'Inizia a postare! Anche se non hai seguaci, i tuoi messaggi pubblici possono essere visti da altri, ad esempio nelle timeline locali e negli hashtag. Se vuoi puoi presentarti con l''hashtag #introductions.'\n      full_handle: Il tuo nome utente completo\n      full_handle_hint: Questo è ciò che diresti ai tuoi amici in modo che possano seguirti o contattarti da un altro server.\n      review_preferences_action: Cambia preferenze\n      review_preferences_step: Dovresti impostare le tue preferenze, ad esempio quali email vuoi ricevere oppure il livello predefinito di privacy per i tuoi post. Se le immagini in movimento non ti danno fastidio, puoi abilitare l'animazione automatica delle GIF.\n      subject: Benvenuto/a su Mastodon\n      tip_federated_timeline: La timeline federata visualizza uno dopo l'altro i messaggi pubblicati su Mastodon. Ma comprende solo gli utenti seguiti dai tuoi vicini, quindi non è completa.\n      tip_following: Per impostazione predefinita, segui l'amministratore/i del tuo server. Per trovare utenti più interessanti, dà un'occhiata alle timeline locale e federata.\n      tip_local_timeline: La timeline locale visualizza uno dopo l'altro i messaggi degli utenti di %{instance}. Questi sono i tuoi vicini!\n      tip_mobile_webapp: Se il tuo browser mobile ti dà la possibilità di aggiungere Mastodon allo schermo, puoi ricevere le notifiche. Funziona un po' come un'app natova!\n      tips: Suggerimenti\n      title: Benvenuto a bordo, %{name}!\n  users:\n    follow_limit_reached: Non puoi seguire più di %{limit} persone\n    invalid_email: L'indirizzo email inserito non è valido\n    invalid_otp_token: Codice d'accesso non valido\n    seamless_external_login: Ti sei collegato per mezzo di un servizio esterno, quindi le impostazioni di email e password non sono disponibili.\n    signed_in_as: 'Hai effettuato l''accesso come:'\n  verification:\n    explanation_html: 'Puoi <strong>certificare te stesso come proprietario dei link nei metadati del tuo profilo</strong>. Per farlo, il sito a cui punta il link deve contenere un link che punta al tuo profilo Mastodon. Il link di ritorno <strong>deve</strong> avere l''attributo <code>rel=\"me\"</code>. Il testo del link non ha importanza. Ecco un esempio:'\n    verification: Verifica\n"
  },
  {
    "path": "config/locales/ja.yml",
    "content": "---\nja:\n  about:\n    about_hashtag_html: ハッシュタグ <strong>#%{hashtag}</strong> の付いた公開トゥートです。どこでもいいので、連合に参加しているSNS上にアカウントを作れば会話に参加することができます。\n    about_mastodon_html: Mastodon は、オープンなウェブプロトコルを採用した、自由でオープンソースなソーシャルネットワークです。電子メールのような分散型の仕組みを採っています。\n    about_this: 詳細情報\n    active_count_after: 人アクティブ\n    active_footnote: 月間アクティブユーザー数 (MAU)\n    administered_by: '管理者:'\n    api: API\n    apps: アプリ\n    apps_platforms: iOSやAndroidなど、各種環境から利用できます\n    browse_directory: ディレクトリから気になる人を探しましょう\n    browse_public_posts: Mastodonの公開ライブストリームをご覧ください\n    contact: 連絡先\n    contact_missing: 未設定\n    contact_unavailable: N/A\n    discover_users: ユーザーを見つける\n    documentation: ドキュメント\n    extended_description_html: |\n      <h3>ルールを書くのに適した場所</h3>\n      <p>詳細説明が設定されていません。</p>\n    federation_hint_html: \"%{instance} のアカウントひとつでどんなMastodon互換サーバーのユーザーでもフォローできるでしょう。\"\n    generic_description: \"%{domain} は、Mastodon サーバーの一つです\"\n    get_apps: モバイルアプリを試す\n    hosted_on: Mastodon hosted on %{domain}\n    learn_more: もっと詳しく\n    privacy_policy: プライバシーポリシー\n    see_whats_happening: やりとりを見てみる\n    server_stats: 'サーバー統計:'\n    source_code: ソースコード\n    status_count_after:\n      other: トゥート\n    status_count_before: トゥート数\n    tagline: Follow friends and discover new ones\n    terms: 利用規約\n    user_count_after:\n      other: 人\n    user_count_before: ユーザー数\n    what_is_mastodon: Mastodon とは？\n  accounts:\n    choices_html: \"%{name} によるおすすめ:\"\n    follow: フォロー\n    followers:\n      other: フォロワー\n    following: フォロー中\n    joined: \"%{date} に登録\"\n    last_active: 最後の活動\n    link_verified_on: このリンクの所有権は %{date} に確認されました\n    media: メディア\n    moved_html: \"%{name} さんは引っ越しました %{new_profile_link}:\"\n    network_hidden: この情報は利用できません\n    nothing_here: 何もありません！\n    people_followed_by: \"%{name} さんがフォロー中のアカウント\"\n    people_who_follow: \"%{name} さんをフォロー中のアカウント\"\n    pin_errors:\n      following: おすすめしたい人はあなたが既にフォローしている必要があります\n    posts:\n      other: トゥート\n    posts_tab_heading: トゥート\n    posts_with_replies: トゥートと返信\n    reserved_username: このユーザー名は予約されています\n    roles:\n      admin: Admin\n      bot: Bot\n      moderator: Mod\n    unavailable: プロフィールは利用できません\n    unfollow: フォロー解除\n  admin:\n    account_actions:\n      action: アクションを実行\n      title: \"%{acct}さんに対してアクションを実行\"\n    account_moderation_notes:\n      create: 書き込む\n      created_msg: モデレーションメモを書き込みました！\n      delete: 削除\n      destroyed_msg: モデレーションメモを削除しました！\n    accounts:\n      approve: 承認\n      approve_all: すべて承認\n      are_you_sure: 本当に実行しますか？\n      avatar: アイコン\n      by_domain: ドメイン\n      change_email:\n        changed_msg: メールアドレスの変更に成功しました！\n        current_email: 現在のメールアドレス\n        label: メールアドレスを変更\n        new_email: 新しいメールアドレス\n        submit: メールアドレスの変更\n        title: \"%{username} さんのメールアドレスを変更\"\n      confirm: 確認\n      confirmed: 確認済み\n      confirming: 確認中\n      deleted: 削除済み\n      demote: 降格\n      disable: 無効化\n      disable_two_factor_authentication: 二段階認証を無効にする\n      disabled: 無効\n      display_name: 表示名\n      domain: ドメイン\n      edit: 編集\n      email: メールアドレス\n      email_status: メールアドレスの状態\n      enable: 有効化\n      enabled: 有効\n      feed_url: フィードURL\n      followers: フォロワー数\n      followers_url: Followers URL\n      follows: フォロー数\n      header: ヘッダー\n      inbox_url: Inbox URL\n      invited_by: 招待した人\n      ip: IP\n      joined: 登録日\n      location:\n        all: すべて\n        local: ローカル\n        remote: リモート\n        title: ロケーション\n      login_status: ログイン\n      media_attachments: 添付されたメディア\n      memorialize: 追悼アカウント化\n      moderation:\n        active: アクティブ\n        all: すべて\n        pending: 承認待ち\n        silenced: サイレンス済み\n        suspended: 停止済み\n        title: モデレーション\n      moderation_notes: モデレーションメモ\n      most_recent_activity: 直近の活動\n      most_recent_ip: 直近のIP\n      no_account_selected: 何も選択されていないため、変更されていません\n      no_limits_imposed: 制限なし\n      not_subscribed: 購読していない\n      outbox_url: Outbox URL\n      pending: 承認待ち\n      perform_full_suspension: 活動を完全に停止させる\n      profile_url: プロフィールURL\n      promote: 昇格\n      protocol: プロトコル\n      public: パブリック\n      push_subscription_expires: PuSH購読期限\n      redownload: プロフィールを更新\n      reject: 却下\n      reject_all: すべて却下\n      remove_avatar: アイコンを削除\n      remove_header: ヘッダーを削除\n      resend_confirmation:\n        already_confirmed: メールアドレスは確認済みです\n        send: 確認メールを再送\n        success: 確認メールを再送信しました!\n      reset: リセット\n      reset_password: パスワード再設定\n      resubscribe: 再講読\n      role: 役割\n      roles:\n        admin: 管理者\n        moderator: モデレーター\n        staff: スタッフ\n        user: ユーザー\n      salmon_url: Salmon URL\n      search: 検索\n      shared_inbox_url: Shared inbox URL\n      show:\n        created_reports: このアカウントで作られた通報\n        targeted_reports: このアカウントについての通報\n      silence: サイレンス\n      silenced: サイレンス済み\n      statuses: トゥート数\n      subscribe: 購読する\n      suspended: 停止済み\n      time_in_queue: \"%{time} 待ち\"\n      title: アカウント\n      unconfirmed_email: 確認待ちのメールアドレス\n      undo_silenced: サイレンスから戻す\n      undo_suspension: 停止から戻す\n      unsubscribe: 購読の解除\n      username: ユーザー名\n      warn: 警告\n      web: Web\n    action_logs:\n      actions:\n        assigned_to_self_report: \"%{name} さんが通報 %{target} を自身の担当に割り当てました\"\n        change_email_user: \"%{name} さんが %{target} さんのメールアドレスを変更しました\"\n        confirm_user: \"%{name} さんが %{target} さんのメールアドレスを確認済みにしました\"\n        create_account_warning: \"%{name} さんが %{target} さんに警告メールを送信しました\"\n        create_custom_emoji: \"%{name} さんがカスタム絵文字 %{target} を追加しました\"\n        create_domain_block: \"%{name} さんがドメイン %{target} をブロックしました\"\n        create_email_domain_block: \"%{name} さんがドメイン %{target} をメールアドレス用ブラックリストに追加しました\"\n        demote_user: \"%{name} さんが %{target} さんを降格しました\"\n        destroy_custom_emoji: \"%{name} さんがカスタム絵文字 %{target} を削除しました\"\n        destroy_domain_block: \"%{name} さんがドメイン %{target} のブロックを外しました\"\n        destroy_email_domain_block: \"%{name} さんがドメイン %{target} をメールアドレス用ブラックリストから外しました\"\n        destroy_status: \"%{name} さんが %{target} さんの投稿を削除しました\"\n        disable_2fa_user: \"%{name} さんが %{target} さんの二段階認証を無効化しました\"\n        disable_custom_emoji: \"%{name} さんがカスタム絵文字 %{target} を無効化しました\"\n        disable_user: \"%{name} さんが %{target} さんのログインを無効化しました\"\n        enable_custom_emoji: \"%{name} さんがカスタム絵文字 %{target} を有効化しました\"\n        enable_user: \"%{name} さんが %{target} さんのログインを有効化しました\"\n        memorialize_account: \"%{name} さんが %{target} さんを追悼アカウントページに登録しました\"\n        promote_user: \"%{name} さんが %{target} さんを昇格しました\"\n        remove_avatar_user: \"%{name} さんが %{target} さんのアイコンを削除しました\"\n        reopen_report: \"%{name} さんが通報 %{target} を再び開きました\"\n        reset_password_user: \"%{name} さんが %{target} さんのパスワードをリセットしました\"\n        resolve_report: \"%{name} さんが通報 %{target} を解決済みにしました\"\n        silence_account: \"%{name} さんが %{target} さんをサイレンスにしました\"\n        suspend_account: \"%{name} さんが %{target} さんを停止しました\"\n        unassigned_report: \"%{name} さんが通報 %{target} の担当を外しました\"\n        unsilence_account: \"%{name} さんが %{target} さんのサイレンスを解除しました\"\n        unsuspend_account: \"%{name} さんが %{target} さんの停止を解除しました\"\n        update_custom_emoji: \"%{name} さんがカスタム絵文字 %{target} を更新しました\"\n        update_status: \"%{name} さんが %{target} さんの投稿を更新しました\"\n      deleted_status: \"(削除済)\"\n      title: 操作履歴\n    custom_emojis:\n      by_domain: ドメイン\n      copied_msg: 絵文字のコピーをローカルに作成しました\n      copy: コピー\n      copy_failed_msg: 絵文字のコピーをローカルに作成できませんでした\n      created_msg: 絵文字の追加に成功しました！\n      delete: 削除\n      destroyed_msg: 絵文字の削除に成功しました！\n      disable: 無効化\n      disabled_msg: 絵文字を無効化しました\n      emoji: 絵文字\n      enable: 有効化\n      enabled_msg: 絵文字を有効化しました\n      image_hint: 50KBまでのPNG画像を利用できます\n      listed: 収載\n      new:\n        title: 新規カスタム絵文字の追加\n      overwrite: 上書き\n      shortcode: ショートコード\n      shortcode_hint: 2文字以上の半角英数字とアンダーバーのみ利用できます\n      title: カスタム絵文字\n      unlisted: 未収載\n      update_failed_msg: 絵文字を更新できませんでした\n      updated_msg: 絵文字の更新に成功しました！\n      upload: アップロード\n    dashboard:\n      backlog: 未処理のジョブ\n      config: 構成\n      feature_deletions: アカウント削除\n      feature_invites: 招待リンク\n      feature_profile_directory: ディレクトリ\n      feature_registrations: 新規登録\n      feature_relay: 連合リレー\n      feature_timeline_preview: タイムラインプレビュー\n      features: 機能\n      hidden_service: 秘匿サービスとの連合\n      open_reports: 未解決の通報\n      recent_users: 最近登録したユーザー\n      search: 全文検索\n      single_user_mode: シングルユーザーモード\n      software: ソフトウェア\n      space: ディスク使用量\n      title: ダッシュボード\n      total_users: 全ユーザー\n      trends: トレンドタグ\n      week_interactions: 今週交流のあった回数\n      week_users_active: 今週活動した人数\n      week_users_new: 今週登録した人数\n    domain_blocks:\n      add_new: ドメインブロックを追加\n      created_msg: ドメインブロック処理を完了しました\n      destroyed_msg: ドメインブロックを外しました\n      domain: ドメイン\n      existing_domain_block_html: 既に%{name}に対して、より厳しい制限を課しています。先に<a href=\"%{unblock_url}\">その制限を解除</a>する必要があります。\n      new:\n        create: ブロックを作成\n        hint: ドメインブロックはデータベース中のアカウント項目の作成を妨げませんが、遡って自動的に指定されたモデレーションをそれらのアカウントに適用します。\n        severity:\n          desc_html: \"<strong>サイレンス</strong>はアカウントのトゥートをフォローしていない人から隠します。<strong>停止</strong>はそのアカウントのコンテンツ、メディア、プロフィールデータをすべて削除します。メディアファイルを拒否したいだけの場合は<strong>なし</strong>を使います。\"\n          noop: なし\n          silence: サイレンス\n          suspend: 停止\n        title: 新規ドメインブロック\n      reject_media: メディアファイルを拒否\n      reject_media_hint: ローカルに保存されたメディアファイルを削除し、今後のダウンロードを拒否します。停止とは無関係です\n      reject_reports: 通報を拒否\n      reject_reports_hint: このドメインからの通報をすべて無視します。停止とは無関係です\n      rejecting_media: メディアファイルを拒否中\n      rejecting_reports: 通報を拒否中\n      severity:\n        silence: サイレンス中\n        suspend: 停止中\n      show:\n        affected_accounts:\n          other: データベース中の%{count}個のアカウントに影響します\n        retroactive:\n          silence: このドメインの既存の影響するアカウントのサイレンスを戻す\n          suspend: このドメインの既存の影響するアカウントの停止を戻す\n        title: \"%{domain}のドメインブロックを戻す\"\n        undo: 元に戻す\n      undo: ドメインブロックを戻す\n    email_domain_blocks:\n      add_new: 新規追加\n      created_msg: ブラックリストに追加しました\n      delete: 消去\n      destroyed_msg: ブラックリストから外しました\n      domain: ドメイン\n      new:\n        create: ドメインを追加\n        title: メールアドレス用ブラックリスト新規追加\n      title: メールブラックリスト\n    followers:\n      back_to_account: 戻る\n      title: \"%{acct}さんのフォロワー\"\n    instances:\n      by_domain: ドメイン\n      delivery_available: 配送可能\n      known_accounts:\n        other: 既知のアカウント数 %{count}\n      moderation:\n        all: すべて\n        limited: 制限あり\n        title: モデレーション\n      title: 既知のサーバー\n      total_blocked_by_us: ブロック合計\n      total_followed_by_them: 被フォロー合計\n      total_followed_by_us: フォロー合計\n      total_reported: 通報合計\n      total_storage: 添付されたメディア\n    invites:\n      deactivate_all: すべて無効化\n      filter:\n        all: すべて\n        available: 使用可能\n        expired: 期限切れ\n        title: フィルター\n      title: 招待\n    pending_accounts:\n      title: 承認待ちアカウント (%{count})\n    relays:\n      add_new: リレーを追加\n      delete: 削除\n      description_html: \"<strong>連合リレー</strong>とは、登録しているサーバー間の公開トゥートを仲介するサーバーです。<strong>中小規模のサーバーが連合のコンテンツを見つけるのを助けます。</strong>これを使用しない場合、ローカルユーザーがリモートユーザーを手動でフォローする必要があります。\"\n      disable: 無効化\n      disabled: 無効\n      enable: 有効化\n      enable_hint: 有効にすると、リレーから全ての公開トゥートを受信するようになり、またこのサーバーの全ての公開トゥートをリレーに送信するようになります。\n      enabled: 有効\n      inbox_url: リレーURL\n      pending: リレーサーバーの承認待ちです\n      save_and_enable: 保存して有効にする\n      setup: リレー接続を設定する\n      status: ステータス\n      title: リレー\n    report_notes:\n      created_msg: 通報メモを書き込みました！\n      destroyed_msg: 通報メモを削除しました！\n    reports:\n      account:\n        note: メモ\n        report: 通報\n      action_taken_by: 通報処理者\n      are_you_sure: 本当に実行しますか？\n      assign_to_self: 担当になる\n      assigned: 担当者\n      comment:\n        none: なし\n      created_at: 通報日時\n      mark_as_resolved: 解決済みとしてマーク\n      mark_as_unresolved: 未解決として再び開く\n      notes:\n        create: 書き込む\n        create_and_resolve: 書き込み、解決済みにする\n        create_and_unresolve: 書き込み、未解決として開く\n        delete: 削除\n        placeholder: どのような措置が取られたか、または関連する更新を記述してください…\n      reopen: 再び開く\n      report: 通報#%{id}\n      reported_account: 報告対象アカウント\n      reported_by: 報告者\n      resolved: 解決済み\n      resolved_msg: 通報を解決済みにしました！\n      status: ステータス\n      title: 通報\n      unassign: 担当を外す\n      unresolved: 未解決\n      updated_at: 更新日時\n    settings:\n      activity_api_enabled:\n        desc_html: 週ごとのローカルに投稿されたトゥート数、アクティブなユーザー数、新規登録者数\n        title: ユーザーアクティビティに関する統計を公開する\n      bootstrap_timeline_accounts:\n        desc_html: 複数のユーザー名はコンマで区切ります。ローカルの公開アカウントのみ有効です。指定しない場合は管理者がデフォルトで指定されます。\n        title: 新規ユーザーが自動フォローするアカウント\n      contact_information:\n        email: ビジネスメールアドレス\n        username: 連絡先ユーザー名\n      custom_css:\n        desc_html: 全ページに適用されるCSSの編集\n        title: カスタムCSS\n      hero:\n        desc_html: フロントページに表示されます。サイズは600x100px以上推奨です。未設定の場合、標準のサムネイルが使用されます\n        title: ヒーローイメージ\n      mascot:\n        desc_html: 複数のページに表示されます。サイズは293x205px以上推奨です。未設定の場合、標準のマスコットが使用されます\n        title: マスコットイメージ\n      peers_api_enabled:\n        desc_html: 連合内でこのサーバーが遭遇したドメインの名前\n        title: 接続しているサーバーのリストを公開する\n      preview_sensitive_media:\n        desc_html: 他のウェブサイトにリンクを貼った際、メディアが閲覧注意としてマークされていてもサムネイルが表示されます\n        title: OpenGraphによるプレビューで閲覧注意のメディアも表示する\n      profile_directory:\n        desc_html: ユーザーが見つかりやすくできるようになります\n        title: ディレクトリを有効にする\n      registrations:\n        closed_message:\n          desc_html: 新規登録を停止しているときにフロントページに表示されます。HTMLタグが使えます\n          title: 新規登録停止時のメッセージ\n        deletion:\n          desc_html: 誰でも自分のアカウントを削除できるようにします\n          title: アカウント削除を受け付ける\n        min_invite_role:\n          disabled: 誰も許可しない\n          title: 招待の作成を許可\n      registrations_mode:\n        modes:\n          approved: 登録には承認が必要\n          none: 誰も許可しない\n          open: 誰でも登録可\n        title: 新規登録\n      show_known_fediverse_at_about_page:\n        desc_html: チェックを入れるとプレビュー欄に既知の連合先全てのトゥートを表示します。外すとローカルのトゥートだけ表示します。\n        title: タイムラインプレビューに連合タイムラインを表示する\n      show_staff_badge:\n        desc_html: ユーザーページにスタッフのバッジを表示します\n        title: スタッフバッジを表示する\n      site_description:\n        desc_html: フロントページへの表示に使用される紹介文です。このMastodonサーバーを特徴付けることやその他重要なことを記述してください。HTMLタグ、特に<code>&lt;a&gt;</code> と <code>&lt;em&gt;</code>が使えます。\n        title: サーバーの説明\n      site_description_extended:\n        desc_html: あなたのサーバーにおける行動規範やルール、ガイドライン、そのほかの記述をする際に最適な場所です。HTMLタグが使えます\n        title: カスタム詳細説明\n      site_short_description:\n        desc_html: サイドバーと meta タグに表示されます。Mastodon とは何か、そしてこのサーバーの特別な何かを1段落で記述してください。空欄の場合、サーバーの説明が使用されます。\n        title: 短いサーバーの説明\n      site_terms:\n        desc_html: 独自のプライバシーポリシーや利用規約、その他の法的根拠を記述できます。HTMLタグが使えます\n        title: カスタム利用規約\n      site_title: サーバーの名前\n      thumbnail:\n        desc_html: OpenGraphとAPIによるプレビューに使用されます。サイズは1200×630px推奨です\n        title: サーバーのサムネイル\n      timeline_preview:\n        desc_html: ランディングページに公開タイムラインを表示します\n        title: タイムラインプレビュー\n      title: サイト設定\n    statuses:\n      back_to_account: アカウントページに戻る\n      batch:\n        delete: 削除\n        nsfw_off: 閲覧注意をはずす\n        nsfw_on: 閲覧注意にする\n      failed_to_execute: 実行に失敗しました\n      media:\n        title: メディア\n      no_media: メディアなし\n      no_status_selected: 何も選択されていないため、変更されていません\n      title: トゥート一覧\n      with_media: メディアあり\n    subscriptions:\n      callback_url: コールバックURL\n      confirmed: 確認済み\n      expires_in: 期限\n      last_delivery: 最終配送\n      title: WebSub\n      topic: トピック\n    tags:\n      accounts: アカウント\n      hidden: 非表示\n      hide: ディレクトリから隠す\n      name: ハッシュタグ\n      title: ハッシュタグ\n      unhide: ディレクトリに表示する\n      visible: 表示\n    title: 管理\n    warning_presets:\n      add_new: 追加\n      delete: 削除\n      edit: 編集\n      edit_preset: プリセット警告文を編集\n      title: プリセット警告文を管理\n  admin_mailer:\n    new_pending_account:\n      body: 新しいアカウントの詳細は以下の通りです。この申請を承認または却下することができます。\n      subject: \"%{instance} で新しいアカウント (%{username}) が承認待ちです\"\n    new_report:\n      body: \"%{reporter} が %{target} を通報しました\"\n      body_remote: \"%{domain} の誰かが %{target} を通報しました\"\n      subject: \"%{instance} の新しい通報 (#%{id})\"\n  appearance:\n    advanced_web_interface: 上級者向け UI\n    advanced_web_interface_hint: ディスプレイを幅いっぱいまで活用したい場合、上級者向け UI をおすすめします。ホーム、通知、連合タイムライン、更にはリストやハッシュタグなど、様々な異なるカラムから望む限りの情報を一度に受け取れるような設定が可能になります。\n    animations_and_accessibility: アニメーションとアクセシビリティー\n    confirmation_dialogs: 確認ダイアログ\n    sensitive_content: 閲覧注意コンテンツ\n  application_mailer:\n    notification_preferences: メール設定の変更\n    salutation: \"%{name} さん\"\n    settings: 'メール設定の変更: %{link}'\n    view: 'リンク:'\n    view_profile: プロフィールを表示\n    view_status: トゥートを表示\n  applications:\n    created: アプリが作成されました\n    destroyed: アプリが削除されました\n    invalid_url: URLが無効です\n    regenerate_token: アクセストークンの再生成\n    token_regenerated: アクセストークンが再生成されました\n    warning: このデータは気をつけて取り扱ってください。他の人と共有しないでください！\n    your_token: アクセストークン\n  auth:\n    apply_for_account: 登録を申請する\n    change_password: パスワード\n    checkbox_agreement_html: <a href=\"%{rules_path}\" target=\"_blank\">サーバーのルール</a> と <a href=\"%{terms_path}\" target=\"_blank\">プライバシーポリシー</a> に同意します\n    confirm_email: メールアドレスの確認\n    delete_account: アカウントの削除\n    delete_account_html: アカウントを削除したい場合、<a href=\"%{path}\">こちら</a> から手続きが行えます。削除する前に、確認画面があります。\n    didnt_get_confirmation: 確認メールを受信できませんか？\n    forgot_password: パスワードをお忘れですか？\n    invalid_reset_password_token: パスワードリセットトークンが正しくないか期限切れです。もう一度リクエストしてください。\n    login: ログイン\n    logout: ログアウト\n    migrate_account: 別のアカウントに引っ越す\n    migrate_account_html: 引っ越し先を明記したい場合は<a href=\"%{path}\">こちら</a>で設定できます。\n    or_log_in_with: または次のサービスでログイン\n    providers:\n      cas: CAS\n      saml: SAML\n    register: 登録する\n    registration_closed: \"%{instance} は現在、新規登録停止中です\"\n    resend_confirmation: 確認メールを再送する\n    reset_password: パスワードを再発行\n    security: セキュリティ\n    set_new_password: 新しいパスワード\n    trouble_logging_in: ログインできませんか？\n  authorize_follow:\n    already_following: あなたは既にこのアカウントをフォローしています\n    error: 残念ながら、リモートアカウント情報の取得中にエラーが発生しました\n    follow: フォロー\n    follow_request: 'あなたは以下のアカウントにフォローリクエストを送信しました:'\n    following: '成功！ あなたは現在以下のアカウントをフォローしています:'\n    post_follow:\n      close: またはこのウィンドウを閉じます。\n      return: ユーザーのプロフィールを見る\n      web: Web を開く\n    title: \"%{acct} をフォロー\"\n  datetime:\n    distance_in_words:\n      about_x_hours: \"%{count}時間\"\n      about_x_months: \"%{count}月\"\n      about_x_years: \"%{count}年\"\n      almost_x_years: \"%{count}年\"\n      half_a_minute: 今\n      less_than_x_minutes: \"%{count}分\"\n      less_than_x_seconds: 今\n      over_x_years: \"%{count}年\"\n      x_days: \"%{count}日\"\n      x_minutes: \"%{count}分\"\n      x_months: \"%{count}月\"\n      x_seconds: \"%{count}秒\"\n  deletes:\n    bad_password_msg: パスワードが違います\n    confirm_password: 本人確認のため、現在のパスワードを入力してください\n    description_html: あなたのアカウントに含まれるコンテンツは全て削除され、アカウントは無効化されます。これは恒久的なもので、<strong>取り消すことはできません</strong>。なりすましを防ぐために、同じユーザー名で再度登録することはできなくなります。\n    proceed: アカウントを削除する\n    success_msg: アカウントは正常に削除されました\n    warning_html: 削除が保証されるのはこのサーバー上のコンテンツのみです。他のサーバー等、外部に広く共有されたコンテンツについては痕跡が残ることがあります。また、現在接続できないサーバーや、あなたの更新を受け取らなくなったサーバーに対しては、削除は反映されません。\n    warning_title: 共有されたコンテンツについて\n  directories:\n    directory: ディレクトリ\n    enabled: あなたはディレクトリに掲載されています。\n    enabled_but_waiting: あなたはディレクトリへの掲載を選択しましたが、掲載に必要な最小フォロワー数 (%{min_followers} 人) を満たしていません。\n    explanation: 関心を軸にユーザーを発見しよう\n    explore_mastodon: \"%{title}を探索\"\n    how_to_enable: あなたはディレクトリへの掲載を選択していません。下記から選択できます。ハッシュタグカラムに掲載するにはプロフィール文にハッシュタグを使用してください。\n    people:\n      other: \"%{count} 人\"\n  errors:\n    '403': このページを表示する権限がありません。\n    '404': お探しのページは見つかりませんでした。\n    '410': お探しのページはもう存在しません。\n    '422':\n      content: セキュリティ認証に失敗しました。Cookieをブロックしていませんか？\n      title: セキュリティ認証に失敗\n    '429': リクエストの制限に達しました\n    '500':\n      content: もうしわけありませんが、なにかが間違っています。\n      title: このページは正しくありません\n    noscript_html: Mastodonのウェブアプリケーションを利用する場合はJavaScriptを有効にしてください。またはあなたのプラットフォーム向けの<a href=\"%{apps_path}\">Mastodonネイティブアプリ</a>を探すことができます。\n  existing_username_validator:\n    not_found: そのようなユーザー名はローカルに見つかりませんでした\n    not_found_multiple: \"%{usernames} は見つかりませんでした\"\n  exports:\n    archive_takeout:\n      date: 日時\n      download: ダウンロード\n      hint_html: \"<strong>トゥートとメディア</strong>のアーカイブをリクエストできます。 データはActivityPub形式で、対応しているソフトウェアで読み込むことができます。7日毎にアーカイブをリクエストできます。\"\n      in_progress: 準備中...\n      request: アーカイブをリクエスト\n      size: 容量\n    blocks: ブロック\n    csv: CSV\n    domain_blocks: 非表示にしたドメイン\n    follows: フォロー\n    lists: リスト\n    mutes: ミュート\n    storage: メディア\n  featured_tags:\n    add_new: 追加\n    errors:\n      limit: 注目のハッシュタグの上限に達しました\n  filters:\n    contexts:\n      home: ホームタイムライン\n      notifications: 通知\n      public: 公開タイムライン\n      thread: 会話\n    edit:\n      title: フィルターを編集\n    errors:\n      invalid_context: 対象がないか無効です\n      invalid_irreversible: この機能はホームタイムラインまたは通知と一緒に指定する場合のみ機能します\n    index:\n      delete: 削除\n      title: フィルター\n    new:\n      title: 新規フィルターを追加\n  footer:\n    developers: 開発者向け\n    more: さらに…\n    resources: リソース\n  generic:\n    all: すべて\n    changes_saved_msg: 正常に変更されました！\n    copy: コピー\n    order_by: 並び順\n    save_changes: 変更を保存\n    validation_errors:\n      other: エラーが発生しました！ 以下の%{count}個のエラーを確認してください\n  html_validator:\n    invalid_markup: '無効なHTMLマークアップが含まれています: %{error}'\n  identity_proofs:\n    active: アクティブ\n    authorize: 許可する\n    authorize_connection_prompt: この暗号化接続を許可しますか？\n    errors:\n      failed: 暗号化接続に失敗しました。%{provider}からもう一度やり直してください。\n      keybase:\n        invalid_token: Keybaseトークンは16進数で66文字のハッシュである必要があります\n        verification_failed: KeybaseはこのトークンをKeybaseユーザー%{kb_username}の署名として認識しませんでした。Keybaseから再試行してください。\n      wrong_user: \"%{current}としてログインしている間%{proving}の証明を作成することはできません。%{proving}としてログインし、もう一度やり直してください。\"\n    explanation_html: ここではKeybaseのような他のサービスのアカウントと暗号化し関連づけることができます。これにより他の人が暗号化されたメッセージを送信したり、その内容を信用できるようになります。\n    i_am_html: I am %{username} on %{service}.\n    identity: Identity\n    inactive: 非アクティブ\n    publicize_checkbox: 'そしてこれをトゥートします:'\n    publicize_toot: 'It is proven! I am %{username} on %{service}: %{url}'\n    status: 認証状態\n    view_proof: 証明を表示\n  imports:\n    modes:\n      merge: 統合\n      merge_long: 現在のレコードを保持したまま新しいものを追加します\n      overwrite: 上書き\n      overwrite_long: 現在のレコードを新しいもので置き換えます\n    preface: 他のサーバーでエクスポートされたファイルから、フォロー/ブロックした情報をこのサーバー上のアカウントにインポートできます。\n    success: ファイルは正常にアップロードされ、現在処理中です。しばらくしてから確認してください\n    types:\n      blocking: ブロックしたアカウントリスト\n      domain_blocking: 非表示にしたドメインリスト\n      following: フォロー中のアカウントリスト\n      muting: ミュートしたアカウントリスト\n    upload: アップロード\n  in_memoriam_html: 故人を偲んで。\n  invites:\n    delete: 無効化\n    expired: 期限切れ\n    expires_in:\n      '1800': 30 分\n      '21600': 6 時間\n      '3600': 1 時間\n      '43200': 12 時間\n      '604800': 1 週間\n      '86400': 1 日\n    expires_in_prompt: 無期限\n    generate: 作成\n    invited_by: '次の人に招待されました:'\n    max_uses:\n      other: \"%{count}\"\n    max_uses_prompt: 無制限\n    prompt: リンクを生成・共有してこのサーバーへの新規登録を受け付けることができます\n    table:\n      expires_at: 有効期限\n      uses: 使用\n    title: 新規ユーザーの招待\n  lists:\n    errors:\n      limit: リストの上限に達しました\n  media_attachments:\n    validations:\n      images_and_video: 既に画像が追加されているため、動画を追加することはできません\n      too_many: 追加できるファイルは4つまでです\n  migrations:\n    acct: 引っ越し先の ユーザー名@ドメイン\n    currently_redirecting: 'あなたのプロフィールは引っ越し先が設定されています:'\n    proceed: 保存\n    updated_msg: アカウントの引っ越し設定を更新しました！\n  moderation:\n    title: モデレーション\n  notification_mailer:\n    digest:\n      action: 全ての通知を表示\n      body: '最後のログイン（%{since}）からの出来事:'\n      mention: \"%{name} さんがあなたに返信しました:\"\n      new_followers_summary:\n        other: また、離れている間に%{count} 人の新たなフォロワーを獲得しました！\n      subject:\n        other: \"新しい%{count}件の通知 \\U0001F418\"\n      title: 不在の間に…\n    favourite:\n      body: \"%{name} さんにお気に入り登録された、あなたのトゥートがあります:\"\n      subject: \"%{name} さんにお気に入りに登録されました\"\n      title: 新たなお気に入り登録\n    follow:\n      body: \"%{name} さんにフォローされています！\"\n      subject: \"%{name} さんにフォローされています\"\n      title: 新たなフォロワー\n    follow_request:\n      action: フォローリクエストの管理\n      body: \"%{name} さんがあなたにフォローをリクエストしました\"\n      subject: \"%{name} さんからのフォローリクエスト\"\n      title: 新たなフォローリクエスト\n    mention:\n      action: 返信\n      body: \"%{name} さんから返信がありました:\"\n      subject: \"%{name} さんに返信されました\"\n      title: 新たな返信\n    reblog:\n      body: \"%{name} さんにブーストされた、あなたのトゥートがあります:\"\n      subject: \"%{name} さんにブーストされました\"\n      title: 新たなブースト\n  number:\n    human:\n      decimal_units:\n        format: \"%n%u\"\n        units:\n          billion: B\n          million: M\n          quadrillion: Q\n          thousand: K\n          trillion: T\n  pagination:\n    newer: 新しいトゥート\n    next: 次\n    older: 以前のトゥート\n    prev: 前\n    truncate: \"&hellip;\"\n  polls:\n    errors:\n      already_voted: このアンケートには投票済みです\n      duplicate_options: に同じものがあります\n      duration_too_long: が長過ぎます\n      duration_too_short: が短過ぎます\n      expired: アンケートは既に終了しました\n      over_character_limit: は%{max}文字より長くすることはできません\n      too_few_options: は複数必要です\n      too_many_options: は%{max}個までです\n  preferences:\n    other: その他\n    posting_defaults: デフォルトの投稿設定\n    public_timelines: 公開タイムライン\n  relationships:\n    activity: 活動\n    dormant: 非アクティブ\n    last_active: 最後の活動\n    most_recent: 新着\n    moved: 引っ越し済み\n    mutual: 相互\n    primary: 標準\n    relationship: 関係性\n    remove_selected_domains: 選択したドメインのフォロワーを全て解除\n    remove_selected_followers: 選択したフォロワーを解除\n    remove_selected_follows: 選択したユーザーをフォロー解除\n    status: 状態\n  remote_follow:\n    acct: あなたの ユーザー名@ドメイン を入力してください\n    missing_resource: リダイレクト先が見つかりませんでした\n    no_account_html: アカウントをお持ちではないですか？<a href='%{sign_up_path}' target='_blank'>こちら</a>からサインアップできます\n    proceed: フォローする\n    prompt: 'フォローしようとしています:'\n    reason_html: \"<strong>なぜこの手順が必要でしょうか？</strong><code>%{instance}</code>はあなたが登録されているサーバーではないかもしれないので、まずあなたのサーバーに転送する必要があります。\"\n  remote_interaction:\n    favourite:\n      proceed: お気に入り登録する\n      prompt: 'お気に入り登録しようとしています:'\n    reblog:\n      proceed: ブーストする\n      prompt: 'ブーストしようとしています:'\n    reply:\n      proceed: 返信する\n      prompt: '返信しようとしています:'\n  remote_unfollow:\n    error: エラー\n    title: タイトル\n    unfollowed: フォロー解除しました\n  scheduled_statuses:\n    over_daily_limit: その日予約できる投稿数 %{limit} を超えています\n    over_total_limit: 予約できる投稿数 %{limit} を超えています\n    too_soon: より先の時間を指定してください\n  sessions:\n    activity: 最後のアクティビティ\n    browser: ブラウザ\n    browsers:\n      alipay: Alipay\n      blackberry: Blackberry\n      chrome: Chrome\n      edge: Microsoft Edge\n      electron: Electron\n      firefox: Firefox\n      generic: 不明なブラウザ\n      ie: Internet Explorer\n      micro_messenger: MicroMessenger\n      nokia: Nokia S40 Ovi Browser\n      opera: Opera\n      otter: Otter\n      phantom_js: PhantomJS\n      qq: QQ Browser\n      safari: Safari\n      uc_browser: UCBrowser\n      weibo: Weibo\n    current_session: 現在のセッション\n    description: \"%{browser} on %{platform}\"\n    explanation: あなたのMastodonアカウントに現在ログインしているウェブブラウザの一覧です。\n    ip: IP\n    platforms:\n      adobe_air: Adobe Air\n      android: Android\n      blackberry: Blackberry\n      chrome_os: ChromeOS\n      firefox_os: Firefox OS\n      ios: iOS\n      linux: Linux\n      mac: Mac\n      other: 不明なプラットフォーム\n      windows: Windows\n      windows_mobile: Windows Mobile\n      windows_phone: Windows Phone\n    revoke: 削除\n    revoke_success: セッションを削除しました\n    title: セッション\n  settings:\n    account: アカウント\n    account_settings: セキュリティ\n    appearance: 外観\n    authorized_apps: 認証済みアプリ\n    back: Mastodon に戻る\n    delete: アカウントの削除\n    development: 開発\n    edit_profile: プロフィールを編集\n    export: データのエクスポート\n    featured_tags: 注目のハッシュタグ\n    identity_proofs: Identity proofs\n    import: データのインポート\n    import_and_export: インポート・エクスポート\n    migrate: アカウントの引っ越し\n    notifications: 通知\n    preferences: ユーザー設定\n    profile: プロフィール\n    relationships: フォロー・フォロワー\n    two_factor_authentication: 二段階認証\n  statuses:\n    attached:\n      description: '添付: %{attached}'\n      image:\n        other: \"%{count} 枚の画像\"\n      video:\n        other: \"%{count} 本の動画\"\n    boosted_from_html: \"%{acct_link} からブースト\"\n    content_warning: '閲覧注意: %{warning}'\n    disallowed_hashtags:\n      other: '許可されていないハッシュタグが含まれています: %{tags}'\n    language_detection: 自動検出\n    open_in_web: Webで開く\n    over_character_limit: 上限は %{max}文字までです\n    pin_errors:\n      limit: 固定できるトゥート数の上限に達しました\n      ownership: 他人のトゥートを固定することはできません\n      private: 非公開のトゥートを固定することはできません\n      reblog: ブーストを固定することはできません\n    poll:\n      total_votes:\n        other: \"%{count}票\"\n      vote: 投票\n    show_more: もっと見る\n    sign_in_to_participate: ログインして会話に参加\n    title: '%{name}: \"%{quote}\"'\n    visibilities:\n      private: フォロワー限定\n      private_long: フォロワーにのみ表示されます\n      public: 公開\n      public_long: 誰でも見ることができ、かつ公開タイムラインに表示されます\n      unlisted: 未収載\n      unlisted_long: 誰でも見ることができますが、公開タイムラインには表示されません\n  stream_entries:\n    pinned: 固定されたトゥート\n    reblogged: さんがブースト\n    sensitive_content: 閲覧注意\n  terms:\n    body_html: |\n      <h2>プライバシーポリシー</h2>\n      <h3 id=\"collect\">どのような情報を収集しますか？</h3>\n\n      <ul>\n      <li><em>基本的なアカウント情報</em>: 当サイトに登録すると、ユーザー名・メールアドレス・パスワードの入力を求められることがあります。また表示名や自己紹介・プロフィール画像・ヘッダー画像といった追加のプロフィールを登録できます。ユーザー名・表示名・自己紹介・プロフィール画像・ヘッダー画像は常に公開されます。</li>\n      <li><em>投稿・フォロー・その他公開情報</em>: フォローしているユーザーの一覧は一般公開されます。フォロワーも同様です。メッセージを投稿する際、日時だけでなく投稿に使用したアプリケーション名も記録されます。メッセージには写真や動画といった添付メディアを含むことがあります。「公開」や「未収載」の投稿は一般公開されます。プロフィールに投稿を載せるとそれもまた公開情報となります。投稿はフォロワーに配信されます。場合によっては他のサーバーに配信され、そこにコピーが保存されることを意味します。投稿を削除した場合も同様にフォロワーに配信されます。他の投稿をリブログやお気に入り登録する行動は常に公開されます。</li>\n      <li><em>「ダイレクト」と「フォロワー限定」投稿</em>: すべての投稿はサーバーに保存され、処理されます。「フォロワー限定」投稿はフォロワーと投稿に書かれたユーザーに配信されます。「ダイレクト」投稿は投稿に書かれたユーザーにのみ配信されます。場合によっては他のサーバーに配信され、そこにコピーが保存されることを意味します。私たちはこれらの閲覧を一部の許可された者に限定するよう誠意を持って努めます。しかし他のサーバーにおいても同様に扱われるとは限りません。したがって、相手の所属するサーバーを吟味することが重要です。設定で新しいフォロワーの承認または拒否を手動で行うよう切り替えることもできます。<em>サーバー管理者は「ダイレクト」や「フォロワー限定」投稿も閲覧する可能性があることを忘れないでください。</em>また受信者がスクリーンショットやコピー、もしくは共有する可能性があることを忘れないでください。<em>いかなる危険な情報もMastodon上で共有しないでください。</em></li>\n      <li><em>IPアドレスやその他メタデータ</em>: ログインする際IPアドレスだけでなくブラウザーアプリケーション名を記録します。ログインしたセッションはすべてユーザー設定で見直し、取り消すことができます。使用されている最新のIPアドレスは最大12ヵ月間保存されます。またサーバーへのIPアドレスを含むすべてのリクエストのログを保持することがあります。</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"use\">情報を何に使用しますか？</h3>\n\n      <p>収集した情報は次の用途に使用されることがあります:</p>\n\n      <ul>\n      <li>Mastodonのコア機能の提供: ログインしている間にかぎり他の人たちと投稿を通じて交流することができます。例えば自分専用のホームタイムラインで投稿をまとめて読むために他の人たちをフォローできます。</li>\n      <li>コミュニティ維持の補助: 例えばIPアドレスを既知のものと比較し、BAN回避目的の複数登録者やその他違反者を判別します。</li>\n      <li>提供されたメールアドレスはお知らせの送信・投稿に対するリアクションやメッセージ送信の通知・お問い合わせやその他要求や質問への返信に使用されることがあります。</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"protect\">情報をどのように保護しますか？</h3>\n\n      <p>私たちはあなたが入力・送信する際や自身の情報にアクセスする際に個人情報を安全に保つため、さまざまなセキュリティ上の対策を実施します。特にブラウザーセッションだけでなくアプリケーションとAPI間の通信もSSLによって保護されます。またパスワードは強力な不可逆アルゴリズムでハッシュ化されます。二段階認証を有効にし、アカウントへのアクセスをさらに安全にすることができます。</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"data-retention\">データ保持方針はどうなっていますか？</h3>\n\n      <p>私たちは次のように誠意を持って努めます:</p>\n\n      <ul>\n      <li>当サイトへのIPアドレスを含むすべての要求に対するサーバーログを90日以内のできるかぎりの間保持します。</li>\n      <li>登録されたユーザーに関連付けられたIPアドレスを12ヵ月以内の間保持します。</li>\n      </ul>\n\n      <p>あなたは投稿・添付メディア・プロフィール画像・ヘッダー画像を含む自身のデータのアーカイブを要求し、ダウンロードすることができます。</p>\n\n      <p>あなたはいつでもアカウントの削除を要求できます。削除は取り消すことができません。</p>\n\n      <hr class=\"spacer\"/>\n\n      <h3 id=\"cookies\">クッキーを使用していますか？</h3>\n\n      <p>はい。クッキーは (あなたが許可した場合に) WebサイトやサービスがWebブラウザーを介してコンピューターに保存する小さなファイルです。使用することでWebサイトがブラウザーを識別し、登録済みのアカウントがある場合関連付けます。</p>\n\n      <p>私たちはクッキーを将来の訪問のために設定を保存し呼び出す用途に使用します。</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"disclose\">なんらかの情報を外部に提供していますか？</h3>\n\n      <p>私たちは個人を特定できる情報を外部へ販売・取引・その他方法で渡すことはありません。これには当サイトの運営・業務遂行・サービス提供を行ううえで補助する信頼できる第三者をこの機密情報の保護に同意するかぎり含みません。法令の遵守やサイトポリシーの施行、権利・財産・安全の保護に適切と判断した場合、あなたの情報を公開することがあります。</p>\n\n      <p>あなたの公開情報はネットワーク上の他のサーバーにダウンロードされることがあります。相手が異なるサーバーに所属する場合、「公開」と「フォロワー限定」投稿はフォロワーの所属するサーバーに配信され、「ダイレクト」投稿は受信者の所属するサーバーに配信されます。</p>\n\n      <p>あなたがアカウントの使用をアプリケーションに許可すると、承認した権限の範囲内で公開プロフィール情報・フォローリスト・フォロワー・リスト・すべての投稿・お気に入り登録にアクセスできます。アプリケーションはメールアドレスやパスワードに決してアクセスできません。</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"children\">児童によるサイト利用について</h3>\n\n      <p>サーバーがEUまたはEEA圏内にある場合: 当サイト・製品・サービスは16歳以上の人を対象としています。あなたが16歳未満の場合、GDPR (<a href=\"https://en.wikipedia.org/wiki/General_Data_Protection_Regulation\">General Data Protection Regulation</a> - EU一般データ保護規則) により当サイトを使用できません。</p>\n\n      <p>サーバーが米国にある場合: 当サイト・製品・サービスは13歳以上の人を対象としています。あなたが13歳未満の場合、COPPA (<a href=\"https://en.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act\">Children's Online Privacy Protection Act</a> - 児童オンラインプライバシー保護法) により当サイトを使用できません。</p>\n\n      <p>サーバーが別の管轄区域にある場合、法的要件は異なることがあります。</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"changes\">プライバシーポリシーの変更</h3>\n\n      <p>プライバシーポリシーの変更を決定した場合、このページに変更点を掲載します。</p>\n\n      <p>この文章のライセンスはCC-BY-SAです。最終更新日は2018年3月7日です。</p>\n\n      <p>オリジナルの出典: <a href=\"https://github.com/discourse/discourse\">Discourse privacy policy</a></p>\n    title: \"%{instance} 利用規約・プライバシーポリシー\"\n  themes:\n    contrast: Mastodon (ハイコントラスト)\n    default: Mastodon (ダーク)\n    mastodon-light: Mastodon (ライト)\n  time:\n    formats:\n      default: \"%Y年%m月%d日 %H:%M\"\n      month: \"%Y年 %b\"\n  two_factor_authentication:\n    code_hint: 確認するには認証アプリで表示されたコードを入力してください\n    description_html: \"<strong>二段階認証</strong>を有効にするとログイン時、認証アプリからコードを入力する必要があります。\"\n    disable: 無効\n    enable: 有効\n    enabled: 二段階認証は有効になっています\n    enabled_success: 二段階認証が有効になりました\n    generate_recovery_codes: リカバリーコードを生成\n    instructions_html: \"<strong>Google Authenticatorか、もしくはほかのTOTPアプリでこのQRコードをスキャンしてください。</strong>これ以降、ログインするときはそのアプリで生成されるコードが必要になります。\"\n    lost_recovery_codes: リカバリーコードを使用すると携帯電話を紛失した場合でもアカウントにアクセスできるようになります。 リカバリーコードを紛失した場合もここで再生成することができますが、古いリカバリーコードは無効になります。\n    manual_instructions: 'QRコードがスキャンできず、手動での登録を希望の場合はこのシークレットコードを利用してください。:'\n    recovery_codes: リカバリーコード\n    recovery_codes_regenerated: リカバリーコードが再生成されました\n    recovery_instructions_html: 携帯電話を紛失した場合、以下の内どれかのリカバリーコードを使用してアカウントへアクセスすることができます。<strong>リカバリーコードは大切に保全してください。</strong>たとえば印刷してほかの重要な書類と一緒に保管することができます。\n    setup: 初期設定\n    wrong_code: コードが間違っています。サーバー上の時間とデバイス上の時間が一致していますか？\n  user_mailer:\n    backup_ready:\n      explanation: Mastodonアカウントのアーカイブを受け付けました。今すぐダウンロードできます！\n      subject: アーカイブの準備ができました\n      title: アーカイブの取り出し\n    warning:\n      explanation:\n        disable: アカウントが凍結されている間、データはそのまま残りますが、凍結が解除されるまでは何の操作もできません。\n        silence: あなたのアカウントは制限されていますが、あなたをフォローしているユーザーのみ、このサーバー上の投稿を見ることができます。そしてあなたは様々な公開リストから除外されるかもしれません。ただし、他のユーザーは手動であなたをフォローすることができます。\n        suspend: あなたのアカウントは停止されています。あなたの投稿とアップロードされたメディアファイルは、このサーバーとあなたのフォロワーが参加していたサーバーから完全に削除されました。\n      review_server_policies: サーバーのポリシーを確認\n      subject:\n        disable: あなたのアカウント %{acct} は凍結されています\n        none: \"%{acct} に対する警告\"\n        silence: あなたのアカウント %{acct} はサイレンスにされています\n        suspend: あなたのアカウント %{acct} は停止されています\n      title:\n        disable: アカウントが凍結されました\n        none: 警告\n        silence: アカウントがサイレンスにされました\n        suspend: アカウントが停止されました\n    welcome:\n      edit_profile_action: プロフィールを設定\n      edit_profile_step: アイコンやヘッダーの画像をアップロードしたり、表示名を変更したりして、自分のプロフィールをカスタマイズすることができます。また、誰かからの新規フォローを許可する前にその人の様子を見ておきたい場合、アカウントを承認制にすることもできます。\n      explanation: 始めるにあたってのアドバイスです\n      final_action: 始めましょう\n      final_step: 'さあ、始めましょう！ たとえフォロワーがまだいなくても、あなたの公開した投稿はローカルタイムラインやハッシュタグなどを通じて誰かの目にとまるはずです。自己紹介をしたいときには #introductions ハッシュタグが便利かもしれません。'\n      full_handle: あなたの正式なユーザーID\n      full_handle_hint: 別のサーバーの友達とフォローやメッセージをやり取りする際には、これを伝えることになります。\n      review_preferences_action: 設定の変更\n      review_preferences_step: 受け取りたいメールの種類や投稿のデフォルト公開範囲など、ユーザー設定を必ず済ませておきましょう。目が回らない自信があるなら、アニメーション GIF を自動再生する設定もご検討ください。\n      subject: Mastodon へようこそ\n      tip_federated_timeline: 連合タイムラインは Mastodon ネットワークの流れを見られるものです。ただしあなたと同じサーバーの人がフォローしている人だけが含まれるので、それが全てではありません。\n      tip_following: 最初は、サーバーの管理者をフォローした状態になっています。もっと興味のある人たちを見つけるには、ローカルタイムラインと連合タイムラインを確認してみましょう。\n      tip_local_timeline: ローカルタイムラインは %{instance} にいる人々の流れを見られるものです。彼らはあなたと同じサーバーにいる隣人のようなものです！\n      tip_mobile_webapp: お使いのモバイル端末で、ブラウザから Mastodon をホーム画面に追加できますか？ もし追加できる場合、プッシュ通知の受け取りなど、まるで「普通の」アプリのような機能が楽しめます！\n      tips: 豆知識\n      title: ようこそ、%{name}！\n  users:\n    follow_limit_reached: あなたは現在 %{limit} 人以上フォローできません\n    invalid_email: メールアドレスが無効です\n    invalid_otp_token: 二段階認証コードが間違っています\n    otp_lost_help_html: どちらも使用できない場合、%{email} に連絡を取ると解決できるかもしれません\n    seamless_external_login: あなたは外部サービスを介してログインしているため、パスワードとメールアドレスの設定は利用できません。\n    signed_in_as: '下記でログイン中:'\n  verification:\n    explanation_html: <strong>プロフィール内のリンクの所有者であることを認証することができます</strong>。そのためにはリンクされたウェブサイトにMastodonプロフィールへのリンクが含まれている必要があります。リンクには<code>rel=\"me\"</code>属性を<strong>必ず</strong>与えなければなりません。リンクのテキストについては重要ではありません。以下は例です：\n    verification: 認証\n"
  },
  {
    "path": "config/locales/ka.yml",
    "content": "---\nka:\n  about:\n    about_hashtag_html: ეს საჯარო ტუტებია, რომლებიც ატარებენ <strong>#%{hashtag}</strong> ტეგს. მათთან ინტერაქციას შეძლებთ, თუ ფედივერსში გაქვთ რაიმე ანგარიში.\n    about_mastodon_html: მასტოდონი ღია ვებ პროტოკოლებზე და უფასო, ღია პროგრამებზე დაფუძნებული სოციალური ქსელია. ის ისეთი დეცენტრალიზებულია როგორც ელ-ფოსტა.\n    about_this: შესახებ\n    administered_by: 'ადმინისტრატორი:'\n    api: აპი\n    apps: მობილური აპლიკაციები\n    contact: კონტაქტი\n    contact_missing: არაა დაყენებული\n    contact_unavailable: მიუწ.\n    documentation: დოკუმენტაცია\n    extended_description_html: |\n      <h3>კარგი ადგილი წესებისთვის</h3>\n      <p>განვრცობილი აღწერილობა ჯერ არ შექმნილა.</p>\n    generic_description: \"%{domain} ერთი სერვერია ქსელში\"\n    hosted_on: მასტოდონს მასპინძლობს %{domain}\n    learn_more: გაიგე მეტი\n    privacy_policy: კონფიდენციალურობის პოლიტიკა\n    source_code: კოდი\n    status_count_before: ვინც უავტორა\n    terms: მომსახურების პირობები\n    user_count_before: სახლი\n    what_is_mastodon: რა არის მასტოდონი?\n  accounts:\n    choices_html: \"%{name}-ის არჩევნები:\"\n    follow: გაყევი\n    following: მიჰყვება\n    joined: გაწევრიანდა %{date}\n    media: მედია\n    moved_html: \"%{name} გადავიდა %{new_profile_link}:\"\n    network_hidden: ეს ინფორმაცია ხელმიუწვდომელია\n    nothing_here: აქ არაფერია!\n    people_followed_by: ხალხი ვისაც %{name} მიჰყვება\n    people_who_follow: ხალხი ვინც მიჰყვება %{name}-ს\n    pin_errors:\n      following: იმ ადამიანს, ვინც მოგწონთ, უკვე უნდა მიჰყვებოდეთ\n    posts_with_replies: ტუტები და პასუხები\n    reserved_username: მომხმარებელი რეზერვირებულია\n    roles:\n      admin: ადმინისტრატორი\n      bot: ბოტი\n      moderator: მოდერატორი\n    unfollow: ნუღარ მიჰყვები\n  admin:\n    account_moderation_notes:\n      create: დატოვეთ ჩანაწერი\n      created_msg: მოდერაციის ჩანაწერი წარმატებით შეიქმნა!\n      delete: გაუქმება\n      destroyed_msg: მოდერაციის ჩანაწერი წარმატებით გაუქმდა!\n    accounts:\n      are_you_sure: დარწმუნებული ხარ?\n      avatar: ავატარი\n      by_domain: დომენი\n      change_email:\n        changed_msg: ანგარიშის ელ-ფოსტა წარმატებით შეიცვალა!\n        current_email: მიმდინარე ელ-ფოსტა\n        label: ელ-ფოსტის შეცვლა\n        new_email: ახალი ელ-ფოსტა\n        submit: ელ-ფოსტის შეცვლა\n        title: შეცვალეთ ელ-ფოსტა მომხმარებლისთვის %{username}\n      confirm: დადასტურება\n      confirmed: დადასტურებულია\n      confirming: დასტურდება\n      demote: დაქვეითება\n      disable: გამორთვა\n      disable_two_factor_authentication: გამორთე 2FA\n      disabled: გამორთულია\n      display_name: დისპლეი სახელი\n      domain: დომენი\n      edit: შეცვლა\n      email: ელ-ფოსტა\n      email_status: ელ-ფოსტის სტატუსი\n      enable: ჩართვა\n      enabled: ჩართულია\n      feed_url: ლენტის ურლ\n      followers: მიმდევრები\n      followers_url: მიმდევრების ურლ\n      follows: დადევნებები\n      inbox_url: ინბოქსის ურლ\n      ip: აი-პი\n      location:\n        all: ყველა\n        local: ლოკალური\n        remote: დისტანციური\n        title: ადგილმდებარეობა\n      login_status: ლოგინის სტატუსი\n      media_attachments: თან-დართული მედია\n      memorialize: აქციე მემორანდუმად\n      moderation:\n        all: ყველა\n        silenced: გაჩუმებული\n        suspended: შეჩერებული\n        title: მოდერაცია\n      moderation_notes: მოდერაციის ჩანაწერები\n      most_recent_activity: უახლესი აქტივობა\n      most_recent_ip: უახლესი აი-პი\n      not_subscribed: გამოუწერელი\n      outbox_url: აუთბოქსის ურლ\n      perform_full_suspension: მოახდინეთ სრული შეჩერება\n      profile_url: პროფილის ურლ\n      promote: დაწინაურება\n      protocol: პროტოკოლი\n      public: საჯარო\n      push_subscription_expires: ფუშ გამოწერა უქმდება\n      redownload: განაახლე ავატარი\n      remove_avatar: გააუქმე ავატარი\n      resend_confirmation:\n        already_confirmed: ეს მომხმარებელი უკვე დამოწმებულია\n        send: დამოწმების ინსტრუქციების გადაგზავნა\n        success: დამოწმების ინსტრუქციები წარმატებით გაიგზავნა!\n      reset: გადატვირთვა\n      reset_password: პაროლის გადატვირთვა\n      resubscribe: ხელახალი გამოწერა\n      role: უფლებები\n      roles:\n        admin: ადმინისტრატორი\n        moderator: მოდერატორი\n        staff: სტაფი\n        user: მომხმარებელი\n      salmon_url: სალმონის ურლ\n      search: ძებნა\n      shared_inbox_url: გაზიარებული ინბოქსის ურლ\n      show:\n        created_reports: ამ ანგარიშის მიერ შექმნილი რეპორტები\n        targeted_reports: ამ ანგარიშზე მიღებული რეპორტები\n      silence: სიჩუმე\n      statuses: სტატუსები\n      subscribe: გამოწერა\n      title: ანგარიშები\n      unconfirmed_email: დაუმოწმებელი ელ-ფოსტა\n      undo_silenced: გაჩუმების მოშორება\n      undo_suspension: შეჩერების მოშორება\n      unsubscribe: გამოწერის შეწყვეტა\n      username: მომხმარებლის სახელი\n      web: ვები\n    action_logs:\n      actions:\n        assigned_to_self_report: \"%{name}-მა დანიშნა რეპორტი %{target} საკუთარ თავზე\"\n        change_email_user: \"%{name}-მა შეცვალა %{target} მომხმარებლის ელ-ფოსტის მისამართი\"\n        confirm_user: \"%{name}-მა დაამოწმა %{target} მომხმარებლის ელ-ფოსტის მისამართი\"\n        create_custom_emoji: \"%{name}-მა ატვირთა ახალი ემოჯი %{target}\"\n        create_domain_block: \"%{name}-მა დაბლოკა დომენი %{target}\"\n        create_email_domain_block: \"%{name}-მა შავ სიაში მოაქცია დომენი %{target}\"\n        demote_user: \"%{name}-მა დააქვეითა მომხმარებელი %{target}\"\n        destroy_domain_block: \"%{name}-მა ბლოკი მოხსნა დომენს %{target}\"\n        destroy_email_domain_block: \"%{name} თეთრ სიაში მოაქცია დომენი %{target}\"\n        destroy_status: \"%{name}-მა გააუქმა სტატუსი %{target}-ზე\"\n        disable_2fa_user: \"%{name} გათიშა მეორე ფაქტორის მოთხოვნილება მომხმარებელზე %{target}\"\n        disable_custom_emoji: \"%{name}-მა გათისა ემოჯი %{target}\"\n        disable_user: \"%{name}-მა გათიშა ლოგინი მომხმარებლისთვის %{target}\"\n        enable_custom_emoji: \"%{name}-მა ჩართო ემოჯი %{target}\"\n        enable_user: \"%{name}-მა ჩართო ლოგინი მომხმარებლისთვის %{target}\"\n        memorialize_account: \"%{name}-მა აქცია ანგარიში %{target} მემორანდუმის გვერდად\"\n        promote_user: \"%{name}-მა დააწინაურა მომხმარებელი %{target}\"\n        remove_avatar_user: \"%{name}-მა გააუქმა %{target} მომხმარებლის ავატარი\"\n        reopen_report: \"%{name}-მა ხელახლა გახსნა რეპორტი %{target}\"\n        reset_password_user: \"%{name} გადატვირთა მომხმარებლის %{target} პაროლი\"\n        resolve_report: \"%{name}-მა მოაგვარა %{target} მომხმარებლის რეპორტი\"\n        silence_account: \"%{name}-მა გააჩუმა %{target} ანგარიში\"\n        suspend_account: \"%{name} შეაჩერა %{target} ანგარიში\"\n        unassigned_report: \"%{name}-მა მოაშორა რეპორტი %{target}\"\n        unsilence_account: \"%{name}-მა მოაშორა გაჩუმება %{target} ანგარიშს\"\n        unsuspend_account: \"%{name}-მა მოაშორა შეჩერება %{target} ანგარიშს\"\n        update_custom_emoji: \"%{name}-მა განაახლა ემოჯი %{target}\"\n        update_status: \"%{name}-მა განაახლა სტატუსი %{target}-ით\"\n      deleted_status: \"(გაუქმებული სტატუსი)\"\n      title: აუდიტის ლოგი\n    custom_emojis:\n      by_domain: დომენი\n      copied_msg: ემოჯის ლოკალური ასლი წარმატებით შეიქმნა\n      copy: კოპირება\n      copy_failed_msg: ამ ემოჯის ლოკალური ასლი ვერ შეიქმნა\n      created_msg: ემოჯი წარმატებით შეიქმნა!\n      delete: გაუქმება\n      destroyed_msg: ემოჯი წარმატებით გაუქმდა!\n      disable: გათიშვა\n      disabled_msg: ეს ემოჯი წარმატებით გაითიშა\n      emoji: ემოჯი\n      enable: ჩართვა\n      enabled_msg: წარმატებით ჩაირთო ეს ემოჯი\n      image_hint: PNG 50კბმდე\n      listed: ჩამოთვლილი\n      new:\n        title: ახალი პერსონალიზირებული ემოჯის დამატება\n      overwrite: გადაწერა\n      shortcode: მოკლე-კოდი\n      shortcode_hint: მინ. 2 ნიშანი, მხოლოდ ალფანუმერიკული ნიშნები და \"ქვედა-ტირეები\"\n      title: პერსონალიზირებული ემოჯიები\n      unlisted: ჩამოუთვლელი\n      update_failed_msg: ემოჯის განახლება ვერ მოხერხდა\n      updated_msg: ემოჯი წარმატებით განახლდა!\n      upload: ატვირთვა\n    dashboard:\n      backlog: დაუსრულებელი საქმეები\n      config: კონფიგურაცია\n      feature_deletions: ანგარიშის გაუქმებები\n      feature_invites: მოწვევის ბმულები\n      feature_registrations: რეგისტრაციები\n      feature_relay: ფედერაციის რილეი\n      features: ფუნქციები\n      hidden_service: ფედერაცია დამალულ სერვისებთან\n      open_reports: ღია რეპორტები\n      recent_users: ახალი მომხმარებლები\n      search: სრული-ტექსტის ძიება\n      single_user_mode: ერთ-მომხმარებლიანი რეჟიმი\n      software: პროგრამა\n      space: მოცულობის მოხმარება\n      title: დაფა\n      total_users: სულ მომხმარებლები\n      trends: ტრენდები\n      week_interactions: ამ კვირის ინტერაქციები\n      week_users_active: აქტიური ამ კვირას\n      week_users_new: ამ კვირის მომხმარებლები\n    domain_blocks:\n      add_new: ახლის დამატება\n      created_msg: დომენის ბლოკი ახლა პროცესირების ქვეშაა\n      destroyed_msg: დომენის ბლოკი გაუქმდა\n      domain: დომენი\n      new:\n        create: ბლოკის შექმნა\n        hint: დომენის ბლოკი არ შეაჩერებს ანგარიშების ჩაწერას მონაცემთა ბაზაში, მაგრამ ეს ამ ანგარიშებზე რეტროაქტიულად და ავტომატურად გაატარებს სპეციფიურ მოდერაციის მეთოდებს.\n        severity:\n          desc_html: \"<strong>გაჩუმება</strong> გახდის ანგარიშის პოსტებს უჩინარს ყველასთვის, ვინც მას არ მიჰყვება. <strong>შეჩერება</strong> გააუქმებს ანგარიშის მთელ კონტენტს, მედიას და პროფილის მონაცემს. გამოიყენეთ <strong>არც ერთი</strong> თუ გსურთ უბრალოდ უარყოთ ფაილები.\"\n          noop: არც ერთი\n          silence: გაჩუმება\n          suspend: შეჩერება\n        title: ახალი დომენის ბლოკი\n      reject_media: მედია ფაილების უარყოფა\n      reject_media_hint: შლის ლოკალურად შენახულ მედია ფაილებს და უარყოფს სამომავლო გადმოტვირთებს. შეუსაბამო შეჩერებებისთვის\n      show:\n        affected_accounts:\n          one: გავლენა იქონია მონაცემთა ბაზაში ერთ ანგარიშზე\n          other: გავლენა იქონიო მონაცემთა ბაზაში %{count} ანგარიშზე\n        retroactive:\n          silence: ამ დომენში ყველა არსებულ ანგარიშზე გაჩუმების მოშორება\n          suspend: ამ დომენში ყველა არსებულ ანგარიშზე შეჩერების მოშორება\n        title: უკუაქციეთ დომენის ბლოკი %{domain} დომენზე\n        undo: უკუქცევა\n      undo: უკუქცევა\n    email_domain_blocks:\n      add_new: ახლის დამატება\n      created_msg: ელ-ფოსტის დომენი წარმატებით დაემატა შავ სიას\n      delete: გაუქმება\n      destroyed_msg: ელ-ფოსტის დომენი წარმატებით ამოიშალა შავი სიიდან\n      domain: დომენი\n      new:\n        create: დომენის დამატება\n        title: ელ-ფოსტის ახალი შენატანი შავ სიაში\n      title: ელ-ფოსტის შავი სია\n    instances:\n      title: ცნობილი ინსტანციები\n    invites:\n      deactivate_all: ყველას დეაქტივაცია\n      filter:\n        all: ყველა\n        available: ხელმისაწვდომი\n        expired: ვადაგასული\n        title: ფილტრი\n      title: მოწვევები\n    relays:\n      add_new: ახელი რილეი\n      description_html: \"<strong>ფედერაციის რილეი</strong> შუამავალი სერვერია, რომელიც ცვლის საჯარო ტუტების დიდ ოდენობას იმ სერვერებს შორის, რომლებიც გამოიწერენ და მასზე გამოაქვეყნებენ. <strong>ეს მცირე და საშუალო სერვერებს ეხმარება აღმოაჩინონ კონტენტი ფედივერსისგან</strong>, რომელიც სხვა შემთხვევაში მომხარებლებს აიძულებდა მექნიკურ რეჟიმში გაჰყოლოდნენ ხალხს სხვა დისტანციურ სერვერებზე.\"\n      enable_hint: ამოქმდების შემდეგ, თქვენი სერვერი გამოიწერს ყველა საჯარო ტუტს ამ რილეიდან და დაიწყებს სერვერის ღია ტუტების იქ გაგზავნას.\n      inbox_url: რილეი ურლ\n      setup: რილეი კავშირის დამყარება\n      status: სტატუსი\n      title: რილეი სია\n    report_notes:\n      created_msg: რეპორტის ჩანაწერი წარმატებით შეიქმნა!\n      destroyed_msg: რეპორტის ჩანაწერი წარმატებით გაუქმდა!\n    reports:\n      account:\n        note: ჩანაწერი\n        report: რეპორტი\n      action_taken_by: მოქმედება შეასრულა\n      are_you_sure: დარწმუნებული ხარ?\n      assign_to_self: დანიშნე ჩემზე\n      assigned: დაინიშნა მოდერატორი\n      comment:\n        none: არაფერი\n      created_at: რეპორტის დრო\n      mark_as_resolved: მონიშნე გადაწყვეტილად\n      mark_as_unresolved: მონიშნე გადაუწყვეტლად\n      notes:\n        create: ჩანაწერის დამატება\n        create_and_resolve: გადაწყვეტა ჩანაწერით\n        create_and_unresolve: ხელახალი გახსნა ჩანაწერით\n        delete: გაუქმება\n        placeholder: აღწერეთ თუ რა ნაბიჯები უნდა გადაიდგას, ან სხვა დაკავშირებული განახლებები...\n      reopen: რეპორტის ხელახალი გახსნა\n      report: 'რეპორტი #%{id}'\n      reported_account: დარეპორტებული ანგარიში\n      reported_by: დაარეპორტა\n      resolved: გადაწყვეტილი\n      resolved_msg: რეპორტი წარმატებით გადაწყდა!\n      status: სტატუსი\n      title: რეპორტები\n      unassign: გადაყენება\n      unresolved: გადაუწყვეტელი\n      updated_at: განახების დრო\n    settings:\n      activity_api_enabled:\n        desc_html: ლოკალურად გამოქვეყნებული სტატუსების, აქტიური მომხმარებლების და ყოველკვირეული რეგისტრაციების მთვლელი\n        title: გამოაქვეყნე აგრეგატი სტატისტიკები მომხმარებლის აქტივობაზე\n      bootstrap_timeline_accounts:\n        desc_html: გამოჰყავი მომხმარებლები მძიმით. იმუშავებს მხოლოდ ლოკალური და \"ბლოკ-მოხსნილ\" ანგარიშები. საწყისი როდესაც ცარიელია ყველა ლოკალური ადმინი.\n        title: საწყისი მიდევნებები ახლა მომხმარებლებზე\n      contact_information:\n        email: ბიზნეს ელ-ფოსტა\n        username: საკონტაქტო მომხმარებლის სახელი\n      hero:\n        desc_html: წინა გვერდზე გამოჩენილი. მინ. 600/100პიქს. რეკომენდირებული. როდესაც არაა დაყენებული, ჩნდება ინსტანციის პიქტოგრამა\n        title: გმირი სურათი\n      peers_api_enabled:\n        desc_html: დომენების სახელები რომლებსაც შეხვდა ეს ინსტანცია ფედივერსში\n        title: გამოაქვეყნე აღმოჩენილი ინსტანციების სია\n      preview_sensitive_media:\n        desc_html: ბმულის პრევიუები სხვა ვებ-საიტებზე გამოაჩენენ პიქტოგრამას, მაშინაც კი თუ მედია მონიშნულია მგრძნობიარედ\n        title: გამოაჩინე მგრძნობიარე მედია ოუფენ-გრეფ პრევიუებში\n      registrations:\n        closed_message:\n          desc_html: გამოჩნდება წინა გვერდზე, როდესაც რეგისტრაციები დახურულია. შეგიძლიათ გამოიყენოთ ჰტმლ ტეგები\n          title: დახურული რეგისტრაციის წერილი\n        deletion:\n          desc_html: უფლება მიეცით ყველას, გააუქმონ თავიანთი ანგარიში\n          title: ღია ანგარიშის გაუქმება\n        min_invite_role:\n          disabled: არავინ\n          title: ნება დაერთოს მოწვეევებს\n      show_known_fediverse_at_about_page:\n        desc_html: ჩართვისას, ეს გამოაჩენს ტუტებს ყველა ცნობილი ფედივერსისგან პრევიუზე. სხვა შემთხვევაში, გამოაჩენს მხოლოდ ლოკალურ ტუტებს.\n        title: გამოჩნდეს ცნობილი ვედივერსი თაიმლაინ პრევიუში\n      show_staff_badge:\n        desc_html: გამოჩნდეს სტაფის ნიშანი მომხმარებლის გვერდზე\n        title: სტაფის ნიშნის გამოჩენა\n      site_description:\n        desc_html: საშესავლო პარაგრაფი წინა გვერდზე. აღწერეთ თუ რა ხდის ამ მასტოდონის სერვერს განსაკუთრებულს და სხვა მნიშვნელოვანი. შეგიძლიათ გამოიყენოთ ჰტმლ ტეგები, კერძოდ <code>&lt;a&gt;</code> და <code>&lt;em&gt;</code>.\n        title: ინსტანციის აღწერილობა\n      site_description_extended:\n        desc_html: კარგი ადგილი მოქცევის კოდექსისთვის, წესები, სახელმძღვანელოები და სხვა რაც გამოარჩევს თქვენს ინსტანციას. შეგიძლიათ გამოიყენოთ ჰტმლ ტეგები\n        title: პერსონალიზირებული განვრცობილი ინფორმაცია\n      site_short_description:\n        desc_html: გამოჩნდება გვერდით ბარში და მეტა ტეგებში. აღწერეთ თუ რა არის მასტოდონი და რა ხდის ამ სერვერს უნიკალურს ერთ პარაგრაფში. თუ ცარიელია, გამოჩნდება ინსტანციის აღწერილობა.\n        title: აჩვენეთ ინსტანციის აღწერილობა\n      site_terms:\n        desc_html: შეგიძლიათ დაწეროთ საკუთარი კონფიდენციალურობის პოლიტიკა, მომსახურების პირობები ან სხვა იურიდიული დოკუმენტი. შეგიძლიათ გამოიყენოთ ჰტმლ ტეგები\n        title: პერსონალიზირებული მომსახურების პირობები\n      site_title: ინსტანციის სახელი\n      thumbnail:\n        desc_html: გამოიყენება პრევიუებისთვის ოუფენ-გრეფში და აპი-ში. 1200/630პიქს. რეკომენდირებული\n        title: ინსტანციის პიქტოგრამა\n      timeline_preview:\n        desc_html: აჩვენეთ საჯარო თაიმლაინი ლენდინგ გვერდზე\n        title: თაიმლაინ პრევიუ\n      title: საიტის პარამეტრები\n    statuses:\n      back_to_account: უკან ანგარიშის გვერდისკენ\n      batch:\n        delete: გაუქმება\n        nsfw_off: მონიშნე არა-მგრძნობიარედ\n        nsfw_on: მონიშნე მგრძნობიარედ\n      failed_to_execute: ვერ გაეშვა\n      media:\n        title: მედია\n      no_media: არაა მედია\n      no_status_selected: სატუსები არ შეცვლილა, რადგან არცერთი არ მონიშნულა\n      title: ანგარიშის სტატუსები\n      with_media: მედიით\n    subscriptions:\n      callback_url: ქოლბექ ურლ\n      confirmed: დამოწმდა\n      expires_in: ვადა გასდის\n      last_delivery: ბოლო მიღება\n      title: ვებ-საბი\n      topic: სათაური\n    title: ადმინისტრაცია\n  admin_mailer:\n    new_report:\n      body: \"%{reporter}-მა დაარეპორტა %{target}\"\n      body_remote: ვიღაცამ %{domain}-იდან დაარეპორტა %{target}\n      subject: ახალი რეპორტი %{instance} (#%{id})-ზე\n  application_mailer:\n    notification_preferences: შეცვალეთ ელ-ფოსტის პრეფერნსიები\n    settings: 'შეცვალეთ ელ-ფოსტის პრეფერენსიები: %{link}'\n    view: 'ჩვენება:'\n    view_profile: პროფილის ჩვენება\n    view_status: სტატუსის ჩვენება\n  applications:\n    created: აპლიკაცია წარმატებით შეიქმნა\n    destroyed: აპლიკაცია წარმატებით გაუქმდა\n    invalid_url: მოწოდებული ურლ არასწორია\n    regenerate_token: წვდომის ტოკენის რეგენერაცია\n    token_regenerated: წვდომის ტოკენის რეგენერაცია მოხერხდა\n    warning: იყავით ძალიან ფრთხილად ამ მონაცემთან. არასდროს გააზიაროთ ეს!\n    your_token: თქვენი წვდომის ტოკენი\n  auth:\n    change_password: პაროლი\n    confirm_email: ელ-ფოსტის დამოწმება\n    delete_account: ანგარიშის გაუქმება\n    delete_account_html: თუ გსურთ გააუქმოთ თქვენი ანგარიში, შეგიძლიათ <a href=\"%{path}\">გააგრძელოთ აქ</a>. საჭირო იქნება დამოწმება.\n    didnt_get_confirmation: არ მოგსვლიათ დამოწმების ინსტრუქციები?\n    forgot_password: დაგავიწყდათ პაროლი?\n    invalid_reset_password_token: პაროლის გადატვირთვის ტოკენი არასწორია ან ვადაგასული. გთხოვთ მოითხოვეთ ახალი.\n    login: შესვლა\n    logout: გასვლა\n    migrate_account: სხვა ანგარიშზე გადასვლა\n    migrate_account_html: თუ გსურთ ამ ანგარიშის რედირექტის ხვაზე, შეგიძლიათ <a href=\"%{path}\">გაუწიოთ კონფიგურაცია აქ</a>.\n    or_log_in_with: ან გამოიყენეთ\n    providers:\n      cas: ქეს\n      saml: სამლ\n    register: რეგისტრაცია\n    resend_confirmation: დამოწმების ინსტრუქციების ხელახალი გამოგზავნა\n    reset_password: პაროლის გადატვირთვა\n    security: უსაფრთხოება\n    set_new_password: ახალი პაროლის დაყენება\n  authorize_follow:\n    already_following: უკვე მიჰყვებით ამ ანგარიშს\n    error: სამწუხაროთ, დისტანციური სერვერის წაკითხვამ გამოიწვია შეცდომა\n    follow: გაყევი\n    follow_request: 'დადევნების მოთხონვა გაეგზავნა:'\n    following: 'წარმატება! ახლა მიჰყვებით:'\n    post_follow:\n      close: ან შეგიძლიათ დახუროთ ეს ფანჯარა.\n      return: მომხმარებლის პროფილის ჩვენება\n      web: ვებზე გადასვლა\n    title: გაყევი %{acct}-ს\n  datetime:\n    distance_in_words:\n      about_x_hours: \"%{count}სთ\"\n      about_x_months: \"%{count}თვე\"\n      about_x_years: \"%{count}წელი\"\n      almost_x_years: \"%{count}წელი\"\n      half_a_minute: ამ წამს\n      less_than_x_minutes: \"%{count}წთ\"\n      less_than_x_seconds: ამ წამს\n      over_x_years: \"%{count}წელი\"\n      x_days: \"%{count}დღე\"\n      x_minutes: \"%{count}წთ\"\n      x_months: \"%{count}თვე\"\n      x_seconds: \"%{count}წმ\"\n  deletes:\n    bad_password_msg: კარგად სცადეთ, ჰაკერებო! არასწორი პაროლი\n    confirm_password: იდენტობის დასამოწმებლად შეიყვანეთ მიმდინარე პაროლი\n    description_html: ეს <strong>სამუდამოდ, დაუბრუნებლად</strong> გააუქმებს კონტენტს თქვენი ანგარიშიდან და მოახდენს მის დეაქტივაციას. მომხმარებლის სახელი კი, სამომავლო იმპერსონაციების შესაჩერებლად, გახდება რეზერვირებული.\n    proceed: ანგარიშის გაუქმება\n    success_msg: თქვენი ანგარიში წარმატებით გაუქმდა\n    warning_html: მოცულობის გაუქმება გარანტირებულია მხოლოდ ამ ინსტანციაზე. კონტენტი რომელიც ფართო მასშტაბით გაზიარდა უფრო დატოვებს კვალს. ოფლაინ სერვერები და სერვერები, რომლებმაც შეწყვიტეს თქვენი განახლებების გამოწერა არ განაახლებენ მონაცემთა ბაზებს.\n    warning_title: წვდომა გავრცელებულ კონტენტზე\n  errors:\n    '403': ამ გვერდის ხილვის უფლება არ გაქვთ.\n    '404': გვერდი რომელსაც ეძებთ არ არსებობს.\n    '410': გვერდი რომელსაც ეძებდით აღარ არსებობს.\n    '422':\n      content: უსაფრთხოების ვერიფიკაცია ვერ მოხერხდა. ბლოკავთ ქუქის?\n      title: უსაფრთხოების ვერიფიკაცია არ შედგა\n    '429': დარტყმა\n    '500':\n      content: ბოდიში, ჩვენ მხარეს რაღაც არია.\n      title: გვერდი არაა სწორი\n    noscript_html: მასტოდონ ვებ-აპლიკაციის გამოყენებისთვის, გთხოვთ ჩართოთ ჯავასკრიპტი. სხვა შემთხვევაში, მასტოდონის თქვენი პატფორმისთვის სცადეთ გამოიყენოთ ერთ-ერთი <a href=\"%{apps_path}\">მშობლიური აპლიკაცია</a>.\n  exports:\n    archive_takeout:\n      date: თარიღი\n      download: ჩამოტვირთეთ თქვენი არქივი\n      hint_html: შეგიძლიათ მოითხოვოთ თქვენი აქივი <strong>ტუტებისა და ატვირთული მედიისა</strong>. ექსპორტირებული მონაცემები იქნება ექთივითი-ფაბ ფორმატში, წაკითხვადი ნებისმიერი თავსებადი პროგრამით. არქივის მოთხოვნა შეგიძლიათ 7 დღეში ერთხელ.\n      in_progress: მიმდინარეობს თქვენი არქივის შედგენა...\n      request: თქვენი არქივის მოთხოვნა\n      size: ზომა\n    blocks: თქვენ ბლოკავთ\n    csv: ცსვ\n    follows: თქვენ მიჰყვებით\n    mutes: თქვენ აჩუმებთ\n    storage: მედია საცავი\n  filters:\n    contexts:\n      home: სახლის თაიმლაინი\n      notifications: შეტყობინებები\n      public: საჯარო თაიმლაინი\n      thread: საუბრები\n    edit:\n      title: ფილტრის ცვლილება\n    errors:\n      invalid_context: მოწოდებულია არასწორი ან ცარიელი კონტექსტი\n      invalid_irreversible: დაუბრუნებელი ფილტრაცია მუშაობს მხოლოდ სახლის ან ნოტიფიკაციის კონტექსტში\n    index:\n      delete: გაუქმება\n      title: ფილტრები\n    new:\n      title: ახალი ფილტრის დამატება\n  footer:\n    developers: დეველოპერები\n    more: მეტი…\n    resources: რესურსები\n  generic:\n    changes_saved_msg: ცვლილებები წარმატებით დამახსოვრდა!\n    save_changes: ცვლილებების შენახვა\n    validation_errors:\n      one: რაღაც ჯერ არაა მთლად კარგად! გთხოვთ განიხილოთ ქვემოთ მოცემული შეცდომები\n      other: რაღაც ჯერ არაა მთლად კარგად! გთხოვთ განიხილოთ ქვემოთ მოცემული %{count} შეცდომა\n  imports:\n    preface: შეგიძლიათ დააიმპორტოთ მონაცემები, რომლებიც დააექსპორტეთ სხვა სერვერიდან, მაგალითად ადამიანების სია, რომლებსაც მიჰყვებით ან ბლოკავთ.\n    success: თქვენი მონაცემები წარმატებით აიტვირთა და მათი პროცესირება მოხდება გარკვეულ დროში\n    types:\n      blocking: ბლოკირების სია\n      following: დადევნების სია\n      muting: გაჩუმების სია\n    upload: ატვირთვა\n  in_memoriam_html: მემორანდუმში.\n  invites:\n    delete: დეაქტივაცია\n    expired: ვადა გაუვიდა\n    expires_in:\n      '1800': 30 წუთში\n      '21600': 6 საათში\n      '3600': 1 საათში\n      '43200': 12 საათში\n      '604800': 1 კვირაში\n      '86400': 1 დღეში\n    expires_in_prompt: არასდროს\n    generate: გენერირება\n    invited_by: 'თქვენ მოგიწვიათ:'\n    max_uses:\n      one: 1 მოხმარება\n      other: \"%{count} მოხმარება\"\n    max_uses_prompt: ლიმიტის გარეშე\n    prompt: ამ ინსტანციაზე წვდომის მისაცემად, დააგენერირეთ და გააზიარეთ ბმულები სხვებთან\n    table:\n      expires_at: ვადა გასდის\n      uses: მოხმარება\n    title: მოიწვიეთ ხალხი\n  lists:\n    errors:\n      limit: მიაღწიეთ სიების მაქსიმალურ ოდენობას\n  media_attachments:\n    validations:\n      images_and_video: ვიდეოს დართვა სტატუსზე, რომელიც უკვე მოიცავს სურათებს, ვერ მოხერხდება\n      too_many: თან ვერ დაურთავთ 4 ფაილზე მეტს\n  migrations:\n    acct: username@domain ახალი ანგარიშის\n    currently_redirecting: 'თქვენი პროფილი გამართულია მოახდინოს გადამისამართება მისამართზე:'\n    proceed: შენახვა\n    updated_msg: თქვენი ანგარიშის მიგრაციის პარამეტრები წარმატეებით დამახსოვრდა!\n  moderation:\n    title: მოდერაცია\n  notification_mailer:\n    digest:\n      action: ყველა შეტყობინების ჩვენება\n      body: 'აქ მოკლე შინაარსია წერილების, რომლებიც გამოგეპარათ წინა სტუმრობის შემდეგ: %{since}'\n      mention: \"%{name}-მა დაგასახელათ:\"\n      new_followers_summary:\n        one: ასევე, არყოფნისას შეგეძინათ ერთი ახალი მიმდევარი! იეი!\n        other: ასევე, არყოფნისას შეგეძინათ %{count} ახალი მიმდევარი! შესანიშნავია!\n      subject:\n        one: \"1 ახალი შეტყობინება თქვენი ბოლო სტუმრობის შემდეგ \\U0001F418\"\n        other: \"%{count} ახალი შეტყობინება თქვენი ბოლო სტუმრობის შემდეგ \\U0001F418\"\n      title: თქვენს არყოფნაში...\n    favourite:\n      body: 'თქვენი სტატუსი ფავორიტი გახადა %{name}-მა:'\n      subject: \"%{name}-მა თქვენი სტატუსი გახადა ფავორიტი\"\n      title: ახალი ფავორიტი\n    follow:\n      body: \"%{name} ახლა მოგყვებათ!\"\n      subject: \"%{name} ახლა მოგყვებათ\"\n      title: ახალი მიმდევარი\n    follow_request:\n      action: დადევნების მოთხოვნების მენეჯმენტი\n      body: \"%{name}-მა მოითხოვა გამოგყვეთ\"\n      subject: 'მიმდევარი მოლოდინში: %{name}'\n      title: ახალი დადევნების მოთხოვნა\n    mention:\n      action: პასუხი\n      body: 'თქვენ %{name}-მა გასახელათ:'\n      subject: თქვენ გასახელათ %{name}-მა\n      title: ახალი სახელობა\n    reblog:\n      body: 'თქვენი სტატუსი გაზარდა %{name}-მა:'\n      subject: \"%{name}-მა გაზარდა თქვენი სტატუსი\"\n      title: ახალი ბუსტი\n  number:\n    human:\n      decimal_units:\n        units:\n          billion: ბილ.\n          million: მილ.\n          quadrillion: კუად.\n          thousand: ათას.\n          trillion: ტრილ.\n  pagination:\n    newer: უფრო ახალი\n    next: შემდეგი\n    older: ძველი\n    prev: წინა\n  preferences:\n    other: სხვა\n  remote_follow:\n    acct: შეიყვანეთ თქვენი username@domain საიდანაც გსურთ გაჰყვეთ\n    missing_resource: საჭირო გადამისამართების ურლ თქვენი ანგარიშისთვის ვერ მოიძებნა\n    no_account_html: არ გაქვთ ანგარიში? შეგიძლიათ <a href='%{sign_up_path}' target='_blank'>დარეგისტრირდეთ აქ</a>\n    proceed: გააგრძელეთ გასაყოლად\n    prompt: 'თქვენ გაჰყვებით:'\n  remote_unfollow:\n    error: შეცდომა\n    title: სათაური\n    unfollowed: დადევნების შეწყვეტა\n  sessions:\n    activity: ბოლო აქტივობა\n    browser: ბრაუზერი\n    browsers:\n      alipay: ალიფეი\n      blackberry: ბლექბერი\n      chrome: ქრომი\n      edge: მაიკროსოფთ ედჯი\n      electron: ელექტრონი\n      firefox: ფაირფოქსი\n      generic: ამოუცნობი ბრაუზერი\n      ie: ინტერნეტ ექფლორერი\n      micro_messenger: მიკრო-მესინჯერი\n      nokia: ნოკია ს40 ოვი ბრაუზერი\n      opera: ოპერა\n      otter: ოტერი\n      phantom_js: ფანტომჯეიესი\n      qq: ქქ ბრაუზერი\n      safari: საფარი\n      uc_browser: იუსიბიბრაუზერი\n      weibo: ვეიბო\n    current_session: მიმდინარე სესია\n    description: \"%{browser} %{platform}-ზე\"\n    explanation: ეს ვებ-ბრაუზერებია, რომლებიც ამჟამად აუტენტიფიცირებულ არიან თქვენს მასტოდონ ანგარიშთან.\n    ip: აი-პი\n    platforms:\n      adobe_air: ედობ ეარი\n      android: ანდროიდი\n      blackberry: ბლექბერი\n      chrome_os: ქრომო-ოსი\n      firefox_os: ფაირფოქს-ოსი\n      ios: აი-ოსი\n      linux: ლინუქსი\n      mac: მაკი\n      other: ამოუცნობი პლატფორმა\n      windows: ვინდოუსი\n      windows_mobile: ვინდოუს მობაილი\n      windows_phone: ვინდოუს ფოუნი\n    revoke: გაუქმება\n    revoke_success: სესია წარმატებით გაუქმდა\n    title: სესიები\n  settings:\n    authorized_apps: ავტორიზირებული აპლიკაციები\n    back: უკან მასტოდონისკენ\n    delete: ანგარიშის გაუქმება\n    development: დეველოპმენტი\n    edit_profile: პროფილის ცვლილება\n    export: მონაცემის ექსპორტი\n    import: იმპორტი\n    migrate: ანგარიშის მიგრაცია\n    notifications: შეტყობინებები\n    preferences: პრეფერენციები\n    two_factor_authentication: მეორე-ფაქტორის აუტენტიფიკაცია\n  statuses:\n    attached:\n      description: 'თან დართული: %{attached}'\n      image:\n        one: \"%{count} სურათი\"\n        other: \"%{count} სურათები\"\n      video:\n        one: \"%{count} ვიდეო\"\n        other: \"%{count} ვიდეოები\"\n    boosted_from_html: გაიზარდა %{acct_link}-იდან\n    content_warning: 'გაფრთხილება კონტენტზე: %{warning}'\n    disallowed_hashtags:\n      one: 'მოიცავდა აკრძალულ ჰეშტეგს: %{tags}'\n      other: 'მოიცავს აკრძალულ ჰეშტეგს: %{tags}'\n    language_detection: ავტომატურად დადგინდეს ენა\n    open_in_web: ვებში გახნსა\n    over_character_limit: ნიშნების ლიმიტი გადასცდა %{max}-ს\n    pin_errors:\n      limit: ტუტების მაქსიმალური რაოდენობა უკვე აპინეთ\n      ownership: სხვისი ტუტი ვერ აიპინება\n      private: არა-საჯარო ტუტი ვერ აიპინება\n      reblog: ბუსტი ვერ აიპინება\n    show_more: მეტის ჩვენება\n    sign_in_to_participate: საუბარში მონაწილეობისთვის გაიარეთ ავტორიზაცია\n    visibilities:\n      private: მხოლოდ-მიმდევრები\n      private_long: აჩვენე მხოლოდ მიმდევრებს\n      public: საჯარო\n      public_long: ხედავს ყველა\n      unlisted: ჩამოუთვლელი\n      unlisted_long: ხედავს ყველა, მაგრამ არ ჩანს საჯარო თაიმლაინებში\n  stream_entries:\n    pinned: აპინული ტუტი\n    reblogged: გაზრდილი\n    sensitive_content: მგრძნობიარე კონტენტი\n  terms:\n    body_html: |\n      <h2>კონფიდენციალურობის პოლიტიკა</h2>\n      <h3 id=\"collect\">რა ინფორმაციას ვაგროვებთ?</h3>\n\n      <ul>\n      <li><em>ძირითადი ანგარიშის ინფორმაცია</em>: თუ დარეგისტრირდებით ამ სერვერზე, შესაძლოა მოგთხოვოთ მომხმარებლის სახელი, ელ-ფოსტის მისამართი და პაროლი. შესაძლებელია, ასევე შეიყვანოთ დამატებითი პროფილის ინორმაცია, როგორიცაა დისპლეის სახელი და ბიოგრაფია, ასევე ატვირთოთ პროფილის და დასათაურების სურათი. მომხმარებლის სახელი, დისპლეის სახელი, ბიოგრაფია, პროფილის სურათი, დასათაურების სურათი ყოველთვის ღიადაა ჩამოთვლილი.</li>\n      <li><em>პოსტები, დადევნებები და სხვა საჯარო ინფორმაცია</em>: ადამიანების სია, რომლებსაც მიჰყვებით საჯაროდაა ჩამოთვლილი, იგივე ეხება თქვენს მიდევრებსაც. როდესაც აგზავნით წერილს, თარიღი, დრო და აპლიკაცია თუ საიდანაც განათავსეთ წერილი ინახება. წერილები შესაძლოა შეიცავდნენ მედია ფაილებს, როგორებიცაა სურათები და ვიდეოები. ღია და ჩამოუთვლელი პოსტები ხელმისაწვდომია საჯაროდ. როდესაც ათავსებთ პოსტს თქვენს პროფილზე, ის ასევე საჟაროდ წვდომადი ხდება. თქვენი პოსტები ეგზავნებათ თქვენს მიმდევრებს, ზოგიერთ შემთხვევაში ეს ნიშნავს, რომ ისინი იგზავნება სხვა სერვერებზე და მათი ასლები იქვე ინახება. როდესაც აუქმებთ პოსტს, ეს მოქმედება ეგზავნებათ თქვენს მიმდევრებს. რე-ბლოგირების ან ფავორიტად ქცევის ქმედებები ასევე საქვეყნოა.</li>\n      <li><em>პირდაპირი და პოსტები მხოლოდ-მიმდევრებისთვის</em>: ყველა პოსტი ინახება და მათი პროცესირება ხდება სერვერზე. პოსტები რომლებიც განეკუთვნება მხოლოდ მიმდევრებს მიეწოდებათ მათ, მომხმარებლები, რომლებიც დასახელებულია პოსტებში და პირდაპირი პოსტები ეგზავნებათ მხოლოდ ჩამოთვლილ მომხმარებლებს. ზოგიერთ შემთხვევაში, ეს ნიშნავს, რომ გადაგზავნა ხდება გარე სერვერებზე და ასლებიც იქ ინახება. ჩვენ დიდ ძალისხმევას ვუწევთ წვდომის ლიმიტს მხოლოდ აუტორიზირებული ადამიანებისთვის, თუმცა სხვა სერვერებმა შეიძლება ეს არ აწარმოონ. აქედან გამომდინარე, მნიშვნელოვანია განიხილოთ სერვერები, საიდანაც მოდიან თქვენი მიმდევრები. შეგიძლიათ ჩართოთ ან გამორთოთ პარამეტრი, დაადასტუროთ ან უარყოთ ახალი მიმდევარი. <em>გთხოვთ გაითვალისწინოთ, რომ სერვერის ოპერაციები და სხვა მიმღები სერვერები შესაძლოა კითხულობდნენ ამგვარ წერილებს</em>, მიმღებებს შეუძლიათ შექმნან სქრინშოთი, დააკოპირონ ან ხელახლა გააზიარონ ისინი. <em>არ გააზიაროთ საშიში ინფორმაცია მასტოდონით.</em></li>\n      <li><em>აი-პიები და სხვა მეტა-მონაცემები</em>: როდესაც გაივლით აუტენტიფიკაციას, ჩვენ ვინახავთ აი-პი მისამართს საიდანაც შემოხვედით, ასევე ბრაუზერის აპლიკაციას. ყველა ავტორიზირებული სესია თქვენთვის განსახილველად და გასაუქმებლად ხელმისაწვდომია პარამეტრებში. ბოლო შენახული აი-პი მისამართი ინახება მაქსიმუმ 12 თვით. ჩვენ ასევე შეიძლება გაგვაჩნდეს სერვერის ლოგი, რომელიც ინახავს თითოეული მოთხოვნის IP მისამართს.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"use\">რაში ვიყენებთ ინფორმაციას?</h3>\n\n      <p>ნებისმიერი სხვა ინფორმაცია, რომელსაც ვაგროვებთ თქვენგან შესაძლოა გამოყენებულ იქნას შემდეგი გზებით:</p>\n\n      <ul>\n      <li>რომ უზრუნველვყოთ მასტოდონის მთავარი ფუნქციონალი. შეგიძლიათ ინტერაქცია გაუწიოთ მხოლოდ სხვის კონტენტს და შექმნათ პოსტები მაშინ როდესაც ავტორიზებული ხართ. მაგალითად, შესაძლოა გაჰყვეთ სხვა ადამიანებს, რათა იხილოთ მათი ჯამური პოსტები საკუთარ პერსონალიზებულ სახლის თაიმლაინზე.</li>\n      <li>რომ შევუწყვოთ ხელი საზოგადოების მოდერაციას, მაგალითად შევადაროთ თქვენი აი-პი მისამართი სხვა ცნობილ მისამართებს, რათა ამოვიცნოთ ბანის გადაუხდელობა ან სხვა დარღვევები.</li>\n      <li>ელ-ფოსტის მისამართი რომელსაც გვაწვდით, შესაძლოა გამოვიყენოთ თქვენთვის ინფორმაციის გამოსაგძავნად, შეგატყობინოთ სხვა ადამიანების ინტერაქციაზე თქვენს კონტენტთან ან თქვენთვის გამოგზავნილ წერილებზე, ასევე რომ გიპასუხოთ მოთხოვნებზე და/ან სხვა საკითხებზე.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"protect\">როგორ ვიცავთ თქვენს ინფორმაციას?</h3>\n\n      <p>მიღებული გვაქვს სხვადასხვა ზომა, შევინარჩუნოთ თქვენი პირადი ინფორმაციის უსაფრთხოება, რომელსაც აგზავნით, შეგყავთ ან კითხულობთ. ამ ყველაფერთან ერთად თქვენი ბრაუზერის სესია, ტრეფიკი თქვენს აპლიკაციასა და აპის შორის დაცულია სსლ-ით, თქვენი პაროლი იშიფრება ძლიერი ალგორითმით. შეგიძლიათ ჩართოთ მეორე-ფაქტორის აუტენტიფიკაცია, რათა გააღმაოთ თქვენი ანგარიშის თავდაცვა.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"data-retention\">რა არის ჩვენი მონაცემის უარყოფის პოლიტიკა?</h3>\n\n      <p>ჩვენ არ დავიშურებთ ძალისხმევას რომ:</p>\n\n      <ul>\n      <li>შევინარჩუნოთ სერვერის ლოგები, რომლებიც მოიცავენ ყველა მოთხოვნის აი-პი მისამართს, თუმცა ესეთი ლოგები არ ინახება 90 დღეზე მეტ ხანს.</li>\n      <li>შევინარჩუნოთ რეგისტრირებული მომხმარებლების აი-პი მისამართები მაქსიმუმ 12 თვით.</li>\n      </ul>\n\n      <p>შეგიძლიათ მოითხოვოთ და ჩამოტვირთოთ თქვენი კონტენტის არქივი, რომელიც მოიცავს თქვენს პოსტებს, მედია ფაილებს, პროფილის და დასათაურების სურათს.</p>\n\n      <p>შეგიძლიათ დაუბრუნებლად გააუქმოთ თქვენი ანგარიში ნებისმიერ დროს.</p>\n\n      <hr class=\"spacer\"/>\n\n      <h3 id=\"cookies\">ვიყენებთ თუ არა ქუქის?</h3>\n\n      <p>დიახ. ქუქიები წარმოადგენენ პატარა ფაილებს, რომელთაც, საიტი ან სერვის-პროვაიდერი, ათავსებს თქვენი კომპიუტერის მყარ დისკზე, ვებ-ბრაუზერის (თუ ნებას რთავთ) მეშვეობით. ქუქიები საშუალებას აძლევს საიტს ამოიცნონ თქვენი ბრაუზზერი და თუ გაქვთ რეგისტრირებული ანგარიში მისი ასოციაცია მოახდინონ თქვენს ანგარიშთან.</p>\n\n      <p>ჩვენ ვიყენებთ ქუქის, ვიცოდეთ და შევინახოთ თქვენი პრეფერენსიები სამომავლო სტუმრობებისთვის.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"disclose\">ვამჟღავნებთ თუ არა ინფორმაციას გარე მხარეებისთვის?</h3>\n\n      <p>ჩვენ არ ვყიდით, ვვაჭრობთ ან გადაქვაქ თქვენთვის პირადად იდენტიფიცირებადი ინფორმაცია სხვა მხარეებისთვის. ეს არ მოიცავს სანდო მხარეებს, რომლებიც გვეხმარება საიტის ოპერირებაში, ჩვენი საქმიანობის ჩატარებაში, ან თქვენთვის მომსახურების გაწევაში, წინაპირობით კონფიდენციალურად შეინახონ თქვენი ინფორმაცია. ჩვენ შესაძლოა გამოვაქვეყნოთ თქვენი ინფორმაცია, რომელიც შესაბამისად შეიძლება ჩავთვალოთ კანონმდებლობასთან შეთავსებისთვის, აღვასრულოთ პოლიტიკა ან დავიცვათ ჩვენი ან სხვისი უფლებები, კუთვნილება ან უსაფრთხოება.</p>\n\n      <p>თქვენი საჯარო ინფორმაცია შესაძლოა ჩამოტვირთულ იქნას სხვა სერვერების მიერ ქსელში. თქვენი ღია და მიმდევრებზე გათვლილი პოსტები მიეწოდება სერვერებს სადაც თქვენი მიმდევრები მოღვაწეობენ, იმ შემთხვევაში თუ მიმღებები მომდინარეობენ სხვა სერვერიდან, პირდაპირი წერილები მიეწოდებათ მიმღებების სერვერებს.</p>\n\n      <p>როდესაც უფლებას მისცემთ აპლიკაციას გამოიყენოს თქვენი ანგარიში, უფლებებისგან გამომდინარე, მან შესაძლოა მოიპოვოს თქვენი საჯარო ინფორმაცია, თქვენი დადევნების სიები, თქვენი მიმდევრები, თქვენი სიები, ყველა პოსტი და თქვენი ფავორიტები. აპლიკაციები ვერასდროს იქონიებენ წვდომას თქვენი ელ-ფოსტის მისამართზე ან პაროლზე.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"children\">საიტის მოხმარებს ბავშვების მიერ</h3>\n\n      <p>თუ ეს სერვერი მდებარეობს ეუ-ში ან ეეა-ში: ჩვენი საიტი, პროდუქტები და სერვისები მიმართულია ადამიანებისთვის, რომელთაც შეუსრულდათ 16 წელი. თუ თქვენი ასაკი 16 წელიწადზე ნაკლებია, ჯიდიფიარის (<a href=\"https://en.wikipedia.org/wiki/General_Data_Protection_Regulation\">ზოგადი მონაცემების დაცვის რეგულაცია/a>) მოთხოვნის მიხედვით არ გამოიყენოთ ეს საიტი.</p>\n\n      <p>თუ ეს სერვერი მდებარეობს ა.შ.შ.-ში: ჩვენი საიტი პროდუქტი და სერვისები მიმართულია ადამიანებისთვის, რომელთაც შეუსრულდათ 13 წელი. თუ თქვენი ასაკი 13 წელიწადზე ნაკლებია, კოპპას (<a href=\"https://en.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act\">ბავშვთა ონლაინ კონფიდენციალურობის დაცვის აქტი</a>) მოთხოვნების მიხედვით არ გამოიყენოთ ეს საიტი.</p>\n\n      <p>იურიდიული მოთხოვნილებები შეიძლება განსხვავდებოდეს, თუ ეს სერვერი იმყოფება სხვა იურისდიქციის ქვეშ.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"changes\">ცვლილებები კონფიდენციალურობის პოლიტიკაში</h3>\n\n      <p>თუ გადავწყვეტთ შევცვალოთ კონფიდენციალურობის პოლიტიკა, გამოვაქვეყნებთ ამ გვერდზე.</p>\n\n      <p>ეს დოკუმენტი არის ცც-ბაი-სა. ეს ბოლოს განახლდა 2018 წლის, 17 აგვისტოს.</p>\n\n      <p>საწყისად ადაპტირებულია <a href=\"https://github.com/discourse/discourse\">გამჟღავნების კონფიდენციალური პოლიტიკისგან</a>.</p>\n    title: \"%{instance} მომსახურების პირობები და კონფიდენციალურობის პოლიტიკა\"\n  themes:\n    contrast: მაღალი კონტრასტი\n    default: მასტოდონი\n    mastodon-light: მასტოდონი (ღია)\n  two_factor_authentication:\n    code_hint: დასამოწმებლად შეიყვანეთ თქვენი აუტენტიფიკატორ აპლიკაციისგან გენერირებული კოდი\n    description_html: თუ ჩართავთ <strong>მეორე-ფაქტორის აუტენტიფიკაციას</strong>, შესვლისას აუცილებელი იქნება ფლობდეთ ტელეფონს, რომელიც დააგენერირებს შესვლის ტოკენებს.\n    disable: გათიშვა\n    enable: ჩართვა\n    enabled: მეორე-ფაქტორის აუტენტიფიკაცია ჩართულია\n    enabled_success: მეორე-ფაქტორის აუტენტიფიკაცია წარმატებით ჩაირთო\n    generate_recovery_codes: აღდგენის კოდების გენერაცია\n    instructions_html: \"<strong>დაასკანირეთ ეს ქრ კოდი გუგლ აუტენტიფიკატორში ან მსგავს ტოტპ აპლიკაციაში თქვენს ტელეფონზე</strong>. ამიერიდან, ეს აპლიკაცია დააგენერირებს ტოკენებს მაშინ როდესაც დაგჭირდებათ ავტორიზაცია.\"\n    lost_recovery_codes: აღდგენის კოდები უფლებას გაძლევთ მიიღოთ ხელმეორე წვდომა თქვენი ანგარიშისადმი თუ დაკარგავთ ტელეფონს. თუ დაკარგეთ აღდგენის კოდები, მათ რეგენერაცია შეგიძლიათ აქ. ძველი აღდგენის კოდები აღარ იქნება ვალიდური.\n    manual_instructions: 'თუ ვერ ასკანირებთ ქრ კოდს და საჭიროებთ მის მექანიკურ რეჟიმში შეყვანას, აქ არის ჩვეულებრივი ტექსტური საიდუმლო:'\n    recovery_codes: გაუწიეთ აღდგენის კოდებს რეზერვაცია\n    recovery_codes_regenerated: აღგენის კოდების რეგენერაცია წარმატებით შესრულდა\n    recovery_instructions_html: თუ როდესმე დაკარგავთ წვდომას თქვენს ტელეფონთან, შეგიძლიათ ქვემოთ მოცემული აღდგენის კოდები გამოიყენოთ, რათა მოიპოვოთ ხელმეორე წვდომა თქვენი ანგარიშისადმი. <strong>იქონიეთ აღდგენის კოდები დაცულად</strong>. მაგალითისთვის, შეგიძლიათ ამობეჭდოთ და შეინახოთ სხვა საბუთებთან ერთად.\n    setup: დაყენება\n    wrong_code: შეყვანილი კოდი არ იყო სწორი! სწორია სერვერის და მოწყობილობის დრო?\n  user_mailer:\n    backup_ready:\n      explanation: თქვენ მოითხოვეთ თქვენი მასტოდონის ანგარიშის სრული რეზერვაცია. ის ახლა უკვე მზადაა გადმოსაწერად!\n      subject: თქვენი არქივი გადმოსაწერად მზადაა\n      title: არქივის მიღება\n    welcome:\n      edit_profile_action: პროფილის მოწყობა\n      edit_profile_step: შეგიძლიათ მოაწყოთ თქვენი პროფილი ავატარის ატვირთვით, დასათაურების სურათით, თქვენი დისპლეი სახელის შეცვლით და სხვა. თუ გსურთ გაუწიოთ ახალ მიმდევრებს რევიუ, სანამ რეალურად გამოგყვებიან, შეგიძლიათ ჩაკეტოთ თქვენი ანგარიში.\n      explanation: აქ რამდენიმე რჩევაა დასაწყისისთვის\n      final_action: დაიწყე პოსტვა\n      final_step: 'დაიწყე პოსტვა! თქვენი ღია წერილები შესაძლოა ნახონ სხვებმა მიმდევრების გარეშეც კი, მაგალითად თქვენს ლოკალურ თაიმლაინზე ან ჰეშტეგებში. შეგიძლიათ წარადგინოთ თქვენი თავი #introductions ჰეშტეგით.'\n      full_handle: თქვენი სრული სახელური\n      full_handle_hint: ეს არის ის რასაც ეტყვით თქვენს მეგობრებს, რათა მოგწერონ ან გამოგყვნენ სხვა ინსტანციიდან.\n      review_preferences_action: შეცვალეთ პრეფერენსიები\n      review_preferences_step: დარწმუნდით რომ აყენებთ თქვენს პრეფერენსიებს, მაგალითად რა ელ-ფოსტის წერილების მიღება გსურთ, ან კონფიდენციალურობის რა დონე გსურთ ჰქონდეთ თქვენს პოსტებს საწყისად. თუ არ გაღიზიანებთ მოძრაობა, შეგიძლიათ ჩართოთ გიფის ავტო-დაკვრა.\n      subject: კეთილი იყოს თქვენი მობრძანება მასტოდონში\n      tip_federated_timeline: ფედერალური თაიმლაინი მასტოდონის ქსელის ცეცხლოვანი ხედია. ის მოიცავს მხოლოდ იმ ადამიანებს, რომელთაგანაც გამოიწერეს თქვენმა მეზობლებმა, ასე რომ ეს არაა სრული.\n      tip_following: თქვენ საწყისად მიჰყვებით თქვენი სერვერის ადმინისტრატორ(ებ)ს. უფრო საინტერესო ადამიანების მოსაძებნად იხილეთ ლოკალური და ფედერალური თაიმლაინები.\n      tip_local_timeline: ლოკალური თაიმლაინი ცეცხლოვანი ხედია ადამიანებისთვის %{instance}-ზე. ისინი არიან თქვენი უსიტყვო მეზობლები!\n      tip_mobile_webapp: თუ თქვენი მობილური ბრაუზერი გთავაზობთ მასტოდონის სახლის-ეკრანზე დამატებას, შეძლებთ ფუშ შეტყობინებების მიღებას. ეს მრავალმხრივ მოქმედებს როგორც მშობლიური აპლიკაცია!\n      tips: რჩევები\n      title: კეთილი იყოს თქვენი მობრძანება, %{name}!\n  users:\n    invalid_email: ელ-ფოსტის მისამართი არაა მართებული\n    invalid_otp_token: არასწორი მეორე ფაქტორის კოდი\n    otp_lost_help_html: თუ დაკარგეთ წვდომა ორივეზე, შესაძლოა დაუკავშირდეთ %{email}-ს\n    seamless_external_login: შესული ხართ გარე სერვისით, აქედან გამომდინარე პაროლი და ელ-ფოსტის მისამართი არაა ხელმისაწვდომი.\n    signed_in_as: 'შესული ხართ როგორც:'\n"
  },
  {
    "path": "config/locales/kk.yml",
    "content": "---\nkk:\n  about:\n    about_hashtag_html: Бұл жерде <strong>#%{hashtag}</strong> хэштегімен жинақталған жазбалар. Желіге тіркеліп, сіз де қосыла аласыз бұл ортаға.\n    about_mastodon_html: Mastodon - әлеуметтік желіге негізделген, тегін және веб протоколды, ашық кодты бағдарлама. Ол email сияқты орталығы жоқ құрылым.\n    about_this: Туралы\n    administered_by: 'Админ:'\n    apps: Мобиль қосымшалар\n    contact: Байланыс\n    contact_missing: Бапталмаған\n    contact_unavailable: Белгісіз\n    documentation: Құжаттама\n    extended_description_html: |\n      <h3>Ережелерге арналған жақсы орын</h3>\n      <p>Әлі ештеңе жазылмапты</p>\n    generic_description: \"%{domain} желідегі серверлердің бірі\"\n    hosted_on: Mastodon орнатылған %{domain} доменінде\n    learn_more: Көбірек білу\n    privacy_policy: Құпиялылық саясаты\n    source_code: Ашық коды\n    status_count_after:\n      one: жазба\n      other: жазба\n    status_count_before: Барлығы\n    terms: Қолдану шарттары\n    user_count_after:\n      one: қолданушы\n      other: қолданушы\n    user_count_before: Желіде\n    what_is_mastodon: Mastodon деген не?\n  accounts:\n    choices_html: \"%{name} таңдаулары:\"\n    follow: Жазылу\n    followers:\n      one: Оқырман\n      other: Оқырман\n    following: Жазылғандары\n    joined: Тіркелген күні %{date}\n    last_active: соңғы әрекеті\n    link_verified_on: Сілтеме меншігі расталған күн %{date}\n    media: Медиа\n    moved_html: \"%{name} мына жерге көшті %{new_profile_link}:\"\n    network_hidden: Бұл ақпарат қолжетімді емес\n    nothing_here: Бұл жерде ештеңе жоқ!\n    people_followed_by: \"%{name} жазылған адамдар\"\n    people_who_follow: \"%{name} атты қолданушының оқырмандары\"\n    pin_errors:\n      following: Оқығыңыз келген адамға жазылуыңыз керек\n    posts:\n      one: Жазба\n      other: Жазба\n    posts_tab_heading: Жазба\n    posts_with_replies: Жазбалар және жауаптар\n    reserved_username: Мұндай логин тіркелген\n    roles:\n      admin: Админ\n      bot: Бот\n      moderator: Мод\n    unfollow: Оқымау\n  admin:\n    account_actions:\n      action: Әрекетті орындаңыз\n      title: Модерация жасаңыз %{acct}\n    account_moderation_notes:\n      create: Жазба қалдырыңыз\n      created_msg: Модерация жазбасы қалдырылды!\n      delete: Өшіру\n      destroyed_msg: Модерация жазбасы өшірілді!\n    accounts:\n      are_you_sure: Шынымен бе?\n      avatar: Аватар\n      by_domain: Домен\n      change_email:\n        changed_msg: Аккаунт email-і сәтті өзгертілді!\n        current_email: Қазіргі email\n        label: email өзгерту\n        new_email: Жаңа email\n        submit: email өзгерт\n        title: Қолданушы email-ін өзгерту %{username}\n      confirm: Құптау\n      confirmed: Құпталды\n      confirming: Құпталуды күтеді\n      deleted: Өшірілді\n      demote: Төмендету\n      disable: Ажырату\n      disable_two_factor_authentication: Ажырату 2FA\n      disabled: Ажыратылды\n      display_name: Атын көрсет\n      domain: Домен\n      edit: Түзету\n      email_status: Email статусы\n      enable: Қосу\n      enabled: Қосылды\n      feed_url: Feеd URL\n      followers: Оқырмандар\n      followers_url: Оқырмандар URL\n      follows: Жазылғандары\n      header: Басы\n      inbox_url: Келген хаттар URL\n      invited_by: Шақырған\n      joined: Қосылды\n      location:\n        all: Барлығы\n        local: Жергілікті\n        remote: Алыс\n        title: Мекен\n      login_status: Логин статусы\n      media_attachments: Медиа файлдар\n      memorialize: Естелік қылу\n      moderation:\n        active: Актив\n        all: Барлығы\n        silenced: Үнсіз\n        suspended: Тоқтатылды\n        title: Модерация\n      moderation_notes: Модерация жазбалары\n      most_recent_activity: Соңғы белсенділіктер\n      most_recent_ip: Соңғы ІР\n      no_limits_imposed: Шектеу жоқ\n      not_subscribed: Жазылмаған\n      outbox_url: Кеткен хаттар URL\n      perform_full_suspension: Тоқтат\n      profile_url: Профиль URL\n      promote: Жарнамалау\n      protocol: Хаттама\n      public: Ашық\n      push_subscription_expires: PuSH жазылу мерзімі аяқталады\n      redownload: Профиль жаңарт\n      remove_avatar: Аватар өшіру\n      remove_header: Мұқаба суретін өшір\n      resend_confirmation:\n        already_confirmed: Қолданушы құпталған\n        send: Құптау хатын қайтадан жібер\n        success: Құптау хаты сәтті жіберілді!\n      reset: Қалпына келтіру\n      reset_password: Құпиясөзді қалпына келтіру\n      resubscribe: Resubscribе\n      role: Қайта жазылу\n      roles:\n        admin: Админ\n        moderator: Модератор\n        staff: Қызметкерлер\n        user: Қолданушы\n      salmon_url: Ақсерке URL\n      search: Іздеу\n      shared_inbox_url: Бөлісілген инбокс URL\n      show:\n        created_reports: Шағымдар жинағы\n        targeted_reports: Жіберілген шағымдар\n      silence: Үнсіз\n      silenced: Үнсіз қылғандар\n      statuses: Статустар\n      subscribe: Жазылу\n      suspended: Тоқтатылды\n      title: Аккаунттар\n      unconfirmed_email: Құпталмаған email\n      undo_silenced: Үнсіздікті қайтып алу\n      undo_suspension: Тоқтатуды қайтып алу\n      unsubscribe: Жазылмау\n      username: Логин\n      warn: Ескерту\n      web: Веб\n    action_logs:\n      actions:\n        assigned_to_self_report: \"%{name} шағым тастады %{target} өздері үшін\"\n        change_email_user: \"%{name} e-mail адресін өзгертті - %{target}\"\n        confirm_user: \"%{name} e-mail адресін құптады - %{target}\"\n        create_account_warning: \"%{name} ескерту жіберді - %{target}\"\n        create_custom_emoji: \"%{name} жаңа эмодзи қосты %{target}\"\n        create_domain_block: \"%{name} домен бұғаттады - %{target}\"\n        create_email_domain_block: \"%{name} e-mail доменін қара тізімге қосты - %{target}\"\n        demote_user: \"%{name} төмендетілген қолданушы - %{target}\"\n        destroy_custom_emoji: \"%{name} эмодзи жойды %{target}\"\n        destroy_domain_block: \"%{name} бұғатталмаған домен %{target}\"\n        destroy_email_domain_block: \"%{name} e-mail доменін ақ тізімге кіргізді %{target}\"\n        destroy_status: \"%{name} жазбасын өшірді %{target}\"\n        disable_2fa_user: \"%{name} қолданушы үшін екі фактор ажыратылған %{target}\"\n        disable_custom_emoji: \"%{name} эмодзи алып тастады %{target}\"\n        disable_user: \"%{name} қосылмаған логин %{target}\"\n        enable_custom_emoji: \"%{name} қосылған эмодзи %{target}\"\n        enable_user: \"%{name} қосылған логин %{target}\"\n        memorialize_account: \"%{name} %{target} аккаунтын естеліктеріне қосты\"\n        promote_user: \"%{name} жарнамалады %{target}\"\n        remove_avatar_user: \"%{name} %{target} аватарын өшірді\"\n        reopen_report: \"%{name} %{target} шағымын қайта қарады\"\n        reset_password_user: \"%{name} %{target} құпиясөзін қалпына келтірді\"\n        resolve_report: \"%{name} %{target} шағымын қарастырды\"\n        silence_account: \"%{name} %{target} аккаунтын үнсіз қылды\"\n        suspend_account: \"%{name} %{target} аккаунтын тоқтатты\"\n        unassigned_report: \"%{name} бекітілмеген есеп %{target}\"\n        unsilence_account: \"%{name} %{target} аккаунтын қайта қосты\"\n        unsuspend_account: \"%{name} %{target} аккаунтын қайта қосты\"\n        update_custom_emoji: \"%{name} эмодзи жаңартты %{target}\"\n        update_status: \"%{name} жазбасын жаңартты %{target}\"\n      deleted_status: \"(өшірілген жазба)\"\n      title: Аудит логы\n    custom_emojis:\n      by_domain: Домен\n      copied_msg: Жергілікті эмодзидің көшірмесі сәтті жасалды\n      copy: Көшіру\n      copy_failed_msg: Жергілікті эмодзидің көшірмесі жасалмады\n      created_msg: Эмодзи сәтті жаңартылды!\n      delete: Өшіру\n      destroyed_msg: Эмодзи сәтті жойылды!\n      disable: Ажырату\n      disabled_msg: Бұл эмодзи сәтті жойылды\n      emoji: Эмодзи\n      enable: Қосу\n      enabled_msg: Эмодзи сәтті қосылды\n      image_hint: PNG 50KB\n      listed: Тізілді\n      new:\n        title: Жаңа эмодзи қос\n      overwrite: Үстіне жаз\n      shortcode: Шорткод\n      shortcode_hint: Кем дегенде 2 символ, тек латын әріптері мен асты сызылған таңбалар\n      title: Таңдаулы эмодзилар\n      unlisted: Тізімде жоқ\n      update_failed_msg: Бұл эмодзи жаңартылмады\n      updated_msg: Эмодзи сәтті жаңартылды!\n      upload: Жүктеу\n    dashboard:\n      backlog: босатылған тапсырмалар\n      config: Конфигурация\n      feature_deletions: Аккаунттарды жою\n      feature_invites: Шақыру сілтемелері\n      feature_profile_directory: Профиль каталогы\n      feature_registrations: Тіркелулер\n      feature_relay: Федерация релесі\n      features: Мүмкіндіктер\n      hidden_service: Жасырын қызметтер федерациясы\n      open_reports: ашық шағымдар\n      recent_users: Соңғы қолданушылар\n      search: Толық мәтінмен іздеу\n      single_user_mode: Жалғыз пайдаланушы режимі\n      software: Бағдарлама\n      space: Пайдаланылған кеңістік\n      title: Басқару тақтасы\n      total_users: барлық қолданушы\n      trends: Трендтер\n      week_interactions: осы аптадағы әрекеттер\n      week_users_active: осы аптадағы белсенділік\n      week_users_new: осы аптадағы қолданушылар\n    domain_blocks:\n      add_new: Жаңа домен блокын қосу\n      created_msg: Домендік блок енді өңделуде\n      destroyed_msg: Домендік блок қалпына келтірілді\n      domain: Домен\n      new:\n        create: Блок құру\n        hint: Домендік блок дерекқорда тіркелгі жазбаларын құруға кедергі жасамайды, бірақ сол есептік жазбаларда ретроактивті және автоматты түрде нақты модерация әдістерін қолданады.\n        severity:\n          desc_html: \"<strong>Silence</strong> will make the account's posts invisible to anyone who isn't following them. <strong>Suspend</strong> will remove all of the account's content, media, and profile data. Use <strong>None</strong> if you just want to reject media filеs.\"\n          noop: Ештеңе\n          silence: Үнсіз\n          suspend: Тоқтатылған\n        title: Жаңа домен блокы\n      reject_media: Медиа файлдарды қабылдамау\n      reject_media_hint: Жергілікті сақталған мультимедиалық файлдарды жояды және болашақта кез келген жүктеуден бас тартады. Суспензияға байланысты емес\n      reject_reports: Шағым қабылдамау\n      reject_reports_hint: Бұл доменнен келген барлық есептерді елемеңіз. Суспензияға байланысты емес\n      rejecting_media: медиа файлдарды қабылдамау\n      rejecting_reports: шағымдарды қабылдамау\n      severity:\n        silence: үнсіз\n        suspend: тоқтатылған\n      show:\n        affected_accounts:\n          one: Дерекқорда бір тіркелгі қозғалды\n          other: дерекқордағы %{count} аккаунт қозғалған\n        retroactive:\n          silence: Осы домендегі бар тіркелгілерді жою\n          suspend: Осы домендегі бар барлық тіркелгілерді тоқтатыңыз\n        title: \"%{domain} доменіндегі блокты алып таста\"\n        undo: Қайтару\n      undo: Домен блокын қайтып алу\n    email_domain_blocks:\n      add_new: Жаңасын қосу\n      created_msg: Қаратізімге email домені қосылды\n      delete: Өшіру\n      destroyed_msg: Successfully deletеd e-mail domain from blacklist\n      domain: Домен\n      new:\n        create: Add dоmain\n        title: New e-mail blаcklist entry\n      title: E-mail қаратізімі\n    followers:\n      back_to_account: Back To Accоunt\n      title: \"%{acct} оқырмандары\"\n    instances:\n      by_domain: Domаin\n      delivery_available: Жеткізу қол жетімді\n      known_accounts:\n        one: \"%{count} таныс аккаунт\"\n        other: \"%{count} таныс аккаунт\"\n      moderation:\n        all: Барлығы\n        limited: Лимит\n        title: Модерация\n      title: Федерация\n      total_blocked_by_us: Біз бұғаттағандар\n      total_followed_by_them: Олар жазылғандар\n      total_followed_by_us: Біз жазылғандар\n      total_reported: Келген шағымдар\n      total_storage: Медиа файлдар\n    invites:\n      deactivate_all: Барлығын сөндір\n      filter:\n        all: Барлығы\n        available: Қолжетімді\n        expired: Уақыты өткен\n        title: Фильтр\n      title: Шақырулар\n    relays:\n      add_new: Жаңа арна қосу\n      delete: Өшіру\n      description_html: A <strong>fedеration relay</strong> is an intermediary server that exchanges large volumes of public toots between servers that subscribe and publish to it. <strong>It can help small and medium servers discover content from the fediverse</strong>, which would otherwise require local users manually following other people on remote servers.\n      disable: Сөндіру\n      disabled: Сөндірілді\n      enable: Қосу\n      enable_hint: Once enabled, your server will subscribe to all public toots from this rеlay, and will begin sending this server's public toots to it.\n      enabled: Қосылды\n      inbox_url: Арна URL\n      pending: Жаңа арна құпталуын күту\n      save_and_enable: Сақта да қос\n      setup: Арна байланысын баптау\n      status: Статус\n      title: Арналар\n    report_notes:\n      created_msg: Шағым жазбасы сәтті құрылды!\n      destroyed_msg: Шағым жазбасы сәтті өшірілді!\n    reports:\n      account:\n        note: жазба\n        report: шағым\n      action_taken_by: Белсенділік жасаған\n      are_you_sure: Шынымен бе?\n      assign_to_self: Мені тағайындау\n      assigned: Модератор тағайындау\n      comment:\n        none: Ештеңе\n      created_at: Шағым тасталды\n      mark_as_resolved: Шешілді деп белгіле\n      mark_as_unresolved: Шешілмеді деп белгіле\n      notes:\n        create: Жазба қос\n        create_and_resolve: Жазба қосып шеш\n        create_and_unresolve: Жазба қосып қайта аш\n        delete: Өшіру\n        placeholder: Қандай әрекеттер жасалғанын немесе қандай да бір қатысты әрекеттерді сипаттаңыз ...\n      reopen: Шағымды қайта аш\n      report: 'Шағым #%{id}'\n      reported_account: Шағымдалған аккаунт\n      reported_by: Шағым тастаушы\n      resolved: Қайта шешілді\n      resolved_msg: Шағым қайтадан шешілді!\n      status: Статус\n      title: Шағымдар\n      unassign: Қайтып алу\n      unresolved: Шешілмеген\n      updated_at: Жаңартылды\n    settings:\n      activity_api_enabled:\n        desc_html: Соңғы аптада жазылған жазбалар, белсенді қолданушылар, жаңа тіркелімдер\n        title: Пайдаланушы әрекеті туралы жиынтық статистиканы жариялау\n      bootstrap_timeline_accounts:\n        desc_html: Бірнеше пайдаланушы атын үтірмен бөліңіз. Тек жергілікті және бұғатталмаған аккаунттар. Барлық жергілікті админдер бос болғанда.\n        title: Жаңа қолданушыларға жазылғандар\n      contact_information:\n        email: Бизнес e-mail\n        username: Қолданушымен байланыс\n      custom_css:\n        desc_html: Әр беттегі өзгерістерді CSS жаңаруымен қарау\n        title: Жеке CSS\n      hero:\n        desc_html: Бастапқы бетінде көрсетіледі. Кем дегенде 600x100px ұсынылады. Орнатылмаған кезде, сервердің нобайына оралады\n        title: Қаһарман суреті\n      mascot:\n        desc_html: Displayed on multiple pages. Кем дегенде 293×205px рекоменделеді. When not set, falls back to default mascot\n        title: Маскот суреті\n      peers_api_enabled:\n        desc_html: Домен names this server has encountered in the fediverse\n        title: Publish list of discovered серверлер\n      preview_sensitive_media:\n        desc_html: Link previews on other websites will display a thumbnail even if the media is marked as сезімтал\n        title: Show sensitive media in OpenGraph превью\n      profile_directory:\n        desc_html: Рұқсат users to be discoverable\n        title: Enable профиль directory\n      registrations:\n        closed_message:\n          desc_html: Displayed on frontpage when registrations are closed. You can use HTML тег\n          title: Closed registration мессадж\n        deletion:\n          desc_html: Allow anyone to delete their аккаунт\n          title: Open аккаунт deletion\n        min_invite_role:\n          disabled: Ешкім\n          title: Allow шақырулар by\n      show_known_fediverse_at_about_page:\n        desc_html: When toggled, it will show toots from all the known fediverse on preview. Otherwise it will only show жергілікті toots.\n        title: Show known fediverse on timeline превью\n      show_staff_badge:\n        desc_html: Show a staff badge on a user бет\n        title: Көрсет staff badge\n      site_description:\n        desc_html: Introductory paragraph on the басты бет. Describe what makes this Mastodon server special and anything else important. You can use HTML tags, in particular <code>&lt;a&gt;</code> and <code>&lt;em&gt;</code>.\n        title: Сервер туралы\n      site_description_extended:\n        desc_html: A good place for your code of conduct, rules, guidelines and other things that set your server apart. You can use HTML тег\n        title: Custom extended ақпарат\n      site_short_description:\n        desc_html: Displayed in sidebar and meta tags. Describe what Mastodon is and what makes this server special in a single paragraph. If empty, defaults to сервер description.\n        title: Short сервер description\n      site_terms:\n        desc_html: You can write your own privacy policy, terms of service or other legalese. You can use HTML тег\n        title: Қолдану шарттары мен ережелер\n      site_title: Сервер аты\n      thumbnail:\n        desc_html: Used for previews via OpenGraph and API. 1200x630px рекоменделеді\n        title: Сервер суреті\n      timeline_preview:\n        desc_html: Display public timeline on лендинг пейдж\n        title: Таймлайн превьюі\n      title: Сайт баптаулары\n    statuses:\n      back_to_account: Аккаунт бетіне оралы\n      batch:\n        delete: Delеte\n        nsfw_off: Сезімтал емес ретінде белгіле\n        nsfw_on: Сезімтал ретінде белгіле\n      failed_to_execute: Орындалмады\n      media:\n        title: Медиa\n      no_media: Медиасыз\n      no_status_selected: Бірде-бір статус өзгерген жоқ, себебі ештеңе таңдалмады\n      title: Аккаунт статустары\n      with_media: Медиамен\n    subscriptions:\n      callback_url: Callbаck URL\n      confirmed: Confirmеd\n      expires_in: Expirеs in\n      last_delivery: Last dеlivery\n      title: WеbSub\n      topic: Tоpic\n    tags:\n      accounts: Accоunts\n      hidden: Hiddеn\n      hide: Hidе from directory\n      name: Hаshtag\n      title: Hashtаgs\n      unhide: Shоw in directory\n      visible: Visiblе\n    title: Administrаtion\n    warning_presets:\n      add_new: Add nеw\n      delete: Deletе\n      edit: Еdit\n      edit_preset: Edit warning prеset\n      title: Manage warning presеts\n  admin_mailer:\n    new_report:\n      body: \"%{reporter} has rеported %{target}\"\n      body_remote: Someone from %{domain} has rеported %{target}\n      subject: New rеport for %{instance} (#%{id})\n  application_mailer:\n    notification_preferences: Change e-mail prеferences\n    settings: 'Change e-mail preferеnces: %{link}'\n    view: 'Viеw:'\n    view_profile: Viеw Profile\n    view_status: Viеw status\n  applications:\n    created: Application succеssfully created\n    destroyed: Application succеssfully deleted\n    invalid_url: The providеd URL is invalid\n    regenerate_token: Regenerate accеss token\n    token_regenerated: Access token succеssfully regenerated\n    warning: Be very carеful with this data. Never share it with anyone!\n    your_token: Your access tokеn\n  auth:\n    change_password: Құпиясөз\n    confirm_email: Еmаil құптау\n    delete_account: Аккаунт өшіру\n    delete_account_html: Аккаунтыңызды жойғыңыз келсе, <a href=\"%{path}\">мына жерді</a> басыңыз. Сізден растау сұралатын болады.\n    didnt_get_confirmation: Растау хаты келмеді ме?\n    forgot_password: Құпиясөзіңізді ұмытып қалдыңыз ба?\n    invalid_reset_password_token: Құпиясөз қайтып алу қолжетімді емес немесе мерзімі аяқталған. Қайтадан сұратыңыз.\n    login: Кіру\n    logout: Шығу\n    migrate_account: Басқа аккаунтқа көшіру\n    migrate_account_html: Егер аккаунтыңызды басқасына байлағыңыз келсе, <a href=\"%{path}\">мына жерге келіңіз</a>.\n    or_log_in_with: Немесе былай кіріңіз\n    providers:\n      cas: САS\n      saml: SАML\n    register: Тіркелу\n    resend_confirmation: Растау нұсқаулықтарын жіберу\n    reset_password: Құпиясөзді қалпына келтіру\n    security: Қауіпсіздік\n    set_new_password: Жаңа құпиясөз қою\n  authorize_follow:\n    already_following: Бұл аккаунтқа жазылғансыз\n    error: Өкінішке орай, қашықтағы тіркелгіні іздеуде қате пайда болды\n    follow: Жазылу\n    follow_request: 'Сіз жазылуға өтініш жібердіңіз:'\n    following: 'Керемет! Сіз енді жазылдыңыз:'\n    post_follow:\n      close: Немесе терезені жаба салыңыз.\n      return: Қолданушы профилін көрсет\n      web: Вебте ашу\n    title: Жазылу %{acct}\n  datetime:\n    distance_in_words:\n      about_x_hours: \"%{count}сағ\"\n      about_x_months: \"%{count}ай\"\n      about_x_years: \"%{count}жыл\"\n      almost_x_years: \"%{count}жыл\"\n      half_a_minute: Осы бойда\n      less_than_x_minutes: \"%{count}мин\"\n      less_than_x_seconds: Осы бойда\n      over_x_years: \"%{count}жыл\"\n      x_days: \"%{count}күн\"\n      x_minutes: \"%{count}мин\"\n      x_months: \"%{count}ай\"\n      x_seconds: \"%{count}сек\"\n  deletes:\n    bad_password_msg: Болмады ма, хакер бала? Құпиясөз қате\n    confirm_password: Қазіргі құпиясөзіңізді жазыңыз\n    description_html: This will <strong>permanently, irreversibly</strong> remove content from your account аnd deactivate it. Your username will remain reserved to prevent future impersonations.\n    proceed: Аккаунт өшіру\n    success_msg: Аккаунтыңыз сәтті өшірілді\n    warning_html: Only deletion of content from this particular server is guaranteed. Content that has been widely sharеd is likely to leave traces. Offline servers and servers that have unsubscribed from your updates will not update their databases.\n    warning_title: Бөлінген мазмұнның қол жетімділігі\n  directories:\n    directory: Профильдер каталогы\n    enabled: Каталогтағы тізімге ендіңіз.\n    enabled_but_waiting: Каталогта көрінгіңіз келетінін түсінеміз, бірақ ол үшін кем дегенде (%{min_followers}) оқырманыңыз болуы қажет.\n    explanation: Қолданушыларды қызығушылықтарына қарай реттеу\n    explore_mastodon: \"%{title} шарлау\"\n    how_to_enable: Сіз қазіргі уақытта каталогқа қосылмағансыз. Төменде қосылуға болады. Арнайы био мәтініндегі хэштегтерді қолданыңыз!\n    people:\n      one: \"%{count} адам\"\n      other: \"%{count} адам\"\n  errors:\n    '403': Бұны көру үшін сізде рұқсат жоқ.\n    '404': Сіз іздеген бет бұл жерде емес екен.\n    '410': Сіз іздеген бет қазір жоқ екен.\n    '422':\n      content: Қауіпсіздік растауы қате. кукилерді блоктағансыз ба?\n      title: Қауіпсіздік растауы жасалмады\n    '429': Қысқартылған\n    '500':\n      content: Кешірерсіз, бірақ қазір бір қате пайда болып тұр.\n      title: Бұл бет дұрыс емес екен\n    noscript_html: Mastodon веб қосымшасын қолдану үшін, JavaScript қосыңыз. Болмай жатса, <a href=\"%{apps_path}\">мына қосымшаларды</a> қосып көріңіз, Mastodon қолдану үшін.\n  exports:\n    archive_takeout:\n      date: Уақыты\n      download: Мұрағатыңызды түсіріп алыңыз\n      hint_html: Өзіңіздің <strong>жазба және медиаларыңыздың</strong> мұрағатын сақтап алуыңызға болады. Экспортталатын деректер ActivityPub форматында болады, сәйкес бағдарламамлармен ашуға болады. Әр 7 күн сайын сұратуыңызға болады.\n      in_progress: Мұрағатыңызды жинақтау...\n      request: Мұрағат сұрату\n      size: Өлшемі\n    blocks: Бұғатталғансыз\n    csv: СSV\n    domain_blocks: Домен блоктары\n    follows: Оқитындарыңыз\n    lists: Тізімдер\n    mutes: Үнсіздер\n    storage: Медиа жинақ\n  featured_tags:\n    add_new: Жаңасын қосу\n    errors:\n      limit: Хэштег лимитинен асып кеттіңіз\n  filters:\n    contexts:\n      home: Ішкі желі\n      notifications: Ескертпелер\n      public: Ашық желі\n      thread: Пікірталас\n    edit:\n      title: Фильтр өңдеу\n    errors:\n      invalid_context: Жоқ немесе жарамсыз контекст берілген\n      invalid_irreversible: Қайтарылмайтын сүзгі тек ішкі немесе ескертпелер контекстімен жұмыс істейді\n    index:\n      delete: Өшіру\n      title: Фильтрлер\n    new:\n      title: Жаңа фильтр қосу\n  footer:\n    developers: Жасаушылар\n    more: Тағы…\n    resources: Ресурстар\n  generic:\n    changes_saved_msg: Өзгерістер сәтті сақталды!\n    copy: Көшіру\n    save_changes: Өзгерістерді сақтау\n    validation_errors:\n      one: Бір нәрсе дұрыс емес! Төмендегі қатені қараңыз\n      other: Бір нәрсе дұрыс емес! Төмендегі %{count} қатені қараңыз\n  imports:\n    modes:\n      merge: Біріктіру\n      merge_long: Бар жазбаларды сақтаңыз және жаңаларын қосыңыз\n      overwrite: Үстіне жазу\n      overwrite_long: Ағымдағы жазбаларды жаңаларына ауыстырыңыз\n    preface: Басқа серверден экспортталған деректерді импорттауға болады, мысалы, сіз бақылайтын немесе блоктайтын адамдардың тізімін.\n    success: Деректеріңіз сәтті жүктелді және дер кезінде өңделеді\n    types:\n      blocking: Бұғат тізімі\n      domain_blocking: Домен бұғаттары тізімі\n      following: Жазылғандар тізімі\n      muting: Үнсіздер тізімі\n    upload: Жүктеу\n  in_memoriam_html: Естеліктерде.\n  invites:\n    delete: Ажырату\n    expired: Мерзімі өткен\n    expires_in:\n      '1800': 30 минут\n      '21600': 6 сағат\n      '3600': 1 сағат\n      '43200': 12 сағат\n      '604800': 1 апта\n      '86400': 1 күн\n    expires_in_prompt: Ешқашан\n    generate: Құру\n    invited_by: 'Сізді шақырған:'\n    max_uses:\n      one: 1 қолданыс\n      other: \"%{count} қолданыс\"\n    max_uses_prompt: Лимитсіз\n    prompt: Осы серверге кіру рұқсатын беру үшін сілтемелерді жасаңыз және бөлісіңіз\n    table:\n      expires_at: Аяқталу мерзімі\n      uses: Қолданыс\n    title: Адам шақыру\n  lists:\n    errors:\n      limit: Сіз тізімдердің максимум мөлшеріне жеттіңіз\n  media_attachments:\n    validations:\n      images_and_video: Жазбаға видео қоса алмайсыз, тек сурет қосуға болады\n      too_many: 4 файлдан артық қосылмайды\n  migrations:\n    acct: жаңа аккаунт үшін username@domain\n    currently_redirecting: 'Профиліңіз көшіріледі:'\n    proceed: Сақтау\n    updated_msg: Аккаунт көшіруіңіз сәтті аяқталды!\n  moderation:\n    title: Модерация\n  notification_mailer:\n    digest:\n      action: Барлық ескертпелер\n      body: Міне, соңғы кірген уақыттан кейін келген хаттардың қысқаша мазмұны %{since}\n      mention: \"%{name} сізді атап өтіпті:\"\n      new_followers_summary:\n        one: Сондай-ақ, сіз бір жаңа оқырман таптыңыз! Алақай!\n        other: Сондай-ақ, сіз %{count} жаңа оқырман таптыңыз! Керемет!\n      subject:\n        one: \"Соңғы кіруіңізден кейін 1 ескертпе келіпті \\U0001F418\"\n        other: \"Соңғы кіруіңізден кейін %{count} ескертпе келіпті \\U0001F418\"\n      title: Сіз жоқ кезде...\n    favourite:\n      body: 'Жазбаңызды ұнатып, таңдаулыға қосты %{name}:'\n      subject: \"%{name} жазбаңызды таңдаулыға қосты\"\n      title: Жаңа таңдаулы\n    follow:\n      body: \"%{name} сізге жазылды!\"\n      subject: \"%{name} сізге жазылды\"\n      title: Жаңа оқырман\n    follow_request:\n      action: Жазылуға сұранымдарды реттеу\n      body: \"%{name} сізге жазылғысы келеді\"\n      subject: 'Жазылғысы келеді: %{name}'\n      title: Жазылуға сұраным\n    mention:\n      action: Жауап\n      body: 'Сізді атап өтіпті %{name} мында:'\n      subject: Сізді %{name} атап өтіпті\n      title: Жаңа аталым\n    reblog:\n      body: 'Жазбаңызды бөліскен %{name}:'\n      subject: \"%{name} жазбаңызды бөлісті\"\n      title: Жаңа бөлісім\n  number:\n    human:\n      decimal_units:\n        units:\n          billion: В\n          million: М\n          thousand: К\n          trillion: Т\n  pagination:\n    newer: Ешқашан\n    next: Келесі\n    older: Ерте\n    prev: Алдыңғы\n  polls:\n    errors:\n      already_voted: Бұл сауалнамаға қатысқансыз\n      duplicate_options: қайталанатын нәрселер бар\n      duration_too_long: тым ұзақ екен\n      duration_too_short: тым аз екен\n      expired: Сауалнама уақыты аяқталған\n      over_character_limit: \"%{max} таңбадан артық болмайды\"\n      too_few_options: бір жауаптан көп болуы керек\n      too_many_options: \"%{max} жауаптан көп болмайды\"\n  preferences:\n    other: Басқа\n  remote_follow:\n    acct: Өзіңіздің username@domain теріңіз\n    missing_resource: Аккаунтыңызға байланған URL табылмады\n    no_account_html: Әлі тіркелмегенсіз бе? Мына жерден <a href='%{sign_up_path}' target='_blank'>тіркеліп алыңыз</a>\n    proceed: Жазылу\n    prompt: 'Жазылғыңыз келеді:'\n    reason_html: \"<strong>Неліктен бұл қадам қажет?</strong> <code>%{instance}</code> тіркелгіңіз келген сервер болмауы мүмкін, сондықтан сізді алдымен ішкі серверіңізге қайта бағыттау қажет.\"\n  remote_interaction:\n    favourite:\n      proceed: Таңдаулыға қосу\n      prompt: 'Мына жазбаны таңдаулыға қосасыз:'\n    reblog:\n      proceed: Жазба бөлісу\n      prompt: 'Сіз мына жазбаны бөлісесіз:'\n    reply:\n      proceed: Жауап жазу\n      prompt: 'Сіз мына жазбаға жауап жазасыз:'\n  remote_unfollow:\n    error: Қате\n    title: Тақырыбы\n    unfollowed: Жазылудан бас тартылды\n  scheduled_statuses:\n    over_daily_limit: Сіз бір күндік %{limit} жазба лимитін тауыстыңыз\n    over_total_limit: Сіз %{limit} жазба лимитін тауыстыңыз\n    too_soon: Жоспарланған күн болашақта болуы керек\n  sessions:\n    activity: Соңғы әрекеттер\n    browser: Браузер\n    browsers:\n      alipay: Аlipay\n      blackberry: Blаckberry\n      chrome: Chrоme\n      edge: Microsоft Edge\n      electron: Electrоn\n      firefox: Firеfox\n      generic: Белгісіз браузер\n      ie: Internet Explоrer\n      micro_messenger: MicroMеssenger\n      nokia: Nokia S40 Ovi Brоwser\n      opera: Opеra\n      otter: Ottеr\n      phantom_js: PhаntomJS\n      qq: QQ Brоwser\n      safari: Safаri\n      uc_browser: UCBrоwser\n      weibo: Weibо\n    current_session: Қазіргі сессия\n    description: \"%{browser} - %{platform}\"\n    explanation: Сіздің аккаунтыңызбен кірілген браузерлер тізімі.\n    ip: ІР\n    platforms:\n      adobe_air: Adobе Air\n      android: Andrоid\n      blackberry: Blackbеrry\n      chrome_os: ChromеOS\n      firefox_os: Firefоx OS\n      ios: iОS\n      linux: Lіnux\n      mac: Mаc\n      other: белгісіз платформа\n      windows: Windоws\n      windows_mobile: Windows Mоbile\n      windows_phone: Windоws Phone\n    revoke: Шығып кету\n    revoke_success: Сессиялар сәтті жабылды\n    title: Сессиялар\n  settings:\n    authorized_apps: Authorizеd apps\n    back: Желіге оралу\n    delete: Аккаунт өшіру\n    development: Жасаушы топ\n    edit_profile: Профиль өңдеу\n    export: Экспорт уақыты\n    featured_tags: Таңдаулы хэштегтер\n    import: Импорт\n    migrate: Аккаунт көшіру\n    notifications: Ескертпелер\n    preferences: Таңдаулар\n    two_factor_authentication: Екі-факторлы авторизация\n  statuses:\n    attached:\n      description: 'Жүктелді: %{attached}'\n      image:\n        one: \"%{count} сурет\"\n        other: \"%{count} сурет\"\n      video:\n        one: \"%{count} видео\"\n        other: \"%{count} видео\"\n    boosted_from_html: Бөлісілді %{acct_link}\n    content_warning: 'Контент ескертуі: %{warning}'\n    disallowed_hashtags:\n      one: 'рұқсат етілмеген хэштег: %{tags}'\n      other: 'рұқсат етілмеген хэштегтер: %{tags}'\n    language_detection: Тілді өздігінен таңда\n    open_in_web: Вебте ашу\n    over_character_limit: \"%{max} максимум таңбадан асып кетті\"\n    pin_errors:\n      limit: Жабыстырылатын жазба саны максимумынан асты\n      ownership: Біреудің жазбасы жабыстырылмайды\n      private: Жабық жазба жабыстырылмайды\n      reblog: Бөлісілген жазба жабыстырылмайды\n    poll:\n      total_votes:\n        one: \"%{count} дауыс\"\n        other: \"%{count} дауыс\"\n      vote: Дауыс беру\n    show_more: Тағы әкел\n    sign_in_to_participate: Сұхбатқа қатысу үшін кіріңіз\n    visibilities:\n      private: Тек оқырмандарға\n      private_long: Тек оқырмандарға ғана көрінеді\n      public: Ашық\n      public_long: Бәрі көре алады\n      unlisted: Тізімге енбеген\n      unlisted_long: Бәрі көре алады, бірақ ашық тізімдерге ене алмайды\n  stream_entries:\n    pinned: Жабыстырылған жазба\n    reblogged: бөлісті\n    sensitive_content: Нәзік мазмұн\n  terms:\n    body_html: |\n      <h2>Құпиялылық шарттары</h2>\n      <h3 id=\"collect\">What information do we collect?</h3>\n\n      <ul>\n      <li><em>Basic account information</em>: If you register on this server, you may be asked to enter a username, an e-mail address and a password. You may also enter additional profile information such as a display name and biography, and upload a profile picture and header image. The username, display name, biography, profile picture and header image are always listed publicly.</li>\n      <li><em>Posts, following and other public information</em>: The list of people you follow is listed publicly, the same is true for your followers. When you submit a message, the date and time is stored as well as the application you submitted the message from. Messages may contain media attachments, such as pictures and videos. Public and unlisted posts are available publicly. When you feature a post on your profile, that is also publicly available information. Your posts are delivered to your followers, in some cases it means they are delivered to different servers and copies are stored there. When you delete posts, this is likewise delivered to your followers. The action of reblogging or favouriting another post is always public.</li>\n      <li><em>Direct and followers-only posts</em>: All posts are stored and processed on the server. Followers-only posts are delivered to your followers and users who are mentioned in them, and direct posts are delivered only to users mentioned in them. In some cases it means they are delivered to different servers and copies are stored there. We make a good faith effort to limit the access to those posts only to authorized persons, but other servers may fail to do so. Therefore it's important to review servers your followers belong to. You may toggle an option to approve and reject new followers manually in the settings. <em>Please keep in mind that the operators of the server and any receiving server may view such messages</em>, and that recipients may screenshot, copy or otherwise re-share them. <em>Do not share any dangerous information over Mastodon.</em></li>\n      <li><em>IPs and other metadata</em>: When you log in, we record the IP address you log in from, as well as the name of your browser application. All the logged in sessions are available for your review and revocation in the settings. The latest IP address used is stored for up to 12 months. We also may retain server logs which include the IP address of every request to our server.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"use\">What do we use your information for?</h3>\n\n      <p>Any of the information we collect from you may be used in the following ways:</p>\n\n      <ul>\n      <li>To provide the core functionality of Mastodon. You can only interact with other people's content and post your own content when you are logged in. For example, you may follow other people to view their combined posts in your own personalized home timeline.</li>\n      <li>To aid moderation of the community, for example comparing your IP address with other known ones to determine ban evasion or other violations.</li>\n      <li>The email address you provide may be used to send you information, notifications about other people interacting with your content or sending you messages, and to respond to inquiries, and/or other requests or questions.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"protect\">How do we protect your information?</h3>\n\n      <p>We implement a variety of security measures to maintain the safety of your personal information when you enter, submit, or access your personal information. Among other things, your browser session, as well as the traffic between your applications and the API, are secured with SSL, and your password is hashed using a strong one-way algorithm. You may enable two-factor authentication to further secure access to your account.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"data-retention\">What is our data retention policy?</h3>\n\n      <p>We will make a good faith effort to:</p>\n\n      <ul>\n      <li>Retain server logs containing the IP address of all requests to this server, in so far as such logs are kept, no more than 90 days.</li>\n      <li>Retain the IP addresses associated with registered users no more than 12 months.</li>\n      </ul>\n\n      <p>You can request and download an archive of your content, including your posts, media attachments, profile picture, and header image.</p>\n\n      <p>You may irreversibly delete your account at any time.</p>\n\n      <hr class=\"spacer\"/>\n\n      <h3 id=\"cookies\">Do we use cookies?</h3>\n\n      <p>Yes. Cookies are small files that a site or its service provider transfers to your computer's hard drive through your Web browser (if you allow). These cookies enable the site to recognize your browser and, if you have a registered account, associate it with your registered account.</p>\n\n      <p>We use cookies to understand and save your preferences for future visits.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"disclose\">Do we disclose any information to outside parties?</h3>\n\n      <p>We do not sell, trade, or otherwise transfer to outside parties your personally identifiable information. This does not include trusted third parties who assist us in operating our site, conducting our business, or servicing you, so long as those parties agree to keep this information confidential. We may also release your information when we believe release is appropriate to comply with the law, enforce our site policies, or protect ours or others rights, property, or safety.</p>\n\n      <p>Your public content may be downloaded by other servers in the network. Your public and followers-only posts are delivered to the servers where your followers reside, and direct messages are delivered to the servers of the recipients, in so far as those followers or recipients reside on a different server than this.</p>\n\n      <p>When you authorize an application to use your account, depending on the scope of permissions you approve, it may access your public profile information, your following list, your followers, your lists, all your posts, and your favourites. Applications can never access your e-mail address or password.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"children\">Site usage by children</h3>\n\n      <p>If this server is in the EU or the EEA: Our site, products and services are all directed to people who are at least 16 years old. If you are under the age of 16, per the requirements of the GDPR (<a href=\"https://en.wikipedia.org/wiki/General_Data_Protection_Regulation\">General Data Protection Regulation</a>) do not use this site.</p>\n\n      <p>If this server is in the USA: Our site, products and services are all directed to people who are at least 13 years old. If you are under the age of 13, per the requirements of COPPA (<a href=\"https://en.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act\">Children's Online Privacy Protection Act</a>) do not use this site.</p>\n\n      <p>Law requirements can be different if this server is in another jurisdiction.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"changes\">Changes to our Privacy Policy</h3>\n\n      <p>If we decide to change our privacy policy, we will post those changes on this page.</p>\n\n      <p>This document is CC-BY-SA. It was last updated March 7, 2018.</p>\n\n      <p>Originally adapted from the <a href=\"https://github.com/discourse/discourse\">Discourse privacy policy</a>.</p>\n    title: \"%{instance} Қызмет көрсету шарттары және Құпиялылық саясаты\"\n  themes:\n    contrast: Mastodon (Жоғары контраст)\n    default: Mastodon (Қою)\n    mastodon-light: Mastodon (Ашық)\n  two_factor_authentication:\n    code_hint: Растау үшін түпнұсқалықты растау бағдарламасы арқылы жасалған кодты енгізіңіз\n    description_html: \"<strong>екі факторлы түпнұсқалықты растауды</strong> қоссаңыз, кіру үшін сізге телефонға кіруіңізді талап етеді, сізге арнайы токен беріледі.\"\n    disable: Ажырату\n    enable: Қосу\n    enabled: Екі-факторлы авторизация қосылған\n    enabled_success: Екі-факторлы авторизация сәтті қосылды\n    generate_recovery_codes: Қалпына келтіру кодтарын жасаңыз\n    instructions_html: \"<strong>Мына QR кодты Google Authenticator арқылы скандаңыз немесе ұқсас TOTP бағдарламалары арқылы</strong>. Одан кейін желіге кіру үшін токендер берілетін болады.\"\n    lost_recovery_codes: Қалпына келтіру кодтары телефонды жоғалтсаңыз, тіркелгіңізге қайта кіруге мүмкіндік береді. Қалпына келтіру кодтарын жоғалтсаңыз, оларды осында қалпына келтіре аласыз. Ескі қалпына келтіру кодтары жарамсыз болады.\n    manual_instructions: 'Егер сіз QR-кодты сканерлей алмасаңыз және оны қолмен енгізуіңіз қажет болса, мұнда қарапайым нұсқаулық:'\n    recovery_codes: Қалпына келтіру кодтарын резервтік көшіру\n    recovery_codes_regenerated: Қалпына келтіру кодтары қалпына келтірілді\n    recovery_instructions_html: Егер сіз телефонға кіруді жоғалтсаңыз, тіркелгіңізге кіру үшін төмендегі қалпына келтіру кодтарының бірін пайдалануға болады. <strong>Қалпына келтіру кодтарын қауіпсіз ұстаңыз </strong>. Мысалы, оларды басып шығарып, оларды басқа маңызды құжаттармен сақтауға болады.\n    setup: Орнату\n    wrong_code: Енгізілген код жарамсыз! Сервер уақыты мен құрылғының уақыты дұрыс па?\n  user_mailer:\n    backup_ready:\n      explanation: Сіз Mastodon аккаунтыңыздың толық мұрағатын сұрадыңыз. Қазір жүктеуге дайын!\n      subject: Мұрағатыңыз түсіріп алуға дайын\n      title: Мұрағатты алу\n    warning:\n      explanation:\n        disable: Аккаунтыңыз қатып қалса, сіздің деректеріңіз өзгеріссіз қалады, бірақ ол құлыптан босатылғанша ешқандай әрекетті орындай алмайсыз.\n        silence: While your account is limited, only people who are already following you will see your toots on this server, and you may be excluded from various public listings. However, others may still manually follоw you.\n        suspend: Сіздің аккаунтыңыз уақытша тоқтатылды және сіздің барлық файлдарыңыз бен жүктеп салынған медиа файлдарыңыз осы серверлерден және оқырманы болған серверлерден қайтарылмайды.\n      review_server_policies: Сервер саясатын қарап шығыңыз\n      subject:\n        disable: Аккаунтыңыз %{acct} уақытша тоқтатылды\n        none: \"%{acct} ескертуі\"\n        silence: \"%{acct} аккаунтыңыз шектеулі\"\n        suspend: \"%{acct} аккаунт тоқтатылды\"\n      title:\n        disable: Аккаунт қатырылды\n        none: Ескерту\n        silence: Аккаунт шектеулі\n        suspend: Аккаунт тоқтатылды\n    welcome:\n      edit_profile_action: Профиль өңдеу\n      edit_profile_step: Профиліңізге аватар, мұқаба сурет жүктей аласыз, аты-жөніңізді көрсете аласыз. Оқырмандарыңызға сізбен танысуға рұқсат бермес бұрын аккаунтыңызды уақытша құлыптап қоюға болады.\n      explanation: Мына кеңестерді шолып өтіңіз\n      final_action: Жазба жазу\n      final_step: 'Жазуды бастаңыз! Тіпті оқырмандарыңыз болмаса да, сіздің жалпы жазбаларыңызды басқа адамдар көре алады, мысалы, жергілікті желіде және хэштегтерде. Жазбаларыңызға # протоколды хэштег қоссаңыз болады.'\n      full_handle: Желі тұтқасы\n      full_handle_hint: This is what you would tell your friends so they can message or follow you frоm another server.\n      review_preferences_action: Таңдауларды өзгерту\n      review_preferences_step: Қандай хат-хабарларын алуды қалайтыныңызды немесе сіздің хабарламаларыңыздың қандай құпиялылық деңгейін алғыңыз келетінін анықтаңыз. Сондай-ақ, сіз GIF автоматты түрде ойнату мүмкіндігін қосуды таңдай аласыз.\n      subject: Mastodon Желісіне қош келдіңіз\n      tip_federated_timeline: Жаһандық желі - Mastodon желісінің негізгі құндылығы.\n      tip_following: Сіз бірден желі админіне жазылған болып саналасыз. Басқа адамдарға жазылу үшін жергілікті және жаһандық желіні шолып шығыңыз.\n      tip_local_timeline: Жерігілкті желіде маңайыздағы адамдардың белсенділігін көре аласыз %{instance}. Олар - негізгі көршілеріңіз!\n      tip_mobile_webapp: Мобиль браузеріңіз Mastodon желісін бастапқы бетке қосуды ұсынса, қабылдаңыз. Ескертпелер де шығатын болады. Арнайы қосымша сияқты бұл!\n      tips: Кеңестер\n      title: Ортаға қош келдің, %{name}!\n  users:\n    follow_limit_reached: Сіз %{limit} лимитінен көп адамға жазыла алмайсыз\n    invalid_email: Бұл e-mail адрес қате\n    invalid_otp_token: Қате екі-факторлы код\n    otp_lost_help_html: Егер кіру жолдарын жоғалтып алсаңыз, сізге %{email} арқылы жіберіледі\n    seamless_external_login: Сыртқы сервис арқылы кіріпсіз, сондықтан құпиясөз және электрондық пошта параметрлері қол жетімді емес.\n    signed_in_as: 'Былай кірдіңіз:'\n  verification:\n    explanation_html: 'Өзіңіздің профиль метадеректеріңіздегі сілтемелердің иесі ретінде өзіңізді <strong>тексере аласыз</strong>. Ол үшін байланыстырылған веб-сайтта Mastodon профиліне <strong>сілтеме болуы керек. </strong> Сілтемеде <code>rel = «me»</code> атрибуты болуы керек. Сілтеме мәтінінің мазмұны маңызды емес. Міне мысал:'\n    verification: Растау\n"
  },
  {
    "path": "config/locales/ko.yml",
    "content": "---\nko:\n  about:\n    about_hashtag_html: \"<strong>#%{hashtag}</strong> 라는 해시태그가 붙은 공개 툿 입니다. 같은 연합에 속한 임의의 인스턴스에 계정을 생성하면 당신도 대화에 참여할 수 있습니다.\"\n    about_mastodon_html: 마스토돈은 <em>오픈 소스 기반의</em> 소셜 네트워크 서비스 입니다. 상용 플랫폼의 대체로서 <em>분산형 구조</em>를 채택해, 여러분의 대화가 한 회사에 독점되는 것을 방지합니다. 신뢰할 수 있는 인스턴스를 선택하세요 &mdash; 어떤 인스턴스를 고르더라도, 누구와도 대화할 수 있습니다. 누구나 자신만의 마스토돈 인스턴스를 만들 수 있으며, 아주 매끄럽게 <em>소셜 네트워크</em>에 참가할 수 있습니다.\n    about_this: 이 인스턴스에 대해서\n    active_count_after: 활성 사용자\n    active_footnote: 월간 활성 사용자\n    administered_by: '관리자:'\n    api: API\n    apps: 모바일 앱\n    apps_platforms: 마스토돈을 iOS, 안드로이드, 다른 플랫폼들에서도 사용하세요\n    browse_directory: 프로필 디렉터리를 둘러보고 관심사 찾기\n    browse_public_posts: 마스토돈의 공개 라이브 스트림을 둘러보기\n    contact: 연락처\n    contact_missing: 미설정\n    contact_unavailable: 없음\n    discover_users: 유저 발견하기\n    documentation: 문서\n    extended_description_html: |\n      <h3>룰을 작성하는 장소</h3>\n      <p>아직 설명이 작성되지 않았습니다.</p>\n    federation_hint_html: \"%{instance}에 계정을 만드는 것으로 모든 마스토돈 서버, 그리고 호환 되는 모든 서버의 사용자를 팔로우 할 수 있습니다.\"\n    generic_description: \"%{domain} 은 네트워크에 있는 한 서버입니다\"\n    get_apps: 모바일 앱 사용해 보기\n    hosted_on: \"%{domain}에서 호스팅 되는 마스토돈\"\n    learn_more: 자세히\n    privacy_policy: 개인정보 정책\n    see_whats_happening: 무슨 일이 일어나는 지 보기\n    server_stats: '서버 통계:'\n    source_code: 소스 코드\n    status_count_after:\n      other: 툿\n    status_count_before: 툿 수\n    tagline: 친구들을 팔로우 하고 새로운 사람들도 만나기\n    terms: 이용약관\n    user_count_after:\n      other: 명\n    user_count_before: 사용자 수\n    what_is_mastodon: 마스토돈이란?\n  accounts:\n    choices_html: \"%{name}의 추천:\"\n    follow: 팔로우\n    followers:\n      other: 팔로워\n    following: 팔로잉\n    joined: \"%{date}에 가입함\"\n    last_active: 최근 활동\n    link_verified_on: \"%{date}에 이 링크의 소유가 확인되었습니다\"\n    media: 미디어\n    moved_html: \"%{name}은 %{new_profile_link}으로 이동되었습니다:\"\n    network_hidden: 이 정보는 사용할 수 없습니다\n    nothing_here: 아무 것도 없습니다!\n    people_followed_by: \"%{name} 님이 팔로우 중인 계정\"\n    people_who_follow: \"%{name} 님을 팔로우 중인 계정\"\n    pin_errors:\n      following: 추천하려는 사람을 팔로우 하고 있어야 합니다\n    posts:\n      other: 툿\n    posts_tab_heading: 툿\n    posts_with_replies: 툿과 답장\n    reserved_username: 이 아이디는 예약되어 있습니다\n    roles:\n      admin: 관리자\n      bot: 봇\n      moderator: 모더레이터\n    unavailable: 프로필 사용 불가\n    unfollow: 팔로우 해제\n  admin:\n    account_actions:\n      action: 조치 취하기\n      title: \"%{acct} 계정에 조정 취하기\"\n    account_moderation_notes:\n      create: 모더레이션 노트 작성하기\n      created_msg: 모더레이션 기록이 성공적으로 작성되었습니다!\n      delete: 삭제\n      destroyed_msg: 모더레이션 기록이 성공적으로 삭제되었습니다!\n    accounts:\n      approve: 승인\n      approve_all: 모두 승인\n      are_you_sure: 정말로 실행하시겠습니까?\n      avatar: 아바타\n      by_domain: 도메인\n      change_email:\n        changed_msg: 이메일이 성공적으로 바뀌었습니다!\n        current_email: 현재 이메일 주소\n        label: 이메일 주소 변경\n        new_email: 새 이메일 주소\n        submit: 이메일 주소 변경\n        title: \"%{username}의 이메일 주소 변경\"\n      confirm: 확인\n      confirmed: 확인됨\n      confirming: 확인 중\n      deleted: 삭제됨\n      demote: 강등\n      disable: 비활성화\n      disable_two_factor_authentication: 2단계 인증을 비활성화\n      disabled: 비활성화된\n      display_name: 이름\n      domain: 도메인\n      edit: 편집\n      email: 이메일\n      email_status: 이메일 상태\n      enable: 활성화\n      enabled: 활성\n      feed_url: 피드 URL\n      followers: 팔로워 수\n      followers_url: 팔로워 URL\n      follows: 팔로잉 수\n      header: 헤더\n      inbox_url: 수신함 URL\n      invited_by: 초대자\n      ip: IP\n      joined: 가입\n      location:\n        all: 전체\n        local: 로컬\n        remote: 리모트\n        title: 위치\n      login_status: 로그인 상태\n      media_attachments: 첨부된 미디어\n      memorialize: 메모리엄으로 전환\n      moderation:\n        active: 활동\n        all: 전체\n        pending: 대기중\n        silenced: 침묵 중\n        suspended: 정지 중\n        title: 모더레이션\n      moderation_notes: 모더레이션 기록\n      most_recent_activity: 최근 활동\n      most_recent_ip: 최근 IP\n      no_account_selected: 아무 계정도 선택 되지 않아 아무 것도 변경 되지 않았습니다\n      no_limits_imposed: 제한 없음\n      not_subscribed: 구독하지 않음\n      outbox_url: 발신함 URL\n      pending: 심사 대기\n      perform_full_suspension: 정지시키기\n      profile_url: 프로필 URL\n      promote: 승급\n      protocol: 프로토콜\n      public: 전체 공개\n      push_subscription_expires: PuSH 구독 기간 만료\n      redownload: 프로필 업데이트\n      reject: 거부\n      reject_all: 모두 거부\n      remove_avatar: 아바타 지우기\n      remove_header: 헤더 삭제\n      resend_confirmation:\n        already_confirmed: 이 사용자는 이미 확인되었습니다\n        send: 다시 확인 이메일\n        success: 확인 이메일이 전송되었습니다!\n      reset: 초기화\n      reset_password: 암호 초기화\n      resubscribe: 다시 구독\n      role: 권한\n      roles:\n        admin: 관리자\n        moderator: 모더레이터\n        staff: 스태프\n        user: 사용자\n      salmon_url: Salmon URL\n      search: 검색\n      shared_inbox_url: 공유된 inbox URL\n      show:\n        created_reports: 이 계정에서 제출된 신고\n        targeted_reports: 이 계정에 대한 신고\n      silence: 침묵\n      silenced: 침묵 됨\n      statuses: 툿 수\n      subscribe: 구독하기\n      suspended: 정지 됨\n      time_in_queue: \"%{time}동안 기다림\"\n      title: 계정\n      unconfirmed_email: 미확인 된 이메일 주소\n      undo_silenced: 침묵 해제\n      undo_suspension: 정지 해제\n      unsubscribe: 구독 해제\n      username: 아이디\n      warn: 경고\n      web: 웹\n    action_logs:\n      actions:\n        assigned_to_self_report: \"%{name}이 리포트 %{target}을 자신에게 할당했습니다\"\n        change_email_user: \"%{name}이 %{target}의 이메일 주소를 변경했습니다\"\n        confirm_user: \"%{name}이 %{target}의 이메일 주소를 컨펌했습니다\"\n        create_account_warning: \"%{name}가 %{target}에게 경고 보냄\"\n        create_custom_emoji: \"%{name}이 새로운 에모지 %{target}를 추가했습니다\"\n        create_domain_block: \"%{name}이 도메인 %{target}를 차단했습니다\"\n        create_email_domain_block: \"%{name}이 이메일 도메인 %{target}를 차단했습니다\"\n        demote_user: \"%{name}이 %{target}을 강등했습니다\"\n        destroy_custom_emoji: \"%{name}이 %{target} 에모지를 삭제함\"\n        destroy_domain_block: \"%{name}이 도메인 %{target}의 차단을 해제했습니다\"\n        destroy_email_domain_block: \"%{name}이 이메일 도메인 %{target}을 화이트리스트에 넣었습니다\"\n        destroy_status: \"%{name}이 %{target}의 툿을 삭제했습니다\"\n        disable_2fa_user: \"%{name}이 %{target}의 2FA를 비활성화 했습니다\"\n        disable_custom_emoji: \"%{name}이 에모지 %{target}를 비활성화 했습니다\"\n        disable_user: \"%{name}이 %{target}의 로그인을 비활성화 했습니다\"\n        enable_custom_emoji: \"%{name}이 에모지 %{target}를 활성화 했습니다\"\n        enable_user: \"%{name}이 %{target}의 로그인을 활성화 했습니다\"\n        memorialize_account: \"%{name}이 %{target}의 계정을 메모리엄으로 전환했습니다\"\n        promote_user: \"%{name}이 %{target}를 승급시켰습니다\"\n        remove_avatar_user: \"%{name}이 %{target}의 아바타를 지웠습니다\"\n        reopen_report: \"%{name}이 리포트 %{target}을 다시 열었습니다\"\n        reset_password_user: \"%{name}이 %{target}의 암호를 초기화했습니다\"\n        resolve_report: \"%{name}이 %{target} 신고를 처리됨으로 변경하였습니다\"\n        silence_account: \"%{name}이 %{target}의 계정을 뮤트시켰습니다\"\n        suspend_account: \"%{name}이 %{target}의 계정을 정지시켰습니다\"\n        unassigned_report: \"%{name}이 리포트 %{target}을 할당 해제했습니다\"\n        unsilence_account: \"%{name}이 %{target}에 대한 뮤트를 해제했습니다\"\n        unsuspend_account: \"%{name}이 %{target}에 대한 정지를 해제했습니다\"\n        update_custom_emoji: \"%{name}이 에모지 %{target}를 업데이트 했습니다\"\n        update_status: \"%{name}이 %{target}의 상태를 업데이트 했습니다\"\n      deleted_status: \"(삭제됨)\"\n      title: 감사 기록\n    custom_emojis:\n      by_domain: 도메인\n      copied_msg: 성공적으로 에모지의 로컬 복사본을 생성했습니다\n      copy: 복사\n      copy_failed_msg: 에모지의 로컬 복사본을 만드는 데 실패하였습니다\n      created_msg: 에모지가 성공적으로 생성되었습니다!\n      delete: 삭제\n      destroyed_msg: 에모지가 성공적으로 삭제되었습니다!\n      disable: 비활성화\n      disabled_msg: 성공적으로 비활성화하였습니다\n      emoji: 에모지\n      enable: 활성화\n      enabled_msg: 성공적으로 활성화하였습니다\n      image_hint: 50KB 이하의 PNG\n      listed: 목록에 실림\n      new:\n        title: 새 커스텀 에모지 추가\n      overwrite: 덮어쓰기\n      shortcode: 짧은 코드\n      shortcode_hint: 최소 2글자, 영문자, 숫자, _만 사용 가능\n      title: 커스텀 에모지\n      unlisted: 목록에 없음\n      update_failed_msg: 에모지를 업데이트 할 수 없습니다\n      updated_msg: 에모지가 성공적으로 업데이트 되었습니다!\n      upload: 업로드\n    dashboard:\n      backlog: 미처리 된 작업\n      config: 설정\n      feature_deletions: 계정 삭제\n      feature_invites: 초대 링크\n      feature_profile_directory: 프로필 디렉토리\n      feature_registrations: 가입\n      feature_relay: 연합 릴레이\n      feature_timeline_preview: 타임라인 미리보기\n      features: 기능\n      hidden_service: 히든 서비스와의 연합\n      open_reports: 미해결 신고\n      recent_users: 최근 가입 한 유저\n      search: 전문 검색\n      single_user_mode: 싱글 유저 모드\n      software: 소프트웨어\n      space: 디스크 사용량\n      title: 대시보드\n      total_users: 총 유저 수\n      trends: 트렌드\n      week_interactions: 이번 주의 상호작용\n      week_users_active: 이번 주의 활성 사용자\n      week_users_new: 이번 주의 신규 유저\n    domain_blocks:\n      add_new: 도메인 차단 추가하기\n      created_msg: 도메인 차단 처리를 완료했습니다\n      destroyed_msg: 도메인 차단이 해제되었습니다\n      domain: 도메인\n      existing_domain_block_html: 이미 %{name}에 대한 더 강력한 제한이 걸려 있습니다, <a href=\"%{unblock_url}\">차단 해제</a>를 먼저 해야 합니다.\n      new:\n        create: 차단 추가\n        hint: 도메인 차단은 내부 데이터베이스에 계정이 생성되는 것까지는 막을 수 없지만, 그 도메인에서 생성된 계정에 자동적으로 특정한 모더레이션을 적용하게 할 수 있습니다.\n        severity:\n          desc_html: |-\n            <strong>침묵</strong>은 계정을 팔로우 하지 않고 있는 사람들에겐 계정의 툿을 보이지 않게 합니다. <strong>정지</strong>는 계정의 컨텐츠, 미디어, 프로필 데이터를 삭제합니다.\n            미디어 파일만을 거부하고 싶다면 <strong>없음</strong>으로 두세요.\n          noop: 없음\n          silence: 침묵\n          suspend: 정지\n        title: 새로운 도메인 차단\n      reject_media: 미디어 파일 거부하기\n      reject_media_hint: 로컬에 저장된 미디어 파일을 삭제하고, 이후로도 다운로드를 거부합니다. 정지와는 관계 없습니다\n      reject_reports: 신고 거부\n      reject_reports_hint: 이 도메인으로부터의 모든 신고를 무시합니다. 정지와는 무관합니다\n      rejecting_media: 미디어 거부\n      rejecting_reports: 신고 거부\n      severity:\n        silence: 침묵\n        suspend: 정지\n      show:\n        affected_accounts:\n          other: 데이터베이스 중 %{count}개의 계정에 영향을 끼칩니다\n        retroactive:\n          silence: 이 도메인에 존재하는 모든 계정의 침묵를 해제\n          suspend: 이 도메인에 존재하는 모든 계정의 계정 정지를 해제\n        title: \"%{domain}의 도메인 차단을 해제\"\n        undo: 실행 취소\n      undo: 도메인 차단 취소\n    email_domain_blocks:\n      add_new: 새로 추가\n      created_msg: 이메일 도메인 차단 규칙을 생성했습니다\n      delete: 삭제\n      destroyed_msg: 이메일 도메인 차단 규칙을 삭제했습니다\n      domain: 도메인\n      new:\n        create: 차단 규칙 생성\n        title: 새 이메일 도메인 차단\n      title: Email 도메인 차단\n    followers:\n      back_to_account: 계정으로 돌아가기\n      title: \"%{acct}의 팔로워\"\n    instances:\n      by_domain: 도메인\n      delivery_available: 전송 가능\n      known_accounts:\n        other: 알려진 계정 %{count}개\n      moderation:\n        all: 모두\n        limited: 제한됨\n        title: 모더레이션\n      title: 연합\n      total_blocked_by_us: 우리에게 차단 됨\n      total_followed_by_them: 우리를 팔로우\n      total_followed_by_us: 우리가 한 팔로우\n      total_reported: 이들에 대한 신고\n      total_storage: 미디어 첨부\n    invites:\n      deactivate_all: 전부 비활성화\n      filter:\n        all: 모두\n        available: 사용가능\n        expired: 만료됨\n        title: 필터\n      title: 초대\n    pending_accounts:\n      title: 대기중인 계정 (%{count})\n    relays:\n      add_new: 릴레이 추가\n      delete: 삭제\n      description_html: \"<strong>연합 릴레이</strong>는 서버들 사이에서 많은 양의 공개 툿을 구독하고 중개하는 서버입니다. <strong>이것은 중소 규모의 서버에서 연합우주를 발견하는 데에 도움을 줄 수 있습니다</strong>, 이제 로컬 유저들이 다른 서버의 유저들을 수동으로 팔로우 하지 않아도 됩니다.\"\n      disable: 비활성화\n      disabled: 비활성화 됨\n      enable: 활성화\n      enable_hint: 활성화 되면, 이 릴레이의 모든 공개 툿을 구독하고 이 서버의 공개 툿을 전송하게 됩니다.\n      enabled: 활성화 됨\n      inbox_url: 릴레이 URL\n      pending: 릴레이의 승인 대기중\n      save_and_enable: 저장하고 활성화\n      setup: 릴레이 연결 설정\n      status: 상태\n      title: 릴레이\n    report_notes:\n      created_msg: 리포트 노트가 성공적으로 작성되었습니다!\n      destroyed_msg: 리포트 노트가 성공적으로 삭제되었습니다!\n    reports:\n      account:\n        note: 노트\n        report: 리포트\n      action_taken_by: 신고 처리자\n      are_you_sure: 정말로 실행하시겠습니까?\n      assign_to_self: 나에게 할당하기\n      assigned: 할당 된 모더레이터\n      comment:\n        none: 없음\n      created_at: 리포트 시각\n      mark_as_resolved: 해결 완료 처리\n      mark_as_unresolved: 미해결로 표시\n      notes:\n        create: 기록 추가\n        create_and_resolve: 기록을 작성하고 해결됨으로 표시\n        create_and_unresolve: 기록 작성과 함께 미해결로 표시\n        delete: 삭제\n        placeholder: 이 리포트에 대한 조치, 기타 관련 된 사항에 대해 설명합니다…\n      reopen: 리포트 다시 열기\n      report: '신고 #%{id}'\n      reported_account: 신고 대상 계정\n      reported_by: 신고자\n      resolved: 해결됨\n      resolved_msg: 리포트가 성공적으로 해결되었습니다!\n      status: 상태\n      title: 신고\n      unassign: 할당 해제\n      unresolved: 미해결\n      updated_at: 업데이트 시각\n    settings:\n      activity_api_enabled:\n        desc_html: 주별 로컬에 게시 된 글, 활성 사용자 및 새로운 가입자 수\n        title: 유저 활동에 대한 통계 발행\n      bootstrap_timeline_accounts:\n        desc_html: 콤마로 여러 유저명을 구분. 로컬의 잠기지 않은 계정만 가능합니다. 비워 둘 경우 모든 로컬 관리자가 기본으로 사용 됩니다.\n        title: 새 유저가 팔로우 할 계정들\n      contact_information:\n        email: 공개할 메일 주소를 입력\n        username: 연락 받을 관리자 유저네임\n      custom_css:\n        desc_html: 모든 페이지에 적용할 CSS\n        title: 커스텀 CSS\n      hero:\n        desc_html: 프론트페이지에 표시 됩니다. 최소 600x100픽셀을 권장합니다. 만약 설정되지 않았다면, 서버의 썸네일이 사용 됩니다\n        title: 히어로 이미지\n      mascot:\n        desc_html: 여러 페이지에서 보여집니다. 최소 293x205px을 추천합니다. 설정 되지 않은 경우, 기본 마스코트가 사용 됩니다\n        title: 마스코트 이미지\n      peers_api_enabled:\n        desc_html: 이 서버가 페디버스에서 만났던 도메인 네임들\n        title: 발견 된 서버들의 리스트 발행\n      preview_sensitive_media:\n        desc_html: 민감한 미디어로 설정되었더라도 다른 웹사이트에서 링크 미리보기에 썸네일을 보여줍니다\n        title: 민감한 미디어를 오픈그래프 미리보기에 보여주기\n      profile_directory:\n        desc_html: 유저들이 발견 될 수 있도록 허용\n        title: 프로필 디렉토리 활성화\n      registrations:\n        closed_message:\n          desc_html: 신규 등록을 받지 않을 때 프론트 페이지에 표시됩니다. HTML 태그를 사용할 수 있습니다\n          title: 신규 등록 정지 시 메시지\n        deletion:\n          desc_html: 유저가 자신의 계정을 삭제할 수 있도록 설정합니다\n          title: 계정 삭제를 허가함\n        min_invite_role:\n          disabled: 아무도 못 하게\n          title: 초대링크를 만들 수 있는 권한\n      registrations_mode:\n        modes:\n          approved: 가입하려면 승인이 필요함\n          none: 아무도 가입 할 수 없음\n          open: 누구나 가입 할 수 있음\n        title: 가입 모드\n      show_known_fediverse_at_about_page:\n        desc_html: 활성화 되면 프리뷰 페이지에서 페디버스의 모든 툿을 표시합니다. 비활성화시 로컬에 있는 툿만 표시 됩니다.\n        title: 타임라인 프리뷰에 알려진 페디버스 표시하기\n      show_staff_badge:\n        desc_html: 유저 페이지에 스태프 배지를 표시합니다\n        title: 스태프 배지 표시\n      site_description:\n        desc_html: API의 소개문에 사용 됩니다.이 마스토돈 서버의 특별한 점 등을 설명하세요. HTML 태그, 주로 <code>&lt;a&gt;</code>, <code>&lt;em&gt;</code> 같은 것을 사용 가능합니다.\n        title: 서버 설명\n      site_description_extended:\n        desc_html: 규칙, 가이드라인 등을 작성하기 좋은 곳입니다. HTML 태그를 사용할 수 있습니다\n        title: 사이트 상세 설명\n      site_short_description:\n        desc_html: 사이드바와 메타 태그에 나타납니다. 마스토돈이 무엇이고 이 서버의 특징은 무엇인지 한 문장으로 설명하세요.\n        title: 짧은 서버 설명\n      site_terms:\n        desc_html: 당신은 독자적인 개인정보 취급 방침이나 이용약관, 그 외의 법적 근거를 작성할 수 있습니다. HTML태그를 사용할 수 있습니다\n        title: 커스텀 서비스 이용 약관\n      site_title: 서버 이름\n      thumbnail:\n        desc_html: OpenGraph와 API의 미리보기로 사용 됩니다. 1200x630px을 권장합니다\n        title: 서버 썸네일\n      timeline_preview:\n        desc_html: 랜딩 페이지에 공개 타임라인을 표시합니다\n        title: 타임라인 프리뷰\n      title: 사이트 설정\n    statuses:\n      back_to_account: 계정으로 돌아가기\n      batch:\n        delete: 삭제\n        nsfw_off: NSFW 끄기\n        nsfw_on: NSFW 켜기\n      failed_to_execute: 실행을 실패하였습니다\n      media:\n        title: 미디어\n      no_media: 미디어 없음\n      no_status_selected: 아무 것도 선택 되지 않아 아무 것도 바뀌지 않았습니다\n      title: 계정 툿\n      with_media: 미디어 있음\n    subscriptions:\n      callback_url: 콜백 URL\n      confirmed: 확인됨\n      expires_in: 기한\n      last_delivery: 최종 발송\n      title: WebSub\n      topic: 토픽\n    tags:\n      accounts: 계정들\n      hidden: 숨겨짐\n      hide: 디렉토리에서 숨기기\n      name: 해시태그\n      title: 해시태그\n      unhide: 디렉토리에 표시\n      visible: 보여짐\n    title: 관리\n    warning_presets:\n      add_new: 새로 추가\n      delete: 삭제\n      edit: 편집\n      edit_preset: 경고 틀 수정\n      title: 경고 틀 관리\n  admin_mailer:\n    new_pending_account:\n      body: 아래에 새 계정에 대한 상세정보가 있습니다. 이 가입을 승인하거나 거부할 수 있습니다.\n      subject: \"%{instance}의 새 계정(%{username})에 대한 심사가 대기중입니다\"\n    new_report:\n      body: \"%{reporter} 가 %{target} 를 신고했습니다\"\n      body_remote: \"%{domain}의 누군가가 %{target}을 신고했습니다\"\n      subject: \"%{instance} 에 새 신고 등록됨 (#%{id})\"\n  appearance:\n    advanced_web_interface: 고급 웹 인터페이스\n    advanced_web_interface_hint: '화면의 가로폭을 가득 채우고 싶다면, 고급 웹 인터페이스는 한 번에 여러 정보를 볼 수 있도록 여러 컬럼을 설정할 수 있도록 합니다: 홈, 알림, 연합타임라인, 리스트, 해시태그 등'\n    animations_and_accessibility: 애니메이션과 접근성\n    confirmation_dialogs: 확인 대화상자\n    sensitive_content: 민감한 내용\n  application_mailer:\n    notification_preferences: 메일 설정 변경\n    salutation: \"%{name} 님,\"\n    settings: '메일 설정을 변경: %{link}'\n    view: '보기:'\n    view_profile: 프로필 보기\n    view_status: 게시물 보기\n  applications:\n    created: 애플리케이션이 성공적으로 생성되었습니다\n    destroyed: 애플리케이션이 성공적으로 삭제되었습니다\n    invalid_url: 올바르지 않은 URL입니다\n    regenerate_token: 토큰 재생성\n    token_regenerated: 액세스 토큰이 성공적으로 재생성되었습니다\n    warning: 이 데이터를 조심히 다뤄 주세요. 다른 사람들과 절대로 공유하지 마세요!\n    your_token: 액세스 토큰\n  auth:\n    apply_for_account: 가입 요청하기\n    change_password: 패스워드\n    checkbox_agreement_html: <a href=\"%{rules_path}\" target=\"_blank\">서버 규칙</a>과 <a href=\"%{terms_path}\" target=\"_blank\">이용약관</a>에 동의합니다\n    confirm_email: 확인 메일 승인\n    delete_account: 계정 삭제\n    delete_account_html: 계정을 삭제하고 싶은 경우, <a href=\"%{path}\">여기서</a> 삭제할 수 있습니다. 삭제 전 확인 화면이 표시됩니다.\n    didnt_get_confirmation: 확인 메일을 받지 못하셨습니까?\n    forgot_password: 비밀번호를 잊어버리셨습니까?\n    invalid_reset_password_token: 암호 리셋 토큰이 올바르지 못하거나 기간이 만료되었습니다. 다시 요청해주세요.\n    login: 로그인\n    logout: 로그아웃\n    migrate_account: 계정 옮기기\n    migrate_account_html: 이 계정을 다른 계정으로 리디렉션 하길 원하는 경우 <a href=\"%{path}\">여기</a>에서 설정할 수 있습니다.\n    or_log_in_with: 다른 방법으로 로그인 하려면\n    providers:\n      cas: CAS\n      saml: SAML\n    register: 등록하기\n    registration_closed: \"%{instance}는 새로운 가입을 받지 않고 있습니다\"\n    resend_confirmation: 확인 메일을 다시 보내기\n    reset_password: 암호 재설정\n    security: 보안\n    set_new_password: 새 암호\n    trouble_logging_in: 로그인 하는데 문제가 있나요?\n  authorize_follow:\n    already_following: 이미 이 계정을 팔로우 하고 있습니다\n    error: 리모트 계정을 확인하는 도중 오류가 발생했습니다\n    follow: 팔로우\n    follow_request: '당신은 다음 계정에 팔로우 신청을 했습니다:'\n    following: '성공! 당신은 다음 계정을 팔로우 하고 있습니다:'\n    post_follow:\n      close: 혹은, 당신은 이 윈도우를 닫을 수 있습니다.\n      return: 유저 프로필 보기\n      web: 웹으로 가기\n    title: \"%{acct} 를 팔로우\"\n  datetime:\n    distance_in_words:\n      about_x_hours: \"%{count}시간\"\n      about_x_months: \"%{count}월\"\n      about_x_years: \"%{count}년\"\n      almost_x_years: \"%{count}년\"\n      half_a_minute: 지금\n      less_than_x_minutes: \"%{count}분\"\n      less_than_x_seconds: 지금\n      over_x_years: \"%{count}년\"\n      x_days: \"%{count}일\"\n      x_minutes: \"%{count}분\"\n      x_months: \"%{count}월\"\n      x_seconds: \"%{count}초\"\n  deletes:\n    bad_password_msg: 비밀번호가 올바르지 않습니다\n    confirm_password: 본인 확인을 위해 현재 사용 중인 암호를 입력해 주십시오\n    description_html: 계정에 업로드된 모든 컨텐츠가 삭제되며, 계정은 비활성화 됩니다. 이것은 영구적으로 이루어지는 것이므로 <strong>되돌릴 수 없습니다</strong>. 사칭 행위를 방지하기 위해 같은 아이디로 다시 등록하는 것은 불가능합니다.\n    proceed: 계정 삭제\n    success_msg: 계정이 성공적으로 삭제되었습니다\n    warning_html: 삭제가 보장되는 것은 이 서버 상에서의 컨텐츠에 한합니다. 타 서버 등, 외부에 멀리 공유된 컨텐츠는 흔적이 남아 삭제되지 않는 경우도 있습니다. 그리고 현재 접속이 불가능한 서버나, 업데이트를 받지 않게 된 서버에 대해서는 삭제가 반영되지 않을 수도 있습니다.\n    warning_title: 공유된 컨텐츠에 대해서\n  directories:\n    directory: 프로필 디렉토리\n    enabled: 당신은 디렉터리에 표시 되고 있습니다.\n    enabled_but_waiting: 디렉터리에 표시 되기 위해서는 수동으로 참여해야 합니다, 하지만 디렉터리에 표시 되기 위한 최소 팔로워(%{min_followers})수에 미치지 못했습니다.\n    explanation: 관심사에 대한 유저들을 발견합니다\n    explore_mastodon: \"%{title} 탐사하기\"\n    how_to_enable: 아직 디렉터리에 참여하지 않았습니다. 아래에서 참여할 수 있습니다. 바이오 텍스트에 해시태그를 사용해 특정 해시태그 디렉터리에 표시 될 수 있습니다!\n    people:\n      other: \"%{count}명\"\n  errors:\n    '403': 이 페이지를 표시할 권한이 없습니다.\n    '404': 당신이 찾으려는 페이지는 존재하지 않습니다.\n    '410': 당신이 보려는 페이지는 더이상 여기에 존재하지 않습니다.\n    '422':\n      content: 보안 인증에 실패했습니다. 쿠키를 차단하고 있진 않습니까?\n      title: 보안 인증 실패\n    '429': 요청 횟수 제한에 도달했습니다\n    '500':\n      content: 죄송합니다, 뭔가 잘못 되었습니다.\n      title: 이 페이지는 잘못되었습니다\n    noscript_html: 마스토돈을 사용하기 위해서는 자바스크립트를 켜 주십시오. 아니면 <a href=\"%{apps_path}\">네이티브 앱</a> 중 하나를 사용할 수 있습니다.\n  existing_username_validator:\n    not_found: 해당 유저네임에 대한 로컬 유저를 찾을 수 없습니다\n    not_found_multiple: \"%{usernames}를 찾을 수 없습니다\"\n  exports:\n    archive_takeout:\n      date: 날짜\n      download: 아카이브 다운로드\n      hint_html: 당신의 <strong>툿과 업로드 된 미디어</strong>의 아카이브를 요청할 수 있습니다. 내보내지는 데이터는 ActivityPub 포맷입니다. 호환 되는 모든 소프트웨어에서 읽을 수 있습니다. 7일마다 새로운 아카이브를 요청할 수 있습니다.\n      in_progress: 당신의 아카이브를 컴파일 중입니다…\n      request: 아카이브 요청하기\n      size: 크기\n    blocks: 차단\n    csv: CSV\n    domain_blocks: 도메인 차단\n    follows: 팔로우\n    lists: 리스트\n    mutes: 뮤트\n    storage: 미디어\n  featured_tags:\n    add_new: 추가\n    errors:\n      limit: 이미 추천 해시태그의 개수가 최대입니다\n  filters:\n    contexts:\n      home: 홈 타임라인\n      notifications: 알림\n      public: 퍼블릭 타임라인\n      thread: 대화\n    edit:\n      title: 필터 편집\n    errors:\n      invalid_context: 컨텍스트가 없거나 올바르지 않습니다\n      invalid_irreversible: 되돌릴 수 없는 필터링은 홈 타임라인과 알림에서만 동작합니다\n    index:\n      delete: 삭제\n      title: 필터\n    new:\n      title: 필터 추가\n  footer:\n    developers: 개발자\n    more: 더 보기…\n    resources: 리소스\n  generic:\n    all: 모두\n    changes_saved_msg: 정상적으로 변경되었습니다!\n    copy: 복사\n    order_by: 순서\n    save_changes: 변경 사항을 저장\n    validation_errors:\n      other: 오류가 발생했습니다. 아래 %{count}개 오류를 확인해 주십시오\n  html_validator:\n    invalid_markup: '올바르지 않은 HTML 마크업을 포함하고 있습니다: %{error}'\n  identity_proofs:\n    active: 활성\n    authorize: 네, 인증합니다\n    authorize_connection_prompt: 이 암호화 연결을 인증합니까?\n    errors:\n      failed: 암호화 연결에 실패했습니다. %{provider}에서 다시 시도해 주세요.\n      keybase:\n        invalid_token: 키베이스 토큰은 서명의 해시이며 66자의 16진수 문자여야 합니다\n        verification_failed: 키베이스가 이 토큰을 키베이스 유저 %{kb_username}의 서명으로 인식하지 못했습니다. 키베이스에서 다시 시도하세요.\n      wrong_user: \"%{current}로 로그인 한 상태에서는 %{proving}에 대한 증명을 할 수 없습니다. %{proving}으로 로그인 한 후 다시 시도하세요.\"\n    explanation_html: 키베이스와 같은 다른 명의에 대한 암호화 연결을 할 수 있습니다. 이것으로 다른 사람들이 당신에게 암호화 된 메시지를 보낼 수 있고 당신의 메시지를 믿을 수 있습니다.\n    i_am_html: 나는 %{service}의 %{username} 입니다.\n    identity: 신원\n    inactive: 비활성\n    publicize_checkbox: '그리고 이것을 툿 하세요:'\n    publicize_toot: '증명되었습니다! 저는 %{service}에 있는 %{username}입니다: %{url}'\n    status: 인증 상태\n    view_proof: 증명 보기\n  imports:\n    modes:\n      merge: 병합\n      merge_long: 기존 것을 그대로 둔 채 새로 추가\n      overwrite: 덮어쓰기\n      overwrite_long: 기존 것을 모두 지우고 새로 추가\n    preface: 다른 서버에서 내보내기 한 파일에서 팔로우 / 차단 정보를 이 계정으로 불러올 수 있습니다.\n    success: 파일이 정상적으로 업로드 되었으며, 현재 처리 중입니다\n    types:\n      blocking: 차단한 계정 목록\n      domain_blocking: 도메인 차단 목록\n      following: 팔로우 중인 계정 목록\n      muting: 뮤트 중인 계정 목록\n    upload: 업로드\n  in_memoriam_html: 메모리엄에 있음.\n  invites:\n    delete: 비활성화\n    expired: 만료됨\n    expires_in:\n      '1800': 30 분\n      '21600': 6 시간\n      '3600': 1 시간\n      '43200': 12 시간\n      '604800': 1주일\n      '86400': 하루\n    expires_in_prompt: 영원히\n    generate: 생성\n    invited_by: '당신을 초대한 사람:'\n    max_uses:\n      other: \"%{count} 회\"\n    max_uses_prompt: 제한 없음\n    prompt: 이 서버에 대한 초대 링크를 만들고 공유합니다\n    table:\n      expires_at: 만료\n      uses: 사용됨\n    title: 초대\n  lists:\n    errors:\n      limit: 리스트 최대치에 도달했습니다\n  media_attachments:\n    validations:\n      images_and_video: 이미 사진이 첨부 된 게시물엔 동영상을 첨부 할 수 없습니다\n      too_many: 최대 4개까지 첨부할 수 있습니다\n  migrations:\n    acct: 새 계정의 username@domain\n    currently_redirecting: '당신의 프로파일은 여기로 리디렉션 됩니다:'\n    proceed: 저장\n    updated_msg: 계정 이동 설정이 저장되었습니다!\n  moderation:\n    title: 모더레이션\n  notification_mailer:\n    digest:\n      action: 모든 알림 보기\n      body: 마지막 로그인(%{since}) 이후로 일어난 일들에 관한 요약\n      mention: \"%{name} 님이 답장했습니다:\"\n      new_followers_summary:\n        other: 게다가, 접속하지 않은 동안 %{count} 명의 팔로워가 생겼습니다!\n      subject:\n        other: \"%{count}건의 새로운 알림 \\U0001F418\"\n      title: 당신이 없는 동안에...\n    favourite:\n      body: \"%{name} 님이 내 툿을 즐겨찾기에 등록했습니다:\"\n      subject: \"%{name} 님이 내 툿을 즐겨찾기에 등록했습니다\"\n      title: 새 즐겨찾기\n    follow:\n      body: \"%{name} 님이 나를 팔로우 했습니다!\"\n      subject: \"%{name} 님이 나를 팔로우 했습니다\"\n      title: 새 팔로워\n    follow_request:\n      action: 팔로우 요청 관리\n      body: \"%{name} 님이 내게 팔로우 요청을 보냈습니다\"\n      subject: \"%{name} 님이 보낸 팔로우 요청\"\n      title: 새 팔로우 요청\n    mention:\n      action: 답장\n      body: \"%{name} 님이 답장을 보냈습니다:\"\n      subject: \"%{name} 님이 답장을 보냈습니다\"\n      title: 새 멘션\n    reblog:\n      body: \"%{name} 님이 내 툿을 부스트 했습니다:\"\n      subject: \"%{name} 님이 내 툿을 부스트 했습니다\"\n      title: 새 부스트\n  number:\n    human:\n      decimal_units:\n        format: \"%n%u\"\n        units:\n          billion: B\n          million: M\n          quadrillion: Q\n          thousand: K\n          trillion: T\n  pagination:\n    newer: 새로운 툿\n    next: 다음\n    older: 오래된 툿\n    prev: 이전\n    truncate: \"&hellip;\"\n  polls:\n    errors:\n      already_voted: 이미 투표에 참여하셨습니다\n      duplicate_options: 중복된 항목이 있습니다\n      duration_too_long: 너무 먼 미래입니다\n      duration_too_short: 너무 가깝습니다\n      expired: 투표가 이미 끝났습니다\n      over_character_limit: 각각 %{max} 글자를 넘을 수 없습니다\n      too_few_options: 한가지 이상의 항목을 포함해야 합니다\n      too_many_options: 항목은 %{max}개를 넘을 수 없습니다\n  preferences:\n    other: 기타\n    posting_defaults: 게시물 기본설정\n    public_timelines: 공개 타임라인\n  relationships:\n    activity: 계정 활동\n    dormant: 휴면\n    last_active: 마지막 활동\n    most_recent: 가장 최근\n    moved: 이동함\n    mutual: 상호 팔로우\n    primary: 주 계정\n    relationship: 관계\n    remove_selected_domains: 선택한 도메인의 모든 팔로워 삭제\n    remove_selected_followers: 선택한 팔로워 삭제\n    remove_selected_follows: 선택한 유저들을 팔로우 해제\n    status: 계정 상태\n  remote_follow:\n    acct: 당신이 사용하는 아이디@도메인을 입력해 주십시오\n    missing_resource: 리디렉션 대상을 찾을 수 없습니다\n    no_account_html: 계정이 없나요? <a href='%{sign_up_path}' target='_blank'>여기에서 가입 할 수 있습니다</a>\n    proceed: 팔로우 하기\n    prompt: '팔로우 하려 하고 있습니다:'\n    reason_html: \"<strong>왜 이 과정이 필요하죠?</strong><code>%{instance}</code>는 당신이 가입한 서버가 아닐 것입니다, 당신의 홈 서버로 먼저 가야 합니다.\"\n  remote_interaction:\n    favourite:\n      proceed: 즐겨찾기 진행\n      prompt: '이 툿을 즐겨찾기 하려고 합니다:'\n    reblog:\n      proceed: 부스트 진행\n      prompt: '이 툿을 부스트 하려 합니다:'\n    reply:\n      proceed: 답장 진행\n      prompt: '이 툿에 답장을 하려 합니다:'\n  remote_unfollow:\n    error: 에러\n    title: 타이틀\n    unfollowed: 언팔로우됨\n  scheduled_statuses:\n    over_daily_limit: 그 날짜에 대한 %{limit}개의 예약 툿 제한을 초과합니다\n    over_total_limit: 예약 툿 제한 %{limit}을 초과합니다\n    too_soon: 예약 날짜는 미래여야 합니다\n  sessions:\n    activity: 마지막 활동\n    browser: 브라우저\n    browsers:\n      alipay: 알리페이\n      blackberry: 블랙베리\n      chrome: 크롬\n      edge: 엣지\n      electron: 일렉트론\n      firefox: 파이어폭스\n      generic: 알 수 없는 브라우저\n      ie: IE\n      micro_messenger: 마이크로메신저\n      nokia: 노키아 S40 Ovi 브라우저\n      opera: 오페라\n      otter: Otter\n      phantom_js: PhantomJS\n      qq: QQ 브라우저\n      safari: 사파리\n      uc_browser: UC브라우저\n      weibo: 웨이보\n    current_session: 현재 세션\n    description: \"%{platform}의 %{browser}\"\n    explanation: 내 마스토돈 계정에 현재 로그인 중인 웹 브라우저 목록입니다.\n    ip: IP\n    platforms:\n      adobe_air: 어도비 에어\n      android: 안드로이드\n      blackberry: 블랙베리\n      chrome_os: 크롬OS\n      firefox_os: 파이어폭스OS\n      ios: iOS\n      linux: 리눅스\n      mac: 맥\n      other: 알 수 없는 플랫폼\n      windows: 윈도우즈\n      windows_mobile: 윈도우즈 모바일\n      windows_phone: 윈도우즈 폰\n    revoke: 삭제\n    revoke_success: 세션이 성공적으로 삭제되었습니다\n    title: 세션\n  settings:\n    account: 계정\n    account_settings: 계정 설정\n    appearance: 외관\n    authorized_apps: 인증된 애플리케이션\n    back: 돌아가기\n    delete: 계정 삭제\n    development: 개발\n    edit_profile: 프로필 편집\n    export: 데이터 내보내기\n    featured_tags: 추천 해시태그\n    identity_proofs: 신원 증명\n    import: 데이터 가져오기\n    import_and_export: 가져오기 / 내보내기\n    migrate: 계정 이동\n    notifications: 알림\n    preferences: 사용자 설정\n    profile: 프로필\n    relationships: 팔로잉과 팔로워\n    two_factor_authentication: 2단계 인증\n  statuses:\n    attached:\n      description: '첨부: %{attached}'\n      image:\n        other: \"%{count} 이미지\"\n      video:\n        other: \"%{count} 영상\"\n    boosted_from_html: \"%{acct_link} 님으로부터 부스트\"\n    content_warning: '열람 주의: %{warning}'\n    disallowed_hashtags:\n      other: '허용되지 않은 해시태그를 포함하고 있습니다: %{tags}'\n    language_detection: 자동으로 언어 감지\n    open_in_web: Web으로 열기\n    over_character_limit: 최대 %{max}자까지 입력할 수 있습니다\n    pin_errors:\n      limit: 이미 너무 많은 툿을 고정했습니다\n      ownership: 다른 사람의 툿은 고정될 수 없습니다\n      private: 비공개 툿은 고정될 수 없습니다\n      reblog: 부스트는 고정될 수 없습니다\n    poll:\n      total_votes:\n        other: \"%{count}명 투표함\"\n      vote: 투표\n    show_more: 더 보기\n    sign_in_to_participate: 로그인 하여 이 대화에 참여하기\n    title: '%{name}: \"%{quote}\"'\n    visibilities:\n      private: 비공개\n      private_long: 팔로워에게만 공개됩니다\n      public: 공개\n      public_long: 누구나 볼 수 있으며, 공개 타임라인에 표시됩니다\n      unlisted: 공개 타임라인 비공개\n      unlisted_long: 누구나 볼 수 있지만, 공개 타임라인에는 표시되지 않습니다\n  stream_entries:\n    pinned: 고정된 툿\n    reblogged: 님이 부스트 했습니다\n    sensitive_content: 민감한 컨텐츠\n  terms:\n    body_html: |\n      <h2>개인정보 정책</h2>\n      <h3 id=\"collect\">우리가 어떤 정보를 수집하나요?</h3>\n\n      <ul>\n      <li><em>기본 계정 정보</em>: 이 서버에 가입하실 때 유저네임, 이메일 주소, 패스워드 등을 입력 받게 됩니다. 추가적으로 디스플레이네임이나 자기소개, 프로필 이미지, 헤더 이미지 등의 프로필 정보를 입력하게 됩니다. 유저네임, 디스플레이네임, 자기소개, 프로필 이미지와 헤더 이미지는 언제나 공개적으로 게시됩니다.</li>\n      <li><em>게시물, 팔로잉, 기타 공개된 정보</em>: 당신이 팔로우 하는 사람들의 리스트는 공개됩니다. 당신을 팔로우 하는 사람들도 마찬가지입니다. 당신이 게시물을 작성하는 경우, 응용프로그램이 메시지를 받았을 때의 날짜와 시간이 기록 됩니다. 게시물은 그림이나 영상 등의 미디어를 포함할 수 있습니다. 퍼블릭과 미표시(unlisted) 게시물은 공개적으로 접근이 가능합니다. 프로필에 게시물을 고정하는 경우 마찬가지로 공개적으로 접근 가능한 정보가 됩니다. 당신의 게시물들은 당신의 팔로워들에게 전송 됩니다. 몇몇 경우 이것은 다른 서버에 전송되고 그곳에 사본이 저장 됩니다. 당신이 게시물을 삭제하는 경우 이 또한 당신의 팔로워들에게 전송 됩니다. 다른 게시물을 리블로깅 하거나 즐겨찾기 하는 경우 이는 언제나 공개적으로 제공 됩니다.</li>\n      <li><em>DM, 팔로워 공개 게시물</em>: 모든 게시물들은 서버에서 처리되고 저장됩니다. 팔로워 공개 게시물은 당신의 팔로워와 멘션 된 사람들에게 전달이 됩니다. 다이렉트 메시지는 멘션 된 사람들에게만 전송 됩니다. 몇몇 경우 이것은 다른 서버에 전송 되고 그곳에 사본이 저장됨을 의미합니다. 우리는 이 게시물들이 권한을 가진 사람들만 열람이 가능하도록 노력을 할 것이지만 다른 서버에서는 이것이 실패할 수도 있습니다. 그러므로 당신의 팔로워들이 속한 서버를 재확인하는 것이 중요합니다. 당신은 새 팔로워를 수동으로 승인하거나 거절하도록 설정을 변경할 수 있습니다. <em>해당 서버의 운영자는 서버가 받는 메시지를 열람할 수 있다는 것을 항상 염두해 두세요</em>, 그리고 수신자들은 스크린샷을 찍거나 복사하는 등의 방법으로 다시 공유할 수 있습니다. <em>위험한 정보를 마스토돈을 통해 공유하지 마세요.</em></li>\n      <li><em>IP와 기타 메타데이터</em>: 당신이 로그인 하는 경우 IP 주소와 브라우저의 이름을 저장합니다. 모든 세션은 당신이 검토하고 취소할 수 있도록 설정에서 제공 됩니다. 마지막으로 사용 된 IP 주소는 최대 12개월 간 저장됩니다. 또한, 모든 요청에 대해 IP주소를 포함한 정보를 로그에 저장할 수 있습니다.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"use\">우리가 당신의 정보를 어디에 쓰나요?</h3>\n\n      <p>당신에게서 수집한 정보는 다음과 같은 곳에 사용 됩니다:</p>\n\n      <ul>\n      <li>마스토돈의 주요 기능 제공. 다른 사람의 게시물에 상호작용 하거나 자신의 게시물을 작성하기 위해서는 로그인을 해야 합니다. 예를 들어, 다른 사람의 게시물을 자신만의 홈 타임라인에서 모아 보기 위해 팔로우를 할 수 있습니다.</li>\n      <li>커뮤니티의 모더레이션을 위해, 예를 들어 당신의 IP 주소와 기타 사항을 비교하여 금지를 우회하거나 다른 규칙을 위반하는지 판단하는 데에 사용할 수 있습니다.</li>\n      <li>당신이 제공한 이메일 주소를 통해 정보, 다른 사람들의 반응이나 받은 메시지에 대한 알림, 기타 요청 등에 관한 응답 요청 등을 보내는 데에 활용됩니다.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"protect\">어떻게 당신의 정보를 보호하나요?</h3>\n\n      <p>우리는 당신이 입력, 전송, 접근하는 개인정보를 보호하기 위해 다양한 보안 대책을 적용합니다. 당신의 브라우저 세션, 당신의 응용프로그램과의 통신, API는 SSL로 보호 되며 패스워드는 강력한 단방향 해시 알고리즘을 사용합니다. 계정의 더 나은 보안을 위해 2단계 인증을 활성화 할 수 있습니다.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"data-retention\">자료 저장 정책은 무엇이죠?</h3>\n\n      <p>우리는 다음을 위해 노력을 할 것입니다:</p>\n\n      <ul>\n      <li>IP를 포함해 이 서버에 전송 되는 모든 요청에 대한 로그는 90일을 초과하여 저장되지 않습니다.</li>\n      <li>가입 된 유저의 IP 정보는 12개월을 초과하여 저장 되지 않습니다.</li>\n      </ul>\n\n      <p>당신은 언제든지 게시물, 미디어 첨부, 프로필 이미지, 헤더 이미지를 포함한 당신의 컨텐트에 대한 아카이브를 요청하고 다운로드 할 수 있습니다.</p>\n\n      <p>언제든지 계정을 완전히 삭제할 수 있습니다.</p>\n\n      <hr class=\"spacer\"/>\n\n      <h3 id=\"cookies\">쿠키를 사용하나요?</h3>\n\n      <p>네. 쿠키는 (당신이 허용한다면) 당신의 웹 브라우저를 통해 서버에서 당신의 하드드라이브에 저장하도록 전송하는 작은 파일들입니다. 이 쿠키들은 당신의 브라우저를 인식하고, 계정이 있는 경우 이와 연결하는 것을 가능하게 합니다.</p>\n\n      <p>당신의 환경설정을 저장하고 다음 방문에 활용하기 위해 쿠키를 사용합니다.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"disclose\">외부에 정보를 공개하나요?</h3>\n\n      <p>우리는 당신을 식별 가능한 개인정보를 외부에 팔거나 제공하거나 전송하지 않습니다. 이는 당사의 사이트를 운영하기 위한, 기밀 유지에 동의하는, 신뢰 가능한 서드파티를 포함하지 않습니다. 또한 법률 준수, 사이트 정책 시행, 또는 당사나 타인에 대한 권리, 재산, 또는 안전보호를 위해 적절하다고 판단되는 경우 당신의 정보를 공개할 수 있습니다.</p>\n\n      <p>당신의 공개 게시물은 네트워크에 속한 다른 서버가 다운로드 할 수 있습니다. 당신의 팔로워나 수신자가 이 서버가 아닌 다른 곳에 존재하는 경우 당신의 공개, 팔로워 공개 게시물은 당신의 팔로워가 존재하는 서버로 전송되며, 다이렉트메시지는 수신자가 존재하는 서버로 전송 됩니다.</p>\n\n      <p>당신이 계정을 사용하기 위해 응용프로그램을 승인하는 경우 당신이 허용한 권한에 따라 응용프로그램은 당신의 공개 계정정보, 팔로잉 리스트, 팔로워 리스트, 게시물, 즐겨찾기 등에 접근이 가능해집니다. 응용프로그램은 절대로 당신의 이메일 주소나 패스워드에 접근할 수 없습니다.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"children\">어린이의 사이트 사용</h3>\n\n      <p>이 서버가 EU나 EEA에 속해 있다면: 당사의 사이트, 제품과 서비스는 16세 이상인 사람들을 위해 제공됩니다. 당신이 16세 미만이라면 GDPR(<a href=\"https://en.wikipedia.org/wiki/General_Data_Protection_Regulation\">General Data Protection Regulation</a>)의 요건에 따라 이 사이트를 사용할 수 없습니다.</p>\n\n      <p>이 서버가 미국에 속해 있다면: 당사의 사이트, 제품과 서비스는 13세 이상인 사람들을 위해 제공됩니다. 당신이 13세 미만이라면 COPPA (<a href=\"https://en.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act\">Children's Online Privacy Protection Act</a>)의 요건에 따라 이 사이트를 사용할 수 없습니다.</p>\n\n      <p>이 서버가 있는 관할권에 따라 법적 요구가 달라질 수 있습니다.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"changes\">개인정보 정책의 변경</h3>\n\n      <p>만약 우리의 개인정보 정책이 바뀐다면, 이 페이지에 바뀐 정책이 포스트 됩니다.</p>\n\n      <p>이 문서는 CC-BY-SA 라이센스입니다. 마지막 업데이트는 2018년 3월 7일입니다.</p>\n\n      <p>Originally adapted from the <a href=\"https://github.com/discourse/discourse\">Discourse privacy policy</a>.</p>\n    title: \"%{instance} 이용약관과 개인정보 취급 방침\"\n  themes:\n    contrast: 마스토돈 (고대비)\n    default: 마스토돈 (어두움)\n    mastodon-light: 마스토돈 (밝음)\n  time:\n    formats:\n      default: \"%Y년 %m월 %d일 %H:%M\"\n      month: \"%Y년 %b\"\n  two_factor_authentication:\n    code_hint: 확인하기 위해서 인증 애플리케이션에서 표시된 코드를 입력해 주십시오\n    description_html: \"<strong>2단계 인증</strong>을 활성화 하면 로그인 시 전화로 인증 코드를 받을 필요가 있습니다.\"\n    disable: 비활성화\n    enable: 활성화\n    enabled: 2단계 인증이 활성화 되어 있습니다\n    enabled_success: 2단계 인증이 활성화 되었습니다\n    generate_recovery_codes: 복구 코드 생성\n    instructions_html: \"<strong>Google Authenticator, 또는 타 TOTP 애플리케이션에서 이 QR 코드를 스캔해 주십시오.</strong> 이후 로그인 시에는 이 애플리케이션에서 생성되는 코드가 필요합니다.\"\n    lost_recovery_codes: 복구 코드를 사용하면 휴대전화를 분실한 경우에도 계정에 접근할 수 있게 됩니다. 복구 코드를 분실한 경우에도 여기서 다시 생성할 수 있지만, 예전 복구 코드는 비활성화 됩니다.\n    manual_instructions: 'QR 코드를 스캔할 수 없어 수동으로 등록을 원하시는 경우 이 비밀 코드를 사용해 주십시오:'\n    recovery_codes: 복구 코드\n    recovery_codes_regenerated: 복구 코드가 다시 생성되었습니다\n    recovery_instructions_html: 휴대전화를 분실한 경우, 아래 복구 코드 중 하나를 사용해 계정에 접근할 수 있습니다. <strong>복구 코드는 안전하게 보관해 주십시오.</strong> 이 코드를 인쇄해 중요한 서류와 함께 보관하는 것도 좋습니다.\n    setup: 초기 설정\n    wrong_code: 코드가 올바르지 않습니다. 서버와 휴대전화 간의 시각이 일치하나요?\n  user_mailer:\n    backup_ready:\n      explanation: 당신이 요청한 계정의 풀 백업이 이제 다운로드 가능합니다!\n      subject: 당신의 아카이브를 다운로드 가능합니다\n      title: 아카이브 테이크 아웃\n    warning:\n      explanation:\n        disable: 당신의 계정이 동결 된 동안 당신의 계정은 유지 됩니다. 하지만 잠금이 풀릴 때까지 당신은 아무 것도 할 수 없습니다.\n        silence: 당신의 계정이 제한 된 동안엔 당신의 팔로워 이외엔 툿을 받아 볼 수 없고 공개 리스팅에서 제외 됩니다. 하지만 다른 사람들은 여전히 당신을 팔로우 가능합니다.\n        suspend: 당신의 계정은 정지 되었으며, 모든 툿과 업로드 한 미디어가 서버에서 삭제 되어 되돌릴 수 없습니다.\n      review_server_policies: 서버 정책 검토하기\n      subject:\n        disable: 당신의 계정 %{acct}가 동결 되었습니다\n        none: \"%{acct}에게의 경고\"\n        silence: 당신의 계정 %{acct}가 제한 되었습니다\n        suspend: 당신의 계정 %{acct}가 정지 되었습니다\n      title:\n        disable: 계정 동결 됨\n        none: 경고\n        silence: 계정 제한 됨\n        suspend: 계정 정지 됨\n    welcome:\n      edit_profile_action: 프로필 설정\n      edit_profile_step: 아바타, 헤더를 업로드하고, 사람들에게 표시 될 이름을 바꾸는 것으로 당신의 프로필을 커스텀 할 수 있습니다. 사람들이 당신을 팔로우 하기 전에 리뷰를 거치게 하고 싶다면 계정을 잠그면 됩니다.\n      explanation: 시작하기 전에 몇가지 팁들을 준비했습니다\n      final_action: 포스팅 시작하기\n      final_step: '포스팅을 시작하세요! 팔로워가 없더라도 퍼블릭 메시지는 다른 사람들이 볼 수 있습니다, 예를 들면 로컬 타임라인이나 해시태그에서요. 사람들에게 자신을 소개하고 싶다면 #introductions 해시태그를 이용해보세요.'\n      full_handle: 당신의 풀 핸들\n      full_handle_hint: 이것을 당신의 친구들에게 알려주면 다른 서버에서 팔로우 하거나 메시지를 보낼 수 있습니다.\n      review_preferences_action: 설정 바꾸기\n      review_preferences_step: 당신의 설정을 확인하세요. 어떤 이메일로 알림을 받을 것인지, 기본적으로 어떤 프라이버시 설정을 사용할 것인지, 멀미가 없다면 GIF를 자동 재생하도록 설정할 수도 있습니다.\n      subject: 마스토돈에 오신 것을 환영합니다\n      tip_federated_timeline: 연합 타임라인은 마스토돈 네트워크의 소방호스입니다. 다만 여기엔 당신의 이웃들이 구독 중인 것만 뜹니다, 모든 것이 다 오는 것은 아니예요.\n      tip_following: 기본적으로 서버의 관리자를 팔로우 하도록 되어 있습니다. 흥미로운 사람들을 더 찾으려면 로컬과 연합 타임라인을 확인해 보세요.\n      tip_local_timeline: 로컬 타임라인은 %{instance}의 소방호스입니다. 여기 있는 사람들은 당신의 이웃들이에요!\n      tip_mobile_webapp: 모바일 브라우저가 홈 스크린에 바로가기를 추가해 줬다면 푸시 알림도 받을 수 있습니다. 이건 거의 네이티브 앱처럼 작동해요!\n      tips: 팁\n      title: 환영합니다 %{name} 님!\n  users:\n    follow_limit_reached: 당신은 %{limit}명의 사람을 넘어서 팔로우 할 수 없습니다\n    invalid_email: 메일 주소가 올바르지 않습니다\n    invalid_otp_token: 2단계 인증 코드가 올바르지 않습니다\n    otp_lost_help_html: 만약 양쪽 모두를 잃어버렸다면 %{email}을 통해 복구할 수 있습니다\n    seamless_external_login: 외부 서비스를 이용해 로그인 했습니다, 패스워드와 이메일 설정을 할 수 없습니다.\n    signed_in_as: '다음과 같이 로그인 중:'\n  verification:\n    explanation_html: '당신은 <strong>프로필 메타데이터의 링크 소유자임을 검증할 수 있습니다</strong>. 이것을 하기 위해서는, 링크 된 웹사이트에서 당신의 마스토돈 프로필을 역으로 링크해야 합니다. 역링크는 <strong>반드시</strong> <code>rel=\"me\"</code> 속성을 가지고 있어야 합니다. 링크의 텍스트는 상관이 없습니다. 여기 예시가 있습니다:'\n    verification: 검증\n"
  },
  {
    "path": "config/locales/lt.yml",
    "content": "---\nlt:\n  about:\n    about_hashtag_html: Čia visiems prieinamas įrankis <strong>#%{hashtag}</strong>. Jūs galite juo naudotis bet kur, jeigu turite paskyra fedi-visatoje.\n    about_mastodon_html: Mastodon, tai socialinis tinklas pagrįstas atviro kodo programavimu, ir atvirais web protokolais. Visiškai nemokamas. Ši sistema decantrilizuota kaip jūsų elektroninis paštas.\n    about_this: Apie\n    administered_by: 'Administruoja:'\n    apps: Mobilioji Aplikacija\n    contact: Kontaktai\n    contact_missing: Nenustatyta\n    documentation: Dokumentacija\n    extended_description_html: |\n      <h3>Taisyklės</h3>\n      <p>Ilgas aprašymas dar nėra sudartyas</p>\n    generic_description: \"%{domain} yra vienas serveris tinkle\"\n    hosted_on: Mastodon palaikomas naudojantis %{domain} talpinimu\n    learn_more: Daugiau\n    privacy_policy: Privatumo Politika\n    source_code: Šaltinio kodas\n    status_count_before: Autorius\n    terms: Naudojimo sąlygos\n    user_count_before: Namai\n    what_is_mastodon: Kas tai, Mastodon?\n  accounts:\n    choices_html: \"%{name} pasirinkimai:\"\n    follow: Sekti\n    following: Sekami\n    joined: Prisijungiai %{date}\n    last_active: paskutinį kartą aktyvus\n    link_verified_on: Nuorodos nuosavybė paskutinį kartą tikrinta %{date}\n    media: Medija\n    moved_html: \"%{name} persikėlė į %{new_profile_link}:\"\n    network_hidden: Ši informacija neprieinama\n    nothing_here: Čia nieko nėra!\n    people_followed_by: Žmonės, kuriuos %{name} seka\n    people_who_follow: Žmonės kurie seka %{name}\n    pin_errors:\n      following: Privalai sekti žmogų kurį nori pagerbti\n    posts_tab_heading: Tootai\n    posts_with_replies: Tootai ir atsakymai\n    reserved_username: Vartotojo vardas rezervuotas\n    roles:\n      admin: Administratorius\n      bot: Bot'as\n      moderator: Moderatorius\n    unfollow: Nesekti\n  admin:\n    account_actions:\n      action: Veiksmas\n      title: Moderuoti %{acct}\n    account_moderation_notes:\n      create: Palikti žinutę\n      created_msg: Moderavimo žinutė sėkimngai sukurta!\n      delete: Ištrinti\n      destroyed_msg: Moderacijos žinutė sėkmingai ištrinta!\n    accounts:\n      are_you_sure: Ar esate įsitikinęs?\n      avatar: Profilio nuotrauka\n      by_domain: Domenas\n      change_email:\n        changed_msg: Paskyros el paštas sėkmingai pakeistas!\n        current_email: Dabartinis el paštas\n        label: Pakeisti el pašto adresą\n        new_email: Naujas el pašto adresas\n        submit: Pakeisti el pašto adresą\n        title: Pakeisti el pašto adresą vartotojui %{username}\n      confirm: Patvirtinti\n      confirmed: Patvirtinta\n      confirming: Tvirtinama\n      deleted: Ištrinti\n      demote: Pažeminti\n      disable: Išjungti\n      disable_two_factor_authentication: Išjungti 2 faktorių autentifikaciją\n      disabled: Išjungta\n      display_name: Matomas vardas\n      domain: Domenas\n      edit: Keisti\n      email: El paštas\n      email_status: El pašto statusas\n      enable: Įjungti\n      enabled: Įjungta\n      feed_url: Srauto URL\n      followers: Sekėjai\n      followers_url: Sekėjų URL\n      follows: Seka\n      header: Antraštė\n      inbox_url: Gautųjų URL\n      invited_by: Pakvietė\n      joined: Prisijungė\n      location:\n        all: Visi\n        local: Lokali\n        remote: Nuotolinis\n        title: Lokacija\n      login_status: Prisijungimo statusas\n      media_attachments: Prisegti medijos failai\n      memorialize: Paversti į memorija\n      moderation:\n        active: Aktyvus\n        all: Visi\n        silenced: Užtildytas\n        suspended: Užrakintas\n        title: Moderacija\n      moderation_notes: Medaracijos žinutės\n      most_recent_activity: Paskutinioji veikla\n      most_recent_ip: Paskutinis IP\n      no_limits_imposed: Be limitu\n      not_subscribed: Ne prenumeruota\n      outbox_url: Išsiustųjų URL\n      perform_full_suspension: Užrakinti\n      profile_url: Profilio URL\n      promote: Paaukštinti\n      protocol: Protokolas\n      public: Viešas\n      push_subscription_expires: PuSH prenumeramivas pasibaigė\n      redownload: Perkrauti profilį\n      remove_avatar: Panaikinti profilio nuotrauką\n      remove_header: Panaikinti antraštę\n      resend_confirmation:\n        already_confirmed: Šis vartotojas jau patvirtintas\n        send: Dar kartą išsiųsti patvirtinimo žinutę\n        success: Patvirtinimo laiškas sėkmingai išsiųstas!\n      reset: Iš naujo\n      reset_password: Atkurti slaptažodį\n      resubscribe: Per prenumeruoti\n      role: Leidimai\n      roles:\n        admin: Administratorius\n        moderator: Moderatorius\n        staff: Personalas\n        user: Vartotojas\n      salmon_url: Lašišos URL\n      search: Ieškoti\n      shared_inbox_url: Bendroji gautųjų URL\n      show:\n        created_reports: Parašyti raportai\n        targeted_reports: Reportuotas kitų\n      silence: Tyla\n      silenced: Užtildytas\n      statuses: Statusai\n      subscribe: Prenumeruoti\n      suspended: Užrakintas\n      title: Vartotojai\n      unconfirmed_email: Nepatvirtintas el pašto adresas\n      undo_silenced: Atšaukti užtildymą\n      undo_suspension: Atšaukti užrakinimą\n      unsubscribe: Nebeprenumeruoti\n      username: Slapyvardis\n      warn: Įspėti\n    action_logs:\n      actions:\n        assigned_to_self_report: \"%{name} paskyrė reportą %{target} saviems\"\n        change_email_user: \"%{name} pakeitė el pašto adresą vartotojui %{target}\"\n        confirm_user: \"%{name} patvirtino el pašto adresą vartotojui %{target}\"\n        create_account_warning: \"%{name} išsiuntė įspėjimą %{target}\"\n        create_custom_emoji: \"%{name} įkėlė naują jaustuką %{target}\"\n        create_domain_block: \"%{name} užblokavo domena %{target}\"\n        create_email_domain_block: \"%{name} įkėlė į juodajį sąrašą el pašto domena %{target}\"\n        demote_user: \"%{name} pažemino %{target}\"\n        destroy_custom_emoji: \"%{name} sunaikino jaustuką %{target}\"\n        destroy_domain_block: \"%{name} atrakino domeną %{target}\"\n        destroy_email_domain_block: \"%{name} pašalino iš juodojo sąrašo el pašto domeną %{target}\"\n        destroy_status: \"%{name} pašalino statusą %{target}\"\n        disable_2fa_user: \"%{name} išjungė 2 faktorių autentikavimo sistemos reikalavimus vartotojui  %{target}\"\n        disable_custom_emoji: \"%{name} išjungė jaustuką %{target}\"\n        disable_user: \"%{name} išjungė prisijungimą vartotojui %{target}\"\n        enable_custom_emoji: \"%{name} įjungė jaustuką %{target}\"\n        enable_user: \"%{name} įjungė prisijungimą vartotojui %{target}\"\n        memorialize_account: \"%{name} pavertė vartotojo %{target} paskyrą į prisiminimų puslapį\"\n        promote_user: \"%{name} paaukštino vartotoją %{target}\"\n        remove_avatar_user: \"%{name} panaikino vartotojo %{target} profilio nuotrauką\"\n        reopen_report: \"%{name} atidarė skundą %{target}\"\n        reset_password_user: \"%{name} atstatyti slaptažodį vartotojui %{target}\"\n        resolve_report: \"%{name} išsprendė skundą %{target}\"\n        silence_account: \"%{name} pritildė vartotojo %{target} paskyrą\"\n        suspend_account: \"%{name} laikinai užblokavo vartotojo %{target} paskyrą\"\n        unassigned_report: \"%{name} nepaskirtas skundas %{target}\"\n        unsilence_account: \"%{name} atitildė vartotojo %{target} paskyrą\"\n        unsuspend_account: \"%{name} atblokavo vartotojo %{target} paskyrą\"\n        update_custom_emoji: \"%{name} atnaujino jaustuką %{target}\"\n        update_status: \"%{name} pakeitė statusą %{target}\"\n      deleted_status: \"(panaikintas statusas)\"\n      title: Audito žurnalas\n    custom_emojis:\n      by_domain: Domenas\n      copied_msg: Sėkmingai sukurta lokali jaustuko kopija\n      copy: Kopijuoti\n      copy_failed_msg: Lokali jaustuko kopija negalėjo būti sukurta\n      created_msg: Jaustukas sukurtas sėkmingai!\n      delete: Ištrinti\n      destroyed_msg: Jaustukas sėkmingai sunaikintas!\n      disable: Išjungti\n      disabled_msg: Šis jaustukas sėkmingai išjungtas\n      emoji: Jaustukas\n      enable: Įjungti\n      enabled_msg: Šis jaustukas sėkmingai įjungtas\n      image_hint: PNG failo dydis iki 50KB\n      listed: Įtrauktas į sąrašą\n      new:\n        title: Pridėti naują jaustuką\n      overwrite: Perrašyti\n      shortcode: Trumpas-kodas\n      shortcode_hint: Bent du ženklai, tik raidiniai skaitmeniniai ženklai bei akcentai(_)\n      title: Asmeniniai jaustukai\n      unlisted: Neįtrauktas į sąrašą\n      update_failed_msg: Jaustukas negalėjo būti pakeistas\n      updated_msg: Jaustukas sėkmingai pakeistas!\n      upload: Įkelti\n    dashboard:\n      backlog: Neatlikti darbai\n      config: Konfiguracija\n      feature_deletions: Paskyrų šalinimas\n      feature_invites: Pakivetimo nuorodos\n      feature_profile_directory: Profilio direktorija\n      feature_registrations: Registracijos\n      feature_relay: Federacijos perjungėjas\n      features: Išskirtinumai\n      hidden_service: Federacija su paslėptomis paslaugomis\n      open_reports: atidaryti skundai\n      recent_users: Neseni vartotojai\n      search: Pilno teksto paieška\n      single_user_mode: Vieno vartotojo būsena\n      software: Programinė įranga\n      space: Naudojama atmintis\n      title: Pagrindinis puslapis\n      total_users: viso vartotoju\n      trends: Tendencijos\n      week_interactions: naudojimai šią savaitę\n      week_users_active: aktyvūs šią savaitę\n      week_users_new: vartotojai šią savaitę\n    domain_blocks:\n      add_new: Pridėti naują domeno bloką\n      created_msg: Domeno užblokavimas nagrinėjamas\n      destroyed_msg: Domeno blokas pašalintas\n      domain: Domenas\n      new:\n        create: Sukurti bloką\n        hint: Domeno blokavimas nesustabdys vartotojų paskyrų sukūrimo duomenų sistemoje, tačiau automatiškai pritaikys atitinkamus moderavimo metodus šioms paskyroms.\n        severity:\n          desc_html: |-\n            <strong>1Tyla</strong>2 padarys paskyros įkelimus nematomus visiems, kurie jų neseka.\n            <strong>3Draudimas</strong>4 panaikins visus paskyros įkėlimus ir profilio informaciją.Naudok<strong>5Nieko</strong>6 jeigu tiesiog norite atmesti medijos failus.\n          noop: Nieko\n          silence: Tyla\n          suspend: Draudimas\n        title: Naujos domeno blokas\n      reject_media: Atmesti medijos failai\n      reject_media_hint: Panaikina lokaliai saugomus medijos failus bei atsisako jų parsisiuntimo ateityje. Neliečia užblokavimu\n      reject_reports: Atmesti skundai\n      reject_reports_hint: Ignoruoti visus skundus, kurie siunčiami iš šio domeno. Neliečia užblokavimu\n      rejecting_media: atmetami medijos failai\n      rejecting_reports: atmetami skundai\n      severity:\n        silence: užtildytas\n        suspend: uždraustas\n      show:\n        retroactive:\n          silence: Atitildyti visus egzistuojančius vartotojus šiame domene\n          suspend: Atblokuotis visus egzistuojančius vartotojus šiame domene\n        title: Atkurti domeno blokavimą domenui %{domain}\n        undo: Atkurti\n      undo: Atkurti domeno bloką\n    email_domain_blocks:\n      add_new: Pridėti naują\n      created_msg: El pašto domenas sėkmingai pridėtas į juodąjį sąrašą\n      delete: Ištrinti\n      destroyed_msg: El pašto adresas sėkmingai pašalintas iš juodojo sąrašo\n      domain: Domenas\n      new:\n        create: Pridėto domeną\n        title: Naujas el pašto juodojo sąrašo įtraukimas\n      title: El pašto juodasis sąrašas\n    followers:\n      back_to_account: Atgal Į Paskyrą\n      title: \"%{acct} Sekėjai\"\n    instances:\n      by_domain: Domenas\n      delivery_available: Pristatymas galimas\n      moderation:\n        all: Visi\n        limited: Limituotas\n        title: Moderacija\n      title: Federacija\n      total_blocked_by_us: Mes užblokavome\n      total_followed_by_them: Jų sekami\n      total_followed_by_us: Mūsų sekami\n      total_reported: Skundai apie juos\n      total_storage: Medijos prisegti failai\n    invites:\n      deactivate_all: Deaktyvuoti visus\n      filter:\n        all: Visi\n        available: Prieinamas\n        expired: Pasibaigęs\n        title: Filtras\n      title: Pakvietimai\n    relays:\n      add_new: Pridėti naują pamainą\n      delete: Ištrinti\n      description_html: \"<strong>Federacijos perjungėjas</strong> tai tarpinis serveris, kuris apsikeičia didelios apimties informacija tarp kitų serverių. <strong> Tai gali padėti mažesniems serveriams atrasti turinį iš fedi-visatos</strong>, kuris kitaip reikalautų vartotojų lokaliai sekti kitus žmones naudojantis kitus tolimus serverius.\"\n      disable: Išjungti\n      disabled: Išjungtas\n      enable: Įjungti\n      enable_hint: Kai įjungta, Jūsų serveris prenumeruos visas viešas žinutes iš šio tinklo, ir pradės siųsti šio serverio viešas žinutes į tinklą.\n      enabled: Įjungtas\n      inbox_url: Perdavimo URL\n      pending: Laukiama perdavimo patvirtinimo\n      save_and_enable: Išsaugoti ir įjungti\n      setup: Sukurti perdavimo ryšį\n      status: Statusas\n      title: Perdavimai\n    report_notes:\n      created_msg: Skundo žinutė sekmingai sukurta!\n      destroyed_msg: Skundo žinutė sekmingai ištrinta!\n    reports:\n      account:\n        note: raštelis\n        report: skundas\n      action_taken_by: Veiksmo ėmėsi\n      are_you_sure: Ar tu įsitikinęs?\n      assign_to_self: Paskirti man\n      assigned: Paskirtas moderatorius\n      comment:\n        none: Nėra\n      created_at: Reportuotas\n      mark_as_resolved: Pažymėti kaip išsprestą\n      mark_as_unresolved: Pažymėti kaip neišsprestą\n      notes:\n        create: Pridėti raštelį\n        create_and_resolve: Išspręsti su rašteliu\n        create_and_unresolve: Atidaryti su rašteliu\n        delete: Ištrinti\n        placeholder: Apibūdink, kokių veiksmų imtasi arba kitokie atnaujinimai..\n      reopen: Atidaryti skundą\n      report: 'Skundas #%{id}'\n      reported_account: Reportuota paskyra\n      reported_by: Skundas sukurtas\n      resolved: Išspręsta\n      resolved_msg: Skundas sėkmingai įšspręstas!\n      status: Statusas\n      title: Skundai\n      unassign: Nepriskirti\n      unresolved: Neišspręsti\n      updated_at: Atnaujinti\n    settings:\n      activity_api_enabled:\n        desc_html: Skaičiai lokaliai įkeltų statusų, aktyvių vartotojų ir naujų registracijų, kas savaitiniuose atnaujinimuose\n        title: Paskelbti agreguotą statistiką apie vartotojo veiklą\n      bootstrap_timeline_accounts:\n        desc_html: Atskirti vartotojų vardus naudojant kablelį (,). Tik lokalios ir neužblokuotos paskyros veiks. Pradinis kai tuščia, visi lokalūs administratoriai.\n        title: Numatyti sekimai naujiems vartotojams\n      contact_information:\n        email: Verslo el paštas\n        username: Kontaktinis slapyvardis\n      custom_css:\n        desc_html: Pakeisk išvaizdą su CSS užkraunamu kiekviename puslapyje\n        title: Asmeninis CSS\n      hero:\n        desc_html: Rodomas pagrindiniame puslapyje. Bent 600x100px rekomenduojama. Kai nenustatyta, renkamasi numatytą serverio nuotrauką\n        title: Herojaus nuotrauka\n      mascot:\n        desc_html: Rodoma keleta puslapių. Bent 293×205px rekomenduoja. Kai nenustatyą, renkamasi numatytą varianta\n        title: Talismano nuotrauka\n      peers_api_enabled:\n        desc_html: Domeno vardai, kuriuos šis serveris sutiko fedi-visatoje\n        title: Paskelbti sąrašą atrastų serveriu\n      preview_sensitive_media:\n        desc_html: Nuorodų peržiūros kituose tinklalapiuose bus rodomos su maža nuotrauka, net jeigu failas parinktas kaip \"jautraus turinio\"\n        title: Rodyti jautrią informaciją OpenGraph peržiūrose\n      profile_directory:\n        desc_html: Leisti vartotojams būti atrastiems\n        title: Įjungti profilio direktorija\n      registrations:\n        closed_message:\n          desc_html: Rodoma pagrindiniame puslapyje, kuomet registracijos uždarytos. Jūs galite naudoti HTML\n          title: Uždarytos registracijos žinutė\n        deletion:\n          desc_html: Leisti visiems ištrinti savo paskyrą\n          title: Atidaryti paskyros trynimą\n        min_invite_role:\n          disabled: Nei vienas\n          title: Leisti pakvietimus\n      show_known_fediverse_at_about_page:\n        desc_html: Kai įjungta, rodys įrašus iš visos žinomos fedi-visatos. Kitokiu atvėju, rodys tik lokalius įrašus.\n        title: Rodyti žinoma fedi-visatos laiko juosta peržiūroje\n      show_staff_badge:\n        desc_html: Rodyti personalo ženklelį vartotojo puslapyje\n        title: Rodyti personalo ženklelį\n      site_description:\n        desc_html: Introdukcinis paragrafas pagrindiniame puslapyje. Apibūdink, kas padaro šį Mastodon serverį išskirtiniu ir visa kita, kas svarbu. Nebijok naudoti HTML žymes, pavyzdžiui <code> &lt; a &gt;</code> bei <code>&lt;em&gt;</code>.\n        title: Serverio apibūdinimas\n      site_description_extended:\n        desc_html: Gera vieta Jūsų elgesio kodeksui, taisyklėms, nuorodms ir kitokiai informacijai, kuri yra išskirtinė Jūsų serveriui. Galite naudoti HTML žymes\n        title: Išsamesnė išskirtine informacija\n      site_short_description:\n        desc_html: Rodoma šoniniame meniu ir meta žymėse. Apibūdink kas yra Mastodon, ir kas daro šį serverį išskirtiniu, vienu paragrafu. Jeigu tuščias, naudojamas numatytasis tekstas.\n        title: Trumpas serverio apibūdinimas\n      site_terms:\n        desc_html: Jūs galite parašyti savo pačio privatumo politika, naudojimo sąlygas ar kita informacija. Galite naudoti HTML žymes\n        title: Išskirtinės naudojimosi taisyklės\n      site_title: Serverio pavadinimas\n      thumbnail:\n        desc_html: Naudojama OpenGraph peržiūroms ir API. Rekomenduojama 1200x630px\n        title: Serverio miniatūra\n      timeline_preview:\n        desc_html: Rodyti viešą laiko juostą apsilankymo puslapyje\n        title: Laiko juostos peržiūra\n      title: Tinklalapio nustatymai\n    statuses:\n      back_to_account: Atgal į paskyros puslapį\n      batch:\n        delete: Ištrinti\n        nsfw_off: Pažymėti kaip ne jautrią informaciją\n        nsfw_on: Pažymėti kaip jautrią informaciją\n      failed_to_execute: Nesėkmingas veiksmas\n      media:\n        title: Medija\n      no_media: Nėra medijos\n      no_status_selected: Jokie statusai nebuvo pakeisti, nes niekas nepasirinkta\n      title: Paskyros statusai\n      with_media: Su medija\n    subscriptions:\n      callback_url: Atgalinė URL\n      confirmed: Patvirtinta\n      expires_in: Pasibaigia\n      last_delivery: Paskutinis pristatymas\n      title: WebSub protokolas\n      topic: Tema\n    tags:\n      accounts: Paskyros\n      hidden: Paslėpti\n      hide: Paslėpti iš direktorijos\n      name: Saitažodis(#)\n      title: Saitažodžiai(#)\n      unhide: Rodyti direktorijoje\n      visible: Matomas\n    title: Administracija\n    warning_presets:\n      add_new: Pridėti naują\n      delete: Ištrinti\n      edit: Keisti\n      edit_preset: Keisti įspėjimo nustatymus\n      title: Valdyti įspėjimo nustatymus\n  admin_mailer:\n    new_report:\n      body: \"%{reporter} parašė skundą apie %{target}\"\n      body_remote: Kažkas iš %{domain} parašė skundą apie %{target}\n      subject: Naujas skundas %{instance} (#%{id})\n  application_mailer:\n    notification_preferences: Keisti el pašto parinktis\n    settings: 'Keisti el pašto parinktis: %{link}'\n    view: 'Peržiūra:'\n    view_profile: Peržiurėti profilį\n    view_status: Peržiūrėti statusą\n  applications:\n    created: Aplikacija sėkmingai sukurta\n    destroyed: Aplikacija sėkmingai ištrinta\n    invalid_url: Gauta URL nuoroda netinkama\n    regenerate_token: Regeneruoti prieigos žetoną\n    token_regenerated: Prieigos žetonas sėkmingai sugeneruotas\n    warning: Būkite atsargūs su šia informacija. Niekada jos nesidalinkite!\n    your_token: Jūsų prieigos žetonas\n  auth:\n    change_password: Slaptažodis\n    confirm_email: Patvirtinti el paštą\n    delete_account: Ištrinti paskyrą\n    delete_account_html: Jeigu norite ištrinti savo paskyrą, galite eiti <a href=\"%{path}\">čia</a>. Jūsų prašys patvirtinti pasirinkimą.\n    didnt_get_confirmation: Negavote patvirtinimo instrukcijų?\n    forgot_password: Pamiršote slaptažodį?\n    invalid_reset_password_token: Slaptažodžio atkūrimo žetonas netinkamas arba jo galiojimo laikas pasibaigęs. Prašykite naujo žetono.\n    login: Prisijungti\n    logout: Atsijungti\n    migrate_account: Prisijungti prie kitos paskyros\n    migrate_account_html: Jeigu norite nukreipti šią paskyrą į kita, galite tai <a href=\"%{path}\">konfiguruoti čia</a>.\n    or_log_in_with: Arba prisijungti su\n    register: Užsiregistruoti\n    resend_confirmation: Išsiųsti dar kartą patvirtinimo instrukcijas\n    reset_password: Atstatyti slaptažodį\n    security: Apsauga\n    set_new_password: Nustatyti naują slaptažodį\n  authorize_follow:\n    already_following: Jūs jau sekate šią paskyrą\n    error: Dėja, aptikta klaida ieškant tolimosios paskyros\n    follow: Sekti\n    follow_request: 'Jūs išsiuntėte sekimo prašymą:'\n    following: 'Puiku! Jūs pradėjote sekti:'\n    post_follow:\n      close: Arba, Jūs galite uždaryti šį langą.\n      return: Rodyti vartotojo paskyrą\n      web: Eiti į\n    title: Sekti %{acct}\n  datetime:\n    distance_in_words:\n      about_x_hours: \"%{count} val\"\n      about_x_months: \"%{count}mėn\"\n      about_x_years: \"%{count}met\"\n      almost_x_years: \"%{count}met\"\n      half_a_minute: Ką tik\n      less_than_x_minutes: \"%{count}min\"\n      less_than_x_seconds: Ką tik\n      over_x_years: \"%{count}met\"\n      x_days: \"%{count}dien\"\n      x_minutes: \"%{count}min\"\n      x_months: \"%{count}mėn\"\n      x_seconds: \"%{count}sek\"\n  deletes:\n    bad_password_msg: Geras bandymas, programišiau! Neteisingas slaptažodis\n    confirm_password: Kad patvirtintumėte savo tapatybę, įveskite dabartini slaptažodį\n    description_html: Tai <strong>be sugrąžinimo, visam laikui</strong> panaikins visa turini iš Jūsų paskyros ir deaktyvuos ją. Jūsų vartotojo vardas paliks rezervuotas, kad išvengtumėme tapatybės pavagimo ateityje.\n    proceed: Ištrinti paskyrą\n    success_msg: Jūsų paskyra sėkmingai ištrinta\n    warning_html: Tiktai panaikinimas turinio iš šio serverio garantuotas. Turinys, kuris buvo viešai prieinamas ir dalinamas kituose serveriuose paliks pėdsakus. Serveriai, kurie neseka jūsų, kurie nėra tinkle, nepakeis savo duomenų sistemos.\n    warning_title: Platinamo turinio prieinamumas\n  directories:\n    directory: Profilio direktorija\n    enabled: Jūs esate rodomas šioje direktorijoje.\n    enabled_but_waiting: Jūs pasirinkote būti įtrauktas į direktorija, bet jūs neturite minimalaus sekėjų skaičiaus (%{min_followers}), kad būtumėte rodomas.\n    explanation: Raskite vartotojus, remiantis tuo, kuo jie domisi\n    explore_mastodon: Naršyti %{title}\n    how_to_enable: Jūs nesate prisijungęs prie šios direktorijos. Galite prisijungti žemiau. Naudokite saitažodžius savo biografiniame tekste, kad būtumėte rastas naudojantis specifinius saitažodžius!\n  errors:\n    '403': Jūs neturie prieigos matyti šiam puslapiui.\n    '404': Puslapis nerastas.\n    '410': Puslapis neegzistuoja.\n    '422':\n      content: Apsaugos patvirtinmas klaidingas. Ar jūs blokuojate sausainius?\n      title: Apsaugos patvirtinimas nepavyko\n    '429': Stabdomas\n    '500':\n      content: Atsiprašome, tačiau mūsų pusėje įvyko klaida.\n      title: Netinkamas puslapis\n    noscript_html: Kad naudotumėtės Mastodon web aplikacija, prašome įsijungti JavaScript. Alternatyviai, pabandykite viena iš <a href=\"%{apps_path}\">vietinių aplikacijų</a> Mastodon savo platformai.\n  exports:\n    archive_takeout:\n      date: Data\n      download: Parsisiųsti archyvą\n      hint_html: Jūs galite prašyti savo <strong>įrašų bei medijos</strong> archyvo. Eksportuota informacija bus ActivityPub formatu, skaitoma suderintų programų. Galite prašyti archyvo, kas 7 dienas.\n      in_progress: Sudaromas archyvas...\n      request: Prašyti savo archyvo\n      size: Dydis\n    blocks: Jūs blokuojate\n    domain_blocks: Domeno blokai\n    follows: Jūs sekate\n    lists: Sąrašai\n    mutes: Jūs tildote\n    storage: Medijos sandėlis\n  featured_tags:\n    add_new: Pridėti naują\n    errors:\n      limit: Jūs jau naudojate maksimalų galimą saitažodžių(#) kiekį\n  filters:\n    contexts:\n      home: Namų laiko juosta\n      notifications: Priminimai\n      public: Viešos laiko juostos\n      thread: Pokalbiai\n    edit:\n      title: Keisti filtrą\n    errors:\n      invalid_context: Jokio arba netinkamas pateiktas kontekstas\n      invalid_irreversible: Negrąžinamas filtras veikia tik namų ir priminimų kontekste\n    index:\n      delete: Ištrinti\n      title: Filtrai\n    new:\n      title: Pridėti naują filtrą\n  footer:\n    developers: Programuotojai\n    more: Daugiau…\n    resources: Resursai\n  generic:\n    changes_saved_msg: Pakeitimai sėkmingai išsaugoti!\n    copy: Kopijuoti\n    save_changes: Išsaugoti pakeitimus\n  imports:\n    modes:\n      merge: Sulieti\n      merge_long: Išsaugoti esančius įrašus ir pridėti naujus\n      overwrite: Perrašyti\n      overwrite_long: Pakeisti senus įrašus naujais\n    preface: Jūs galite importuoti informaciją iš kito serverio, tokią kaip sąrašą žmonių kuriuos sekate.\n    success: Jūsų informacija sėkmingai įkelta ir bus apdorota kaip įmanoma greičiau\n    types:\n      blocking: Blokuojamų sąrašas\n      domain_blocking: Domeno blokavimo sąrašas\n      following: Sekėju sąrašas\n      muting: Tildomų sąrašas\n    upload: Įkelti\n  in_memoriam_html: Atminimui.\n  invites:\n    delete: Deaktyvuoti\n    expired: Pasibaigęs\n    expires_in:\n      '1800': 30 minučių\n      '21600': 6 valandų\n      '3600': 1 valandos\n      '43200': 12 valandų\n      '604800': 1 savaitės\n      '86400': 1 dienos\n    expires_in_prompt: Niekada\n    generate: Generuoti\n    invited_by: 'Jus pakvietė:'\n    max_uses_prompt: Be limito\n    prompt: Generuoti ir dalintis įrašais su kitais, kad sukurti prieigą prie serverio\n    table:\n      expires_at: Pasibaigia\n      uses: Naudojimai\n    title: Pakviesti žmones\n  lists:\n    errors:\n      limit: Jūs pasieketė maksimalų sąrašų skaičių\n  media_attachments:\n    validations:\n      images_and_video: Negalima pridėti video prie statuso, kuris jau turi nuotrauką\n      too_many: Negalima pridėti daugiau nei 4 failų\n  migrations:\n    acct: slapyvardis@domenas naujam vartotojui\n    currently_redirecting: 'Jūsų profilis nustatytas nukreipimui į:'\n    proceed: Išsaugoti\n    updated_msg: Jūsų paskyros migracijos nustatymai sėkmingai pakeisti!\n  moderation:\n    title: Moderacija\n  notification_mailer:\n    digest:\n      action: Peržiurėti visus pranešimus\n      body: Čia yra trumpa santrauka žinutės, kurią jūs praleidote nuo jūsų paskutinio apsilankymo %{since}\n      mention: \"%{name} paminėjo jus:\"\n      title: Kol jūsų nebuvo...\n    favourite:\n      body: 'Jūsų statusą pamėgo %{name}:'\n      subject: \"%{name} pamėgo Jūsų statusą\"\n      title: Naujas mėgstamas\n    follow:\n      body: \"%{name} pradėjo jus sekti!\"\n      subject: \"%{name} pradėjo jus sekti\"\n      title: Naujas sekėjas\n    follow_request:\n      action: Tvarkyti prašymus sekti\n      body: \"%{name} nori tapti Jūsų sekėju\"\n      subject: 'Laukiantis sprendimo sekėjas:  %{name}'\n      title: Naujas prašymas sekti\n    mention:\n      action: Atsakyti\n      body: 'Jus paminėjo %{name} pranešime:'\n      subject: Jus paminėjo %{name}\n      title: Naujas paminėjimas\n    reblog:\n      body: 'Jūsų statusą pakėlė %{name}:'\n      subject: \"%{name} pakėlė Jūsų statusą\"\n      title: Naujas pakėlimas\n  pagination:\n    newer: Naujesnis\n    next: Kitas\n    older: Senesnis\n    prev: Ankstesnis\n  preferences:\n    other: Kita\n  remote_follow:\n    acct: Įveskite Jūsų slapyvardį@domenas kurį norite naudoti\n    missing_resource: Jūsų paskyros nukreipimo URL nerasta\n    no_account_html: Neturite paskyros? Jūs galite<a href='%{sign_up_path}' target='_blank'> užsiregistruoti čia </a>\n    proceed: Sekti\n    prompt: 'Jūs seksite:'\n    reason_html: \"<strong>Kodėl šis žingsnis svarbus?</strong><code>%{instance}</code> gali būti serveris, kuriame jūs nesate užsiregistravęs, todėl mes turime jus nukreipti į Jūsų namų serveri.\"\n  remote_interaction:\n    favourite:\n      proceed: Pamėgti\n      prompt: 'Jūs norite pamėgti šį toot''ą:'\n    reblog:\n      proceed: Pakelti\n      prompt: 'Jūs norite pakelti šį toot''ą:'\n    reply:\n      proceed: Atsakyti\n      prompt: 'Jūs norite atsakyti šiam toot''ui:'\n  remote_unfollow:\n    error: Klaida\n    title: Pavadinimas\n    unfollowed: Nebesekama\n  scheduled_statuses:\n    over_daily_limit: Jūs pasieketė limitą (%{limit}) galimų toot'ų per dieną\n    over_total_limit: Jūs pasieketė %{limit} limitą galimų toot'ų\n    too_soon: Planuota data privalo būti ateityje\n  sessions:\n    activity: Paskutinė veikla\n    browser: Naršyklė\n    browsers:\n      generic: Nežinoma naršyklė\n    current_session: Dabartinė sesija\n    description: \"%{browser} ant %{platform}\"\n    explanation: Čia rodomos web naršyklės prijungtos prie Jūsų Mastodon paskyros.\n    platforms:\n      other: nežinoma platforma\n    revoke: Atšaukti\n    revoke_success: Sesija sėkmingai atšaukta\n    title: Sesijos\n  settings:\n    authorized_apps: Autorizuotos aplikacijos\n    back: Atgal į Mastodon\n    delete: Paskyros trynimas\n    development: Plėtojimas\n    edit_profile: Keisti profilį\n    export: Informacijos eksportas\n    featured_tags: Rodomi saitažodžiai(#)\n    import: Importuoti\n    migrate: Paskyros migracija\n    notifications: Pranešimai\n    preferences: Preferencijos\n    two_factor_authentication: Dviejų veiksnių autentikacija\n  statuses:\n    attached:\n      description: 'Pridėta: %{attached}'\n    boosted_from_html: Pakelta iš %{acct_link}\n    content_warning: 'Turinio įspėjimas: %{warning}'\n    language_detection: Automatiškai nustatyti kalbą\n    open_in_web: Atidaryti naudojan Web\n    over_character_limit: pasiektas %{max} simbolių limitas\n    pin_errors:\n      limit: Jūs jau prisegėte maksimalų toot'ų skaičų\n      ownership: Kitų vartotojų toot'ai negali būti prisegti\n      private: Ne vieši toot'ai negali būti prisegti\n      reblog: Pakeltos žinutės negali būti prisegtos\n    show_more: Daugiau\n    sign_in_to_participate: Prisijunkite jeigu norite dalyvauti pokalbyje\n    visibilities:\n      private: Tik sekėjams\n      private_long: Rodyti tik sekėjams\n      public: Viešas\n      public_long: Matyti gali visi\n      unlisted: Neįtrauktas į sąrašus\n      unlisted_long: Matyti gali visi, tačiau nėra įtraukta į viešas laiko juostas\n  stream_entries:\n    pinned: Prisegtas toot'as\n    reblogged: pakeltas\n    sensitive_content: Jautrus turinys\n  terms:\n    body_html: |\n      <h2>Privatumo politika</h2>\n      <h3 id=\"collect\">Kokia informacija yra renkama?</h3>\n      <ul>\n      <li><em>Paprasa paskyros informacija</em>: Jeigu Jūs užsiregistruojate šiame serveryje, Jūsų gali paklausti, kad įrašytumėte slapyvardį, el pašto adresą ir paskyros slaptąžodį. Jūs irgi galite įrašyti papildomą profilio informaciją, tokią kaip rodomas vardas ir biografiją bei įkelti profilio nuotrauką ir antraštės nuotrauką. Slapyvardis , rodomas vardas, biografija, profilio nuotrauka ir antraštės nuotrauka visada viešai prieinama informacija.</li>\n      <li><em>Įrašai, sekami ir kita vieša informacija</em>: Sąrašas žmonių, kuriuos Jūs sekate yra matomas viešai, taip pat kaip ir Jūsų sekėjams. Kai Jūs išsiunčiate žinutę, data ir laikas yra išsaugomi bei aplikacija iš kurios jūs išsiuntėte žinutę. Žinutėse gali būti prisegtų medijos failų kaip vaizdo įrašai bei nuotraukos. Viešos ir neįtrauktos į sąrašus žinutės yra viešai prieinamos. Kai nusprendžiate rodyti pranešimą ant savo profilio, tai irgi yra viešai prieinama informacija. Jūsų pranešimai yra pristatomi Jūsų sekėjams, kai kuriais atvėjais tai gali reikšti, kad šie pranešimai yra pristatomi į kitus serverius ir saugomi ten. Kai Jūs ištrinate įrašus, šie įrašai ištrinami ir Jūsų sekėjams. Veiksmas pamėgti kitus įrašus irgi yra viešas.\n      </li><li><em>Tiesioginiai ir tik sekėjams įrašai</em>: Visi įrašai yra saugomi ir apdorojami serveryje. Tik sekėjams įrašai yra pristatomi Jūsų sekėjams ir vartotojams, kurie yra paminėti įrašuose, ir tiesioginiai įrašai pristatomi tik vartotojams, kurie yra paminėti įraše. Kai kuriais atvėjais tai gali reikšti, kad šie įrašai yra pristatomi į kitą serverį ir įrašų kopijos saugomos ten. Mes stengiames riboti prieigą prie šių pranešimų tiktai autorizuotiems gavėjams, tačiau kiti serveriai to gali nedaryti. Todėl yra svarbu peržiurėti serverius, kuriems Jūsų sekėjai priklauso. Jūs galite įjungti būseną nustatymuose, kad galėtumetė priimti arba atmesti naujas sekimo užklausas.<em> Prašome nepamiršti, kad serverio operatoriai ir kiti serveriai, kurie gauna šias žinutes, gali jas peržiurėti </em> bei, kad gavėjai gali padaryti foto kopija, tektso kopija ar kitaip pasidalinti Jūsų žinutėmis.<em> Nesidalinkite jokia jautria ar pavojinga informacija naudojantis Mastodon.</em></li>\n      <li><em>IP adresai ir kiti metaduomenys</em>: Kai prisijungiate, mes įrašome IP adresą iš kurio jūs prisijungėte, ir naudojamos naršyklės pavadinimą. Visos prisijungimo sesijos yra prieinamos Jūsų apžvalgai ir atšaukimams nustatymuose. Paskutiniai IP adresai yra saugomi iki 12-kos mėnesių. Mes taipogi galime pasilikti serverio registrą, kuriuose yra saugoma IP adresai iš visų bandymu prisijungti prie serverio prašant informacijos.\n      </li></ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"use\">Kam mes naudojame Jūsų informaciją?</h3>\n      <p>Visa surinkta informacija apie jus, gali būti panaudota šiems tikslams: </p>\n      <ul>\n      <li>Suteikti pagrindį Mastodon funkcialumą. Jūs galite sąveikauti su kitų vartotojų turiniu ir kelti sąvajį, kuomet esate prisijungęs. Pavyzdžiui, galite sekti kitus žmones, peržiūrėti jų sujungtus įrašus savo pačio personalizuotoje laiko juostoje. </li>\n      <li>Padėti bendruomenės moderavimui, pavyzdžiui, lyginant Jūsų IP adresą, su kitu žinomu IP adresu, kad nustatyti bandymus vengti užblokavimo.</li>\n      <li>Jūsų el pašto adresas gali būti naudojamas išsiųsti informacija jums, priminimus apie kitų vartotojų interakciją su jūsų paskyra, pavyzdžiui, kai jie jums siunčia žinutes, ir atsakyti į užklausas ir/arba kitais klausimais. </li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"protect\">Kaip mes saugome Jūsų informacija? </h3>\n\n      <p>Mes implementavome saugumo priemones, tam, kad apsaugotume Jūsų privačią informaciją. Tarp šių dalykų, Jūsų naršyklės sesija, taip pat ir eismas tarp Jūsų aplikacijos ir API yra apsaugoti SSL, ir Jūsų slaptažodis yra užsifruotas sudėtingu algoritmu. Jūs galite įjungti dviejų veiksnių autentikaciją savo paskyrai, taip apsaugodami ją dar daugiau.\n      </p>\n\n      <hr class=\"spacer\" />\n      <h3 id=\"data-retention\"> Kokia yra mūsų duomenų laikymo politika? </h3>\n\n      <p>Mes stengiamės:</p>\n\n      <ul>\n      <li> Išsaugoti serverio registrą, kuriame yra visi IP adresai, kurie kreipėsi į serverį, šie duomenys laikomi neilgiau nei 90 dienų.</li>\n      <li> Išsaugoti IP adresus asocijuotus su registruotais vartotojais, ne ilgiau nei 12 mėnesių.</li>\n      </ul>\n\n      <p> Jūs galite pateikti prašymą ir parsisiųsti savo turinio archyvą, kuriame bus Jūsų įrašai, medijos failai, profilio nuotrauka ir antraštės nuotrauka.</p>\n\n      <p> Jūs galite VISIŠKAI ištrinti savo paskyrą bet kuriuo metu.</p>\n\n      <hr class=\"spacer\"/>\n\n      <h3 id=\"cookies\">Ar mes naudojame sausainiukus?</h3>\n\n      <p> Taip. Sausainiukai yra mažos apimties failai, kuriuos svetainė arba svetainės tiekėjas perkelia į Jūsų kompiuterio kietąjį diską naudojantis interneto naršykle (jeigu jūs leidžiate). Šie sausainiai leidžia svetainiai prisiminti Jūsų naršyklę ir jeigu turite registruotą vartotoją, ji asocijuoti su Jūsu vartotoju.</p>\n      <p>Mes naudojame sausainius, kad suprastumėme ir išsaugotumėme Jūsų poreikius kitam apsilankymui.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"disclose\">Ar mes atskleidžiame Jūsų informacija kitoms šalims?</h3>\n\n      <p>Mes neparduodame, nesikeičiame, ar kitaip mainomės Jūsų privačiais duomenimis su trečiosiomis šalimis. Į šį sąrašą neįeina patikimos trečiosios šalys, kurios padeda mums naudotis tinklalapiu, daryti verslą, ar padėti jums, tol, kol šios šalys sutinka laikyti šią informaciją konfidencialiai. Mes taippat galime paviešinti Jūsų informaciją, jeigu manome, kad Jūs pažeidėte įstatymus, naudojimosi politiką, ar apsaugoti, ginti Jūsų, mūsų ar kitų teises. </p>\n\n      <p>Jūsų vieši duomenys gali būti atsisiųsti kitų serverių esančių tinkle. Jūsų vieši bei tik sekėjams skirti įrašai pristatomi serveriams, kuriuose Jūsų sekėjai egzistuoja, o tiesioginės žinutės pristatomos tiesiai į gavėjo serverį, tol, kol šie sekėjai ar gavėjai yra naudotojai iš kitų serverių. </p>\n\n      <p>Kai jūs patvirtinate Jūsų paskyros naudojimą aplikacijai, atitinkamai priklausant nuo leidimų, kuriuos jūs suteikėte, aplikacija turi prieiga prie Jūsų viešojo profilio informacijos, Jūsų sekėjų sąrašo, sekamų sąrašo, visų Jūsų įrašų, ir pamėgtų įrašų.\n      Aplikacijos niekada negali turėti prieigos prie Jūsų el pašto adreso arba slaptažodžio.</p>\n\n      <hr class=\"spacer\" />\n\n\n      <h3 id=\"children\">Tinklalapio naudojimas nepilnamečiams</h3>\n\n      <p> Jeigu serveris yra EU arba EEA: Mūsų tinklalapis, produktai ir visi teikiami aptarnavimai yra teikiami tik žmonėms, kuriems yra bent 16 metų. Jeigu jums yra mažiau nei 16 metų, sekant GDPR reikalavimais (<a href=\"https://en.wikipedia.org/wiki/General_Data_Protection_Regulation\">General Data Protection Regulation</a>) prašome nenaudoti šios svetainės. </p>\n\n      <p> Jeigu šis serveris yra USA: Mūsų tinklalapis, produktai ir visi teikiami aptarnavimai yra teikiami žmonėms, kuriems yra bent 13 metų. Jeigu jums mažiau nei 13 metų, sekant COPPA reikalavimais (<a href=\"https://en.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act\">Children's Online Privacy Protection Act</a>) prašome nenaudotis šios svetainės.</p>\n\n      <p>Legalūs reikalavimai gali būti kitokie, jeigu serveris yra kitoje jurisdikcijoje.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"changes\">Pasikeitimai mūsų privatumo politikoje</h3>\n\n      <p>Jeigu mes nusprendžiame pakeisti savo privatumo politiką, mes įrašysime šiuos pakeitimus šiame tinklalapyje.</p>\n\n      <p>Šis dokumentas yra CC-BY-SA. Paskutinį kartą keistas Kovo 7, 2018.</p>\n\n      <p>Originaliai adaptuotas iš <a href=\"https://github.com/discourse/discourse\">Discourse privatumo politika</a>.</p>\n    title: \"%{instance} Naudojimosi Sąlygos ir Privatumo Politika\"\n  themes:\n    contrast: Mastodon (Didelio Kontrasto)\n    default: Mastodon (Tamsus)\n    mastodon-light: Mastodon (Šviesus)\n  two_factor_authentication:\n    code_hint: Įveskite autentikacijos aplikacijos sugeneruotą kodą kad galėtumete tęsti\n    description_html: Jeigu įjungiate <strong>dviejų veiksnių autentikaciją</strong>, prisijungiant jums reikės turėti su savimi savo telefoną, kuris jums generuos prisijungimo žetonus.\n    disable: Išjungti\n    enable: Įjungti\n    enabled: Dviejų veiksnių autentikacija įjungta\n    enabled_success: Dviejų veiksnių autentikacija sėkmingai įjungta\n    generate_recovery_codes: Sugeneruoti atkūrimo kodus\n    instructions_html: \"<strong>Nuskenuokite šį QR kodą į Google Autentikatorių arba panašią TOTP aplikaciją jūsų telefone</strong>. Nuo šiol, ši aplikacija jums generuos žetonus, kurių reikės norint prisijungti.\"\n    lost_recovery_codes: Atkūrimo kodai jums leidžia atgauti prisijungimą prie Jūsų paskyros, jeigu prarandate telefoną. Jeigu praradote atkūrimo kodus, juos galite sugeneruoti čia. Jūsų senieji atkūrimo kodai nebeveiks.\n    manual_instructions: 'Jeigu jūs negalite nuskenuoti QR kodo ir turite jį įvesti savarankiškai, štai čia yra tekstas šiam kodui:'\n    recovery_codes: Atsarginio atkūrimo kodai\n    recovery_codes_regenerated: Atkūrimo kodai sėkmingai sugeneruoti\n    recovery_instructions_html: Jeigu prarandate prieiga prie telefono, jūs galite naudoti atkūrimo kodus esančius žemiau, kad atgautumėte priega prie savo paskyros.<strong>Laikykite atkūrimo kodus saugiai</strong> Pavyzdžiui, galite norėti juos išspausdinti, ir laikyti kartu su kitais svarbiais dokumentais.\n    setup: Nustatyti\n    wrong_code: Koda netinkamas! Ar serverio laikas ir prietaiso laikas vienodi?\n  user_mailer:\n    backup_ready:\n      explanation: Jūs prašėte pilnos Mastodon paskyros atsarginės kopijos. Ji paruošta parsisiuntimui!\n      subject: Jūsų archyvas paruoštas parsisiuntimui\n      title: Archyvas išimtas\n    warning:\n      explanation:\n        disable: Kol Jūsų paskyra užšaldyta, Jūsų duomenys tebėra matomi, tačiau jūs negalite atlikti jokių veiksmu, tol, kol užšaldymas panaikintas.\n        silence: Kol Jūsų paskyra limituota, tik žmonės, kurie jus jau sekė matus Jūsų toot'us serveryje, Jūs taip pat būsite išimtas iš viešųjų sąrašų. Tačiau, kiti gali jus rasti, savo rankomis.\n        suspend: Jūsų paskyra buvo užrakinta, ir visi Jūsų toot'ai, medijos failai, buvo panaikinti iš šio serverio, ir visų kitų serverių, kur turėjote sekėjų.\n      review_server_policies: Apžvelgti serverio politiką\n      subject:\n        disable: Jūsų paskyra %{acct} buvo užšaldyta\n        none: Įspėjmas vartotojui %{acct}\n        silence: Jūsų paskyra %{acct} buvo limituota\n        suspend: Jūsų paskyra %{acct} buvo užrakinta\n      title:\n        disable: Paskyra užšaldyta\n        none: Įspėjimas\n        silence: Paskyra limituota\n        suspend: Paskyra užrakinta\n    welcome:\n      edit_profile_action: Nustatyti profilį\n      edit_profile_step: Jūs galite keisti savo profilį įkeldami profilio nuotrauką, antraštę, pakeičiant savo rodomą vardą ir dar daugiau. Jeigu norėtumete peržiurėti naujus sekėjus prieš leidžiant jiems jus sekti, galite užrakinti savo paskyrą.\n      explanation: Štai keletas patarimų Jums\n      final_action: Pradėti kelti įrašus\n      final_step: 'Pradėk kelti įrašus! Net jeigu neturi sekėjų, Jūsų viešos žinutės gali būti matomos kitų, pavyzdžiui, lokalioje laiko juostoje ir saitažodžiuose. Galite norėti prisistatyti naudojan saitąžodį #introductions.'\n      full_handle: Jūsų pilnas slapyvardis\n      full_handle_hint: Štai ką jūs sakytumėte savo draugams, kad jie galėtų jums siųsti žinutes arba just sekti iš kitų serverių.\n      review_preferences_action: Pakeisti pasirinkimus\n      review_preferences_step: Nustatykite savo pasirinkimus, tokius kaip el pašto laiškai, kuriuos norėtumėte gauti, arba kokiu privatumo lygiu norėtumėte, kad jūsų įrašai būtų talpinami, taip pat galite įjungti automatinį GIF paleidimą.\n      subject: Sveiki atvykę į Mastodon\n      tip_federated_timeline: Federuota laiko juosta yra lyg gaisrininkų žarną rodanti Mastodon tinklą. Tačiau, joje rodomi tik žmonės kurie yra sekami Jūsų kaimynų.\n      tip_following: Jūs sekate savo serverio administratorius numatyta tvarka. Norint rasti įdomesnių žmonių, patikrinkite lokalią bei federuotą laiko juostas.\n      tip_local_timeline: Lokali laiko juosta, joje rodomi žmonės iš %{instance}. Jie yra Jūsų artimiausi kaimynai!\n      tip_mobile_webapp: Jeigu Jūsų mobilioji naršyklė leidžia jums pridėti Mastodon prie namų ekrano, jūs galite gauti priminimus. Tai gali veikti kaip vietinė aplikacija!\n      tips: Patarimai\n      title: Sveiki atvykę, %{name}!\n  users:\n    follow_limit_reached: Negalite sekti daugiau nei %{limit} žmonių\n    invalid_email: Netinkamas el pašto adresas\n    invalid_otp_token: Netinkamas dviejų veiksnių kodas\n    otp_lost_help_html: Jeigu praradote prieiga prie abiejų, susisiekite su mumis per %{email}\n    seamless_external_login: Jūs esate prisijungę per išorini įrenginį, todėl slaptąžodis ir el pašto nustatymai neprieinami.\n    signed_in_as: 'Prisijungta kaip:'\n  verification:\n    explanation_html: 'Jūs galite <strong>patvirtinti savę kaip savininką nuorodų savo profilio meta duomenyse</strong>. Kad tai padarytumėte, susieta svetainė privalo turėti nuorodą atgal į Jūsų Mastodon profilį. Nuoroda atgal <strong> privalo </strong> turėti <code>rel=\"me\"</code> savybę. Teksto turinys nuorodoje nesvarbus. Štai pavyzdys:'\n    verification: Patvirtinimas\n"
  },
  {
    "path": "config/locales/lv.yml",
    "content": "---\nlv:\n  errors:\n    '403': You don't have permission to view this page.\n    '404': The page you are looking for isn't here.\n    '410': The page you were looking for doesn't exist here anymore.\n    '422': \n    '429': Throttled\n    '500': \n  invites:\n    expires_in:\n      '1800': 30 minutes\n      '21600': 6 hours\n      '3600': 1 hour\n      '43200': 12 hours\n      '604800': 1 week\n      '86400': 1 day\n"
  },
  {
    "path": "config/locales/ms.yml",
    "content": "---\nms:\n  about:\n    about_hashtag_html: Terdapat toot awam yang ditanda dengan <strong>#%{hashtag}</strong>. Anda boleh berinteraksi dengan mereka jika anda mempunyai akaun di mana-mana dunia persekutuan Mastodon.\n    about_mastodon_html: Mastodon ialah rangkaian sosial berasaskan protokol web terbuka dan perisian percuma bersumber terbuka. Ianya tak terpusat seperti emel.\n    about_this: Mengenai Kami\n    administered_by: 'Ditadbir oleh:'\n    apps: Aplikasi mudah alih\n    contact: Hubungi kami\n    contact_missing: Tidak ditetapkan\n    contact_unavailable: Tidak tersedia\n    documentation: Pendokumenan\n    extended_description_html: |\n      <h3>Tempat sesuai untuk peraturan</h3>\n      <p>Kenyataan penuh masih belum ditetapkan.</p>\n    generic_description: \"%{domain} ialah salah sebuah pelayan dalam rangkaian Mastodon\"\n    hosted_on: Mastodon dihoskan di %{domain}\n    learn_more: Ketahui lebih lanjut\n    privacy_policy: Polisi privasi\n    source_code: Kod sumber\n    status_count_after:\n      other: status\n    status_count_before: Telah menulis\n    terms: Terma perkhidmatan\n    user_count_after:\n      other: pengguna\n    user_count_before: Rumah kepada\n    what_is_mastodon: Apakah itu Mastodon?\n  accounts:\n    choices_html: 'Pilihan %{name}:'\n    follow: Ikut\n    followers:\n      other: Pengikut\n    following: Mengikuti\n    joined: Sertai pada %{date}\n    link_verified_on: Pemilikan pautan ini diperiksa pada %{date}\n    moved_html: \"%{name} telah berpindah ke %{new_profile_link}:\"\n    network_hidden: Maklumat ini tidak tersedia\n    nothing_here: Tiada apa-apa di sini!\n    people_followed_by: Orang yang %{name} ikuti\n    people_who_follow: Orang yang mengikut %{name}\n    pin_errors:\n      following: Anda mestilah sudah mengikuti orang yang anda ingin syorkan\n    posts:\n      other: Toot\n    posts_tab_heading: Toot\n    posts_with_replies: Toot dan maklum balas\n    reserved_username: Nama pengguna ini terpelihara\n    roles:\n      moderator: Pengawal\n    unfollow: Nyahikut\n  admin:\n    account_moderation_notes:\n      create: Tinggalkan nota\n      created_msg: Nota kawalan telah berjaya dicipta!\n      delete: Padam\n      destroyed_msg: Nota kawalan telah berjaya dipadam!\n    accounts:\n      are_you_sure: Anda pasti?\n      change_email:\n        changed_msg: Emel akaun telah berjaya ditukar!\n        current_email: Emel Semasa\n        label: Tukar Emel\n        new_email: Emel Baru\n        submit: Tukar Emel\n        title: Tukar Emel untuk %{username}\n      confirm: Sahkan\n      confirmed: Disahkan\n      confirming: Mengesahkan\n      demote: Turunkan pangkat\n      disable: Lumpuhkan\n      disable_two_factor_authentication: Lumpuhkan 2FA\n      disabled: Dilumpuhkan\n      display_name: Nama paparan\n      edit: Tukar\n      email: Emel\n      email_status: Status Emel\n      enable: Bolehkan\n      enabled: Dibolehkan\n      feed_url: Suapan URL\n      followers: Pengikut\n      followers_url: URL Pengikut\n      follows: Mengikuti\n      inbox_url: URL mesej masuk\n      ip: Alamat IP\n      location:\n        all: Semua\n        local: Tempatan\n        remote: Jarak Jauh\n        title: Kedudukan\n      login_status: Status log masuk\n      media_attachments: Lampiran media\n      memorialize: Tukarkan menjadi akaun peringatan\n      moderation:\n        all: Semua\n        silenced: Disenyapkan\n        suspended: Digantungkan\n        title: Kawalan\n      moderation_notes: Nota kawalan\n      most_recent_activity: Aktiviti terbaru\n      most_recent_ip: IP terbaru\n      no_limits_imposed: Tiada had dikuatkuasakan\n      not_subscribed: Tiada langganan\n      outbox_url: URL mesej keluar\n      perform_full_suspension: Gantung\n      profile_url: URL profil\n      promote: Naikkan pangkat\n      protocol: Protokol\n      public: Awam\n      push_subscription_expires: Langganan PuSH tamat tempoh\n      redownload: Segarkan semula avatar\n      remove_avatar: Buang avatar\n      resend_confirmation:\n        already_confirmed: Pengguna ini telah disahkan\n        send: Hantar semula emel pengesahan\n        success: Emel pengesahan telah berjaya dihantar!\n      reset: Set semula\n      reset_password: Set semula kata laluan\n      resubscribe: Langgan semula\n      role: Kebenaran\n      roles:\n        admin: Pentadbir\n        moderator: Pengawal\n        staff: Kakitangan\n        user: Pengguna\n      salmon_url: URL Salmon\n      search: Cari\n      shared_inbox_url: URL Peti Masuk Berkongsi\n      show:\n        created_reports: Laporan yang dicipta oleh akaun ini\n        targeted_reports: Laporan yang dicipta berkaitan akaun ini\n      silence: Senyap\n      silenced: Disenyapkan\n      statuses: Status\n      subscribe: Langgan\n      suspended: Digantung\n      title: Akaun\n      unconfirmed_email: Emel Belum Disahkan\n      undo_silenced: Buang senyap\n      undo_suspension: Buang penggantungan\n      unsubscribe: Buang langganan\n      username: Nama pengguna\n    action_logs:\n      actions:\n        assigned_to_self_report: \"%{name} memberikan laporan %{target} kepada diri mereka sendiri\"\n        change_email_user: \"%{name} menukar alamat emel pengguna %{target}\"\n        confirm_user: \"%{name} mengesahkan alamat emel pengguna %{target}\"\n        create_custom_emoji: \"%{name} memuat naik emoji baru %{target}\"\n        create_domain_block: \"%{name} menyekat domain %{target}\"\n        create_email_domain_block: \"%{name} menyenaraihitamkan domain emel %{target}\"\n        demote_user: \"%{name} menurunkan pangkat pengguna %{target}\"\n        destroy_custom_emoji: \"%{name} membuang emoji %{target}\"\n        destroy_domain_block: \"%{name} membuang sekatan domain %{target}\"\n        destroy_email_domain_block: \"%{name} menyenaraiputihkan domain emel %{target}\"\n        destroy_status: \"%{name} membuang status oleh %{target}\"\n        disable_2fa_user: \"%{name} melumpuhkan keperluan dua faktor untuk pengguna %{target}\"\n        disable_custom_emoji: \"%{name} melumpuhkan emoji %{target}\"\n        disable_user: \"%{name} melumpuhkan log masuk untuk pengguna %{target}\"\n        enable_custom_emoji: \"%{name} membolehkan emoji %{target}\"\n        enable_user: \"%{name} membolehkan log masuk untuk pengguna %{target}\"\n        memorialize_account: \"%{name} menukarkan akaun %{target} menjadi halaman peringatan\"\n        promote_user: \"%{name} menaikkan pangkat pengguna %{target}\"\n        remove_avatar_user: \"%{name} membuang avatar pengguna %{target}\"\n        reopen_report: \"%{name} membuka semula laporan %{target}\"\n        reset_password_user: \"%{name} set semula kata laluan pengguna %{target}\"\n        resolve_report: \"%{name} menyelesaikan laporan %{target}\"\n        silence_account: \"%{name} menyenyapkan akaun %{target}\"\n        suspend_account: \"%{name} menggantung akaun %{target}\"\n        unassigned_report: \"%{name} menyahtugaskan laporan %{target}\"\n        unsilence_account: \"%{name} menyahsenyapkan akaun %{target}\"\n        unsuspend_account: \"%{name} menyahgantungkan akaun %{target}\"\n        update_custom_emoji: \"%{name} mengemaskini emoji %{target}\"\n        update_status: \"%{name} mengemaskini status oleh %{target}\"\n      deleted_status: \"(status telah dipadam)\"\n      title: Log audit\n    custom_emojis:\n      copied_msg: Telah berjaya mencipta salinan tempatan emoji\n      copy: Salin\n      copy_failed_msg: Tidak dapat membuat salinan tempatan emoji tersebut\n      created_msg: Emoji berjaya dicipta!\n      delete: Padam\n      destroyed_msg: Emoji berjaya dipadam!\n      disable: Lumpuhkan\n      disabled_msg: Emoji tersebut berjaya dilumpuhkan\n      enable: Bolehkan\n      enabled_msg: Emoji tersebut berjaya dibolehkan\n      image_hint: PNG, maksimum 50KB\n      listed: Disenaraikan\n      new:\n        title: Tambah emoji sendiri baru\n      overwrite: Tulis ganti\n      shortcode: Kod pendek\n      shortcode_hint: Sekurang-kurangnya 2 aksara, hanya aksara angka abjad dan garis bawah\n      title: Emoji sendiri\n      unlisted: Tidak disenaraikan\n      update_failed_msg: Tidak boleh mengemaskini emoji tersebut\n      updated_msg: Emoji berjaya dikemaskini!\n      upload: Muat naik\n    dashboard:\n      backlog: tugasan tunggakan\n      config: Tatarajah\n      feature_deletions: Pemadaman akaun\n      feature_invites: Pautan undangan\n      feature_registrations: Pendaftaran\n      feature_relay: Geganti persekutuan\n      features: Ciri-ciri\n      hidden_service: Persekutuan dengan perkhidmatan tersembunyi\n      open_reports: laporan belum selesai\n      recent_users: Pengguna terbaru\n      search: Carian teks penuh\n      single_user_mode: Mod pengguna tunggal\n      software: Perisian\n      space: Kegunaan ruang\n      title: Papan pemuka\n      total_users: pengguna keseluruhannya\n      trends: Trend\n      week_interactions: interaksi minggu ini\n      week_users_active: aktif minggu ini\n      week_users_new: pengguna minggu ini\n    domain_blocks:\n      add_new: Tambah\n      created_msg: Sekatan domain sedang diproses\n      destroyed_msg: Sekatan domain telah dibatalkan\n      new:\n        create: Cipta sekatan\n        hint: Sekatan domain tidak akan menghindarkan penciptaan entri akaun dalam pangkalan data, tetapi akan diberikan kaedah kawalan khusus tertentu pada akaun-akaun tersebut secara retroaktif dan automatik.\n        severity:\n          desc_html: \"<strong>Senyapkan</strong> akan membuatkan hantaran akaun tidak kelihatan kepada sesiapa yang tidak mengikut mereka. <strong>Gantungkan</strong> akan membuang semua kandungan, media, dan data profil akaun tersebut. Gunakan <strong>Tiada</strong> jika anda hanya ingin menolak fail media.\"\n          noop: Tiada\n          silence: Senyapkan\n          suspend: Gantungkan\n        title: Sekatan domain baru\n      reject_media: Tolak fail media\n      reject_media_hint: Buang fail media yang disimpan di sini dan menolak sebarang muat turun pada masa depan. Tidak berkaitan dengan penggantungan\n      reject_reports: Tolak laporan\n      reject_reports_hint: Abaikan semua laporan daripada domain ini. Tidak dikira untuk penggantungan\n      show:\n        affected_accounts:\n          other: \"%{count} akaun dalam pangkalan data menerima kesan\"\n        retroactive:\n          silence: Buang penyenyapan semua akaun sedia ada daripada domain ini\n          suspend: Buang penggantungan semua akaun sedia ada daripada domain ini\n        title: Buang sekatan domain %{domain}\n        undo: Buang\n      undo: Buang\n    email_domain_blocks:\n      add_new: Tambah\n      created_msg: Berjaya menambah domain emel ke dalam senarai hitam\n      delete: Padam\n      destroyed_msg: Berjaya memadam domain emel daripada senarai hitam\n      new:\n        create: Tambah domain\n        title: Entri senarai hitam emel baru\n      title: Senarai hitam emel\n    instances:\n      title: Tika diketahui\n    invites:\n      deactivate_all: Nyahaktifkan semua\n      filter:\n        all: Semua\n        available: Tersedia\n        expired: Tamat tempoh\n        title: Tapis\n      title: Undangan\n    relays:\n      add_new: Tambah geganti baru\n      delete: Padam\n      description_html: \"<strong>Geganti persekutuan</strong> ialah pelayan perantara yang saling menukar toot awam dalam jumlah yang banyak di antara pelayan yang melanggan ia dan menerbitkan kepada ia. <strong>Ia boleh bantu pelayan kecil dan sederhana untuk menemui kandungan daripada dunia persekutuan Mastodon</strong>, yang mana jika tidak digunakan akan memerlukan pengguna tempatan mengikut orang lain di pelayan jarak jauh secara manual.\"\n      disable: Lumpuhkan\n      disabled: Dilumpuhkan\n      enable: Bolehkan\n      enable_hint: Apabila dibolehkan, pelayan anda akan melanggan kesemua toot awam daripada geganti ini, dan akan mula menghantar toot awam pelayan ini kepada ia.\n      enabled: Dibolehkan\n      inbox_url: URL geganti\n      pending: Menunggu persetujuan geganti\n      save_and_enable: Simpan dan bolehkan\n      setup: Tetapkan sambungan geganti\n      title: Geganti\n    report_notes:\n      created_msg: Nota laporan berjaya dicipta!\n      destroyed_msg: Nota laporan berjaya dipadam!\n    reports:\n      account:\n        note: nota\n        report: laporan\n      action_taken_by: Tindakan oleh\n      are_you_sure: Anda pasti?\n      assign_to_self: Berikan pada saya\n      assigned: Pengawal yang menerima\n      comment:\n        none: Tiada\n      created_at: Dilaporkan\n      mark_as_resolved: Tanda sebagai sudah selesai\n      mark_as_unresolved: Tanda sebagai belum selesai\n      notes:\n        create: Tambah nota\n        create_and_resolve: Selesaikan dengan nota\n        placeholder: Terangkan tindakan apa yang telah diambil, atau sebarang kemas kini lain yang berkaitan...\n  errors:\n    '403': You don't have permission to view this page.\n    '404': The page you are looking for isn't here.\n    '410': The page you were looking for doesn't exist here anymore.\n    '422': \n    '429': Throttled\n    '500': \n  exports:\n    archive_takeout:\n      in_progress: Mengkompil arkib anda...\n  invites:\n    expires_in:\n      '1800': 30 minutes\n      '21600': 6 hours\n      '3600': 1 hour\n      '43200': 12 hours\n      '604800': 1 week\n      '86400': 1 day\n  notification_mailer:\n    digest:\n      title: Ketika anda tiada di sini...\n  users:\n    follow_limit_reached: Anda tidak boleh mengikut lebih daripada %{limit} orang\n"
  },
  {
    "path": "config/locales/nl.yml",
    "content": "---\nnl:\n  about:\n    about_hashtag_html: Dit zijn openbare toots die getagged zijn met <strong>#%{hashtag}</strong>. Je kunt er op reageren of iets anders mee doen als je op Mastodon (of ergens anders in de fediverse) een account hebt.\n    about_mastodon_html: Mastodon is een sociaal netwerk dat gebruikt maakt van open webprotocollen en vrije software. Het is net zoals e-mail gedecentraliseerd.\n    about_this: Over deze server\n    active_count_after: actief\n    active_footnote: Actieve gebruikers per maand (MAU)\n    administered_by: 'Beheerd door:'\n    api: API\n    apps: Mobiele apps\n    apps_platforms: Gebruik Mastodon op iOS, Android en op andere platformen\n    browse_directory: Gebruikersgids doorbladeren en op interesses filteren\n    browse_public_posts: Livestream van openbare Mastodonberichten bekijken\n    contact: Contact\n    contact_missing: Niet ingesteld\n    contact_unavailable: n.v.t\n    discover_users: Gebruikers ontdekken\n    documentation: Documentatie\n    extended_description_html: |\n      <h3>Een goede plek voor richtlijnen</h3>\n      <p>De uitgebreide omschrijving is nog niet ingevuld.</p>\n    federation_hint_html: Met een account op %{instance} ben je in staat om mensen die zich op andere Mastodonservers (en op andere plekken) bevinden te volgen.\n    generic_description: \"%{domain} is een server in het Mastodonnetwerk\"\n    get_apps: Mobiele apps\n    hosted_on: Mastodon op %{domain}\n    learn_more: Meer leren\n    privacy_policy: Privacybeleid\n    see_whats_happening: Kijk wat er aan de hand is\n    server_stats: 'Serverstatistieken:'\n    source_code: Broncode\n    status_count_after:\n      one: toot\n      other: toots\n    status_count_before: Zij schreven\n    tagline: Vrienden volgen en nieuwe ontdekken\n    terms: Gebruiksvoorwaarden\n    user_count_after:\n      one: gebruiker\n      other: gebruikers\n    user_count_before: Thuisbasis van\n    what_is_mastodon: Wat is Mastodon?\n  accounts:\n    choices_html: 'Aanbevelingen van %{name}:'\n    follow: Volgen\n    followers:\n      one: Volger\n      other: Volgers\n    following: Volgend\n    joined: Geregistreerd in %{date}\n    last_active: laatst actief\n    link_verified_on: Eigendom van deze link is gecontroleerd op %{date}\n    media: Media\n    moved_html: \"%{name} is verhuisd naar %{new_profile_link}:\"\n    network_hidden: Deze informatie is niet beschikbaar\n    nothing_here: Hier is niets!\n    people_followed_by: Mensen die %{name} volgen\n    people_who_follow: Mensen die %{name} volgen\n    pin_errors:\n      following: Je moet dit account wel al volgen, alvorens je het kan aanbevelen\n    posts:\n      one: Toot\n      other: Toots\n    posts_tab_heading: Toots\n    posts_with_replies: Toots en reacties\n    reserved_username: Deze gebruikersnaam is gereserveerd\n    roles:\n      admin: Beheerder\n      bot: Bot\n      moderator: Moderator\n    unavailable: Profiel niet beschikbaar\n    unfollow: Ontvolgen\n  admin:\n    account_actions:\n      action: Actie uitvoeren\n      title: Moderatieactie op %{acct} uitvoeren\n    account_moderation_notes:\n      create: Laat een opmerking achter\n      created_msg: Aanmaken van opmerking voor moderatoren geslaagd!\n      delete: Verwijderen\n      destroyed_msg: Verwijderen van opmerking voor moderatoren geslaagd!\n    accounts:\n      approve: Goedkeuren\n      approve_all: Alles goedkeuren\n      are_you_sure: Weet je het zeker?\n      avatar: Avatar\n      by_domain: Domein\n      change_email:\n        changed_msg: E-mailadres van account succesvol veranderd!\n        current_email: Huidig e-mailadres\n        label: E-mailadres wijzigen\n        new_email: Nieuw e-mailadres\n        submit: E-mailadres veranderen\n        title: E-mailadres wijzigen voor %{username}\n      confirm: Bevestigen\n      confirmed: Bevestigd\n      confirming: Bevestiging\n      deleted: Verwijderd\n      demote: Degraderen\n      disable: Uitschakelen\n      disable_two_factor_authentication: 2FA uitschakelen\n      disabled: Uitgeschakeld\n      display_name: Weergavenaam\n      domain: Domein\n      edit: Bewerken\n      email: E-mail\n      email_status: E-mailstatus\n      enable: Inschakelen\n      enabled: Ingeschakeld\n      feed_url: Feed-URL\n      followers: Volgers\n      followers_url: Volgers-URL\n      follows: Volgt\n      header: Omslagfoto\n      inbox_url: Inbox-URL\n      invited_by: Uitgenodigd door\n      ip: IP\n      joined: Geregistreerd in\n      location:\n        all: Alles\n        local: Lokaal\n        remote: Extern\n        title: Locatie\n      login_status: Loginstatus\n      media_attachments: Mediabijlagen\n      memorialize: In gedenkpagina veranderen\n      moderation:\n        active: Actief\n        all: Alles\n        pending: In afwachting\n        silenced: Genegeerd\n        suspended: Opgeschort\n        title: Moderatie\n      moderation_notes: Opmerkingen voor moderatoren\n      most_recent_activity: Laatst actief\n      most_recent_ip: Laatst gebruikt IP-adres\n      no_account_selected: Er zijn geen accounts veranderd, omdat er geen een was geselecteerd\n      no_limits_imposed: Geen limieten ingesteld\n      not_subscribed: Niet geabonneerd\n      outbox_url: Outbox-URL\n      pending: Moet nog beoordeeld worden\n      perform_full_suspension: Opschorten\n      profile_url: Profiel-URL\n      promote: Promoveren\n      protocol: Protocol\n      public: Openbaar\n      push_subscription_expires: PuSH-abonnement verloopt op\n      redownload: Profiel vernieuwen\n      reject: Afkeuren\n      reject_all: Alles afkeuren\n      remove_avatar: Avatar verwijderen\n      remove_header: Omslagfoto verwijderen\n      resend_confirmation:\n        already_confirmed: Deze gebruiker is al bevestigd\n        send: Verzend bevestigingsmail opnieuw\n        success: Bevestigingsmail succesvol verzonden!\n      reset: Opnieuw\n      reset_password: Wachtwoord opnieuw instellen\n      resubscribe: Opnieuw abonneren\n      role: Bevoegdheden\n      roles:\n        admin: Beheerder\n        moderator: Moderator\n        staff: Medewerkers\n        user: Gebruiker\n      salmon_url: Salmon-URL\n      search: Zoeken\n      shared_inbox_url: Gedeelde inbox-URL\n      show:\n        created_reports: Aangemaakte rapportages\n        targeted_reports: Door anderen gerapporteerd\n      silence: Negeren\n      silenced: Genegeerd\n      statuses: Toots\n      subscribe: Abonneren\n      suspended: Opgeschort\n      time_in_queue: \"%{time} in de wachtrij\"\n      title: Accounts\n      unconfirmed_email: Onbevestigd e-mailadres\n      undo_silenced: Niet langer negeren\n      undo_suspension: Niet langer opschorten\n      unsubscribe: Opzeggen\n      username: Gebruikersnaam\n      warn: Waarschuwen\n      web: Webapp\n    action_logs:\n      actions:\n        assigned_to_self_report: \"%{name} heeft rapportage %{target} aan zichzelf toegewezen\"\n        change_email_user: \"%{name} veranderde het e-mailadres van gebruiker %{target}\"\n        confirm_user: E-mailadres van gebruiker %{target} is door %{name} bevestigd\n        create_account_warning: \"%{name} verzond een waarschuwing naar %{target}\"\n        create_custom_emoji: Nieuwe emoji %{target} is door %{name} geüpload\n        create_domain_block: Domein %{target} is door %{name} geblokkeerd\n        create_email_domain_block: E-maildomein %{target} is door %{name} op de zwarte lijst geplaatst\n        demote_user: Gebruiker %{target} is door %{name} gedegradeerd\n        destroy_custom_emoji: \"%{name} verwijderde emoji %{target}\"\n        destroy_domain_block: Domein %{target} is door %{name} gedeblokkeerd\n        destroy_email_domain_block: E-maildomein %{target} is door %{name} op de witte lijst geplaatst\n        destroy_status: Toot van %{target} is door %{name} verwijderd\n        disable_2fa_user: Vereisten tweestapsverificatie van %{target} zijn door %{name} uitgeschakeld\n        disable_custom_emoji: Emoji %{target} is door %{name} uitgeschakeld\n        disable_user: Inloggen voor %{target} is door %{name} uitgeschakeld\n        enable_custom_emoji: Emoji %{target} is door %{name} ingeschakeld\n        enable_user: Inloggen voor %{target} is door %{name} ingeschakeld\n        memorialize_account: Account %{target} is door %{name} in een gedenkpagina veranderd\n        promote_user: Gebruiker %{target} is door %{name} gepromoveerd\n        remove_avatar_user: \"%{name} verwijderde de avatar van %{target}\"\n        reopen_report: \"%{name} heeft rapportage %{target} heropend\"\n        reset_password_user: Wachtwoord van gebruiker %{target} is door %{name} opnieuw ingesteld\n        resolve_report: \"%{name} heeft rapportage %{target} opgelost\"\n        silence_account: Account %{target} is door %{name} genegeerd\n        suspend_account: Account %{target} is door %{name} opgeschort\n        unassigned_report: \"%{name} heeft het toewijzen van rapportage %{target} ongedaan gemaakt\"\n        unsilence_account: Negeren van account %{target} is door %{name} opgeheven\n        unsuspend_account: Opschorten van account %{target} is door %{name} opgeheven\n        update_custom_emoji: Emoji %{target} is door %{name} bijgewerkt\n        update_status: De toots van %{target} zijn door %{name} bijgewerkt\n      deleted_status: \"(verwijderde toot}\"\n      title: Auditlog\n    custom_emojis:\n      by_domain: Domein\n      copied_msg: Lokale kopie van emoji maken geslaagd\n      copy: Kopiëren\n      copy_failed_msg: Kan geen lokale kopie van deze emoji maken\n      created_msg: Aanmaken van emoji geslaagd!\n      delete: Verwijderen\n      destroyed_msg: Verwijderen van emoji geslaagd!\n      disable: Uitschakelen\n      disabled_msg: Uitschakelen van deze emoji geslaagd\n      emoji: Emoji\n      enable: Inschakelen\n      enabled_msg: Inschakelen van deze emoji geslaagd\n      image_hint: PNG van max. 50KB\n      listed: Weergegeven\n      new:\n        title: Lokale emoji toevoegen\n      overwrite: Overschrijven\n      shortcode: Verkorte code\n      shortcode_hint: Tenminste 2 tekens (alleen alfanumeriek en underscores)\n      title: Lokale emoji’s\n      unlisted: Niet weergegeven\n      update_failed_msg: Deze emoji kon niet worden bijgewerkt\n      updated_msg: Bijwerken van emoji is geslaagd!\n      upload: Uploaden\n    dashboard:\n      backlog: achterstallige taken\n      config: Configuratie\n      feature_deletions: Verwijderen van account\n      feature_invites: Uitnodigingen\n      feature_profile_directory: Gebruikersgids\n      feature_registrations: Registraties\n      feature_relay: Federatierelay\n      feature_timeline_preview: Voorvertoning van tijdlijn\n      features: Functies\n      hidden_service: Federatie met verborgen diensten\n      open_reports: onopgeloste rapportages\n      recent_users: Recente gebruikers\n      search: In volledige tekst zoeken\n      single_user_mode: Modus voor één gebruiker\n      software: Software\n      space: Ruimtegebruik\n      title: Dashboard\n      total_users: gebruikers in totaal\n      trends: Trends\n      week_interactions: interacties deze week\n      week_users_active: actieve gebruikers deze week\n      week_users_new: nieuwe gebruikers deze week\n    domain_blocks:\n      add_new: Nieuwe domeinblokkade toevoegen\n      created_msg: Domeinblokkade wordt nu verwerkt\n      destroyed_msg: Domeinblokkade is ongedaan gemaakt\n      domain: Domein\n      existing_domain_block_html: Jij hebt al strengere beperkingen opgelegd aan %{name}, je moet het domein eerst <a href=\"%{unblock_url}\">deblokkeren</a>.\n      new:\n        create: Blokkade aanmaken\n        hint: Een domeinblokkade voorkomt niet dat accountgegevens van dit domein aan de database worden toegevoegd, maar dat er met terugwerkende kracht en automatisch bepaalde moderatiemethoden op deze accounts worden toegepast.\n        severity:\n          desc_html: \"<strong>Negeren</strong> zorgt ervoor dat berichten van accounts van dit domein voor iedereen onzichtbaar zijn, behalve als een account wordt gevolgd. <strong>Opschorten</strong> zorgt ervoor dat alle berichten, media en profielgegevens van accounts van dit domein worden verwijderd. Gebruik <strong>Geen</strong> wanneer je alleen mediabestanden wilt weigeren.\"\n          noop: Geen\n          silence: Negeren\n          suspend: Opschorten\n        title: Nieuwe domeinblokkade\n      reject_media: Mediabestanden weigeren\n      reject_media_hint: Verwijderd lokaal opgeslagen mediabestanden en weigert deze in de toekomst te downloaden. Irrelevant voor opgeschorte domeinen\n      reject_reports: Rapportages weigeren\n      reject_reports_hint: Alle rapportages die vanaf dit domein komen negeren. Irrelevant voor opgeschorte domeinen\n      rejecting_media: mediabestanden worden geweigerd\n      rejecting_reports: rapportages worden geweigerd\n      severity:\n        silence: genegeerd\n        suspend: opgeschort\n      show:\n        affected_accounts:\n          one: Eén account in de database aangepast\n          other: \"%{count} accounts in de database aangepast\"\n        retroactive:\n          silence: Alle genegeerde accounts van dit domein niet langer negeren\n          suspend: Alle opgeschorte accounts van dit domein niet langer opschorten\n        title: Domeinblokkade voor %{domain} ongedaan maken\n        undo: Ongedaan maken\n      undo: domeinblokkade ongedaan maken\n    email_domain_blocks:\n      add_new: Nieuwe toevoegen\n      created_msg: Blokkeren e-maildomein geslaagd\n      delete: Verwijderen\n      destroyed_msg: Deblokkeren e-maildomein geslaagd\n      domain: Domein\n      new:\n        create: Blokkeren\n        title: Nieuw e-maildomein blokkeren\n      title: E-maildomeinen blokkeren\n    followers:\n      back_to_account: Terug naar account\n      title: Volgers van %{acct}\n    instances:\n      by_domain: Domein\n      delivery_available: Bezorging is mogelijk\n      known_accounts:\n        one: \"%{count} bekend account\"\n        other: \"%{count} bekende accounts\"\n      moderation:\n        all: Alles\n        limited: Beperkt\n        title: Moderatie\n      title: Andere domeinen\n      total_blocked_by_us: Door ons geblokkeerd\n      total_followed_by_them: Door hun gevolgd\n      total_followed_by_us: Door ons gevolgd\n      total_reported: Rapportages over hun\n      total_storage: Mediabijlagen\n    invites:\n      deactivate_all: Alles deactiveren\n      filter:\n        all: Alles\n        available: Beschikbaar\n        expired: Verlopen\n        title: Filter\n      title: Uitnodigingen\n    pending_accounts:\n      title: Accounts in afwachting (%{count})\n    relays:\n      add_new: Nieuwe relayserver toevoegen\n      delete: Verwijderen\n      description_html: Een <strong>federatierelay</strong> is een tussenliggende server die grote hoeveelheden openbare toots uitwisselt tussen servers die zich hierop hebben geabonneerd. <strong>Het kan kleine en middelgrote servers helpen om content uit de fediverse te ontdekken</strong>, waarvoor anders lokale gebruikers handmatig mensen van externe servers moeten volgen.\n      disable: Uitschakelen\n      disabled: Uitgeschakeld\n      enable: Inschakelen\n      enable_hint: Eenmaal ingeschakeld gaat jouw server zich op alle openbare toots van deze relayserver abonneren en stuurt het de openbare toots van jouw server naar de relayserver.\n      enabled: Ingeschakeld\n      inbox_url: Relay-URL\n      pending: Aan het wachten op toestemming van de relayserver\n      save_and_enable: Opslaan en inschakelen\n      setup: Een verbinding met een relayserver maken\n      status: Status\n      title: Relayservers\n    report_notes:\n      created_msg: Opmerking bij rapportage succesvol aangemaakt!\n      destroyed_msg: Opmerking bij rapportage succesvol verwijderd!\n    reports:\n      account:\n        note: opmerking\n        report: rapportage\n      action_taken_by: Actie uitgevoerd door\n      are_you_sure: Weet je het zeker?\n      assign_to_self: Aan mij toewijzen\n      assigned: Toegewezen moderator\n      comment:\n        none: Geen\n      created_at: Gerapporteerd op\n      mark_as_resolved: Markeer als opgelost\n      mark_as_unresolved: Markeer als onopgelost\n      notes:\n        create: Opmerking toevoegen\n        create_and_resolve: Oplossen met opmerking\n        create_and_unresolve: Heropenen met opmerking\n        delete: Verwijderen\n        placeholder: Beschrijf welke acties zijn ondernomen of andere gerelateerde opmerkingen…\n      reopen: Rapportage heropenen\n      report: 'Rapportage #%{id}'\n      reported_account: Gerapporteerde account\n      reported_by: Gerapporteerd door\n      resolved: Opgelost\n      resolved_msg: Rapportage succesvol opgelost!\n      status: Toot\n      title: Rapportages\n      unassign: Niet langer toewijzen\n      unresolved: Onopgelost\n      updated_at: Bijgewerkt\n    settings:\n      activity_api_enabled:\n        desc_html: Wekelijks overzicht van de hoeveelheid lokale toots, actieve gebruikers en nieuwe registraties\n        title: Statistieken over gebruikersactiviteit publiceren\n      bootstrap_timeline_accounts:\n        desc_html: Meerdere gebruikersnamen met komma's scheiden. Alleen lokale en niet opgeschorte accounts werken. Laat leeg voor alle lokale beheerders.\n        title: Standaard te volgen accounts voor nieuwe gebruikers\n      contact_information:\n        email: Vul een openbaar gebruikt e-mailadres in\n        username: Vul een gebruikersnaam in\n      custom_css:\n        desc_html: Het uiterlijk van deze server met CSS aanpassen\n        title: Aangepaste CSS\n      hero:\n        desc_html: Wordt op de voorpagina getoond. Tenminste 600x100px aanbevolen. Wanneer dit niet is ingesteld wordt de thumbnail van de Mastodonserver getoond\n        title: Hero-afbeelding\n      mascot:\n        desc_html: Wordt op meerdere pagina's weergegeven. Tenminste 293×205px aanbevolen. Wanneer dit niet is ingesteld wordt de standaardmascotte getoond\n        title: Mascotte-afbeelding\n      max_bio_chars:\n        desc_html: 'Maximum aantal tekens toegestaan in bio (standaard: 500)'\n        title: Max tekens in bio\n      max_toot_chars:\n        desc_html: 'Maximum aantal tekens in toot (standaard: 500)'\n        title: Max tekens in toot\n      peers_api_enabled:\n        desc_html: Domeinnamen die deze server in de fediverse is tegengekomen\n        title: Lijst van bekende servers publiceren\n      preview_sensitive_media:\n        desc_html: Linkvoorvertoningen op andere websites hebben een thumbnail, zelfs als een afbeelding of video als gevoelig is gemarkeerd\n        title: Gevoelige afbeeldingen en video's in OpenGraph-voorvertoningen tonen\n      profile_directory:\n        desc_html: Gebruikers toestaan om vindbaar te zijn\n        title: Gebruikersgids inschakelen\n      registrations:\n        closed_message:\n          desc_html: Wordt op de voorpagina weergegeven wanneer registratie van nieuwe accounts is uitgeschakeld<br>En ook hier kan je HTML gebruiken\n          title: Bericht wanneer registratie is uitgeschakeld\n        deletion:\n          desc_html: Toestaan dat iedereen hun eigen account kan verwijderen\n          title: Verwijderen account toestaan\n        min_invite_role:\n          disabled: Niemand\n          title: Uitnodigingen toestaan door\n      registrations_mode:\n        modes:\n          approved: Goedkeuring vereist om te kunnen registreren\n          none: Niemand kan zich registreren\n          open: Iedereen kan zich registreren\n        title: Registratiemodus\n      show_known_fediverse_at_about_page:\n        desc_html: Wanneer ingeschakeld wordt de globale tijdlijn op de voorpagina getoond en wanneer uitgeschakeld de lokale tijdljn.\n        title: De globale tijdlijn op de voorpagina tonen\n      show_staff_badge:\n        desc_html: Medewerkersbadge op profielpagina tonen\n        title: Medewerkersbadge tonen\n      site_description:\n        desc_html: Introductie-alinea voor de API. Beschrijf wat er speciaal is aan deze server en andere zaken die van belang zijn. Je kan HTML gebruiken, zoals <code>&lt;a&gt;</code> en <code>&lt;em&gt;</code>.\n        title: Omschrijving Mastodonserver (API)\n      site_description_extended:\n        desc_html: Een goede plek voor je gedragscode, regels, richtlijnen en andere zaken die jouw server uniek maken. Je kan ook hier HTML gebruiken\n        title: Uitgebreide omschrijving Mastodonserver\n      site_short_description:\n        desc_html: Dit wordt gebruikt op de voorpagina, in de zijbalk op profielpagina's en als metatag in de paginabron. Beschrijf in één alinea wat Mastodon is en wat deze server speciaal maakt.\n        title: Omschrijving Mastodonserver (website)\n      site_terms:\n        desc_html: Je kan hier jouw eigen privacybeleid, gebruiksvoorwaarden en ander juridisch jargon kwijt. Je kan HTML gebruiken\n        title: Aangepaste gebruiksvoorwaarden\n      site_title: Naam Mastodonserver\n      thumbnail:\n        desc_html: Gebruikt als voorvertoning voor OpenGraph en de API. 1200x630px aanbevolen\n        title: Thumbnail Mastodonserver\n      timeline_preview:\n        desc_html: Toon een openbare tijdlijn op de voorpagina\n        title: Tijdlijn op de voorpagina tonen\n      title: Server-instellingen\n    statuses:\n      back_to_account: Terug naar accountpagina\n      batch:\n        delete: Verwijderen\n        nsfw_off: Als niet gevoelig markeren\n        nsfw_on: Als gevoelig markeren\n      failed_to_execute: Uitvoeren mislukt\n      media:\n        title: Media\n      no_media: Geen media\n      no_status_selected: Er werden geen toots gewijzigd, omdat er geen enkele werd geselecteerd\n      title: Toots van account\n      with_media: Met media\n    subscriptions:\n      callback_url: Callback-URL\n      confirmed: Bevestigd\n      expires_in: Verloopt over\n      last_delivery: Laatste bezorging\n      title: WebSub\n      topic: Account\n    tags:\n      accounts: Accounts\n      hidden: Verborgen\n      hide: Niet in gebruikersgids tonen\n      name: Hashtag\n      title: Hashtags\n      unhide: In gebruikersgids tonen\n      visible: Zichtbaar\n    title: Beheer\n    warning_presets:\n      add_new: Nieuwe toevoegen\n      delete: Verwijderen\n      edit: Bewerken\n      edit_preset: Voorinstelling van waarschuwing bewerken\n      title: Voorinstellingen van waarschuwingen beheren\n  admin_mailer:\n    new_pending_account:\n      body: Zie hieronder de details van het nieuwe account. Je kunt de aanvraag goedkeuren of afkeuren.\n      subject: Er dient een nieuw account op %{instance} te worden beoordeeld (%{username})\n    new_report:\n      body: \"%{reporter} heeft %{target} gerapporteerd\"\n      body_remote: Iemand van %{domain} heeft %{target} gerapporteerd\n      subject: Nieuwe rapportage op %{instance} (#%{id})\n  appearance:\n    advanced_web_interface: Geavanceerde webomgeving\n    advanced_web_interface_hint: 'Wanneer je van de hele schermbreedte gebruik wilt maken, stelt de geavanceerde webomgeving je in staat om meerdere verschillende kolommen te configureren. Hiermee kun je zoveel mogelijk informatie op hetzelfde moment bekijken, zoals: Start, meldingen, de globale tijdlijn, meerdere lijsten en hashtags.'\n    animations_and_accessibility: Animaties en toegankelijkheid\n    confirmation_dialogs: Bevestigingen\n    sensitive_content: Gevoelige inhoud\n  application_mailer:\n    notification_preferences: E-mailvoorkeuren wijzigen\n    salutation: \"%{name},\"\n    settings: 'E-mailvoorkeuren wijzigen: %{link}'\n    view: 'Bekijk:'\n    view_profile: Profiel bekijken\n    view_status: Status bekijken\n  applications:\n    created: Aanmaken toepassing geslaagd\n    destroyed: Verwijderen toepassing geslaagd\n    invalid_url: De opgegeven URL is ongeldig\n    regenerate_token: Toegangscode opnieuw aanmaken\n    token_regenerated: Opnieuw aanmaken toegangscode geslaagd\n    warning: Wees voorzichtig met deze gegevens. Deel het nooit met iemand anders!\n    your_token: Jouw toegangscode\n  auth:\n    apply_for_account: Een uitnodiging aanvragen\n    change_password: Wachtwoord\n    checkbox_agreement_html: Ik ga akkoord met de <a href=\"%{rules_path}\" target=\"_blank\">regels van deze server</a> en de <a href=\"%{terms_path}\" target=\"_blank\">gebruiksvoorwaarden</a>\n    confirm_email: E-mail bevestigen\n    delete_account: Account verwijderen\n    delete_account_html: Wanneer je jouw account graag wilt verwijderen, kun je dat <a href=\"%{path}\">hier doen</a>. We vragen jou daar om een bevestiging.\n    didnt_get_confirmation: Geen bevestigingsinstructies ontvangen?\n    forgot_password: Wachtwoord vergeten?\n    invalid_reset_password_token: De code om jouw wachtwoord opnieuw in te stellen is verlopen. Vraag een nieuwe aan.\n    login: Inloggen\n    logout: Uitloggen\n    migrate_account: Naar een ander account verhuizen\n    migrate_account_html: Wanneer je dit account naar een ander account wilt doorverwijzen, kun je <a href=\"%{path}\">dit hier instellen</a>.\n    or_log_in_with: Of inloggen met\n    providers:\n      cas: CAS\n      saml: SAML\n    register: Registreren\n    registration_closed: \"%{instance} laat geen nieuwe gebruikers toe\"\n    resend_confirmation: Verstuur de bevestigingsinstructies nogmaals\n    reset_password: Wachtwoord opnieuw instellen\n    security: Beveiliging\n    set_new_password: Nieuw wachtwoord instellen\n    trouble_logging_in: Problemen met inloggen?\n  authorize_follow:\n    already_following: Je volgt dit account al\n    error: Helaas, er is een fout opgetreden bij het opzoeken van de externe account\n    follow: Volgen\n    follow_request: 'Jij hebt een volgverzoek ingediend bij:'\n    following: 'Succes! Jij volgt nu:'\n    post_follow:\n      close: Of je kan dit venster gewoon sluiten.\n      return: Profiel van deze gebruiker tonen\n      web: Ga naar de webapp\n    title: Volg %{acct}\n  datetime:\n    distance_in_words:\n      about_x_hours: \"%{count}u\"\n      about_x_months: \"%{count}ma\"\n      about_x_years: \"%{count}j\"\n      almost_x_years: \"%{count}j\"\n      half_a_minute: Zojuist\n      less_than_x_minutes: \"%{count}m\"\n      less_than_x_seconds: Zojuist\n      over_x_years: \"%{count}j\"\n      x_days: \"%{count}d\"\n      x_minutes: \"%{count}m\"\n      x_months: \"%{count}ma\"\n      x_seconds: \"%{count}s\"\n  deletes:\n    bad_password_msg: Goed geprobeerd hackers! Ongeldig wachtwoord\n    confirm_password: Voer jouw huidige wachtwoord in om jouw identiteit te bevestigen\n    description_html: Hierdoor worden alle gegevens van jouw account <strong>permanent, onomkeerbaar</strong> verwijderd en wordt deze gedeactiveerd. Om toekomstige identiteitsdiefstal te voorkomen, kan op deze server jouw gebruikersnaam niet meer gebruikt worden.\n    proceed: Account verwijderen\n    success_msg: Jouw account is succesvol verwijderd\n    warning_html: We kunnen alleen garanderen dat jouw gegevens op deze server worden verwijderd. Berichten (toots), incl. media, die veel zijn gedeeld laten mogelijk sporen achter. Offline servers en servers die niet meer op jouw updates zijn geabonneerd zullen niet hun databases updaten.\n    warning_title: Verwijdering gegevens op andere servers\n  directories:\n    directory: Gebruikersgids\n    enabled: Je staat momenteel in de gebruikersgids vermeldt.\n    enabled_but_waiting: Je hebt er voor gekozen om in de gebruikersgids te worden vermeldt, maar je hebt daarvoor nog niet het minimaal aantal volgers (%{min_followers}).\n    explanation: Ontdek gebruikers aan de hand van hun interesses\n    explore_mastodon: \"%{title} verkennen\"\n    how_to_enable: Je geeft momenteel geen toestemming om in de gebruikersgids te worden vermeldt. Je kunt hieronder toestemming geven. Gebruik hashtags in de tekst van jouw bio, om onder bepaalde hashtags te worden vermeldt!\n    people:\n      one: \"%{count} gebruikers\"\n      other: \"%{count} gebruikers\"\n  errors:\n    '403': Jij hebt geen toestemming om deze pagina te bekijken.\n    '404': De pagina waarnaar jij op zoek bent bestaat niet.\n    '410': De pagina waarnaar jij op zoek bent bestaat niet meer.\n    '422':\n      content: Veiligheidsverificatie mislukt. Blokkeer je toevallig cookies?\n      title: Veiligheidsverificatie mislukt\n    '429': Te veel verbindingsaanvragen\n    '500':\n      content: Het spijt ons, er is aan onze kant iets fout gegaan.\n      title: Er is iets mis\n    noscript_html: Schakel JavaScript in om de webapp van Mastodon te kunnen gebruiken. Als alternatief kan je een <a href=\"%{apps_path}\">Mastodon-app</a> zoeken voor jouw platform.\n  existing_username_validator:\n    not_found: Kon geen lokale gebruiker met die gebruikersnaam vinden\n    not_found_multiple: Kon %{usernames} niet vinden\n  exports:\n    archive_takeout:\n      date: Datum\n      download: Jouw archief downloaden\n      hint_html: Je kunt een archief opvragen van jouw <strong>toots en geüploade media</strong>. De geëxporteerde gegevens zijn in het ActivityPub-formaat, dat door hiervoor geschikte software valt uit te lezen. Je kunt elke 7 dagen een kopie van je archief aanvragen.\n      in_progress: Jouw archief wordt samengesteld...\n      request: Jouw archief opvragen\n      size: Omvang\n    blocks: Jij blokkeert\n    csv: CSV\n    domain_blocks: Domeinblokkades\n    follows: Jij volgt\n    lists: Lijsten\n    mutes: Jij negeert\n    storage: Mediaopslag\n  featured_tags:\n    add_new: Nieuwe toevoegen\n    errors:\n      limit: Je hebt al het maximaal aantal hashtags uitgelicht\n  filters:\n    contexts:\n      home: Starttijdlijn\n      notifications: Meldingen\n      public: Openbare tijdlijnen\n      thread: Gesprekken\n    edit:\n      title: Filter bewerken\n    errors:\n      invalid_context: Geen of ongeldige context verstrekt\n      invalid_irreversible: Onomkeerbaar filteren werkt alleen met de starttijdlijn en meldingen\n    index:\n      delete: Verwijderen\n      title: Filters\n    new:\n      title: Nieuw filter toevoegen\n  footer:\n    developers: Ontwikkelaars\n    more: Meer…\n    resources: Hulpmiddelen\n  generic:\n    all: Alles\n    changes_saved_msg: Wijzigingen succesvol opgeslagen!\n    copy: Kopiëren\n    order_by: Sorteer op\n    save_changes: Wijzigingen opslaan\n    validation_errors:\n      one: Er is iets niet helemaal goed! Bekijk onderstaande fout\n      other: Er is iets niet helemaal goed! Bekijk onderstaande %{count} fouten\n  html_validator:\n    invalid_markup: 'bevat ongeldige HTML-opmaak: %{error}'\n  identity_proofs:\n    active: Actief\n    authorize: Ja, autoriseren\n    authorize_connection_prompt: Deze cryptografische verbinding autoriseren?\n    errors:\n      failed: De cryptografische verbinding is mislukt. Probeer het opnieuw vanaf %{provider}.\n      keybase:\n        invalid_token: Keybasetokens zijn hashes van handtekeningen en moeten een lengte hebben van 66 hexadecimale tekens\n        verification_failed: Keybase herkent deze token niet als een handtekening van Keybasegebruiker %{kb_username}. Probeer het opnieuw vanuit Keybase.\n      wrong_user: Er kan geen bewijs worden aangemaakt voor %{proving}   terwijl je bent ingelogd als %{current}. Log in als %{proving} en probeer het opnieuw.\n    explanation_html: Hier kun je met behulp van cryptografie jouw andere identiteiten verbinden, zoals een Keybaseprofiel. Hiermee kunnen andere mensen jou versleutelde berichten sturen en inhoud die jij verstuurt vertrouwen.\n    i_am_html: Ik ben %{username} op %{service}.\n    identity: Identiteit\n    inactive: Inactief\n    publicize_checkbox: 'En toot dit:'\n    publicize_toot: 'Het is bewezen! Ik ben %{username} op %{service}: %{url}'\n    status: Verificatiestatus\n    view_proof: Bekijk bewijs\n  imports:\n    modes:\n      merge: Samenvoegen\n      merge_long: Bestaande gegevens behouden en nieuwe toevoegen\n      overwrite: Overschrijven\n      overwrite_long: Huidige gegevens met de nieuwe gegevens vervangen\n    preface: Je kunt bepaalde gegevens, zoals de mensen die jij volgt of hebt geblokkeerd, naar jouw account op deze server importeren. Je moet deze gegevens wel eerst op de oorspronkelijke server exporteren.\n    success: Jouw gegevens zijn succesvol geüpload en worden binnenkort verwerkt\n    types:\n      blocking: Blokkeerlijst\n      domain_blocking: Lijst met genegeerde servers\n      following: Volglijst\n      muting: Negeerlijst\n    upload: Uploaden\n  in_memoriam_html: In memoriam.\n  invites:\n    delete: Deactiveren\n    expired: Verlopen\n    expires_in:\n      '1800': 30 minuten\n      '21600': 6 uur\n      '3600': 1 uur\n      '43200': 12 uur\n      '604800': 1 week\n      '86400': 1 dag\n    expires_in_prompt: Nooit\n    generate: Genereren\n    invited_by: 'Jij bent uitgenodigd door:'\n    max_uses:\n      one: 1 keer\n      other: \"%{count} keer\"\n    max_uses_prompt: Onbeperkt\n    prompt: Genereer en deel speciale links om mensen toegang tot deze Mastodonserver te geven\n    table:\n      expires_at: Verloopt op\n      uses: Aantal keer te gebruiken\n    title: Mensen uitnodigen\n  lists:\n    errors:\n      limit: Je hebt het maximaal aantal lijsten bereikt\n  media_attachments:\n    validations:\n      images_and_video: Een video kan niet aan een toot met afbeeldingen worden gekoppeld\n      too_many: Er kunnen niet meer dan 4 afbeeldingen toegevoegd worden\n  migrations:\n    acct: gebruikersnaam@domein van het nieuwe account\n    currently_redirecting: 'Jouw profiel wordt nu doorverwezen naar:'\n    proceed: Opslaan\n    updated_msg: Jouw accountmigratie-instelling is succesvol bijgewerkt!\n  moderation:\n    title: Moderatie\n  notification_mailer:\n    digest:\n      action: Alle meldingen bekijken\n      body: Hier is een korte samenvatting van de berichten die je sinds jouw laatste bezoek op %{since} hebt gemist\n      mention: \"%{name} vermeldde jou in:\"\n      new_followers_summary:\n        one: Je hebt trouwens sinds je weg was er ook een nieuwe volger bijgekregen! Hoera!\n        other: Je hebt trouwens sinds je weg was er ook %{count} nieuwe volgers bijgekregen! Fantastisch!\n      subject:\n        one: \"1 nieuwe melding sinds jouw laatste bezoek \\U0001F418\"\n        other: \"%{count} nieuwe meldingen sinds jouw laatste bezoek \\U0001F418\"\n      title: Tijdens jouw afwezigheid...\n    favourite:\n      body: 'Jouw toot werd door %{name} aan hun favorieten toegevoegd:'\n      subject: \"%{name} voegde jouw toot als favoriet toe\"\n      title: Nieuwe favoriet\n    follow:\n      body: \"%{name} volgt jou nu!\"\n      subject: \"%{name} volgt jou nu\"\n      title: Nieuwe volger\n    follow_request:\n      action: Volgverzoeken beheren\n      body: \"%{name} wil jou graag volgen\"\n      subject: 'Volgen in afwachting: %{name}'\n      title: Nieuw volgverzoek\n    mention:\n      action: Reageren\n      body: 'Jij bent door %{name} vermeld in:'\n      subject: Jij bent vermeld door %{name}\n      title: Nieuwe vermelding\n    reblog:\n      body: 'Jouw toot werd door %{name} geboost:'\n      subject: \"%{name} boostte jouw toot\"\n      title: Nieuwe boost\n  number:\n    human:\n      decimal_units:\n        format: \"%n%u\"\n        units:\n          billion: mld.\n          million: mln.\n          quadrillion: qdn.\n          thousand: K\n          trillion: bln.\n  pagination:\n    newer: Nieuwer\n    next: Volgende\n    older: Ouder\n    prev: Vorige\n    truncate: \"&hellip;\"\n  polls:\n    errors:\n      already_voted: Je hebt al op deze poll gestemd\n      duplicate_options: bevat dubbele items\n      duration_too_long: ligt te ver in de toekomst\n      duration_too_short: is te kort van duur\n      expired: De poll is al beëindigd\n      over_character_limit: kan stuk voor stuk niet langer zijn dan %{max} tekens\n      too_few_options: moet meer dan één item bevatten\n      too_many_options: kan niet meer dan %{max} items bevatten\n  preferences:\n    other: Overig\n    posting_defaults: Standaardinstellingen voor posten\n    public_timelines: Openbare tijdlijnen\n  relationships:\n    activity: Accountactiviteit\n    dormant: Sluimerend\n    last_active: Laatst actief\n    most_recent: Recentelijk gevolgd\n    moved: Verhuisd\n    mutual: Wederzijds\n    primary: Primair\n    relationship: Relatie\n    remove_selected_domains: Alle volgers van de geselecteerde domeinen verwijderen\n    remove_selected_followers: Geselecteerde volgers verwijderen\n    remove_selected_follows: Geselecteerde gebruikers ontvolgen\n    status: Accountstatus\n  remote_follow:\n    acct: Geef jouw account@domein op die je wilt gebruiken\n    missing_resource: Kon vereiste doorverwijzings-URL voor jouw account niet vinden\n    no_account_html: Heb je geen account? Je kunt er <a href='%{sign_up_path}' target='_blank'>hier een registreren</a>\n    proceed: Ga verder om te volgen\n    prompt: 'Jij gaat volgen:'\n    reason_html: \"<strong> Waarom is deze extra stap nodig? </strong> <code>%{instance}</code> is wellicht niet de server waarop jij je geregistreerd hebt. We verwijzen je eerst door naar jouw eigen server.\"\n  remote_interaction:\n    favourite:\n      proceed: Doorgaan met toevoegen aan jouw favorieten\n      prompt: 'Je wilt de volgende toot aan jouw favorieten toevoegen:'\n    reblog:\n      proceed: Doorgaan met boosten\n      prompt: 'Je wilt de volgende toot boosten:'\n    reply:\n      proceed: Doorgaan met reageren\n      prompt: 'Je wilt op de volgende toot reageren:'\n  remote_unfollow:\n    error: Fout\n    title: Titel\n    unfollowed: Ontvolgd\n  scheduled_statuses:\n    over_daily_limit: Je hebt de limiet van %{limit} in te plannen toots voor die dag overschreden\n    over_total_limit: Je hebt de limiet van %{limit} in te plannen toots overschreden\n    too_soon: De datum voor de ingeplande toot moet in de toekomst liggen\n  sessions:\n    activity: Laatst actief\n    browser: Webbrowser\n    browsers:\n      alipay: Alipay\n      blackberry: Blackberry\n      chrome: Chrome\n      edge: Microsoft Edge\n      electron: Electron\n      firefox: Firefox\n      generic: Onbekende webbrowser\n      ie: Internet Explorer\n      micro_messenger: MicroMessenger\n      nokia: Nokia S40 Ovi Browser\n      opera: Opera\n      otter: Otter\n      phantom_js: PhantomJS\n      qq: QQ Browser\n      safari: Safari\n      uc_browser: UCBrowser\n      weibo: Weibo\n    current_session: Huidige sessie\n    description: \"%{browser} op %{platform}\"\n    explanation: Dit zijn de webbrowsers die momenteel met jouw Mastodonaccount zijn ingelogd.\n    ip: IP\n    platforms:\n      adobe_air: Adobe Air\n      android: Android\n      blackberry: Blackberry\n      chrome_os: ChromeOS\n      firefox_os: Firefox OS\n      ios: iOS\n      linux: Linux\n      mac: Mac\n      other: Onbekend platform\n      windows: Windows\n      windows_mobile: Windows Mobile\n      windows_phone: Windows Phone\n    revoke: Intrekken\n    revoke_success: Sessie succesvol ingetrokken\n    title: Sessies\n  settings:\n    account: Account\n    account_settings: Accountinstellingen\n    appearance: Uiterlijk\n    authorized_apps: Geautoriseerde apps\n    back: Terug naar Mastodon\n    delete: Account verwijderen\n    development: Ontwikkelaars\n    edit_profile: Profiel bewerken\n    export: Exporteren\n    featured_tags: Uitgelichte hashtags\n    identity_proofs: Identiteitsbewijzen\n    import: Importeren\n    import_and_export: Importeren en exporteren\n    migrate: Accountmigratie\n    notifications: Meldingen\n    preferences: Voorkeuren\n    profile: Profiel\n    relationships: Volgers en gevolgden\n    two_factor_authentication: Tweestapsverificatie\n  statuses:\n    attached:\n      description: 'Bijlagen: %{attached}'\n      image:\n        one: \"%{count} afbeelding\"\n        other: \"%{count} afbeeldingen\"\n      video:\n        one: \"%{count} video\"\n        other: \"%{count} video's\"\n    boosted_from_html: Geboost van %{acct_link}\n    content_warning: 'Tekstwaarschuwing: %{warning}'\n    disallowed_hashtags:\n      one: 'bevatte een niet toegestane hashtag: %{tags}'\n      other: 'bevatte niet toegestane hashtags: %{tags}'\n    language_detection: Taal automatisch detecteren\n    open_in_web: In de webapp openen\n    over_character_limit: Limiet van %{max} tekens overschreden\n    pin_errors:\n      limit: Je hebt het maximaal aantal toots al vastgezet\n      ownership: Een toot van iemand anders kan niet worden vastgezet\n      private: Alleen openbare toots kunnen worden vastgezet\n      reblog: Een boost kan niet worden vastgezet\n    poll:\n      total_votes:\n        one: \"%{count} stem\"\n        other: \"%{count} stemmen\"\n      vote: Stemmen\n    show_more: Meer tonen\n    sign_in_to_participate: Meld je aan om aan dit gesprek mee te doen\n    title: '%{name}: \"%{quote}\"'\n    visibilities:\n      private: Alleen volgers\n      private_long: Alleen aan jouw volgers tonen\n      public: Openbaar\n      public_long: Aan iedereen tonen, ook op openbare tijdlijnen\n      unlisted: Minder openbaar\n      unlisted_long: Aan iedereen tonen, maar niet op openbare tijdlijnen\n  stream_entries:\n    pinned: Vastgemaakte toot\n    reblogged: boostte\n    sensitive_content: Gevoelige inhoud\n  terms:\n    body_html: |\n      <h2>Privacy Policy</h2>\n      <h3 id=\"collect\">What information do we collect?</h3>\n\n      <ul>\n      <li><em>Basic account information</em>: If you register on this server, you may be asked to enter a username, an e-mail address and a password. You may also enter additional profile information such as a display name and biography, and upload a profile picture and header image. The username, display name, biography, profile picture and header image are always listed publicly.</li>\n      <li><em>Posts, following and other public information</em>: The list of people you follow is listed publicly, the same is true for your followers. When you submit a message, the date and time is stored as well as the application you submitted the message from. Messages may contain media attachments, such as pictures and videos. Public and unlisted posts are available publicly. When you feature a post on your profile, that is also publicly available information. Your posts are delivered to your followers, in some cases it means they are delivered to different servers and copies are stored there. When you delete posts, this is likewise delivered to your followers. The action of reblogging or favouriting another post is always public.</li>\n      <li><em>Direct and followers-only posts</em>: All posts are stored and processed on the server. Followers-only posts are delivered to your followers and users who are mentioned in them, and direct posts are delivered only to users mentioned in them. In some cases it means they are delivered to different servers and copies are stored there. We make a good faith effort to limit the access to those posts only to authorized persons, but other servers may fail to do so. Therefore it's important to review servers your followers belong to. You may toggle an option to approve and reject new followers manually in the settings. <em>Please keep in mind that the operators of the server and any receiving server may view such messages</em>, and that recipients may screenshot, copy or otherwise re-share them. <em>Do not share any dangerous information over Mastodon.</em></li>\n      <li><em>IPs and other metadata</em>: When you log in, we record the IP address you log in from, as well as the name of your browser application. All the logged in sessions are available for your review and revocation in the settings. The latest IP address used is stored for up to 12 months. We also may retain server logs which include the IP address of every request to our server.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"use\">What do we use your information for?</h3>\n\n      <p>Any of the information we collect from you may be used in the following ways:</p>\n\n      <ul>\n      <li>To provide the core functionality of Mastodon. You can only interact with other people's content and post your own content when you are logged in. For example, you may follow other people to view their combined posts in your own personalized home timeline.</li>\n      <li>To aid moderation of the community, for example comparing your IP address with other known ones to determine ban evasion or other violations.</li>\n      <li>The email address you provide may be used to send you information, notifications about other people interacting with your content or sending you messages, and to respond to inquiries, and/or other requests or questions.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"protect\">How do we protect your information?</h3>\n\n      <p>We implement a variety of security measures to maintain the safety of your personal information when you enter, submit, or access your personal information. Among other things, your browser session, as well as the traffic between your applications and the API, are secured with SSL, and your password is hashed using a strong one-way algorithm. You may enable two-factor authentication to further secure access to your account.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"data-retention\">What is our data retention policy?</h3>\n\n      <p>We will make a good faith effort to:</p>\n\n      <ul>\n      <li>Retain server logs containing the IP address of all requests to this server, in so far as such logs are kept, no more than 90 days.</li>\n      <li>Retain the IP addresses associated with registered users no more than 12 months.</li>\n      </ul>\n\n      <p>You can request and download an archive of your content, including your posts, media attachments, profile picture, and header image.</p>\n\n      <p>You may irreversibly delete your account at any time.</p>\n\n      <hr class=\"spacer\"/>\n\n      <h3 id=\"cookies\">Do we use cookies?</h3>\n\n      <p>Yes. Cookies are small files that a site or its service provider transfers to your computer's hard drive through your Web browser (if you allow). These cookies enable the site to recognize your browser and, if you have a registered account, associate it with your registered account.</p>\n\n      <p>We use cookies to understand and save your preferences for future visits.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"disclose\">Do we disclose any information to outside parties?</h3>\n\n      <p>We do not sell, trade, or otherwise transfer to outside parties your personally identifiable information. This does not include trusted third parties who assist us in operating our site, conducting our business, or servicing you, so long as those parties agree to keep this information confidential. We may also release your information when we believe release is appropriate to comply with the law, enforce our site policies, or protect ours or others rights, property, or safety.</p>\n\n      <p>Your public content may be downloaded by other servers in the network. Your public and followers-only posts are delivered to the servers where your followers reside, and direct messages are delivered to the servers of the recipients, in so far as those followers or recipients reside on a different server than this.</p>\n\n      <p>When you authorize an application to use your account, depending on the scope of permissions you approve, it may access your public profile information, your following list, your followers, your lists, all your posts, and your favourites. Applications can never access your e-mail address or password.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"children\">Site usage by children</h3>\n\n      <p>If this server is in the EU or the EEA: Our site, products and services are all directed to people who are at least 16 years old. If you are under the age of 16, per the requirements of the GDPR (<a href=\"https://en.wikipedia.org/wiki/General_Data_Protection_Regulation\">General Data Protection Regulation</a>) do not use this site.</p>\n\n      <p>If this server is in the USA: Our site, products and services are all directed to people who are at least 13 years old. If you are under the age of 13, per the requirements of COPPA (<a href=\"https://en.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act\">Children's Online Privacy Protection Act</a>) do not use this site.</p>\n\n      <p>Law requirements can be different if this server is in another jurisdiction.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"changes\">Changes to our Privacy Policy</h3>\n\n      <p>If we decide to change our privacy policy, we will post those changes on this page.</p>\n\n      <p>This document is CC-BY-SA. It was last updated March 7, 2018.</p>\n\n      <p>Originally adapted from the <a href=\"https://github.com/discourse/discourse\">Discourse privacy policy</a>.</p>\n    title: Gebruiksvoorwaarden en privacybeleid van %{instance}\n  themes:\n    contrast: Mastodon (hoog contrast)\n    default: Mastodon (donker)\n    mastodon-light: Mastodon (licht)\n  time:\n    formats:\n      default: \"%d %B %Y om %H:%M\"\n      month: \"%b %Y\"\n  two_factor_authentication:\n    code_hint: Voer de code in die door de authenticatie-app gegenereerd is\n    description_html: Na het instellen van <strong>tweestapsverificatie</strong>, kun je alleen inloggen als je jouw mobiele telefoon bij je hebt. Hiermee genereer je namelijk de in te voeren aanmeldcode.\n    disable: Uitschakelen\n    enable: Inschakelen\n    enabled: Tweestapsverificatie is ingeschakeld\n    enabled_success: Inschakelen tweestapsverificatie geslaagd\n    generate_recovery_codes: Herstelcodes genereren\n    instructions_html: \"<strong>Scan deze QR-code in Google Authenticator of een soortgelijke app op jouw mobiele telefoon</strong>. Van nu af aan genereert deze app aanmeldcodes die je bij het inloggen moet invoeren.\"\n    lost_recovery_codes: Met herstelcodes kun je toegang tot jouw account krijgen wanneer je jouw telefoon bent kwijtgeraakt. Wanneer je jouw herstelcodes bent kwijtgeraakt, kan je ze hier opnieuw genereren. Jouw oude herstelcodes zijn daarna ongeldig.\n    manual_instructions: Voor het geval je de QR-code niet kunt scannen en het handmatig moet invoeren, vind je hieronder de geheime code in platte tekst.\n    recovery_codes: Herstelcodes back-uppen\n    recovery_codes_regenerated: Opnieuw genereren herstelcodes geslaagd\n    recovery_instructions_html: Wanneer je ooit de toegang verliest tot jouw telefoon, kan je met behulp van een van de herstelcodes hieronder opnieuw toegang krijgen tot jouw account. <strong>Zorg ervoor dat je de herstelcodes op een veilige plek bewaard</strong>. Je kunt ze bijvoorbeeld printen en ze samen met andere belangrijke documenten bewaren.\n    setup: Instellen\n    wrong_code: De ingevoerde code is ongeldig! Klopt de systeemtijd van de server en die van jouw apparaat?\n  user_mailer:\n    backup_ready:\n      explanation: Je hebt een volledige back-up van jouw Mastodon-account opgevraagd. Het staat nu klaar om te worden gedownload!\n      subject: Jouw archief staat klaar om te worden gedownload\n      title: Archief ophalen\n    warning:\n      explanation:\n        disable: Zolang jouw account is bevroren blijven jouw accountgegevens intact, maar kun je geen handelingen uitvoeren totdat het account is vrijgegeven.\n        silence: Zolang jouw account wordt beperkt, kunnen alleen mensen die jou al volgen jouw toots op deze server zien. Tevens ben je niet zichtbaar in meldingen, gesprekken en op openbare tijdlijnen. Anderen kunnen je echter wel handmatig volgen.\n        suspend: Jouw account is opgeschort. Jouw toots en geüploade media zijn onomkeerbaar van deze server verwijderd, en ook o.a. van de servers waar jij volgers had.\n      review_server_policies: Serverbeleid bekijken\n      subject:\n        disable: Jouw account %{acct} is bevroren\n        none: Waarschuwing voor %{acct}\n        silence: Jouw account %{acct} is nu beperkt\n        suspend: Jouw account %{acct} is opgeschort\n      title:\n        disable: Account bevroren\n        none: Waarschuwing\n        silence: Account beperkt\n        suspend: Account opgeschort\n    welcome:\n      edit_profile_action: Profiel instellen\n      edit_profile_step: Je kunt jouw profiel aanpassen door een avatar (profielfoto) en omslagfoto te uploaden, jouw weergavenaam in te stellen en iets over jezelf te vertellen. Wanneer je nieuwe volgers eerst wilt goedkeuren, kun je jouw account besloten maken.\n      explanation: Hier zijn enkele tips om je op weg te helpen\n      final_action: Begin berichten te plaatsen\n      final_step: 'Begin berichten te plaatsen! Zelfs zonder volgers kunnen jouw openbare berichten door anderen gezien worden, bijvoorbeeld op de lokale tijdlijn en via hashtags. Je wilt jezelf misschien introduceren met de hashtag #introductions.'\n      full_handle: Jouw volledige Mastodonadres\n      full_handle_hint: Dit geef je aan jouw vrienden, zodat ze jouw berichten kunnen sturen of (vanaf een andere Mastodonserver) kunnen volgen.\n      review_preferences_action: Instellingen veranderen\n      review_preferences_step: Zorg dat je jouw instellingen naloopt, zoals welke e-mails je wilt ontvangen of voor wie jouw berichten standaard zichtbaar moeten zijn. Wanneer je geen last hebt van bewegende beelden, kun je het afspelen van geanimeerde GIF's inschakelen.\n      subject: Welkom op Mastodon\n      tip_federated_timeline: De globale tijdlijn toont berichten in het Mastodonnetwerk. Het bevat echter alleen berichten van mensen waar jouw buren mee zijn verbonden, dus het is niet compleet.\n      tip_following: Je volgt standaard de beheerder(s) van jouw Mastodonserver. Bekijk de lokale en de globale tijdlijnen om meer interessante mensen te vinden.\n      tip_local_timeline: De lokale tijdlijn toont berichten van mensen op %{instance}. Dit zijn jouw naaste buren!\n      tip_mobile_webapp: Wanneer jouw mobiele webbrowser Mastodon aan jouw startscherm wilt toevoegen, kun je pushmeldingen ontvangen. Het gedraagt zich op meerdere manieren als een native app!\n      tips: Tips\n      title: Welkom aan boord %{name}!\n  users:\n    follow_limit_reached: Je kunt niet meer dan %{limit} accounts volgen\n    invalid_email: E-mailadres is ongeldig\n    invalid_otp_token: Ongeldige tweestaps-aanmeldcode\n    otp_lost_help_html: Als je toegang tot beiden kwijt bent geraakt, neem dan contact op via %{email}\n    seamless_external_login: Je bent ingelogd via een externe dienst, daarom zijn wachtwoorden en e-mailinstellingen niet beschikbaar.\n    signed_in_as: 'Ingelogd als:'\n  verification:\n    explanation_html: 'Je kunt <strong>jezelf verifiëren als de eigenaar van de links in de metadata van jouw profiel</strong>. Hiervoor moet op de gelinkte website een link terug naar jouw Mastodonprofiel staan. Deze link <strong>moet</strong> het <code>rel=\"me\"</code>-attribuut bevatten. De omschrijving van de link maakt niet uit. Hier is een voorbeeld:'\n    verification: Verificatie\n"
  },
  {
    "path": "config/locales/no.yml",
    "content": "---\n'no':\n  about:\n    about_hashtag_html: Dette er offentlige toots merket med <strong>#%{hashtag}</strong>. Du kan interagere med dem om du har en konto et sted i fediverset.\n    about_mastodon_html: Mastodon er et sosialt nettverk laget med <em>fri programvare</em>. Et <em>desentralisert</em> alternativ til kommersielle plattformer. Slik kan det unngå risikoene ved å ha et enkelt selskap som monopoliserer din kommunikasjon. Velg en tjener du stoler på &mdash; uansett hvilken du velger så kan du kommunisere med alle andre. Alle kan kjøre sin egen Mastodon og delta sømløst i det sosiale nettverket.\n    about_this: Om denne instansen\n    contact: Kontakt\n    contact_missing: Ikke innstilt\n    contact_unavailable: Ikke tilgjengelig\n    extended_description_html: |\n      <h3>En god plassering for regler</h3>\n      <p>En utvidet beskrivelse er ikke satt opp ennå.</p>\n    generic_description: \"%{domain} er en tjener i nettverket\"\n    hosted_on: Mastodon driftet på %{domain}\n    learn_more: Lær mer\n    source_code: Kildekode\n    status_count_before: Som skrev\n    user_count_before: Her bor\n    what_is_mastodon: Hva er Mastodon?\n  accounts:\n    follow: Følg\n    following: Følger\n    moved_html: \"%{name} har flyttet til %{new_profile_link}:\"\n    nothing_here: Det er ingenting her!\n    people_followed_by: Folk som %{name} følger\n    people_who_follow: Folk som følger %{name}\n    posts_with_replies: Tuter med svar\n    reserved_username: Brukernavnet er reservert\n    roles:\n      moderator: Moderere\n    unfollow: Slutte følge\n  admin:\n    account_moderation_notes:\n      create: Lag\n      created_msg: Moderasjonsnotat laget uten problem!\n      delete: Slett\n      destroyed_msg: Moderasjonsnotat slettet uten problem!\n    accounts:\n      are_you_sure: Er du sikker?\n      by_domain: Domene\n      confirm: Bekreft\n      confirmed: Bekreftet\n      confirming: Bekrefte\n      demote: Degrader\n      disable: Deaktiver\n      disable_two_factor_authentication: Skru av 2FA\n      disabled: Deaktivert\n      display_name: Visningsnavn\n      domain: Domene\n      edit: Redigér\n      email: E-post\n      email_status: E-poststatus\n      enable: Aktiver\n      enabled: Aktivert\n      feed_url: Feed-URL\n      followers: Følgere\n      followers_url: Følgere URL\n      follows: Følginger\n      inbox_url: Innboks URL\n      ip: IP-adresse\n      location:\n        all: Alle\n        local: Lokalt\n        remote: Fjernt\n        title: Sted\n      login_status: Innloggingsstatus\n      media_attachments: Mediavedlegg\n      memorialize: Gjør om til et minne\n      moderation:\n        all: Alle\n        silenced: Målbundet\n        suspended: Utvist\n        title: Moderasjon\n      moderation_notes: Moderasjonsnotater\n      most_recent_activity: Nyligste aktivitet\n      most_recent_ip: Nyligste IP\n      not_subscribed: Ikke abonnért\n      outbox_url: Utboks URL\n      perform_full_suspension: Utfør full utvisning\n      profile_url: Profil-URL\n      promote: Oppgradere\n      protocol: Protokoll\n      public: Offentlig\n      push_subscription_expires: PuSH-abonnent utløper\n      redownload: Oppdater avatar\n      resend_confirmation:\n        already_confirmed: Denne brukeren er allerede bekreftet\n        send: Send bekreftelses-epost på nytt\n        success: Bekreftelses e-post er vellykket sendt!\n      reset: Tilbakestill\n      reset_password: Nullstill passord\n      resubscribe: Abonner på nytt\n      role: Rettigheter\n      roles:\n        staff: Personale\n        user: Bruker\n      salmon_url: Salmon-URL\n      search: Søk\n      shared_inbox_url: Delt Innboks URL\n      show:\n        created_reports: Rapporter laget av denne kontoen\n        targeted_reports: Rapporter laget om denne kontoen\n      silence: Målbind\n      statuses: Statuser\n      subscribe: Abonnere\n      title: Kontoer\n      undo_silenced: Angre målbinding\n      undo_suspension: Angre utvisning\n      unsubscribe: Avslutte abonnementet\n      username: Brukernavn\n    action_logs:\n      actions:\n        confirm_user: \"%{name} bekreftet e-postadresse for bruker %{target}\"\n        create_custom_emoji: \"%{name} lastet opp ny emoji %{target}\"\n        create_domain_block: \"%{name} blokkerte domenet %{target}\"\n        create_email_domain_block: \"%{name} svartelistet e-postdomenet %{target}\"\n        demote_user: \"%{name} degraderte bruker %{target}\"\n        destroy_domain_block: \"%{name} fjernet blokkeringen av domenet %{target}\"\n        destroy_email_domain_block: \"%{name} hvitelistet e-postdomenet %{target}\"\n        destroy_status: \"%{name} fjernet status av %{target}\"\n        disable_2fa_user: \"%{name} deaktiverte tofaktor-autentiseringskravet for bruker %{target}\"\n        disable_custom_emoji: \"%{name} deaktiverte emoji %{target}\"\n        disable_user: \"%{name} deaktiverte innlogging for bruker %{target}\"\n        enable_custom_emoji: \"%{name} aktiverte emoji %{target}\"\n        enable_user: \"%{name} aktiverte innlogging for bruker %{target}\"\n        memorialize_account: \"%{name} endret %{target}s konto til en minneside\"\n        promote_user: \"%{name} oppgraderte bruker %{target}\"\n        reset_password_user: \"%{name} nullstilte passordet til bruker %{target}\"\n        resolve_report: \"%{name} avviste rapporten %{target}\"\n        silence_account: \"%{name} forstummet %{target}s konto\"\n        suspend_account: \"%{name} suspendert %{target}s konto\"\n        unsilence_account: \"%{name} fjernet forstummingen av %{target}s konto\"\n        unsuspend_account: \"%{name} opphevde suspenderingen av %{target}s konto\"\n        update_custom_emoji: \"%{name} oppdaterte emoji %{target}\"\n        update_status: \"%{name} oppdaterte status for %{target}\"\n      title: Revisionslogg\n    custom_emojis:\n      by_domain: Domene\n      copied_msg: Laget en lokal kopi av emoji uten problem\n      copy: Kopiere\n      copy_failed_msg: Kunne ikke lage en lokal kopi av den emojien\n      created_msg: Emoji laget uten problem!\n      delete: Slett\n      destroyed_msg: Emojo slettet uten problem!\n      disable: Deaktivere\n      disabled_msg: Deaktiverte emoji uten problem\n      enable: Aktivere\n      enabled_msg: Aktiverte emojien uten problem\n      image_hint: PNG opp til 50KB\n      listed: Oppførte\n      new:\n        title: Legg til ny egen emoji\n      overwrite: Overskrive\n      shortcode: Kortkode\n      shortcode_hint: Minst 2 tegn, kun alfanumeriske tegn og understrek\n      title: Egenoppførte emojier\n      unlisted: Unoterte\n      update_failed_msg: Kunne ikke oppdatere emojien\n      updated_msg: Emoji oppdatert uten problemer!\n      upload: Last opp\n    domain_blocks:\n      add_new: Lag ny\n      created_msg: Domeneblokkering blir nå behandlet\n      destroyed_msg: Domeneblokkering har nå blitt angret\n      domain: Domene\n      new:\n        create: Lag blokkering\n        hint: Domeneblokkeringen vil ikke hindre opprettelse av kontooppføringer i databasen, men vil retroaktivt og automatisk benytte spesifikke moderasjonsmetoder på de kontoene.\n        severity:\n          desc_html: \"<strong>Målbind</strong> gjør kontoens poster usynlige for alle som ikke følger den. <strong>Utvis</strong> fjerner alt innhold, media og profildata fra kontoen. Bruk <strong>Ingen</strong> hvis du bare vil fjerne mediafiler.\"\n          noop: Ingen\n          silence: Målbind\n          suspend: Utvis\n        title: Ny domeneblokkering\n      reject_media: Avvis mediefiler\n      reject_media_hint: Fjerner lokalt lagrede mediefiler og nekter å laste dem ned i fremtiden. Irrelevant for utvisninger\n      show:\n        affected_accounts:\n          one: En konto i databasen påvirket\n          other: \"%{count} kontoer i databasen påvirket\"\n        retroactive:\n          silence: Avmålbind alle eksisterende kontoer fre dette domenet\n          suspend: Avutvis alle eksisterende kontoer fra dette domenet\n        title: Angre domeneblokkering for %{domain}\n        undo: Angre\n      undo: Angre\n    email_domain_blocks:\n      add_new: Lag ny\n      created_msg: E-postdomenet ble lagt til i blokkeringslisten uten problemer\n      delete: Fjern\n      destroyed_msg: E-postdomenet har blitt fjernet fra blokkeringslisten uten problemer\n      domain: Domene\n      new:\n        create: Legg til domene\n        title: Ny blokkeringsoppføring av e-postdomene\n      title: Blokkering av e-postdomene\n    instances:\n      title: Kjente instanser\n    invites:\n      filter:\n        all: Alle\n        available: Tilgjengelig\n        expired: Utløpt\n      title: Invitasjoner\n    reports:\n      action_taken_by: Handling utført av\n      are_you_sure: Er du sikker?\n      comment:\n        none: Ingen\n      mark_as_resolved: Merk som løst\n      report: 'Rapportér #%{id}'\n      reported_account: Rapportert konto\n      reported_by: Rapportert av\n      resolved: Løst\n      title: Rapporter\n      unresolved: Uløst\n    settings:\n      activity_api_enabled:\n        desc_html: Antall lokale statusposter, aktive brukere og nye registreringer i ukentlige oppdelinger\n        title: Publiser samlet statistikk om brukeraktiviteter\n      bootstrap_timeline_accounts:\n        desc_html: Separer flere brukernavn med komma. Kun lokale og ulåste kontoer vil kunne brukes. Dersom tomt er standarden alle lokale administratorer.\n        title: Standard følgere for nye brukere\n      contact_information:\n        email: Skriv en offentlig e-postadresse\n        username: Skriv brukernavn\n      peers_api_enabled:\n        desc_html: Domenenavn denne instansen har truffet på i fediverset\n        title: Publiser liste over oppdagede instanser\n      registrations:\n        closed_message:\n          desc_html: Vises på forsiden når registreringer er lukket<br>Du kan bruke HTML-tagger\n          title: Melding for lukket registrering\n        deletion:\n          desc_html: Tillat alle å slette sin konto\n          title: Åpne kontosletting\n        min_invite_role:\n          disabled: Ingen\n          title: Tillat invitasjoner fra\n      show_staff_badge:\n        desc_html: Vis personalemerke på brukersiden\n        title: Vis personalemerke\n      site_description:\n        desc_html: Vises som et avsnitt på forsiden og brukes som en meta-tagg. Du kan bruke HTML-tagger, spesielt <code>&lt;a&gt;</code> og <code>&lt;em&gt;</code>.\n        title: Nettstedsbeskrivelse\n      site_description_extended:\n        desc_html: Vises på side for utvidet informasjon.<br>Du kan bruke HTML-tagger\n        title: Utvidet nettstedsinformasjon\n      site_terms:\n        desc_html: Du kan skrive din egen personverns-strategi, bruksviklår og andre regler. Du kan bruke HTML tagger\n        title: Skreddersydde bruksvilkår\n      site_title: Nettstedstittel\n      thumbnail:\n        desc_html: Brukes ved forhandsvisning via OpenGraph og API. 1200x630px anbefales\n        title: Miniatyrbilde for instans\n      timeline_preview:\n        desc_html: Vis offentlig tidslinje på landingssiden\n        title: Forhandsvis tidslinjen\n      title: Nettstedsinnstillinger\n    statuses:\n      back_to_account: Tilbake til kontosiden\n      batch:\n        delete: Slett\n        nsfw_off: NSFW AV\n        nsfw_on: NSFW PÅ\n      failed_to_execute: Utføring mislyktes\n      no_media: Ingen media\n      title: Kontostatuser\n      with_media: Med media\n    subscriptions:\n      callback_url: Callback-URL\n      confirmed: Bekreftet\n      expires_in: Utløper om\n      last_delivery: Siste levering\n      topic: Emne\n    title: Administrasjon\n  admin_mailer:\n    new_report:\n      body: \"%{reporter} har rapportert %{target}\"\n      subject: Ny rapport for %{instance} (#%{id})\n  application_mailer:\n    notification_preferences: Endre e-post innstillingene\n    settings: 'Endre foretrukne e-postinnstillinger: %{link}'\n    view: 'Se:'\n    view_profile: Vis Profil\n    view_status: Vis status\n  applications:\n    created: Søknaden ble vellykket oppretttet\n    destroyed: Søknaden ble vellykket slettet\n    invalid_url: Den oppgitte URLen er ugyldig\n    regenerate_token: Regenerer tilgangsnøkkel\n    token_regenerated: Tilgangsnøkkel vellykket regenerert\n    warning: Vær veldig forsiktig med denne data. Aldri del den med noen!\n    your_token: Din tilgangsnøkkel\n  auth:\n    delete_account: Slett konto\n    delete_account_html: Hvis du ønsker å slette din konto kan du <a href=\"%{path}\">fortsette her</a>. Du vil bli spurt om bekreftelse.\n    didnt_get_confirmation: Mottok du ikke instruksjoner om bekreftelse?\n    forgot_password: Har du glemt passordet ditt?\n    invalid_reset_password_token: Tilbakestillingsnøkkelen for passord er ugyldig eller utløpt. Vennligst be om en ny.\n    login: Innlogging\n    logout: Logg ut\n    migrate_account: Flytt til en annen konto\n    migrate_account_html: Hvis du ønsker å henvise denne kontoen til en annen, kan du <a href=\"%{path}\">konfigurere det her</a>.\n    register: Bli med\n    resend_confirmation: Send bekreftelsesinstruksjoner på nytt\n    reset_password: Nullstill passord\n    security: Sikkerhet\n    set_new_password: Sett nytt passord\n  authorize_follow:\n    error: Uheldigvis skjedde det en feil da vi prøvde å få tak i en bruker fra en annen instans\n    follow: Følg\n    follow_request: 'Du har sendt en følgeforespørsel til:'\n    following: 'Suksess! Nå følger du:'\n    post_follow:\n      close: Eller så kan du lukke dette vinduet.\n      return: Gå tilbake til brukerens profil\n      web: Gå til nettsiden\n    title: Følg %{acct}\n  datetime:\n    distance_in_words:\n      about_x_hours: \"%{count} timer\"\n      about_x_months: \"%{count} mnd\"\n      about_x_years: \"%{count} år\"\n      almost_x_years: \"%{count} år\"\n      half_a_minute: Nettopp\n      less_than_x_minutes: \"%{count} min\"\n      less_than_x_seconds: Nettopp\n      over_x_years: \"%{count} år\"\n      x_days: \"%{count} dager\"\n      x_minutes: \"%{count} min\"\n      x_months: \"%{count} mnd\"\n      x_seconds: \"%{count} sek\"\n  deletes:\n    bad_password_msg: Godt forsøk, hacker! Feil passord\n    confirm_password: Skriv inn ditt passord for å verifisere din identitet\n    description_html: Dette vil <strong>permanent, irreversibelt</strong> fjerne innhold fra din konto og deaktivere den. Ditt brukernavn vil forbli reservert for å forhindre fremtidige etterligninger.\n    proceed: Slett konto\n    success_msg: Din konto ble slettet\n    warning_html: Kun sletting av innhold fra denne instansen er garantert. Innhold som har blitt delt i stor utstrekning vil sannsynligvis legge igjen spor. Tjenere som er frakoblet og tjenere som ikke abbonerer på dine oppdatereringer vil ikke oppdatere sine databaser.\n    warning_title: Tilgjengelighet av spredt innhold\n  errors:\n    '403': Du har ikke tillatelse til å vise denne siden.\n    '404': Siden du leter etter finnes ikke.\n    '410': Siden du leter etter finnes ikke lenger.\n    '422':\n      content: Sikkerhetsverifisering feilet. Blokkerer du informasjonskapsler?\n      title: Sikkerhetsverifisering feilet\n    '429': Overfyllt\n    '500':\n      content: Beklager men noe gikk galt ved vår ende.\n      title: Denne siden er ikke korrekt\n    noscript_html: For å bruke Mastodon webapplikasjon må du aktivere JavaScript. Alternativt kan du forsøke en av de mange <a href=\"%{apps_path}\">integrerte appene</a> for Mastodon til din plattform.\n  exports:\n    blocks: Du blokkerer\n    follows: Du følger\n    mutes: Du demper\n    storage: Medialagring\n  generic:\n    changes_saved_msg: Vellykket lagring av endringer!\n    save_changes: Lagre endringer\n    validation_errors:\n      one: Noe er ikke helt riktig ennå. Vennligst se etter en gang til\n      other: Noe er ikke helt riktig ennå. Det er ennå %{count} feil å rette på\n  imports:\n    preface: Du kan importere data om brukere du følger eller blokkerer til kontoen din på denne instansen med eksportfiler fra andre instanser.\n    success: Dine data ble mottatt og vil bli behandlet så fort som mulig\n    types:\n      blocking: Blokkeringsliste\n      following: Følgeliste\n      muting: Dempeliste\n    upload: Opplastning\n  in_memoriam_html: Til minne.\n  invites:\n    delete: Deaktiver\n    expired: Utløpt\n    expires_in:\n      '1800': 30 minutter\n      '21600': 6 timer\n      '3600': 1 time\n      '43200': 12 timer\n      '604800': 1 week\n      '86400': 1 dag\n    expires_in_prompt: Aldri\n    generate: Generer\n    max_uses:\n      one: 1 uke\n      other: \"%{count} bruk\"\n    max_uses_prompt: Ubegrenset\n    prompt: Generer og del lenker med andre for å gi tilgang til denne instansen\n    table:\n      expires_at: Utløper\n      uses: Bruk\n    title: Inviter personer\n  lists:\n    errors:\n      limit: Du har nådd det maksimale antall lister\n  media_attachments:\n    validations:\n      images_and_video: Kan ikke legge ved video på en status som allerede inneholder bilder\n      too_many: Kan ikke legge ved mer enn 4 filer\n  migrations:\n    acct: brukernavn@domene til den nye kontoen\n    currently_redirecting: 'Din profil er omdirigert til:'\n    proceed: Lagre\n    updated_msg: Dine innstillinger for kontomigrering er oppdatert!\n  moderation:\n    title: Moderasjon\n  notification_mailer:\n    digest:\n      action: Vis alle varslinger\n      body: Her er en kort oppsummering av hva du har gått glipp av siden du sist logget inn den %{since}\n      mention: \"%{name} nevnte deg i:\"\n      new_followers_summary:\n        one: I tillegg har du fått en ny følger mens du var borte. Hurra!\n        other: I tillegg har du har fått %{count} nye følgere mens du var borte! Imponerende!\n      subject:\n        one: \"1 ny hendelse siden ditt siste besøk \\U0001F418\"\n        other: \"%{count} nye hendelser siden ditt siste besøk \\U0001F418\"\n      title: I ditt fravær…\n    favourite:\n      body: 'Statusen din ble likt av %{name}:'\n      subject: \"%{name} likte statusen din\"\n      title: Ny favoritt\n    follow:\n      body: \"%{name} følger deg!\"\n      subject: \"%{name} følger deg\"\n      title: Ny følger\n    follow_request:\n      action: Behandle følgerforespørsler\n      body: \"%{name} har bedt om lov til å følge deg\"\n      subject: 'Ventende følginger: %{name}'\n      title: Ny følgerforespørsel\n    mention:\n      action: Svar\n      body: 'Du ble nevnt av %{name} i:'\n      subject: Du ble nevnt av %{name}\n      title: Ny nevning\n    reblog:\n      body: 'Din status ble fremhevd av %{name}:'\n      subject: \"%{name} fremhevde din status\"\n      title: Ny fremheving\n  pagination:\n    next: Neste\n    prev: Forrige\n  preferences:\n    other: Annet\n  remote_follow:\n    acct: Tast inn brukernavn@domene som du vil følge fra\n    missing_resource: Kunne ikke finne URLen for din konto\n    proceed: Fortsett med følging\n    prompt: 'Du vil følge:'\n  sessions:\n    activity: Siste aktivitet\n    browser: Nettleser\n    browsers:\n      generic: Ukjent nettleser\n    current_session: Nåværende økt\n    description: \"%{browser} på %{platform}\"\n    explanation: Dette er nettlesere innlogget på din Mastodon-konto akkurat nå.\n    ip: IP-adresse\n    platforms:\n      other: ukjent plattform\n    revoke: Tilbakekall\n    revoke_success: Økt tilbakekalt\n    title: Økter\n  settings:\n    authorized_apps: Autoriserte applikasjoner\n    back: Tilbake til Mastodon\n    delete: Kontosletting\n    development: Utvikling\n    edit_profile: Endre profil\n    export: Dataeksport\n    import: Importér\n    migrate: Kontomigrering\n    notifications: Varslinger\n    preferences: Preferanser\n    two_factor_authentication: Tofaktorautentisering\n  statuses:\n    open_in_web: Åpne i nettleser\n    over_character_limit: grense på %{max} tegn overskredet\n    pin_errors:\n      limit: Du har allerede festet det maksimale antall tuter\n      ownership: Kun egne tuter kan festes\n      private: Kun offentlige tuter kan festes\n      reblog: En fremheving kan ikke festes\n    show_more: Vis mer\n    visibilities:\n      private: Privat\n      private_long: Synlig kun for følgere\n      public: Offentlig\n      public_long: Synlig for alle\n      unlisted: Uoppført\n      unlisted_long: Synlig for alle, men ikke på offentlige tidslinjer\n  stream_entries:\n    pinned: Festet tut\n    reblogged: fremhevde\n    sensitive_content: Følsomt innhold\n  terms:\n    title: \"%{instance} Personvern og villkår for bruk av nettstedet\"\n  themes:\n    default: Mastodon\n  time:\n    formats:\n      default: \"%-d. %b %Y, %H:%M\"\n  two_factor_authentication:\n    code_hint: Tast koden som ble generert av din autentiseringsapp for å bekrefte\n    description_html: Hvis du skrur på <strong>tofaktorautentisering</strong> må du ha din telefon for å logge inn. Denne vil generere koder som du må taste inn.\n    disable: Skru av\n    enable: Skru på\n    enabled: To-faktor autentisering er aktivert\n    enabled_success: Aktivering av tofaktorautentisering vellykket\n    generate_recovery_codes: Generér gjenopprettingskoder\n    instructions_html: \"<strong>Scan denne QR-koden med Google Authenticator eller en lignende app på telefonen din</strong>. Fra nå av vil denne applikasjonen generere koder for deg som skal brukes under innlogging.\"\n    lost_recovery_codes: Gjenopprettingskoder lar deg gjenoppnå tilgang til din konto hvis du mister din telefon. Hvis du har mistet gjenopprettingskodene, kan du regenerere dem her. Dine gamle gjenopprettingskoder vil bli ugyldige.\n    manual_instructions: 'Hvis du ikke får scannet QR-koden må du skrive inn følgende kode manuelt:'\n    recovery_codes: Reservekoder\n    recovery_codes_regenerated: Generering av reservekoder fullført\n    recovery_instructions_html: Hvis du skulle miste tilgang til telefonen din, kan du bruke en av gjenopprettingskodene nedenfor til å gjenopprette tilgang til din konto. <strong>Oppbevar gjenopprettingskodene sikkert</strong>, for eksempel ved å skrive dem ut og gjemme dem på et lurt sted bare du vet om.\n    setup: Sett opp\n    wrong_code: Den angitte koden var ugyldig! Stemmer instansens tid overalt med enhetens tid?\n  user_mailer:\n    welcome:\n      edit_profile_action: Sett opp profil\n      edit_profile_step: Du kan tilpasse din profil ved å laste opp en avatar, overskrift, endre ditt visningsnavn med mer. Hvis du vil godkjenne hvilke personer som får lov til å følge deg kan du låse kontoen.\n      explanation: Her er noen tips for å komme i gang\n      final_action: Start postingen\n      final_step: 'Start å poste! Selv uten følgere kan dine offentlige meldinger bli sett av andre, for eksempel på den lokale tidslinjen og i emneknagger. Du kan introdusere deg selv ved å bruke emneknaggen #introductions.'\n      full_handle: Ditt fullstendige brukernavn\n      full_handle_hint: Dette er hva du forteller venner slik at de kan sende melding eller følge deg fra en annen instanse.\n      review_preferences_action: Endre innstillinger\n      review_preferences_step: Husk å justere dine innstillinger, som hvilke e-poster du ønsker å motta, eller hvor private du ønsker at dine poster skal være som standard. Hvis du ikke har bevegelsessyke kan du skru på automatisk avspilling av GIF-animasjoner.\n      subject: Velkommen til Mastodon\n      tip_federated_timeline: Den forente tidslinjen blir konstant matet med meldinger fra Mastodon-nettverket. Men den inkluderer bare personer dine naboer abbonerer på, så den er ikke komplett.\n      tip_following: Du følger din tjeners administrator(er) som standard. For å finne mer interessante personer, sjekk den lokale og forente tidslinjen.\n      tip_local_timeline: Den lokale tidslinjen blir kontant matet med meldinger fra personer på %{instance}. Dette er dine nærmeste naboer!\n      tip_mobile_webapp: Hvis din mobile nettleser tilbyr deg å legge Mastadon til din hjemmeskjerm kan du motta push-varslinger. Det er nesten som en integrert app på mange måter!\n      title: Velkommen ombord, %{name}!\n  users:\n    invalid_email: E-postaddressen er ugyldig\n    invalid_otp_token: Ugyldig to-faktorkode\n    signed_in_as: 'Innlogget som:'\n"
  },
  {
    "path": "config/locales/oc.yml",
    "content": "---\noc:\n  about:\n    about_hashtag_html: Vaquí los estatuts publics ligats a <strong>#%{hashtag}</strong>. Podètz interagir amb eles s’avètz un compte ont que siasque sul fediverse.\n    about_mastodon_html: Mastodon es un malhum social bastit amb de protocòls liures e gratuits. Es descentralizat coma los corrièls.\n    about_this: A prepaus d’aquesta instància\n    active_count_after: actius\n    active_footnote: Utilizaire actius per mes (UAM)\n    administered_by: 'Administrat per :'\n    apps: Aplicacions per mobil\n    apps_platforms: Utilizatz Mastodon d‘iOS, Android o d’autras plataforma estant\n    browse_directory: Navigatz per l’annuari de perfil e filtratz segon çò qu’aimatz\n    browse_public_posts: Navigatz pel flux public a Mastodon\n    contact: Contacte\n    contact_missing: Pas parametrat\n    contact_unavailable: Pas disponible\n    discover_users: Descobrissètz de nòvas personas\n    documentation: Documentacion\n    extended_description_html: |\n      <h3>Una bona plaça per las règlas</h3>\n      <p>La descripcion longa es pas estada causida pel moment.</p>\n    generic_description: \"%{domain} es un dels servidors del malhum\"\n    get_apps: Ensajatz una aplicacion mobil\n    hosted_on: Mastodon albergat sus %{domain}\n    learn_more: Ne saber mai\n    privacy_policy: Politica de confidencialitat\n    see_whats_happening: Agachatz çò qu’arriba\n    server_stats: 'Estatisticas del servidor :'\n    source_code: Còdi font\n    status_count_after:\n      one: estatut\n      other: estatuts\n    status_count_before: qu’an escrich\n    terms: Condicions d’utilizacion\n    user_count_after:\n      one: utilizaire\n      other: utilizaires\n    user_count_before: Ostal de\n    what_is_mastodon: Qu’es Mastodon ?\n  accounts:\n    choices_html: 'Recomandacions de %{name} :'\n    follow: Sègre\n    followers:\n      one: Seguidor\n      other: Seguidors\n    following: Abonaments\n    joined: Arribèt en %{date}\n    last_active: darrièra activitat\n    link_verified_on: La proprietat d’aqueste ligam foguèt verificada lo %{date}\n    media: Mèdias\n    moved_html: \"%{name} a mudat a %{new_profile_link} :\"\n    network_hidden: Aquesta informacion es pas disponibla\n    nothing_here: I a pas res aquí !\n    people_followed_by: Lo monde que %{name} sèc\n    people_who_follow: Lo monde que sègon %{name}\n    pin_errors:\n      following: Vos cal d’en primièr sègre las personas que volètz promòure\n    posts:\n      one: Tut\n      other: Tuts\n    posts_tab_heading: Tuts\n    posts_with_replies: Tuts e responsas\n    reserved_username: Aqueste nom d’utilizaire es reservat\n    roles:\n      bot: Robòt\n      moderator: Moderador\n    unfollow: Quitar de sègre\n  admin:\n    account_actions:\n      action: Realizar una accion\n      title: Realizar una accion de moderacion sus %{acct}\n    account_moderation_notes:\n      create: Crear una nòta\n      created_msg: Nòta de moderacion ben creada !\n      delete: Suprimir\n      destroyed_msg: Nòta de moderacion ben suprimida !\n    accounts:\n      approve: Aprovar\n      are_you_sure: Sètz segur ?\n      by_domain: Domeni\n      change_email:\n        changed_msg: Adreça corrèctament cambiada !\n        current_email: Adreça actuala\n        label: Cambiar d’adreça\n        new_email: Novèla adreça\n        submit: Cambiar l’adreça\n        title: Cambiar l’adreça a %{username}\n      confirm: Confirmar\n      confirmed: Confirmat\n      confirming: Confirmacion\n      deleted: Suprimits\n      demote: Retrogradar\n      disable: Desactivar\n      disable_two_factor_authentication: Desactivar 2FA\n      disabled: Desactivat\n      display_name: Escais-nom\n      domain: Domeni\n      edit: Modificar\n      email: Corrièl\n      email_status: Estat de l’adreça\n      enable: Activar\n      enabled: Activat\n      feed_url: Flux URL\n      followers: Seguidors\n      followers_url: URL dels seguidors\n      follows: Abonaments\n      header: Bandièra\n      inbox_url: URL de recepcion\n      invited_by: Convidat per\n      joined: Venguèt\n      location:\n        all: Totes\n        local: Locals\n        remote: Alonhats\n        title: Emplaçament\n      login_status: Estat formulari de connexion\n      media_attachments: Mèdias enviats\n      memorialize: Passar en memorial\n      moderation:\n        active: Actius\n        all: Totes\n        pending: En espèra\n        silenced: Resconduts\n        suspended: Suspenduts\n        title: Moderacion\n      moderation_notes: Nòtas de moderacion\n      most_recent_activity: Activitat mai recenta\n      most_recent_ip: IP mai recenta\n      no_limits_imposed: Cap de limit impausat\n      not_subscribed: Pas seguidor\n      outbox_url: URL Outbox\n      pending: Revision en espèra\n      perform_full_suspension: Suspendre\n      profile_url: URL del perfil\n      promote: Promòure\n      protocol: Protocòl\n      push_subscription_expires: Fin de l’abonament PuSH\n      redownload: Actualizar lo perfil\n      remove_avatar: Supriir l’avatar\n      remove_header: Levar la bandièra\n      resend_confirmation:\n        already_confirmed: Aqueste utilizaire es ja confirmat\n        send: Tornar mandar lo corrièl de confirmacion\n        success: Corrièl de confirmacion corrèctament mandat !\n      reset: Reïnicializar\n      reset_password: Reïnicializar lo senhal\n      resubscribe: Se tornar abonar\n      roles:\n        moderator: Moderador\n        staff: Personnal\n        user: Uitlizaire\n      salmon_url: URL Salmon\n      search: Cercar\n      shared_inbox_url: URL de recepcion partejada\n      show:\n        created_reports: Senhalaments creats\n        targeted_reports: Senhalaments dels autres\n      silence: Silenci\n      silenced: Rescondut\n      statuses: Estatuts\n      subscribe: S’abonar\n      suspended: Suspendut\n      title: Comptes\n      unconfirmed_email: Adreça pas confirmada\n      undo_silenced: Levar lo silenci\n      undo_suspension: Levar la suspension\n      unsubscribe: Se desabonar\n      username: Nom d’utilizaire\n      warn: Avisar\n    action_logs:\n      actions:\n        assigned_to_self_report: \"%{name} s’assignèt lo rapòrt %{target}\"\n        change_email_user: \"%{name} cambièt l’adreça de corrièl de %{target}\"\n        confirm_user: \"%{name} confirmèt l’adreça a %{target}\"\n        create_account_warning: \"%{name} mandèt un avertiment a %{target}\"\n        create_custom_emoji: \"%{name} mandèt un nòu emoji %{target}\"\n        create_domain_block: \"%{name} bloquèt lo domeni %{target}\"\n        create_email_domain_block: \"%{name} botèt a la lista nègra lo domeni de corrièl %{target}\"\n        demote_user: \"%{name} retragradèt l‘utilizaire %{target}\"\n        destroy_custom_emoji: \"%{name} destruguèt l’emoji %{target}\"\n        destroy_domain_block: \"%{name} desbloquèt lo domeni %{target}\"\n        destroy_email_domain_block: \"%{name} botèt a la lista blanca lo domeni de corrièl %{target}\"\n        destroy_status: \"%{name} levèt l‘estatut a %{target}\"\n        disable_2fa_user: \"%{name} desactivèt l’autentificacion en dos temps per %{target}\"\n        disable_custom_emoji: \"%{name} desactivèt l’emoji %{target}\"\n        disable_user: \"%{name} desactivèt la connexion per %{target}\"\n        enable_custom_emoji: \"%{name} activèt l’emoji %{target}\"\n        enable_user: \"%{name} activèt la connexion per %{target}\"\n        memorialize_account: \"%{name} transformèt en memorial la pagina de perfil a %{target}\"\n        promote_user: \"%{name} promoguèt %{target}\"\n        remove_avatar_user: \"%{name} suprimèt l’avatar a %{target}\"\n        reopen_report: \"%{name} tornèt dobrir lo rapòrt %{target}\"\n        reset_password_user: \"%{name} reïnicializèt lo senhal a %{target}\"\n        resolve_report: \"%{name} anullèt lo rapòrt %{target}\"\n        silence_account: \"%{name} metèt en silenci lo compte a %{target}\"\n        suspend_account: \"%{name} susprenguèt lo compte a %{target}\"\n        unassigned_report: \"%{name} daissèt de tractar lo rapòrt %{target}\"\n        unsilence_account: \"%{name} levèt lo silenci del compte a %{target}\"\n        unsuspend_account: \"%{name} restabliguèt lo compte a %{target}\"\n        update_custom_emoji: \"%{name} metèt a jorn l’emoji %{target}\"\n        update_status: \"%{name} metèt a jorn l’estatut a %{target}\"\n      deleted_status: \"(estatut suprimit)\"\n      title: Audit dels jornals\n    custom_emojis:\n      by_domain: Domeni\n      copied_msg: Còpia locala de l’emoji ben creada\n      copy: Copiar\n      copy_failed_msg: Fracàs de la còpia locala de l’emoji\n      created_msg: Emoji ben creat !\n      delete: Suprimir\n      destroyed_msg: Emoji ben suprimit !\n      disable: Desactivar\n      disabled_msg: Aqueste emoji es ben desactivat\n      enable: Activar\n      enabled_msg: Aqueste emoji es ben activat\n      image_hint: PNG cap a 50Ko\n      listed: Listat\n      new:\n        title: Ajustar un nòu emoji personal\n      overwrite: Remplaçar\n      shortcode: Acorchi\n      shortcode_hint: Almens 2 caractèrs, solament alfanumerics e jonhent bas\n      title: Emojis personals\n      unlisted: Pas listat\n      update_failed_msg: Mesa a jorn de l’emoji fracasada\n      updated_msg: Emoji ben mes a jorn !\n      upload: Enviar\n    dashboard:\n      backlog: Accions en retard\n      config: Configuracion\n      feature_deletions: Supressions de comptes\n      feature_invites: Ligams convidat\n      feature_profile_directory: Annuari de perfils\n      feature_registrations: Inscripcions\n      feature_relay: Relai de federacion\n      features: Foncionalitats\n      hidden_service: Federacion amb servicis amagats\n      open_reports: Senhalaments dobèrts\n      recent_users: Utilizaires recents\n      search: Recèrca tèxte complèt\n      single_user_mode: Mòde sol utilizaire\n      software: Logicial\n      space: Utilizacion de l’espaci\n      title: Tablèu de bòrd\n      total_users: total dels utilizaires\n      trends: Tendéncias\n      week_interactions: interaccions aquesta setmana\n      week_users_active: actius aquesta setmana\n      week_users_new: utilizaires aquesta setmana\n    domain_blocks:\n      add_new: Ajustar un novèl blocatge de domeni\n      created_msg: Domeni blocat es a èsser tractat\n      destroyed_msg: Lo blocatge del domeni es estat levat\n      domain: Domeni\n      new:\n        create: Crear blocatge\n        hint: Lo blocatge empacharà pas la creacion de compte dins la basa de donadas, mai aplicarà la moderacion sus aquestes comptes.\n        severity:\n          desc_html: \"<strong>Silenci</strong> farà venir invisibles los estatuts del compte al monde que son pas de seguidors. <strong>Suspendre</strong> levarà tot lo contengut del compte, los mèdias e las donadas de perfil. Utilizatz <strong>Cap</strong> se volètz regetar totes los mèdias.\"\n          noop: Cap\n          silence: Silenci\n          suspend: Suspendre\n        title: Nòu blocatge domeni\n      reject_media: Regetar los fichièrs mèdias\n      reject_media_hint: Lèva los fichièrs gardats localament e regèta las demandas de telecargament dins lo futur. Servís pas a res per las suspensions\n      reject_reports: Regetar los senhalaments\n      reject_reports_hint: Ignorar totes los senhalaments que venon d’aqueste domeni. Pas pertiment per las suspensions\n      rejecting_media: regeta los fichièrs multimèdias\n      rejecting_reports: regeta los senhalements\n      severity:\n        silence: mes en silenci\n        suspend: suspendut\n      show:\n        affected_accounts:\n          one: Un compte de la basa de donadas tocat\n          other: \"%{count} compte de la basa de donadas tocat\"\n        retroactive:\n          silence: Levar lo silenci de totes los comptes d’aqueste domeni\n          suspend: Levar la suspension de totes los comptes d’aqueste domeni\n        title: Restablir lo blocatge de domeni de %{domain}\n        undo: Restablir\n      undo: Restablir\n    email_domain_blocks:\n      add_new: Ajustar\n      created_msg: Blocatge del domeni de corrièl ben plaçat\n      delete: Suprimir\n      destroyed_msg: Blocatge del domeni de corrièl ben levat\n      domain: Domeni\n      new:\n        create: Crear un blocatge\n        title: Nòu blocatge de domeni de corrièl\n      title: Blocatge de domeni de corrièl\n    followers:\n      back_to_account: Tornar al compte\n      title: Seguidors de %{acct}\n    instances:\n      by_domain: Domeni\n      delivery_available: Liurason disponibla\n      known_accounts:\n        one: \"%{count} compte conegut\"\n        other: \"%{count} comptes coneguts\"\n      moderation:\n        all: Totas\n        limited: Limitat\n        title: Moderacion\n      title: Federacion\n      total_blocked_by_us: Avèm blocat\n      total_followed_by_them: Sègon\n      total_followed_by_us: Seguèm\n      total_reported: Senhalament a prepaus d’eles\n      total_storage: Fichièrs junts\n    invites:\n      deactivate_all: O desactivar tot\n      filter:\n        all: Totes\n        available: Disponibles\n        expired: Expirats\n        title: Filtre\n      title: Convits\n    relays:\n      add_new: Ajustar un nòu relai\n      delete: Suprimir\n      description_html: Un <strong> relai de federacion</strong> es un servidor intermediari qu’escàmbia de bèls volumes de tuts publics entre servidors que son abonats e i publican.<strong>Pòt ajudar de pichons e mejans servidors a trobar de contenguts del fediverse estant</strong>, qu’autrament demandariá als utilizaires locals de s’abonar manualament a d’autres monde marcats sus de servidors alonhats.\n      disable: Desactivar\n      disabled: Desactivat\n      enable: Activar\n      enable_hint: Un còp activat, vòstre servidor s’abonarà a totes los tuts publics del relai estant, e començarà de mandar sos tuts publics a aqueste d’enlà.\n      enabled: Activat\n      inbox_url: URL del relai\n      pending: En espèra d’aprovacion del relai\n      save_and_enable: Salvar e activar\n      setup: Configurar una connexion relai\n      status: Estatut\n      title: Relais\n    report_notes:\n      created_msg: Nòta de moderacion corrèctament creada !\n      destroyed_msg: Nòta de moderacion corrèctament suprimida !\n    reports:\n      account:\n        note: nòta\n        report: rapòrt\n      action_taken_by: Mesura menada per\n      are_you_sure: Es segur ?\n      assign_to_self: Me l’assignar\n      assigned: Moderador assignat\n      comment:\n        none: Pas cap\n      created_at: Creacion\n      mark_as_resolved: Marcar coma resolgut\n      mark_as_unresolved: Marcar coma pas resolgut\n      notes:\n        create: Ajustar una nòta\n        create_and_resolve: Resòlvre amb una nòta\n        create_and_unresolve: Tornar dobrir amb una nòta\n        delete: Escafar\n        placeholder: Explicatz las accions que son estadas menadas o quicòm de ligat al senhalament…\n      reopen: Tornar dobrir lo rapòrt\n      report: 'Senhalament #%{id}'\n      reported_account: Compte senhalat\n      reported_by: Senhalat per\n      resolved: Resolgut\n      resolved_msg: Rapòrt corrèctament resolgut !\n      status: Estatut\n      title: Senhalament\n      unassign: Levar\n      unresolved: Pas resolgut\n      updated_at: Actualizat\n    settings:\n      activity_api_enabled:\n        desc_html: Nombre d’estatuts publicats, d’utilizaires actius e de novèlas inscripcions en rapòrt setmanièr\n        title: Publicar las estatisticas totalas de l’activitat dels utilizaires\n      bootstrap_timeline_accounts:\n        desc_html: Separatz los noms d’utilizaire amb de virgula. Pas que los comptes locals e pas clavats foncionaràn. Se lo camp es void los admins seràn selecionats.\n        title: Per defaut los nòuvenguts sègon\n      contact_information:\n        email: Picatz una adreça de corrièl\n        username: Picatz un nom d’utilizaire\n      custom_css:\n        desc_html: Modificar l’estil amb una fuèlha CSS cargada sus cada pagina\n        title: CSS personalizada\n      hero:\n        desc_html: Mostrat en primièra pagina. Almens 600x100px recomandat. S’es pas configurat l’imatge del servidor serà mostrat\n        title: Imatge de l’eròi\n      mascot:\n        desc_html: Mostrat sus mantun paginas. Almens 293×205px recomandat. S’es pas configurat, mostrarem la mascòta per defaut\n        title: Imatge de la mascòta\n      peers_api_enabled:\n        desc_html: Noms de domeni qu’aqueste servidor a trobats pel fediverse\n        title: Publicar la lista dels servidors coneguts\n      preview_sensitive_media:\n        desc_html: Los apercebuts dels ligams sus los autres sites mostraràn una vinheta encara que lo mèdia siá marcat coma sensible\n        title: Mostrar los mèdias sensibles dins los apercebuts OpenGraph\n      profile_directory:\n        desc_html: Permet als utilizaires d’èsser trobats\n        title: Activar l’annuari de perfils\n      registrations:\n        closed_message:\n          desc_html: Mostrat sus las pagina d’acuèlh quand las inscripcions son tampadas.<br>Podètz utilizar de balisas HTML\n          title: Messatge de barradura de las inscripcions\n        deletion:\n          desc_html: Autorizar lo monde a suprimir lor compte\n          title: Possibilitat de suprimir lo compte\n        min_invite_role:\n          disabled: Degun\n          title: Autorizat amb invitacions\n      registrations_mode:\n        modes:\n          none: Degun pòt pas se marcar\n        title: Mòdes d’inscripcion\n      show_known_fediverse_at_about_page:\n        desc_html: Un còp activat mostrarà los tuts de totes los fediverse dins l’apercebut. Autrament mostrarà pas que los tuts locals.\n        title: Mostrar los fediverse coneguts dins l’apercebut del flux\n      show_staff_badge:\n        desc_html: Mostrar lo badge Personal sus la pagina de perfil\n        title: Mostrar lo badge personal\n      site_description:\n        desc_html: Paragraf d’introduccion sus la pagina d’acuèlh. Explicatz çò que fa diferent aqueste servidor Mastodon e tot çò qu’es important de dire. Podètz utilizare de balises HTML, en particular <code>&lt;a&gt;</code> e<code>&lt;em&gt;</code>.\n        title: Descripcion del servidor\n      site_description_extended:\n        desc_html: Un bon lòc per las règles de compòrtament e d’autras causas que fan venir vòstre servidor diferent. Podètz utilizar de balisas HTML\n        title: Descripcion espandida del site\n      site_short_description:\n        desc_html: Mostrat dins la barra laterala e dins las meta balisas. Explica çò qu’es Mastodon e perque aqueste servidor es especial en un solet paragraf. S’es void, serà garnit amb la descripcion del servidor.\n        title: Descripcion corta del servidor\n      site_terms:\n        desc_html: Afichada sus la pagina de las condicions d’utilizacion<br>Podètz utilizar de balisas HTML\n        title: Politica de confidencialitat del site\n      site_title: Títol del servidor\n      thumbnail:\n        desc_html: Servís pels apercebuts via OpenGraph e las API. Talha de 1200x630px recomandada\n        title: Miniatura del servidor\n      timeline_preview:\n        desc_html: Mostrar lo flux public sus la pagina d’acuèlh\n        title: Apercebut flux public\n      title: Paramètres del site\n    statuses:\n      back_to_account: Tornar a la pagina Compte\n      batch:\n        delete: Suprimir\n        nsfw_off: Marcar coma pas sensible\n        nsfw_on: Marcar coma sensible\n      failed_to_execute: Fracàs\n      media:\n        title: Mèdia\n      no_media: Cap de mèdia\n      no_status_selected: Cap d’estatut pas cambiat estant que cap èra pas seleccionat\n      title: Estatuts del compte\n      with_media: Amb mèdia\n    subscriptions:\n      callback_url: URL de rapèl\n      confirmed: Confirmat\n      expires_in: S’acaba dins\n      last_delivery: Darrièra distribucion\n      topic: Subjècte\n    tags:\n      accounts: Comptes\n      hidden: Amagat\n      hide: Amagar dins l’annuari\n      name: Etiqueta\n      title: Etiquetas\n      unhide: Aparéisser dins l’annuari\n    title: Administracion\n    warning_presets:\n      add_new: N’ajustar un nòu\n      delete: Escafar\n      edit: Modificar\n      edit_preset: Modificar lo tèxt predefinit d’avertiment\n      title: Gerir los tèxtes predefinits\n  admin_mailer:\n    new_report:\n      body: \"%{reporter} a senhalat %{target}\"\n      body_remote: Qualqu’un de %{domain} senhalèt %{target}\n      subject: Novèl senhalament per %{instance} (#%{id})\n  application_mailer:\n    notification_preferences: Cambiar las preferéncias de corrièl\n    settings: 'Cambiar las preferéncias de corrièl : %{link}'\n    view: 'Veire :'\n    view_profile: Veire lo perfil\n    view_status: Veire los estatuts\n  applications:\n    created: Aplicacion ben creada\n    destroyed: Aplication corrcètament suprimida\n    invalid_url: L’URL donada es invalida\n    regenerate_token: Tornar generar lo geton d’accès\n    token_regenerated: Geton d’accès ben regenerat\n    warning: Mèfi ! Agachatz de partejar aquela donada amb degun !\n    your_token: Vòstre geton d’accès\n  auth:\n    apply_for_account: Demandar una invitacion\n    change_password: Senhal\n    checkbox_agreement_html: Accepti las <a href=\"%{rules_path}\" target=\"_blank\">règlas del servidor</a> e <a href=\"%{terms_path}\" target=\"_blank\">los tèrmes del servici</a>\n    confirm_email: Confirmar lo corrièl\n    delete_account: Suprimir lo compte\n    delete_account_html: Se volètz suprimir vòstre compte, podètz <a href=\"%{path}\">o far aquí</a>. Vos demandarem que confirmetz.\n    didnt_get_confirmation: Avètz pas recebut las instruccions de confirmacion ?\n    forgot_password: Senhal oblidat ?\n    invalid_reset_password_token: Lo geton de reïnicializacion es invalid o acabat. Tornatz demandar un geton se vos plai.\n    login: Se connectar\n    logout: Se desconnectar\n    migrate_account: Mudar endacòm mai\n    migrate_account_html: Se volètz mandar los visitors d’aqueste compte a un autre, podètz<a href=\"%{path}\"> o configurar aquí</a>.\n    or_log_in_with: O autentificatz-vos amb\n    register: Se marcar\n    registration_closed: \"%{instance} accepta pas de nòus membres\"\n    resend_confirmation: Tornar mandar las instruccions de confirmacion\n    reset_password: Reïnicializar lo senhal\n    security: Seguretat\n    set_new_password: Picar un nòu senhal\n    trouble_logging_in: Problèmas de connexion ?\n  authorize_follow:\n    already_following: Seguètz ja aqueste compte\n    error: O planhèm, i a agut una error al moment de cercar lo compte\n    follow: Sègre\n    follow_request: 'Avètz demandat de sègre :'\n    following: 'Felicitacion ! Seguètz ara :'\n    post_follow:\n      close: O podètz tampar aquesta fenèstra.\n      return: Veire lo perfil a la persona\n      web: Tornar a l’interfàcia Web\n    title: Sègre %{acct}\n  datetime:\n    distance_in_words:\n      about_x_hours: \"%{count} h\"\n      about_x_months: \"%{count} meses\"\n      about_x_years: \"%{count} ans\"\n      almost_x_years: \"%{count} ans\"\n      half_a_minute: Ara\n      less_than_x_minutes: \"%{count} min\"\n      less_than_x_seconds: Ara meteis\n      over_x_years: \"%{count} ans\"\n      x_days: \"%{count} jorns\"\n      x_minutes: \"%{count} min\"\n      x_months: \"%{count} meses\"\n  deletes:\n    bad_password_msg: Ben ensajat pirata ! Senhal incorrècte\n    confirm_password: Picatz vòstre senhal actual per verificar vòstra identitat\n    description_html: Aquò suprimirà <strong>definitivament e sens possibilitat de retorn</strong> lo contengut de vòstre compte e lo desactivarà. Lo nom d’utilizaire serà gardat per evitar una futura impostura.\n    proceed: Suprimir lo compte\n    success_msg: Compte ben suprimit\n    warning_html: La supression del contengut d’aqueste servidor es sola assegurada. Lo contengut fòrça partejat daissarà probablament de traças. Los servidors fòra-linha e los que vos sègon pas mai auràn pas la mesa a jorn de lor basa de donada.\n    warning_title: Disponibilitat del contengut difusat\n  directories:\n    directory: Annuari de perfils\n    enabled: Sètz actualament listat dins l'annuari.\n    enabled_but_waiting: Avètz causit d'èsser listat dins l'annuari mas avètz pas encara lo nombre minimum de seguidors (%{min_followers}) per i èsser listat.\n    explanation: Trobar d’utilizaires segon lor interèsses\n    explore_mastodon: Explorar %{title}\n    how_to_enable: Sètz pas actualament listat dins l’annuari. Podètz cambiar aquò çai-jos. Utilizatz d'etiquetas dins vòstre tèxt de bio per èsser listat amb d’etiquetas especificas !\n    people:\n      one: \"%{count} persona\"\n      other: \"%{count} personas\"\n  errors:\n    '403': Avètz pas l’autorizacion de veire aquesta pagina.\n    '404': La pagina que cercatz existís pas aquí.\n    '410': La pagina que cercatz existís pas mai aquí.\n    '422':\n      content: Verificacion de seguretat fracassada. Blocatz los cookies ?\n      title: Verificacion de seguretat fracassada\n    '429': Lo servidor mòla (subrecargada)\n    '500':\n      content: Un quicomet a pas foncionat coma caliá.\n      title: Aquesta pagina es pas corrècta\n    noscript_html: Per utilizar l’aplicacion web de Mastodon, mercés d’activar JavaScript. O podètz utilizar <a href=\"%{apps_path}\">una aplicacion</a> per vòstra plataforma coma alernativa.\n  exports:\n    archive_takeout:\n      date: Data\n      download: Telecargar vòstre archiu\n      hint_html: Podètz demandar un archiu de vòstres <strong>tuts e mèdias enviats</strong>. Las donadas exportadas seràn al format ActivityPub, ligible pels logicials compatibles. Podètz demandar un archiu cada 7 jorns.\n      in_progress: Complilacion de vòstre archiu...\n      request: Demandar vòstre archiu\n      size: Talha\n    blocks: Personas que blocatz\n    domain_blocks: Blocatge de domenis\n    follows: Personas que seguètz\n    lists: Listas\n    mutes: Personas rescondudas\n    storage: Mèdias gardats\n  featured_tags:\n    add_new: Ajustar una etiqueta nòva\n    errors:\n      limit: Avètz ja utilizat lo maximum d’etiquetas\n  filters:\n    contexts:\n      home: Flux d’acuèlh\n      notifications: Notificacions\n      public: Flux public\n      thread: Conversacions\n    edit:\n      title: Modificar lo filtre\n    errors:\n      invalid_context: Cap de contèxte o contèxte invalid fornit\n      invalid_irreversible: Lo filtratge irreversible fonciona pas qu’amb lo flux d’actualitat o en contèxte de notificacion\n    index:\n      delete: Suprimir\n      title: Filtres\n    new:\n      title: Ajustar un nòu filtre\n  footer:\n    developers: Desvolopaires\n    more: Mai…\n    resources: Ressorsas\n  generic:\n    all: Tot\n    changes_saved_msg: Cambiaments ben realizats !\n    copy: Copiar\n    save_changes: Salvar los cambiaments\n    validation_errors:\n      one: I a quicòm que truca ! Mercés de corregir l’error çai-jos\n      other: I a quicòm que truca ! Mercés de corregir las %{count} errors çai-jos\n  identity_proofs:\n    authorize: Òc, autorizar\n    authorize_connection_prompt: Autorizar aquesta connexion criptografica ?\n    i_am_html: Soi %{username} a %{service}.\n    identity: Identitat\n    status: Estatut de verificacion\n  imports:\n    modes:\n      merge: Fondre\n      merge_long: Gardar los enregistraments existents e ajustar los nòus\n      overwrite: Remplaçar\n      overwrite_long: Remplaçar los enregistraments actuals pels nòus\n    preface: Podètz importar qualques donadas d’un autre servidor, coma lo monde que seguètz o blocatz.\n    success: Vòstras donadas son ben estadas mandadas e seràn tractadas tre que possible\n    types:\n      blocking: Lista de blocatge\n      domain_blocking: Lista dels domenis blocats\n      following: Lista de monde que seguètz\n      muting: Lista de monde que volètz pas legir\n    upload: Importar\n  in_memoriam_html: En Memòria.\n  invites:\n    delete: Desactivar\n    expired: Expirat\n    expires_in:\n      '1800': 30 minutas\n      '21600': 6 oras\n      '3600': 1 ora\n      '43200': 12 oras\n      '604800': 1 setmana\n      '86400': 1 jorn\n    expires_in_prompt: Jamai\n    generate: Generar\n    invited_by: 'Vos a convidat :'\n    max_uses:\n      one: 1 persona\n      other: \"%{count} personas\"\n    max_uses_prompt: Cap de limit\n    prompt: Generar e partejar los ligams per donar accès a aqueste servidor\n    table:\n      expires_at: Expirats\n      uses: Usatges\n    title: Convidar de monde\n  lists:\n    errors:\n      limit: Avètz atengut lo maximum de listas\n  media_attachments:\n    validations:\n      images_and_video: Se pòt pas ajustar una vidèo a un estatut que ten ja d’imatges\n      too_many: Se pòt pas ajustar mai de 4 fichièrs\n  migrations:\n    acct: nomutilizaire@domeni del nòu compte\n    currently_redirecting: 'Vòstre perfil es parametrat per mandar a :'\n    proceed: Enregistrar\n    updated_msg: Vòstre paramètre de migracion es ben estat mes a jorn !\n  moderation:\n    title: Moderacion\n  notification_mailer:\n    digest:\n      action: Veire totas las notificacions\n      body: Trobatz aquí un resumit dels messatges qu’avètz mancats dempuèi vòstra darrièra visita lo %{since}\n      mention: \"%{name} vos a mencionat dins :\"\n      new_followers_summary:\n        one: Avètz un nòu seguidor dempuèi vòstra darrièra visita ! Ouà !\n        other: Avètz %{count} nòus seguidors dempuèi vòstra darrièra visita ! Qué crane !\n      subject:\n        one: \"Una nòva notificacion dempuèi vòstra darrièra visita \\U0001F418\"\n        other: \"%{count} nòvas notificacions dempuèi vòstra darrièra visita \\U0001F418\"\n      title: Pendent vòstra abséncia…\n    favourite:\n      body: \"%{name} a mes vòstre estatut en favorit :\"\n      subject: \"%{name} a mes vòstre estatut en favorit\"\n      title: Novèl apondut als favorits\n    follow:\n      body: \"%{name} vos sèc ara !\"\n      subject: \"%{name} vos sèc ara\"\n      title: Nòu seguidor\n    follow_request:\n      action: Gerir las demandas d’abonament\n      body: \"%{name} a demandat a vos sègre\"\n      subject: 'Demandas en espèra : %{name}'\n      title: Novèla demanda d’abonament\n    mention:\n      action: Respondre\n      body: \"%{name} vos a mencionat dins :\"\n      subject: \"%{name} vos a mencionat\"\n      title: Novèla mencion\n    reblog:\n      body: \"%{name} a tornat partejar vòstre estatut :\"\n      subject: \"%{name} a tornat partejar vòstre estatut\"\n      title: Novèl partatge\n  pagination:\n    newer: Mai recents\n    next: Seguent\n    older: Mai ancians\n    prev: Precedent\n  polls:\n    errors:\n      already_voted: Avètz ja votat per aqueste sondatge\n      duplicate_options: conten d’opcions en doble\n      duration_too_long: es tròp alonhat dins lo futur\n      duration_too_short: es tròp d’ora\n      expired: Lo sondatge es ja acabat\n      over_character_limit: pòt pas èsser superior a %{max} caractèrs cadun\n      too_few_options: deu contenir mai d’una opcion\n      too_many_options: pòt pas contenir mai de %{max} opcions\n  preferences:\n    other: Autre\n  relationships:\n    activity: Activitat del compte\n    dormant: Inactiu\n    moved: Mudat\n    mutual: Mutuala\n    primary: Pirmària\n    relationship: Relacion\n    status: Estat del compte\n  remote_follow:\n    acct: Picatz vòstre utilizaire@domeni que que volètz utilizar per sègre aqueste utilizaire\n    missing_resource: URL de redireccion pas trobada\n    no_account_html: Avètz pas cap de compte ? Podètz <a href='%{sign_up_path}' target='_blank'>vos marcar aquí</a>\n    proceed: Clicatz per sègre\n    prompt: 'Sètz per sègre :'\n    reason_html: \"<strong>Perque aquesta etapa es necessària ?</strong><code>%{instance}</code> es benlèu pas lo servidor ont vos marquèretz, doncas nos cal vos redirigir cap a vòstre prim servidor per començar.\"\n  remote_interaction:\n    favourite:\n      proceed: Contunhar per metre en favorit\n      prompt: 'Volètz metre en favorit aqueste tut :'\n    reblog:\n      proceed: Contunhar per repartejar\n      prompt: 'Volètz repartejar aqueste tut :'\n    reply:\n      proceed: Contunhar per respondre\n      prompt: 'Volètz respondre a aqueste tut :'\n  remote_unfollow:\n    title: Títol\n    unfollowed: Pas mai seguit\n  scheduled_statuses:\n    over_daily_limit: Avètz passat la limita de %{limit}  tuts programats per aquel jorn\n    over_total_limit: Avètz passat la limita de %{limit}  tuts programats\n    too_soon: La data planificada deu èsser dins lo futur\n  sessions:\n    activity: Darrièra activitat\n    browser: Navigator\n    browsers:\n      generic: Navigator desconegut\n    current_session: Session en cors\n    description: \"%{browser} sus %{platform}\"\n    explanation: Aquí los navigators connectats a vòstre compte Mastodon.\n    platforms:\n      other: plataforma desconeguda\n    revoke: Revocar\n    revoke_success: Session ben revocada\n  settings:\n    authorized_apps: Aplicacions autorizadas\n    back: Tornar a Mastodon\n    delete: Supression de compte\n    development: Desvolopament\n    edit_profile: Modificar lo perfil\n    export: Exportar de donadas\n    featured_tags: Etiquetas en avant\n    import: Importar de donadas\n    migrate: Migracion de compte\n    notifications: Notificacions\n    preferences: Preferéncias\n    relationships: Abonaments e seguidors\n    two_factor_authentication: Autentificacion en dos temps\n  statuses:\n    attached:\n      description: 'Ajustat : %{attached}'\n      image:\n        one: \"%{count} imatge\"\n        other: \"%{count} imatges\"\n      video:\n        one: \"%{count} vidèo\"\n        other: \"%{count} vidèos\"\n    boosted_from_html: Partejat de %{acct_link}\n    content_warning: 'Avertiment de contengut : %{warning}'\n    disallowed_hashtags:\n      one: 'conten una etiqueta desactivada : %{tags}'\n      other: 'conten las etiquetas desactivadas : %{tags}'\n    language_detection: Detectar automaticament la lenga\n    open_in_web: Dobrir sul web\n    over_character_limit: limit de %{max} caractèrs passat\n    pin_errors:\n      limit: Avètz ja lo maximum de tuts penjats\n      ownership: Se pòt pas penjar lo tut de qualqu’un mai\n      private: Se pòt pas penjar los tuts pas publics\n      reblog: Se pòt pas penjar un tut partejat\n    poll:\n      total_votes:\n        one: \"%{count} vòte\"\n        other: \"%{count} vòtes\"\n      vote: Votar\n    show_more: Ne veire mai\n    sign_in_to_participate: Inscrivètz-vos per participar a la conversacion\n    title: '%{name} : \"%{quote}\"'\n    visibilities:\n      private: Seguidors solament\n      private_long: Mostrar pas qu’als seguidors\n      public_long: Tot lo monde pòt veire\n      unlisted: Pas listat\n      unlisted_long: Tot lo monde pòt veire mai serà pas visible sul flux public\n  stream_entries:\n    pinned: Tut penjat\n    reblogged: a partejat\n    sensitive_content: Contengut sensible\n  terms:\n    body_html: |\n      <h2>Politica de confidencialitat</h2>\n      <h3 id=\"collect\">Quinas informacions reculhèm ?</h3>\n\n      <ul>\n      <li><em>Inforacions de basa del compte</em> :  se vos marcatz sus aqueste servidor, vos podèm demandar de picar un escais-nom, una adreça de corrièl e un senhal. Podètz tanben ajustar d’informacions de perfil addicionalas coma un nom de far veire, una biografia, un imatge de perfil e una banièra. L’escais-nom, lo nom d’afichatge, la biografia, l’imatge de perfil e la banièra son totjorn indicats per èsser vistes publicament.</li>\n      <li><em>Publicacions, abonaments e autras informacions publicas</em> : La lista del monde que seguètz es visibla publicament, tot parièr per vòstres seguidors. Quand enviatz un messatge, la data e l’ora son gardats, l’aplicacion qu’avètz utilizada tanben. Los messatges pòdon conténer de mèdias juntats coma d’imatge e vidèos. Las publicacions publicas e pas listadas son disponiblas publicament. Quand penjatz una publicacion per vòstre perfil, aquò tanben es visible per tot lo monde. Vòstras publicacions son mandadas a vòstre seguidors, dins qualques cases aquò significa que passaràn per diferents servidors e seràn copiadas e gardadas sus aqueles servidors. Quand escafatz de publicacions, aquò es tanben mandat a vòstre seguidors. L’accion de partejar o d’ajustar als favorits una publicacion es totjorn quicòm de public.</li>\n      <li><em>Publicacions dirèctas e solament pels seguidors</em> :</li> totas las publicacions son gardadas e tractadas pel servidor. Las publicacions pas que per vòstres seguidors son enviadas a vòstres seguidors e las personas mencionadas dedins, las publicacions dirèctas son pas qu’enviadas a las personas mencionadas. Dins qualques cases aquò significa que passaràn per diferents servidors, copiadas e gardadas sus eles. Ensagem de limitar l’accès a aquelas publicacions a monde autorizat, mas los demai servidors pòdon fracar a far parièr. A causa d’aquò es fòrça important de repassar los servidors d’apertenéncia de vòstres seguidors. Podètz activar una opcion per autorizar o regetar una demanda de seguiment dins los paramètres. <em>Vos cal pas oblidar que’ls administrators dels servidors e dels servidors de recepcion pòdon veire aqueles messatges</em>, e que’ls destinataris pòdon realizar de captura d’ecran, copiar e tornar partejar los messatges.<em>Partegetz pas cap informacion perilhosa sus Mastodon</em><li>.\n      <li><em>Adreças IP e autras metadonadas</em> : quand vos connectatz, enregistrem l’adreça IP qu’utilizatz per establir la connexion, e tanben lo nom de vòstre navigador. Totas las sessions de connexion son disponiblas per que las repassetz e tiretz dins los paramètres. Las darrièras adreças IP son salvagardas fins a 12 meses. Podèm tanben gardar de jornals d’audit del servidor que pòdon conténer las adreças IP de cada requèstas mandadas a nòstre servidor.</li>\n\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"use\">Qué fasèm de vòstras informacions ?</h3>\n\n      <p>Totas las informacions que collectem de vos pòdon servir dins los cases seguents :</p>\n\n      <ul>\n      <li>Per provesir la foncionament màger de Mastodon. Podètz pas qu’interagir amb lo contengut del monde e de vòstras publicacions quand sètz connectat. Per exemple, avètz la possibilitat de sègre de monde per veire lors publicacions amassadas dins vòstre flux d’actualitat personalizat.</li>\n      <li>Per ajudar la moderacion de la comunitat, per exemple en comparant vòstra adreça IP amb d’autras per determinar d’ensages de contornament de bandiment e d’autras violéncias.</li>\n      <li>Podèm utilizar l’adreça qu’avètz donada per vos enviar d’informacions e de notificacions que demandatz tocant de cambiaments dins los subjèctes del forum o en responsa a vòstre nom d’utilizaire, en responsa a una demanda, e/o tota autra question.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"protect\">Cossí protegèm vòstras informacions ?</h3>\n\n      <p>Apliquem tota una mena de mesuras de seguretat per manténer la fisança de vòstras informacions personalas quand las picatz, mandatz, o i accedètz. Entre aquelas, vòstre session de navigacion, coma lo trafic entre vòstra aplicacion e l’API, son securizats amb SSL e lo senhal es copat en tròces en emplegar un algorisme fòrt a sens unic. Podètz activar l’autentificacion en dos temps pels accèsses futurs a vòstre compte.</p>\n      <hr class=\"spacer\" />\n\n      <h3 id=\"data-retention\">Quala es nòstra politica de conservacion de donadas ?</h3>\n\n      <p>Farem esfòrces per :</p>\n\n      <ul>\n      <li>Gardar los jornals del servidor que contenon las adreças IP de totas las demandas al servidor pas mai de 90 jorns.</li>\n      <li>Gardar las adreças IP ligadas als utilizaires e lors publicacions pas mai de 12 messes.</li>\n      </ul>\n\n      <p>Podètz demandar e telecargar vòstre archiu de contengut, amb vòstras publicacions, los mèdias enviats, l’imatge de perfil e l’imatge de bandièra.</p>\n\n      <p>Podètz suprimir sens anullacion possibla vòstre compte quand volgatz.</p>\n\n      <hr class=\"spacer\"/>\n\n\n      <h3 id=\"cookies\">Utilizem de cookies ?</h3>\n\n      <p>Òc-ben. Los cookies son de pichons fichièrs qu’un site o sos provesidors de servicis plaçan dins lo disc dur de vòstre ordenador via lo navigator Web (Se los acceptatz). Aqueles cookies permeton al site de reconéisser vòstre navigator e se tenètz un compte enregistrat de l’associar a vòstre compte.</p>\n\n      <p>Empleguem de cookies per comprendre e enregistrar vòstras preferéncias per vòstras visitas venentas</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"disclose\">Divulguem d’informacions a de tèrces ?</h3>\n\n\n      <p>Vendèm pas, comercem o qualque transferiment que siasque a de tèrces vòstras informacions personalas identificablas. Aquò inclutz pas los tèrces partits de confisança que nos assiston a menar nòstre site, menar nòstre afar o vos servir, baste que son d’acòrd per gardar aquelas informacions confidencialas. Pòt tanben arribar que liberèssem vòstras informacions quand cresèm qu’es apropriat d’o far per se sometre a la lei, per refortir nòstras politicas, o per protegir los dreches, proprietats o seguritat de qualqu’un o de nosautres.</p>\n\n      <p>Vòstre contengut public pòt èsser telecargat per los autres servidors del malhum. Vòstras publicacions publicas e las dels seguidors solament son enviadas als servidors qu’albergan vòstres seguidors, los messatges dirèctes son mandats als servidors dels destinaris se son pas de vòstra instància.</p>\n\n      <p>Quand autorizatz una aplicacion d’utilizar vòstre compte, segon l’encastre que volètz permetre, pòt accedir a l’informacion de vòstre perfil public, vòstra lista d’abonaments, vòstres seguidors, vòstras listas, totas vòstras publicacions e vòstres favorits. Las aplicacions pòdon pas jamai accedir a vòstra adreça electronica o vòstre senhal.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"children\">Utilizacion del site pels enfants</h3>\n\n      <p>S’aqueste servidor es en EU o la EEA : òstre site, nòstres produches e servicis son totas a destinacion de monde de mai de 16 ans. S’avètz mens de 16 ans, per cumplir lo RGPD (<a href=\"https://ca.wikipedia.org/wiki/Reglament_General_de_Protecci%C3%B3_de_Dades\">Reglament General de Proteccion de Donadas</a>) utilizetz pas aqueste site.</p>\n\n      <p>S’aqueste servidor se tròba en los Estats Units : nòstre site, nòstres produches e servicis son totas a destinacion de monde de mai de 13 ans. S’avètz mens de 13 ans, per acontentar las exigéncias del COPPA (<a href=\"https://en.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act\">Children's Online Privacy Protection Act</a>) utilizetz pas aqueste site.</p>\n\n      <p>Las exigéncias legalas pòdon èsser diferentas se lo servidor es en una autra juridiccion</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"changes\">Cambiament dins nòstra politica de confidencialitat</h3>\n\n      <p>Se decidèm de cambiar nòstra politica de confidencialitat, publicarem los cambiaments sus aquesta pagina.</p>\n\n      <p>Aqueste document es jos licéncia CC-BY-SA. Darrièra mesa a jorn lo 4 de març de 2018</p>\n\n      <p>Prima adaptacion de la <a href=\"https://github.com/discourse/discourse\">politica de confidencialitat de Discourse</a>.</p>\n    title: Condicions d’utilizacion e politica de confidencialitat de %{instance}\n  themes:\n    contrast: Mastodon (Fòrt contrast)\n    default: Mastodon (Escur)\n    mastodon-light: Mastodon (Clar)\n  time:\n    formats:\n      default: Lo %d %b de %Y a %Ho%M\n  two_factor_authentication:\n    code_hint: Picatz lo còdi generat per vòstra aplicacion d’autentificacion per confirmar\n    description_html: S’activatz <strong> l’autentificacion two-factor</strong>, vos caldrà vòstre mobil per vos connectar perque generarà un geton per vos daissar dintrar.\n    disable: Desactivar\n    enable: Activar\n    enabled: Autentificacion en dos temps activada\n    enabled_success: L’autentificacion en dos temps es ben activada\n    generate_recovery_codes: Generar los còdis de recuperacion\n    instructions_html: \"<strong>Escanatz aqueste còdi QR amb Google Authenticator o una aplicacion similària sus vòstre mobil</strong>. A partir d’ara, aquesta aplicacion generarà un geton que vos caldrà picar per vos connectar.\"\n    lost_recovery_codes: Los còdi de recuperacion vos permeton d’accedir a vòstre compte se perdètz vòstre mobil. S’avètz perdut vòstres còdis de recuperacion los podètz tornar generar aquí. Los ancians còdis seràn pas mai valides.\n    manual_instructions: 'Se podètz pas numerizar lo còdi QR e que vos cal picar lo còdi a la man, vaquí lo còdi en clar :'\n    recovery_codes: Salvar los còdis de recuperacion\n    recovery_codes_regenerated: Los còdis de recuperacion son ben estats tornats generar\n    recovery_instructions_html: Se vos arriba de perdre vòstre mobil, podètz utilizar un dels còdis de recuperacion cai-jos per poder tornar accedir a vòstre compte. <strong>Gardatz los còdis en seguretat</strong>, per exemple, imprimissètz los e gardatz los amb vòstres documents importants.\n    setup: Parametrar\n    wrong_code: Lo còdi picat es invalid ! L’ora es bona sul servidor e lo mobil ?\n  user_mailer:\n    backup_ready:\n      explanation: Avètz demandat una salvagarda complèta de vòstre compte Mastodon. Es prèsta per telecargament !\n      subject: Vòstre archiu es prèst per telecargament\n      title: Archiu per emportar\n    warning:\n      explanation:\n        disable: Quand vòstre compte es gelat, las donadas d’aqueste demòran senceras, mas podètz pas realizar cap d’accion fins que siá desblocat.\n        silence: Del temps que vòstre compte es limitat, solament lo monde que vos sègon veiràn vòstres tuts sus aqueste servidor, e poiriatz èsser tirat de mantunas listas publicas. Pasmens, d’autres vos pòdon sègre manualament.\n        suspend: Vòstre compte es suspendut e totes vòstres tuts e fichièrs enviats son estats suprimits sens retorn possible d’aqueste servidor e los de vòstres seguidors.\n      review_server_policies: Repassar las politicas del servidor\n      subject:\n        disable: Vòstre compte %{acct} es gelat\n        none: Avertiment per %{acct}\n        silence: Vòstre compte %{acct} es limitat\n        suspend: Vòstre compte %{acct} es suspendut\n      title:\n        disable: Compte gelat\n        none: Avertiment\n        silence: Compte limitat\n        suspend: Compte suspendut\n    welcome:\n      edit_profile_action: Configuracion del perfil\n      edit_profile_step: Podètz personalizar lo perfil en mandar un avatard, cambiar l’escais-nom e mai. Se volètz repassar las demandas d’abonaments abans que los nòus seguidors pòscan veire vòstre perfil, podètz clavar vòstre compte.\n      explanation: Vaquí qualques astúcias per vos preparar\n      final_action: Començar de publicar\n      final_step: 'Començatz de publicar ! Quitament s’avètz pas de seguidors los autres pòdon veire vòstres messatges publics, per exemple pel flux d’actualitat local e per las etiquetas. Benlèu que volètz vos presentar amb l’etiquetas #introductions.'\n      full_handle: Vòstre escais-nom complèt\n      full_handle_hint: Es aquò que vos cal donar a vòstres amics per que pòscan vos escriure o sègre a partir d’un autre servidor.\n      review_preferences_action: Cambiar las preferéncias\n      review_preferences_step: Pensatz de configurar vòstras preferéncias, tal coma los corrièls que volètz recebrer o lo nivèl de confidencialitat de vòstres tuts per defaut. O se l’animacion vos dòna pas enveja de rendre, podètz activar la lectura automatica dels GIF.\n      subject: Benvengut a Mastodon\n      tip_federated_timeline: Lo flux d’actualitat federat es una vista generala del malhum Mastodon. Mas aquò inclutz solament lo monde que vòstres vesins sègon, doncas es pas complèt.\n      tip_following: Seguètz l’administrator del servidor per defaut. Per trobar de monde mai interessant, agachatz lo flux d’actualitat local e lo global.\n      tip_local_timeline: Lo flux d’actualitat local es una vista del monde de %{instance}. Son vòstres vesins dirèctes !\n      tip_mobile_webapp: Se vòstre navigator mobil nos permet d’apondre Mastodon a l’ecran d‘acuèlh, podètz recebre de notificacions. Aquò se compòrta coma una aplicacion nativa !\n      tips: Astúcias\n      title: Vos desirem la benvenguda a bòrd %{name} !\n  users:\n    follow_limit_reached: Podètz pas sègre mai de %{limit} personas\n    invalid_email: L’adreça de corrièl es invalida\n    invalid_otp_token: Còdi d’autentificacion en dos temps invalid\n    otp_lost_help_html: Se perdatz l’accès al dos, podètz benlèu contactar %{email}\n    seamless_external_login: Sètz connectat via un servici extèrn, los paramètres de senhal e de corrièl son doncas pas disponibles.\n    signed_in_as: 'Session a :'\n  verification:\n    explanation_html: 'Podètz <strong>verificar vosautres meteisses coma proprietari dels ligams per las metadonadas de vòstre perfil</strong>. Per aquò far, lo site Web ligat deu conténer un ligam cap a vòstre perfil Mastodon. Lo ligam <strong>deu</strong> aver un atribut <code>rel=\"me\"</code>. Lo contengut tèxte del ligam impòrta pas. Vaquí un exemple :'\n    verification: Verificacion\n"
  },
  {
    "path": "config/locales/pl.yml",
    "content": "---\npl:\n  about:\n    about_hashtag_html: Znajdują się tu publiczne wpisy oznaczone hashtagiem <strong>#%{hashtag}</strong>. Możesz dołączyć do dyskusji, jeżeli posiadasz konto gdziekolwiek w Fediwersum.\n    about_mastodon_html: Mastodon jest wolną i otwartą siecią społecznościową, zdecentralizowaną alternatywą dla zamkniętych, komercyjnych platform.\n    about_this: O tej instancji\n    active_count_after: aktywni\n    active_footnote: Aktywni użytkownicy miesięcznie (MAU)\n    administered_by: 'Administrowana przez:'\n    api: API\n    apps: Aplikacje\n    apps_platforms: Korzystaj z Mastodona z poziomu iOS-a, Androida i innych\n    browse_directory: Przeglądaj katalog profilów i filtruj z uwzględnieniem zainteresowań\n    browse_public_posts: Przeglądaj strumień publicznych wpisów na Mastodonie na żywo\n    contact: Kontakt\n    contact_missing: Nie ustawiono\n    contact_unavailable: Nie dotyczy\n    discover_users: Odkrywaj użytkowników\n    documentation: Dokumentacja\n    extended_description_html: |\n      <h3>Dobre miejsce na zasady użytkowania</h3>\n      <p>Nie ustawiono jeszcze szczegółowego opisu</p>\n    federation_hint_html: Z kontem na %{instance}, możesz śledzić użytkowników każdego serwera Mastodona i nie tylko.\n    generic_description: \"%{domain} jest jednym z serwerów sieci\"\n    get_apps: Spróbuj aplikacji mobilnej\n    hosted_on: Mastodon uruchomiony na %{domain}\n    learn_more: Dowiedz się więcej\n    privacy_policy: Polityka prywatności\n    see_whats_happening: Zobacz co się dzieje\n    server_stats: 'Statystyki serwera:'\n    source_code: Kod źródłowy\n    status_count_after:\n      few: wpisów\n      many: wpisów\n      one: wpisu\n      other: wpisów\n    status_count_before: Są autorami\n    tagline: Śledź znajomych i poznawal nowych\n    terms: Zasady użytkowania\n    user_count_after:\n      few: użytkowników\n      many: użytkowników\n      one: użytkownik\n      other: użytkowników\n    user_count_before: Z serwera korzysta\n    what_is_mastodon: Czym jest Mastodon?\n  accounts:\n    choices_html: 'Polecani przez %{name}:'\n    follow: Śledź\n    followers:\n      few: śledzących\n      many: śledzących\n      one: śledzący\n      other: Śledzących\n    following: Śledzonych\n    joined: Dołączył(a) %{date}\n    last_active: ostatnio aktywny(-a)\n    link_verified_on: Własność tego odnośnika została sprawdzona %{date}\n    media: Zawartość multimedialna\n    moved_html: \"%{name} korzysta teraz z konta %{new_profile_link}:\"\n    network_hidden: Ta informacja nie jest dostępna\n    nothing_here: Niczego tu nie ma!\n    people_followed_by: Konta śledzone przez %{name}\n    people_who_follow: Osoby, które śledzą konto %{name}\n    pin_errors:\n      following: Musisz śledzić osobę, którą chcesz polecać\n    posts:\n      few: wpisy\n      many: wpisów\n      one: wpis\n      other: Wpisów\n    posts_tab_heading: Wpisy\n    posts_with_replies: Wpisy z odpowiedziami\n    reserved_username: Ta nazwa użytkownika jest zarezerwowana\n    roles:\n      admin: Administrator\n      bot: Bot\n      moderator: Moderator\n    unavailable: Profil niedostępny\n    unfollow: Przestań śledzić\n  admin:\n    account_actions:\n      action: Wykonaj działanie\n      title: Wykonaj działanie moderacyjne na %{acct}\n    account_moderation_notes:\n      create: Pozostaw notatkę\n      created_msg: Pomyślnie dodano notatkę moderacyjną!\n      delete: Usuń\n      destroyed_msg: Pomyślnie usunięto notatkę moderacyjną!\n    accounts:\n      approve: Przyjmij\n      approve_all: Zatwierdź wszystkie\n      are_you_sure: Jesteś tego pewien?\n      avatar: Awatar\n      by_domain: Domena\n      change_email:\n        changed_msg: Pomyślnie zmieniono adres e-mail konta!\n        current_email: Obecny adres e-mail\n        label: Zmień adres e-mail\n        new_email: Nowy adres e-mail\n        submit: Zmień adres e-mail\n        title: Zmień adres e-mail dla %{username}\n      confirm: Potwierdź\n      confirmed: Potwierdzono\n      confirming: Potwierdzanie\n      deleted: Usunięto\n      demote: Degraduj\n      disable: Dezaktywuj\n      disable_two_factor_authentication: Wyłącz uwierzytelnianie dwuetapowe\n      disabled: Dezaktywowano\n      display_name: Wyświetlana nazwa\n      domain: Domena\n      edit: Edytuj\n      email: Adres e-mail\n      email_status: Stan e-maila\n      enable: Aktywuj\n      enabled: Aktywowano\n      feed_url: Adres kanału\n      followers: Śledzący\n      followers_url: Adres śledzących\n      follows: Śledzeni\n      header: Nagłówek\n      inbox_url: Adres skrzynki\n      invited_by: Zaproszony(-a) przez\n      ip: Adres IP\n      joined: Dołączył(-a)\n      location:\n        all: Wszystkie\n        local: Lokalne\n        remote: Zdalne\n        title: Położenie\n      login_status: Stan logowania\n      media_attachments: Załączniki multimedialne\n      memorialize: Przełącz na „In Memoriam”\n      moderation:\n        active: Aktywne\n        all: Wszystkie\n        pending: Oczekujące\n        silenced: Wyciszone\n        suspended: Zawieszone\n        title: Moderacja\n      moderation_notes: Notatki moderacyjne\n      most_recent_activity: Najnowsza aktywność\n      most_recent_ip: Ostatnie IP\n      no_account_selected: Żadne konto nie zostało zmienione, bo żadne nie zostało wybrane\n      no_limits_imposed: Nie nałożono ograniczeń\n      not_subscribed: Nie zasubskrybowano\n      outbox_url: Adres skrzynki nadawczej\n      pending: Oczekuje na przegląd\n      perform_full_suspension: Zawieś\n      profile_url: Adres profilu\n      promote: Podnieś uprawnienia\n      protocol: Protokół\n      public: Publiczne\n      push_subscription_expires: Subskrypcja PuSH wygasa\n      redownload: Odśwież profil\n      reject: Odrzuć\n      reject_all: Odrzuć wszystkie\n      remove_avatar: Usun awatar\n      remove_header: Usuń nagłówek\n      resend_confirmation:\n        already_confirmed: To konto zostało już potwierdzone\n        send: Wyślij ponownie e-mail z potwierdzeniem\n        success: E-mail z potwierdzeniem został wysłany!\n      reset: Resetuj\n      reset_password: Resetuj hasło\n      resubscribe: Ponów subskrypcję\n      role: Uprawnienia\n      roles:\n        admin: Administrator\n        moderator: Moderator\n        staff: Ekipa\n        user: Użytkownik\n      salmon_url: Adres Salmon\n      search: Szukaj\n      shared_inbox_url: Adres udostępnianej skrzynki\n      show:\n        created_reports: Zgłoszenia tego użytkownika\n        targeted_reports: Zgłoszenia dotyczące tego użytkownika\n      silence: Wycisz\n      silenced: Wyciszono\n      statuses: Wpisy\n      subscribe: Subskrybuj\n      suspended: Zawieszono\n      time_in_queue: Czekanie w kolejce %{time}\n      title: Konta\n      unconfirmed_email: Niepotwierdzony adres e-mail\n      undo_silenced: Cofnij wyciszenie\n      undo_suspension: Cofnij zawieszenie\n      unsubscribe: Przestań subskrybować\n      username: Nazwa użytkownika\n      warn: Ostrzeż\n      web: Sieć\n    action_logs:\n      actions:\n        assigned_to_self_report: \"%{name} przypisał(a) sobie zgłoszenie %{target}\"\n        change_email_user: \"%{name} zmienił(a) adres e-mail użytkownika %{target}\"\n        confirm_user: \"%{name} potwierdził(a) adres e-mail użytkownika %{target}\"\n        create_account_warning: \"%{name} wysłał(a) ostrzeżenie do %{target}\"\n        create_custom_emoji: \"%{name} dodał(a) nowe emoji %{target}\"\n        create_domain_block: \"%{name} zablokował(a) domenę %{target}\"\n        create_email_domain_block: \"%{name} dodał(a) domenę e-mail %{target} na czarną listę\"\n        demote_user: \"%{name} zdegradował(a) użytkownika %{target}\"\n        destroy_custom_emoji: \"%{name} usunął(-ęła) emoji %{target}\"\n        destroy_domain_block: \"%{name} odblokował(a) domenę %{target}\"\n        destroy_email_domain_block: \"%{name} usunął(-ęła) domenę e-mail %{target} z czarnej listy\"\n        destroy_status: \"%{name} usunął(-ęła) wpis użytkownika %{target}\"\n        disable_2fa_user: \"%{name} wyłączył(a) uwierzytelnianie dwustopniowe użytkownikowi %{target}\"\n        disable_custom_emoji: \"%{name} wyłączył(a) emoji %{target}\"\n        disable_user: \"%{name} zablokował(a) możliwość logowania użytkownikowi %{target}\"\n        enable_custom_emoji: \"%{name} włączył(a) emoji %{target}\"\n        enable_user: \"%{name} przywrócił(a) możliwość logowania użytkownikowi %{target}\"\n        memorialize_account: \"%{name} nadał(a) kontu %{target} status in memoriam\"\n        promote_user: \"%{name} podniósł(a) uprawnienia użytkownikowi %{target}\"\n        remove_avatar_user: \"%{name} usunął(-ęła) awatar użytkownikowi %{target}\"\n        reopen_report: \"%{name} otworzył(a) ponownie zgłoszenie %{target}\"\n        reset_password_user: \"%{name} przywrócił(a) hasło użytkownikowi %{target}\"\n        resolve_report: \"%{name} rozwiązał(a) zgłoszenie %{target}\"\n        silence_account: \"%{name} wyciszył(a) konto %{target}\"\n        suspend_account: \"%{name} zawiesił(a) konto %{target}\"\n        unassigned_report: \"%{name} cofnął(-ęła) przypisanie zgłoszenia %{target}\"\n        unsilence_account: \"%{name} cofnął(-ęła) wyciszenie konta %{target}\"\n        unsuspend_account: \"%{name} cofnął(-ęła) zawieszenie konta %{target}\"\n        update_custom_emoji: \"%{name} zaktualizował(a) emoji %{target}\"\n        update_status: \"%{name} zaktualizował(a) wpis użytkownika %{target}\"\n      deleted_status: \"(usunięty wpis)\"\n      title: Dziennik działań administracyjnych\n    custom_emojis:\n      by_domain: Domeny\n      copied_msg: Pomyślnie utworzono lokalną kopię emoji\n      copy: Kopiuj\n      copy_failed_msg: Nie udało się utworzyć lokalnej kopii emoji\n      created_msg: Pomyślnie utworzono emoji!\n      delete: Usuń\n      destroyed_msg: Pomyślnie usunięto emoji!\n      disable: Wyłącz\n      disabled_msg: Pomyślnie wyłączono emoji\n      emoji: Emotikona\n      enable: Włącz\n      enabled_msg: Pomyślnie przywrócono emoji\n      image_hint: Plik PNG ważący do 50KB\n      listed: Widoczne\n      new:\n        title: Dodaj nowe niestandardowe emoji\n      overwrite: Zastąp\n      shortcode: Krótki kod\n      shortcode_hint: Co najmniej 2 znaki, tylko znaki alfanumeryczne i podkreślniki\n      title: Niestandardowe emoji\n      unlisted: Niewidoczne\n      update_failed_msg: Nie udało się zaktualizować emoji\n      updated_msg: Pomyślnie zaktualizowano emoji!\n      upload: Dodaj\n    dashboard:\n      backlog: zaległe zadania\n      config: Konfiguracja\n      feature_deletions: Usuwanie kont\n      feature_invites: Zaproszenia\n      feature_profile_directory: Katalog profilów\n      feature_registrations: Rejestracja\n      feature_relay: Przekazywanie federacji\n      feature_timeline_preview: Podgląd osi czasu\n      features: Możliwości\n      hidden_service: Federowanie z ukrytymi usługami\n      open_reports: otwarte zgłoszenia\n      recent_users: Ostatni użytkownicy\n      search: Wyszukiwanie pełnego tekstu\n      single_user_mode: Tryb jednego użytkownika\n      software: Oprogramowanie\n      space: Używana powierzchnia\n      title: Panel administracyjny\n      total_users: łącznie użytkowników\n      trends: Na czasie\n      week_interactions: interakcje w tym tygodniu\n      week_users_active: aktywni w tym tygodniu\n      week_users_new: rejestracje w tym tygodniu\n    domain_blocks:\n      add_new: Dodaj nową\n      created_msg: Blokada domen jest przetwarzana\n      destroyed_msg: Blokada domeny nie może zostać odwrócona\n      domain: Domena\n      existing_domain_block_html: Już narzuciłeś bardziej rygorystyczne limity na %{name}, musisz najpierw <a href=\"%{unblock_url}\">je odblokować</a>.\n      new:\n        create: Utwórz blokadę\n        hint: Blokada domen nie zabroni tworzenia wpisów kont w bazie danych, ale pozwoli na automatyczną moderację kont do nich należących.\n        severity:\n          desc_html: \"<strong>Wyciszenie</strong> uczyni wpisy użytkownika widoczne tylko dla osób, które go śledzą. <strong>Zawieszenie</strong> spowoduje usunięcie całej zawartości dodanej przez użytkownika. Użyj <strong>Żadne</strong>, jeżeli chcesz jedynie odrzucać zawartość multimedialną.\"\n          noop: Nic nie rób\n          silence: Wycisz\n          suspend: Zawieś\n        title: Nowa blokada domen\n      reject_media: Odrzucaj pliki multimedialne\n      reject_media_hint: Usuwa przechowywane lokalnie pliki multimedialne i nie pozwala na ich pobieranie. Nieprzydatne przy zawieszeniu\n      reject_reports: Odrzucaj zgłoszenia\n      reject_reports_hint: Zgłoszenia z tej instancji będą ignorowane. Nieprzydatne przy zawieszeniu\n      rejecting_media: pliki multimedialne są odrzucane\n      rejecting_reports: zgłoszenia są odrzucane\n      severity:\n        silence: wyciszono\n        suspend: zawieszono\n      show:\n        affected_accounts:\n          few: Dotknęło %{count} kont w bazie danych\n          many: Dotknęło %{count} kont w bazie danych\n          one: Dotknęło jedno konto w bazie danych\n          other: Dotknęło %{count} kont w bazie danych\n        retroactive:\n          silence: Odwołaj wyciszenie wszystkich kont w tej domenie\n          suspend: Odwołaj zawieszenie wszystkich kont w tej domenie\n        title: Odwołaj blokadę dla domeny %{domain}\n        undo: Cofnij\n      undo: Cofnij\n    email_domain_blocks:\n      add_new: Dodaj nową\n      created_msg: Pomyślnie utworzono blokadę domeny e-mail\n      delete: Usuń\n      destroyed_msg: Pomyślnie usunięto blokadę domeny e-mail\n      domain: Domena\n      new:\n        create: Utwórz blokadę\n        title: Nowa blokada domeny e-mail\n      title: Blokowanie domen e-mail\n    followers:\n      back_to_account: Wróć do konta\n      title: Śledzący %{acct}\n    instances:\n      by_domain: Domena\n      delivery_available: Doręczanie jest dostępne\n      known_accounts:\n        few: \"%{count} znane konta\"\n        many: \"%{count} znane konta\"\n        one: \"%{count} znane konto\"\n        other: \"%{count} znane konta\"\n      moderation:\n        all: Wszystkie\n        limited: Ograniczone\n        title: Moderacja\n      title: Znane instancje\n      total_blocked_by_us: Zablokowane przez nas\n      total_followed_by_them: Śledzeni przez nich\n      total_followed_by_us: Śledzeni przez nas\n      total_reported: Zgłoszenia dotyczące ich\n      total_storage: Załączniki multimedialne\n    invites:\n      deactivate_all: Unieważnij wszystkie\n      filter:\n        all: Wszystkie\n        available: Dostępne\n        expired: Wygasłe\n        title: Filtruj\n      title: Zaproszenia\n    pending_accounts:\n      title: Oczekujące konta (%{count})\n    relays:\n      add_new: Dodaj nowy\n      delete: Usuń\n      description_html: \"<strong>Przekaźnik federacji</strong> jest pośredniczącym serwerem wymieniającym duże ilości publicznych wpisów pomiędzy serwerami które subskrybują je i publikują na nich. <strong>Pomaga to małym i średnim instancją poznawać nową zawartość z Fediwersum</strong>, co w innym przypadku wymagałoby od użytkowników ręcznego śledzenia osób z innych serwerów.\"\n      disable: Wyłącz\n      disabled: Wyłączony\n      enable: Włącz\n      enable_hint: Jeżeli włączone, Twój serwer zasubskrybuje wszystkie publiczne wpisy z tego przekaźnika i zacznie wysyłać tam publiczne wpisy z tego serwera.\n      enabled: Włączony\n      inbox_url: Adres przekaźnika\n      pending: Oczekiwanie na przyjęcie przez przekaźnik\n      save_and_enable: Zapisz i aktywuj\n      setup: Skonfiguruj połączenie z przekaźnikiem\n      status: Stan\n      title: Przekaźniki\n    report_notes:\n      created_msg: Pomyslnie utworzono notatkę moderacyjną.\n      destroyed_msg: Pomyślnie usunięto notatkę moderacyjną.\n    reports:\n      account:\n        note: notatka\n        report: zgłoszenie\n      action_taken_by: Działanie podjęte przez\n      are_you_sure: Czy na pewno?\n      assign_to_self: Przypisz do siebie\n      assigned: Przypisany moderator\n      comment:\n        none: Brak\n      created_at: Zgłoszono\n      mark_as_resolved: Oznacz jako rozwiązane\n      mark_as_unresolved: Oznacz jako nierozwiązane\n      notes:\n        create: Utwórz notatkę\n        create_and_resolve: Rozwiąż i pozostaw notatkę\n        create_and_unresolve: Cofnij rozwiązanie i pozostaw notatkę\n        delete: Usuń\n        placeholder: Opisz wykonane akcje i inne szczegóły dotyczące tego zgłoszenia…\n      reopen: Otwórz ponownie\n      report: 'Zgłoszenie #%{id}'\n      reported_account: Zgłoszone konto\n      reported_by: Zgłaszający\n      resolved: Rozwiązane\n      resolved_msg: Pomyślnie rozwiązano zgłoszenie.\n      status: Stan\n      title: Zgłoszenia\n      unassign: Cofnij przypisanie\n      unresolved: Nierozwiązane\n      updated_at: Zaktualizowano\n    settings:\n      activity_api_enabled:\n        desc_html: Liczy publikowane lokalnie wpisy, aktywnych użytkowników i nowe rejestracje w ciągu danego tygodnia\n        title: Publikuj zbiorowe statystyki o aktywności użytkowników\n      bootstrap_timeline_accounts:\n        desc_html: Oddzielaj nazwy użytkowników przecinkami. Działa tylko dla niezablokowanych kont w obrębie instancji. Jeżeli puste, zostaną użyte konta administratorów instancji.\n        title: Domyślnie obserwowani użytkownicy\n      contact_information:\n        email: Służbowy adres e-mail\n        username: Nazwa użytkownika do kontaktu\n      custom_css:\n        desc_html: Modyfikuj wygląd pliku CSS ładowanego na każdej stronie\n        title: Niestandardowy CSS\n      hero:\n        desc_html: Wyświetlany na stronie głównej. Zalecany jest rozmiar przynajmniej 600x100 pikseli. Jeżeli nie ustawiony, zostanie użyta miniatura serwera\n        title: Obraz bohatera\n      mascot:\n        desc_html: Wyświetlany na wielu stronach. Zalecany jest rozmiar przynajmniej 293px × 205px. Jeżeli nie ustawiono, zostanie użyta domyślna\n        title: Obraz maskotki\n      max_toot_chars:\n        desc_html: Ustaw maksymalną liczbę znakow we wpisach (domyślnie 500)\n        title: Maksymalna długość wpisów\n      peers_api_enabled:\n        desc_html: Nazwy domen, z którymi ten serwer wchodził w interakcje\n        title: Publikuj listę znanych serwerów\n      preview_sensitive_media:\n        desc_html: Podgląd odnośników na innych instancjach będzie wyświetlał miniaturę nawet jeśli zawartość multimedialna zostanie oznaczona jako wrażliwa\n        title: Wyświetlaj zawartość wrażliwą w podglądzie OpenGraph\n      profile_directory:\n        desc_html: Pozwalaj na poznawanie użytkowników\n        title: Włącz katalog profilów\n      registrations:\n        closed_message:\n          desc_html: Wyświetlana na stronie głównej, gdy możliwość otwarej rejestracji nie jest dostępna. Możesz korzystać z tagów HTML\n          title: Wiadomość o nieaktywnej rejestracji\n        deletion:\n          desc_html: Pozwól każdemu na usunięcie konta\n          title: Możliwość usunięcia\n        min_invite_role:\n          disabled: Nikt\n          title: Kto może zapraszać użytkowników\n      registrations_mode:\n        modes:\n          approved: Przyjęcie jest wymagane do rejestracji\n          none: Nikt nie może się zarejestrować\n          open: Każdy może się zarejestrować\n        title: Tryb rejestracji\n      show_known_fediverse_at_about_page:\n        desc_html: Jeśli włączone, podgląd instancji będzie wyświetlał wpisy z całego Fediwersum. W innym przypadku, będą wyświetlane tylko lokalne wpisy.\n        title: Pokazuj wszystkie znane wpisy na podglądzie instancji\n      show_staff_badge:\n        desc_html: Pokazuj odznakę uprawnień na stronie profilu użytkownika\n        title: Pokazuj odznakę administracji\n      site_description:\n        desc_html: Akapit wprowadzający, widoczny na stronie głównej. Opisz, co czyni tę instancję wyjątkową. Możesz korzystać ze znaczników HTML, w szczególności <code>&lt;a&gt;</code> i <code>&lt;em&gt;</code>.\n        title: Opis serwera\n      site_description_extended:\n        desc_html: Dobre miejsce na zasady użytkowania, wprowadzenie i inne rzeczy, które wyróżniają ten serwer. Możesz korzystać ze znaczników HTML\n        title: Niestandardowy opis strony\n      site_short_description:\n        desc_html: Wyświetlany na pasku bocznym i w znacznikach meta. Opisz w jednym akapicie, czym jest Mastodon i czym wyróżnia się ten serwer. Jeżeli pusty, zostanie użyty opis serwera.\n        title: Krótki opis serwera\n      site_terms:\n        desc_html: Miejsce na własną politykę prywatności, zasady użytkowania i inne unormowania prawne. Możesz korzystać ze znaczników HTML\n        title: Niestandardowe zasady użytkowania\n      site_title: Nazwa serwera\n      thumbnail:\n        desc_html: 'Używana w podglądzie przez OpenGraph i API. Zalecany rozmiar: 1200x630 pikseli'\n        title: Miniatura serwera\n      timeline_preview:\n        desc_html: Wyświetlaj publiczną oś czasu na stronie widocznej dla niezalogowanych\n        title: Podgląd osi czasu\n      title: Ustawienia strony\n    statuses:\n      back_to_account: Wróć na konto\n      batch:\n        delete: Usuń\n        nsfw_off: Cofnij NSFW\n        nsfw_on: Oznacz jako NSFW\n      failed_to_execute: Nie udało się wykonać\n      media:\n        title: Multimedia\n      no_media: Bez zawartości multimedialnej\n      no_status_selected: Żaden wpis nie został zmieniony, bo żaden nie został wybrany\n      title: Wpisy konta\n      with_media: Z zawartością multimedialną\n    subscriptions:\n      callback_url: URL zwrotny\n      confirmed: Potwierdzone\n      expires_in: Wygasa\n      last_delivery: Ostatnio doręczono\n      title: WebSub\n      topic: Temat\n    tags:\n      accounts: Konta\n      hidden: Ukryte\n      hide: Ukryj w katalogu\n      name: Hasztag\n      title: Hashtagi\n      unhide: Pokazuj w katalogu\n      visible: Widoczne\n    title: Administracja\n    warning_presets:\n      add_new: Dodaj nowy\n      delete: Usuń\n      edit: Edytuj\n      edit_preset: Edytuj szablon ostrzeżenia\n      title: Zarządzaj szablonami ostrzeżeń\n  admin_mailer:\n    new_pending_account:\n      body: Poniżej znajdują się szczegóły dotycząće nowego konta. Możesz przyjąć lub odrzucić to podanie.\n      subject: Nowe konto czeka na przegląd na %{instance} (%{username})\n    new_report:\n      body: Użytkownik %{reporter} zgłosił(a) %{target}\n      body_remote: Użytkownik instancji %{domain} zgłosił(a) %{target}\n      subject: Nowe zgłoszenie na %{instance} (#%{id})\n  appearance:\n    advanced_web_interface: Zaawansowany interfejs użytkownika\n    advanced_web_interface_hint: Jeśli chcesz użyć pełną szerokość swojego ekranu, zaawansowany interfejs użytkownika pozwala Ci skonfigurować wiele różnych kolumn, by zobaczyć jak najwięcej informacji kiedy tylko chcesz. Strona główna, Powiadomienia, Globalna oś czasu, dowolna ilość list i hasztagów.\n    animations_and_accessibility: Animacje i dostępność\n    confirmation_dialogs: Dialogi potwierdzenia\n    sensitive_content: Wrażliwa zawartość\n  application_mailer:\n    notification_preferences: Zmień ustawienia e-maili\n    salutation: \"%{name},\"\n    settings: 'Zmień ustawienia powiadamiania: %{link}'\n    view: 'Zobacz:'\n    view_profile: Wyświetl profil\n    view_status: Wyświetl wpis\n  applications:\n    created: Pomyślnie utworzono aplikację\n    destroyed: Pomyślnie usunięto aplikację\n    invalid_url: Wprowadzony adres URL jest nieprawidłowy\n    regenerate_token: Wygeneruj nowy token dostępu\n    token_regenerated: Pomyślnie wygenerowano nowy token dostępu\n    warning: Przechowuj te dane ostrożnie. Nie udostępniaj ich nikomu!\n    your_token: Twój token dostępu\n  auth:\n    apply_for_account: Poproś o zaproszenie\n    change_password: Hasło\n    checkbox_agreement_html: Zgadzam się z <a href=\"%{rules_path}\" target=\"_blank\">regułami serwera</a> i <a href=\"%{terms_path}\" target=\"_blank\">zasadami korzystania z usługi</a>\n    confirm_email: Potwierdź adres e-mail\n    delete_account: Usunięcie konta\n    delete_account_html: Jeżeli chcesz usunąć konto, <a href=\"%{path}\">przejdź tutaj</a>. Otrzymasz prośbę o potwierdzenie.\n    didnt_get_confirmation: Nie otrzymałeś(-aś) instrukcji weryfikacji?\n    forgot_password: Nie pamiętasz hasła?\n    invalid_reset_password_token: Token do resetowania hasła jest nieprawidłowy lub utracił ważność. Spróbuj uzyskać nowy.\n    login: Zaloguj się\n    logout: Wyloguj się\n    migrate_account: Przenieś konto\n    migrate_account_html: Jeżeli chcesz skonfigurować przekierowanie z obecnego konta na inne, możesz <a href=\"%{path}\">zrobić to tutaj</a>.\n    or_log_in_with: Lub zaloguj się z użyciem\n    providers:\n      cas: CAS\n      saml: SAML\n    register: Rejestracja\n    registration_closed: \"%{instance} nie przyjmuje nowych członków\"\n    resend_confirmation: Ponownie prześlij instrukcje weryfikacji\n    reset_password: Zresetuj hasło\n    security: Bezpieczeństwo\n    set_new_password: Ustaw nowe hasło\n    trouble_logging_in: Masz problem z zalogowaniem się?\n  authorize_follow:\n    already_following: Już śledzisz to konto\n    error: Niestety, podczas sprawdzania zdalnego konta wystąpił błąd\n    follow: Śledź\n    follow_request: 'Wysłano prośbę o pozwolenie na śledzenie:'\n    following: 'Pomyślnie! Od teraz śledzisz:'\n    post_follow:\n      close: Ewentualnie, możesz po prostu zamknąć tę stronę.\n      return: Pokaż stronę użytkownika\n      web: Przejdź do sieci\n    title: Śledź %{acct}\n  datetime:\n    distance_in_words:\n      about_x_hours: \"%{count}g\"\n      about_x_months: \"%{count} miesięcy\"\n      about_x_years: \"%{count} lat\"\n      almost_x_years: \"%{count} lat\"\n      half_a_minute: Przed chwilą\n      less_than_x_minutes: \"%{count}min\"\n      less_than_x_seconds: Przed chwilą\n      over_x_years: \"%{count} lat\"\n      x_days: \"%{count} dni\"\n      x_minutes: \"%{count}min\"\n      x_months: \"%{count} miesięcy\"\n      x_seconds: \"%{count}s\"\n  deletes:\n    bad_password_msg: Niezła próba, hakerze! Wprowadzono nieprawidłowe hasło\n    confirm_password: Wprowadź aktualne hasło, aby potwierdzić tożsamość\n    description_html: Ta opcja usunie <strong>bezpowrotnie i nieodwracalnie</strong> całą zawartość konta i zdezaktywuje je. Twoja nazwa użytkownika pozostanie zarezerwowana, aby zapobiec nadużyciom.\n    proceed: Usuń konto\n    success_msg: Twoje konto zostało pomyślnie usunięte\n    warning_html: Możemy usunąć zawartość jedynie w obrębie tego serwera. Zawartość udostępniona publicznie pozostawia trwałe ślady. Serwery niepodłączone do sieci bądź nieśledzące Twoich aktualizacji mogą zachować Twoje dane.\n    warning_title: Dostępność usuniętej zawartości\n  directories:\n    directory: Katalog profilów\n    enabled: Jesteś obecnie zapisany(-a) do katalogu\n    enabled_but_waiting: Jesteś zapisany(-a) do katalogu, ale jeszcze nie śledzi Cię wystarczająca liczba osób (%{min_followers}), aby się tam pojawić.\n    explanation: Poznaj profile na podstawie zainteresowań\n    explore_mastodon: Odkrywaj %{title}\n    how_to_enable: Nie jesteś obecnie zapisany(-a) do katalogu. Poniżej możesz zapisać się. Użyj hashtagów w swoim opisie, aby zostać wyświetlonym pod określonymi hashtagami!\n    people:\n      few: \"%{count} osoby\"\n      many: \"%{count} osób\"\n      one: \"%{count} osoba\"\n      other: \"%{count} osób\"\n  errors:\n    '403': Nie masz uprawnień, aby wyświetlić tę stronę.\n    '404': Strona, którą próbujesz odwiedzić, nie istnieje.\n    '410': Strona, którą próbujesz odwiedzić, przestała istnieć.\n    '422':\n      content: Sprawdzanie bezpieczeństwa nie powiodło się. Czy blokujesz pliki cookie?\n      title: Sprawdzanie bezpieczeństwa nie powiodło się\n    '429': Uduszono\n    '500':\n      content: Przepraszamy, coś poszło nie tak, po naszej stronie.\n      title: Ta strona jest nieprawidłowa\n    noscript_html: Aby korzystać z aplikacji Mastodon, włącz JavaScript. Możesz też skorzystać z jednej z <a href=\"%{apps_path}\">natywnych aplikacji</a> obsługującej Twoje urządzenie.\n  existing_username_validator:\n    not_found: nie znaleziono lokalnego użytkownika o tej nazwie\n    not_found_multiple: nie znaleziono %{usernames}\n  exports:\n    archive_takeout:\n      date: Data\n      download: Pobierz swoje archiwum\n      hint_html: Możesz uzyskać archiwum swoich <strong>wpisów i wysłanej zawartości multimedialnej</strong>. Wyeksportowane dane będą dostępne w formacie ActivityPub, który możesz otworzyć w obsługujących go programach. Możesz wyeksportować je po 7 dniach od poprzedniego eksportu.\n      in_progress: Tworzenie archiwum…\n      request: Uzyskaj archiwum\n      size: Rozmiar\n    blocks: Zablokowani\n    csv: CSV\n    domain_blocks: Blokady domen\n    follows: Śledzeni\n    lists: Listy\n    mutes: Wyciszeni\n    storage: Urządzenie przechowujące dane\n  featured_tags:\n    add_new: Dodaj nowy\n    errors:\n      limit: Już przekroczyłeś(-aś) maksymalną liczbę wyróżnionych hashtagów\n  filters:\n    contexts:\n      home: Strona główna\n      notifications: Powiadomienia\n      public: Publiczne osie czasu\n      thread: Konwersacje\n    edit:\n      title: Edytuj filtr\n    errors:\n      invalid_context: Nie podano lub podano nieprawidłową treść\n      invalid_irreversible: Nieodwracalne filtrowanie działa tylko na stronie głównej i w powiadomieniach\n    index:\n      delete: Usuń\n      title: Filtry\n    new:\n      title: Dodaj nowy filtr\n  footer:\n    developers: Dla programistów\n    more: Więcej…\n    resources: Zasoby\n  generic:\n    all: Wszystkie\n    changes_saved_msg: Ustawienia zapisane!\n    copy: Kopiuj\n    order_by: Uporządkuj według\n    save_changes: Zapisz zmiany\n    validation_errors:\n      few: Coś jest wciąż nie tak! Przejrzyj %{count} poniższe błędy\n      many: Coś jest wciąż nie tak! Przejrzyj %{count} poniższych błędów\n      one: Coś jest wciąż nie tak! Przyjrzyj się poniższemu błędowi\n      other: Coś jest wciąż nie tak! Przejrzyj poniższe błędy (%{count})\n  html_validator:\n    invalid_markup: 'zawiera nieprawidłową składnię HTML: %{error}'\n  identity_proofs:\n    active: Aktywny\n    authorize: Tak, autoryzuj\n    authorize_connection_prompt: Czy chcesz autoryzować to połączenie kryptograficzne?\n    errors:\n      failed: Połączenioe kryptograficzne nie powiodło się. Spróbuj ponownie z poziomu %{provider}.\n      keybase:\n        invalid_token: Tokeny Keybase są hashami podpisów i musza składać się z 66 znaków heksadecymalnych\n        verification_failed: Keybase nie rozpoznaje tego tokenu jako podpisu użytkownika Keybase %{kb_username}. Spróbuj ponownie z poziomu Keybase.\n      wrong_user: Nie można utworzyć dowodu dla %{proving}, gdy jesteś zalogowany(-a) jako %{current}. Zaloguj się jako %{proving} i spróbuj ponownie.\n    explanation_html: Tutaj możesz połączyć kryptograficznie swoje inne tożsamości, takie jak profil Keybase. To pozwoli innym wysłać Ci szyfrowane wiadomości i zaufać zawartości którą im wysyłasz.\n    i_am_html: Jestem %{username} na %{service}.\n    identity: Tożsamość\n    inactive: Niekatywny\n    publicize_checkbox: 'I opublikuj to:'\n    publicize_toot: 'Udowodnione! Jestem %{username} na %{service}: %{url}'\n    status: Stan weryfikacji\n    view_proof: Wyświetl dowód\n  imports:\n    modes:\n      merge: Połącz\n      merge_long: Zachowaj obecne wpisy i dodaj nowe\n      overwrite: Nadpisz\n      overwrite_long: Zastąp obecne wpisy nowymi\n    preface: Możesz zaimportować pewne dane (np. lista kont, które śledzisz lub blokujesz) do swojego konta na tym serwerze, korzystając z danych wyeksportowanych z innego serwera.\n    success: Twoje dane zostały załadowane i zostaną niebawem przetworzone\n    types:\n      blocking: Lista blokowanych\n      domain_blocking: Lista zablokowanych domen\n      following: Lista śledzonych\n      muting: Lista wyciszonych\n    upload: Załaduj\n  in_memoriam_html: Ku pamięci.\n  invites:\n    delete: Wygaś\n    expired: Wygasły\n    expires_in:\n      '1800': 30 minutach\n      '21600': 6 godzinach\n      '3600': godzinie\n      '43200': 12 godzinach\n      '604800': 1 tygodniu\n      '86400': dobie\n    expires_in_prompt: Nigdy\n    generate: Wygeneruj\n    invited_by: 'Zostałeś(-aś) zaproszony(-a) przez:'\n    max_uses:\n      few: \"%{count} użycia\"\n      many: \"%{count} użyć\"\n      one: jedno użycie\n      other: \"%{count} użyć\"\n    max_uses_prompt: Bez ograniczenia\n    prompt: Wygeneruj odnośniki i udostępnij je innym, aby pozwolić na rejestrację na tym serwerze\n    table:\n      expires_at: Wygaśnie po\n      uses: Użycia\n    title: Zaproś użytkowników\n  lists:\n    errors:\n      limit: Przekroczyłeś maksymalną liczbę utworzonych list\n  media_attachments:\n    validations:\n      images_and_video: Nie możesz załączyć pliku wideo do wpisu, który zawiera już zdjęcia\n      too_many: Nie możesz załączyć więcej niż 4 plików\n  migrations:\n    acct: nazwa@domena nowego konta\n    currently_redirecting: 'Obecnie Twoje konto przekierowuje do:'\n    proceed: Zapisz\n    updated_msg: Pomyślnie zaktualizowano ustawienia migracji Twojego konta!\n  moderation:\n    title: Moderacja\n  notification_mailer:\n    digest:\n      action: Wyświetl wszystkie powiadomienia\n      body: Oto krótkie podsumowanie wiadomości, które ominęły Cię od Twojej ostatniej wizyty (%{since})\n      mention: \"%{name} wspomniał o Tobie w:\"\n      new_followers_summary:\n        few: \"(%{count}) nowe osoby śledzą Cię!\"\n        many: \"(%{count}) nowych osób Cię śledzi! Wspaniale!\"\n        one: Dodatkowo, w czasie nieobecności zaczęła śledzić Cię jedna osoba Gratulacje!\n        other: Dodatkowo, zaczęło Cię śledzić %{count} nowych osób! Wspaniale!\n      subject:\n        few: \"%{count} nowe powiadomienia od Twojej ostatniej wizyty \\U0001F418\"\n        many: \"%{count} nowych powiadomień od Twojej ostatniej wizyty \\U0001F418\"\n        one: \"1 nowe powiadomienie od Twojej ostatniej wizyty \\U0001F418\"\n        other: \"%{count} nowych powiadomień od Twojej ostatniej wizyty \\U0001F418\"\n      title: W trakcie Twojej nieobecności…\n    favourite:\n      body: 'Twój wpis został polubiony przez %{name}:'\n      subject: \"%{name} lubi Twój wpis\"\n      title: Nowe polubienie\n    follow:\n      body: \"%{name} Cię śledzi!\"\n      subject: \"%{name} Cię śledzi\"\n      title: Nowy śledzący\n    follow_request:\n      action: Zarządzaj prośbami o możliwość śledzenia\n      body: \"%{name} poprosił(a) o możliwość śledzenia Cię\"\n      subject: 'Prośba o możliwość śledzenia: %{name}'\n      title: Nowa prośba o możliwość śledzenia\n    mention:\n      action: Odpowiedz\n      body: \"%{name} wspomniał(a) o Tobie w:\"\n      subject: \"%{name} wspomniał(a) o Tobie\"\n      title: Nowe wspomnienie o Tobie\n    reblog:\n      body: 'Twój wpis został podbity przez %{name}:'\n      subject: Twój wpis został podbity przez %{name}\n      title: Nowe podbicie\n  number:\n    human:\n      decimal_units:\n        format: \"%n%u\"\n        units:\n          billion: mld\n          million: mil\n          quadrillion: bld\n          thousand: tys\n          trillion: bln\n  pagination:\n    newer: Nowsze\n    next: Następna\n    older: Starsze\n    prev: Poprzednia\n    truncate: \"&hellip;\"\n  polls:\n    errors:\n      already_voted: Już oddałeś(-aś) głos w tym głosowaniu\n      duplicate_options: zawiera powtarzające się opcje\n      duration_too_long: jest zbyt odległa\n      duration_too_short: jest zbyt bliska\n      expired: To głosowanie już zakończyło się\n      over_character_limit: nie może zawierać więcej niż %{max} znaków\n      too_few_options: musi zawierać przynajmniej dwie opcje\n      too_many_options: nie może zawierać więcej niż %{max} opcji\n  preferences:\n    other: Pozostałe\n    posting_defaults: Domyślne ustawienia wpisów\n    public_timelines: Publiczne osie czasu\n  relationships:\n    activity: Aktywność konta\n    dormant: Uśpione\n    last_active: Ostatnia aktywność\n    most_recent: Ostatnie\n    moved: Przeniesione\n    mutual: Wspólna\n    primary: Jednostronna\n    relationship: Relacja\n    remove_selected_domains: Usuń wszystkich śledzących z zaznaczonych domen\n    remove_selected_followers: Usuń zaznaczonych śledzących\n    remove_selected_follows: Przestań śledzić zaznaczonych użytkowników\n    status: Stan konta\n  remote_follow:\n    acct: Podaj swój adres (nazwa@domena), z którego chcesz wykonać działanie\n    missing_resource: Nie udało się znaleźć adresu przekierowania z Twojej domeny\n    no_account_html: Nie masz konta? Możesz <a href='%{sign_up_path}' target='_blank'>zarejestrować się tutaj</a>\n    proceed: Śledź\n    prompt: 'Zamierzasz śledzić:'\n    reason_html: \"<strong>Dlaczego ten krok jest konieczny?</strong> <code>%{instance}</code> może nie być serwerem na którym jesteś zarejestrowany(-a), więc musisz zostać przekierowany(-a) na swój serwer.\"\n  remote_interaction:\n    favourite:\n      proceed: Przejdź do dodania do ulubionych\n      prompt: 'Chcesz dodać ten wpis do ulubionych:'\n    reblog:\n      proceed: Przejdź do podbicia\n      prompt: 'Chcesz podbić ten wpis:'\n    reply:\n      proceed: Przejdź do dodawania odpowiedzi\n      prompt: 'Chcesz odpowiedzieć na ten wpis:'\n  remote_unfollow:\n    error: Błąd\n    title: Tytuł\n    unfollowed: Przestałeś(-aś) śledzić\n  scheduled_statuses:\n    over_daily_limit: Przekroczyłeś(-aś) limit %{limit} zaplanowanych wpisów na ten dzień\n    over_total_limit: Przekroczyłeś(-aś) limit %{limit} zaplanowanych wpisów\n    too_soon: Zaplanowana data musi wypadać w przyszłości\n  sessions:\n    activity: Ostatnia aktywność\n    browser: Przeglądarka\n    browsers:\n      alipay: Alipay\n      blackberry: Blackberry\n      chrome: Chrome\n      edge: Microsoft Edge\n      electron: Electron\n      firefox: Firefox\n      generic: nieznana przeglądarka\n      ie: Internet Explorer\n      micro_messenger: MicroMessenger\n      nokia: Nokia S40 Ovi Browser\n      opera: Opera\n      otter: Przeglądarka Otter\n      phantom_js: PhantomJS\n      qq: QQ Browser\n      safari: Safari\n      uc_browser: UCBrowser\n      weibo: Weibo\n    current_session: Obecna sesja\n    description: \"%{browser} na %{platform}\"\n    explanation: Przeglądarki z aktywną sesją Twojego konta.\n    ip: Adres IP\n    platforms:\n      adobe_air: Adobe Air\n      android: Android\n      blackberry: Blackberry\n      chrome_os: ChromeOS\n      firefox_os: Firefox OS\n      ios: iOS\n      linux: Linux\n      mac: macOS\n      other: nieznana platforma\n      windows: Windows\n      windows_mobile: Windows Mobile\n      windows_phone: Windows Phone\n    revoke: Unieważnij\n    revoke_success: Pomyślnie unieważniono sesję\n    title: Sesje\n  settings:\n    account: Konto\n    account_settings: Ustawienia konta\n    appearance: Wygląd\n    authorized_apps: Uwierzytelnione aplikacje\n    back: Powrót do Mastodona\n    delete: Usuń konto\n    development: Tworzenie aplikacji\n    edit_profile: Edytuj profil\n    export: Eksportowanie danych\n    featured_tags: Wyróżnione hashtagi\n    identity_proofs: Dowody tożsamości\n    import: Importowanie danych\n    import_and_export: Import i eksport\n    migrate: Migracja konta\n    notifications: Powiadomienia\n    preferences: Preferencje\n    profile: Profil\n    relationships: Śledzeni i śledzący\n    two_factor_authentication: Uwierzytelnianie dwuetapowe\n  statuses:\n    attached:\n      description: 'Załączono: %{attached}'\n      image:\n        few: \"%{count} obrazy\"\n        many: \"%{count} obrazów\"\n        one: \"%{count} obraz\"\n        other: \"%{count} obrazów\"\n      video:\n        few: \"%{count} filmy\"\n        many: \"%{count} filmów\"\n        one: \"%{count} film\"\n        other: \"%{count} filmów\"\n    boosted_from_html: Podbito przez %{acct_link}\n    content_warning: 'Ostrzeżenie o zawartości: %{warning}'\n    disallowed_hashtags:\n      few: 'zawiera niedozwolone hashtagi: %{tags}'\n      many: 'zawiera niedozwolone hashtagi: %{tags}'\n      one: 'zawiera niedozwolony hashtag: %{tags}'\n      other: 'zawiera niedozwolone hashtagi: %{tags}'\n    language_detection: Automatycznie wykrywaj język\n    open_in_web: Otwórz w przeglądarce\n    over_character_limit: limit %{max} znaków przekroczony\n    pin_errors:\n      limit: Przekroczyłeś maksymalną liczbę przypiętych wpisów\n      ownership: Nie możesz przypiąć cudzego wpisu\n      private: Nie możesz przypiąć niepublicznego wpisu\n      reblog: Nie możesz przypiąć podbicia wpisu\n    poll:\n      total_votes:\n        few: \"%{count} głosy\"\n        many: \"%{count} głosy\"\n        one: \"%{count} głos\"\n        other: \"%{count} głosy\"\n      vote: Głosuj\n    show_more: Pokaż więcej\n    sign_in_to_participate: Zaloguj się, aby udzielić się w tej konwersacji\n    title: '%{name}: \"%{quote}\"'\n    visibilities:\n      private: Tylko dla śledzących\n      private_long: Widoczne tylko dla osób, które Cię śledzą\n      public: Publiczne\n      public_long: Widoczne dla wszystkich użytkowników\n      unlisted: Niewypisane\n      unlisted_long: Widoczne dla wszystkich, ale nie wyświetlane na publicznych osiach czasu\n  stream_entries:\n    pinned: Przypięty wpis\n    reblogged: podbił\n    sensitive_content: Wrażliwa zawartość\n  terms:\n    body_html: |\n      <h2>Polityka prywatności</h2>\n      <h3 id=\"collect\">Jakie informacje zbieramy?</h3>\n\n      <ul>\n      <li><em>Podstawowe informacje o koncie</em>: Podczas rejestracji na tym serwerze, możesz zostać poproszony(-a) o wprowadzenie nazwy użytkownika, adresu e-mail i hasła. Możesz także wprowadzić dodatkowe informacje o profilu, takie jak nazwa wyświetlana i biografia oraz wysłać awatar i obraz nagłówka. Nazwa użytkownika, nazwa wyświetlana, biografia, awatar i obraz nagłówka są zawsze widoczne dla wszystkich.</li>\n      <li><em>Wpisy, śledzenie i inne publiczne informacje</em>: Lista osób które śledzisz jest widoczna publicznie, tak jak lista osób, które Cię śledzą. Jeżeli dodasz wpis, data i czas jego utworzenia i aplikacja, z której go wysłano są przechowywane. Wiadomości mogą zawierać załączniki multimedialne, takie jak zdjęcia i filmy. Publiczne i niewidoczne wpisy są dostępne publicznie. Udostępniony wpis również jest widoczny publicznie. Twoje wpisy są dostarczane obserwującym, co oznacza że jego kopie mogą zostać dostarczone i być przechowywane na innych serwerach. Kiedy usuniesz wpis, przestaje być widoczny również dla osób śledzących Cię. „Podbijanie” i dodanie do ulubionych jest zawsze publiczne.</li>\n      <li><em>Wpisy bezpośrednie i tylko dla śledzących</em>: Wszystkie wpisy są przechowywane i przetwarzane na serwerze. Wpisy przeznaczone tylko dla śledzących są widoczne tylko dla nich i osób wspomnianych we wpisie, a wpisy bezpośrednie tylko dla wspomnianych. W wielu przypadkach oznacza to, że ich kopie są dostarczane i przechowywane na innych serwerach. Staramy się ograniczać zasięg tych wpisów wyłącznie do właściwych odbiorców, ale inne serwery mogą tego nie robić. Ważne jest, aby sprawdzać jakich serwerów używają osoby, które Cię śledzą. Możesz aktywować opcję pozwalającą na ręczne akceptowanie i odrzucanie nowych śledzących. <em>Pamiętaj, że właściciele serwerów mogą zobaczyć te wiadomości</em>, a odbiorcy mogą wykonać zrzut ekranu, skopiować lub udostępniać ten wpis. <em>Nie udostępniaj wrażliwych danych z użyciem Mastodona.</em></li>\n      <li><em>Adresy IP i inne metadane</em>: Kiedy zalogujesz się, przechowujemy adres IP użyty w trakcie logowania wraz z nazwą używanej przeglądarki. Wszystkie aktywne sesje możesz zobaczyć (i wygasić) w ustawieniach. Ostatnio używany adres IP jest przechowywany przez nas do 12 miesięcy. Możemy również przechowywać adresy IP wykorzystywane przy każdym działaniu na serwerze.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"use\">W jakim celu wykorzystujecie informacje?</h3>\n\n      <p>Zebrane informacje mogą zostać użyte w następujące sposoby:</p>\n\n      <ul>\n      <li>Aby dostarczyć podstawową funkcjonalność Mastodona. Możesz wchodzić w interakcje z zawartością tworzoną przez innych tylko gdy jesteś zalogowany. Na przykład, możesz śledzić innych, aby widzieć ich wpisy w dostosowanej osi czasu.</li>\n      <li>Aby wspomóc moderację społeczności, na przykład porównując Twój adres IP ze znanymi, aby rozpoznać próbę obejścia blokady i inne naruszenia.</li>\n      <li>Adres e-mail może zostać wykorzystany, aby wysyłać Ci informacje, powiadomienia o osobach wchodzących w interakcje z tworzoną przez Ciebie zawartością, wysyłających Ci wiadomości, odpowiadać na zgłoszenia i inne żądania lub zapytania.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"protect\">W jaki sposób chronimy Twoje dane?</h3>\n\n      <p>Wykorzystujemy różne zabezpieczenia, aby zapewnić bezpieczeństwo informacji, które wprowadzasz, wysyłasz lub do których uzyskujesz dostęp. Poza tym, sesja przeglądarki oraz ruch pomiędzy aplikacją a API jest zabezpieczany z użyciem SSL, a hasło jest hashowane z użyciem silnego algorytmu. Możesz też aktywować uwierzytelnianie dwustopniowe, aby lepiej zabezpieczyć dostęp do konta.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"data-retention\">Jaka jest nasza polityka przechowywania danych?</h3>\n\n      <p>Staramy się:</p>\n\n      <ul>\n      <li>Przechowywać logi zawierające adresy IP używane przy każdym żądaniu do serwera przez nie dłużej niż 90 dni.</li>\n      <li>Przechowywać adresy IP przypisane do użytkowników przez nie dłużej niż 12 miesięcy.</li>\n      </ul>\n\n      <p>Możesz zażądać i pobrać archiwum tworzonej zawartości, wliczając Twoje wpisy, załączniki multimedialne, awatar i zdjęcie nagłówka.</p>\n\n      <p>Możesz nieodwracalnie usunąć konto w każdej chwili.</p>\n\n      <hr class=\"spacer\"/>\n\n      <h3 id=\"cookies\">Czy używany plików cookies?</h3>\n\n      <p>Tak. Pliki cookies są małymi plikami, które strona lub dostawca jej usługi dostarcza na dysk twardy komputera z użyciem przeglądarki internetowej (jeżeli na to pozwoli). Pliki cookies pozwalają na rozpoznanie przeglądarki i – jeśli jesteś zarejestrowany(-a) – przypisanie jej do konta.</p>\n\n      <p>Wykorzystujemy pliki cookies, aby przechowywać preferencje użytkowników na przyszłe wizyty.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"disclose\">Czy przekazujemy informacje osobom trzecim?</h3>\n\n      <p>Nie sprzedajemy, nie wymieniamy i nie przekazujemy osobom trzecim informacji pozwalających na identyfikację Ciebie. Nie dotyczy to zaufanych dostawców pomagających w prowadzeniu strony lub obsługiwaniu użytkowników, jeżeli zgadzają się, aby nie przekazywać dalej tych informacji. Możemy również udostępnić informacje, jeżeli uważany to za wymagane przez prawo, konieczne do wypełnienia polityki strony, przestrzegania naszych lub cudzych praw, własności i bezpieczeństwa.</p>\n\n      <p>Twoja publiczna zawartość może zostać pobrana przez inne serwery w sieci. Wpisy publiczne i tylko dla śledzących są dostarczane na serwery, na których znajdują się śledzący Cię, a wiadomości bezpośrednie trafiają na serwery adresatów, jeżeli są oni użytkownikami innego serwera.</p>\n\n      <p>Kiedy pozwolisz aplikacji na dostęp do Twojego konta, w zależności od nadanych jej pozwoleń, może uzyskać dostęp do publicznych informacji, listy śledzonych, Twoich list, wszystkich wpisów i ulubionych. Aplikacje nie mogą uzyskać dostępu do Twojego adresu e-mail i hasła.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"children\">Korzystanie ze strony przez dzieci</h3>\n\n      <p>Jeżeli serwer znajduje się w UE lub w EOG: Ta strona, produkty i usługi są przeznaczone dla osób, które ukończyły 16 lat. Jeżeli nie ukończyłeś(-aś) 16 roku życia, zgodnie z wymogami COPPA (<a href=\"https://pl.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act\">Prawo o Ochronie Prywatności Dzieci w Internecie</a>), nie używaj tej strony.</p>\n\n      <p>Jeżeli serwer znajduje się w USA: Ta strona, produkty i usługi są przeznaczone dla osób, które ukończyły 13 lat. Jeżeli nie ukończyłeś(-aś) 13 roku życia, zgodnie z wymogami RODO (<a href=\"https://pl.wikipedia.org/wiki/Ogólne_rozporządzenie_o_ochronie_danych\">Ogólne rozporządzenie o ochronie danych</a>), nie używaj tej strony.</p>\n\n      <p>Wymogi mogą być inne, jeżeli serwer znajduje się w innym kraju.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"changes\">Zmiany w naszej polityce prywatności</h3>\n\n      <p>Jeżeli zdecydujemy się na zmiany w polityce prywatności, pojawią się na tej stronie.</p>\n\n      <p>Dokument jest dostępny na licencji CC-BY-SA. Ostatnio zmodyfikowano go 7 marca 2018, przetłumaczono 9 kwietnia 2018. Tłumaczenie (mimo dołożenia wszelkich starań) może nie być w pełni poprawne.</p>\n\n      <p>Bazowano na <a href=\"https://github.com/discourse/discourse\">polityce prywatności Discourse</a>.</p>\n    title: Zasady korzystania i polityka prywatności %{instance}\n  themes:\n    contrast: Mastodon (Wysoki kontrast)\n    default: Mastodon (Ciemny)\n    mastodon-light: Mastodon (Jasny)\n  time:\n    formats:\n      default: \"%d. %b %Y, %H:%M\"\n      month: \"%b %Y\"\n  two_factor_authentication:\n    code_hint: Aby kontynuować, wprowadź kod wyświetlany przez aplikację uwierzytelniającą\n    description_html: Jeśli włączysz <strong>uwierzytelnianie dwuetapowe</strong>, logowanie się będzie wymagało podania tokenu wyświetlonego na Twoim telefonie.\n    disable: Wyłącz\n    enable: Włącz\n    enabled: Uwierzytelnianie dwuetapowe jest włączone\n    enabled_success: Pomyślnie aktywowano uwierzytelnianie dwuetapowe\n    generate_recovery_codes: Generuj kody zapasowe\n    instructions_html: \"<strong>Zeskanuj ten kod QR na swoim urządzeniu za pomocą Google Authenticator, FreeOTP lub podobnej aplikacji</strong>. Od teraz będzie ona generowała kody wymagane przy logowaniu.\"\n    lost_recovery_codes: Kody zapasowe pozwolą uzyskać dostęp do portalu, jeżeli utracisz dostęp do telefonu. Jeżeli utracisz dostęp do nich, możesz wygenerować je ponownie tutaj. Poprzednie zostaną unieważnione.\n    manual_instructions: 'Jeżeli nie możesz zeskanować kodu QR, musisz wprowadzić ten kod ręcznie:'\n    recovery_codes: Przywróć kody zapasowe\n    recovery_codes_regenerated: Pomyślnie wygenerowano ponownie kody zapasowe\n    recovery_instructions_html: Jeżeli kiedykolwiek utracisz dostęp do telefonu, możesz wykorzystać jeden z kodów zapasowych, aby odzyskać dostęp do konta. <strong>Trzymaj je w bezpiecznym miejscu</strong>. Na przykład, wydrukuj je i przechowuj z ważnymi dokumentami.\n    setup: Skonfiguruj\n    wrong_code: Wprowadzony kod jest niepoprawny! Czy czas serwera i urządzenia jest poprawny?\n  user_mailer:\n    backup_ready:\n      explanation: Zażądałeś pełnej kopii zapasowej konta na Mastodonie. Jest ona dostępna do pobrania!\n      subject: Twoje archiwum jest gotowe do pobrania\n      title: Odbiór archiwum\n    warning:\n      explanation:\n        disable: Kiedy Twoje konto jest wyłączone, Twoje dane pozostają na serwerze, ale nie możesz wykonywać żadnych działań, zanim zostanie odblokowane.\n        silence: Kiedy Twoje konto jest ograniczone, tylko osoby które je śledzą będą widzieć Twoje wpisy. Może ono też przestać być widoczne na publicznych listach. Inni wciąż mogą zacząć Cię śledzić.\n        suspend: Twoje konto zostało zawieszone i wszystkie Twoje wpisy wraz z zawartością multimedialną zostały nieodwracalnie usunięte z tego serwera i serwerów, których użytkownicy śledzili Cię.\n      review_server_policies: Przejrzyj zasady serwera\n      subject:\n        disable: Twoje konto %{acct} zostało wyłączone\n        none: Ostrzeżenie dla %{acct}\n        silence: Twoje konto %{acct} zostało ograniczone\n        suspend: Twoje konto %{acct} zostało zawieszone\n      title:\n        disable: Konto wyłączone\n        none: Ostrzeżenie\n        silence: Konto ograniczone\n        suspend: Konto zawieszone\n    welcome:\n      edit_profile_action: Skonfiguruj profil\n      edit_profile_step: Możesz dostować profil wysyłając awatar, obraz nagłówka, zmieniając wyświetlaną nazwę i wiele więcej. Jeżeli chcesz, możesz zablokować konto, aby kontrolować, kto może Cię śledzić.\n      explanation: Kilka wskazówek, które pomogą Ci rozpocząć\n      final_action: Zacznij pisać\n      final_step: 'Zacznij tworzyć! Nawet jeżeli nikt Cię nie śledzi, Twoje publiczne wiadomości będą widziane przez innych, na przykład na lokalnej osi czasu i w hashtagach. Możesz też utworzyć wpis wprowadzający używając hashtagu #introductions.'\n      full_handle: Twój pełny adres\n      full_handle_hint: Ten adres możesz podać znajomym, aby mogli skontaktować się z Tobą lub zacząć śledzić z innego serwera.\n      review_preferences_action: Zmień ustawienia\n      review_preferences_step: Upewnij się, że zmieniłeś(-aś) ustawienia, takie jak maile, które chciałbyś otrzymywać lub domyślne opcje prywatności. Jeżeli nie masz choroby lokomocyjnej, możesz włączyć automatyczne odtwarzanie animacji GIF.\n      subject: Witaj w Mastodonie\n      tip_federated_timeline: Oś czasu federacji przedstawia całą sieć Mastodona. Wyświetla tylko wpisy osób, które śledzą użytkownicy Twojej instancji, więc nie jest kompletna.\n      tip_following: Domyślnie śledzisz administratora/ów swojej instancji. Aby znaleźć więcej ciekawych ludzi, zajrzyj na lokalną i federalną oś czasu.\n      tip_local_timeline: Lokalna oś czasu przedstawia osoby z %{instance}. To Twoi najbliżsi sąsiedzi!\n      tip_mobile_webapp: Jeżeli Twoja przeglądarka pozwala na dodanie Mastodona na ekran główny, będziesz otrzymywać natychmiastowe powiadomienia. Działa to prawie jak natywna aplikacja!\n      tips: Wskazówki\n      title: Witaj na pokładzie, %{name}!\n  users:\n    follow_limit_reached: Nie możesz śledzić więcej niż %{limit} osób\n    invalid_email: Adres e-mail jest niepoprawny\n    invalid_otp_token: Kod uwierzytelniający jest niepoprawny\n    otp_lost_help_html: Jeżeli utracisz dostęp do obu, możesz skontaktować się z %{email}\n    seamless_external_login: Zalogowano z użyciem zewnętrznej usługi, więc ustawienia hasła i adresu e-mail nie są dostępne.\n    signed_in_as: 'Zalogowany jako:'\n  verification:\n    explanation_html: 'Możesz <strong>zweryfikować siebie jako właściciela stron, do których odnośniki znajdują się w metadanych</strong>. Aby to zrobić, strona musi zawierać odnośnik do Twojego profilu na Mastodonie. Odnośnik <strong>musi</strong> zawierać atrybut <code>rel=\"me\"</code>. Jego zawartość nie ma znaczenia. Przykład:'\n    verification: Weryfikacja\n"
  },
  {
    "path": "config/locales/pt-BR.yml",
    "content": "---\npt-BR:\n  about:\n    about_hashtag_html: Estes são toots públicos com a hashtag <strong>#%{hashtag}</strong>. Você pode interagir com eles se tiver uma conta em qualquer lugar no fediverso.\n    about_mastodon_html: Mastodon é uma rede social baseada em protocolos abertos e software gratuito e de código aberto. É descentralizada como e-mail.\n    about_this: Sobre\n    active_count_after: Ativo\n    active_footnote: Usuários ativos mensais (UAM)\n    administered_by: 'Administrado por:'\n    apps: Apps\n    apps_platforms: Use o Mastodon a partir de iOS, Android e outras plataformas\n    browse_directory: Navegue pelo diretório de perfis e filtre por interesses\n    browse_public_posts: Navegue pelos posts públicos sendo postados ao vivo no Mastodon\n    contact: Contato\n    contact_missing: Não definido\n    contact_unavailable: Não disponível\n    discover_users: Descubra usuários\n    documentation: Documentação\n    extended_description_html: |\n      <h3>Um bom lugar para regras</h3>\n      <p>A descrição da instância ainda não foi feita.</p>\n    federation_hint_html: Com uma conta em %{instance} você vai poder seguir pessoas em qualquer servidor Mastodon ou outros do fediverso.\n    generic_description: \"%{domain} é um servidor na rede\"\n    get_apps: Experimente um aplicativo\n    hosted_on: Mastodon hospedado em %{domain}\n    learn_more: Saiba mais\n    privacy_policy: Política de Privacidade\n    see_whats_happening: Veja o que está acontecendo\n    server_stats: 'Estatísticas do servidor:'\n    source_code: Código-fonte\n    status_count_before: Autores de\n    tagline: Siga amigos e encontre novos\n    terms: Termos de serviço\n    user_count_after:\n      one: usuário\n      other: usuários\n    user_count_before: Casa de\n    what_is_mastodon: O que é Mastodon?\n  accounts:\n    choices_html: 'Escolhas de %{name}:'\n    follow: Seguir\n    followers:\n      one: Seguidor\n      other: Seguidores\n    following: Seguindo\n    joined: Participa desde %{date}\n    last_active: última atividade\n    link_verified_on: A posse desse link foi checada em %{date}\n    media: Mídia\n    moved_html: \"%{name} se mudou para %{new_profile_link}:\"\n    network_hidden: Esta informação não está disponível\n    nothing_here: Não há nada aqui!\n    people_followed_by: Pessoas que %{name} segue\n    people_who_follow: Pessoas que seguem %{name}\n    pin_errors:\n      following: Você tem que estar seguindo a pessoa que você quer sugerir\n    posts_with_replies: Toots e respostas\n    reserved_username: Este usuário está reservado\n    roles:\n      admin: Administrador\n      bot: Robô\n      moderator: Moderador\n    unavailable: Perfil indisponível\n    unfollow: Deixar de seguir\n  admin:\n    account_actions:\n      action: Tomar uma ação\n      title: Realizar uma ação de moderação em %{acct}\n    account_moderation_notes:\n      create: Criar uma advertência\n      created_msg: Nota de moderação criada com sucesso!\n      delete: Excluir\n      destroyed_msg: Nota de moderação excluída com sucesso!\n    accounts:\n      approve: Aprovar\n      approve_all: Aprovar tudo\n      are_you_sure: Você tem certeza?\n      by_domain: Domínio\n      change_email:\n        changed_msg: E-mail da conta modificado com sucesso!\n        current_email: E-mail atual\n        label: Mudar e-mail\n        new_email: Novo e-mail\n        submit: Mudar e-mail\n        title: Mudar e-mail para %{username}\n      confirm: Confirmar\n      confirmed: Confirmado\n      confirming: Confirmando\n      deleted: Excluído\n      demote: Rebaixar\n      disable: Desativar\n      disable_two_factor_authentication: Desativar 2FA\n      disabled: Desativada\n      display_name: Nome de exibição\n      domain: Domínio\n      edit: Editar\n      email: E-mail\n      email_status: Estado do e-mail\n      enable: Ativar\n      enabled: Ativado\n      feed_url: URL do feed\n      followers: Seguidores\n      followers_url: URL de seguidores\n      follows: Segue\n      header: Cabeçalho\n      inbox_url: URL da caixa de entrada\n      invited_by: Convidado por\n      joined: Se cadastrou\n      location:\n        all: Todos\n        remote: Remoto\n        title: Localização\n      login_status: Situação de login\n      media_attachments: Mídia(s) anexada(s)\n      memorialize: Tornar um memorial\n      moderation:\n        active: Ativo\n        all: Todos\n        pending: Pendente\n        silenced: Silenciados\n        suspended: Suspensos\n        title: Moderação\n      moderation_notes: Notas de moderação\n      most_recent_activity: Atividade mais recente\n      most_recent_ip: IP mais recente\n      no_account_selected: Nenhuma conta foi modificada, pois nenhuma conta foi selecionada\n      no_limits_imposed: Nenhum limite imposto\n      not_subscribed: Não está inscrito\n      outbox_url: URL da caixa de saída\n      pending: Esperando revisão\n      perform_full_suspension: Suspender\n      profile_url: URL do perfil\n      promote: Promover\n      protocol: Protocolo\n      public: Público\n      push_subscription_expires: Inscrição PuSH expira\n      redownload: Atualizar perfil\n      reject: Rejeitar\n      reject_all: Rejeitar tudo\n      remove_avatar: Remover avatar\n      remove_header: Remover cabeçalho\n      resend_confirmation:\n        already_confirmed: Este usuário já está confirmado\n        send: Re-enviar o e-mail de confirmação\n        success: E-mail de confirmação enviado com sucesso!\n      reset: Anular\n      reset_password: Modificar senha\n      resubscribe: Reinscrever-se\n      role: Permissões\n      roles:\n        admin: Administrador\n        moderator: Moderador\n        staff: Equipe\n        user: Usuário\n      salmon_url: URL Salmon\n      search: Pesquisar\n      shared_inbox_url: URL da caixa de entrada compartilhada\n      show:\n        created_reports: Denúncias criadas por esta conta\n        targeted_reports: Denúncias feitas sobre esta conta\n      silence: Silenciar\n      silenced: Silenciado\n      statuses: Postagens\n      subscribe: Inscrever-se\n      suspended: Suspenso\n      title: Contas\n      unconfirmed_email: E-mail não confirmado\n      undo_silenced: Retirar silenciamento\n      undo_suspension: Retirar suspensão\n      unsubscribe: Desinscrever-se\n      username: Nome de usuário\n      warn: Notificar\n    action_logs:\n      actions:\n        assigned_to_self_report: \"%{name} designou a denúncia %{target} para si\"\n        change_email_user: \"%{name} mudou o endereço de e-mail do usuário %{target}\"\n        confirm_user: \"%{name} confirmou o endereço de e-mail do usuário %{target}\"\n        create_account_warning: \"%{name} enviou um aviso para %{target}\"\n        create_custom_emoji: \"%{name} enviou o emoji novo %{target}\"\n        create_domain_block: \"%{name} bloqueou o domínio %{target}\"\n        create_email_domain_block: \"%{name} colocou o domínio de e-mail %{target} na lista negra\"\n        demote_user: \"%{name} rebaixou o usuário %{target}\"\n        destroy_custom_emoji: \"%{name} destruiu emoji %{target}\"\n        destroy_domain_block: \"%{name} desbloqueou o domínio %{target}\"\n        destroy_email_domain_block: \"%{name} retirou o domínio de e-mail %{target} da lista negra\"\n        destroy_status: \"%{name} removeu postagem feita por %{target}\"\n        disable_2fa_user: \"%{name} desabilitou a exigência de autenticação em dois passos para o usuário %{target}\"\n        disable_custom_emoji: \"%{name} desabilitou o emoji %{target}\"\n        disable_user: \"%{name} desabilitou o acesso para o usuário %{target}\"\n        enable_custom_emoji: \"%{name} habilitou o emoji %{target}\"\n        enable_user: \"%{name} habilitou o acesso para o usuário %{target}\"\n        memorialize_account: \"%{name} transformou a conta de %{target} em um memorial\"\n        promote_user: \"%{name} promoveu o usuário %{target}\"\n        remove_avatar_user: \"%{name} removeu o avatar de %{target}\"\n        reopen_report: \"%{name} reabriu a denúncia %{target}\"\n        reset_password_user: \"%{name} redefiniu a senha do usuário %{target}\"\n        resolve_report: \"%{name} resolveu a denúncia %{target}\"\n        silence_account: \"%{name} silenciou a conta de %{target}\"\n        suspend_account: \"%{name} suspendeu a conta de %{target}\"\n        unassigned_report: \"%{name} desatribuiu a denúncia %{target}\"\n        unsilence_account: \"%{name} desativou o silêncio de %{target}\"\n        unsuspend_account: \"%{name} desativou a suspensão de  %{target}\"\n        update_custom_emoji: \"%{name} atualizou o emoji %{target}\"\n        update_status: \"%{name} atualizou o estado de %{target}\"\n      deleted_status: \"(status deletado)\"\n      title: Auditar relatório\n    custom_emojis:\n      by_domain: Domínio\n      copied_msg: Cópia local do emoji criada com sucesso\n      copy: Copiar\n      copy_failed_msg: Não foi possível criar uma cópia local deste emoji\n      created_msg: Emoji criado com sucesso!\n      delete: Excluir\n      destroyed_msg: Emoji deletado com sucesso!\n      disable: Desabilitar\n      disabled_msg: Emoji desabilitado com sucesso\n      enable: Habilitar\n      enabled_msg: Emoji habilitado com sucesso\n      image_hint: PNG de até 50KB\n      listed: Listado\n      new:\n        title: Adicionar novo emoji customizado\n      overwrite: Sobrescrever\n      shortcode: Atalho\n      shortcode_hint: Pelo menos 2 caracteres, apenas caracteres alfanuméricos e underscores\n      title: Emojis customizados\n      unlisted: Não listado\n      update_failed_msg: Não foi possível atualizar esse emoji\n      updated_msg: Emoji atualizado com sucesso!\n      upload: Enviar\n    dashboard:\n      backlog: tarefas na fila\n      config: Configuração\n      feature_deletions: Remoção de contas\n      feature_invites: Convites\n      feature_profile_directory: Diretório de perfis\n      feature_registrations: Cadastros\n      feature_relay: Repetidor da federação\n      feature_timeline_preview: pré-visualização da timeline\n      features: Funcionalidades\n      hidden_service: Federação com serviços onion\n      open_reports: Denúncias em aberto\n      recent_users: Usuários recentes\n      search: Pesquisa em texto\n      single_user_mode: Modo de usuário único\n      space: Uso de espaço em disco\n      title: Painel de controle\n      total_users: usuários no total\n      trends: Tendências\n      week_interactions: interações essa semana\n      week_users_active: ativos essa semana\n      week_users_new: usuários essa semana\n    domain_blocks:\n      add_new: Adicionar novo bloqueio de domínio\n      created_msg: Bloqueio de domínio está sendo processado\n      destroyed_msg: Bloqueio de domínio desfeito\n      domain: Domínio\n      new:\n        create: Criar bloqueio\n        hint: O bloqueio de domínio não prevenirá a criação de entradas de contas na base de dados, mas vai reatroativa e automaticamente aplicar métodos específicos de moderação nestas contas.\n        severity:\n          desc_html: O <strong>Silêncio</strong> fará com que as postagens da conta fiquem invisíveis para qualquer um que não a esteja seguindo. A <strong>Suspensão</strong> removerá todo o conteúdo da conta, mídia e dados de perfil. Use <strong>Nenhum</strong> se você apenas deseja rejeitar arquivos de mídia.\n          noop: Nenhum\n          silence: Silêncio\n          suspend: Suspensão\n        title: Novo bloqueio de domínio\n      reject_media: Rejeitar arquivos de mídia\n      reject_media_hint: Remove arquivos de mídia armazenados localmente e recusa quaisquer outros no futuro. Irrelevante para suspensões\n      reject_reports: Rejeitar denúncias\n      reject_reports_hint: Ignorar todas as denúncias vindas deste domíno. Irrelevante para suspensões\n      rejecting_media: rejeitando arquivos de mídia\n      rejecting_reports: rejeitando denúncias\n      severity:\n        silence: silenciado\n        suspend: suspenso\n      show:\n        affected_accounts:\n          one: Uma conta no banco de dados foi afetada\n          other: \"%{count} contas no banco de dados foram afetadas\"\n        retroactive:\n          silence: Desativar silêncio de todas as contas existentes desse domínio\n          suspend: Retirar suspensão de todas as contas neste domínio\n        title: Retirar bloqueio de domínio de %{domain}\n        undo: Retirar\n      undo: Retirar bloqueio de domínio\n    email_domain_blocks:\n      add_new: Adicionar novo\n      created_msg: Bloqueio de domínio de e-mail criado com sucesso\n      delete: Excluir\n      destroyed_msg: Bloqueio de domínio de e-mail excluído com sucesso\n      domain: Domínio\n      new:\n        create: Adicionar domínio\n        title: Novo bloqueio de domínio de e-mail\n      title: Bloqueio de Domínio de E-mail\n    followers:\n      back_to_account: Voltar para a conta\n      title: Pessoas que seguem %{acct}\n    instances:\n      by_domain: Domínio\n      delivery_available: Entrega está disponível\n      known_accounts:\n        one: \"%{count} conta conhecida\"\n        other: \"%{count} contas conhecidas\"\n      moderation:\n        all: Todas\n        limited: Limitado\n        title: Moderação\n      title: Federação\n      total_blocked_by_us: Bloqueado por nós\n      total_followed_by_them: Seguidos por eles\n      total_followed_by_us: Seguidos por nós\n      total_reported: Denúncias sobre eles\n      total_storage: Mídias anexadas\n    invites:\n      deactivate_all: Desativar todos\n      filter:\n        all: Todos\n        available: Disponíveis\n        expired: Expirados\n        title: Filtro\n      title: Convites\n    pending_accounts:\n      title: Contas pendentes (%{count})\n    relays:\n      add_new: Adicionar novo repetidor\n      delete: Excluir\n      description_html: Um <strong>repetidor de federação</strong> é um servidor intermediário que troca um grande volume de toots públicos entre servidores que se inscrevem e publicam nele. <strong>O repetidor pode ser usado para ajudar servidores pequenos e médios a descobrir conteúdo do fediverso</strong>, que normalmente precisariam que usuários locais manualmente seguissem outras pessoas em servidores remotos.\n      disable: Desativar\n      disabled: Desabilitar\n      enable: Habilitar\n      enable_hint: Uma vez habilitado, seu servidor vai se inscrever para receber todos os toots públicos desse repetidor; E vai começar a enviar todos os toots públicos desse servidor para o repetidor.\n      enabled: Habilitado\n      inbox_url: URL do repetidor\n      pending: Esperando pela aprovação do repetidor\n      save_and_enable: Salvar e habilitar\n      setup: Configurar uma conexão de repetidor\n      title: Repetidores\n    report_notes:\n      created_msg: Nota de denúncia criada com sucesso!\n      destroyed_msg: Nota de denúncia excluída com sucesso!\n    reports:\n      account:\n        note: nota\n        report: denúncia\n      action_taken_by: Ação realizada por\n      are_you_sure: Você tem certeza?\n      assign_to_self: Designar para mim\n      assigned: Moderador designado\n      comment:\n        none: Nenhum\n      created_at: Denunciado\n      mark_as_resolved: Marcar como resolvido\n      mark_as_unresolved: Marcar como não resolvido\n      notes:\n        create: Adicionar nota\n        create_and_resolve: Resolver com nota\n        create_and_unresolve: Reabrir com nota\n        delete: Excluir\n        placeholder: Descreva que ações foram tomadas, ou quaisquer outras atualizações relacionadas…\n      reopen: Reabrir denúncia\n      report: 'Denúncia #%{id}'\n      reported_account: Conta denunciada\n      reported_by: Denunciada por\n      resolved: Resolvido\n      resolved_msg: Denúncia resolvida com sucesso!\n      title: Denúncias\n      unassign: Desatribuir\n      unresolved: Não resolvido\n      updated_at: Atualizado\n    settings:\n      activity_api_enabled:\n        desc_html: Contagem de status postados localmente, usuários ativos e novos cadastros filtrados semanalmente\n        title: Publicar estatísticas agregadas sobre atividade de usuários\n      bootstrap_timeline_accounts:\n        desc_html: Separe nomes de usuário através de vírgulas. Funciona apenas com contas locais e destrancadas. O padrão quando vazio são todos os administradores locais.\n        title: Usuários a serem seguidos por padrão por novas contas\n      contact_information:\n        email: E-mail\n        username: Usuário de contato\n      custom_css:\n        desc_html: Modificar o visual com CSS que é carregado em todas as páginas\n        title: CSS customizado\n      hero:\n        desc_html: Aparece na página inicial. Ao menos 600x100px é recomendado. Se não estiver definido, o thumbnail da instância é usado no lugar\n        title: Imagem de capa\n      mascot:\n        desc_html: Mostrado em diversas páginas. Ao menos 293×205px recomendado. Quando não está configurado, o mascote padrão é mostrado\n        title: Imagem do mascote\n      peers_api_enabled:\n        desc_html: Nomes de domínio que essa instância encontrou no fediverso\n        title: Publicar lista de instâncias descobertas\n      preview_sensitive_media:\n        desc_html: A pré-visualização do link em outros sites vai incluir uma miniatura mesmo se a mídia estiver marcada como sensível\n        title: Mostrar mídia sensível em pré-visualizações OpenGraph\n      profile_directory:\n        desc_html: Permitir que usuários possam ser descobertos\n        title: Ativar diretório de perfis\n      registrations:\n        closed_message:\n          desc_html: Exibido na página inicial quando cadastros estão fechados. Você pode usar tags HTML\n          title: Mensagem de cadastros fechados\n        deletion:\n          desc_html: Permitir que qualquer um delete a sua conta\n          title: Exclusão aberta de contas\n        min_invite_role:\n          disabled: Ninguém\n          title: Permitir convites de\n      registrations_mode:\n        modes:\n          approved: Aprovação necessária para cadastro\n          none: Ninguém pode se cadastrar\n          open: Qualquer um pode se cadastrar\n        title: Modo de cadastro\n      show_known_fediverse_at_about_page:\n        desc_html: Quando ligado, vai mostrar toots de todo o fediverso conhecido na prévia da timeline. Senão, mostra somente toots locais.\n        title: Mostrar fediverso conhecido na prévia da timeline\n      show_staff_badge:\n        desc_html: Mostrar uma insígnia de Equipe na página de usuário\n        title: Mostrar insígnia de equipe\n      site_description:\n        desc_html: Parágrafo introdutório na página inicial. Descreva o que faz esse servidor especial, e qualquer outra coisa de importante. Você pode usar tags HTML, em especial <code>&lt;a&gt;</code> e <code>&lt;em&gt;</code>.\n        title: Descrição da instância\n      site_description_extended:\n        desc_html: Um ótimo lugar para seu código de conduta, regras, diretrizes e outras coisas para diferenciar a sua instância. Você pode usar tags HTML\n        title: Informação estendida customizada\n      site_short_description:\n        desc_html: Aparece na barra lateral e nas meta tags. Descreva o que é Mastodon e o que faz esse servidor especial em um único parágrafo. Se não for preenchido, é substituído pela descrição da instância.\n        title: Descrição curta da instância\n      site_terms:\n        desc_html: Você pode escrever a sua própria política de privacidade, termos de serviço, entre outras coisas. Você pode usar tags HTML\n        title: Termos de serviço customizados\n      site_title: Nome da instância\n      thumbnail:\n        desc_html: Usada para prévias via OpenGraph e API. Recomenda-se 1200x630px\n        title: Miniatura da instância\n      timeline_preview:\n        desc_html: Exibir a timeline pública na página inicial\n        title: Prévia da timeline\n      title: Configurações do site\n    statuses:\n      back_to_account: Voltar para página da conta\n      batch:\n        delete: Deletar\n        nsfw_off: Marcar como não-sensível\n        nsfw_on: Marcar como sensível\n      failed_to_execute: Falha em executar\n      media:\n        title: Mídia\n      no_media: Não há mídia\n      no_status_selected: Nenhum status foi modificado porque nenhum estava selecionado\n      title: Postagens da conta\n      with_media: Com mídia\n    subscriptions:\n      callback_url: URL de Callback\n      confirmed: Confirmado\n      expires_in: Expira em\n      last_delivery: Última entrega\n      topic: Tópico\n    tags:\n      accounts: Contas\n      hidden: Escondido\n      hide: Esconder do diretório\n      unhide: Mostrar no diretório\n      visible: Visível\n    title: Administração\n    warning_presets:\n      add_new: Adicionar um novo\n      delete: Excluir\n      edit: Editar\n      edit_preset: Editar o aviso pré-definido\n      title: Gerenciar os avisos pré-definidos\n  admin_mailer:\n    new_pending_account:\n      body: Os detalhes da nova conta estão abaixo. Você pode aprovar ou rejeitar essa aplicação.\n      subject: Nova conta para revisão em %{instance} (%{username})\n    new_report:\n      body: \"%{reporter} denunciou %{target}\"\n      body_remote: Alguém da instância %{domain} reportou %{target}\n      subject: Nova denúncia sobre %{instance} (#%{id})\n  application_mailer:\n    notification_preferences: Mudar preferências de e-mail\n    settings: 'Mudar e-mail de preferência: %{link}'\n    view: 'Visualizar:'\n    view_profile: Ver perfil\n    view_status: Ver status\n  applications:\n    created: Aplicação criada com sucesso\n    destroyed: Aplicação excluída com sucesso\n    invalid_url: A URL provida é inválida\n    regenerate_token: Regenerar token de acesso\n    token_regenerated: Token de acesso renegerado com sucesso\n    warning: Tenha cuidado com estes dados. Nunca compartilhe com alguém!\n    your_token: Seu token de acesso\n  auth:\n    apply_for_account: Pedir um convite\n    change_password: Senha\n    checkbox_agreement_html: Eu concordo com <a href=\"%{rules_path}\" target=\"_blank\">as regras do servidor</a> e com <a href=\"%{terms_path}\" target=\"_blank\">os termos de serviço</a>\n    confirm_email: Confirmar e-mail\n    delete_account: Excluir conta\n    delete_account_html: Se você deseja excluir a sua conta, você pode <a href=\"%{path}\">prosseguir para cá</a>. Uma confirmação será requisitada.\n    didnt_get_confirmation: Não recebeu instruções de confirmação?\n    forgot_password: Esqueceu a sua senha?\n    invalid_reset_password_token: Token de modificação de senha é inválido ou expirou. Por favor, requisite um novo.\n    login: Entrar\n    logout: Sair\n    migrate_account: Mudar para uma conta diferente\n    migrate_account_html: Se você quer redirecionar essa conta para uma outra você pode <a href=\"%{path}\">configurar isso aqui</a>.\n    or_log_in_with: Ou faça login com\n    register: Cadastrar-se\n    registration_closed: \"%{instance} não está aceitando novos membros\"\n    resend_confirmation: Reenviar instruções de confirmação\n    reset_password: Redefinir senha\n    security: Segurança\n    set_new_password: Definir uma nova senha\n    trouble_logging_in: Problemas para se conectar?\n  authorize_follow:\n    already_following: Você já está seguindo esta conta\n    error: Infelizmente, ocorreu um erro ao buscar a conta remota\n    follow: Seguir\n    follow_request: 'Você mandou uma solicitação de seguidor para:'\n    following: 'Sucesso! Você agora está seguindo:'\n    post_follow:\n      close: Ou você pode simplesmente fechar esta janela.\n      return: Exibir o perfil do usuário\n      web: Voltar para a página inicial\n    title: Seguir %{acct}\n  datetime:\n    distance_in_words:\n      about_x_months: \"%{count} meses\"\n      about_x_years: \"%{count} anos\"\n      almost_x_years: \"%{count} anos\"\n      half_a_minute: Agora\n      less_than_x_minutes: \"%{count} meses\"\n      less_than_x_seconds: Agora\n      over_x_years: \"%{count} anos\"\n      x_days: \"%{count} dias\"\n      x_minutes: \"%{count} minutos\"\n      x_months: \"%{count} meses\"\n      x_seconds: \"%{count} segundos\"\n  deletes:\n    bad_password_msg: Boa tentativa, hackers! Senha incorreta\n    confirm_password: Insira a sua senha atual para verificar a sua identidade\n    description_html: Isto vai <strong>permanente e irreversivelmente</strong> remover conteúdo de sua conta e desativá-la. O seu nome de usuário permanecerá reservado para previnir futuros roubos de identidade.\n    proceed: Excluir conta\n    success_msg: A sua conta foi excluída com sucesso\n    warning_html: Apenas a exclusão de conteúdo desta instância em particular é garantida. Conteúdo que tenha sido largamente compartilhado muito provavelmente deixará traços. Servidores offline e servidores que se desinscreveram de suas atualizações não irão atualizar as suas bases de dados.\n    warning_title: Disponibilidade de conteúdo disseminado\n  directories:\n    directory: Diretório de perfis\n    enabled: Você está na lista do diretório.\n    enabled_but_waiting: Você escolheu ser listado no diretório, mas você ainda não tem o mínimo de seguidores (%{min_followers}) para ser listado.\n    explanation: Descobrir usuários baseado em seus interesses\n    explore_mastodon: Explorar %{title}\n    how_to_enable: Você não se inscreveu no diretório. Você pode se inscrever abaixo. Use hashtags no texto da sua bio para ser listado em hashtags específicas!\n    people:\n      one: \"%{count} pessoa\"\n      other: \"%{count} pessoas\"\n  errors:\n    '403': Você não tem permissão para ver esta página.\n    '404': A página pela qual você está procurando não existe.\n    '410': A página pela qual você está procurando não existe mais.\n    '422':\n      content: A verificação de segurança falhou. Você desativou o uso de cookies?\n      title: Verificação de segurança falhou\n    '429': Muitas requisições\n    '500':\n      content: Desculpe, algo deu errado.\n      title: Esta página não está certa\n    noscript_html: Para usar o aplicativo web do Mastodon, por favor ative o JavaScript. Ou, se quiser, experimente um dos <a href=\"%{apps_path}\">apps nativos</a> para o Mastodon em sua plataforma.\n  existing_username_validator:\n    not_found: não foi possível encontrar um usuário local com esse nome de usuário\n    not_found_multiple: não foi possível encontrar %{usernames}\n  exports:\n    archive_takeout:\n      date: Data\n      download: Baixe o seu arquivo\n      hint_html: Você pode pedir um arquivo dos seus <strong>toots e mídia enviada</strong>. Os dados exportados estarão no formato ActivityPub, que podem ser lidos por qualquer software compatível. Você pode pedir um arquivo a cada 7 dias.\n      in_progress: Preparando o seu arquivo...\n      request: Solicitar o seu arquivo\n      size: Tamanho\n    blocks: Você bloqueou\n    domain_blocks: Bloqueios de domínio\n    follows: Você segue\n    lists: Listas\n    mutes: Você silenciou\n    storage: Armazenamento de mídia\n  featured_tags:\n    add_new: Adicionar uma nova hashtag\n    errors:\n      limit: Você atingiu o limite de hashtags em destaque\n  filters:\n    contexts:\n      home: Página inicial\n      notifications: Notificações\n      public: Timelines públicas\n      thread: Conversas\n    edit:\n      title: Editar filtro\n    errors:\n      invalid_context: Contexto inválido ou nenhum contexto informado\n      invalid_irreversible: O filtro irreversível só funciona com contexto de página inicial ou notificações\n    index:\n      delete: Remover\n      title: Filtros\n    new:\n      title: Adicionar novo filtro\n  footer:\n    developers: Desenvolvedores\n    more: Mais…\n    resources: Recursos\n  generic:\n    all: Tudo\n    changes_saved_msg: Mudanças salvas com sucesso!\n    copy: Copiar\n    order_by: Ordenar por\n    save_changes: Salvar mudanças\n    validation_errors:\n      one: Algo não está certo! Por favor, reveja o erro abaixo\n      other: Algo não está certo! Por favor, reveja os %{count} erros abaixo\n  html_validator:\n    invalid_markup: 'contém HTML inválido: %{error}'\n  identity_proofs:\n    active: Ativo\n    authorize: Sim, autorizar\n    authorize_connection_prompt: Autorizar essa conexão criptográfica?\n    errors:\n      failed: A conexão criptográfica falhou. Por favor tente novamente a partir de %{provider}.\n      keybase:\n        invalid_token: Tokens keybase são hashs de assinatura e devem conter 66 caracteres hexa\n        verification_failed: Keybase não reconhece esse token como uma assinatura do usuário keybase %{kb_username}. Por favor tente novamente a partir de Keybase.\n      wrong_user: Não é possível criar uma prova para %{proving} estando logado como %{current}. Faça login como %{proving} e tente novamente.\n    explanation_html: Você pode conectar criptograficamente suas outras identidades, tais quais seu perfil Keybase. Isso permite outras pessoas de lhe enviarem mensagens encriptadas e confiar no conteúdo que você as envia.\n    i_am_html: Eu sou %{username} em %{service}.\n    identity: Identidade\n    inactive: Inativo\n    publicize_checkbox: 'E publique isso:'\n    publicize_toot: 'Está provado! Eu sou %{username} no %{service}: %{url}'\n    status: Status da verificação\n    view_proof: Ver prova\n  imports:\n    modes:\n      merge: Juntar\n      merge_long: Manter os registros existentes e adicionar os novos\n      overwrite: Sobreescrever\n      overwrite_long: Substituir os registros atuais com os novos\n    preface: Você pode importar dados que você exportou de outra instância, como a lista de pessoas que você segue ou bloqueou.\n    success: Os seus dados foram enviados com sucesso e serão processados em instantes\n    types:\n      blocking: Lista de bloqueio\n      domain_blocking: Lista de domínios bloqueados\n      following: Pessoas que você segue\n      muting: Lista de silêncio\n    upload: Enviar\n  in_memoriam_html: Em memória.\n  invites:\n    delete: Desativar\n    expired: Expirados\n    expires_in:\n      '1800': 30 minutos\n      '21600': 6 horas\n      '3600': 1 hora\n      '43200': 12 horas\n      '604800': 1 semana\n      '86400': 1 dia\n    expires_in_prompt: Nunca\n    generate: Gerar\n    invited_by: 'Você recebeu um convite de:'\n    max_uses:\n      one: 1 uso\n      other: \"%{count} usos\"\n    max_uses_prompt: Sem limite\n    prompt: Gerar e compartilha links com outras pessoas para permitir acesso a essa instância\n    table:\n      expires_at: Expira em\n      uses: Usos\n    title: Convidar pessoas\n  lists:\n    errors:\n      limit: Você alcançou o número máximo de listas\n  media_attachments:\n    validations:\n      images_and_video: Não é possível anexar um vídeo a uma postagem que já contém imagens\n      too_many: Não é possível anexar mais de 4 imagens\n  migrations:\n    acct: username@domain da nova conta\n    currently_redirecting: 'Seu perfil está configurado para redirecionar para:'\n    proceed: Salvar\n    updated_msg: As configurações de migração da sua conta foram atualizadas com sucesso!\n  moderation:\n    title: Moderação\n  notification_mailer:\n    digest:\n      action: Ver todas as notificações\n      body: Aqui está um breve resumo das mensagens que você perdeu desde o seu último acesso em %{since}\n      mention: \"%{name} te mencionou em:\"\n      new_followers_summary:\n        one: Você tem um novo seguidor! Yay!\n        other: Você tem %{count} novos seguidores! Maravilha!\n      subject:\n        one: \"Uma nova notificação desde o seu último acesso \\U0001F418\"\n        other: \"%{count} novas notificações desde o seu último acesso \\U0001F418\"\n      title: Enquanto você estava ausente...\n    favourite:\n      body: 'Sua postagem foi favoritada por %{name}:'\n      subject: \"%{name} favoritou a sua postagem\"\n      title: Novo favorito\n    follow:\n      body: \"%{name} está te seguindo!\"\n      subject: \"%{name} está te seguindo\"\n      title: Novo seguidor\n    follow_request:\n      action: Gerenciar solicitações para seguir\n      body: \"%{name} requisitou autorização para te seguir\"\n      subject: 'Seguidor pendente: %{name}'\n      title: Nova solicitação de seguidor\n    mention:\n      action: Responder\n      body: 'Você foi mencionado por %{name} em:'\n      subject: Você foi mencionado por %{name}\n      title: Nova menção\n    reblog:\n      body: 'Sua postagem foi compartilhada por %{name}:'\n      subject: \"%{name} compartilhou a sua postagem\"\n      title: Novo compartilhamento\n  pagination:\n    newer: Mais novo\n    next: Próximo\n    older: Mais antigo\n    prev: Anterior\n  polls:\n    errors:\n      already_voted: Você já votou nessa enquete\n      duplicate_options: contém itens duplicados\n      duration_too_long: está muito longe no futuro\n      duration_too_short: é curto demais\n      expired: A enquete já terminou\n      over_character_limit: não pode ter mais que %{max} caracteres em cada\n      too_few_options: deve ter mais que um item\n      too_many_options: não pode ter mais que %{max} itens\n  preferences:\n    other: Outro\n  relationships:\n    activity: Atividade da conta\n    dormant: Inativo\n    last_active: Ativo por último em\n    most_recent: Mais recente\n    moved: Mudou-se\n    mutual: Mútuo\n    primary: Primário\n    relationship: Relação\n    remove_selected_domains: Remover todos os seguidores dos domínios selecionados\n    remove_selected_followers: Remover os seguidores selecionados\n    remove_selected_follows: Deixar de seguir usuários selecionados\n    status: Status da conta\n  remote_follow:\n    acct: Insira o seu usuário@domínio a partir do qual você deseja agir\n    missing_resource: Não foi possível encontrar a URL de direcionamento para a sua conta\n    no_account_html: Não tem uma conta? Você pode <a href='%{sign_up_path}' target='_blank'>cadastrar-se aqui</a>\n    proceed: Prosseguir para seguir\n    prompt: 'Você irá seguir:'\n    reason_html: \"<strong>Por que esse passo é necessário?</strong> <code>%{instance}</code> pode não ser o servidor onde você se registrou, então precisamos redirecionar você para o seu servidor primeiro.\"\n  remote_interaction:\n    favourite:\n      proceed: Proceder para favoritar\n      prompt: 'Você quer favoritar este toot:'\n    reblog:\n      proceed: Proceder para compartilhar\n      prompt: 'Você quer compartilhar esse toot:'\n    reply:\n      proceed: Proceder para responder\n      prompt: 'Você quer responder à esse toot:'\n  remote_unfollow:\n    error: Erro\n    title: Título\n    unfollowed: Deixou de seguir\n  scheduled_statuses:\n    over_daily_limit: Você excedeu o limite de %{limit} toots planejados para esse dia\n    over_total_limit: Você excedeu o limite de %{limit} toots planejados\n    too_soon: A data planejada precisa ser no futuro\n  sessions:\n    activity: Última atividade\n    browser: Navegador\n    browsers:\n      generic: Navegador desconhecido\n      nokia: Navegador Nokia S40 Ovi\n    current_session: Sessão atual\n    description: \"%{browser} em %{platform}\"\n    explanation: Estes são os navegadores que estão conectados com a sua conta do Mastodon.\n    platforms:\n      other: Plataforma desconhecida\n    revoke: Revogar\n    revoke_success: Sessão revogada com sucesso\n    title: Sessões\n  settings:\n    account: Conta\n    account_settings: Configurações da conta\n    appearance: Aparência\n    authorized_apps: Apps autorizados\n    back: Voltar para o Mastodon\n    delete: Exclusão de conta\n    development: Desenvolvimento\n    edit_profile: Editar perfil\n    export: Exportar dados\n    featured_tags: Hashtags em destaque\n    identity_proofs: Provas de identidade\n    import: Importar\n    import_and_export: Importar e exportar\n    migrate: Migração de conta\n    notifications: Notificações\n    preferences: Preferências\n    profile: Perfil\n    relationships: Seguindo e seguidores\n    two_factor_authentication: Autenticação em dois passos\n  statuses:\n    attached:\n      description: 'Anexado: %{attached}'\n      image:\n        one: \"%{count} imagem\"\n        other: \"%{count} imagens\"\n      video:\n        one: \"%{count} vídeo\"\n        other: \"%{count} vídeos\"\n    boosted_from_html: Compartilhada de %{acct_link}\n    content_warning: 'Aviso de conteúdo: %{warning}'\n    disallowed_hashtags:\n      one: 'continha a hashtag não permitida: %{tags}'\n      other: 'continha as hashtags não permitidas: %{tags}'\n    language_detection: Detectar idioma automaticamente\n    open_in_web: Abrir na web\n    over_character_limit: limite de caracteres de %{max} excedido\n    pin_errors:\n      limit: Você já fixou a quantidade máxima de toots\n      ownership: Toots de outras pessoas não podem ser fixados\n      private: Toot não-público não pode ser fixado\n      reblog: Um compartilhamento não pode ser fixado\n    poll:\n      total_votes:\n        one: \"%{count} voto\"\n        other: \"%{count} votos\"\n      vote: Votar\n    show_more: Mostrar mais\n    sign_in_to_participate: Entre para participar dessa conversa\n    visibilities:\n      private: Apenas seguidores\n      private_long: Mostrar apenas para seguidores\n      public: Público\n      public_long: Todos podem ver\n      unlisted: Não listado\n      unlisted_long: Todos podem ver, porém não será postado nas timelines públicas\n  stream_entries:\n    pinned: Toot fixado\n    reblogged: compartilhou\n    sensitive_content: Conteúdo sensível\n  terms:\n    body_html: |\n      <h2>Política de privacidade</h2>\n      <h3 id=\"collect\">Que informação nós coletamos?</h3>\n\n      <ul>\n      <li><em>Informação básica de conta</em>: Se você se registrar nesse servidor, podemos pedir que você utilize um nome de usuário, um e-mail e uma senha. Você também pode adicionar informações extras como um nome de exibição e biografia; enviar uma imagem de perfil e imagem de cabeçalho. O nome de usuário, nome de exibição, biografia, imagem de perfil e imagem de cabeçalho são sempre listadas publicamente.</li>\n      <li><em>Posts, informação de seguidores e outras informações públicas</em>: A lista de pessoas que você segue é listada publicamente, o mesmo é verdade para quem te segue. Quando você envia uma mensagem, a data e o horário são armazenados, assim como a aplicação que você usou para enviar a mensagem. Mensagens podem conter mídias anexadas, como imagens e vídeos. Posts públicos e não-listados estão disponíveis publicamente. Quando você destaca um post no seu perfil, isso também é uma informação pública. Seus posts são entregues aos seus seguidores e em alguns casos isso significa que eles são enviados para servidores diferentes e cópias são armazenadas nesses servidores. Quando você remove posts, essa informação também é entregue aos seus seguidores. O ato de compartilhar ou favoritar um outro post é sempre público.</li>\n      <li><em>Mensagens diretas e posts somente para seguidores</em>: Todos os posts são armazenados e processados no servidor. Posts somente para seguidores são entregues aos seus seguidores e usuários que são mencionados neles; mensagens diretas são entregues somente aos usuários mencionados nelas. Em alguns casos isso significa que as mensagens são entregues para servidores diferentes e cópias são armazenadas nesses servidores. Nós fazemos esforços substanciais para limitar o acesso dessas mensagens somente para as pessoas autorizadas, mas outros servidores podem não fazer o mesmo. É importante portanto revisar os servidores à qual seus seguidores pertencem. Você pode usar uma opção para aprovar ou rejeitar novos seguidores manualmente nas configurações. <em>Por favor tenha em mente que os operadores do servidor e de qualquer servidores do destinatário podem ver tais mensagens</em>, e que os destinatários podem fazer capturas de tela, copiar ou de outra maneira compartilhar as mensagens. <em>Não compartilhe informação confidencial pelo Mastodon.</em></li>\n      <li><em>IPs e outros metadados</em>: Quando você faz se autentica, nos guardamos o endereço de IP que você usou ao se autenticar e o nome do seu navegador da internet. Todas as sessões autenticadas são disponíveis para serem analisadas e revogadas nas configurações. O último endereço de IP usado é guardado por até 12 meses. Nós também podemos reter históricos do servidor que incluem o endereço de IP de todas as requisições ao nosso servidor.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"use\">Para que usamos os seus dados?</h3>\n\n      <p>Toda informação que coletamos de você pode ser usada das seguintes maneiras:</p>\n\n      <ul>\n      <li>Para prover a funcionalidade básica do Mastodon. Você só pode interagir com o conteúdo de outras pessoas e postar seu próprio conteúdo estando autenticado. Por exemplo, você pode seguir outras pessoas para ver seus posts combinados na sua linha do tempo personalizada.</li>\n      <li>Para auxiliar na moderação da comunidade, por exemplo ao comparar o seu endereço de IP com outros endereços de IP conhecidos para determinar evasão de banimento e outras violações.</li>\n      <li>O endereço de email que você prover pode ser usado para lhe enviar informação, notificação sobre outras pessoas interagindo com o seu conteúdo ou lhe enviando mensagens e para responder a questões ou outros pedidos.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"protect\">Como protegemos as suas informações?</h3>\n\n      <p>Nós implementamos diversas medidas de segurança para manter a segurança das suas informações pessoais quando você as acessa ou as envia. Entre outras coisas, sua sessão do navegador, bem como o tráfego entre as aplicações e a API são asseguradas usando SSL e a sua senha é guardada usando um algoritmo forte de encriptação de mão única. Você pode ativar autenticação em dois fatores como forma de aumentar a segurança no acesso à sua conta.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"data-retention\">Qual é a nossa política de retenção de dados?</h3>\n\n      <p>Nós fazemos esforços substanciais para:</p>\n\n      <ul>\n      <li>Reter o histórico do servidor contendo os endereços de IP de todas as requisições feitas à esse servidor, e com respeito a quanto tempo esses logs são retidos, não mais que 90 dias.</li>\n      <li>Reter o endereço de IP associado com usuários registrados não mais que 12 meses.</li>\n      </ul>\n\n      <p>Você pode pedir e fazer o download de um arquivo de todo o conteúdo da sua conta, incluindo as suas mensagens, suas mídias anexadas, imagem de perfil e imagem de topo.</p>\n\n      <p>Você pode remover irreversivelmente a sua conta a qualquer momento.</p>\n\n      <hr class=\"spacer\"/>\n\n      <h3 id=\"cookies\">Nós usamos cookies?</h3>\n\n      <p>Sim. Cookies são pequenos arquivos que um site ou serviço transfere ao seu disco rígido do seu computador através do seu navegador da web (se você permitir). Esses cookies permitem ao site conhecer seu navegador e, se você tiver uma conta registrada, associá-lo a sua conta.</p>\n\n      <p>Nós usamos cookies para compreender e salvar suas preferências para visitas futuras.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"disclose\">Nós compartilhamos qualquer informação para terceiros?</h3>\n\n      <p>Nós não vendemos, trocamos ou transferimos de qualquer maneira informação que pode lhe identificar à terceiros. Isso não inclui terceiros que podemos nos auxiliam a operar o nosso site, realizar nossos negócios ou lhe prestar serviços, contanto que esses terceiros se comprometam a manter essa informação confidencial. Nós podemos também divulgar informação quando acreditamos que é apropriado para obedecer a lei, para fazer cumprir nossas políticas ou proteger nossos direitos, propriedade ou segurança ou o direito, propriedade e segurança de outrem.</p>\n\n      <p>Seu conteúdo público pode ser descarregado por outros servidores na rede. Suas mensagens públicas e somente para seus seguidores são entregues aos servidores onde seus seguidores resides e as suas mensagens diretas são entregues ao servidor dos usuários mencionados nelas, contanto que esses seguidores ou usuários residam em um servidor diferente deste.</p>\n\n      <p>Quando você autoriza uma aplicação a usar sua conta, dependendo do escopo de permissões que você aprovar, a aplicação pode acessar sua informação pública, a lista de usuários que você segue, seus seguidores, suas listas, suas mensagens e suas mensagens favoritas. Aplicações nunca podem acessar o seu endereço de e-mail ou senha.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"children\">Uso desse site por crianças</h3>\n\n      <p>Se este servidor está na UE ou no EEE: Nosso site, produto e serviços são direcionados à pessoas que tem ao menos 16 anos de idade. Se você tem menos de 16 anos, de acordo com os requisitos da RGPD (<a href=\"https://pt.wikipedia.org/wiki/Regulamento_Geral_sobre_a_Prote%C3%A7%C3%A3o_de_Dados\">Regulamento Geral sobre a Proteção de Dados</a>) não use este site.</p>\n\n      <p>Se este servidor está hospedado nos EUA: Nosso site, produto e serviços são direcionados à pessoas que tem ao menos 13 anos de idade. Se você tem menos de 13 anos, de acordo com os requerimentos da COPPA (<a href=\"https://en.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act\">Children's Online Privacy Protection Act</a>) não use este site</p>\n\n      <p>Os requisitos da lei podem ser diferentes se esse servidor estiver em outra jurisdição</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"changes\">Mudanças à nossa política de privacidade</h3>\n\n      <p>Se decidirmos mudar nossa política de privacidade, nós iremos disponibilizar as mudanças nesta página.</p>\n\n      <p>Este documento é CC-BY-SA. Ele foi atualizado pela última vez em 7 de março de 2018.</p>\n\n      <p>Adaptado originalmente a partir da <a href=\"https://github.com/discourse/discourse\">política de privacidade Discourse</a>.</p>\n    title: \"%{instance} Termos de Serviço e Política de Privacidade\"\n  themes:\n    contrast: Mastodon  (Alto contraste)\n    default: Mastodon (Escuro)\n    mastodon-light: Mastodon (claro)\n  time:\n    formats:\n      month: \"%B de %Y\"\n  two_factor_authentication:\n    code_hint: Insira o código gerado pelo seu aplicativo auteticador para confirmar\n    description_html: Se você ativar a <strong>autenticação em dois passos</strong>, o acesso à sua conta exigirá posse de seu celular, que irá gerar tokens para validação.\n    disable: Desativar\n    enable: Ativar\n    enabled: A autenticação em dois passos está ativada\n    enabled_success: Autenticação em dois passos ativada com sucesso\n    generate_recovery_codes: Gerar códigos de recuperação\n    instructions_html: \"<strong>Escaneie este QR Code no Google Authenticator ou aplicativo TOTP similar com o seu celular</strong>. De agora em diante, este aplicativo irá gerar tokens que você terá que inserir quando desejar acessar a sua conta.\"\n    lost_recovery_codes: Códigos de recuperação permitem que você recupere acesso à sua conta caso perca o seu celular. Se você perdeu seus códigos de recuperação, você pode gerá-los novamente aqui. Seus códigos de recuperaçãp anteriores serão invalidados.\n    manual_instructions: 'Se você não pode escanear o QR code e precisa inserí-lo manualmente, aqui está o segredo em texto:'\n    recovery_codes: Códigos de recuperação de reserva\n    recovery_codes_regenerated: Códigos de recuperação regenerados com sucesso\n    recovery_instructions_html: Se você perder acesso ao seu celular, você pode usar um dos códigos de recuperação abaixo para reganhar acesso à sua conta. <strong>Mantenha os códigos de recuperação em um local seguro</strong>. Por exemplo, você pode imprimi-los e guardá-los com outros documentos importantes.\n    setup: Configurar\n    wrong_code: O código inserido é invalido! O horário do servidor e o horário do seu aparelho estão corretos?\n  user_mailer:\n    backup_ready:\n      explanation: Você pediu um backup completo da sua conta no Mastodon. E agora está pronto para ser baixado!\n      subject: Seu arquivo está pronto para ser baixado\n      title: Baixar arquivo\n    warning:\n      explanation:\n        disable: Enquanto sua conta está congelada, seus dados estão intactos, mas você não pode realizar nenhuma ação até que sua conta seja desbloqueada.\n        silence: Enquanto sua conta está limitada, somente pessoas que já estão seguindo você poderão ver seus toots nesse servidor, e você pode ser excluído de diversas listagens públicas. No entanto, outros ainda podem seguir você manualmente.\n        suspend: Sua conta está suspensa e todos os seus toots e mídias foram irreversivelmente removidas desse servidor e de servidores onde você tinha seguidores.\n      review_server_policies: Revisar as políticas do servidor\n      subject:\n        disable: Sua conta %{acct} foi congelada\n        none: Aviso para %{acct}\n        silence: Sua conta %{acct} foi limitada\n        suspend: Sua conta %{acct} foi suspensa\n      title:\n        disable: Conta congelada\n        none: Aviso\n        silence: Conta limitada\n        suspend: Conta suspensa\n    welcome:\n      edit_profile_action: Configurar perfil\n      edit_profile_step: Você pode customizar o seu perfil enviando um avatar, uma imagem de topo, mudando seu nome de exibição, dentre outros. Se você gostaria de aprovar novos seguidores antes que eles possam seguir você, você pode trancar a sua conta.\n      explanation: Aqui estão algumas dicas para te ajudar a começar\n      final_action: Comece a postar\n      final_step: 'Comece a postar! Mesmo sem seguidores, suas mensagens públicas podem ser vistas por outros, por exemplo nas timelines locais e buscando hashtags. Você pode querer fazer uma introdução usando a hashtag #introduções, ou em inglês usando a hashtag #introductions.'\n      full_handle: Seu nome de usuário completo\n      full_handle_hint: Isso é o que você diz aos seus amigos para que eles possam te mandar mensagens ou te seguir a partir de outra instância.\n      review_preferences_action: Mudar as preferências\n      review_preferences_step: Não se esqueça de configurar suas preferências, como quais e-mails você gostaria de receber, que nível de privacidade você gostaria que seus posts tenham por padrão. Se você não sofre de enjôo com movimento, você pode habilitar GIFs animando automaticamente.\n      subject: Boas-vindas ao Mastodon\n      tip_federated_timeline: A timeline global é uma visão contínua da rede do Mastodon. Mas ela só inclui pessoas que outras pessoas da sua instância estão seguindo, então não é a rede completa.\n      tip_following: Você vai seguir administrador(es) da sua instância por padrão. Para encontrar mais gente interessante, confira as timelines local e global.\n      tip_local_timeline: A timeline local é uma visão contínua das pessoas que estão em %{instance}. Esses são seus vizinhos próximos!\n      tip_mobile_webapp: Se o seu navegador móvel oferecer a opção de adicionar Mastodon à tela inicial, você pode receber notificações push. Vai funcionar quase como um aplicativo nativo!\n      tips: Dicas\n      title: Boas-vindas a bordo, %{name}!\n  users:\n    follow_limit_reached: Você não pode seguir mais que %{limit} pessoas\n    invalid_email: O endereço de e-mail é inválido\n    invalid_otp_token: Código de autenticação inválido\n    otp_lost_help_html: Se você perder o acesso à ambos, você pode entrar em contato com %{email}\n    seamless_external_login: Você está logado usando um serviço externo, então configurações de e-mail e senha não estão disponíveis.\n    signed_in_as: 'Acesso como:'\n  verification:\n    explanation_html: 'Você pode <strong>verificar-se como tendo posse dos links nos metadados do seu perfil</strong>. Para isso, o site conectado deve conter um link de volta para o seu perfil do Mastodon. O link de volta <strong>deve</strong> conter um atributo <code>rel=\"me\"</code>. O conteúdo ou texto do link não importa. Aqui está um exemplo:'\n    verification: Verificação\n"
  },
  {
    "path": "config/locales/pt.yml",
    "content": "---\npt:\n  about:\n    about_hashtag_html: Estes são toots públicos marcados com <strong>#%{hashtag}</strong>. Podes interagir com eles se tiveres uma conta Mastodon.\n    about_mastodon_html: Mastodon é uma rede social baseada em protocolos abertos da web e software livre e gratuito. É descentralizado como e-mail.\n    about_this: Sobre esta instância\n    administered_by: 'Administrado por:'\n    apps: Aplicações móveis\n    contact: Contacto\n    contact_missing: Não configurado\n    contact_unavailable: n.d.\n    documentation: Documentação\n    extended_description_html: |\n      <h3>Um bom lugar para regras</h3>\n      <p>A descrição estendida ainda não foi configurada.</p>\n    generic_description: \"%{domain} é um servidor na rede\"\n    hosted_on: Mastodon em %{domain}\n    learn_more: Saber mais\n    privacy_policy: Política de privacidade\n    source_code: Código fonte\n    status_count_after:\n      one: publicação\n      other: publicações\n    status_count_before: Que fizeram\n    terms: termos de serviço\n    user_count_after:\n      one: utilizador\n      other: utilizadores\n    user_count_before: Casa para\n    what_is_mastodon: O que é o Mastodon?\n  accounts:\n    choices_html: 'escolhas de %{name}:'\n    follow: Seguir\n    followers:\n      one: Seguidor\n      other: Seguidores\n    following: A seguir\n    joined: Aderiu %{date}\n    last_active: última vez activo\n    link_verified_on: A posse deste link foi verificada em %{date}\n    moved_html: \"%{name} mudou-se para %{new_profile_link}:\"\n    network_hidden: Esta informação não está disponível\n    nothing_here: Não há nada aqui!\n    people_followed_by: Pessoas seguidas por %{name}\n    people_who_follow: Pessoas que seguem %{name}\n    pin_errors:\n      following: Tu tens de estar a seguir a pessoa que pretendes apoiar\n    posts:\n      one: Publicação\n      other: Publicações\n    posts_tab_heading: Publicações\n    posts_with_replies: Posts e Respostas\n    reserved_username: Este nome de utilizadores é reservado\n    roles:\n      admin: Administrador\n      bot: Robô\n      moderator: Moderador\n    unfollow: Deixar de seguir\n  admin:\n    account_actions:\n      action: Executar acção\n      title: Executar acção de moderação em %{acct}\n    account_moderation_notes:\n      create: Criar\n      created_msg: Nota de moderação criada com sucesso!\n      delete: Eliminar\n      destroyed_msg: Nota de moderação excluída com sucesso!\n    accounts:\n      are_you_sure: Tens a certeza?\n      by_domain: Domínio\n      change_email:\n        changed_msg: E-mail da conta alterado com sucesso!\n        current_email: E-mail actual\n        label: Alterar e-mail\n        new_email: Novo e-mail\n        submit: Alterar e-mail\n        title: Alterar e-mail para %{username}\n      confirm: Confirme\n      confirmed: Confirmado\n      confirming: Confirmer\n      deleted: Apagada\n      demote: Rebaixar\n      disable: Desativar\n      disable_two_factor_authentication: Desativar 2FA\n      disabled: Desativado\n      display_name: Nome a mostrar\n      domain: Domínio\n      edit: Editar\n      email: E-mail\n      email_status: Estado do correio electrónico\n      enable: Ativar\n      enabled: Ativado\n      feed_url: URL do Feed\n      followers: Seguidores\n      followers_url: URL dos seguidores\n      follows: A seguir\n      header: Cabeçalho\n      inbox_url: URL da caixa de entrada\n      invited_by: Convidado por\n      joined: Aderiu\n      location:\n        all: Todos\n        remote: Remoto\n        title: Local\n      login_status: Estado de início de sessão\n      media_attachments: Media anexa\n      memorialize: Converter em memorial\n      moderation:\n        active: Activo\n        all: Todos\n        silenced: Silenciados\n        suspended: Supensos\n        title: Moderação\n      moderation_notes: Notas de moderação\n      most_recent_activity: Actividade mais recente\n      most_recent_ip: IP mais recente\n      no_limits_imposed: Sem limites impostos\n      not_subscribed: Não inscrito\n      outbox_url: URL da caixa de saída\n      perform_full_suspension: Fazer suspensão completa\n      profile_url: URL do perfil\n      promote: Promover\n      protocol: Protocolo\n      public: Público\n      push_subscription_expires: A Inscrição PuSH expira\n      redownload: Atualizar avatar\n      remove_avatar: Remover o avatar\n      remove_header: Remover o cabeçalho\n      resend_confirmation:\n        already_confirmed: Este usuário já está confirmado\n        send: Reenviar um email de confirmação\n        success: Email de confirmação enviado com sucesso!\n      reset: Restaurar\n      reset_password: Reset palavra-passe\n      resubscribe: Reinscrever\n      role: Permissões\n      roles:\n        admin: Administrador\n        moderator: Moderador\n        staff: Equipa\n        user: Utilizador\n      salmon_url: URL Salmon\n      search: Pesquisar\n      shared_inbox_url: URL da caixa de entrada compartilhada\n      show:\n        created_reports: Relatórios gerados por esta conta\n        targeted_reports: Relatórios feitos sobre esta conta\n      silence: Silêncio\n      silenced: Silenciada\n      statuses: Status\n      subscribe: Inscrever-se\n      suspended: Suspensa\n      title: Contas\n      unconfirmed_email: E-mail não confirmado\n      undo_silenced: Desfazer silenciar\n      undo_suspension: Desfazer supensão\n      unsubscribe: Cancelar inscrição\n      username: Usuário\n      warn: Aviso\n    action_logs:\n      actions:\n        assigned_to_self_report: \"%{name} atribuiu o relatório %{target} a si próprios\"\n        change_email_user: \"%{name} alterou o endereço de e-mail do utilizador %{target}\"\n        confirm_user: \"%{name} confirmou o endereço de e-mail do utilizador %{target}\"\n        create_account_warning: \"%{name} enviou um aviso para %{target}\"\n        create_custom_emoji: \"%{name} enviado emoji novo %{target}\"\n        create_domain_block: \"%{name} bloqueou o domínio %{target}\"\n        create_email_domain_block: \"%{name} adicionou na lista negra o domínio de correio electrónico %{target}\"\n        demote_user: \"%{name} rebaixou o utilizador %{target}\"\n        destroy_custom_emoji: \"%{name} destruiu o emoji %{target}\"\n        destroy_domain_block: \"%{name} desbloqueou o domínio %{target}\"\n        destroy_email_domain_block: \"%{name} adicionou na lista branca o domínio de correio electrónico %{target}\"\n        destroy_status: \"%{name} removeu o publicação feita por %{target}\"\n        disable_2fa_user: \"%{name} desactivou o requerimento de autenticação em dois passos para o utilizador %{target}\"\n        disable_custom_emoji: \"%{name} desabilitou o emoji %{target}\"\n        disable_user: \"%{name} desativou o acesso para o utilizador %{target}\"\n        enable_custom_emoji: \"%{name} habilitou o emoji %{target}\"\n        enable_user: \"%{name} ativou o acesso para o utilizador %{target}\"\n        memorialize_account: \"%{name} transformou a conta de %{target} em um memorial\"\n        promote_user: \"%{name} promoveu o utilizador %{target}\"\n        remove_avatar_user: \"%{name} removeu o avatar de %{target}\"\n        reopen_report: \"%{name} reabriu o relatório %{target}\"\n        reset_password_user: \"%{name} restabeleceu a palavra-passe do utilizador %{target}\"\n        resolve_report: \"%{name} recusou o relatório %{target}\"\n        silence_account: \"%{name} silenciou a conta de %{target}\"\n        suspend_account: \"%{name} suspendeu a conta de %{target}\"\n        unassigned_report: \"%{name} não atribuiu o relatório %{target}\"\n        unsilence_account: \"%{name} desativou o silêncio de %{target}\"\n        unsuspend_account: \"%{name} desativou a suspensão de  %{target}\"\n        update_custom_emoji: \"%{name} atualizou o emoji %{target}\"\n        update_status: \"%{name} atualizou o estado de %{target}\"\n      deleted_status: \"(apagou a publicação)\"\n      title: Registo de auditoria\n    custom_emojis:\n      by_domain: Domínio\n      copied_msg: Cópia local do emoji criada com sucesso\n      copy: Copiar\n      copy_failed_msg: Não foi possível criar uma cópia local deste emoji\n      created_msg: Emoji criado com sucesso!\n      delete: Apagar\n      destroyed_msg: Emoji destruído com sucesso!\n      disable: Desativar\n      disabled_msg: Desativado com sucesso este emoji\n      enable: Ativar\n      enabled_msg: Ativado com sucesso este emoji\n      image_hint: PNG de até 50KB\n      listed: Listado\n      new:\n        title: Adicionar novo emoji customizado\n      overwrite: Sobrescrever\n      shortcode: Código de atalho\n      shortcode_hint: Pelo menos 2 caracteres, apenas caracteres alfanuméricos e underscores\n      title: Emojis customizados\n      unlisted: Não listado\n      update_failed_msg: Não foi possível atualizar esse emoji\n      updated_msg: Emoji atualizado com sucesso!\n      upload: Enviar\n    dashboard:\n      backlog: trabalhos atrasados\n      config: Configuração\n      feature_deletions: Eliminações da conta\n      feature_invites: Links de convites\n      feature_profile_directory: Directório de perfil\n      feature_registrations: Registos\n      feature_relay: Repetidor da federação\n      features: Componentes\n      hidden_service: Federação com serviços escondidos\n      open_reports: relatórios abertos\n      recent_users: Utilizadores recentes\n      search: Pesquisa com texto completo\n      single_user_mode: Modo de utilizador único\n      space: Utilização do espaço\n      title: Painel de controlo\n      total_users: total de utilizadores\n      trends: Tendências\n      week_interactions: interacções desta semana\n      week_users_active: activo esta semana\n      week_users_new: utilizadores nesta semana\n    domain_blocks:\n      add_new: Adicionar novo\n      created_msg: Bloqueio do domínio está a ser processado\n      destroyed_msg: Bloqueio de domínio está a ser removido\n      domain: Domínio\n      new:\n        create: Criar bloqueio\n        hint: O bloqueio de dominio não vai previnir a criação de entradas na base de dados, mas irá retroativamente e automaticamente aplicar métodos de moderação específica nessas contas.\n        severity:\n          desc_html: \"<strong>Silenciar</strong> irá fazer com que os posts dessas contas sejam invisíveis para todos que não a seguem. <strong>Supender</strong> irá eliminar todo o conteúdo guardado dessa conta, media e informação de perfil.Usa <strong>Nenhum</strong> se  apenas desejas rejeitar arquivos de media.\"\n          noop: Nenhum\n          silence: Silenciar\n          suspend: Suspender\n        title: Novo bloqueio de domínio\n      reject_media: Rejeitar ficheiros de media\n      reject_media_hint: Remove localmente arquivos armazenados e rejeita fazer guardar novos no futuro. Irrelevante na suspensão\n      reject_reports: Rejeitar relatórios\n      reject_reports_hint: Ignorar todos os relatórios vindos deste domínio. Irrelevantes para efectuar suspensões\n      rejecting_media: a rejeitar ficheiros de media\n      rejecting_reports: a rejeitar relatórios\n      severity:\n        silence: silenciado\n        suspend: suspenso\n      show:\n        affected_accounts:\n          one: Uma conta na base de dados afectada\n          other: \"%{count} contas na base de dados afectadas\"\n        retroactive:\n          silence: Não silenciar todas as contas existentes nesse domínio\n          suspend: Não suspender todas as contas existentes nesse domínio\n        title: Remover o bloqueio de domínio de %{domain}\n        undo: Anular\n      undo: Anular\n    email_domain_blocks:\n      add_new: Adicionar novo\n      created_msg: Bloqueio de domínio de email criado com sucesso\n      delete: Eliminar\n      destroyed_msg: Bloqueio de domínio de email excluído com sucesso\n      domain: Domínio\n      new:\n        create: Adicionar domínio\n        title: Novo bloqueio de domínio de email\n      title: Bloqueio de Domínio de Email\n    followers:\n      back_to_account: Voltar à conta\n      title: Seguidores de %{acct}\n    instances:\n      by_domain: Domínio\n      delivery_available: Entrega disponível\n      known_accounts:\n        one: \"%{count} conta conhecida\"\n        other: \"%{count} contas conhecidas\"\n      moderation:\n        all: Todas\n        limited: Limitadas\n        title: Moderação\n      title: Instâncias conhecidas\n      total_blocked_by_us: Bloqueadas por nós\n      total_followed_by_them: Seguidas por eles\n      total_followed_by_us: Seguidas por nós\n      total_reported: Relatórios sobre eles\n      total_storage: Anexos de media\n    invites:\n      deactivate_all: Desactivar todos\n      filter:\n        all: Todos\n        available: Disponíveis\n        expired: Expirados\n        title: Filtro\n      title: Convites\n    relays:\n      add_new: Adicionar novo repetidor\n      delete: Apagar\n      description_html: Um <strong>repetidor da federação</strong> é um servidor intermediário que troca grandes volumes de publicações públicas entre servidores que o subscrevem e publicam. <strong>Ele pode ajudar pequenos e médios servidores a descobrir conteúdo do \"fediverse\"</strong>que, de outro modo, exigiria que os utilizadores locais seguissem manualmente outras pessoas em servidores remotos.\n      disable: Desactivar\n      disabled: Desactivado\n      enable: Activar\n      enable_hint: Uma vez activado, o teu servidor irá subscrever a todas as publicações deste repetidor e irá começar a enviar as suas publicações públicas para ele.\n      enabled: Ativado\n      inbox_url: URL do repetidor\n      pending: À espera da aprovação do repetidor\n      save_and_enable: Guardar e ativar\n      setup: Configurar uma ligação ao repetidor\n      status: Estado\n      title: Retransmissores\n    report_notes:\n      created_msg: Relatório criado com sucesso!\n      destroyed_msg: Relatório apagado com sucesso!\n    reports:\n      account:\n        note: nota\n        report: relatório\n      action_taken_by: Ação tomada por\n      are_you_sure: Tens a certeza?\n      assign_to_self: Atribuí-me a mim\n      assigned: Atribuído ao moderador\n      comment:\n        none: Nenhum\n      created_at: Relatado\n      mark_as_resolved: Marcar como resolvido\n      mark_as_unresolved: Marcar como não resolvido\n      notes:\n        create: Adicionar nota\n        create_and_resolve: Resolver com nota\n        create_and_unresolve: Reabrir com nota\n        delete: Apagar\n        placeholder: Descreve as ações que foram tomadas ou quaisquer outras atualizações relacionadas...\n      reopen: Reabrir relatório\n      report: 'Denúncia #%{id}'\n      reported_account: Conta denunciada\n      reported_by: Denúnciada por\n      resolved: Resolvido\n      resolved_msg: Relatório resolvido com sucesso!\n      status: Estado\n      title: Denúncias\n      unassign: Não atribuir\n      unresolved: Por resolver\n      updated_at: Atualizado\n    settings:\n      activity_api_enabled:\n        desc_html: Contagem semanais de publicações locais, utilizadores activos e novos registos\n        title: Publicar estatísticas agregadas sobre atividade dos utilizadores\n      bootstrap_timeline_accounts:\n        desc_html: Separa os nomes de utilizadores por vírgulas. Funciona apenas com contas locais e desbloqueadas. O padrão quando vazio são todos os administradores locais.\n        title: Seguidores predefinidos para novas contas\n      contact_information:\n        email: Inserir um endereço de email para tornar público\n        username: Insira um nome de utilizador\n      custom_css:\n        desc_html: Modificar a aparência com CSS carregado em cada página\n        title: CSS personalizado\n      hero:\n        desc_html: Apresentado na primeira página. Pelo menos 600x100px recomendados. Quando não é definido, é apresentado o thumbnail do servidor\n        title: Imagem Hero\n      mascot:\n        desc_html: Apresentada em múltiplas páginas. Pelo menos 293x205px recomendados. Quando não é definida, é apresentada a mascote predefinida\n        title: Imagem da mascote\n      peers_api_enabled:\n        desc_html: Nomes de domínio que esta instância encontrou no fediverso\n        title: Publicar lista de instâncias descobertas\n      preview_sensitive_media:\n        desc_html: Previsualização de links noutros websites irá apresentar uma miniatura, mesmo que a media seja marcada como sensível\n        title: Mostrar media sensível em previsualizações OpenGraph\n      profile_directory:\n        desc_html: Permite aos utilizadores serem descobertos\n        title: Ativar directório do perfil\n      registrations:\n        closed_message:\n          desc_html: Mostrar na página inicial quando registos estão encerrados<br/>Podes usar tags HTML\n          title: Mensagem de registos encerrados\n        deletion:\n          desc_html: Permite a qualquer um apagar a conta\n          title: Permitir eliminar contas\n        min_invite_role:\n          disabled: Ninguém\n          title: Permitir convites de\n      show_known_fediverse_at_about_page:\n        desc_html: Quando comutado, irá mostrar a previsualização de publicações de todo o fediverse conhecido. De outro modo só mostrará publicações locais.\n        title: Mostrar o fediverse conhecido na previsualização da cronologia\n      show_staff_badge:\n        desc_html: Mostrar um crachá da equipa na página de utilizador\n        title: Mostrar crachá da equipa\n      site_description:\n        desc_html: Mostrar como parágrafo na página inicial e usado como meta tag.Podes usar tags HTML, em particular <code>&lt;a&gt;</code> e <code>&lt;em&gt;</code>.\n        title: Descrição do site\n      site_description_extended:\n        desc_html: Mostrar na página de mais informações<br/>Podes usar tags HTML\n        title: Página de mais informações\n      site_short_description:\n        desc_html: Mostrada na barra lateral e em etiquetas de metadados. Descreve o que o Mastodon é e o que torna este servidor especial num único parágrafo. Se deixada em branco, remete para a descrição do servidor.\n        title: Breve descrição do servidor\n      site_terms:\n        desc_html: Podes escrever a tua própria política de privacidade, termos de serviço, entre outras coisas. Podes usar tags HTML\n        title: Termos de serviço customizados\n      site_title: Título do site\n      thumbnail:\n        desc_html: Usada para visualizações via OpenGraph e API. Recomenda-se 1200x630px\n        title: Miniatura da instância\n      timeline_preview:\n        desc_html: Exibir a linha temporal pública na página inicial\n        title: Visualização da linha temporal\n      title: Preferências do site\n    statuses:\n      back_to_account: Voltar para página da conta\n      batch:\n        delete: Eliminar\n        nsfw_off: NSFW OFF\n        nsfw_on: NSFW ON\n      failed_to_execute: Falhou ao executar\n      media:\n        title: Média\n      no_media: Não há média\n      no_status_selected: Nenhum estado foi alterado porque nenhum foi selecionado\n      title: Estado das contas\n      with_media: Com media\n    subscriptions:\n      callback_url: URL de Callback\n      confirmed: Confirmado\n      expires_in: Expira em\n      last_delivery: Última entrega\n      topic: Tópico\n    tags:\n      accounts: Contas\n      hidden: Escondidas\n      hide: Esconder no diretório\n      unhide: Mostrar no diretório\n      visible: Visível\n    title: Administração\n    warning_presets:\n      add_new: Adicionar novo\n      delete: Apagar\n      edit: Editar\n      edit_preset: Editar o aviso predefinido\n      title: Gerir os avisos predefinidos\n  admin_mailer:\n    new_report:\n      body: \"%{reporter} relatou %{target}\"\n      body_remote: Alguém de %{domain} relatou %{target}\n      subject: Novo relatório sobre %{instance} (#%{id})\n  application_mailer:\n    notification_preferences: Alterar preferências de e-mail\n    settings: 'Alterar preferências de email: %{link}'\n    view: 'Ver:'\n    view_profile: Ver perfil\n    view_status: Ver publicação\n  applications:\n    created: Aplicação criada com sucesso\n    destroyed: Aplicação eliminada com sucesso\n    invalid_url: O URL é inválido\n    regenerate_token: Regenerar token de acesso\n    token_regenerated: Token de acesso regenerado com sucesso\n    warning: Cuidado com estes dados. Não partilhar com ninguém!\n    your_token: O teu token de acesso\n  auth:\n    change_password: Palavra-passe\n    confirm_email: Confirmar e-mail\n    delete_account: Eliminar conta\n    delete_account_html: Se desejas eliminar a conta, podes <a href=\"%{path}\">continua aqui</a>. Uma confirmação será pedida.\n    didnt_get_confirmation: Não recebeu o email de confirmação?\n    forgot_password: Esqueceste a palavra-passe?\n    invalid_reset_password_token: Token de modificação da palavra-passe é inválido ou expirou. Por favor, solicita um novo.\n    login: Entrar\n    logout: Sair\n    migrate_account: Mudar para uma conta diferente\n    migrate_account_html: Se desejas redirecionar esta conta para uma outra podes<a href=\"%{path}\">configurar isso aqui</a>.\n    or_log_in_with: Ou iniciar sessão com\n    register: Registar\n    resend_confirmation: Reenviar instruções de confirmação\n    reset_password: Criar nova palavra-passe\n    security: Alterar palavra-passe\n    set_new_password: Editar palavra-passe\n  authorize_follow:\n    already_following: Tu já estás a seguir esta conta\n    error: Infelizmente, ocorreu um erro ao buscar a conta remota\n    follow: Seguir\n    follow_request: 'Enviaste uma solicitação de seguidor para:'\n    following: 'Sucesso! Agora estás a seguir a:'\n    post_follow:\n      close: Ou podes simplesmente fechar esta janela.\n      return: Voltar ao perfil do utilizador\n      web: Voltar à página inicial\n    title: Seguir %{acct}\n  datetime:\n    distance_in_words:\n      about_x_months: \"%{count} meses\"\n      about_x_years: \"%{count} anos\"\n      almost_x_years: \"%{count} anos\"\n      half_a_minute: Justo agora\n      less_than_x_minutes: \"%{count} meses\"\n      less_than_x_seconds: Justo agora\n      over_x_years: \"%{count} anos\"\n      x_days: \"%{count} dias\"\n      x_minutes: \"%{count} minutos\"\n      x_months: \"%{count} meses\"\n      x_seconds: \"%{count} segundos\"\n  deletes:\n    bad_password_msg: Boa tentativa, hackers! Palavra-passe incorreta\n    confirm_password: Introduz a palavra-passe atual para verificar a tua identidade\n    description_html: Isto vai <strong>permanente e irreversivelmente</strong> remover conteúdo da tua conta e desativá-la. O teu nome de utilizador permanecerá reservado para prevenir futuros roubos de identidade.\n    proceed: Eliminar conta\n    success_msg: A tua conta foi eliminada com sucesso\n    warning_html: |-\n      Apenas a eliminação de conteúdo desta instância é garantido.\n      Conteúdo que tenha sido partilhado com outras instâncias muito provavelmente deixará pegadas. Servidores offline e servidores que se desinscreveram das tuas atualizações não  atualizarão as suas bases de dados.\n    warning_title: Disponibilidade de conteúdo disseminado\n  directories:\n    directory: Dirétorio de perfil\n    enabled: Neste momento tu estás listado no dirétorio.\n    enabled_but_waiting: Tu escolheste ser listado no diretório, mas ainda não tens o número mínimo de seguidores (%{min_followers}) para integrares esta lista.\n    explanation: Descobre utilizadores com base nos seus interesses\n    explore_mastodon: Explorar %{title}\n    how_to_enable: Tu ainda não integras este directório. Podes fazer isso abaixo. Usa hashtags na tua biografia para seres listado em hashtags específicas!\n    people:\n      one: \"%{count} pessoa\"\n      other: \"%{count} pessoas\"\n  errors:\n    '403': Não tens a permissão necessária para ver esta página.\n    '404': A página que estás a procurar não existe.\n    '410': A página que estás a procurar não existe mais.\n    '422':\n      content: \"A verificação de segurança falhou. \\nDesativaste o uso de cookies?\"\n      title: A verificação de segurança falhou\n    '429': Desacelerado\n    '500':\n      content: Desculpe, mas algo correu mal.\n      title: Esta página não está correta\n    noscript_html: Para usar o aplicativo web do Mastodon, por favor ativa o JavaScript. Alternativamente, experimenta um dos <a href=\"%{apps_path}\">apps nativos</a> para o Mastodon na sua plataforma.\n  exports:\n    archive_takeout:\n      date: Data\n      download: Descarregar o teu arquivo\n      hint_html: Podes pedir um arquivo das tuas <strong> publicações e ficheiros de media carregados</strong>. Os dados do ficheiro exportado estarão no formato ActivityPub, que pode ser lido com qualquer software compatível. Tu podes pedir um arquivo destes a cada 7 dias.\n      in_progress: A compilar o seu arquivo...\n      request: Pede o teu arquivo\n      size: Tamanho\n    blocks: Bloqueaste\n    domain_blocks: Bloqueios de domínio\n    follows: Segues\n    lists: Listas\n    mutes: Tens em silêncio\n    storage: Armazenamento de média\n  featured_tags:\n    add_new: Adicionar nova\n    errors:\n      limit: Já atingiste o limite máximo de hashtags\n  filters:\n    contexts:\n      home: Cronologia inicial\n      notifications: Notificações\n      public: Cronologias públicas\n      thread: Conversações\n    edit:\n      title: Editar filtros\n    errors:\n      invalid_context: Inválido ou nenhum contexto fornecido\n      invalid_irreversible: Filtragem irreversível só funciona no contexto das notificações ou do início\n    index:\n      delete: Apagar\n      title: Filtros\n    new:\n      title: Adicionar novo filtro\n  footer:\n    developers: Responsáveis pelo desenvolvimento\n    more: Mais…\n    resources: Recursos\n  generic:\n    changes_saved_msg: Alterações guardadas!\n    copy: Copiar\n    save_changes: Guardar alterações\n    validation_errors:\n      one: Algo não está correcto. Por favor vê o erro abaixo\n      other: Algo não está correto. Por favor vê os %{count} erros abaixo\n  imports:\n    modes:\n      merge: Juntar\n      merge_long: Manter os registos existentes e adicionar novos registos\n      overwrite: Escrever por cima\n      overwrite_long: Substituir os registos atuais pelos novos\n    preface: Podes importar dados que tenhas exportado de outra instância, como a lista de pessoas que segues ou bloqueadas.\n    success: Os teus dados foram enviados com sucesso e serão processados em breve\n    types:\n      blocking: Lista de bloqueio\n      domain_blocking: Lista de domínios bloqueados\n      following: Lista de pessoas que estás a seguir\n      muting: Lista de utilizadores silenciados\n    upload: Enviar\n  in_memoriam_html: Em memória.\n  invites:\n    delete: Desativar\n    expired: Expirados\n    expires_in:\n      '1800': 30 minutos\n      '21600': 6 horas\n      '3600': 1 hora\n      '43200': 12 horas\n      '604800': 1 semana\n      '86400': 1 dia\n    expires_in_prompt: Nunca\n    generate: Gerar\n    invited_by: 'Tu foste convidado por:'\n    max_uses:\n      one: 1 uso\n      other: \"%{count} usos\"\n    max_uses_prompt: Sem limite\n    prompt: Gerar e partilhar ligações com outras pessoas para permitir acesso a essa instância\n    table:\n      expires_at: Expira\n      uses: Usos\n    title: Convidar pessoas\n  lists:\n    errors:\n      limit: Número máximo de listas alcançado\n  media_attachments:\n    validations:\n      images_and_video: Não é possível anexar um vídeo a uma publicação que já contém imagens\n      too_many: Não é possível anexar mais de 4 arquivos\n  migrations:\n    acct: username@domain da nova conta\n    currently_redirecting: 'O teu perfil está configurado para redirecionar para:'\n    proceed: Salvar\n    updated_msg: As configurações de migração da tua conta foram atualizadas com sucesso!\n  moderation:\n    title: Moderação\n  notification_mailer:\n    digest:\n      action: Ver todas as notificações\n      body: Aqui tens um breve resumo do que perdeste desde o último acesso a %{since}\n      mention: \"%{name} mencionou-te em:\"\n      new_followers_summary:\n        one: Tens um novo seguidor! Boa!\n        other: Tens %{count} novos seguidores! Fantástico!\n      subject:\n        one: \"1 nova notificação desde o último acesso \\U0001F418\"\n        other: \"%{count} novas notificações desde o  último acesso \\U0001F418\"\n      title: Enquanto estiveste ausente…\n    favourite:\n      body: 'O teu post foi adicionado aos favoritos por %{name}:'\n      subject: \"%{name} adicionou o teu post aos favoritos\"\n      title: Novo favorito\n    follow:\n      body: \"%{name} é teu seguidor!\"\n      subject: \"%{name} começou a seguir-te\"\n      title: Novo seguidor\n    follow_request:\n      action: Gerir pedidos de seguidores\n      body: \"%{name} solicitou autorização para te seguir\"\n      subject: 'Seguidor pendente: %{name}'\n      title: Nova solicitação de seguidor\n    mention:\n      action: Responder\n      body: 'Foste mencionado por %{name}:'\n      subject: \"%{name} mencionou-te\"\n      title: Nova menção\n    reblog:\n      body: 'O teu post foi partilhado por %{name}:'\n      subject: \"%{name} partilhou o teu post\"\n      title: Nova partilha\n  pagination:\n    newer: Mais nova\n    next: Seguinte\n    older: Mais velha\n    prev: Anterior\n  polls:\n    errors:\n      already_voted: Tu já votaste nesta sondagem\n      duplicate_options: contém itens duplicados\n      duration_too_long: está demasiado à frente no futuro\n      duration_too_short: é demasiado cedo\n      expired: A sondagem já terminou\n      over_character_limit: não pode ter mais do que %{max} caracteres cada um\n      too_few_options: tem de ter mais do que um item\n      too_many_options: não pode conter mais do que %{max} itens\n  preferences:\n    other: Outro\n  remote_follow:\n    acct: Entre seu usuário@domínio do qual quer seguir\n    missing_resource: Não foi possível achar a URL de redirecionamento para sua conta\n    no_account_html: Não tens uma conta? Tu podes <a href='%{sign_up_path}' target='_blank'> aderir aqui</a>\n    proceed: Prossiga para seguir\n    prompt: 'Você vai seguir:'\n    reason_html: \"<strong> Porque é que este passo é necessário?</strong> <code>%{instance}</code> pode não ser o servidor onde tu estás registado. Por isso, nós precisamos de te redirecionar para o teu servidor inicial em primeiro lugar.\"\n  remote_interaction:\n    favourite:\n      proceed: Prosseguir para os favoritos\n      prompt: 'Queres favoritar esta publicação:'\n    reblog:\n      proceed: Prosseguir com partilha\n      prompt: 'Queres partilhar esta publicação:'\n    reply:\n      proceed: Prosseguir com resposta\n      prompt: 'Queres responder a esta publicação:'\n  remote_unfollow:\n    error: Erro\n    title: Título\n    unfollowed: Não seguido\n  scheduled_statuses:\n    over_daily_limit: Excedeste o limite de %{limit} publicações agendadas para esse dia\n    over_total_limit: Tu excedeste o limite de %{limit} publicações agendadas\n    too_soon: A data de agendamento tem de ser futura\n  sessions:\n    activity: Última atividade\n    browser: Navegador\n    browsers:\n      generic: Navegador desconhecido\n      nokia: Navegador Nokia S40 Ovi\n      otter: Lontra\n    current_session: Sessão atual\n    description: \"%{browser} em %{platform}\"\n    explanation: Estes são os navegadores que estão conectados com a tua conta do Mastodon.\n    platforms:\n      firefox_os: SO Firefox\n      other: Plataforma desconhecida\n    revoke: Revogar\n    revoke_success: Sessão revogada com sucesso\n    title: Sessões\n  settings:\n    authorized_apps: Aplicativos autorizados\n    back: Voltar ao Mastodon\n    delete: Eliminação da conta\n    development: Desenvolvimento\n    edit_profile: Editar perfil\n    export: Exportar dados\n    featured_tags: Hashtags destacadas\n    import: Importar\n    migrate: Migração de conta\n    notifications: Notificações\n    preferences: Preferências\n    two_factor_authentication: Autenticação em dois passos\n  statuses:\n    attached:\n      description: 'Anexadas: %{attached}'\n      image:\n        one: \"%{count} imagem\"\n        other: \"%{count} imagens\"\n      video:\n        one: \"%{count} vídeo\"\n        other: \"%{count} vídeos\"\n    boosted_from_html: Partilhadas de %{acct_link}\n    content_warning: 'Aviso de conteúdo: %{warning}'\n    disallowed_hashtags:\n      one: 'continha uma hashtag proibida: %{tags}'\n      other: 'continha as hashtags proibidas: %{tags}'\n    language_detection: Detectar automaticamente a língua\n    open_in_web: Abrir no browser\n    over_character_limit: limite de caracter excedeu %{max}\n    pin_errors:\n      limit: Já fixaste a quantidade máxima de publicações\n      ownership: Posts de outras pessoas não podem ser fixados\n      private: Post não-público não pode ser fixado\n      reblog: Não podes fixar uma partilha\n    poll:\n      total_votes:\n        one: \"%{count} voto\"\n        other: \"%{count} votos\"\n      vote: Votar\n    show_more: Mostrar mais\n    sign_in_to_participate: Inicie a sessão para participar na conversa\n    visibilities:\n      private: Mostrar apenas para seguidores\n      private_long: Mostrar apenas para seguidores\n      public: Público\n      public_long: Todos podem ver\n      unlisted: Público, mas não mostre no timeline público\n      unlisted_long: Todos podem ver, porém não será postado nas timelines públicas\n  stream_entries:\n    pinned: Toot fixado\n    reblogged: partilhado\n    sensitive_content: Conteúdo sensível\n  terms:\n    body_html: |\n      <h2>Política de privacidade</h2>\n      <h3 id=\"collect\">Que informação nós recolhemos?</h3>\n\n      <ul>\n      <li><em>Informação básica da conta</em>: Se te registares neste servidor, pode-te ser pedido que indiques um nome de utilizador, um endereço de e-mail e uma palavra-passe. Também podes introduzir informação adicional de perfil, tal como um nome a mostrar e dados biográficos, que carregues uma fotografia para o teu perfil e para o cabeçalho. O nome de utilizador, o nome a mostrar, a biografia, a imagem de perfil e a imagem de cabeçalho são sempre listados publicamente.</li>\n      <li><em>Publicações, seguimento e outra informação pública</em>: A lista de pessoas que tu segues é pública, o mesmo é verdade para os teus seguidores. Quando tu publicas uma mensagem, a data e a hora são guardados, tal como a aplicação a partir da qual a mensagem foi enviada. As mensagens podem conter anexos multimédia, tais como fotografias ou vídeos. Publicações públicas e não listadas são acessíveis publicamente. Quando expões uma publicação no teu perfil, isso é também informação disponível publicamente. As tuas publicações são enviadas aos teus seguidores. Em alguns casos isso significa que elas são enviadas para servidores diferentes onde são guardadas cópias. Quando tu apagas publicações, isso também é enviado para os teus seguidores. A acção de republicar ou favoritar outra publicação é sempre pública.</li>\n      <li><em>Publicações directas e exclusivas para seguidores</em>: Todas as publicações são guardadas e processadas no servidor. Publicações exclusivas para seguidores são enviadas para os teus seguidores e para utilizadores que são nelas mencionados. As publicações directas são enviadas apenas para os utilizadores nelas mencionados. Em alguns casos isso significa que elas são enviadas para diferentes servidores onde são guardadas cópias das mesmas. Nós fazemos um grande esforço para limitar o acesso a estas publicações aos utilizadores autorizados, mas outros servidores podem falhar neste objectivo.  Por isso, tu deves rever os servidores a que os teus seguidores pertencem. Tu podes activar uma opção para aprovar e rejeitar manualmente novos seguidores nas configurações. <em>Por favor, tem em mente que os gestores do servidor e qualquer servidor que receba a publicação pode lê-la</em>e que os destinatários podem fazer uma captura de tela, copiar ou partilhar a publicação. <em>Não partilhes qualquer informação perigosa no Mastodon.</em></li>\n      <li><em>IPs e outros metadados</em>: Quando inicias sessão, nós guardamos o endereço de IP a partir do qual iniciaste a sessão, tal como o nome do teu navegador. Todas as sessões estão disponíveis para verificação e revogação nas configurações. O último endereço de IP usado é guardado até 12 meses. Nós também podemos guardar registos de servidor, os quais incluem o endereço de IP de cada pedido dirigido ao nosso servidor.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"use\">Para que usamos a tua informação?</h3>\n\n      <p>Qualquer informação que recolhemos sobre ti pode ser usada dos seguintes modos:</p>\n\n      <ul>\n      <li>Para providenciar a funcionalidade central do Mastodon. Tu só podes interagir com o conteúdo de outras pessoas e publicar o teu próprio conteúdo depois de teres iniciado sessão. Por exemplo, tu podes seguir outras pessoas para veres as suas publicações na tua cronologia inicial personalizada. </li>\n      <li>Para ajudar na moderação da comunidade para, por exemplo, comparar o teu endereço IP com outros conhecidos, para determinar a fuga ao banimento ou outras violações.</li>\n      <li>O endereço de e-mail que tu forneces pode ser usado para te enviar informações e/ou notificações sobre outras pessoas que estão a interagir com o teu conteúdo ou a enviar-te mensagens, para responderes a inquéritos e/ou outros pedidos ou questões.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"protect\">Como é que nós protegemos a tua informação?</h3>\n\n      <p>Nós implementamos uma variedade de medidas de segurança para garantir a segurança da tua informação pessoal quando tu introduzes, submetes ou acedes à mesma. Entre outras coisas, a tua sessão de navegação, tal como o tráfego entre as tuas aplicações e a API, estão seguras por SSL e a tua palavra-passe é codificada usando um forte algoritmo de sentido único. Tu podes activar a autenticação em dois passos para aumentares ainda mais a segurança do acesso à tua conta.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"data-retention\">Qual é a nossa política de retenção de dados?</h3>\n\n      <p>Nós envidaremos todos os esforços no sentido de:</p>\n\n      <ul>\n      <li>Guardar registos do servidor contendo o endereço de IP de todos os pedidos feitos a este  servidor, considerando que estes registos não serão guardados por mais de 90 dias.</li>\n      <li>Guardar os endereços de IP associados aos utilizadores registados durante um período que não ultrapassará os 12 meses.</li>\n      </ul>\n\n      <p>Tu podes pedir e descarregar um ficheiro com o teu conteúdo, incluindo as tuas publicações, os ficheiros multimédia, a imagem de perfil e a imagem de cabeçalho.</p>\n\n      <p>Tu podes apagar a tua conta de modo definitivo e a qualquer momento.</p>\n\n      <hr class=\"spacer\"/>\n\n      <h3 id=\"cookies\">Usamos cookies?</h3>\n\n      <p>Sim. Cookies são pequenos ficheiros que um site ou o seu fornecedor de serviço transfere para o disco rígido do teu computador através do teu navegador (se tu permitires). Estes cookies permitem ao site reconhecer o teu navegador e, se tu tiveres uma conta registada, associá-lo a ela.</p>\n\n      <p>Nós usamos os cookies para compreender e guardar as tuas preferências para as visitas futuras.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"disclose\">Nós divulgamos alguma informação para entidades externas?</h3>\n\n      <p>Nós não vendemos, trocamos ou transferimos de qualquer modo a tua informação pessoal que seja identificável para qualquer entidade externa. Isto não inclui terceiros de confiança que nos ajudam a manter o nosso site, conduzir o nosso negócio ou prestar-te este serviço, desde que esses terceiros concordem em manter essa informação confidencial. Poderemos também revelar a tua informação quando nós acreditamos que isso é apropriado para cumprir a lei, forçar a aplicação dos nossos termos de serviço ou proteger os direitos, propriedade e segurança, nossos e de outrem.</p>\n\n      <p>O teu conteúdo público pode ser descarregado por outros servidores na rede. As tuas publicações públicas e exclusivas para os teus seguidores são enviadas para os servidores onde os teus seguidores residem e as mensagens directas são entregues aos servidores dos seus destinatários, no caso desses seguidores ou destinatários residirem num servidor diferente deste.</p>\n\n      <p>Quando tu autorizas uma aplicação a usar a tua conta, dependendo da abrangência das permissões que tu aprovas, ela pode ter acesso à informação pública do teu perfil, à lista de quem segues, aos teus seguidores, às tuas listas, a todas as tuas publicações e aos teus favoritos. As aplicações nunca terão acesso ao teu endereço de e-mail ou à tua palavra-passe.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"children\">Utilização do site por crianças</h3>\n\n      <p>Se este servidor estiver na EU ou na EEA: O nosso site, produtos e serviços são todos dirigidos a pessoas que têm, pelo menos, 16 de idade. Se tu tens menos de 16 anos, devido aos requisitos da GDPR (<a href=\"https://en.wikipedia.org/wiki/General_Data_Protection_Regulation\">General Data Protection Regulation</a>) não uses este site.</p>\n\n      <p>Se este servidor estiver nos EUA: O nosso site, produtos e serviços são todos dirigidos a pessoas que têm, pelo menos, 13 anos de idade. Se tu tens menos de 13 anos de idade, devido aos requisitos da COPPA (<a href=\"https://en.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act\">Children's Online Privacy Protection Act</a>) não uses este site.</p>\n\n      <p>Os requisitos legais poderão ser diferentes se este servidor estiver noutra jurisdição.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"changes\">Alterações à nossa Política de Privacidade</h3>\n\n      <p>Se nós decidirmos alterar a nossa política de privacidade, nós iremos publicar essas alterações nesta página.</p>\n\n      <p>Este documento é CC-BY-SA. Ele foi actualizado pela última vez em 7 de Março 2018.</p>\n\n      <p>Originalmente adaptado de <a href=\"https://github.com/discourse/discourse\">Discourse privacy policy</a>.</p>\n    title: \"%{instance} Termos de Serviço e Política de Privacidade\"\n  themes:\n    contrast: Mastodon (Elevado contraste)\n    default: Mastodon\n    mastodon-light: Mastodon (Leve)\n  two_factor_authentication:\n    code_hint: Entre o código gerado pelo seu aplicativo para confirmar\n    description_html: Se ativar a <strong>autenticação em dois passos</strong>, quando logar será necessário o seu telefone que vai gerar os tokens para validação.\n    disable: Desativar\n    enable: Ativar\n    enabled: A autenticação em dois passos está ativada\n    enabled_success: Autenticação em dois passos ativada com sucesso\n    generate_recovery_codes: Gerar códigos para recuperar conta\n    instructions_html: \"<strong>Scaneie este código QR no seu Google Authenticator ou aplicativo similar no seu telefone</strong>. A partir de agora seu aplicativo irá gerar tokens que deverão ser digitados para você logar.\"\n    lost_recovery_codes: Códigos de recuperação permite que você recupere o acesso a sua conta se você perder seu telefone. Se você perder os códigos de recuperação, você pode regera-los aqui. Seus códigos antigos serão invalidados.\n    manual_instructions: 'Se você não puder scanear o código QR e precisa digita-los manualmente, aqui está o segredo em texto.:'\n    recovery_codes: Cópia de segurança dos códigos de recuperação\n    recovery_codes_regenerated: Códigos de recuperação foram gerados com sucesso\n    recovery_instructions_html: Se tu alguma vez perderes o teu smartphone, to poderás usar um dos códigos de recuperação para voltares a ter acesso à tua conta. <strong>Mantém os códigos de recuperação seguros</strong>. Por exemplo, tu podes imprimi-los e guardá-los junto a outros documentos importantes.\n    setup: Configurar\n    wrong_code: O código inserido é invalido! O horário do servidor e o horário do seu aparelho estão corretos?\n  user_mailer:\n    backup_ready:\n      explanation: Pediste uma cópia completa da tua conta Mastodon. Ela já está pronta para descarregares!\n      subject: O teu arquivo está pronto para descarregar\n      title: Arquivo de ficheiros\n    warning:\n      explanation:\n        disable: Enquanto a tua conta está congelada, os seus dados permanecem intactos, mas tu não podes executar quaisquer acções até que ela seja desbloqueada.\n        silence: Enquanto a tua conta estiver limitada, só pessoas que já estiveres a seguir irão ver as tuas publicações neste servidor e poderás ser excluído de várias listagens públicas. No entanto, outros ainda te poderão seguir de forma manual.\n        suspend: A tua conta foi suspensa e todas as tuas publicações e os teus ficheiros de media foram irreversivelmente removidos deste servidor e dos servidores onde tinhas seguidores.\n      review_server_policies: Revê as políticas do servidor\n      subject:\n        disable: A tua conta %{acct} foi congelada\n        none: Aviso para %{acct}\n        silence: A tua conta %{acct} foi limitada\n        suspend: A tua conta %{acct} foi suspensa\n      title:\n        disable: Conta congelada\n        none: Aviso\n        silence: Conta limitada\n        suspend: Conta suspensa\n    welcome:\n      edit_profile_action: Configura o perfil\n      edit_profile_step: Tu podes personalizar o teu perfil por carregar um avatar, cabeçalho, alterar o teu nickname e mais. Se tu preferires rever os novos seguidores antes deles te poderem seguir, podes bloquear a tua conta.\n      explanation: Aqui estão algumas dicas para começares\n      final_action: Começa a publicar\n      final_step: 'Começa a publicar! Mesmo sem seguidores, as tuas mensagens públicas podem ser vistas por outros, por exemplo, na cronologia local e em hashtags. Tu podes querer apresentar-te na hashtag #introductions.'\n      full_handle: O teu nome completo\n      full_handle_hint: Isto é o que tu dirias aos teus amigos para que eles te possam enviar mensagens ou seguir-te a partir de outro servidor.\n      review_preferences_action: Alterar preferências\n      review_preferences_step: Certifica-te de configurar as tuas preferências, tais como os e-mails que gostarias de receber ou o nível de privacidade que desejas que as tuas publicações tenham por defeito. Se não sofres de enjoo, podes activar a opção GIF autoplay.\n      subject: Bem-vindo ao Mastodon\n      tip_federated_timeline: A cronologia federativa é uma visão global da rede Mastodon. Mas só inclui pessoas que os teus vizinhos subscrevem, por isso não é uma visão completa.\n      tip_following: Tu segues o(s) administrador(es) do teu servidor por defeito. Para encontrares mais pessoas interessantes, procura nas cronologias local e federativa.\n      tip_local_timeline: A cronologia local é uma visão global das pessoas em %{instance}. Estes são os teus vizinhos próximos!\n      tip_mobile_webapp: Se o teu navegador móvel te oferecer a possibilidade de adicionar o Mastodon ao teu homescreen, tu podes receber notificações push. Ele age como uma aplicação nativa de vários modos!\n      tips: Dicas\n      title: Bem-vindo a bordo, %{name}!\n  users:\n    follow_limit_reached: Não podes seguir mais do que %{limit} pessoas\n    invalid_email: O endereço de e-mail é inválido\n    invalid_otp_token: Código de autenticação inválido\n    otp_lost_help_html: Se tu perdeste acesso a ambos, tu podes entrar em contacto com %{email}\n    seamless_external_login: Tu estás ligado via um serviço externo. Por isso, as configurações da palavra-passe e do e-mail não estão disponíveis.\n    signed_in_as: 'Registado como:'\n  verification:\n    explanation_html: 'Tu podes <strong>comprovar que és o dono dos links nos metadados do teu perfil</strong>. Para isso, o website para o qual o link aponta tem de conter um link para o teu perfil do Mastodon. Este link <strong>tem</strong> de ter um <code>rel=\"me\"</code> atributo. O conteúdo do texto não é relevante. Aqui está um exemplo:'\n    verification: Verificação\n"
  },
  {
    "path": "config/locales/ro.yml",
    "content": "---\nro:\n  about:\n    hosted_on: Mastodon găzduit de %{domain}\n  auth:\n    change_password: Parolă\n    confirm_email: Confirmă email\n    delete_account: Șterge contul\n    delete_account_html: Dacă vrei să ștergi acest cont <a href=\"%{path}\">poți începe aici</a>. Va trebui să confirmi această acțiune.\n    didnt_get_confirmation: Nu ai primit instrucțiunile de confirmare?\n    forgot_password: Ai uitat parola?\n    invalid_reset_password_token: Această cerere este invalidă sau a expirat. Încearcă resetarea parolei din nou.\n    login: Conectare\n    logout: Deconectare\n    migrate_account: Transfer către un alt cont\n    migrate_account_html: Dacă dorești să redirecționezi acest cont către un altul, poți <a href=\"%{path}\">configura asta aici</a>.\n    or_log_in_with: Sau conectează-te cu\n    register: Înregistrare\n    resend_confirmation: Retrimite instrucțiunile de confirmare\n    reset_password: Resetare parolă\n    security: Securitate\n    set_new_password: Setează o nouă parolă\n  authorize_follow:\n    already_following: Urmărești deja acest cont\n    error: Din păcate a apărut o eroare\n    follow: Urmărește\n    follow_request: 'Ai trimis o cerere de urmărire către:'\n    following: 'Gata! De acum urmărești:'\n    post_follow:\n      close: Sau, poți închide această fereastră.\n      return: Arată profilul utilizatorului\n      web: Mergi la web\n    title: Urmărește %{acct}\n  datetime:\n    distance_in_words:\n      about_x_hours: \"%{count}o\"\n      about_x_months: \"%{count}l\"\n      about_x_years: \"%{count}ani\"\n      almost_x_years: \"%{count}ani\"\n      half_a_minute: Chiar acum\n      less_than_x_minutes: \"%{count}l\"\n      less_than_x_seconds: Chiar acum\n      over_x_years: \"%{count}ani\"\n      x_days: \"%{count}z\"\n      x_months: \"%{count}l\"\n  deletes:\n    bad_password_msg: Bună încercare, hackere! Parolă incorectă\n    confirm_password: Introdu parola curentă pentru a-ți verifica identitatea\n    description_html: Această acțiune este <strong>permanentă și ireversibilă,</strong> elimină conținutul și dezactivează contul tău. Acest username va rămâne permanent rezervat pentru a evita furtul de identitate.\n    proceed: Șterge contul\n    success_msg: Contul tău a fost șterg. Nu mai poate fi recuperat :D\n    warning_html: Doar ștergerea conținutului de pe acest server este garantată. Conținutul tău care a fost redistribuit în alte instațe e posibil să lase urme. Serverele deconecate sau care nu mai sunt abonate la actualizările contului tău nu își vor mai actualiza baza de date.\n  directories:\n    explanation: Descoperă oameni și companii în funcție de interesele lor\n    explore_mastodon: Explorează %{title}\n    people:\n      few: \"%{count} persoană\"\n      one: \"%{count} persoană\"\n      other: \"%{count} oameni\"\n  errors:\n    '403': Nu ai permisiunea să vizitezi această pagină.\n    '404': Pagina pe care o cauți nu există.\n    '410': Pagina pe care o cauți nu mai există.\n    '422':\n      content: Verificarea securității a eșuat. Ai blocat cookiurile?\n      title: Verificarea securității a eșuat\n    '429': Strangulat\n    '500':\n      content: Ne pare rău, dar ceva a funcționat greșit. Încercați din nou!?\n      title: Această pagină nu este corectă\n    noscript_html: Pentru a utiliza o aplicație web Mastodon, te rog activează JavaScript. Alternativ, încearcă una din <a href=\"%{apps_path}\">aplicațiile native</a> Mastodon pentru platforma ta.\n  exports:\n    archive_takeout:\n      date: Data\n      download: Descarcă arhiva contului tău\n      hint_html: Poți solicita arhiva<strong>postărilor și conținutul media</strong> a contului tău. Datele furnizate sunt în formatul ActivityPub. Poți solicita cate o arhivă la 7 zile.\n      in_progress: Pregătim arhiva ta...\n      request: Cere arhiva ta\n      size: Dimensiune\n    blocks: Blocați\n    follows: Tu urmărești\n    mutes: Opriți\n    storage: Depozitare media\n  filters:\n    contexts:\n      home: Fluxul Acasă\n      notifications: Notificări\n      public: Fluxul public\n      thread: Conversații\n    edit:\n      title: Editează filtru\n    errors:\n      invalid_context: Lipsa conținut sau acesta este invalid\n      invalid_irreversible: Filtrarea ireversibilă funcționează dor cu context din fluxul Acasă și notificări\n    index:\n      delete: Șterge\n      title: Filtre\n    new:\n      title: Adaugă un filtru nou\n  invites:\n    expires_in:\n      '1800': 30 minutes\n      '21600': 6 hours\n      '3600': 1 hour\n      '43200': 12 hours\n      '604800': 1 week\n      '86400': 1 day\n"
  },
  {
    "path": "config/locales/ru.yml",
    "content": "---\nru:\n  about:\n    about_hashtag_html: Это публичные статусы, отмеченные хэштегом <strong>#%{hashtag}</strong>. Вы можете взаимодействовать с ними при наличии у Вас аккаунта в глобальной сети Mastodon.\n    about_mastodon_html: Mastodon - это <em>свободная</em> социальная сеть с <em>открытым исходным кодом</em>. Как <em>децентрализованная</em> альтернатива коммерческим платформам, Mastodon предотвращает риск монополизации Вашего общения одной компанией. Выберите сервер, которому Вы доверяете &mdash; что бы Вы ни выбрали, Вы сможете общаться со всеми остальными. Любой может запустить свой собственный узел Mastodon и участвовать в <em>социальной сети</em> совершенно бесшовно.\n    about_this: Об этом узле\n    active_count_after: активных\n    active_footnote: Ежемесячно активные пользователи (MAU)\n    administered_by: 'Администратор узла:'\n    api: API\n    apps: Приложения\n    apps_platforms: Используйте Mastodon на iOS, Android и других платформах\n    browse_directory: Изучайте каталог профилей и ищите по интересам\n    browse_public_posts: Просматривайте в реальном времени новые статусы в Mastodon\n    contact: Связаться\n    contact_missing: не указан\n    contact_unavailable: неизв.\n    discover_users: Находите пользователей\n    documentation: Документация\n    extended_description_html: |\n      <h3>Хорошее место для правил</h3>\n      <p>Расширенное описание еще не настроено.</p>\n    federation_hint_html: С учётной записью на %{instance} вы сможете подписываться на людей с любого сервера Mastodon и не только.\n    generic_description: \"%{domain} - один из серверов сети\"\n    get_apps: Попробуйте мобильное приложение\n    hosted_on: Mastodon размещен на %{domain}\n    learn_more: Узнать больше\n    privacy_policy: Политика конфиденциальности\n    see_whats_happening: Узнавайте, что происходит вокруг\n    server_stats: 'Статистика сервера:'\n    source_code: Исходный код\n    status_count_after:\n      few: статуса\n      many: статусов\n      one: статус\n      other: статусов\n    status_count_before: Опубликовано\n    tagline: Подписывайтесь на друзей и заводите новые знакомства\n    terms: Условия использования\n    user_count_after:\n      few: пользователя\n      many: пользователей\n      one: пользователь\n      other: пользователей\n    user_count_before: Здесь живет\n    what_is_mastodon: Что такое Mastodon?\n  accounts:\n    choices_html: \"%{name} рекомендует:\"\n    follow: Подписаться\n    followers:\n      few: подписчика\n      many: подписчиков\n      one: подписчик\n      other: подписчиков\n    following: подписки\n    joined: 'Дата регистрации: %{date}'\n    last_active: последняя активность\n    link_verified_on: Владение этой ссылкой было проверено %{date}\n    media: Медиа\n    moved_html: \"%{name} переехал(а) на %{new_profile_link}:\"\n    network_hidden: Эта информация недоступна\n    nothing_here: Здесь ничего нет!\n    people_followed_by: Люди, на которых подписан(а) %{name}\n    people_who_follow: Подписчики %{name}\n    pin_errors:\n      following: Чтобы порекомендовать кого-то, надо сначала на них подписаться\n    posts:\n      few: статуса\n      many: статусов\n      one: статус\n      other: статусов\n    posts_tab_heading: Статусы\n    posts_with_replies: Посты с ответами\n    reserved_username: Имя пользователя зарезервировано\n    roles:\n      admin: Администратор\n      bot: Бот\n      moderator: Модератор\n    unavailable: Профиль недоступен\n    unfollow: Отписаться\n  admin:\n    account_actions:\n      action: Выполнить действие\n      title: Произвести модерацию аккаунта %{acct}\n    account_moderation_notes:\n      create: Создать\n      created_msg: Заметка модератора успешно создана!\n      delete: Удалить\n      destroyed_msg: Заметка модератора успешно удалена!\n    accounts:\n      approve: Подтвердить\n      approve_all: Подтвердить все\n      are_you_sure: Вы уверены?\n      avatar: Аватар\n      by_domain: Домен\n      change_email:\n        changed_msg: E-mail аккаунта успешно изменён!\n        current_email: Текущий e-mail\n        label: Сменить e-mail\n        new_email: Новый e-mail\n        submit: Сменить e-mail\n        title: Сменить e-mail для %{username}\n      confirm: Подтвердить\n      confirmed: Подтверждено\n      confirming: Подтверждение\n      deleted: Удалён\n      demote: Разжаловать\n      disable: Отключить\n      disable_two_factor_authentication: Отключить 2FA\n      disabled: Отключено\n      display_name: Отображаемое имя\n      domain: Домен\n      edit: Изменить\n      email: E-mail\n      email_status: Статус e-mail\n      enable: Включить\n      enabled: Включен\n      feed_url: URL фида\n      followers: Подписчики\n      followers_url: URL подписчиков\n      follows: Подписки\n      header: Заголовок\n      inbox_url: URL входящих\n      invited_by: Приглашение выдал(а)\n      ip: IP\n      joined: Дата регистрации\n      location:\n        all: Все\n        local: Локальные\n        remote: Удаленные\n        title: Размещение\n      login_status: Статус аккаунта\n      media_attachments: Мультимедийные вложения\n      memorialize: Превратить в Памятник\n      moderation:\n        active: Действующие\n        all: Все\n        pending: В ожидании\n        silenced: Заглушенные\n        suspended: Заблокированные\n        title: Модерация\n      moderation_notes: Заметки модератора\n      most_recent_activity: Последняя активность\n      most_recent_ip: Последний IP\n      no_account_selected: Ничего не выбрано, никакие аккаунты не изменены\n      no_limits_imposed: Без ограничений\n      not_subscribed: Не подписаны\n      outbox_url: URL исходящих\n      pending: Ожидает рассмотрения\n      perform_full_suspension: Полная блокировка\n      profile_url: URL профиля\n      promote: Повысить\n      protocol: Протокол\n      public: Публичный\n      push_subscription_expires: Подписка PuSH истекает\n      redownload: Обновить аватар\n      reject: Отклонить\n      reject_all: Отклонить все\n      remove_avatar: Удалить аватар\n      remove_header: Удалить шапку\n      resend_confirmation:\n        already_confirmed: Этот пользователь уже подтвержден\n        send: Повторно отправить подтверждение по электронной почте\n        success: Письмо с подтверждением успешно отправлено!\n      reset: Сбросить\n      reset_password: Сбросить пароль\n      resubscribe: Переподписаться\n      role: Разрешения\n      roles:\n        admin: Администратор\n        moderator: Модератор\n        staff: Персонал\n        user: Пользователь\n      search: Поиск\n      shared_inbox_url: URL общих входящих\n      show:\n        created_reports: Жалобы, отправленные этим аккаунтом\n        targeted_reports: Жалобы на этот аккаунт\n      silence: Заглушить\n      silenced: Заглушен\n      statuses: Статусы\n      subscribe: Подписаться\n      suspended: Заморожен\n      title: Аккаунты\n      unconfirmed_email: Неподтверждённый e-mail\n      undo_silenced: Снять глушение\n      undo_suspension: Снять блокировку\n      unsubscribe: Отписаться\n      username: Имя пользователя\n      warn: Предупредить\n      web: Веб\n    action_logs:\n      actions:\n        assigned_to_self_report: \"%{name} назначил(а) жалобу %{target} на себя\"\n        change_email_user: \"%{name} сменил(а) e-mail пользователя %{target}\"\n        confirm_user: \"%{name} подтвердил(а) e-mail адрес пользователя %{target}\"\n        create_account_warning: \"%{name} отправил(а) предупреждение для %{target}\"\n        create_custom_emoji: \"%{name} загрузил(а) новый эмодзи %{target}\"\n        create_domain_block: \"%{name} заблокировал(а) домен %{target}\"\n        create_email_domain_block: \"%{name} добавил(а) e-mail домен %{target} в чёрный список\"\n        demote_user: \"%{name} разжаловал(а) пользователя %{target}\"\n        destroy_custom_emoji: \"%{name} удалил(а) эмодзи %{target}\"\n        destroy_domain_block: \"%{name} разблокировал(а) домен %{target}\"\n        destroy_email_domain_block: \"%{name} добавил(а) e-mail домен %{target} в белый список\"\n        destroy_status: \"%{name} удалил(а) статус пользователя %{target}\"\n        disable_2fa_user: \"%{name} отключил(а) двухэтапную авторизацию у пользователя %{target}\"\n        disable_custom_emoji: \"%{name} отключил(а) эмодзи %{target}\"\n        disable_user: \"%{name} запретил(а) вход пользователя %{target}\"\n        enable_custom_emoji: \"%{name} включил(а) эмодзи %{target}\"\n        enable_user: \"%{name} включил(а) вход пользователя %{target}\"\n        memorialize_account: \"%{name} перевел(а) аккаунт пользователя %{target} в режим памятника\"\n        promote_user: \"%{name} повысил(а) пользователя %{target}\"\n        remove_avatar_user: \"%{name} удалил(а) аватар пользователя %{target}\"\n        reopen_report: \"%{name} переоткрыл(а) жалобу %{target}\"\n        reset_password_user: \"%{name} сбросил(а) пароль пользователя %{target}\"\n        resolve_report: \"%{name} решил(а) жалобу %{target}\"\n        silence_account: \"%{name} заглушил(а) аккаунт %{target}\"\n        suspend_account: \"%{name} заморозил(а) аккаунт %{target}\"\n        unassigned_report: \"%{name} сняла назначение жалобы %{target}\"\n        unsilence_account: \"%{name} снял(а) глушение аккаунта %{target}\"\n        unsuspend_account: \"%{name} разморозил(а) аккаунт %{target}\"\n        update_custom_emoji: \"%{name} обновил(а) эмодзи %{target}\"\n        update_status: \"%{name} изменил(а) статус пользователя %{target}\"\n      deleted_status: \"(удалённый статус)\"\n      title: Журнал событий\n    custom_emojis:\n      by_domain: Домен\n      copied_msg: Локальная копия эмодзи успешно создана\n      copy: Копировать\n      copy_failed_msg: Не удалось создать локальную копию эмодзи\n      created_msg: Эмодзи успешно создано!\n      delete: Удалить\n      destroyed_msg: Эмодзи успешно удалено!\n      disable: Отключить\n      disabled_msg: Эмодзи успешно отключено\n      emoji: Эмодзи\n      enable: Включить\n      enabled_msg: Эмодзи успешно включено\n      image_hint: PNG до 50KB\n      listed: В списке\n      new:\n        title: Добавить новый эмодзи\n      overwrite: Заменить\n      shortcode: Шорткод\n      shortcode_hint: Как минимум 2 символа, только алфавитно-цифровые символы и подчеркивания\n      title: Собственные эмодзи\n      unlisted: Не в списке\n      update_failed_msg: Невозможно обновить этот эмодзи\n      updated_msg: Эмодзи обновлён!\n      upload: Загрузить\n    dashboard:\n      backlog: задачи\n      config: Конфигурация\n      feature_deletions: Удаление аккаунтов\n      feature_invites: Пригласительные ссылки\n      feature_profile_directory: Каталог профилей\n      feature_registrations: Регистрация\n      feature_relay: Ретрансляторы\n      feature_timeline_preview: Предпросмотр ленты\n      features: Возможности\n      hidden_service: Федерация со скрытыми сервисами\n      open_reports: открытых жалоб\n      recent_users: Недавние пользователи\n      search: Полнотекстовый поиск\n      single_user_mode: Однопользовательский режим\n      software: Программное обеспечение\n      space: Использовано места\n      title: Панель управления\n      total_users: всего пользователей\n      trends: Тренды\n      week_interactions: взаимодействий на этой неделе\n      week_users_active: активно на этой неделе\n      week_users_new: пользователей на этой неделе\n    domain_blocks:\n      add_new: Заблокировать домен\n      created_msg: Блокировка домена обрабатывается\n      destroyed_msg: Блокировка домена снята\n      domain: Домен\n      new:\n        create: Создать блокировку\n        hint: Блокировка домена не предотвратит создание новых аккаунтов в базе данных, но ретроактивно и автоматически применит указанные методы модерации для этих аккаунтов.\n        severity:\n          desc_html: \"<strong>Глушение</strong> сделает статусы аккаунта невидимыми для всех, кроме их подписчиков. <strong>Блокировка</strong> удалит весь контент аккаунта, включая мультимедийные вложения и данные профиля. Используйте <strong>Ничего</strong>, если хотите только запретить медиаконтент.\"\n          noop: Ничего\n          silence: Глушение\n          suspend: Блокировка\n        title: Новая доменная блокировка\n      reject_media: Запретить медиаконтент\n      reject_media_hint: Удаляет локально хранимый медиаконтент и запрещает его загрузку в будущем. Не имеет значения в случае блокировки.\n      reject_reports: Отклонять жалобы\n      reject_reports_hint: Игнорировать все жалобы с этого домена. Не имеет значения в случае блокировки.\n      rejecting_media: отклонение медиафайлов\n      rejecting_reports: отклонение жалоб\n      severity:\n        silence: заглушен\n        suspend: заморожен\n      show:\n        affected_accounts:\n          few: Влияет на %{count} аккаунта в базе данных\n          many: Влияет на %{count} аккаунтов в базе данных\n          one: Влияет на один аккаунт в базе данных\n          other: Влияет на %{count} аккаунтов в базе данных\n        retroactive:\n          silence: Снять глушение со всех существующих аккаунтов этого домена\n          suspend: Снять блокировку со всех существующих аккаунтов этого домена\n        title: Снять блокировку с домена %{domain}\n        undo: Отменить\n      undo: Отменить блокировку домена\n    email_domain_blocks:\n      add_new: Добавить новую\n      created_msg: Доменная блокировка еmail успешно создана\n      delete: Удалить\n      destroyed_msg: Доменная блокировка еmail успешно удалена\n      domain: Домен\n      new:\n        create: Создать блокировку\n        title: Новая доменная блокировка еmail\n      title: Доменная блокировка email\n    followers:\n      back_to_account: Вернуться к аккаунту\n      title: Подписчики пользователя %{acct}\n    instances:\n      by_domain: Домен\n      delivery_available: Доставка возможна\n      known_accounts:\n        few: \"%{count} известных аккаунта\"\n        many: \"%{count} известных аккаунтов\"\n        one: \"%{count} известный аккаунт\"\n        other: \"%{count} известных аккаунтов\"\n      moderation:\n        all: Все\n        limited: Ограниченные\n        title: Модерация\n      title: Известные узлы\n      total_blocked_by_us: Заблокировано нами\n      total_followed_by_them: Заблокировано ими\n      total_followed_by_us: Наших подписчиков\n      total_reported: Жалобы на них\n      total_storage: Медиафайлы\n    invites:\n      deactivate_all: Отключить все\n      filter:\n        all: Все\n        available: Актуальные\n        expired: Истёкшие\n        title: Фильтр\n      title: Приглашения\n    pending_accounts:\n      title: Ожидающие аккаунты (%{count})\n    relays:\n      add_new: Добавить ретранслятор\n      delete: Удалить\n      description_html: \"<strong>Федеративный ретранслятор</strong> – это промежуточный сервер, который передаёт большие объёмы публичных статусов между серверами, которые подписываются и публикуют туда. <strong>Это может помочь небольшим и средним серверам находить записи со всей федерации</strong>, ведь в противном случае пользователям нужно будет вручную подписываться на людей с удалённых узлов.\"\n      disable: Отключить\n      disabled: Отключено\n      enable: Включить\n      enable_hint: Если включено, ваш сервер будет подписан на все публичные статусы с этого ретранслятора и начнёт туда отправлять публичные статусы со своего узла.\n      enabled: Включено\n      inbox_url: URL ретранслятора\n      pending: Ожидание подтверждения ретранслятора\n      save_and_enable: Сохранить и включить\n      setup: Настроить соединение с ретранслятором\n      status: Состояние\n      title: Ретрансляторы\n    report_notes:\n      created_msg: Примечание жалобы создано!\n      destroyed_msg: Примечание жалобы удалено!\n    reports:\n      account:\n        note: заметок\n        report: жалоб\n      action_taken_by: 'Действие предпринято:'\n      are_you_sure: Вы уверены?\n      assign_to_self: Назначить себе\n      assigned: Назначенный модератор\n      comment:\n        none: Нет\n      created_at: Создано\n      mark_as_resolved: Отметить как разрешенную\n      mark_as_unresolved: Отметить как неразрешённую\n      notes:\n        create: Добавить заметку\n        create_and_resolve: Разрешить с примечанием\n        create_and_unresolve: Переоткрыть с примечанием\n        delete: Удалить\n        placeholder: Опишите, какие действия были приняты, или любые другие подробности…\n      reopen: Переоткрыть жалобу\n      report: 'Жалоба #%{id}'\n      reported_account: Аккаунт нарушителя\n      reported_by: Отправитель жалобы\n      resolved: Разрешенные\n      resolved_msg: Жалоба успешно обработана!\n      status: Статус\n      title: Жалобы\n      unassign: Снять назначение\n      unresolved: Неразрешенные\n      updated_at: Обновлена\n    settings:\n      activity_api_enabled:\n        desc_html: Подсчёт количества локальных статусов, активных пользователей и новых регистраций на еженедельной основе\n        title: Публикация агрегированной статистики активности пользователей\n      bootstrap_timeline_accounts:\n        desc_html: Разделяйте имена пользователей запятыми. Сработает только для локальных незакрытых аккаунтов. По умолчанию включены все локальные администраторы.\n        title: Подписки по умолчанию для новых пользователей\n      contact_information:\n        email: Введите публичный e-mail\n        username: Введите имя пользователя\n      custom_css:\n        desc_html: Измените внешний вид с CSS, загружаемым на каждой странице\n        title: Особый CSS\n      hero:\n        desc_html: Отображается на главной странице. Рекомендуется разрешение не менее 600х100px. Если не установлено, используется изображение узла\n        title: Баннер узла\n      mascot:\n        desc_html: Отображается на различных страницах. Рекомендуется размер не менее 293×205px. Если ничего не выбрано, используется персонаж по умолчанию\n        title: Персонаж сервера\n      peers_api_enabled:\n        desc_html: Домены, которые были замечены этим узлом среди всей федерации\n        title: Публикация списка обнаруженных узлов\n      preview_sensitive_media:\n        desc_html: Предпросмотр ссылок с остальных веб-сайтов будет показан даже если медиаконтент отмечен как чувствительный\n        title: Показывать чувствительный медиаконтент в предпросмотре OpenGraph\n      profile_directory:\n        desc_html: Позволять находить пользователей\n        title: Включить каталог профилей\n      registrations:\n        closed_message:\n          desc_html: Отображается на титульной странице, когда закрыта регистрация<br>Можно использовать HTML-теги\n          title: Сообщение о закрытой регистрации\n        deletion:\n          desc_html: Позволяет всем удалять собственные аккаунты\n          title: Разрешить удаление аккаунтов\n        min_invite_role:\n          disabled: Никого\n          title: Разрешать приглашения от\n      registrations_mode:\n        modes:\n          approved: Для регистрации требуется подтверждение\n          none: Никто не может регистрироваться\n          open: Все могут регистрироваться\n        title: Режим регистраций\n      show_known_fediverse_at_about_page:\n        desc_html: Если включено, показывает посты со всех известных узлов в предпросмотре ленты. В противном случае отображаются только локальные посты.\n        title: Показывать известные узлы в предпросмотре ленты\n      show_staff_badge:\n        desc_html: Показывать метку персонала на странице пользователя\n        title: Показывать метку персонала\n      site_description:\n        desc_html: Отображается в качестве параграфа на титульной странице и используется в качестве мета-тега.<br>Можно использовать HTML-теги, в особенности <code>&lt;a&gt;</code> и <code>&lt;em&gt;</code>.\n        title: Описание сайта\n      site_description_extended:\n        desc_html: Отображается на странице дополнительной информации<br>Можно использовать HTML-теги\n        title: Расширенное описание узла\n      site_short_description:\n        desc_html: Отображается в боковой панели и в тегах. Опишите, что такое Mastodon и что делает именно этот узел особенным. Если пусто, используется описание узла по умолчанию.\n        title: Краткое описание узла\n      site_terms:\n        desc_html: Вы можете добавить сюда собственную политику конфиденциальности, пользовательское соглашение и другие документы. Можно использовать теги HTML\n        title: Условия использования\n      site_title: Название сайта\n      thumbnail:\n        desc_html: Используется для предпросмотра с помощью OpenGraph и API. Рекомендуется разрешение 1200x630px\n        title: Картинка узла\n      timeline_preview:\n        desc_html: Показывать публичную ленту на приветственной странице\n        title: Предпросмотр ленты\n      title: Настройки сайта\n    statuses:\n      back_to_account: Назад к странице аккаунта\n      batch:\n        delete: Удалить\n        nsfw_off: Выключить NSFW\n        nsfw_on: Включить NSFW\n      failed_to_execute: Не удалось выполнить\n      media:\n        title: Медиаконтент\n      no_media: Без медиаконтента\n      no_status_selected: Не выбран ни один статус, ничего не изменено\n      title: Статусы аккаунта\n      with_media: С медиаконтентом\n    subscriptions:\n      callback_url: Callback URL\n      confirmed: Подтверждено\n      expires_in: Истекает через\n      last_delivery: Последняя доставка\n      title: WebSub\n      topic: Тема\n    tags:\n      accounts: Аккаунты\n      hidden: Скрыты\n      hide: Скрыть из каталога\n      name: Хэштег\n      title: Хэштеги\n      unhide: Показывать в каталоге\n      visible: Видны\n    title: Администрирование\n    warning_presets:\n      add_new: Добавить\n      delete: Удалить\n      edit: Изменить\n      edit_preset: Удалить шаблон предупреждения\n      title: Управление шаблонами предупреждений\n  admin_mailer:\n    new_pending_account:\n      body: Ниже указана информация об аккаунте. Вы можете одобрить или отклонить заявку.\n      subject: Новый аккаунт для рассмотрения на %{instance} (%{username})\n    new_report:\n      body: \"%{reporter} подал(а) жалобу на %{target}\"\n      body_remote: Кто-то с узла %{domain} пожаловался на %{target}\n      subject: Новая жалоба, узел %{instance} (#%{id})\n  appearance:\n    advanced_web_interface: Многоколоночный интерфейс\n    sensitive_content: Чувствительное содержимое\n  application_mailer:\n    notification_preferences: Изменить настройки e-mail\n    salutation: \"%{name},\"\n    settings: 'Изменить настройки e-mail: %{link}'\n    view: 'Просмотр:'\n    view_profile: Просмотреть профиль\n    view_status: Просмотреть статус\n  applications:\n    created: Приложение успешно создано\n    destroyed: Приложение успешно удалено\n    invalid_url: Введенный URL неверен\n    regenerate_token: Повторно сгенерировать токен доступа\n    token_regenerated: Токен доступа успешно сгенерирован\n    warning: Будьте очень внимательны с этими данными. Не делитесь ими ни с кем!\n    your_token: Ваш токен доступа\n  auth:\n    apply_for_account: Запросить приглашение\n    change_password: Пароль\n    checkbox_agreement_html: Я соглашаюсь с <a href=\"%{rules_path}\" target=\"_blank\">правилами сервера</a> и <a href=\"%{terms_path}\" target=\"_blank\">Условиями использования</a>\n    confirm_email: Подтвердите email\n    delete_account: Удалить аккаунт\n    delete_account_html: Если Вы хотите удалить свой аккаунт, вы можете <a href=\"%{path}\">перейти сюда</a>. У Вас будет запрошено подтверждение.\n    didnt_get_confirmation: Не получили инструкцию для подтверждения?\n    forgot_password: Забыли пароль?\n    invalid_reset_password_token: Токен сброса пароля неверен или устарел. Пожалуйста, запросите новый.\n    login: Войти\n    logout: Выйти\n    migrate_account: Перенести аккаунт\n    migrate_account_html: Если Вы хотите перенести этот аккаунт на другой, вы можете <a href=\"%{path}\">сделать это здесь</a>.\n    or_log_in_with: Или войти с помощью\n    providers:\n      cas: CAS\n      saml: SAML\n    register: Зарегистрироваться\n    registration_closed: \"%{instance} не принимает новых участников\"\n    resend_confirmation: Повторить отправку инструкции для подтверждения\n    reset_password: Сбросить пароль\n    security: Безопасность\n    set_new_password: Задать новый пароль\n    trouble_logging_in: Не удаётся войти?\n  authorize_follow:\n    already_following: Вы уже подписаны на этот аккаунт\n    error: К сожалению, при поиске удаленного аккаунта возникла ошибка\n    follow: Подписаться\n    follow_request: 'Вы отправили запрос на подписку:'\n    following: 'Ура! Теперь Вы подписаны на:'\n    post_follow:\n      close: Или просто закрыть это окно.\n      return: Вернуться к профилю пользователя\n      web: Перейти к WWW\n    title: Подписаться на %{acct}\n  datetime:\n    distance_in_words:\n      about_x_hours: \"%{count}ч\"\n      about_x_months: \"%{count}мес\"\n      about_x_years: \"%{count}г\"\n      almost_x_years: \"%{count}г\"\n      half_a_minute: Только что\n      less_than_x_minutes: \"%{count}мин\"\n      less_than_x_seconds: Только что\n      over_x_years: \"%{count}г\"\n      x_days: \"%{count}д\"\n      x_minutes: \"%{count}мин\"\n      x_months: \"%{count}мес\"\n      x_seconds: \"%{count}сек\"\n  deletes:\n    bad_password_msg: Не вышло, хакеры! Неверный пароль\n    confirm_password: Введите текущий пароль для подтверждения Вашей личности\n    description_html: Это действие <strong>перманентно и необратимо</strong> удалит контент Вашего аккаунта и деактивирует его. Ваше имя пользователя будет зарезервировано для предотвращения имперсонации в будущем.\n    proceed: Удалить аккаунт\n    success_msg: Ваш аккаунт был успешно удален\n    warning_html: Гарантируется удаление контента только на этом узле. Широко распространившийся контент, скорее всего, оставит следы. Сервера, отключенные от сети или отписавшиеся от Ваших обновлений, не обновят свои базы данных.\n    warning_title: О доступности распространившегося контента\n  directories:\n    directory: Каталог профилей\n    enabled: В настоящий момент вы указаны в каталоге.\n    enabled_but_waiting: Вы согласились находиться в каталоге, но у вас ещё нет необходимого количества подписчиков (%{min_followers}), чтобы оказаться в каталоге.\n    explanation: Находите пользователей по интересам\n    explore_mastodon: Изучайте %{title}\n    how_to_enable: Вы ещё не находитесь в каталоге. Можете добавиться ниже. Используйте хэштеги в разделе \"о себе\", чтобы вас находили по этим хэштегам!\n    people:\n      few: \"%{count} человека\"\n      many: \"%{count} человек\"\n      one: \"%{count} человек\"\n      other: \"%{count} человек\"\n  errors:\n    '403': У Вас нет доступа к просмотру этой страницы.\n    '404': Страница, которую Вы искали, не существует.\n    '410': Страница, которую Вы искали, больше не существует.\n    '422':\n      content: Проверка безопасности не удалась. Возможно, Вы блокируете cookies?\n      title: Проверка безопасности не удалась\n    '429': Слишком много запросов\n    '500':\n      content: Приносим извинения, но на нашей стороне что-то пошло не так.\n      title: Страница неверна\n    noscript_html: Для работы с Mastodon, пожалуйста, включите JavaScript. Кроме того, вы можете использовать одно из <a href=\"%{apps_path}\">приложений</a> Mastodon для Вашей платформы.\n  existing_username_validator:\n    not_found: не удалось найти локального пользователя с таким именем\n    not_found_multiple: не удалось найти %{usernames}\n  exports:\n    archive_takeout:\n      date: Дата\n      download: Скачать ваш архив\n      hint_html: Вы можете запросить архив своих <strong>статусов и загруженных медиа-файлов</strong>. Экспортированные данные будут в формате ActivityPub, который можно прочесть любой соответствующей программой. Запрашивать архив можно каждые 7 дней.\n      in_progress: Собирается ваш архив...\n      request: Запросить ваш архив\n      size: Размер\n    blocks: Список блокировки\n    csv: CSV\n    domain_blocks: Доменные блокировки\n    follows: Подписки\n    lists: Списки\n    mutes: Список глушения\n    storage: Ваш медиаконтент\n  featured_tags:\n    add_new: Добавить\n    errors:\n      limit: Вы уже добавили максимальное число хэштегов\n  filters:\n    contexts:\n      home: Домашняя лента\n      notifications: Уведомления\n      public: Публичные ленты\n      thread: Диалоги\n    edit:\n      title: Изменить фильтр\n    errors:\n      invalid_context: Некорректный контекст или ничего\n      invalid_irreversible: Необратимая фильтрация работает только с лентой уведомлений и домашней лентой\n    index:\n      delete: Удалить\n      title: Фильтры\n    new:\n      title: Добавить фильтр\n  footer:\n    developers: Разработчикам\n    more: Ещё…\n    resources: Ссылки\n  generic:\n    all: Все\n    changes_saved_msg: Изменения успешно сохранены!\n    copy: Копировать\n    order_by: Сортировать по\n    save_changes: Сохранить изменения\n    validation_errors:\n      few: Что-то здесь не так! Пожалуйста, прочитайте о %{count} ошибках ниже\n      many: Что-то здесь не так! Пожалуйста, прочитайте о %{count} ошибках ниже\n      one: Что-то здесь не так! Пожалуйста, прочитайте об ошибке ниже\n      other: Что-то здесь не так! Пожалуйста, прочитайте о %{count} ошибках ниже\n  html_validator:\n    invalid_markup: 'невалидная разметка HTML: %{error}'\n  identity_proofs:\n    active: Активно\n    authorize: Да, авторизовать\n    authorize_connection_prompt: Авторизовать эту криптографическую связь?\n    errors:\n      failed: Криптографическое соединение не установлено. Попробуйте ещё раз на %{provider}.\n      keybase:\n        invalid_token: Токены Keybase — это хэши от подписей и должны быть по длине в 66 hex-символов\n        verification_failed: Keybase не распознаёт этот токен как подпись пользователя %{kb_username}. Пожалуйста, повторите на Keybase.\n      wrong_user: Невозможно подтвердить пользователя %{proving}, будучи залогиненным как %{current}. Выполните вход как %{proving} и попробуйте ещё раз.\n    explanation_html: Здесь вы можете криптографически связать свои остальные идентификаторы, такие как профиль Keybase. Это позволит другим дюдям отправлять вам зашифрованные сообщения и верить отправляемым вами сообщениям.\n    i_am_html: Я %{username} на %{service}.\n    identity: Идентификатор\n    inactive: Неактивно\n    publicize_checkbox: 'И опубликуйте текст:'\n    publicize_toot: 'Подтверждено! Я %{username} на %{service}: %{url}'\n    status: Статус подтверждения\n    view_proof: Посмотреть доказательство личности\n  imports:\n    modes:\n      merge: Объединить\n      merge_long: Сохранить имеющиеся данные и добавить новые\n      overwrite: Перезаписать\n      overwrite_long: Перезаписать имеющиеся данные новыми\n    preface: Вы можете загрузить некоторые данные, например, списки людей, на которых Вы подписаны или которых блокируете, в Ваш аккаунт на этом узле из файлов, экспортированных с другого узла.\n    success: Ваши данные были успешно загружены и будут обработаны с должной скоростью\n    types:\n      blocking: Список блокировки\n      domain_blocking: Список доменных блокировок\n      following: Подписки\n      muting: Список глушения\n    upload: Загрузить\n  in_memoriam_html: Памятник.\n  invites:\n    delete: Удалить\n    expired: Истекло\n    expires_in:\n      '1800': 30 минут\n      '21600': 6 часов\n      '3600': 1 час\n      '43200': 12 часов\n      '604800': 1 неделю\n      '86400': 1 день\n    expires_in_prompt: Никогда\n    generate: Сгенерировать\n    invited_by: 'Вас пригласил(а):'\n    max_uses:\n      few: \"%{count} исп.\"\n      many: \"%{count} исп.\"\n      one: 1 исп\n      other: \"%{count} исп\"\n    max_uses_prompt: Без лимита\n    prompt: Генерируйте и делитесь ссылками с другими, чтобы предоставить им доступ к этому узлу\n    table:\n      expires_at: Истекает\n      uses: Исп.\n    title: Пригласить людей\n  lists:\n    errors:\n      limit: Вы достигли максимального числа списков\n  media_attachments:\n    validations:\n      images_and_video: Нельзя добавить видео к статусу с изображениями\n      too_many: Нельзя добавить более 4 файлов\n  migrations:\n    acct: имя@домен нового аккаунта\n    currently_redirecting: 'Ваш профиль будет перенаправлен на:'\n    proceed: Сохранить\n    updated_msg: Настройки миграции вашего аккаунта обновлены!\n  moderation:\n    title: Модерация\n  notification_mailer:\n    digest:\n      action: Просмотреть все уведомления\n      body: Кратко о пропущенных Вами сообщениях с Вашего последнего захода %{since}\n      mention: \"%{name} упомянул(а) Вас в:\"\n      new_followers_summary:\n        few: У вас появилось %{count} новых подписчика! Отлично!\n        many: У вас появилось %{count} новых подписчиков! Отлично!\n        one: Также, пока вас не было, у вас появился новый подписчик! Ура!\n        other: Также, пока вас не было, у вас появилось %{count} новых подписчиков! Отлично!\n      subject:\n        few: \"%{count} новых уведомления с вашего последнего захода \\U0001F418\"\n        many: \"%{count} новых уведомлений с вашего последнего захода \\U0001F418\"\n        one: \"1 новое уведомление с вашего последнего захода \\U0001F418\"\n        other: \"%{count} новых уведомлений с вашего последнего захода \\U0001F418\"\n      title: В ваше отсутствие…\n    favourite:\n      body: 'Ваш статус понравился %{name}:'\n      subject: \"%{name} понравился ваш статус\"\n      title: Понравившийся статус\n    follow:\n      body: \"%{name} теперь подписан(а) на вас!\"\n      subject: \"%{name} теперь подписан(а) на вас\"\n      title: Новый подписчик\n    follow_request:\n      action: Управление запросами на подписку\n      body: \"%{name} запросил вас о подписке\"\n      subject: \"%{name} хочет подписаться на вас\"\n      title: Новый запрос о подписке\n    mention:\n      action: Ответить\n      body: 'Вас упомянул(а) %{name} в:'\n      subject: Вы были упомянуты %{name}\n      title: Новое упоминание\n    reblog:\n      body: 'Ваш статус был продвинут %{name}:'\n      subject: \"%{name} продвинул(а) ваш статус\"\n      title: Новое продвижение\n  number:\n    human:\n      decimal_units:\n        format: \"%n %u\"\n        units:\n          billion: млрд\n          million: млн\n          quadrillion: квадрлн\n          thousand: тыс\n          trillion: трлн\n  pagination:\n    newer: Новее\n    next: След\n    older: Старше\n    prev: Пред\n    truncate: \"&hellip;\"\n  polls:\n    errors:\n      already_voted: Вы уже голосовали в этом опросе\n      duplicate_options: содержит одинаковые варианты\n      duration_too_long: слишком далеко в будущем\n      duration_too_short: слишком короткий срок\n      expired: Опрос уже завершился\n      over_character_limit: каждый не вариант не может быть длиннее %{max} символов\n      too_few_options: должно быть больше 1 варианта\n      too_many_options: может содержать не больше %{max} вариантов\n  preferences:\n    other: Другое\n    public_timelines: Публичные ленты\n  relationships:\n    activity: Активность аккаунта\n    dormant: Заброшенные\n    last_active: Недавно активные\n    most_recent: Новые\n    moved: Переехавший\n    mutual: Общие\n    primary: Основной\n    relationship: Связь\n    remove_selected_domains: Удалить всех подписчиков для выбранных доменов\n    remove_selected_followers: Удалить выбранных подписчиков\n    remove_selected_follows: Отписаться от выбранных пользователей\n    status: Статус аккаунта\n  remote_follow:\n    acct: Введите свой username@domain для продолжения\n    missing_resource: Поиск требуемого перенаправления URL для Вашего аккаунта завершился неудачей\n    no_account_html: Нет учётной записи? Вы можете <a href='%{sign_up_path}' target='_blank'>зарегистрироваться здесь</a>\n    proceed: Продолжить подписку\n    prompt: 'Вы хотите подписаться на:'\n    reason_html: \"<strong>Почему это необходимо?</strong> <code>%{instance}</code> может не являться сервером, на котором вы зарегистрированы, поэтому нам сперва нужно перенаправить вас на домашний сервер.\"\n  remote_interaction:\n    favourite:\n      proceed: Отметить как \"нравится\"\n      prompt: 'Вы собираетесь поставить отметку \"нравится\" этому статусу:'\n    reblog:\n      proceed: Продвинуть статус\n      prompt: 'Вы хотите продвинуть этот статус:'\n    reply:\n      proceed: Ответить\n      prompt: 'Вы собираетесь ответить на этот статус:'\n  remote_unfollow:\n    error: Ошибка\n    title: Заголовок\n    unfollowed: Отписаны\n  scheduled_statuses:\n    over_daily_limit: Вы превысили лимит в %{limit} запланированных постов на указанный день\n    over_total_limit: Вы превысили лимит на %{limit} запланированных постов\n    too_soon: Запланированная дата должна быть в будущем\n  sessions:\n    activity: Последняя активность\n    browser: Браузер\n    browsers:\n      alipay: Alipay\n      blackberry: Blackberry\n      chrome: Chrome\n      edge: Microsoft Edge\n      electron: Electron\n      firefox: Firefox\n      generic: Неизвестный браузер\n      ie: Internet Explorer\n      micro_messenger: MicroMessenger\n      nokia: Nokia S40 Ovi Browser\n      opera: Opera\n      otter: Otter\n      phantom_js: PhantomJS\n      qq: QQ Browser\n      safari: Safari\n      uc_browser: UCBrowser\n      weibo: Weibo\n    current_session: Текущая сессия\n    description: \"%{browser} на %{platform}\"\n    explanation: Это веб-браузеры, в которых на данный момент выполнен вход в Ваш аккаунт Mastodon.\n    ip: IP\n    platforms:\n      adobe_air: Adobe Air\n      android: Android\n      blackberry: Blackberry\n      chrome_os: ChromeOS\n      firefox_os: Firefox OS\n      ios: iOS\n      linux: Linux\n      mac: Mac\n      other: неизвестной платформе\n      windows: Windows\n      windows_mobile: Windows Mobile\n      windows_phone: Windows Phone\n    revoke: Завершить\n    revoke_success: Сессия завершена успешно\n    title: Сессии\n  settings:\n    account: Учётная запись\n    account_settings: Настройки учётной записи\n    appearance: Внешний вид\n    authorized_apps: Авторизованные приложения\n    back: Назад в Mastodon\n    delete: Удаление аккаунта\n    development: Разработка\n    edit_profile: Изменить профиль\n    export: Экспорт данных\n    featured_tags: Особенные хэштеги\n    identity_proofs: Подтверждения личности\n    import: Импорт\n    import_and_export: Импорт и экспорт\n    migrate: Перенос аккаунта\n    notifications: Уведомления\n    preferences: Настройки\n    profile: Профиль\n    relationships: Подписки и подписчики\n    two_factor_authentication: Двухфакторная аутентификация\n  statuses:\n    attached:\n      description: 'Вложение: %{attached}'\n      image:\n        few: \"%{count} изображения\"\n        many: \"%{count} изображений\"\n        one: \"%{count} изображение\"\n        other: \"%{count} изображений\"\n      video:\n        few: \"%{count} видео\"\n        many: \"%{count} видео\"\n        one: \"%{count} видео\"\n        other: \"%{count} видео\"\n    boosted_from_html: Продвижение польз. %{acct_link}\n    content_warning: 'Спойлер: %{warning}'\n    disallowed_hashtags:\n      few: 'содержались запрещённые хэштеги: %{tags}'\n      many: 'содержались запрещённые хэштеги: %{tags}'\n      one: 'содержался запрещённый хэштег: %{tags}'\n      other: 'содержались запрещённые хэштеги: %{tags}'\n    language_detection: Определять язык автоматически\n    open_in_web: Открыть в WWW\n    over_character_limit: превышен лимит символов (%{max})\n    pin_errors:\n      limit: Вы закрепили максимально возможное число статусов\n      ownership: Нельзя закрепить чужой статус\n      private: Нельзя закрепить непубличный статус\n      reblog: Нельзя закрепить продвинутый статус\n    poll:\n      total_votes:\n        few: \"%{count} голоса\"\n        many: \"%{count} голосов\"\n        one: \"%{count} голос\"\n        other: \"%{count} голосов\"\n      vote: Голосовать\n    show_more: Ещё\n    sign_in_to_participate: Войдите, чтобы принять участие в дискуссии\n    title: '%{name}: \"%{quote}\"'\n    visibilities:\n      private: Для подписчиков\n      private_long: Показывать только подписчикам\n      public: Для всех\n      public_long: Показывать всем\n      unlisted: Скрывать из лент\n      unlisted_long: Показывать всем, но не отображать в публичных лентах\n  stream_entries:\n    pinned: Закреплённый статус\n    reblogged: продвинул(а)\n    sensitive_content: Чувствительный контент\n  terms:\n    body_html: |\n      <h2>Privacy Policy</h2>\n      <h3 id=\"collect\">What information do we collect?</h3>\n\n      <ul>\n      <li><em>Basic account information</em>: If you register on this server, you may be asked to enter a username, an e-mail address and a password. You may also enter additional profile information such as a display name and biography, and upload a profile picture and header image. The username, display name, biography, profile picture and header image are always listed publicly.</li>\n      <li><em>Posts, following and other public information</em>: The list of people you follow is listed publicly, the same is true for your followers. When you submit a message, the date and time is stored as well as the application you submitted the message from. Messages may contain media attachments, such as pictures and videos. Public and unlisted posts are available publicly. When you feature a post on your profile, that is also publicly available information. Your posts are delivered to your followers, in some cases it means they are delivered to different servers and copies are stored there. When you delete posts, this is likewise delivered to your followers. The action of reblogging or favouriting another post is always public.</li>\n      <li><em>Direct and followers-only posts</em>: All posts are stored and processed on the server. Followers-only posts are delivered to your followers and users who are mentioned in them, and direct posts are delivered only to users mentioned in them. In some cases it means they are delivered to different servers and copies are stored there. We make a good faith effort to limit the access to those posts only to authorized persons, but other servers may fail to do so. Therefore it's important to review servers your followers belong to. You may toggle an option to approve and reject new followers manually in the settings. <em>Please keep in mind that the operators of the server and any receiving server may view such messages</em>, and that recipients may screenshot, copy or otherwise re-share them. <em>Do not share any dangerous information over Mastodon.</em></li>\n      <li><em>IPs and other metadata</em>: When you log in, we record the IP address you log in from, as well as the name of your browser application. All the logged in sessions are available for your review and revocation in the settings. The latest IP address used is stored for up to 12 months. We also may retain server logs which include the IP address of every request to our server.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"use\">What do we use your information for?</h3>\n\n      <p>Any of the information we collect from you may be used in the following ways:</p>\n\n      <ul>\n      <li>To provide the core functionality of Mastodon. You can only interact with other people's content and post your own content when you are logged in. For example, you may follow other people to view their combined posts in your own personalized home timeline.</li>\n      <li>To aid moderation of the community, for example comparing your IP address with other known ones to determine ban evasion or other violations.</li>\n      <li>The email address you provide may be used to send you information, notifications about other people interacting with your content or sending you messages, and to respond to inquiries, and/or other requests or questions.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"protect\">How do we protect your information?</h3>\n\n      <p>We implement a variety of security measures to maintain the safety of your personal information when you enter, submit, or access your personal information. Among other things, your browser session, as well as the traffic between your applications and the API, are secured with SSL, and your password is hashed using a strong one-way algorithm. You may enable two-factor authentication to further secure access to your account.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"data-retention\">What is our data retention policy?</h3>\n\n      <p>We will make a good faith effort to:</p>\n\n      <ul>\n      <li>Retain server logs containing the IP address of all requests to this server, in so far as such logs are kept, no more than 90 days.</li>\n      <li>Retain the IP addresses associated with registered users no more than 12 months.</li>\n      </ul>\n\n      <p>You can request and download an archive of your content, including your posts, media attachments, profile picture, and header image.</p>\n\n      <p>You may irreversibly delete your account at any time.</p>\n\n      <hr class=\"spacer\"/>\n\n      <h3 id=\"cookies\">Do we use cookies?</h3>\n\n      <p>Yes. Cookies are small files that a site or its service provider transfers to your computer's hard drive through your Web browser (if you allow). These cookies enable the site to recognize your browser and, if you have a registered account, associate it with your registered account.</p>\n\n      <p>We use cookies to understand and save your preferences for future visits.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"disclose\">Do we disclose any information to outside parties?</h3>\n\n      <p>We do not sell, trade, or otherwise transfer to outside parties your personally identifiable information. This does not include trusted third parties who assist us in operating our site, conducting our business, or servicing you, so long as those parties agree to keep this information confidential. We may also release your information when we believe release is appropriate to comply with the law, enforce our site policies, or protect ours or others rights, property, or safety.</p>\n\n      <p>Your public content may be downloaded by other servers in the network. Your public and followers-only posts are delivered to the servers where your followers reside, and direct messages are delivered to the servers of the recipients, in so far as those followers or recipients reside on a different server than this.</p>\n\n      <p>When you authorize an application to use your account, depending on the scope of permissions you approve, it may access your public profile information, your following list, your followers, your lists, all your posts, and your favourites. Applications can never access your e-mail address or password.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"coppa\">Children's Online Privacy Protection Act Compliance</h3>\n\n      <p>Our site, products and services are all directed to people who are at least 13 years old. If this server is in the USA, and you are under the age of 13, per the requirements of COPPA (<a href=\"https://en.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act\">Children's Online Privacy Protection Act</a>) do not use this site.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"changes\">Changes to our Privacy Policy</h3>\n\n      <p>If we decide to change our privacy policy, we will post those changes on this page.</p>\n\n      <p>This document is CC-BY-SA. It was last updated March 7, 2018.</p>\n\n      <p>Originally adapted from the <a href=\"https://github.com/discourse/discourse\">Discourse privacy policy</a>.</p>\n    title: Условия обслуживания и политика конфиденциальности %{instance}\n  themes:\n    contrast: Mastodon (высококонтрастная)\n    default: Mastodon (тёмная)\n    mastodon-light: Mastodon (светлая)\n  time:\n    formats:\n      default: \"%d %b %Y, %H:%M\"\n      month: \"%m.%Y\"\n  two_factor_authentication:\n    code_hint: Для подтверждения введите код, сгенерированный приложением аутентификатора\n    description_html: При включении <strong>двухфакторной аутентификации</strong>, вход потребует от Вас использования Вашего телефона, который сгенерирует входные токены.\n    disable: Отключить\n    enable: Включить\n    enabled: Двухфакторная аутентификация включена\n    enabled_success: Двухфакторная аутентификация успешно включена\n    generate_recovery_codes: Сгенерировать коды восстановления\n    instructions_html: \"<strong>Отсканируйте этот QR-код с помощью Google Authenticator или другого подобного приложения на Вашем телефоне</strong>. С этого момента приложение будет генерировать токены, которые будет необходимо ввести для входа.\"\n    lost_recovery_codes: Коды восстановления позволяют вернуть доступ к аккаунту в случае утери телефона. Если Вы потеряли Ваши коды восстановления, вы можете заново сгенерировать их здесь. Ваши старые коды восстановления будут аннулированы.\n    manual_instructions: 'Если Вы не можете отсканировать QR-код и хотите ввести его вручную, секрет представлен здесь открытым текстом:'\n    recovery_codes: Коды восстановления\n    recovery_codes_regenerated: Коды восстановления успешно сгенерированы\n    recovery_instructions_html: В случае утери доступа к Вашему телефону Вы можете использовать один из кодов восстановления, указанных ниже, чтобы вернуть доступ к аккаунту. Держите коды восстановления в безопасности, например, распечатав их и храня с другими важными документами.\n    setup: Настроить\n    wrong_code: Введенный код неверен! Правильно ли установлены серверное время и время устройства?\n  user_mailer:\n    backup_ready:\n      explanation: Вы запросили полный архив вашего аккаунта Mastodon. Он готов к загрузке!\n      subject: Ваш архив готов к загрузке\n      title: Вынос архива\n    warning:\n      explanation:\n        disable: Пока ваш аккаунт заморожен, ваши данные остаются нетронутыми, но вы не можете производить никаких действий до разблокировки.\n        silence: Пока ваш аккаунт ограничен, ваши посты на этом сервере увидят только ваши действующие подписчики, а ваш аккаунт может быть исключён из различных каталогов. Впрочем, остальные могут подписаться на вас вручную.\n        suspend: Ваш аккаунт заблокирован и все ваши посты и загруженные медиафайлы безвозвратно удалены с этого сервера и других серверов, где у вас были подписчики.\n      review_server_policies: Посмотреть правила сервера\n      subject:\n        disable: Ваш аккаунт %{acct} заморожен\n        none: \"%{acct}, вам вынесено предупреждение\"\n        silence: Ваш аккаунт %{acct} был ограничен\n        suspend: Ваш аккаунт %{acct} был заблокирован\n      title:\n        disable: Аккаунт заморожен\n        none: Предупреждение\n        silence: Аккаунт ограничен\n        suspend: Аккаунт заблокирован\n    welcome:\n      edit_profile_action: Настроить профиль\n      edit_profile_step: Вы можете настроить свой профиль, загрузив аватар, обложку, сменив имя и много чего ещё. Если вы хотите фильтровать подписчиков до того, как они смогут на вас подписаться, вы можете закрыть свой аккаунт.\n      explanation: Несколько советов для новичков\n      final_action: Начать постить\n      final_step: 'Начните постить! Ваши публичные посты могут видеть другие, например, в локальной ленте или по хэштегам, даже если у вас нет подписчиков. Вы также можете поздороваться с остальными и представиться, используя хэштег #приветствие.'\n      full_handle: Ваше обращение\n      full_handle_hint: То, что Вы хотите сообщить своим друзьям, чтобы они могли написать Вам или подписаться с другого узла.\n      review_preferences_action: Изменить настройки\n      review_preferences_step: Проверьте все настройки, например, какие письма вы хотите получать или уровень приватности статусов по умолчанию. Если вы не страдаете морской болезнью, можете включить автовоспроизведение GIF.\n      subject: Добро пожаловать в Mastodon\n      tip_federated_timeline: В глобальной ленте отображается сеть Mastodon. Но в ней показаны посты только от людей, на которых подписаны вы и ваши соседи, поэтому лента может быть неполной.\n      tip_following: По умолчанию вы подписаны на администратора(-ов) вашего узла. Чтобы найти других интересных людей, проверьте локальную и глобальную ленты.\n      tip_local_timeline: В локальной ленте показаны посты от людей с %{instance}. Это ваши непосредственные соседи!\n      tip_mobile_webapp: Если ваш мобильный браузер предлагает добавить иконку Mastodon на домашний экран, то вы можете получать push-уведомления. Прямо как полноценное приложение!\n      tips: Советы\n      title: Добро пожаловать на борт, %{name}!\n  users:\n    follow_limit_reached: Вы не можете подписаться больше, чем на %{limit} человек\n    invalid_email: Введенный e-mail неверен\n    invalid_otp_token: Введен неверный код двухфакторной аутентификации\n    otp_lost_help_html: Если Вы потеряли доступ к обоим, свяжитесь с %{email}\n    seamless_external_login: Вы залогинены через сторонний сервис, поэтому настройки e-mail и пароля недоступны.\n    signed_in_as: 'Выполнен вход под именем:'\n  verification:\n    explanation_html: 'Вы можете <strong>подтвердить себя как владельца ссылок в вашем профиле</strong>. Для этого указанный веб-сайт должен содержать обратную ссылку на ваш профиль в Mastodon. У обратной ссылки <strong>должен</strong> быть атрибут <code>rel=\"me\"</code>. Сам текст ссылки не имеет значения. Пример:'\n    verification: Подтверждение\n"
  },
  {
    "path": "config/locales/simple_form.ar.yml",
    "content": "---\nar:\n  simple_form:\n    hints:\n      account_warning_preset:\n        text: بإمكانك استخدام نفس القواعد التي نجدها في التبويقات كعناوين الروابط والوسوم والإشارات\n      admin_account_action:\n        send_email_notification: سوف يتلقى المستخدم رسالة تُفسِّر ما حدث على حسابه\n        type_html: اختر ما تود إجراؤه على <strong>%{acct}</strong>\n        warning_preset_id: اختياري. يمكنك إضافة نص مخصص إلى نهاية النموذج\n      defaults:\n        autofollow: سوف يتابعك تلقائيًا الأشخاص الذين يقومون بالتسجيل من خلال الدعوة\n        avatar: ملف PNG أو GIF أو JPG. حجمه على أقصى تصدير %{size}. سيتم تصغيره إلى %{dimensions}px\n        bot: يُعلِم أنّ هذا الحساب لا يمثل شخصًا\n        context: واحد أو أكثر من السياقات التي يجب أن ينطبق عليها عامل التصفية\n        digest: تُرسَل إليك بعد مُضيّ مدة مِن خمول نشاطك و فقط إذا ما تلقيت رسائل شخصية مباشِرة أثناء فترة غيابك مِن الشبكة\n        email: سوف تتلقى رسالة إلكترونية للتأكيد\n        fields: يُمكنك عرض 4 عناصر على شكل جدول في ملفك الشخصي\n        header: ملف PNG أو GIF أو JPG. حجمه على أقصى تصدير %{size}. سيتم تصغيره إلى %{dimensions}px\n        inbox_url: نسخ العنوان الذي تريد استخدامه مِن صفحة الاستقبال للمُرحَّل\n        irreversible: التبويقات التي تم تصفيتها ستختفي لا محالة حتى و إن تمت إزالة عامِل التصفية لاحقًا\n        locale: لغة واجهة المستخدم و الرسائل الإلكترونية و الإشعارات\n        locked: يتطلب منك الموافقة يدويا على طلبات المتابعة\n        password: يُنصح باستخدام 8 أحرف على الأقل\n        phrase: سوف يتم العثور عليه مهما كان نوع النص أو حتى و إن كان داخل الويب فيه تحذير عن المحتوى\n        scopes: ما هي المجالات المسموح بها في التطبيق ؟ إن قمت باختيار أعلى المجالات فيمكنك الاستغناء عن الخَيار اليدوي.\n        setting_aggregate_reblogs: لا تقم بعرض المشارَكات الجديدة لتبويقات قد قُمتَ بمشاركتها سابقا (هذا الإجراء يعني المشاركات الجديدة فقط التي تلقيتَها)\n        setting_display_media_default: إخفاء الوسائط المُعيَّنة كحساسة\n        setting_display_media_hide_all: إخفاء كافة الوسائط دائمًا\n        setting_display_media_show_all: دائمًا عرض الوسائط المُعيَّنة كحساسة\n        setting_hide_network: الحسابات التي تُتابعها و التي تُتابِعك على حد سواء لن تُعرَض على صفحتك الشخصية\n        setting_noindex: ذلك يؤثر على حالة ملفك الشخصي و صفحاتك\n        username: اسم المستخدم الخاص بك سوف يكون فريدا مِن نوعه على %{domain}\n      featured_tag:\n        name: 'رُبَّما تريد/ي استخدام أحد هؤلاء:'\n      imports:\n        data: ملف CSV تم تصديره مِن خادوم ماستدون آخر\n      invite_request:\n        text: هذا سوف يساعدنا في مراجعة تطبيقك\n      sessions:\n        otp: 'قم بإدخال رمز المصادقة بخطوتين الذي قام بتوليده تطبيق جهازك أو استخدم أحد رموز النفاذ الاحتياطية:'\n      user:\n        chosen_languages: لن تظهر على الخيوط العمومية إلّا التبويقات المنشورة في اللغات المختارة\n    labels:\n      account:\n        fields:\n          name: التسمية\n          value: المحتوى\n      account_warning_preset:\n        text: نموذج نصي\n      admin_account_action:\n        send_email_notification: إشعار المستخدِم عبر البريد الإلكتروني\n        text: تحذير مخصص\n        type: الإجراء\n        types:\n          disable: تعطيل\n          none: لا تفعل شيئا\n          silence: كتم\n          suspend: تعليق و حذف كافة بيانات الحساب\n        warning_preset_id: استخدم نموذج تنبيه\n      defaults:\n        autofollow: إرسال دعوة لمتابعة حسابك\n        avatar: الصورة الرمزية\n        bot: إنّ هذا الحساب روبوت آلي\n        chosen_languages: تصفية اللغات\n        confirm_new_password: تأكيد كلمة السر الجديدة\n        confirm_password: تأكيد كلمة السر\n        context: تصفية السياقات\n        current_password: كلمة السر الحالية\n        data: البيانات\n        discoverable: القيام بإدراج هذا الحساب في قائمة دليل الحسابات\n        display_name: الاسم المعروض\n        email: عنوان البريد الإلكتروني\n        expires_in: تنتهي مدة صلاحيته بعد\n        fields: البيانات الوصفية للصفحة الشخصية\n        header: الرأسية\n        inbox_url: عنوان رابط صندوق المُرَحِّل\n        irreversible: إسقاط بدلا من إخفائها\n        locale: لغة الواجهة\n        locked: تجميد الحساب\n        max_uses: عدد مرات استخدام الرابط\n        new_password: كلمة السر الجديدة\n        note: السيرة الذاتية\n        otp_attempt: رمز المصادقة بخطوتين\n        password: كلمة السر\n        phrase: كلمة مفتاح أو عبارة\n        setting_advanced_layout: تمكين واجهة الويب المتقدمة\n        setting_aggregate_reblogs: جمع الترقيات في خيوط زمنية\n        setting_auto_play_gif: تشغيل تلقائي لِوَسائط جيف المتحركة\n        setting_boost_modal: إظهار مربع حوار للتأكيد قبل ترقية أي تبويق\n        setting_default_language: لغة النشر\n        setting_default_privacy: خصوصية المنشور\n        setting_default_sensitive: اعتبر الوسائط دائما كمحتوى حساس\n        setting_delete_modal: إظهار مربع حوار للتأكيد قبل حذف أي تبويق\n        setting_display_media: عرض الوسائط\n        setting_display_media_default: افتراضي\n        setting_display_media_hide_all: إخفاء الكل\n        setting_display_media_show_all: عرض الكل\n        setting_expand_spoilers: توسيع التبويقات التي تحتوي على تحذيرات عن المحتوى تلقائيا\n        setting_hide_network: إخفِ شبكتك\n        setting_noindex: عدم السماح لمحركات البحث بفهرسة ملفك الشخصي\n        setting_reduce_motion: تخفيض عدد الصور في الوسائط المتحركة\n        setting_show_application: اكشف اسم التطبيقات المستخدمة لنشر التبويقات\n        setting_system_font_ui: استخدم الخطوط الافتراضية للنظام\n        setting_theme: سمة الموقع\n        setting_unfollow_modal: إظهار مربع حوار للتأكيد قبل إلغاء متابعة أي حساب\n        severity: القوّة\n        type: صيغة الاستيراد\n        username: اسم المستخدم\n        username_or_email: اسم المستخدم أو كلمة السر\n        whole_word: الكلمة كاملة\n      featured_tag:\n        name: الوسم\n      interactions:\n        must_be_follower: حظر الإخطارات القادمة من حسابات لا تتبعك\n        must_be_following: حظر الإخطارات القادمة من الحسابات التي لا تتابعها\n        must_be_following_dm: حظر الرسائل المباشرة القادمة من طرف أشخاص لا تتبعهم\n      invite_request:\n        text: لماذا ترغب في الانضمام؟\n      notification_emails:\n        digest: إرسال ملخصات عبر البريد الإلكتروني\n        favourite: ابعث بريداً إلكترونيًا عندما يُعجَب أحدهم بمنشورك\n        follow: ابعث بريداً إلكترونيًا عندما يتبعك أحد\n        follow_request: ابعث بريدا إلكترونيا عندما يقوم أحدهم بإرسال طلب بالمتابعة\n        mention: ابعث بريداً إلكترونيًا عندما يُشير إليك أو يذكُرك أحدهم\n        reblog: ابعث بريداً إلكترونيًا عندما يقوم أحدهم بترقية منشورك\n        report: إرسال رسالة إلكترونية عند تلقّي إبلاغ جديد\n    'no': لا\n    recommended: موصى بها\n    required:\n      mark: \"*\"\n      text: مطلوب\n    'yes': نعم\n"
  },
  {
    "path": "config/locales/simple_form.ast.yml",
    "content": "---\nast:\n  simple_form:\n    hints:\n      defaults:\n        autofollow: La xente que se rexistre pente la invitación va siguite automáticamente\n        bot: Esta cuenta fai principalmente aiciones automatizaes y podría nun supervisase\n        digest: Namái s'unvia tres un periodu llargu d'inactividá y namái si recibiesti cualesquier mensaxe personal na to ausencia\n        email: Vamos unviate un corréu de confirmación\n        irreversible: Los toots peñeraos van desapaecer de mou irreversible, magar que se desanicie la peñera dempués\n        password: Usa 8 caráuteres polo menos\n        setting_hide_network: La xente que sigas y teas siguiendo nun va amosase nel perfil\n        username: El nome d'usuariu va ser únicu en %{domain}\n      imports:\n        data: El ficheru CSV esportáu dende otra instancia de Mastodon\n    labels:\n      account:\n        fields:\n          name: Etiqueta\n          value: Conteníu\n      defaults:\n        bot: Esta cuenta ye d'un robó\n        chosen_languages: Peñera de llingües\n        confirm_new_password: Confirmación de la contraseña nueva\n        current_password: Contraseña actual\n        data: Datos\n        display_name: Nome a amosar\n        email: Direición de corréu\n        expires_in: Caduca tres\n        fields: Datos meta del perfil\n        header: Testera\n        irreversible: Escartar en cuentes d'anubrir\n        locale: Llingua de la interfaz\n        locked: Bloquiar cuenta\n        max_uses: Númberu máximu d'usos\n        new_password: Contraseña nueva\n        otp_attempt: Códigu de verificación en dos pasos\n        password: Contraseña\n        phrase: Pallabra clave o fras\n        setting_auto_play_gif: Reproducir GIFs automáticamente\n        setting_default_language: Llingua de les espublizaciones\n        setting_default_privacy: Privacidá d'espublizaciones\n        setting_delete_modal: Amosar el diálogu de confirmación enantes de desaniciar un toot\n        setting_system_font_ui: Usar la fonte predeterminada del sistema\n        setting_unfollow_modal: Amosar el diálogu de confirmación enantes de dexar de siguir a daquién\n        severity: Severidá\n        type: Triba de la importación\n        username: Nome d'usuariu\n        username_or_email: Nome d'usuariu o corréu\n      interactions:\n        must_be_follower: Bloquiar avisos de persones que nun son siguidores\n        must_be_following: Bloquiar avisos de persones que nun sigues\n        must_be_following_dm: Bloquiar mensaxes direutos de persones que nun sigues\n      notification_emails:\n        favourite: Unviar un corréu cuando daquién conseñe como favoritu los tos estaos\n        follow: Unviar un corréu cuando daquién te siga\n        follow_request: Unviar un corréu cuando daquién solicite siguite\n        mention: Unviar un corréu cuando daquién te mente\n    'no': Non\n    required:\n      text: ríquese\n    'yes': Sí\n"
  },
  {
    "path": "config/locales/simple_form.bg.yml",
    "content": "---\nbg:\n  simple_form:\n    hints:\n      defaults:\n        avatar: PNG, GIF или JPG. До %{size}. Ще бъде смалена до %{dimensions} пиксела\n        header: PNG, GIF или JPG. До %{size}. Ще бъде смалена до %{dimensions} пиксела\n        locked: Изисква ръчно одобрение на последователите. По подразбиране, публикациите са достъпни само до последователи.\n      imports:\n        data: CSV файл, експортиран от друга инстанция на Mastodon\n    labels:\n      defaults:\n        avatar: Аватар\n        confirm_new_password: Потвърди новата парола\n        confirm_password: Потвърди паролата\n        current_password: Текуща парола\n        data: Данни\n        display_name: Показвано име\n        email: E-mail адрес\n        header: Заглавен ред\n        locale: Език\n        locked: Направи акаунта поверителен\n        new_password: Нова парола\n        note: Био\n        otp_attempt: Двустепенен код\n        password: Парола\n        setting_default_privacy: Поверителност на публикациите\n        type: Тип на импортиране\n        username: Потребителско име\n      interactions:\n        must_be_follower: Блокирай известия от не-последователи\n        must_be_following: Блокирай известия от хора, които не следваш\n      notification_emails:\n        digest: Изпращай извлечения на съобщенията\n        favourite: Изпращай e-mail, когато някой хареса твоя публикация\n        follow: Изпращай e-mail, когато някой те последва\n        follow_request: Изпращай e-mail, когато някой пожелае да те последва\n        mention: Изпращай e-mail, когато някой те спомене\n        reblog: Изпращай e-mail, когато някой сподели твоя публикация\n    'no': Не\n    required:\n      text: задължително\n    'yes': Да\n"
  },
  {
    "path": "config/locales/simple_form.bn.yml",
    "content": "bn:\n"
  },
  {
    "path": "config/locales/simple_form.ca.yml",
    "content": "---\nca:\n  simple_form:\n    hints:\n      account_warning_preset:\n        text: Pots utilitzar totes les sintaxi com ara URL, etiquetes i mencions\n      admin_account_action:\n        send_email_notification: L'usuari rebrà una explicació del que ha passat amb el seu compte\n        text_html: Opcional. Pots utilitzar tota la sintaxi. Pots <a href=\"%{path}\">afegir configuracions predefinides d'avís</a> per a estalviar temps\n        type_html: Tria què fer amb <strong>%{acct}</strong>\n        warning_preset_id: Opcional. Encara pots afegir text personalitzat al final de la configuració predefinida\n      defaults:\n        autofollow: Les persones que es registrin a través de la invitació et seguiran automàticament\n        avatar: PNG, GIF o JPG. Màxim %{size}. S'escalarà a %{dimensions}px\n        bot: Aquest compte realitza principalment accions automatitzades i pot no estar controlat per cap persona\n        context: Un o diversos contextos on s'ha d'aplicar el filtre\n        digest: Només s'envia després d'un llarg període d'inactivitat amb un resum de les mencions que has rebut en la teva absència\n        discoverable_html: El <a href=\"%{path}\" target=\"_blank\">directori</a> permet trobar usuaris en funció dels interessos i activitat. Requereix almenys %{min_followers} seguidors\n        email: Se t'enviarà un correu electrònic de confirmació\n        fields: Pots tenir fins a 4 elements que es mostren com a taula al teu perfil\n        header: PNG, GIF o JPG. Màxim %{size}. S'escalarà a %{dimensions}px\n        inbox_url: Copia l'URL des de la pàgina principal del relay que vols utilitzar\n        irreversible: Els nodes filtrats desapareixeran de manera irreversible, fins i tot si el filtre es retira més tard\n        locale: El llenguatge de l’interfície d’usuari, els correus i les notificacions push\n        locked: Requereix que aprovis manualment els seguidors\n        password: Utilitza com a mínim 8 caràcters\n        phrase: Es combinarà independentment del format en el text o l'avís de contingut d'un toot\n        scopes: A quines API es permetrà l'accés a l'aplicació. Si selecciones un àmbit d'alt nivell, no cal que seleccionis un d'individual.\n        setting_aggregate_reblogs: No mostra els nous impulsos dels toots que ja s'han impulsat recentment (només afecta als impulsos nous rebuts)\n        setting_default_sensitive: Els mèdia sensibles estan ocults per defecte i es poden revelar amb un clic\n        setting_display_media_default: Amaga els multimèdia marcats com a sensibles\n        setting_display_media_hide_all: Sempre oculta tots els multimèdia\n        setting_display_media_show_all: Mostra sempre els elements multimèdia marcats com a sensibles\n        setting_hide_network: Qui tu segueixes i els que et segueixen a tu no es mostraran en el teu perfil\n        setting_noindex: Afecta el teu perfil públic i les pàgines d'estat\n        setting_show_application: L'aplicació que fas servir per a publicar es mostrarà a la vista detallada dels teus toots\n        username: El teu nom d'usuari serà únic a %{domain}\n        whole_word: Quan la paraula clau o la frase sigui només alfanumèrica, s'aplicarà si coincideix amb la paraula sencera\n      featured_tag:\n        name: 'És possible que vulguis utilitzar un d''aquests:'\n      imports:\n        data: Fitxer CSV exportat des d'un altre servidor de Mastodon\n      invite_request:\n        text: Això ens ajudarà a revisar la teva petició\n      sessions:\n        otp: 'Introdueix el codi de dos factors generat per el teu telèfon o utilitza un dels teus codis de recuperació:'\n      user:\n        chosen_languages: Quan estigui marcat, només es mostraran els toots de les llengües seleccionades en les línies de temps públiques\n    labels:\n      account:\n        fields:\n          name: Etiqueta\n          value: Contingut\n      account_warning_preset:\n        text: Text predefinit\n      admin_account_action:\n        send_email_notification: Notifica l'usuari per correu electrònic\n        text: Avís personalitzat\n        type: Acció\n        types:\n          disable: Inhabilita\n          none: No fer res\n          silence: Silenci\n          suspend: Suspèn i elimina irreversiblement les dades del compte\n        warning_preset_id: Utilitza una configuració predefinida d'avís\n      defaults:\n        autofollow: Convida a seguir el teu compte\n        avatar: Avatar\n        bot: Aquest compte és un bot\n        chosen_languages: Filtrar llengües\n        confirm_new_password: Confirma la contrasenya nova\n        confirm_password: Confirma la contrasenya\n        context: Filtre els contextos\n        current_password: Contrasenya actual\n        data: Informació\n        discoverable: Mostra aquest compte en el directori\n        display_name: Nom visible\n        email: Adreça de correu electrònic\n        expires_in: Expira després\n        fields: Metadades del perfil\n        header: Capçalera\n        inbox_url: URL de la safata d'entrada del relay\n        irreversible: Cau en lloc d'ocultar\n        locale: Llengua de la interfície\n        locked: Fes aquest compte privat\n        max_uses: Nombre màxim d'usos\n        new_password: Contrasenya nova\n        note: Biografia\n        otp_attempt: Codi de dos factors\n        password: Contrasenya\n        phrase: Paraula clau o frase\n        setting_advanced_layout: Activar l’interfície web avançada\n        setting_aggregate_reblogs: Agrupa impulsos en les línies de temps\n        setting_auto_play_gif: Reproducció automàtica de GIFs animats\n        setting_boost_modal: Mostra la finestra de confirmació abans d'impulsar\n        setting_default_language: Llengua de les publicacions\n        setting_default_privacy: Privacitat de les publicacions\n        setting_default_sensitive: Marca sempre els elements multimèdia com a sensibles\n        setting_delete_modal: Mostra la finestra de confirmació abans de suprimir un toot\n        setting_display_media: Visualització multimèdia\n        setting_display_media_default: Per defecte\n        setting_display_media_hide_all: Amaga-ho tot\n        setting_display_media_show_all: Mostra-ho tot\n        setting_expand_spoilers: Sempre amplia els toots marcats amb advertències de contingut\n        setting_hide_network: Amaga la teva xarxa\n        setting_noindex: Desactivació de la indexació del motor de cerca\n        setting_reduce_motion: Redueix el moviment en animacions\n        setting_show_application: Desvela l'aplicació utilitzada per enviar toots\n        setting_system_font_ui: Utilitza el tipus de lletra predeterminat del sistema\n        setting_theme: Tema del lloc\n        setting_unfollow_modal: Mostra el diàleg de confirmació abans de deixar de seguir a algú\n        severity: Severitat\n        type: Importa el tipus\n        username: Nom d'usuari\n        username_or_email: Nom d'usuari o adreça electrònica\n        whole_word: Paraula sencera\n      featured_tag:\n        name: Etiqueta\n      interactions:\n        must_be_follower: Blocar les notificacions de persones que no et segueixen\n        must_be_following: Bloca les notificacions de persones que no segueixes\n        must_be_following_dm: Bloca els missatges directes de persones que no segueixes\n      invite_request:\n        text: Per què vols unir-te?\n      notification_emails:\n        digest: Envia un resum per correu electrònic\n        favourite: Envia un correu electrònic si algú marca com a preferit el teu estat\n        follow: Envia un correu electrònic si algú et segueix\n        follow_request: Envia un correu electrònic si algú sol·licita seguir-te\n        mention: Envia un correu electrònic si algú et menciona\n        pending_account: Envia un correu electrònic quan es necessiti revisar un compte nou\n        reblog: Envia un correu electrònic si algú comparteix el teu estat\n        report: Envia un correu electrònic quan s'enviï un nou informe\n    'no': 'No'\n    recommended: Recomanat\n    required:\n      mark: \"*\"\n      text: necessari\n    'yes': Sí\n"
  },
  {
    "path": "config/locales/simple_form.co.yml",
    "content": "---\nco:\n  simple_form:\n    hints:\n      account_warning_preset:\n        text: Pudete utilizà a sintassa di i statuti, per esempiu l'URL, hashtag, minzione\n      admin_account_action:\n        send_email_notification: L'utilizatore hà da riceve una spiegazione di cio chì hè accadutu à u so contu\n        text_html: In uzzione. Pudete utilizà a sintassa di i statuti. Pudete ancu <a href=\"%{path}\">aghjustà preselezzione d'avertimentu</a> per piglià tempu\n        type_html: Sceglie chì fà cù <strong>%{acct}</strong>\n        warning_preset_id: In uzzione. Pudete sempre aghjustà un testu persunalizatu à a fine di a preselezzione\n      defaults:\n        autofollow: Quelli·e chì s'arregistranu cù l'invitazione saranu autumaticamente abbunati·e à voi\n        avatar: Furmatu PNG, GIF o JPG. %{size} o menu. Sarà ridottu à %{dimensions}px\n        bot: Stu contu hè autumatizatu è ùn hè forse micca survegliatu\n        context: Cuntestu·i induve u filtru deve esse applicatu\n        digest: Solu mandatu dopu à una longa perioda d’inattività, è solu s’elli ci sò novi missaghji diretti\n        discoverable_html: L'<a href=\"%{path}\" target=\"_blank\">annuariu</a> permette à a ghjente di truvà conti à partesi d'interessi è d'attività. Ci vole à avè almenu %{min_followers} abbunati\n        email: Avete da riceve un'e-mail di cunfirmazione\n        fields: Pudete avè fin’à 4 elementi mustrati cum’un tavulone nant’à u vostru prufile\n        header: Furmatu PNG, GIF o JPG. %{size} o menu. Sarà ridottu à %{dimensions}px\n        inbox_url: Cupiate l'URL di a pagina d'accolta di u ripetitore chì vulete utilizà\n        irreversible: I statuti filtrati saranu sguassati di manera irreversibile, ancu s'ellu hè toltu u filtru\n        locale: A lingua di l'interfaccia utilizatore, di l'e-mail è di e nutificazione push\n        locked: Duvarete appruvà e dumande d’abbunamentu\n        password: Ci volenu almenu 8 caratteri\n        phrase: Sarà trovu senza primura di e maiuscule o di l'avertimenti\n        scopes: L'API à quelle l'applicazione averà accessu. S'è voi selezziunate un parametru d'altu livellu, un c'hè micca bisognu di selezziunà quell'individuali.\n        setting_aggregate_reblogs: Ùn mustrà micca e nove spartere per i statuti chì sò stati spartuti da pocu (tocca solu e spartere più ricente)\n        setting_default_sensitive: I media sensibili sò piattati, salvu un cambiamentu di i paramettri, è ponu esse visti cù un cliccu\n        setting_display_media_default: Piattà i media marcati cum'è sensibili\n        setting_display_media_hide_all: Sempre piattà tutti i media\n        setting_display_media_show_all: Sempre affissà i media marcati cum'è sensibili\n        setting_hide_network: I vostri abbunati è abbunamenti ùn saranu micca mustrati nant’à u vostru prufile\n        setting_noindex: Tocca à u vostru prufile pubblicu è i vostri statuti\n        setting_show_application: L'applicazione chì voi utilizate per mandà statuti sarà affissata indè a vista ditagliata di quelli\n        username: U vostru cugnome sarà unicu nant'à %{domain}\n        whole_word: Quandu a parolla o a frasa sana hè alfanumerica, sarà applicata solu s'ella currisponde à a parolla sana\n      featured_tag:\n        name: 'Pudete vulè utilizà unu di quelli:'\n      imports:\n        data: Un fugliale CSV da un’altru servore di Mastodon\n      invite_request:\n        text: Quessu ci aiutarà à valutà a vostra dumanda\n      sessions:\n        otp: 'Entrate u codice d’identificazione à dui fattori nant’à u vostru telefuninu, o unu di i vostri codici di ricuperazione:'\n      user:\n        chosen_languages: Soli i statuti scritti in e lingue selezziunate saranu mustrati indè e linee pubbliche\n    labels:\n      account:\n        fields:\n          name: Marcu\n          value: Cuntinutu\n      account_warning_preset:\n        text: Testu preselezziunatu\n      admin_account_action:\n        send_email_notification: Nutificà l'utilizatore cù un'e-mail\n        text: Avertimentu persunalizatu\n        type: Azzione\n        types:\n          disable: Disattivà\n          none: Ùn fà nunda\n          silence: Silenzà\n          suspend: Suspende è sguassà i dati di u contu di manera irreversibile\n        warning_preset_id: Utilizà un'avertimentu preselezziunatu\n      defaults:\n        autofollow: Invità à siguità u vostru contu\n        avatar: Ritrattu di prufile\n        bot: Stu contu hè un bot\n        chosen_languages: Filtrà lingue\n        confirm_new_password: Cunfirmà a nova chjave d’accessu\n        confirm_password: Cunfirmà a chjave d’accessu\n        context: Cuntesti di u filtru\n        current_password: Chjave d’accessu attuale\n        data: Dati\n        discoverable: Arregistrà stu contu indè l'annuariu\n        display_name: Nome pubblicu\n        email: Indirizzu e-mail\n        expires_in: Spira dopu à\n        fields: Metadata di u prufile\n        header: Ritrattu di cuprendula\n        inbox_url: URL di l'inbox di u ripetitore\n        irreversible: Sguassà invece di piattà\n        locale: Lingua di l'interfaccia\n        locked: Privatizà u contu\n        max_uses: Numeru massimale d’utilizazione\n        new_password: Nova chjave d’accessu\n        note: Descrizzione\n        otp_attempt: Codice d’identificazione à dui fattori\n        password: Chjave d’accessu\n        phrase: Parolla-chjave o frasa\n        setting_advanced_layout: Attivà l'interfaccia web avanzata\n        setting_aggregate_reblogs: Gruppà e spartere indè e linee\n        setting_auto_play_gif: Lettura autumatica di i GIF animati\n        setting_boost_modal: Mustrà una cunfirmazione per sparte un statutu\n        setting_default_language: Lingua di pubblicazione\n        setting_default_privacy: Cunfidenzialità di i statuti\n        setting_default_sensitive: Sempre cunsiderà media cum’è sensibili\n        setting_delete_modal: Mustrà une cunfirmazione per toglie un statutu\n        setting_display_media: Affissera di i media\n        setting_display_media_default: Predefinitu\n        setting_display_media_hide_all: Piattà tuttu\n        setting_display_media_show_all: Affissà tuttu\n        setting_expand_spoilers: Sempre slibrà i statutu marcati cù un'avertimentu CW\n        setting_hide_network: Piattà a vostra rete\n        setting_noindex: Dumandà à i motori di ricerca internet d’un pudè micca esse truvatu·a cusì\n        setting_reduce_motion: Fà chì l’animazione vanu più pianu\n        setting_show_application: Indicà u nome di l'applicazione utilizata per mandà statuti\n        setting_system_font_ui: Pulizza di caratteri di u sistemu\n        setting_theme: Tema di u situ\n        setting_unfollow_modal: Mustrà una cunfirmazione per siguità qualch’unu\n        severity: Severità\n        type: Tippu d’impurtazione\n        username: Cugnome\n        username_or_email: Cugnome o Email\n        whole_word: Parolla sana\n      featured_tag:\n        name: Hashtag\n      interactions:\n        must_be_follower: Piattà e nutificazione di quelli·e ch’ùn vi seguitanu\n        must_be_following: Piattà e nutificazione di quelli·e ch’ùn seguitate\n        must_be_following_dm: Bluccà e missaghji diretti di quelli·e ch’ùn seguitate\n      invite_request:\n        text: Perchè vulete ghjunghje?\n      notification_emails:\n        digest: Mandà e-mail di ricapitulazione\n        favourite: Mandà un’e-mail quandu qualch’unu aghjunghje i mo statuti à i so favuriti\n        follow: Mandà un’e-mail quandu qualch’unu mi seguita\n        follow_request: Mandà un’e-mail quandu qualch’unu vole seguitami\n        mention: Mandà un’e-mail quandu qualch’unu mi mintuva\n        pending_account: Mandà un'e-mail quandu un novu contu hà bisognu d'esse valutatu\n        reblog: Mandà un’e-mail quandu qualch’unu sparte i mo statuti\n        report: Mandà un'e-mail quandu c'hè un novu signalamentu\n    'no': Nò\n    recommended: Ricumandati\n    required:\n      mark: \"*\"\n      text: riquisiti\n    'yes': Ié\n"
  },
  {
    "path": "config/locales/simple_form.cs.yml",
    "content": "---\ncs:\n  simple_form:\n    hints:\n      account_warning_preset:\n        text: Můžete používat syntaxi tootů, jako například URL, hashtagy a zmínky\n      admin_account_action:\n        send_email_notification: Uživatel obdrží vysvětlení toho, co se stalo s jeho účtem\n        text_html: Volitelné. Můžete používat syntaxi tootů. Pro ušetření času si můžete <a href=\"%{path}\">přidat předlohy pro varování</a>\n        type_html: Vyberte, co chcete udělat s účtem <strong>%{acct}</strong>\n        warning_preset_id: Volitelné. Můžete stále vložit na konec předlohy vlastní text\n      defaults:\n        autofollow: Lidé, kteří se zaregistrují přes pozvání, vás budou automaticky sledovat\n        avatar: PNG, GIF či JPG. Maximálně %{size}. Bude zmenšen na %{dimensions} px\n        bot: Tento účet provádí hlavně automatizované akce a nemusí být spravován\n        context: Jeden či více kontextů, ve kterých má být filtr uplatněn\n        digest: Odesíláno pouze po dlouhé době nečinnosti a pouze, pokud jste při své nepřítomnosti obdržel/a osobní zprávy\n        discoverable_html: <a href=\"%{path}\" target=\"_blank\">Adresář</a> dovoluje lidem najít účty podle zájmů a aktivity. Vyžaduje alespoň %{min_followers} sledujících\n        email: Bude vám poslán potvrzovací e-mail\n        fields: Na profilu můžete mít až 4 položky zobrazené jako tabulka\n        header: PNG, GIF či JPG. Maximálně %{size}. Bude zmenšen na %{dimensions} px\n        inbox_url: Zkopírujte URL z hlavní stránky mostu, který chcete použít\n        irreversible: Filtrované tooty nenávratně zmizí, i pokud bude filtr později odstraněn\n        locale: Jazyk uživatelského rozhraní, e-mailů a oznámení push\n        locked: Vyžaduje, abyste ručně schvaloval/a sledující\n        password: Použijte alespoň 8 znaků\n        phrase: Shoda bude nalezena bez ohledu na velikost písmen v těle tootu či varování o obsahu\n        scopes: Která API bude aplikaci povoleno používat. Pokud vyberete rozsah nejvyššího stupně, nebudete je muset vybírat jednotlivě.\n        setting_aggregate_reblogs: Nezobrazovat nové boosty pro tooty, které byly nedávno boostnuty (ovlivňuje pouze nově přijaté boosty)\n        setting_default_sensitive: Citlivá média jsou ve výchozím stavu skryta a mohou být zobrazena kliknutím\n        setting_display_media_default: Skrývat média označená jako citlivá\n        setting_display_media_hide_all: Vždy skrývat všechna média\n        setting_display_media_show_all: Vždy zobrazovat média označená jako citlivá\n        setting_hide_network: Koho sledujete a kdo sleduje vás nebude zobrazeno na vašem profilu\n        setting_noindex: Ovlivňuje váš veřejný profil a stránky tootů\n        setting_show_application: Aplikace, kterou používáte k psaní tootů, bude zobrazena v detailním zobrazení vašich tootů\n        username: Vaše uživatelské jméno bude na %{domain} unikátní\n        whole_word: Je-li klíčové slovo či fráze pouze alfanumerická, bude aplikována pouze, pokud se shoduje s celým slovem\n      featured_tag:\n        name: 'Nejspíš budete chtít použít jeden z těchto:'\n      imports:\n        data: Soubor CSV exportovaný z jiného serveru Mastodon\n      invite_request:\n        text: To nám pomůže posoudit váš požadavek\n      sessions:\n        otp: 'Napište dvoufázový kód vygenerovaný vaší mobilní aplikací, nebo použijte jeden z vašich záložních kódů:'\n      user:\n        chosen_languages: Je-li tohle zaškrtnuto, budou ve veřejných časových osách zobrazeny pouze tooty ve zvolených jazycích\n    labels:\n      account:\n        fields:\n          name: Označení\n          value: Obsah\n      account_warning_preset:\n        text: Text předlohy\n      admin_account_action:\n        send_email_notification: Informovat uživatele e-mailem\n        text: Vlastní varování\n        type: Akce\n        types:\n          disable: Deaktivovat\n          none: Nic nedělat\n          silence: Utišit\n          suspend: Pozastavit a nenávratně smazat data účtu\n        warning_preset_id: Použít předlohu pro varování\n      defaults:\n        autofollow: Pozvat ke sledování vašeho účtu\n        avatar: Avatar\n        bot: Tohle je účet robota\n        chosen_languages: Filtrovat jazyky\n        confirm_new_password: Potvrďte nové heslo\n        confirm_password: Potvrdit heslo\n        context: Kontexty filtrů\n        current_password: Současné heslo\n        data: Data\n        discoverable: Zveřejnit tento účet v adresáři\n        display_name: Zobrazované jméno\n        email: E-mailová adresa\n        expires_in: Vypršet za\n        fields: Metadata profilu\n        header: Záhlaví\n        inbox_url: URL příchozí schránky mostu\n        irreversible: Zahodit místo skrytí\n        locale: Jazyk rozhraní\n        locked: Uzamknout účet\n        max_uses: Maximální počet použití\n        new_password: Nové heslo\n        note: O vás\n        otp_attempt: Dvoufázový kód\n        password: Heslo\n        phrase: Klíčové slovo či fráze\n        setting_advanced_layout: Povolit pokročilé webové rozhraní\n        setting_aggregate_reblogs: Seskupovat boosty v časových osách\n        setting_auto_play_gif: Automaticky přehrávat animace GIF\n        setting_boost_modal: Zobrazovat před boostnutím potvrzovací okno\n        setting_default_language: Jazyk příspěvků\n        setting_default_privacy: Soukromí příspěvků\n        setting_default_sensitive: Vždy označovat média jako citlivá\n        setting_delete_modal: Zobrazovat před smazáním tootu potvrzovací okno\n        setting_display_media: Zobrazování médií\n        setting_display_media_default: Výchozí\n        setting_display_media_hide_all: Skrýt vše\n        setting_display_media_show_all: Zobrazit vše\n        setting_expand_spoilers: Vždy rozbalit tooty označené varováními o obsahu\n        setting_hide_network: Skrýt svou síť\n        setting_noindex: Neindexovat svůj profil vyhledávači\n        setting_reduce_motion: Redukovat pohyb v animacích\n        setting_show_application: Zobrazit aplikaci používanou k psaní tootů\n        setting_system_font_ui: Použít výchozí písmo systému\n        setting_theme: Motiv stránky\n        setting_unfollow_modal: Zobrazovat před zrušením sledování potvrzovací okno\n        severity: Přísnost\n        type: Typ importu\n        username: Uživatelské jméno\n        username_or_email: Uživatelské jméno nebo e-mail\n        whole_word: Celé slovo\n      featured_tag:\n        name: Hashtag\n      interactions:\n        must_be_follower: Blokovat oznámení od lidí, kteří vás nesledují\n        must_be_following: Blokovat oznámení od lidí, které nesledujete\n        must_be_following_dm: Blokovat přímé zprávy od lidí, které nesledujete\n      invite_request:\n        text: Proč se chcete připojit?\n      notification_emails:\n        digest: Posílat e-maily s přehledem\n        favourite: Posílat e-maily, když si někdo oblíbí váš toot\n        follow: Posílat e-maily, když vás někdo začne sledovat\n        follow_request: Posílat e-maily, když vás někdo požádá o sledování\n        mention: Posílat e-maily, když vás někdo zmíní\n        pending_account: Posílat e-maily, když je třeba posoudit nový účet\n        reblog: Posílat e-maily, když někdo boostne váš toot\n        report: Posílat e-maily, je-li odesláno nové nahlášení\n    'no': Ne\n    recommended: Doporučeno\n    required:\n      mark: \"*\"\n      text: požadováno\n    'yes': Ano\n"
  },
  {
    "path": "config/locales/simple_form.cy.yml",
    "content": "---\ncy:\n  simple_form:\n    hints:\n      defaults:\n        autofollow: Bydd pobl sy'n cofrestru drwy'r gwahoddiad yn eich dilyn yn awtomatig\n        avatar: PNG, GIF neu JPG. %{size} ar y mwyaf. Caiff ei israddio i %{dimensions}px\n        bot: Mae'r cyfrif hwn yn perfformio gweithredoedd awtomatig yn bennaf ac mae'n bosib nad yw'n cael ei fonitro\n        context: Un neu fwy cyd-destun lle dylai'r hidlydd weithio\n        digest: Ond yn cael eu hanfon ar ôl cyfnod hir o anweithgarwch ac ond os ydych wedi derbyn unrhyw negeseuon personol yn eich absenoldeb\n        email: Byddwch yn derbyn e-bost i gadarnhau\n        fields: Mae modd i chi arddangos hyd at 4 eitem fel tabl ar eich proffil\n        header: PNG, GIF neu JPG. %{size} ar y mwyaf. Ceith ei israddio i %{dimensions}px\n        inbox_url: Copïwch yr URL o dudalen flaen y relái yr ydych am ei ddefnyddio\n        irreversible: Bydd tŵtiau wedi eu hidlo yn diflannu am byth, hyd yn oed os ceith yr hidlydd ei ddileu'n hwyrach\n        locale: Iaith y rhyngwyneb, e-byst a hysbysiadau push\n        locked: Ei wneud yn ofynnol i chi i ganiatau dilynwyr a llaw\n        password: Defnyddiwch oleiaf 8 nodyn\n        phrase: Caiff ei gyfateb heb ystyriaeth o briflythrennu mewn testun neu rhybudd ynghylch cynnwys tŵt\n        scopes: Pa APIau y bydd gan y rhaglen ganiatad i gael mynediad iddynt. Os dewiswch maes lefel uchaf, yna nid oes angen dewis rhai unigol.\n        setting_display_media_default: Cuddio cyfryngau wedi eu marcio'n sensitif\n        setting_display_media_hide_all: Cuddio cyfryngau bob tro\n        setting_display_media_show_all: Dangos cyfryngau wedi eu marcio'n sensitif bob tro\n        setting_hide_network: Ni fydd y rheini yr ydych yn eu dilyn a phwy sy'n eich dilyn chi yn cael ei ddangos ar eich proffil\n        setting_noindex: Mae hyn yn effeithio ar eich proffil cyhoeddus a'ch tudalennau statws\n        username: Bydd eich enw defnyddiwr yn unigryw ar %{domain}\n        whole_word: Os yw'r allweddair neu'r ymadrodd yn alffaniwmerig yn unig, mi fydd ond yn cael ei osod os yw'n cyfateb a'r gair cyfan\n      imports:\n        data: Allforiwyd dogfen CSV o achos Mastodon arall\n      sessions:\n        otp: 'Mewnbynnwch y cod dau gam a gynhyrchwyd gan eich ap ffôn neu defnyddiwch un o''ch codau adfer:'\n      user:\n        chosen_languages: Wedi eu dewis, dim ond tŵtiau yn yr ieithoedd hyn bydd yn cael eu harddangos mewn ffrydiau cyhoeddus\n    labels:\n      account:\n        fields:\n          value: Cynnwys\n      account_warning_preset:\n        text: Testun rhagosodedig\n      admin_account_action:\n        send_email_notification: Hysbysu'r defnyddiwr trwy e-bost\n        text: Rhybudd wedi'i addasu\n        type: Gweithredu\n        types:\n          disable: Analluogi\n          none: Gwneud dim\n          silence: Tawelwch\n          suspend: Dileu data cyfrif\n        warning_preset_id: Defnyddiwch ragnod rhag rhybudd\n      defaults:\n        autofollow: Gwahodd i ddilyn eich cyfrif\n        avatar: Afatar\n        bot: Cyfrif bot yw hwn\n        chosen_languages: Hidlo ieithoedd\n        confirm_new_password: Cadarnhau cyfrinair newydd\n        confirm_password: Cadarnhau cyfrinair\n        context: Hidlo cyd-destunau\n        current_password: Cyfrinair presennol\n        discoverable: Rhestrwch y cyfrif hwn ar y cyfeiriadur\n        display_name: Enw arddangos\n        email: Cyfeiriad e-bost\n        expires_in: Yn dod i ben ar ôl\n        fields: Metadata proffil\n        header: Pennyn\n        inbox_url: URL y mewnflwch relái\n        irreversible: Gollwng yn hytrach na chuddio\n        locale: Iaith y rhyngwyneb\n        locked: Cloi cyfrif\n        max_uses: Uchafswm y nifer o ddefnyddiau\n        new_password: Cyfrinair newydd\n        note: Bywgraffiad\n        otp_attempt: Côd dau gam\n        password: Cyfrinair\n        phrase: Allweddair neu ymadrodd\n        setting_aggregate_reblogs: Grŵp hybiau mewn ffrydiau\n        setting_auto_play_gif: Chwarae GIFs wedi'u hanimeiddio yn awtomatig\n        setting_boost_modal: Dangos deialog cadarnhad cyn bŵstio\n        setting_default_language: Cyhoeddi iaith\n        setting_default_privacy: Cyfrinachedd cyhoeddi\n        setting_default_sensitive: Marcio cyfryngau fel eu bod yn sensitif bob tro\n        setting_delete_modal: Dangos deialog cadarnhau cyn dileu tŵt\n        setting_display_media: Arddangos cyfryngau\n        setting_display_media_default: Rhagosodiad\n        setting_display_media_hide_all: Cuddio oll\n        setting_display_media_show_all: Dangos oll\n        setting_expand_spoilers: Ymestyn tŵtiau wedi'u marcio a rhybudd cynnwys bob tro\n        setting_hide_network: Cuddio eich rhwydwaith\n        setting_noindex: Dewis peidio mynegeio peiriant chwilota\n        setting_reduce_motion: Lleihau mudiant mewn animeiddiadau\n        setting_system_font_ui: Defnyddio ffont rhagosodedig y system\n        setting_theme: Thema'r wefan\n        setting_unfollow_modal: Dangos deialog cadarnhau cyn dad-ddilyn rhywun\n        severity: Difrifoldeb\n        type: Modd mewnforio\n        username: Enw defnyddiwr\n        username_or_email: Enw defnyddiwr neu e-bost\n        whole_word: Gair cyfan\n      interactions:\n        must_be_follower: Blocio hysbysiadau o bobl nad ydynt yn eich dilyn\n        must_be_following: Blocio hysbysiadau o bobl nad ydych yn eu dilyn\n        must_be_following_dm: Blocio negeseuon uniongyrchol o bobl nad ydych yn eu dilyn\n      notification_emails:\n        digest: Anfonwch e-byst crynhoi\n        favourite: Anfon e-bost pan mae rhywun yn ffefrynnu eich statws\n        follow: Anfon e-bost pan mae rhywun yn eich dilyn chi\n        follow_request: Anfon e-bost pan mae rhywun yn gofyn i chi i'w dilyn\n        mention: Anfon e-bost pan mae rhywun yn eich crybwyll\n        reblog: Anfon e-bost pan mae rhywun yn bŵstio eich statws\n        report: Anfon e-bost pan y cyflwynir adroddiad newydd\n    'no': Na\n    required:\n      text: gofynnol\n    'yes': Ie\n"
  },
  {
    "path": "config/locales/simple_form.da.yml",
    "content": "---\nda:\n  simple_form:\n    hints:\n      admin_account_action:\n        type_html: Vælg hvad du vil gøre med <strong>%{acct}</strong>\n      defaults:\n        autofollow: Folk der har oprettet sig gennem invitationen vil automatisk følge dig\n        avatar: PNG, GIF eller JPG. Højest %{size}. Vil blive skaleret ned til %{dimensions}px\n        bot: Denne konto udfører hovedsageligt automatiserede handlinger og bliver muligvis ikke overvåget\n        context: En eller flere sammenhænge hvor filteret skal være gældende\n        digest: Sendes kun efter en lang periode med inaktivitet og kun hvis du har modtaget nogle personlige beskeder mens du er væk\n        email: Du vil få tilsendt en bekræftelsed mail\n        fields: Du kan have op til 4 ting vist som en tabel på din profil\n        header: PNG, GIF eller JPG. Højest %{size}. Vil blive skaleret ned til %{dimensions}px\n        inbox_url: Kopiere linket fra forsiden af den relay som du ønsker at bruge\n        irreversible: Filtrerede trut vil forsvinde fulstændigt, selv hvis filteret senere skulle blive fjernet\n        locale: Sproget på interfacet, emails og push beskeder\n        locked: Kræver, at du godkender følgere manuelt\n        password: Brug mindst 8 tegn\n        phrase: Vil blive parret uanset om der er store eller små bogstaver i teksten eller om der er en advarsel om et trut\n        scopes: Hvilke APIs applikationen vil få adgang til. Hvis du vælger et højtlevel omfang, behøver du ikke vælge enkeltstående.\n        setting_display_media_default: Skjul medier markeret som følsomt\n        setting_display_media_hide_all: Skjul altid alle medier\n        setting_hide_network: Hvem du følger og hvem der følger dig vil ikke blive vist på din profil\n        setting_noindex: Påvirker din offentlige profil og status sider\n        username: Dit brugernavn vil være unikt på %{domain}\n        whole_word: Når nøgle ordet eller udtrykket kun er alfanumerisk, vil det kun blive brugt hvis det passer hele ordet\n      imports:\n        data: CSV fil eksporteret fra en anden Mastodon server\n      sessions:\n        otp: 'Indtast to-faktor koden der generes af appen af appen på din telefon eller brug en af din genoprettelses koder:'\n      user:\n        chosen_languages: Når markeret, vil kun trut i de valgte sprog blive vist på offentlige tidslinjer\n    labels:\n      account:\n        fields:\n          name: Etiket\n          value: Indhold\n      admin_account_action:\n        type: Handling\n        types:\n          disable: Deaktiver\n          none: Gør intet\n      defaults:\n        autofollow: Inviter til at følge din konto\n        avatar: Profilbillede\n        bot: Dette er en robot konto\n        chosen_languages: Filtrer sprog\n        confirm_new_password: Bekræft din nye adgangskode\n        confirm_password: Bekræft adgangskode\n        context: Filtrer sammenhænge\n        current_password: Nuværende adgangskode\n        display_name: Visningsnavn\n        email: E-mail adresse\n        expires_in: Udløber efter\n        fields: Profil metadata\n        header: Overskrift\n        inbox_url: Link til relay indbakken\n        irreversible: Ignorer istedet for at skjule\n        locale: Sprog på interface\n        locked: Lås konto\n        max_uses: Højeste antal benyttelser\n        new_password: Ny adgangskode\n        note: Biografi\n        otp_attempt: To-faktor kode\n        password: Adgangskode\n        phrase: Nøgleord eller sætning\n        setting_auto_play_gif: Afspil automatisk animerede GIFs\n        setting_boost_modal: Vis bekræftelses dialog før du fremhæver\n        setting_default_language: Sprog for opslag\n        setting_default_privacy: Privatliv\n        setting_default_sensitive: Marker altid medier som værende følsomt\n        setting_delete_modal: Vis bekræftelses dialog før du sletter et trut\n        setting_display_media: Visning af medier\n        setting_display_media_default: Standard\n        setting_display_media_hide_all: Skjul alle\n        setting_display_media_show_all: Vis alle\n        setting_expand_spoilers: Udvid altid trut der er markeret med indholdsadvarsler\n        setting_hide_network: Skjul dit netværk\n        setting_noindex: Frameld dig søgemaskiners indeksering\n        setting_reduce_motion: Reducer animationers bevægelse\n        setting_system_font_ui: Brug systemets standard font\n        setting_theme: Tema for side\n        setting_unfollow_modal: Vis bekræftelses dialog før du stopper med at følge nogen\n        severity: Omfang\n        type: Importtype\n        username: Brugernavn\n        username_or_email: Brugernavn eller Email\n        whole_word: Helt ord\n      interactions:\n        must_be_follower: Bloker notifikationer fra folk der ikke følger dig\n        must_be_following: Bloker notifikationer fra folk du ikke følger\n        must_be_following_dm: Bloker direkte beskeder fra folk du ikke følger\n      notification_emails:\n        digest: Send sammendrag via emails\n        favourite: Send email når nogen favoriserer din status\n        follow: Send e-mail når nogen følger dig\n        follow_request: Send email når nogen anmoder om at følge dig\n        mention: Send e-mail når nogen nævner dig\n        reblog: Send email når nogen fremhæver din status\n        report: Send email når en ny anmeldelse bliver indsendt\n    'no': Nej\n    required:\n      text: påkrævet\n    'yes': Ja\n"
  },
  {
    "path": "config/locales/simple_form.de.yml",
    "content": "---\nde:\n  simple_form:\n    hints:\n      account_warning_preset:\n        text: Du kannst Beitragssyntax benutzen, wie z.B. URLs, Hashtags und Erwähnungen\n      admin_account_action:\n        send_email_notification: Benutzer_in wird Bescheid gegeben, was mit dem Konto geschehen ist\n        text_html: Optional. Du kannst Beitragssyntax nutzen. Du kannst <a href=\"%{path}\">Warnungsvorlagen</a> benutzen um Zeit zu sparen\n        type_html: Wähle aus, was du mit <strong>%{acct}</strong> machen möchtest\n        warning_preset_id: Optional. Du kannst immer noch eigenen Text an das Ende der Vorlage hinzufügen\n      defaults:\n        autofollow: Leute, die sich über deine Einladung registrieren, werden dir automatisch folgen\n        avatar: PNG, GIF oder JPG. Maximal %{size}. Wird auf %{dimensions} px herunterskaliert\n        bot: Dieses Konto führt lediglich automatisierte Aktionen durch und wird möglicherweise nicht überwacht\n        context: Ein oder mehrere Kontexte, wo der Filter aktiv werden soll\n        digest: Wenn du eine lange Zeit inaktiv bist, wird dir eine Zusammenfassung von Erwähnungen zugeschickt, die du in deiner Abwesenheit empfangen hast\n        discoverable_html: Das <a href=\"%{path}\" target=\"_blank\">Verzeichnis</a> erlaubt es dein Profil durch deine Hashtags und deine Aktivitäten zu entdecken. Voraussetzung ist allerdings mindestens %{min_followers} Folger_innen\n        email: Du wirst eine Bestätigungs-E-Mail erhalten\n        fields: Du kannst bis zu 4 Elemente auf deinem Profil anzeigen lassen, die als Tabelle dargestellt werden\n        header: PNG, GIF oder JPG. Maximal %{size}. Wird auf %{dimensions} px herunterskaliert\n        inbox_url: Kopiere die URL von der Startseite des gewünschten Relays\n        irreversible: Gefilterte Beiträge werden unwiderruflich gelöscht, selbst wenn der Filter später entfernt wird\n        locale: Die Sprache der Oberfläche, E-Mails und Push-Benachrichtigungen\n        locked: Wer dir folgen möchte, muss um deine Erlaubnis bitten\n        password: Verwende mindestens 8 Zeichen\n        phrase: Wird schreibungsunabhängig mit dem Text und Inhaltswarnung eines Beitrags verglichen\n        scopes: Welche Schnittstellen der Applikation erlaubt sind. Wenn du einen Top-Level-Scope auswählst, dann musst du nicht jeden einzelnen darunter auswählen.\n        setting_aggregate_reblogs: Zeige denselben Beitrag nicht nochmal an, wenn er erneut geteilt wurde (dies betrifft nur neulich erhaltene erneut geteilte Beiträge)\n        setting_default_sensitive: Heikle Medien werden erst nach einem Klick sichtbar\n        setting_display_media_default: Verstecke Medien, die als sensibel markiert sind\n        setting_display_media_hide_all: Alle Medien immer verstecken\n        setting_display_media_show_all: Medien, die als sensibel markiert sind, immer anzeigen\n        setting_hide_network: Wem du folgst und wer dir folgt, wird in deinem Profil nicht angezeigt\n        setting_noindex: Betrifft dein öffentliches Profil und deine Beiträge\n        setting_show_application: Die Anwendung die du nutzst wird in der detaillierten Ansicht deiner Beiträge angezeigt\n        username: Dein Profilname wird auf %{domain} einzigartig sein\n        whole_word: Wenn das Schlagwort nur aus Buchstaben und Zahlen besteht, wird es nur angewendet, wenn es dem ganzen Wort entspricht\n      featured_tag:\n        name: 'Du möchtest vielleicht einen von diesen benutzen:'\n      imports:\n        data: CSV-Datei, die aus einem anderen Mastodon-Server exportiert wurde\n      invite_request:\n        text: Dies wird uns helfen deine Anmeldungsanfrage besser zu verarbeiten\n      sessions:\n        otp: 'Gib die Zwei-Faktor-Authentifizierung von deinem Telefon ein oder benutze einen deiner Wiederherstellungscodes:'\n      user:\n        chosen_languages: Wenn aktiviert, werden nur Beiträge in den ausgewählten Sprachen auf den öffentlichen Zeitleisten angezeigt\n    labels:\n      account:\n        fields:\n          name: Bezeichnung\n          value: Inhalt\n      account_warning_preset:\n        text: Vorlagentext\n      admin_account_action:\n        send_email_notification: Benachrichtige den Nutzer per E-Mail\n        text: Eigene Warnung\n        type: Aktion\n        types:\n          disable: Deaktivieren\n          none: Nichts tun\n          silence: Stummschalten\n          suspend: Deaktivieren und Benutzerdaten unwiderruflich löschen\n        warning_preset_id: Benutze eine Warnungsvorlage\n      defaults:\n        autofollow: Eingeladene Nutzer_innen sollen dir automatisch folgen\n        avatar: Profilbild\n        bot: Dieses Profil ist ein Bot\n        chosen_languages: Sprachen filtern\n        confirm_new_password: Neues Passwort bestätigen\n        confirm_password: Passwort bestätigen\n        context: In Kontexten filtern\n        current_password: Derzeitiges Passwort\n        data: Daten\n        discoverable: Dieses Profil im Profilverzeichnis zeigen\n        display_name: Anzeigename\n        email: E-Mail-Adresse\n        expires_in: Läuft ab\n        fields: Tabellenfelder\n        header: Titelbild\n        inbox_url: Inbox-URL des Relais\n        irreversible: Verwerfen statt verstecken\n        locale: Sprache der Benutzeroberfläche\n        locked: Profil sperren\n        max_uses: Maximale Verwendungen\n        new_password: Neues Passwort\n        note: Über mich\n        otp_attempt: Zwei-Faktor-Authentifizierung\n        password: Passwort\n        phrase: Schlagwort oder Satz\n        setting_advanced_layout: Fortgeschrittene Benutzeroberfläche benutzen\n        setting_aggregate_reblogs: Gruppiere erneut geteilte Beiträge auf der Startseite\n        setting_auto_play_gif: Animierte GIFs automatisch abspielen\n        setting_boost_modal: Bestätigungsdialog anzeigen, bevor ein Beitrag geteilt wird\n        setting_default_language: Beitragssprache\n        setting_default_privacy: Beitragssichtbarkeit\n        setting_default_sensitive: Medien immer als heikel markieren\n        setting_delete_modal: Bestätigungsdialog anzeigen, bevor ein Beitrag gelöscht wird\n        setting_display_media: Medien-Anzeige\n        setting_display_media_default: Heikle Inhalte verstecken\n        setting_display_media_hide_all: Alle Medien verstecken\n        setting_display_media_show_all: Alle Medien anzeigen\n        setting_expand_spoilers: Beiträge mit Inhaltswarnungen immer ausklappen\n        setting_hide_network: Netzwerk ausblenden\n        setting_noindex: Suchmaschinen-Indexierung verhindern\n        setting_reduce_motion: Bewegung in Animationen verringern\n        setting_show_application: Anwendung preisgeben, die benutzt wurde um Beiträge zu versenden\n        setting_system_font_ui: Standardschriftart des Systems verwenden\n        setting_theme: Theme\n        setting_unfollow_modal: Bestätigungsdialog anzeigen, bevor jemandem entfolgt wird\n        severity: Schweregrad\n        type: Art des Imports\n        username: Profilname\n        username_or_email: Profilname oder E-Mail\n        whole_word: Ganzes Wort\n      featured_tag:\n        name: Hashtag\n      interactions:\n        must_be_follower: Benachrichtigungen von Profilen blockieren, die mir nicht folgen\n        must_be_following: Benachrichtigungen von Profilen blockieren, denen ich nicht folge\n        must_be_following_dm: Private Nachrichten von Profilen, denen ich nicht folge, blockieren\n      invite_request:\n        text: Warum möchtest du beitreten?\n      notification_emails:\n        digest: Kurzfassungen über E-Mail senden\n        favourite: E-Mail senden, wenn jemand meinen Beitrag favorisiert\n        follow: E-Mail senden, wenn mir jemand folgt\n        follow_request: E-Mail senden, wenn mir jemand folgen möchte\n        mention: E-Mail senden, wenn mich jemand erwähnt\n        pending_account: E-Mail senden, wenn ein neues Benutzerkonto zur Überprüfung aussteht\n        reblog: E-Mail senden, wenn jemand meinen Beitrag teilt\n        report: E-Mail senden, wenn ein neuer Bericht vorliegt\n    'no': Nein\n    recommended: Empfohlen\n    required:\n      mark: \"*\"\n      text: Pflichtfeld\n    'yes': Ja\n"
  },
  {
    "path": "config/locales/simple_form.el.yml",
    "content": "---\nel:\n  simple_form:\n    hints:\n      account_warning_preset:\n        text: Μπορεις να χρησιμοποιήσεις συντακτικό ενός τουτ όπως διευθύνσεις URL, ταμπέλες και αναφορές\n      admin_account_action:\n        send_email_notification: Ο χρήστης θα λάβει μια εξήγηση του τι συνέβη με τον λογαριασμό του\n        text_html: Προαιρετικό. Μπορείς να χρησιμοποιήσεις συντακτικό ενός τουτ. Μπορείς να <a href=\"%{path}\">ορίσεις προκαθορισμένες προειδοποιήσεις</a> για να γλυτώσεις χρόνο\n        type_html: Διάλεξε τι θα κανείς με τον  <strong>%{acct}</strong>\n        warning_preset_id: Προαιρετικό. Μπορείς να προσθέσεις επιπλέον κείμενο μετά το προκαθορισμένο κείμενο\n      defaults:\n        autofollow: Όσοι εγγραφούν μέσω της πρόσκλησης θα σε ακολουθούν αυτόματα\n        avatar: PNG, GIF ή JPG. Έως %{size}. Θα περιοριστεί σε διάσταση %{dimensions}px\n        bot: Ο λογαριασμός αυτός εκτελεί κυρίως αυτοματοποιημένες ενέργειες και ίσως να μην παρακολουθείται\n        context: Ένα ή περισσότερα πλαίσια στα οποία μπορεί να εφαρμόζεται αυτό το φίλτρο\n        digest: Αποστέλλεται μόνο μετά από μακρά περίοδο αδράνειας και μόνο αν έχεις λάβει προσωπικά μηνύματα κατά την απουσία σου\n        discoverable_html: \"Ο <a href=\\\"%{path}\\\" target=\\\"_blank\\\">κατάλογος</a> \\nσου επιτρέπει να βρεις λογαριασμούς βάσει ενδιαφερόντων και δραστηριότητας. Απαιτεί τουλάχιστον %{min_followers} ακόλουθους\"\n        email: Θα σου σταλεί email επιβεβαίωσης\n        fields: Μπορείς να έχεις έως 4 σημειώσεις σε μορφή πίνακα στο προφίλ σου\n        header: PNG, GIF ή JPG. Έως %{size}. Θα περιοριστεί σε διάσταση %{dimensions}px\n        inbox_url: Αντέγραψε το URL της αρχικής σελίδας του ανταποκριτή (relay) που θέλεις να χρησιμοποιήσεις\n        irreversible: Τα φιλτραρισμένα τουτ θα εξαφανιστούν αμετάκλητα, ακόμα και αν το φίλτρο αργότερα αφαιρεθεί\n        locale: Η γλώσσα του περιβάλλοντος χρήσης, των email και των ειδοποιήσεων ώθησης\n        locked: Απαιτεί να εγκρίνεις χειροκίνητα τους ακόλουθούς σου\n        password: Χρησιμοποίησε τουλάχιστον 8 χαρακτήρες\n        phrase: Θα ταιριάζει ανεξαρτήτως πεζών/κεφαλαίων ή προειδοποίησης περιεχομένου του τουτ\n        scopes: Ποια API θα επιτρέπεται στην εφαρμογή να χρησιμοποιήσεις. Αν επιλέξεις κάποιο υψηλό εύρος εφαρμογής, δε χρειάζεται να επιλέξεις και εξειδικευμένα.\n        setting_aggregate_reblogs: Απόκρυψη των νέων προωθήσεωνγια τα τουτ που έχουν προωθηθεί πρόσφατα (επηρεάζει μόνο τις νέες προωθήσεις)\n        setting_default_sensitive: Τα ευαίσθητα πολυμέσα είναι κρυμμένα και εμφανίζονται με ένα κλικ\n        setting_display_media_default: Απόκρυψη ευαίσθητων πολυμέσων\n        setting_display_media_hide_all: Μόνιμη απόκρυψη όλων των πολυμέσων\n        setting_display_media_show_all: Μόνιμη εμφάνιση ευαίσθητων πολυμέσων\n        setting_hide_network: Δε θα εμφανίζεται στο προφίλ σου ποιους ακολουθείς και ποιοι σε ακολουθούν\n        setting_noindex: Επηρεάζει το δημόσιο προφίλ και τις δημοσιεύσεις σου\n        setting_show_application: Η εφαρμογή που χρησιμοποιείς για να στέλνεις τα τουτ σου θα εμφανίζεται στις αναλυτικές λεπτομέρειες τους\n        username: Το όνομα χρήστη σου θα είναι μοναδικό στο %{domain}\n        whole_word: Όταν η λέξη ή η φράση κλειδί είναι μόνο αλφαριθμητική, θα εφαρμοστεί μόνο αν ταιριάζει με ολόκληρη τη λέξη\n      featured_tag:\n        name: 'Ίσως να θες να χρησιμοποιήσεις μια από αυτές:'\n      imports:\n        data: Αρχείο CSV που έχει εξαχθεί από διαφορετικό κόμβο Mastodon\n      invite_request:\n        text: Αυτό θα μας βοηθήσει να επιθεωρήσουμε την αίτησή σου\n      sessions:\n        otp: 'Βάλε τον κωδικό δυο παραγόντων (2FA) από την εφαρμογή του τηλεφώνου σου ή χρησιμοποίησε κάποιον από τους κωδικούς ανάκτησης σου:'\n      user:\n        chosen_languages: Όταν ενεργοποιηθεί, στη δημόσια ροή θα εμφανίζονται τουτ μόνο από τις επιλεγμένες γλώσσες\n    labels:\n      account:\n        fields:\n          name: Ταμπέλα\n          value: Περιεχόμενο\n      account_warning_preset:\n        text: Προκαθορισμένο κείμενο\n      admin_account_action:\n        send_email_notification: Ενημέρωση χρήστη μέσω email\n        text: Προσαρμοσμένη προειδοποίηση\n        type: Ενέργεια\n        types:\n          disable: Απενεργοποίηση\n          none: Καμία ενέργεια\n          silence: Αποσιώπηση\n          suspend: Αναστολή και αμετάκλητη διαγραφή στοιχείων λογαριασμού\n        warning_preset_id: Χρήση προκαθορισμένης προειδοποίησης\n      defaults:\n        autofollow: Προσκάλεσε για να ακολουθήσουν το λογαριασμό σου\n        avatar: Αβατάρ\n        bot: Αυτός είναι ένας αυτοματοποιημένος λογαριασμός (bot)\n        chosen_languages: Φίλτραρε γλώσσες\n        confirm_new_password: Επιβεβαίωσε νέο συνθηματικό\n        confirm_password: Επιβεβαίωσε συνθηματικό\n        context: Πλαίσια φιλτραρίσματος\n        current_password: Τρέχον συνθηματικό\n        data: Δεδομένα\n        discoverable: Εμφάνιση αυτού του λογαριασμού στον κατάλογο\n        display_name: Όνομα εμφάνισης\n        email: Διεύθυνση email\n        expires_in: Λήξη μετά από\n        fields: Μετεδεδομένα προφίλ\n        header: Επικεφαλίδα\n        inbox_url: Το URL του inbox του ανταποκριτή (relay)\n        irreversible: Απόρριψη αντί για κρύψιμο\n        locale: Γλώσσα περιβάλλοντος\n        locked: Κλείδωμα λογαριασμού\n        max_uses: Μέγιστος αριθμός χρήσεων\n        new_password: Νέο συνθηματικό\n        note: Βιογραφικό\n        otp_attempt: Κωδικός δυο παραγόντων\n        password: Συνθηματικό\n        phrase: Λέξη ή φράση κλειδί\n        setting_advanced_layout: Ενεργοποίηση προηγμένης λειτουργίας χρήσης\n        setting_aggregate_reblogs: Ομαδοποίηση προωθήσεων στις ροές\n        setting_auto_play_gif: Αυτόματη αναπαραγωγή των GIF\n        setting_boost_modal: Εμφάνιση ερώτησης επιβεβαίωσης πριν την προώθηση\n        setting_default_language: Γλώσσα δημοσιεύσεων\n        setting_default_privacy: Ιδιωτικότητα δημοσιεύσεων\n        setting_default_sensitive: Σημείωνε πάντα τα πολυμέσα ως ευαίσθητου περιεχομένου\n        setting_delete_modal: Εμφάνιση ερώτησης επιβεβαίωσης πριν διαγράψεις ένα τουτ\n        setting_display_media: Εμφάνιση πολυμέσων\n        setting_display_media_default: Προκαθορισμένο\n        setting_display_media_hide_all: Απόκρυψη όλων\n        setting_display_media_show_all: Εμφάνιση όλων\n        setting_expand_spoilers: Μόνιμη ανάπτυξη των τουτ με προειδοποίηση περιεχομένου\n        setting_hide_network: Κρύψε τις διασυνδέσεις σου\n        setting_noindex: Επέλεξε να μην συμμετέχεις στα αποτελέσματα μηχανών αναζήτησης\n        setting_reduce_motion: Μείωση κίνησης κινουμένων στοιχείων\n        setting_show_application: Να αποκαλύπτεται η εφαρμογή που χρησιμοποιήθηκε για την αποστολή των τουτ\n        setting_system_font_ui: Χρησιμοποίησε την προεπιλεγμένη γραμματοσειρά του συστήματος\n        setting_theme: Θέμα ιστότοπου\n        setting_unfollow_modal: Εμφάνιση ερώτησης επιβεβαίωσης πριν διακόψεις την παρακολούθηση κάποιου\n        severity: Αυστηρότητα\n        type: Τύπος εισαγωγής\n        username: Όνομα χρηστη\n        username_or_email: Όνομα ή διεύθυνση email χρήστη\n        whole_word: Ολόκληρη λέξη\n      featured_tag:\n        name: Ταμπέλα\n      interactions:\n        must_be_follower: Μπλόκαρε τις ειδοποιήσεις από όσους δεν ακολουθείς\n        must_be_following: Μπλόκαρε τις ειδοποιήσεις που προέρχονται από άτομα που δεν τα ακολουθείς\n        must_be_following_dm: Μπλόκαρε τα προσωπικά μηνύματα από όσους δεν ακολουθείς\n      invite_request:\n        text: Γιατί θέλεις να συμμετάσχεις;\n      notification_emails:\n        digest: Στέλνε συνοπτικά email\n        favourite: Στελνε email όταν κάποιος σημειώνει ως αγαπημένη τη δημοσίευσή σου\n        follow: Στελνε email όταν κάποιος σε ακολουθεί\n        follow_request: Στέλνε email όταν κάποιος ζητάει να σε ακολουθήσει\n        mention: Στέλνε email όταν κάποιος σε αναφέρει\n        pending_account: Αποστολή email όταν υπάρχει νέος λογαριασμός για επιθεώρηση\n        reblog: Στέλνε email όταν κάποιος προωθεί τη δημοσίευση σου\n        report: Αποστολή email όταν υποβάλλεται νέα καταγγελία\n    'no': Όχι\n    recommended: Προτείνεται\n    required:\n      mark: \"*\"\n      text: απαιτείται\n    'yes': Ναι\n"
  },
  {
    "path": "config/locales/simple_form.en.yml",
    "content": "---\nen:\n  simple_form:\n    hints:\n      account_warning_preset:\n        text: You can use toot syntax, such as URLs, hashtags and mentions\n      admin_account_action:\n        send_email_notification: The user will receive an explanation of what happened with their account\n        text_html: Optional. You can use toot syntax. You can <a href=\"%{path}\">add warning presets</a> to save time\n        type_html: Choose what to do with <strong>%{acct}</strong>\n        warning_preset_id: Optional. You can still add custom text to end of the preset\n      defaults:\n        autofollow: People who sign up through the invite will automatically follow you\n        avatar: PNG, GIF or JPG. At most %{size}. Will be downscaled to %{dimensions}px\n        bot: This account mainly performs automated actions and might not be monitored\n        context: One or multiple contexts where the filter should apply\n        digest: Only sent after a long period of inactivity and only if you have received any personal messages in your absence\n        discoverable_html: The <a href=\"%{path}\" target=\"_blank\">directory</a> lets people find accounts based on interests and activity. Requires at least %{min_followers} followers\n        email: You will be sent a confirmation e-mail\n        fields: You can have up to 4 items displayed as a table on your profile\n        header: PNG, GIF or JPG. At most %{size}. Will be downscaled to %{dimensions}px\n        inbox_url: Copy the URL from the frontpage of the relay you want to use\n        irreversible: Filtered toots will disappear irreversibly, even if filter is later removed\n        locale: The language of the user interface, e-mails and push notifications\n        locked: Requires you to manually approve followers\n        password: Use at least 8 characters\n        phrase: Will be matched regardless of casing in text or content warning of a toot\n        scopes: Which APIs the application will be allowed to access. If you select a top-level scope, you don't need to select individual ones.\n        setting_aggregate_reblogs: Do not show new boosts for toots that have been recently boosted (only affects newly-received boosts)\n        setting_default_sensitive: Sensitive media is hidden by default and can be revealed with a click\n        setting_display_media_default: Hide media marked as sensitive\n        setting_display_media_hide_all: Always hide all media\n        setting_display_media_show_all: Always show media marked as sensitive\n        setting_hide_network: Who you follow and who follows you will not be shown on your profile\n        setting_noindex: Affects your public profile and status pages\n        setting_show_application: The application you use to toot will be displayed in the detailed view of your toots\n        username: Your username will be unique on %{domain}\n        whole_word: When the keyword or phrase is alphanumeric only, it will only be applied if it matches the whole word\n      featured_tag:\n        name: 'You might want to use one of these:'\n      imports:\n        data: CSV file exported from another Mastodon server\n      invite_request:\n        text: This will help us review your application\n      sessions:\n        otp: 'Enter the two-factor code generated by your phone app or use one of your recovery codes:'\n      user:\n        chosen_languages: When checked, only toots in selected languages will be displayed in public timelines\n    labels:\n      account:\n        fields:\n          name: Label\n          value: Content\n      account_warning_preset:\n        text: Preset text\n      admin_account_action:\n        send_email_notification: Notify the user per e-mail\n        text: Custom warning\n        type: Action\n        types:\n          disable: Disable\n          none: Do nothing\n          silence: Silence\n          suspend: Suspend and irreversibly delete account data\n        warning_preset_id: Use a warning preset\n      defaults:\n        autofollow: Invite to follow your account\n        avatar: Avatar\n        bot: This is a bot account\n        chosen_languages: Filter languages\n        confirm_new_password: Confirm new password\n        confirm_password: Confirm password\n        context: Filter contexts\n        current_password: Current password\n        data: Data\n        discoverable: List this account on the directory\n        display_name: Display name\n        email: E-mail address\n        expires_in: Expire after\n        fields: Profile metadata\n        header: Header\n        inbox_url: URL of the relay inbox\n        irreversible: Drop instead of hide\n        locale: Interface language\n        locked: Lock account\n        max_uses: Max number of uses\n        new_password: New password\n        note: Bio\n        otp_attempt: Two-factor code\n        password: Password\n        phrase: Keyword or phrase\n        setting_advanced_layout: Enable advanced web interface\n        setting_aggregate_reblogs: Group boosts in timelines\n        setting_auto_play_gif: Auto-play animated GIFs\n        setting_boost_modal: Show confirmation dialog before boosting\n        setting_default_language: Posting language\n        setting_default_privacy: Posting privacy\n        setting_default_sensitive: Always mark media as sensitive\n        setting_delete_modal: Show confirmation dialog before deleting a toot\n        setting_display_media: Media display\n        setting_display_media_default: Default\n        setting_display_media_hide_all: Hide all\n        setting_display_media_show_all: Show all\n        setting_expand_spoilers: Always expand toots marked with content warnings\n        setting_hide_network: Hide your network\n        setting_home_dms: Show direct messages in home timeline\n        setting_noindex: Opt-out of search engine indexing\n        setting_reduce_motion: Reduce motion in animations\n        setting_show_application: Disclose application used to send toots\n        setting_system_font_ui: Use system's default font\n        setting_theme: Site theme\n        setting_unfollow_modal: Show confirmation dialog before unfollowing someone\n        severity: Severity\n        type: Import type\n        username: Username\n        username_or_email: Username or Email\n        whole_word: Whole word\n      featured_tag:\n        name: Hashtag\n      interactions:\n        must_be_follower: Block notifications from non-followers\n        must_be_following: Block notifications from people you don't follow\n        must_be_following_dm: Block direct messages from people you don't follow\n      invite_request:\n        text: Why do you want to join?\n      notification_emails:\n        digest: Send digest e-mails\n        favourite: Send e-mail when someone favourites your status\n        follow: Send e-mail when someone follows you\n        follow_request: Send e-mail when someone requests to follow you\n        mention: Send e-mail when someone mentions you\n        pending_account: Send e-mail when a new account needs review\n        reblog: Send e-mail when someone boosts your status\n        report: Send e-mail when a new report is submitted\n    'no': 'No'\n    recommended: Recommended\n    required:\n      mark: \"*\"\n      text: required\n    'yes': 'Yes'\n"
  },
  {
    "path": "config/locales/simple_form.en_GB.yml",
    "content": "---\nen_GB:\n  simple_form:\n    hints:\n      account_warning_preset:\n        text: You can use toot syntax, such as URLs, hashtags and mentions\n      admin_account_action:\n        send_email_notification: The user will receive an explanation of what happened with their account\n        text_html: Optional. You can use toot syntax. You can <a href=\"%{path}\">add warning presets</a> to save time\n        type_html: Choose what to do with <strong>%{acct}</strong>\n        warning_preset_id: Optional. You can still add custom text to end of the preset\n      defaults:\n        autofollow: People who sign up through the invite will automatically follow you\n        avatar: PNG, GIF or JPG. At most %{size}. Will be downscaled to %{dimensions}px\n        bot: This account mainly performs automated actions and might not be monitored\n        context: One or multiple contexts where the filter should apply\n        digest: Only sent after a long period of inactivity and only if you have received any personal messages in your absence\n        discoverable_html: The <a href=\"%{path}\" target=\"_blank\">directory</a> lets people find accounts based on interests and activity. Requires at least %{min_followers} followers\n        email: You will be sent a confirmation e-mail\n        fields: You can have up to 4 items displayed as a table on your profile\n        header: PNG, GIF or JPG. At most %{size}. Will be downscaled to %{dimensions}px\n        inbox_url: Copy the URL from the frontpage of the relay you want to use\n        irreversible: Filtered toots will disappear irreversibly, even if filter is later removed\n        locale: The language of the user interface, e-mails and push notifications\n        locked: Requires you to manually approve followers\n        password: Use at least 8 characters\n        phrase: Will be matched regardless of casing in text or content warning of a toot\n        scopes: Which APIs the application will be allowed to access. If you select a top-level scope, you don't need to select individual ones.\n        setting_aggregate_reblogs: Do not show new boosts for toots that have been recently boosted (only affects newly-received boosts)\n        setting_display_media_default: Hide media marked as sensitive\n        setting_display_media_hide_all: Always hide all media\n        setting_display_media_show_all: Always show media marked as sensitive\n        setting_hide_network: Who you follow and who follows you will not be shown on your profile\n        setting_noindex: Affects your public profile and status pages\n        setting_show_application: The application you use to toot will be displayed in the detailed view of your toots\n        username: Your username will be unique on %{domain}\n        whole_word: When the keyword or phrase is alphanumeric only, it will only be applied if it matches the whole word\n      featured_tag:\n        name: 'You might want to use one of these:'\n      imports:\n        data: CSV file exported from another Mastodon server\n      sessions:\n        otp: 'Enter the two-factor code generated by your phone app or use one of your recovery codes:'\n      user:\n        chosen_languages: When checked, only toots in selected languages will be displayed in public timelines\n    labels:\n      account:\n        fields:\n          name: Label\n          value: Content\n      account_warning_preset:\n        text: Preset text\n      admin_account_action:\n        send_email_notification: Notify the user per e-mail\n        text: Custom warning\n        type: Action\n        types:\n          disable: Disable\n          none: Do nothing\n          silence: Silence\n          suspend: Suspend and irreversibly delete account data\n        warning_preset_id: Use a warning preset\n      defaults:\n        autofollow: Invite to follow your account\n        avatar: Avatar\n        bot: This is a bot account\n        chosen_languages: Filter languages\n        confirm_new_password: Confirm new password\n        confirm_password: Confirm password\n        context: Filter contexts\n        current_password: Current password\n        data: Data\n        discoverable: List this account on the directory\n        display_name: Display name\n        email: E-mail address\n        expires_in: Expire after\n        fields: Profile metadata\n        header: Header\n        inbox_url: URL of the relay inbox\n        irreversible: Drop instead of hide\n        locale: Interface language\n        locked: Lock account\n        max_uses: Max number of uses\n        new_password: New password\n        note: Bio\n        otp_attempt: Two-factor code\n        password: Password\n        phrase: Keyword or phrase\n        setting_aggregate_reblogs: Group boosts in timelines\n        setting_auto_play_gif: Auto-play animated GIFs\n        setting_boost_modal: Show confirmation dialog before boosting\n        setting_default_language: Posting language\n        setting_default_privacy: Post privacy\n        setting_default_sensitive: Always mark media as sensitive\n        setting_delete_modal: Show confirmation dialog before deleting a toot\n        setting_display_media: Media display\n        setting_display_media_default: Default\n        setting_display_media_hide_all: Hide all\n        setting_display_media_show_all: Show all\n        setting_expand_spoilers: Always expand toots marked with content warnings\n        setting_hide_network: Hide your network\n        setting_noindex: Opt-out of search engine indexing\n        setting_reduce_motion: Reduce motion in animations\n        setting_show_application: Disclose application used to send toots\n        setting_system_font_ui: Use system's default font\n        setting_theme: Site theme\n        setting_unfollow_modal: Show confirmation dialog before unfollowing someone\n        severity: Severity\n        type: Import type\n        username: Username\n        username_or_email: Username or Email\n        whole_word: Whole word\n      featured_tag:\n        name: Hashtag\n      interactions:\n        must_be_follower: Block notifications from non-followers\n        must_be_following: Block notifications from people you don't follow\n        must_be_following_dm: Block direct messages from people you don't follow\n      notification_emails:\n        digest: Send digest e-mails\n        favourite: Send e-mail when someone favourites your status\n        follow: Send e-mail when someone follows you\n        follow_request: Send e-mail when someone requests to follow you\n        mention: Send e-mail when someone mentions you\n        reblog: Send e-mail when someone boosts your status\n        report: Send e-mail when a new report is submitted\n    'no': 'No'\n    required:\n      mark: \"*\"\n      text: required\n    'yes': 'Yes'\n"
  },
  {
    "path": "config/locales/simple_form.eo.yml",
    "content": "---\neo:\n  simple_form:\n    hints:\n      account_warning_preset:\n        text: Vi povas uzi skribmanierojn de mesaĝoj, kiel URL-ojn, kradvortojn kaj menciojn\n      admin_account_action:\n        send_email_notification: La uzanto ricevos klarigon pri tio, kio okazis al ties konto\n        text_html: Malnepra. Vi povas uzi skribmanierojn de mesaĝoj. Vi povas <a href=\"%{path}\">aldoni avertajn antaŭagordojn</a> por ŝpari tempon\n        type_html: Elektu kion fari kun <strong>%{acct}</strong>\n        warning_preset_id: Malnepra. Vi povas ankoraŭ aldoni propran tekston al la fino de la antaŭagordo\n      defaults:\n        autofollow: Homoj, kiuj registriĝos per la invito aŭtomate sekvos vin\n        avatar: Formato PNG, GIF aŭ JPG. Ĝis %{size}. Estos malgrandigita al %{dimensions}px\n        bot: Tiu konto ĉefe faras aŭtomatajn agojn, kaj povas esti ne kontrolata\n        context: Unu ol pluraj kuntekstoj kie la filtrilo devus agi\n        digest: Sendita nur post longa tempo de neaktiveco, kaj nur se vi ricevis personan mesaĝon en via foresto\n        discoverable_html: La <a href=\"%{path}\" target=\"_blank\">profilujo</a> permesas al homoj trovi kontojn laŭ interesoj kaj aktiveco. Postulas almenaŭ %{min_followers} sekvantojn\n        email: Vi ricevos konfirman retmesaĝon\n        fields: Vi povas havi ĝis 4 tabelajn elementojn en via profilo\n        header: Formato PNG, GIF aŭ JPG. Ĝis %{size}. Estos malgrandigita al %{dimensions}px\n        inbox_url: Kopiu la URL de la ĉefpaĝo de la ripetilo, kiun vi volas uzi\n        irreversible: Elfiltritaj mesaĝoj malaperos por ĉiam, eĉ se la filtrilo estas poste forigita\n        locale: La lingvo de la uzant-interfaco, retmesaĝoj kaj puŝ-sciigoj\n        locked: Vi devos aprobi ĉiun peton de sekvado mane\n        password: Uzu almenaŭ 8 signojn\n        phrase: Estos provita senzorge pri la uskleco de teksto aŭ averto pri enhavo de mesaĝo\n        scopes: Kiujn API-ojn la aplikaĵo permesiĝos atingi. Se vi elektas supran amplekson, vi ne bezonas elekti la individuajn.\n        setting_aggregate_reblogs: Ne montri novajn diskonigojn de mesaĝoj laste diskonigitaj (nur efikas al novaj diskonigoj)\n        setting_default_sensitive: Sentema komunikilo estas kaŝita defaŭlte kaj povas esti rivelita per alklako\n        setting_display_media_default: Kaŝi aŭdovidaĵojn markitajn kiel tiklaj\n        setting_display_media_hide_all: Ĉiam kaŝi ĉiujn aŭdovidaĵojn\n        setting_display_media_show_all: Ĉiam montri aŭdovidaĵojn markitajn kiel tiklaj\n        setting_hide_network: Tiuj, kiujn vi sekvas, kaj tiuj, kiuj sekvas vin ne estos videblaj en via profilo\n        setting_noindex: Influas vian publikan profilon kaj mesaĝajn paĝojn\n        setting_show_application: La aplikaĵo, kiun vi uzas por afiŝi, estos montrita en la detala vido de viaj mesaĝoj\n        username: Via uzantnomo estos unika ĉe %{domain}\n        whole_word: Kiam la vorto aŭ frazo estas nur litera aŭ cifera, ĝi estos uzata nur se ĝi kongruas kun la tuta vorto\n      featured_tag:\n        name: 'Vi povus uzi iun el la jenaj:'\n      imports:\n        data: CSV-dosiero el alia Mastodon-servilo\n      invite_request:\n        text: Ĉi tio helpos nin revizii vian kandidatiĝon\n      sessions:\n        otp: 'Enmetu la kodon de dufaktora aŭtentigo el via telefono aŭ uzu unu el viaj realiraj kodoj:'\n      user:\n        chosen_languages: Kiam estas elekto, nur mesaĝoj en elektitaj lingvoj aperos en publikaj tempolinioj\n    labels:\n      account:\n        fields:\n          name: Etikedo\n          value: Enhavo\n      account_warning_preset:\n        text: Antaŭagordita teksto\n      admin_account_action:\n        send_email_notification: Atentigi la uzanton retpoŝte\n        text: Propra averto\n        type: Ago\n        types:\n          disable: Malebligi\n          none: Fari nenion\n          silence: Silentigi\n          suspend: Haltigi kaj nemalfereble forigi kontajn datumojn\n        warning_preset_id: Uzi antaŭagorditan averton\n      defaults:\n        autofollow: Inviti al sekvi vian konton\n        avatar: Profilbildo\n        bot: Tio estas robota konto\n        chosen_languages: Filtri lingvojn\n        confirm_new_password: Konfirmi novan pasvorton\n        confirm_password: Konfirmi pasvorton\n        context: Filtri kuntekstojn\n        current_password: Nuna pasvorto\n        data: Datumoj\n        discoverable: Montri ĉi tiun konton en la profilujo\n        display_name: Publika nomo\n        email: Retadreso\n        expires_in: Eksvalidiĝas post\n        fields: Profilaj metadatumoj\n        header: Fonbildo\n        inbox_url: URL de la ripetila enirkesto\n        irreversible: Forĵeti anstataŭ kaŝi\n        locale: Interfaca lingvo\n        locked: Ŝlosi konton\n        max_uses: Maksimuma nombro de uzoj\n        new_password: Nova pasvorto\n        note: Sinprezento\n        otp_attempt: Kodo de dufaktora aŭtentigo\n        password: Pasvorto\n        phrase: Vorto aŭ frazo\n        setting_advanced_layout: Ebligi altnivelan retpaĝan interfacon\n        setting_aggregate_reblogs: Grupigi diskonigojn en tempolinioj\n        setting_auto_play_gif: Aŭtomate ekigi GIF-ojn\n        setting_boost_modal: Montri fenestron por konfirmi antaŭ ol diskonigi\n        setting_default_language: Publikada lingvo\n        setting_default_privacy: Mesaĝa videbleco\n        setting_default_sensitive: Ĉiam marki aŭdovidaĵojn tiklaj\n        setting_delete_modal: Montri fenestron por konfirmi antaŭ ol forigi mesaĝon\n        setting_display_media: Aŭdovidaĵa montrado\n        setting_display_media_default: Dekomenca\n        setting_display_media_hide_all: Kaŝi ĉiujn\n        setting_display_media_show_all: Montri ĉiujn\n        setting_expand_spoilers: Ĉiam grandigi mesaĝojn markitajn per avertoj pri enhavo\n        setting_hide_network: Kaŝi viajn sekvantojn kaj sekvatojn\n        setting_noindex: Ellistiĝi de retserĉila indeksado\n        setting_reduce_motion: Malrapidigi animaciojn\n        setting_show_application: Publikigi la aplikaĵon uzatan por sendi mesaĝojn\n        setting_system_font_ui: Uzi la dekomencan tiparon de la sistemo\n        setting_theme: Reteja etoso\n        setting_unfollow_modal: Montri fenestron por konfirmi antaŭ ol ĉesi sekvi iun\n        severity: Graveco\n        type: Importa tipo\n        username: Uzantnomo\n        username_or_email: Uzantnomo aŭ Retadreso\n        whole_word: Tuta vorto\n      featured_tag:\n        name: Kradvorto\n      interactions:\n        must_be_follower: Bloki sciigojn de nesekvantoj\n        must_be_following: Bloki sciigojn de homoj, kiujn vi ne sekvas\n        must_be_following_dm: Bloki rektajn mesaĝojn de homoj, kiujn vi ne sekvas\n      invite_request:\n        text: Kial vi volas aliĝi?\n      notification_emails:\n        digest: Sendi resumajn retmesaĝojn\n        favourite: Sendi retmesaĝon kiam iu stelumas vian mesaĝon\n        follow: Sendi retmesaĝon kiam iu sekvas vin\n        follow_request: Sendi retmesaĝon kiam iu petas sekvi vin\n        mention: Sendi retmesaĝon kiam iu mencias vin\n        pending_account: Sendi retmesaĝon kiam nova konto bezonas kontrolon\n        reblog: Sendi retmesaĝon kiam iu diskonigas vian mesaĝon\n        report: Sendi retmesaĝon kiam nova signalo estas sendita\n    'no': Ne\n    recommended: Rekomendita\n    required:\n      mark: \"*\"\n      text: bezonata\n    'yes': Jes\n"
  },
  {
    "path": "config/locales/simple_form.es.yml",
    "content": "---\nes:\n  simple_form:\n    hints:\n      account_warning_preset:\n        text: Puede usar sintaxis de toots, como URLs, hashtags y menciones\n      admin_account_action:\n        send_email_notification: El usuario recibirá una explicación de lo que sucedió con respecto a su cuenta\n      defaults:\n        autofollow: Los usuarios que se registren mediante la invitación te seguirán automáticamente\n        avatar: PNG, GIF o JPG. Máximo %{size}. Será escalado a %{dimensions}px\n        bot: Esta cuenta ejecuta principalmente acciones automatizadas y podría no ser monitorizada\n        context: Uno o múltiples contextos en los que debe aplicarse el filtro\n        digest: Solo enviado tras un largo periodo de inactividad y solo si has recibido mensajes personales durante tu ausencia\n        email: Se le enviará un correo de confirmación\n        fields: Puedes tener hasta 4 elementos mostrándose como una tabla en tu perfil\n        header: PNG, GIF o JPG. Máximo %{size}. Será escalado a %{dimensions}px\n        inbox_url: Copia la URL de la página principal del relés que quieres utilizar\n        irreversible: Los toots filtrados desaparecerán irreversiblemente, incluso si este filtro es eliminado más adelante\n        locale: El idioma de la interfaz de usuario, correos y notificaciones push\n        locked: Requiere que manualmente apruebes seguidores y las publicaciones serán mostradas solamente a tus seguidores\n        password: Utilice al menos 8 caracteres\n        phrase: Se aplicará sin importar las mayúsculas o los avisos de contenido de un toot\n        scopes: Qué APIs de la aplicación tendrán acceso. Si seleccionas el alcance de nivel mas alto, no necesitas seleccionar las individuales.\n        setting_hide_network: A quién sigues y quién te sigue no será mostrado en tu perfil\n        setting_noindex: Afecta a tu perfil público y páginas de estado\n        setting_show_application: La aplicación que utiliza usted para publicar toots se mostrará en la vista detallada de sus toots\n        whole_word: Cuando la palabra clave o frase es solo alfanumérica, solo será aplicado si concuerda con toda la palabra\n      imports:\n        data: Archivo CSV exportado desde otra instancia de Mastodon\n      invite_request:\n        text: Esto nos ayudará a revisar su aplicación\n      sessions:\n        otp: 'Introduce el código de autenticación de dos factores geberado por tu aplicación de teléfono o usa uno de tus códigos de recuperación:'\n      user:\n        chosen_languages: Cuando se marca, solo se mostrarán los toots en los idiomas seleccionados en los timelines públicos\n    labels:\n      account:\n        fields:\n          name: Etiqueta\n          value: Contenido\n      admin_account_action:\n        send_email_notification: Notificar al usuario por correo electrónico\n        text: Aviso personalizado\n        type: Acción\n        types:\n          disable: Deshabilitar\n          silence: Silenciar\n      defaults:\n        autofollow: Invitar a seguir tu cuenta\n        bot: Esta es una cuenta bot\n        chosen_languages: Filtrar idiomas\n        confirm_new_password: Confirmar nueva contraseña\n        confirm_password: Confirmar contraseña\n        context: Filtrar contextos\n        current_password: Contraseña actual\n        data: Información\n        display_name: Nombre para mostrar\n        email: Dirección de correo electrónico\n        expires_in: Expirar tras\n        fields: Metadatos de perfil\n        header: Img. cabecera\n        inbox_url: URL de la entrada de relés\n        irreversible: Dejar en lugar de ocultar\n        locale: Idioma\n        locked: Hacer privada esta cuenta\n        max_uses: Máx. número de usos\n        new_password: Nueva contraseña\n        note: Biografía\n        otp_attempt: Código de dos factores\n        password: Contraseña\n        phrase: Palabra clave o frase\n        setting_auto_play_gif: Reproducir automáticamente los GIFs animados\n        setting_boost_modal: Mostrar ventana de confirmación antes de un Retoot\n        setting_default_language: Idioma de publicación\n        setting_default_privacy: Privacidad de publicaciones\n        setting_default_sensitive: Marcar siempre imágenes como sensibles\n        setting_delete_modal: Mostrar diálogo de confirmación antes de borrar un toot\n        setting_hide_network: Ocultar tu red\n        setting_noindex: Excluirse del indexado de motores de búsqueda\n        setting_reduce_motion: Reducir el movimiento de las animaciones\n        setting_show_application: Mostrar aplicación usada para publicar toots\n        setting_system_font_ui: Utilizar la tipografía por defecto del sistema\n        setting_theme: Tema del sitio\n        setting_unfollow_modal: Mostrar diálogo de confirmación antes de dejar de seguir a alguien\n        severity: Severidad\n        type: Importar tipo\n        username: Nombre de usuario\n        username_or_email: Usuario o Email\n        whole_word: Toda la palabra\n      interactions:\n        must_be_follower: Bloquear notificaciones de personas que no te siguen\n        must_be_following: Bloquear notificaciones de personas que no sigues\n        must_be_following_dm: Bloquear mensajes directos de la gente que no sigues\n      invite_request:\n        text: \"¿Por qué quiere unirse usted?\"\n      notification_emails:\n        digest: Enviar resumen de correos electrónicos\n        favourite: Enviar correo electrónico cuando alguien de a favorito en su publicación\n        follow: Enviar correo electrónico cuando alguien te siga\n        follow_request: Enviar correo electrónico cuando alguien solicita seguirte\n        mention: Enviar correo electrónico cuando alguien te mencione\n        pending_account: Enviar correo electrónico cuando una nueva cuenta necesita revisión\n        reblog: Enviar correo electrónico cuando alguien comparta su publicación\n        report: Enviar un correo cuando se envía un nuevo informe\n    'no': 'No'\n    recommended: Recomendado\n    required:\n      text: necesario\n    'yes': Sí\n"
  },
  {
    "path": "config/locales/simple_form.eu.yml",
    "content": "---\neu:\n  simple_form:\n    hints:\n      account_warning_preset:\n        text: Toot sintaxia erabili dezakezu, URLak, traolak eta aipamenak\n      admin_account_action:\n        send_email_notification: Erabiltzaileak bere kontuarekin gertatutakoaren azalpen bat jasoko du\n        text_html: Aukerakoa. Toot sintaxia erabili dezakezu. <a href=\"%{path}\">Abisu aurre-ezarpenak</a> gehitu ditzakezu denbora aurrezteko\n        type_html: Erabaki zer egin <strong>%{acct}</strong> kontuarekin\n        warning_preset_id: Aukerakoa. Zure testua gehitu dezakezu aurre-ezarpenaren ostean\n      defaults:\n        autofollow: Gonbidapena erabiliz izena ematen dutenek automatikoki jarraituko dizute\n        avatar: PNG, GIF edo JPG. Gehienez %{size}. %{dimensions}px neurrira eskalatuko da\n        bot: Kontu honek nagusiki automatizatutako ekintzak burutzen ditu eta agian ez du inork monitorizatzen\n        context: Iragazkia aplikatzeko testuinguru bat edo batzuk\n        digest: Soilik jarduerarik gabeko epe luze bat eta gero, eta soilik ez zeudela mezu pertsonalen bat jaso baduzu\n        discoverable_html: <a href=\"%{path}\" target=\"_blank\">Direktorioa</a>k Jendea interesen eta jardueraren arabera aurkitzea ahalbidetzen du. Gutxienez %{min_followers} jarraitzaile behar dira bertan agertzeko\n        email: Baieztapen e-mail bat bidaliko zaizu\n        fields: 4 elementu bistaratu ditzakezu taula batean zure profilean\n        header: PNG, GIF edo JPG. Gehienez %{size}. %{dimensions}px eskalara txikituko da\n        inbox_url: Kopiatu erabili nahi duzun errelearen hasiera orriaren URLa\n        irreversible: Iragazitako Toot-ak betirako galduko dira, geroago iragazkia kentzen baduzu ere\n        locale: Erabiltzaile-interfazea, e-mail mezuen eta jakinarazpenen hizkuntza\n        locked: Jarraitzaileak eskuz onartu behar dituzu\n        password: Erabili 8 karaktere gutxienez\n        phrase: Bat egingo du Maiuskula/minuskula kontuan hartu gabe eta edukiaren abisua kontuan hartu gabe\n        scopes: Zeintzuk API atzitu ditzakeen aplikazioak. Goi mailako arloa aukeratzen baduzu, ez dituzu azpikoak aukeratu behar.\n        setting_aggregate_reblogs: Ez erakutsi buktzada berriak berriki bultzada jaso duten tootentzat (berriki jasotako bultzadei eragiten die besterik ez)\n        setting_default_sensitive: Multimedia hunkigarria lehenetsita ezkutatzen da, eta sakatuz ikusi daiteke\n        setting_display_media_default: Ezkutatu hunkigarri gisa markatutako multimedia\n        setting_display_media_hide_all: Ezkutatu multimedia guztia beti\n        setting_display_media_show_all: Erakutsi beti hunkigarri gisa markatutako multimedia\n        setting_hide_network: Nor jarraitzen duzun eta nork jarraitzen zaituen ez da bistaratuko zure profilean\n        setting_noindex: Zure profil publiko eta Toot-en orrietan eragina du\n        setting_show_application: Tootak bidaltzeko erabiltzen duzun aplikazioa zure tooten ikuspegi xehetsuan bistaratuko da\n        username: Zure erabiltzaile-izena bakana izango da %{domain} domeinuan\n        whole_word: Hitz eta esaldi gakoa alfanumerikoa denean, hitz osoarekin bat datorrenean besterik ez da aplikatuko\n      featured_tag:\n        name: 'Hauetakoren bat erabili zenezake:'\n      imports:\n        data: Beste Mastodon zerbitzari batetik esportatutako CSV fitxategia\n      invite_request:\n        text: Honek zure eskaera berrikustean lagunduko digu\n      sessions:\n        otp: 'Sartu zure telefonoko aplikazioak sortutako bi faktoreetako kodea, edo erabili zure berreskuratze kodeetako bat:'\n      user:\n        chosen_languages: Ezer markatzekotan, hautatutako hizkuntzetan dauden toot-ak besterik ez dira erakutsiko\n    labels:\n      account:\n        fields:\n          name: Etiketa\n          value: Edukia\n      account_warning_preset:\n        text: Aurrez ezarritako testua\n      admin_account_action:\n        send_email_notification: Jakinarazi erabiltzaileari e-mail bidez\n        text: Abisu pertsonalizatua\n        type: Ekintza\n        types:\n          disable: Desaktibatu\n          none: Ez egin ezer\n          silence: Isiltarazi\n          suspend: Kanporatu eta behin betiko ezabatu kontuko datuak\n        warning_preset_id: Erabili aurre-ezarritako abisu bat\n      defaults:\n        autofollow: Gonbidatu zure kontua jarraitzera\n        avatar: Abatarra\n        bot: Hau bot kontu bat da\n        chosen_languages: Iragazi hizkuntzak\n        confirm_new_password: Berretsi pasahitz berria\n        confirm_password: Berretsi pasahitza\n        context: Iragazkiaren testuinguruak\n        current_password: Oraingo pasahitza\n        data: Datuak\n        discoverable: Zerrendatu kontu hau direktorioan\n        display_name: Pantaila-izena\n        email: E-mail helbidea\n        expires_in: Iraungitzea\n        fields: Profilaren metadatuak\n        header: Goiburua\n        inbox_url: Errelearen sarrera ontziaren URLa\n        irreversible: Baztertu ezkutatu ordez\n        locale: Interfazearen hizkuntza\n        locked: Giltzapetu kontua\n        max_uses: Gehieneko erabiltzaile kopurua\n        new_password: Pasahitz berria\n        note: Biografia\n        otp_attempt: Bi faktoreetako kodea\n        password: Pasahitza\n        phrase: Hitz edo esaldi gakoa\n        setting_advanced_layout: Gaitu web interfaze aurreratua\n        setting_aggregate_reblogs: Taldekatu bultzadak denbora-lerroetan\n        setting_auto_play_gif: Erreproduzitu GIF animatuak automatikoki\n        setting_boost_modal: Erakutsi baieztapen elkarrizketa-koadroa bultzada eman aurretik\n        setting_default_language: Argitalpenen hizkuntza\n        setting_default_privacy: Mezuen pribatutasuna\n        setting_default_sensitive: Beti markatu edukiak hunkigarri gisa\n        setting_delete_modal: Erakutsi baieztapen elkarrizketa-koadroa toot bat ezabatu aurretik\n        setting_display_media: Multimedia bistaratzea\n        setting_display_media_default: Lehenetsia\n        setting_display_media_hide_all: Ezkutatu guztia\n        setting_display_media_show_all: Erakutsi guztia\n        setting_expand_spoilers: Hedatu beti edukia abisua (CW) duten  tootak\n        setting_hide_network: Ezkutatu zure sarea\n        setting_noindex: Atera bilaketa motorraren indexaziotik\n        setting_reduce_motion: Murriztu animazioen mugimenduak\n        setting_show_application: Utzi agerian tootak bidaltzeko erabilitako aplikazioa\n        setting_system_font_ui: Erabili sistemako tipografia lehenetsia\n        setting_theme: Gunearen gaia\n        setting_unfollow_modal: Erakutsi baieztapen elkarrizketa-koadroa inor jarraitzeari utzi aurretik\n        severity: Larritasuna\n        type: Inportazio mota\n        username: Erabiltzaile-izena\n        username_or_email: Erabiltzaile-izena edo e-mail helbidea\n        whole_word: Hitz osoa\n      featured_tag:\n        name: Traola\n      interactions:\n        must_be_follower: Blokeatu jarraitzaile ez direnen jakinarazpenak\n        must_be_following: Blokeatu zuk jarraitzen ez dituzunen jakinarazpenak\n        must_be_following_dm: Blokeatu zuk jarraitzen ez dituzunen mezu zuzenak\n      invite_request:\n        text: Zergatik elkartu nahi duzu?\n      notification_emails:\n        digest: Bidali laburpenak e-mail bidez\n        favourite: Bidali e-mail bat norbaitek zure mezua gogoko duenean\n        follow: Bidali e-mail bat norbaitek jarraitzen zaituenean\n        follow_request: Bidali e-mail bat norbaitek zu jarraitzea eskatzen duenean\n        mention: Bidali e-mail bat norbaitek zu aipatzean\n        pending_account: Bidali e-mail bat kontu bat berrikusi behar denean\n        reblog: Bidali e-mail bat norbaitek zure mezuari bultzada ematen badio\n        report: Bidali e-maila txosten berri bat aurkezten denean\n    'no': Ez\n    recommended: Aholkatua\n    required:\n      mark: \"*\"\n      text: beharrezkoa\n    'yes': Bai\n"
  },
  {
    "path": "config/locales/simple_form.fa.yml",
    "content": "---\nfa:\n  simple_form:\n    hints:\n      account_warning_preset:\n        text: می‌توانید مانند بوق‌های معمولی کاربران دیگر را نام ببرید یا پیوند و برچسب بگذارید\n      admin_account_action:\n        send_email_notification: توضیحی که کاربر می‌بینید که برای حسابش چه رخ داده است\n        text_html: اختیاری. می‌توانید مثل بوق‌های معمولی بنویسید. می‌توانید برای صرفه‌جویی در زمان <a href=\"%{path}\">هشدارهای ازپیش‌آماده بیفزایید</a>\n        type_html: با حساب <strong>%{acct}</strong> می‌خواهید چه کار کنید؟‌\n        warning_preset_id: اختیاری. همچنان می‌توانید در پایان متن آماده چیزی بیفزایید\n      defaults:\n        autofollow: کسانی که از راه دعوت‌نامه عضو می‌شوند به طور خودکار پیگیر شما خواهند شد\n        avatar: یکی از قالب‌های PNG یا  GIF یا JPG. بیشترین اندازه %{size}. تصویر به اندازهٔ %{dimensions} پیکسل تبدیل خواهد شد\n        bot: این حساب بیشتر به طور خودکار فعالیت می‌کند و نظارت پیوسته‌ای روی آن وجود ندارد\n        context: یک یا چند زمینه که فیلتر باید در آن‌ها اعمال شود\n        digest: تنها وقتی فرستاده می‌شود که مدتی طولانی فعالیتی نداشته باشید و در این مدت برای شما پیغام خصوصی‌ای نوشته شده باشد\n        discoverable_html: با <a href=\"%{path}\" target=\"_blank\">فهرست گزیدهٔ کاربران</a> مردم می‌توانند حساب‌های این سرور را بر اساس علاقه‌مندی‌ها و فعالیت‌شان پیدا کنند. هر حساب دست‌کم باید %{min_followers} پیگیر داشته باشد\n        email: به شما ایمیل تأییدی فرستاده خواهد شد\n        fields: شما می‌توانید تا چهار مورد را در یک جدول در نمایهٔ خود نمایش دهید\n        header: یکی از قالب‌های PNG یا  GIF یا JPG. بیشترین اندازه %{size}. تصویر به اندازهٔ %{dimensions} پیکسل تبدیل خواهد شد\n        inbox_url: نشانی صفحهٔ اصلی رله‌ای را که می‌خواهید به کار ببرید کپی کنید\n        irreversible: بوق‌های فیلترشده به طور برگشت‌ناپذیری ناپدید می‌شوند، حتی اگر فیلتر را بعداً بردارید\n        locale: زبان محیط کاربری، ایمیل‌ها، و اعلان‌ها\n        locked: باید پیگیران تازه را خودتان تأیید کنید\n        password: دست‌کم باید ۸ نویسه داشته باشد\n        phrase: مستقل از کوچکی و بزرگی حروف، با متن اصلی یا هشدار محتوای بوق‌ها مقایسه می‌شود\n        scopes: واسط‌های برنامه‌نویسی که این برنامه به آن دسترسی دارد. اگر بالاترین سطح دسترسی را انتخاب کنید، دیگر نیازی به انتخاب سطح‌های پایینی ندارید.\n        setting_aggregate_reblogs: برای بازبوق‌هایی که به تازگی برایتان نمایش داده شده‌اند، بازبوق‌های بیشتر را نشان نده (فقط روی بازبوق‌های اخیر تأثیر می‌گذارد)\n        setting_display_media_default: تصویرهایی را که به عنوان حساس علامت زده شده‌اند پنهان کن\n        setting_display_media_hide_all: همیشه همهٔ عکس‌ها و ویدیوها را پنهان کن\n        setting_display_media_show_all: همیشه تصویرهایی را که به عنوان حساس علامت زده شده‌اند را نشان بده\n        setting_hide_network: فهرست پیگیران شما و فهرست کسانی که شما پی می‌گیرید روی نمایهٔ شما دیده نخواهد شد\n        setting_noindex: روی نمایهٔ عمومی و صفحهٔ نوشته‌های شما تأثیر می‌گذارد\n        setting_show_application: برنامه‌ای که به کمک آن بوق می‌زنید، در جزئیات بوق شما نمایش خواهد یافت\n        username: نام کاربری شما روی %{domain} یکتا خواهد بود\n        whole_word: اگر کلیدواژه فقط دارای حروف و اعداد باشد، تنها وقتی پیدا می‌شود که با کل یک واژه در متن منطبق باشد، نه با بخشی از یک واژه\n      featured_tag:\n        name: 'شاید بخواهید چنین چیزهایی را به کار ببرید:'\n      imports:\n        data: پروندهٔ CSV که از سرور ماستدون دیگری برون‌سپاری شده\n      sessions:\n        otp: 'کد تأیید دومرحله‌ای که اپ روی تلفن شما ساخته را وارد کنید یا یکی از کدهای بازیابی را به کار ببرید:'\n      user:\n        chosen_languages: اگر انتخاب کنید، تنها نوشته‌هایی که به زبان‌های برگزیدهٔ شما نوشته شده‌اند در فهرست نوشته‌های عمومی نشان داده می‌شوند\n    labels:\n      account:\n        fields:\n          name: برچسب\n          value: محتوا\n      account_warning_preset:\n        text: متن از پیش آماده‌شده\n      admin_account_action:\n        send_email_notification: اطلاع‌رسانی به کاربر از راه ایمیل\n        text: هشدار موردی\n        type: نوع کنش\n        types:\n          disable: غیرفعال‌کردن\n          none: کاری نکن\n          silence: بی‌صدا کردن\n          suspend: تعلیق و پاک‌کردن کامل همهٔ اطلاعات حساب\n        warning_preset_id: یک هشدار از پیش‌آماده را به کار ببرید\n      defaults:\n        autofollow: دعوت از دیگران برای عضو شدن و پیگیری حساب شما\n        avatar: تصویر نمایه\n        bot: این حساب یک ربات است\n        chosen_languages: جدا کردن زبان‌ها\n        confirm_new_password: تأیید رمز تازه\n        confirm_password: تأیید رمز\n        context: زمینه‌های فیلترکردن\n        current_password: رمز فعلی\n        data: داده‌ها\n        discoverable: این حساب را در فهرست گزیدهٔ کاربران نشان بده\n        display_name: نمایش به نام\n        email: نشانی ایمیل\n        expires_in: تاریخ انقضا\n        fields: اطلاعات تکمیلی نمایه\n        header: تصویر زمینه\n        inbox_url: نشانی صندوق ورودی رله\n        irreversible: به جای پنهان‌سازی، حذف کن\n        locale: زبان محیط کاربری\n        locked: خصوصی‌کردن حساب\n        max_uses: بیشترین شمار استفاده\n        new_password: رمز تازه\n        note: دربارهٔ شما\n        otp_attempt: کد ورود دومرحله‌ای\n        password: رمز\n        phrase: کلیدواژه یا عبارت\n        setting_aggregate_reblogs: بازبوق‌ها را متحد کن\n        setting_auto_play_gif: پخش خودکار تصویرهای متحرک\n        setting_boost_modal: نمایش پیغام تأیید پیش از بازبوقیدن\n        setting_default_language: زبان نوشته‌های شما\n        setting_default_privacy: حریم خصوصی نوشته‌ها\n        setting_default_sensitive: همیشه تصاویر را به عنوان حساس علامت بزن\n        setting_delete_modal: نمایش پیغام تأیید پیش از پاک کردن یک نوشته\n        setting_display_media: نمایش عکس و ویدیو\n        setting_display_media_default: پیش‌فرض\n        setting_display_media_hide_all: نهفتن همه\n        setting_display_media_show_all: نمایش همه\n        setting_expand_spoilers: همیشه بوق‌هایی را که هشدار محتوا دارند کامل نشان بده\n        setting_hide_network: نهفتن شبکهٔ ارتباطی\n        setting_noindex: درخواست از موتورهای جستجوگر برای ظاهر نشدن در نتایج جستجو\n        setting_reduce_motion: کاستن از حرکت در پویانمایی‌ها\n        setting_show_application: برنامه‌ای که به کار می‌برید آشکار شود\n        setting_system_font_ui: به‌کاربردن قلم پیش‌فرض سیستم\n        setting_theme: تم سایت\n        setting_unfollow_modal: نمایش پیغام تأیید پیش از لغو پیگیری دیگران\n        severity: شدت\n        type: نوع درون‌ریزی\n        username: نام کاربری (لاتین)\n        username_or_email: نام کاربری یا ایمیل\n        whole_word: تطابق واژهٔ کامل\n      featured_tag:\n        name: برچسب\n      interactions:\n        must_be_follower: مسدودکردن اعلان‌های همه به جز پیگیران\n        must_be_following: مسدودکردن اعلان‌های کسانی که شما پی نمی‌گیرید\n        must_be_following_dm: مسدودکردن پیغام‌های خصوصی کسانی که شما پی نمی‌گیرید\n      notification_emails:\n        digest: خلاصه‌کردن چند اعلان در یک ایمیل\n        favourite: وقتی کسی نوشتهٔ شما را پسندید ایمیل بفرست\n        follow: وقتی کسی پیگیر شما شد ایمیل بفرست\n        follow_request: وقتی کسی درخواست پیگیری کرد ایمیل بفرست\n        mention: وقتی کسی از شما نام برد ایمیل بفرست\n        reblog: وقتی کسی نوشتهٔ شما را بازبوقید ایمیل بفرست\n        report: وقتی گزارش تازه‌ای فرستاده شد ایمیل بفرست\n    'no': خیر\n    required:\n      text: ضروری\n    'yes': بله\n"
  },
  {
    "path": "config/locales/simple_form.fi.yml",
    "content": "---\nfi:\n  simple_form:\n    hints:\n      admin_account_action:\n        send_email_notification: Käyttäjä saa selityksen mitä tapahtui hänen tililleen\n      defaults:\n        avatar: PNG, GIF tai JPG. Enintään %{size}. Skaalataan kokoon %{dimensions} px\n        digest: Lähetetään vain pitkän poissaolon jälkeen ja vain, jos olet saanut suoria viestejä poissaolosi aikana\n        fields: Sinulla voi olla korkeintaan 4 asiaa profiilissasi taulukossa\n        header: PNG, GIF tai JPG. Enintään %{size}. Skaalataan kokoon %{dimensions} px\n        locked: Sinun täytyy hyväksyä seuraajat manuaalisesti\n        setting_noindex: Vaikuttaa julkiseen profiiliisi ja tilasivuihisi\n      imports:\n        data: Toisesta Mastodon-instanssista tuotu CSV-tiedosto\n      sessions:\n        otp: Syötä puhelimeen saamasi kaksivaiheisen tunnistautumisen koodi tai käytä palautuskoodia.\n    labels:\n      account:\n        fields:\n          value: Sisältö\n      defaults:\n        avatar: Profiilikuva\n        confirm_new_password: Vahvista uusi salasana\n        confirm_password: Vahvista salasana\n        current_password: Nykyinen salasana\n        data: Tiedot\n        display_name: Nimimerkki\n        email: Sähköpostiosoite\n        expires_in: Vanhenee\n        fields: Profiilin metadata\n        header: Otsakekuva\n        locale: Kieli\n        locked: Lukitse tili\n        max_uses: Käyttökertoja enintään\n        new_password: Uusi salasana\n        note: Kuvaus\n        otp_attempt: Kaksivaiheisen tunnistuksen koodi\n        password: Salasana\n        setting_auto_play_gif: Toista GIF-animaatiot automaattisesti\n        setting_boost_modal: Kysy vahvistusta ennen buustausta\n        setting_default_privacy: Julkaisun näkyvyys\n        setting_default_sensitive: Merkitse media aina arkaluontoiseksi\n        setting_delete_modal: Kysy vahvistusta ennen tuuttauksen poistamista\n        setting_noindex: Jättäydy pois hakukoneindeksoinnista\n        setting_reduce_motion: Vähennä animaatioiden liikettä\n        setting_system_font_ui: Käytä järjestelmän oletusfonttia\n        setting_theme: Sivuston teema\n        setting_unfollow_modal: Kysy vahvistusta, ennen kuin lopetat seuraamisen\n        severity: Vakavuus\n        type: Tietojen laji\n        username: Käyttäjänimi\n        username_or_email: Käyttäjänimi tai sähköposti\n      interactions:\n        must_be_follower: Estä ilmoitukset käyttäjiltä, jotka eivät seuraa sinua\n        must_be_following: Estä ilmoitukset käyttäjiltä, joita et seuraa\n        must_be_following_dm: Estä suorat viestit käyttäjiltä, joita et seuraa\n      notification_emails:\n        digest: Lähetä koosteviestejä sähköpostitse\n        favourite: Lähetä sähköposti, kun joku tykkää tilastasi\n        follow: Lähetä sähköposti, kun joku seuraa sinua\n        follow_request: Lähetä sähköposti, kun joku pyytää seurata sinua\n        mention: Lähetä sähköposti, kun sinut mainitaan\n        reblog: Lähetä sähköposti, kun joku buustaa julkaisusi\n    'no': Ei\n    required:\n      text: pakollinen tieto\n    'yes': Kyllä\n"
  },
  {
    "path": "config/locales/simple_form.fr.yml",
    "content": "---\nfr:\n  simple_form:\n    hints:\n      account_warning_preset:\n        text: Vous pouvez utiliser la syntaxe des pouets, comme les URLs, les hashtags et les mentions\n      admin_account_action:\n        send_email_notification: L’utilisateur recevra une explication de ce qu’il s’est passé avec son compte\n        text_html: Optionnel. Vous pouvez utilisez la syntaxe des pouets. Vous pouvez <a href=\"%{path}\">ajouter des présélections d’attention</a> pour économiser du temps\n        type_html: Choisir que faire avec <strong>%{acct}</strong>\n        warning_preset_id: Optionnel. Vous pouvez toujours ajouter un texte personnalisé à la fin de la présélection\n      defaults:\n        autofollow: Les personnes qui s’inscrivent grâce à l’invitation vous suivront automatiquement\n        avatar: Au format PNG, GIF ou JPG. %{size} maximum. Sera réduit à %{dimensions}px\n        bot: Ce compte exécute principalement des actions automatisées et pourrait ne pas être surveillé\n        context: Un ou plusieurs contextes où le filtre devrait s’appliquer\n        digest: Uniquement envoyé après une longue période d’inactivité et uniquement si vous avez reçu des messages personnels pendant votre absence\n        discoverable_html: L’<a href=\"%{path}\" target=\"_blank\">annuaire</a> permet aux gens de trouver des comptes en se basant sur les intérêts et les activités. Nécessite au moins %{min_followers} abonnés\n        email: Vous recevrez un courriel de confirmation\n        fields: Vous pouvez avoir jusqu’à 4 éléments affichés en tant que tableau sur votre profil\n        header: Au format PNG, GIF ou JPG. %{size} maximum. Sera réduit à %{dimensions}px\n        inbox_url: Copiez l’URL depuis la page d’accueil du relais que vous souhaitez utiliser\n        irreversible: Les pouets filtrés disparaîtront irrémédiablement, même si le filtre est supprimé plus tard\n        locale: La langue de l’interface, des courriels et des notifications\n        locked: Vous devrez approuver chaque abonné⋅e et vos statuts ne s’afficheront qu’à vos abonné⋅es\n        password: Utilisez au moins 8 caractères\n        phrase: Sera trouvé sans que la case ou l’avertissement de contenu du pouet soit pris en compte\n        scopes: À quelles APIs l’application sera autorisée à accéder. Si vous sélectionnez un périmètre de haut-niveau, vous n’avez pas besoin de sélectionner les individuels.\n        setting_aggregate_reblogs: Ne pas afficher de nouveaux repartagés pour les pouets qui ont été récemment repartagés (n’affecte que les repartagés nouvellement reçus)\n        setting_default_sensitive: Les médias sensibles sont cachés par défaut et peuvent être révélés d’un simple clic\n        setting_display_media_default: Masquer les médias marqués comme sensibles\n        setting_display_media_hide_all: Toujours masquer tous les médias\n        setting_display_media_show_all: Toujours afficher les médias marqués comme sensibles\n        setting_hide_network: Ceux que vous suivez et ceux qui vous suivent ne seront pas affichés sur votre profil\n        setting_noindex: Affecte votre profil public ainsi que vos statuts\n        setting_show_application: Le nom de l’application que vous utilisez afin d’envoyer des pouets sera affiché dans la vue détaillée de ceux-ci\n        username: Votre nom d’utilisateur sera unique sur %{domain}\n        whole_word: Lorsque le mot-clef ou la phrase-clef est uniquement alphanumérique, ça sera uniquement appliqué s’il correspond au mot entier\n      featured_tag:\n        name: 'Vous pourriez vouloir utiliser l’un d’entre eux :'\n      imports:\n        data: Un fichier CSV généré par un autre serveur de Mastodon\n      invite_request:\n        text: Cela nous aidera à considérer votre demande\n      sessions:\n        otp: 'Entrez le code d’authentification à deux facteurs généré par l’application de votre téléphone ou utilisez un de vos codes de récupération :'\n      user:\n        chosen_languages: Lorsque coché, seuls les pouets dans les langues sélectionnées seront affichés sur les fils publics\n    labels:\n      account:\n        fields:\n          name: Étiquette\n          value: Contenu\n      account_warning_preset:\n        text: Texte de présélection\n      admin_account_action:\n        send_email_notification: Notifier l’utilisateur par courriel\n        text: Attention personnalisée\n        type: Action\n        types:\n          disable: Désactiver\n          none: Ne rien faire\n          silence: Masquer\n          suspend: Suspendre et effacer les données du compte de manière irréversible\n        warning_preset_id: Utiliser un modèle d’avertissement\n      defaults:\n        autofollow: Invitation à suivre votre compte\n        avatar: Image de profil\n        bot: Ceci est un robot\n        chosen_languages: Filtrer les langues\n        confirm_new_password: Confirmation du nouveau mot de passe\n        confirm_password: Confirmation du mot de passe\n        context: Contextes du filtre\n        current_password: Mot de passe actuel\n        data: Données\n        discoverable: Inscrire ce compte dans l’annuaire\n        display_name: Nom public\n        email: Adresse courriel\n        expires_in: Expire après\n        fields: Métadonnées du profil\n        header: Image d’en-tête\n        inbox_url: URL de la boîte de relais\n        irreversible: Supprimer plutôt que de cacher\n        locale: Langue de l’interface\n        locked: Verrouiller le compte\n        max_uses: Nombre maximum d’utilisations\n        new_password: Nouveau mot de passe\n        note: Présentation\n        otp_attempt: Code d’identification à deux facteurs\n        password: Mot de passe\n        phrase: Mot-clé ou phrase\n        setting_advanced_layout: Activer l’interface Web avancée\n        setting_aggregate_reblogs: Repartagés en groupe dans la ligne de temps\n        setting_auto_play_gif: Lire automatiquement les GIFs animés\n        setting_boost_modal: Afficher une fenêtre de confirmation avant de partager\n        setting_default_language: Langue de publication\n        setting_default_privacy: Confidentialité des statuts\n        setting_default_sensitive: Toujours marquer les médias comme sensibles\n        setting_delete_modal: Afficher une fenêtre de confirmation avant de supprimer un pouet\n        setting_display_media: Affichage des médias\n        setting_display_media_default: Défaut\n        setting_display_media_hide_all: Masquer tout\n        setting_display_media_show_all: Montrer tout\n        setting_expand_spoilers: Toujours développer les pouets marqués d’un avertissement de contenu\n        setting_hide_network: Cacher votre réseau\n        setting_home_dms: Montrer les messages directs sur le fil d'accueil\n        setting_noindex: Demander aux moteurs de recherche de ne pas indexer vos informations personnelles\n        setting_reduce_motion: Réduire la vitesse des animations\n        setting_show_application: Dévoiler le nom de l’application utilisée pour envoyer des pouets\n        setting_system_font_ui: Utiliser la police par défaut du système\n        setting_theme: Thème du site\n        setting_unfollow_modal: Afficher une fenêtre de confirmation avant de vous désabonner d’un compte\n        severity: Sévérité\n        type: Type d’import\n        username: Identifiant\n        username_or_email: Nom d’utilisateur·ice ou courriel\n        whole_word: Mot entier\n      featured_tag:\n        name: Hashtag\n      interactions:\n        must_be_follower: Masquer les notifications des personnes qui ne vous suivent pas\n        must_be_following: Masquer les notifications des personnes que vous ne suivez pas\n        must_be_following_dm: Bloquer les messages directs des personnes que vous ne suivez pas\n      invite_request:\n        text: Pourquoi voulez-vous vous inscrire ?\n      notification_emails:\n        digest: Envoyer des courriels récapitulatifs\n        favourite: Envoyer un courriel lorsque quelqu’un ajoute mes statuts à ses favoris\n        follow: Envoyer un courriel lorsque quelqu’un me suit\n        follow_request: Envoyer un courriel lorsque quelqu’un demande à me suivre\n        mention: Envoyer un courriel lorsque quelqu’un me mentionne\n        pending_account: Envoyer un courriel lorsqu’un nouveau compte est en attente d’approbation\n        reblog: Envoyer un courriel lorsque quelqu’un partage mes statuts\n        report: Envoyer un courriel lorsqu’un nouveau rapport est soumis\n    'no': Non\n    recommended: Recommandé\n    required:\n      mark: \"*\"\n      text: Champs requis\n    'yes': Oui\n"
  },
  {
    "path": "config/locales/simple_form.gl.yml",
    "content": "---\ngl:\n  simple_form:\n    hints:\n      account_warning_preset:\n        text: Vostede pode utilizar dar formato ao toot, como URLs, etiquetas e mencións\n      admin_account_action:\n        send_email_notification: A usuaria recibirá unha explicación sobre o que lle aconteceu a súa conta\n        text_html: Optativo. Pode utilizar formato no toot. Pode <a href=\"%{path}\">engadir avisos preestablecidos</a> para aforrar tempo\n        type_html: Escolla que facer con <strong>%{acct}</strong>\n        warning_preset_id: Optativo. Poderá engadir texto personalizado ao final do preestablecido\n      defaults:\n        autofollow: As persoas que se conectaron a través de un convite seguirana automáticamente a vostede\n        avatar: PNG, GIF ou JPG.  Máximo %{size}. Será reducida a %{dimensions}px\n        bot: Esta conta realiza principalmente accións automatizadas e podería non estar monitorizada\n        context: Un ou varios contextos onde se debería aplicar o filtro\n        digest: Enviar só tras un longo período de inactividade e só si recibeu algunha mensaxe persoal na súa ausencia\n        discoverable_html: O <a href=\"%{path}\" target=\"_blank\">directorio</a> permite atopar contas en función de intereses e actividade. Require ter ao menos %{min_followers} seguidoras\n        email: Enviaráselle un correo-e de confirmación\n        fields: Pode ter ate 4 elementos no seu perfil mostrados como unha táboa\n        header: PNG, GIF ou JPG. Máximo %{size}. Será reducida a %{dimensions}px\n        inbox_url: Copiar o URL desde a páxina de inicio do repetidor que quere utilizar\n        irreversible: Os toots filtrados desaparecerán de xeito irreversible, incluso si despois se elimina o filtro\n        locale: O idioma da interface de usuaria, correos e notificacións\n        locked: Require que vostede acepte as seguidoras de xeito manual\n        password: Utilice 8 caracteres ao menos\n        phrase: Concordará independentemente das maiúsculas ou avisos de contido no toot\n        scopes: A que APIs terá acceso a aplicación. Si selecciona un ámbito de alto nivel, non precisa seleccionar elementos individuais.\n        setting_aggregate_reblogs: Non mostrar novas promocións de toots que foron promocionados recentemente (só afecta a promocións recén recibidas)\n        setting_default_sensitive: Medios sensibles marcados como ocultos por defecto e móstranse cun click\n        setting_display_media_default: Ocultar medios marcados como sensibles\n        setting_display_media_hide_all: Ocultar sempre os medios\n        setting_display_media_show_all: Mostrar sempre os medios marcados como sensibles\n        setting_hide_network: Non se mostrará no seu perfil quen a segue e quen a está a seguir\n        setting_noindex: Afecta ao seu perfil público e páxinas de estado\n        setting_show_application: A aplicación que está a utilizar para enviar toots mostrarase na vista detallada do toot\n        username: O seu nome de usuaria será único en %{domain}\n        whole_word: Se a chave ou frase de paso é só alfanumérica, só se aplicará se concorda a palabra completa\n      featured_tag:\n        name: 'Podería utilizar algunha de estas:'\n      imports:\n        data: Ficheiro CSV exportado desde outro servidor Mastodon\n      invite_request:\n        text: Esto axudaranos a revisar a súa aplicación\n      sessions:\n        otp: 'Introduza o código de doble-factor xerado no aplicativo do seu móbil ou utilice un dos seus códigos de recuperación:'\n      user:\n        chosen_languages: Se ten marca, só os toots nos idiomas seleccionados serán mostrados en liñas temporais públicas\n    labels:\n      account:\n        fields:\n          name: Etiqueta\n          value: Contido\n      account_warning_preset:\n        text: Texto preestablecido\n      admin_account_action:\n        send_email_notification: Notificar a usuaria por correo-e\n        text: Aviso personalizado\n        type: Acción\n        types:\n          disable: Desactivar\n          none: Non facer nada\n          silence: Acalar\n          suspend: Suspender e eliminar irreversiblemente datos da conta\n        warning_preset_id: Utilizar un aviso preestablecido\n      defaults:\n        autofollow: Convide a seguir a súa conta\n        avatar: Avatar\n        bot: Esta conta é de un bot\n        chosen_languages: Filtrar idiomas\n        confirm_new_password: Confirme o novo contrasinal\n        confirm_password: Confirme o contrasinal\n        context: Contextos do filtro\n        current_password: Contrasinal actual\n        data: Datos\n        discoverable: Incluír esta conta no directorio\n        display_name: Nome mostrado\n        email: enderezo correo electrónico\n        expires_in: Caducidade despois de\n        fields: Metadatos do perfil\n        header: Cabeceira\n        inbox_url: URL da caixa de entrada do repetidor\n        irreversible: Soltar en lugar de agochar\n        locale: Idioma da interface\n        locked: Protexer conta\n        max_uses: Número máximo de usos\n        new_password: Novo contrasinal\n        note: Sobre vostede\n        otp_attempt: Código de Doble-Factor\n        password: Contrasinal\n        phrase: Palabra chave ou frase\n        setting_advanced_layout: Activar interface web avanzada\n        setting_aggregate_reblogs: Agrupar promocións nas liñas temporais\n        setting_auto_play_gif: Reprodución automática de GIFs animados\n        setting_boost_modal: Pedir confirmación antes de promocionar\n        setting_default_language: Idioma de publicación\n        setting_default_privacy: Intimidade da publicación\n        setting_default_sensitive: Marcar sempre multimedia como sensible\n        setting_delete_modal: Solicitar confirmación antes de eliminar unha mensaxe\n        setting_display_media: Mostrar medios\n        setting_display_media_default: Por omisión\n        setting_display_media_hide_all: Ocultar todo\n        setting_display_media_show_all: Mostrar todo\n        setting_expand_spoilers: Despregar sempre as mensaxes marcadas con avisos de contido\n        setting_hide_network: Non mostrar contactos\n        setting_noindex: Pedir non aparecer nas buscas dos motores de busca\n        setting_reduce_motion: Reducir o movemento nas animacións\n        setting_show_application: Mostrar a aplicación utilizada para tootear\n        setting_system_font_ui: Utilizar a tipografía por defecto do sistema\n        setting_theme: Decorado da instancia\n        setting_unfollow_modal: Solicitar confirmación antes de deixar de seguir alguén\n        severity: Severidade\n        type: Tipo de importación\n        username: Nome de usuaria\n        username_or_email: Nome de usuaria ou Correo-e\n        whole_word: Palabra completa\n      featured_tag:\n        name: Etiqueta\n      interactions:\n        must_be_follower: Bloquear as notificacións de non-seguidoras\n        must_be_following: Bloquea as notificacións de personas que non segue\n        must_be_following_dm: Bloquea as mensaxes directas de personas que non segue\n      invite_request:\n        text: Por que quere unirse?\n      notification_emails:\n        digest: Enviar correos con resumos\n        favourite: Enviar un correo cando alguén marca como favorita unha das súas publicacións\n        follow: Enviar un correo cando alguén a segue\n        follow_request: Enviar un correo cando alguén solicita seguila\n        mention: Enviar un correo cando alguén a menciona\n        pending_account: Enviar correo-e cando unha nova conta precisa revisión\n        reblog: Enviar un correo cando alguén promociona a súa mensaxe\n        report: Enviar un correo cando se envíe un novo informe\n    'no': Non\n    recommended: Recomendado\n    required:\n      mark: \"*\"\n      text: requerido\n    'yes': Si\n"
  },
  {
    "path": "config/locales/simple_form.he.yml",
    "content": "---\nhe:\n  simple_form:\n    hints:\n      defaults:\n        avatar: PNG, GIF או JPG. מקסימום %{size}. גודל התמונה יוקטן ל-%{dimensions}px\n        digest: נשלח לאחר תקופה ארוכה של אי-פעילות עם סיכום איזכורים שקיבלת בהעדרך\n        header: PNG, GIF או JPG. מקסימום %{size}. גודל התמונה יוקטן %{dimensions}px\n        locked: מחייב אישור עוקבים באופן ידני. פרטיות ההודעות תהיה עוקבים-בלבד אלא אם יצוין אחרת\n        setting_noindex: משפיע על הפרופיל הציבורי שלך ועמודי ההודעות\n      imports:\n        data: קובץ CSV שיוצא משרת מסטודון אחר\n      sessions:\n        otp: נא להקליד קוד אימות דו-שלבי ממכשירך או קוד אחזור גישה.\n    labels:\n      defaults:\n        avatar: תמונת פרופיל\n        confirm_new_password: אישור סיסמא חדשה\n        confirm_password: אישור סיסמא\n        current_password: סיסמא נוכחית\n        data: מידע\n        display_name: שם להצגה\n        email: כתובת דוא\"ל\n        expires_in: תפוגה לאחר\n        header: ראשה\n        locale: שפה\n        locked: הפוך חשבון לפרטי\n        max_uses: מספר מרבי של שימושים\n        new_password: סיסמא חדשה\n        note: אודות\n        otp_attempt: קוד אימות דו-שלבי\n        password: סיסמא\n        setting_auto_play_gif: ניגון אוטומטי של גיפים\n        setting_boost_modal: הצגת דיאלוג אישור לפני הדהוד\n        setting_default_privacy: פרטיות ההודעות\n        setting_default_sensitive: תמיד לתת סימון \"רגיש\" למדיה\n        setting_delete_modal: להראות תיבת אישור לפני מחיקת חיצרוץ\n        setting_noindex: לבקש הסתרה ממנועי חיפוש\n        setting_reduce_motion: הפחתת תנועה בהנפשות\n        setting_system_font_ui: להשתמש בגופן ברירת המחדל של המערכת\n        setting_theme: ערכת העיצוב של האתר\n        setting_unfollow_modal: להראות תיבת אישור לפני הפסקת מעקב אחרי אחרים\n        severity: חומרה\n        type: סוג יבוא\n        username: שם משתמש\n      interactions:\n        must_be_follower: חסימת התראות משאינם עוקבים\n        must_be_following: חסימת התראות משאינם נעקבים\n        must_be_following_dm: חסימת הודעות ישירות מכותבים שאינם במעקב\n      notification_emails:\n        digest: שליחת הודעות דוא\"ל מסכמות\n        favourite: שליחת דוא\"ל כשמחבבים חצרוץ\n        follow: שליחת דוא\"ל כשנוספות עוקבות\n        follow_request: שליחת דוא\"ל כשמבקשים לעקוב\n        mention: שליחת דוא\"ל כשפונים אלייך\n        reblog: שליחת דוא\"ל כשמהדהדים חצרוץ שלך\n    'no': לא\n    required:\n      text: שדה חובה\n    'yes': כן\n"
  },
  {
    "path": "config/locales/simple_form.hr.yml",
    "content": "---\nhr:\n  simple_form:\n    hints:\n      defaults:\n        avatar: PNG, GIF ili JPG. Najviše %{size}. Bit će smanjen na %{dimensions}px\n        header: PNG, GIF ili JPG. Najviše %{size}. Bit će smanjen na %{dimensions}px\n        locked: traži te da ručno odobriš sljedbenike i postavlja privatnost postova na dostupnu samo sljedbenicima\n      imports:\n        data: CSV fajl izvezen iz druge Mastodon instance\n    labels:\n      defaults:\n        confirm_new_password: Potvrdi novu lozinku\n        confirm_password: Potvrdi lozinku\n        current_password: Trenutna lozinka\n        data: Podaci\n        display_name: Ime koje ću prikazati\n        email: E-mail adresa\n        locale: Jezik\n        locked: Učini račun privatnim\n        new_password: Nova lozinka\n        otp_attempt: Dvo-faktorski kod\n        password: Lozinka\n        setting_auto_play_gif: Automatski pokreni animirane GIFove\n        setting_default_privacy: Privatnost posta\n        type: Tip uvoženja\n        username: Korisničko ime\n      interactions:\n        must_be_follower: Blokiraj notifikacije onih koji me ne slijede\n        must_be_following: Blokiraj notifikacije ljudi koje ne slijedim\n      notification_emails:\n        digest: Šalji mi e-mailove s notifikacijama\n        favourite: Pošalji mi e-mail kad netko lajka moj status\n        follow: Pošalji mi e-mail kad me netko počne slijediti\n        follow_request: Pošalji mi e-mail kad mi netko pošalje zahtjev da me želi slijediti\n        mention: Pošalji mi e-mail kad me netko spomene\n        reblog: Pošalji mi e-mail kad netko rebloga moj status\n    'no': Ne\n    required:\n      text: traženo\n    'yes': Da\n"
  },
  {
    "path": "config/locales/simple_form.hu.yml",
    "content": "---\nhu:\n  simple_form:\n    hints:\n      defaults:\n        avatar: PNG, GIF vagy JPG. Maximum %{size}. Át lesz méretezve %{dimensions} pixelre\n        digest: Csak hosszú távollét esetén küldve és csak ha személyes üzenetet kaptál távollétedben\n        header: PNG, GIF vagy JPG. Maximum %{size}. Át lesz méretezve %{dimensions} pixelre\n        locked: Egyenként engedélyezned kell a követőidet\n        setting_noindex: A publikus profilodra és státusz oldalra vonatkozik\n      imports:\n        data: Egy másik Mastodon szerverről exportált CSV fájl\n      sessions:\n        otp: Add meg a Második-faktor kódodat a telefonodról vagy használd az egyik tartalék bejelentkező kódodat.\n    labels:\n      defaults:\n        avatar: Profilkép\n        confirm_new_password: Új jelszó megerősítése\n        confirm_password: Jelszó megerősítése\n        current_password: Jelenlegi jelszó\n        data: Adatok\n        display_name: Megjelenített név\n        email: E-mail cím\n        expires_in: Elévül\n        header: Fejléc\n        locale: Nyelv\n        locked: Zárt felhasználói fiók\n        max_uses: Felhasználhatóság\n        new_password: Új jelszó\n        note: Önéletrajz\n        otp_attempt: Második-faktor kód\n        password: Jelszó\n        setting_auto_play_gif: GIF-ek automatikus lejátszása\n        setting_boost_modal: Megerősítés kérése reblogolás előtt\n        setting_default_privacy: Tülkök alapártelmezett adatvédelmi szintje\n        setting_default_sensitive: Minden médiafájl megjelölése szenzitívként\n        setting_delete_modal: Megerősítés kérése tülk törlése előtt\n        setting_noindex: Megtiltom a keresőmotoroknak, hogy indexeljék a tülkjeimet\n        setting_reduce_motion: Animációk mozgásának csökkentése\n        setting_system_font_ui: Rendszer betűtípusának használata\n        setting_theme: Oldalsablon\n        setting_unfollow_modal: Megerősítés kérése mielőtt abbahagyod valaki követését\n        severity: Súlyosság\n        type: Importálás típusa\n        username: Felhasználónév\n      interactions:\n        must_be_follower: Nem követőidtől érkező értesítések tiltása\n        must_be_following: Nem követettjeidtől érkező értesítések tiltása\n        must_be_following_dm: Nem követettjeidtől érkező üzenetek tiltása\n      notification_emails:\n        digest: Összevont e-mailek küldése\n        favourite: E-mail küldése amikor valaki kedvencnek jelöli az állapotod\n        follow: E-mail küldése amikor valaki követni kezd téged\n        follow_request: E-mail küldése amikor valaki követni szeretne téged\n        mention: E-mail küldése amikor valaki megemlít téged\n        reblog: E-mail küldése amikor valaki reblogolja az állapotod\n    'no': Nem\n    required:\n      text: kötelező\n    'yes': Igen\n"
  },
  {
    "path": "config/locales/simple_form.hy.yml",
    "content": "hy:\n"
  },
  {
    "path": "config/locales/simple_form.id.yml",
    "content": "---\nid:\n  simple_form:\n    hints:\n      defaults:\n        avatar: PNG, GIF atau JPG. Maksimal %{size}. Ukuran dikecilkan menjadi %{dimensions}px\n        header: PNG, GIF atau JPG. Maksimal %{size}. Ukuran dikecilkan menjadi %{dimensions}px\n        locked: Anda harus menerima permintaan pengikut secara manual dan setting privasi postingan akan diubah khusus untuk pengikut\n      imports:\n        data: File CSV yang diexpor dari server Mastodon lain\n      sessions:\n        otp: Masukkan kode dua-faktor dari handphone atau gunakan kode pemulihan anda.\n    labels:\n      defaults:\n        confirm_new_password: Konfirmasi kata sandi baru\n        confirm_password: Konfirmasi kata sandi\n        current_password: Kata sandi sekarang\n        display_name: Nama yang ditampilkan\n        email: Alamat e-mail\n        locale: Bahasa\n        locked: Buat akun menjadi pribadi\n        new_password: Password baru\n        otp_attempt: Kode dua-faktor\n        password: Kata sandi\n        setting_boost_modal: Tampilkan dialog konfirmasi dialog sebelum boost\n        setting_default_privacy: Privasi postingan\n        severity: Keparahan\n        type: Tipe impor\n        username: Nama pengguna\n      interactions:\n        must_be_follower: Blokir notifikasi dari non-pengikut\n        must_be_following: Blokir notifikasi dari orang yang tidak anda ikuti\n      notification_emails:\n        digest: Kirim email berisi rangkuman\n        favourite: Kirim email saat seseorang menyukai status anda\n        follow: Kirim email saat seseorang mengikuti anda\n        follow_request: Kirim email saat seseorang meminta untuk mengikuti anda\n        mention: Kirim email saat seseorang menyebut anda\n        reblog: Kirim email saat seseorang mem-boost status anda\n    'no': Tidak\n    required:\n      text: wajib\n    'yes': Ya\n"
  },
  {
    "path": "config/locales/simple_form.io.yml",
    "content": "---\nio:\n  simple_form:\n    hints:\n      defaults:\n        avatar: En la formato PNG, GIF o JPG. Til %{size}. Esos mikrigita a %{dimensions}px\n        header: En la formato PNG, GIF o JPG. Til %{size}. Esos mikrigita a %{dimensions}px\n        locked: Tu devos aprobar omna demandi di sequado, e tua mesaji esos senchanje nur por tua sequanti.\n      imports:\n        data: Dosiero CSV de altra instaluro di Mastodon\n      sessions:\n        otp: Enter the Two-factor code from your phone or use one of your recovery codes.\n    labels:\n      defaults:\n        avatar: Profilimajo\n        confirm_new_password: Konfirmar nova pasvorto\n        confirm_password: Konfirmar nova pasvorto\n        current_password: Nuna pasvorto\n        data: Datumi\n        display_name: Publika nomo\n        email: Retpost-adreso\n        header: Kapimajo\n        locale: Linguo\n        locked: Privatigar la konto\n        new_password: Nova pasvorto\n        note: Suprizento\n        otp_attempt: Dufaktora identigilo\n        password: Pasvorto\n        setting_default_privacy: Videbleso di la mesaji\n        type: Tipo di importaco\n        username: Uzernomo\n      interactions:\n        must_be_follower: Celar la savigi da homi, qui ne sequas tu\n        must_be_following: Celar la savigi da homi, quin tu ne sequas\n      notification_emails:\n        digest: Sendar rezuma retpost-mesaji\n        favourite: Sendar retpost-mesajo, kande ulu favoras mesajo da tu\n        follow: Sendar retpost-mesajo, kande ulu sequeskas tu\n        follow_request: Sendar retpost-mesajo, kande ulu diskonocigas mesajo da tu\n        mention: Sendar retpost-mesajo, kande ulu mencionas tu\n        reblog: Sendar retpost-mesajo, kande ulu diskonocigas mesajo da tu\n    required:\n      text: bezonata\n"
  },
  {
    "path": "config/locales/simple_form.it.yml",
    "content": "---\nit:\n  simple_form:\n    hints:\n      account_warning_preset:\n        text: Puoi usare la sintassi dei toot, come URL, hashtag e menzioni\n      admin_account_action:\n        send_email_notification: L'utente riceverà una spiegazione di ciò che è successo con suo account\n        text_html: Opzionale. Puoi usare la sintassi dei toot. Puoi <a href=\"%{path}\">aggiungere avvisi preimpostati</a> per risparmiare tempo\n        type_html: Decidi cosa fare con <strong>%{acct}</strong>\n        warning_preset_id: Opzionale. Puoi aggiungere un testo personalizzato alla fine di quello preimpostato\n      defaults:\n        autofollow: Le persone che si iscrivono attraverso l'invito ti seguiranno automaticamente\n        avatar: PNG, GIF o JPG. Al massimo %{size}. Verranno scalate a %{dimensions}px\n        bot: Questo account esegue principalmente operazioni automatiche e potrebbe non essere tenuto sotto controllo da una persona\n        context: Uno o più contesti nei quali il filtro dovrebbe essere applicato\n        digest: Inviata solo dopo un lungo periodo di inattività e solo se hai ricevuto qualche messaggio personale in tua assenza\n        discoverable_html: La <a href=\"%{path}\" target=\"_blank\">directory</a> permette alle persone di trovare account in base a determinati interessi o attività. Richiede almeno %{min_followers} seguaci\n        email: Ti manderemo una email di conferma\n        fields: Puoi avere fino a 4 voci visualizzate come una tabella sul tuo profilo\n        header: PNG, GIF o JPG. Al massimo %{size}. Verranno scalate a %{dimensions}px\n        inbox_url: Copia la URL dalla pagina iniziale del ripetitore che vuoi usare\n        irreversible: I toot filtrati scompariranno in modo irreversibile, anche se il filtro viene eliminato\n        locale: La lingua dell'interfaccia utente, di email e notifiche push\n        locked: Richiede che approvi i follower manualmente\n        password: Usa almeno 8 caratteri\n        phrase: Il confronto sarà eseguito ignorando minuscole/maiuscole e i content warning\n        scopes: A quali API l'applicazione potrà avere accesso. Se selezionate un ambito di alto livello, non c'è bisogno di selezionare quelle singole.\n        setting_aggregate_reblogs: Non mostrare nuove condivisioni per toot che sono stati condivisi di recente (ha effetto solo sulle nuove condivisioni)\n        setting_display_media_default: Nascondi media segnati come sensibili\n        setting_display_media_hide_all: Nascondi sempre tutti i media\n        setting_display_media_show_all: Nascondi sempre i media segnati come sensibili\n        setting_hide_network: Chi segui e chi segue te non saranno mostrati sul tuo profilo\n        setting_noindex: Ha effetto sul tuo profilo pubblico e sulle pagine degli status\n        setting_show_application: L'applicazione che usi per pubblicare i toot sarà mostrata nella vista di dettaglio dei tuoi toot\n        username: Il tuo nome utente sarà unico su %{domain}\n        whole_word: Quando la parola chiave o la frase è solo alfanumerica, si applica solo se corrisponde alla parola intera\n      featured_tag:\n        name: 'Eccone alcuni che potresti usare:'\n      imports:\n        data: File CSV esportato da un altro server Mastodon\n      sessions:\n        otp: 'Inserisci il codice a due fattori generato dall''app del tuo telefono o usa uno dei codici di recupero:'\n      user:\n        chosen_languages: Quando una o più lingue sono contrassegnate, nelle timeline pubbliche vengono mostrati solo i toot nelle lingue selezionate\n    labels:\n      account:\n        fields:\n          name: Etichetta\n          value: Contenuto\n      account_warning_preset:\n        text: Testo preimpostato\n      admin_account_action:\n        send_email_notification: Informa l'utente via email\n        text: Avviso personalizzato\n        type: Azione\n        types:\n          disable: Disabilita\n          none: Non fare nulla\n          silence: Silenzia\n          suspend: Sospendi e cancella i dati dell'account in modo irreversibile\n        warning_preset_id: Usa un avviso preimpostato\n      defaults:\n        autofollow: Invita a seguire il tuo account\n        bot: Questo account è un bot\n        chosen_languages: Filtra lingue\n        confirm_new_password: Conferma nuova password\n        confirm_password: Conferma password\n        context: Contesti del filtro\n        current_password: Password corrente\n        discoverable: Inserisci questo account nella directory\n        display_name: Nome visualizzato\n        email: Indirizzo email\n        expires_in: Scade dopo\n        fields: Metadati del profilo\n        header: Intestazione\n        inbox_url: URL della inbox del ripetitore\n        irreversible: Elimina invece di nascondere\n        locale: Lingua dell'interfaccia\n        locked: Blocca account\n        max_uses: Numero massimo di utilizzi\n        new_password: Nuova password\n        note: Biografia\n        otp_attempt: Codice due-fattori\n        phrase: Parola chiave o frase\n        setting_aggregate_reblogs: Raggruppa condivisioni in timeline\n        setting_auto_play_gif: Play automatico GIF animate\n        setting_boost_modal: Mostra dialogo di conferma prima del boost\n        setting_default_language: Lingua dei post\n        setting_default_privacy: Privacy dei post\n        setting_default_sensitive: Segna sempre i media come sensibili\n        setting_delete_modal: Mostra dialogo di conferma prima di eliminare un toot\n        setting_display_media: Visualizzazione dei media\n        setting_display_media_default: Predefinita\n        setting_display_media_hide_all: Nascondi tutti\n        setting_display_media_show_all: Mostra tutti\n        setting_expand_spoilers: Espandi sempre toot con content warning\n        setting_hide_network: Nascondi la tua rete\n        setting_noindex: Non farti indicizzare dai motori di ricerca\n        setting_reduce_motion: Riduci movimento nelle animazioni\n        setting_show_application: Rendi pubblica l'applicazione usata per inviare i toot\n        setting_system_font_ui: Usa il carattere predefinito del sistema\n        setting_theme: Tema sito\n        setting_unfollow_modal: Chiedi conferma prima di smettere di seguire qualcuno\n        severity: Severità\n        type: Tipo importazione\n        username: Nome utente\n        username_or_email: Nome utente o email\n        whole_word: Parola intera\n      interactions:\n        must_be_follower: Blocca notifiche da chi non ti segue\n        must_be_following: Blocca notifiche dalle persone che non segui\n        must_be_following_dm: Blocca i messaggi diretti dalle persone che non segui\n      notification_emails:\n        digest: Invia email riassuntive\n        favourite: Invia email quando segna come preferito al tuo stato\n        follow: Invia email quando qualcuno ti segue\n        follow_request: Invia email quando qualcuno richiede di seguirti\n        mention: Invia email quando qualcuno ti menziona\n        reblog: Invia email quando qualcuno da un boost al tuo stato\n        report: Manda una mail quando viene inviato un nuovo rapporto\n    required:\n      text: richiesto\n    'yes': Si\n"
  },
  {
    "path": "config/locales/simple_form.ja.yml",
    "content": "---\nja:\n  simple_form:\n    hints:\n      account_warning_preset:\n        text: URL、ハッシュタグ、メンションなど、投稿に用いる構文が使用できます\n      admin_account_action:\n        send_email_notification: ユーザーは自分のアカウントに何が起こったのか説明を受け取ります\n        text_html: オプションです。投稿に用いる構文を使うことができます。簡略化のため<a href=\"%{path}\">プリセット警告文を追加</a>することができます\n        type_html: \"<strong>%{acct}</strong>さんに対し、何を行うか選択してください\"\n        warning_preset_id: オプションです。プリセット警告文の末尾に任意の文字列を追加することができます\n      defaults:\n        autofollow: 招待から登録した人が自動的にあなたをフォローするようになります\n        avatar: \"%{size}までのPNG、GIF、JPGが利用可能です。%{dimensions}pxまで縮小されます\"\n        bot: このアカウントは主に自動で動作し、人が見ていない可能性があります\n        context: フィルターを適用する対象 (複数選択可)\n        digest: 長期間使用していない場合と不在時に返信を受けた場合のみ送信されます\n        discoverable_html: <a href=\"%{path}\" target=\"_blank\">ディレクトリ</a> は興味や活動をもとにアカウントを見つけることを可能にします。 掲載には %{min_followers} 人以上のフォロワーが必要です\n        email: 確認のメールが送信されます\n        fields: プロフィールに表として4つまでの項目を表示することができます\n        header: \"%{size}までのPNG、GIF、JPGが利用可能です。 %{dimensions}pxまで縮小されます\"\n        inbox_url: 使用したいリレーサーバーのトップページからURLをコピーします\n        irreversible: フィルターが後で削除されても、除外されたトゥートは元に戻せなくなります\n        locale: ユーザーインターフェース、メールやプッシュ通知の言語\n        locked: フォロワーを手動で承認する必要があります\n        password: 少なくとも8文字は入力してください\n        phrase: トゥートの大文字小文字や閲覧注意に関係なく一致\n        scopes: アプリの API に許可するアクセス権を選択してください。最上位のスコープを選択する場合、個々のスコープを選択する必要はありません。\n        setting_aggregate_reblogs: 最近ブーストされたトゥートが新たにブーストされても表示しません (設定後受信したものにのみ影響)\n        setting_default_sensitive: 閲覧注意状態のメディアはデフォルトでは内容が伏せられ、クリックして初めて閲覧できるようになります\n        setting_display_media_default: 閲覧注意としてマークされたメディアは隠す\n        setting_display_media_hide_all: 全てのメディアを常に隠す\n        setting_display_media_show_all: 閲覧注意としてマークされたメディアも常に表示する\n        setting_hide_network: フォローとフォロワーの情報がプロフィールページで見られないようにします\n        setting_noindex: 公開プロフィールおよび各投稿ページに影響します\n        setting_show_application: トゥートするのに使用したアプリがトゥートの詳細ビューに表示されるようになります\n        username: あなたのユーザー名は %{domain} の中で重複していない必要があります\n        whole_word: キーワードまたはフレーズが英数字のみの場合、単語全体と一致する場合のみ適用されるようになります\n      featured_tag:\n        name: 'これらを使うといいかもしれません:'\n      imports:\n        data: 他の Mastodon サーバーからエクスポートしたCSVファイルを選択して下さい\n      invite_request:\n        text: このサーバーは現在承認制です。申請を承認する際に役立つメッセージを添えてください\n      sessions:\n        otp: '携帯電話のアプリで生成された二段階認証コードを入力するか、リカバリーコードを使用してください:'\n      user:\n        chosen_languages: 選択すると、選択した言語のトゥートのみが公開タイムラインに表示されるようになります\n    labels:\n      account:\n        fields:\n          name: ラベル\n          value: 内容\n      account_warning_preset:\n        text: プリセット警告文\n      admin_account_action:\n        send_email_notification: メールでユーザーに通知\n        text: カスタム警告文\n        type: アクション\n        types:\n          disable: 無効化\n          none: 何もしない\n          silence: サイレンス\n          suspend: 停止しアカウントのデータを恒久的に削除する\n        warning_preset_id: プリセット警告文を使用\n      defaults:\n        autofollow: 招待から参加後、あなたをフォロー\n        avatar: アイコン\n        bot: これは BOT アカウントです\n        chosen_languages: 表示する言語\n        confirm_new_password: 新しいパスワード（確認用）\n        confirm_password: パスワード（確認用）\n        context: 除外対象\n        current_password: 現在のパスワード\n        data: データ\n        discoverable: ディレクトリに掲載する\n        display_name: 表示名\n        email: メールアドレス\n        expires_in: 有効期限\n        fields: プロフィール補足情報\n        header: ヘッダー\n        inbox_url: リレーサーバーの inbox URL\n        irreversible: 隠すのではなく除外する\n        locale: 言語\n        locked: 承認制アカウントにする\n        max_uses: 使用できる回数\n        new_password: 新しいパスワード\n        note: プロフィール\n        otp_attempt: 二段階認証コード\n        password: パスワード\n        phrase: キーワードまたはフレーズ\n        setting_advanced_layout: 上級者向け UI を有効にする\n        setting_aggregate_reblogs: ブーストをまとめる\n        setting_auto_play_gif: アニメーションGIFを自動再生する\n        setting_boost_modal: ブーストする前に確認ダイアログを表示する\n        setting_default_language: 投稿する言語\n        setting_default_privacy: 投稿の公開範囲\n        setting_default_sensitive: メディアを常に閲覧注意としてマークする\n        setting_delete_modal: トゥートを削除する前に確認ダイアログを表示する\n        setting_display_media: メディアの表示\n        setting_display_media_default: 標準\n        setting_display_media_hide_all: 非表示\n        setting_display_media_show_all: 表示\n        setting_expand_spoilers: 閲覧注意としてマークされたトゥートを常に展開する\n        setting_hide_network: 繋がりを隠す\n        setting_noindex: 検索エンジンによるインデックスを拒否する\n        setting_reduce_motion: アニメーションの動きを減らす\n        setting_show_application: 送信したアプリを開示する\n        setting_system_font_ui: システムのデフォルトフォントを使う\n        setting_theme: サイトテーマ\n        setting_unfollow_modal: フォローを解除する前に確認ダイアログを表示する\n        severity: 重大性\n        type: インポートする項目\n        username: ユーザー名\n        username_or_email: ユーザー名またはメールアドレス\n        whole_word: 単語全体にマッチ\n      featured_tag:\n        name: ハッシュタグ\n      interactions:\n        must_be_follower: フォロワー以外からの通知をブロック\n        must_be_following: フォローしていないユーザーからの通知をブロック\n        must_be_following_dm: フォローしていないユーザーからのダイレクトメッセージをブロック\n      invite_request:\n        text: 意気込みをお聞かせください\n      notification_emails:\n        digest: タイムラインからピックアップしてメールで通知する\n        favourite: お気に入りに登録された時にメールで通知する\n        follow: フォローされた時にメールで通知する\n        follow_request: フォローリクエストを受けた時にメールで通知する\n        mention: 返信が来た時にメールで通知する\n        pending_account: 新しいアカウントの承認が必要な時にメールで通知する\n        reblog: トゥートがブーストされた時にメールで通知する\n        report: 通報を受けた時にメールで通知する\n    'no': いいえ\n    recommended: おすすめ\n    required:\n      text: 必須\n    'yes': はい\n"
  },
  {
    "path": "config/locales/simple_form.ka.yml",
    "content": "---\nka:\n  simple_form:\n    hints:\n      defaults:\n        autofollow: ადამიანები რომლებიც დარეგისტრირდებიან მოწვევით, ავტომატურად გამოგყვებიან\n        avatar: პნგ, გიფ ან ჯპგ. მაქს. %{size}. ზომა დაპატარავდება %{dimensions}პიქს.-ზე\n        bot: ეს ანგარიში უმთავრესად ასრულებს ავტომატურ მოქმედებებს და შესაძლოა არ იყოს მონიტორინგის ქვეშ\n        context: ერთ ან მრავალი კონტექსტი სადაც ფილტრი უნდა შესრულდეს\n        digest: იგზავნება მხოლოდ ხანგრძლივი უაქტივობის პერიოდის შემდეგ და არყოფნისას თუ მიიღეთ ერთი წერილი მაინც\n        fields: პროფილზე ტაბულის სახით შესაძლოა საჩვენებლად გაგაჩნდეთ მაქს. 4 პუნქტი\n        header: პნგ, გიფ ან ჯპგ. მაქს. %{size}. ზომა დაპატარავდება %{dimensions}პიქს.-ზე\n        inbox_url: ურლ დააკოირეთ გამოყენებისთვის სასურველი რილეის წინა გვერდიდან\n        irreversible: გაფილტრული ტუტები გაუქმდება აღუდგენლად, იმ შემთხვევაშიც კი თუ ფილტრი სამომავლოდ გაუქმდება\n        locale: მომხმარებლის ინტერფეისის, ელ-ფოსტის წერილების და ფუშ შეტყობინებების ენა\n        locked: საჭიროებს თქვენ მიერ მიმდევრების ხელით დადასტურებას\n        phrase: დამთხვევა მოხდება დიდი და პატარა ასოების ან კონტენტის გაფრთხილების გათვალისწინების გარეშე\n        scopes: რომელი აპიებისადმი ექნება აპლიკაციას ცვდომა. თუ არიჩევთ უმთავრეს ფარგლებს, არ დაგჭირდებათ ინდივიდუალურების ამორჩევა.\n        setting_hide_network: ვის მიყვებით და ვინ მოგყვებათ არ გამოჩნდება აქ\n        setting_noindex: გავლენას ახდენს თქვენს ღია პროფილისა და სტატუსის გვერდებზე\n        whole_word: როდესაც სიტყვა ან ფრაზა მხოლოდ ალფა-ნუმერიკულია, ის დაფიქსირდება თუ ემთხვევა სრულ სიტყვას\n      imports:\n        data: ცსვ ფაილის ექსპორტი მოხდა მასტოდონის სხვა ინსტანციიდან\n      sessions:\n        otp: 'შეიყვანეთ მეორე ფაქტორის კოდი, რომელიც დააგერირა თქვენმა ტელეფონმა ან მოიხმარეთ შემდეგი აღდგენის კოდებიდან ერთ-ერთი:'\n      user:\n        chosen_languages: როდესაც მოინიშნება, ღია თაიმლაინზე გამოჩნდება ტუტები მხოლოდ არჩეულ ენებზე\n    labels:\n      account:\n        fields:\n          name: ლეიბლი\n          value: მოცულობა\n      defaults:\n        autofollow: მოიწვიეთ რომ გამოჰყვნენ თქვენს ანგარიშს\n        avatar: ავატარი\n        bot: ეს ბოტის ანგარიშია\n        chosen_languages: ენების ფილტრი\n        confirm_new_password: დაადასტურეთ ახალი პაროლი\n        confirm_password: დაადასტურეთ პაროლი\n        context: კონტექსტის ფილტრი\n        current_password: მიმდინარე პაროლი\n        data: მონაცემები\n        display_name: დისპლეის სახელი\n        email: ელ-ფოსტის მისამართი\n        expires_in: ვადის გასვლის დრო\n        fields: პროფილის მეტა-მონაცემი\n        header: დასათაურება\n        inbox_url: რილეი ინბოქსის ურლ\n        irreversible: გაუქმდეს დამალვის მაგივრად\n        locale: ინტერფეისის ენა\n        locked: ანგარიშის ჩაკეტვა\n        max_uses: მოხმარების მაქს. ოდენობა\n        new_password: ახალი პაროლი\n        note: ბიო.\n        otp_attempt: მეორე-ფაქტორის კოდი\n        password: პაროლი\n        phrase: სიტყვა ან ფრაზა\n        setting_auto_play_gif: ანიმაციური გიფების ავტო-დაკვრა\n        setting_boost_modal: ბუსტამე მოხდეს დამოწმება\n        setting_default_language: პოსტინგის ენა\n        setting_default_privacy: პოსტის კონფიდენციალურობა\n        setting_default_sensitive: ყოველთვის მოინიშნოს მედია მგრძნობიარედ\n        setting_delete_modal: ტუტის გაუქმებამდე გამოჩნდეს დადასტურების ფანჯარა\n        setting_hide_network: თქვენი ქსელის დამალვა\n        setting_noindex: საძოები სისტემების ინდექსაციის შეჩერება\n        setting_reduce_motion: მოძრაობის შემცირება ანიმაციებში\n        setting_system_font_ui: მოხდეს სისტემის საწყისი ფონტის მოხმარება\n        setting_theme: საიტის თემა\n        setting_unfollow_modal: გამოჩნდეს დადასტურების ფანჯარა, სანამ შეყვეტთ ვინმეს დადევნებას\n        severity: სიმძიმე\n        type: იმპორტის სახეობა\n        username: მომხმარებლის სახელი\n        username_or_email: მომხმარებლის სახელი ან ელ-ფოსტა\n        whole_word: მთელი სიტყვა\n      interactions:\n        must_be_follower: დაიბლოკოს შეტყობინებები არა მიმდევრებისგან\n        must_be_following: დაიბლოკოს შეტყობინებები ადამიანებისგან ვისაც არ მიჰყვებით\n        must_be_following_dm: დაიბლოკოს პირადი წერილები ადამიანბისგან ვისაც არ მიჰყვებით\n      notification_emails:\n        digest: გამოიგზავნოს დაიჯესტ წერილები\n        favourite: გამოიგზავნოს წერილი როდესაც ვინმე ფავორიტად აქცევს თქვენს სტატუსს\n        follow: გამოიგზავნოს წერილი როდესაც ვინმე გამოგყვებათ\n        follow_request: გამოიგზავნოს წერილი როდესაც ვინმე მოგთხოვთ გაჰყვეთ\n        mention: გამოიგზავნოს წერილი როდესაც ვინმე გასახელებთ\n        reblog: გამოიგზავნოს წერილი როდესაც ვინმე გაზრდის თქვენს სტატუსს\n    'no': არა\n    required:\n      text: აუცილებელი\n    'yes': კი\n"
  },
  {
    "path": "config/locales/simple_form.kk.yml",
    "content": "kk:\n"
  },
  {
    "path": "config/locales/simple_form.ko.yml",
    "content": "---\nko:\n  simple_form:\n    hints:\n      account_warning_preset:\n        text: URL, 해시태그, 멘션과 같은 툿 문법을 사용할 수 있습니다\n      admin_account_action:\n        send_email_notification: 유저는 어떤 일이 일어났는 지에 대한 설명을 받게 됩니다\n        text_html: 선택사항. 툿 문법을 사용할 수 있습니다. <a href=\"%{path}\">경고 틀을 추가</a>하여 시간을 절약할 수 있습니다\n        type_html: \"<strong>%{acct}</strong>에 대해 취할 행동 선택\"\n        warning_preset_id: 선택사항. 틀의 마지막에 임의의 텍스트를 추가 할 수 있습니다\n      defaults:\n        autofollow: 이 초대를 통해 가입하는 사람은 당신을 자동으로 팔로우 하게 됩니다\n        avatar: PNG, GIF 혹은 JPG. 최대 %{size}. %{dimensions}px로 다운스케일 될 것임\n        bot: 사람들에게 계정이 사람이 아님을 알립니다\n        context: 필터를 적용 할 한 개 이상의 컨텍스트\n        digest: 오랫동안 활동하지 않았을 때 받은 멘션들에 대한 요약 받기\n        discoverable_html: <a href=\"%{path}\" target=\"_blank\">디렉토리</a> 는 사람들의 관심사와 활동에 관련 된 계정들을 찾을 수 있게 해 줍니다. 최소 %{min_followers}명의 팔로어가 필요합니다\n        email: 당신은 확인 메일을 받게 됩니다\n        fields: 당신의 프로파일에 최대 4개까지 표 형식으로 나타낼 수 있습니다\n        header: PNG, GIF 혹은 JPG. 최대 %{size}. %{dimensions}px로 다운스케일 됨\n        inbox_url: 사용 할 릴레이 서버의 프론트페이지에서 URL을 복사합니다\n        irreversible: 필터링 된 툿은 나중에 필터가 사라지더라도 돌아오지 않게 됩니다\n        locale: 유저 인터페이스, 이메일, 푸시 알림 언어\n        locked: 수동으로 팔로워를 승인하고, 기본 툿 프라이버시 설정을 팔로워 전용으로 변경\n        password: 최소 8글자\n        phrase: 툿 내용이나 CW 내용 안에서 대소문자 구분 없이 매칭 됩니다\n        scopes: 애플리케이션에 허용할 API들입니다. 최상위 스코프를 선택하면 개별적인 것은 선택하지 않아도 됩니다.\n        setting_aggregate_reblogs: 내가 부스트 했던 툿은 새로 부스트 되어도 보여주지 않습니다\n        setting_default_sensitive: 민감한 미디어는 기본적으로 가려져 있으며 클릭해서 볼 수 있습니다\n        setting_display_media_default: 민감함으로 설정 된 미디어 가리기\n        setting_display_media_hide_all: 항상 모든 미디어를 가리기\n        setting_display_media_show_all: 민감함으로 설정 된 미디어를 항상 보이기\n        setting_hide_network: 나를 팔로우 하는 사람들과 내가 팔로우 하는 사람들이 내 프로필에 표시되지 않게 합니다\n        setting_noindex: 공개 프로필 및 각 툿페이지에 영향을 미칩니다\n        setting_show_application: 당신이 툿을 작성하는데에 사용한 앱이 툿의 상세정보에 표시 됩니다\n        username: 당신의 유저네임은 %{domain} 안에서 유일해야 합니다\n        whole_word: 키워드가 영문과 숫자로만 이루어 진 경우, 단어 전체에 매칭 되었을 때에만 작동하게 합니다\n      featured_tag:\n        name: '이것들을 사용하면 좋을 것 같습니다:'\n      imports:\n        data: 다른 마스토돈 서버에서 추출된 CSV 파일\n      invite_request:\n        text: 이 정보는 우리가 심사를 하는 데에 참고할 수 있습니다\n      sessions:\n        otp: '휴대전화에서 생성 된 2단계 인증 코드를 입력하거나, 복구 코드 중 하나를 사용하세요:'\n      user:\n        chosen_languages: 체크하면, 선택 된 언어들만 공개 타임라인에 보여집니다\n    labels:\n      account:\n        fields:\n          name: 라벨\n          value: 내용\n      account_warning_preset:\n        text: 프리셋 텍스트\n      admin_account_action:\n        send_email_notification: 이메일로 유저에게 알리기\n        text: 커스텀 경고\n        type: 조치\n        types:\n          disable: 비활성화\n          none: 아무 것도 하지 않기\n          silence: 침묵\n          suspend: 정지하고 되돌릴 수 없는 데이터 삭제\n        warning_preset_id: 경고 틀 사용하기\n      defaults:\n        autofollow: 초대를 통한 팔로우\n        avatar: 아바타\n        bot: 이것은 봇 계정입니다\n        chosen_languages: 언어 필터링\n        confirm_new_password: 암호 다시 입력\n        confirm_password: 암호 다시 입력\n        context: 필터 컨텍스트\n        current_password: 현재 암호 입력\n        data: 데이터\n        discoverable: 이 계정을 디렉토리에서 찾을 수 있도록 합니다\n        display_name: 표시되는 이름\n        email: 이메일 주소\n        expires_in: 만료시각\n        fields: 프로필 메타데이터\n        header: 헤더\n        inbox_url: 릴레이 서버의 inbox URL\n        irreversible: 숨기는 대신 삭제\n        locale: 인터페이스 언어\n        locked: 계정 잠금\n        max_uses: 사용 횟수 제한\n        new_password: 새로운 암호 입력\n        note: 자기소개\n        otp_attempt: 2단계 인증 코드\n        password: 암호\n        phrase: 키워드 또는 문장\n        setting_advanced_layout: 고급 웹 UI 활성화\n        setting_aggregate_reblogs: 타임라인의 부스트를 그룹화\n        setting_auto_play_gif: 애니메이션 GIF를 자동 재생\n        setting_boost_modal: 부스트 전 확인 창을 표시\n        setting_default_language: 게시물 언어\n        setting_default_privacy: 툿 프라이버시\n        setting_default_sensitive: 미디어를 언제나 민감한 컨텐츠로 설정\n        setting_delete_modal: 툿 삭제 전 확인 창을 표시\n        setting_display_media: 미디어 표시\n        setting_display_media_default: 기본\n        setting_display_media_hide_all: 모두 가리기\n        setting_display_media_show_all: 모두 보이기\n        setting_expand_spoilers: 열람주의 툿을 항상 펼치기\n        setting_hide_network: 내 네트워크 숨기기\n        setting_noindex: 검색엔진의 인덱싱을 거절\n        setting_reduce_motion: 애니메이션 줄이기\n        setting_show_application: 툿 작성에 사용한 앱을 공개\n        setting_system_font_ui: 시스템의 초기 설정 폰트를 사용\n        setting_theme: 사이트 테마\n        setting_unfollow_modal: 언팔로우 전 언팔로우 확인 표시\n        severity: 심각도\n        type: 불러오기 종류\n        username: 유저 이름\n        username_or_email: 유저네임 또는 이메일\n        whole_word: 단어 전체에 매칭\n      featured_tag:\n        name: 해시태그\n      interactions:\n        must_be_follower: 나를 팔로우 하지 않는 사람에게서 온 알림을 차단\n        must_be_following: 내가 팔로우 하지 않는 사람에게서 온 알림을 차단\n        must_be_following_dm: 내가 팔로우 하지 않은 사람에게서 오는 다이렉트메시지를 차단\n      invite_request:\n        text: 가입하려는 이유가 무엇인가요?\n      notification_emails:\n        digest: 요약 이메일 보내기\n        favourite: 누군가 내 상태를 즐겨찾기로 등록했을 때 이메일 보내기\n        follow: 누군가 나를 팔로우 했을 때 이메일 보내기\n        follow_request: 누군가 나를 팔로우 하길 원할 때 이메일 보내기\n        mention: 누군가 나에게 답장했을 때 이메일 보내기\n        pending_account: 새 계정이 심사가 필요할 때 이메일 보내기\n        reblog: 누군가 내 툿을 부스트 했을 때 이메일 보내기\n        report: 새 신고 등록시 이메일로 알리기\n    'no': 아니오\n    recommended: 추천함\n    required:\n      text: 필수 항목\n    'yes': 네\n"
  },
  {
    "path": "config/locales/simple_form.lt.yml",
    "content": "lt:\n"
  },
  {
    "path": "config/locales/simple_form.lv.yml",
    "content": "lv:\n"
  },
  {
    "path": "config/locales/simple_form.ms.yml",
    "content": "ms:\n"
  },
  {
    "path": "config/locales/simple_form.nl.yml",
    "content": "---\nnl:\n  simple_form:\n    hints:\n      account_warning_preset:\n        text: Je kunt voor toots specifieke tekst gebruiken, zoals URL's, hashtags en vermeldingen\n      admin_account_action:\n        send_email_notification: De gebruiker ontvangt een uitleg over wat er met hun account is gebeurd\n        text_html: Optioneel. Je kunt voor toots specifieke tekst gebruiken. Om tijd te besparen kun je <a href=\"%{path}\">voorinstellingen van waarschuwingen toevoegen</a>\n        type_html: Kies wat er met <strong>%{acct}</strong> moet gebeuren\n        warning_preset_id: Optioneel. Je kunt nog steeds handmatig tekst toevoegen aan het eind van de voorinstelling\n      defaults:\n        autofollow: Mensen die zich via de uitnodiging hebben geregistreerd, volgen jou automatisch\n        avatar: PNG, GIF of JPG. Maximaal %{size}. Wordt teruggeschaald naar %{dimensions}px\n        bot: Dit is een geautomatiseerd account en wordt mogelijk niet gemonitord\n        context: Een of meerdere locaties waar de filter actief moet zijn\n        digest: Wordt alleen na een lange periode van inactiviteit verzonden en alleen wanneer je tijdens jouw afwezigheid persoonlijke berichten hebt ontvangen\n        discoverable_html: In de <a href=\"%{path}\" target=\"_blank\">gebruikersgids</a> kunnen mensen andere accounts vinden aan de hand van interesses en activiteit. Dit vereist tenminste %{min_followers} volgers\n        email: Je krijgt een bevestigingsmail\n        fields: Je kan maximaal 4 items als een tabel op je profiel weergeven\n        header: PNG, GIF of JPG. Maximaal %{size}. Wordt teruggeschaald naar %{dimensions}px\n        inbox_url: Kopieer de URL van de voorpagina van de relayserver die je wil gebruiken\n        irreversible: Gefilterde toots verdwijnen onomkeerbaar, zelfs als de filter later wordt verwijderd\n        locale: De taal van de gebruikersomgeving, e-mails en pushmeldingen\n        locked: Vereist dat je handmatig volgers moet accepteren\n        password: Gebruik tenminste 8 tekens\n        phrase: Komt overeen ongeacht hoofd-/kleine letters of tekstwaarschuwingen\n        scopes: Tot welke API's heeft de toepassing toegang. Wanneer je een toestemming van het bovenste niveau kiest, hoef je geen individuele toestemmingen meer te kiezen.\n        setting_aggregate_reblogs: Geen nieuwe boosts tonen voor toots die recentelijk nog zijn geboost (heeft alleen effect op nieuw ontvangen boosts)\n        setting_default_sensitive: Gevoelige media wordt standaard verborgen en kan met één klik worden getoond\n        setting_display_media_default: Als gevoelig gemarkeerde media verbergen\n        setting_display_media_hide_all: Media altijd verbergen\n        setting_display_media_show_all: Als gevoelig gemarkeerde media altijd verbergen\n        setting_hide_network: Wie jij volgt en wie jou volgen wordt niet op jouw profiel getoond\n        setting_noindex: Heeft invloed op jouw openbare profiel en toots\n        setting_show_application: De toepassing de je gebruikt om te tooten wordt in de gedetailleerde weergave van de toot getoond\n        username: Jouw gebruikersnaam is uniek op %{domain}\n        whole_word: Wanneer het trefwoord of zinsdeel alfanumeriek is, wordt het alleen gefilterd wanneer het hele woord overeenkomt\n      featured_tag:\n        name: 'Je wilt misschien een van deze gebruiken:'\n      imports:\n        data: CSV-bestand dat op een andere Mastodonserver werd geëxporteerd\n      invite_request:\n        text: Dit helpt ons om jouw aanvraag te beoordelen\n      sessions:\n        otp: 'Voer de tweestaps-aanmeldcode vanaf jouw mobiele telefoon in of gebruik een van jouw herstelcodes:'\n      user:\n        chosen_languages: Alleen toots in de aangevinkte talen worden op de openbare tijdlijnen getoond\n    labels:\n      account:\n        fields:\n          name: Label\n          value: Inhoud\n      account_warning_preset:\n        text: Tekst van voorinstelling\n      admin_account_action:\n        send_email_notification: Meld dit per e-mail aan de gebruiker\n        text: Aangepaste waarschuwing\n        type: Actie\n        types:\n          disable: Uitschakelen\n          none: Niets doen\n          silence: Negeren\n          suspend: Opschorten en onomkeerbaar accountgegevens verwijderen\n        warning_preset_id: Gebruik een voorinstelling van een waarschuwing\n      defaults:\n        autofollow: Uitnodigen om jouw account te volgen\n        avatar: Avatar\n        bot: Dit is een bot-account\n        chosen_languages: Talen filteren\n        confirm_new_password: Nieuw wachtwoord bevestigen\n        confirm_password: Wachtwoord bevestigen\n        context: Filterlocaties\n        current_password: Huidig wachtwoord\n        data: Gegevens\n        discoverable: Dit account in de gebruikersgids tonen\n        display_name: Weergavenaam\n        email: E-mailadres\n        expires_in: Vervalt na\n        fields: Metadata profiel\n        header: Omslagfoto\n        inbox_url: Inbox-URL van de relayserver\n        irreversible: Verwijderen in plaats van verbergen\n        locale: Taal van de gebruikersomgeving\n        locked: Maak account besloten\n        max_uses: Max. aantal keer te gebruiken\n        new_password: Nieuwe wachtwoord\n        note: Bio\n        otp_attempt: Tweestaps-aanmeldcode\n        password: Wachtwoord\n        phrase: Trefwoord of zinsdeel\n        setting_advanced_layout: Geavanceerde webomgeving inschakelen\n        setting_aggregate_reblogs: Boosts in tijdlijnen groeperen\n        setting_auto_play_gif: Speel geanimeerde GIF's automatisch af\n        setting_boost_modal: Vraag voor het boosten van een toot een bevestiging\n        setting_default_language: Taal van jouw toots\n        setting_default_privacy: Standaardzichtbaarheid van jouw toots\n        setting_default_sensitive: Media altijd als gevoelig markeren\n        setting_delete_modal: Vraag voor het verwijderen van een toot een bevestiging\n        setting_display_media: Mediaweergave\n        setting_display_media_default: Standaard\n        setting_display_media_hide_all: Alles verbergen\n        setting_display_media_show_all: Alles tonen\n        setting_expand_spoilers: Altijd toots met tekstwaarschuwingen uitklappen\n        setting_hide_network: Jouw volgers en wie je volgt verbergen\n        setting_home_dms: Directe berichten onder Start tonen\n        setting_noindex: Jouw toots niet door zoekmachines laten indexeren\n        setting_reduce_motion: Langzamere animaties\n        setting_show_application: Toepassing onthullen die je voor het verzenden van toots gebruikt\n        setting_system_font_ui: Standaardlettertype van jouw systeem gebruiken\n        setting_theme: Thema website\n        setting_unfollow_modal: Vraag voor het ontvolgen van iemand een bevestiging\n        severity: Zwaarte\n        type: Importtype\n        username: Gebruikersnaam\n        username_or_email: Gebruikersnaam of e-mailadres\n        whole_word: Heel woord\n      featured_tag:\n        name: Hashtag\n      interactions:\n        must_be_follower: Meldingen van mensen die jou niet volgen blokkeren\n        must_be_following: Meldingen van mensen die jij niet volgt blokkeren\n        must_be_following_dm: Directe berichten van mensen die jij niet volgt blokkeren\n      invite_request:\n        text: Waarom wil jij je aanmelden?\n      notification_emails:\n        digest: Periodiek e-mails met een samenvatting versturen\n        favourite: Een e-mail versturen wanneer iemand jouw toot aan hun favorieten heeft toegevoegd\n        follow: Een e-mail versturen wanneer iemand jou volgt\n        follow_request: Een e-mail versturen wanneer iemand jou wil volgen\n        mention: Een e-mail versturen wanneer iemand jou vermeld\n        pending_account: Een e-mail verzenden wanneer een nieuw account moet worden beoordeeld\n        reblog: Een e-mail versturen wanneer iemand jouw toot heeft geboost\n        report: Verstuur een e-mail wanneer een nieuw rapportage is ingediend\n    'no': Nee\n    recommended: Aanbevolen\n    required:\n      mark: \"*\"\n      text: vereist\n    'yes': Ja\n"
  },
  {
    "path": "config/locales/simple_form.no.yml",
    "content": "---\n'no':\n  simple_form:\n    hints:\n      defaults:\n        avatar: PNG, GIF eller JPG. Maksimalt %{size}. Vil bli nedskalert til %{dimensions}px\n        digest: Kun sendt etter en lang periode med inaktivitet og bare dersom du har mottatt noen personlige meldinger mens du var borte\n        header: PNG, GIF eller JPG. Maksimalt %{size}. Vil bli nedskalert til %{dimensions}px\n        locked: Krever at du manuelt godkjenner følgere\n        setting_noindex: Påvirker din offentlige profil og statussider\n      imports:\n        data: CSV-fil eksportert fra en annen Mastodon-instans\n      sessions:\n        otp: Angi tofaktorkoden fra din telefon eller bruk en av dine gjenopprettingskoder.\n    labels:\n      defaults:\n        confirm_new_password: Bekreft nytt passord\n        confirm_password: Bekreft passord\n        current_password: Nåværende passord\n        display_name: Visningsnavn\n        email: E-postadresse\n        expires_in: Utløper etter\n        header: Overskrift\n        locale: Språk\n        locked: Lås konto\n        max_uses: Maksimalt antall bruk\n        new_password: Nytt passord\n        note: Om meg\n        otp_attempt: Tofaktorkode\n        password: Passord\n        setting_auto_play_gif: Autoavspill animert GIF-filer\n        setting_boost_modal: Vis bekreftelse før fremheving\n        setting_default_privacy: Postintegritet\n        setting_default_sensitive: Marker alltid media som sensitivt\n        setting_delete_modal: Vis bekreftelse før du sletter en tut\n        setting_noindex: Ikke delta i søkemotorsindeksering\n        setting_reduce_motion: Reduser bevegelser i animasjoner\n        setting_system_font_ui: Bruk systemets standardfont\n        setting_theme: Sidens tema\n        setting_unfollow_modal: Vis bekreftelse før du slutter å følge noen\n        severity: Alvorlighetsgrad\n        type: Importeringstype\n        username: Brukernavn\n      interactions:\n        must_be_follower: Blokker varslinger fra ikke-følgere\n        must_be_following: Blokker varslinger fra personer du ikke følger\n        must_be_following_dm: Blokker direkte meldinger fra personer du ikke følger\n      notification_emails:\n        digest: Send sammendrag på e-post\n        favourite: Send e-post når noen setter din status som favoritt\n        follow: Send e-post når noen følger deg\n        follow_request: Send e-post når noen ber om å få følge deg\n        mention: Send e-post når noen nevner deg\n        reblog: Send e-post når noen fremhever din status\n    'no': Nei\n    required:\n      text: obligatorisk\n    'yes': Ja\n"
  },
  {
    "path": "config/locales/simple_form.oc.yml",
    "content": "---\noc:\n  simple_form:\n    hints:\n      account_warning_preset:\n        text: Podètz utilizar la sintaxi dels tuts, coma las URL, las etiquetas e las mencions\n      admin_account_action:\n        send_email_notification: L’utilizaire recebrà una explicacion de çò qu’arribèt a son compte\n        text_html: Opcional. Podètz utilizar la sintaxi dels tuts. Podètz <a href=\"%{path}\">ajustar un avertiment personalizat</a> per estalviar de temps\n        type_html: Causir de qué far amb <strong>%{acct}</strong>\n        warning_preset_id: Opcional. Podètz ajustar un tèxt personalizat a a fin de çò predefinit\n      defaults:\n        autofollow: Lo monde que se marcan gràcia a l’invitacion vos segràn automaticament\n        avatar: PNG, GIF o JPG. Maximum %{size}. Serà retalhat en %{dimensions}px\n        bot: Avisar lo monde qu’aqueste compte es pas d’una persona\n        context: Un o mai de contèxtes ont lo filtre deuriá s’aplicar\n        digest: Solament enviat aprèp un long moment d’inactivitat e solament s’avètz recebut de messatges personals pendent vòstra abséncia\n        discoverable_html: L’<a href=\"%{path}\" target=\"_blank\">annuari</a> permet al monde de trobar de comptes segon lor interèsses e activitats. Requerís almens %{min_followers} seguidors\n        email: Vos mandarem un corrièl de confirmacion\n        fields: Podètz far veire cap a 4 elements sus vòstre perfil\n        header: PNG, GIF o JPG. Maximum %{size}. Serà retalhada en %{dimensions}px\n        inbox_url: Copiatz l’URL de la pagina màger del relai que volètz utilizar\n        irreversible: Los tuts filtrats desapareisseràn irreversiblament, encara que lo filtre siá suprimit mai tard\n        locale: La lenga de l’interfàcia d’utilizacion, los messatges e las notificacions\n        locked: Demanda qu’acceptetz manualament lo mond que vos sègon e botarà la visibilitat de vòstras publicacions coma accessiblas a vòstres seguidors solament\n        password: Utilizatz almens 8 caractèrs\n        phrase: Serà pres en compte que siá en majuscula o minuscula o dins un avertiment de contengut sensible\n        scopes: A quinas APIs poiràn accedir las aplicacions. Se seleccionatz un encastre de naut nivèl, fa pas mestièr de seleccionar los nivèls mai basses.\n        setting_aggregate_reblogs: Mostrar pas los nòus partatges que son estats partejats recentament (afecta pas que los nòus partatges recebuts)\n        setting_display_media_default: Rescondre los mèdias marcats coma sensibles\n        setting_display_media_hide_all: Totjorn rescondre los mèdias\n        setting_display_media_show_all: Totjorn mostrar los mèdias marcats coma sensibles\n        setting_hide_network: Vòstre perfil mostrarà pas los que vos sègon e lo monde que seguètz\n        setting_noindex: Aquò es destinat a vòstre perfil public e vòstra pagina d’estatuts\n        setting_show_application: Lo nom de l’aplicacion qu’utilizatz per publicar serà mostrat dins la vista detalhada de vòstres tuts\n        username: Vòstre nom d’utilizaire serà unic sus %{domain}\n        whole_word: Quand lo mot-clau o frasa es solament alfranumeric, serà pas qu’aplicat se correspond al mot complèt\n      featured_tag:\n        name: 'Benlèu que volètz utilizar una d’aquestas causas :'\n      imports:\n        data: Fichièr CSV exportat d’un autre servidor Mastodon\n      invite_request:\n        text: Aquò nos ajudarà per validar vòstra demanda\n      sessions:\n        otp: 'Picatz lo còdi d’autentificacion en dos temps (Two factor code) de vòstra aplicacion mobil o utilizatz un de vòstres còdis de recuperacion :'\n      user:\n        chosen_languages: Quand seleccionadas, solament los tuts dins las lengas triadas seràn mostrats dins vòstre flux d’actualitat\n    labels:\n      account:\n        fields:\n          name: Nom\n          value: Contengut\n      account_warning_preset:\n        text: Tèxt predefinit\n      admin_account_action:\n        send_email_notification: Avisar l’utilizaire per corrièl\n        text: Avertiment personalizat\n        type: Accions\n        types:\n          disable: Desactivar\n          none: Far pas res\n          silence: Metre en silence\n          suspend: Suspendre e escafar per de bon las donadas del compte\n        warning_preset_id: Utilizar un avertiment predefinit\n      defaults:\n        autofollow: Convidar a sègre vòstre compte\n        bot: Aquò es lo compte a un robòt\n        chosen_languages: Filtrar las lengas\n        confirm_new_password: Confirmacion del nòu senhal\n        confirm_password: Confirmatz lo nòu senhal\n        context: Contèxte del filtre\n        current_password: Senhal actual\n        data: Donadas\n        discoverable: Far aparéisser aqueste compte a l’annuari\n        display_name: Escais\n        email: Corrièl\n        expires_in: Expira aprèp\n        fields: Metadonada del perfil\n        header: Bandièra\n        inbox_url: URL de la bóstia de recepcion del relai\n        irreversible: Suprimir allòc de rescondre\n        locale: Lenga de l’interfàcia\n        locked: Far venir lo compte privat\n        max_uses: Limit d’utilizacions\n        new_password: Nòu senhal\n        otp_attempt: Còdi Two-factor\n        password: Senhal\n        phrase: Senhal o frasa\n        setting_aggregate_reblogs: Agropar los partatges dins lo flux d’actualitat\n        setting_auto_play_gif: Lectura automatica dels GIFS animats\n        setting_boost_modal: Mostrar una fenèstra de confirmacion abans de partejar un estatut\n        setting_default_language: Lenga de publicacion\n        setting_default_privacy: Confidencialitat dels tuts\n        setting_default_sensitive: Totjorn marcar los mèdias coma sensibles\n        setting_delete_modal: Mostrar una fenèstra de confirmacion abans de suprimir un estatut\n        setting_display_media: Afichatge dels mèdias\n        setting_display_media_default: Defaut\n        setting_display_media_hide_all: O rescondre tot\n        setting_display_media_show_all: O mostrar tot\n        setting_expand_spoilers: Totjorn desplegar los tuts marcats amb un avertiment de contengut\n        setting_hide_network: Amagar vòstre malhum\n        setting_noindex: Èsser pas indexat pels motors de recèrca\n        setting_reduce_motion: Reduire la velocitat de las animacions\n        setting_show_application: Revelar lo nom de l’aplicacion utilizada per enviar de tuts\n        setting_system_font_ui: Utilizar la polissa del sistèma\n        setting_theme: Tèma del site\n        setting_unfollow_modal: Mostrar una confirmacion abans de quitar de sègre qualqu’un\n        severity: Severitat\n        type: Tipe d’impòrt\n        username: Nom d’utilizaire\n        username_or_email: Nom d’utilizaire o corrièl\n        whole_word: Mot complèt\n      featured_tag:\n        name: Etiqueta\n      interactions:\n        must_be_follower: Blocar las notificacions del mond que vos sègon pas\n        must_be_following: Blocar las notificacions del mond que seguètz pas\n        must_be_following_dm: Blocar los messatges del monde que seguètz pas\n      invite_request:\n        text: Perqué volètz vos marcar ?\n      notification_emails:\n        digest: Enviar un corrièl recapitulatiu\n        favourite: Enviar un corrièl quand qualqu’un plaça vòstre estatut en favorit\n        follow: Enviar un corrièl quand qualqu’un vos sèc\n        follow_request: Enviar un corrièl quand qualqu’un demanda de vos sègre\n        mention: Enviar un corrièl quand qualqu’un vos menciona\n        pending_account: Enviar un corrièl quand cal validar un compte novèl\n        reblog: Enviar un corrièl quand qualqu’un tòrna partejar vòstre estatut\n        report: Enviar un corrièl pels nòus senhalaments\n    'no': Non\n    required:\n      text: requesit\n    'yes': Òc\n"
  },
  {
    "path": "config/locales/simple_form.pl.yml",
    "content": "---\npl:\n  simple_form:\n    hints:\n      account_warning_preset:\n        text: Możesz korzystać ze składni której używasz we wpisach, takiej jak adresy URL, hashtagi i wspomnienia\n      admin_account_action:\n        send_email_notification: Użytkownik otrzyma informację, co stało się z jego kontem\n        text_html: Możesz używać składni której używasz we wpisach. Możesz <a href=\"%{path}\">dodać szablon ostrzeżenia</a> aby zaoszczędzić czas\n        type_html: Wybierz co chcesz zrobić z <strong>%{acct}</strong>\n        warning_preset_id: Nieobowiązkowe. Możesz dodać niestandardowy tekst do końcowki szablonu\n      defaults:\n        autofollow: Osoby, które zarejestrują się z Twojego zaproszenia automatycznie zaczną Cię śledzić\n        avatar: PNG, GIF lub JPG. Maksymalnie %{size}. Zostanie zmniejszony do %{dimensions}px\n        bot: To konto wykonuje głównie zautomatyzowane działania i może nie być monitorowane\n        context: Jedno lub wiele miejsc, w których filtr zostanie zastosowany\n        digest: Wysyłane tylko po długiej nieaktywności, jeżeli w tym czasie otrzymaleś jakąś wiadomość bezpośrednią\n        discoverable_html: <a href=\"%{path}\" target=\"_blank\">Katalog</a> pozwala znaleźć konta na podstawie zainteresowań i aktywności. Profil musi śledzić przynajmniej %{min_followers} osób\n        email: Otrzymasz e-mail potwierdzający\n        fields: Możesz ustawić maksymalnie 4 niestandardowe pola wyświetlane jako tabela na Twoim profilu\n        header: PNG, GIF lub JPG. Maksymalnie %{size}. Zostanie zmniejszony do %{dimensions}px\n        inbox_url: Skopiuj adres ze strony głównej przekaźnika, którego chcesz użyć\n        irreversible: Filtrowane wpisy znikną bezpowrotnie, nawet gdy filtr zostanie usunięty\n        locale: Język interfejsu, wiadomości e-mail i powiadomieniach push\n        locked: Musisz akceptować prośby o śledzenie\n        password: Użyj co najmniej 8 znaków\n        phrase: Zostanie wykryte nawet, gdy znajduje się za ostrzeżeniem o zawartości\n        scopes: Wybór API, do których aplikacja będzie miała dostęp. Jeżeli wybierzesz nadrzędny zakres, nie musisz wybierać jego elementów.\n        setting_aggregate_reblogs: Nie pokazuj nowych podbić dla wpisów, które zostały niedawno podbite (dotyczy tylko nowo otrzymanych podbić)\n        setting_default_sensitive: Wrażliwe multimedia są domyślnie schowane i mogą być odkryte kliknięciem\n        setting_display_media_default: Ukrywaj zawartość oznaczoną jako wrażliwa\n        setting_display_media_hide_all: Zawsze oznaczaj zawartość multimedialną jako wrażliwą\n        setting_display_media_show_all: Nie ukrywaj zawartości multimedialnej oznaczonej jako wrażliwa\n        setting_hide_network: Informacje o tym, kto Cię śledzi i kogo śledzisz nie będą widoczne\n        setting_noindex: Wpływa na widoczność strony profilu i Twoich wpisów\n        setting_show_application: W informacjach o wpisie będzie widoczna informacja o aplikacji, z której został wysłany\n        username: Twoja nazwa użytkownika będzie niepowtarzalna na %{domain}\n        whole_word: Jeśli słowo lub fraza składa się jedynie z liter lub cyfr, filtr będzie zastosowany tylko do pełnych wystąpień\n      featured_tag:\n        name: 'Sugerujemy użycie jednego z następujących:'\n      imports:\n        data: Plik CSV wyeksportowany z innego serwera Mastodona\n      invite_request:\n        text: To pomoże nam w recenzji Twojej aplikacji\n      sessions:\n        otp: 'Wprowadź kod weryfikacji dwuetapowej z telefonu lub wykorzystaj jeden z kodów zapasowych:'\n      user:\n        chosen_languages: Jeżeli zaznaczone, tylko wpisy w wybranych językach będą wyświetlane na publicznych osiach czasu\n    labels:\n      account:\n        fields:\n          name: Nazwa\n          value: Zawartość\n      account_warning_preset:\n        text: Tekst szablonu\n      admin_account_action:\n        send_email_notification: Powiadom użytkownika mailem\n        text: Niestandardowe ostrzeżenie\n        type: Działanie\n        types:\n          disable: Wyłącz\n          none: Nie rób niczego\n          silence: Wycisz\n          suspend: Zawieś i nieodwracalnie usuń dane konta\n        warning_preset_id: Użyj szablonu ostrzeżenia\n      defaults:\n        autofollow: Zapraszaj do śledzenia swojego konta\n        avatar: Awatar\n        bot: To konto jest prowadzone przez bota\n        chosen_languages: Filtrowanie języków\n        confirm_new_password: Potwierdź nowe hasło\n        confirm_password: Potwierdź hasło\n        context: Filtruj zawartość\n        current_password: Obecne hasło\n        data: Dane\n        discoverable: Wyświetlaj ten profil w katalogu\n        display_name: Widoczna nazwa\n        email: Adres e-mail\n        expires_in: Wygaśnie po\n        fields: Metadane profilu\n        header: Nagłówek\n        inbox_url: Adres skrzynki przekaźnika\n        irreversible: Usuwaj zamiast ukrywać\n        locale: Język interfejsu\n        locked: Ustaw konto jako prywatne\n        max_uses: Maksymalna liczba użyć\n        new_password: Nowe hasło\n        note: Biogram\n        otp_attempt: Kod uwierzytelnienia dwustopniowego\n        password: Hasło\n        phrase: Słowo kluczowe lub fraza\n        setting_advanced_layout: Włącz zaawansowany interfejs użytkownika\n        setting_aggregate_reblogs: Grupuj podbicia na osiach czasu\n        setting_auto_play_gif: Automatycznie odtwarzaj animowane GIFy\n        setting_boost_modal: Pytaj o potwierdzenie przed podbiciem\n        setting_default_language: Język wpisów\n        setting_default_privacy: Widoczność wpisów\n        setting_default_sensitive: Zawsze oznaczaj zawartość multimedialną jako wrażliwą\n        setting_delete_modal: Pytaj o potwierdzenie przed usunięciem wpisu\n        setting_display_media: Wyświetlanie zawartości multimedialnej\n        setting_display_media_default: Domyślne\n        setting_display_media_hide_all: Ukryj wszystko\n        setting_display_media_show_all: Pokaż wszystko\n        setting_expand_spoilers: Zawsze rozwijaj wpisy oznaczone ostrzeżeniem o zawartości\n        setting_hide_network: Ukryj swoją sieć\n        setting_noindex: Nie indeksuj mojego profilu w wyszukiwarkach internetowych\n        setting_reduce_motion: Ogranicz ruch w animacjach\n        setting_show_application: Informuj o aplikacji z której wysłano wpisy\n        setting_system_font_ui: Używaj domyślnej czcionki systemu\n        setting_theme: Motyw strony\n        setting_unfollow_modal: Pytaj o potwierdzenie przed cofnięciem śledzenia\n        severity: Priorytet\n        type: Importowane dane\n        username: Nazwa użytkownika\n        username_or_email: Nazwa użytkownika lub adres e-mail\n        whole_word: Całe słowo\n      featured_tag:\n        name: Hasztag\n      interactions:\n        must_be_follower: Nie wyświetlaj powiadomień od osób, które Cię nie śledzą\n        must_be_following: Nie wyświetlaj powiadomień od osób, których nie śledzisz\n        must_be_following_dm: Nie wyświetlaj wiadomości bezpośrednich od osób, których nie śledzisz\n      invite_request:\n        text: Czemu chcesz dołączyć?\n      notification_emails:\n        digest: Wysyłaj podsumowania e-mailem\n        favourite: Powiadamiaj mnie e-mailem, gdy ktoś polubi mój wpis\n        follow: Powiadamiaj mnie e-mailem, gdy ktoś zacznie mnie śledzić\n        follow_request: Powiadamiaj mnie e-mailem, gdy ktoś poprosi o pozwolenie na śledzenie mnie\n        mention: Powiadamiaj mnie e-mailem, gdy ktoś o mnie wspomni\n        pending_account: Wyślij e-mail kiedy nowe konto potrzebuje recenzji\n        reblog: Powiadamiaj mnie e-mailem, gdy ktoś podbije mój wpis\n        report: Powiadamiaj mnie e-mailem, gdy zostanie utworzone nowe zgłoszenie\n    'no': Nie\n    recommended: Polecane\n    required:\n      mark: \"*\"\n      text: pole wymagane\n    'yes': Tak\n"
  },
  {
    "path": "config/locales/simple_form.pt-BR.yml",
    "content": "---\npt-BR:\n  simple_form:\n    hints:\n      account_warning_preset:\n        text: Você pode usar a sintaxe de um toot, como URLs, hashtags e menções\n      admin_account_action:\n        send_email_notification: O usuário vai receber uma explicação do que aconteceu com a sua conta\n        text_html: Opcional. Você pode usar a sintaxe de toots. Você pode <a href=\"%{path}\">adicionar avisos pré-definidos</a> para ganhar tempo\n        type_html: Escolha o que fazer com <strong>%{acct}</strong>\n        warning_preset_id: Opcional. Você ainda pode adicionar texto customizado no fim do texto pré-definido\n      defaults:\n        autofollow: Pessoas que se cadastrarem através de seu convite te seguirão automaticamente\n        avatar: PNG, GIF or JPG. Arquivos de até %{size}. Eles serão diminuídos para %{dimensions}px\n        bot: Essa conta executa principalmente ações automatizadas e pode não ser monitorada\n        context: Um ou mais contextos onde o filtro deve ser aplicado\n        digest: Enviado após um longo período de inatividade com um resumo das menções que você recebeu em sua ausência\n        discoverable_html: O <a href=\"%{path}\" target=\"_blank\">diretório</a> permite encontrar contas baseado em seus interesses e atividades. Requer pelo menos %{min_followers} seguidores\n        email: Você receberá um email de confirmação\n        fields: Você pode ter até 4 itens exibidos em forma de tabela no seu perfil\n        header: PNG, GIF or JPG. Arquivos de até %{size}. Eles serão diminuídos para %{dimensions}px\n        inbox_url: Copie a URL da página inicial do repetidor que você quer usar\n        irreversible: Os toots filtrados vão desaparecer irreversivelmente, mesmo se o filtro for removido depois\n        locale: O idioma das telas de usuário, e-mails e notificações push\n        locked: Requer aprovação manual de seguidores\n        password: Use pelo menos 8 caracteres\n        phrase: Vai coincidir, independente de maiúsculas ou minúsculas, no texto ou no aviso de conteúdo de um toot\n        scopes: Quais APIs a aplicação vai ter permissão de acessar. Se você selecionar um escopo de alto nível, você não precisa selecionar individualmente os outros.\n        setting_aggregate_reblogs: Não mostrar novos compartilhamentos para toots que foram compartilhados recentemente (afeta somente novos compartilhamentos recebidos)\n        setting_display_media_default: Esconder mídia marcada como sensível\n        setting_display_media_hide_all: Sempre esconder todas as mídias\n        setting_display_media_show_all: Sempre mostrar mídia marcada como sensível\n        setting_hide_network: Quem você segue e quem segue você não serão exibidos no seu perfil\n        setting_noindex: Afeta seu perfil público e as páginas de suas postagens\n        setting_show_application: A aplicação que você usar para enviar seus toots vai aparecer na visão detalhada dos seus toots\n        username: Seu nome de usuário será único em %{domain}\n        whole_word: Quando a palavra ou frase é inteiramente alfanumérica, ela será aplicada somente se corresponder a palavra inteira\n      featured_tag:\n        name: 'Você pode querer usar um destes:'\n      imports:\n        data: Arquivo CSV exportado de outra instância do Mastodon\n      invite_request:\n        text: Isso vai nos ajudar a revisar sua aplicação\n      sessions:\n        otp: 'Insira o código de autenticação gerado pelo app no seu celular ou use um dos códigos de recuperação:'\n      user:\n        chosen_languages: Ao marcar, apenas toots dos idiomas selecionados serão exibidos nas timelines públicas\n    labels:\n      account:\n        fields:\n          name: Rótulo\n          value: Conteúdo\n      account_warning_preset:\n        text: Texto pré-definido\n      admin_account_action:\n        send_email_notification: Notificar o usuário por e-mail\n        text: Aviso customizado\n        type: Ação\n        types:\n          disable: Desabilitar\n          none: Não fazer nada\n          silence: Silenciar\n          suspend: Suspender e excluir irreversivelmente dados da conta\n        warning_preset_id: Usar um aviso pré-definido\n      defaults:\n        autofollow: Convite para seguir a sua conta\n        bot: Esta é uma conta-robô\n        chosen_languages: Filtros de idioma\n        confirm_new_password: Confirmar nova senha\n        confirm_password: Confirmar senha\n        context: Contextos de filtro\n        current_password: Senha atual\n        data: Dados\n        discoverable: Listar essa conta no diretório\n        display_name: Nome de exibição\n        email: Endereço de e-mail\n        expires_in: Expira em\n        fields: Metadados do perfil\n        header: Cabeçalho\n        inbox_url: URL da caixa de entrada do repetidor\n        irreversible: Ignorar ao invés de esconder\n        locale: Idioma das telas\n        locked: Trancar conta\n        max_uses: Número máximo de usos\n        new_password: Nova senha\n        otp_attempt: Código de autenticação em dois passos\n        password: Senha\n        phrase: Palavra-chave ou frase\n        setting_aggregate_reblogs: Agrupar compartilhamentos nas timelines\n        setting_auto_play_gif: Reproduzir GIFs automaticamente\n        setting_boost_modal: Mostrar diálogo de confirmação antes de compartilhar postagem\n        setting_default_language: Idioma das postagens\n        setting_default_privacy: Privacidade das postagens\n        setting_default_sensitive: Sempre marcar mídia como sensível\n        setting_delete_modal: Mostrar diálogo de confirmação antes de deletar uma postagem\n        setting_display_media: Exibição das mídias\n        setting_display_media_default: Padrão\n        setting_display_media_hide_all: Esconder tudo\n        setting_display_media_show_all: Mostrar tudo\n        setting_expand_spoilers: Sempre expandir toots marcados com aviso de conteúdo\n        setting_hide_network: Esconder as suas redes\n        setting_noindex: Não quero ser indexado por mecanismos de busca\n        setting_reduce_motion: Reduz movimento em animações\n        setting_show_application: Mostrar o nome da aplicação utilizada para enviar os toots\n        setting_system_font_ui: Usar a fonte padrão de seu sistema\n        setting_theme: Tema do site\n        setting_unfollow_modal: Mostrar diálogo de confirmação antes de deixar de seguir alguém\n        severity: Gravidade\n        type: Tipo de importação\n        username: Nome de usuário\n        username_or_email: Nome de usuário ou e-mail\n        whole_word: Palavra inteira\n      interactions:\n        must_be_follower: Bloquear notificações de não-seguidores\n        must_be_following: Bloquear notificações de pessoas que você não segue\n        must_be_following_dm: Bloquear mensagens diretas de pessoas que você não segue\n      invite_request:\n        text: Por que você quer se cadastrar?\n      notification_emails:\n        digest: Mandar e-mails com relatórios\n        favourite: Mandar um e-mail quando alguém favoritar suas postagens\n        follow: Mandar um e-mail quando alguém te seguir\n        follow_request: Mandar um e-maill quando alguém solicitar ser seu seguidor\n        mention: Mandar um e-mail quando alguém te mencionar\n        pending_account: Mandar um -mail quando uma nova conta precisar ser revisada\n        reblog: Mandar um e-mail quando alguém compartilhar suas postagens\n        report: Mandar um e-mail quando uma nova denúncia é submetida\n    'no': Não\n    required:\n      text: obrigatório\n    'yes': Sim\n"
  },
  {
    "path": "config/locales/simple_form.pt.yml",
    "content": "---\npt:\n  simple_form:\n    hints:\n      account_warning_preset:\n        text: Tu podes usar sintaxe de escrita, como URLs, hashtags e referências\n      admin_account_action:\n        send_email_notification: O utilizador receberá uma explicação sobre o que aconteceu com a sua conta\n        text_html: Opcional. Tu podes usar sintaxe de escrita. Tu podes <a href=\"%{path}\"> adicionar predefinições de aviso</a> para poupar tempo\n        type_html: Escolhe o que fazer com <strong>%{acct}</strong>\n        warning_preset_id: Opcional. Tu ainda podes adicionar texto personalizado no fim do predefinido\n      defaults:\n        autofollow: As pessoas que aderem através do convite seguir-te-ão automaticamente\n        avatar: PNG, GIF or JPG. Arquivos até %{size}. Vão ser reduzidos para %{dimensions}px\n        bot: Esta conta executa essencialmente acções automáticas e pode não poder ser monitorizada\n        context: Um ou múltiplos contextos nos quais o filtro deve ser aplicado\n        digest: Enviado após um longo período de inatividade e apenas se foste mencionado na tua ausência\n        discoverable_html: O <a href=\"%{path}\" target=\"_blank\">directory</a> permite encontrar contas de pessoas com base nos seus interesses e actividades. Exige, pelo menos %{min_followers} seguidores\n        email: Será enviado um e-mail de confirmação\n        fields: Podes ter até 4 itens expostos, em forma de tabela, no teu perfil\n        header: PNG, GIF or JPG. Arquivos até %{size}. Vão ser reduzidos para %{dimensions}px\n        inbox_url: Copia a URL da página inicial do repetidor que queres usar\n        irreversible: Publicações filtradas irão desaparecer irremediavelmente, mesmo que o filtro seja removido posteriormente\n        locale: A língua da interface de utilizador, e-mails e notificações push\n        locked: Requer aprovação manual de seguidores\n        password: Usa, pelo menos, 8 caracteres\n        phrase: Será correspondido independentemente da capitalização ou do aviso de conteúdo duma publicação\n        scopes: Quais as APIs a que será concedido acesso. Se escolheres uma abrangência de nível superior, não precisarás de as seleccionar individualmente.\n        setting_aggregate_reblogs: Não mostrar novas partilhas que foram partilhadas recentemente (só afecta as novas partilhas)\n        setting_display_media_default: Esconder media marcada como sensível\n        setting_display_media_hide_all: Esconder sempre toda a media\n        setting_display_media_show_all: Mostrar sempre a media marcada como sensível\n        setting_hide_network: Quem tu segues e quem te segue não será mostrado no teu perfil\n        setting_noindex: Afecta o teu perfil público e as páginas das tuas publicações\n        setting_show_application: A aplicação que tu usas para publicar será mostrada na vista detalhada das tuas publicações\n        username: O teu nome de utilizador será único em %{domain}\n        whole_word: Quando a palavra-chave ou expressão-chave é somente alfanumérica, ela só será aplicada se corresponder à palavra completa\n      featured_tag:\n        name: 'Poderás querer usar um destes:'\n      imports:\n        data: Arquivo CSV exportado de outro servidor do Mastodon\n      sessions:\n        otp: 'Insere o código de autenticação em dois passos gerado pelo teu telemóvel ou usa um dos teus códigos de recuperação:'\n      user:\n        chosen_languages: Quando seleccionado, só publicações nas línguas escolhidas serão mostradas nas cronologias públicas\n    labels:\n      account:\n        fields:\n          name: Rótulo\n          value: Conteúdo\n      account_warning_preset:\n        text: Texto pré-definido\n      admin_account_action:\n        send_email_notification: Notificar o utilizador por e-mail\n        text: Aviso personalizado\n        type: Acção\n        types:\n          disable: Desactivar\n          none: Não fazer algo\n          silence: Silenciar\n          suspend: Suspender e apagar irreversivelmente os dados da conta\n        warning_preset_id: Usar um aviso pré-definido\n      defaults:\n        autofollow: Convidar para seguir a tua conta\n        avatar: Imagem de Perfil\n        bot: Esta é uma conta robô\n        chosen_languages: Filtrar línguas\n        confirm_new_password: Confirmar nova palavra-passe\n        confirm_password: Confirmar palavra-passe\n        context: Filtrar contextos\n        current_password: Palavra-passe actual\n        data: Dados\n        discoverable: Listar esta conta no directório\n        display_name: Nome Público\n        email: Endereço de e-mail\n        expires_in: Expira em\n        fields: Meta-dados de perfil\n        header: Cabeçalho\n        inbox_url: URL da caixa de entrada do repetidor\n        irreversible: Expandir em vez de esconder\n        locale: Idioma\n        locked: Trancar conta\n        max_uses: Número máximo de utilizações\n        new_password: Nova palavra-passe\n        note: Biografia\n        otp_attempt: Código de autenticação em dois passos\n        password: Palavra-passe\n        phrase: Palavra ou expressão-chave\n        setting_aggregate_reblogs: Agrupar partilhas em cronologias\n        setting_auto_play_gif: Reproduzir GIFs automaticamente\n        setting_boost_modal: Solicitar confirmação antes de partilhar uma publicação\n        setting_default_language: Língua de publicação\n        setting_default_privacy: Privacidade da publicação\n        setting_default_sensitive: Sempre marcar media como sensível\n        setting_delete_modal: Solicitar confirmação antes de eliminar uma publicação\n        setting_display_media: Exposição de media\n        setting_display_media_default: Pré-definição\n        setting_display_media_hide_all: Esconder todos\n        setting_display_media_show_all: Mostrar todos\n        setting_expand_spoilers: Expandir sempre as publicações marcadas com avisos de conteúdo\n        setting_hide_network: Esconder a tua rede\n        setting_noindex: Não quero ser indexado por motores de pesquisa\n        setting_reduce_motion: Reduz movimento em animações\n        setting_show_application: Revelar sempre qual a aplicação usada para enviar as publicações\n        setting_system_font_ui: Usar a fonte padrão do teu sistema\n        setting_theme: Tema do site\n        setting_unfollow_modal: Solicitar confirmação antes de deixar de seguir alguém\n        severity: Gravidade\n        type: Tipo de importação\n        username: Nome de utilizador\n        username_or_email: Nome de utilizador ou e-mail\n        whole_word: Palavra completa\n      interactions:\n        must_be_follower: Bloquear notificações de não-seguidores\n        must_be_following: Bloquear notificações de pessoas que não segues\n        must_be_following_dm: Bloquear mensagens directas de pessoas que tu não segues\n      notification_emails:\n        digest: Enviar e-mails de resumo\n        favourite: Enviar e-mail quando alguém adiciona uma publicação tua aos favoritos\n        follow: Enviar e-mail quando alguém te segue\n        follow_request: Enviar e-mail quando alguém solicita ser teu seguidor\n        mention: Enviar e-mail quando alguém te menciona\n        reblog: Enviar e-mail quando alguém partilha uma publicação tua\n        report: Enviar um e-mail quando um novo relatório é submetido\n    'no': Não\n    required:\n      text: obrigatório\n    'yes': Sim\n"
  },
  {
    "path": "config/locales/simple_form.ro.yml",
    "content": "---\nro:\n  simple_form:\n    hints:\n      account_warning_preset:\n        text: Poți utiliza sintaxe precum URL, hastag sau menționări\n      admin_account_action:\n        send_email_notification: Utilizatorul va primi o explicație cu privire la ceea ce sa întâmplat cu contul lui\n        text_html: Opțional. Poți utiliza sintaxe. Poți <a href=\"%{path}\">adăuga avertismente predefinite</a> pentru a salva timp\n        type_html: Alege ce se întâmplă cu <strong>%{acct}</strong>\n        warning_preset_id: Opțional. Poți adăuga text personalizat la sfârșitul presetului\n      defaults:\n        autofollow: Persoanele care se înregistrează datorită invitației tale te vor urmări automat\n        avatar: PNG, GIF sau JPG. Cel mult %{size}. Va fi redimensionată la %{dimensions}px\n        bot: Acest cont performează în cea mai mare parte acțiuni automate și nu poate fi monitorizat\n        context: Contextele în care filtrul trebuie aplicat\n        digest: Este trimis doar după o lungă perioadă de inactivitate și numai dacă primești mesaje personale în perioada de absență\n        discoverable_html: <a href=\"%{path}\" target=\"_blank\">Directorul</a> permite utilizatorilor să găsească conturi după interese și activități. Necesită minim %{min_followers} urmăritori\n        email: Vei primi un e-mail de confirmare\n        fields: Poti afișa pană la maxim 4 adrese sub formă de tabel pe pofilul tău\n        header: PNG, GIF sau JPG. Cel mult %{size}. Vor fi redimensionate la %{dimensions}px\n        inbox_url: Copiază adresa URL de pe prima pagină a reului pe care vrei să îl utilizezi\n        irreversible: Postările sortate vor dispărea ireversibil, chiar dacă filtrul este ulterior șters\n        locale: Limba interfaței de utilizator, e-mailurile si notificările push\n        locked: Necesită aprobare manuală a urmăritorilor\n        password: Utilizează cel puțin 8 caractere\n        phrase: Vor fi potrivite indiferent de textul din casetă sau advertismentul unei postări\n        scopes: La care API-uri aplicația are nevoie de acces. Dacă selectezi un scop principal nu mai e nevoie să selectezi fiecare sub-scop al acestuia.\n        setting_aggregate_reblogs: Nu afișa redistribuirile noi pentru postările care au fost deja recent redistribuite (afectează doar noile redistribuiri primite)\n        setting_display_media_default: Ascunde conținutul media marcat ca sensibil (NSFW)\n        setting_display_media_hide_all: Întotdeauna ascunde tot conținutul media\n        setting_display_media_show_all: Întotdeauna afișează conținutul media marcat ca sensibil\n        setting_hide_network: Pe cine urmărești și cine te urmărește nu vor fi afișați pe profilul tău\n        setting_noindex: Afecteazâ profilul tău public și statusurile tale\n        username: Numele tău de utilizator va fi unic pe %{domain}\n        whole_word: Când fraza sau cuvântul este doar alfanumeric, acesta se aplică doar dacă există o potrivire completă\n      imports:\n        data: Fișierul CSV exportat de la o altă instanță\n      sessions:\n        otp: 'Introdu codul pentru dubla protecție generat de telefonul mobil sau unul din codurile de rezervă:'\n      user:\n        chosen_languages: Doar postările în limbile selectate vor fi afișate în fluxurile publice\n    labels:\n      account:\n        fields:\n          name: Etichetă\n          value: Conținut\n      account_warning_preset:\n        text: Text presetat\n      admin_account_action:\n        send_email_notification: Notificați utilizatorul prin e-mail\n        text: Avertisment personalizat\n        type: Acțiune\n        types:\n          disable: Dezactivează\n          none: Nu fă nimic\n          silence: Liniște\n          suspend: Suspendă și șterge ireversibil datele contului\n        warning_preset_id: Utilizează un avertisment predefinit\n      defaults:\n        autofollow: Invită să te urmărească\n        avatar: Fotografie de profil\n        bot: Acesta este un cont automat (bot)\n        chosen_languages: Limbile filtrului\n        confirm_new_password: Confirmă noua parolă\n        confirm_password: Confirmă parola\n        context: Contextele filtrului\n        current_password: Parola actuală\n        discoverable: Listează acest cont in director\n        display_name: Numele afișat\n        email: Adresa de e-mail\n        expires_in: Expiră după\n        fields: Rețele externe - Unde mai poți fi găsit\n        header: Antet\n        inbox_url: Adresa URL a inbox-ului\n        irreversible: Lasă înloc să ascunzi\n        locale: Limbă\n        locked: Cont Privat\n        max_uses: Numărul maxim de utilizatori\n        new_password: Parola nouă\n        note: Descriere\n        otp_attempt: Cod dublă protecție\n        password: Parolă\n        phrase: Cuvânt sau frază\n        setting_auto_play_gif: Redă automat animațiile GIF\n        setting_boost_modal: Arată dialogul de confirmare înainte de a redistribui\n        setting_default_language: În ce limbă postezi\n        setting_default_privacy: Cine vede postările tale\n        setting_default_sensitive: Întotdeauna marchează conținutul media ca sensibil\n        setting_delete_modal: Arată dialogul de confirmare înainte de a șterge o postare\n        setting_display_media_default: Standard\n        setting_hide_network: Ascunde rețeaua\n        setting_noindex: Nu permite motoarelor de căutare să indexeze rețeaua ta\n        setting_reduce_motion: Redu mișcarea în animații\n        setting_system_font_ui: Utilizează fontul standard as sistemului\n        setting_theme: Tema siteului\n        setting_unfollow_modal: Arată dialogul de confirmare înainte de a nu mai urmări pe cineva\n        severity: Severitate\n        type: Ce importați\n        username: Nume de utilizator\n        username_or_email: Numele de utilizator sau adresa de E-mail\n        whole_word: Cuvânt întreg\n      interactions:\n        must_be_follower: Blochează notificările de la persoane care nu te urmăresc\n        must_be_following: Blochează notificările de la persoane pe care nu le urmărești\n        must_be_following_dm: Blochează mesajele directe de la persoane pe care nu le urmărești\n      notification_emails:\n        digest: Trimite rezumate\n        favourite: Trimite e-mail când cineva favorizează unul din statusurile tale\n        follow: Trimite e-mail când cineva te urmărește\n        follow_request: Trimite e-mail când cineva trimite o cerere de urmărire\n        mention: Trimite e-mail când cineva te menționează\n        reblog: Trimite e-mail când cineva redistribuie unul din statusurile tale\n        report: Trimite e-mail când un raport nou este trimis\n    'no': Nu\n    required:\n      text: obligatoriu\n    'yes': Da\n"
  },
  {
    "path": "config/locales/simple_form.ru.yml",
    "content": "---\nru:\n  simple_form:\n    hints:\n      account_warning_preset:\n        text: Вы можете использовать всё, что в обычных постах — ссылки, хэштеги, упоминания и т.д.\n      admin_account_action:\n        send_email_notification: Пользователь получит сообщение о том, что случилось с его/её аккаунтом\n        text_html: (Необязательно) Можно использовать обычный синтаксис. Для экономии времени <a href=\"%{path}\">добавьте шаблоны предупреждений</a>\n        type_html: Выберите, что делать с аккаунтом <strong>%{acct}</strong>\n        warning_preset_id: Необязательно. Вы можете добавить собственный текст в конце шаблона\n      defaults:\n        autofollow: Люди, пришедшие по этому приглашению автоматически будут подписаны на Вас\n        avatar: PNG, GIF или JPG. Максимально %{size}. Будет уменьшено до %{dimensions}px\n        bot: Этот аккаунт обычно выполяет автоматизированные действия и может не просматриваться владельцем\n        context: Один или несколько контекстов, к которым должны быть применены фильтры\n        digest: Отсылается лишь после длительной неактивности, если вы в это время получали личные сообщения\n        discoverable_html: <a href=\"%{path}\" target=\"_blank\">Каталог</a> позволяет пользователям искать людей по интересам и активности. Необходимо наличие не менее %{min_followers} подписчиков\n        email: Вам будет отправлено электронное письмо с подтверждением\n        fields: В профиле можно отобразить до 4 пунктов как таблицу\n        header: PNG, GIF или JPG. Максимально %{size}. Будет уменьшено до %{dimensions}px\n        inbox_url: Копировать URL с главной страницы ретранслятора, который вы хотите использовать\n        irreversible: Отфильтрованные статусы будут утеряны навсегда, даже если в будущем фильтр будет убран\n        locale: Язык интерфейса, e-mail писем и push-уведомлений\n        locked: Потребует от вас ручного подтверждения подписчиков, изменит приватность постов по умолчанию на \"только для подписчиков\"\n        password: Укажите не менее 8 символов\n        phrase: Будет сопоставлено независимо от присутствия в тексте или предупреждения о содержании статуса\n        scopes: Какие API приложению будет позволено использовать. Если вы выберете самый верхний, нижестоящие будут выбраны автоматически.\n        setting_aggregate_reblogs: Не показывать новые продвижения статусов, которые уже были недавно продвинуты (относится только к новым продвижениям)\n        setting_default_sensitive: Чувствительные медиафайлы скрыты по умолчанию и могут быть показаны по нажатию на них\n        setting_display_media_default: Скрывать чувствительные медиафайлы\n        setting_display_media_hide_all: Всегда скрывать любые медиафайлы\n        setting_display_media_show_all: Всегда показывать чувствительные медиафайлы\n        setting_hide_network: Те, на кого вы подписаны и кто подписан на Вас, не будут отображены в вашем профиле\n        setting_noindex: Относится к вашему публичному профилю и страницам статусов\n        setting_show_application: В окне просмотра вашего статуса будет видно, с какого приложения он был отправлен\n        username: Ваш юзернейм будет уникальным на %{domain}\n        whole_word: Если слово или фраза состоит только из букв и цифр, сопоставление произойдёт только по полному совпадению\n      featured_tag:\n        name: 'Возможно, вы захотите выбрать из них:'\n      imports:\n        data: Файл CSV, экспортированный с другого узла Mastodon\n      invite_request:\n        text: Это поможет нам рассмотреть вашу заявку\n      sessions:\n        otp: 'Введите код двухфакторной аутентификации, сгенерированный в мобильном приложении, или используйте один из ваших кодов восстановления:'\n      user:\n        chosen_languages: Если выбрано, то в публичных лентах будут показаны только посты на выбранных языках\n    labels:\n      account:\n        fields:\n          name: Пункт\n          value: Значение\n      account_warning_preset:\n        text: Текст шаблона\n      admin_account_action:\n        send_email_notification: Уведомить юзера по e-mail\n        text: Свой текст предупреждения\n        type: Действие\n        types:\n          disable: Заморозить\n          none: Ничего не делать\n          silence: Заглушить\n          suspend: Заблокировать и безвозвратно удалить все данные аккаунта\n        warning_preset_id: Использовать шаблон\n      defaults:\n        autofollow: Пригласите подписаться на Ваш аккаунт\n        avatar: Аватар\n        bot: Это аккаунт бота\n        chosen_languages: Фильтр языков\n        confirm_new_password: Повторите новый пароль\n        confirm_password: Повторите пароль\n        context: Контекст фильтра\n        current_password: Текущий пароль\n        data: Данные\n        discoverable: Показывать этот аккаунт в каталоге\n        display_name: Показываемое имя\n        email: Адрес e-mail\n        expires_in: Истекает через\n        fields: Метаданные профиля\n        header: Заголовок\n        inbox_url: URL для входящих от ретрансляторов\n        irreversible: Удалять, а не скрывать\n        locale: Язык интерфейса\n        locked: Сделать аккаунт закрытым\n        max_uses: Макс. число использований\n        new_password: Новый пароль\n        note: О Вас\n        otp_attempt: Двухфакторный код\n        password: Пароль\n        phrase: Слово или фраза\n        setting_advanced_layout: Включить многоколоночный интерфейс\n        setting_aggregate_reblogs: Группировать продвижения в лентах\n        setting_auto_play_gif: Автоматически проигрывать анимированные GIF\n        setting_boost_modal: Показывать диалог подтверждения перед продвижением\n        setting_default_language: Язык отправляемых статусов\n        setting_default_privacy: Видимость постов\n        setting_default_sensitive: Всегда отмечать медиаконтент как чувствительный\n        setting_delete_modal: Показывать диалог подтверждения перед удалением\n        setting_display_media: Отображение медиафайлов\n        setting_display_media_default: По умолчанию\n        setting_display_media_hide_all: Скрывать все\n        setting_display_media_show_all: Показывать все\n        setting_expand_spoilers: Всегда раскрывать статусы, имеющие предупреждение о содержании\n        setting_hide_network: Скрыть свои связи\n        setting_noindex: Отказаться от индексации в поисковых машинах\n        setting_reduce_motion: Уменьшить движение в анимации\n        setting_show_application: Раскрывать приложение, с которого отправляются статусы\n        setting_system_font_ui: Использовать шрифт системы по умолчанию\n        setting_theme: Тема сайта\n        setting_unfollow_modal: Показывать диалог подтверждения перед тем, как отписаться от аккаунта\n        severity: Строгость\n        type: Тип импорта\n        username: Имя пользователя\n        username_or_email: Имя пользователя или e-mail\n        whole_word: Слово целиком\n      featured_tag:\n        name: Хэштег\n      interactions:\n        must_be_follower: Заблокировать уведомления не от подписчиков\n        must_be_following: Заблокировать уведомления от людей, на которых вы не подписаны\n        must_be_following_dm: Заблокировать личные сообщения от людей, на которых вы не подписаны\n      invite_request:\n        text: Почему вы хотите присоединиться к нам?\n      notification_emails:\n        digest: Присылать дайджест по e-mail\n        favourite: Уведомлять по e-mail, когда кому-то нравится ваш статус\n        follow: Уведомлять по e-mail, когда кто-то подписался на вас\n        follow_request: Уведомлять по e-mail, когда кто-то запрашивает разрешение на подписку\n        mention: Уведомлять по e-mail, когда кто-то упомянул вас\n        pending_account: Отправлять e-mail при наличии новых заявок на присоединение\n        reblog: Уведомлять по e-mail, когда кто-то продвинул ваш статус\n        report: Уведомлять по e-mail при создании жалобы\n    'no': Нет\n    recommended: Рекомендуется\n    required:\n      mark: \"*\"\n      text: обязательно\n    'yes': Да\n"
  },
  {
    "path": "config/locales/simple_form.sk.yml",
    "content": "---\nsk:\n  simple_form:\n    hints:\n      account_warning_preset:\n        text: Môžeš používať rovnakú syntaxiu ako v rámci príspevkov, čiže URL, haštagy, a spomenutia\n      admin_account_action:\n        send_email_notification: Užívateľ dostane vysvetlenie ohľadom toho, čo sa stalo s ich účtom\n        text_html: Voliteľné. Môžeš používať rovnakú syntaxiu ako v príspevkoch. Môžeš pridať <a href=\"%{path}\">varovné predlohy</a> a ušetriť tak čas\n        type_html: Vyber si, čo urobiť s účtom <strong>%{acct}</strong>\n        warning_preset_id: Voliteľné. Stále môžeš vložiť vlastný text na samý koniec predlohy\n      defaults:\n        autofollow: Ľudia ktorí sa zaregistrujú prostredníctvom pozvánky, ťa budú inheď následovať\n        avatar: PNG, GIF alebo JPG. Maximálne %{size}. Bude zmenšený na %{dimensions}px\n        bot: Tento účet vykonáva hlavne automatizované akcie, a je pravdepodobne nespravovaný\n        context: Jedno, alebo viac kritérií, v ktorých má byť filtrovanie uplatnené\n        digest: Odoslané iba v prípade dlhodobej neprítomnosti, a len ak si obdržal/a nejaké osobné správy kým si bol/a preč\n        discoverable_html: Táto <a href=\"%{path}\" target=\"_blank\">databáza</a> umožňuje ľudom nájsť profily podľa záujmu a aktívnosti. Vyžaduje aby mali aspoň %{min_followers} sledovateľov\n        email: Bude ti odoslaný potvrdzujúci email\n        fields: Až štyri položky môžeš mať na svojom profile zobrazené vo forme tabuľky\n        header: PNG, GIF, alebo JPG. Maximálne %{size}. Bude zmenšený na %{dimensions}px\n        inbox_url: Skopíruj adresu z hlavnej stránky mostíka, ktorý chceš používať\n        irreversible: Vytriedené príspevky zmiznú nenávratne, aj keď triedenie neskôr zrušíš\n        locale: Jazyk užívateľského rozhrania, emailových, a nástenkových oboznámení\n        locked: Vyžaduje sa manuálne schvaľovanie sledujúcich\n        password: Zadaj aspoň osem znakov\n        phrase: Zhoda sa nájde nezávisle od toho, či je text napísaný, veľkými, alebo malými písmenami, či už v tele, alebo v hlavičke\n        scopes: Ktoré API budú povolené aplikácii pre prístup. Ak vyberieš vrcholný stupeň, nemusíš už potom vyberať po jednom.\n        setting_aggregate_reblogs: Nezobrazuj nové vyzdvihnutia pre príspevky, ktoré už boli len nedávno povýšené (týka sa iba nanovo získaných povýšení)\n        setting_default_sensitive: Chúlostivé médiá sú štandardne ukryté, a môžu byť zobrazené kliknutím\n        setting_display_media_default: Ukry médiá označené ako citlivé\n        setting_display_media_hide_all: Vždy ukry všetky médiá\n        setting_display_media_show_all: Stále zobrazuj médiá označené ako citlivé\n        setting_hide_network: Koho následuješ, a kto následuje teba, nebude zobrazené na tvojom profile\n        setting_noindex: Ovplyvňuje verejný profil a stránky s príspevkami\n        setting_show_application: Aplikácia, ktorú používaš na písanie príspevkov, bude zobrazená v podrobnom náhľade jednotlivých tvojích príspevkov\n        username: Tvoja prezývka bude unikátna pre server %{domain}\n        whole_word: Ak je kľúčové slovo, alebo fráza poskladaná iba s písmen a čísel, bude použité iba ak sa zhoduje s celým výrazom\n      featured_tag:\n        name: 'Možno by si chcel/a použiť niektoré z týchto:'\n      imports:\n        data: CSV súbor vyexportovaný z iného Mastodon serveru\n      invite_request:\n        text: Toto pomôže s vyhodnocovaním tvojej žiadosti\n      sessions:\n        otp: 'Napíš sem dvoj-faktorový kód z telefónu, alebo použi jeden z tvojích obnovovacích kódov:'\n      user:\n        chosen_languages: Keď je zaškrtnuté, vo verejnej osi budú zobrazené iba príspevky vo vybraných jazykoch\n    labels:\n      account:\n        fields:\n          name: Označenie\n          value: Obsah\n      account_warning_preset:\n        text: Text predlohy\n      admin_account_action:\n        send_email_notification: Oznam užívateľovi cez email\n        text: Špecifické varovanie\n        type: Úkon\n        types:\n          disable: Deaktivuj\n          none: Neurob nič\n          silence: Utíš\n          suspend: Vylúč a nenávratne vymaž dáta na účte\n        warning_preset_id: Použi varovnú predlohu\n      defaults:\n        autofollow: Pozvi k následovaniu tvojho profilu\n        bot: Toto je automatizovaný bot účet\n        chosen_languages: Filtruj jazyky\n        confirm_new_password: Znovu tvoje nové heslo, pre potvrdenie\n        confirm_password: Over heslo\n        context: Triedenie kontextov\n        current_password: Súčasné heslo\n        data: Dáta\n        discoverable: Zaraď tento účet do databázy profilov\n        display_name: Zobrazované meno\n        email: Emailová adresa\n        expires_in: Expiruj po\n        fields: Metadáta profilu\n        header: Obrázok v hlavičke\n        inbox_url: URL adresa prechodnej schránky\n        irreversible: Zahoď, namiesto ukrytia\n        locale: Jazyk rozhrania\n        locked: Zamknúť účet\n        max_uses: Najviac možno použiť\n        new_password: Nové heslo\n        note: O tebe\n        otp_attempt: Dvoj-faktorový overovací (2FA) kód\n        password: Heslo\n        phrase: Kľúčové slovo, alebo fráza\n        setting_advanced_layout: Zapni pokročilé užívateľské rozhranie\n        setting_aggregate_reblogs: Zoskupuj vyzdvihnutia v časovej osi\n        setting_auto_play_gif: Automaticky prehrávaj animované GIFy\n        setting_boost_modal: Zobrazuj potvrdzovacie okno pred povýšením\n        setting_default_language: Píšeš v jazyku\n        setting_default_privacy: Súkromie príspevkov\n        setting_default_sensitive: Označ všetky mediálne súbory ako chúlostivé\n        setting_delete_modal: Zobrazuj potvrdzovacie okno pred vymazaním toot-u\n        setting_display_media: Zobrazovanie médií\n        setting_display_media_default: Štandard\n        setting_display_media_hide_all: Ukry všetky\n        setting_display_media_show_all: Ukáž všetky\n        setting_expand_spoilers: Stále rozbaľ príspevky označené varovaním o obsahu\n        setting_hide_network: Ukry svoju sieť kontaktov\n        setting_noindex: Nezaraďuj príspevky do indexu pre vyhľadávče\n        setting_reduce_motion: Mierni pohyb pri animáciách\n        setting_show_application: Zverejni akú aplikáciu používaš na posielanie príspevkov\n        setting_system_font_ui: Použi základné systémové písmo\n        setting_theme: Vzhľad webu\n        setting_unfollow_modal: Vyžaduj potvrdenie pred skončením sledovania iného užívateľa\n        severity: Závažnosť\n        type: Typ importu\n        username: Prezývka\n        username_or_email: Prezývka, alebo email\n        whole_word: Celé slovo\n      featured_tag:\n        name: Haštag\n      interactions:\n        must_be_follower: Blokuj oboznámenia od užívateľov, ktorí ma nenásledujú\n        must_be_following: Blokuj oboznámenia od ľudí, ktorých nesledujem\n        must_be_following_dm: Blokuj súkromné správy od ľudí ktorých nesledujem\n      notification_emails:\n        digest: Zasielať súhrnné emaily\n        favourite: Zaslať email, ak si niekto obľúbi tvoj príspevok\n        follow: Zaslať email, ak ťa niekto začne následovať\n        follow_request: Zaslať email, ak ti niekto pošle žiadosť o sledovanie\n        mention: Zaslať email, ak ťa niekto spomenie vo svojom príspevku\n        pending_account: Zaslať email, ak treba prehodnotiť nový účet\n        reblog: Zaslať email, ak niekto re-tootne tvoj príspevok\n        report: Zaslať email, ak niekto podá nové nahlásenie\n    'no': Nie\n    required:\n      text: povinné\n    'yes': Áno\n"
  },
  {
    "path": "config/locales/simple_form.sl.yml",
    "content": "---\nsl:\n  simple_form:\n    hints:\n      defaults:\n        autofollow: Osebe, ki se prijavijo prek povabila, vas bodo samodejno sledile\n        avatar: PNG, GIF ali JPG. Največ %{size}. Zmanjšana bo na %{dimensions}px\n        bot: Ta račun v glavnem opravlja samodejna dejanja in morda ni pod nadzorom\n        context: En ali več kontekstov, kjer naj se uporabi filter\n        digest: Pošlje se le po dolgem obdobju nedejavnosti in samo, če ste prejeli osebna sporočila v vaši odsotnosti\n        email: Poslali vam bomo potrditveno e-pošto\n        fields: Na svojem profilu lahko imate do 4 predmete prikazane kot tabelo.\n        header: PNG, GIF ali JPG. Največ %{size}. Zmanjšana bo na %{dimensions}px\n        inbox_url: Kopirajte URL naslov s prve strani releja, ki ga želite uporabiti\n        irreversible: Filtrirani trobi bodo nepovratno izginili, tudi če je filter kasneje odstranjen\n        locale: Jezik uporabniškega vmesnika, e-poštnih sporočil in potisnih obvestil\n        locked: Zahteva, da ročno odobrite sledilce\n        password: Uporabite najmanj 8 znakov\n        phrase: Se bo ujemal, ne glede na začetnice v tekstu ali opozorilo o vsebini troba\n        scopes: Do katerih API-jev bo imel program dostop. Če izberete obseg najvišje ravni, vam ni treba izbrati posameznih.\n        setting_display_media_default: Skrij medij, ki je označen kot občutljiv\n        setting_display_media_hide_all: Vedno skrij vse medije\n        setting_display_media_show_all: Vedno pokaži medij, ki je označen kot občutljiv\n        setting_hide_network: Kogar spremljate in kdo vas spremlja ne bo prikazano na vašem profilu\n        setting_noindex: Vpliva na vaš javni profil in na strani s stanjem\n        username: Vaše uporabniško ime bo edinstveno na %{domain}\n        whole_word: Ko je ključna beseda ali fraza samo alfanumerična, se bo uporabljala le, če se bo ujemala s celotno besedo\n      imports:\n        data: Izvožena CSV datoteka iz drugega Mastodon vozlišča\n      sessions:\n        otp: 'Vnesite dvomestno kodo, ki je ustvarjena z aplikacijo na telefonu, ali uporabite eno od vaših obnovitvenih kod:'\n      user:\n        chosen_languages: Ko je označeno, bodo v javnih časovnicah prikazani samo trobi v izbranih jezikih\n    labels:\n      account:\n        fields:\n          name: Oznaka\n          value: Vsebina\n      defaults:\n        autofollow: Povabite, da sledi vašemu računu\n        avatar: Podoba\n        bot: To je račun robota\n        chosen_languages: Filtriraj jezike\n        confirm_new_password: Potrdite novo geslo\n        confirm_password: Potrdite geslo\n        context: Filtriraj vsebino\n        current_password: Trenutno geslo\n        data: Podatki\n        display_name: Prikazno ime\n        email: E-poštni naslov\n        expires_in: Preteče po\n        fields: Metapodatki profila\n        header: Glava\n        inbox_url: URL mape \"Prejeto\"\n        irreversible: Opusti namesto skrij\n        locale: Jezik vmesnika\n        locked: Zaklenjen račun\n        max_uses: Največje število uporabnikov\n        new_password: Novo geslo\n        otp_attempt: Dvofaktorska koda\n        password: Geslo\n        phrase: Ključna beseda ali fraza\n        setting_auto_play_gif: Samodejno predvajanje animiranih GIF-ov\n        setting_boost_modal: Pred sunkom pokaži potrditveno okno\n        setting_default_language: Jezik objavljanja\n        setting_default_privacy: Zasebnost objave\n        setting_default_sensitive: Vedno označi medije kot občutljive\n        setting_delete_modal: Pred brisanjem troba prikaži okno za pritrditev\n        setting_display_media: Prikaz medijev\n        setting_display_media_default: Privzeto\n        setting_display_media_hide_all: Skrij vse\n        setting_display_media_show_all: Prikaži vse\n        setting_expand_spoilers: Vedno razširi trobe, označene z opozorili o vsebini\n        setting_hide_network: Skrij svoje omrežje\n        setting_noindex: Odsotnost indeksiranja iskalnikov\n        setting_reduce_motion: Zmanjšanje premikanja v animacijah\n        setting_system_font_ui: Uporabi privzeto pisavo sistema\n        setting_theme: Tema strani\n        setting_unfollow_modal: Pokaži potrditveno okno, preden nekoga prenehamo slediti\n        severity: Strogost\n        type: Vrsta uvoza\n        username: Uporabniško ime\n        username_or_email: Uporabniško ime ali E-pošta\n        whole_word: Celotna beseda\n      interactions:\n        must_be_follower: Blokiraj obvestila nesledilcev\n        must_be_following: Blokiraj obvestila oseb, ki jim ne sledite\n        must_be_following_dm: Blokiraj neposredna sporočila oseb, ki jim ne sledite\n      notification_emails:\n        digest: Pošlji izvlečke e-pošt\n        favourite: Pošlji e-pošto, ko nekdo doda vaše stanje med priljubljene\n        follow: Pošlji e-pošto, ko vas nekdo sledi\n        follow_request: Pošlji e-pošto, ko vam nekdo želi slediti\n        mention: Pošlji e-pošto, ko vas nekdo omeni\n        reblog: Pošlji e-pošto, ko nekdo sune vaše stanje\n        report: Pošlji e-pošto, ko je oddana nova prijava\n    'no': Ne\n    required:\n      text: zahtevano\n    'yes': Da\n"
  },
  {
    "path": "config/locales/simple_form.sq.yml",
    "content": "---\nsq:\n  simple_form:\n    hints:\n      account_warning_preset:\n        text: Mund të përdorni sintaksë mesazhesh, të tillë si URL, hashtagë dhe përmendje\n      admin_account_action:\n        send_email_notification: Përdoruesi do të marrë një shpjegim mbi çfarë ndodhi me llogarinë e tij\n        text_html: Opsionale. Mund të përdorni sintaksë mesazhesh. Për të kursyer kohë, mund të <a href=\"%{path}\">shtoni paracaktime sinjalizimesh</a>\n        type_html: Zgjidhni ç’të bëhet me <strong>%{acct}</strong>\n        warning_preset_id: Opsionale. Mundeni sërish të shtoni tekst vetjak në fund të paracaktimit\n      defaults:\n        autofollow: Personat që regjistrohen përmes ftesës do t’ju ndjekin vetvetiu\n        avatar: PNG, GIF ose JPG. Maksimumi %{size}. Do të zvogëlohen në %{dimensions}px\n        bot: Kjo llogari kryesisht bën veprime të automatizuara dhe mund të mos mbikëqyret dot\n        context: Një ose disa kontekste kur duhet të zbatohet filtri\n        digest: I dërguar vetëm pas një periudhe të gjatë pasiviteti dhe vetëm nëse keni marrë ndonjë mesazh personal gjatë mungesës suaj\n        discoverable_html: <a href=\"%{path}\" target=\"_blank\">Drejtoria</a> u lejon njerëzve të gjejnë llogari bazuar në interesat dhe veprimtarinë. Lyp të paktën %{min_followers} ndjekës\n        email: Do t’ju dërgohet një email ripohimi\n        fields: Te profili juaj mund të keni deri në 4 objekte të shfaqur si tabelë\n        header: PNG, GIF ose JPG. E shumta %{size}. Do të ripërmasohet në %{dimensions}px\n        inbox_url: Kopjoni URL-në prej faqes ballore të relesë që doni të përdorni\n        irreversible: Mesazhet e filtruar do të zhduket në mënyrë të pakthyeshme, edhe nëse filtri hiqet më vonë\n        locale: Gjuha e ndërfaqes së përdoruesit, email-eve dhe njoftimeve <em>push</em>\n        locked: Lyp që ju të miratoni dorazi ndjekësit\n        password: Përdorni të paktën 8 shenja\n        phrase: Do të kërkohet përputhje pavarësish se teksti ose sinjalizimi mbi lëndën e një mesazhi është shkruar me të mëdha apo me të vogla\n        scopes: Cilat API do të lejohet të përdorë aplikacioni. Nëse përzgjidhni një shkallë të epërme, nuk ju duhet të përzgjidhni individualet një nga një.\n        setting_aggregate_reblogs: Mos shfaq përforcime të reja për mesazhe që janë përforcuar tani së fundi (prek vetëm përforcime të marra rishtas)\n        setting_display_media_default: Fshih media me shenjën rezervat\n        setting_display_media_hide_all: Fshih përherë krejt mediat\n        setting_display_media_show_all: Mediat me shenjën rezervat shfaqi përherë\n        setting_hide_network: Cilët ndiqni dhe cilët ju ndjekin nuk do të shfaqen në profilin tuaj\n        setting_noindex: Prek faqet e profilit tuaj publik dhe gjendjeve\n        setting_show_application: Aplikacioni që përdorni për mesazhe do të shfaqet te pamja e hollësishme për mesazhet tuaj\n        username: Emri juaj i përdoruesit do të jetë unik në %{domain}\n        whole_word: Kur fjalëkyçi ose fraza është vetëm numerike, do të aplikohet vetëm nëse përputhet me krejt fjalën\n      featured_tag:\n        name: 'Mund të doni të përdorni një nga këto:'\n      imports:\n        data: Kartelë CSV të eksportuar nga një tjetër shërbyes Mastodon\n      sessions:\n        otp: 'Jepni kodin dyfaktorësh të prodhuar nga aplikacioni i telefonit tuaj ose përdorni një nga kodet tuaj të rikthimive:'\n      user:\n        chosen_languages: Në iu vëntë shenjë, te rrjedha kohore publike do të shfaqen vetëm mesazhe në gjjuhët e përzgjedhura\n    labels:\n      account:\n        fields:\n          name: Etiketë\n          value: Lëndë\n      account_warning_preset:\n        text: Tekst i paracaktuar\n      admin_account_action:\n        send_email_notification: Njoftoje përdoruesin me email\n        text: Sinjalizim vetjak\n        type: Veprim\n        types:\n          disable: Çaktivizoje\n          none: Mos bëj gjë\n          silence: Heshtje\n          suspend: Pezulloje dhe fshi në mënyrë të pakthyeshme të dhënat e llogarisë\n        warning_preset_id: Përdor një sinjalizim të paracaktuar\n      defaults:\n        autofollow: Ftesë për ndjekje të llogarisë tuaj\n        bot: Kjo është një llogari robot\n        chosen_languages: Filtro gjuhë\n        confirm_new_password: Ripohoni fjalëkalimin e ri\n        confirm_password: Ripohoni fjalëkalimin\n        context: Filtroni kontekste\n        current_password: Fjalëkalimi i tanishëm\n        data: Të dhëna\n        discoverable: Shfaqe këtë llogari te lista\n        display_name: Emër në ekran\n        email: Adresë email\n        expires_in: Skadon pas\n        fields: Tejtëdhëna profili\n        header: Krye\n        inbox_url: URL e Të marrëve të relesë\n        irreversible: Heqje, në vend se fshehje\n        locale: Gjuhë ndërfaqeje\n        locked: Kyçe llogarinë\n        max_uses: Numër maksimum përdorimesh\n        new_password: Fjalëkalim i ri\n        note: Jetëshkrim\n        otp_attempt: Kod mirëfilltësimi dyfaktorësh\n        password: Fjalëkalim\n        phrase: Fjalëkyç ose frazë\n        setting_aggregate_reblogs: Grupoji përforcimet në rrjedha kohore\n        setting_auto_play_gif: Vetëluaji GIF-et e animuar\n        setting_boost_modal: Shfaq dialog ripohimi përpara përforcimi\n        setting_default_language: Gjuhë postimi\n        setting_default_privacy: Privatësi postim\n        setting_default_sensitive: Mediave vëru përherë shenjë si rezervat\n        setting_delete_modal: Shfaq dialog ripohimi përpara fshirjes së një mesazhi\n        setting_display_media: Shfaqje mediash\n        setting_display_media_default: Parazgjedhje\n        setting_display_media_hide_all: Fshihi krejt\n        setting_display_media_show_all: Shfaqi krejt\n        setting_expand_spoilers: Mesazhet me sinjalizime mbi lëndën, zgjeroji përherë\n        setting_hide_network: Fshiheni rrjetin tuaj\n        setting_noindex: Përfundim i indeksimit nga motor kërkimesh\n        setting_reduce_motion: Zvogëlo lëvizjen në animacione\n        setting_show_application: Tregoje aplikacionin e përdorur për të dërguar mesazhe\n        setting_system_font_ui: Përdor shkronja parazgjedhje të sistemit\n        setting_theme: Temë sajti\n        setting_unfollow_modal: Shfaq dialog ripohimi përpara heqjes së ndjekjes për dikë\n        severity: Rreptësi\n        type: Lloj importimi\n        username: Emër përdoruesi\n        username_or_email: Emër përdoruesi ose Email\n        whole_word: Krejt fjalën\n      interactions:\n        must_be_follower: Blloko njoftime nga jo-ndjekës\n        must_be_following: Blloko njoftime nga persona që nuk i ndiqni\n        must_be_following_dm: Blloko mesazhe të drejtpërdrejt nga persona që nuk i ndiqni\n      notification_emails:\n        digest: Dërgo email-e përmbledhës\n        favourite: Të dërgohet email kur dikush parapëlqen gjendjen tuaj\n        follow: Të dërgohet email kur dikush fillon t’ju ndjekë\n        follow_request: Të dërgohet email kur dikush kërkon t’ju ndjekë\n        mention: Të dërgohet email kur dikush ju përmend\n        reblog: Dërgo email kur dikush përforcon gjendjen time\n        report: Dërgo email kur parashtrohet një raportim i ri\n    'no': Jo\n    required:\n      text: e domosdoshme\n    'yes': Po\n"
  },
  {
    "path": "config/locales/simple_form.sr-Latn.yml",
    "content": "---\nsr-Latn:\n  simple_form:\n    hints:\n      defaults:\n        avatar: PNG, GIF ili JPG. Najviše %{size}. Biće smanjena na %{dimensions}px\n        digest: Poslato posle dužeg perioda neaktivnosti sa pregledom svih bitnih stvari koje ste dobili dok ste bili odsutni\n        header: PNG, GIF ili JPG. Najviše %{size}. Biće smanjena na %{dimensions}px\n        locked: Zahteva da pojedinačno odobrite pratioce\n        setting_noindex: Utiče na Vaš javni profil i statusne strane\n      imports:\n        data: CSV fajl izvezen sa druge Mastodont instance\n      sessions:\n        otp: 'Unesite dvofaktorski kod sa Vašeg telefona ili koristite jedan od kodova za oporavak:'\n    labels:\n      defaults:\n        confirm_new_password: Potvrdite novu lozinku\n        confirm_password: Potvrdite lozinku\n        current_password: Trenutna lozinka\n        data: Podaci\n        display_name: Ime za prikaz\n        email: Adresa e-pošte\n        expires_in: Ističe nakon\n        header: Zaglavlje\n        locale: Jezik\n        locked: Zaključaj nalog\n        max_uses: Maksimalni broj korišćenja\n        new_password: Nova lozinka\n        note: Biografija\n        otp_attempt: Dvofaktorski kod\n        password: Lozinka\n        setting_auto_play_gif: Automatski puštaj animirane GIF-ove\n        setting_boost_modal: Prikaži dijalog za potvrdu pre davanja podrške\n        setting_default_privacy: Privatnost objava\n        setting_default_sensitive: Uvek označi multimediju kao osetljivu\n        setting_delete_modal: Prikaži dijalog za potvrdu pre brisanja tuta\n        setting_noindex: Odjavi se od indeksiranja search engine-a\n        setting_reduce_motion: Smanji pokrete u animacijama\n        setting_system_font_ui: Koristi sistemski font\n        setting_theme: Tema sajta\n        setting_unfollow_modal: Prikaži dijalog za potvrdu pre nego što otpratite nekoga\n        severity: Oštrina\n        type: Tip uvoza\n        username: Korisničko ime\n      interactions:\n        must_be_follower: Blokiraj obaveštenja od korisnika koji me ne prate\n        must_be_following: Blokiraj obaveštenja od ljudi koje ne pratim\n        must_be_following_dm: Blokiraj direktne poruke od ljudi koje ne pratim\n      notification_emails:\n        digest: Šalji e-poštu sa sažetkom\n        favourite: Šalji e-poštu kada neko stavi da mu je Vaš status omiljen\n        follow: Šalji e-poštu kada Vas neko zaprati\n        follow_request: Šalji e-poštu kada neko zatraži da Vas zaprati\n        mention: Šalji e-poštu kada Vas neko pomene\n        reblog: Šalji e-poštu kada neko podrži Vaš status\n    'no': Ne\n    required:\n      text: obavezno\n    'yes': Da\n"
  },
  {
    "path": "config/locales/simple_form.sr.yml",
    "content": "---\nsr:\n  simple_form:\n    hints:\n      account_warning_preset:\n        text: Можете користити синтаксу труба, као што су нпр. УРЛ-ова, тарабе и помињања\n      admin_account_action:\n        send_email_notification: Корисник ће добити објашњење тога шта му се десило са налога\n        text_html: Опционално. Можете користити синтаксу труба. Можете <a href=\"%{path}\">додати упозоравајућа преподешавање</a> да сачувате време\n        type_html: Изаберите шта да радите са <strong>%{acct}</strong>\n        warning_preset_id: Опционално. Можете и даље додати прилагођени текст на крај пресета\n      defaults:\n        autofollow: Особе које се пријаве кроз позивнице ће вас аутоматски запратити\n        avatar: PNG, GIF или JPG. Највише %{size}. Биће смањена на %{dimensions}px\n        bot: Овај налог углавном врши аутоматизоване радње и можда се не надгледа\n        context: Један или више контекста у којима треба да се примени филтер\n        digest: Послато после дужег периода неактивности са прегледом свих битних ствари које сте добили док сте били одсутни\n        discoverable_html: <a href=\"%{path}\" target=\"_blank\">Директоријум</a> омогућава људима да пронађу налоге засноване на интересима и активности.  Захтева бар %{min_followers} пратиоца\n        email: Биће вам послата е-пошта са потврдом\n        fields: Можете имати до 4 ставке приказане као табела на вашем профилу\n        header: PNG, GIF или JPG. Највише %{size}. Биће смањена на %{dimensions}px\n        inbox_url: Копирајте URL са насловне стране релеја који желите користити\n        irreversible: Филтриранe трубе ће нестати неповратно, чак и ако је филтер касније уклоњен\n        locale: Језик корисничког интерфејса, е-поште и мобилних обавештења\n        locked: Захтева да појединачно одобрите пратиоце\n        password: Користите најмање 8 знакова\n        phrase: Биће упарена без обзира на велико или мало слово у тексту или упозорења о садржају трубе\n        scopes: Којим API-јима ће апликација дозволити приступ. Ако изаберете опсег највишег нивоа, не морате одабрати појединачне.\n        setting_aggregate_reblogs: Не показуј нова дељења за трубе које су недавно подељене (утиче само на недавно примљена дељења)\n        setting_display_media_default: Сакриј медије означене као осетљиве\n        setting_display_media_hide_all: Увек сакриј све медије\n        setting_display_media_show_all: Увек прикажи медије означене као осетљиве\n        setting_hide_network: Кога пратите и ко вас прати неће бити приказано на вашем профилу\n        setting_noindex: Утиче на Ваш јавни профил и статусне стране\n        username: Ваш надимак ће бити јединствен на %{domain}\n        whole_word: Када је кључна реч или фраза искључиво алфанумеричка, биће примењена само ако се подудара са целом речи\n      imports:\n        data: CSV фајл извезен са друге Мастодонт инстанце\n      sessions:\n        otp: 'Унесите двофакторски код са Вашег телефона или користите један од кодова за опоравак:'\n      user:\n        chosen_languages: Када означите, трубе у изабраним језицима ће се приказати на јавној временској линији\n    labels:\n      account:\n        fields:\n          name: Етикета\n          value: Садржај\n      account_warning_preset:\n        text: Текст пресета\n      admin_account_action:\n        send_email_notification: Обавести корисника преко е-поште\n        text: Прилагођено упозорење\n        type: Радња\n        types:\n          disable: Онемогући\n          none: Не ради ништа\n          silence: Утишај\n          suspend: Обуставите и неповратно избришите податке о налогу\n        warning_preset_id: Користи упозоравајући пресет\n      defaults:\n        autofollow: Позовите да прати ваш налог\n        avatar: Аватар\n        bot: Ово је налог бота\n        chosen_languages: Филтрирај језике\n        confirm_new_password: Потврдите нову лозинку\n        confirm_password: Потврдите лозинку\n        context: Филтрирај контексте\n        current_password: Тренутна лозинка\n        data: Подаци\n        discoverable: Наведите овај налог у фасцикли\n        display_name: Име за приказ\n        email: Адреса е-поште\n        expires_in: Истиче након\n        fields: Профилирај метаподатке\n        header: Заглавље\n        inbox_url: URL од релејног пријемног сандучета\n        irreversible: Испустити уместо сакрити\n        locale: Језик\n        locked: Закључај налог\n        max_uses: Максимални број коришћења\n        new_password: Нова лозинка\n        note: Биографија\n        otp_attempt: Двофакторски код\n        password: Лозинка\n        phrase: Кључна реч или фраза\n        setting_aggregate_reblogs: Групиши дељења у временским линијама\n        setting_auto_play_gif: Аутоматски пуштај анимиране GIF-ове\n        setting_boost_modal: Прикажи дијалог за потврду пре давања подршке\n        setting_default_language: Језик објављивања\n        setting_default_privacy: Приватност објава\n        setting_default_sensitive: Увек означи мултимедију као осетљиву\n        setting_delete_modal: Прикажи дијалог за потврду пре брисања тута\n        setting_display_media: Приказ медија\n        setting_display_media_default: Подразумевано\n        setting_display_media_hide_all: Сакриј све\n        setting_display_media_show_all: Прикажи све\n        setting_expand_spoilers: Увек прошити трубе које су означене упозорењем садржаја\n        setting_hide_network: Сакриј своју мрежу\n        setting_noindex: Одјави се од индексирања search engine-а\n        setting_reduce_motion: Смањи покрете у анимацијама\n        setting_system_font_ui: Користи системски фонт\n        setting_theme: Тема сајта\n        setting_unfollow_modal: Прикажи дијалог за потврду пре него што отпратите некога\n        severity: Оштрина\n        type: Тип увоза\n        username: Корисничко име\n        username_or_email: Корисничко име или Е-пошта\n        whole_word: Цела реч\n      interactions:\n        must_be_follower: Блокирај обавештења од корисника који ме не прате\n        must_be_following: Блокирај обавештења од људи које не пратим\n        must_be_following_dm: Блокирај директне поруке од људи које не пратим\n      notification_emails:\n        digest: Шаљи е-пошту са сажетком\n        favourite: Шаљи е-пошту када неко стави да му је Ваш статус омиљен\n        follow: Шаљи е-пошту када Вас неко запрати\n        follow_request: Шаљи е-пошту када неко затражи да Вас запрати\n        mention: Шаљи е-пошту када Вас неко помене\n        reblog: Шаљи е-пошту када неко подржи Ваш статус\n        report: Пошаљи Е-пошту када се поднесе нова пријава\n    'no': Не\n    required:\n      text: обавезно\n    'yes': Да\n"
  },
  {
    "path": "config/locales/simple_form.sv.yml",
    "content": "---\nsv:\n  simple_form:\n    hints:\n      account_warning_preset:\n        text: Du kan använda inläggssyntax som webbadresser, hashtaggar och omnämnanden\n      admin_account_action:\n        send_email_notification: Användaren kommer att få en förklaring av vad som hände med sitt konto\n        type_html: Välj vad du vill göra med <strong>%{acct}</strong>\n      defaults:\n        autofollow: Användarkonton som skapas genom din inbjudan kommer automatiskt följa dig\n        avatar: PNG, GIF eller JPG. Högst %{size}. Kommer att skalas ner till %{dimensions}px\n        bot: Detta konto utför huvudsakligen automatiserade åtgärder och kanske inte övervakas\n        digest: Skickas endast efter en lång period av inaktivitet och endast om du har fått några personliga meddelanden i din frånvaro\n        email: Ett konfirmationsmeddelande kommer att skickas till dig via epost\n        fields: Du kan ha upp till 4 objekt visade som en tabell på din profil\n        header: PNG, GIF eller JPG. Högst %{size}. Kommer att skalas ner till %{dimensions}px\n        irreversible: Filtrerade inlägg kommer att försvinna oåterkalleligt, även om filter tas bort senare\n        locale: Användargränssnittets språk, e-post och push-aviseringar\n        locked: Kräver att du manuellt godkänner följare\n        password: Använd minst 8 tecken\n        setting_hide_network: Vem du följer och vilka som följer dig kommer inte att visas på din profilsida\n        setting_noindex: Påverkar din offentliga profil och statussidor\n      imports:\n        data: CSV-fil som exporteras från en annan Mastodon-instans\n      sessions:\n        otp: 'Ange tvåfaktorkoden genererad från din telefonapp eller använd någon av dina återställningskoder:'\n      user:\n        chosen_languages: När aktiverat så visas bara inlägg i dina valda språk i den offentliga tidslinjen\n    labels:\n      account:\n        fields:\n          name: Etikett\n          value: Innehåll\n      defaults:\n        autofollow: Bjud in till att följa ditt konto\n        bot: Detta är ett botkonto\n        chosen_languages: Filtrera språk\n        confirm_new_password: Bekräfta nytt lösenord\n        confirm_password: Bekräfta lösenord\n        current_password: Nuvarande lösenord\n        display_name: Visningsnamn\n        email: E-postadress\n        expires_in: Förfaller efter\n        fields: Profil-metadata\n        header: Bakgrundsbild\n        locale: Språk\n        locked: Lås konto\n        max_uses: Högst antal  användningar\n        new_password: Nytt lösenord\n        note: Biografi\n        otp_attempt: Tvåstegslösenord\n        password: Lösenord\n        setting_auto_play_gif: Auto-play animerade GIF-filer\n        setting_boost_modal: Visa bekräftelsedialog innan du knuffar\n        setting_default_language: Språk\n        setting_default_privacy: Postintegritet\n        setting_default_sensitive: Markera alltid media som känsligt\n        setting_delete_modal: Visa bekräftelsedialog innan du raderar en toot\n        setting_hide_network: Göm ditt nätverk\n        setting_noindex: Uteslutning av sökmotorindexering\n        setting_reduce_motion: Minska rörelser i animationer\n        setting_system_font_ui: Använd systemets standardfont\n        setting_theme: Sidans tema\n        setting_unfollow_modal: Visa bekräftelse innan du slutar följa någon\n        severity: Strikthet\n        type: Importtyp\n        username: Användarnamn\n        username_or_email: Användarnamn eller e-mail\n      interactions:\n        must_be_follower: Blockera meddelanden från icke-följare\n        must_be_following: Blockera meddelanden från personer du inte följer\n        must_be_following_dm: Blockera direktmeddelanden från personer du inte följer\n      notification_emails:\n        digest: Skicka sammandrag via e-post\n        favourite: Skicka e-post när någon favoriserar din status\n        follow: Skicka e-post när någon följer dig\n        follow_request: Skicka e-post när någon begär att följa dig\n        mention: Skicka e-post när någon nämner dig\n        reblog: Skicka e-post när någon knuffar din status\n    'no': Nej\n    required:\n      text: obligatorisk\n    'yes': Ja\n"
  },
  {
    "path": "config/locales/simple_form.ta.yml",
    "content": "ta:\n"
  },
  {
    "path": "config/locales/simple_form.te.yml",
    "content": "te:\n"
  },
  {
    "path": "config/locales/simple_form.th.yml",
    "content": "---\nth:\n  simple_form:\n    hints:\n      account_warning_preset:\n        text: คุณสามารถใช้ไวยากรณ์โพสต์ เช่น URL, แฮชแท็ก และการกล่าวถึง\n      admin_account_action:\n        send_email_notification: ผู้ใช้จะได้รับคำอธิบายว่าเกิดอะไรขึ้นกับบัญชีของเขา\n        text_html: ตัวเลือกเพิ่มเติม คุณสามารถใช้ไวยากรณ์โพสต์ คุณสามารถ <a href=\"%{path}\">เพิ่มคำเตือนที่ตั้งไว้ล่วงหน้า</a> เพื่อประหยัดเวลา\n        type_html: เลือกสิ่งที่จะทำกับ <strong>%{acct}</strong>\n        warning_preset_id: ตัวเลือกเพิ่มเติม คุณยังคงสามารถเพิ่มข้อความที่กำหนดเองที่จุดสิ้นสุดของค่าที่ตั้งไว้ล่วงหน้า\n      defaults:\n        autofollow: ผู้คนที่ลงทะเบียนผ่านคำเชิญจะติดตามคุณโดยอัตโนมัติ\n        avatar: PNG, GIF หรือ JPG สูงสุด %{size} จะถูกย่อขนาดเป็น %{dimensions}px\n        bot: บัญชีนี้ทำการกระทำอัตโนมัติเป็นหลักและอาจไม่ได้รับการสังเกตการณ์\n        context: บริบทจำนวนหนึ่งหรือมากกว่าที่ตัวกรองควรใช้\n        digest: ส่งเฉพาะหลังจากไม่มีการใช้งานเป็นเวลานานและในกรณีที่คุณได้รับข้อความส่วนบุคคลใด ๆ เมื่อคุณไม่อยู่เท่านั้น\n        discoverable_html: <a href=\"%{path}\" target=\"_blank\">ไดเรกทอรี</a> ช่วยให้ผู้คนค้นหาบัญชีตามความสนใจและกิจกรรม ต้องการอย่างน้อย %{min_followers} ผู้ติดตาม\n        email: คุณจะได้รับอีเมลยืนยัน\n        fields: คุณสามารถมีได้มากถึง 4 รายการแสดงผลเป็นตารางในโปรไฟล์ของคุณ\n        header: PNG, GIF หรือ JPG สูงสุด %{size} จะถูกย่อขนาดเป็น %{dimensions}px\n        inbox_url: คัดลอก URL จากหน้าแรกของรีเลย์ที่คุณต้องการใช้\n        irreversible: โพสต์ที่กรองจะหายไปอย่างถาวร แม้ว่าจะเอาตัวกรองออกในภายหลัง\n        locale: ภาษาของส่วนติดต่อผู้ใช้, อีเมล และการแจ้งเตือนแบบผลัก\n        locked: คุณต้องอนุมัติผู้ติดตามด้วยตนเอง\n        password: ใช้อย่างน้อย 8 ตัวอักษร\n        phrase: จะถูกจับคู่โดยไม่คำนึงถึงตัวอักษรใหญ่เล็กในข้อความหรือคำเตือนเนื้อหาของโพสต์\n        scopes: API ใดที่แอปพลิเคชันจะได้รับอนุญาตให้เข้าถึง หากคุณเลือกขอบเขตระดับบนสุด คุณไม่จำเป็นต้องเลือกแต่ละขอบเขต\n        setting_aggregate_reblogs: ไม่แสดงการดันใหม่สำหรับโพสต์ที่เพิ่งดัน (มีผลต่อการดันที่ได้รับใหม่เท่านั้น)\n        setting_display_media_default: ซ่อนสื่อที่ถูกทำเครื่องหมายว่าละเอียดอ่อน\n        setting_display_media_hide_all: ซ่อนสื่อทั้งหมดเสมอ\n        setting_display_media_show_all: แสดงสื่อที่ถูกทำเครื่องหมายว่าละเอียดอ่อนเสมอ\n        setting_hide_network: จะไม่แสดงผู้ที่คุณติดตามและผู้ที่ติดตามคุณในโปรไฟล์ของคุณ\n        setting_noindex: มีผลต่อโปรไฟล์สาธารณะและหน้าสถานะของคุณ\n        setting_show_application: จะแสดงผลแอปพลิเคชันที่คุณใช้เพื่อโพสต์ในมุมมองโดยละเอียดของโพสต์ของคุณ\n        username: ชื่อผู้ใช้ของคุณจะไม่ซ้ำกันบน %{domain}\n        whole_word: เมื่อคำสำคัญหรือวลีมีแค่ตัวอักษรและตัวเลข จะถูกใช้หากตรงกันทั้งคำเท่านั้น\n      featured_tag:\n        name: 'คุณอาจต้องการใช้หนึ่งในนี้:'\n      imports:\n        data: ไฟล์ CSV ที่ส่งออกจากเซิร์ฟเวอร์ Mastodon อื่น\n      sessions:\n        otp: 'ป้อนรหัสสองปัจจัยที่สร้างโดยแอปในโทรศัพท์ของคุณหรือใช้หนึ่งในรหัสกู้คืนของคุณ:'\n      user:\n        chosen_languages: เมื่อกาเครื่องหมาย จะแสดงผลเฉพาะโพสต์ในภาษาที่เลือกในเส้นเวลาสาธารณะ\n    labels:\n      account:\n        fields:\n          name: ป้ายชื่อ\n          value: เนื้อหา\n      account_warning_preset:\n        text: ข้อความที่ตั้งไว้ล่วงหน้า\n      admin_account_action:\n        send_email_notification: แจ้งเตือนผู้ใช้ทางอีเมล\n        text: คำเตือนที่กำหนดเอง\n        type: การกระทำ\n        types:\n          disable: ปิดใช้งาน\n          none: ไม่ทำสิ่งใด\n          silence: เงียบ\n          suspend: ระงับและลบข้อมูลบัญชีอย่างถาวร\n        warning_preset_id: ใช้คำเตือนที่ตั้งไว้ล่วงหน้า\n      defaults:\n        autofollow: เชิญให้ติดตามบัญชีของคุณ\n        avatar: ภาพประจำตัว\n        bot: นี่คือบัญชีบอต\n        chosen_languages: กรองภาษา\n        confirm_new_password: ยืนยันรหัสผ่านใหม่\n        confirm_password: ยืนยันรหัสผ่าน\n        context: บริบทตัวกรอง\n        current_password: รหัสผ่านปัจจุบัน\n        data: ข้อมูล\n        discoverable: แสดงรายการบัญชีนี้ในไดเรกทอรี\n        display_name: ชื่อที่แสดงผล\n        email: ที่อยู่อีเมล\n        expires_in: หมดอายุหลังจาก\n        fields: ข้อมูลเมตาโปรไฟล์\n        header: ส่วนหัว\n        inbox_url: URL กล่องขาเข้าแบบรีเลย์\n        irreversible: ลบแทนที่จะซ่อน\n        locale: ภาษาส่วนติดต่อ\n        locked: ล็อคบัญชี\n        max_uses: จำนวนการใช้งานสูงสุด\n        new_password: รหัสผ่านใหม่\n        note: ชีวประวัติ\n        otp_attempt: รหัสสองปัจจัย\n        password: รหัสผ่าน\n        phrase: คำสำคัญหรือวลี\n        setting_aggregate_reblogs: จัดกลุ่มการดันในเส้นเวลา\n        setting_auto_play_gif: เล่น GIF แบบเคลื่อนไหวโดยอัตโนมัติ\n        setting_boost_modal: แสดงกล่องโต้ตอบการยืนยันก่อนดัน\n        setting_default_language: ภาษาที่โพสต์\n        setting_default_privacy: ความเป็นส่วนตัวของโพสต์\n        setting_default_sensitive: ทำเครื่องหมายสื่อว่าละเอียดอ่อนเสมอ\n        setting_delete_modal: แสดงกล่องโต้ตอบการยืนยันก่อนลบโพสต์\n        setting_display_media: การแสดงผลสื่อ\n        setting_display_media_default: ค่าเริ่มต้น\n        setting_display_media_hide_all: ซ่อนทั้งหมด\n        setting_display_media_show_all: แสดงทั้งหมด\n        setting_expand_spoilers: ขยายโพสต์ที่ทำเครื่องหมายด้วยคำเตือนเนื้อหาเสมอ\n        setting_hide_network: ซ่อนเครือข่ายของคุณ\n        setting_noindex: เลือกไม่รับการทำดัชนีโดยเครื่องมือค้นหา\n        setting_reduce_motion: ลดการเคลื่อนไหวในภาพเคลื่อนไหว\n        setting_show_application: เปิดเผยแอปพลิเคชันที่ใช้ในการส่งโพสต์\n        setting_system_font_ui: ใช้แบบอักษรเริ่มต้นของระบบ\n        setting_theme: ชุดรูปแบบไซต์\n        setting_unfollow_modal: แสดงกล่องโต้ตอบการยืนยันก่อนเลิกติดตามใครสักคน\n        severity: ความรุนแรง\n        type: ชนิดการนำเข้า\n        username: ชื่อผู้ใช้\n        username_or_email: ชื่อผู้ใช้หรืออีเมล\n        whole_word: ทั้งคำ\n      featured_tag:\n        name: แฮชแท็ก\n      interactions:\n        must_be_follower: ปิดกั้นการแจ้งเตือนจากที่ไม่ใช่ผู้ติดตาม\n        must_be_following: ปิดกั้นการแจ้งเตือนจากผู้คนที่คุณไม่ได้ติดตาม\n        must_be_following_dm: ปิดกั้นข้อความโดยตรงจากผู้คนที่คุณไม่ได้ติดตาม\n      notification_emails:\n        digest: ส่งอีเมลสรุป\n        favourite: ส่งอีเมลเมื่อใครสักคนชื่นชอบสถานะของคุณ\n        follow: ส่งอีเมลเมื่อใครสักคนติดตามคุณ\n        follow_request: ส่งอีเมลเมื่อใครสักคนขอติดตามคุณ\n        mention: ส่งอีเมลเมื่อใครสักคนกล่าวถึงคุณ\n        reblog: ส่งอีเมลเมื่อใครสักคนดันสถานะของคุณ\n        report: ส่งอีเมลเมื่อมีการส่งรายงานใหม่\n    'no': ไม่\n    required:\n      text: ต้องระบุ\n    'yes': ใช่\n"
  },
  {
    "path": "config/locales/simple_form.tr.yml",
    "content": "---\ntr:\n  simple_form:\n    hints:\n      admin_account_action:\n        send_email_notification: Kullanıcı, hesabına ne olduğu hakkında bir bildirim alacak\n        warning_preset_id: İsteğe bağlı. Hazır ayarın sonuna hala özel metin ekleyebilirsiniz\n      defaults:\n        autofollow: Davetiyeyle kaydolan kişiler sizi otomatik olarak takip eder\n        avatar: En fazla %{size} olacak şekilde PNG, GIF veya JPG formatında yükleyiniz. %{dimensions}px büyüklüğüne indirgenecektir\n        header: En fazla %{size} olacak şekilde PNG, GIF veya JPG formatında yükleyiniz. %{dimensions}px büyüklüğüne indirgenecektir.\n        locked: Takipçilerinizi manuel olarak kabul etmenizi ve gönderilerinizi varsayılan olarak sadece takipçilerinizin göreceği şekilde paylaşmanızı sağlar.\n      imports:\n        data: Diğer Mastodon sunucusundan dışarı aktardığınız CSV dosyası\n      sessions:\n        otp: Telefonunuzdaki two-factor kodunuzu giriniz veya kurtarma kodlarınızdan birini giriniz.\n    labels:\n      defaults:\n        avatar: Profil resmi\n        confirm_new_password: Yeni parolanız (tekrar)\n        confirm_password: Parolanız (tekrar)\n        current_password: Mevcut parolanız\n        data: Dosya\n        display_name: Görünen adınız\n        email: E-posta adresiniz\n        header: Kapak resmi\n        locale: Dil\n        locked: Hesabımı kilitle\n        new_password: Yeni parolanız\n        note: Kişisel bilgiler\n        otp_attempt: İki-faktörlü kod\n        password: Parolanız\n        setting_auto_play_gif: GIF'leri otomatik oynatt\n        setting_boost_modal: Boost etmeden önce onay diyaloğu göster\n        setting_default_privacy: Gönderi gizliliği\n        severity: Zorluk\n        type: Dosya türü\n        username: Kullanıcı adınız\n      interactions:\n        must_be_follower: Takipçim olmayan kişilerden gelen bildirimleri engelle\n        must_be_following: Takip etmediğim kişilerden gelen bildirimleri engelle\n      notification_emails:\n        digest: Özet e-postaları gönder\n        favourite: Biri durumumu favorilerine eklediginde bana e-posta gönder\n        follow: Biri beni takip ettiğinde bana e-posta gönder\n        follow_request: Biri bana takip isteği gönderdiğinde, bana e-posta gönder\n        mention: Biri benden bahsettiğinde, bana e-posta gönder\n        reblog: Biri durumumu paylaştığında, bana e-posta gönder\n    'no': Hayır\n    required:\n      text: gerekli\n    'yes': Evet\n"
  },
  {
    "path": "config/locales/simple_form.uk.yml",
    "content": "---\nuk:\n  simple_form:\n    hints:\n      defaults:\n        avatar: PNG, GIF, або JPG. Максимум - %{size}. Буде зменшено до %{dimensions}px\n        bot: Цей аккаунт в основному виконує автоматичні дії та може не відстежуватіся\n        header: PNG, GIF, або JPG. Максимум - %{size}. Буде зменшено до %{dimensions}px\n        locked: Буде вимагати від Вас самостійного підтверждення підписників, змінить приватність постів за замовчуванням на \"тільки для підписників\"\n      imports:\n        data: Файл CSV, экспортированный с другого узла Mastodon\n      sessions:\n        otp: Введите код двухфакторной аутентификации или используйте один из Ваших кодов восстановления.\n    labels:\n      defaults:\n        avatar: Аватар\n        confirm_new_password: Підтвердіть новий пароль\n        confirm_password: Підтвердіть пароль\n        current_password: Поточний пароль\n        data: Дані\n        display_name: Ім'я\n        email: Email адреса\n        header: Заголовок\n        locale: Мова\n        locked: Зробити акаунт приватним\n        new_password: Новий пароль\n        note: Про Вас\n        otp_attempt: Двофакторний код\n        password: Пароль\n        setting_auto_play_gif: Автоматично відтворювати анімовані GIF\n        setting_boost_modal: Показывать диалог подтверждения перед продвижением\n        setting_default_privacy: Видимость постов\n        severity: Строгость\n        type: Тип импорта\n        username: Имя пользователя\n      interactions:\n        must_be_follower: Блокувати сповіщення від непідписаних людей\n        must_be_following: Блокувати сповіщення від людей, на яких ви не підписані\n      notification_emails:\n        digest: Присылать дайджест по e-mail\n        favourite: Надсилати листа, коли комусь подобається Ваш статус\n        follow: Надсилати листа, коли хтось підписується на Вас\n        follow_request: Надсилати листа, коли хтось запитує дозволу на підписку\n        mention: Надсилати листа, коли хтось згадує Вас\n        reblog: Надсилати листа, коли хтось передмухує Ваш статус\n    'no': Ні\n    required:\n      text: обов'язкове\n    'yes': Так\n"
  },
  {
    "path": "config/locales/simple_form.zh-CN.yml",
    "content": "---\nzh-CN:\n  simple_form:\n    hints:\n      account_warning_preset:\n        text: 你可以使用嘟文格式，在嘟文中加入 URL、话题标签和提及“@”\n      admin_account_action:\n        send_email_notification: 用户将收到对其帐号上发生的事的解释\n        text_html: 可选。你可以使用嘟文格式。你可以<a href=\"%{path}\">预置警告</a>以节省时间\n        type_html: 用<strong>%{acct}</strong>选择做什么\n        warning_preset_id: 可选。你可以在预置文本末尾添加自定义文本\n      defaults:\n        autofollow: 通过邀请链接注册的用户将会自动关注你\n        avatar: 文件大小限制 %{size}，只支持 PNG、GIF 或 JPG 格式。图片分辨率将会压缩至 %{dimensions}px\n        bot: 来自这个帐户的绝大多数操作都是自动进行的，并且可能无人监控\n        context: 过滤器的应用场景\n        digest: 仅在你长时间未登录，且收到了私信时发送\n        discoverable_html: <a href=\"%{path}\" target=\"_blank\">目录</a> 让大家能根据兴趣和活动寻找用户。需要至少 %{min_followers} 位关注者\n        email: 我们会向你发送一封确认邮件\n        fields: 这将会在个人资料页上以表格的形式展示，最多 4 个项目\n        header: 文件大小限制 %{size}，只支持 PNG、GIF 或 JPG 格式。图片分辨率将会压缩至 %{dimensions}px\n        inbox_url: 从你想要使用的中继的主页上复制 URL\n        irreversible: 已过滤的嘟文会不可逆转地消失，即便移除过滤器之后也一样\n        locale: 用户界面、电子邮件和推送通知中使用的语言\n        locked: 你需要手动审核所有关注请求\n        password: 至少需要8个字符\n        phrase: 匹配将无视大小写和嘟文的内容警告\n        scopes: 哪些 API 被允许使用。如果你选中了更高一级的范围，就不能单个选中了。\n        setting_aggregate_reblogs: 请不要显示最近已经被转嘟过的转嘟（只会影响新收到的转嘟）\n        setting_default_sensitive: 敏感内容默认隐藏，并在点击后显示\n        setting_display_media_default: 隐藏被标记为敏感内容的媒体\n        setting_display_media_hide_all: 总是隐藏所有媒体\n        setting_display_media_show_all: 总是显示被标记为敏感内容的媒体\n        setting_hide_network: 你关注的人和关注你的人将不会在你的个人资料页上展示\n        setting_noindex: 此设置会影响到你的公开个人资料以及嘟文页面\n        setting_show_application: 你用来发表嘟文的应用程序将会在你嘟文的详细内容中显示\n        username: 你的用户名在 %{domain} 上是独特的\n        whole_word: 如果关键词只包含字母和数字，就只会在整个词被匹配时才会套用\n      featured_tag:\n        name: 你可能想要使用以下之一：\n      imports:\n        data: 从其他 Mastodon 服务器导出的 CSV 文件\n      invite_request:\n        text: 这会有助于我们处理你的申请\n      sessions:\n        otp: 输入你手机应用上生成的双重认证码，或者任意一个恢复代码：\n      user:\n        chosen_languages: 仅选中语言的嘟文会出现在公共时间轴上（全不选则显示所有语言的嘟文）\n    labels:\n      account:\n        fields:\n          name: 标签\n          value: 内容\n      account_warning_preset:\n        text: 预置文本\n      admin_account_action:\n        send_email_notification: 通过邮件提醒此用户\n        text: 内容警告\n        type: 动作\n        types:\n          disable: 禁用\n          none: 忽略\n          silence: 静音\n          suspend: 停用并永久删除账户数据\n        warning_preset_id: 使用预置警告\n      defaults:\n        autofollow: 让被邀请人关注你的帐户\n        avatar: 头像\n        bot: 这是一个机器人帐户\n        chosen_languages: 语言过滤\n        confirm_new_password: 确认新密码\n        confirm_password: 确认密码\n        context: 过滤器场景\n        current_password: 当前密码\n        data: 数据文件\n        discoverable: 在本站用户资料目录中列出此账户\n        display_name: 昵称\n        email: 电子邮件地址\n        expires_in: 失效时间\n        fields: 个人资料附加信息\n        header: 个人资料页横幅图片\n        inbox_url: 中继收件箱的 URL\n        irreversible: 放弃而非隐藏\n        locale: 界面语言\n        locked: 保护你的帐户（锁嘟）\n        max_uses: 最大使用次数\n        new_password: 新密码\n        note: 简介\n        otp_attempt: 双重认证代码\n        password: 密码\n        phrase: 关键词\n        setting_advanced_layout: 启用高级 web 界面\n        setting_aggregate_reblogs: 在时间线中合并转嘟\n        setting_auto_play_gif: 自动播放 GIF 动画\n        setting_boost_modal: 在转嘟前询问我\n        setting_default_language: 发布语言\n        setting_default_privacy: 嘟文默认可见范围\n        setting_default_sensitive: 总是将我发送的媒体文件标记为敏感内容\n        setting_delete_modal: 在删除嘟文前询问我\n        setting_display_media: 媒体展示\n        setting_display_media_default: 默认\n        setting_display_media_hide_all: 隐藏全部\n        setting_display_media_show_all: 显示全部\n        setting_expand_spoilers: 始终展开具有内容警告的嘟文\n        setting_hide_network: 隐藏你的社交网络\n        setting_noindex: 禁止搜索引擎建立索引\n        setting_reduce_motion: 降低过渡动画效果\n        setting_show_application: 展示你用来发嘟的应用\n        setting_system_font_ui: 使用系统默认字体\n        setting_theme: 站点主题\n        setting_unfollow_modal: 在取消关注前询问我\n        severity: 级别\n        type: 导入数据类型\n        username: 用户名\n        username_or_email: 用户名或电子邮件地址\n        whole_word: 整个词条\n      featured_tag:\n        name: 话题标签\n      interactions:\n        must_be_follower: 屏蔽来自未关注我的用户的通知\n        must_be_following: 屏蔽来自我未关注的用户的通知\n        must_be_following_dm: 屏蔽来自我未关注的用户的私信\n      invite_request:\n        text: 你为什么想要加入？\n      notification_emails:\n        digest: 发送摘要邮件\n        favourite: 当有用户收藏了我的嘟文时，发送电子邮件提醒我\n        follow: 当有用户关注我时，发送电子邮件提醒我\n        follow_request: 当有用户向我发送关注请求时，发送电子邮件提醒我\n        mention: 当有用户在嘟文中提及我时，发送电子邮件提醒我\n        pending_account: 在有账户需要审核时，发送电子邮件提醒我\n        reblog: 当有用户转嘟了我的嘟文时，发送电子邮件提醒我\n        report: 在提交新举报时，发送电子邮件提醒我\n    'no': 否\n    recommended: 推荐\n    required:\n      text: 必填\n    'yes': 是\n"
  },
  {
    "path": "config/locales/simple_form.zh-HK.yml",
    "content": "---\nzh-HK:\n  simple_form:\n    hints:\n      defaults:\n        autofollow: 通過邀請網址註冊的用戶將會自動關注你\n        avatar: 支援 PNG, GIF 或 JPG 圖片，檔案最大為 %{size}，會縮裁成 %{dimensions}px\n        bot: 提醒用戶本帳號是機械人\n        digest: 僅在你長時間未登錄，且收到了私信時發送\n        fields: 個人資料頁可顯示多至 4 個項目\n        header: 支援 PNG, GIF 或 JPG 圖片，檔案最大為 %{size}，會縮裁成 %{dimensions}px\n        locale: 使用者介面、電郵和通知的語言\n        locked: 你必須人手核准每個用戶對你的關注請求，而你的文章私隱會被預設為「只有關注你的人能看」\n        setting_hide_network: 你關注的人和關注你的人將不會在你的個人資料頁上顯示\n        setting_noindex: 此設定會影響到你的公開個人資料以及文章頁面\n      imports:\n        data: 自其他服務站匯出的 CSV 檔案\n      sessions:\n        otp: 輸入你手機上生成的雙重認證碼，或者任意一個恢復代碼：\n      user:\n        chosen_languages: 只有被選擇的語言會在公開時間軸內顯示\n    labels:\n      account:\n        fields:\n          name: 標籤\n          value: 內容\n      defaults:\n        autofollow: 邀請別人關注你的賬號\n        avatar: 個人頭像\n        bot: 這帳號是機械人\n        chosen_languages: 語言過濾\n        confirm_new_password: 確認新密碼\n        confirm_password: 確認密碼\n        current_password: 目前密碼\n        data: 資料\n        display_name: 顯示名稱\n        email: 電郵地址\n        expires_in: 失效時間\n        fields: 資料\n        header: 個人頁面頂部\n        locale: 介面語言\n        locked: 將用戶轉為「私人」\n        max_uses: 最大使用次數\n        new_password: 新密碼\n        note: 簡介\n        otp_attempt: 雙重認證碼\n        password: 密碼\n        setting_auto_play_gif: 自動播放 GIF\n        setting_boost_modal: 在轉推前詢問我\n        setting_default_language: 文章語言\n        setting_default_privacy: 文章預設為\n        setting_default_sensitive: 預設我的內容為敏感內容\n        setting_delete_modal: 刪推前詢問我\n        setting_hide_network: 隱藏你的社交網絡\n        setting_noindex: 阻止搜尋引擎檢索\n        setting_reduce_motion: 減低動畫效果\n        setting_system_font_ui: 使用系統預設字型\n        setting_theme: 網站主題\n        setting_unfollow_modal: 取消關注前跳出詢問我\n        severity: 等級\n        type: 匯入資料類型\n        username: 用戶名稱\n        username_or_email: 用戶名稱或電郵\n      interactions:\n        must_be_follower: 隱藏沒有關注你的用戶的通知\n        must_be_following: 隱藏你不關注的用戶的通知\n        must_be_following_dm: 隱藏你不關注的用戶的私信\n      notification_emails:\n        digest: 定期電郵摘要\n        favourite: 當有用戶喜歡你的文章時，發電郵通知\n        follow: 當有用戶關注你時，發電郵通知\n        follow_request: 當有用戶要求關注你時，發電郵通知\n        mention: 當有用戶在文章提及你時，發電郵通知\n        reblog: 當有用戶轉推你的文章時，發電郵通知\n    'no': 否\n    required:\n      text: 必須填寫\n    'yes': 是\n"
  },
  {
    "path": "config/locales/simple_form.zh-TW.yml",
    "content": "---\nzh-TW:\n  simple_form:\n    hints:\n      account_warning_preset:\n        text: 您可使用嘟文語法，例如網址、「#」標籤和提及功能\n      admin_account_action:\n        send_email_notification: 使用者將收到帳戶發生之事情的解釋\n        text_html: 選用。您能使用嘟文語法。您可 <a href=\"%{path}\">新增警告預設</a> 來節省時間\n        type_html: 設定要使用 <strong>%{acct}</strong> 做的事\n        warning_preset_id: 選用。您仍可在預設的結尾新增自訂文字\n      defaults:\n        autofollow: 通過邀請網址註冊的使用者將自動關注你\n        avatar: 支援 PNG, GIF 或 JPG 圖片，檔案最大為 %{size}，會等比例縮減成 %{dimensions} 像素\n        bot: 此帳戶主要執行自動操作且可能未被監控\n        context: 應該套用過濾器的一項或多項內容\n        digest: 僅在你長時間未登入且在未登入期間收到私訊時傳送\n        discoverable_html: <a href=\"%{path}\" target=\"_blank\">目錄</a> 讓使用者們能基於興趣與活動尋找帳戶。需要至少 %{min_followers} 位關注者\n        email: 您將收到一封確認電子郵件\n        fields: 您可在個人資料上有至多 4 個以表格形式顯示的項目\n        header: 支援 PNG, GIF 或 JPG 圖片，檔案最大為 %{size}，會按比例縮小成 %{dimensions} 像素\n        inbox_url: 從您想要使用的中繼首頁複製網址\n        irreversible: 已過濾的嘟文將會不可逆的消失，即便過濾器移除之後也一樣\n        locale: 使用者介面、電子信件和推送通知的語言\n        locked: 需要您手動核准關注請求\n        password: 使用至少 8 個字元\n        phrase: 無論是嘟文的本文或是內容警告都會被過濾\n        scopes: 允許讓應用程式存取的 API。 若您選擇最高階範圍，則無須選擇個別項目。\n        setting_aggregate_reblogs: 請勿顯示最近已被轉嘟之嘟文的最新轉嘟（只影響最新收到的嘟文）\n        setting_display_media_default: 隱藏標為敏感的媒體\n        setting_display_media_hide_all: 總是隱藏所有媒體\n        setting_display_media_show_all: 總是顯示標為敏感的媒體\n        setting_hide_network: 你關注的人與關注你的人將不會在你的個人資料頁上顯示\n        setting_noindex: 會影響您的公開個人資料與嘟文頁面\n        setting_show_application: 您用來發嘟文的應用程式將會在您嘟文的詳細檢視顯示\n        username: 您的使用者名稱將在 %{domain} 是獨一無二的\n        whole_word: 如果關鍵字或詞組僅有字母與數字，則其將只在符合整個單字的時候才會套用\n      featured_tag:\n        name: 您可能想使用其中一個：\n      imports:\n        data: 從其他 Mastodon 伺服器匯出的 CSV 檔案\n      sessions:\n        otp: 請輸入產生自您手機 App 的兩步驟驗證碼，或輸入其中一個復原代碼：\n      user:\n        chosen_languages: 當核取時，只有選取語言的嘟文會在公開時間軸中顯示\n    labels:\n      account:\n        fields:\n          name: 標籤\n          value: 內容\n      account_warning_preset:\n        text: 預設文字\n      admin_account_action:\n        send_email_notification: 透過電子信件通知使用者\n        text: 自訂警告\n        type: 動作\n        types:\n          disable: 停用\n          none: 什麼也不做\n          silence: 安靜\n          suspend: 停權並不可逆的刪除帳戶資料\n        warning_preset_id: 使用警告預設\n      defaults:\n        autofollow: 邀請別人關注你的帳戶\n        avatar: 大頭貼\n        bot: 此帳號是台機器人\n        chosen_languages: 過濾語言\n        confirm_new_password: 確認新密碼\n        confirm_password: 確認密碼\n        context: 過濾情境\n        current_password: 目前密碼\n        data: 資料\n        discoverable: 在目錄列出此帳戶\n        display_name: 顯示名稱\n        email: 電子信箱位址\n        expires_in: 失效時間\n        fields: 個人資料中繼資料\n        header: 頁面頂端\n        inbox_url: 中繼收件匣的 URL\n        irreversible: 放棄而非隱藏\n        locale: 介面語言\n        locked: 鎖定帳號\n        max_uses: 最大使用次數\n        new_password: 新密碼\n        note: 簡介\n        otp_attempt: 兩步驟驗證碼\n        password: 密碼\n        phrase: 關鍵字或片語\n        setting_aggregate_reblogs: 時間軸中的群組轉嘟\n        setting_auto_play_gif: 自動播放 GIF 動畫\n        setting_boost_modal: 在轉嘟前先詢問我\n        setting_default_language: 嘟文語言\n        setting_default_privacy: 嘟文可見範圍\n        setting_default_sensitive: 總是將媒體標記為敏感內容\n        setting_delete_modal: 刪除嘟文前先詢問我\n        setting_display_media: 媒體顯示\n        setting_display_media_default: 預設\n        setting_display_media_hide_all: 全部隱藏\n        setting_display_media_show_all: 全部顯示\n        setting_expand_spoilers: 永遠展開標有內容警告的嘟文\n        setting_hide_network: 隱藏您的社交網路\n        setting_noindex: 阻止搜尋引擎建立索引\n        setting_reduce_motion: 減少過渡動畫效果\n        setting_show_application: 顯示用來傳送嘟文的應用程式\n        setting_system_font_ui: 使用系統預設字型\n        setting_theme: 站點主題\n        setting_unfollow_modal: 取消關注某人前先詢問我\n        severity: 優先級\n        type: 匯入類型\n        username: 使用者名稱\n        username_or_email: 使用者名稱或電子信箱位址\n        whole_word: 整個詞彙\n      featured_tag:\n        name: \"「#」標籤\"\n      interactions:\n        must_be_follower: 封鎖非關注者的通知\n        must_be_following: 封鎖您未關注之使用者的通知\n        must_be_following_dm: 封鎖您未關注之使用者的私訊\n      notification_emails:\n        digest: 傳送摘要信件\n        favourite: 當有使用者喜歡你的嘟文時，傳送電子信件通知\n        follow: 當有使用者關注你時，傳送電子信件通知\n        follow_request: 當有使用者請求關注你時，傳送電子信件通知\n        mention: 當有使用者在嘟文提及你時，傳送電子信件通知\n        reblog: 當有使用者轉嘟你的嘟文時，傳送電子信件通知\n        report: 當提交新檢舉時傳送電子郵件\n    'no': 否\n    required:\n      text: 必須填寫\n    'yes': 是\n"
  },
  {
    "path": "config/locales/sk.yml",
    "content": "---\nsk:\n  about:\n    about_hashtag_html: Toto sú verejné príspevky, otagované pod <strong>#%{hashtag}</strong>. Ak máš účet hocikde v rámci fediversa, môžeš s nimi narábať.\n    about_mastodon_html: Mastodon je sociálna sieť založená na otvorených webových protokoloch a na slobodnom softvéri. Je decentralizovaná, podobne ako email.\n    about_this: O tomto serveri\n    active_count_after: aktívni\n    active_footnote: Mesačne aktívnych užívateľov (MAU)\n    administered_by: 'Správcom je:'\n    apps: Aplikácie\n    apps_platforms: Uživaj Mastodon z iOSu, Androidu a iných platforiem\n    browse_directory: Prehľadávaj databázu profilov, filtruj podľa záujmov\n    browse_public_posts: Prebádaj naživo prúd verejných príspevkov na Mastodone\n    contact: Kontakt\n    contact_missing: Nezadaný\n    contact_unavailable: Neuvedený/á\n    discover_users: Objavuj užívateľov\n    documentation: Dokumentácia\n    extended_description_html: |\n      <h3>Pravidlá</h3>\n      <p>Žiadne zatiaľ uvedené nie sú</p>\n    federation_hint_html: S účtom na %{instance} budeš môcť následovať ľúdí na hociakom Mastodon serveri, ale aj inde.\n    generic_description: \"%{domain} je jeden server v sieti\"\n    get_apps: Vyskúšaj aplikácie\n    hosted_on: Mastodon hostovaný na %{domain}\n    learn_more: Zisti viac\n    privacy_policy: Ustanovenia o súkromí\n    see_whats_happening: Pozoruj, čo sa deje\n    server_stats: 'Serverové štatistiky:'\n    source_code: Zdrojový kód\n    status_count_before: Ktorí napísali\n    tagline: Následuj kamarátov, a objavuj nových\n    terms: Podmienky užívania\n    user_count_before: Domov pre\n    what_is_mastodon: Čo je Mastodon?\n  accounts:\n    choices_html: \"%{name}vé voľby:\"\n    follow: Následuj\n    following: Následujem\n    joined: Pridal/a sa v %{date}\n    last_active: naposledy aktívny\n    link_verified_on: Vlastníctvo tohto odkazu bolo skontrolované %{date}\n    media: Médiá\n    moved_html: \"%{name} účet bol presunutý na %{new_profile_link}:\"\n    network_hidden: Táto informácia nieje k dispozícii\n    nothing_here: Nič tu nie je!\n    people_followed_by: Ľudia, ktorých %{name} sleduje\n    people_who_follow: Ľudia sledujúci %{name}\n    pin_errors:\n      following: Musíš už následovať toho človeka, ktorého si praješ zviditeľniť\n    posts_tab_heading: Príspevky\n    posts_with_replies: Príspevky s odpoveďami\n    reserved_username: Prihlasovacie meno je vyhradené\n    roles:\n      admin: Správca\n      moderator: Moderátor\n    unavailable: Profil nieje dostupný\n    unfollow: Prestaň sledovať\n  admin:\n    account_actions:\n      action: Vykonaj\n      title: Vykonaj moderovací úkon voči %{acct}\n    account_moderation_notes:\n      create: Zanechaj poznámku\n      created_msg: Poznámka moderátora bola úspešne vytvorená!\n      delete: Vymaž\n      destroyed_msg: Moderátorska poznámka bola úspešne zmazaná!\n    accounts:\n      approve: Schváľ\n      approve_all: Schváľ všetky\n      are_you_sure: Si si istý/á?\n      avatar: Maskot\n      by_domain: Doména\n      change_email:\n        changed_msg: Email pre tento účet bol úspešne zmenený!\n        current_email: Súčasný email\n        label: Zmeň email\n        new_email: Nový email\n        submit: Zmeň email\n        title: Zmeň email pre %{username}\n      confirm: Potvrď\n      confirmed: Potvrdený\n      confirming: Potvrdzujúci\n      deleted: Vymazané\n      demote: Degraduj\n      disable: Zablokuj\n      disable_two_factor_authentication: Zakáž 2FA\n      disabled: Blokovaný\n      display_name: Ukáž meno\n      domain: Doména\n      edit: Uprav\n      email_status: Stav emailu\n      enable: Povoľ\n      enabled: Povolený\n      feed_url: adresa časovej osi\n      followers: Sledujúci\n      followers_url: URL adresa sledujúcich\n      follows: Sledovania\n      header: Záhlavie\n      inbox_url: URL adresa prijatých správ\n      invited_by: Pozvaný/á užívateľom\n      ip: IP adresa\n      joined: Pridal/a sa\n      location:\n        all: Všetko\n        local: Miestne\n        remote: Federované\n        title: Umiestnenie\n      login_status: Stav prihlásenia\n      media_attachments: Prílohy\n      memorialize: Zmeň na \"Navždy budeme spomínať\"\n      moderation:\n        active: Aktívny/a\n        all: Všetko\n        pending: Čakajúci\n        silenced: Umlčané\n        suspended: Vylúčený/á\n        title: Moderácia\n      moderation_notes: Moderátorské poznámky\n      most_recent_activity: Posledná aktivita\n      most_recent_ip: Posledná IP adresa\n      no_account_selected: Nedošlo k žiadnému pozmeneniu účtov, keďže žiadne neboli vybrané\n      no_limits_imposed: Nie sú stanovené žiadné obmedzenia\n      not_subscribed: Neodoberá\n      outbox_url: URL poslaných\n      pending: Vyžaduje posúdenie\n      perform_full_suspension: Vylúč\n      profile_url: URL adresa profilu\n      promote: Vyzdvihni\n      protocol: Protokol\n      public: Verejná časová os\n      push_subscription_expires: PuSH odoberanie expiruje\n      redownload: Obnov profil\n      reject: Zamietni\n      reject_all: Zamietni všetky\n      remove_avatar: Vymaž avatar\n      remove_header: Vymaž záhlavie\n      resend_confirmation:\n        already_confirmed: Tento užívateľ je už potvrdený\n        send: Odošli potvrdzovací email znovu\n        success: Potvrdzujúci email bol úspešne odoslaný!\n      reset: Resetuj\n      reset_password: Obnov heslo\n      resubscribe: Znovu odoberaj\n      role: Oprávnenia\n      roles:\n        admin: Správca\n        moderator: Moderátor\n        staff: Člen\n        user: Užívateľ\n      salmon_url: Salmon adresa\n      search: Hľadaj\n      shared_inbox_url: URL zdieľanej schránky\n      show:\n        created_reports: Vytvorené hlásenia\n        targeted_reports: Nahlásenia od ostatných\n      silence: Stíš\n      silenced: Stíšený/é\n      statuses: Príspevky\n      subscribe: Odoberaj\n      suspended: Vylúčený/á\n      title: Účty\n      unconfirmed_email: Nepotvrdený email\n      undo_silenced: Zruš stíšenie\n      undo_suspension: Zruš blokovanie\n      unsubscribe: Prestaň odoberať\n      username: Prezývka\n      warn: Varuj\n    action_logs:\n      actions:\n        assigned_to_self_report: \"%{name}pridelil/a hlásenie užívateľa %{target}sebe\"\n        change_email_user: \"%{name} zmenil/a emailovú adresu užívateľa %{target}\"\n        confirm_user: \"%{name} potvrdil e-mailovú adresu používateľa %{target}\"\n        create_account_warning: \"%{name} poslal/a varovanie užívateľovi %{target}\"\n        create_custom_emoji: \"%{name} nahral nový emoji %{target}\"\n        create_domain_block: \"%{name} zablokoval doménu %{target}\"\n        create_email_domain_block: \"%{name} pridal e-mailovú doménu %{target} na zoznam zakázaných\"\n        demote_user: \"%{name} degradoval používateľa %{target}\"\n        destroy_custom_emoji: \"%{name} zničil/a %{target} emoji\"\n        destroy_domain_block: \"%{name} povolil doménu %{target}\"\n        destroy_email_domain_block: \"%{name} pridal e-mailovú doménu %{target} na zoznam povolených\"\n        destroy_status: \"%{name} zmazal status %{target}\"\n        disable_2fa_user: \"%{name} zakázal 2FA pre používateľa %{target}\"\n        disable_custom_emoji: \"%{name} zakázal emoji %{target}\"\n        disable_user: \"%{name} zakázal prihlásenie pre používateľa %{target}\"\n        enable_custom_emoji: \"%{name} povolil emoji %{target}\"\n        enable_user: \"%{name} povolil prihlásenie pre používateľa %{target}\"\n        memorialize_account: '%{name} zmenil účet %{target} na stránku \"Navždy budeme spomínať\"'\n        promote_user: \"%{name} povýšil/a používateľa %{target}\"\n        remove_avatar_user: \"%{name} odstránil/a %{target}ov avatár\"\n        reopen_report: \"%{name} znovu otvoril/a hlásenie užívateľa %{target}\"\n        reset_password_user: \"%{name} resetoval/a heslo pre používateľa %{target}\"\n        resolve_report: \"%{name} vyriešili nahlásenie užívateľa %{target}\"\n        silence_account: \"%{name} utíšil/a účet %{target}\"\n        suspend_account: \"%{name} zablokoval/a účet používateľa %{target}\"\n        unassigned_report: \"%{name} odobral/a report od %{target}\"\n        unsilence_account: \"%{name} zrušil/a stíšenie účtu používateľa %{target}\"\n        unsuspend_account: \"%{name} zrušil/a blokovanie účtu používateľa %{target}\"\n        update_custom_emoji: \"%{name} aktualizoval/a emoji %{target}\"\n        update_status: \"%{name} aktualizoval/a status pre %{target}\"\n      deleted_status: \"(zmazaný príspevok)\"\n      title: Kontrólny záznam\n    custom_emojis:\n      by_domain: Doména\n      copied_msg: Miestna kópia emoji bola úspešne vytvorená\n      copy: Kopíruj\n      copy_failed_msg: Nebolo možné vytvoriť miestnu kópiu tohto emoji\n      created_msg: Emoji úspešne vytvorené!\n      delete: Zmaž\n      destroyed_msg: Emoji úspešne zničené!\n      disable: Zakáž\n      disabled_msg: Emoji bolo úspešne zakázané\n      emoji: Emotikony\n      enable: Povoľ\n      enabled_msg: Emoji bolo úspešne povolené\n      image_hint: PNG do 50KB\n      listed: V zozname\n      new:\n        title: Pridaj nové, vlastné emoji\n      overwrite: Prepíš\n      shortcode: Skratka\n      shortcode_hint: Aspoň 2 znaky, povolené sú alfanumerické, alebo podčiarkovník\n      title: Vlastné emoji\n      unlisted: Nie je na zozname\n      update_failed_msg: Nebolo možné aktualizovať toto emoji\n      updated_msg: Emoji bolo úspešne aktualizované!\n      upload: Nahraj\n    dashboard:\n      backlog: odložené aktivity\n      config: Nastavenia\n      feature_deletions: Vymazanie účtov\n      feature_invites: Pozvánky\n      feature_profile_directory: Katalóg profilov\n      feature_registrations: Registrácie\n      feature_relay: Federovací mostík\n      feature_timeline_preview: Náhľad časovej osi\n      features: Vymoženosti\n      hidden_service: Federácia so skrytými službami\n      open_reports: otvorené hlásenia\n      recent_users: Nedávni užívatelia\n      search: Celofrázové vyhľadávanie\n      single_user_mode: Jednouživateľské rozhranie\n      software: Softvér\n      space: Využitie miesta\n      title: Spravovacie rozhranie\n      total_users: užívateľov celkovo\n      trends: Trendy\n      week_interactions: Tohto-týždňové interakcie\n      week_users_active: aktívni tento týždeň\n      week_users_new: užívateľov počas tohto týždňa\n    domain_blocks:\n      add_new: Blokuj novú doménu\n      created_msg: Doména je v štádiu blokovania\n      destroyed_msg: Blokovanie domény bolo zrušené\n      domain: Doména\n      existing_domain_block_html: Pre účet %{name} si už nahodil/a přísnejšie obmedzenie, najskôr ho teda musíš <a href=\"%{unblock_url}\">odblokovať</a>.\n      new:\n        create: Vytvor blokovanie domény\n        hint: Blokovanie domény stále dovolí vytvárať nové účty v databázi, ale tieto budú spätne automaticky moderované.\n        severity:\n          desc_html: \"<strong>Stíšenie</strong> urobí všetky príspevky daného účtu neviditeľné pre všetkých ktorí nenásledujú tento účet. <strong>Suspendácia</strong> zmaže všetky príspevky, médiá a profilové informácie. Použi <strong>Žiadne</strong>, ak chceš iba neprijímať súbory médií.\"\n          noop: Nič\n          silence: Stíš\n          suspend: Vylúč\n        title: Nové blokovanie domény\n      reject_media: Odmietaj súbory s obrázkami, alebo videami\n      reject_media_hint: Vymaže miestne uložené súbory médií a odmietne ich sťahovanie v budúcnosti. Nepodstatné pri vylúčení\n      reject_reports: Zamietni hlásenia\n      reject_reports_hint: Ignoruj všetky hlásenia prichádzajúce z tejto domény. Nevplýva na blokovania\n      rejecting_media: odmietanie médiálnych súborov\n      rejecting_reports: odmietanie hlásení\n      severity:\n        silence: stíšené\n        suspend: vylúčené\n      show:\n        retroactive:\n          silence: Zruš stíšenie všetkých momentálne utíšených účtov z tejto domény\n          suspend: Zruš suspendáciu všetkých momentálne ovplyvnených účtov z tejto domény\n        title: Zruš blokovanie domény %{domain}\n        undo: Vráť späť\n      undo: Odvolaj blokovanie domény\n    email_domain_blocks:\n      add_new: Pridaj nový\n      created_msg: Emailová doména bola úspešne pridaná do zoznamu zakázaných\n      delete: Vymaž\n      destroyed_msg: Emailová doména bola úspešne vymazaná zo zoznamu zakázaných\n      domain: Doména\n      new:\n        create: Pridaj doménu\n        title: Nový email na zablokovanie\n      title: Blokované emailové adresy\n    followers:\n      back_to_account: Späť na účet\n      title: Sledovatielia užívateľa %{acct}\n    instances:\n      by_domain: Doména\n      delivery_available: Je v dosahu doručovania\n      moderation:\n        all: Všetky\n        limited: Obmedzené\n        title: Moderácia\n      title: Federácia\n      total_blocked_by_us: Nami blokované\n      total_followed_by_them: Nimi sledované\n      total_followed_by_us: Nami sledované\n      total_reported: Nahlásenia o nich\n      total_storage: Mediálne prílohy\n    invites:\n      deactivate_all: Pozastav všetky\n      filter:\n        all: Všetky\n        available: Dostupné\n        expired: Vypršalo\n        title: Filtruj\n      title: Pozvánky\n    pending_accounts:\n      title: Čakajúcich účtov (%{count})\n    relays:\n      add_new: Pridaj nový federovací mostík\n      delete: Vymaž\n      description_html: \"<strong>Federovací mostík</strong> je prechodný server, ktorý obmieňa veľké množstvá verejných príspevkov medzi tými servermi ktoré na od neho odoberajú, aj doňho prispievajú. <strong>Môže to pomôcť malým a stredným instanciám objavovať federovaný obsah</strong>, čo inak vyžaduje aby miestni užívatelia ručne následovali iných ľudí zo vzdialených instancií.\"\n      disable: Vypni\n      disabled: Vypnutý\n      enable: Povoľ\n      enable_hint: Ak povolíš, tvoj server bude odoberať všetky verejné príspevky z tohto mostu, a začne posielať verejné príspevky tvojho servera na tento most.\n      enabled: Povolené\n      inbox_url: URL adresa mostu\n      pending: Čaká sa na povolenie od prechodného mostu\n      save_and_enable: Ulož a povoľ\n      setup: Nastav prepojenie s mostom\n      status: Stav\n      title: Mosty\n    report_notes:\n      created_msg: Poznámka o nahlásení úspešne vytvorená!\n      destroyed_msg: Poznámka o nahlásení úspešne vymazaná!\n    reports:\n      account:\n        note: poznámka\n        report: nahlás\n      action_taken_by: Zákrok vykonal/a\n      are_you_sure: Si si istý/á?\n      assign_to_self: Priraď sebe\n      assigned: Priradený moderátor\n      comment:\n        none: Žiadne\n      created_at: Nahlásené\n      mark_as_resolved: Označiť ako vyriešené\n      mark_as_unresolved: Označ ako nevyriešené\n      notes:\n        create: Pridaj poznámku\n        create_and_resolve: Vyrieš s poznámkou\n        create_and_unresolve: Otvor znovu, s poznámkou\n        delete: Vymaž\n        placeholder: Opíš aké opatrenia boli urobené, alebo akékoľvek iné súvisiace aktualizácie…\n      reopen: Znovu otvor report\n      report: 'Nahlásiť #%{id}'\n      reported_account: Nahlásený účet\n      reported_by: Nahlásené užívateľom\n      resolved: Vyriešené\n      resolved_msg: Hlásenie úspešne vyriešené!\n      status: Stav\n      title: Hlásenia\n      unassign: Odober\n      unresolved: Nevyriešené\n      updated_at: Aktualizované\n    settings:\n      activity_api_enabled:\n        desc_html: Sčítanie miestne uverejnených príspevkov, aktívnych užívateľov, a nových registrácii, v týždenných intervaloch\n        title: Vydať hromadné štatistiky o užívateľskej aktivite\n      bootstrap_timeline_accounts:\n        desc_html: Ak je prezývok viacero, každú oddeľ čiarkou. Je možné zadať iba miestne, odomknuté účty. Pokiaľ necháš prázdne, je to pre všetkých miestnych správcov.\n        title: Štandardní následovníci nových užívateľov\n      contact_information:\n        email: Pracovný email\n        username: Kontaktné užívateľské meno\n      custom_css:\n        desc_html: Uprav vzhľad pomocou CSS, ktoré je načítané na každej stránke\n        title: Vlastné CSS\n      hero:\n        desc_html: Zobrazuje sa na hlavnej stránke. Doporučené je rozlišenie aspoň 600x100px. Pokiaľ nič nieje dodané, bude nastavený základný orázok serveru.\n        title: Obrázok hrdinu\n      mascot:\n        desc_html: Zobrazované na viacerých stránkach. Odporúčaná veľkosť aspoň 293×205px. Pokiaľ nieje nahraté, bude zobrazený základný maskot.\n        title: Obrázok maskota\n      peers_api_enabled:\n        desc_html: Domény, na ktoré tento server už v rámci fediversa natrafil\n        title: Zverejni zoznam objavených serverov\n      preview_sensitive_media:\n        desc_html: Náhľad odkazov z iných serverov, bude zobrazený aj vtedy, keď sú médiá označené ako citlivé\n        title: Ukazuj aj chúlostivé médiá v náhľadoch OpenGraph\n      profile_directory:\n        desc_html: Povoľ užívateľom, aby mohli byť nájdení\n        title: Zapni profilový katalóg\n      registrations:\n        closed_message:\n          desc_html: Toto sa zobrazí na hlavnej stránke v prípade, že sú registrácie uzavreté. Možno tu použiť aj HTML kód\n          title: Správa o uzavretých registráciách\n        deletion:\n          desc_html: Dovoľ každému aby si mohli zmazať svok účet\n          title: Sprístupni možnosť vymazať si účet\n        min_invite_role:\n          disabled: Nikto\n          title: Povoľ pozvánky od\n      registrations_mode:\n        modes:\n          approved: Pre registráciu je nutné povolenie\n          none: Nikto sa nemôže registrovať\n          open: Ktokoľvek sa môže zaregistrovať\n        title: Režím registrácií\n      show_known_fediverse_at_about_page:\n        desc_html: Ak je zapnuté, bude v ukážke osi možné nahliadnúť príspevky z celého známeho fediversa. Inak budú ukázané iba príspevky z miestnej osi.\n        title: Ukáž celé známe fediverse na náhľade osi\n      show_staff_badge:\n        desc_html: Ukáž moderátorsky odznak na užívateľovom profile\n        title: Ukáž značku moderátora\n      site_description:\n        desc_html: Oboznamujúci paragraf na hlavnej stránke a pri meta tagoch. Opíš, čo robí tento Mastodon server špecifickým, a ďalej hocičo iné, čo považuješ za dôležité. Môžeš použiť HTML kód, hlavne <code>&lt;a&gt;</code> a <code>&lt;em&gt;</code>.\n        title: Popis servera\n      site_description_extended:\n        desc_html: Toto je vhodné miesto pre tvoje pravidlá o prevádzke, pokyny, podmienky a iné veci, ktorými je tvoj server špecifický. Je možné tu používať HTML tagy\n        title: Vlastné doplňujúce informácie\n      site_short_description:\n        desc_html: Zobrazené na bočnom paneli a pri meta tagoch. Popíš čo je Mastodon, a čo robí tento server iným, v jednom paragrafe. Pokiaľ toto necháš prázdne, bude tu zobrazený základný popis servera.\n        title: Krátky popis serveru\n      site_terms:\n        desc_html: Môžeš si napísať svoje vlastné pravidla o súkromí, prevádzke, alebo aj iné legality. Môžeš tu používať HTML kód\n        title: Vlastné pravidlá prevádzky\n      site_title: Názov servera\n      thumbnail:\n        desc_html: Používané pre náhľady cez OpenGraph a API. Doporučuje sa rozlišenie 1200x630px\n        title: Miniatúra servera\n      timeline_preview:\n        desc_html: Zobraziť verejnú nástenku na hlavnej stránke\n        title: Náhľad nástenky\n      title: Nastavenia stránky\n    statuses:\n      back_to_account: Späť na účet\n      batch:\n        delete: Vymaž\n        nsfw_off: Označ ako nechúlostivé\n        nsfw_on: Označ ako chúlostivé\n      failed_to_execute: Nepodarilo sa vykonať\n      media:\n        title: Médiá\n      no_media: Žiadné médiá\n      no_status_selected: Žiadne príspevky neboli zmenené, keďže si žiadne nemal/a zvolené\n      title: Príspevky na účte\n      with_media: S médiami\n    subscriptions:\n      callback_url: Zdrojová adresa URL\n      confirmed: Potvrdené\n      expires_in: Vyprší do\n      last_delivery: Posledné doručenie\n      topic: Téma\n    tags:\n      accounts: Účty\n      hidden: Skryté\n      hide: Ukri od databázy\n      name: Haštag\n      title: Haštagy\n      unhide: Ukáž v databázi\n      visible: Viditeľné\n    title: Spravovanie\n    warning_presets:\n      add_new: Pridaj nové\n      delete: Vymaž\n      edit: Uprav\n      edit_preset: Uprav varovnú predlohu\n      title: Spravuj varovné predlohy\n  admin_mailer:\n    new_pending_account:\n      body: Podrobnosti o novom účte sú uvedené nižšie. Môžeš túto registračnú požiadavku buď prijať, alebo zamietnúť.\n    new_report:\n      body: \"%{reporter} nahlásil/a %{target}\"\n      body_remote: Niekto z %{domain} nahlásil/a %{target}\n      subject: Nové hlásenie pre %{instance} (#%{id})\n  appearance:\n    advanced_web_interface: Pokročilé webové rozhranie\n    animations_and_accessibility: Animácie a prístupnosť\n    confirmation_dialogs: Potvrdzovacie dialógy\n    sensitive_content: Chúlostivý obsah\n  application_mailer:\n    notification_preferences: Zmeň emailové voľby\n    settings: 'Zmeň emailové voľby: %{link}'\n    view: 'Zobraziť:'\n    view_profile: Zobraz profil\n    view_status: Zobraz status\n  applications:\n    created: Aplikácia bola vytvorená úspešne\n    destroyed: Aplikáciu sa podarilo odstrániť\n    invalid_url: Zadaná URL adresa je nesprávna\n    regenerate_token: Znovu vygenerovať prístupový token\n    token_regenerated: Prístupový token bol úspešne vygenerovaný znova\n    warning: Na tieto údaje dávaj ohromný pozor. Nikdy ich s nikým nezďieľaj!\n    your_token: Tvoj prístupový token\n  auth:\n    apply_for_account: Vyžiadaj si pozvánku\n    change_password: Heslo\n    checkbox_agreement_html: Súhlasím s <a href=\"%{rules_path}\" target=\"_blank\">pravidlami servera</a>, aj s <a href=\"%{terms_path}\" target=\"_blank\">prevoznými podmienkami</a>\n    confirm_email: Potvrď email\n    delete_account: Vymaž účet\n    delete_account_html: Pokiaľ chceš svoj účet odtiaľto vymazať, môžeš tak <a href=\"%{path}\">urobiť tu</a>. Budeš požiadaný/á o potvrdenie tohto kroku.\n    didnt_get_confirmation: Neobdržal/a si kroky na potvrdenie?\n    forgot_password: Zabudnuté heslo?\n    invalid_reset_password_token: Token na obnovu hesla vypršal. Prosím vypítaj si nový.\n    login: Prihlás sa\n    logout: Odhlás sa\n    migrate_account: Presúvam sa na iný účet\n    migrate_account_html: Ak si želáš presmerovať tento účet na nejaký iný, môžeš si to <a href=\"%{path}\">nastaviť tu</a>.\n    or_log_in_with: Alebo prihlás s\n    register: Zaregistruj sa\n    resend_confirmation: Zašli potvrdzujúce pokyny znovu\n    reset_password: Obnov heslo\n    security: Zabezpečenie\n    set_new_password: Nastav nové heslo\n    trouble_logging_in: Problém s prihlásením?\n  authorize_follow:\n    already_following: Tento účet už následuješ\n    error: Naneštastie nastala chyba pri hľadaní vzdialeného účtu\n    follow: Následuj\n    follow_request: 'Poslal/a si žiadosť následovať užívateľa:'\n    following: 'Podarilo sa! Teraz už následuješ užívateľa:'\n    post_follow:\n      close: Alebo môžeš iba zatvoriť toto okno.\n      return: Ukáž užívateľov profil\n      web: Prejdi do siete\n    title: Následuj %{acct}\n  datetime:\n    distance_in_words:\n      about_x_hours: \"%{count}hod\"\n      about_x_months: \"%{count}mesiace\"\n      about_x_years: \"%{count}rok\"\n      almost_x_years: \"%{count}rok\"\n      half_a_minute: Práve teraz\n      less_than_x_minutes: \"%{count}min\"\n      less_than_x_seconds: Práve teraz\n      over_x_years: \"%{count}rok\"\n      x_days: \"%{count}dni\"\n      x_minutes: \"%{count}min\"\n      x_months: \"%{count}mesiace\"\n      x_seconds: \"%{count}sek\"\n  deletes:\n    bad_password_msg: Dobrý pokus, hakeri! Nesprávne heslo\n    confirm_password: Napíšte svoje terajšie heslo pre overenie vašej identity\n    description_html: Týmto <strong> natrvalo, nenavrátiteľne </strong> vymažeš obsah tvojho účtu, a deaktivuješ ho. Tvoja prezývka ale ostane rezervovaná ako prevencia pred budúcimi impersonáciami.\n    proceed: Vymaž účet\n    success_msg: Tvoj účet bol úspešne vymazaný\n    warning_html: Iba vymazanie obsahu z tohto konkrétneho serveru je zaručené. Obsah, ktorý bol zdieľaný široko-ďaleko pravdepodobne zanechá nejaké stopy. Servery ktoré sú offline a tie ktoré ignorujú tvoje zmeny teda nezaktualizujú svoje databázy.\n    warning_title: Dostupnosť rozšírovaného obsahu\n  directories:\n    directory: Katalóg profilov\n    enabled: Momentálne si uvedený/á na zozname profilov.\n    enabled_but_waiting: Vyjadril/a si záujem o uvedenie na zozname profilov, lenže ešte nemáš minimálny vyžadovaný počet následovateľov (%{min_followers}), aby si tam bol/a uveden/á.\n    explanation: Pátraj po užívateľoch podľa ich záujmov\n    explore_mastodon: Prebádaj %{title}\n    how_to_enable: Momentálne niesi zaradený/á do verejnej profilovej databázy. Prihlásiť sa môžeš nižšie. Použi haštagy vo svojom biografickom popise na profile, ak chceš byť uvedený/á aj pod konkrétnými haštagmi!\n  errors:\n    '403': Nemáš povolenie pre zobrazenie tejto stránky.\n    '404': Stránka ktorú hľadáš nieje tu.\n    '410': Stránka ktorú si tu hľadal/a sa tu už viac nenachádza.\n    '422':\n      content: Bezpečtnostné overenie zlyhalo. Blokuješ cookies?\n      title: Bezpečtnostné overenie zlyhalo\n    '429': Zamlčané\n    '500':\n      content: Ospravedlňujem sa. Niečo sa pokazilo na našom konci.\n      title: Táto stránka nieje v poriadku\n    noscript_html: Aby bolo možné používať Mastodon web aplikáciu, povoľ prosím JavaScript. Alebo skús jednu z <a href=\"%{apps_path}\"> aplikácii </a> dostupných pre vašu platformu.\n  exports:\n    archive_takeout:\n      date: Dátum\n      download: Stiahni si svoj archív\n      hint_html: Môžeš si vyžiadať <strong>archív svojích príspevkov a nahratých médií</strong>. Exportované dáta budú v ActivityPub formáte, čítateľné hociakým kompatibilným softvérom. Archív si je možné vyžiadať každých sedem dní.\n      in_progress: Balím tvoj archív...\n      request: Vyžiadaj si tvoj archív\n      size: Veľkosť\n    blocks: Blokujete\n    domain_blocks: Blokované domény\n    follows: Následujete\n    lists: Zoznamy\n    mutes: Stíšil/a si\n    storage: Úložisko médií\n  featured_tags:\n    add_new: Pridaj nový\n    errors:\n      limit: Už si si predvolil/a najvyšší možný počet obľúbených haštagov\n  filters:\n    contexts:\n      home: Domáca os\n      notifications: Oznámenia\n      public: Verejné osi\n      thread: Konverzácie\n    edit:\n      title: Uprav triedenie\n    errors:\n      invalid_context: Nebola poskytnutá žiadna, alebo ide o neplatnú súvislosť\n      invalid_irreversible: Nezvratné filtrovanie funguje iba so súvislostiami domovskej osi a oboznámení\n    index:\n      delete: Vymaž\n      title: Triedenia\n    new:\n      title: Pridaj nové triedenie\n  footer:\n    developers: Vývojári\n    more: Viac…\n    resources: Podklady\n  generic:\n    changes_saved_msg: Zmeny boli úspešne uložené!\n    copy: Kopíruj\n    save_changes: Ulož zmeny\n  imports:\n    modes:\n      merge: Spoj dohromady\n      merge_long: Ponechaj existujúce záznamy a pridaj k nim nové\n      overwrite: Prepíš\n      overwrite_long: Nahraď súčasné záznamy novými\n    preface: Môžeš nahrať dáta ktoré si exportoval/a z iného Mastodon serveru, ako sú napríklad zoznamy ľudí ktorých sleduješ, alebo blokuješ.\n    success: Tvoje dáta boli nahraté úspešne, a teraz budú spracované v danom čase\n    types:\n      blocking: Zoznam blokovaných\n      domain_blocking: Zoznam blokovaných domén\n      following: Zoznam sledovaných\n      muting: Zoznam ignorovaných\n    upload: Nahraj\n  in_memoriam_html: V pamäti.\n  invites:\n    delete: Deaktivuj\n    expired: Neplatné\n    expires_in:\n      '1800': 30 minút\n      '21600': 6 hodín\n      '3600': 1 hodina\n      '43200': 12 hodín\n      '604800': 1 týždeň\n      '86400': 1 deň\n    expires_in_prompt: Nikdy\n    generate: Vygeneruj\n    invited_by: 'Bol/a si pozvaný/á užívateľom:'\n    max_uses_prompt: Bez obmedzení\n    prompt: Vygeneruj a zdieľaj linky s ostatnými, aby mali umožnený prístup k tomuto serveru\n    table:\n      expires_at: Vyprší\n      uses: Používa\n    title: Pozvi ľudí\n  lists:\n    errors:\n      limit: Dosiahli ste maximálny možný počet zoznamov\n  media_attachments:\n    validations:\n      images_and_video: K príspevku ktorý už obsahuje obrázky nemôžeš priložiť video\n      too_many: Nemôžeš priložiť viac ako 4 súbory\n  migrations:\n    acct: prezývka@doména nového účtu\n    currently_redirecting: 'Tvoj profil má nastavené presmerovanie na:'\n    proceed: Uložiť\n    updated_msg: Tvoje nastavenia pre presmerovanie účtu boli úspešne aktualizované!\n  moderation:\n    title: Moderovanie\n  notification_mailer:\n    digest:\n      action: Zobraziť všetky notifikácie\n      body: Tu nájdete krátky súhrn správ ktoré ste zmeškali od svojej poslednj návštevi od %{since}\n      mention: \"%{name} ťa spomenul/a v:\"\n      title: Zatiaľ čo si bol/a preč…\n    favourite:\n      body: 'Tvoj príspevok bol uložený medzi obľúbené užívateľa %{name}:'\n      subject: \"%{name} si obľúbil/a tvoj príspevok\"\n      title: Nové obľúbené\n    follow:\n      body: \"%{name} ťa teraz následuje!\"\n      subject: \"%{name} ťa teraz následuje\"\n      title: Nový sledovateľ\n    follow_request:\n      action: Spravuj žiadosti o sledovanie\n      body: \"%{name} žiada povolenie ťa následovať\"\n      subject: \"%{name} ťa žiadá o možnosť sledovania\"\n      title: Nová žiadosť o následovanie\n    mention:\n      action: Odpovedať\n      body: \"%{name} ťa spomenul/a v:\"\n      subject: Bol/a si spomenutý/á užívateľom %{name}\n      title: Novo spomenutý/á\n    reblog:\n      body: 'Tvoj príspevok bol vyzdvihnutý užívateľom %{name}:'\n      subject: \"%{name} vyzdvihli tvoj príspevok\"\n      title: Novo vyzdvyhnuté\n  pagination:\n    newer: Novšie\n    next: Ďalšie\n    older: Staršie\n    prev: Predchádzajúce\n  polls:\n    errors:\n      already_voted: V tejto ankete si už hlasoval/a\n      duplicate_options: obsahuje opakujúce sa položky\n      duration_too_long: je príliš ďaleko do budúcnosti\n      duration_too_short: je príliš skoro\n      expired: Anketa už skončila\n      over_character_limit: každá nemôže byť dlhšia ako %{max} znakov\n      too_few_options: musí mať viac ako jednu položku\n      too_many_options: nemôže zahŕňať viac ako %{max} položiek\n  preferences:\n    other: Ostatné\n  remote_follow:\n    acct: Napíš svoju prezývku@doménu z ktorej chceš následovať\n    missing_resource: Nemožno nájsť potrebnú presmerovaciu adresu k tvojmu účtu\n    no_account_html: Nemáš účet? Môžeš sa <a href='%{sign_up_path}' target='_blank'>zaregistrovať tu</a>\n    proceed: Začni následovať\n    prompt: 'Budeš sledovať:'\n    reason_html: \"<strong>Načo je tento krok potrebný?</strong> <code>%{instance}</code> nemusí byť práve tým serverom na ktorom si zaregistrovaný/á, takže je ťa najprv potrebné presmerovať na tvoj domáci server.\"\n  remote_interaction:\n    favourite:\n      proceed: Pokračuj k obľúbeniu\n      prompt: 'Chceš si obľúbiť tento príspevok:'\n    reblog:\n      proceed: Pokračuj k vyzdvihnutiu\n      prompt: 'Chceš vyzdvihnúť tento príspevok:'\n    reply:\n      proceed: Pokračuj odpovedaním\n      prompt: 'Chceš odpovedať na tento príspevok:'\n  remote_unfollow:\n    error: Chyba\n    title: Názov\n    unfollowed: Už nesleduješ\n  scheduled_statuses:\n    over_daily_limit: Prekročil/a si denný limit %{limit} predplánovaných príspevkov\n    over_total_limit: Prekročil/a si limit %{limit} predplánovaných príspevkov\n    too_soon: Dátum musí byť stanovený do budúcnosti\n  sessions:\n    activity: Najnovšia aktivita\n    browser: Prehliadač\n    browsers:\n      blackberry: RIM Blackberry\n      chrome: Google Chrome\n      firefox: Mozilla Firefox\n      generic: Neznámy prehliadač\n      nokia: Nokia Ovi Browser\n      otter: Prehliadač Otter\n      qq: QQ Prehliadač\n      safari: Apple Safari\n      weibo: Sina/Tencent Weibo\n    current_session: Aktuálna sezóna\n    description: \"%{browser} na %{platform}\"\n    explanation: Tieto sú prehliadače ktoré sú teraz prihlásené na tvoj Mastodon účet.\n    ip: IP adresa\n    platforms:\n      chrome_os: Google ChromeOS\n      ios: Apple iOS\n      linux: GNU/Linux\n      mac: MacOSX\n      other: neznáma platforma\n      windows: Microsoft Windows\n    revoke: Zamietni\n    revoke_success: Sezóna úspešne zamietnutá\n    title: Sezóny\n  settings:\n    account: Účet\n    account_settings: Nastavenia účtu\n    appearance: Vzhľad\n    authorized_apps: Povolené aplikácie\n    back: Späť na Mastodon\n    delete: Vymazanie účtu\n    development: Vývoj\n    edit_profile: Uprav profil\n    export: Exportuj dáta\n    featured_tags: Zvýraznené haštagy\n    import: Importuj\n    import_and_export: Import a export\n    migrate: Presuň účet\n    notifications: Oboznámenia\n    preferences: Voľby\n    profile: Profil\n    relationships: Následovaní a následovatelia\n    two_factor_authentication: Dvoj-faktorové overenie\n  statuses:\n    attached:\n      description: 'Priložené: %{attached}'\n    boosted_from_html: Povýšené od %{acct_link}\n    content_warning: 'Varovanie o obsahu: %{warning}'\n    language_detection: Zisti automaticky\n    open_in_web: Otvor v okne na webe\n    over_character_limit: limit %{max} znakov bol presiahnutý\n    pin_errors:\n      limit: Už si si pripol ten najvyšší možný počet hlášok\n      ownership: Nieje možné pripnúť hlášku od niekoho iného\n      private: Neverejné príspevky nemôžu byť pripnuté\n      reblog: Vyzdvihnutie sa nedá pripnúť\n    poll:\n      vote: Hlasuj\n    show_more: Ukáž viac\n    sign_in_to_participate: Prihlás sa pre zapojenie do diskusie\n    title: '%{name}: „%{quote}\"'\n    visibilities:\n      private: Iba pre sledovateľov\n      private_long: Ukáž iba následovateľom\n      public: Verejné\n      public_long: Všetci môžu vidieť\n      unlisted: Nezaradené\n      unlisted_long: Všetci môžu vidieť, ale nieje zaradené do verejnej osi\n  stream_entries:\n    pinned: Pripnutý príspevok\n    reblogged: vyzdvihnutý\n    sensitive_content: Senzitívny obsah\n  terms:\n    body_html: |\n      <h2>Podmienky súkromia</h2>\n\n      <h3 id=\"collect\">Aké informácie sú zbierané?</h3>\n\n      <ul>\n      <li><em>Základné informácie o účte</em>: Ak sa na tomto serveri zaregistruješ, budeš môcť byť požiadaný/á zadať prezývku, emailovú adresu a heslo. Budeš tiež môcť zadať aj ďalšie profilové údaje, ako napríklad meno a životopis, a nahrať profilovú fotku aj obrázok v záhlaví. Tvoja prezývka, meno, životopis, profilová fotka a obrázok v záhlaví sú vždy zobrazené verejne.</li><li><em>Príspevky, sledovania a iné verejné informácie</em>:\n      Zoznam ľudí, ktorých sleduješ je zobrazený verejne, a to isté platí aj pre zoznam tvojích následovateľov. Keď pošleš správu, ukladá sa jej dátum a čas, ale aj z akej aplikácie bola poslaná. Správy môžu obsahovať mediálne prílohy, ako obrázky a videá. Verejné, a nezaradené príspevky sú verejne prístupné. Keď si pripneš príspevok na svoj profil, toto je tiež verejne dostupnou informáciou. Tvoje príspevky sú takisto doručené tvojím sledovateľom, a to aj v rámci iných serverov, kde je potom uložená kópia tvojho príspevku. Ak vymažeš príspevok, táto akcia bude takisto doručená tvojím sledovateľom. Vyzdvihnutie, alebo obľúbenie iného príspevku je vždy verejne viditeľné.</li>\n\n      <li><em>Priame príspevky, a príspevky určené iba pre sledovateľov</em>: Všetky príspevky sú uložené a spracované na serveri. Príspevky iba pre sledovateľov sú doručené tvojím sledovateľom a užívateľom ktorí sú v nich spomenutí, pričom priame príspevky sú doručené iba tím užívateľom ktorí sú v nich spomenutí. V niektorých prípadoch to môže znamenať, že tieto príspevkz sú doručené aj v rámci iných serverov, a kópie príspevkov sú na nich uložené.\n      V dobrej viere robíme všetko preto, aby bol prístup k tímto príspevkom vymedzený iba pre oprávnených používateľov, ale môže sa stať, že iné servery v tomto ohľade zlyhajú. Preto je dôležité prezrieť si a zhodnotiť, na aké servery patria tvoji následovatelia. V nastaveniach si môžeš zapnúť voľbu ručne povoľovať a odmietať nových následovateľov.\n      <em>Prosím maj na pamäti, že správcovia tvojho, aj vzdialeného obdŕžiavajúceho servera majú možnosť vidieť dané príspevky a správy, ale aj, že obdŕžitelia týchto správ si ich môzu odfotiť, skopírovať, alebo ich inak zdieľať. <em>Nezdieľaj žiadne nebezpečné, alebo ohrozujúce správy pomocou Mastodonu!</em></li>\n\n      <li><em>IPky a iné metadáta</em>: Keď sa prihlásiš, zaznamenáva sa IP adresa z ktorej si sa prihlásil/a, takisto ako aj názov tvojho prehliadača. Všetky zaznamenané sezóny sú pre teba dostupné na konktolu, alebo na zamietnutie prístupu v nastaveniach. Posledná použitá IP adresa je uložená až po dobu dvanástich mesiacov. Môžeme si tiež ponechať serverové záznamy, ktoré obsahujú IP adresu každej požiadavky na tento server.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"use\">Načo sú tvoje údaje používané?</h3>\n\n      <p>Hociktorá z informácií, ktoré sú o tebe zozbierané, môže byť použité následujúcimi spôsobmi:</p>\n      <ul>\n      <li>Pre zabezpečenie základného fungovania Mastodonu. Narábať s užívateľským obsahom iných, ako aj prispievať svoj vlastný obsah, možeš len keď si prihlásený/á. Môžeš napríklad následovať iných ľudí, aby si potom videl/a ich príspevky v rámci svojej osobne prispôsobenej domácej osi.</li>\n      <li>Pre lepšie moderovanie komunity sa napríklad môže tvoja IP adresa porovnať s ostatnými už známimi adresami, aby bolo možné zistiť, či nedochádza napríklad k obchádzaniu pravidiel vylúčenia, aleb k iným porušeniam zásad.</li>\n      <li>Emailová adresa, ktorú poskytneš, môže byť použitá na zasielanie informácií, oboznámení keď ostatní užívatelia interaktujú s tvojím obsahom, alebo na posielanie správ, odpovedí na otázky a iné požiadavky.</li>\n      </ul>\n    title: Podmienky užívania, a pravidlá súkromia pre %{instance}\n  themes:\n    contrast: Mastodon (vysoký kontrast)\n    default: Mastodon (tmavý)\n    mastodon-light: Mastodon (svetlý)\n  time:\n    formats:\n      default: \"%b %d, %R, %H:%M\"\n  two_factor_authentication:\n    code_hint: Pre potvrdenie teraz zadaj kód vygenerovaný pomocou tvojej overovacej aplikácie\n    description_html: Ak povolíš <strong> dvoj-faktorové overovanie</strong>, na prihlásenie potom budeš potrebovať svoj telefón, ktorý vygeneruje prístupové kódy, čo musíš zadať.\n    disable: Zakáž\n    enable: Povoľ\n    enabled: Dvoj-faktorové overovanie je povolené\n    enabled_success: Dvoj-faktorové overovanie bolo úspešne povolené\n    generate_recovery_codes: Vygeneruj zálohové kódy\n    instructions_html: \"<strong>Naskenuj tento QR kód do Google Autentikátora, alebo do podobnej TOTP aplikácie pomocou svojho telefónu.</strong> Od tejto chvíle bude táto aplikácia pre teba generovať kódy ktoré musíš zadať aby si sa prihlásil/a.\"\n    lost_recovery_codes: Zálohové kódy ti umožnia dostať sa k svojmu účtu ak stratíš telefón. Pokiaľ si stratila svoje zálohové kódy, môžeš si ich tu znovu vygenerovať. Tvoje staré zálohové kódy budú zneplatnené.\n    manual_instructions: 'Pokiaľ nemôžeš oskenovať daný QR kód, a potrebuješ ho zadať ručne, tu je tajomstvo v textovom formáte:'\n    recovery_codes: Zálohuj kódy pre obnovu\n    recovery_codes_regenerated: Zálohové kódy boli úspešne zvova vygenerované\n    recovery_instructions_html: Keď hocikedy stratíš prístup k svojmu telefónu, môžeš použiť jeden z prístupových kódov nižšie pre obnovenie prístupu k svojmu účtu. <strong>Skladuj tieto prístupové kódy na bezpečnom mieste</strong>. Napríklad ich môžeš vytlačiť a uložiť ich spolu s inými dôležitými dokumentami.\n    setup: Nastav\n    wrong_code: Zadaný kód bol neplatný! Je serverový čas a čas na zariadení správny?\n  user_mailer:\n    backup_ready:\n      explanation: Vyžiadal/a si si úplnú zálohu svojho Mastodon účtu. Táto záloha je teraz pripravená na stiahnutie!\n      subject: Tvoj archív je pripravený na stiahnutie\n      title: Odber archívu\n    warning:\n      explanation:\n        disable: Pokiaľ je tvoj účet zamrazený, tvoje dáta zostávajú nedoknuté, ale nemôžeš v rámci neho nič robiť, až kým nebude odomknutý.\n        silence: Kým máš účet obmedzený, tvoje príspevky na tomto serveri uvidia iba tí ľudia, ktorí ťa už následujú, a môžeš byť vylúčený/á z rôznych verejných záznamov. Ostatní ťa však stále budú môcť následovať manuálne.\n        suspend: Tvoj účet bol vylúčený, a všetky tvoje príspevky a nahraté médiálné súbory boli nenávratne zmazané z tohto serveru, a zo serverov na ktorých si mal následovateľov.\n      review_server_policies: Prehodnoť pravidlá servera\n      subject:\n        disable: Tvoj účet %{acct} bol zamrazený\n        none: Varovanie pre %{acct}\n        silence: Tvoj účet %{acct} bol obmedzený\n        suspend: Tvoj účet %{acct} bol vylúčený\n      title:\n        disable: Účet bol zamrazený\n        none: Varovanie\n        silence: Účet bol obmedzený\n        suspend: Tvoj účet bol vylúčený\n    welcome:\n      edit_profile_action: Nastav profil\n      edit_profile_step: Profil si môžeš prispôsobiť nahratím portrétu a hlavičky, môžeš upraviť svoje meno a viac. Pokiaľ chceš preverovať nových následovateľov predtým než ťa budú môcť sledovať, môžeš uzamknúť svoj účet.\n      explanation: Tu nájdeš nejaké tipy do začiatku\n      final_action: Začni prispievať\n      final_step: 'Začni písať! Aj bez následovateľov budú tvoje verejné príspevky videné ostatnými, napríklad na miestnej osi a pod haštagmi. Ak chceš, môžeš sa ostatným predstaviť pod haštagom #introductions.'\n      full_handle: Adresa tvojho profilu v celom formáte\n      full_handle_hint: Toto je čo musíš dať vedieť svojím priateľom aby ti mohli posielať správy, alebo ťa následovať z iného serveru.\n      review_preferences_action: Zmeniť nastavenia\n      review_preferences_step: Daj si záležať na svojích nastaveniach, napríklad že aké emailové notifikácie chceš dostávať, alebo pod aký level súkromia sa tvoje príspevky majú sami automaticky zaradiť. Pokiaľ nemáš malátnosť z pohybu, môžeš si zvoliť aj automatické spúšťanie GIF animácií.\n      subject: Vitaj na Mastodone\n      tip_federated_timeline: Federovaná os zobrazuje sieť Mastodonu až po jej hranice. Ale zahŕňa iba ľúdí ktorých ostatní okolo teba sledujú, takže predsa nieje úplne celistvá.\n      tip_following: Správcu servera následuješ automaticky. Môžeš ale nájsť mnoho iných zaujímavých ľudí ak prezrieš tak lokálnu, ako aj globálne federovanú os.\n      tip_local_timeline: Miestna časová os je celkový pohľad na aktivitu užívateľov %{instance}. Toto sú tvoji najbližší susedia!\n      tip_mobile_webapp: Pokiaľ ti prehliadač ponúkne možnosť pridať Mastodon na tvoju obrazovku, môžeš potom dostávať notifikácie skoro ako z natívnej aplikácie!\n      tips: Tipy\n      title: Vitaj na palube, %{name}!\n  users:\n    follow_limit_reached: Nemôžeš následovať viac ako %{limit} ľudí\n    invalid_email: Emailová adresa je neplatná\n    invalid_otp_token: Neplatný kód pre dvojfaktorovú autentikáciu\n    otp_lost_help_html: Pokiaľ si stratil/a prístup k obom, môžeš dať vedieť %{email}\n    seamless_external_login: Si prihlásená/ý cez externú službu, takže nastavenia hesla a emailu ti niesú prístupné.\n    signed_in_as: 'Prihlásená/ý ako:'\n  verification:\n    explanation_html: 'Môžeš sa <strong>overiť ako majiteľ odkazov v metadátach tvojho profilu</strong>. Na to ale musí odkazovaná stránka obsahovať odkaz späť na tvoj Mastodon profil. Tento spätný odkaz <strong>musí</strong> mať prívlastok <code>rel=\"me\"</code>. Na texte odkazu nezáleží. Tu je príklad:'\n    verification: Overenie\n"
  },
  {
    "path": "config/locales/sl.yml",
    "content": "---\nsl:\n  about:\n    about_hashtag_html: To so javni tuti, označeni z <strong>#%{hashtag}</strong>. Z njimi se lahko povežete, če imate račun kjerkoli v fediversu.\n    about_mastodon_html: Mastodon je socialno omrežje, ki temelji na odprtih spletnih protokolih in prosti ter odprtokodni programski opremi. Je decentraliziran, kot e-pošta.\n    about_this: O Mastodonu\n    administered_by: 'Upravlja:'\n    apps: Mobilne aplikacije\n    contact: Kontakt\n    contact_missing: Ni nastavljeno\n    contact_unavailable: Ni na voljo\n    documentation: Dokumentacija\n    extended_description_html: |\n      <h3>Dober prostor za pravila</h3>\n      <p>Razširjen opis še ni bil nastavljen.</p>\n    generic_description: \"%{domain} je en strežnik v omrežju\"\n    hosted_on: Mastodon gostuje na %{domain}\n    learn_more: Spoznaj več\n    privacy_policy: Politika zasebnosti\n    source_code: Izvorna koda\n    status_count_after:\n      few: stanja\n      one: stanje\n      other: stanj\n      two: stanja\n    status_count_before: Ki so avtorji\n    terms: Pogoji storitve\n    user_count_after:\n      few: uporabniki\n      one: uporabnik\n      other: uporabnikov\n      two: uporabniki\n    user_count_before: Dom za\n    what_is_mastodon: Kaj je Mastodon?\n  accounts:\n    choices_html: \"%{name} izbire:\"\n    follow: Sledi\n    followers:\n      few: Sledilci\n      one: Sledilec\n      other: Sledilci\n      two: Sledilci\n    following: Sledim\n    joined: Se je pridružil na %{date}\n    last_active: zadnji aktivni\n    link_verified_on: Lastništvo te povezave je bilo preverjeno na %{date}\n    media: Medij\n    moved_html: \"%{name} se je prestavil na %{new_profile_link}:\"\n    network_hidden: Te informacije niso na voljo\n    nothing_here: Nič ni tukaj!\n    people_followed_by: Ljudje, ki jim sledi %{name}\n    people_who_follow: Ljudje, ki sledijo %{name}\n    pin_errors:\n      following: Verjetno že sledite osebi, ki jo želite potrditi\n    posts:\n      few: Trob\n      one: Trob\n      other: Trob\n      two: Trob\n    posts_tab_heading: Trobi\n    posts_with_replies: Tuti in odgovori\n    reserved_username: Uporabniško ime je zasedeno\n    roles:\n      admin: Skrbnik\n      bot: Robot\n    unfollow: Prenehaj slediti\n  admin:\n    account_actions:\n      action: Izvedi dejanje\n      title: Izvedi moderirano dejanje %{acct}\n    account_moderation_notes:\n      create: Pusti opombo\n      created_msg: Uspešno ustvarjena opomba moderiranja!\n      delete: Izbriši\n      destroyed_msg: Moderirana opomba je uspešno uničena!\n    accounts:\n      are_you_sure: Ali si prepričan?\n      by_domain: Domena\n      change_email:\n        changed_msg: E-pošta računa je uspešno spremenjena!\n        current_email: Trenutna E-pošta\n        label: Spremeni E-pošto\n        new_email: Nova E-pošta\n        submit: Spremeni E-pošto\n        title: Spremeni E-pošto za %{username}\n      confirm: Potrdi\n      confirmed: Potrjeno\n      confirming: Potrjujem\n      deleted: Izbrisano\n      demote: Ponižaj\n      disable: Onemogoči\n      disable_two_factor_authentication: Onemogoči 2FA\n      disabled: Onemogočeno\n      display_name: Prikazno ime\n      domain: Domena\n      edit: Uredi\n      email: E-pošta\n      email_status: Stanje E-pošte\n      enable: Omogoči\n      enabled: Omogočeno\n      feed_url: URL vir\n      followers: Sledilci\n      followers_url: URL sledilci\n      follows: Sledi\n      header: Glava\n      inbox_url: URl v mapi \"Prejeto\"\n      invited_by: Povabljen od\n      joined: Pridružil\n      location:\n        all: Vse\n        local: Lokalno\n        remote: Oddaljeni\n        title: Lokacija\n      login_status: Stanje prijave\n      media_attachments: Medijske priloge\n      memorialize: Spremenite v spomin\n      moderation:\n        active: Dejaven\n        all: Vse\n        silenced: Utišan\n        suspended: Suspendiran\n        title: Moderiranje\n      moderation_notes: Opombe moderiranja\n      most_recent_activity: Zadnja aktivnost\n      most_recent_ip: Zadnji IP\n      no_limits_imposed: Brez omejitev\n      not_subscribed: Ni naročeno\n      outbox_url: URl za pošiljanje\n      perform_full_suspension: Začasno ustavi\n      profile_url: URL profila\n      promote: Spodbujanje\n      protocol: Protokol\n      public: Javen\n      push_subscription_expires: Naročnina PuSH preteče\n      redownload: Osveži profil\n      remove_avatar: Odstrani podobo\n      remove_header: Odstrani glavo\n      resend_confirmation:\n        already_confirmed: Ta uporabnik je že potrjen\n        send: Ponovno pošlji potrditveno e-pošto\n        success: Potrditvena e-pošta je uspešno poslana!\n      reset: Ponastavi\n      reset_password: Ponastavi geslo\n      resubscribe: Ponovno se naroči\n      role: Dovoljenja\n      roles:\n        admin: Skrbnik\n        staff: Osebje\n        user: Uporabnik\n      search: Poišči\n      shared_inbox_url: URL mape \"Prejeto v skupni rabi\"\n      show:\n        created_reports: Narejene prijave\n        targeted_reports: Prijavili drugi\n      silence: Utišaj\n      silenced: Utišan\n      statuses: Stanja\n      subscribe: Naroči\n      suspended: Suspendiran\n      title: Računi\n      unconfirmed_email: Nepotrjena e-pošta\n      undo_silenced: Razveljavi utišanje\n      undo_suspension: Razveljavi suspendiranje\n      unsubscribe: Odjavi se od naročnine\n      username: Uporabniško ime\n      warn: Opozori\n      web: Splet\n    action_logs:\n      actions:\n        assigned_to_self_report: \"%{name} je prijavil %{target} sebi\"\n        change_email_user: \"%{name} je spremenil naslov e-pošte uporabnika %{target}\"\n        confirm_user: \"%{name} je potrdil naslov e-pošte uporabnika %{target}\"\n        create_account_warning: \"%{name} je poslal opozorilo %{target}\"\n        create_custom_emoji: \"%{name} je poslal nove emotikone %{target}\"\n        create_domain_block: \"%{name} je blokiral domeno %{target}\"\n        create_email_domain_block: \"%{name} je dal na črni seznam e-pošto domene %{target}\"\n        demote_user: \"%{name} je degradiral uporabnika %{target}\"\n        destroy_custom_emoji: \"%{name} je uničil emotikon %{target}\"\n        destroy_domain_block: \"%{name} je odblokiral domeno %{target}\"\n        destroy_email_domain_block: \"%{name} je dal na beli seznam e-pošto domene %{target}\"\n        destroy_status: \"%{name} je odstranil stanje od %{target}\"\n        disable_2fa_user: \"%{name} je onemogočil dvofaktorsko zahtevo za uporabnika %{target}\"\n        disable_custom_emoji: \"%{name} je onemogočil emotikon %{target}\"\n        disable_user: \"%{name} je onemogočil prijavo za uporabnika %{target}\"\n        enable_custom_emoji: \"%{name} je omogočil emotikon %{target}\"\n        enable_user: \"%{name} je omogočil prijavo za uporabnika %{target}\"\n        memorialize_account: \"%{name} je spremenil račun od %{target} v stran spominov\"\n        promote_user: \"%{name} je spodbudil uporabnika %{target}\"\n        remove_avatar_user: \"%{name} je odstranil podobo od %{target}\"\n        reopen_report: \"%{name} je ponovno odprl prijavo %{target}\"\n        reset_password_user: \"%{name} je ponastavil geslo od uporabnika %{target}\"\n        resolve_report: \"%{name} je razrešil prijavo %{target}\"\n        silence_account: \"%{name} je utišal račun od %{target}\"\n        suspend_account: \"%{name} je začasno ustavil račun od %{target}\"\n        unassigned_report: \"%{name} je nedodeljeno prijavil %{target}\"\n        unsilence_account: \"%{name} je preklical utišanje računa od %{target}\"\n        unsuspend_account: \"%{name} je aktiviral račun od %{target}\"\n        update_custom_emoji: \"%{name} je posodobil emotikone %{target}\"\n        update_status: \"%{name} je posodobil stanje od %{target}\"\n      deleted_status: \"(izbrisano stanje)\"\n      title: Dnevnik revizije\n    custom_emojis:\n      by_domain: Domena\n      copied_msg: Lokalna kopija emotikona je bila uspešno ustvarjena\n      copy: Kopiraj\n      copy_failed_msg: Lokalne kopije emotikona ni bilo mogoče ustvariti\n      created_msg: Emotikon je uspešno ustvarjen!\n      delete: Izbriši\n      destroyed_msg: Emotikon je uspešno uničen!\n      disable: Onemogoči\n      disabled_msg: Ta emotikon je uspešno onemogočen\n      emoji: Emotikon\n      enable: Omogoči\n      enabled_msg: Ta emotikon je uspešno omogočen\n      image_hint: PNG do 50KB\n      listed: Navedeno\n      new:\n        title: Dodaj nove emotikone\n      overwrite: Prepiši\n      shortcode: Kratka koda\n      shortcode_hint: Najmanj 2 znaka, samo alfanumerični znaki in podčrtaji\n      title: Emotikoni po meri\n      unlisted: Neuvrščeni\n      update_failed_msg: Tega emotikona ni bilo mogoče posodobiti\n      updated_msg: Emotikon je uspešno posodobljen!\n      upload: Pošlji\n    dashboard:\n      backlog: Zaostala opravila\n      config: Nastavitve\n      feature_deletions: Brisanje računov\n      feature_invites: Poveza povabil\n      feature_profile_directory: Mapa profila\n      feature_registrations: Registracije\n      feature_relay: Rele federacije\n      features: Zmožnosti\n      hidden_service: Federacija s skritimi storitvami\n      open_reports: odprte prijave\n      recent_users: Nedavni uporabniki\n      search: Iskanje po celotnem besedilu\n      single_user_mode: Način enega uporabnika\n      software: Programska oprema\n      space: Uporaba prostora\n      title: Nadzorna plošča\n      total_users: Skupaj uporabnikov\n      trends: Trendi\n      week_interactions: interakcije ta teden\n      week_users_active: aktivni ta teden\n      week_users_new: uporabniki ta teden\n    domain_blocks:\n      add_new: Dodaj nov domenski blok\n      created_msg: Domenski blok se sedaj obdeluje\n      destroyed_msg: Domenski blok je bil razveljavljen\n      domain: Domena\n      new:\n        create: Ustvari blok\n        hint: Domenski blok ne bo preprečil ustvarjanja vnosov računov v zbirko podatkov, ampak bo retroaktivno in samodejno uporabil posebne metode moderiranja na teh računih.\n        severity:\n          desc_html: \"<strong>Utišaj</strong> bo vse objave računa naredil nevidne vsem, ki jih ne sledijo. <strong>Suspendiraj</strong> bo odstranil vso vsebino, medije in podatke profila računa. Uporabi <strong>nič</strong>, če želite le zavrniti predstavnostne datoteke.\"\n          noop: Nič\n          silence: Utišaj\n          suspend: Suspendiraj\n        title: Nov domenski blok\n      reject_media: Zavrni predstavnostne datoteke\n      reject_media_hint: Odstrani lokalno shranjene predstavnostne datoteke in zavrača prenašanje le-teh v prihodnosti. Za suspenzije ni pomembno\n      reject_reports: Zavrnjene prijave\n      reject_reports_hint: Prezri vse prijave, ki pridejo iz te domene. Za suspenzije ni pomembno\n      rejecting_media: zavrnitev predstavnostnih datotek\n      rejecting_reports: zavrnitev prijav\n      severity:\n        silence: utišani\n        suspend: suspendirani\n      show:\n        affected_accounts:\n          few: \"%{count} računov v bazi podatkov so prizadeti\"\n          one: En račun v bazi podatkov je prizadet\n          other: \"%{count} računov v bazi podatkov so prizadeti\"\n          two: \"%{count} računov v bazi podatkov so prizadeti\"\n        retroactive:\n          silence: Prekliči utišanje za vse obstoječe račune iz te domene\n          suspend: Odsuspendiraj vse obstoječe račune iz te domene\n        title: Razveljavi domenski blok za %{domain}\n        undo: Razveljavi\n      undo: Razveljavi domenski blok\n    email_domain_blocks:\n      add_new: Dodaj novo\n      created_msg: Domena e-pošte je bila uspešno dodana na črni seznam\n      delete: Izbriši\n      destroyed_msg: Domena e-pošte je bila uspešno izbrisana iz črnega seznama\n      domain: Domena\n      new:\n        create: Dodaj domeno\n        title: Nov vnos e-pošte na črni seznam\n      title: Črni seznam e-pošte\n    followers:\n      back_to_account: Nazaj na račun\n      title: Sledilci od %{acct}\n    instances:\n      delivery_available: Na voljo je dostava\n      known_accounts:\n        few: \"%{count} znanih računov\"\n        one: \"%{count} znan račun\"\n        other: \"%{count} znanih računov\"\n        two: \"%{count} znanih računov\"\n      moderation:\n        all: Vse\n        limited: Omejeno\n        title: Moderiranje\n      title: Federacija\n      total_blocked_by_us: Blokirano iz naše strani\n      total_followed_by_them: Oni ti sledijo\n      total_followed_by_us: Mi ti sledimo\n      total_reported: Poročila o njih\n      total_storage: Predstavnostne priloge\n    invites:\n      deactivate_all: Onemogoči vse\n      filter:\n        all: Vse\n        available: Razpoložljivo\n        expired: Potekel\n      title: Povabila\n    relays:\n      add_new: Dodaj nov rele\n      delete: Izbriši\n      description_html: \"<strong>Rele federacije</strong> je posredniški strežnik, ki si izmenjuje velike količine javnih trobov med strežniki, ki so se naročili in objavili na njem. <strong>Majhnim in srednjim strežnikom lahko pomaga pri odkrivanju vsebine iz sistema fediverse</strong>, kar bi sicer zahtevalo, da lokalni uporabniki ročno sledijo druge osebe na oddaljenih strežnikih.\"\n      disable: Onemogoči\n      disabled: Onemogočeno\n      enable: Omogoči\n      enable_hint: Ko je omogočen, se bo vaš strežnik naročil na vse javne trobe iz tega releja in začel pošiljati javne trobe tega strežnika.\n      enabled: Omogočeno\n      inbox_url: URL releja\n      pending: Čakanje na odobritev releja\n      save_and_enable: Shrani in omogoči\n      setup: Nastavi povezavo releja\n      status: Stanje\n      title: Releji\n    report_notes:\n      created_msg: Opomba o prijavi je uspešno ustvarjena!\n      destroyed_msg: Opomba o prijavi je uspešno izbrisana!\n    reports:\n      account:\n        note: opomba\n        report: prijava\n      action_taken_by: Dejanje, ki ga je sprejel\n      are_you_sure: Ali ste prepričani?\n      assign_to_self: Dodeli meni\n      assigned: Dodeljen moderator\n      comment:\n        none: Nič\n      created_at: Prijavljeno\n      mark_as_resolved: Označi kot rešeno\n      mark_as_unresolved: Označi kot nerešeno\n      notes:\n        create: Dodaj opombo\n        create_and_resolve: Razreši z opombo\n        create_and_unresolve: Ponovo odpri z opombo\n        delete: Izbriši\n        placeholder: Opišite dejanja, ki ste jih izvedli, ali katere koli druge posodobitve...\n      reopen: Ponovno odpri prijavo\n      report: 'Prijavi #%{id}'\n      reported_account: Prijavljeni račun\n      reported_by: Prijavljen od\n      resolved: Razrešeno\n      resolved_msg: Prijava je uspešno razrešena!\n      status: Stanje\n      title: Prijave\n      unassign: Odstopi\n      unresolved: Nerešeno\n      updated_at: Posodobljen\n    settings:\n      activity_api_enabled:\n        desc_html: Številke lokalno objavljenih stanj, aktivnih uporabnikov in novih registracij na tedenskih seznamih\n        title: Objavi združeno statistiko o dejavnosti uporabnikov\n      bootstrap_timeline_accounts:\n        desc_html: Več uporabniških imen ločite z vejico. Deluje samo na lokalnih in odklenjenih računih. Privzeto, ko je prazno, pri vseh lokalnih skrbnikih.\n        title: Privzeta sledenja za nove uporabnike\n      contact_information:\n        email: Poslovna e-pošta\n        username: Uporabniško ime stika\n      custom_css:\n        desc_html: Spremeni videz z naloženim CSS na vsaki strani\n        title: CSS po meri\n  errors:\n    '403': You don't have permission to view this page.\n    '404': The page you are looking for isn't here.\n    '410': The page you were looking for doesn't exist here anymore.\n    '422': \n    '429': Throttled\n    '500': \n  invites:\n    expires_in:\n      '1800': 30 minutes\n      '21600': 6 hours\n      '3600': 1 hour\n      '43200': 12 hours\n      '604800': 1 week\n      '86400': 1 day\n  statuses:\n    pin_errors:\n      ownership: Trob nekoga drugega ne more biti pripet\n      private: Nejavnega troba ni mogoče pripeti\n  stream_entries:\n    pinned: Pripet trob\n"
  },
  {
    "path": "config/locales/sq.yml",
    "content": "---\nsq:\n  about:\n    about_hashtag_html: Këto janë mesazhe publike të etiketuar me <strong>#%{hashtag}</strong>. Mundeni të ndërveproni me ta, nëse keni një llogari kudo qoftë në fediverse.\n    about_mastodon_html: Mastodon-i është një rrjet shoqëror i bazuar në protokolle web të hapur dhe në software të lirë, me burim të hapur. Është i decentralizuar, si email-ii.\n    about_this: Mbi\n    administered_by: 'Administruar nga:'\n    apps: Aplikacione për celular\n    contact: Kontakt\n    contact_missing: I parregulluar\n    documentation: Dokumentim\n    extended_description_html: |\n      <h3>Një vend i mirë për rregulla</h3>\n      <p>Përshkrimi i zgjeruar s’është sajuar ende.</p>\n    generic_description: \"%{domain} është një shërbyes te rrjeti\"\n    hosted_on: Mastodon i strehuar në %{domain}\n    learn_more: Mësoni më tepër\n    privacy_policy: Rregulla privatësie\n    source_code: Kod burim\n    status_count_after:\n      one: gjendje\n      other: gjendje\n    status_count_before: Cili krijoi\n    terms: Kushte shërbimi\n    user_count_after:\n      one: përdorues\n      other: përdorues\n    what_is_mastodon: Ç’është Mastodon-i?\n  accounts:\n    choices_html: 'Zgjedhje të %{name}:'\n    follow: Ndiqeni\n    followers:\n      one: Ndjekës\n      other: Ndjekës\n    following: Ndjekje\n    joined: U bë pjesë më %{date}\n    last_active: aktiv së fundi\n    link_verified_on: Pronësia e kësaj lidhjeje qe kontrolluar më %{date}\n    moved_html: \"%{name} ka kaluar te %{new_profile_link}:\"\n    network_hidden: Këto të dhëna nuk mund të kihen\n    nothing_here: S’ka gjë këtu!\n    people_followed_by: Persona të ndjekur nga %{name}\n    people_who_follow: Persona që ndjekin %{name}\n    pin_errors:\n      following: Duhet ta ndiqni tashmë personin që doni të pasqyroni\n    posts:\n      one: Mesazh\n      other: Mesazhe\n    posts_tab_heading: Mesazhe\n    posts_with_replies: Mesazhe dhe përgjigje\n    reserved_username: Emri i përdoruesit është i ruajtur për dikë\n    roles:\n      admin: Përgjegjës\n    unfollow: Resht së ndjekuri\n  admin:\n    account_actions:\n      action: Kryeje veprimin\n      title: Kryeni veprim moderimi te %{acct}\n    account_moderation_notes:\n      create: Lini një shënim\n      created_msg: Shënimi i moderimit u krijua me sukses!\n      delete: Fshije\n      destroyed_msg: Shënimi i moderimit u asgjësua me sukses!\n    accounts:\n      are_you_sure: A jeni i sigurt?\n      by_domain: Përkatësi\n      change_email:\n        changed_msg: Email-i i llogarisë u ndryshua me sukses!\n        current_email: Email-i i tanishëm\n        label: Ndrysho email-in\n        new_email: Email i ri\n        submit: Ndrysho email-in\n        title: Ndrysho email-in për %{username}\n      confirm: Ripohojeni\n      confirmed: U ripohua\n      confirming: Po ripohohet\n      deleted: U fshi\n      demote: Zhgradoje\n      disable: Çaktivizoje\n      disable_two_factor_authentication: Çaktivizoni 2FA\n      disabled: E çaktivizuar\n      display_name: Emër në ekran\n      domain: Përkatësi\n      edit: Përpunojeni\n      email_status: Gjendje email-i\n      enable: Aktivizoje\n      enabled: E aktivizuar\n      feed_url: URL prurjeje\n      followers: Ndjekës\n      followers_url: URL Ndjekësish\n      follows: Ndjekje\n      header: Krye\n      inbox_url: URL Mesazhesh të Marrë\n      invited_by: Ftuar nga\n      joined: U bë pjesë\n      location:\n        all: Krejt\n        local: Vendore\n        remote: E largët\n        title: Vendndodhje\n      login_status: Gjendje hyrjeje\n      media_attachments: Bashkëngjitje media\n      memorialize: Shndërroje në përkujtimore\n      moderation:\n        active: Aktiv\n        all: Krejt\n        silenced: U heshtua\n        suspended: Të pezulluara\n        title: Moderim\n      moderation_notes: Shënime moderimesh\n      most_recent_activity: Veprimtaria më e freskët\n      most_recent_ip: IP-ja më e freskët\n      no_limits_imposed: Pa imponim kufijsh\n      not_subscribed: Jo i pajtuar\n      outbox_url: URL Mesazhesh të Dërguar\n      perform_full_suspension: Pezulloje\n      profile_url: URL profili\n      promote: Promovojeni\n      protocol: Protokoll\n      public: Publike\n      push_subscription_expires: Pajtimi PuSH skadon më\n      redownload: Rifresko profilin\n      remove_avatar: Hiqe avatarin\n      remove_header: Hiqe kryen\n      resend_confirmation:\n        already_confirmed: Ky përdorues është i ripohuar tashmë\n        send: Ridërgo email ripohimi\n        success: Email-i i ripohimit u dërgua me sukses!\n      reset: Riktheje te parazgjedhjet\n      reset_password: Ricaktoni fjalëkalimin\n      resubscribe: Ripajtohuni\n      role: Leje\n      roles:\n        admin: Përgjegjës\n        staff: Staf\n        user: Përdorues\n      search: Kërkoni\n      shared_inbox_url: URL kutie të përbashkët mesazesh\n      show:\n        created_reports: Ka bërë raportime\n        targeted_reports: Raportuar nga të tjerë\n      silence: Heshtoje\n      silenced: E heshtuar\n      statuses: Gjendje\n      subscribe: Pajtomë\n      suspended: Të pezulluara\n      title: Llogari\n      unconfirmed_email: Email i paripohuar\n      undo_silenced: Zhbëje heshtjen\n      undo_suspension: Zhbëje pezullimin\n      unsubscribe: Shpajtohuni\n      username: Emër përdoruesi\n      warn: Sinjalizoje\n    action_logs:\n      actions:\n        assigned_to_self_report: \"%{name} ia kaloi raportimin %{target} në ngarkim vetvetes\"\n        change_email_user: \"%{name} ndryshoi adresën email të përdoruesit %{target}\"\n        confirm_user: \"%{name} ripohoi adresën email të përdoruesit %{target}\"\n        create_account_warning: \"%{name} dërgoi një sinjalizim për %{target}\"\n        create_custom_emoji: \"%{name} ngarkoi emotikon të ri %{target}\"\n        create_domain_block: \"%{name} bllokoi përkatësinë %{target}\"\n        create_email_domain_block: \"%{name} e shtoi në listë bllokimesh përkatësinë %{target}\"\n        demote_user: \"%{name} zhgradoi përdoruesin %{target}\"\n        destroy_custom_emoji: \"%{name} asgjësoi emotikonin %{target}\"\n        destroy_domain_block: \"%{name} zhbllokoi përkatësinë %{target}\"\n        destroy_email_domain_block: \"%{name} e shtoi në listë të lejuarash përkatësinë %{target}\"\n        destroy_status: \"%{name} hoqi gjendje nga %{target}\"\n        disable_2fa_user: \"%{name} çaktivizoi domosdoshmëritë për dyfaktorësh për përdoruesin %{target}\"\n        disable_custom_emoji: \"%{name} çaktivizoi emotikonin %{target}\"\n        disable_user: \"%{name} çaktivizoi hyrje për përdoruesin %{target}\"\n        enable_custom_emoji: \"%{name} aktivizoi emotikonin %{target}\"\n        enable_user: \"%{name} aktivizoi hyrje për përdoruesin %{target}\"\n        memorialize_account: \"%{name} e shndërroi llogarinë e %{target} në një faqe përkujtimore\"\n        promote_user: \"%{name} gradoi përdoruesin %{target}\"\n        remove_avatar_user: \"%{name} hoqi avatarin e %{target}\"\n        reopen_report: \"%{name} rihapi raportimin %{target}\"\n        reset_password_user: \"%{name} ricaktoi fjalëkalimi për përdoruesin %{target}\"\n        resolve_report: \"%{name} zgjidhi raportimin %{target}\"\n        silence_account: \"%{name} heshtoi llogarinë e %{target}\"\n        suspend_account: \"%{name} pezulloi llogarinë e %{target}\"\n        unassigned_report: \"%{name} rihapi raportimin %{target}\"\n        unsilence_account: \"%{name} hoqi heshtimin për llogarinë %{target}\"\n        unsuspend_account: \"%{name} hoqi pezullimin për llogarinë e %{target}\"\n        update_custom_emoji: \"%{name} përditësoi emotikonin %{target}\"\n        update_status: \"%{name} përditësoi gjendjen me %{target}\"\n      deleted_status: \"(fshiu gjendjen)\"\n      title: Auditim regjistri\n    custom_emojis:\n      by_domain: Përkatësi\n      copied_msg: Kopja vendore e emotikonëve u krijua me sukses\n      copy: Kopjoje\n      copy_failed_msg: S’u bë dot një kopje vendore e emotikoneve\n      created_msg: Emotikoni u krijua me sukses!\n      delete: Fshije\n      destroyed_msg: Emotikoni u asgjësua me sukses!\n      disable: Çaktivizoje\n      disabled_msg: Ai emotikon u çaktivizua me sukses\n      emoji: Emotikon\n      enable: Aktivizoje\n      enabled_msg: Ai emotikon u aktivizua me sukses\n      image_hint: PNG deri 50KB\n      listed: Në listë\n      new:\n        title: Shtoni emotikon të ri vetjak\n      overwrite: Mbishkruaje\n      shortcode: Kod i shkurtër\n      shortcode_hint: Të paktën 2 shenja, vetëm shenja alfanumerike dhe nënvija\n      title: Emotikone vetjake\n      unlisted: Hequr prej liste\n      update_failed_msg: S’u përditësua dot ai emotikon\n      updated_msg: Emotikoni u përditësua me sukses!\n      upload: Ngarkoje\n    dashboard:\n      backlog: punë të prapambetura\n      config: Formësim\n      feature_deletions: Fshirje llogarish\n      feature_invites: Lidhje ftesash\n      feature_profile_directory: Drejtori profilesh\n      feature_registrations: Regjistrime\n      feature_relay: Rele federimi\n      features: Veçori\n      hidden_service: Federim me shërbime të fshehura\n      open_reports: raportime të hapur\n      recent_users: Përdorues së fundi\n      search: Kërko tekstin e plotë\n      single_user_mode: Mënyrë me përdorues të vetëm\n      space: Përdorim hapësire\n      title: Pult\n      total_users: përdorues gjithsej\n      trends: Tendenca\n      week_interactions: ndërveprime këtë javë\n      week_users_active: aktivë këtë javë\n      week_users_new: përdorues këtë javë\n    domain_blocks:\n      add_new: Shtoni bllokim të ri përkatësie\n      created_msg: Bllokimi i përkatësisë tani po përpunohet\n      destroyed_msg: Bllokimi i përkatësisë u hoq\n      domain: Përkatësi\n      new:\n        create: Krijoni bllokim\n        hint: Bllokimi i përkatësisë nuk do të pengojë krijim zërash llogarie te baza e të dhënave, por do të aplikojë në mënyrë retroaktive dhe të vetvetishme metoda specifike moderimi mbi këto llogari.\n        severity:\n          desc_html: \"<strong>Heshtja</strong> do t’i bëjë postimet e llogarisë të padukshme për këdo që nuk i ndjek ato. <strong>Pezullimi</strong> do të heqë krejt lëndën e llogarisë, media, dhe të dhëna profili. Përdorni <strong>Asnjë</strong>, nëse thjesht doni të mos pranohen kartela media.\"\n          noop: Asnjë\n          silence: Heshtoji\n          suspend: Pezulloje\n        title: Bllokim i ri përkatësie\n      reject_media: Mos prano kartela media\n      reject_media_hint: Heq kartela media të depozituara lokalisht dhe nuk pranon të shkarkohen të tilla në të ardhmen. Pa peshë për pezullimet\n      reject_reports: Hidh tej raportimet\n      reject_reports_hint: Shpërfillini krejt raportimet e ardhura nga kjo përkatësi. Pa peshë për pezullimet\n      rejecting_media: mospranim kartelash media\n      rejecting_reports: mospranim raportimesh\n      severity:\n        silence: e heshtuar\n        suspend: e pezulluar\n      show:\n        affected_accounts:\n          one: Pat ndikim te një llogari në bazën e të dhënave\n          other: Pat ndikim te %{count} llogari në bazën e të dhënave\n        retroactive:\n          silence: Hiqu heshtimin krejt llogarive ekzistuese nga kjo përkatësi\n          suspend: Hiqu pezullimin krejt llogarive ekzistuese nga kjo përkatësi\n        title: Zhbëje bllokimin e përkatësisë për %{domain}\n        undo: Zhbëje\n      undo: Zhbëje bllokimin e përkatësisë\n    email_domain_blocks:\n      add_new: Shtoni të ri\n      created_msg: Përkatësia email u shtua me sukses te lista e bllokimeve\n      delete: Fshije\n      destroyed_msg: Përkatësia email u fshi me sukses nga lista e bllokimeve\n      domain: Përkatësi\n      new:\n        create: Shtoni përkatësi\n        title: Zë i ri email në listë bllokimesh\n      title: Listë bllokimesh email-esh\n    followers:\n      back_to_account: Mbrapsht Te Llogaria\n      title: Ndjekës të %{acct}\n    instances:\n      delivery_available: Ka shpërndarje të mundshme\n      known_accounts:\n        one: \"%{count} llogari e njohur\"\n        other: \"%{count} llogari të njohura\"\n      moderation:\n        all: Krejt\n        limited: E kufizuar\n        title: Moderim\n      title: Federim\n      total_blocked_by_us: Bllokuar nga ne\n      total_followed_by_them: Ndjekur prej tyre\n      total_followed_by_us: Ndjekur nga ne\n      total_reported: Raportime rreth tyre\n      total_storage: Bashkëngjitje media\n    invites:\n      deactivate_all: Çaktivizoji krejt\n      filter:\n        all: Krejt\n        available: I përdorshëm\n        expired: I skaduar\n        title: Filtër\n      title: Ftesa\n    relays:\n      add_new: Shtoni rele të re\n      delete: Fshije\n      description_html: Një <strong>rele federimesh</strong> është një shërbyes ndërmjetës që shkëmben vëllime të mëdha mesazhesh publike mes shërbyesve që janë pajtuar në të dhe publikojnë në të. <strong>Mund t’u vijë në ndihmë shërbyesve të vegjël dhe të mesëm të gjejnë lëndë nga fediversi</strong>, gjë që përndryshe do të kërkonte që përdoruesit vendorë të ndiqnin dorazi persona të tjerë nëpër shërbyes të largët.\n      disable: Çaktivizoje\n      disabled: E çaktivizuar\n      enable: Aktivizoje\n      enable_hint: Pasi të aktivizohet, shërbyesi juaj do të pajtohet te krejt mesazhet publike prej kësaj releje, dhe do të fillojë të dërgojë në të mesazhet publike të këtij shërbyesi.\n      enabled: E aktivizuar\n      inbox_url: URL releje\n      pending: Në pritje të miratimit të relesë\n      save_and_enable: Ruaje dhe aktivizoje\n      setup: Ujdisni një lidhje releje\n      status: Gjendje\n      title: Rele\n    report_notes:\n      created_msg: Shënimi i raportimit u krijua me sukses!\n      destroyed_msg: Shënimi i raportimit u fshi me sukses!\n    reports:\n      account:\n        note: shënim\n        report: raportojeni\n      action_taken_by: Veprimi i ndërmarrë nga\n      are_you_sure: A jeni i sigurt?\n      assign_to_self: Caktojani vetes\n      assigned: Iu caktua moderator\n      comment:\n        none: Asnjë\n      created_at: Raportuar më\n      mark_as_resolved: Vëri shenjë si i zgjidhur\n      mark_as_unresolved: Vëri shenjë si të pazgjidhur\n      notes:\n        create: Shtoni shënim\n        create_and_resolve: Zgjidhe me shënim\n        create_and_unresolve: Rihape me shënim\n        delete: Fshije\n        placeholder: Përshkruani ç’veprime janë ndërmarrë, ose çfarëdo përditësimi tjetër që lidhet me të…\n      reopen: Rihape raportimin\n      report: 'Raportim #%{id}'\n      reported_account: Llogari e raportuar\n      reported_by: Raportuar nga\n      resolved: I zgjidhur\n      resolved_msg: Raportimi u zgjidh me sukses!\n      status: Gjendje\n      title: Raportime\n      unassign: Hiqja\n      unresolved: Të pazgjidhur\n      updated_at: U përditësua më\n    settings:\n      activity_api_enabled:\n        desc_html: Numër gjendjesh të postuara lokalisht, përdorues aktivë, dhe regjistrime të reja në kosha javorë\n        title: Botoni statistika përmbledhëse mbi veprimtarinë e përdoruesve\n      bootstrap_timeline_accounts:\n        desc_html: Emrat e përdoruesve ndajini prej njëri-tjetrit me presje. Do të funksionojë vetëm për llogari vendore dhe të pakyçura. Si parazgjedhje, kur lihet e zbrazët, është krejt përgjegjësit vendorë.\n        title: Ndjekje parazgjedhje për përdorues të rinj\n      contact_information:\n        email: Email biznesi\n        username: Emër përdoruesi kontakti\n      custom_css:\n        desc_html: Modifikojeni pamjen me CSS të nagrkuar në çdo faqe\n        title: CSS Vetjake\n      hero:\n        desc_html: E shfaqur në faqen ballore. Këshillohet të paktën 600x100px. Kur nuk caktohet gjë, përdoret miniaturë e shërbyesit\n        title: Figurë heroi\n      mascot:\n        desc_html: E shfaqur në faqe të shumta. Këshillohet të paktën 293x205. Kur nuk caktohet gjë, përdoret simboli parazgjedhje\n        title: Figurë simboli\n      peers_api_enabled:\n        desc_html: Emra përkatësish që ka hasur në fedivers ky shërbyes\n        title: Boto listë shërbyesish të gjetur\n      preview_sensitive_media:\n        desc_html: Në sajte të tjera, paraparjet e lidhjeve do të shfaqin një miniaturë, edhe pse medias i është vënë shenjë si rezervat\n        title: Shfaq në paraparje OpenGraph media me shenjën rezervat\n      profile_directory:\n        desc_html: Lejoju përdoruesve të jenë të zbulueshëm\n        title: Aktivizo drejtori profilesh\n      registrations:\n        closed_message:\n          desc_html: E shfaqur në faqen ballore, kur regjistrimet janë të mbyllura. Mund të përdorni etiketa HTML\n          title: Mesazh mbylljeje regjistrimesh\n        deletion:\n          desc_html: Lejo këdo të fshijë llogarinë e vet\n          title: Hapni fshirje llogarie\n        min_invite_role:\n          disabled: Asnjë\n          title: Lejo vetëm me ftesa\n      show_known_fediverse_at_about_page:\n        desc_html: Kur përdoret, do të shfaqë mesazhe prej krejt fediversit të njohur, si paraparje. Përndryshe do të shfaqë vetëm mesazhe vendore.\n        title: Shfaq te paraparja e rrjedhës kohore fedivers të njohur\n      show_staff_badge:\n        desc_html: Shfaq një stemë stafi në faqen e një përdoruesi\n        title: Shfaq stemë stafi\n      site_description:\n        desc_html: Paragraf hyrës te faqja ballore. Përshkruani ç’e bën special këtë shërbyes Mastodon dhe çfarëdo gjëje tjetër të rëndësishme. Mund të përdorni etiketa HTML, veçanërisht <code>&lt;a&gt;</code> dhe <code>&lt;em&gt;</code>.\n        title: Përshkrim shërbyesi\n      site_description_extended:\n        desc_html: Një vend i mirë për kodin e sjelljes në shërbyesin tuaj, rregulla, udhëzime dhe gjëra të tjera që e bëjnë të veçantë këtë shërbyes. Mund të përdorni etiketa HTML\n        title: Informacion i zgjeruar vetjak\n      site_short_description:\n        desc_html: E shfaqur në anështyllë dhe etiketa meta. Përshkruani në një paragraf të vetëm ç’është Mastodon-i dhe ç’e bën special këtë shërbyes. Në u lëntë i zbrazët, për shërbyesin do të përdoret përshkrimi parazgjedhje.\n        title: Përshkrim i shkurtër shërbyesi\n      site_terms:\n        desc_html: Mund të shkruani rregullat tuaja të privatësisë, kushtet e shërbimit ose gjëra të tjera ligjore. Mund të përdorni etiketa HTML\n        title: Kushte vetjake shërbimi\n      site_title: Emër shërbyesi\n      thumbnail:\n        desc_html: I përdorur për paraparje përmes OpenGraph-it dhe API-t. Këshillohet 1200x630px\n        title: Miniaturë shërbyesi\n      timeline_preview:\n        desc_html: Shfaqni rrjedhë kohore publike te faqja ardhjesh\n        title: Paraparje rrjedhe kohore\n      title: Rregullime sajti\n    statuses:\n      back_to_account: Mbrapsht te faqja e llogarisë\n      batch:\n        delete: Fshije\n        nsfw_off: Vëri shenjë si jo rezervat\n        nsfw_on: Vëri shenjë si rezervat\n      failed_to_execute: S’u arrit të përmbushej\n      no_media: S’ka media\n      no_status_selected: S’u ndryshua ndonjë gjendje, ngaqë s’u përzgjodh ndonjë e tillë\n      title: Gjendje llogarish\n      with_media: Me media\n    subscriptions:\n      callback_url: URL Callback-u\n      confirmed: U ripohua\n      expires_in: Skadon më\n      last_delivery: Dorëzimi e fundit\n      topic: Temë\n    tags:\n      accounts: Llogari\n      hidden: Fshehur\n      hide: Fshihe prej drejtorie\n      title: Hashtage\n      unhide: Shfaqe në drejtori\n      visible: E dukshme\n    title: Administrim\n    warning_presets:\n      add_new: Shtoni të ri\n      delete: Fshije\n      edit: Përpunoni\n      edit_preset: Përpunoni sinjalizim të paracaktuar\n      title: Administroni sinjalizime të paracaktuara\n  admin_mailer:\n    new_report:\n      body: \"%{reporter} ka raportuar %{target}\"\n      body_remote: Dikush nga %{domain} ka raportuar %{target}\n      subject: Raport i ri për %{instance} (#%{id})\n  application_mailer:\n    notification_preferences: Ndryshoni parapëlqime email-i\n    settings: 'Ndryshoni parapëlqime email-i: %{link}'\n    view: 'Parje:'\n    view_profile: Shihni Profilin\n    view_status: Shihini gjendjen\n  applications:\n    created: Aplikacioni u krijua me sukses\n    destroyed: Aplikacioni u fshi me sukses\n    invalid_url: URL-ja e dhënë është e pavlefshme\n    regenerate_token: Riprodho token hyrjesh\n    token_regenerated: Token-i i hyrjeve u riprodhuan me sukses\n    warning: Hapni sytë me ato të dhëna. Mos ia jepni kurrë njeriu!\n    your_token: Token-i juaj për hyrje\n  auth:\n    change_password: Fjalëkalim\n    confirm_email: Ripohoni email-in\n    delete_account: Fshije llogarinë\n    delete_account_html: Nëse dëshironi të fshihni llogarinë tuaj, mund <a href=\"%{path}\">ta bëni që këtu</a>. Do t’ju kërkohet ta ripohoni.\n    didnt_get_confirmation: S’morët udhëzime ripohimi?\n    forgot_password: Harruat fjalëkalimin tuaj?\n    invalid_reset_password_token: Token-i i ricaktimit të fjalëkalimit është i pavlefshëm ose ka skaduar. Ju lutemi, kërkoni një të ri.\n    login: Hyni\n    logout: Dalje\n    migrate_account: Kaloni në një tjetër llogari\n    migrate_account_html: Nëse doni ta ridrejtoni këtë llogari te një tjetër, këtë mund <a href=\"%{path}\">ta formësoni këtu</a>.\n    or_log_in_with: Ose bëni hyrjen me\n    register: Regjistrohuni\n    resend_confirmation: Ridërgo udhëzime ripohimi\n    reset_password: Ricaktoni fjalëkalimin\n    security: Siguri\n    set_new_password: Caktoni fjalëkalim të ri\n  authorize_follow:\n    already_following: E ndiqni tashmë këtë llogari\n    error: Mjerisht, pati një gabim gjatë kërkimit të llogarisë së largët\n    follow: Ndiqeni\n    follow_request: 'Keni dërguar një kërkesë ndjekjeje te:'\n    following: 'Sukses! Tani e ndiqni:'\n    post_follow:\n      close: Ose, thjesht mund të mbyllni këtë dritare.\n      return: Shfaq profilin e përdoruesit\n      web: Kalo në web\n    title: Ndiq %{acct}\n  datetime:\n    distance_in_words:\n      about_x_hours: \"%{count}o\"\n      about_x_months: \"%{count}mj\"\n      about_x_years: \"%{count}v\"\n      almost_x_years: \"%{count}v\"\n      half_a_minute: Mu tani\n      less_than_x_seconds: Mu tani\n      over_x_years: \"%{count}v\"\n      x_months: \"%{count}mj\"\n  deletes:\n    bad_password_msg: Provë e bukur, trimosha! Fjalëkalim i pasaktë\n    confirm_password: Jepni fjalëkalimin tuaj të tanishëm që të verifikohet identiteti juaj\n    description_html: Kjo të heqë <strong>në mënyrë të përhershme, të pakthyeshme</strong> lëndë nga llogaria juaj dhe do ta çaktivizojë atë. Emri juaj i përdoruesit do të mbetet i rezervuar për të shmangur sozi të ardhme.\n    proceed: Fshini llogarinë\n    success_msg: Llogaria juaj u fshi me sukses\n    warning_html: Garantohet vetëm fshirja e lëndës prej këtij shërbyesi të veçantë. Lënda që është ndarë gjerësisht me të tjerët ka gjasa të lërë gjurmë. Shërbyesit <em>offline</em> dhe shërbyesit që janë shpajtuar prej përditësimeve tuaja, s’do t’i përditësojnë bazat e tyre të të dhënave.\n    warning_title: Mund të ketë lëndë të përhapur\n  directories:\n    directory: Drejtori profilesh\n    enabled: Gjendeni te lista e drejtorisë.\n    enabled_but_waiting: Keni zgjedhur të jeni pjesë e drejtorisë, por ende s’keni numrin minimum të ndjekësve (%{min_followers}) për përfshirje në të.\n    explanation: Zbuloni përdorues bazuar në interesat e tyre\n    explore_mastodon: Eksploroni %{title}\n    how_to_enable: S’keni zgjedhur të jeni i pranishëm te drejtoria. Mund ta bëni më poshtë. Përdorni te teksti i jetëshkrimit tuaj hashtagë, për t’u përfshirë nën hashtagë specifikë!\n  errors:\n    '403': S’keni leje të shihni këtë faqe.\n    '404': Faqja që po kërkonit, s’gjendet këtu.\n    '410': Faqja që po kërkonit, s’gjendet më këtu.\n    '422':\n      content: Verifikimi i sigurisë dështoi. Mos i bllokoni gjë cookie-t?\n      title: Verifikimi i sigurisë dështoi\n    '429': Shumë kërkesa të bëra brenda një intervali të dhënë\n    '500':\n      content: Na ndjeni, diçka shkoi ters në anën tonë.\n      title: Kjo faqe s’është e saktë\n    noscript_html: Që të përdorni aplikacionin web Mastodon, ju lutemi, aktivizoni JavaScript-in. Ndryshe, provoni për Mastodon-in një nga <a href=\"%{apps_path}\">aplikacionet e brendshëm</a> të platformës tuaj.\n  exports:\n    archive_takeout:\n      date: Datë\n      download: Shkarkoni arkivin tuaj\n      hint_html: Mund të kërkoni një arkiv të <strong>mesazheve tuaja dhe medias së ngarkuar</strong> nga ju. Të dhënat e eksportuara do të jenë në formatin ActivityPub, të lexueshme nga cilido software i përputhshëm me të. Mund të kërkoni arkiv çdo 7 ditë.\n      in_progress: Po përpilohet arkivi juaj…\n      request: Kërkoni arkivin tuaj\n      size: Madhësi\n    blocks: Bllokoni\n    domain_blocks: Bllokime përkatësish\n    follows: Ndiqni\n    lists: Lista\n    mutes: Heshtoni\n    storage: Depozitim për media\n  featured_tags:\n    add_new: Shtoni të re\n    errors:\n      limit: Keni përdorur tashmë si të zgjedhur sasinë maksimum të hashtagëve\n  filters:\n    contexts:\n      home: Rrjedhë kohore vetjake\n      notifications: Njoftime\n      public: Rrjedha publike kohore\n      thread: Biseda\n    edit:\n      title: Përpunoni filtër\n    errors:\n      invalid_context: Ose s’u dha fare, ose u dha kontekst i pavlefshëm\n      invalid_irreversible: Filtrim i pakthyeshëm funksionon vetëm me kontekste <em>home</em> ose njoftimesh\n    index:\n      delete: Fshije\n      title: Filtra\n    new:\n      title: Shtoni filtër të ri\n  footer:\n    developers: Zhvillues\n    more: Më tepër…\n    resources: Burime\n  generic:\n    changes_saved_msg: Ndryshimet u ruajtën me sukses!\n    copy: Kopjoje\n    save_changes: Ruaji ndryshimet\n    validation_errors:\n      one: Diçka s’është ende si duhet! Ju lutemi, shqyrtoni gabimin më poshtë\n      other: Diçka s’është ende si duhet! Ju lutemi, shqyrtoni %{count} gabimet më poshtë\n  imports:\n    modes:\n      merge: Përzieji\n      merge_long: Mbaji zërat ekzistues dhe shto të rinjtë\n      overwrite: Mbishkruaje\n      overwrite_long: Zëvendësoji zërat ekzistues me të rinjtë\n    preface: Mund të importoni të dhëna që keni eksportuar nga një shërbyes tjetër, bie fjala, një listë të personave që ndiqni ose bllokoni.\n    success: Të dhënat tuaja u ngarkuan me sukses dhe tani do të përpunohet në kohë\n    types:\n      blocking: Listë bllokimesh\n      domain_blocking: Listë bllokimesh përkatësish\n      following: Listë ndjekjesh\n      muting: Listë heshtimesh\n    upload: Ngarkoje\n  invites:\n    delete: Çaktivizoje\n    expired: Ka skaduar\n    expires_in:\n      '1800': 30 minuta\n      '21600': 6 orë\n      '3600': 1 orë\n      '43200': 12 orë\n      '604800': 1 javë\n      '86400': 1 ditë\n    expires_in_prompt: Kurrë\n    generate: Prodhoje\n    invited_by: 'Qetë ftuar nga:'\n    max_uses:\n      one: 1 përdorim\n      other: \"%{count} përdorime\"\n    max_uses_prompt: Pa kufi\n    prompt: Prodhoni dhe ndani me të tjerët lidhje për të akorduar hyrje në këtë shërbyes\n    table:\n      expires_at: Skadon më\n      uses: Përdorime\n    title: Ftoni njerëz\n  lists:\n    errors:\n      limit: Keni mbërritur në numrin maksimum të sasisë së listave\n  media_attachments:\n    validations:\n      images_and_video: S’mund të bashkëngjitet video te një gjendje që përmban figura tashmë\n      too_many: S’mund të bashkëngjiten më shumë se 4 kartela\n  migrations:\n    acct: emërpërdoruesi@përkatësi e llogarisë së re\n    currently_redirecting: 'Profili juaj është caktuar të ridrejtojë te:'\n    proceed: Ruaje\n    updated_msg: Rregullimi juaj për migrim llogarish u përditësua me sukses!\n  moderation:\n    title: Moderim\n  notification_mailer:\n    digest:\n      action: Shihini krejt njoftimet\n      body: Ja një përmbledhje e shkurtër e mesazheve që keni humbur që nga vizita juaj e fundit më %{since}\n      mention: \"%{name} ju ka përmendur te:\"\n      new_followers_summary:\n        one: Veç kësaj, u bëtë me një ndjekës të ri, teksa s’ishit këtu! Ëhë!\n        other: Veç kësaj, u bëtë me %{count} ndjekës të rinj, teksa s’ishit këtu! Shkëlqyeshëm!\n      subject:\n        one: \"1 njoftim i ri që nga vizita juaj e fundit \\U0001F418\"\n        other: \"%{count} 1 njoftime të reja që nga vizita juaj e fundit \\U0001F418\"\n      title: Gjatë mungesës tuaj…\n    favourite:\n      body: 'Gjendja juaj u parapëlqye nga %{name}:'\n      subject: \"%{name} parapëlqeu gjendjen tuaj\"\n      title: E parapëlqyer e re\n    follow:\n      body: Tani ju ndjek %{name}!\n      subject: Tani ju ndjek %{name}\n      title: Ndjekës i ri\n    follow_request:\n      action: Administroni kërkesa ndjekjeje\n      body: \"%{name} ka kërkuar t’ju ndjekë\"\n      subject: 'Ndjekës pezull: %{name}'\n      title: Kërkesë e re ndjekjeje\n    mention:\n      action: Përgjigjuni\n      body: 'U përmendët nga %{name} në:'\n      subject: U përmendët nga %{name}\n      title: Përmendje e re\n    reblog:\n      body: 'Gjendja juaj u përforcua nga %{name}:'\n      subject: \"%{name} përforcoi gjendjen tuaj\"\n      title: Përforcim i ri\n  number:\n    human:\n      decimal_units:\n        units:\n          quadrillion: K\n  pagination:\n    newer: Më të ri\n    next: Pasuesi\n    older: Më të vjetër\n    prev: I mëparshmi\n  preferences:\n    other: Tjetër\n  remote_follow:\n    acct: Jepni çiftin tuaj emërpërdoruesi@përkatësi prej të cilit doni që të veprohet\n    missing_resource: S’u gjet dot URL-ja e domosdoshme e ridrejtimit për llogarinë tuaj\n    no_account_html: S’keni llogari? Mund të <a href='%{sign_up_path}' target='_blank'>regjistroheni këtu</a>\n    proceed: Ripohoni ndjekjen\n    prompt: 'Do të ndiqni:'\n    reason_html: \"<strong>Pse është i domosdoshëm ky hap?</strong> <code>%{instance}</code> mund të mos jetë shërbyesi ku jeni regjistruar, ndaj na duhet t’ju ridrejtojmë së pari te shërbyesi juaj Home.\"\n  remote_interaction:\n    favourite:\n      proceed: Ripohoni parapëlqimin\n      prompt: 'Doni të parapëlqeni këtë mesazh:'\n    reblog:\n      proceed: Ripohoni përforcimin\n      prompt: 'Doni të përforconi këtë mesazh:'\n    reply:\n      proceed: Ripohoni përgjigjen\n      prompt: 'Doni t’i përgjigjeni këtij mesazhi:'\n  remote_unfollow:\n    error: Gabim\n    title: Titull\n    unfollowed: U hoq ndjekja\n  scheduled_statuses:\n    over_daily_limit: Keni tejkaluar kufirin e %{limit} mesazheve të planifikuara për atë ditë\n    over_total_limit: Keni tejkaluar kufirin prej %{limit} mesazhesh të planifikuara\n    too_soon: Data e planifikimit duhet të bjerë në të ardhmen\n  sessions:\n    activity: Veprimtaria e fundit\n    browser: Shfletues\n    browsers:\n      generic: Shfletues i panjohur\n      nokia: Shfletues Nokia S40 Ovi\n    current_session: Sesioni i tanishëm\n    description: \"%{browser} në %{platform}\"\n    explanation: Këta janë shfletuesit e futur në këtë çast te llogaria juaj Mastodon.\n    platforms:\n      other: platformë e panjohur\n    revoke: Shfuqizoje\n    revoke_success: Sesioni u shfuqizua me sukses\n    title: Sesione\n  settings:\n    authorized_apps: Aplikacione të autorizuara\n    back: Mbrapsht te Mastodon\n    delete: Fshirje llogarie\n    development: Zhvillim\n    edit_profile: Përpunoni profilin\n    export: Eksportim të dhënash\n    featured_tags: Hashtagë të zgjedhur\n    import: Importo\n    migrate: Migrim llogarie\n    notifications: Njoftime\n    preferences: Parapëlqime\n    two_factor_authentication: Mirëfilltësim Dyfaktorësh\n  statuses:\n    attached:\n      description: 'Bashkëngjitur: %{attached}'\n      image:\n        one: \"%{count} figurë\"\n        other: \"%{count} figura\"\n    boosted_from_html: Përforcuar nga %{acct_link}\n    content_warning: 'Sinjalizim lënde: %{warning}'\n    disallowed_hashtags:\n      one: 'përmbante një hashtag të palejuar: %{tags}'\n      other: 'përmbante hashtagët e palejuar: %{tags}'\n    language_detection: Zbulo gjuhë vetvetiu\n    open_in_web: Hape në internet\n    over_character_limit: u tejkalua kufi shenjash prej %{max}\n    pin_errors:\n      limit: Keni fiksuar tashmë numrin maksimum të mesazheve\n      ownership: S’mund të fiksohen mesazhet e të tjerëve\n      private: S’mund të fiksohet mesazh jopublik\n      reblog: S’mund të fiksohet një përforcim\n    show_more: Shfaq më tepër\n    sign_in_to_participate: Bëni hyrjen, që të merrni pjesë te biseda\n    visibilities:\n      private: Vetëm ndjekësve\n      private_long: Shfaqua vetëm ndjekësve\n      public: Publike\n      public_long: Mund ta shohë kushdo\n      unlisted: Jo në listë\n      unlisted_long: Mund ta shohë gjithkush, por s’gjendet në rrjedha publike kohore\n  stream_entries:\n    pinned: Mesazh i fiksuar\n    reblogged: të përforcuara\n    sensitive_content: Lëndë me spec\n  terms:\n    body_html: |\n      <h2>Rregulla Privatësie</h2>\n      <h3 id=\"collect\">Ç’të dhëna grumbullojmë?</h3>\n\n      <ul>\n      <li><em>Të dhëna bazë llogarie</em>: Nëse regjistroheni në këtë shërbyes, mund t’ju kërkohet të jepni një emër përdoruesi, një adresë email dhe një fjalëkalim. Mundet të jepni edhe të dhëna shtesë profili, të tilla si emër në ekran dhe jetëshkrim, dhe të ngarkoni një foto profili dhe figurë kryesh. Emri i përdoruesit, emri për në ekran, jetëshkrimi, fotoja e profilit dhe figura për kryet shfaqen përherë publikisht.</li>\n      <li><em>Postime, ndjekje dhe të tjera të dhëna publike</em>: Lista e personave që ndiqni shfaqet publikisht, po njësoj edhe ajo e ndjekësve tuaj. Kur parashtroni një mesazh, depozitohet data dhe koha, si dhe aplikacioni prej nga u parashtrua mesazhi. Mesazhet mund të përmbajnë bashkëngjitje media, bie fjala, foto dhe video. Postimet publike dhe ato të pashfaqura janë të passhme publikisht. Kur një postim e vini të zgjedhur në profilin tuaj, edhe ky është informacion i passhëm publikisht. Postimet tuaja janë u dërgohen ndjekësve tuaj, në disa raste kjo do të thotë se dërgohen në shërbyes të ndryshëm dhe në ta depozitohen kopje të tyre. Kur fshini postime, edhe kjo u dërgohet ndjekësve tuaj. Veprimi i riblogimit apo i parapëlqimit të një postimi tjetër është përherë publik.</li>\n      <li><em>Postime të drejtpërdrejta dhe ato vetëm për ndjekësit</em>: Krejt postimet depozitohen dhe trajtohen te shërbyesi. Postimet vetëm për ndjekës u dërgohen ndjekësve tuaj të cilët përmenden në to, dhe postimet e drejtpërdrejta u dërgohen vetëm përdoruesve të përmendur në to. Në disa raste kjo do të thotë se dërgohen në shërbyes të ndryshëm dhe në ta depozitohen kopje të tyre. Përpiqemi pa hile të kufizojmë hyrjen në këto postime vetëm të personave të autorizuar, por shërbyesit e tjerë mund të mos bëjnë të njëjtën gjë. Ndaj është e rëndësishme të shqyrtoni shërbyesit pjesë e të cilëve janë ndjekësit tuaj. Te rregullimet mund të përdorni një mundësi për të miratuar ose hedhur poshtë dorazi ndjekës të rinj. <em>Ju lutemi, mbani parasysh se operatorët e shërbyesit dhe cilido shërbyes marrës mund t’i shohin mesazhe të tillë</em>, dhe që marrësit mund të bëjnë për ta foto ekrani, t’i kopjojnë ose t’i rindajnë ato me të tjerët. <em>Mos u jepni të tjerëve të dhëna të rrezikshme përmes Mastodon-it.</em></li>\n      <li><em>IP dhe të tjera tejtëdhëna</em>: Kur bëni hyrjen, regjistrojmë adresën IP prej nga hytë, si dhe emrin e shfletuesit tuaj. Krejt sesionet e hyrjeve janë të shqyrtueshme nga ju dhe shfuqizim, që nga rregullimet. Adresa e fundit IP e përdorur depozitohet për 12 muaj. Mund të mbajmë edhe regjistra shërbyesi të cilët përfshijnë adresën IP të çdo kërkese ndaj shërbyesit tonë.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"use\">Përse i përdorim të dhënat tuaja?</h3>\n\n      <p>Cilado prej të dhënave që grumbullojmë prej jush mund të përdoret në rrugët vijuese:</p>\n\n      <ul>\n      <li>Për të mundësuar funksionimin bazë të Mastodon-it. Mundeni të ndërveproni me lëndën e personave të tjerë dhe të postoni lëndë tuajën vetëm kur jeni i futur në llogarinë tuaj. Për shembull, mund të ndiqni njerëz të tjerë për të parë postimet e tyre të ndërthurura te rrjedha juaj kohore e përshtatur.</li>\n      <li>Për të ndihmuar moderimin e bashkësisë, për shembull, duke krahasuar adresën tuaj IP me të tjera të njohura, për të përcaktuar shmangie nga dëbime ose cenime të tjera.</li>\n      <li>Adresa email që jepni mund të përdoret për t’ju dërguar informacion, njoftime mbi persona të tjerë që ndërveprojnë me lëndën tuaj ose që ju dërgojnë mesazhe, dhe për t’iu përgjigju pyetjeve dhe/ose kërkesave të tjera.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"protect\">Si i mbrojmë të dhënat tuaja?</h3>\n\n      <p>Vëmë në punë një larmi masash sigurie për të ruajtur të parrezikuara të dhënat tuaja personale kur jepni, parashtroni, ose hyni në to. Mes të tjerash, sesioni juaj i shfletimit, si edhe trafiku mes aplikacioneve tuaja dhe API-t, sigurohen me SSL, dhe fjalëkalimi juaj mbrohet duke përdorur një algoritëm të sigurt njëdrejtimsh. Për të siguruar edhe më hyrjet te llogaria juaj, mund të aktivizoni mirëfilltësimin dyfaktorësh.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"data-retention\">Cilat janë rregullat tona mbi mbajtjen e të dhënave?</h3>\n\n      <p>Do të përpiqemi pa hile:</p>\n\n      <ul>\n      <li>Të mbajmë regjistra shërbyesi që përmbajnë adresën IP të krejt kërkesave te ky shërbyes, sa kohë që regjistra të tillë mbahen, për jo më shumë se 90 ditë.</li>\n      <li>Të mbajmë adresat IP përshoqëruar me përdoruesit e regjistruar, për jo më shumë se 12 muaj.</li>\n      </ul>\n\n      <p>Mund të kërkoni dhe të shkarkoni një arkiv të lëndës tuaj, përfshi postimet tuaja, bashkëngjitje media, foto profili, dhe figurë kryesh.</p>\n\n      <p>Mund të fshini në mënyrë të pakthyeshme llogarinë tuaj në çfarëdo kohe.</p>\n\n      <hr class=\"spacer\"/>\n\n      <h3 id=\"cookies\">A përdorim <em>cookies</em>?</h3>\n\n      <p>Po. <em>Cookie</em>-t janë kartela të vockla që një sajt ose furnizuesi i shërbimit për të i depoziton në diskun e kompjuterit tuaj përmes shfletuesit (nëse e lejoni ju). Këto <em>cookies</em> i bëjnë të mundur sajtit të njohë shfletuesin tuaj dhe, nëse keni një llogari të regjistuar, ta përshoqërojë atë    me llogarinë tuaj të regjistuar.</p>\n\n      <p>Ne i përdorim <em>cookie</em>-t për të kuptuar dhe ruajtur parapëlqimet tuaja, për vizita të ardhshme.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"disclose\">A u japim palëve të treta ndonjë të dhënë?</h3>\n\n      <p>Nuk u shesim, shkëmbejmë, ose transferojmë në rrugë të tjera palëve të treta të dhëna tuajat personale që lejojnë identifikimin tuaj. Kjo nuk përfshin palë të treta të besuara që nga ndihmojnë të xhirojmë sajtin tonë, të bëjmë punën tonë, ose t’ju shërbejmë juve, sa kohë që këto palë pajtohen t’i mbajnë të fshehta këto të dhëna. Mund të japim të dhëna tuajat kur besojmë se kjo është e nevojshme për të qenë në rregull me ligjin, për të zbatuar rregullat e sajtit tonë, ose për të mbrojtur të drejta, pronësi, ose siguri tonën apo të të tjerëve.</p>\n\n      <p>Lënda juaj publike mund të shkarkohet nga shërbyes të tjerë në rrjet. Postimet tuaja publike dhe ato vetëm për ndjekësit dërgohen te shërbyesit ku gjenden ndjekësit tuaj, dhe mesazhet e drejtpërdrejtë jepen te shërbyesit e marrësve, për rastet ku këta ndjekës apo marrës gjenden në një tjetër shërbyes nga i këtushmi.</p>\n\n      <p>Kur autorizoni një aplikacion të përdorë llogarinë tuaj, në varësi të shtrirje së lejeve që miratoni, aplikacioni mund të hyjë në të dhënat e profilit tuaj publik, listat tuaja të ndjekjeve, ndjekësit tuaj, lista tuajat, krejt postimet tuaja, dhe të parapëlqyerit tuaj. Aplikacionet s’mund të njohin kurrë adresën tuaj email ose fjalëkalimin.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"children\">Përdorim i sajtit nga fëmijë</h3>\n\n      <p>Nëse ky shërbyes gjendet në BE apo në ZEE: Krejt sajti, produktet dhe shërbimet tona u drejtohen personave që janë të paktën 16 vjeç. Nëse jeni nën moshën 16 vjeç, sipas kërkesave të GDPR-së (<a href=\"https://en.wikipedia.org/wiki/General_Data_Protection_Regulation\">General Data Protection Regulation</a>), mos e përdorni këtë sajt.</p>\n\n      <p>Nëse ky shërbyes gjendet në ShBA: Krejt sajti, produktet dhe shërbimet tona u drejtohen personave që janë të paktën 13 vjeç. Nëse jeni nën moshën 13 vjeç, sipas kërkesave të COPPA (<a href=\"https://en.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act\">Children's Online Privacy Protection Act</a>), mos e përdorni këtë sajt.</p>\n\n      <p>Domosdoshmëritë e ligjit mund të jenë të ndryshme, nëse ky shërbyes gjendet në një tjetër juridiksion.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"changes\">Ndryshime te Rregullat tona të Privatësisë</h3>\n\n      <p>Nëse vendosim të ndryshojmë rregullat tona të privatësisë, këto ndryshime do t’i botojmë në këtë faqe.</p>\n\n      <p>Ky dokument është CC-BY-SA. U përditësua së fundmi më 7 mars, 2018.</p>\n\n      <p>Përshtatur fillimisht nga <a href=\"https://github.com/discourse/discourse\">rregullat e privatësisë në Discourse</a>.</p>\n    title: Kushte Shërbimi dhe Rregulla Privatësie te %{instance}\n  themes:\n    contrast: Mastodon (Me shumë kontrast)\n    default: Mastodon (I errët)\n    mastodon-light: Mastodon (I çelët)\n  time:\n    formats:\n      default: \"%d %b, %Y, %H:%M\"\n  two_factor_authentication:\n    code_hint: Që të bëhet ripohimi, jepni kodin e prodhuar nga aplikacioni juaj i mirëfilltësimeve\n    description_html: Nëse aktivizoni <strong>mirëfilltësimin dyfaktorësh</strong>, hyrja do të kërkojë të jeni në zotërim të telefonit tuaj, i cili do të prodhojë kod që duhet ta jepni.\n    disable: Çaktivizoje\n    enable: Aktivizoje\n    enabled: Mirëfilltësimi dyfaktorësh është i aktivizuar\n    enabled_success: Mirëfilltësimi dyfaktorësh u aktivizua me sukses\n    generate_recovery_codes: Prodho kode rikthimesh\n    instructions_html: \"<strong>Skanojeni këtë kod QR me Google Authenticator ose një aplikacion TOTP të ngjashëm në telefonin tuaj</strong>. Tani e tutje, ai aplikacion do të prodhojë kode të cilët duhet t’i jepni kur bëni hyrje.\"\n    lost_recovery_codes: Kodet e rikthimit ju lejojnë të rifitoni hyrje në llogarinë tuaj, nëse humbni telefonin tuaj. Nëse keni humbur kodet tuaj të rikthimit, mund t’i prodhoni sërish këtu. Kodet tuaj të vjetër të rikthimit do të bëhen të pavlefshëm.\n    manual_instructions: 'Nëse s’skanoni dot kodin QR dhe ju duhet ta jepni dorazi, ja e fshehta si tekst i thjeshtë:'\n    recovery_codes: Kopjeruani kode rikthimesh\n    recovery_codes_regenerated: Kodet e rikthimeve u riprodhuan me sukses\n    recovery_instructions_html: Në ndodhtë që të humbni hyrje te telefoni juaj, mund të përdorni një nga kodet e rikthimit më poshtë, që të rifitoni hyrje te llogaria juaj. <strong>Mbajini të parrezikuar kodet e rikthimeve</strong>. Për shembull, mund t’i shtypni dhe t’i ruani tok me dokumente të tjerë të rëndësishëm.\n    setup: Rregullojeni\n    wrong_code: Kodi i dhënë është i pavlefshëm! A janë të sakta koha e shërbyesit dhe koha e pajisjes?\n  user_mailer:\n    backup_ready:\n      explanation: Kërkuat një kopjeruajtje të plotë të llogarisë tuaj Mastodon. E keni gati për shkarkim!\n      subject: Arkivi juaj është gati për shkarkim\n      title: Marrje arkivi me vete\n    warning:\n      explanation:\n        disable: Kur llogaria juaj është e ngrirë, të dhënat në llogarinë tuaj mbeten të paprekura, por s’mund të kryeni ndonjë veprim, para se të shkyçet.\n        silence: Kur llogaria juaj është e kufizuar, mesazhet tuaj në këtë shërbyes do t’i shohin vetëm personat që ju ndjekin tashmë. dhe mund të liheni jashtë nga lista të ndryshme publike. Megjithatë, të tjerët prapë mund t’ju ndjekin dorazi.\n        suspend: Llogaria juaj është pezulluar, dhe krejt mesazhet tuaja dhe kartelat media të ngarkuara janë hequr në mënyrë të pakthyeshme nga ky shërbyes, dhe nga shërbyesit te të cilët kishit ndjekës.\n      review_server_policies: Shqyrtoni rregullat e shërbyesit\n      subject:\n        disable: Llogaria juaj %{acct} është ngrirë\n        none: Sinjalizim për %{acct}\n        silence: Llogaria juaj %{acct} është kufizuar\n        suspend: Llogaria juaj %{acct} është pezulluar\n      title:\n        disable: Llogari e ngrirë\n        none: Sinjalizim\n        silence: Llogari e kufizuar\n        suspend: Llogari e pezulluar\n    welcome:\n      edit_profile_action: Rregullim profili\n      edit_profile_step: Profilin mund ta personalizoni duke ngarkuar një avatar, figurë kryesh, duke ndryshuar emrin tuaj në ekran, etj. Nëse dëshironi të shqyrtoni ndjekës të rinj, përpara se të jenë lejuar t’ju ndjekin, mund të kyçni llogarinë tuaj.\n      explanation: Ja disa ndihmëza, sa për t’ia filluar\n      final_action: Filloni të postoni\n      final_step: 'Filloni të postoni! Edhe pse pa ndjekës, mesazhet tuaj publike mund të shihen nga të tjerët, për shembull te rrjedha kohore vendore dhe në hashtagë. Mund të donit të prezantoni veten nën hashtagun #introductions.'\n      full_handle: Identifikuesi juaj i plotë\n      full_handle_hint: Kjo është ajo çka do të duhej t’u tregonit shokëve tuaj, që të mund t’ju dërgojnë mesazhe ose t’ju ndjekin nga një shërbyes tjetër.\n      review_preferences_action: Ndryshoni parapëlqime\n      review_preferences_step: Mos harroni të caktoni parapëlqimet tuaja, fjala vjen, ç’email-e dëshironi të merrni, ose çfarë shkalle privatësie do të donit të kishin, si parazgjedhje, postimet tuaja. Nëse nuk ju merren mendtë nga rrotullimi, mund të zgjidhni të aktivizoni vetëluajtje GIF-esh.\n      subject: Mirë se vini te Mastodon-i\n      tip_federated_timeline: Rrjedha kohore e të federuarve është një pamje e fluksit të rrjetit Mastodon. Por përfshin vetëm persona te të cilët janë pajtuar fqinjët tuaj, pra s’është e plotë.\n      tip_following: Përgjegjësin e shërbyesit tuaj e ndiqni, si parazgjedhje. Për të gjetur më shumë persona interesantë, shihni te rrjedha kohore vendore dhe ajo e të federuarve.\n      tip_local_timeline: Rrjedha kohore vendore është një pamje e fluksit të njerëzve në %{instance}. Këta janë fqinjët tuaj më të afërt!\n      tip_mobile_webapp: Nëse shfletuesi juaj celular ju ofron të shtohet Mastodon-i te skena juaj e kreut, mund të merrni njoftime <em>push</em>. Nga shumë pikëpamje vepron si një aplikacion i brendshëm i platformës së celularit!\n      tips: Ndihmëza\n      title: Mirë se vini, %{name}!\n  users:\n    follow_limit_reached: S’mund të ndiqni më tepër se %{limit} persona\n    invalid_email: Adresa email është e pavlefshme\n    invalid_otp_token: Kod dyfaktorësh i pavlefshëm\n    otp_lost_help_html: Nëse humbi hyrjen te të dy, mund të lidheni me %{email}\n    seamless_external_login: Jeni futur përmes një shërbimi të jashtëm, ndaj s’ka rregullime fjalëkalimi dhe email.\n    signed_in_as: 'I futur si:'\n  verification:\n    explanation_html: 'Mundeni <strong>të verifikoni veten si i zoti i lidhjeve te tejtëdhënat e profilit tuaj</strong>. Për këtë, sajti i lidhur duhet të përmbajë një lidhje për te profili juaj Mastodon. Lidhje për te ajo <strong>duhet</strong> të ketë një atribut <code>rel=\"me\"</code>. Lënda tekst e lidhjes nuk ngre peshë. Ja një shembull:'\n    verification: Verifikim\n"
  },
  {
    "path": "config/locales/sr-Latn.rb",
    "content": "require 'rails_i18n/common_pluralizations/romanian'\n\n::RailsI18n::Pluralization::Romanian.with_locale(:'sr-Latn')\n"
  },
  {
    "path": "config/locales/sr-Latn.yml",
    "content": "---\nsr-Latn:\n  about:\n    about_hashtag_html: Ovo su javni statusi tagovani sa <strong>#%{hashtag}</strong>. Možete odgovarati na njih ako imate nalog bilo gde u fediversu.\n    about_mastodon_html: Mastodont je društvena mreža bazirana na otvorenim protokolima i slobodnom softveru otvorenog koda. Decentralizovana je kao što je decentralizovana e-pošta.\n    about_this: O instanci\n    contact: Kontakt\n    contact_missing: Nije postavljeno\n    extended_description_html: |\n      <h3>Dobro mesto za pravila</h3>\n      <p>Prošireni opis koji još nije postavljen.</p>\n    generic_description: \"%{domain} je server na mreži\"\n    hosted_on: Mastodont hostovan na %{domain}\n    learn_more: Saznajte više\n    source_code: Izvorni kod\n    status_count_before: Koji su napisali\n    user_count_before: Dom za\n    what_is_mastodon: Šta je Mastodont?\n  accounts:\n    media: Multimedija\n    moved_html: \"%{name} je pomeren na %{new_profile_link}:\"\n    nothing_here: Ovde nema ništa!\n    people_followed_by: Ljudi koje %{name} prati\n    people_who_follow: Ljudi koji prate %{name}\n    posts_with_replies: Tutovi i odgovori\n    reserved_username: Korisničko ime je rezervisano\n    roles:\n      admin: Administrator\n      moderator: Moderator\n    unfollow: Otprati\n  admin:\n    account_moderation_notes:\n      create: Napravi\n      created_msg: Moderatorska beleška uspešno napravljena!\n      delete: Obriši\n      destroyed_msg: Moderatorska beleška uspešno obrisana!\n    accounts:\n      are_you_sure: Da li ste sigurni?\n      by_domain: Domen\n      confirm: Potvrdi\n      confirmed: Potvrđeno\n      confirming: Potvrđujući\n      demote: Ražaluj\n      disable: Isključi\n      disable_two_factor_authentication: Isključi 2FA\n      disabled: Isključena\n      display_name: Prikazano ime\n      domain: Domen\n      edit: Izmeni\n      email: E-pošta\n      email_status: Status e-pošte\n      enable: Uključi\n      enabled: Uključeno\n      feed_url: Adresa dovoda\n      followers: Pratioci\n      followers_url: Adresa pratioca\n      follows: Praćeni\n      inbox_url: Adresa sandučeta\n      location:\n        all: Sve\n        local: Lokalne\n        remote: Udaljene\n        title: Lokacija\n      login_status: Status prijave\n      media_attachments: Multimedijalni prilozi\n      memorialize: Prebaci u in memoriam\n      moderation:\n        all: Svi\n        silenced: Ućutkani\n        suspended: Suspendovani\n        title: Moderacija\n      moderation_notes: Moderatorske beleške\n      most_recent_activity: Najskorija aktivnost\n      most_recent_ip: Najskorija IP adresa\n      not_subscribed: Nije pretplaćen\n      outbox_url: Odlazno sanduče\n      perform_full_suspension: Izvrši kompletno isključenje\n      profile_url: Adresa profila\n      promote: Unapredi\n      protocol: Protokol\n      public: Javno\n      redownload: Osveži avatar\n      resend_confirmation:\n        already_confirmed: Ovaj korisnik je već potvrđen\n        send: Ponovo pošaljite e-poruku za potvrdu\n        success: E-mail potvrde je uspešno poslat!\n      reset: Resetuj\n      reset_password: Resetuj lozinku\n      resubscribe: Ponovo se pretplati\n      role: Ovlašćenja\n      roles:\n        staff: Osoblje\n        user: Korisnik\n      salmon_url: Salmon adresa\n      search: Pretraga\n      shared_inbox_url: Adresa deljenog sandučeta\n      show:\n        created_reports: Prijave koje je napravio ovaj nalog\n        targeted_reports: Prijave napravljene o ovom nalogu\n      silence: Ućutkaj\n      statuses: Statusi\n      subscribe: Pretplati se\n      title: Nalozi\n      undo_silenced: Ukini ćutanje\n      undo_suspension: Ukini suspenziju\n      unsubscribe: Ukini pretplatu\n      username: Korisničko ime\n      web: Veb\n    action_logs:\n      actions:\n        confirm_user: \"%{name} je potvrdio adresu e-pošte korisnika %{target}\"\n        create_custom_emoji: \"%{name} je otpremio novi emotikon %{target}\"\n        create_domain_block: \"%{name} je blokirao domen %{target}\"\n        create_email_domain_block: \"%{name} je stavio na crnu listu domen e-pošte %{target}\"\n        demote_user: \"%{name} je ražalovao korisnika %{target}\"\n        destroy_domain_block: \"%{name} je odblokirao domen %{target}\"\n        destroy_email_domain_block: \"%{name} je stavio na belu listu domen e-pošte %{target}\"\n        destroy_status: \"%{name} je uklonio status korisnika %{target}\"\n        disable_2fa_user: \"%{name} je isključio obaveznu dvofaktorsku identifikaciju za korisnika %{target}\"\n        disable_custom_emoji: \"%{name} je onemogućio emotikon %{target}\"\n        disable_user: \"%{name} je onemogućio prijavljivanje korisniku %{target}\"\n        enable_custom_emoji: \"%{name} je omogućio emotikon %{target}\"\n        enable_user: \"%{name} je omogućio prijavljivanje za korisnika %{target}\"\n        memorialize_account: \"%{name} je pretvorio stranu naloga %{target} kao in memoriam stranu\"\n        promote_user: \"%{name} je unapredio korisnika %{target}\"\n        reset_password_user: \"%{name} je resetovao lozinku korisniku %{target}\"\n        resolve_report: \"%{name} je odbacio prijavu %{target}\"\n        silence_account: \"%{name} je ućutkao nalog %{target}\"\n        suspend_account: \"%{name} je suspendovao nalog %{target}\"\n        unsilence_account: \"%{name} je ukinuo ćutanje nalogu %{target}\"\n        unsuspend_account: \"%{name} je ukinuo suspenziju nalogu %{target}\"\n        update_custom_emoji: \"%{name} je izmenio emotikon %{target}\"\n        update_status: \"%{name} je izmenio status korisnika %{target}\"\n      title: Zapisnik\n    custom_emojis:\n      by_domain: Domen\n      copied_msg: Uspešno napravljena lokalna kopija emotikona\n      copy: Kopiraj\n      copy_failed_msg: Ne mogu da napravim lokalnu kopiju tog emotikona\n      created_msg: Emotikon uspešno napravljen!\n      delete: Obriši\n      destroyed_msg: Emotikon uspešno obrisan!\n      disable: Onemogući\n      disabled_msg: Emotikon uspešno onemogućen\n      emoji: Emotikon\n      enable: Omogući\n      enabled_msg: Emotikon uspešno omogućen\n      image_hint: PNG do 50KB\n      listed: Izlistan\n      new:\n        title: Dodaj novi proizvoljni emotikon\n      overwrite: Prepiši\n      shortcode: Prečica\n      shortcode_hint: Najmanje 2 karaktera, dozvoljeni su samo slova, brojevi i donje crte\n      title: Proizvoljni emotikoni\n      unlisted: Neizlistan\n      update_failed_msg: Ne mogu da ažuriram ovaj emotikon\n      updated_msg: emotikon uspešno ažuriran!\n      upload: Otpremi\n    domain_blocks:\n      add_new: Dodaj novi\n      created_msg: Blokiranje domena se obrađuje\n      destroyed_msg: Blokiranje domena je opozvano\n      domain: Domen\n      new:\n        create: Napravi blokadu\n        hint: Blokiranje domena neće sprečiti pravljenje naloga u bazi, ali će retroaktivno i automatski primeniti određene moderatorske metode nad tim nalozima.\n        severity:\n          desc_html: \"<strong>Ućutkavanje</strong> će sve statuse ovog naloga učiniti nevidiljivim za sve, osim za one koji nalog već prate. <strong>Suspenzija</strong> će ukloniti sav sadržaj naloga, svu multimediju, i profilne podatke. Koristite <strong>Ništa</strong> ako samo želite da odbacite multimedijalne fajlove.\"\n          noop: Ništa\n          silence: Ućutkavanje\n          suspend: Suspenzija\n        title: Novo blokiranje domena\n      reject_media: Odbaci multimediju\n      reject_media_hint: Uklanja lokalno uskladištene multimedijske fajlove i odbija da ih skida na dalje. Nebitno je za suspenziju\n      show:\n        affected_accounts:\n          few: Utiče na %{count} naloga u bazi\n          one: Utiče na jedan nalog u bazi\n          other: Utiče na %{count} naloga u bazi\n        retroactive:\n          silence: Ugasi ućutkivanje za sve postojeće naloge sa ovog domena\n          suspend: Ugasi suspenzije za sve postojeće naloge sa ovog domena\n        title: Poništi blokadu domena za domen %{domain}\n        undo: Poništi\n      undo: Poništi\n    email_domain_blocks:\n      add_new: Dodaj novuAdd new\n      created_msg: Uspešno dodao domen e-pošte na crnu listu\n      delete: Ukloni\n      destroyed_msg: Uspešno uklonjen domen e-pošte sa crne liste\n      domain: Domen\n      new:\n        create: Dodaj domen\n        title: Nova stavka u crnoj listi e-pošti\n      title: Crna lista adresa e-pošte\n    instances:\n      title: Poznate instance\n    invites:\n      filter:\n        all: Sve\n        available: Aktivne\n        expired: Istekle\n      title: Pozivnice\n    reports:\n      action_taken_by: Akciju izveo\n      are_you_sure: Da li ste sigurni?\n      comment:\n        none: Ništa\n      mark_as_resolved: Označi kao rešen\n      report: 'Prijava #%{id}'\n      reported_account: Prijavljeni nalog\n      reported_by: Prijavio\n      resolved: Rešeni\n      title: Prijave\n      unresolved: Nerešeni\n    settings:\n      bootstrap_timeline_accounts:\n        desc_html: Odvojite više korisničkih imena zarezom. Radi samo za lokalne i otključane naloge. Ako je prazno, onda se odnosi na sve lokalne administratore.\n        title: Nalozi za automatsko zapraćivanje za nove korisnike\n      contact_information:\n        email: Poslovna e-pošta\n        username: Kontakt korisničko ime\n      registrations:\n        closed_message:\n          desc_html: Prikazuje se na glavnoj strani kada je instanca zatvorena za registracije. Možete koristiti HTML tagove\n          title: Poruka o zatvorenoj registraciji\n        deletion:\n          desc_html: Dozvoli svima da mogu da obrišu svoj nalog\n          title: Otvori brisanje naloga\n        min_invite_role:\n          disabled: Niko\n          title: Samo preko pozivnice\n      show_staff_badge:\n        desc_html: Prikaži bedž osoblja na korisničkoj strani\n        title: Prikaži bedž osoblja\n      site_description:\n        desc_html: Uvodni pasus na naslovnoj strani i u meta HTML tagovima. Možete koristiti HTML tagove, konkretno <code>&lt;a&gt;</code> i <code>&lt;em&gt;</code>.\n        title: Opis instance\n      site_description_extended:\n        desc_html: Dobro mesto za vaš kod ponašanja, pravila, smernice i druge stvari po kojima se Vaša instanca razlikuje. Možete koristiti HTML tagove\n        title: Proizvoljne dodatne informacije\n      site_terms:\n        desc_html: Možete pisati Vašu politiku privatnosti, uslove korišćenja i ostale legalne stvari. Možete koristiti HTML tagove\n        title: Proizvoljni uslovi korišćenja\n      site_title: Ime instance\n      thumbnail:\n        desc_html: Koristi se za preglede kroz OpenGraph i API. Preporučuje se 1200x630px\n        title: Sličica instance\n      timeline_preview:\n        desc_html: Prikaži javnu lajnu na početnoj strani\n        title: Pregled lajne\n      title: Postavke sajta\n    statuses:\n      back_to_account: Nazad na stranu naloga\n      batch:\n        delete: Obriši\n        nsfw_off: NSFW isključen\n        nsfw_on: NSFW uključen\n      failed_to_execute: Neuspelo izvršavanje\n      media:\n        title: Multimedija\n      no_media: Bez multimedije\n      title: Statusi naloga\n      with_media: Sa multimedijom\n    subscriptions:\n      confirmed: Potvrđeno\n      expires_in: Ističe za\n      last_delivery: Poslednja dostava\n    title: Administracija\n  admin_mailer:\n    new_report:\n      body: \"%{reporter} je prijavio %{target}\"\n      subject: Nova prijava za %{instance} (#%{id})\n  application_mailer:\n    settings: 'Promeni podešavanja e-pošte: %{link}'\n    view: 'Pogledaj:'\n  applications:\n    created: Aplikacija uspešno napravljena\n    destroyed: Aplikacija uspešno obrisana\n    invalid_url: Data adresa nije ispravna\n    regenerate_token: Rekreiraj pristupni token\n    token_regenerated: Pristupni token uspešno rekreiran\n    warning: Oprezno sa ovim podacima. Nikad je ne delite ni sa kim!\n    your_token: Vaš pristupni token\n  auth:\n    delete_account: Obriši nalog\n    delete_account_html: Ako želite da obrišete Vaš nalog, možete <a href=\"%{path}\">nastaviti ovde</a>. Bićete upitani da potvrdite.\n    didnt_get_confirmation: Niste dobili poruku sa uputstvima za potvrdu naloga?\n    forgot_password: Zaboravili ste lozinku?\n    invalid_reset_password_token: Token za resetovanje lozinke je neispravan ili je istekao. Zatražite novi.\n    login: Prijavi se\n    logout: Odjava\n    migrate_account: Pomeri u drugi nalog\n    migrate_account_html: Ako želite da preusmerite ovaj nalog na neki drugi, možete to <a href=\"%{path}\">podesiti ovde</a>.\n    register: Registruj se\n    resend_confirmation: Pošalji poruku sa uputstvima o potvrdi naloga ponovo\n    reset_password: Resetuj lozinku\n    security: Bezbednost\n    set_new_password: Postavi novu lozinku\n  authorize_follow:\n    error: Nažalost, desila se greška pri traženju udaljenog naloga\n    follow: Zaprati\n    follow_request: 'Poslali ste zahtev za praćenjen za:'\n    following: 'Sjajno! Sada pratite:'\n    post_follow:\n      close: Ili možete zatvoriti ovaj prozor.\n      return: Vrati se na profil ovog korisnika\n      web: Idi na veb\n    title: Zaprati %{acct}\n  datetime:\n    distance_in_words:\n      about_x_months: \"%{count}mesec\"\n      about_x_years: \"%{count}god\"\n      almost_x_years: \"%{count}god\"\n      half_a_minute: Upravo sad\n      less_than_x_seconds: Upravo sad\n      over_x_years: \"%{count}god\"\n      x_months: \"%{count}mesec\"\n  deletes:\n    bad_password_msg: Dobar pokušaj, hakeri! Neispravna lozinka\n    confirm_password: Unesite trenutnu lozinku da bismo proverili Vaš identitet\n    description_html: Ovo će <strong>trajno, bespovratno</strong> ukloniti sadržaj sa Vašef naloga i deaktivirati ga. Vaše korisničko ime će ostati rezervisano da se spreči da se neko ne predstavlja kao Vi sutra.\n    proceed: Obriši nalog\n    success_msg: Vaš nalog je uspešno obrisan\n    warning_html: Garantovano je samo brisanje sadržaja sa ove instance. Sadržaj koji je deljen dalje će verovatno da ostavi neke tragove. Nedostupni i ugašeni serveri, kao i serveri koji su odjavljeni od primanja statusa od Vas, neće ažurirati svoje baze.\n    warning_title: Dostupnost rasejanog sadržaja\n  errors:\n    '403': Nemate dozvola da vidite ovu stranu.\n    '404': Strana koju ste tražili ne postoji.\n    '410': Strana koju ste tražili više ne postoji.\n    '422': \n    '429': Uspored\n    '500':\n      content: Izvinjavamo se, nešto je pošlo po zlu sa ove strane.\n      title: Strana nije ispravna\n    noscript_html: Da biste koristili Mastodont veb aplikaciju, omogućite JavaScript. U suprotnom, probajte neku od <a href=\"%{apps_path}\">originalnih aplikacija</a> za Mastodont za Vašu platformu.\n  exports:\n    blocks: Blokirali ste\n    follows: Pratite\n    mutes: Ućutkali ste\n    storage: Multimedijalno skladište\n  generic:\n    changes_saved_msg: Izmene uspešno sačuvane!\n    save_changes: Snimi izmene\n    validation_errors:\n      few: Nešto nije baš kako treba! Pregledajte %{count} greške ispod\n      one: Nešto nije baš kako treba! Pregledajte greške ispod\n      other: Nešto nije baš kako treba! Pregledajte %{count} grešaka ispod\n  imports:\n    preface: Možete uvesti podatke koje ste izvezli sa druge instance, kao što su liste ljudi koje ste pratili ili blokirali.\n    success: Vaši podaci su uspešno otpremljeni i biće obrađeni uskoro\n    types:\n      blocking: Lista blokiranja\n      following: Lista pratilaca\n      muting: Lista ućutkanih\n    upload: Otpremi\n  invites:\n    delete: Deaktiviraj\n    expired: Isteklo\n    expires_in:\n      '1800': 30 minuta\n      '21600': 6 sati\n      '3600': 1 sad\n      '43200': 12 sati\n      '604800': 1 week\n      '86400': 1 dan\n    expires_in_prompt: Nikad\n    generate: Generiši\n    max_uses:\n      few: \"%{count} korišćenja\"\n      one: 1 korišćenje\n      other: \"%{count} korišćenja\"\n    max_uses_prompt: Bez ograničenja\n    prompt: Generiši i podeli linkove sa drugima da im odobrite pristup ovoj instanci\n    table:\n      expires_at: Ističe\n      uses: Korišćenja\n    title: Pozovi ljude\n  lists:\n    errors:\n      limit: Dostigli ste limit broja listi\n  media_attachments:\n    validations:\n      images_and_video: Ne može da se prikači video na status koji već ima slike\n      too_many: Ne može se prikačiti više od 4 fajla\n  migrations:\n    acct: korisnik@domen novog naloga\n    currently_redirecting: 'Profil Vam je podešen da preusmerava na :'\n    proceed: Sačuvaj\n    updated_msg: Prebacivanje postavki Vašeg naloga uspešno izmenjeno!\n  moderation:\n    title: Moderacija\n  notification_mailer:\n    digest:\n      body: Evo kratak pregled šta ste propustili od poslednje posete od %{since}\n      mention: \"%{name} Vas je pomenuo u:\"\n      new_followers_summary:\n        few: Dobili ste %{count} nova pratioca! Sjajno!\n        one: Dobili ste jednog novog pratioca! Jeee!\n        other: Dobili ste %{count} novih pratioca! Sjajno!\n      subject:\n        few: \"%{count} nova obaveštenja od poslednje posete \\U0001F418\"\n        one: \"1 novo obaveštenje od poslednje posete \\U0001F418\"\n        other: \"%{count} novih obaveštenja od poslednje posete \\U0001F418\"\n    favourite:\n      body: \"%{name} je postavio kao omiljen Vaš status:\"\n      subject: \"%{name} je postavio kao omiljen Vaš status\"\n    follow:\n      body: \"%{name} Vas je zapratio!\"\n      subject: \"%{name} Vas je zapratio\"\n    follow_request:\n      body: \"%{name} je zatražio da Vas zaprati\"\n      subject: 'Pratioci na čekanju: %{name}'\n    mention:\n      body: \"%{name} Vas je pomenuo u:\"\n      subject: \"%{name} Vas je pomenuo\"\n    reblog:\n      body: \"%{name} Vam je podržao(la) status:\"\n      subject: \"%{name} je podržao(la) Vaš status\"\n  pagination:\n    next: Sledeći\n    prev: Prethodni\n  preferences:\n    other: Ostali\n  remote_follow:\n    acct: Unesite Vaš korisnik@domen sa koga želite da pratite\n    missing_resource: Ne mogu da nađem zahtevanu adresu preusmeravanja za Vaš nalog\n    proceed: Nastavite da zapratite\n    prompt: 'Zapratite će:'\n  sessions:\n    activity: Poslednja aktivnost\n    browser: Veb čitač\n    browsers:\n      blackberry: Blekberi\n      chrome: Hrom\n      generic: Nepoznati veb čitač\n    current_session: Trenutna sesija\n    description: \"%{browser} sa %{platform}\"\n    explanation: Ovo su trenutno prijavljeni veb čitači na Vaš Mastodont nalog.\n    platforms:\n      adobe_air: Adobe Air-a\n      android: Androida\n      blackberry: Blekberija\n      chrome_os: Hrom OS-a\n      firefox_os: Fajerfoks OS-a\n      linux: Linuksa\n      mac: Mac-a\n      other: nepoznate platforme\n      windows: Vindouza\n      windows_mobile: Vindouz mobilnog\n      windows_phone: Vindouz telefona\n    revoke: Opozovi\n    revoke_success: Sesija uspešno opozvana\n    title: Sesije\n  settings:\n    authorized_apps: Autorizovane aplikacije\n    back: Nazad na Mastodonta\n    delete: Brisanje naloga\n    development: Razvoj\n    edit_profile: Izmena profila\n    export: Izvoz podataka\n    import: Uvoz\n    migrate: Prebacivanje naloga\n    notifications: Obaveštenja\n    preferences: Podešavanja\n    two_factor_authentication: Dvofaktorska identifikacija\n  statuses:\n    open_in_web: Otvori u vebu\n    over_character_limit: ograničenje od %{max} karaktera prekoračeno\n    pin_errors:\n      limit: Već imate prikačen najveći broj tutova\n      ownership: Tuđi tutovi ne mogu da se prikače\n      private: Tutovi koji nisu javni ne mogu da se prikače\n      reblog: Podrška ne može da se prikači\n    show_more: Prikaži još\n    visibilities:\n      private: Samo pratioci\n      private_long: Samo prikaži pratiocima\n      public: Javno\n      public_long: Svako može da vidi\n      unlisted: Neizlistano\n      unlisted_long: Svako može da vidi, ali nije izlistano na javnim lajnama\n  stream_entries:\n    pinned: Prikačeni tut\n    reblogged: podržano\n    sensitive_content: Osetljiv sadržaj\n  terms:\n    title: Uslovi korišćenja i politika privatnosti instance %{instance}\n  themes:\n    default: Mastodont\n  two_factor_authentication:\n    code_hint: Unesite kod sa Vaše aplikacije za proveru identiteta da potvrdite\n    description_html: Ako uključite <strong>dvofaktorsku identifikaciju</strong>, moraćete da imate telefon sa sobom da biste mogli da se prijavite. Telefon će onda generisati tokene za Vašu prijavu.\n    disable: Isključi\n    enable: Uključi\n    enabled: Dvofaktorska identifikacija je uključena\n    enabled_success: Dvofaktorska identifikacija je uspešno uključena\n    generate_recovery_codes: Generiši kodove za oporavak\n    instructions_html: \"<strong>Skenirajte ovaj QR kod u Google Authenticator ili nekoj sličnoj TOTP aplikaciji na Vašem telefonu</strong>. Od sada, ta aplikacija će Vam generisati tokene koje morate uneti da biste se prijavili.\"\n    lost_recovery_codes: Kodovi za oporavak Vam omogućavaju da povratite pristup nalogu ako izgubite telefon. Ako izgubite kodove za oporavak, možete ih regenerisati ovde. Od tog trenutka, stari kodovi za oporavak više ne važe.\n    manual_instructions: 'Ukoliko ne možete da skenirate QR kod i morate ga unesete ručno, evo je ogoljena šifra:'\n    recovery_codes: Napravite rezervu kodova za oporavak\n    recovery_codes_regenerated: Kodovi za oporavak uspešno regenerisani\n    recovery_instructions_html: Ako ikada izgubite pristup telefonu, možete iskoristiti kodove za oporavak date ispod da povratite pristup nalogu. <strong>Držite kodove za oporavak na sigurnom</strong>. Na primer, odštampajte ih i čuvajte ih sa ostalim važnim dokumentima.\n    setup: Nameštanje\n    wrong_code: Uneseni kod nije ispravan! Da li su vremena na serveru i na uređaju ispravna?\n  users:\n    invalid_email: Adresa e-pošte nije ispravna\n    invalid_otp_token: Neispravni dvofaktorski kod\n    signed_in_as: 'Prijavljen kao:'\n"
  },
  {
    "path": "config/locales/sr.rb",
    "content": "require 'rails_i18n/common_pluralizations/romanian'\n\n::RailsI18n::Pluralization::Romanian.with_locale(:sr)\n"
  },
  {
    "path": "config/locales/sr.yml",
    "content": "---\nsr:\n  about:\n    about_hashtag_html: Ово су јавни статуси таговани са <strong>#%{hashtag}</strong>. Можете одговарати на њих ако имате налог било где у федиверсу.\n    about_mastodon_html: Мастодон је друштвена мрежа базирана на отвореним протоколима и слободном софтверу отвореног кода. Децентрализована је као што је децентрализована е-пошта.\n    about_this: О инстанци\n    administered_by: 'Администрирано од стране:'\n    apps: Мобилне апликације\n    contact: Контакт\n    contact_missing: Није постављено\n    documentation: Документација\n    extended_description_html: |\n      <h3>Добро место за правила</h3>\n      <p>Проширени опис који још није постављен.</p>\n    generic_description: \"%{domain} је сервер на мрежи\"\n    hosted_on: Мастодонт хостован на %{domain}\n    learn_more: Сазнајте више\n    privacy_policy: Полиса приватности\n    source_code: Изворни код\n    status_count_after:\n      few: статуси\n      one: статус\n      other: статуса\n    status_count_before: Који су написали\n    terms: Услови коришћења\n    user_count_after:\n      few: корисници\n      one: корисник\n      other: корисника\n    user_count_before: Дом за\n    what_is_mastodon: Шта је Мастодон?\n  accounts:\n    choices_html: \"%{name}'s избори:\"\n    follow: Запрати\n    followers:\n      few: Пратиоци\n      one: Пратиоц\n      other: Пратиоци\n    following: Пратим\n    joined: Придружио/ла се %{date}\n    last_active: последњи пут активни\n    link_verified_on: Власништво над овом везом је проверено %{date}\n    media: Медији\n    moved_html: \"%{name} је прешао на %{new_profile_link}:\"\n    network_hidden: Ова информација није доступна\n    nothing_here: Овде нема ништа!\n    people_followed_by: Људи које %{name} прати\n    people_who_follow: Људи који прате %{name}\n    pin_errors:\n      following: Морате пратити ову особу ако хоћете да потврдите\n    posts:\n      few: Трубе\n      one: Труба\n      other: Трубе\n    posts_tab_heading: Трубе\n    posts_with_replies: Трубе и одговори\n    reserved_username: Корисничко име је резервисано\n    roles:\n      admin: Администратор\n      bot: Бот\n      moderator: Модератор\n    unfollow: Отпрати\n  admin:\n    account_actions:\n      action: Извршите радњу\n      title: Извршите модераторске радње на %{acct}\n    account_moderation_notes:\n      create: Оставите белешку\n      created_msg: Модераторска белешка успешно направљена!\n      delete: Обриши\n      destroyed_msg: Модераторска белешка успешно обрисана!\n    accounts:\n      are_you_sure: Да ли сте сигурни?\n      avatar: Аватар\n      by_domain: Домен\n      change_email:\n        changed_msg: Е-пошта налога успешно промењена!\n        current_email: Тренутна е-пошта\n        label: Промените е-пошту\n        new_email: Нова e-пошта\n        submit: Промените e-пошту\n        title: Промените e-пошту за %{username}\n      confirm: Потврди\n      confirmed: Потврђено\n      confirming: Потврдување\n      deleted: Избрисано\n      demote: Ражалуј\n      disable: Искључи\n      disable_two_factor_authentication: Искључи 2FA\n      disabled: Искључена\n      display_name: Приказано име\n      domain: Домен\n      edit: Измени\n      email: Е-пошта\n      email_status: Статус е-поште\n      enable: Омогући\n      enabled: Укључено\n      feed_url: Адреса довода\n      followers: Пратиоци\n      followers_url: Адреса пратиоца\n      follows: Праћени\n      header: Заглавље\n      inbox_url: Адреса сандучета\n      invited_by: Позван од стране\n      joined: Придружио се\n      location:\n        all: Све\n        local: Локалне\n        remote: Удаљене\n        title: Локација\n      login_status: Статус пријаве\n      media_attachments: Мултимедијални прилози\n      memorialize: Пребаци у in memoriam\n      moderation:\n        active: Активан\n        all: Сви\n        silenced: Ућуткани\n        suspended: Суспендовани\n        title: Модерација\n      moderation_notes: Модераторске белешке\n      most_recent_activity: Најскорија активност\n      most_recent_ip: Најскорија IP адреса\n      no_limits_imposed: Нема ограничења\n      not_subscribed: Није претплаћен\n      outbox_url: Одлазно сандуче\n      perform_full_suspension: Искључи\n      profile_url: Адреса профила\n      promote: Унапреди\n      protocol: Протокол\n      public: Јавно\n      push_subscription_expires: PuSH претплата истиче\n      redownload: Освежи профил\n      remove_avatar: Уклони аватар\n      remove_header: Одстрани заглавље\n      resend_confirmation:\n        already_confirmed: Овој корисник е веќе потврден\n        send: Препрати го е-мајлот за потврда\n        success: Е-пошта за потврда успешно испратена!\n      reset: Ресетуј\n      reset_password: Ресетуј лозинку\n      resubscribe: Поново се претплати\n      role: Овлашћења\n      roles:\n        admin: Администратор\n        moderator: Модератор\n        staff: Особље\n        user: Корисник\n      salmon_url: Salmon адреса\n      search: Претрага\n      shared_inbox_url: Адреса дељеног сандучета\n      show:\n        created_reports: Направљени извештаји\n        targeted_reports: Пријаве од стране других\n      silence: Ућуткај\n      silenced: Ућуткан\n      statuses: Статуси\n      subscribe: Претплати се\n      suspended: Суспендовани\n      title: Налози\n      unconfirmed_email: Непотврђена е-пошта\n      undo_silenced: Укини ћутање\n      undo_suspension: Укини суспензију\n      unsubscribe: Укини претплату\n      username: Корисничко име\n      warn: Упозори\n      web: Веб\n    action_logs:\n      actions:\n        assigned_to_self_report: \"%{name} је доделио/ла извештај %{target} себи\"\n        change_email_user: \"%{name} је променио/ла адресу Е-поште коисника/це %{target}\"\n        confirm_user: \"%{name} је потврдио адресу е-поште корисника %{target}\"\n        create_account_warning: \"%{name} је послао пријаву %{target}\"\n        create_custom_emoji: \"%{name} је отпремио нови емоџи %{target}\"\n        create_domain_block: \"%{name} је блокирао домен %{target}\"\n        create_email_domain_block: \"%{name} је ставио на црну листу домен е-поште %{target}\"\n        demote_user: \"%{name} је ражаловао корисника %{target}\"\n        destroy_custom_emoji: \"%{name} је уништио емоџи %{target}\"\n        destroy_domain_block: \"%{name} је одблокирао домен %{target}\"\n        destroy_email_domain_block: \"%{name} је ставио на белу листу домен е-поште %{target}\"\n        destroy_status: \"%{name} је уклонио статус корисника %{target}\"\n        disable_2fa_user: \"%{name} је искључио обавезну двофакторску идентификацију за корисника %{target}\"\n        disable_custom_emoji: \"%{name} је онемогућио емотикон %{target}\"\n        disable_user: \"%{name} је онемогућио пријављивање кориснику %{target}\"\n        enable_custom_emoji: \"%{name} је омогућио емотикон %{target}\"\n        enable_user: \"%{name} је омогућио пријављивање за корисника %{target}\"\n        memorialize_account: \"%{name} је претворио страну налога %{target} као in memoriam страну\"\n        promote_user: \"%{name} је унапредио корисника %{target}\"\n        remove_avatar_user: \"%{name} је уклонио/ла %{target}'s аватар\"\n        reopen_report: \"%{name} је поново отворио/ла извештај %{target}\"\n        reset_password_user: \"%{name} је ресетовао лозинку кориснику %{target}\"\n        resolve_report: \"%{name} је одбацио пријаву %{target}\"\n        silence_account: \"%{name} је ућуткао налог %{target}\"\n        suspend_account: \"%{name} је суспендовао налог %{target}\"\n        unassigned_report: \"%{name} недодељен извештај %{target}\"\n        unsilence_account: \"%{name} је укинуо ћутање налогу %{target}\"\n        unsuspend_account: \"%{name} је укинуо суспензију налогу %{target}\"\n        update_custom_emoji: \"%{name} је изменио емотикон %{target}\"\n        update_status: \"%{name} је изменио статус корисника %{target}\"\n      deleted_status: \"(обрисан статус)\"\n      title: Записник\n    custom_emojis:\n      by_domain: Домен\n      copied_msg: Успешно направљена локална копија емоџија\n      copy: Копирај\n      copy_failed_msg: Не могу да направим локалну копију тог емотиџија\n      created_msg: Емоџи успешно направљен!\n      delete: Обриши\n      destroyed_msg: Емоџи успешно обрисан!\n      disable: Онемогући\n      disabled_msg: Емоџи успешно онемогућен\n      emoji: Емоџи\n      enable: Омогући\n      enabled_msg: Емоџи успешно омогућен\n      image_hint: PNG до 50KB\n      listed: Излистан\n      new:\n        title: Додај нови произвољни емоџи\n      overwrite: Препиши\n      shortcode: Пречица\n      shortcode_hint: Најмање 2 карактера, дозвољени су само слова, бројеви и доње црте\n      title: Произвољни емотиџији\n      unlisted: Неизлистан\n      update_failed_msg: Не могу да ажурирам овај емоџи\n      updated_msg: Емоџи успешно ажуриран!\n      upload: Отпреми\n    dashboard:\n      backlog: Позадински записи\n      config: Конфигурација\n      feature_deletions: Брисање налога\n      feature_invites: Позивнице\n      feature_profile_directory: Фасцикла профила\n      feature_registrations: Регистрација\n      feature_relay: Федеративни релеј\n      features: Карактеристике\n      hidden_service: Федерација са скривеним услугама\n      open_reports: отворене пријаве\n      recent_users: Недавни корисници\n      search: Потпуна претрага текста\n      single_user_mode: Појединачни корисник\n      software: Софтвер\n      space: Коришћење простора\n      title: Командна табла\n      total_users: укупан број корисника\n      trends: Трендови\n      week_interactions: интеракције ове недеље\n      week_users_active: активно ове недеље\n      week_users_new: корисника ове недеље\n    domain_blocks:\n      add_new: Додај нови блок домена\n      created_msg: Блокирање домена се обрађује\n      destroyed_msg: Блокирање домена је опозвано\n      domain: Домен\n      new:\n        create: Направи блокаду\n        hint: Блокирање домена неће спречити прављење налога у бази, али ће ретроактивно и аутоматски применити одређене модераторске методе над тим налозима.\n        severity:\n          desc_html: \"<strong>Ућуткавање</strong> ће све статусе овог налога учинити невидљивим за све, осим за оне који већ прате налог. <strong>Суспензија</strong> ће уклонити сав садржај налога, сву мултимедију, и профилне податке. Користите <strong>Ништа</strong> само ако желите да одбаците мултимедијалне фајлове.\"\n          noop: Ништа\n          silence: Ућуткавање\n          suspend: Суспензија\n        title: Ново блокирање домена\n      reject_media: Одбаци мултимедију\n      reject_media_hint: Уклања локално ускладиштене мултимедијске фајлове и одбија да их скида убудуће. Небитно је за суспензију\n      reject_reports: Одбаци извештај\n      reject_reports_hint: Игнориши све извештаје који долазе са овог домена. Небитно је за суспензије\n      rejecting_media: одбацивање медијских датотека\n      rejecting_reports: одбацивање пријава\n      severity:\n        silence: ућуткани\n        suspend: суспендовани\n      show:\n        affected_accounts:\n          few: Утиче на %{count} налога у бази\n          one: Један налог у бази података је под утицајем\n          other: Утиче на %{count} налога у бази података\n        retroactive:\n          silence: Угаси ућуткивање за све постојеће налоге са овог домена\n          suspend: Уклони суспензије за све постојеће налоге са овог домена\n        title: Поништи блокаду домена за %{domain}\n        undo: Поништи\n      undo: Поништи блок домена\n    email_domain_blocks:\n      add_new: Додај нови\n      created_msg: Успешно додао домен Е-поште на црну листу\n      delete: Обриши\n      destroyed_msg: Успешно уклоњен домен Е-поште са црне листе\n      domain: Домен\n      new:\n        create: Додај домен\n        title: Нова ставка е-поштe у црној листи\n      title: Црна листа E-поште\n    followers:\n      back_to_account: Назад на налог\n      title: \"%{acct} Пратиоци\"\n    instances:\n      delivery_available: Достава је доступна\n      known_accounts:\n        few: \"%{count} знаних налога\"\n        one: \"%{count} знан налог\"\n        other: \"%{count} знаних налога\"\n      moderation:\n        all: Све\n        limited: Ограничено\n        title: Модерација\n      title: Федерација\n      total_blocked_by_us: Блокирано од стране нас\n      total_followed_by_them: Праћени од стране њих\n      total_followed_by_us: Праћени од стране нас\n      total_reported: Пријаве везане за њих\n    invites:\n      deactivate_all: Деактивирај све\n      filter:\n        all: Све\n        available: Доступни\n        expired: Истекли\n        title: Филтер\n      title: Позивнице\n    relays:\n      add_new: Додај нови релеј\n      delete: Обриши\n      description_html: \"<strong>Федерални релеј</strong> је посреднички сервер који размењује велике количине јавних труба између сервера на који је претплаћен и на који објављује.<strong>Може помоћи малим и средњим серверима да открију садржај из федиверса</strong>, који иначе захтева од локалних корисника да ручно пратити остале људе на удаљеним серверима.\"\n      disable: Искључи\n      disabled: Искључен\n      enable: Укључи\n      enable_hint: Када се омогући, Ваш сервер ће бити претплаћен на све јавне трубе са овог релеја, и почеће да шаље своје јавне трубу на њега.\n      enabled: Укључен\n      inbox_url: URL Релеја\n      pending: Чека се одобрење релеја\n      save_and_enable: Сачувај и омогући\n      setup: Подеси везу релеја\n      status: Статус\n      title: Релеји\n    report_notes:\n      created_msg: Белешка пријаве успешно направљена!\n      destroyed_msg: Белешка пријаве успешно избрисана!\n    reports:\n      account:\n        note: белешка\n        report: извештај\n      action_taken_by: Акцију извео\n      are_you_sure: Да ли сте сигурни?\n      assign_to_self: Додели мени\n      assigned: Додељени модератор\n      comment:\n        none: Ништа\n      created_at: Пријављена\n      mark_as_resolved: Означи као решену\n      mark_as_unresolved: Означи као нерешену\n      notes:\n        create: Додај белешку\n        create_and_resolve: Реши са белешком\n        create_and_unresolve: Отвори поново са белешком\n        delete: Обриши\n        placeholder: Опишите какве су радње предузете, или било какве повезане новости...\n      reopen: Отвори пријаву поново\n      report: 'Пријава #%{id}'\n      reported_account: Пријављени налог\n      reported_by: Пријавио\n      resolved: Решена\n      resolved_msg: Пријава успешно разрешена!\n      status: Статус\n      title: Пријаве\n      unassign: Уклони доделу\n      unresolved: Нерешене\n      updated_at: Ажурирана\n    settings:\n      activity_api_enabled:\n        desc_html: Бројеви локално објављених статуса, активних корисника и нових регистрација по недељама\n        title: Објављуј агрегиране статистике о корисничким активностима\n      bootstrap_timeline_accounts:\n        desc_html: Одвојите више корисничких имена зарезом. Ради само за локалне и откључане налоге. Ако је празно, онда се односи на све локалне администраторе.\n        title: Налози за аутоматско запраћивање за нове кориснике\n      contact_information:\n        email: Пословна е-пошта\n        username: Контакт корисничко име\n      custom_css:\n        desc_html: Промени изглед на свакој страни када се CSS учита\n        title: Произвољни CSS\n      hero:\n        desc_html: Приказано на почетној страни. Препоручено је бар 600х100рх. Када се не одреди, враћа се на иконицу инстанце\n        title: Лого слика\n      mascot:\n        desc_html: Приказано на више страна. Препоручено је бар 293×205px. Када није постављена, користи се подразумевана маскота\n        title: Слика маскоте\n      peers_api_enabled:\n        desc_html: Имена домена које је ова инстанца срела у федиверсу\n        title: Објављуј списак откривених инстанци\n      preview_sensitive_media:\n        desc_html: Преглед веза на другим веб страницама ће приказати иконицу чак и ако је медиј означен као осетљиво\n        title: Покажи осетљив медиј у ОпенГраф прегледу\n      profile_directory:\n        desc_html: Дозволи корисницима да буду откривени\n        title: Омогући профил фасцикле\n      registrations:\n        closed_message:\n          desc_html: Приказује се на главној страни када је инстанца затворена за регистрације. Можете користити HTML тагове\n          title: Порука о затвореној регистрацији\n        deletion:\n          desc_html: Дозволи свима да могу да обришу свој налог\n          title: Отвори брисање налога\n        min_invite_role:\n          disabled: Нико\n          title: Само преко позивнице\n      show_known_fediverse_at_about_page:\n        desc_html: Када се упали, показаће трубе из свих знаних федиверса на преглед. У супротном ће само показати локалне трубе.\n        title: Покажи познате здружене инстанце у прегледнику временске линије\n      show_staff_badge:\n        desc_html: Прикажи беџ особља на корисничкој страни\n        title: Прикажи беџ особља\n      site_description:\n        desc_html: Уводни пасус на насловној страни и у meta HTML таговима. Можете користити HTML тагове, конкретно <code>&lt;a&gt;</code> и <code>&lt;em&gt;</code>.\n        title: Опис инстанце\n      site_description_extended:\n        desc_html: Добро место за ваш код понашања, правила, смернице и друге ствари по којима се Ваша инстанца разликује. Можете користити HTML тагове\n        title: Произвољне додатне информације\n      site_short_description:\n        desc_html: Приказано у изборнику са стране и у мета ознакама. Опиши шта је Мастодон и шта чини овај сервер посебним у једном пасусу. Ако остане празно, вратиће се првобитни опис инстанце.\n        title: Кратак опис инстанце\n      site_terms:\n        desc_html: Можете писати Вашу политику приватности, услове коришћења и остале легалне ствари. Можете користити HTML тагове\n        title: Произвољни услови коришћења\n      site_title: Име инстанце\n      thumbnail:\n        desc_html: Користи се за прегледе кроз OpenGraph и API. Препоручује се 1200x630px\n        title: Сличица инстанце\n      timeline_preview:\n        desc_html: Прикажи јавну лајну на почетној страни\n        title: Преглед лајне\n      title: Поставке сајта\n    statuses:\n      back_to_account: Назад на страну налога\n      batch:\n        delete: Обриши\n        nsfw_off: NSFW искључен\n        nsfw_on: NSFW укључен\n      failed_to_execute: Неуспело извршавање\n      media:\n        title: Мултимедија\n      no_media: Без мултимедије\n      no_status_selected: Ниједан статус није промењен јер ниједан није изабран\n      title: Статуси налога\n      with_media: Са мултимедијом\n    subscriptions:\n      confirmed: Потврђено\n      expires_in: Истиче за\n      last_delivery: Последња достава\n    tags:\n      accounts: Налози\n      hidden: Скривено\n      hide: Сакриј од фасцикле\n      name: Тараба\n      title: Тараба\n      unhide: Прикажи у фасцикли\n      visible: Видљиво\n    title: Администрација\n    warning_presets:\n      add_new: Додај нови\n      delete: Избриши\n      edit: Уреди\n      edit_preset: Уреди пресет упозорења\n      title: Управљај пресетима упозорења\n  admin_mailer:\n    new_report:\n      body: \"%{reporter} је пријавио %{target}\"\n      body_remote: Нека са домена %{domain} је пријавио %{target}\n      subject: Нова пријава за %{instance} (#%{id})\n  application_mailer:\n    notification_preferences: Промени преференце Е-поште\n    settings: 'Промени подешавања е-поште: %{link}'\n    view: 'Погледај:'\n    view_profile: Погледај профил\n    view_status: Погледај статус\n  applications:\n    created: Апликација успешно направљена\n    destroyed: Апликација успешно обрисана\n    invalid_url: Дата адреса није исправна\n    regenerate_token: Рекреирај приступни токен\n    token_regenerated: Приступни токен успешно рекреиран\n    warning: Опрезно са овим подацима. Никад је не делите ни са ким!\n    your_token: Ваш приступни токен\n  auth:\n    change_password: Лозинка\n    confirm_email: Потврдите адресу е-поште\n    delete_account: Обриши налог\n    delete_account_html: Ако желите да обришете Ваш налог, можете <a href=\"%{path}\">наставити овде</a>. Бићете упитани да потврдите.\n    didnt_get_confirmation: Нисте добили поруку са упутствима за потврду налога?\n    forgot_password: Заборавили сте лозинку?\n    invalid_reset_password_token: Токен за ресетовање лозинке је неисправан или је истекао. Затражите нови.\n    login: Пријави се\n    logout: Одјава\n    migrate_account: Помери у други налог\n    migrate_account_html: Ако желите да преусмерите овај налог на неки други, можете то <a href=\"%{path}\">подесити овде</a>.\n    or_log_in_with: Или се пријавите са\n    providers:\n      cas: CAS-ом\n      saml: SAML-ом\n    register: Региструј се\n    resend_confirmation: Пошаљи поруку са упутствима о потврди налога поново\n    reset_password: Ресетуј лозинку\n    security: Безбедност\n    set_new_password: Постави нову лозинку\n  authorize_follow:\n    already_following: Већ пратите овај налог\n    error: Нажалост, десила се грешка при тражењу удаљеног налога\n    follow: Запрати\n    follow_request: 'Послали сте захтев за праћењен за:'\n    following: 'Сјајно! Сада пратите:'\n    post_follow:\n      close: Или можете затворити овај прозор.\n      return: Врати се на профил овог корисника\n      web: Иди на веб\n    title: Запрати %{acct}\n  datetime:\n    distance_in_words:\n      about_x_months: \"%{count}месец\"\n      about_x_years: \"%{count}год\"\n      almost_x_years: \"%{count}год\"\n      half_a_minute: Управо сад\n      less_than_x_seconds: Управо сад\n      over_x_years: \"%{count}год\"\n      x_days: \"%{count}д\"\n      x_months: \"%{count}месец\"\n  deletes:\n    bad_password_msg: Добар покушај, хакери! Неисправна лозинка\n    confirm_password: Унесите тренутну лозинку да бисмо проверили Ваш идентитет\n    description_html: Ово ће <strong>трајно, бесповратно</strong> уклонити садржај са Вашеф налога и деактивирати га. Ваше корисничко име ће остати резервисано да се спречи да се неко не представља као Ви сутра.\n    proceed: Обриши налог\n    success_msg: Ваш налог је успешно обрисан\n    warning_html: Гарантовано је само брисање садржаја са ове инстанце. Садржај који је дељен даље ће вероватно да остави неке трагове. Недоступни и угашени сервери, као и сервери који су одјављени од примања статуса од Вас, неће ажурирати своје базе.\n    warning_title: Доступност расејаног садржаја\n  directories:\n    directory: Профил фасцикле\n    enabled: Ви сте тренутно видљиви у фасцикли.\n    explanation: Откријте кориснике на основу њихових интереса\n    explore_mastodon: Истражи %{title}\n    people:\n      few: \"%{count} људе\"\n      one: \"%{count} особа/е\"\n      other: \"%{count} људи\"\n  errors:\n    '403': Немате дозвола да видите ову страну.\n    '404': Страна коју сте тражили не постоји.\n    '410': Страна коју сте тражили више не постоји.\n    '422':\n      content: Безбедоносна провера није успела. Да не блокирате колачиће?\n      title: Безбедоносна провера није успела\n    '429': Успоред\n    '500':\n      content: Извињавамо се, нешто је пошло по злу са ове стране.\n      title: Страна није исправна\n    noscript_html: Да бисте користили Мастодонт веб апликацију, омогућите JavaScript. У супротном, пробајте неку од <a href=\"%{apps_path}\">оригиналних апликација</a> за Мастодонт за Вашу платформу.\n  exports:\n    archive_takeout:\n      date: Датум\n      download: Преузмите Вашу архиву\n      hint_html: Можете затражити архиву ваших <strong>труба и отпремљених медија</strong>. Извезени подаци ће бити у АктивитиПаб формату, који можете читати са било којим усаглашеним софтвером. Архиву можете затражити сваких 7 дана.\n      in_progress: Састављање ваше архиве...\n      request: Затражите Вашу архиву\n      size: Величина\n    blocks: Блокирали сте\n    domain_blocks: Блокови домена\n    follows: Пратите\n    lists: Листе\n    mutes: Ућуткали сте\n    storage: Мултимедијално складиште\n  filters:\n    contexts:\n      home: Временска линија почетне\n      notifications: Обавештења\n      public: Јавна временска линија\n      thread: Разговори\n    edit:\n      title: Измени филтер\n    errors:\n      invalid_context: Ниједан или неважећи контекст испоручен\n      invalid_irreversible: Неповратно филтрирање функционише само са почетном или контекстом обавештења\n    index:\n      delete: Избриши\n      title: Филтери\n    new:\n      title: Додај нови филтер\n  footer:\n    developers: Програмери\n    more: Више…\n    resources: Ресурси\n  generic:\n    changes_saved_msg: Измене успешно сачуване!\n    copy: Копирај\n    save_changes: Сними измене\n    validation_errors:\n      few: Нешто није баш како треба! Прегледајте %{count} грешке испод\n      one: Нешто није баш како треба! Прегледајте грешке испод\n      other: Нешто није баш како треба! Прегледајте %{count} грешака испод\n  imports:\n    preface: Можете увести податке које сте извезли са друге инстанце, као што су листе људи које сте пратили или блокирали.\n    success: Ваши подаци су успешно отпремљени и биће обрађени ускоро\n    types:\n      blocking: Листа блокирања\n      following: Листа пратилаца\n      muting: Листа ућутканих\n    upload: Отпреми\n  invites:\n    delete: Деактивирај\n    expired: Истекло\n    expires_in:\n      '1800': 30 минута\n      '21600': 6 сати\n      '3600': 1 сад\n      '43200': 12 сати\n      '604800': 1 недеља\n      '86400': 1 дан\n    expires_in_prompt: Никад\n    generate: Генериши\n    invited_by: 'Позвао Вас је:'\n    max_uses:\n      few: \"%{count} коришћења\"\n      one: 1 коришћење\n      other: \"%{count} коришћења\"\n    max_uses_prompt: Без ограничења\n    prompt: Генериши и подели линкове са другима да им одобрите приступ овој инстанци\n    table:\n      expires_at: Истиче\n      uses: Коришћења\n    title: Позовите људе\n  lists:\n    errors:\n      limit: Достигли сте лимит броја листи\n  media_attachments:\n    validations:\n      images_and_video: Не може да се прикачи видео на статус који већ има слике\n      too_many: Не може се прикачити више од 4 фајла\n  migrations:\n    acct: корисник@домен новог налога\n    currently_redirecting: 'Профил Вам је подешен да преусмерава на :'\n    proceed: Сачувај\n    updated_msg: Пребацивање поставки Вашег налога успешно измењено!\n  moderation:\n    title: Модерација\n  notification_mailer:\n    digest:\n      action: Погледајте сва обавештења\n      body: Ево кратак преглед порука које сте пропустили од последње посете од %{since}\n      mention: \"%{name} Вас је поменуо у:\"\n      new_followers_summary:\n        few: Добили сте %{count} нова пратиоца! Сјајно!\n        one: Добили сте једног новог пратиоца! Јеее!\n        other: Добили сте %{count} нових пратиоца! Сјајно!\n      subject:\n        few: \"%{count} нова обавештења од последње посете \\U0001F418\"\n        one: \"1 ново обавештење од последње посете \\U0001F418\"\n        other: \"%{count} нових обавештења од последње посете \\U0001F418\"\n      title: Док нисте били ту...\n    favourite:\n      body: \"%{name} је поставио као омиљен Ваш статус:\"\n      subject: \"%{name} је поставио као омиљен Ваш статус\"\n      title: Нови омиљени\n    follow:\n      body: \"%{name} Вас је запратио!\"\n      subject: \"%{name} Вас је запратио\"\n      title: Нови пратиоц\n    follow_request:\n      action: Управљајте захтевима за праћење\n      body: \"%{name} је затражио да Вас запрати\"\n      subject: 'Пратиоци на чекању: %{name}'\n      title: Нови захтев за праћење\n    mention:\n      action: Одговори\n      body: \"%{name} Вас је поменуо у:\"\n      subject: \"%{name} Вас је поменуо\"\n      title: Ново спомињање\n    reblog:\n      body: \"%{name} Вам је подржао/ла статус:\"\n      subject: \"%{name} је подржао/ла Ваш статус\"\n      title: Нова подршка\n  pagination:\n    newer: Новије\n    next: Следеће\n    older: Старије\n    prev: Претходни\n  preferences:\n    other: Остало\n  remote_follow:\n    acct: Унесите Ваш корисник@домен са кога желите да пратите\n    missing_resource: Не могу да нађем захтевану адресу преусмеравања за Ваш налог\n    no_account_html: Немате налог? Можете се <a href='%{sign_up_path}' target='_blank'>пријавити овде</a>\n    proceed: Наставите да би сте запратили\n    prompt: 'Запратићете:'\n    reason_html: \"<strong>Зашто је овај корак неопходан?</strong><code>%{instance}</code> можда није сервер на којем сте регистровани, тако да прво морамо да вас преусмеримо на ваш сервер.\"\n  remote_interaction:\n    reblog:\n      proceed: Наставите да бисте поделили\n      prompt: 'Желите да делите ову трубу:'\n    reply:\n      proceed: Наставите да бисте одговорили\n      prompt: 'Желите да одговорите на ову трубу:'\n  remote_unfollow:\n    error: Грешка\n    title: Наслов\n    unfollowed: Отпраћени\n  scheduled_statuses:\n    over_daily_limit: Прекорачили сте границу од %{limit} планираних труба за тај дан\n    over_total_limit: Прекорачили сте границу од %{limit} планираних труба\n    too_soon: Планирани датум мора бити у будућности\n  sessions:\n    activity: Последња активност\n    browser: Веб читач\n    browsers:\n      alipay: Алипеј\n      blackberry: Блекберија\n      chrome: Хром\n      edge: Мајкрософт Еџ\n      electron: Електрон\n      firefox: Фајерфокс\n      generic: Непознати веб читач\n      ie: Интернет Експлорер\n      micro_messenger: МајкроМесенџер\n      nokia: Нокија С40 Ови Претраживач\n      opera: Опера\n      otter: Отер\n      phantom_js: ФантомЏејЕс\n      qq: КјуКју Претраживач\n      safari: Сафари\n      uc_browser: УЦПретраживач\n      weibo: Веибо\n    current_session: Тренутна сесија\n    description: \"%{browser} са %{platform}\"\n    explanation: Ово су веб претраживачи који су тренутно пријављени на Ваш Мастодон налог.\n    platforms:\n      adobe_air: Адоб Ер-а\n      android: Андроида\n      blackberry: Блекберија\n      chrome_os: Хром ОС-а\n      firefox_os: Фајерфокс ОС-а\n      ios: иОС-а\n      linux: Линукса\n      mac: Мека\n      other: непознате платформе\n      windows: Виндоуза\n      windows_mobile: Виндоуз мобилног\n      windows_phone: Виндоуз телефона\n    revoke: Опозови\n    revoke_success: Сесија успешно опозвана\n    title: Сесије\n  settings:\n    authorized_apps: Ауторизоване апликације\n    back: Назад на Мастодон\n    delete: Брисање налога\n    development: Развој\n    edit_profile: Измена профила\n    export: Извоз података\n    import: Увоз\n    migrate: Пребацивање налога\n    notifications: Обавештења\n    preferences: Подешавања\n    two_factor_authentication: Двофакторска идентификација\n  statuses:\n    attached:\n      description: 'У прилогу: %{attached}'\n      image:\n        few: \"%{count} слика\"\n        one: \"%{count} слику\"\n        other: \"%{count} слика\"\n      video:\n        few: \"%{count} видео записа\"\n        one: \"%{count} видео запис\"\n        other: \"%{count} видео записа\"\n    boosted_from_html: Подржано од %{acct_link}\n    content_warning: 'Упозорење на садржај: %{warning}'\n    disallowed_hashtags:\n      few: 'садржи забрањене хештегове: %{tags}'\n      one: 'садржи забрањени хештег: %{tags}'\n      other: 'садржи забрањене хештегове: %{tags}'\n    language_detection: Аутоматскo откривање језика\n    open_in_web: Отвори у вебу\n    over_character_limit: ограничење од %{max} карактера прекорачено\n    pin_errors:\n      limit: Већ имате прикачен највећи број труба\n      ownership: Туђе трубе не могу да се прикаче\n      private: Трубе које нису јавне не могу бити прикачене\n      reblog: Подршка не може да се прикачи\n    show_more: Прикажи још\n    sign_in_to_participate: Пријавите се да учествујете у разговору\n    visibilities:\n      private: Само пратиоци\n      private_long: Прикажи само пратиоцима\n      public: Јавно\n      public_long: Свако може да види\n      unlisted: Неизлистано\n      unlisted_long: Свако може да види, али није излистано на јавним временским линијама\n  stream_entries:\n    pinned: Прикачена труба\n    reblogged: подржано\n    sensitive_content: Осетљив садржај\n  terms:\n    title: Услови коришћења и политика приватности инстанце %{instance}\n  themes:\n    contrast: Велики контраст\n    default: Мастодон\n    mastodon-light: Мастодон (светло)\n  two_factor_authentication:\n    code_hint: Да бисте потврдили, унесите код генерисан од стране ваше апликације за потврду идентитета\n    description_html: Ако укључите <strong>двофакторску идентификацију</strong>, мораћете да имате телефон са собом да бисте могли да се пријавите. Телефон ће онда генерисати токене за Вашу пријаву.\n    disable: Искључи\n    enable: Омогући\n    enabled: Двофакторска идентификација је укључена\n    enabled_success: Двофакторска идентификација је успешно укључена\n    generate_recovery_codes: Генериши кодове за опоравак\n    instructions_html: \"<strong>Скенирајте овај QR код у Google Authenticator или некој сличној TOTP апликацији на Вашем телефону</strong>. Од сада, та апликација ће Вам генерисати токене које морате унети да бисте се пријавили.\"\n    lost_recovery_codes: Кодови за опоравак Вам омогућавају да повратите приступ налогу ако изгубите телефон. Ако изгубите кодове за опоравак, можете их ре-генерисати овде. Од тог тренутка, стари кодови за опоравак више не важе.\n    manual_instructions: 'Уколико не можете да скенирате QR код и морате га унесете ручно, ево је огољена шифра:'\n    recovery_codes: Направите резерву кодова за опоравак\n    recovery_codes_regenerated: Кодови за опоравак успешно ре-генерисани\n    recovery_instructions_html: Ако икада изгубите приступ телефону, можете искористити кодове за опоравак дате испод да повратите приступ налогу. <strong>Држите кодове за опоравак на сигурном</strong>. На пример, одштампајте их и чувајте их са осталим важним документима.\n    setup: Намештање\n    wrong_code: Унесени код није исправан! Да ли су времена на серверу и на уређају исправна?\n  user_mailer:\n    backup_ready:\n      explanation: Тражили сте потпуну резервну копију вашег Мастодон рачуна. Спремна за преузимање!\n      subject: Ваша архива је спремна за преузимање\n      title: Извоз архиве\n    warning:\n      explanation:\n        disable: Док је ваш рачун замрзнут, подаци о вашем рачуну остају нетакнути, али не можете вршити никакве радње док се не откључа.\n        silence: Иако је ваш налог ограничен, само људи који вас већ прате ће видети ваше трубе на овом серверу, и можда ћете бити искључени из различитих јавних листа. Међутим, други вас могу и даље ручно пратити.\n        suspend: Ваш налог је суспендован, а све ваше трубе и учитане медијске датотеке неповратно су уклоњени са овог сервера и сервера на којима сте имали следбенике.\n      review_server_policies: Прегледај политику сервера\n      subject:\n        disable: Ваш налог %{acct} је замрзнут\n        none: Упозорење за %{acct}\n        silence: Ваш налог %{acct} је ограничен\n        suspend: Ваш налог %{acct} је суспендован\n      title:\n        disable: Налог замрзнут\n        none: Упозорење\n        silence: Налог ограничен\n        suspend: Налог суспендован\n    welcome:\n      edit_profile_action: Подеси профил\n      edit_profile_step: Профил можете прилагодити постављањем аватара, заглавља, променом имена и још много тога. Ако желите да прегледате нове пратиоце пре него што буду дозвољени да вас прате, можете закључати свој налог.\n      explanation: Ево неколико савета за почетак\n      final_action: Почните објављивати\n      final_step: 'Почните објављивати! Чак и без пратиоца ваше јавне поруке ће бити виђене од стране других, нпр. на локалној јавног линији и у тараба за означавање. Можда бисте желели да се представите у #увод тараби за означавање.'\n      full_handle: Ваш пун надимак\n      full_handle_hint: Ово бисте рекли својим пријатељима како би вам они послали поруку, или запратили са друге инстанце.\n      review_preferences_action: Промените подешавања\n      review_preferences_step: Обавезно поставите своја подешавања, као што су какву Е-пошту желите да примите или на који ниво приватности желите да ваше поруке буду постављене. Ако немате морску болест или епилепсију, можете изабрати аутоматско покретање ГИФ-а.\n      subject: Добродошли на Мастодон\n      tip_federated_timeline: Здружена временска линија пружа комплетан увид у Мастодонову мрежу. Али она само укључује људе на које су ваше комшије претплаћене, тако да није комплетна.\n      tip_following: Аутоматски пратите админа/не вашег сервера. Да пронађете занимљиве људе, проверите локалне и здружене временске линије.\n      tip_local_timeline: Локална временска линија је комплетан увид људи у %{instance}.  Ово су вам прве комшије!\n      tip_mobile_webapp: Ако вам мобилни претраживач предложи да додате Мастодон на Ваш почетни екран, добијаћете мобилна обавештења. Делује као изворна апликација на много начина!\n      tips: Савети\n      title: Добродошли, %{name}!\n  users:\n    follow_limit_reached: Не можете пратити више од %{limit} људи\n    invalid_email: Адреса Е-поште није исправна\n    invalid_otp_token: Неисправни двофакторски код\n    otp_lost_help_html: Ако изгубите приступ за оба, можете ступити у контакт са %{email}\n    seamless_external_login: Пријављени сте путем спољашње услуге, тако да лозинка и подешавања Е-поште нису доступни.\n    signed_in_as: 'Пријављен/а као:'\n  verification:\n    explanation_html: 'Можете <strong>извршити проверу да сте Ви власник веза у Вашем профилу</strong>. Да би то радило, повезани веб сајт мора да садржи везу назад ка Вашем Мастодон профилу. Веза назад <strong>мора</strong> да има <code>rel=\"me\"</code> атрибут. Текстуелни садржај везе није битан. Ево примера:'\n    verification: Провера\n"
  },
  {
    "path": "config/locales/sv.yml",
    "content": "---\nsv:\n  about:\n    about_hashtag_html: Dessa är offentliga toots märkta med <strong>#%{hashtag}</strong>. Du kan interagera med dem om du har ett konto någonstans i federationen.\n    about_mastodon_html: Mastodon är ett socialt nätverk baserat på öppna webbprotokoll och gratis, öppen källkodsprogramvara. Det är decentraliserat som e-post.\n    about_this: Om\n    administered_by: 'Administreras av:'\n    api: API\n    contact: Kontakt\n    contact_missing: Inte inställd\n    extended_description_html: |\n      <h3>En bra plats för regler</h3>\n      <p>Den utökade beskrivningen har inte konfigurerats ännu.</p>\n    generic_description: \"%{domain} är en server i nätverket\"\n    hosted_on: Mastodon värd på %{domain}\n    learn_more: Lär dig mer\n    source_code: Källkod\n    status_count_before: Som skapat\n    terms: Användarvillkor\n    user_count_before: Hem till\n    what_is_mastodon: Vad är Mastodon?\n  accounts:\n    follow: Följa\n    following: Följer\n    media: Media\n    moved_html: \"%{name} har flyttat till %{new_profile_link}:\"\n    network_hidden: Denna information är inte tillgänglig\n    nothing_here: Det finns inget här!\n    people_followed_by: Personer som %{name} följer\n    people_who_follow: Personer som följer %{name}\n    posts_with_replies: Toots med svar\n    reserved_username: Användarnamnet är reserverat\n    roles:\n      moderator: Moderator\n    unfollow: Sluta följa\n  admin:\n    account_moderation_notes:\n      create: Lämna kommentar\n      created_msg: Modereringsnotering skapad utan problem!\n      delete: Ta bort\n      destroyed_msg: Modereringsnotering borttagen utan problem!\n    accounts:\n      are_you_sure: Är du säker?\n      by_domain: Domän\n      change_email:\n        changed_msg: E-postadressen har ändrats!\n        current_email: Nuvarande E-postadress\n        label: Byt E-postadress\n        new_email: Ny E-postadress\n        submit: Byt E-postadress\n        title: Byt E-postadress för %{username}\n      confirm: Bekräfta\n      confirmed: Bekräftad\n      confirming: Bekräftande\n      demote: Degradera\n      disable: inaktivera\n      disable_two_factor_authentication: Inaktivera 2FA\n      disabled: inaktiverad\n      display_name: Visningsnamn\n      domain: Domän\n      edit: Redigera\n      email: E-post\n      email_status: E-poststatus\n      enable: Aktivera\n      enabled: Aktiverad\n      feed_url: Flödes URL\n      followers: Följare\n      followers_url: Följare URL\n      follows: Följs\n      inbox_url: Inkorgs URL\n      location:\n        all: Alla\n        local: Lokal\n        remote: Avlägsen\n        title: Plats\n      login_status: Inloggningsstatus\n      media_attachments: Media bifogade filer\n      memorialize: Förvandla till ett memoriam\n      moderation:\n        all: Alla\n        silenced: Tystas\n        suspended: Avstängd\n        title: Moderering\n      moderation_notes: Moderation anteckning\n      most_recent_activity: Senaste aktivitet\n      most_recent_ip: Senaste IP\n      not_subscribed: Inte prenumererat\n      outbox_url: Utkorg URL\n      perform_full_suspension: Utför full avstängning\n      profile_url: Profil URL\n      promote: Befordra\n      protocol: Protokoll\n      public: Offentlig\n      push_subscription_expires: PuSH-prenumerationen löper ut\n      redownload: Uppdatera avatar\n      remove_avatar: Ta bort avatar\n      resend_confirmation:\n        already_confirmed: Den här användaren är redan bekräftad\n        send: Skicka om e-postbekräftelse\n        success: Bekräftelsemeddelande skickas framgångsrikt!\n      reset: Återställ\n      reset_password: Återställ lösenord\n      resubscribe: Starta en ny prenumeration\n      role: Behörigheter\n      roles:\n        admin: Administratör\n        staff: Personal\n        user: Användare\n      salmon_url: Lax URL\n      search: Sök\n      shared_inbox_url: Delad inkorg URL\n      show:\n        created_reports: Anmälningar som skapats av det här kontot\n        targeted_reports: Anmälningar gjorda om detta konto\n      silence: Tystnad\n      statuses: Status\n      subscribe: Prenumerera\n      title: Konton\n      unconfirmed_email: Obekräftad E-postadress\n      undo_silenced: Ångra tystnad\n      undo_suspension: Ångra avstängning\n      unsubscribe: Avsluta prenumeration\n      username: Användarnamn\n      web: Webb\n    action_logs:\n      actions:\n        assigned_to_self_report: \"%{name} tilldelade anmälan %{target} till sig själv\"\n        change_email_user: \"%{name} bytte e-postadress för användare %{target}\"\n        confirm_user: \"%{name} bekräftade e-postadress för användare %{target}\"\n        create_custom_emoji: \"%{name} laddade upp ny emoji %{target}\"\n        create_domain_block: \"%{name} blockerade domän %{target}\"\n        create_email_domain_block: \"%{name} svartlistade e-postdomän %{target}\"\n        demote_user: \"%{name} degraderade användare %{target}\"\n        destroy_domain_block: \"%{name} avblockerade domän %{target}\"\n        destroy_email_domain_block: \"%{name} vitlistade e-postdomän %{target}\"\n        destroy_status: \"%{name} tog bort status av %{target}\"\n        disable_2fa_user: \"%{name} inaktiverade tvåstegsautentiseringskrav för användare %{target}\"\n        disable_custom_emoji: \"%{name} inaktiverade emoji %{target}\"\n        disable_user: \"%{name} inaktiverade inloggning för användare %{target}\"\n        enable_custom_emoji: \"%{name} aktiverade emoji %{target}\"\n        enable_user: \"%{name} aktiverade inloggning för användare %{target}\"\n        memorialize_account: \"%{name} omvandlade %{target}s konto till en memoriam-sida\"\n        promote_user: \"%{name} flyttade upp användare %{target}\"\n        remove_avatar_user: \"%{name} tog bort %{target}s avatar\"\n        reopen_report: \"%{name} återupptog anmälan %{target}\"\n        reset_password_user: \"%{name} återställde lösenord för användaren %{target}\"\n        resolve_report: \"%{name} löste anmälan %{target}\"\n        silence_account: \"%{name} tystade ner %{target}s konto\"\n        suspend_account: \"%{name} suspenderade %{target}s konto\"\n        unassigned_report: \"%{name} otilldelade anmälan %{target}\"\n        unsilence_account: \"%{name} återljudade %{target}s konto\"\n        unsuspend_account: \"%{name} aktiverade %{target}s konto\"\n        update_custom_emoji: \"%{name} uppdaterade emoji %{target}\"\n        update_status: \"%{name} uppdaterade status för %{target}\"\n      title: Revisionslogg\n    custom_emojis:\n      by_domain: Domän\n      copied_msg: Skapade en lokal kopia av emoji utan problem\n      copy: Kopia\n      copy_failed_msg: Kunde inte skapa en lokal kopia av den emoji\n      created_msg: Emoji skapades utan problem!\n      delete: Radera\n      destroyed_msg: Emojo borttagen utan problem!\n      disable: Inaktivera\n      disabled_msg: Inaktiverade emoji utan problem\n      enable: Aktivera\n      enabled_msg: Aktiverade den emoji utan problem\n      image_hint: PNG upp till 50KB\n      listed: Noterade\n      new:\n        title: Lägg till ny egen emoji\n      overwrite: Skriva över\n      shortcode: Kortkod\n      shortcode_hint: Minst 2 tecken, endast alfanumeriska tecken och understreck\n      title: Egentillverkade emojis\n      unlisted: Olistade\n      update_failed_msg: Kunde inte uppdatera emoji\n      updated_msg: Emoji uppdaterades utan problem!\n      upload: Ladda upp\n    domain_blocks:\n      add_new: Lägg till ny\n      created_msg: Domänblocket behandlas nu\n      destroyed_msg: Domänblockering har återtagits\n      domain: Domän\n      new:\n        create: Skapa block\n        hint: Domänblocket hindrar inte skapandet av kontoposter i databasen, men kommer retroaktivt, automatiskt att tillämpa specifika modereringsmetoder på dessa konton.\n        severity:\n          desc_html: \"<strong>Tysta ner</strong> kommer att göra kontoinlägg osynliga för alla som inte följer dem. <strong>Suspendera</strong> kommer ta bort allt av kontots innehåll, media och profildata. Använd <strong>Ingen</strong> om du bara vill avvisa mediefiler.\"\n          noop: Ingen\n          silence: Tysta ner\n          suspend: Suspendera\n        title: Nytt domänblock\n      reject_media: Avvisa mediafiler\n      reject_media_hint: Raderar lokalt lagrade mediefiler och förhindrar möjligheten att ladda ner något i framtiden. Irrelevant för suspensioner\n      show:\n        affected_accounts:\n          one: Ett konto i databasen drabbades\n          other: \"%{count} konton i databasen har drabbats\"\n        retroactive:\n          silence: Ta bort tysta ner från alla befintliga konton på den här domänen\n          suspend: Ta bort suspendering från alla befintliga konton på den här domänen\n        title: Ångra domänblockering för %{domain}\n        undo: Ångra\n      undo: Ångra\n    email_domain_blocks:\n      add_new: Lägg till ny\n      created_msg: E-postdomän har lagts till i domänblockslistan utan problem\n      delete: Radera\n      destroyed_msg: E-postdomän har tagits bort från domänblockslistan utan problem\n      domain: Domän\n      new:\n        create: Skapa domän\n        title: Ny E-postdomänblocklistningsinmatning\n      title: E-postdomänblock\n    instances:\n      title: Kända instanser\n    invites:\n      filter:\n        all: Alla\n        available: Tillgängliga\n        expired: Utgångna\n        title: Filtrera\n      title: Inbjudningar\n    report_notes:\n      created_msg: Anmälningsanteckning har skapats!\n      destroyed_msg: Anmälningsanteckning har raderats!\n    reports:\n      account:\n        note: anteckning\n        report: anmälan\n      action_taken_by: Åtgärder vidtagna av\n      are_you_sure: Är du säker?\n      assign_to_self: Tilldela till mig\n      assigned: Tilldelad moderator\n      comment:\n        none: Ingen\n      created_at: Anmäld\n      mark_as_resolved: Markera som löst\n      mark_as_unresolved: Markera som olöst\n      notes:\n        create: Lägg till anteckning\n        create_and_resolve: Lös med anteckning\n        create_and_unresolve: Återuppta med anteckning\n        delete: Radera\n        placeholder: Beskriv vilka åtgärder som vidtagits eller andra uppdateringar till den här anmälan.\n      reopen: Återuppta anmälan\n      report: 'Anmäl #%{id}'\n      reported_account: Anmält konto\n      reported_by: Anmäld av\n      resolved: Löst\n      resolved_msg: Anmälan har lösts framgångsrikt!\n      title: Anmälningar\n      unassign: Otilldela\n      unresolved: Olösta\n      updated_at: Uppdaterad\n    settings:\n      activity_api_enabled:\n        desc_html: Räkning av lokalt postade statusar, aktiva användare och nyregistreringar per vecka\n        title: Publicera uppsamlad statistik om användaraktivitet\n      bootstrap_timeline_accounts:\n        desc_html: Separera flera användarnamn med kommatecken. Endast lokala och olåsta konton kommer att fungera. Standard när det är tomt och alla är lokala administratörer.\n        title: Standard att följa för nya användare\n      contact_information:\n        email: Företag E-post\n        username: Användarnamn för kontakt\n      hero:\n        desc_html: Visas på framsidan. Minst 600x100px rekommenderas. Om inte angiven faller den tillbaka på instansens miniatyrbild\n        title: Hjältebild\n      peers_api_enabled:\n        desc_html: Domännamn denna instans har påträffat i fediverse\n        title: Publicera lista över upptäckta instanser\n      registrations:\n        closed_message:\n          desc_html: Visas på framsidan när registreringen är stängd. Du kan använda HTML-taggar\n          title: Stängt registreringsmeddelande\n        deletion:\n          desc_html: Tillåt alla att ta bort sitt konto\n          title: Öppen kontoradering\n        min_invite_role:\n          disabled: Ingen\n          title: Tillåt inbjudningar av\n      show_known_fediverse_at_about_page:\n        desc_html: När den växlas, kommer toots från hela fediverse visas på förhandsvisning. Annars visas bara lokala toots.\n        title: Visa det kända fediverse på tidslinjens förhandsgranskning\n      show_staff_badge:\n        desc_html: Visa en personalbricka på en användarsida\n        title: Visa personalbricka\n      site_description:\n        desc_html: Inledande stycke på framsidan och i metataggar. Du kan använda HTML-taggar, i synnerhet <code>&lt;a&gt;</code> och <code>&lt;em&gt;</code>.\n        title: Instansbeskrivning\n      site_description_extended:\n        desc_html: Ett bra ställe för din uppförandekod, regler, riktlinjer och andra saker som stämmer med din instans. Du kan använda HTML-taggar\n        title: Egentillverkad utökad information\n      site_terms:\n        desc_html: Du kan skriva din egen integritetspolicy, användarvillkor eller andra regler. Du kan använda HTML-taggar\n        title: Egentillverkad villkor för tjänster\n      site_title: Namn på instans\n      thumbnail:\n        desc_html: Används för förhandsgranskningar via OpenGraph och API. 1200x630px rekommenderas\n        title: Instans tumnagelbild\n      timeline_preview:\n        desc_html: Visa offentlig tidslinje på landingsidan\n        title: Förhandsgranska tidslinje\n      title: Sidans inställningar\n    statuses:\n      back_to_account: Tillbaka till kontosidan\n      batch:\n        delete: Radera\n        nsfw_off: Markera som ej känslig\n        nsfw_on: Markera som känslig\n      failed_to_execute: Misslyckades att utföra\n      no_media: Ingen media\n      title: Kontostatus\n      with_media: med media\n    subscriptions:\n      callback_url: Återanrop URL\n      confirmed: Bekräftad\n      expires_in: Utgår om\n      last_delivery: Sista leverans\n      topic: Ämne\n  admin_mailer:\n    new_report:\n      body: \"%{reporter} har rapporterat %{target}\"\n      body_remote: Någon från %{domain} har rapporterat %{target}\n      subject: Ny rapport för %{instance} (#%{id})\n  application_mailer:\n    notification_preferences: Ändra e-postinställningar\n    settings: 'Ändra e-postinställningar: %{link}'\n    view: 'Granska:'\n    view_profile: Visa profil\n    view_status: Visa status\n  applications:\n    created: Ansökan är framgångsrikt skapad\n    destroyed: Ansökan är framgångsrikt borttagen\n    invalid_url: Den angivna webbadressen är ogiltig\n    regenerate_token: Regenerera access token\n    token_regenerated: Access token lyckades regenereras\n    warning: Var mycket försiktig med denna data. Dela aldrig den med någon!\n    your_token: Din access token\n  auth:\n    change_password: Lösenord\n    confirm_email: Bekräfta e-postadress\n    delete_account: Ta bort konto\n    delete_account_html: Om du vill radera ditt konto kan du <a href=\"%{path}\">fortsätta här</a>. Du kommer att bli ombedd att bekräfta.\n    didnt_get_confirmation: Fick inte instruktioner om bekräftelse?\n    forgot_password: Glömt ditt lösenord?\n    invalid_reset_password_token: Lösenordsåterställningstoken är ogiltig eller utgått. Vänligen be om en ny.\n    login: Logga in\n    logout: Logga ut\n    migrate_account: Flytta till ett annat konto\n    migrate_account_html: Om du vill omdirigera detta konto till ett annat, kan du <a href=\"%{path}\">konfigurera det här</a>.\n    or_log_in_with: Eller logga in med\n    providers:\n      cas: CAS\n      saml: SAML\n    register: Registrera\n    resend_confirmation: Skicka instruktionerna om bekräftelse igen\n    reset_password: Återställ lösenord\n    security: Säkerhet\n    set_new_password: Skriv in nytt lösenord\n  authorize_follow:\n    already_following: Du följer redan detta konto\n    error: Tyvärr inträffade ett fel när vi kontrollerade fjärrkontot\n    follow: Följ\n    follow_request: 'Du har skickat en följaförfrågan till:'\n    following: 'Succé! Du följer nu:'\n    post_follow:\n      close: Eller så kan du stänga detta fönster.\n      return: Visa användarens profil\n      web: Gå till webb\n    title: Följ %{acct}\n  datetime:\n    distance_in_words:\n      about_x_hours: \"%{count}tim\"\n      about_x_months: \"%{count}mån\"\n      about_x_years: \"%{count}år\"\n      almost_x_years: \"%{count}år\"\n      half_a_minute: Just nu\n      less_than_x_minutes: \"%{count}min\"\n      less_than_x_seconds: Just nu\n      over_x_years: \"%{count}år\"\n      x_minutes: \"%{count}min\"\n      x_months: \"%{count}mån\"\n      x_seconds: \"%{count}sek\"\n  deletes:\n    bad_password_msg: Bra försök, hackare! Fel lösenord\n    confirm_password: Ange ditt lösenord för att verifiera din identitet\n    description_html: Detta vill <strong>permanent, irreversibelt</strong> ta bort innehåll från ditt konto och avaktivera det. Ditt användarnamn kommer att förbli reserverat för att förhindra framtida efterföljare.\n    proceed: Ta bort konto\n    success_msg: Ditt konto har tagits bort\n    warning_html: Endast borttagning av innehåll från denna speciella instans garanteras. Innehåll som har delats i stor utsträckning kommer sannolikt att lämna spår. Offline-servrar och servrar som har avstängt från dina uppdateringar uppdaterar inte sina databaser.\n    warning_title: Spridet innehåll och tillgänglighet\n  errors:\n    '403': Du har inte behörighet att visa den här sidan.\n    '404': Sidan du letade efter existerar inte.\n    '410': Sidan du letade efter existerar inte längre.\n    '422':\n      content: Säkerhetsverifiering misslyckades Blockerar du cookies?\n      title: Säkerhetsverifiering misslyckades\n    '429': Strypt\n    '500':\n      content: Vi är ledsna, men något gick fel från vårat håll.\n      title: Den här sidan är inte korrekt\n    noscript_html: För att använda Mastodon webbapplikationen, vänligen aktivera JavaScript. Alternativt kan du prova en av <a href=\"%{apps_path}\">inhemska appar</a> för Mastodon för din plattform.\n  exports:\n    archive_takeout:\n      date: Datum\n      download: Ladda ner ditt arkiv\n      hint_html: Du kan begära ett arkiv av dina <strong>toots och uppladdad media</strong>. Den exporterade datan kommer att vara i ActivityPub-format och läsbar av kompatibel programvara. Du kan begära ett arkiv var sjunde dag.\n      in_progress: Kompilerar ditt arkiv...\n      request: Efterfråga ditt arkiv\n      size: Storlek\n    blocks: Du blockerar\n    csv: CSV\n    follows: Du följer\n    mutes: Du tystar\n    storage: Medialagring\n  generic:\n    changes_saved_msg: Ändringar sparades framgångsrikt!\n    save_changes: Spara ändringar\n    validation_errors:\n      one: Något är inte riktigt rätt ännu! Kontrollera felet nedan\n      other: Något är inte riktigt rätt ännu! Kontrollera dom %{count} felen nedan\n  imports:\n    preface: Du kan importera data som du exporterat från en annan instans, till exempel en lista över personer du följer eller blockerar.\n    success: Dina uppgifter har laddats upp och kommer nu att behandlas snarast\n    types:\n      blocking: Lista av blockerade\n      following: Lista av följare\n      muting: Lista av nertystade\n    upload: Ladda upp\n  in_memoriam_html: Till minne av.\n  invites:\n    delete: Avaktivera\n    expired: Utgånget\n    expires_in:\n      '1800': 30 minuter\n      '21600': 6 timmar\n      '3600': 1 timma\n      '43200': 12 timmar\n      '604800': 1 vecka\n      '86400': 1 dag\n    expires_in_prompt: Aldrig\n    generate: Skapa\n    invited_by: 'Du blev inbjuden av:'\n    max_uses:\n      one: 1 användning\n      other: \"%{count} användningar\"\n    max_uses_prompt: Ingen gräns\n    prompt: Skapa och dela länkar med andra för att ge tillgång till denna instans\n    table:\n      expires_at: Utgår\n      uses: Användningar\n    title: Bjud in andra\n  lists:\n    errors:\n      limit: Du har nått det maximala antalet listor\n  media_attachments:\n    validations:\n      images_and_video: Det går inte att bifoga en video till en status som redan innehåller bilder\n      too_many: Det går inte att bifoga mer än 4 filer\n  migrations:\n    acct: användarnamn@domän av det nya kontot\n    currently_redirecting: 'Din profil är satt att omdirigeras till:'\n    proceed: Spara\n    updated_msg: Dina kontoflyttsinställning har uppdaterats!\n  moderation:\n    title: Moderera\n  notification_mailer:\n    digest:\n      action: Visa alla notifieringar\n      body: Här är en kort sammanfattning av de meddelanden du missade sedan ditt senaste besök på %{since}\n      mention: \"%{name} nämnde dig i:\"\n      new_followers_summary:\n        one: Du har också förvärvat en ny följare! Jippie!\n        other: Du har också fått %{count} nya följare medans du var iväg! Otroligt!\n      subject:\n        one: \"1 nytt meddelande sedan ditt senaste besök \\U0001F418\"\n        other: \"%{count} nya meddelanden sedan ditt senaste besök \\U0001F418\"\n      title: I din frånvaro...\n    favourite:\n      body: 'Din status favoriserades av %{name}:'\n      subject: \"%{name} favoriserade din status\"\n      title: Ny favorit\n    follow:\n      body: \"%{name} följer nu dig!\"\n      subject: \"%{name} följer nu dig\"\n      title: Ny följare\n    follow_request:\n      action: Hantera följefterfrågningar\n      body: \"%{name} har begärt att följa dig\"\n      subject: 'Väntande följare: %{name}'\n      title: Ny följefterfrågning\n    mention:\n      action: Svar\n      body: 'Du nämndes av %{name} in:'\n      subject: Du nämndes av %{name}\n      title: Ny omnämning\n    reblog:\n      body: 'Din status knuffades av %{name}:'\n      subject: \"%{name} knuffade din status\"\n      title: Ny knuff\n  pagination:\n    newer: Nyare\n    next: Nästa\n    older: Äldre\n    prev: Tidigare\n  preferences:\n    other: Annat\n  remote_follow:\n    acct: Ange ditt användarnamn@domän du vill följa från\n    missing_resource: Det gick inte att hitta den begärda omdirigeringsadressen för ditt konto\n    proceed: Fortsätt för att följa\n    prompt: 'Du kommer att följa:'\n  remote_unfollow:\n    error: Fel\n    title: Titel\n    unfollowed: Slutade följa\n  sessions:\n    activity: Senaste aktivitet\n    browser: Webbläsare\n    browsers:\n      edge: Microsoft Edge\n      electron: Electron\n      firefox: Firefox\n      generic: Okänd browser\n      ie: Internet Explorer\n      micro_messenger: MicroMessenger\n      opera: Opera\n      otter: Otter\n      phantom_js: PhantomJS\n      safari: Safari\n    current_session: Nuvarande session\n    description: \"%{browser} på %{platform}\"\n    explanation: Detta är inloggade webbläsare på Mastodon just nu.\n    ip: IP\n    platforms:\n      adobe_air: Adobe Air\n      android: Android\n      blackberry: Blackberry\n      chrome_os: ChromeOS\n      firefox_os: Firefox OS\n      ios: iOS\n      linux: Linux\n      mac: Mac\n      other: okänd plattform\n      windows: Windows\n    revoke: Återkalla\n    revoke_success: Sessionen återkallas framgångsrikt\n    title: Sessioner\n  settings:\n    authorized_apps: Godkända appar\n    back: Tillbaka till Mastodon\n    delete: Konto radering\n    development: Utveckling\n    edit_profile: Redigera profil\n    export: Exportera data\n    migrate: Kontoflytt\n    notifications: Meddelanden\n    preferences: Inställningar\n    two_factor_authentication: Tvåstegsautentisering\n  statuses:\n    attached:\n      description: 'Bifogad: %{attached}'\n      image:\n        one: \"%{count} bild\"\n        other: \"%{count} bilder\"\n    boosted_from_html: Boosted från %{acct_link}\n    content_warning: 'Innehållsvarning: %{warning}'\n    disallowed_hashtags:\n      one: 'innehöll en otillåten hashtag: %{tags}'\n      other: 'innehöll de otillåtna hashtagarna: %{tags}'\n    language_detection: Lista ut språk automatiskt\n    open_in_web: Öppna på webben\n    over_character_limit: teckengräns på %{max} har överskridits\n    pin_errors:\n      limit: Du har redan fäst det maximala antalet toots\n      ownership: Någon annans toot kan inte fästas\n      private: Icke-offentliga toot kan inte fästas\n      reblog: Knuffar kan inte fästas\n    show_more: Visa mer\n    visibilities:\n      private: Endast följare\n      private_long: Visa endast till följare\n      public: Offentlig\n      public_long: Alla kan se\n      unlisted: Olistade\n      unlisted_long: Alla kan se, men listas inte på offentliga tidslinjer\n  stream_entries:\n    pinned: Fäst toot\n    reblogged: boostad\n    sensitive_content: Känsligt innehåll\n  terms:\n    body_html: |\n      <h2>Integritetspolicy</h2>\n      <h3 id=\"collect\">Vilken information samlar vi in?</h3>\n\n      <ul>\n      <li><em>Grundläggande kontoinformation</em>: Det användarnamn du väljer, visningsnamn, biografi, avatar/profilbild och bakgrundsbild kommer alltid vara tillgängliga för alla som kan nå webbsidan. </li>\n      <li><em>Inlägg, vem du följer och annan tillgänglig information</em>: Dina följare och de konton du följer är alltid tillgängliga. När du skapar ett nytt inlägg sparas datum och tid för meddelandet, samt vilket program du använde för att skapa inlägget. Detta gäller även bilder och media som inlägg kan innehålla.Både \"Publika\" och \"Olistade\" inlägg kan vara tillgängliga för alla som har åtkomst till webbsidan. When you feature a post on your profile, that is also publicly available information. Your posts are delivered to your followers, in some cases it means they are delivered to different servers and copies are stored there. When you delete posts, this is likewise delivered to your followers. The action of reblogging or favouriting another post is always public.</li>\n      <li><em>Direct and followers-only posts</em>: All posts are stored and processed on the server. Followers-only posts are delivered to your followers and users who are mentioned in them, and direct posts are delivered only to users mentioned in them. In some cases it means they are delivered to different servers and copies are stored there. We make a good faith effort to limit the access to those posts only to authorized persons, but other servers may fail to do so. Therefore it's important to review servers your followers belong to. You may toggle an option to approve and reject new followers manually in the settings. <em>Please keep in mind that the operators of the server and any receiving server may view such messages</em>, and that recipients may screenshot, copy or otherwise re-share them. <em>Do not share any dangerous information over Mastodon.</em></li>\n      <li><em>IPs and other metadata</em>: When you log in, we record the IP address you log in from, as well as the name of your browser application. All the logged in sessions are available for your review and revocation in the settings. The latest IP address used is stored for up to 12 months. We also may retain server logs which include the IP address of every request to our server.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"use\">What do we use your information for?</h3>\n\n      <p>Any of the information we collect from you may be used in the following ways:</p>\n\n      <ul>\n      <li>To provide the core functionality of Mastodon. You can only interact with other people's content and post your own content when you are logged in. For example, you may follow other people to view their combined posts in your own personalized home timeline.</li>\n      <li>To aid moderation of the community, for example comparing your IP address with other known ones to determine ban evasion or other violations.</li>\n      <li>The email address you provide may be used to send you information, notifications about other people interacting with your content or sending you messages, and to respond to inquiries, and/or other requests or questions.</li>\n      </ul>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"protect\">How do we protect your information?</h3>\n\n      <p>We implement a variety of security measures to maintain the safety of your personal information when you enter, submit, or access your personal information. Among other things, your browser session, as well as the traffic between your applications and the API, are secured with SSL, and your password is hashed using a strong one-way algorithm. You may enable two-factor authentication to further secure access to your account.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"data-retention\">What is our data retention policy?</h3>\n\n      <p>We will make a good faith effort to:</p>\n\n      <ul>\n      <li>Retain server logs containing the IP address of all requests to this server, in so far as such logs are kept, no more than 90 days.</li>\n      <li>Retain the IP addresses associated with registered users no more than 12 months.</li>\n      </ul>\n\n      <p>You can request and download an archive of your content, including your posts, media attachments, profile picture, and header image.</p>\n\n      <p>You may irreversibly delete your account at any time.</p>\n\n      <hr class=\"spacer\"/>\n\n      <h3 id=\"cookies\">Do we use cookies?</h3>\n\n      <p>Yes. Cookies are small files that a site or its service provider transfers to your computer's hard drive through your Web browser (if you allow). These cookies enable the site to recognize your browser and, if you have a registered account, associate it with your registered account.</p>\n\n      <p>We use cookies to understand and save your preferences for future visits.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"disclose\">Do we disclose any information to outside parties?</h3>\n\n      <p>We do not sell, trade, or otherwise transfer to outside parties your personally identifiable information. This does not include trusted third parties who assist us in operating our site, conducting our business, or servicing you, so long as those parties agree to keep this information confidential. We may also release your information when we believe release is appropriate to comply with the law, enforce our site policies, or protect ours or others rights, property, or safety.</p>\n\n      <p>Your public content may be downloaded by other servers in the network. Your public and followers-only posts are delivered to the servers where your followers reside, and direct messages are delivered to the servers of the recipients, in so far as those followers or recipients reside on a different server than this.</p>\n\n      <p>When you authorize an application to use your account, depending on the scope of permissions you approve, it may access your public profile information, your following list, your followers, your lists, all your posts, and your favourites. Applications can never access your e-mail address or password.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"children\">Site usage by children</h3>\n\n      <p>If this server is in the EU or the EEA: Our site, products and services are all directed to people who are at least 16 years old. If you are under the age of 16, per the requirements of the GDPR (<a href=\"https://en.wikipedia.org/wiki/General_Data_Protection_Regulation\">General Data Protection Regulation</a>) do not use this site.</p>\n\n      <p>If this server is in the USA: Our site, products and services are all directed to people who are at least 13 years old. If you are under the age of 13, per the requirements of COPPA (<a href=\"https://en.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act\">Children's Online Privacy Protection Act</a>) do not use this site.</p>\n\n      <p>Law requirements can be different if this server is in another jurisdiction.</p>\n\n      <hr class=\"spacer\" />\n\n      <h3 id=\"changes\">Changes to our Privacy Policy</h3>\n\n      <p>If we decide to change our privacy policy, we will post those changes on this page.</p>\n\n      <p>This document is CC-BY-SA. It was last updated March 7, 2018.</p>\n\n      <p>Originally adapted from the <a href=\"https://github.com/discourse/discourse\">Discourse privacy policy</a>.</p>\n    title: \"%{instance} Användarvillkor och Sekretesspolicy\"\n  themes:\n    contrast: Hög kontrast\n    default: Mastodon\n    mastodon-light: Mastodon (ljust)\n  two_factor_authentication:\n    code_hint: Ange koden som genererats av din autentiseringsapp för att bekräfta\n    description_html: Om du aktiverar <strong>tvåstegsautentisering</strong> kommer inloggningen kräva att du har din telefon tillgänglig, vilket kommer att generera tokens för dig att uppge.\n    disable: Avaktivera\n    enable: Aktivera\n    enabled: Tvåfaktorsautentisering är aktiverad\n    enabled_success: Tvåfaktors autentisering aktiverad\n    generate_recovery_codes: Generera återställningskoder\n    instructions_html: \"<strong>Skanna den här QR-koden i Google Authenticator eller en liknande TOTP-app på din telefon </strong>. Från och med nu genererar den appen tokens som du måste ange när du loggar in.\"\n    lost_recovery_codes: Återställningskoder tillåter dig att få tillgång till ditt konto om du förlorar din telefon. Om du har förlorat dina återställningskoder kan du regenerera dem här. Dina gamla återställningskoder kommer att ogiltigförklaras.\n    manual_instructions: 'Om du inte kan skanna QR-koden och behöver skriva in den manuellt, här är den enkla texten:'\n    recovery_codes: Backup återställningskod\n    recovery_codes_regenerated: Återställningskoder regenererades framgångsrikt\n    recovery_instructions_html: Om du någonsin tappar åtkomst till din telefon kan du använda någon av återställningskoderna nedan för att återställa åtkomst till ditt konto. <strong> Håll återställningskoderna säkra </strong>. Du kan till exempel skriva ut dem och lagra dem med andra viktiga dokument.\n    setup: Ställ in\n    wrong_code: Den angivna koden var ogiltig! Är servertid och enhetstid korrekt?\n  user_mailer:\n    backup_ready:\n      explanation: Du begärde en fullständig säkerhetskopiering av ditt Mastodon-konto. Det är nu klart för nedladdning!\n      subject: Ditt arkiv är klart för nedladdning\n      title: Arkivuttagning\n    welcome:\n      edit_profile_action: Profilinställning\n      edit_profile_step: Du kan anpassa din profil genom att ladda upp en avatar, bakgrundsbild, ändra ditt visningsnamn och mer. Om du vill granska nya följare innan de får följa dig kan du låsa ditt konto.\n      explanation: Här är några tips för att komma igång\n      final_action: Börja posta\n      final_step: 'Börja posta! Även utan anhängare kan dina offentliga meddelanden ses av andra, till exempel på den lokala tidslinjen och i hashtags. Du får gärna presentera dig via hashtaggen #introductions.'\n      full_handle: Ditt fullständiga användarnamn/mastodonadress\n      full_handle_hint: Det här är vad du skulle berätta för dina vänner så att de kan meddela eller följa dig från en annan instans.\n      review_preferences_action: Ändra inställningar\n      review_preferences_step: Se till att du ställer in dina inställningar, t.ex. vilka e-postmeddelanden du vill ta emot eller vilken integritetsnivå du vill att dina inlägg ska vara. Om du inte har åksjuka, kan du välja att aktivera automatisk uppspelning av GIF-bilder.\n      subject: Välkommen till Mastodon\n      tip_federated_timeline: Den förenade tidslinjen är en störtflodsvy av Mastodon-nätverket. Men det inkluderar bara människor som dina grannar följer, så det är inte komplett.\n      tip_following: Du följer din servers administratör(er) som standard. För att hitta fler intressanta personer, kolla de lokala och förenade tidslinjerna.\n      tip_local_timeline: Den lokala tidslinjen är en störtflodsvy av personer på %{instance}. Det här är dina närmaste grannar!\n      tip_mobile_webapp: Om din mobila webbläsare erbjuder dig att lägga till Mastodon till ditt hemskärm kan du få push-meddelanden. Det fungerar som en inbyggd app på många sätt!\n      title: Välkommen ombord, %{name}!\n  users:\n    invalid_email: E-postadressen är ogiltig\n    invalid_otp_token: Ogiltig tvåfaktorkod\n    otp_lost_help_html: Om du förlorat åtkomst till båda kan du komma i kontakt med %{email}\n    seamless_external_login: Du är inloggad via en extern tjänst, så lösenord och e-postinställningar är inte tillgängliga.\n    signed_in_as: 'Inloggad som:'\n"
  },
  {
    "path": "config/locales/ta.yml",
    "content": "---\nta:\n  errors:\n    '403': You don't have permission to view this page.\n    '404': The page you are looking for isn't here.\n    '410': The page you were looking for doesn't exist here anymore.\n    '422': \n    '429': Throttled\n    '500': \n  invites:\n    expires_in:\n      '1800': 30 minutes\n      '21600': 6 hours\n      '3600': 1 hour\n      '43200': 12 hours\n      '604800': 1 week\n      '86400': 1 day\n"
  },
  {
    "path": "config/locales/te.yml",
    "content": "---\nte:\n  about:\n    about_hashtag_html: ఇవి <strong>#%{hashtag}</strong>తో ట్గాగ్ చేయబడిన పబ్లిక్ టూట్లు. ఫెడివర్స్ లో ఎక్కడ ఖాతావున్నా వీటిలో పాల్గొనవచ్చు.\n    about_mastodon_html: మాస్టొడాన్ అనేది ఒక సామాజిక మాధ్యమం. ఇది పూర్తిగా ఉచితం మరియు స్వేచ్ఛా సాఫ్టువేరు. ఈమెయిల్ లాగానే ఇది వికేంద్రీకరించబడినది.\n    about_this: గురించి\n    administered_by: 'నిర్వహణలో:'\n    apps: మొబైల్ యాప్స్\n    contact: సంప్రదించండి\n    contact_missing: ఇంకా సెట్ చేయలేదు\n    contact_unavailable: వర్తించదు\n    documentation: పత్రీకరణ\n    extended_description_html: |\n      <h3>నియమాలకు ఒక మంచి ప్రదేశం</h3>\n      <p>మరింత విశదీకరణ ఇంకా సెట్ చేయబడలేదు.</p>\n    generic_description: \"%{domain} అనేది నెట్వర్కులోని ఒక సర్వరు\"\n    hosted_on: మాస్టొడాన్ %{domain} లో హోస్టు చేయబడింది\n    learn_more: మరింత తెలుసుకోండి\n    privacy_policy: గోప్యత విధానము\n    source_code: సోర్సు కోడ్\n    status_count_after:\n      one: స్థితి\n      other: స్థితులు\n    status_count_before: ఎవరు రాశారు\n    terms: సేవా నిబంధనలు\n    user_count_after:\n      one: వినియోగదారు\n      other: వినియోగదారులు\n    user_count_before: హోం కు\n    what_is_mastodon: మాస్టొడాన్ అంటే ఏమిటి?\n  accounts:\n    choices_html: \"%{name}'s ఎంపికలు:\"\n    follow: అనుసరించు\n    followers:\n      one: అనుచరి\n      other: అనుచరులు\n    following: అనుసరిస్తున్నారు\n    joined: \"%{date}న చేరారు\"\n    last_active: చివరిగా క్రియాశీలకంగా వుంది\n    link_verified_on: ఈ లంకె యొక్క యాజమాన్యాన్ని చివరిగా పరిశీలించింది %{date}న\n    media: మీడియా\n    moved_html: \"%{name} ఈ %{new_profile_link}కు మారారు:\"\n    network_hidden: ఈ సమాచారం అందుబాటులో లేదు\n    nothing_here: ఇక్కడ ఏమీ లేదు!\n    people_followed_by: \"%{name} అనుసరించే వ్యక్తులు\"\n    people_who_follow: \"%{name}ను అనుసరించే వ్యక్తులు\"\n    pin_errors:\n      following: మీరు ధృవీకరించాలనుకుంటున్న వ్యక్తిని మీరిప్పటికే అనుసరిస్తూ వుండాలి\n    posts:\n      one: టూటు\n      other: టూట్లు\n    posts_tab_heading: టూట్లు\n    posts_with_replies: టూట్లు మరియు ప్రత్యుత్తరాలు\n    reserved_username: ఈ username రిజర్వ్ చేయబడింది\n    roles:\n      admin: నిర్వాహకులు\n      bot: బోట్\n      moderator: నియంత్రికుడు\n    unfollow: అనుసరించవద్దు\n  admin:\n    account_actions:\n      action: చర్య తీసుకో\n      title: \"%{acct}పై మోడరేషన్ చర్యను తీసుకో\"\n    account_moderation_notes:\n      create: ఏదైనా గమనికను వదులు\n      created_msg: మోడరేషన్ గమనిక విజయవంతంగా సృష్టించబడింది!\n      delete: తీసివేయి\n      destroyed_msg: మోడరేషన్ గమనిక విజయవంతంగా తొలగించబడింది!\n    accounts:\n      are_you_sure: ఖచ్ఛితమేగా?\n      avatar: అవతారం\n      by_domain: డొమైను\n      change_email:\n        changed_msg: ఖాతా యొక్క ఈమెయిల్ విజయవంతంగా మార్చబడింది!\n        current_email: ప్రస్తుత ఈమెయిల్\n        label: ఈమెయిల్ ను మార్చు\n        new_email: కొత్త ఈమెయిల్\n        submit: ఈమెయిల్ ను మార్చు\n        title: \"%{username} యొక్క ఈమెయిల్ ను మార్చు\"\n      confirm: ధృవీకరించు\n      confirmed: ధృవీకరించబడింది\n      confirming: ధృవీకరిస్తుంది\n      demote: స్థానం తగ్గించు\n      disable: అచేతనం చేయి\n      disable_two_factor_authentication: 2FAను అచేతనం చేయి\n      disabled: అచేతనం చేయబడింది\n      display_name: పేరును చూపు\n      domain: డొమైను\n      edit: మార్చు\n      email: ఈమెయిల్\n      email_status: ఈమెయిల్ స్థితి\n      enable: చేతనం\n      enabled: చేతనం చేయబడింది\n      feed_url: ఫీడ్ URL\n      followers: అనుచరులు\n      followers_url: అనుచరుల URL\n      follows: అనుసరిస్తున్నారు\n      inbox_url: ఇన్ బాక్స్ URL\n      location:\n        all: అన్నీ\n        local: లోకల్\n        remote: రిమోట్\n        title: లొకేషన్\n      login_status: లాగిన్ స్థితి\n      media_attachments: మీడియా అటాచ్మెంట్లు\n      moderation:\n        active: యాక్టివ్\n        all: అన్నీ\n        silenced: నిశ్శబ్ధం చేయబడింది\n        suspended: నిషేధించబడింది\n        title: మోడరేషన్\n      moderation_notes: మోడరేషన్ నోట్స్\n      most_recent_activity: ఇటీవల యాక్టివిటీ\n      most_recent_ip: ఇటీవలి IP\n  errors:\n    '403': You don't have permission to view this page.\n    '404': The page you are looking for isn't here.\n    '410': The page you were looking for doesn't exist here anymore.\n    '422': \n    '429': Throttled\n    '500': \n  invites:\n    expires_in:\n      '1800': 30 minutes\n      '21600': 6 hours\n      '3600': 1 hour\n      '43200': 12 hours\n      '604800': 1 week\n      '86400': 1 day\n"
  },
  {
    "path": "config/locales/th.yml",
    "content": "---\nth:\n  about:\n    about_mastodon_html: Mastodon เป็นเครือข่ายสังคมที่ทำงานบนโปรโตคอลเว็บแบบเปิดและซอฟต์แวร์เสรีที่เปิดต้นฉบับ กระจายศูนย์เหมือนอีเมล\n    about_this: เกี่ยวกับ\n    active_count_after: ที่ใช้งาน\n    active_footnote: ผู้ใช้งานรายเดือน (MAU)\n    administered_by: 'ดูแลโดย:'\n    apps: แอปสำหรับมือถือ\n    apps_platforms: ใช้ Mastodon จาก iOS, Android และแพลตฟอร์มอื่น ๆ\n    browse_directory: เรียกดูไดเรกทอรีโปรไฟล์และกรองตามความสนใจ\n    browse_public_posts: เรียกดูสตรีมสดของโพสต์สาธารณะใน Mastodon\n    contact: ติดต่อ\n    contact_missing: ไม่ได้ตั้ง\n    contact_unavailable: ไม่มี\n    discover_users: ค้นพบผู้ใช้\n    documentation: เอกสารประกอบ\n    extended_description_html: |\n      <h3>สถานที่ที่ดีสำหรับกฎ</h3>\n      <p>ยังไม่ได้ตั้งคำอธิบายแบบขยาย</p>\n    generic_description: \"%{domain} เป็นเซิร์ฟเวอร์หนึ่งในเครือข่าย\"\n    get_apps: ลองแอปสำหรับมือถือ\n    learn_more: เรียนรู้เพิ่มเติม\n    privacy_policy: นโยบายความเป็นส่วนตัว\n    server_stats: 'สถิติเซิร์ฟเวอร์:'\n    source_code: โค้ดต้นฉบับ\n    status_count_after:\n      other: สถานะ\n    status_count_before: ผู้สร้าง\n    user_count_after:\n      other: ผู้ใช้\n    user_count_before: บ้านของ\n    what_is_mastodon: Mastodon คืออะไร?\n  accounts:\n    follow: ติดตาม\n    followers:\n      other: ผู้ติดตาม\n    following: กำลังติดตาม\n    joined: เข้าร่วมเมื่อ %{date}\n    last_active: ใช้งานล่าสุด\n    media: สื่อ\n    moved_html: \"%{name} ได้ย้ายไปยัง %{new_profile_link}:\"\n    network_hidden: ไม่มีข้อมูลนี้\n    nothing_here: ไม่มีสิ่งใดที่นี่!\n    people_followed_by: ผู้คนที่ %{name} ติดตาม\n    people_who_follow: ผู้คนที่ติดตาม %{name}\n    posts:\n      other: โพสต์\n    posts_tab_heading: โพสต์\n    posts_with_replies: โพสต์และการตอบกลับ\n    roles:\n      admin: ผู้ดูแล\n      bot: บอต\n      moderator: ผู้ควบคุม\n    unfollow: เลิกติดตาม\n  admin:\n    account_moderation_notes:\n      created_msg: สร้างหมายเหตุการควบคุมสำเร็จ!\n      delete: ลบ\n      destroyed_msg: ทำลายหมายเหตุการควบคุมสำเร็จ!\n    accounts:\n      approve: อนุมัติ\n      are_you_sure: คุณแน่ใจหรือไม่?\n      avatar: ภาพประจำตัว\n      by_domain: โดเมน\n      change_email:\n        changed_msg: เปลี่ยนอีเมลบัญชีสำเร็จ!\n        current_email: อีเมลปัจจุบัน\n        label: เปลี่ยนอีเมล\n        new_email: อีเมลใหม่\n        submit: เปลี่ยนอีเมล\n        title: เปลี่ยนอีเมลสำหรับ %{username}\n      confirm: ยืนยัน\n      confirmed: ยืนยันแล้ว\n      confirming: กำลังยืนยัน\n      deleted: ลบแล้ว\n      demote: ลดระดับ\n      disable: ปิดใช้งาน\n      disable_two_factor_authentication: ปิดใช้งาน 2FA\n      disabled: ปิดใช้งานอยู่\n      display_name: ชื่อที่แสดงผล\n      domain: โดเมน\n      edit: แก้ไข\n      email: อีเมล\n      email_status: สถานะอีเมล\n      enable: เปิดใช้งาน\n      enabled: เปิดใช้งานอยู่\n      feed_url: URL ฟีด\n      followers: ผู้ติดตาม\n      followers_url: URL ผู้ติดตาม\n      follows: ติดตาม\n      header: ส่วนหัว\n      inbox_url: URL กล่องขาเข้า\n      invited_by: เชิญโดย\n      joined: เข้าร่วมเมื่อ\n      location:\n        all: ทั้งหมด\n        local: ในเว็บ\n        remote: ระยะไกล\n        title: ตำแหน่งที่ตั้ง\n      login_status: สถานะการเข้าสู่ระบบ\n      media_attachments: ไฟล์แนบสื่อ\n      moderation:\n        all: ทั้งหมด\n        silenced: เงียบอยู่\n        suspended: ระงับอยู่\n        title: การควบคุม\n      moderation_notes: หมายเหตุการควบคุม\n      most_recent_activity: กิจกรรมล่าสุด\n      most_recent_ip: IP ล่าสุด\n      not_subscribed: ไม่ได้บอกรับ\n      outbox_url: URL กล่องขาออก\n      perform_full_suspension: ระงับ\n      profile_url: URL โปรไฟล์\n      protocol: โปรโตคอล\n      public: สาธารณะ\n      push_subscription_expires: การบอกรับ PuSH หมดอายุเมื่อ\n      reject: ปฏิเสธ\n      remove_avatar: เอาภาพประจำตัวออก\n      remove_header: เอาส่วนหัวออก\n      resend_confirmation:\n        already_confirmed: ผู้ใช้นี้ได้รับการยืนยันอยู่แล้ว\n        send: ส่งอีเมลยืนยันอีกครั้ง\n        success: ส่งอีเมลยืนยันสำเร็จ!\n      reset_password: ตั้งรหัสผ่านใหม่\n      resubscribe: บอกรับใหม่\n      roles:\n        admin: ผู้ดูแล\n        moderator: ผู้ควบคุม\n        staff: พนักงาน\n        user: ผู้ใช้\n      search: ค้นหา\n      show:\n        created_reports: รายงานที่สร้าง\n        targeted_reports: รายงานโดยผู้อื่น\n      silence: เงียบ\n      silenced: เงียบอยู่\n      statuses: สถานะ\n      subscribe: บอกรับ\n      suspended: ระงับอยู่\n      title: บัญชี\n      undo_silenced: เลิกทำการเงียบ\n      undo_suspension: เลิกทำการระงับ\n      unsubscribe: เลิกบอกรับ\n      username: ชื่อผู้ใช้\n      warn: เตือน\n      web: เว็บ\n    action_logs:\n      deleted_status: \"(สถานะที่ลบแล้ว)\"\n      title: รายการบันทึกการตรวจสอบ\n    custom_emojis:\n      by_domain: โดเมน\n      copy: คัดลอก\n      created_msg: สร้างอีโมจิสำเร็จ!\n      delete: ลบ\n      disable: ปิดใช้งาน\n      emoji: อีโมจิ\n      enable: เปิดใช้งาน\n      new:\n        title: เพิ่มอีโมจิที่กำหนดเองใหม่\n      overwrite: เขียนทับ\n      shortcode: รหัสย่อ\n      title: อีโมจิที่กำหนดเอง\n      unlisted: ไม่อยู่ในรายการ\n      update_failed_msg: ไม่สามารถอัปเดตอีโมจินั้น\n      updated_msg: อัปเดตอีโมจิสำเร็จ!\n      upload: อัปโหลด\n    dashboard:\n      config: การกำหนดค่า\n      feature_deletions: การลบบัญชี\n      feature_invites: ลิงก์เชิญ\n      feature_profile_directory: ไดเรกทอรีโปรไฟล์\n      feature_registrations: การลงทะเบียน\n      features: คุณลักษณะ\n      open_reports: รายงานที่เปิด\n      recent_users: ผู้ใช้ล่าสุด\n      search: การค้นหาข้อความแบบเต็ม\n      single_user_mode: โหมดผู้ใช้เดี่ยว\n      software: ซอฟต์แวร์\n      space: การใช้พื้นที่\n      title: แดชบอร์ด\n      total_users: ผู้ใช้ทั้งหมด\n      trends: แนวโน้ม\n      week_interactions: การโต้ตอบในสัปดาห์นี้\n      week_users_active: ที่ใช้งานในสัปดาห์นี้\n      week_users_new: ผู้ใช้ในสัปดาห์นี้\n    domain_blocks:\n      add_new: เพิ่มการปิดกั้นโดเมนใหม่\n      created_msg: กำลังประมวลผลการปิดกั้นโดเมน\n      destroyed_msg: เลิกทำการปิดกั้นโดเมนแล้ว\n      domain: โดเมน\n      new:\n        create: สร้างการปิดกั้น\n        hint: การปิดกั้นโดเมนจะไม่ป้องกันการสร้างรายการบัญชีในฐานข้อมูล แต่จะใช้วิธีการควบคุมเฉพาะกับบัญชีเหล่านั้นย้อนหลังและโดยอัตโนมัติ\n        severity:\n          desc_html: \"<strong>เงียบ</strong> จะทำให้โพสต์ของบัญชีมองไม่เห็นกับใครก็ตามที่ไม่ได้กำลังติดตามบัญชี <strong>ระงับ</strong> จะเอาเนื้อหา, สื่อ และข้อมูลโปรไฟล์ทั้งหมดของบัญชีออก ใช้ <strong>ไม่มี</strong> หากคุณเพียงแค่ต้องการปฏิเสธไฟล์สื่อ\"\n          noop: ไม่มี\n          silence: เงียบ\n          suspend: ระงับ\n        title: การปิดกั้นโดเมนใหม่\n      reject_media: ปฏิเสธไฟล์สื่อ\n      reject_media_hint: เอาไฟล์สื่อที่จัดเก็บไว้ในเว็บออกและปฏิเสธที่จะดาวน์โหลดไฟล์ใด ๆ ในอนาคต ไม่เกี่ยวข้องกับการระงับ\n      reject_reports: ปฏิเสธรายงาน\n      severity:\n        silence: เงียบอยู่\n        suspend: ระงับอยู่\n      show:\n        affected_accounts:\n          other: มีผลต่อ %{count} บัญชีในฐานข้อมูล\n        retroactive:\n          silence: เลิกเงียบบัญชีที่มีอยู่ทั้งหมดจากโดเมนนี้\n          suspend: เลิกระงับบัญชีที่มีอยู่ทั้งหมดจากโดเมนนี้\n        title: เลิกทำการปิดกั้นโดเมนสำหรับ %{domain}\n        undo: เลิกทำ\n      undo: เลิกทำการปิดกั้นโดเมน\n    email_domain_blocks:\n      add_new: เพิ่มใหม่\n      delete: ลบ\n      domain: โดเมน\n      new:\n        create: เพิ่มโดเมน\n    followers:\n      back_to_account: กลับไปที่บัญชี\n      title: ผู้ติดตามของ %{acct}\n    instances:\n      by_domain: โดเมน\n      moderation:\n        all: ทั้งหมด\n        limited: จำกัดอยู่\n        title: การควบคุม\n      title: การติดต่อกับภายนอก\n      total_storage: ไฟล์แนบสื่อ\n    invites:\n      deactivate_all: ปิดใช้งานทั้งหมด\n      title: คำเชิญ\n    relays:\n      add_new: เพิ่มรีเลย์ใหม่\n      delete: ลบ\n      disable: ปิดใช้งาน\n      disabled: ปิดใช้งานอยู่\n      enable: เปิดใช้งาน\n      enabled: เปิดใช้งานอยู่\n      inbox_url: URL รีเลย์\n      status: สถานะ\n      title: รีเลย์\n    report_notes:\n      created_msg: สร้างหมายเหตุรายงานสำเร็จ!\n      destroyed_msg: ลบหมายเหตุรายงานสำเร็จ!\n    reports:\n      account:\n        note: หมายเหตุ\n        report: รายงาน\n      are_you_sure: คุณแน่ใจหรือไม่?\n      assign_to_self: มอบหมายให้ฉัน\n      comment:\n        none: ไม่มี\n      created_at: รายงานเมื่อ\n      mark_as_resolved: ทำเครื่องหมายว่าแก้ปัญหาแล้ว\n      mark_as_unresolved: ทำเครื่องหมายว่ายังไม่ได้แก้ปัญหา\n      notes:\n        create: เพิ่มหมายเหตุ\n        delete: ลบ\n      report: 'รายงาน #%{id}'\n      reported_account: บัญชีที่ได้รับการรายงาน\n      reported_by: รายงานโดย\n      resolved: แก้ปัญหาแล้ว\n      resolved_msg: แก้ปัญหารายงานสำเร็จ!\n      status: สถานะ\n      title: รายงาน\n      unassign: เลิกมอบหมาย\n      unresolved: ยังไม่ได้แก้ปัญหา\n      updated_at: อัปเดตเมื่อ\n    settings:\n      contact_information:\n        email: อีเมลธุรกิจ\n        username: ชื่อผู้ใช้ในการติดต่อ\n      custom_css:\n        title: CSS ที่กำหนดเอง\n      profile_directory:\n        title: เปิดใช้งานไดเรกทอรีโปรไฟล์\n      registrations:\n        closed_message:\n          desc_html: แสดงผลในหน้าแรกเมื่อปิดการลงทะเบียน คุณสามารถใช้แท็ก HTML\n          title: ข้อความการปิดการลงทะเบียน\n        deletion:\n          desc_html: อนุญาตให้ใครก็ตามลบบัญชีของเขา\n          title: เปิดการลบบัญชี\n        min_invite_role:\n          disabled: ไม่มีใคร\n          title: อนุญาตคำเชิญโดย\n      registrations_mode:\n        modes:\n          none: ไม่มีใครสามารถลงทะเบียน\n          open: ใครก็ตามสามารถลงทะเบียน\n        title: โหมดการลงทะเบียน\n      show_staff_badge:\n        desc_html: แสดงป้ายพนักงานในหน้าผู้ใช้\n        title: แสดงป้ายพนักงาน\n      site_description:\n        desc_html: ย่อหน้าเกริ่นนำในหน้าแรก อธิบายถึงสิ่งที่ทำให้เซิร์ฟเวอร์ Mastodon นี้พิเศษและสิ่งอื่นใดที่สำคัญ คุณสามารถใช้แท็ก HTML โดยเฉพาะอย่างยิ่ง <code>&lt;a&gt;</code> และ <code>&lt;em&gt;</code>\n        title: คำอธิบายเซิร์ฟเวอร์\n      site_description_extended:\n        desc_html: สถานที่ที่ดีสำหรับแนวทางปฏิบัติ, กฎ, หลักเกณฑ์ และสิ่งอื่น ๆ ของคุณที่ทำให้เซิร์ฟเวอร์ของคุณแตกต่าง คุณสามารถใช้แท็ก HTML\n        title: ข้อมูลแบบขยายที่กำหนดเอง\n      site_short_description:\n        title: คำอธิบายเซิร์ฟเวอร์แบบสั้น\n      site_title: ชื่อเซิร์ฟเวอร์\n      timeline_preview:\n        desc_html: แสดงเส้นเวลาสาธารณะในหน้าเริ่มต้น\n        title: ตัวอย่างเส้นเวลา\n      title: การตั้งค่าไซต์\n    statuses:\n      back_to_account: กลับไปที่หน้าบัญชี\n      batch:\n        delete: ลบ\n        nsfw_off: ทำเครื่องหมายว่าไม่ละเอียดอ่อน\n        nsfw_on: ทำเครื่องหมายว่าละเอียดอ่อน\n      media:\n        title: สื่อ\n      no_media: ไม่มีสื่อ\n      title: สถานะบัญชี\n    subscriptions:\n      callback_url: URL เรียกกลับ\n      confirmed: ยืนยันแล้ว\n      expires_in: หมดอายุภายใน\n      last_delivery: ส่งล่าสุด\n      topic: หัวข้อ\n    tags:\n      accounts: บัญชี\n      hidden: ซ่อนอยู่\n      hide: ซ่อนจากไดเรกทอรี\n      name: แฮชแท็ก\n      title: แฮชแท็ก\n      unhide: แสดงในไดเรกทอรี\n      visible: มองเห็น\n    title: การดูแล\n    warning_presets:\n      add_new: เพิ่มใหม่\n      delete: ลบ\n      edit: แก้ไข\n      edit_preset: แก้ไขคำเตือนที่ตั้งไว้ล่วงหน้า\n      title: จัดการคำเตือนที่ตั้งไว้ล่วงหน้า\n  application_mailer:\n    notification_preferences: เปลี่ยนการกำหนดลักษณะอีเมล\n    settings: 'เปลี่ยนการกำหนดลักษณะอีเมล: %{link}'\n    view: 'มุมมอง:'\n    view_profile: ดูโปรไฟล์\n    view_status: ดูสถานะ\n  applications:\n    invalid_url: URL ที่ระบุไม่ถูกต้อง\n  auth:\n    apply_for_account: ขอคำเชิญ\n    change_password: รหัสผ่าน\n    confirm_email: ยืนยันอีเมล\n    delete_account: ลบบัญชี\n    forgot_password: ลืมรหัสผ่านของคุณ?\n    login: เข้าสู่ระบบ\n    logout: ออกจากระบบ\n    migrate_account: ย้ายไปยังบัญชีอื่น\n    or_log_in_with: หรือเข้าสู่ระบบด้วย\n    register: ลงทะเบียน\n    resend_confirmation: ส่งขั้นตอนวิธีการยืนยันใหม่อีกครั้ง\n    reset_password: ตั้งรหัสผ่านใหม่\n    security: ความปลอดภัย\n    set_new_password: ตั้งรหัสผ่านใหม่\n    trouble_logging_in: มีปัญหาในการเข้าสู่ระบบ?\n  authorize_follow:\n    already_following: คุณกำลังติดตามบัญชีนี้อยู่แล้ว\n    follow: ติดตาม\n    following: 'สำเร็จ! คุณกำลังติดตาม:'\n    post_follow:\n      return: แสดงโปรไฟล์ของผู้ใช้\n      web: ไปยังเว็บ\n    title: ติดตาม %{acct}\n  datetime:\n    distance_in_words:\n      about_x_hours: \"%{count} ชั่วโมง\"\n      about_x_months: \"%{count} เดือน\"\n      about_x_years: \"%{count} ปี\"\n      almost_x_years: \"%{count} ปี\"\n      half_a_minute: เมื่อกี้นี้\n      less_than_x_minutes: \"%{count} นาที\"\n      less_than_x_seconds: เมื่อกี้นี้\n      over_x_years: \"%{count} ปี\"\n      x_days: \"%{count} วัน\"\n      x_minutes: \"%{count} นาที\"\n      x_months: \"%{count} เดือน\"\n      x_seconds: \"%{count} วินาที\"\n  deletes:\n    proceed: ลบบัญชี\n    success_msg: ลบบัญชีของคุณสำเร็จ\n  directories:\n    directory: ไดเรกทอรีโปรไฟล์\n    explanation: ค้นพบผู้ใช้ตามความสนใจของเขา\n    explore_mastodon: สำรวจ %{title}\n  errors:\n    '403': คุณไม่มีสิทธิดูหน้านี้\n    '404': หน้าที่คุณกำลังมองหาไม่ได้อยู่ที่นี่\n    '410': หน้าที่คุณกำลังมองหาไม่มีอยู่ที่นี่อีกต่อไป\n    '422':\n      content: การตรวจสอบความปลอดภัยล้มเหลว คุณกำลังปิดกั้นคุกกี้หรือไม่?\n      title: การตรวจสอบความปลอดภัยล้มเหลว\n    '429': Throttled\n    '500':\n      title: หน้านี้ไม่ถูกต้อง\n  exports:\n    archive_takeout:\n      date: วันที่\n      download: ดาวน์โหลดการเก็บถาวรของคุณ\n      request: ขอการเก็บถาวรของคุณ\n      size: ขนาด\n    blocks: คุณปิดกั้น\n    domain_blocks: การปิดกั้นโดเมน\n    follows: คุณติดตาม\n    lists: รายการ\n    mutes: คุณปิดเสียง\n    storage: ที่เก็บข้อมูลสื่อ\n  featured_tags:\n    add_new: เพิ่มใหม่\n  filters:\n    contexts:\n      home: เส้นเวลาหน้าแรก\n      notifications: การแจ้งเตือน\n      public: เส้นเวลาสาธารณะ\n      thread: การสนทนา\n    edit:\n      title: แก้ไขตัวกรอง\n    index:\n      delete: ลบ\n      title: ตัวกรอง\n    new:\n      title: เพิ่มตัวกรองใหม่\n  footer:\n    developers: นักพัฒนา\n    more: เพิ่มเติม…\n    resources: ทรัพยากร\n  generic:\n    all: ทั้งหมด\n    changes_saved_msg: บันทึกการเปลี่ยนแปลงสำเร็จ!\n    copy: คัดลอก\n    save_changes: บันทึกการเปลี่ยนแปลง\n  imports:\n    modes:\n      merge: ผสาน\n      overwrite: เขียนทับ\n    preface: You can import certain data like all the people you are following or blocking into your account on this instance, from files created by an export on another instance.\n    types:\n      blocking: รายการปิดกั้น\n      following: รายการติดตาม\n      muting: รายการปิดเสียง\n    upload: อัปโหลด\n  invites:\n    delete: ปิดใช้งาน\n    expires_in:\n      '1800': 30 นาที\n      '21600': 6 ชั่วโมง\n      '3600': 1 ชั่วโมง\n      '43200': 12 ชั่วโมง\n      '604800': 1 สัปดาห์\n      '86400': 1 วัน\n    expires_in_prompt: ไม่เลย\n    generate: สร้าง\n    max_uses_prompt: ไม่มีขีดจำกัด\n    table:\n      expires_at: หมดอายุเมื่อ\n    title: เชิญผู้คน\n  media_attachments:\n    validations:\n      images_and_video: ไม่สามารถแนบวิดีโอกับสถานะที่มีภาพอยู่แล้ว\n      too_many: ไม่สามารถแนบมากกว่า 4 ไฟล์\n  migrations:\n    acct: username@domain ของบัญชีใหม่\n    proceed: บันทึก\n  moderation:\n    title: การควบคุม\n  notification_mailer:\n    digest:\n      action: ดูการแจ้งเตือนทั้งหมด\n      mention: \"%{name} ได้กล่าวถึงคุณใน:\"\n      new_followers_summary:\n        other: You have gotten %{count} new followers! Amazing!\n    favourite:\n      body: 'สถานะของคุณได้รับการชื่นชอบโดย %{name}:'\n      subject: \"%{name} ได้ชื่นชอบสถานะของคุณ\"\n      title: รายการโปรดใหม่\n    follow:\n      body: \"%{name} กำลังติดตามคุณ!\"\n      subject: \"%{name} กำลังติดตามคุณ\"\n      title: ผู้ติดตามใหม่\n    follow_request:\n      action: จัดการคำขอติดตาม\n      body: \"%{name} ได้ขอติดตามคุณ\"\n      subject: 'ผู้ติดตามที่รอดำเนินการ: %{name}'\n      title: คำขอติดตามใหม่\n    mention:\n      action: ตอบกลับ\n      body: 'คุณได้รับการกล่าวถึงโดย %{name} ใน:'\n      subject: คุณได้รับการกล่าวถึงโดย %{name}\n      title: การกล่าวถึงใหม่\n    reblog:\n      body: 'สถานะของคุณได้รับการดันโดย %{name}:'\n      subject: \"%{name} ได้ดันสถานะของคุณ\"\n      title: การดันใหม่\n  pagination:\n    newer: ใหม่กว่า\n    next: ถัดไป\n    older: เก่ากว่า\n    prev: ก่อนหน้า\n  relationships:\n    activity: กิจกรรมบัญชี\n    relationship: ความสัมพันธ์\n    remove_selected_domains: เอาผู้ติดตามทั้งหมดออกจากโดเมนที่เลือก\n    remove_selected_followers: เอาผู้ติดตามที่เลือกออก\n    remove_selected_follows: เลิกติดตามผู้ใช้ที่เลือก\n    status: สถานะบัญชี\n  remote_follow:\n    acct: ป้อน username@domain ของคุณที่คุณต้องการกระทำจาก\n    no_account_html: ไม่มีบัญชี? คุณสามารถ <a href='%{sign_up_path}' target='_blank'>ลงทะเบียนที่นี่</a>\n    proceed: ดำเนินการต่อเพื่อติดตาม\n    prompt: 'คุณกำลังจะติดตาม:'\n  remote_interaction:\n    favourite:\n      proceed: ดำเนินการต่อเพื่อชื่นชอบ\n      prompt: 'คุณต้องการชื่นชอบโพสต์นี้:'\n    reblog:\n      proceed: ดำเนินการต่อเพื่อดัน\n      prompt: 'คุณต้องการดันโพสต์นี้:'\n    reply:\n      proceed: ดำเนินการต่อเพื่อตอบกลับ\n      prompt: 'คุณต้องการตอบกลับโพสต์นี้:'\n  remote_unfollow:\n    error: ข้อผิดพลาด\n    title: ชื่อเรื่อง\n    unfollowed: เลิกติดตามแล้ว\n  sessions:\n    activity: กิจกรรมล่าสุด\n    browser: เบราว์เซอร์\n    revoke: เพิกถอน\n  settings:\n    authorized_apps: แอปที่ได้รับอนุญาต\n    back: กลับไปที่ Mastodon\n    delete: การลบบัญชี\n    development: การพัฒนา\n    edit_profile: แก้ไขโปรไฟล์\n    export: การส่งออกข้อมูล\n    import: นำเข้า\n    notifications: การแจ้งเตือน\n    preferences: การกำหนดลักษณะ\n    relationships: การติดตามและผู้ติดตาม\n    two_factor_authentication: การรับรองความถูกต้องด้วยสองปัจจัย\n  statuses:\n    attached:\n      description: 'แนบ: %{attached}'\n      image:\n        other: \"%{count} ภาพ\"\n      video:\n        other: \"%{count} วิดีโอ\"\n    content_warning: 'คำเตือนเนื้อหา: %{warning}'\n    open_in_web: เปิดในเว็บ\n    pin_errors:\n      reblog: ไม่สามารถปักหมุดการดัน\n    poll:\n      total_votes:\n        other: \"%{count} การลงคะแนน\"\n    show_more: แสดงเพิ่มเติม\n    sign_in_to_participate: ลงชื่อเข้าเพื่อเข้าร่วมการสนทนา\n    visibilities:\n      private: ผู้ติดตามเท่านั้น\n      private_long: แสดงต่อผู้ติดตามเท่านั้น\n      public: สาธารณะ\n      public_long: ทุกคนสามารถเห็น\n      unlisted: ไม่อยู่ในรายการ\n  stream_entries:\n    pinned: โพสต์ที่ปักหมุด\n    sensitive_content: เนื้อหาที่ละเอียดอ่อน\n  themes:\n    contrast: Mastodon (ความคมชัดสูง)\n    default: Mastodon (มืด)\n    mastodon-light: Mastodon (สว่าง)\n  time:\n    formats:\n      default: \"%d %b %Y, %H:%M\"\n  two_factor_authentication:\n    disable: ปิดใช้งาน\n    enable: เปิดใช้งาน\n    enabled: เปิดใช้งานการรับรองความถูกต้องด้วยสองปัจจัยแล้ว\n    enabled_success: เปิดใช้งานการรับรองความถูกต้องด้วยสองปัจจัยสำเร็จ\n    generate_recovery_codes: สร้างรหัสกู้คืน\n    recovery_instructions_html: If you ever lose access to your phone, you can use one of the recovery codes below to regain access to your account. Keep the recovery codes safe, for example by printing them and storing them with other important documents.\n    setup: ตั้งค่า\n    wrong_code: รหัสที่ป้อนไม่ถูกต้อง! เวลาเซิร์ฟเวอร์และเวลาอุปกรณ์ถูกต้องหรือไม่?\n  user_mailer:\n    warning:\n      title:\n        none: คำเตือน\n        silence: จำกัดบัญชีอยู่\n        suspend: ระงับบัญชีอยู่\n    welcome:\n      review_preferences_action: เปลี่ยนการกำหนดลักษณะ\n      subject: ยินดีต้อนรับสู่ Mastodon\n      tips: เคล็ดลับ\n  users:\n    invalid_email: ที่อยู่อีเมลไม่ถูกต้อง\n    invalid_otp_token: รหัสสองปัจจัยไม่ถูกต้อง\n    signed_in_as: 'ลงชื่อเข้าเป็น:'\n  verification:\n    verification: การตรวจสอบ\n"
  },
  {
    "path": "config/locales/tr.yml",
    "content": "---\ntr:\n  about:\n    about_hashtag_html: Bunlar <strong>#%{hashtag}X</strong> ile etiketlenen genel paylaşımlar. Açık alanda herhangi bir yerde bir hesabınız varsa, onlarla etkileşime geçebilirsiniz.\n    about_mastodon_html: Mastodon <em>ücretsiz ve açık kaynaklı</em> bir sosyal ağdır. <em>Merkezileştirilmemiş</em> yapısı sayesinde diğer ticari sosyal platformların aksine iletişimininizin tek bir firmada tutulmasının/yönetilmesinin önüne geçer. Güvendiğiniz bir sunucuyu seçerek oradaki kişilerle etkileşimde bulunabilirsiniz. Herkes kendi Mastodon sunucusunu kurabilir ve sorunsuz bir şekilde Mastodon <em>sosyal ağına</em> dahil edebilir.\n    about_this: Bu sunucu hakkında\n    administered_by: 'Tarafından yönetildi:'\n    apps: Mobil uygulamalar\n    contact: İletişim\n    contact_missing: Ayarlanmadı\n    contact_unavailable: Yok\n    documentation: Belgeler\n    extended_description_html: |\n      <h3>Kural için iyi bir yer</h3>\n      <p>Genişletilmiş açıklama henüz ayarlanmamış.</p>\n    generic_description: \"%{domain} ağdaki bir sunucudur\"\n    hosted_on: Mastodon %{domain} üzerinde barındırılıyor\n    learn_more: Daha fazla bilgi edinin\n    privacy_policy: Gizlilik politikası\n    source_code: Kaynak kodu\n    status_count_after:\n      one: durum\n      other: durum\n    status_count_before: Şu ana kadar\n    terms: Kullanım şartları\n    user_count_after:\n      one: kullanıcı\n      other: kullanıcı\n    user_count_before: Kayıtlı\n    what_is_mastodon: Mastodon nedir?\n  accounts:\n    choices_html: \"%{name} seçimleri:\"\n    follow: Takip et\n    followers:\n      one: Takipçi\n      other: Takipçi\n    following: Takip ediliyor\n    joined: \"%{date} tarihinde katıldı\"\n    link_verified_on: Bu bağlantının mülkiyeti %{date} tarihinde kontrol edildi\n    media: Medya\n    moved_html: \"%{name}, %{new_profile_link} adresine taşındı:\"\n    network_hidden: Bu bilgi mevcut değil\n    nothing_here: Burada henüz hiçbir gönderi yok!\n    people_followed_by: Kullanıcı %{name}'in takip ettikleri\n    people_who_follow: Kullanıcı %{name}'i takip edenler\n    pin_errors:\n      following: Onaylamak istediğiniz kişiyi zaten takip ediyor olmalısınız\n    posts_tab_heading: Tootlar\n    posts_with_replies: Tootlar ve yanıtlar\n    reserved_username: Kullanıcı adı saklıdır\n    roles:\n      admin: Yönetici\n      moderator: Denetleyici\n    unfollow: Takibi bırak\n  admin:\n    account_actions:\n      action: Eylemi gerçekleştir\n    account_moderation_notes:\n      create: Not bırakın\n      created_msg: Denetim notu başarıyla oluşturuldu!\n      delete: Sil\n      destroyed_msg: Denetim notu başarıyla yok edildi!\n    accounts:\n      are_you_sure: Emin misiniz?\n      by_domain: Sunucu\n      change_email:\n        changed_msg: Hesap e-postası başarıyla değiştirildi!\n        current_email: Mevcut e-posta\n        label: E-postayı değiştir\n        new_email: Yeni e-posta\n        submit: E-postayı değiştir\n        title: \"%{username} için e-postayı değiştir\"\n      confirm: Onayla\n      confirmed: Onaylandı\n      confirming: Onaylama\n      deleted: Silinen\n      disable: Devre dışı\n      disable_two_factor_authentication: 2AD kapat\n      disabled: Kapalı\n      display_name: Görünen adınız\n      domain: Sunucu\n      edit: Düzenle\n      email: E-posta\n      email_status: E-posta durumu\n      enable: Etkinleştir\n      enabled: Etkin\n      feed_url: Besleme linki\n      followers: Takipçiler\n      followers_url: Takipçi bağlantısı\n      follows: Takip edilen\n      header: Üstbilgi\n      inbox_url: Gelen kutusu bağlantısı\n      invited_by: Tarafından davet edildi\n      joined: Katıldı\n      location:\n        all: Hepsi\n        local: Yerel\n        remote: Uzaktan\n        title: Konum\n      login_status: Giriş durumu\n      media_attachments: Medya ekleri\n      memorialize: Bir hatıraya dön\n      moderation:\n        all: Hepsi\n        silenced: Susturulanlar\n        suspended: Uzaklaştırılanlar\n        title: Yönetim\n      moderation_notes: Denetleme notları\n      most_recent_activity: Son aktivite\n      most_recent_ip: Son IP\n      not_subscribed: Abone edilmedi\n      perform_full_suspension: Askıya al\n      profile_url: Profil linki\n      promote: Yükselt\n      protocol: Protokol\n      public: Herkese açık\n      push_subscription_expires: PuSH aboneliği dolumu\n      redownload: Profili yenile\n      remove_avatar: Avatarı kaldır\n      remove_header: Üstbilgiyi kaldır\n      resend_confirmation:\n        already_confirmed: Bu kullanıcı zaten onaylandı\n        send: Doğrulama epostasını yeniden gönder\n        success: Onay e-postası başarıyla gönderildi!\n      reset: Sıfırla\n      reset_password: Parolayı değiştir\n      resubscribe: Yeniden abone ol\n      role: İzinler\n      roles:\n        admin: Yönetici\n        moderator: Denetleyici\n        staff: Personel\n        user: Kullanıcı\n      salmon_url: Salmon Linki\n      search: Ara\n      shared_inbox_url: Paylaşılan gelen kutusu bağlantısı\n      show:\n        created_reports: Yapılan şikayetler\n        targeted_reports: Başkaları tarafından şikayet edildi\n      silence: Sustur\n      silenced: Susturulmuş\n      statuses: Durumlar\n      subscribe: Abone ol\n      suspended: Askıya alındı\n      title: Hesaplar\n      unconfirmed_email: Onaylanmamış e-posta\n      undo_silenced: Susturmayı geri al\n      undo_suspension: Uzaklaştırmayı geri al\n      unsubscribe: Abonelikten çık\n      username: Kullanıcı adı\n      warn: Uyar\n    action_logs:\n      actions:\n        confirm_user: \"%{name} %{target} kullanıcısının e-posta adresini onayladı\"\n        create_custom_emoji: \"%{name} yeni ifade yükledi %{target}\"\n        disable_2fa_user: \"%{name}, %{target} kullanıcısı için iki adım gereksinimini kapattı\"\n    domain_blocks:\n      add_new: Yeni ekle\n      created_msg: Domain bloğu şu an işleniyor\n      destroyed_msg: Domain bloğu silindi\n      new:\n        create: Yeni blok oluştur\n        hint: Domain bloğu, veri tabanında hesap kayıtlarının oluşturulmasını engellemez, fakat o hesapların üzerine otomatik olarak belirli yönetim metodlarını olarak uygular.\n        severity:\n          desc_html: \"<strong>Susturma</strong>, uygulanan hesabın gönderilerini, o hesabı takip etmeyen diğer herkese gizler. <strong>Uzaklaştırma</strong> hesabın bütün içeriğini, ortam dosyalarını ve profil verisini siler.\"\n          silence: Sustur\n          suspend: Uzaklaştır\n        title: Yeni domain bloğu\n      reject_media: Ortam dosyalarını reddetme\n      reject_media_hint: Yerel olarak depolanmış ortam dosyalarını ve gelecekte indirilecek olanları reddeder. Uzaklaştırma için uygun değildir\n      show:\n        affected_accounts:\n          one: Veritabanındaki bir hesap etkilendi\n          other: Veritabanındaki %{count} hesap etkilendi\n        retroactive:\n          silence: Bu domaindeki tüm hesapların üzerindeki susturulma işlemini kaldır\n          suspend: Bu domaindeki tüm hesapların üzerindeki uzaklaştırma işlemini kaldır\n        title: \"%{domain} domain'i için yapılan işlemi geri al\"\n        undo: Geri al\n      undo: Geri al\n    instances:\n      title: Bilinen Sunucular\n    reports:\n      comment:\n        none: Yok\n      mark_as_resolved: Giderildi olarak işaretle\n      report: 'Şikayet #%{id}'\n      reported_account: Şikayet edilen hesap\n      reported_by: Şikayet eden\n      resolved: Giderildi\n      status: Durum\n      title: Şikayetler\n      unresolved: Giderilmedi\n    settings:\n      contact_information:\n        email: Herkese açık e-posta adresiniz\n        username: Bir kullanıcı adı giriniz\n      registrations:\n        closed_message:\n          desc_html: Kayıt alımları kapatıldığında ana sayfada görüntülenecek mesajdır. <br> HTML etiketleri kullanabilirsiniz\n          title: Kayıt alımları kapatılma mesajı\n      site_description:\n        desc_html: Ana sayfada paragraf olarak görüntülenecek bilgidir.<br>Özellikle <code>&lt;a&gt;</code> ve <code>&lt;em&gt;</code> olmak suretiyle HTML etiketlerini kullanabilirsiniz.\n        title: Site açıklaması\n      site_description_extended:\n        desc_html: Harici bilgi sayfasında gösterilir.<br>HTML etiketleri girebilirsiniz\n        title: Sunucu hakkında detaylı bilgi\n      site_title: Site başlığı\n      title: Site Ayarları\n    subscriptions:\n      callback_url: Callback linki\n      confirmed: Onaylandı\n      expires_in: Bitiş Tarihi\n      last_delivery: Son gönderim\n      topic: Konu\n    tags:\n      accounts: Hesaplar\n      name: Etiketler\n      title: Etiketler\n    title: Yönetim\n    warning_presets:\n      add_new: Yeni ekle\n      delete: Sil\n      edit: Düzenle\n  application_mailer:\n    settings: 'E-mail tercihlerini değiştir: %{link}'\n    view: 'Görüntüle:'\n  applications:\n    invalid_url: Verilen URL geçerli değil\n  auth:\n    didnt_get_confirmation: Hesap doğrulama mailini almadınız mı?\n    forgot_password: Parolanızı unuttunuz mu?\n    login: Giriş yap\n    logout: Çıkış\n    register: Üye ol\n    resend_confirmation: Doğrulama mailini tekrar gönder\n    reset_password: Parolayı değiştir\n    security: Kimlik bilgileri\n    set_new_password: Yeni parola oluştur\n  authorize_follow:\n    error: Uzak hesap aranırken bir hata oluştu\n    follow: Takip et\n    title: \"%{acct}'i takip et\"\n  datetime:\n    distance_in_words:\n      about_x_hours: \"%{count}sa\"\n      about_x_months: \"%{count}ay\"\n      about_x_years: \"%{count}yıl\"\n      almost_x_years: \"%{count}yıl\"\n      half_a_minute: Şimdi\n      less_than_x_minutes: \"%{count}ay\"\n      less_than_x_seconds: Şimdi\n      over_x_years: \"%{count}yıl\"\n      x_days: \"%{count}gün\"\n      x_minutes: \"%{count}dk\"\n      x_months: \"%{count}ay\"\n      x_seconds: \"%{count}sn\"\n  errors:\n    '403': Bu sayfayı görmek için izniniz yok.\n    '404': Aradığınız sayfa bulunamadı.\n    '410': Aradığınız sayfa artık yok.\n    '422':\n      content: Güvenlik doğrulaması başarısız oldu. Site cookie'lerini engellemiş olabilirsiniz.\n      title: Güvenlik doğrulamasu başarısız\n    '429': Throttled\n    '500': \n  exports:\n    blocks: Blokladıklarınız\n    follows: Takip ettikleriniz\n    mutes: Susturduklarınız\n    storage: Ortam deposu\n  generic:\n    changes_saved_msg: Değişiklikler başarıyla kaydedildi!\n    save_changes: Değişiklikleri kaydet\n    validation_errors:\n      one: Bir şeyler ters gitti! Lütfen aşağıdaki hatayı gözden geçiriniz\n      other: Bir şeyler ters gitti! Lütfen aşağıdaki %{count} hatayı gözden geçiriniz\n  imports:\n    preface: Diğer sunucudan alarak oluşturduğunuz dosyalar sayesinde, bu sunucudaki hesabınıza takipçilerinizi aktarabilir veya istemediğiniz kişileri otomatik olarak engelleyebilirsiniz.\n    success: Verileriniz başarıyla yüklendi ve zaman içinde işlenecek\n    types:\n      blocking: Engellenenler listesi\n      following: Takip edilenler listesi\n      muting: Susturulanlar listesi\n    upload: Yükle\n  invites:\n    expires_in:\n      '1800': 30 minutes\n      '21600': 6 hours\n      '3600': 1 hour\n      '43200': 12 hours\n      '604800': 1 week\n      '86400': 1 day\n  media_attachments:\n    validations:\n      images_and_video: Halihazırda görsel içeren bir gönderiye video ekleyemezsiniz\n      too_many: 4'ten fazla dosya ekleyemezsiniz\n  notification_mailer:\n    digest:\n      body: Son ziyaretiniz olan %{since}'den beri'da kaçırdığınız şeylerin özeti\n      mention: \"%{name} senden bahsetti:\"\n      new_followers_summary:\n        one: Yeni bir takipçiniz var!\n        other: Yeni %{count} takipçiniz var!\n      subject:\n        one: \"Son ziyaretinizden beri 1 yeni bildiriminiz var \\U0001F418\"\n        other: \"Son ziyaretinizden beri %{count} yeni bildiriminiz var \\U0001F418\"\n    favourite:\n      body: \"%{name} durumunuzu favorilere ekledi:\"\n      subject: \"%{name} favorilere ekledi\"\n    follow:\n      body: \"%{name} sizi takip etmeye başladı!\"\n      subject: \"%{name} sizi takip etmeye başladı\"\n    follow_request:\n      body: \"%{name} size takip isteği gönderdi\"\n      subject: 'Takip isteği: %{name}'\n    mention:\n      body: \"%{name} sizden bahsetti:\"\n      subject: \"%{name} sizden bahsetti\"\n    reblog:\n      body: \"%{name} durumunuzu boost etti:\"\n      subject: \"%{name} durumunuzu boost etti\"\n  pagination:\n    next: Sonraki\n    prev: Önceki\n  remote_follow:\n    acct: Takip edeceğiniz kişiyi kullaniciadi@sunuculinki şeklinde giriniz\n    missing_resource: Hesabınız için yönlendirme linki bulunamadı\n    proceed: Takip onayı\n    prompt: Bu kullanıcıyı takip etmek istediğinize emin misiniz?\n  settings:\n    authorized_apps: Yetkilendirilen uygulamalar\n    back: Mastodon'a geri dön\n    edit_profile: Profili düzenle\n    export: Dışa aktar\n    import: İçe aktar\n    preferences: Tercihler\n    two_factor_authentication: İki-faktörlü doğrulama\n  statuses:\n    open_in_web: Web sayfasında aç\n    over_character_limit: \"%{max} karakter limiti aşıldı\"\n    show_more: Daha fazla\n    visibilities:\n      private: Sadece takipçiler\n      private_long: Sadece takipçilerime gönder\n      public: Herkese açık\n      public_long: Herkese açık zaman tüneline gönder\n      unlisted: Listelenmemiş\n      unlisted_long: Herkes görebilir fakat herkese açık zaman tünellerinde listelenmez\n  stream_entries:\n    reblogged: boost edildi\n    sensitive_content: Hassas içerik\n  two_factor_authentication:\n    code_hint: Onaylamak için kimlik doğrulama uygulamanızın oluşturduğu kodu giriniz\n    description_html: Eğer <strong>iki-faktörlü kimlik doğrulamayı</strong> aktif ederseniz, giriş yaparken sizin için giriş kodu üreten telefonunuza ihtiyaç duyacaksınız.\n    disable: Devre dışı bırak\n    enable: Aktifleştir\n    enabled_success: İki-faktörlü kimlik doğrulama başarıyla aktif edildi\n    generate_recovery_codes: Kurtarma Kodlarını Oluştur\n    instructions_html: <strong>Bu QR kodunu, telefonunuzdaki <a href=\"https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2\">Google Authenticator</a> veya benzer bir TOTP uygulamasıyla taratınız</strong>. Bundan sonra giriş yaparken uygulamanın ürettiği kodu kullanarak giriş yapacaksınız.\n    lost_recovery_codes: Kurtarma kodları telefonunuzu kaybettiğiniz durumlarda hesabınıza erişim yapabilmenize olanak tanır. Eğer kurtarma kodlarınızı kaybettiyseniz burada tekrar oluşturabilirsiniz. Eski kurtarma kodlarınız geçersiz hale gelecektir.\n    manual_instructions: 'Eğer QR kodunu taratamıyorsanız ve elle giriş yapmanız gerekiyorsa buradaki gizli düz metni girebilirsiniz:'\n    recovery_codes_regenerated: Kurtarma kodları başarıyla oluşturuldu\n    recovery_instructions_html: 'Eğer telefonunuza erişiminizi kaybederseniz, aşağıdaki kurtarma kodlarından birini kullanarak hesabınıza giriş yapabilirsiniz. Kurtarma kodlarınızı güvenli halde tutunuz. Örneğin: kodların çıktısını alıp diğer önemli belgeleriniz ile birlikte saklayabilirsiniz.'\n    setup: Kuruluma başla\n    wrong_code: Girdiğiniz kod geçersiz! Telefonunuzun saati geri/ileri kalmış olabilir.\n  users:\n    invalid_email: E-posta adresiniz geçersiz\n    invalid_otp_token: İki-faktörlü kodunuz geçersiz\n"
  },
  {
    "path": "config/locales/uk.yml",
    "content": "---\nuk:\n  about:\n    about_hashtag_html: Немає публічних постів з хештегом<strong>#%{hashtag}</strong>. Ви можете  You can interact with them if you have an account anywhere in the fediverse.\n    about_mastodon_html: Mastodon - це <em>вільна</em> соціальна мережа з <em>відкритим вихідним кодом</em>. Вона є <em>децентралізованою</em> альтернативою комерційним платформам, що дозволяє уникнути ризиків монополізації вашого спілкування однією компанією. Виберіть сервер, якому ви довіряєте &mdash; що б ви не вибрали, Ви зможете спілкуватись з усіма іншими. Будь-який користувач може запустити власну інстанцію Mastodon та без проблем брати участь в <em>соціальній мережі</em>.\n    about_this: Про цю інстанцію\n    administered_by: 'Адміністратор:'\n    contact: Зв'язатися\n    contact_missing: Не зазначено\n    contact_unavailable: Недоступно\n    documentation: Документація\n    extended_description_html: |\n      <h3>Гарне місце для правил</h3>\n      <p>Детальний опис ще не налаштований.</p>\n    generic_description: \"%{domain} є одним сервером у мережі\"\n    hosted_on: Mastodon розміщено на %{domain}\n    learn_more: Дізнатися більше\n    privacy_policy: Політика приватності\n    source_code: Вихідний код\n    status_count_before: Опубліковано\n    terms: Правила використання\n    user_count_before: Тут живе\n    what_is_mastodon: Що таке Mastodon?\n  accounts:\n    follow: Підписатися\n    following: Підписаний(-а)\n    joined: Приєднався %{date}\n    media: Медіа\n    moved_html: \"%{name} переїхав на %{new_profile_link}:\"\n    network_hidden: Ця інформація недоступна\n    nothing_here: Тут нічого немає!\n    people_followed_by: Люди, на яких підписаний(-а) %{name}\n    people_who_follow: Підписники %{name}\n    posts_with_replies: Пости і відповіді\n    reserved_username: Це ім'я користувача зарезервоване\n    roles:\n      admin: Адміністратор\n      bot: Бот\n      moderator: Мод\n    unfollow: Відписатися\n  admin:\n    account_moderation_notes:\n      create: Залишити примітки\n      created_msg: Примітку модератора успішно створено!\n      delete: Видалити\n      destroyed_msg: Примітку модератора успішно видалено!\n    accounts:\n      are_you_sure: Ви впевнені?\n      avatar: Аватар\n      by_domain: Домен\n      change_email:\n        changed_msg: Поштова адреса аккаунту успішно змінена!\n        current_email: Поточна поштова адреса\n        label: Змінити поштову адресу\n        new_email: Новий e-mail\n        submit: Змінити поштову адресу\n        title: Змінити поштову адресу для %{username}\n      confirm: Зберегти\n      confirmed: Збережено\n      confirming: Зберігається\n      demote: Усунути\n      disable: Вимкнути\n      disable_two_factor_authentication: Вимкнути двофакторну авторизацію\n      disabled: Вимкнено\n      display_name: Відображуване ім'я\n      domain: Домен\n      edit: Змінити\n      email_status: Статус e-mail\n      enable: Увімкнути\n      enabled: Увімкнено\n      feed_url: URL фіду\n      followers: Підписники\n      followers_url: URL підписників\n      follows: Підписки\n      inbox_url: Вхідний URL\n      location:\n        all: Усі\n        local: Локальні\n        remote: Віддалені\n        title: Розміщення\n      login_status: Статус авторизації\n      media_attachments: Мультимедійні вкладення\n      memorialize: Зробити пам'ятником\n      moderation:\n        all: Усі\n        silenced: Заглушені\n        suspended: Заблоковані\n        title: Модерація\n      moderation_notes: Примітки модераторів\n      most_recent_activity: Остання активність\n      most_recent_ip: Останній IP\n      not_subscribed: Не підписані\n      outbox_url: Вихідний URL\n      perform_full_suspension: Повне блокування\n      profile_url: URL профілю\n      promote: Просунути\n      protocol: Протокол\n      public: Публічний\n      push_subscription_expires: Підписка PuSH спливає\n      redownload: Оновити аватар\n      remove_avatar: Видалити аватар\n      resend_confirmation:\n        already_confirmed: Цей користувач уже підтверджений\n        send: Надіслати підтвердження ще раз\n        success: Повідомлення з підтвердженням успішно надіслано!\n      reset: Скинути\n      reset_password: Зкинути пароль\n      resubscribe: Перепідписатися\n      role: Дозволи\n      roles:\n        admin: Адміністратор\n        moderator: Модератор\n        staff: Персонал\n        user: Користувач\n      search: Пошук\n      shared_inbox_url: URL спільного вхідного кошика\n      show:\n        created_reports: Скарги створені цим аккаунтом\n        targeted_reports: Скарги щодо цього аккаунту\n      silence: Глушення\n      statuses: Статуси\n      subscribe: Підписатися\n      title: Акаунти\n      unconfirmed_email: Непідтверджений e-mail\n      undo_silenced: Зняти глушення\n      undo_suspension: Зняти блокування\n      unsubscribe: Відписатися\n      username: Ім'я користувача\n      web: WWW\n    action_logs:\n      actions:\n        assigned_to_self_report: \"%{name} призначив(-ла) скаргу %{target} на себе\"\n        change_email_user: \"%{name} змінив(-ла) поштову адресу користувача %{target}\"\n        confirm_user: \"%{name} підтвердив(-ла) статус поштової адреси користувача %{target}\"\n        create_custom_emoji: \"%{name} вивантажив(-ла) нове емодзі %{target}\"\n        create_domain_block: \"%{name} заблокував(-ла) домен %{target}\"\n        create_email_domain_block: \"%{name} додав(-ла) поштовий домен %{target} до чорного списку\"\n        demote_user: \"%{name} понизив(-ла) %{target}\"\n        destroy_domain_block: \"%{name} розблокував(-ла) домен %{target}\"\n        destroy_email_domain_block: \"%{name} додав(-ла) поштовий домен %{target} до білого списку\"\n        destroy_status: \"%{name} видалив(-ла) статус користувача %{target}\"\n        disable_2fa_user: \"%{name} вимкнув(-ла) двофакторну авторизацію для користувача %{target}\"\n        disable_custom_emoji: \"%{name} вимкнув(-ла) емодзі %{target}\"\n        disable_user: \"%{name} заборонив(-ла) авторизацію користувачу %{target}\"\n        enable_custom_emoji: \"%{name} увімкнув(-ла) емодзі %{target}\"\n        enable_user: \"%{name} увімкнув(-ла) авторизацію користувачу %{target}\"\n        memorialize_account: \"%{name} перетворив(-ла) сторінку %{target} у пам'ятник\"\n        promote_user: \"%{name} підвищив(-ла) користувача %{target}\"\n        remove_avatar_user: \"%{name} прибрав(-ла) аватар користувача %{target}\"\n        reopen_report: \"%{name} перевідкрив(-ла) скаргу %{target}\"\n        reset_password_user: \"%{name} скинув(-ла) пароль користувача %{target}\"\n        resolve_report: \"%{name} розв'язав(-ла) скаргу %{target}\"\n        silence_account: \"%{name} заглушив(-ла) аккаунт %{target}\"\n        suspend_account: \"%{name} заблокував аккаунт користувача %{target}\"\n        unassigned_report: \"%{name} зняв(-ла) призначення скарги %{target}\"\n        unsilence_account: \"%{name} розглушив(-ла) аккаунт %{target}\"\n        unsuspend_account: \"%{name} розблокував аккаунт користувача %{target}\"\n        update_custom_emoji: \"%{name} оновив(-ла) емодзі %{target}\"\n        update_status: \"%{name} змінив(-ла) статус користуача %{target}\"\n      title: Журнал подій\n    custom_emojis:\n      by_domain: Домен\n      copied_msg: Локальна копія емодзі успішно створена\n      copy: Копіювати\n      copy_failed_msg: Не вийшло створити локальну копію емодзі\n      created_msg: Емодзі успішно створене!\n      delete: Видалити\n      destroyed_msg: Емодзі усіпішно видалене!\n      disable: Вимкнути\n      disabled_msg: Емодзі успішно вимкнено\n      emoji: Емодзі\n      enable: Увімкнути\n      enabled_msg: Емодзі успішно увімкнене\n      image_hint: PNG розміром до 50 КБ\n      listed: У списку\n      new:\n        title: Додати новий емодзі\n      overwrite: Переписати\n      shortcode: Шорткод\n      shortcode_hint: Мінімум два символи, тільки цифрові й латинські символи або нижні підкреслення\n      title: Особливі емодзі\n      unlisted: Не у списку\n      update_failed_msg: Не вийшло оновити емозді\n      updated_msg: Емодзі успішно оновлене!\n      upload: Вивантажити\n    dashboard:\n      config: Налаштування\n      feature_deletions: Видалення аккаунтів\n      feature_invites: Посилання-запрошення\n      feature_registrations: Реєстрації\n      features: Можливості\n      hidden_service: Федерація з прихованими сервісами\n      open_reports: відкриті скарги\n      recent_users: Останні користувачі\n      search: Повнотекстовий пошук\n      single_user_mode: Режим одного користувача\n      software: Програмне забезпечення\n      space: Використання дискового простору\n      title: Дашборд\n      total_users: користувачів загалом\n      trends: Тренди\n      week_interactions: дій за цей тиждень\n      week_users_active: активно протягом тижня\n      week_users_new: користувачів цього тижня\n    domain_blocks:\n      add_new: Додати нове\n      created_msg: Блокування домену оброблюється\n      destroyed_msg: Блокування домену знято\n      domain: Домен\n      new:\n        create: Створити блокування\n        hint: Блокування домену не завадить створенню нових акаунтів у базі даних, але ретроактивно та автоматично застосує вказані методи модерації для цих акаунтів.\n        severity:\n          desc_html: \"<strong>Глушення</strong> зробить статуси акаунту невидимими для всіх, окрім їхніх підписників. <strong>Блокування</strong> видалить увесь контент акаунту, включаючи мультимедійні вкладення та дані профілю.\"\n          noop: Нічого\n          silence: Глушення\n          suspend: Блокування\n        title: Нове блокування домену\n      reject_media: Заборонити медіаконтент\n      reject_media_hint: Видаляє медіаконтент, збережений локально, і забороняє його завантаження у майбутньому. Не має значення у випадку блокування\n      show:\n        affected_accounts:\n          few: Впливає на %{count} акаунти у базі даних\n          many: Впливає на %{count} акаунтів у базі даних\n          one: Впливає на один акаунт у базі даних\n          other: Впливає на %{count} акаунтів у базі даних\n        retroactive:\n          silence: Зняти глушення з усіх існуючих акаунтів цього домену\n          suspend: Зняти блокування з усіх існуючих акаунтів цього домену\n        title: Зняти блокування з домена %{domain}\n        undo: Відмінити\n      undo: Відмінити\n    email_domain_blocks:\n      add_new: Додати\n      created_msg: Успішно додано поштовий домен до чорного списку\n      delete: Видалити\n      destroyed_msg: Успішно видалено поштовий домен з чорного списку\n      domain: Домен\n      new:\n        create: Додати домен\n        title: Нове доменне блокування домену email\n      title: Чорний список поштових доменів\n    instances:\n      title: Відомі інстанції\n    invites:\n      filter:\n        all: Все\n        available: Доступно\n        expired: Просрочено\n        title: Фільтр\n      title: Запрошення\n    relays:\n      status: Статус\n    report_notes:\n      created_msg: Скарга успішно створена!\n      destroyed_msg: Скарга успішно видалена!\n    reports:\n      account:\n        note: примітка\n        report: скарга\n      action_taken_by: Дія виконана\n      are_you_sure: Ви впевнені?\n      assign_to_self: Призначити мені\n      assigned: Призначений модератор\n      comment:\n        none: Немає\n      created_at: Створено\n      mark_as_resolved: Відмітити як вирішену\n      mark_as_unresolved: Відмітити як невирішену\n      notes:\n        create: Додати примітку\n        create_and_resolve: Розв'язати з приміткою\n        create_and_unresolve: Перевідкрити з приміткою\n        delete: Видалити\n        placeholder: Опишіть, які дії були виконані, або інші зміни, що стосуються справи...\n      reopen: Перевідкрити скаргу\n      report: 'Скарга #%{id}'\n      reported_account: Акаунт порушника\n      reported_by: Відправник скарги\n      resolved: Вирішено\n      resolved_msg: Скаргу успішно вирішено!\n      status: Статус\n      title: Скарги\n      unassign: Зняти призначення\n      unresolved: Невирішені\n      updated_at: Оновлені\n    settings:\n      activity_api_enabled:\n        desc_html: Кількість локальних постів, активних та нових користувачів у тижневих розрізах\n        title: Публікація агрегованої статистики про активність користувачів\n      bootstrap_timeline_accounts:\n        title: Підписки за замовчуванням для нових користувачів\n      contact_information:\n        email: Введіть публічний email\n        username: Введіть ім'я користувача\n      hero:\n        desc_html: Відображається на головній сторінці. Рекомендована як мінімум 600x100 пікселів. Якщо не вказано, буде використано передпоказ інстанції\n        title: Банер інстанції\n      peers_api_enabled:\n        desc_html: Доменні ім'я, помічені цією інстанцією федисвіту\n        title: Опублікувати список знайдених інстанцій\n      preview_sensitive_media:\n        desc_html: Передпоказ посилання на інших сайтах буде відображати мініатюру навіть якщо медіа відмічене як вразливе\n        title: Показувати вразливе медія у перепоказі OpenGraph\n      registrations:\n        closed_message:\n          desc_html: Відображається на титульній сторінці, коли реєстрація закрита <br>Можна використовувати HTML-теги\n          title: Повідомлення про закриту реєстрацію\n        deletion:\n          desc_html: Дозволити будь-кому видаляти свій аккаунт\n          title: Дозволити видалення аккаунтів\n        min_invite_role:\n          disabled: Ніхто\n          title: Дозволити запрошення від\n      show_known_fediverse_at_about_page:\n        desc_html: Коли увімкнено, будуть показані пости з усього відомого федисвіту у передпоказі. Інакше будуть показані локальні пости.\n        title: Показувати доступний федисвіт у передпоказі фіду\n      show_staff_badge:\n        desc_html: Відмічати персонал на сторінці користувачів\n        title: Показувати персонал\n      site_description:\n        desc_html: Відображається у якості параграфа на титульній сторінці та використовується у якості мета-тега.<br>Можна використовувати HTML-теги, особливо <code>&lt;a&gt;</code> і <code>&lt;em&gt;</code>.\n        title: Опис інстанції\n      site_description_extended:\n        desc_html: Відображається на сторінці додаткової информації<br>Можна використовувати HTML-теги\n        title: Розширений опис сайту\n      site_terms:\n        desc_html: |-\n          Ви можене написати власну політику приватності, умови використанні та інші законні штуки<br>\n          Можете використовувати HTML теги\n        title: Особливі умови використання\n      site_title: Назва сайту\n      thumbnail:\n        desc_html: Використовується для передпоказів через OpenGraph та API. Бажано розміром 1200х640 пікселів\n        title: Мініатюра інстанції\n      timeline_preview:\n        desc_html: Показувати публічний фід на головній сторінці\n        title: Передпоказ фіду\n      title: Налаштування сайту\n    statuses:\n      back_to_account: Назад на сторінку профілю\n      batch:\n        delete: Видалити\n        nsfw_off: Відмітити сприйнятливим\n        nsfw_on: Відмітити несприйнятливим\n      failed_to_execute: Не вийшло\n      media:\n        title: Медіа\n      no_media: Немає медіа\n      title: Статуси аккаунтів\n      with_media: З медіа\n    subscriptions:\n      confirmed: Підтверджено\n      expires_in: Спливає через\n      last_delivery: Остання доставка\n      topic: Тема\n    title: Адміністрування\n  admin_mailer:\n    new_report:\n      body: \"%{reporter} поскаржився(-лася) %{target}\"\n      body_remote: Хтось з домену %{domain} поскаржився(-лася) %{target}\n      subject: Нова скарга до %{instance} (#%{id})\n  application_mailer:\n    notification_preferences: Змінити налаштування e-mail\n    settings: 'Змінити налаштування e-mail: %{link}'\n    view: 'Перегляд:'\n    view_profile: Показати профіль\n    view_status: Показати статус\n  applications:\n    created: Застосунок успішно створений\n    destroyed: Застосунок успішно видалений\n    invalid_url: Введена URL неправильна\n    regenerate_token: Перегенерувати токен доступу\n    token_regenerated: Токен доступу успішне перегенеровано\n    warning: Будьте дуже обережні з цими даними. Ніколи не діліться ними ні з ким!\n    your_token: Ваш токен доступу\n  auth:\n    change_password: Пароль\n    confirm_email: Підтвердьте e-mail адресу\n    delete_account: Видалити аккаунт\n    delete_account_html: Якщо ви хочете видалити аккаунт, ви можете <a href=\"%{path}\">перейти сюди</a>. Вас попросять підтвердити дію.\n    didnt_get_confirmation: Ви не отримали інструкції з підтвердження?\n    forgot_password: Забули свій пароль?\n    invalid_reset_password_token: Токен скидання паролю неправильний або просрочений. Спробуйте попросити новий.\n    login: Увійти\n    logout: Вийти\n    migrate_account: Переїхати до іншого аккаунту\n    migrate_account_html: Якщо ви бажаєте, щоб відвідувачі цього акканту були перенаправлені до іншого, ви можете <a href=\"%{path}\">налаштувати це тут</a>.\n    or_log_in_with: Або увійдіть з\n    register: Зареєструватися\n    resend_confirmation: Повторно відправити інструкції з підтвердження\n    reset_password: Скинути пароль\n    security: Зміна паролю\n    set_new_password: Встановити новий пароль\n  authorize_follow:\n    already_following: Ви вже підписані на цей аккаунт\n    error: На жаль, при пошуку віддаленого аккаунту виникла помилка\n    follow: Підписатися\n    follow_request: 'Вам надіслали запит на підписку:'\n    following: 'Ура! Ви тепер підписані на:'\n    post_follow:\n      close: Або, ви можете просто закрити вікно.\n      return: Перейти до профілю користувача\n      web: Перейти до вебу\n    title: Підписатися на %{acct}\n  datetime:\n    distance_in_words:\n      about_x_hours: \"%{count}г\"\n      about_x_months: \"%{count}міс\"\n      about_x_years: \"%{count}р\"\n      almost_x_years: \"%{count}р\"\n      half_a_minute: Щойно\n      less_than_x_minutes: \"%{count}хв\"\n      less_than_x_seconds: Щойно\n      over_x_years: \"%{count}р\"\n      x_days: \"%{count}д\"\n      x_minutes: \"%{count}хв\"\n      x_months: \"%{count}міс\"\n      x_seconds: \"%{count}сек\"\n  deletes:\n    bad_password_msg: Гарна спроба, гакери! Неправильний пароль\n    confirm_password: Введіть актуальний пароль щоб перевірити що ви це ви\n    description_html: Це <strong>безвідворотно і назавжди</strong> видалить контент з вашого аккаунту та деактивує його. Ваше ім'я користувача буде залишатися зарезервованим для уникнення вашої деперсоналізації.\n    proceed: Видалити аккаунт\n    success_msg: Ваш аккаунт було успішно видалено\n    warning_html: Ми можемо гарантувати видалення контенти <b>лише з цього сайту</b>. Контент, що був поширений залишає сліди. Сервери, що є офлайн та ті, що відписалися від наших оновлень не запишуть змін до своїх баз даних.\n    warning_title: Про доступність поширеного контенту\n  errors:\n    '403': У Вас немає доступу до перегляду даної сторінки.\n    '404': Сторінка, яку Ви шукали, не існує.\n    '410': Сторінка, яку Ви шукали, більше не існує.\n    '422':\n      content: Перевірка безпеки не вдалася. Можливо, Ви блокуєте cookies?\n      title: Перевірка безпеки не вдалася\n    '429': Забагато запитів\n    '500':\n      content: Пробачте, та щось пішло не так з нашого боку.\n      title: Ця сторінка неправильна\n    noscript_html: Для використання веб-застосунку Mastodon, будь-ласка увімкніть JavaScript. Якщо у вас немає такої можливості, скористайтесь одним із <a href=\"%{apps_path}\">нативних застосунків</a> для Mastodon для вашої платформи.\n  exports:\n    archive_takeout:\n      date: Дата\n      download: Завантажити ваш архів\n      hint_html: Ви можете зробити запит на архів ваших <strong>постів та вивантаженого медіа контенту</strong>. Завантажені дані будуть у форматі ActivityPub, доступні для читання будь-яким сумісним програмним забезпеченням. Ви можете робити запит на архів кожні 7 днів.\n      in_progress: Збираємо ваш архів...\n      request: Зробити запит на архів\n      size: Розмір\n    blocks: Список блокувань\n    follows: Підписки\n    mutes: Список глушення\n    storage: Ваш медіаконтент\n  filters:\n    contexts:\n      home: Ваш фід\n      notifications: Сповіщення\n      public: Публічний фід\n      thread: Повідомлення\n    edit:\n      title: Редагувати фільтр\n    errors:\n      invalid_context: Контекст неправильний або не був наданий\n      invalid_irreversible: Незворотне фільтрування працює тільки в контексті свого фіду або сповіщень\n    index:\n      delete: Видалити\n      title: Фільтри\n    new:\n      title: Додати фільтр\n  generic:\n    changes_saved_msg: Зміни успішно збережені!\n    save_changes: Зберегти зміни\n  imports:\n    preface: Вы можете завантажити деякі дані, наприклад, списки людей, на яких Ви підписані чи яких блокуєте, в Ваш акаунт на цій інстанції з файлів, експортованих з іншої інстанції.\n    success: Ваші дані були успішно загружені та будуть оброблені в найближчий момент\n    types:\n      blocking: Список блокувань\n      following: Підписки\n      muting: Список глушення\n    upload: Завантажити\n  in_memoriam_html: Пам'ятник.\n  invites:\n    delete: Деактивувати\n    expired: Вийшов\n    expires_in:\n      '1800': 30 хвилин\n      '21600': 6 годин\n      '3600': 1 година\n      '43200': 12 годин\n      '604800': 1 тиждень\n      '86400': 1 день\n    expires_in_prompt: Ніколи\n    generate: Згенерувати\n    invited_by: 'Вас запросив(-ла):'\n    max_uses_prompt: Без обмеження\n    prompt: Генеруйте та діліться посиланням з іншими для надання доступу до сайту\n    table:\n      expires_at: Час роботи\n      uses: Використання\n    title: Запросити людей\n  lists:\n    errors:\n      limit: Ви досягнули максимальної кількості списків\n  media_attachments:\n    validations:\n      images_and_video: Не можна додати відео до статусу з зображеннями\n      too_many: Не можна додати більше 4 файлів\n  migrations:\n    acct: username@domain нового аккаунту\n    currently_redirecting: 'Ваш профіль налаштований перенаправляти на:'\n    proceed: Зберегти\n    updated_msg: Переїзд вашого аккаунту успішно оновлений!\n  moderation:\n    title: Модерація\n  notification_mailer:\n    digest:\n      action: Показати усі сповіщення\n      body: Коротко про пропущене вами з Вашого останнього входу %{since}\n      mention: \"%{name} згадав(-ла) Вас в:\"\n      new_followers_summary:\n        few: У Вас з'явилось %{count} нових підписники! Чудово!\n        many: У Вас з'явилось %{count} нових підписників! Чудово!\n        one: Також, у Вас з'явився новий підписник, коли ви були відсутні! Ура!\n        other: Також, у Вас з'явилось %{count} нових підписників, поки ви були відсутні! Чудово!\n      subject:\n        few: \"%{count} нові сповіщення з Вашого останнього входу \\U0001F418\"\n        many: \"%{count} нових сповіщень з Вашого останнього входу \\U0001F418\"\n        one: \"1 нове сповіщення з Вашого останнього входу \\U0001F418\"\n        other: \"%{count} нових сповіщень з Вашого останнього входу \\U0001F418\"\n      title: Поки ви були відсутні...\n    favourite:\n      body: 'Ваш статус подобається %{name}:'\n      subject: Користувачу %{name} сподобався ваш статус\n      title: Нове вподобання\n    follow:\n      body: \"%{name} тепер підписаний на вас!\"\n      subject: \"%{name} тепер підписаний(-а) на вас\"\n      title: Новий підписник\n    follow_request:\n      action: Керувати запитами на підписку\n      body: \"%{name} запитав Вас про підписку\"\n      subject: \"%{name} хоче підписатися на Вас\"\n      title: Новий запит на підписку\n    mention:\n      action: Відповісти\n      body: 'Вас згадав(-ла) %{name} в:'\n      subject: Вас згадав(-ла) %{name}\n      title: Нова згадка\n    reblog:\n      body: 'Ваш статус було передмухнуто %{name}:'\n      subject: \"%{name} передмухнув ваш статус\"\n      title: Нове передмухування\n  number:\n    human:\n      decimal_units:\n        units:\n          billion: млрд\n          million: млн\n          quadrillion: квдрл\n          thousand: тис\n          trillion: трлн\n  pagination:\n    newer: Новіше\n    next: Далі\n    prev: Назад\n  preferences:\n    other: Інше\n  remote_follow:\n    acct: Введіть username@domain, яким ви хочете підписатися\n    missing_resource: Пошук потрібного перенаправлення URL для Вашого аккаунта закінчився невдачею\n    no_account_html: Не маєте аккаунту? Не біда, ви можете <a href='%{sign_up_path}' target='_blank'>зареєструватися</a>\n    proceed: Перейти до підписки\n    prompt: 'Ви хочете підписатися на:'\n  remote_unfollow:\n    error: Помилка\n    title: Заголовок\n    unfollowed: Відписані\n  sessions:\n    activity: Остання активність\n    browser: Браузер\n    browsers:\n      generic: Невідомий браузер\n    current_session: Активна сесія\n    description: \"%{browser} на %{platform}\"\n    explanation: Це веб-браузери, нині авторизовані до вашого аккаунту Mastodon.\n    platforms:\n      other: невідома платформа\n    revoke: Закінчити\n    revoke_success: Сесія успішно закінчена\n    title: Сесії\n  settings:\n    authorized_apps: Авторизовані застосунки\n    back: Назад у Mastodon\n    delete: Видалення аккаунту\n    development: Розробка\n    edit_profile: Редагувати профіль\n    export: Експорт даних\n    import: Імпорт\n    migrate: Міграція акаунту\n    notifications: Сповіщення\n    preferences: Налаштування\n    two_factor_authentication: Двофакторна авторизація\n  statuses:\n    attached:\n      description: 'Прикріплено: %{attached}'\n    boosted_from_html: Просунуто від %{acct_link}\n    content_warning: 'Попередження про контент: %{warning}'\n    language_detection: Автоматично визначати мову\n    open_in_web: Відкрити у вебі\n    over_character_limit: перевищено ліміт символів (%{max})\n    pin_errors:\n      limit: Ви вже закріпили максимальну кількість постів\n      ownership: Не можна закріпити чужий пост\n      private: Не можна закріпити непублічний пост\n      reblog: Не можна закріпити просунутий пост\n    show_more: Детальніше\n    visibilities:\n      private: Для підписників\n      private_long: Показувати тільки підписникам\n      public: Для всіх\n      public_long: Показувати всім\n      unlisted: Приховувати зі стрічок\n      unlisted_long: Показувати всім, але не відображати в публічних стрічках\n  stream_entries:\n    pinned: Закріплений пост\n    reblogged: передмухнув(-ла)\n    sensitive_content: Несприйнятливий контент\n  terms:\n    title: Умови використання та Політика приватності %{instance}\n  themes:\n    contrast: Висока контрасність\n    default: Mastodon\n    mastodon-light: Mastodon (світла)\n  two_factor_authentication:\n    code_hint: Для підтверждення введіть код, згенерований застосунком аутентифікатора\n    description_html: При увімкненні <strong>двофакторної аутентифікації</strong>, вхід буде вимагати від Вас використовування Вашого телефона, який згенерує вхідний код.\n    disable: Вимкнути\n    enable: Увімкнути\n    enabled: Двофакторна аутентифікація увімкнена\n    enabled_success: Двофакторна аутентифікація успішно увімкнена\n    generate_recovery_codes: Згенерувати коди відновлення\n    instructions_html: \"<strong>Відскануйте цей QR-код за допомогою Google Authenticator чи іншого TOTP-застосунку на Вашому телефоні</strong>. З цього моменту він буде генерувати коди, які буде необхідно ввести для входу.\"\n    lost_recovery_codes: Коди відновлення дозволяють повернути доступ до акаунту у випадку втрати телефону. Якщо Ви втратили Ваші коди відновлення, Ви можете знову згенерувати їх тут. Тоді ваші старі коди відновлення будуть анульовані.\n    manual_instructions: 'Якщо Ви не можете відсканувати QR-код та хочете ввести його вручну, секрет представлений тут відкритим текстом:'\n    recovery_codes: Запасні коди відновлення\n    recovery_codes_regenerated: Коди відновлення успішно згенеровані\n    recovery_instructions_html: У випадку втрати доступу до вашого телефону ви можете використати один з кодів відновлення, вказаних нижче, щоб повернути доступ до акаунту. Тримайте коди відновлення у безпеці, наприклад, роздруйте їх та зберігайте їх з іншими важливими документами.\n    setup: Налаштувати\n    wrong_code: Введений код неправильний! Чи правильно встановлений час на сервері та пристрої?\n  user_mailer:\n    backup_ready:\n      explanation: Ви зробили запит на повний архів вашого аккаунту Mastodon. Він вже готовий для завантаження!\n      subject: Ваш архів готовий до завантаження\n      title: Винесення архіву\n    welcome:\n      edit_profile_action: Налаштувати профіль\n      edit_profile_step: Ви можете налаштувати профіль під себе завантаживши аватар, шпалери, змінивши відображуване ім'я тощо. Якщо ви захочете переглядати нових підписників до того, як вони зможуть підписатися на вас, ви можете заблокувати свій аккаунт.\n      explanation: Ось декілька порад для початку\n      final_action: Почати постити\n      final_step: 'Почність постити! Навіть не підписавшись на вас, інші зможуть побачити ваші пости, наприкоал, у локальному фіді та у хештеґах. Якщо ви хочете представитися, можете скористатися хештеґом #introductions.'\n      full_handle: Ваше звернення\n      full_handle_hint: Те, що ви хочете сказати друзям, щоб вони могли написати вам або підписатися з інших сайтів.\n      review_preferences_action: Змінити налаштування\n      review_preferences_step: Переконайтеся у тому, що ви налаштували все необхідне, як от які e-mail повідомлення ви хочете отримувати, або який рівень приватності ви хочете встановити вашим постам за замовчуванням. Якщо хочете, ви можете увімкнути автоматичне програвання GIF анімацій.\n      subject: Ласкаво просимо до Mastodon\n      tip_federated_timeline: Федерований фід є широким поглядом на мережу Mastodon. Але він включає лише людей, на яких підписані ваші сусіди по сайту, тому він не є повним.\n      tip_following: Ви автоматично підписані на адміністратора(-ів) сервера. Для того, щоб знайти ще цікавих людей, дослідіть локальний та федерований фіди.\n      tip_local_timeline: Локальний фід - це погляд згори на людей на %{instance}. Це ваші прямі сусіди!\n      tip_mobile_webapp: Якщо ваш мобільний браузер пропонує вам додати Mastodon на робочий стіл, ви можете отримувати push-сповіщення. Все може виглядати як нативний застосунок у багатьох речах.\n      tips: Поради\n      title: Ласкаво просимо, %{name}!\n  users:\n    invalid_email: Введена адреса e-mail неправильна\n    invalid_otp_token: Введено неправильний код\n    otp_lost_help_html: Якщо ви втратили доступ до обох, ви можете отримати доступ з %{email}\n"
  },
  {
    "path": "config/locales/zh-CN.yml",
    "content": "---\nzh-CN:\n  about:\n    about_hashtag_html: 这里展示的是带有话题标签 <strong>#%{hashtag}</strong> 的公开嘟文。如果你想与他们互动，你需要在任意一个 Mastodon 实例或与其兼容的网站上拥有一个帐户。\n    about_mastodon_html: Mastodon（长毛象）是一个建立在开放式网络协议和自由、开源软件之上的社交网络，有着类似于电子邮件的分布式设计。\n    about_this: 关于本实例\n    active_count_after: 活跃\n    active_footnote: 每月活跃用户\n    administered_by: 本实例的管理员：\n    apps: 移动应用\n    contact: 联系方式\n    contact_missing: 未设定\n    contact_unavailable: 未公开\n    documentation: 文档\n    extended_description_html: |\n      <h3>这里可以写一些规定</h3>\n      <p>本站尚未设置详细介绍。</p>\n    generic_description: \"%{domain} 是这个庞大网络中的一台服务器\"\n    hosted_on: 一个在 %{domain} 上运行的 Mastodon 实例\n    learn_more: 了解详情\n    privacy_policy: 隐私政策\n    source_code: 源代码\n    status_count_after:\n      other: 条嘟文\n    status_count_before: 他们共嘟出了\n    terms: 使用条款\n    user_count_after:\n      other: 位用户\n    user_count_before: 这里共注册有\n    what_is_mastodon: Mastodon 是什么？\n  accounts:\n    follow: 关注\n    followers:\n      other: 关注者\n    following: 正在关注\n    joined: 加入于 %{date}\n    media: 媒体\n    moved_html: \"%{name} 已经迁移到 %{new_profile_link}：\"\n    network_hidden: 此信息不可用\n    nothing_here: 这里神马都没有！\n    people_followed_by: \"%{name} 关注的人\"\n    people_who_follow: 关注 %{name} 的人\n    posts:\n      other: 嘟文\n    posts_tab_heading: 嘟文\n    posts_with_replies: 嘟文和回复\n    reserved_username: 此用户名已被保留\n    roles:\n      admin: 管理员\n      bot: 机器人\n      moderator: 监察员\n    unfollow: 取消关注\n  admin:\n    account_moderation_notes:\n      create: 新建\n      created_msg: 管理备忘建立成功！\n      delete: 删除\n      destroyed_msg: 管理备忘删除成功！\n    accounts:\n      are_you_sure: 你确定吗？\n      avatar: 头像\n      by_domain: 域名\n      change_email:\n        changed_msg: 帐户电子邮件地址更改成功！\n        current_email: 当前的电子邮件地址\n        label: 更改电子邮件地址\n        new_email: 新的电子邮件地址\n        submit: 更改电子邮件地址\n        title: 为 %{username} 更改电子邮件地址\n      confirm: 确认\n      confirmed: 已确认\n      confirming: 确认\n      demote: 降任\n      disable: 停用\n      disable_two_factor_authentication: 停用双重认证\n      disabled: 已停用\n      display_name: 昵称\n      domain: 域名\n      edit: 编辑\n      email: 电子邮件地址\n      email_status: 电子邮件地址状态\n      enable: 启用\n      enabled: 已启用\n      feed_url: 订阅 URL\n      followers: 关注者\n      followers_url: 关注者（Followers）URL\n      follows: 正在关注\n      inbox_url: 收件箱（Inbox）URL\n      ip: IP 地址\n      location:\n        all: 全部\n        local: 本地\n        remote: 远程\n        title: 位置\n      login_status: 登录状态\n      media_attachments: 媒体文件\n      memorialize: 设置为追悼帐户\n      moderation:\n        all: 全部\n        silenced: 已隐藏\n        suspended: 已封禁\n        title: 帐户状态\n      moderation_notes: 管理备忘\n      most_recent_activity: 最后一次活跃的时间\n      most_recent_ip: 最后一次活跃的 IP 地址\n      not_subscribed: 未订阅\n      outbox_url: 发件箱（Outbox）URL\n      perform_full_suspension: 封禁\n      profile_url: 个人资料页面 URL\n      promote: 升任\n      protocol: 协议\n      public: 公开页面\n      push_subscription_expires: PuSH 订阅过期时间\n      redownload: 刷新个人资料\n      remove_avatar: 删除头像\n      resend_confirmation:\n        already_confirmed: 该用户已被确认\n        send: 重发确认邮件\n        success: 确认邮件发送成功！\n      reset: 重置\n      reset_password: 重置密码\n      resubscribe: 重新订阅\n      role: 用户组\n      roles:\n        admin: 管理员\n        moderator: 监察员\n        staff: 管理人员\n        user: 普通用户\n      salmon_url: 三文鱼协议网址（Salmon URL）\n      search: 搜索\n      shared_inbox_url: 公用收件箱（Shared Inbox）URL\n      show:\n        created_reports: 这个帐户提交的举报\n        targeted_reports: 针对这个帐户的举报\n      silence: 隐藏\n      statuses: 嘟文\n      subscribe: 订阅\n      title: 用户\n      unconfirmed_email: 待验证的电子邮件地址\n      undo_silenced: 解除隐藏\n      undo_suspension: 解除封禁\n      unsubscribe: 取消订阅\n      username: 用户名\n      web: 站内页面\n    action_logs:\n      actions:\n        assigned_to_self_report: \"%{name} 接管了举报 %{target}\"\n        change_email_user: \"%{name} 更改了用户 %{target} 的电子邮件地址\"\n        confirm_user: \"%{name} 确认了用户 %{target} 的电子邮件地址\"\n        create_custom_emoji: \"%{name} 添加了新的自定义表情 %{target}\"\n        create_domain_block: \"%{name} 屏蔽了域名 %{target}\"\n        create_email_domain_block: \"%{name} 屏蔽了电子邮件域名 %{target}\"\n        demote_user: \"%{name} 对用户 %{target} 进行了降任操作\"\n        destroy_domain_block: \"%{name} 解除了对域名 %{target} 的屏蔽\"\n        destroy_email_domain_block: \"%{name} 解除了对电子邮件域名 %{target} 的屏蔽\"\n        destroy_status: \"%{name} 删除了 %{target} 的嘟文\"\n        disable_2fa_user: \"%{name} 停用了用户 %{target} 的双重认证\"\n        disable_custom_emoji: \"%{name} 停用了自定义表情 %{target}\"\n        disable_user: \"%{name} 将用户 %{target} 设置为禁止登录\"\n        enable_custom_emoji: \"%{name} 启用了自定义表情 %{target}\"\n        enable_user: \"%{name} 将用户 %{target} 设置为允许登录\"\n        memorialize_account: \"%{name} 将 %{target} 设置为追悼帐户\"\n        promote_user: \"%{name} 对用户 %{target} 进行了升任操作\"\n        remove_avatar_user: \"%{name} 删除了 %{target} 的头像\"\n        reopen_report: \"%{name} 重开了举报 %{target}\"\n        reset_password_user: \"%{name} 重置了用户 %{target} 的密码\"\n        resolve_report: \"%{name} 处理了举报 %{target}\"\n        silence_account: \"%{name} 隐藏了用户 %{target}\"\n        suspend_account: \"%{name} 封禁了用户 %{target}\"\n        unassigned_report: \"%{name} 放弃了举报 %{target} 的接管\"\n        unsilence_account: \"%{name} 解除了用户 %{target} 的隐藏状态\"\n        unsuspend_account: \"%{name} 解除了用户 %{target} 的封禁状态\"\n        update_custom_emoji: \"%{name} 更新了自定义表情 %{target}\"\n        update_status: \"%{name} 刷新了 %{target} 的嘟文\"\n      deleted_status: \"（嘟文已删除）\"\n      title: 运营日志\n    custom_emojis:\n      by_domain: 域名\n      copied_msg: 成功将表情复制到本地\n      copy: 复制\n      copy_failed_msg: 无法将表情复制到本地\n      created_msg: 表情添加成功！\n      delete: 删除\n      destroyed_msg: 表情删除成功！\n      disable: 停用\n      disabled_msg: 表情停用成功\n      emoji: 表情\n      enable: 启用\n      enabled_msg: 表情启用成功\n      image_hint: PNG 格式，最大 50KB\n      listed: 已显示\n      new:\n        title: 添加新的自定义表情\n      overwrite: 覆盖\n      shortcode: 短代码\n      shortcode_hint: 至少 2 个字符，只能使用字母、数字和下划线\n      title: 自定义表情\n      unlisted: 已隐藏\n      update_failed_msg: 表情更新失败\n      updated_msg: 表情更新成功！\n      upload: 上传新表情\n    dashboard:\n      backlog: 未处理任务数\n      config: 服务器配置\n      feature_deletions: 帐户删除\n      feature_invites: 邀请链接\n      feature_registrations: 公开注册\n      feature_relay: 同步中继\n      features: 功能\n      hidden_service: 匿名服务连通性\n      open_reports: 待处理举报数\n      recent_users: 新用户\n      search: 全文搜索\n      single_user_mode: 单用户模式\n      software: 软件\n      space: 存储使用情况\n      title: 仪表盘\n      total_users: 总用户数\n      trends: 趋势\n      week_interactions: 本周互动数\n      week_users_active: 本周活跃用户数\n      week_users_new: 本周新用户数\n    domain_blocks:\n      add_new: 添加新屏蔽域名\n      created_msg: 正在进行域名屏蔽\n      destroyed_msg: 域名屏蔽已撤销\n      domain: 域名\n      new:\n        create: 添加屏蔽\n        hint: 域名屏蔽不会阻止该域名下的帐户进入本站的数据库，但是会对来自这个域名的帐户自动进行预先设置的管理操作。\n        severity:\n          desc_html: 选择<strong>自动隐藏</strong>会将该域名下帐户发送的嘟文设置为仅关注者可见；选择<strong>自动封禁</strong>会将该域名下帐户发送的嘟文、媒体文件以及个人资料数据从本实例上删除；如果你只是想拒绝接收来自该域名的任何媒体文件，请选择<strong>无</strong>。\n          noop: 无\n          silence: 自动隐藏\n          suspend: 自动封禁\n        title: 添加域名屏蔽\n      reject_media: 拒绝接收媒体文件\n      reject_media_hint: 删除本地已缓存的媒体文件，并且不再接收来自该域名的任何媒体文件。此选项不影响封禁\n      show:\n        affected_accounts:\n          other: 将会影响到数据库中的 %{count} 个帐户\n        retroactive:\n          silence: 对此域名的所有帐户解除隐藏\n          suspend: 对此域名的所有帐户解除封禁\n        title: 撤销对 %{domain} 的域名屏蔽\n        undo: 撤销\n      undo: 撤销屏蔽域名\n    email_domain_blocks:\n      add_new: 添加新条目\n      created_msg: 电子邮件域名屏蔽添加成功\n      delete: 删除\n      destroyed_msg: 电子邮件域名屏蔽删除成功\n      domain: 域名\n      new:\n        create: 添加域名\n        title: 添加电子邮件域名屏蔽\n      title: 电子邮件域名屏蔽\n    instances:\n      title: 已知实例\n    invites:\n      deactivate_all: 撤销所有邀请链接\n      filter:\n        all: 全部\n        available: 可用\n        expired: 已失效\n        title: 筛选\n      title: 邀请用户\n    relays:\n      add_new: 添加新的中继\n      description_html: \"<strong>同步中继</strong>是一种中间服务器，各实例可以通过订阅中继和向中继推送信息的方式来大量交换公开嘟文。<strong>它可以帮助中小型实例发现网络中的内容</strong>，而无需本地用户手动关注其他远程实例上的用户。\"\n      enable_hint: 启用此功能后，你的实例会订阅此中继的所有公开嘟文，并同时向其推送本服务器的公开嘟文。\n      inbox_url: 中继 URL\n      pending: 等待中继确认\n      save_and_enable: 保存并启用\n      setup: 设置中继连接\n      status: 状态\n      title: 中继\n    report_notes:\n      created_msg: 举报记录建立成功！\n      destroyed_msg: 举报记录删除成功！\n    reports:\n      account:\n        note: 条记录\n        report: 条举报\n      action_taken_by: 操作执行者\n      are_you_sure: 你确定吗？\n      assign_to_self: 接管\n      assigned: 已接管的监察员\n      comment:\n        none: 没有\n      created_at: 举报时间\n      mark_as_resolved: 标记为“已处理”\n      mark_as_unresolved: 标记为“未处理”\n      notes:\n        create: 添加记录\n        create_and_resolve: 添加记录并标记为“已处理”\n        create_and_unresolve: 添加记录并重开\n        delete: 删除\n        placeholder: 描述已经执行的操作，或其他任何相关的跟进情况…\n      reopen: 重开举报\n      report: '举报 #%{id}'\n      reported_account: 举报用户\n      reported_by: 举报人\n      resolved: 已处理\n      resolved_msg: 举报处理成功！\n      status: 状态\n      title: 举报\n      unassign: 取消接管\n      unresolved: 未处理\n      updated_at: 更新时间\n    settings:\n      activity_api_enabled:\n        desc_html: 本站用户发布的嘟文数，以及本站的活跃用户数和一周内新用户数\n        title: 公开用户活跃度的统计数据\n      bootstrap_timeline_accounts:\n        desc_html: 用半角逗号分隔多个用户名。只能添加来自本站且未开启保护的帐户。如果留空，则默认关注本站所有的管理员。\n        title: 新用户默认关注\n      contact_information:\n        email: 用于联系的公开电子邮件地址\n        username: 用于联系的公开用户名\n      custom_css:\n        desc_html: 通过 CSS 代码调整所有页面的显示效果\n        title: 自定义 CSS\n      hero:\n        desc_html: 用于在首页展示。推荐分辨率 600×100px 以上。未指定的情况下将默认使用本站缩略图\n        title: 主题图片\n      peers_api_enabled:\n        desc_html: 截至目前本实例在网络中已发现的域名\n        title: 公开已知实例的列表\n      preview_sensitive_media:\n        desc_html: 始终在站外链接预览中展示缩略图，无论媒体内容是否标记为敏感\n        title: 在 OpenGraph 预览中显示敏感媒体内容\n      registrations:\n        closed_message:\n          desc_html: 本站关闭注册期间的提示信息。可以使用 HTML 标签\n          title: 关闭注册时的提示信息\n        deletion:\n          desc_html: 允许所有人删除自己的帐户\n          title: 开放删除帐户权限\n        min_invite_role:\n          disabled: 没有人\n          title: 允许发送邀请的用户组\n      show_known_fediverse_at_about_page:\n        desc_html: 启用此选项将会在预览中显示来自已知实例的嘟文，否则只会显示本站时间轴的内容.\n        title: 在时间轴预览中显示已知实例\n      show_staff_badge:\n        desc_html: 在个人资料页上显示管理人员标志\n        title: 显示管理人员标志\n      site_description:\n        desc_html: 首页上的介绍文字。 描述一下本 Mastodon 实例的特殊之处以及其他重要信息。可以使用 HTML 标签，包括 <code>&lt;a&gt;</code> 和 <code>&lt;em&gt;</code> 。\n        title: 本站简介\n      site_description_extended:\n        desc_html: 可以填写行为守则、规定、指南或其他本站特有的内容。可以使用 HTML 标签\n        title: 本站详细介绍\n      site_terms:\n        desc_html: 可以填写自己的隐私权政策、使用条款或其他法律文本。可以使用 HTML 标签\n        title: 自定义使用条款\n      site_title: 本站名称\n      thumbnail:\n        desc_html: 用于在 OpenGraph 和 API 中显示预览图。推荐分辨率 1200×630px\n        title: 本站缩略图\n      timeline_preview:\n        desc_html: 在主页显示公共时间轴\n        title: 时间轴预览\n      title: 网站设置\n    statuses:\n      back_to_account: 返回帐户信息页\n      batch:\n        delete: 删除\n        nsfw_off: 标记为非敏感内容\n        nsfw_on: 标记为敏感内容\n      failed_to_execute: 执行失败\n      media:\n        title: 媒体文件\n      no_media: 不含媒体文件\n      title: 帐户嘟文\n      with_media: 含有媒体文件\n    subscriptions:\n      callback_url: 回调 URL\n      confirmed: 已确认\n      expires_in: 失效时间\n      last_delivery: 最后一次接收数据的时间\n    title: 管理\n  admin_mailer:\n    new_report:\n      body: \"%{reporter} 举报了用户 %{target}\"\n      body_remote: 来自 %{domain} 的用户举报了用户 %{target}\n      subject: 来自 %{instance} 的用户举报（#%{id}）\n  application_mailer:\n    notification_preferences: 更改电子邮件首选项\n    settings: 使用此链接更改你的电子邮件首选项：%{link}\n    view: 点此链接查看详情：\n    view_profile: 查看个人资料页\n    view_status: 查看嘟文\n  applications:\n    created: 应用创建成功\n    destroyed: 应用删除成功\n    invalid_url: URL 无效\n    regenerate_token: 重置访问令牌\n    token_regenerated: 访问令牌重置成功\n    warning: 一定小心，千万不要把它分享给任何人！\n    your_token: 你的访问令牌\n  auth:\n    change_password: 密码\n    confirm_email: 确认电子邮件地址\n    delete_account: 删除帐户\n    delete_account_html: 如果你想删除你的帐户，请<a href=\"%{path}\">点击这里继续</a>。你需要确认你的操作。\n    didnt_get_confirmation: 没有收到确认邮件？\n    forgot_password: 忘记密码？\n    invalid_reset_password_token: 密码重置令牌无效或已过期。请重新发起重置密码请求。\n    login: 登录\n    logout: 登出\n    migrate_account: 迁移到另一个帐户\n    migrate_account_html: 如果你希望引导他人关注另一个帐户，请<a href=\"%{path}\">点击这里进行设置</a>。\n    or_log_in_with: 或通过其他方式登录\n    register: 注册\n    resend_confirmation: 重新发送确认邮件\n    reset_password: 重置密码\n    security: 帐户安全\n    set_new_password: 设置新密码\n  authorize_follow:\n    already_following: 你已经在关注此用户了\n    error: 对不起，寻找这个跨站用户时出错\n    follow: 关注\n    follow_request: 关注请求已发送给：\n    following: 成功！你正在关注：\n    post_follow:\n      close: 你也可以直接关闭这个窗口。\n      return: 查看用户个人资料\n      web: 返回本站\n    title: 关注 %{acct}\n  datetime:\n    distance_in_words:\n      about_x_hours: \"%{count}时\"\n      about_x_months: \"%{count}个月\"\n      about_x_years: \"%{count}年\"\n      almost_x_years: \"%{count}年\"\n      half_a_minute: 刚刚\n      less_than_x_minutes: \"%{count}分\"\n      less_than_x_seconds: 刚刚\n      over_x_years: \"%{count}年\"\n      x_days: \"%{count}天\"\n      x_minutes: \"%{count}分\"\n      x_months: \"%{count}个月\"\n      x_seconds: \"%{count}秒\"\n  deletes:\n    bad_password_msg: 想得美，黑客！密码输入错误\n    confirm_password: 输入你当前的密码来验证身份\n    description_html: 继续操作将会<strong>永久地、不可撤销地</strong>删除帐户中的所有内容，然后冻结帐户。你的用户名将会被保留，以防有人冒用你的身份。\n    proceed: 删除帐户\n    success_msg: 你的帐户已经成功删除\n    warning_html: 我们只能保证本实例上的内容将会被彻底删除。对于已经被广泛传播的内容，它们在本实例以外的某些地方可能仍然可见。此外，失去连接的服务器以及停止接收订阅的服务器所存储的数据亦无法删除。\n    warning_title: 关于已传播的内容的警告\n  errors:\n    '403': 你没有访问这个页面的权限。\n    '404': 无法找到你所要访问的页面。\n    '410': 你所要访问的页面此处已不存在。\n    '422':\n      content: 无法确认登录信息。你是不是屏蔽了 Cookie？\n      title: 无法确认登录信息\n    '429': 请求被限制\n    '500':\n      content: 抱歉，我们的后台出错了。\n      title: 这个页面有问题\n    noscript_html: 使用 Mastodon 网页版应用需要启用 JavaScript。你也可以选择适用于你的平台的 <a href=\"%{apps_path}\">Mastodon 应用</a>。\n  exports:\n    archive_takeout:\n      date: 日期\n      download: 下载你的存档\n      hint_html: 你可以请求一份帐户数据存档，其中包含你的<strong>嘟文和已上传的媒体文件</strong>。导出的数据为 ActivityPub 格式，因而可以被兼容的软件读取。每次允许请求存档的间隔至少为 7 天。\n      in_progress: 正在准备你的存档……\n      request: 请求你的存档\n      size: 大小\n    blocks: 屏蔽的用户\n    follows: 关注的用户\n    mutes: 隐藏的用户\n    storage: 媒体文件存储\n  filters:\n    contexts:\n      home: 主页时间轴\n      notifications: 通知\n      public: 公共时间轴\n      thread: 对话\n    edit:\n      title: 编辑过滤器\n    errors:\n      invalid_irreversible: 此功能只适用于主页时间轴或通知\n    index:\n      delete: 删除\n      title: 过滤器\n    new:\n      title: 添加新的过滤器\n  generic:\n    changes_saved_msg: 更改保存成功！\n    save_changes: 保存更改\n    validation_errors:\n      other: 出错啦！检查一下下面 %{count} 处出错的地方吧\n  imports:\n    preface: 你可以在此导入你在其他实例导出的数据，比如你所关注或屏蔽的用户列表。\n    success: 数据上传成功，正在处理中\n    types:\n      blocking: 屏蔽列表\n      following: 关注列表\n      muting: 隐藏列表\n    upload: 上传\n  in_memoriam_html: 谨此悼念。\n  invites:\n    delete: 停用\n    expired: 已失效\n    expires_in:\n      '1800': 30 分钟后\n      '21600': 6 小时后\n      '3600': 1 小时后\n      '43200': 12 小时后\n      '604800': 1 周后\n      '86400': 1 天后\n    expires_in_prompt: 永不过期\n    generate: 生成邀请链接\n    invited_by: 你的邀请人是：\n    max_uses:\n      other: \"%{count} 次\"\n    max_uses_prompt: 无限制\n    prompt: 生成分享链接，邀请他人在本实例注册\n    table:\n      expires_at: 失效时间\n      uses: 已使用次数\n    title: 邀请用户\n  lists:\n    errors:\n      limit: 你所建立的列表数量已经达到上限\n  media_attachments:\n    validations:\n      images_and_video: 无法在嘟文中同时插入视频和图片\n      too_many: 最多只能添加 4 张图片\n  migrations:\n    acct: 新帐户的 用户名@域名\n    currently_redirecting: 目前你的个人资料页显示的新帐户是：\n    proceed: 保存\n    updated_msg: 帐户迁移设置更新成功！\n  moderation:\n    title: 运营\n  notification_mailer:\n    digest:\n      action: 查看所有通知\n      body: 以下是自%{since}你最后一次登录以来错过的消息的摘要\n      mention: \"%{name} 在嘟文中提到了你：\"\n      new_followers_summary:\n        other: 而且，你不在的时候，有 %{count} 个人关注了你！好棒！\n      title: 在你不在的这段时间……\n    favourite:\n      body: 你的嘟文被 %{name} 收藏了：\n      subject: \"%{name} 收藏了你的嘟文\"\n      title: 新的收藏\n    follow:\n      body: \"%{name} 关注了你！\"\n      subject: \"%{name} 关注了你\"\n      title: 新的关注者\n    follow_request:\n      action: 处理关注请求\n      body: \"%{name} 向你发送了关注请求\"\n      subject: 来自 %{name} 的关注请求\n      title: 新的关注请求\n    mention:\n      action: 回复\n      body: \"%{name} 在嘟文中提到了你：\"\n      subject: \"%{name} 提到了你\"\n      title: 新的提及\n    reblog:\n      body: 你的嘟文被 %{name} 转嘟了：\n      subject: \"%{name} 转嘟了你的嘟文\"\n      title: 新的转嘟\n  pagination:\n    newer: 更新\n    next: 下一页\n    older: 更早\n    prev: 上一页\n  remote_follow:\n    acct: 请输入你的“用户名@实例域名”\n    missing_resource: 无法确定你的帐户的跳转 URL\n    no_account_html: 还没有帐号？你可以<a href='%{sign_up_path}' target='_blank'>注册一个</a>\n    proceed: 确认关注\n    prompt: 你正准备关注：\n  remote_unfollow:\n    error: 错误\n    title: 标题\n    unfollowed: 已取消关注\n  sessions:\n    activity: 最后一次活跃的时间\n    browser: 浏览器\n    browsers:\n      alipay: 支付宝\n      generic: 未知浏览器\n      micro_messenger: 微信\n      nokia: Nokia S40 Ovi 浏览器\n      qq: QQ浏览器\n      uc_browser: UC浏览器\n      weibo: 新浪微博\n    current_session: 当前会话\n    description: \"%{platform} 上的 %{browser}\"\n    explanation: 你的 Mastodon 帐户目前已在这些浏览器上登录。\n    ip: IP 地址\n    revoke: 注销\n    revoke_success: 会话注销成功\n    title: 会话\n  settings:\n    authorized_apps: 已授权的应用\n    back: 返回 Mastodon\n    delete: 删除帐户\n    development: 开发\n    edit_profile: 更改个人资料\n    export: 导出\n    import: 导入\n    migrate: 帐户迁移\n    notifications: 通知\n    preferences: 首选项\n    two_factor_authentication: 双重认证\n  statuses:\n    attached:\n      description: 附加媒体：%{attached}\n      image:\n        other: \"%{count} 张图片\"\n      video:\n        other: \"%{count} 段视频\"\n    boosted_from_html: 转嘟自 %{acct_link}\n    content_warning: 内容警告：%{warning}\n    disallowed_hashtags:\n      other: 包含了这些禁止的话题标签：%{tags}\n    language_detection: 自动检测语言\n    open_in_web: 在站内打开\n    over_character_limit: 超过了 %{max} 字的限制\n    pin_errors:\n      limit: 你所置顶的嘟文数量已经达到上限\n      ownership: 不能置顶他人的嘟文\n      private: 不能置顶非公开的嘟文\n      reblog: 不能置顶转嘟\n    show_more: 显示更多\n    title: \"%{name}：“%{quote}”\"\n    visibilities:\n      private: 仅关注者\n      private_long: 只有关注你的用户能看到\n      public: 公开\n      public_long: 所有人可见，并会出现在公共时间轴上\n      unlisted: 不公开\n      unlisted_long: 所有人可见，但不会出现在公共时间轴上\n  stream_entries:\n    pinned: 置顶嘟文\n    reblogged: 转嘟\n    sensitive_content: 敏感内容\n  terms:\n    title: \"%{instance} 使用条款和隐私权政策\"\n  themes:\n    contrast: Mastodon（高对比度）\n    default: Mastodon（暗色主题）\n    mastodon-light: Mastodon（亮色主题）\n  time:\n    formats:\n      default: \"%Y年%-m月%d日 %H:%M\"\n  two_factor_authentication:\n    code_hint: 输入认证器生成的代码以确认操作\n    description_html: 启用<strong>双重认证</strong>后，你需要输入手机认证器生成的代码才能登录.\n    disable: 停用\n    enable: 启用\n    enabled: 双重认证已启用\n    enabled_success: 双重认证启用成功\n    generate_recovery_codes: 生成恢复代码\n    instructions_html: \"<strong>请使用 Google 身份验证器或其他 TOTP 双重认证手机应用扫描此处的二维码</strong>。启用双重认证后，你需要输入该应用生成的代码来登录你的帐户。\"\n    lost_recovery_codes: 如果你的手机不慎丢失，你可以使用恢复代码来重新获得对帐户的访问权。如果你遗失了恢复代码，可以在此处重新生成。之前使用的恢复代码将会失效。\n    manual_instructions: 如果你无法扫描二维码，请手动输入下列文本：\n    recovery_codes: 备份恢复代码\n    recovery_codes_regenerated: 恢复代码重新生成成功\n    recovery_instructions_html: 如果你的手机无法使用，你可以使用下列任意一个恢复代码来重新获得对帐户的访问权。<strong>请妥善保管好你的恢复代码</strong>（例如，你可以将它们打印出来，然后和其他重要的文件放在一起）。\n    setup: 设置\n    wrong_code: 输入的认证码无效！请确认服务器时间与设备时间是否正确？\n  user_mailer:\n    backup_ready:\n      explanation: 你请求了一份 Mastodon 帐户的完整备份。现在你可以下载了！\n      subject: 你的存档已经准备完毕\n      title: 存档导出\n    welcome:\n      edit_profile_action: 设置个人资料\n      edit_profile_step: 你可以自定义你的个人资料，包括上传头像、横幅图片、更改昵称等等。如果你想在新的关注者关注你之前对他们进行审核，你也可以选择为你的帐户开启保护。\n      explanation: 下面是几个小贴士，希望它们能帮到你\n      final_action: 开始嘟嘟\n      final_step: '开始嘟嘟吧！即便你现在没有关注者，其他人仍然能在本站时间轴或者话题标签等地方看到你的公开嘟文。试着用 #introductions 这个话题标签介绍一下自己吧。'\n      full_handle: 你的完整用户地址\n      full_handle_hint: 你需要把这个告诉你的朋友们，这样他们就能从另一个实例向你发送信息或者关注你。\n      review_preferences_action: 更改首选项\n      review_preferences_step: 记得调整你的偏好设置，比如你想接收什么类型的邮件，或者你想把你的嘟文可见范围默认设置为什么级别。如果你没有晕动病的话，考虑一下启用“自动播放 GIF 动画”这个选项吧。\n      subject: 欢迎来到 Mastodon\n      tip_federated_timeline: 跨站公共时间轴可以让你一窥更广阔的 Mastodon 网络。不过，由于它只显示你的邻居们所订阅的内容，所以并不是全部。\n      tip_following: 默认情况下，你会自动关注你所在实例的管理员。想结交更多有趣的人的话，记得多逛逛本站时间轴和跨站公共时间轴哦。\n      tip_local_timeline: 本站时间轴可以让你一窥 %{instance} 上的用户。他们就是离你最近的邻居！\n      tip_mobile_webapp: 如果你的移动设备浏览器允许你将 Mastodon 添加到主屏幕，你就能够接收推送消息。它就像本地应用一样好使！\n      tips: 小贴士\n      title: \"%{name}，欢迎你的加入！\"\n  users:\n    invalid_email: 输入的电子邮件地址无效\n    invalid_otp_token: 输入的双重认证代码无效\n    otp_lost_help_html: 如果你不慎丢失了所有的代码，请联系 %{email} 寻求帮助\n    seamless_external_login: 因为你是通过外部服务登录的，所以密码和电子邮件地址设置都不可用。\n    signed_in_as: 当前登录的帐户：\n"
  },
  {
    "path": "config/locales/zh-HK.yml",
    "content": "---\nzh-HK:\n  about:\n    about_hashtag_html: 這些是包含「<strong>#%{hashtag}</strong>」標籤的公開文章。只要你有任何 Mastodon 服務站、或者聯盟網站的用戶，便可以與他們互動。\n    about_mastodon_html: Mastodon（萬象）是<em>自由、開源</em>的社交網絡。服務站<em>各自獨立而互連</em>，避免單一商業機構壟斷。找你所信任的服務站，建立帳號，你即可與任何服務站上的用戶溝通，享受無縫的<em>網絡交流</em>。\n    about_this: 關於本服務站\n    administered_by: 管理者：\n    contact: 聯絡\n    contact_missing: 未設定\n    contact_unavailable: 未公開\n    extended_description_html: |\n      <h3>這裡可以寫一些網站規則</h3>\n      <p>本站未有詳細介紹</p>\n    generic_description: \"%{domain} 是 Mastodon 網絡中其中一個服務站\"\n    hosted_on: 在 %{domain} 運作的 Mastodon 服務站\n    learn_more: 了解更多\n    source_code: 源代碼\n    status_count_before: 他們共發佈了\n    tagline: 關注朋友並探索新朋友\n    user_count_before: 這裏共註冊有\n    what_is_mastodon: Mastodon 是甚麼？\n  accounts:\n    follow: 關注\n    followers:\n      other: 關注者\n    following: 正在關注\n    media: 媒體\n    moved_html: \"%{name} 已經轉移到 %{new_profile_link}：\"\n    network_hidden: 此信息不可用\n    nothing_here: 暫時未有內容可以顯示。\n    people_followed_by: \"%{name} 關注的人\"\n    people_who_follow: 關注 %{name} 的人\n    posts_with_replies: 文章和回覆\n    reserved_username: 此用戶名已被保留\n    roles:\n      admin: 管理員\n      bot: 機械人\n      moderator: 監察員\n    unfollow: 取消關注\n  admin:\n    account_moderation_notes:\n      create: 記錄\n      created_msg: 管理記錄已新增\n      delete: 刪除\n      destroyed_msg: 管理記錄已被刪除\n    accounts:\n      are_you_sure: 你確定嗎？\n      avatar: 頭像\n      by_domain: 域名\n      change_email:\n        changed_msg: 帳號電郵更新成功！\n        current_email: 現時電郵\n        label: 改變電郵\n        new_email: 新的電郵\n        submit: 改變電郵\n        title: 改變 %{username} 的電郵\n      confirm: 確定\n      confirmed: 已確定\n      confirming: 確定\n      demote: 降任\n      disable: 停用\n      disable_two_factor_authentication: 停用雙重認證\n      disabled: 已停用\n      display_name: 顯示名稱\n      domain: 域名\n      edit: 編輯\n      email: 電郵地址\n      email_status: 电子邮件状态\n      enable: 啟用\n      enabled: 已啟用\n      feed_url: 訂閱 URL\n      followers: 關注者\n      followers_url: 關注者（Followers）URL\n      follows: 正在關注\n      inbox_url: 收件箱（Inbox）URL\n      ip: IP 位域\n      location:\n        all: 全部\n        local: 本地\n        remote: 遠端\n        title: 地點\n      login_status: 登入狀態\n      media_attachments: 媒體檔案\n      memorialize: 設定為追悼帳戶\n      moderation:\n        all: 全部\n        silenced: 被靜音的\n        suspended: 被停權的\n        title: 管理操作\n      moderation_notes: 管理記錄\n      most_recent_activity: 最新活動\n      most_recent_ip: 最新 IP 位域\n      not_subscribed: 未訂閱\n      outbox_url: 寄件箱（Outbox）URL\n      perform_full_suspension: 完全停權\n      profile_url: 個人檔案 URL\n      promote: 升任\n      protocol: 協議\n      public: 公共\n      push_subscription_expires: PuSH 訂閱過期\n      redownload: 更新頭像\n      remove_avatar: 取消頭像\n      resend_confirmation:\n        already_confirmed: 该用户已被确认\n        send: 重发确认邮件\n        success: 确认电子邮件成功发送！\n      reset: 重設\n      reset_password: 重設密碼\n      resubscribe: 重新訂閱\n      role: 身份\n      roles:\n        admin: 管理員\n        moderator: 監察員\n        staff: 管理人員\n        user: 普通用戶\n      salmon_url: Salmon 反饋 URL\n      search: 搜索\n      shared_inbox_url: 公共收件箱（Shared Inbox）URL\n      show:\n        created_reports: 此用戶所提舉報的紀錄\n        targeted_reports: 此用戶被舉報的紀錄\n      silence: 靜音\n      statuses: 文章\n      subscribe: 訂閱\n      title: 用戶\n      unconfirmed_email: 未確認的電郵\n      undo_silenced: 解除靜音\n      undo_suspension: 解除停權\n      unsubscribe: 取消訂閱\n      username: 用戶名稱\n      web: 用戶頁面\n    action_logs:\n      actions:\n        assigned_to_self_report: \"%{name} 指派了 %{target} 的舉報給自己\"\n        change_email_user: \"%{name} 改變了用戶 %{target} 的電郵地址\"\n        confirm_user: \"%{name} 確認了用戶 %{target} 的電郵地址\"\n        create_custom_emoji: \"%{name} 加入自訂表情符號 %{target}\"\n        create_domain_block: \"%{name} 阻隔了網域 %{target}\"\n        create_email_domain_block: \"%{name} 阻隔了電郵網域 %{target}\"\n        demote_user: \"%{name} 把用戶 %{target} 降任\"\n        destroy_domain_block: \"%{name} 取消了對網域 %{target} 的阻隔\"\n        destroy_email_domain_block: \"%{name} 取消了對電郵網域 %{target} 的阻隔\"\n        destroy_status: \"%{name} 刪除了 %{target} 的文章\"\n        disable_2fa_user: \"%{name} 停用了用戶 %{target} 的雙重認證\"\n        disable_custom_emoji: \"%{name} 停用了自訂表情符號 %{target}\"\n        disable_user: \"%{name} 把用戶 %{target} 設定為禁止登入\"\n        enable_custom_emoji: \"%{name} 啟用了自訂表情符號 %{target}\"\n        enable_user: \"%{name} 把用戶 %{target} 設定為允許登入\"\n        memorialize_account: \"%{name} 把 %{target} 設定為追悼帳戶\"\n        promote_user: \"%{name} 對用戶 %{target} 进行了升任操作\"\n        remove_avatar_user: \"%{name} 取消了 %{target} 的頭像\"\n        reopen_report: \"%{name} 重開 %{target} 的舉報\"\n        reset_password_user: \"%{name} 重設了用戶 %{target} 的密碼\"\n        resolve_report: \"%{name} 處理了 %{target}　的舉報\"\n        silence_account: \"%{name} 靜音了用戶 %{target}\"\n        suspend_account: \"%{name} 停權了用戶 %{target}\"\n        unassigned_report: \"%{name} 取消指派 %{target} 的舉報\"\n        unsilence_account: \"%{name} 取消了用戶 %{target} 的靜音狀態\"\n        unsuspend_account: \"%{name} 取消了用戶 %{target} 的停權狀態\"\n        update_custom_emoji: \"%{name} 更新了自訂表情符號 %{target}\"\n        update_status: \"%{name} 刷新了 %{target} 的文章\"\n      title: 營運日誌\n    custom_emojis:\n      by_domain: 網域\n      copied_msg: 成功將表情複製到本地\n      copy: 複製\n      copy_failed_msg: 無法將表情複製到本地\n      created_msg: 已新增表情符號\n      delete: 刪除\n      destroyed_msg: 已刪除表情符號\n      disable: 停用\n      disabled_msg: 已停用表情符號\n      emoji: emoji\n      enable: 啟用\n      enabled_msg: 已啟用表情符號\n      image_hint: PNG 格式，最大 50KB\n      listed: 已顯示\n      new:\n        title: 加入新的自訂表情符號\n      overwrite: 覆蓋\n      shortcode: 短代碼\n      shortcode_hint: 至少 2 個字元，只能使用字母、數字和下劃線\n      title: 自訂 emoji\n      unlisted: 已隱藏\n      update_failed_msg: 無法更新表情符號\n      updated_msg: 已更新表情符號\n      upload: 上傳新的表情符號\n    domain_blocks:\n      add_new: 新增\n      created_msg: 正處理域名阻隔\n      destroyed_msg: 已撤銷域名阻隔\n      domain: 域名阻隔\n      new:\n        create: 新增域名阻隔\n        hint: \"「域名阻隔」不會隔絕該域名用戶的用戶進入本站資料庫，而是會在時候自動套用特定的審批操作。\"\n        severity:\n          desc_html: \"「<strong>自動靜音</strong>」令該域名下用戶的文章，設為只對關注者顯示，沒有關注的人會看不到。 「<strong>自動刪除</strong>」會刪除將該域名下用戶的文章、媒體檔案和個人資料。「<strong>無</strong>」則會拒絕接收來自該域名的媒體檔案。\"\n          noop: 無\n          silence: 自動靜音\n          suspend: 自動刪除\n        title: 新增域名阻隔\n      reject_media: 拒絕媒體檔案\n      reject_media_hint: 刪除本地緩存的媒體檔案，再也不在未來下載這個站點的檔案。和自動刪除無關\n      show:\n        retroactive:\n          silence: 對此域名的所有用戶取消靜音\n          suspend: 對此域名的所有用戶取消除名\n        title: 撤銷 %{domain} 的域名阻隔\n        undo: 撤銷\n      undo: 撤銷\n    email_domain_blocks:\n      add_new: 加入新項目\n      created_msg: 已新增電郵網域阻隔\n      delete: 刪除\n      destroyed_msg: 已刪除電郵網域阻隔\n      domain: 網域\n      new:\n        create: 新增網域\n        title: 新增電郵網域阻隔\n      title: 電郵網域阻隔\n    followers:\n      back_to_account: 返回帳戶\n      title: \"%{acct} 的關注者\"\n    instances:\n      title: 已知服務站\n      total_followed_by_us: 開始關注你\n    invites:\n      filter:\n        all: 全部\n        available: 可用\n        expired: 已失效\n        title: 篩選\n      title: 邀請用戶\n    relays:\n      description_html: \"<strong>聯邦中繼站</strong> 是種中繼伺服器，會在訂閱並推送至此中繼站的伺服器之間交換大量的公開嘟文。<strong>中繼站也能協助小型或中型伺服器從聯邦中探索內容</strong>，而無須本地使用者手動關注遠端伺服器的其他使用者。\"\n    report_notes:\n      created_msg: 舉報筆記已建立。\n      destroyed_msg: 舉報筆記已刪除。\n    reports:\n      account:\n        note: 筆記\n        report: 舉報\n      action_taken_by: 操作執行者\n      are_you_sure: 你確認嗎？\n      assign_to_self: 指派給自己\n      assigned: 指派負責人\n      comment:\n        none: 沒有\n      created_at: 日期\n      mark_as_resolved: 標示為「已處理」\n      mark_as_unresolved: 標示為「未處理」\n      notes:\n        create: 建立筆記\n        create_and_resolve: 建立筆記並標示為「已處理」\n        create_and_unresolve: 建立筆記並標示為「未處理」\n        delete: 刪除\n        placeholder: 記錄已執行的動作，或其他相關的更新……\n      reopen: 重開舉報\n      report: '舉報 #%{id}'\n      reported_account: 舉報用戶\n      reported_by: 舉報者\n      resolved: 已處理\n      resolved_msg: 舉報已處理。\n      status: 狀態\n      title: 舉報\n      unassign: 取消指派\n      unresolved: 未處理\n      updated_at: 更新\n    settings:\n      activity_api_enabled:\n        desc_html: 本站用戶發佈的文章，以及本站的活躍用戶和一週內新用戶數\n        title: 公開用戶活躍度的統計數據\n      bootstrap_timeline_accounts:\n        desc_html: 以半形逗號分隔多個用戶名。只能加入來自本站且未開啟保護的帳號。如果留空，則默認關注本站所有管理員。\n        title: 新用戶默認關注\n      contact_information:\n        email: 輸入一個公開的電郵地址\n        username: 輸入用戶名稱\n      hero:\n        desc_html: 在首頁顯示。推薦最小 600x100px。如果留空，就會默認為服務站縮圖\n        title: 主題圖片\n      peers_api_enabled:\n        desc_html: 現時本服務站在網絡中已發現的域名\n        title: 公開已知服務站的列表\n      registrations:\n        closed_message:\n          desc_html: 當本站暫停接受註冊時，會顯示這個訊息。<br/> 可使用 HTML\n          title: 暫停註冊訊息\n        deletion:\n          desc_html: 允許所有人刪除自己的帳戶\n          title: 開放刪除帳戶的權限\n        min_invite_role:\n          disabled: 沒有人\n          title: 允許發送邀請的身份\n      show_known_fediverse_at_about_page:\n        desc_html: 如果開啟，就會在時間軸預覽顯示跨站文章，否則就只會顯示本站文章。\n        title: 在時間軸預覽顯示跨站文章\n      show_staff_badge:\n        desc_html: 在個人資料頁上顯示管理人員標誌\n        title: 顯示管理人員標誌\n      site_description:\n        desc_html: 在首頁顯示，及在 meta 標籤使用作網站介紹。<br/> 你可以在此使用 <code>&lt;a&gt;</code> 和 <code>&lt;em&gt;</code> 等 HTML 標籤。\n        title: 本站介紹\n      site_description_extended:\n        desc_html: 本站詳細資訊頁的內文<br/>你可以在此使用 HTML\n        title: 本站詳細資訊\n      site_terms:\n        desc_html: 可以填寫自己的隱私權政策、使用條款或其他法律文本。可以使用 HTML 標籤\n        title: 自訂使用條款\n      site_title: 本站名稱\n      thumbnail:\n        desc_html: 用於在 OpenGraph 和 API 中顯示預覽圖。推薦大小 1200×630px\n        title: 本站縮圖\n      timeline_preview:\n        desc_html: 在主頁顯示本站時間軸\n        title: 時間軸預覽\n      title: 網站設定\n    statuses:\n      back_to_account: 返回帳戶信息頁\n      batch:\n        delete: 刪除\n        nsfw_off: 取消 NSFW 標記\n        nsfw_on: 添加 NSFW 標記\n      failed_to_execute: 執行失敗\n      media:\n        title: 媒體檔案\n      no_media: 不含媒體檔案\n      title: 帳戶文章\n      with_media: 含有媒體檔案\n    subscriptions:\n      callback_url: 回傳 URL\n      confirmed: 確定\n      expires_in: 期限\n      last_delivery: 資料最後送抵時間\n      title: PuSH 訂閱\n      topic: 所訂閱資源\n    title: 管理\n  admin_mailer:\n    new_report:\n      body: \"%{reporter} 舉報了用戶 %{target}\"\n      body_remote: 來自 %{domain} 的用戶舉報了用戶 %{target}\n      subject: 來自 %{instance} 的用戶舉報（#%{id}）\n  application_mailer:\n    notification_preferences: 更改電郵首選項\n    salutation: \"%{name}：\"\n    settings: 修改電郵設定︰%{link}\n    view: 進入瀏覽︰\n    view_profile: 檢視個人資料頁\n    view_status: 檢視文章\n  applications:\n    created: 已建立應用\n    destroyed: 已刪除應用\n    invalid_url: 所提供的網址不正確\n    regenerate_token: 重設 token\n    token_regenerated: 已重設 token\n    warning: 警告，不要把它分享給任何人！\n    your_token: token\n  auth:\n    change_password: 密碼\n    confirm_email: 確認電郵\n    delete_account: 刪除帳戶\n    delete_account_html: 如果你想刪除你的帳戶，請<a href=\"%{path}\">點擊這裡繼續</a>。你需要確認你的操作。\n    didnt_get_confirmation: 沒有收到確認指示電郵？\n    forgot_password: 忘記了密碼？\n    invalid_reset_password_token: 密碼重置 token 無效或已過期。請重新重設密碼。\n    login: 登入\n    logout: 登出\n    migrate_account: 轉移到另一個帳號\n    migrate_account_html: 想要將這個帳號指向另一個帳號可<a href=\"%{path}\">到這裡設定</a>。\n    or_log_in_with: 或登入於\n    register: 登記\n    resend_confirmation: 重發確認指示電郵\n    reset_password: 重設密碼\n    security: 登入資訊\n    set_new_password: 設定新密碼\n  authorize_follow:\n    already_following: 你已經關注了這個帳號\n    error: 對不起，尋找這個跨站用戶的過程發生錯誤\n    follow: 關注\n    follow_request: 關注請求已發送给：\n    following: 成功！你正在關注：\n    post_follow:\n      close: 你也可以直接關閉這個頁面。\n      return: 顯示個人資料頁\n      web: 返回本站\n    title: 關注 %{acct}\n  datetime:\n    distance_in_words:\n      about_x_hours: \"%{count}小時前\"\n      about_x_months: \"%{count}個月前\"\n      about_x_years: \"%{count}年前\"\n      almost_x_years: 接近%{count}年前\n      half_a_minute: 剛剛\n      less_than_x_minutes: 少於%{count}分鐘前\n      less_than_x_seconds: 剛剛\n      over_x_years: \"%{count}年\"\n      x_days: \"%{count}日\"\n      x_minutes: \"%{count}分鐘\"\n      x_months: \"%{count}個月\"\n      x_seconds: \"%{count}秒\"\n  deletes:\n    bad_password_msg: 想得美，黑客！密碼輸入錯誤\n    confirm_password: 輸入你現在的密碼來驗證身份\n    description_html: 繼續操作將會<strong>永久地、不可還原地</strong>刪除帳戶中的所有內容，然後凍結帳戶。你的用戶名將會被保留，以防有人冒用你的身份。\n    proceed: 刪除帳戶\n    success_msg: 你的帳戶已經成功刪除\n    warning_html: 我們只能保證本服務站上的內容將會被徹底刪除。對於已經被廣泛傳播的內容，它們在本服務站以外的某些地方可能仍然可見。此外，失去連接的服務站以及停止接收訂閱的服務站所存儲的數據亦無法刪除。\n    warning_title: 關於已傳播的內容的警告\n  errors:\n    '403': 你沒有觀看本頁的權限。\n    '404': 找不到內容。\n    '410': 內容已被刪除。\n    '422':\n      content: 無法確認登入資訊。會不會你阻擋了本站使用 Cookies 的權限？\n      title: 無法確認登入資訊\n    '429': 伺服器繁忙\n    '500':\n      content: 抱歉，我們的後台出錯了。\n      title: 這個頁面有問題\n    noscript_html: 使用 Mastodon 網頁版應用需要啟用 JavaScript。你也可以選擇適用於你的平台的 <a href=\"%{apps_path}\">Mastodon 應用</a>。\n  exports:\n    archive_takeout:\n      date: 日期\n      download: 下載檔案\n      hint_html: 你可以下載包含你的<strong>文章和媒體</strong>的檔案。資料以 ActivityPub 格式儲存，可用於相容的軟體。你可以每七天下載一次。\n      in_progress: 檔案製作中...\n      request: 下載檔案\n      size: 檔案大小\n    blocks: 被你封鎖的用戶\n    follows: 你所關注的用戶\n    mutes: 你所靜音的用戶\n    storage: 媒體容量大小\n  generic:\n    changes_saved_msg: 已成功儲存修改。\n    save_changes: 儲存修改\n    validation_errors:\n      other: 提交的資料有 %{count} 項問題\n  imports:\n    preface: 你可以在此匯入你在其他服務站所匯出的資料檔，包括︰你所關注的用戶，被你封鎖的用戶。\n    success: 你已成功上載資料檔，我們正將資料匯入，請稍候\n    types:\n      blocking: 被你封鎖的用戶名單\n      following: 你所關注的用戶名單\n      muting: 靜音名單\n    upload: 上載\n  in_memoriam_html: 謹此悼念。\n  invites:\n    delete: 停用\n    expired: 已失效\n    expires_in:\n      '1800': 30 分鐘後\n      '21600': 6 小時後\n      '3600': 1 小時後\n      '43200': 12 小時後\n      '604800': 1 週後\n      '86400': 1 天後\n    expires_in_prompt: 永不過期\n    generate: 生成邀請連結\n    invited_by: 你的邀請人是：\n    max_uses:\n      other: \"%{count} 次\"\n    max_uses_prompt: 無限制\n    prompt: 生成分享連結，邀請他人在本服務站註冊\n    table:\n      expires_at: 失效時間\n      uses: 已使用次數\n    title: 邀請用戶\n  lists:\n    errors:\n      limit: 你所建立的列表數量已經達到上限\n  media_attachments:\n    validations:\n      images_and_video: 不能在已有圖片的文章上加入影片\n      too_many: 不可以加入超過 4 個檔案\n  migrations:\n    acct: 新帳戶的 用戶名@域名\n    currently_redirecting: 目前你的個人資料頁顯示的新帳戶是：\n    proceed: 保存\n    updated_msg: 帳戶遷移設置更新成功！\n  moderation:\n    title: 營運\n  notification_mailer:\n    digest:\n      action: 查看所有通知\n      body: 這是自從你在%{since}使用以後，你錯失了的訊息︰\n      mention: \"%{name} 在此提及了你︰\"\n      new_followers_summary:\n        other: 你新獲得了 %{count} 位關注者了！好厲害！\n      subject:\n        other: \"自從上次登入以來，你收到 %{count} 則新的通知 \\U0001F418\"\n      title: 在你不在的這段時間……\n    favourite:\n      body: 您的文章被 %{name} 收藏：\n      subject: \"%{name} 收藏了你的文章\"\n      title: 新的收藏\n    follow:\n      body: \"%{name} 開始關注你！\"\n      subject: \"%{name} 現正關注你\"\n      title: 新的關注者\n    follow_request:\n      action: 處理關注請求\n      body: \"%{name} 要求關注你\"\n      subject: 等候關注你的用戶︰ %{name}\n      title: 新的關注請求\n    mention:\n      action: 回覆\n      body: \"%{name} 在文章中提及你︰\"\n      subject: \"%{name} 在文章中提及你\"\n      title: 新的提及\n    reblog:\n      body: 您的文章被 %{name} 轉推：\n      subject: \"%{name} 轉推了你的文章\"\n      title: 新的轉推\n  pagination:\n    newer: 較新\n    next: 下一頁\n    older: 較舊\n    prev: 上一頁\n    truncate: \"……\"\n  relationships:\n    remove_selected_followers: 刪除所選選項\n  remote_follow:\n    acct: 請輸入你的︰用戶名稱@服務點域名\n    missing_resource: 無法找到你用戶的轉接網址\n    proceed: 下一步\n    prompt: 你希望關注︰\n  remote_unfollow:\n    error: 錯誤\n    title: 標題\n    unfollowed: 取消關注\n  sessions:\n    activity: 最近活動\n    browser: 瀏覽器\n    browsers:\n      alipay: 支付寶\n      chrome: Chrome 瀏覽器\n      edge: Microsoft Edge 瀏覽器\n      electron: Electron 瀏覽器\n      firefox: Firefox 瀏覽器\n      generic: 未知的瀏覽器\n      ie: Internet Explorer 瀏覽器\n      micro_messenger: 微信\n      nokia: Nokia S40 Ovi 瀏覽器\n      otter: Otter 瀏覽器\n      qq: QQ瀏覽器\n      uc_browser: UC瀏覽器\n      weibo: 新浪微博\n    current_session: 目前的作業階段\n    description: \"%{platform} 上的 %{browser}\"\n    explanation: 這些是現在正登入於你的 Mastodon 帳號的瀏覽器。\n    ip: IP 位址\n    revoke: 取消\n    revoke_success: 作業階段成功取消\n    title: 作業階段\n  settings:\n    authorized_apps: 授權應用程式\n    back: 回到 Mastodon\n    delete: 刪除帳戶\n    development: 開發\n    edit_profile: 修改個人資料\n    export: 匯出\n    import: 匯入\n    migrate: 帳戶遷移\n    notifications: 通知\n    preferences: 偏好設定\n    two_factor_authentication: 雙重認證\n  statuses:\n    attached:\n      description: 附件： %{attached}\n      image:\n        other: \"%{count} 幅圖片\"\n      video:\n        other: \"%{count} 段影片\"\n    boosted_from_html: 轉推自 %{acct_link}\n    content_warning: 內容警告： %{warning}\n    disallowed_hashtags:\n      other: 包含不允許的標籤： %{tags}\n    language_detection: 自動偵測語言\n    open_in_web: 開啟網頁\n    over_character_limit: 超過了 %{max} 字的限制\n    pin_errors:\n      limit: 你所置頂的文章數量已經達到上限\n      ownership: 不能置頂他人的文章\n      private: 不能置頂非公開的文章\n      reblog: 不能置頂轉推\n    show_more: 顯示更多\n    title: \"%{name}：「%{quote}」\"\n    visibilities:\n      private: 關注者觀看\n      private_long: 只有關注你的人能看到\n      public: 公開\n      public_long: 所有人都能看到\n      unlisted: 公開，但不在公共時間軸顯示\n      unlisted_long: 所有人都能看到，但不在公共時間軸（本站時間軸、跨站時間軸）顯示\n  stream_entries:\n    pinned: 置頂文章\n    reblogged: 轉推\n    sensitive_content: 敏感內容\n  terms:\n    title: \"%{instance} 使用條款和隱私權政策\"\n  themes:\n    contrast: 高對比\n    default: 萬象\n    mastodon-light: 萬象（亮色主題）\n  time:\n    formats:\n      default: \"%Y年%-m月%d日 %H:%M\"\n  two_factor_authentication:\n    code_hint: 請輸入你認證器產生的代碼，以確認設定\n    description_html: 當你啟用<strong>雙重認證</strong>後，你登入時將需要使你手機、或其他種類認證器產生的代碼。\n    disable: 停用\n    enable: 啟用\n    enabled: 雙重認證已啟用\n    enabled_success: 已成功啟用雙重認證\n    generate_recovery_codes: 產生備用驗證碼\n    instructions_html: \"<strong>請用你手機的認證器應用程式（如 Google Authenticator、Authy），掃描這裏的QR 圖形碼</strong>。在雙重認證啟用後，你登入時將須要使用此應用程式產生的認證碼。\"\n    lost_recovery_codes: 讓你可以在遺失電話時，使用備用驗證碼登入。如果你遺失了備用驗證碼，可以在這裏產生一批新的，舊有的備用驗證碼將會失效。\n    manual_instructions: 如果你無法掃描 QR 圖形碼，請手動輸入這個文字密碼︰\n    recovery_codes: 備份恢復驗證碼\n    recovery_codes_regenerated: 成功產生新的備用驗證碼\n    recovery_instructions_html: 如果你遺失了安裝認證器的裝置（如︰你的電話），你可以使用備用驗證碼進行登入。請確保將備用驗證碼收藏穩當，（如列印出來，和你其他重要文件一起存放）。\n    setup: 設定\n    wrong_code: 你輸入的認證碼並不正確！可能伺服器時間和你手機不一致，請檢查你手機的時鐘，或與本站管理員聯絡。\n  user_mailer:\n    backup_ready:\n      explanation: 你要求的 Mastodon 帳號完整備份檔案現已就緒，可供下載。\n      subject: 你的備份檔已可供下載\n      title: 檔案匯出\n    welcome:\n      edit_profile_action: 設定個人資料\n      edit_profile_step: 你可以設定你的個人資料，包括上傳頭像、橫幅圖片、更改顯示名稱等等。如果你想在新的關注者關注你之前對他們進行審核，你也可以選擇為你的帳戶設為「私人」。\n      explanation: 下面是幾個小貼士，希望它們能幫到你\n      final_action: 開始發文\n      final_step: '開始發文吧！即使你現在沒有關注者，其他人仍然能在本站時間軸或者話題標籤等地方看到你的公開文章。試著用 #introductions 這個話題標籤介紹一下自己吧。'\n      full_handle: 你的完整用戶地址\n      full_handle_hint: 你需要把這個告訴你的朋友們，這樣他們就能從另一個實例向你發送信息或者關注你。\n      review_preferences_action: 更改首選項\n      review_preferences_step: 記得調整你的偏好設置，比如你想接收什麼類型的郵件，或者你想把你的文章可見範圍默認設定為什麼級別。如果你沒有暈車的話，考慮一下啟用「自動播放 GIF 動畫」這個選項吧。\n      subject: 歡迎來到 Mastodon\n      tip_federated_timeline: 跨站公共時間軸可以讓你一窺更廣闊的 Mastodon 網絡。不過，由於它只顯示你的鄰居們所訂閱的內容，所以並不是全部。\n      tip_following: 默認情況下，你會自動關注你所在服務站的管理員。想結交更多有趣的人的話，記得多逛逛本站時間軸和跨站公共時間軸哦。\n      tip_local_timeline: 本站時間軸可以讓你一窺 %{instance} 上的用戶。他們就是離你最近的鄰居！\n      tip_mobile_webapp: 如果你的移動設備瀏覽器允許你將 Mastodon 添加到主屏幕，你就能夠接收推送消息。它就像本地應用一樣好使！\n      tips: 小貼士\n      title: \"%{name}，歡迎你的加入！\"\n  users:\n    invalid_email: 電郵地址格式不正確\n    invalid_otp_token: 雙重認證確認碼不正確\n    otp_lost_help_html: 如果你無法訪問這兩者，可以通過 %{email} 與我們聯繫\n    seamless_external_login: 由於你是從外部系統登入，所以不能設定密碼和電郵。\n    signed_in_as: 目前登入的帳戶：\n"
  },
  {
    "path": "config/locales/zh-TW.yml",
    "content": "---\nzh-TW:\n  about:\n    about_hashtag_html: 這些是包含「<strong>#%{hashtag}</strong>」標籤的公開文章。只要你有任何 Mastodon 站點、或者其他站點的使用者，便可以與他們互動。\n    about_mastodon_html: Mastodon （長毛象）是一個<em>自由、開放原始碼</em>的社群網站。它是一個分散式的服務，避免您的通訊被單一商業機構壟斷操控。請您選擇一家您信任的 Mastodon 站點，在上面建立帳戶，然後您就可以和任一 Mastodon 站點上的使用者互通，享受無縫的<em>社群網路</em>交流。\n    about_this: 關於本站\n    active_count_after: 活躍\n    active_footnote: 每月活躍使用者 (MAU)\n    administered_by: 管理者：\n    apps: 行動應用程式\n    apps_platforms: 在 iOS、Android 和其他平台使用 Mastodon\n    browse_directory: 依興趣瀏覽個人資料目錄和過濾器\n    browse_public_posts: 在 Mastodon 瀏覽公開嘟文的即時串流\n    contact: 聯絡我們\n    contact_missing: 未設定\n    contact_unavailable: 未公開\n    discover_users: 探索使用者\n    documentation: 文件\n    extended_description_html: |\n      <h3>這裡可以寫一些網站規則</h3>\n      <p>本站點未有詳細介紹</p>\n    generic_description: \"%{domain} 是 Mastodon 網路中其中一個站點\"\n    get_apps: 嘗試行動應用程式\n    hosted_on: 在 %{domain} 運作的 Mastodon 站點\n    learn_more: 了解詳細\n    privacy_policy: 隱私權政策\n    see_whats_happening: 看看發生什麼事\n    server_stats: 伺服器統計：\n    source_code: 原始碼\n    status_count_after:\n      other: 條嘟文\n    status_count_before: 他們共嘟出了\n    tagline: 關注朋友並探索新朋友\n    terms: 使用條款\n    user_count_after:\n      other: 位使用者\n    user_count_before: 註冊使用者數\n    what_is_mastodon: 什麼是 Mastodon?\n  accounts:\n    choices_html: \"%{name} 的選擇：\"\n    follow: 關注\n    followers:\n      other: 關注者\n    following: 正在關注\n    joined: 加入於 %{date}\n    last_active: 上次活躍時間\n    link_verified_on: 此連結的所有權已在 %{date} 檢查過\n    media: 媒體\n    moved_html: \"%{name} 已經搬遷到 %{new_profile_link}:\"\n    network_hidden: 此訊息不可用\n    nothing_here: 暫時沒有內容可供顯示!\n    people_followed_by: \"%{name} 關注的人\"\n    people_who_follow: 關注 %{name} 的人\n    posts:\n      other: 嘟文\n    posts_tab_heading: 嘟文\n    posts_with_replies: 嘟文與回覆\n    reserved_username: 此使用者名稱已被保留\n    roles:\n      admin: 管理員\n      bot: 機器人\n      moderator: 版主\n    unfollow: 取消關注\n  admin:\n    account_actions:\n      action: 執行動作\n      title: 在 %{acct} 執行管理員動作\n    account_moderation_notes:\n      create: 記錄\n      created_msg: 已新增管理備忘!\n      delete: 刪除\n      destroyed_msg: 成功刪除管理備忘!\n    accounts:\n      approve: 核准\n      are_you_sure: 您確定嗎?\n      avatar: 頭像\n      by_domain: 站點\n      change_email:\n        changed_msg: 已成功變更帳戶電子信箱位址！\n        current_email: 目前的電子信箱位址\n        label: 變更電子信箱位址\n        new_email: 新的電子信箱位址\n        submit: 變更電子信箱位址\n        title: 為 %{username} 變更電子信箱位址\n      confirm: 確定\n      confirmed: 已確定\n      confirming: 確定\n      deleted: 已刪除\n      demote: 降級\n      disable: 停用\n      disable_two_factor_authentication: 停用兩階段認證\n      disabled: 已停用\n      display_name: 暱稱\n      domain: 站點\n      edit: 編輯\n      email: 電子信箱位址\n      email_status: 電子信箱狀態\n      enable: 啟用\n      enabled: 已啟用\n      feed_url: 訂閱 URL\n      followers: 關注者\n      followers_url: 關注者（Followers）URL\n      follows: 正在關注\n      header: 開頭\n      inbox_url: 收件箱 (Inbox) URL\n      invited_by: 邀請者\n      ip: IP 位址\n      joined: 已加入\n      location:\n        all: 全部\n        local: 本站\n        remote: 遠端\n        title: 位置\n      login_status: 登入狀態\n      media_attachments: 多媒體附件\n      memorialize: 設定為追悼帳戶\n      moderation:\n        active: 活躍\n        all: 全部\n        pending: 等待中\n        silenced: 已靜音\n        suspended: 已停權\n        title: 版務\n      moderation_notes: 管理備忘\n      most_recent_activity: 最近活動\n      most_recent_ip: 最近 IP 位址\n      no_limits_imposed: 未受限制\n      not_subscribed: 未訂閱\n      outbox_url: 寄件箱 (Outbox) URL\n      pending: 等待審核中\n      perform_full_suspension: 停權\n      profile_url: 個人檔案 URL\n      promote: 晉級\n      protocol: 協議\n      public: 公開\n      push_subscription_expires: PuSH 訂閱過期\n      redownload: 重新整理個人資料\n      reject: 拒絕\n      remove_avatar: 取消頭像\n      remove_header: 移除開頭\n      resend_confirmation:\n        already_confirmed: 此使用者已被確認\n        send: 重新發送驗證信\n        success: 驗證信發送成功!\n      reset: 重設\n      reset_password: 重設密碼\n      resubscribe: 重新訂閱\n      role: 身份\n      roles:\n        admin: 管理員\n        moderator: 版主\n        staff: 管理人員\n        user: 普通使用者\n      salmon_url: Salmon 網址\n      search: 搜尋\n      shared_inbox_url: 共享收件箱網址\n      show:\n        created_reports: 建立檢舉\n        targeted_reports: 由其他人檢舉\n      silence: 靜音\n      silenced: 已靜音\n      statuses: 嘟文\n      subscribe: 訂閱\n      suspended: 已停權\n      title: 帳戶\n      unconfirmed_email: 未確認的電子信箱位址\n      undo_silenced: 取消靜音\n      undo_suspension: 取消停權\n      unsubscribe: 取消訂閱\n      username: 使用者名稱\n      warn: 警告\n      web: 頁面\n    action_logs:\n      actions:\n        assigned_to_self_report: \"%{name} 接受了檢舉 %{target}\"\n        change_email_user: \"%{name} 變更了使用者 %{target} 的電子信箱位址\"\n        confirm_user: \"%{name} 確認了使用者 %{target} 的電子信箱位址\"\n        create_account_warning: \"%{name} 已對 %{target} 送出警告\"\n        create_custom_emoji: \"%{name} 加入自訂表情符號 %{target}\"\n        create_domain_block: \"%{name} 封鎖了站點 %{target}\"\n        create_email_domain_block: \"%{name} 封鎖了電子信箱網域 %{target}\"\n        demote_user: \"%{name} 把使用者 %{target} 降級\"\n        destroy_custom_emoji: \"%{name} 破壞了 %{target} 表情符號\"\n        destroy_domain_block: \"%{name} 取消了對站點 %{target} 的封鎖\"\n        destroy_email_domain_block: \"%{name} 取消了對電子信箱網域 %{target} 的封鎖\"\n        destroy_status: \"%{name} 刪除了 %{target} 的嘟文\"\n        disable_2fa_user: \"%{name} 停用了使用者 %{target} 的兩階段認證\"\n        disable_custom_emoji: \"%{name} 停用了自訂表情符號 %{target}\"\n        disable_user: \"%{name} 將使用者 %{target} 設定為禁止登入\"\n        enable_custom_emoji: \"%{name} 啟用了自訂表情符號 %{target}\"\n        enable_user: \"%{name} 將使用者 %{target} 設定為允許登入\"\n        memorialize_account: \"%{name} 將 %{target} 設定為追悼帳戶\"\n        promote_user: \"%{name} 對使用者 %{target} 進行了晉級操作\"\n        remove_avatar_user: \"%{name} 移除了 %{target} 的頭像\"\n        reopen_report: \"%{name} 重新開啟 %{target} 的檢舉\"\n        reset_password_user: \"%{name} 重新設定了使用者 %{target} 的密碼\"\n        resolve_report: \"%{name} 處理了 %{target}　的檢舉\"\n        silence_account: \"%{name} 靜音了使用者 %{target}\"\n        suspend_account: \"%{name} 停權了使用者 %{target}\"\n        unassigned_report: \"%{name} 取消指派 %{target} 的檢舉\"\n        unsilence_account: \"%{name} 取消了使用者 %{target} 的靜音狀態\"\n        unsuspend_account: \"%{name} 取消了使用者 %{target} 的停權狀態\"\n        update_custom_emoji: \"%{name} 更新了自訂表情符號 %{target}\"\n        update_status: \"%{name} 重整了 %{target} 的嘟文\"\n      deleted_status: \"（已刪除嘟文）\"\n      title: 營運日誌\n    custom_emojis:\n      by_domain: 站點\n      copied_msg: 成功將表情複製到本地\n      copy: 複製\n      copy_failed_msg: 無法將表情複製到本地\n      created_msg: 已新增表情符號!\n      delete: 刪除\n      destroyed_msg: 已刪除表情符號!\n      disable: 停用\n      disabled_msg: 已停用表情符號\n      emoji: 表情符號\n      enable: 啟用\n      enabled_msg: 已啟用表情符號\n      image_hint: PNG 格式, 最大 50KB\n      listed: 已顯示\n      new:\n        title: 加入新的自訂表情符號\n      overwrite: 覆蓋\n      shortcode: 短代碼\n      shortcode_hint: 至少 2 個字元，只能使用字母、數字和下劃線\n      title: 自訂表情符號\n      unlisted: 已隱藏\n      update_failed_msg: 無法更新表情符號\n      updated_msg: 已更新表情符號!\n      upload: 上傳新的表情符號\n    dashboard:\n      backlog: 未處理工作數\n      config: 設定\n      feature_deletions: 帳戶刪除\n      feature_invites: 邀請連結\n      feature_profile_directory: 個人資料目錄\n      feature_registrations: 註冊\n      feature_relay: 聯邦中繼站\n      features: 功能\n      hidden_service: 與隱密服務互連\n      open_reports: 待處理檢舉數\n      recent_users: 最近加入的使用者\n      search: 全文搜尋\n      single_user_mode: 單一使用者模式\n      software: 軟體\n      space: 儲存空間用量\n      title: 儀表板\n      total_users: 總使用者數\n      trends: 趨勢\n      week_interactions: 本週互動次數\n      week_users_active: 本週活躍使用者數\n      week_users_new: 本週新使用者數\n    domain_blocks:\n      add_new: 新增欲封鎖域名\n      created_msg: 正在進行站點封鎖\n      destroyed_msg: 已撤銷站點封鎖\n      domain: 站點\n      new:\n        create: 新增封鎖\n        hint: 站點封鎖動作並不會阻止帳戶紀錄被新增至資料庫，但會自動回溯性地對那些帳戶套用特定管理設定。\n        severity:\n          desc_html: \"「<strong>靜音</strong>」令該站點下使用者的嘟文，設定為只對關注者顯示，沒有關注的人會看不到。「<strong>停權</strong>」會刪除將該站點下使用者的嘟文、媒體檔案和個人資料。「<strong>無</strong>」則會拒絕接收來自該站點的媒體檔案。\"\n          noop: 無\n          silence: 靜音\n          suspend: 停權\n        title: 新增封鎖站點\n      reject_media: 拒絕媒體檔案\n      reject_media_hint: 刪除本地快取的媒體檔案，並且不再接收來自該站點的任何媒體檔案。與停權無關\n      reject_reports: 拒絕檢舉\n      reject_reports_hint: 忽略所有來自此站點的檢舉。與停權無關\n      rejecting_media: 拒絕媒體檔案\n      rejecting_reports: 拒絕檢舉中\n      severity:\n        silence: 已靜音\n        suspend: 已停權\n      show:\n        affected_accounts:\n          other: 將影響到資料庫中的 %{count} 個帳戶\n        retroactive:\n          silence: 對此站點的所有使用者取消靜音\n          suspend: 對此站點的所有使用者取消停權\n        title: 撤銷 %{domain} 的站點封鎖\n        undo: 撤銷\n      undo: 復原欲封鎖域名\n    email_domain_blocks:\n      add_new: 加入新項目\n      created_msg: 已成功將電子信箱網域加入黑名單\n      delete: 刪除\n      destroyed_msg: 已成功從黑名單刪除電子信箱網域\n      domain: 站點\n      new:\n        create: 新增站點\n        title: 新增電子信箱黑名單項目\n      title: 電子信箱黑名單\n    followers:\n      back_to_account: 返回帳戶\n      title: \"%{acct} 的關注者\"\n    instances:\n      title: 聯邦\n    invites:\n      filter:\n        all: 全部\n        available: 可用\n        expired: 已失效\n        title: 篩選\n      title: 邀請使用者\n    relays:\n      description_html: \"<strong>聯邦中繼站</strong> 是種中繼伺服器，會在訂閱並推送至此中繼站的伺服器之間交換大量的公開嘟文。<strong>中繼站也能協助小型或中型伺服器從聯邦中探索內容</strong>，而無須本地使用者手動關注遠端伺服器的其他使用者。\"\n    report_notes:\n      created_msg: 檢舉記錄建立成功!\n      destroyed_msg: 檢舉記錄刪除成功!\n    reports:\n      account:\n        note: 條記錄\n        report: 條檢舉\n      action_taken_by: 操作執行者\n      are_you_sure: 你確定嗎?\n      assign_to_self: 指派給自己\n      assigned: 指派負責人\n      comment:\n        none: 無\n      created_at: 日期\n      mark_as_resolved: 標記為「已解決」\n      mark_as_unresolved: 標記為「未解決」\n      notes:\n        create: 建立記錄\n        create_and_resolve: 建立記錄並標記為「已解決」\n        create_and_unresolve: 建立記錄並標記「未解決」\n        delete: 刪除\n        placeholder: 記錄已執行的動作，或其他相關的更新...\n      reopen: 重開檢舉\n      report: '檢舉 #%{id}'\n      reported_account: 被檢舉使用者\n      reported_by: 檢舉人\n      resolved: 已解決\n      resolved_msg: 檢舉已處理!\n      status: 嘟文\n      title: 檢舉\n      unassign: 取消指派\n      unresolved: 未解決\n      updated_at: 更新\n    settings:\n      activity_api_enabled:\n        desc_html: 本站使用者發佈的嘟文數量，以及本站的活躍使用者與一週內新使用者數量\n        title: 公開使用者活躍度的統計數據\n      bootstrap_timeline_accounts:\n        desc_html: 以半形逗號分隔多個使用者名。只能加入來自本站且未開啟保護的帳戶。如果留空，則預設關注本站所有管理員。\n        title: 新使用者預設關注\n      contact_information:\n        email: 用於聯絡的公開電子信箱位址\n        username: 請輸入使用者名稱\n      hero:\n        desc_html: 在首頁顯示。推薦最小 600x100px。如果留空，就會重設回伺服器預覽圖\n        title: 主題圖片\n      peers_api_enabled:\n        desc_html: 本伺服器在聯邦中發現的站點\n        title: 發布已知伺服器的列表\n      registrations:\n        closed_message:\n          desc_html: 關閉註冊時顯示在首頁的內容，可使用 HTML 標籤\n          title: 關閉註冊訊息\n        deletion:\n          desc_html: 允許所有人刪除自己的帳戶\n          title: 開放刪除帳戶的權限\n        min_invite_role:\n          disabled: 沒有人\n          title: 允許發送邀請的身份\n      show_known_fediverse_at_about_page:\n        desc_html: 如果開啟，就會在時間軸預覽顯示其他站點嘟文，否則就只會顯示本站點嘟文。\n        title: 在時間軸預覽顯示其他站點嘟文\n      show_staff_badge:\n        desc_html: 在個人資料頁面上顯示管理人員標誌\n        title: 顯示管理人員標誌\n      site_description:\n        desc_html: 首頁上的介紹文字，描述此 Mastodon 伺服器的特別之處和其他重要資訊。可使用 HTML 標籤，包括 <code>&lt;a&gt;</code> 和 <code>&lt;em&gt;</code>。\n        title: 伺服器描述\n      site_description_extended:\n        desc_html: 可放置行為準則、規定以及其他此伺服器特有的內容。可使用 HTML 標籤\n        title: 本站詳細資訊\n      site_terms:\n        desc_html: 可以填寫自己的隱私權政策、使用條款或其他法律文本。可以使用 HTML 標籤\n        title: 自訂使用條款\n      site_title: 伺服器名稱\n      thumbnail:\n        desc_html: 用於在 OpenGraph 和 API 中顯示預覽圖。推薦大小 1200×630px\n        title: 伺服器縮圖\n      timeline_preview:\n        desc_html: 在主頁顯示本站時間軸\n        title: 時間軸預覽\n      title: 網站設定\n    statuses:\n      back_to_account: 返回帳戶訊息頁\n      batch:\n        delete: 刪除\n        nsfw_off: 標記為非敏感內容\n        nsfw_on: 標記為敏感內容\n      failed_to_execute: 執行失敗\n      media:\n        title: 媒體檔案\n      no_media: 不含媒體檔案\n      title: 帳戶嘟文\n      with_media: 含有媒體檔案\n    subscriptions:\n      callback_url: 回傳網址\n      confirmed: 已確認\n      expires_in: 期限\n      last_delivery: 最後遞送\n      title: WebSub 訂閱\n      topic: 主題\n    title: 管理介面\n  admin_mailer:\n    new_report:\n      body: \"%{reporter} 檢舉了使用者 %{target}\"\n      body_remote: 來自 %{domain} 的使用者檢舉了使用者 %{target}\n      subject: 來自 %{instance} 的使用者檢舉（#%{id}）\n  application_mailer:\n    notification_preferences: 變更電子信件設定\n    salutation: \"%{name}、\"\n    settings: 變更電子信箱設定︰%{link}\n    view: '進入瀏覽:'\n    view_profile: 檢視個人資料頁\n    view_status: 檢視嘟文\n  applications:\n    created: 已建立應用\n    destroyed: 已刪除應用\n    invalid_url: 網址不正確\n    regenerate_token: 重設 token\n    token_regenerated: 已重設 token\n    warning: 警告，不要把它分享給任何人!\n    your_token: 你的 token\n  auth:\n    change_password: 密碼\n    confirm_email: 確認電子信箱位址\n    delete_account: 刪除帳戶\n    delete_account_html: 如果你想刪除你的帳戶，請<a href=\"%{path}\">點擊這裡繼續</a>。你需要確認你的操作。\n    didnt_get_confirmation: 沒有收到驗證信?\n    forgot_password: 忘記密碼？\n    invalid_reset_password_token: 密碼重設 token 無效或已過期。請重新設定密碼。\n    login: 登入\n    logout: 登出\n    migrate_account: 轉移到另一個帳戶\n    migrate_account_html: 如果你希望引導他人關注另一個帳戶，請<a href=\"%{path}\">到這裡設定</a>。\n    or_log_in_with: 或透過其他方式登入\n    register: 註冊\n    resend_confirmation: 重新寄送確認指引\n    reset_password: 重設密碼\n    security: 登入資訊\n    set_new_password: 設定新密碼\n  authorize_follow:\n    already_following: 你已經關注了這個使用者\n    error: 對不起，搜尋其他站點使用者出現錯誤\n    follow: 關注\n    follow_request: 關注請求已經發送給：\n    following: 成功! 你正在關注：\n    post_follow:\n      close: 你也可以直接關閉這個頁面。\n      return: 顯示個人資料頁\n      web: 返回本站\n    title: 關注 %{acct}\n  datetime:\n    distance_in_words:\n      about_x_hours: \"%{count}小時前\"\n      about_x_months: \"%{count}個月前\"\n      about_x_years: \"%{count}年前\"\n      almost_x_years: 接近%{count}年前\n      half_a_minute: 剛剛\n      less_than_x_minutes: 小於%{count}分鐘前\n      less_than_x_seconds: 剛剛\n      over_x_years: \"%{count}年\"\n      x_days: \"%{count}天\"\n      x_minutes: \"%{count}分\"\n      x_months: \"%{count}個月\"\n      x_seconds: \"%{count}秒\"\n  deletes:\n    bad_password_msg: 想得美，駭客! 密碼輸入錯誤\n    confirm_password: 輸入你現在的密碼來驗證身份\n    description_html: 繼續操作將會<strong>永久地、不可還原地</strong>刪除帳戶中的所有內容，然後凍結帳戶。你的使用者名稱將會被保留，以防有人冒用你的身份。\n    proceed: 刪除帳戶\n    success_msg: 你的帳戶已經成功刪除\n    warning_html: 我們只能保證本伺服器上的內容將會被徹底刪除。對於已經被廣泛傳播的內容，它們在本伺服器以外的某些地方可能仍然可見。此外，離線伺服器以及停止接收訂閱的伺服器所儲存的資料亦無法刪除。\n    warning_title: 關於已傳播的內容警告\n  errors:\n    '403': 你沒有觀看這個頁面的權限。\n    '404': 您所尋找的網頁不存在。\n    '410': 您所尋找的網頁此處已不存在。\n    '422':\n      content: 安全驗證失敗。請確定有開啟瀏覽器 Cookies 功能?\n      title: 安全驗證失敗\n    '429': 伺服器繁忙\n    '500':\n      content: 抱歉，我們的後台出現問題了。\n      title: 這個頁面有問題\n    noscript_html: 使用 Mastodon 網頁版應用需要啟用 JavaScript。你也可以選擇適用於你的平台的 <a href=\"%{apps_path}\">Mastodon 應用</a>。\n  exports:\n    archive_takeout:\n      date: 日期\n      download: 下載檔案\n      hint_html: 你可以下載包含你的<strong>文章和媒體</strong>的檔案。資料以 ActivityPub 格式儲存，可用於相容的軟體。每次允許存檔的間隔至少7天。\n      in_progress: 正在準備你的存檔...\n      request: 下載存檔\n      size: 大小\n    blocks: 您封鎖的使用者\n    follows: 您關注的使用者\n    mutes: 您靜音的使用者\n    storage: 儲存空間大小\n  generic:\n    changes_saved_msg: 已成功儲存修改!\n    save_changes: 儲存修改\n  imports:\n    preface: 您可以在此匯入您在其他伺服器所匯出的資料檔，包括關注的使用者、封鎖的使用者名單。\n    success: 資料檔上傳成功，正在匯入，請稍候\n    types:\n      blocking: 您封鎖的使用者名單\n      following: 您關注的使用者名單\n      muting: 您靜音的使用者名單\n    upload: 上傳\n  in_memoriam_html: 謹此悼念。\n  invites:\n    delete: 停用\n    expired: 已失效\n    expires_in:\n      '1800': 30 分鐘後\n      '21600': 6 小時後\n      '3600': 1 小時後\n      '43200': 12 小時後\n      '604800': 1 週後\n      '86400': 1 天後\n    expires_in_prompt: 永不過期\n    generate: 建立邀請連結\n    invited_by: 你的邀請人是：\n    max_uses_prompt: 無限制\n    prompt: 建立分享連結，邀請他人在本伺服器註冊\n    table:\n      expires_at: 失效時間\n      uses: 已使用次數\n    title: 邀請使用者\n  lists:\n    errors:\n      limit: 你所建立的列表數量已經達到上限\n  media_attachments:\n    validations:\n      images_and_video: 無法在已有圖片的文章上加入影片\n      too_many: 無法加入超過 4 個檔案\n  migrations:\n    acct: 新帳戶的 使用者名稱@站點網域\n    currently_redirecting: 目前你的個人資料頁顯示的新帳戶是：\n    proceed: 儲存\n    updated_msg: 帳戶搬遷設定更新成功!\n  moderation:\n    title: 營運\n  notification_mailer:\n    digest:\n      action: 閱覽所有通知\n      body: 以下是自%{since}你最後一次登入以來錯過的訊息摘要\n      mention: \"%{name} 在此提及了你:\"\n      title: 你不在的時候...\n    favourite:\n      body: '你的嘟文被 %{name} 加入了最愛:'\n      subject: \"%{name} 將你的嘟文加入了最愛\"\n      title: 新的最愛\n    follow:\n      body: \"%{name} 開始關注你！\"\n      subject: \"%{name} 開始關注你\"\n      title: 新的關注者\n    follow_request:\n      action: 處理關注請求\n      body: \"%{name} 要求關注你\"\n      subject: 等待關注你的使用者︰ %{name}\n      title: 新的關注請求\n    mention:\n      action: 回覆\n      body: \"%{name} 在嘟文中提及你:\"\n      subject: \"%{name} 在嘟文中提及你\"\n      title: 新的提及\n    reblog:\n      body: '你的嘟文被 %{name} 轉嘟:'\n      subject: \"%{name} 轉嘟了你的嘟文\"\n      title: 新的轉嘟\n  pagination:\n    newer: 較新\n    next: 下一頁\n    older: 較舊\n    prev: 上一頁\n  remote_follow:\n    acct: 請輸入您的使用者名稱@站點網域\n    missing_resource: 無法找到資源\n    proceed: 下一步\n    prompt: '您希望關注:'\n  remote_unfollow:\n    error: 錯誤\n    title: 標題\n    unfollowed: 取消關注\n  sessions:\n    activity: 最近活動\n    browser: 瀏覽器\n    browsers:\n      alipay: 支付寶\n      blackberry: 黑莓機\n      chrome: Chrome 瀏覽器\n      edge: Microsoft Edge 瀏覽器\n      electron: Electron 瀏覽器\n      firefox: Firefox 瀏覽器\n      generic: 未知的瀏覽器\n      ie: Internet Explorer 瀏覽器\n      micro_messenger: 微信\n      nokia: Nokia S40 Ovi 瀏覽器\n      opera: Opera 瀏覽器\n      otter: Otter 瀏覽器\n      phantom_js: PhantomJS 瀏覽器\n      qq: QQ 瀏覽器\n      safari: Safari 瀏覽器\n      uc_browser: UC 瀏覽器\n      weibo: 新浪微博\n    current_session: 目前的 session\n    description: \"%{platform} 上的 %{browser}\"\n    explanation: 這些是現在正登入於你的 Mastodon 帳戶的瀏覽器。\n    ip: IP 位址\n    revoke: 取消\n    revoke_success: Session 取消成功\n    title: 作業階段\n  settings:\n    authorized_apps: 已授權應用程式\n    back: 回到 Mastodon\n    delete: 刪除帳戶\n    development: 開發\n    edit_profile: 編輯使用者資訊\n    export: 匯出\n    import: 匯入\n    migrate: 帳戶搬遷\n    notifications: 通知\n    preferences: 偏好設定\n    two_factor_authentication: 兩階段認證\n  statuses:\n    attached:\n      description: 附件： %{attached}\n    boosted_from_html: 轉嘟自 %{acct_link}\n    content_warning: 內容警告： %{warning}\n    language_detection: 自動偵測語言\n    open_in_web: 以網頁開啟\n    over_character_limit: 超過了 %{max} 字的限制\n    pin_errors:\n      limit: 你所置頂的嘟文數量已經達到上限\n      ownership: 不能置頂他人的嘟文\n      private: 不能置頂非公開的嘟文\n      reblog: 不能置頂轉嘟\n    show_more: 顯示更多\n    visibilities:\n      private: 僅關注者\n      private_long: 只有關注你的人能看到\n      public: 公開\n      public_long: 所有人都能看到\n      unlisted: 公開，但不在公共時間軸顯示\n      unlisted_long: 所有人都能看到，但不會出現在公共時間軸上\n  stream_entries:\n    pinned: 置頂嘟文\n    reblogged: 轉嘟\n    sensitive_content: 敏感內容\n  terms:\n    title: \"%{instance} 使用條款和隱私權政策\"\n  themes:\n    contrast: Mastodon（高對比）\n    mastodon-light: Mastodon（亮色主題）\n  time:\n    formats:\n      default: \"%Y年%-m月%d日 %H:%M\"\n  two_factor_authentication:\n    code_hint: 請輸入您認證器產生的代碼，以進行認證\n    description_html: 啟用<strong>兩階段認證</strong>後，登入時將需要使手機、或其他種類認證器產生的代碼。\n    disable: 停用\n    enable: 啟用\n    enabled: 兩階段認證已啟用\n    enabled_success: 已成功啟用兩階段認證\n    generate_recovery_codes: 產生備用驗證碼\n    instructions_html: \"<strong>請用您手機的認證器應用程式（如 Google Authenticator、Authy），掃描這裡的 QR 圖形碼</strong>。在兩階段認證啟用後，您登入時將須要使用此應用程式產生的認證碼。\"\n    lost_recovery_codes: 讓你可以在遺失手機時，使用備用驗證碼登入。如果你遺失了備用驗證碼，可以在這裏產生一批新的，舊有的備用驗證碼將會失效。\n    manual_instructions: '如果您無法掃描 QR 圖形碼，請手動輸入:'\n    recovery_codes: 備份備用驗證碼\n    recovery_codes_regenerated: 成功產生新的備用驗證碼\n    recovery_instructions_html: 如果你的手機無法使用，你可以使用下列任意一個備用驗證碼來重新獲得帳戶的訪問權。<strong>請妥善保管好你的備用驗證碼</strong>（例如，你可以將它們列印出來，與你的其他重要文件放在一起）。\n    setup: 設定\n    wrong_code: 您輸入的認證碼無效! 請確認伺服器時間與設備時間是否正確?\n  user_mailer:\n    backup_ready:\n      explanation: 你要求的 Mastodon 帳戶完整備份檔案現已就緒，可供下載!\n      subject: 你的備份檔已可供下載\n      title: 檔案匯出\n    welcome:\n      edit_profile_action: 設定個人資料\n      edit_profile_step: 你可以設定你的個人資料，包括上傳頭像、橫幅圖片、變更顯示名稱等等。如果你想在新的關注者關注你之前對他們進行審核，你也可以選擇為你的帳戶設為「私人」。\n      explanation: 下面是幾個小幫助，希望它們能幫到你\n      final_action: 開始嘟嘟\n      final_step: '開始嘟嘟吧! 即使你現在沒有關注者，其他人仍然能在本站時間軸或著話題標籤等地方看到你的公開嘟文。試著用 #introductions 這個話題標籤介紹一下自己吧。'\n      full_handle: 你的完整帳戶名稱\n      full_handle_hint: 你需要把這告訴你的朋友們，這樣他們就能從另一個伺服器向你發送訊息或著關注你。\n      review_preferences_action: 變更偏好設定\n      review_preferences_step: 記得調整你的偏好設定，比如你想接收什麼類型的電子郵件，或著你想把你的嘟文可見範圍預設設定什麼級別。如果你沒有暈車的話，考慮一下啟用「自動播放 GIF 動畫」這個選項吧。\n      subject: 歡迎來到 Mastodon\n      tip_federated_timeline: 跨站公共時間軸可以讓你一窺更廣闊的 Mastodon 網路。不過，由於它們只顯示你的鄰居們所訂閱的內容，所以並不是全部。\n      tip_following: 預設情況下，你會自動關注你所在站點的管理員。想結交更多有趣的人的話，記得多逛逛本站時間軸與跨站公共時間軸哦。\n      tip_local_timeline: 本站時間軸可以讓你一窺 %{instance} 上的使用者。他們就是離你最近的鄰居！\n      tip_mobile_webapp: 如果你的行動裝置瀏覽器允許你將 Mastodon 新增到主螢幕，你就能夠接收推送訊息。它就像手機APP一樣好用!\n      tips: 小幫手\n      title: \"%{name} 歡迎你的加入！\"\n  users:\n    invalid_email: 電子信箱位址不正確\n    invalid_otp_token: 兩階段認證碼不正確\n    otp_lost_help_html: 如果你無法訪問這兩者，可以通過 %{email} 與我們聯繫\n    seamless_external_login: 由於你是從外部系統登入，所以不能設定密碼與電子郵件。\n    signed_in_as: 目前登入的帳戶：\n"
  },
  {
    "path": "config/navigation.rb",
    "content": "# frozen_string_literal: true\n\nSimpleNavigation::Configuration.run do |navigation|\n  navigation.items do |n|\n    n.item :web, safe_join([fa_icon('chevron-left fw'), t('settings.back')]), root_url\n\n    n.item :profile, safe_join([fa_icon('user fw'), t('settings.profile')]), settings_profile_url do |s|\n      s.item :profile, safe_join([fa_icon('pencil fw'), t('settings.appearance')]), settings_profile_url, highlights_on: %r{/settings/profile|/settings/migration}\n      s.item :featured_tags, safe_join([fa_icon('hashtag fw'), t('settings.featured_tags')]), settings_featured_tags_url\n      s.item :identity_proofs, safe_join([fa_icon('key fw'), t('settings.identity_proofs')]), settings_identity_proofs_path, highlights_on: %r{/settings/identity_proofs*}, if: proc { current_account.identity_proofs.exists? }\n    end\n\n    n.item :preferences, safe_join([fa_icon('cog fw'), t('settings.preferences')]), settings_preferences_url do |s|\n      s.item :appearance, safe_join([fa_icon('desktop fw'), t('settings.appearance')]), settings_preferences_appearance_url\n      s.item :notifications, safe_join([fa_icon('bell fw'), t('settings.notifications')]), settings_preferences_notifications_url\n      s.item :other, safe_join([fa_icon('cog fw'), t('preferences.other')]), settings_preferences_other_url\n    end\n\n    n.item :relationships, safe_join([fa_icon('users fw'), t('settings.relationships')]), relationships_url\n    n.item :filters, safe_join([fa_icon('filter fw'), t('filters.index.title')]), filters_path, highlights_on: %r{/filters}\n\n    n.item :security, safe_join([fa_icon('lock fw'), t('settings.account')]), edit_user_registration_url do |s|\n      s.item :password, safe_join([fa_icon('lock fw'), t('settings.account_settings')]), edit_user_registration_url, highlights_on: %r{/auth/edit|/settings/delete}\n      s.item :two_factor_authentication, safe_join([fa_icon('mobile fw'), t('settings.two_factor_authentication')]), settings_two_factor_authentication_url, highlights_on: %r{/settings/two_factor_authentication}\n      s.item :authorized_apps, safe_join([fa_icon('list fw'), t('settings.authorized_apps')]), oauth_authorized_applications_url\n    end\n\n    n.item :data, safe_join([fa_icon('cloud-download fw'), t('settings.import_and_export')]), settings_export_url do |s|\n      s.item :import, safe_join([fa_icon('cloud-upload fw'), t('settings.import')]), settings_import_url\n      s.item :export, safe_join([fa_icon('cloud-download fw'), t('settings.export')]), settings_export_url\n    end\n\n    n.item :invites, safe_join([fa_icon('user-plus fw'), t('invites.title')]), invites_path, if: proc { Setting.min_invite_role == 'user' }\n    n.item :development, safe_join([fa_icon('code fw'), t('settings.development')]), settings_applications_url\n\n    n.item :moderation, safe_join([fa_icon('gavel fw'), t('moderation.title')]), admin_reports_url, if: proc { current_user.staff? } do |s|\n      s.item :action_logs, safe_join([fa_icon('bars fw'), t('admin.action_logs.title')]), admin_action_logs_url\n      s.item :reports, safe_join([fa_icon('flag fw'), t('admin.reports.title')]), admin_reports_url, highlights_on: %r{/admin/reports}\n      s.item :accounts, safe_join([fa_icon('users fw'), t('admin.accounts.title')]), admin_accounts_url, highlights_on: %r{/admin/accounts|/admin/pending_accounts}\n      s.item :invites, safe_join([fa_icon('user-plus fw'), t('admin.invites.title')]), admin_invites_path\n      s.item :tags, safe_join([fa_icon('tag fw'), t('admin.tags.title')]), admin_tags_path\n      s.item :instances, safe_join([fa_icon('cloud fw'), t('admin.instances.title')]), admin_instances_url(limited: '1'), highlights_on: %r{/admin/instances|/admin/domain_blocks}, if: -> { current_user.admin? }\n      s.item :email_domain_blocks, safe_join([fa_icon('envelope fw'), t('admin.email_domain_blocks.title')]), admin_email_domain_blocks_url, highlights_on: %r{/admin/email_domain_blocks}, if: -> { current_user.admin? }\n    end\n\n    n.item :admin, safe_join([fa_icon('cogs fw'), t('admin.title')]), admin_dashboard_url, if: proc { current_user.staff? } do |s|\n      s.item :dashboard, safe_join([fa_icon('tachometer fw'), t('admin.dashboard.title')]), admin_dashboard_url\n      s.item :settings, safe_join([fa_icon('cogs fw'), t('admin.settings.title')]), edit_admin_settings_url, if: -> { current_user.admin? }, highlights_on: %r{/admin/settings}\n      s.item :custom_emojis, safe_join([fa_icon('smile-o fw'), t('admin.custom_emojis.title')]), admin_custom_emojis_url, highlights_on: %r{/admin/custom_emojis}\n      s.item :relays, safe_join([fa_icon('exchange fw'), t('admin.relays.title')]), admin_relays_url, if: -> { current_user.admin? }, highlights_on: %r{/admin/relays}\n      s.item :subscriptions, safe_join([fa_icon('paper-plane-o fw'), t('admin.subscriptions.title')]), admin_subscriptions_url, if: -> { current_user.admin? }\n      s.item :sidekiq, safe_join([fa_icon('diamond fw'), 'Sidekiq']), sidekiq_url, link_html: { target: 'sidekiq' }, if: -> { current_user.admin? }\n      s.item :pghero, safe_join([fa_icon('database fw'), 'PgHero']), pghero_url, link_html: { target: 'pghero' }, if: -> { current_user.admin? }\n    end\n\n    n.item :logout, safe_join([fa_icon('sign-out fw'), t('auth.logout')]), destroy_user_session_url, link_html: { 'data-method' => 'delete' }\n  end\nend\n"
  },
  {
    "path": "config/puma.rb",
    "content": "threads_count = ENV.fetch('MAX_THREADS') { 5 }.to_i\nthreads threads_count, threads_count\n\nif ENV['SOCKET']\n  bind 'unix://' + ENV['SOCKET']\nelse\n  port ENV.fetch('PORT') { 3000 }\nend\n\nenvironment ENV.fetch('RAILS_ENV') { 'development' }\nworkers     ENV.fetch('WEB_CONCURRENCY') { 2 }\n\npreload_app!\n\non_worker_boot do\n  ActiveSupport.on_load(:active_record) do\n    ActiveRecord::Base.establish_connection\n  end\nend\n\nplugin :tmp_restart\n"
  },
  {
    "path": "config/routes.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'sidekiq/web'\nrequire 'sidekiq-scheduler/web'\n\nSidekiq::Web.set :session_secret, Rails.application.secrets[:secret_key_base]\n\nRails.application.routes.draw do\n  mount LetterOpenerWeb::Engine, at: 'letter_opener' if Rails.env.development?\n\n  authenticate :user, lambda { |u| u.admin? } do\n    mount Sidekiq::Web, at: 'sidekiq', as: :sidekiq\n    mount PgHero::Engine, at: 'pghero', as: :pghero\n  end\n\n  use_doorkeeper do\n    controllers authorizations: 'oauth/authorizations',\n                authorized_applications: 'oauth/authorized_applications',\n                tokens: 'oauth/tokens'\n  end\n\n  get '.well-known/host-meta', to: 'well_known/host_meta#show', as: :host_meta, defaults: { format: 'xml' }\n  get '.well-known/webfinger', to: 'well_known/webfinger#show', as: :webfinger\n  get '.well-known/change-password', to: redirect('/auth/edit')\n  get '.well-known/keybase-proof-config', to: 'well_known/keybase_proof_config#show'\n\n  get 'manifest', to: 'manifests#show', defaults: { format: 'json' }\n  get 'intent', to: 'intents#show'\n  get 'custom.css', to: 'custom_css#show', as: :custom_css\n\n  devise_scope :user do\n    get '/invite/:invite_code', to: 'auth/registrations#new', as: :public_invite\n    match '/auth/finish_signup' => 'auth/confirmations#finish_signup', via: [:get, :patch], as: :finish_signup\n  end\n\n  devise_for :users, path: 'auth', controllers: {\n    omniauth_callbacks: 'auth/omniauth_callbacks',\n    sessions:           'auth/sessions',\n    registrations:      'auth/registrations',\n    passwords:          'auth/passwords',\n    confirmations:      'auth/confirmations',\n  }\n\n  get '/users/:username', to: redirect('/@%{username}'), constraints: lambda { |req| req.format.nil? || req.format.html? }\n  get '/authorize_follow', to: redirect { |_, request| \"/authorize_interaction?#{request.params.to_query}\" }\n\n  resources :accounts, path: 'users', only: [:show], param: :username do\n    resources :stream_entries, path: 'updates', only: [:show] do\n      member do\n        get :embed\n      end\n    end\n\n    get :remote_follow,  to: 'remote_follow#new'\n    post :remote_follow, to: 'remote_follow#create'\n\n    resources :statuses, only: [:show] do\n      member do\n        get :activity\n        get :embed\n        get :replies\n      end\n    end\n\n    resources :followers, only: [:index], controller: :follower_accounts\n    resources :following, only: [:index], controller: :following_accounts\n    resource :follow, only: [:create], controller: :account_follow\n    resource :unfollow, only: [:create], controller: :account_unfollow\n\n    resource :outbox, only: [:show], module: :activitypub\n    resource :inbox, only: [:create], module: :activitypub\n    resources :collections, only: [:show], module: :activitypub\n  end\n\n  resource :inbox, only: [:create], module: :activitypub\n\n  get '/@:username', to: 'accounts#show', as: :short_account\n  get '/@:username/with_replies', to: 'accounts#show', as: :short_account_with_replies\n  get '/@:username/media', to: 'accounts#show', as: :short_account_media\n  get '/@:username/tagged/:tag', to: 'accounts#show', as: :short_account_tag\n  get '/@:account_username/:id', to: 'statuses#show', as: :short_account_status\n  get '/@:account_username/:id/embed', to: 'statuses#embed', as: :embed_short_account_status\n\n  get  '/interact/:id', to: 'remote_interaction#new', as: :remote_interaction\n  post '/interact/:id', to: 'remote_interaction#create'\n\n  get '/explore', to: 'directories#index', as: :explore\n  get '/explore/:id', to: 'directories#show', as: :explore_hashtag\n\n  get '/settings', to: redirect('/settings/profile')\n\n  namespace :settings do\n    resource :profile, only: [:show, :update]\n\n    get :preferences, to: redirect('/settings/preferences/appearance')\n\n    namespace :preferences do\n      resource :appearance, only: [:show, :update], controller: :appearance\n      resource :notifications, only: [:show, :update]\n      resource :other, only: [:show, :update], controller: :other\n    end\n\n    resource :import, only: [:show, :create]\n    resource :export, only: [:show, :create]\n\n    namespace :exports, constraints: { format: :csv } do\n      resources :follows, only: :index, controller: :following_accounts\n      resources :blocks, only: :index, controller: :blocked_accounts\n      resources :mutes, only: :index, controller: :muted_accounts\n      resources :lists, only: :index, controller: :lists\n      resources :domain_blocks, only: :index, controller: :blocked_domains\n    end\n\n    resource :two_factor_authentication, only: [:show, :create, :destroy]\n\n    namespace :two_factor_authentication do\n      resources :recovery_codes, only: [:create]\n      resource :confirmation, only: [:new, :create]\n    end\n\n    resources :identity_proofs, only: [:index, :show, :new, :create, :update]\n\n    resources :applications, except: [:edit] do\n      member do\n        post :regenerate\n      end\n    end\n\n    resource :delete, only: [:show, :destroy]\n    resource :migration, only: [:show, :update]\n\n    resources :sessions, only: [:destroy]\n    resources :featured_tags, only: [:index, :create, :destroy]\n  end\n\n  resources :media, only: [:show] do\n    get :player\n  end\n\n  resources :tags,   only: [:show]\n  resources :emojis, only: [:show]\n  resources :invites, only: [:index, :create, :destroy]\n  resources :filters, except: [:show]\n  resource :relationships, only: [:show, :update]\n\n  get '/public', to: 'public_timelines#show', as: :public_timeline\n  get '/media_proxy/:id/(*any)', to: 'media_proxy#show', as: :media_proxy\n\n  # Remote follow\n  resource :remote_unfollow, only: [:create]\n  resource :authorize_interaction, only: [:show, :create]\n  resource :share, only: [:show, :create]\n\n  namespace :admin do\n    get '/dashboard', to: 'dashboard#index'\n\n    resources :subscriptions, only: [:index]\n    resources :domain_blocks, only: [:new, :create, :show, :destroy]\n    resources :email_domain_blocks, only: [:index, :new, :create, :destroy]\n    resources :action_logs, only: [:index]\n    resources :warning_presets, except: [:new]\n    resource :settings, only: [:edit, :update]\n\n    resources :invites, only: [:index, :create, :destroy] do\n      collection do\n        post :deactivate_all\n      end\n    end\n\n    resources :relays, only: [:index, :new, :create, :destroy] do\n      member do\n        post :enable\n        post :disable\n      end\n    end\n\n    resources :instances, only: [:index, :show], constraints: { id: /[^\\/]+/ }\n\n    resources :reports, only: [:index, :show] do\n      member do\n        post :assign_to_self\n        post :unassign\n        post :reopen\n        post :resolve\n      end\n\n      resources :reported_statuses, only: [:create]\n    end\n\n    resources :report_notes, only: [:create, :destroy]\n\n    resources :accounts, only: [:index, :show] do\n      member do\n        post :subscribe\n        post :unsubscribe\n        post :enable\n        post :unsilence\n        post :unsuspend\n        post :redownload\n        post :remove_avatar\n        post :remove_header\n        post :memorialize\n        post :approve\n        post :reject\n      end\n\n      resource :change_email, only: [:show, :update]\n      resource :reset, only: [:create]\n      resource :action, only: [:new, :create], controller: 'account_actions'\n      resources :statuses, only: [:index, :show, :create, :update, :destroy]\n      resources :followers, only: [:index]\n\n      resource :confirmation, only: [:create] do\n        collection do\n          post :resend\n        end\n      end\n\n      resource :role do\n        member do\n          post :promote\n          post :demote\n        end\n      end\n    end\n\n    resources :pending_accounts, only: [:index] do\n      collection do\n        post :approve_all\n        post :reject_all\n        post :batch\n      end\n    end\n\n    resources :users, only: [] do\n      resource :two_factor_authentication, only: [:destroy]\n    end\n\n    resources :custom_emojis, only: [:index, :new, :create, :update, :destroy] do\n      member do\n        post :copy\n        post :enable\n        post :disable\n      end\n    end\n\n    resources :account_moderation_notes, only: [:create, :destroy]\n\n    resources :tags, only: [:index] do\n      member do\n        post :hide\n        post :unhide\n      end\n    end\n  end\n\n  get '/admin', to: redirect('/admin/dashboard', status: 302)\n\n  namespace :api do\n    # PubSubHubbub outgoing subscriptions\n    resources :subscriptions, only: [:show]\n    post '/subscriptions/:id', to: 'subscriptions#update'\n\n    # PubSubHubbub incoming subscriptions\n    post '/push', to: 'push#update', as: :push\n\n    # Salmon\n    post '/salmon/:id', to: 'salmon#update', as: :salmon\n\n    # OEmbed\n    get '/oembed', to: 'oembed#show', as: :oembed\n\n    # Identity proofs\n    get :proofs, to: 'proofs#index'\n\n    # JSON / REST API\n    namespace :v1 do\n      resources :statuses, only: [:create, :show, :destroy] do\n        scope module: :statuses do\n          resources :reblogged_by, controller: :reblogged_by_accounts, only: :index\n          resources :favourited_by, controller: :favourited_by_accounts, only: :index\n          resource :reblog, only: :create\n          post :unreblog, to: 'reblogs#destroy'\n\n          resource :favourite, only: :create\n          post :unfavourite, to: 'favourites#destroy'\n\n          resource :mute, only: :create\n          post :unmute, to: 'mutes#destroy'\n\n          resource :pin, only: :create\n          post :unpin, to: 'pins#destroy'\n        end\n\n        member do\n          get :context\n          get :card\n        end\n      end\n\n      namespace :timelines do\n        resource :direct, only: :show, controller: :direct\n        resource :home, only: :show, controller: :home\n        resource :public, only: :show, controller: :public\n        resources :tag, only: :show\n        resources :list, only: :show\n      end\n\n      resources :streaming, only: [:index]\n      resources :custom_emojis, only: [:index]\n      resources :suggestions, only: [:index, :destroy]\n      resources :scheduled_statuses, only: [:index, :show, :update, :destroy]\n      resources :preferences, only: [:index]\n\n      resources :conversations, only: [:index, :destroy] do\n        member do\n          post :read\n        end\n      end\n\n      get '/search', to: 'search#index', as: :search\n\n      resources :follows,      only: [:create]\n      resources :media,        only: [:create, :update]\n      resources :blocks,       only: [:index]\n      resources :mutes,        only: [:index]\n      resources :favourites,   only: [:index]\n      resources :reports,      only: [:create]\n      resources :filters,      only: [:index, :create, :show, :update, :destroy]\n      resources :endorsements, only: [:index]\n\n      namespace :apps do\n        get :verify_credentials, to: 'credentials#show'\n      end\n\n      resources :apps, only: [:create]\n\n      resource :instance, only: [:show] do\n        resources :peers, only: [:index], controller: 'instances/peers'\n        resource :activity, only: [:show], controller: 'instances/activity'\n      end\n\n      resource :domain_blocks, only: [:show, :create, :destroy]\n\n      resources :follow_requests, only: [:index] do\n        member do\n          post :authorize\n          post :reject\n        end\n      end\n\n      resources :notifications, only: [:index, :show] do\n        collection do\n          post :clear\n          post :dismiss # Deprecated\n        end\n\n        member do\n          post :dismiss\n        end\n      end\n\n      namespace :accounts do\n        get :verify_credentials, to: 'credentials#show'\n        patch :update_credentials, to: 'credentials#update'\n        resource :search, only: :show, controller: :search\n        resources :relationships, only: :index\n      end\n\n      resources :accounts, only: [:create, :show] do\n        resources :statuses, only: :index, controller: 'accounts/statuses'\n        resources :followers, only: :index, controller: 'accounts/follower_accounts'\n        resources :following, only: :index, controller: 'accounts/following_accounts'\n        resources :lists, only: :index, controller: 'accounts/lists'\n        resources :identity_proofs, only: :index, controller: 'accounts/identity_proofs'\n\n        member do\n          post :follow\n          post :unfollow\n          post :block\n          post :unblock\n          post :mute\n          post :unmute\n        end\n\n        resource :pin, only: :create, controller: 'accounts/pins'\n        post :unpin, to: 'accounts/pins#destroy'\n      end\n\n      resources :lists, only: [:index, :create, :show, :update, :destroy] do\n        resource :accounts, only: [:show, :create, :destroy], controller: 'lists/accounts'\n      end\n\n      resources :polls, only: [:create, :show] do\n        resources :votes, only: :create, controller: 'polls/votes'\n      end\n\n      namespace :push do\n        resource :subscription, only: [:create, :show, :update, :destroy]\n      end\n    end\n\n    namespace :v2 do\n      get '/search', to: 'search#index', as: :search\n    end\n\n    namespace :web do\n      resource :settings, only: [:update]\n      resource :embed, only: [:create]\n      resources :push_subscriptions, only: [:create] do\n        member do\n          put :update\n        end\n      end\n    end\n  end\n\n  get '/web/(*any)', to: 'home#index', as: :web\n\n  get '/about',      to: 'about#show'\n  get '/about/more', to: 'about#more'\n  get '/terms',      to: 'about#terms'\n\n  root 'home#index'\n\n  match '*unmatched_route',\n        via: :all,\n        to: 'application#raise_not_found',\n        format: false\nend\n"
  },
  {
    "path": "config/secrets.yml",
    "content": "# Be sure to restart your server when you modify this file.\n\n# Your secret key is used for verifying the integrity of signed cookies.\n# If you change this key, all old signed cookies will become invalid!\n\n# Make sure the secret is at least 30 characters and all random,\n# no regular words or you'll be exposed to dictionary attacks.\n# You can use `rails secret` to generate a secure secret key.\n\n# Make sure the secrets in this file are kept private\n# if you're sharing your code publicly.\n\ndevelopment:\n  secret_key_base: d4398e4af52f1fc5be5c3c8764e9ecce7beac5462826cb8b649373b2aad5a0f133598ed817c4e9931e943041460d6b6eda40a854e825e1bbd510c4594b1538f2\n\ntest:\n  secret_key_base: 5be187ddbd651211a906f9aa399f4a148edf6e06b971c7c0b5429b9483df6e21d262cc846447d0f89b89c32d56a99e151039df5dd874ede7f712afbe041a9269\n\n# Do not keep production secrets in the repository,\n# instead read values from the environment.\nproduction:\n  secret_key_base: <%= ENV[\"SECRET_KEY_BASE\"] %>\n"
  },
  {
    "path": "config/settings.yml",
    "content": "# This file contains default values, and does not need to be edited. All\n# important settings can be changed from the admin interface.\n\ndefaults: &defaults\n  site_title: Mastodon\n  site_short_description: ''\n  site_description: ''\n  site_extended_description: ''\n  site_terms: ''\n  site_contact_username: ''\n  site_contact_email: ''\n  registrations_mode: 'open'\n  max_bio_chars: 500\n  max_toot_chars: 500\n  profile_directory: true\n  closed_registrations_message: ''\n  open_deletion: true\n  min_invite_role: 'admin'\n  timeline_preview: true\n  show_staff_badge: true\n  default_sensitive: false\n  hide_network: false\n  unfollow_modal: false\n  boost_modal: false\n  delete_modal: true\n  auto_play_gif: false\n  display_media: 'default'\n  expand_spoilers: false\n  preview_sensitive_media: false\n  reduce_motion: false\n  show_application: true\n  system_font_ui: false\n  noindex: false\n  theme: 'default'\n  aggregate_reblogs: true\n  advanced_layout: false\n  home_dms: false\n  notification_emails:\n    follow: false\n    reblog: false\n    favourite: false\n    mention: false\n    follow_request: true\n    digest: true\n    report: true\n    pending_account: true\n  interactions:\n    must_be_follower: false\n    must_be_following: false\n    must_be_following_dm: false\n  reserved_usernames:\n    - admin\n    - support\n    - help\n    - root\n    - webmaster\n    - administrator\n    - mod\n    - moderator\n  disallowed_hashtags: # space separated string or list of hashtags without the hash\n  bootstrap_timeline_accounts: ''\n  activity_api_enabled: true\n  peers_api_enabled: true\n  show_known_fediverse_at_about_page: true\n\ndevelopment:\n  <<: *defaults\n\ntest:\n  <<: *defaults\n\nproduction:\n  <<: *defaults\n"
  },
  {
    "path": "config/sidekiq.yml",
    "content": "---\n:concurrency: 5\n:queues:\n  - [default, 6]\n  - [push, 4]\n  - [mailers, 2]\n  - [pull]\n:schedule:\n  scheduled_statuses_scheduler:\n    every: '5m'\n    class: Scheduler::ScheduledStatusesScheduler\n  subscriptions_scheduler:\n    cron: '<%= Random.rand(0..59) %> <%= Random.rand(4..6) %> * * *'\n    class: Scheduler::SubscriptionsScheduler\n  media_cleanup_scheduler:\n    cron: '<%= Random.rand(0..59) %> <%= Random.rand(3..5) %> * * *'\n    class: Scheduler::MediaCleanupScheduler\n  feed_cleanup_scheduler:\n    cron: '<%= Random.rand(0..59) %> <%= Random.rand(0..2) %> * * *'\n    class: Scheduler::FeedCleanupScheduler\n  doorkeeper_cleanup_scheduler:\n    cron: '<%= Random.rand(0..59) %> <%= Random.rand(0..2) %> * * 0'\n    class: Scheduler::DoorkeeperCleanupScheduler\n  user_cleanup_scheduler:\n    cron: '<%= Random.rand(0..59) %> <%= Random.rand(4..6) %> * * *'\n    class: Scheduler::UserCleanupScheduler\n  subscriptions_cleanup_scheduler:\n    cron: '<%= Random.rand(0..59) %> <%= Random.rand(1..3) %> * * 0'\n    class: Scheduler::SubscriptionsCleanupScheduler\n  ip_cleanup_scheduler:\n    cron: '<%= Random.rand(0..59) %> <%= Random.rand(3..5) %> * * *'\n    class: Scheduler::IpCleanupScheduler\n  email_scheduler:\n    cron: '0 10 * * 2'\n    class: Scheduler::EmailScheduler\n  backup_cleanup_scheduler:\n    cron: '<%= Random.rand(0..59) %> <%= Random.rand(3..5) %> * * *'\n    class: Scheduler::BackupCleanupScheduler\n  pghero_scheduler:\n    cron: '0 0 * * *'\n    class: Scheduler::PgheroScheduler\n"
  },
  {
    "path": "config/themes.yml",
    "content": "default: styles/application.scss\ncontrast: styles/contrast.scss\nmastodon-light: styles/mastodon-light.scss\n"
  },
  {
    "path": "config/webpack/configuration.js",
    "content": "// Common configuration for webpacker loaded from config/webpacker.yml\n\nconst { resolve } = require('path');\nconst { env } = require('process');\nconst { safeLoad } = require('js-yaml');\nconst { readFileSync } = require('fs');\n\nconst configPath = resolve('config', 'webpacker.yml');\nconst settings = safeLoad(readFileSync(configPath), 'utf8')[env.RAILS_ENV || env.NODE_ENV];\n\nconst themePath = resolve('config', 'themes.yml');\nconst themes = safeLoad(readFileSync(themePath), 'utf8');\n\nfunction removeOuterSlashes(string) {\n  return string.replace(/^\\/*/, '').replace(/\\/*$/, '');\n}\n\nfunction formatPublicPath(host = '', path = '') {\n  let formattedHost = removeOuterSlashes(host);\n  if (formattedHost && !/^http/i.test(formattedHost)) {\n    formattedHost = `//${formattedHost}`;\n  }\n  const formattedPath = removeOuterSlashes(path);\n  return `${formattedHost}/${formattedPath}/`;\n}\n\nconst output = {\n  path: resolve('public', settings.public_output_path),\n  publicPath: formatPublicPath(env.CDN_HOST, settings.public_output_path),\n};\n\nmodule.exports = {\n  settings,\n  themes,\n  env: {\n    CDN_HOST: env.CDN_HOST,\n    NODE_ENV: env.NODE_ENV,\n  },\n  output,\n};\n"
  },
  {
    "path": "config/webpack/development.js",
    "content": "// Note: You must restart bin/webpack-dev-server for changes to take effect\n\nconst merge = require('webpack-merge');\nconst sharedConfig = require('./shared');\nconst { settings, output } = require('./configuration');\n\nconst watchOptions = {};\n\nif (process.env.VAGRANT) {\n  // If we are in Vagrant, we can't rely on inotify to update us with changed\n  // files, so we must poll instead. Here, we poll every second to see if\n  // anything has changed.\n  watchOptions.poll = 1000;\n}\n\nmodule.exports = merge(sharedConfig, {\n  mode: 'development',\n  cache: true,\n  devtool: 'cheap-module-eval-source-map',\n\n  stats: {\n    errorDetails: true,\n  },\n\n  output: {\n    pathinfo: true,\n  },\n\n  devServer: {\n    clientLogLevel: 'none',\n    compress: settings.dev_server.compress,\n    quiet: settings.dev_server.quiet,\n    disableHostCheck: settings.dev_server.disable_host_check,\n    host: settings.dev_server.host,\n    port: settings.dev_server.port,\n    https: settings.dev_server.https,\n    hot: settings.dev_server.hmr,\n    contentBase: output.path,\n    inline: settings.dev_server.inline,\n    useLocalIp: settings.dev_server.use_local_ip,\n    public: settings.dev_server.public,\n    publicPath: output.publicPath,\n    historyApiFallback: {\n      disableDotRule: true,\n    },\n    headers: settings.dev_server.headers,\n    overlay: settings.dev_server.overlay,\n    stats: {\n      entrypoints: false,\n      errorDetails: false,\n      modules: false,\n      moduleTrace: false,\n    },\n    watchOptions: Object.assign(\n      {},\n      settings.dev_server.watch_options,\n      watchOptions\n    ),\n  },\n});\n"
  },
  {
    "path": "config/webpack/generateLocalePacks.js",
    "content": "// To avoid adding a lot of boilerplate, locale packs are\n// automatically generated here. These are written into the tmp/\n// directory and then used to generate locale_en.js, locale_fr.js, etc.\n\nconst fs = require('fs');\nconst path = require('path');\nconst rimraf = require('rimraf');\nconst mkdirp = require('mkdirp');\n\nconst localesJsonPath = path.join(__dirname, '../../app/javascript/mastodon/locales');\nconst locales = fs.readdirSync(localesJsonPath).filter(filename => {\n  return /\\.json$/.test(filename) &&\n    !/defaultMessages/.test(filename) &&\n    !/whitelist/.test(filename);\n}).map(filename => filename.replace(/\\.json$/, ''));\n\nconst outPath = path.join(__dirname, '../../tmp/packs');\n\nrimraf.sync(outPath);\nmkdirp.sync(outPath);\n\nconst outPaths = [];\n\nlocales.forEach(locale => {\n  const localePath = path.join(outPath, `locale_${locale}.js`);\n  const baseLocale = locale.split('-')[0]; // e.g. 'zh-TW' -> 'zh'\n  const localeDataPath = [\n    // first try react-intl\n    `../../node_modules/react-intl/locale-data/${baseLocale}.js`,\n    // then check locales/locale-data\n    `../../app/javascript/mastodon/locales/locale-data/${baseLocale}.js`,\n    // fall back to English (this is what react-intl does anyway)\n    '../../node_modules/react-intl/locale-data/en.js',\n  ].filter(filename => fs.existsSync(path.join(outPath, filename)))\n    .map(filename => filename.replace(/..\\/..\\/node_modules\\//, ''))[0];\n\n  const localeContent = `//\n// locale_${locale}.js\n// automatically generated by generateLocalePacks.js\n//\nimport messages from '../../app/javascript/mastodon/locales/${locale}.json';\nimport localeData from ${JSON.stringify(localeDataPath)};\nimport { setLocale } from '../../app/javascript/mastodon/locales';\nsetLocale({messages, localeData});\n`;\n  fs.writeFileSync(localePath, localeContent, 'utf8');\n  outPaths.push(localePath);\n});\n\nmodule.exports = outPaths;\n\n\n"
  },
  {
    "path": "config/webpack/production.js",
    "content": "// Note: You must restart bin/webpack-dev-server for changes to take effect\n\nconst path = require('path');\nconst { URL } = require('url');\nconst merge = require('webpack-merge');\nconst { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');\nconst OfflinePlugin = require('offline-plugin');\nconst TerserPlugin = require('terser-webpack-plugin');\nconst CompressionPlugin = require('compression-webpack-plugin');\nconst { output } = require('./configuration');\nconst sharedConfig = require('./shared');\n\nlet attachmentHost;\n\nif (process.env.S3_ENABLED === 'true') {\n  if (process.env.S3_ALIAS_HOST || process.env.S3_CLOUDFRONT_HOST) {\n    attachmentHost = process.env.S3_ALIAS_HOST || process.env.S3_CLOUDFRONT_HOST;\n  } else {\n    attachmentHost = process.env.S3_HOSTNAME || `s3-${process.env.S3_REGION || 'us-east-1'}.amazonaws.com`;\n  }\n} else if (process.env.SWIFT_ENABLED === 'true') {\n  const { host } = new URL(process.env.SWIFT_OBJECT_URL);\n  attachmentHost = host;\n} else {\n  attachmentHost = null;\n}\n\nmodule.exports = merge(sharedConfig, {\n  mode: 'production',\n  devtool: 'source-map',\n  stats: 'normal',\n  bail: true,\n  optimization: {\n    minimize: true,\n    minimizer: [\n      new TerserPlugin({\n        cache: true,\n        parallel: true,\n        sourceMap: true,\n      }),\n    ],\n  },\n\n  plugins: [\n    new CompressionPlugin({\n      filename: '[path].gz[query]',\n      cache: true,\n      test: /\\.(js|css|html|json|ico|svg|eot|otf|ttf|map)$/,\n    }),\n    new BundleAnalyzerPlugin({ // generates report.html\n      analyzerMode: 'static',\n      openAnalyzer: false,\n      logLevel: 'silent', // do not bother Webpacker, who runs with --json and parses stdout\n    }),\n    new OfflinePlugin({\n      publicPath: output.publicPath, // sw.js must be served from the root to avoid scope issues\n      safeToUseOptionalCaches: true,\n      caches: {\n        main: [':rest:'],\n        additional: [':externals:'],\n        optional: [\n          '**/locale_*.js', // don't fetch every locale; the user only needs one\n          '**/*_polyfills-*.js', // the user may not need polyfills\n          '**/*.woff2', // the user may have system-fonts enabled\n          // images/audio can be cached on-demand\n          '**/*.png',\n          '**/*.jpg',\n          '**/*.jpeg',\n          '**/*.svg',\n          '**/*.mp3',\n          '**/*.ogg',\n        ],\n      },\n      externals: [\n        '/emoji/1f602.svg', // used for emoji picker dropdown\n        '/emoji/sheet_10.png', // used in emoji-mart\n      ],\n      excludes: [\n        '**/*.gz',\n        '**/*.map',\n        'stats.json',\n        'report.html',\n        // any browser that supports ServiceWorker will support woff2\n        '**/*.eot',\n        '**/*.ttf',\n        '**/*-webfont-*.svg',\n        '**/*.woff',\n      ],\n      ServiceWorker: {\n        entry: `imports-loader?ATTACHMENT_HOST=>${encodeURIComponent(JSON.stringify(attachmentHost))}!${encodeURI(path.join(__dirname, '../../app/javascript/mastodon/service_worker/entry.js'))}`,\n        cacheName: 'mastodon',\n        output: '../assets/sw.js',\n        publicPath: '/sw.js',\n        minify: true,\n      },\n    }),\n  ],\n});\n"
  },
  {
    "path": "config/webpack/rules/babel.js",
    "content": "const { join, resolve } = require('path');\nconst { env, settings } = require('../configuration');\n\nmodule.exports = {\n  test: /\\.(js|jsx|mjs)$/,\n  include: [\n    settings.source_path,\n    ...settings.resolved_paths,\n  ].map(p => resolve(p)),\n  exclude: /node_modules/,\n  use: [\n    {\n      loader: 'babel-loader',\n      options: {\n        cacheDirectory: join(settings.cache_path, 'babel-loader'),\n        cacheCompression: env.NODE_ENV === 'production',\n        compact: env.NODE_ENV === 'production',\n      },\n    },\n  ],\n};\n"
  },
  {
    "path": "config/webpack/rules/css.js",
    "content": "const MiniCssExtractPlugin = require('mini-css-extract-plugin');\n\nmodule.exports = {\n  test: /\\.s?css$/i,\n  use: [\n    MiniCssExtractPlugin.loader,\n    {\n      loader: 'css-loader',\n      options: {\n        sourceMap: true,\n        importLoaders: 2,\n        localIdentName: '[name]__[local]___[hash:base64:5]',\n      },\n    },\n    {\n      loader: 'postcss-loader',\n      options: {\n        sourceMap: true,\n      },\n    },\n    {\n      loader: 'sass-loader',\n      options: {\n        implementation: require('sass'),\n        sourceMap: true,\n      },\n    },\n  ],\n};\n"
  },
  {
    "path": "config/webpack/rules/file.js",
    "content": "const { join } = require('path');\nconst { settings } = require('../configuration');\n\nmodule.exports = {\n  test: new RegExp(`(${settings.static_assets_extensions.join('|')})$`, 'i'),\n  use: [\n    {\n      loader: 'file-loader',\n      options: {\n        name(file) {\n          if (file.includes(settings.source_path)) {\n            return 'media/[path][name]-[hash].[ext]';\n          }\n          return 'media/[folder]/[name]-[hash:8].[ext]';\n        },\n        context: join(settings.source_path),\n      },\n    },\n  ],\n};\n"
  },
  {
    "path": "config/webpack/rules/index.js",
    "content": "const babel = require('./babel');\nconst css = require('./css');\nconst file = require('./file');\nconst nodeModules = require('./node_modules');\n\n// Webpack loaders are processed in reverse order\n// https://webpack.js.org/concepts/loaders/#loader-features\n// Lastly, process static files using file loader\nmodule.exports = {\n  file,\n  css,\n  nodeModules,\n  babel,\n};\n"
  },
  {
    "path": "config/webpack/rules/mark.js",
    "content": "if (process.env.NODE_ENV === 'production') {\n  module.exports = {};\n} else {\n  module.exports = {\n    test: /\\.js$/,\n    loader: 'mark-loader',\n  };\n}\n"
  },
  {
    "path": "config/webpack/rules/node_modules.js",
    "content": "const { join } = require('path');\nconst { settings, env } = require('../configuration');\n\nmodule.exports = {\n  test: /\\.(js|mjs)$/,\n  include: /node_modules/,\n  exclude: /@babel(?:\\/|\\\\{1,2})runtime/,\n  use: [\n    {\n      loader: 'babel-loader',\n      options: {\n        babelrc: false,\n        plugins: [\n          'transform-react-remove-prop-types',\n        ],\n        cacheDirectory: join(settings.cache_path, 'babel-loader-node-modules'),\n        cacheCompression: env.NODE_ENV === 'production',\n        compact: false,\n        sourceMaps: false,\n      },\n    },\n  ],\n};\n"
  },
  {
    "path": "config/webpack/shared.js",
    "content": "// Note: You must restart bin/webpack-dev-server for changes to take effect\n\nconst webpack = require('webpack');\nconst { basename, dirname, join, relative, resolve } = require('path');\nconst { sync } = require('glob');\nconst MiniCssExtractPlugin = require('mini-css-extract-plugin');\nconst AssetsManifestPlugin = require('webpack-assets-manifest');\nconst extname = require('path-complete-extname');\nconst { env, settings, themes, output } = require('./configuration');\nconst rules = require('./rules');\nconst localePackPaths = require('./generateLocalePacks');\n\nconst extensionGlob = `**/*{${settings.extensions.join(',')}}*`;\nconst entryPath = join(settings.source_path, settings.source_entry_path);\nconst packPaths = sync(join(entryPath, extensionGlob));\n\nmodule.exports = {\n  entry: Object.assign(\n    packPaths.reduce((map, entry) => {\n      const localMap = map;\n      const namespace = relative(join(entryPath), dirname(entry));\n      localMap[join(namespace, basename(entry, extname(entry)))] = resolve(entry);\n      return localMap;\n    }, {}),\n    localePackPaths.reduce((map, entry) => {\n      const localMap = map;\n      localMap[basename(entry, extname(entry, extname(entry)))] = resolve(entry);\n      return localMap;\n    }, {}),\n    Object.keys(themes).reduce((themePaths, name) => {\n      themePaths[name] = resolve(join(settings.source_path, themes[name]));\n      return themePaths;\n    }, {})\n  ),\n\n  output: {\n    filename: 'js/[name]-[chunkhash].js',\n    chunkFilename: 'js/[name]-[chunkhash].chunk.js',\n    hotUpdateChunkFilename: 'js/[id]-[hash].hot-update.js',\n    path: output.path,\n    publicPath: output.publicPath,\n  },\n\n  optimization: {\n    runtimeChunk: {\n      name: 'common',\n    },\n    splitChunks: {\n      cacheGroups: {\n        default: false,\n        vendors: false,\n        common: {\n          name: 'common',\n          chunks: 'all',\n          minChunks: 2,\n          minSize: 0,\n          test: /^(?!.*[\\\\\\/]node_modules[\\\\\\/]react-intl[\\\\\\/]).+$/,\n        },\n      },\n    },\n    occurrenceOrder: true,\n  },\n\n  module: {\n    rules: Object.keys(rules).map(key => rules[key]),\n  },\n\n  plugins: [\n    new webpack.EnvironmentPlugin(JSON.parse(JSON.stringify(env))),\n    new webpack.NormalModuleReplacementPlugin(\n      /^history\\//, (resource) => {\n        // temporary fix for https://github.com/ReactTraining/react-router/issues/5576\n        // to reduce bundle size\n        resource.request = resource.request.replace(/^history/, 'history/es');\n      }\n    ),\n    new MiniCssExtractPlugin({\n      filename: 'css/[name]-[contenthash:8].css',\n      chunkFilename: 'css/[name]-[contenthash:8].chunk.css',\n    }),\n    new AssetsManifestPlugin({\n      integrity: false,\n      entrypoints: true,\n      writeToDisk: true,\n      publicPath: true,\n    }),\n  ],\n\n  resolve: {\n    extensions: settings.extensions,\n    modules: [\n      resolve(settings.source_path),\n      'node_modules',\n    ],\n  },\n\n  resolveLoader: {\n    modules: ['node_modules'],\n  },\n\n  node: {\n    // Called by http-link-header in an API we never use, increases\n    // bundle size unnecessarily\n    Buffer: false,\n  },\n};\n"
  },
  {
    "path": "config/webpack/test.js",
    "content": "// Note: You must restart bin/webpack-dev-server for changes to take effect\n\nconst merge = require('webpack-merge');\nconst sharedConfig = require('./shared.js');\n\nmodule.exports = merge(sharedConfig, {\n  mode: 'development',\n});\n"
  },
  {
    "path": "config/webpack/translationRunner.js",
    "content": "const fs = require('fs');\nconst path = require('path');\nconst { default: manageTranslations } = require('react-intl-translations-manager');\n\nconst RFC5646_REGEXP = /^[a-z]{2,3}(?:-(?:x|[A-Za-z]{2,4}))*$/;\n\nconst rootDirectory = path.resolve(__dirname, '..', '..');\nconst translationsDirectory = path.resolve(rootDirectory, 'app', 'javascript', 'mastodon', 'locales');\nconst messagesDirectory = path.resolve(rootDirectory, 'build', 'messages');\nconst availableLanguages = fs.readdirSync(translationsDirectory).reduce((languages, filename) => {\n  const basename = path.basename(filename, '.json');\n  if (RFC5646_REGEXP.test(basename)) {\n    languages.push(basename);\n  }\n  return languages;\n}, []);\n\nconst testRFC5646 = language => {\n  if (!RFC5646_REGEXP.test(language)) {\n    throw new Error('Not RFC5646 name');\n  }\n};\n\nconst testAvailability = language => {\n  if (!availableLanguages.includes(language)) {\n    throw new Error('Not an available language');\n  }\n};\n\nconst validateLanguages = (languages, validators) => {\n  const invalidLanguages = languages.reduce((acc, language) => {\n    try {\n      validators.forEach(validator => validator(language));\n    } catch (error) {\n      acc.push({ language, error });\n    }\n    return acc;\n  }, []);\n\n  if (invalidLanguages.length > 0) {\n    console.error(`\nError: Specified invalid LANGUAGES:\n${invalidLanguages.map(({ language, error }) => `* ${language}: ${error.message}`).join('\\n')}\n\nUse yarn \"manage:translations -- --help\" for usage information\n`);\n    process.exit(1);\n  }\n};\n\nconst usage = `Usage: yarn manage:translations [OPTIONS] [LANGUAGES]\n\nManage JavaScript translation files in Mastodon. Generates and update translations in translationsDirectory: ${translationsDirectory}\n\nLANGUAGES\nThe RFC5646 language tag for the language you want to test or fix. If you want to input multiple languages, separate them with space.\n\nAvailable languages:\n${availableLanguages.join(', ')}\n`;\n\nconst { argv } = require('yargs')\n  .usage(usage)\n  .option('f', {\n    alias: 'force',\n    default: false,\n    describe: 'force using the provided languages. create files if not exists.',\n    type: 'boolean',\n  });\n\n// check if message directory exists\nif (!fs.existsSync(messagesDirectory)) {\n  console.error(`\nError: messagesDirectory not exists\n(${messagesDirectory})\nTry to run \"yarn build:development\" first`);\n  process.exit(1);\n}\n\n// determine the languages list\nconst languages = (argv._.length > 0) ? argv._ : availableLanguages;\n\n// validate languages\nvalidateLanguages(languages, [\n  testRFC5646,\n  !argv.force && testAvailability,\n].filter(Boolean));\n\n// manage translations\nmanageTranslations({\n  messagesDirectory,\n  translationsDirectory,\n  detectDuplicateIds: false,\n  singleMessagesFile: true,\n  languages,\n  jsonOptions: {\n    trailingNewline: true,\n  },\n});\n"
  },
  {
    "path": "config/webpacker.yml",
    "content": "# Note: You must restart bin/webpack-dev-server for changes to take effect\n\ndefault: &default\n  source_path: app/javascript\n  source_entry_path: packs\n  public_root_path: public\n  public_output_path: packs\n  cache_path: tmp/cache/webpacker\n  check_yarn_integrity: false\n  webpack_compile_output: false\n\n  # Additional paths webpack should lookup modules\n  # ['app/assets', 'engine/foo/app/assets']\n  resolved_paths: []\n\n  # Reload manifest.json on all requests so we reload latest compiled packs\n  cache_manifest: false\n\n  # Extract and emit a css file\n  extract_css: true\n\n  static_assets_extensions:\n    - .jpg\n    - .jpeg\n    - .png\n    - .tiff\n    - .ico\n    - .svg\n    - .eot\n    - .otf\n    - .ttf\n    - .woff\n    - .woff2\n\n  extensions:\n    - .mjs\n    - .js\n    - .sass\n    - .scss\n    - .css\n    - .module.sass\n    - .module.scss\n    - .module.css\n    - .png\n    - .svg\n    - .gif\n    - .jpeg\n    - .jpg\n\ndevelopment:\n  <<: *default\n\n  compile: true\n\n  # Reference: https://webpack.js.org/configuration/dev-server/\n  dev_server:\n    https: false\n    host: localhost\n    port: 3035\n    public: localhost:3035\n    hmr: false\n    # Inline should be set to true if using HMR\n    inline: true\n    overlay: true\n    compress: true\n    disable_host_check: true\n    use_local_ip: false\n    quiet: false\n    headers:\n      'Access-Control-Allow-Origin': '*'\n    watch_options:\n      ignored: '**/node_modules/**'\n\ntest:\n  <<: *default\n\n  # CircleCI precompiles packs prior to running the tests.\n  # Also avoids race conditions in parallel_tests.\n  compile: false\n\n  # Compile test packs to a separate directory\n  public_output_path: packs-test\n\nproduction:\n  <<: *default\n\n  # Production depends on precompilation of packs prior to booting for performance.\n  compile: false\n\n  # Cache manifest.json for performance\n  cache_manifest: true\n"
  },
  {
    "path": "config.ru",
    "content": "# frozen_string_literal: true\n# This file is used by Rack-based servers to start the application.\n\nrequire ::File.expand_path('../config/environment', __FILE__)\nrun Rails.application\n"
  },
  {
    "path": "db/migrate/20160220174730_create_accounts.rb",
    "content": "class CreateAccounts < ActiveRecord::Migration[4.2]\n  def change\n    create_table :accounts do |t|\n      t.string :username, null: false, default: ''\n      t.string :domain, null: true\n\n      # PuSH credentials\n      t.string :verify_token, null: false, default: ''\n      t.string :secret, null: false, default: ''\n\n      # RSA key pair\n      t.text :private_key, null: true\n      t.text :public_key, null: false, default: ''\n\n      # URLs\n      t.string :remote_url, null: false, default: ''\n      t.string :salmon_url, null: false, default: ''\n      t.string :hub_url, null: false, default: ''\n\n      t.timestamps null: false\n    end\n\n    add_index :accounts, [:username, :domain], unique: true\n  end\nend\n"
  },
  {
    "path": "db/migrate/20160220211917_create_statuses.rb",
    "content": "class CreateStatuses < ActiveRecord::Migration[4.2]\n  def change\n    create_table :statuses do |t|\n      t.string :uri, null: false, default: ''\n      t.integer :account_id, null: false\n      t.text :text, null: false, default: ''\n\n      t.timestamps null: false\n    end\n\n    add_index :statuses, :uri, unique: true\n  end\nend\n"
  },
  {
    "path": "db/migrate/20160221003140_create_users.rb",
    "content": "class CreateUsers < ActiveRecord::Migration[4.2]\n  def change\n    create_table :users do |t|\n      t.string :email, null: false, default: ''\n      t.integer :account_id, null: false\n\n      t.timestamps null: false\n    end\n\n    add_index :users, :email, unique: true\n  end\nend\n"
  },
  {
    "path": "db/migrate/20160221003621_create_follows.rb",
    "content": "class CreateFollows < ActiveRecord::Migration[4.2]\n  def change\n    create_table :follows do |t|\n      t.integer :account_id, null: false\n      t.integer :target_account_id, null: false\n\n      t.timestamps null: false\n    end\n\n    add_index :follows, [:account_id, :target_account_id], unique: true\n  end\nend\n"
  },
  {
    "path": "db/migrate/20160222122600_create_stream_entries.rb",
    "content": "class CreateStreamEntries < ActiveRecord::Migration[4.2]\n  def change\n    create_table :stream_entries do |t|\n      t.integer :account_id\n      t.integer :activity_id\n      t.string :activity_type\n\n      t.timestamps null: false\n    end\n  end\nend\n"
  },
  {
    "path": "db/migrate/20160222143943_add_profile_fields_to_accounts.rb",
    "content": "class AddProfileFieldsToAccounts < ActiveRecord::Migration[4.2]\n  def change\n    add_column :accounts, :note, :text, null: false, default: ''\n    add_column :accounts, :display_name, :string, null: false, default: ''\n    add_column :accounts, :uri, :string, null: false, default: ''\n  end\nend\n"
  },
  {
    "path": "db/migrate/20160223162837_add_metadata_to_statuses.rb",
    "content": "class AddMetadataToStatuses < ActiveRecord::Migration[4.2]\n  def change\n    add_column :statuses, :in_reply_to_id, :integer, null: true\n    add_column :statuses, :reblog_of_id, :integer, null: true\n  end\nend\n"
  },
  {
    "path": "db/migrate/20160223164502_make_uris_nullable_in_statuses.rb",
    "content": "class MakeUrisNullableInStatuses < ActiveRecord::Migration[4.2]\n  def change\n    change_column :statuses, :uri, :string, null: true, default: nil\n  end\nend\n"
  },
  {
    "path": "db/migrate/20160223165723_add_url_to_statuses.rb",
    "content": "class AddUrlToStatuses < ActiveRecord::Migration[4.2]\n  def change\n    add_column :statuses, :url, :string, null: true, default: nil\n  end\nend\n"
  },
  {
    "path": "db/migrate/20160223165855_add_url_to_accounts.rb",
    "content": "class AddUrlToAccounts < ActiveRecord::Migration[4.2]\n  def change\n    add_column :accounts, :url, :string, null: true, default: nil\n  end\nend\n"
  },
  {
    "path": "db/migrate/20160223171800_create_favourites.rb",
    "content": "class CreateFavourites < ActiveRecord::Migration[4.2]\n  def change\n    create_table :favourites do |t|\n      t.integer :account_id, null: false\n      t.integer :status_id, null: false\n\n      t.timestamps null: false\n    end\n\n    add_index :favourites, [:account_id, :status_id], unique: true\n  end\nend\n"
  },
  {
    "path": "db/migrate/20160224223247_create_mentions.rb",
    "content": "class CreateMentions < ActiveRecord::Migration[4.2]\n  def change\n    create_table :mentions do |t|\n      t.integer :account_id\n      t.integer :status_id\n\n      t.timestamps null: false\n    end\n\n    add_index :mentions, [:account_id, :status_id], unique: true\n  end\nend\n"
  },
  {
    "path": "db/migrate/20160227230233_add_attachment_avatar_to_accounts.rb",
    "content": "class AddAttachmentAvatarToAccounts < ActiveRecord::Migration[4.2]\n  def self.up\n    change_table :accounts do |t|\n      t.attachment :avatar\n    end\n  end\n\n  def self.down\n    remove_attachment :accounts, :avatar\n  end\nend\n"
  },
  {
    "path": "db/migrate/20160305115639_add_devise_to_users.rb",
    "content": "class AddDeviseToUsers < ActiveRecord::Migration[4.2]\n  def self.up\n    change_table(:users) do |t|\n      ## Database authenticatable\n      t.string :encrypted_password, null: false, default: \"\"\n\n      ## Recoverable\n      t.string   :reset_password_token\n      t.datetime :reset_password_sent_at\n\n      ## Rememberable\n      t.datetime :remember_created_at\n\n      ## Trackable\n      t.integer  :sign_in_count, default: 0, null: false\n      t.datetime :current_sign_in_at\n      t.datetime :last_sign_in_at\n      t.inet     :current_sign_in_ip\n      t.inet     :last_sign_in_ip\n    end\n\n    add_index :users, :reset_password_token, unique: true\n  end\n\n  def self.down\n    remove_index :users, :reset_password_token\n\n    remove_column :users, :encrypted_password\n    remove_column :users, :reset_password_token\n    remove_column :users, :reset_password_sent_at\n    remove_column :users, :remember_created_at\n    remove_column :users, :sign_in_count\n    remove_column :users, :current_sign_in_at\n    remove_column :users, :current_sign_in_ip\n    remove_column :users, :last_sign_in_at\n    remove_column :users, :last_sign_in_ip\n  end\nend\n"
  },
  {
    "path": "db/migrate/20160306172223_create_doorkeeper_tables.rb",
    "content": "class CreateDoorkeeperTables < ActiveRecord::Migration[4.2]\n  def change\n    create_table :oauth_applications do |t|\n      t.string  :name,         null: false\n      t.string  :uid,          null: false\n      t.string  :secret,       null: false\n      t.text    :redirect_uri, null: false\n      t.string  :scopes,       null: false, default: ''\n      t.timestamps\n    end\n\n    add_index :oauth_applications, :uid, unique: true\n\n    create_table :oauth_access_grants do |t|\n      t.integer  :resource_owner_id, null: false\n      t.integer  :application_id,    null: false\n      t.string   :token,             null: false\n      t.integer  :expires_in,        null: false\n      t.text     :redirect_uri,      null: false\n      t.datetime :created_at,        null: false\n      t.datetime :revoked_at\n      t.string   :scopes\n    end\n\n    add_index :oauth_access_grants, :token, unique: true\n\n    create_table :oauth_access_tokens do |t|\n      t.integer  :resource_owner_id\n      t.integer  :application_id\n\n      # If you use a custom token generator you may need to change this column\n      # from string to text, so that it accepts tokens larger than 255\n      # characters. More info on custom token generators in:\n      # https://github.com/doorkeeper-gem/doorkeeper/tree/v3.0.0.rc1#custom-access-token-generator\n      #\n      # t.text     :token,             null: false\n      t.string   :token, null: false\n\n      t.string   :refresh_token\n      t.integer  :expires_in\n      t.datetime :revoked_at\n      t.datetime :created_at, null: false\n      t.string   :scopes\n    end\n\n    add_index :oauth_access_tokens, :token, unique: true\n    add_index :oauth_access_tokens, :resource_owner_id\n    add_index :oauth_access_tokens, :refresh_token, unique: true\n  end\nend\n"
  },
  {
    "path": "db/migrate/20160312193225_add_attachment_header_to_accounts.rb",
    "content": "class AddAttachmentHeaderToAccounts < ActiveRecord::Migration[4.2]\n  def self.up\n    change_table :accounts do |t|\n      t.attachment :header\n    end\n  end\n\n  def self.down\n    remove_attachment :accounts, :header\n  end\nend\n"
  },
  {
    "path": "db/migrate/20160314164231_add_owner_to_application.rb",
    "content": "class AddOwnerToApplication < ActiveRecord::Migration[4.2]\n  def change\n    add_column :oauth_applications, :owner_id, :integer, null: true\n    add_column :oauth_applications, :owner_type, :string, null: true\n    add_index :oauth_applications, [:owner_id, :owner_type]\n  end\nend\n"
  },
  {
    "path": "db/migrate/20160316103650_add_missing_indices.rb",
    "content": "class AddMissingIndices < ActiveRecord::Migration[4.2]\n  def change\n    add_index :users, :account_id\n    add_index :statuses, :account_id\n    add_index :statuses, :in_reply_to_id\n    add_index :statuses, :reblog_of_id\n    add_index :stream_entries, :account_id\n    add_index :stream_entries, [:activity_id, :activity_type]\n  end\nend\n"
  },
  {
    "path": "db/migrate/20160322193748_add_avatar_remote_url_to_accounts.rb",
    "content": "class AddAvatarRemoteUrlToAccounts < ActiveRecord::Migration[4.2]\n  def change\n    add_column :accounts, :avatar_remote_url, :string, null: true, default: nil\n  end\nend\n"
  },
  {
    "path": "db/migrate/20160325130944_add_admin_to_users.rb",
    "content": "class AddAdminToUsers < ActiveRecord::Migration[4.2]\n  def change\n    add_column :users, :admin, :boolean, default: false\n  end\nend\n"
  },
  {
    "path": "db/migrate/20160826155805_add_superapp_to_oauth_applications.rb",
    "content": "class AddSuperappToOauthApplications < ActiveRecord::Migration[5.0]\n  def change\n    add_column :oauth_applications, :superapp, :boolean, default: false, null: false\n  end\nend\n"
  },
  {
    "path": "db/migrate/20160905150353_create_media_attachments.rb",
    "content": "class CreateMediaAttachments < ActiveRecord::Migration[5.0]\n  def change\n    create_table :media_attachments do |t|\n      t.integer :status_id, null: true, default: nil\n      t.attachment :file\n      t.string :remote_url, null: false, default: ''\n      t.integer :account_id\n\n      t.timestamps\n    end\n\n    add_index :media_attachments, :status_id\n  end\nend\n"
  },
  {
    "path": "db/migrate/20160919221059_add_subscription_expires_at_to_accounts.rb",
    "content": "class AddSubscriptionExpiresAtToAccounts < ActiveRecord::Migration[5.0]\n  def change\n    add_column :accounts, :subscription_expires_at, :datetime, null: true, default: nil\n  end\nend\n"
  },
  {
    "path": "db/migrate/20160920003904_remove_verify_token_from_accounts.rb",
    "content": "class RemoveVerifyTokenFromAccounts < ActiveRecord::Migration[5.0]\n  def change\n    remove_column :accounts, :verify_token, :string, null: false, default: ''\n  end\nend\n"
  },
  {
    "path": "db/migrate/20160926213048_remove_owner_from_application.rb",
    "content": "class RemoveOwnerFromApplication < ActiveRecord::Migration[5.0]\n  def change\n    remove_index :oauth_applications, [:owner_id, :owner_type]\n    remove_column :oauth_applications, :owner_id, :integer, null: true\n    remove_column :oauth_applications, :owner_type, :string, null: true\n  end\nend\n"
  },
  {
    "path": "db/migrate/20161003142332_add_confirmable_to_users.rb",
    "content": "class AddConfirmableToUsers < ActiveRecord::Migration[5.0]\n  def change\n    add_column :users, :confirmation_token, :string\n    add_column :users, :confirmed_at, :datetime\n    add_column :users, :confirmation_sent_at, :datetime\n    add_column :users, :unconfirmed_email, :string\n    add_index :users, :confirmation_token, unique: true\n  end\nend\n"
  },
  {
    "path": "db/migrate/20161003145426_create_blocks.rb",
    "content": "class CreateBlocks < ActiveRecord::Migration[5.0]\n  def change\n    create_table :blocks do |t|\n      t.integer :account_id, null: false\n      t.integer :target_account_id, null: false\n\n      t.timestamps null: false\n    end\n\n    add_index :blocks, [:account_id, :target_account_id], unique: true\n  end\nend\n"
  },
  {
    "path": "db/migrate/20161006213403_rails_settings_migration.rb",
    "content": "MIGRATION_BASE_CLASS = if ActiveRecord::VERSION::MAJOR >= 5\n  ActiveRecord::Migration[5.0]\nelse\n  ActiveRecord::Migration[4.2]\nend\n\nclass RailsSettingsMigration < MIGRATION_BASE_CLASS\n  def self.up\n    create_table :settings do |t|\n      t.string     :var, :null => false\n      t.text       :value\n      t.references :target, :null => false, :polymorphic => true\n      t.timestamps :null => true\n    end\n    add_index :settings, [ :target_type, :target_id, :var ], :unique => true\n  end\n\n  def self.down\n    drop_table :settings\n  end\nend\n"
  },
  {
    "path": "db/migrate/20161009120834_create_domain_blocks.rb",
    "content": "class CreateDomainBlocks < ActiveRecord::Migration[5.0]\n  def change\n    create_table :domain_blocks do |t|\n      t.string :domain, null: false, default: ''\n      t.timestamps\n    end\n\n    add_index :domain_blocks, :domain, unique: true\n  end\nend\n"
  },
  {
    "path": "db/migrate/20161027172456_add_silenced_to_accounts.rb",
    "content": "class AddSilencedToAccounts < ActiveRecord::Migration[5.0]\n  def change\n    add_column :accounts, :silenced, :boolean, null: false, default: false\n  end\nend\n"
  },
  {
    "path": "db/migrate/20161104173623_create_tags.rb",
    "content": "class CreateTags < ActiveRecord::Migration[5.0]\n  def change\n    create_table :tags do |t|\n      t.string :name, null: false, default: ''\n\n      t.timestamps\n    end\n\n    add_index :tags, :name, unique: true\n  end\nend\n"
  },
  {
    "path": "db/migrate/20161105130633_create_statuses_tags_join_table.rb",
    "content": "class CreateStatusesTagsJoinTable < ActiveRecord::Migration[5.0]\n  def change\n    create_join_table :statuses, :tags do |t|\n      t.index :tag_id\n      t.index [:tag_id, :status_id], unique: true\n    end\n  end\nend\n"
  },
  {
    "path": "db/migrate/20161116162355_add_locale_to_users.rb",
    "content": "class AddLocaleToUsers < ActiveRecord::Migration[5.0]\n  def change\n    add_column :users, :locale, :string\n  end\nend\n"
  },
  {
    "path": "db/migrate/20161119211120_create_notifications.rb",
    "content": "class CreateNotifications < ActiveRecord::Migration[5.0]\n  def change\n    create_table :notifications do |t|\n      t.integer :account_id\n      t.integer :activity_id\n      t.string :activity_type\n\n      t.timestamps\n    end\n\n    add_index :notifications, :account_id\n    add_index :notifications, [:account_id, :activity_id, :activity_type], unique: true, name: 'account_activity'\n  end\nend\n"
  },
  {
    "path": "db/migrate/20161122163057_remove_unneeded_indexes.rb",
    "content": "class RemoveUnneededIndexes < ActiveRecord::Migration[5.0]\n  def change\n    remove_index :notifications, name: \"index_notifications_on_account_id\"\n    remove_index :settings, name: \"index_settings_on_target_type_and_target_id\"\n    remove_index :statuses_tags, name: \"index_statuses_tags_on_tag_id\"\n  end\nend\n"
  },
  {
    "path": "db/migrate/20161123093447_add_sensitive_to_statuses.rb",
    "content": "class AddSensitiveToStatuses < ActiveRecord::Migration[5.0]\n  def change\n    add_column :statuses, :sensitive, :boolean, default: false\n  end\nend\n"
  },
  {
    "path": "db/migrate/20161128103007_create_subscriptions.rb",
    "content": "class CreateSubscriptions < ActiveRecord::Migration[5.0]\n  def change\n    create_table :subscriptions do |t|\n      t.string :callback_url, null: false, default: ''\n      t.string :secret\n      t.datetime :expires_at, null: true, default: nil\n      t.boolean :confirmed, null: false, default: false\n      t.integer :account_id, null: false\n\n      t.timestamps\n    end\n\n    add_index :subscriptions, [:callback_url, :account_id], unique: true\n  end\nend\n"
  },
  {
    "path": "db/migrate/20161130142058_add_last_successful_delivery_at_to_subscriptions.rb",
    "content": "class AddLastSuccessfulDeliveryAtToSubscriptions < ActiveRecord::Migration[5.0]\n  def change\n    add_column :subscriptions, :last_successful_delivery_at, :datetime, null: true, default: nil\n  end\nend\n"
  },
  {
    "path": "db/migrate/20161130185319_add_visibility_to_statuses.rb",
    "content": "class AddVisibilityToStatuses < ActiveRecord::Migration[5.0]\n  def change\n    add_column :statuses, :visibility, :integer, null: false, default: 0\n  end\nend\n"
  },
  {
    "path": "db/migrate/20161202132159_add_in_reply_to_account_id_to_statuses.rb",
    "content": "class AddInReplyToAccountIdToStatuses < ActiveRecord::Migration[5.0]\n  def up\n    add_column :statuses, :in_reply_to_account_id, :integer, null: true, default: nil\n\n    ActiveRecord::Base.transaction do\n      Status.where.not(in_reply_to_id: nil).includes(:thread).find_each do |status|\n        next if status.thread.nil?\n\n        status.in_reply_to_account_id = status.thread.account_id\n        status.save(validate: false)\n      end\n    end\n  end\n\n  def down\n    remove_column :statuses, :in_reply_to_account_id\n  end\nend\n"
  },
  {
    "path": "db/migrate/20161203164520_add_from_account_id_to_notifications.rb",
    "content": "class AddFromAccountIdToNotifications < ActiveRecord::Migration[5.0]\n  def up\n    add_column :notifications, :from_account_id, :integer\n\n    Notification.where(from_account_id: nil).where(activity_type: 'Status').update_all('from_account_id = (SELECT statuses.account_id FROM notifications AS notifications1 INNER JOIN statuses ON notifications1.activity_id = statuses.id WHERE notifications1.activity_type = \\'Status\\' AND notifications1.id = notifications.id)')\n    Notification.where(from_account_id: nil).where(activity_type: 'Mention').update_all('from_account_id = (SELECT statuses.account_id FROM notifications AS notifications1 INNER JOIN mentions ON notifications1.activity_id = mentions.id INNER JOIN statuses ON mentions.status_id = statuses.id WHERE notifications1.activity_type = \\'Mention\\' AND notifications1.id = notifications.id)')\n    Notification.where(from_account_id: nil).where(activity_type: 'Favourite').update_all('from_account_id = (SELECT favourites.account_id FROM notifications AS notifications1 INNER JOIN favourites ON notifications1.activity_id = favourites.id WHERE notifications1.activity_type = \\'Favourite\\' AND notifications1.id = notifications.id)')\n    Notification.where(from_account_id: nil).where(activity_type: 'Follow').update_all('from_account_id = (SELECT follows.account_id FROM notifications AS notifications1 INNER JOIN follows ON notifications1.activity_id = follows.id WHERE notifications1.activity_type = \\'Follow\\' AND notifications1.id = notifications.id)')\n  end\n\n  def down\n    remove_column :notifications, :from_account_id\n  end\nend\n"
  },
  {
    "path": "db/migrate/20161205214545_add_suspended_to_accounts.rb",
    "content": "class AddSuspendedToAccounts < ActiveRecord::Migration[5.0]\n  def change\n    add_column :accounts, :suspended, :boolean, null: false, default: false\n  end\nend\n"
  },
  {
    "path": "db/migrate/20161221152630_add_hidden_to_stream_entries.rb",
    "content": "class AddHiddenToStreamEntries < ActiveRecord::Migration[5.0]\n  def change\n    add_column :stream_entries, :hidden, :boolean, null: false, default: false\n  end\nend\n"
  },
  {
    "path": "db/migrate/20161222201034_add_locked_to_accounts.rb",
    "content": "class AddLockedToAccounts < ActiveRecord::Migration[5.0]\n  def change\n    add_column :accounts, :locked, :boolean, null: false, default: false\n  end\nend\n"
  },
  {
    "path": "db/migrate/20161222204147_create_follow_requests.rb",
    "content": "class CreateFollowRequests < ActiveRecord::Migration[5.0]\n  def change\n    create_table :follow_requests do |t|\n      t.integer :account_id, null: false\n      t.integer :target_account_id, null: false\n\n      t.timestamps null: false\n    end\n\n    add_index :follow_requests, [:account_id, :target_account_id], unique: true\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170105224407_add_shortcode_to_media_attachments.rb",
    "content": "class AddShortcodeToMediaAttachments < ActiveRecord::Migration[5.0]\n  def up\n    add_column :media_attachments, :shortcode, :string, null: true, default: nil\n    add_index :media_attachments, :shortcode, unique: true\n\n    # Migrate old links\n    MediaAttachment.local.update_all('shortcode = id')\n  end\n\n  def down\n    remove_index :media_attachments, :shortcode\n    remove_column :media_attachments, :shortcode\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170109120109_create_web_settings.rb",
    "content": "class CreateWebSettings < ActiveRecord::Migration[5.0]\n  def change\n    create_table :web_settings do |t|\n      t.integer :user_id\n      t.json :data\n\n      t.timestamps\n    end\n\n    add_index :web_settings, :user_id, unique: true\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170112154826_migrate_settings.rb",
    "content": "class MigrateSettings < ActiveRecord::Migration[4.2]\n  def up\n    remove_index :settings, [:target_type, :target_id, :var]\n    rename_column :settings, :target_id, :thing_id\n    rename_column :settings, :target_type, :thing_type\n    change_column :settings, :thing_id, :integer, null: true, default: nil\n    change_column :settings, :thing_type, :string, null: true, default: nil\n    add_index :settings, [:thing_type, :thing_id, :var], unique: true\n  end\n\n  def down\n    remove_index :settings, [:thing_type, :thing_id, :var]\n    rename_column :settings, :thing_id, :target_id\n    rename_column :settings, :thing_type, :target_type\n    change_column :settings, :target_id, :integer, null: false\n    change_column :settings, :target_type, :string, null: false, default: ''\n    add_index :settings, [:target_type, :target_id, :var], unique: true\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170114194937_add_application_to_statuses.rb",
    "content": "class AddApplicationToStatuses < ActiveRecord::Migration[5.0]\n  def change\n    add_column :statuses, :application_id, :int\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170114203041_add_website_to_oauth_application.rb",
    "content": "class AddWebsiteToOauthApplication < ActiveRecord::Migration[5.0]\n  def change\n    add_column :oauth_applications, :website, :string\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170119214911_create_preview_cards.rb",
    "content": "class CreatePreviewCards < ActiveRecord::Migration[5.0]\n  def change\n    create_table :preview_cards do |t|\n      t.integer :status_id\n      t.string :url, null: false, default: ''\n\n      # OpenGraph\n      t.string :title, null: true\n      t.string :description, null: true\n      t.attachment :image\n\n      t.timestamps\n    end\n\n    add_index :preview_cards, :status_id, unique: true\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170123162658_add_severity_to_domain_blocks.rb",
    "content": "class AddSeverityToDomainBlocks < ActiveRecord::Migration[5.0]\n  def change\n    add_column :domain_blocks, :severity, :integer, default: 0\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170123203248_add_reject_media_to_domain_blocks.rb",
    "content": "class AddRejectMediaToDomainBlocks < ActiveRecord::Migration[5.0]\n  def change\n    add_column :domain_blocks, :reject_media, :boolean\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170125145934_add_spoiler_text_to_statuses.rb",
    "content": "class AddSpoilerTextToStatuses < ActiveRecord::Migration[5.0]\n  def change\n    add_column :statuses, :spoiler_text, :text, default: \"\", null: false\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170127165745_add_devise_two_factor_to_users.rb",
    "content": "class AddDeviseTwoFactorToUsers < ActiveRecord::Migration[5.0]\n  def change\n    add_column :users, :encrypted_otp_secret, :string\n    add_column :users, :encrypted_otp_secret_iv, :string\n    add_column :users, :encrypted_otp_secret_salt, :string\n    add_column :users, :consumed_timestep, :integer\n    add_column :users, :otp_required_for_login, :boolean\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170129000348_create_devices.rb",
    "content": "class CreateDevices < ActiveRecord::Migration[5.0]\n  def change\n    create_table :devices do |t|\n      t.integer :account_id, null: false\n      t.string :registration_id, null: false, default: ''\n\n      t.timestamps\n    end\n\n    add_index :devices, :registration_id\n    add_index :devices, :account_id\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170205175257_remove_devices.rb",
    "content": "class RemoveDevices < ActiveRecord::Migration[5.0]\n  def change\n    drop_table :devices\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170209184350_add_reply_to_statuses.rb",
    "content": "class AddReplyToStatuses < ActiveRecord::Migration[5.0]\n  def up\n    add_column :statuses, :reply, :boolean, nil: false, default: false\n    Status.update_all('reply = (in_reply_to_id IS NOT NULL)')\n  end\n\n  def down\n    remove_column :statuses, :reply\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170214110202_create_reports.rb",
    "content": "class CreateReports < ActiveRecord::Migration[5.0]\n  def change\n    create_table :reports do |t|\n      t.integer :account_id, null: false\n      t.integer :target_account_id, null: false\n      t.integer :status_ids, array: true, null: false, default: []\n      t.text :comment, null: false, default: ''\n      t.boolean :action_taken, null: false, default: false\n\n      t.timestamps\n    end\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170217012631_add_reblog_of_id_foreign_key_to_statuses.rb",
    "content": "class AddReblogOfIdForeignKeyToStatuses < ActiveRecord::Migration[5.0]\n  def change\n    add_foreign_key :statuses, :statuses, column: :reblog_of_id, on_delete: :cascade\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170301222600_create_mutes.rb",
    "content": "class CreateMutes < ActiveRecord::Migration[5.0]\n  def change\n    create_table :mutes do |t|\n      t.integer :account_id, null: false\n      t.integer :target_account_id, null: false\n      t.timestamps null: false\n    end\n\n    add_index :mutes, [:account_id, :target_account_id], unique: true\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170303212857_add_last_emailed_at_to_users.rb",
    "content": "class AddLastEmailedAtToUsers < ActiveRecord::Migration[5.0]\n  def change\n    add_column :users, :last_emailed_at, :datetime, null: true, default: nil\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170304202101_add_type_to_media_attachments.rb",
    "content": "class AddTypeToMediaAttachments < ActiveRecord::Migration[5.0]\n  def up\n    add_column :media_attachments, :type, :integer, default: 0, null: false\n\n    MediaAttachment.where(file_content_type: MediaAttachment::IMAGE_MIME_TYPES).update_all(type: MediaAttachment.types[:image])\n    MediaAttachment.where(file_content_type: MediaAttachment::VIDEO_MIME_TYPES).update_all(type: MediaAttachment.types[:video])\n  end\n\n  def down\n    remove_column :media_attachments, :type\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170317193015_add_search_index_to_accounts.rb",
    "content": "class AddSearchIndexToAccounts < ActiveRecord::Migration[5.0]\n  def up\n    execute 'CREATE INDEX search_index ON accounts USING gin((setweight(to_tsvector(\\'simple\\', accounts.display_name), \\'A\\') || setweight(to_tsvector(\\'simple\\', accounts.username), \\'B\\') || setweight(to_tsvector(\\'simple\\', coalesce(accounts.domain, \\'\\')), \\'C\\')));'\n  end\n\n  def down\n    remove_index :accounts, name: :search_index\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170318214217_add_header_remote_url_to_accounts.rb",
    "content": "class AddHeaderRemoteUrlToAccounts < ActiveRecord::Migration[5.0]\n  def change\n    add_column :accounts, :header_remote_url, :string, null: false, default: ''\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170322021028_add_lowercase_index_to_accounts.rb",
    "content": "class AddLowercaseIndexToAccounts < ActiveRecord::Migration[5.0]\n  def up\n    execute 'CREATE INDEX index_accounts_on_username_and_domain_lower ON accounts (lower(username), lower(domain))'\n  end\n\n  def down\n    remove_index :accounts, name: 'index_accounts_on_username_and_domain_lower'\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170322143850_change_primary_key_to_bigint_on_statuses.rb",
    "content": "class ChangePrimaryKeyToBigintOnStatuses < ActiveRecord::Migration[5.0]\n  def change\n    change_column :statuses, :id, :bigint\n    change_column :statuses, :reblog_of_id, :bigint\n    change_column :statuses, :in_reply_to_id, :bigint\n\n    change_column :media_attachments, :status_id, :bigint\n    change_column :mentions, :status_id, :bigint\n    change_column :notifications, :activity_id, :bigint\n    change_column :preview_cards, :status_id, :bigint\n    change_column :reports, :status_ids, :bigint, array: true\n    change_column :statuses_tags, :status_id, :bigint\n    change_column :stream_entries, :activity_id, :bigint\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170322162804_add_search_index_to_tags.rb",
    "content": "class AddSearchIndexToTags < ActiveRecord::Migration[5.0]\n  def up\n    execute 'CREATE INDEX hashtag_search_index ON tags USING gin(to_tsvector(\\'simple\\', tags.name));'\n  end\n\n  def down\n    remove_index :tags, name: :hashtag_search_index\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170330021336_add_counter_caches.rb",
    "content": "class AddCounterCaches < ActiveRecord::Migration[5.0]\n  def change\n    add_column :statuses, :favourites_count, :integer, null: false, default: 0\n    add_column :statuses, :reblogs_count, :integer, null: false, default: 0\n    add_column :accounts, :statuses_count, :integer, null: false, default: 0\n    add_column :accounts, :followers_count, :integer, null: false, default: 0\n    add_column :accounts, :following_count, :integer, null: false, default: 0\n  end\nend\n\n# To make the new fields contain correct data:\n# update statuses set favourites_count = (select count(*) from favourites where favourites.status_id = statuses.id), reblogs_count = (select count(*) from statuses as reblogs where reblogs.reblog_of_id = statuses.id);\n# update accounts set statuses_count = (select count(*) from statuses where account_id = accounts.id), followers_count = (select count(*) from follows where target_account_id = accounts.id), following_count = (select count(*) from follows where account_id = accounts.id);\n"
  },
  {
    "path": "db/migrate/20170330163835_create_imports.rb",
    "content": "class CreateImports < ActiveRecord::Migration[5.0]\n  def change\n    create_table :imports do |t|\n      t.integer :account_id, null: false\n      t.integer :type, null: false\n      t.boolean :approved\n\n      t.timestamps\n    end\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170330164118_add_attachment_data_to_imports.rb",
    "content": "class AddAttachmentDataToImports < ActiveRecord::Migration[4.2]\n  def self.up\n    change_table :imports do |t|\n      t.attachment :data\n    end\n  end\n\n  def self.down\n    remove_attachment :imports, :data\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170403172249_add_action_taken_by_account_id_to_reports.rb",
    "content": "class AddActionTakenByAccountIdToReports < ActiveRecord::Migration[5.0]\n  def change\n    add_column :reports, :action_taken_by_account_id, :integer\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170405112956_add_index_on_mentions_status_id.rb",
    "content": "class AddIndexOnMentionsStatusId < ActiveRecord::Migration[5.0]\n  def change\n    add_index :mentions, :status_id\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170406215816_add_notifications_and_favourites_indices.rb",
    "content": "class AddNotificationsAndFavouritesIndices < ActiveRecord::Migration[5.0]\n  def change\n    add_index :notifications, [:activity_id, :activity_type]\n    add_index :accounts, :url\n    add_index :favourites, :status_id\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170409170753_add_last_webfingered_at_to_accounts.rb",
    "content": "class AddLastWebfingeredAtToAccounts < ActiveRecord::Migration[5.0]\n  def change\n    add_column :accounts, :last_webfingered_at, :datetime\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170414080609_add_devise_two_factor_backupable_to_users.rb",
    "content": "class AddDeviseTwoFactorBackupableToUsers < ActiveRecord::Migration[5.0]\n  def change\n    add_column :users, :otp_backup_codes, :string, array: true\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170414132105_add_language_to_statuses.rb",
    "content": "class AddLanguageToStatuses < ActiveRecord::Migration[5.0]\n  def change\n    add_column :statuses, :language, :string, null: false, default: 'en'\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170418160728_add_indexes_to_reports_for_accounts.rb",
    "content": "class AddIndexesToReportsForAccounts < ActiveRecord::Migration[5.0]\n  def change\n    add_index :reports, :account_id\n    add_index :reports, :target_account_id\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170423005413_add_allowed_languages_to_user.rb",
    "content": "class AddAllowedLanguagesToUser < ActiveRecord::Migration[5.0]\n  def change\n    add_column :users, :allowed_languages, :string, array: true, default: [], null: false\n    add_index :users, :allowed_languages, using: :gin\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170424003227_create_account_domain_blocks.rb",
    "content": "class CreateAccountDomainBlocks < ActiveRecord::Migration[5.0]\n  def change\n    create_table :account_domain_blocks do |t|\n      t.integer :account_id\n      t.string :domain\n\n      t.timestamps\n    end\n\n    add_index :account_domain_blocks, [:account_id, :domain], unique: true\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170424112722_add_status_id_index_to_statuses_tags.rb",
    "content": "class AddStatusIdIndexToStatusesTags < ActiveRecord::Migration[5.0]\n  def change\n    add_index :statuses_tags, :status_id\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170425131920_add_media_attachment_meta.rb",
    "content": "class AddMediaAttachmentMeta < ActiveRecord::Migration[5.0]\n  def change\n    add_column :media_attachments, :file_meta, :json\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170425202925_add_oembed_to_preview_cards.rb",
    "content": "class AddOEmbedToPreviewCards < ActiveRecord::Migration[5.0]\n  def change\n    add_column :preview_cards, :type, :integer, default: 0, null: false\n    add_column :preview_cards, :html, :text, null: false, default: ''\n    add_column :preview_cards, :author_name, :string, null: false, default: ''\n    add_column :preview_cards, :author_url, :string, null: false, default: ''\n    add_column :preview_cards, :provider_name, :string, null: false, default: ''\n    add_column :preview_cards, :provider_url, :string, null: false, default: ''\n    add_column :preview_cards, :width, :integer, default: 0, null: false\n    add_column :preview_cards, :height, :integer, default: 0, null: false\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170427011934_re_add_owner_to_application.rb",
    "content": "class ReAddOwnerToApplication < ActiveRecord::Migration[5.0]\n  def change\n    add_column :oauth_applications, :owner_id, :integer, null: true\n    add_column :oauth_applications, :owner_type, :string, null: true\n    add_index :oauth_applications, [:owner_id, :owner_type]\n    add_foreign_key :oauth_applications, :users, column: :owner_id, on_delete: :cascade\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170506235850_create_conversations.rb",
    "content": "class CreateConversations < ActiveRecord::Migration[5.0]\n  def change\n    create_table :conversations, id: :bigserial do |t|\n      t.string :uri, null: true, default: nil\n      t.timestamps\n    end\n\n    add_index :conversations, :uri, unique: true\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170507000211_add_conversation_id_to_statuses.rb",
    "content": "class AddConversationIdToStatuses < ActiveRecord::Migration[5.0]\n  def change\n    add_column :statuses, :conversation_id, :bigint, null: true, default: nil\n    add_index :statuses, :conversation_id\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170507141759_optimize_index_subscriptions.rb",
    "content": "class OptimizeIndexSubscriptions < ActiveRecord::Migration[5.0]\n  def up\n    add_index :subscriptions, [:account_id, :callback_url], unique: true\n    remove_index :subscriptions, [:callback_url, :account_id]\n  end\n\n  def down\n    add_index :subscriptions, [:callback_url, :account_id], unique: true\n    remove_index :subscriptions, [:account_id, :callback_url]\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170508230434_create_conversation_mutes.rb",
    "content": "class CreateConversationMutes < ActiveRecord::Migration[5.0]\n  def change\n    create_table :conversation_mutes do |t|\n      t.integer :account_id, null: false\n      t.bigint :conversation_id, null: false\n    end\n\n    add_index :conversation_mutes, [:account_id, :conversation_id], unique: true\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170516072309_add_index_accounts_on_uri.rb",
    "content": "class AddIndexAccountsOnUri < ActiveRecord::Migration[5.0]\n  def change\n    add_index :accounts, :uri\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170520145338_change_language_filter_to_opt_out.rb",
    "content": "class ChangeLanguageFilterToOptOut < ActiveRecord::Migration[5.0]\n  def change\n    remove_index :users, :allowed_languages\n    remove_column :users, :allowed_languages\n\n    add_column :users, :filtered_languages, :string, array: true, default: [], null: false\n    add_index :users, :filtered_languages, using: :gin\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170601210557_add_index_on_media_attachments_account_id.rb",
    "content": "class AddIndexOnMediaAttachmentsAccountId < ActiveRecord::Migration[5.1]\n  def change\n    add_index :media_attachments, :account_id\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170604144747_add_foreign_keys_for_accounts.rb",
    "content": "class AddForeignKeysForAccounts < ActiveRecord::Migration[5.1]\n  def change\n    add_foreign_key :statuses, :accounts, on_delete: :cascade\n    add_foreign_key :statuses, :accounts, column: :in_reply_to_account_id, on_delete: :nullify\n    add_foreign_key :statuses, :statuses, column: :in_reply_to_id, on_delete: :nullify\n    add_foreign_key :account_domain_blocks, :accounts, on_delete: :cascade\n    add_foreign_key :conversation_mutes, :accounts, on_delete: :cascade\n    add_foreign_key :conversation_mutes, :conversations, on_delete: :cascade\n    add_foreign_key :favourites, :accounts, on_delete: :cascade\n    add_foreign_key :favourites, :statuses, on_delete: :cascade\n    add_foreign_key :blocks, :accounts, on_delete: :cascade\n    add_foreign_key :blocks, :accounts, column: :target_account_id, on_delete: :cascade\n    add_foreign_key :follow_requests, :accounts, on_delete: :cascade\n    add_foreign_key :follow_requests, :accounts, column: :target_account_id, on_delete: :cascade\n    add_foreign_key :follows, :accounts, on_delete: :cascade\n    add_foreign_key :follows, :accounts, column: :target_account_id, on_delete: :cascade\n    add_foreign_key :mutes, :accounts, on_delete: :cascade\n    add_foreign_key :mutes, :accounts, column: :target_account_id, on_delete: :cascade\n    add_foreign_key :imports, :accounts, on_delete: :cascade\n    add_foreign_key :media_attachments, :accounts, on_delete: :nullify\n    add_foreign_key :media_attachments, :statuses, on_delete: :nullify\n    add_foreign_key :mentions, :accounts, on_delete: :cascade\n    add_foreign_key :mentions, :statuses, on_delete: :cascade\n    add_foreign_key :notifications, :accounts, on_delete: :cascade\n    add_foreign_key :notifications, :accounts, column: :from_account_id, on_delete: :cascade\n    add_foreign_key :preview_cards, :statuses, on_delete: :cascade\n    add_foreign_key :reports, :accounts, on_delete: :cascade\n    add_foreign_key :reports, :accounts, column: :target_account_id, on_delete: :cascade\n    add_foreign_key :reports, :accounts, column: :action_taken_by_account_id, on_delete: :nullify\n    add_foreign_key :statuses_tags, :statuses, on_delete: :cascade\n    add_foreign_key :statuses_tags, :tags, on_delete: :cascade\n    add_foreign_key :stream_entries, :accounts, on_delete: :cascade\n    add_foreign_key :subscriptions, :accounts, on_delete: :cascade\n    add_foreign_key :users, :accounts, on_delete: :cascade\n    add_foreign_key :web_settings, :users, on_delete: :cascade\n    add_foreign_key :oauth_access_grants, :users, column: :resource_owner_id, on_delete: :cascade\n    add_foreign_key :oauth_access_grants, :oauth_applications, column: :application_id, on_delete: :cascade\n    add_foreign_key :oauth_access_tokens, :users, column: :resource_owner_id, on_delete: :cascade\n    add_foreign_key :oauth_access_tokens, :oauth_applications, column: :application_id, on_delete: :cascade\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170606113804_change_tag_search_index_to_btree.rb",
    "content": "class ChangeTagSearchIndexToBtree < ActiveRecord::Migration[5.1]\n  def up\n    remove_index :tags, name: :hashtag_search_index\n    execute 'CREATE INDEX hashtag_search_index ON tags (name text_pattern_ops);'\n  end\n\n  def down\n    remove_index :tags, name: :hashtag_search_index\n    execute 'CREATE INDEX hashtag_search_index ON tags USING gin(to_tsvector(\\'simple\\', tags.name));'\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170609145826_remove_default_language_from_statuses.rb",
    "content": "class RemoveDefaultLanguageFromStatuses < ActiveRecord::Migration[5.1]\n  def change\n    change_column :statuses, :language, :string, default: nil, null: true\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170610000000_add_statuses_index_on_account_id_id.rb",
    "content": "class AddStatusesIndexOnAccountIdId < ActiveRecord::Migration[5.1]\n  disable_ddl_transaction!\n\n  def change\n    # Statuses queried by account_id are often sorted by id. Querying statuses\n    # of an account to show them in his status page is one of the most\n    # significant examples.\n    # Add this index to improve the performance in such cases.\n    add_index 'statuses', ['account_id', 'id'], algorithm: :concurrently, name: 'index_statuses_on_account_id_id'\n\n    remove_index 'statuses', algorithm: :concurrently, column: 'account_id', name: 'index_statuses_on_account_id'\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170623152212_create_session_activations.rb",
    "content": "class CreateSessionActivations < ActiveRecord::Migration[5.1]\n  def change\n    create_table :session_activations do |t|\n      t.integer :user_id,   null: false\n      t.string :session_id, null: false\n\n      t.timestamps\n    end\n\n    add_index :session_activations, :user_id\n    add_index :session_activations, :session_id, unique: true\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170624134742_add_description_to_session_activations.rb",
    "content": "class AddDescriptionToSessionActivations < ActiveRecord::Migration[5.1]\n  def change\n    add_column :session_activations, :user_agent, :string, null: false, default: ''\n    add_column :session_activations, :ip, :inet\n    add_foreign_key :session_activations, :users, on_delete: :cascade\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170625140443_add_access_token_id_to_session_activations.rb",
    "content": "class AddAccessTokenIdToSessionActivations < ActiveRecord::Migration[5.1]\n  def change\n    add_column :session_activations, :access_token_id, :integer\n    add_foreign_key :session_activations, :oauth_access_tokens, column: :access_token_id, on_delete: :cascade\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170711225116_fix_null_booleans.rb",
    "content": "class FixNullBooleans < ActiveRecord::Migration[5.1]\n  def change\n    change_column_default :domain_blocks, :reject_media, false\n    change_column_null :domain_blocks, :reject_media, false, false\n\n    change_column_default :imports, :approved, false\n    change_column_null :imports, :approved, false, false\n\n    change_column_null :statuses, :sensitive, false, false\n    change_column_null :statuses, :reply, false, false\n\n    change_column_null :users, :admin, false, false\n\n    change_column_default :users, :otp_required_for_login, false\n    change_column_null :users, :otp_required_for_login, false, false\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170713112503_make_tag_search_case_insensitive.rb",
    "content": "class MakeTagSearchCaseInsensitive < ActiveRecord::Migration[5.1]\n  def up\n    remove_index :tags, name: :hashtag_search_index\n    execute 'CREATE INDEX hashtag_search_index ON tags (lower(name) text_pattern_ops);'\n  end\n\n  def down\n    remove_index :tags, name: :hashtag_search_index\n    execute 'CREATE INDEX hashtag_search_index ON tags (name text_pattern_ops);'\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170713175513_create_web_push_subscriptions.rb",
    "content": "class CreateWebPushSubscriptions < ActiveRecord::Migration[5.1]\n  def change\n    create_table :web_push_subscriptions do |t|\n      t.string :endpoint, null: false\n      t.string :key_p256dh, null: false\n      t.string :key_auth, null: false\n      t.json :data\n\n      t.timestamps\n    end\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170713190709_add_web_push_subscription_to_session_activations.rb",
    "content": "class AddWebPushSubscriptionToSessionActivations < ActiveRecord::Migration[5.1]\n  def change\n    add_column :session_activations, :web_push_subscription_id, :integer\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170714184731_add_domain_to_subscriptions.rb",
    "content": "class AddDomainToSubscriptions < ActiveRecord::Migration[5.1]\n  def change\n    add_column :subscriptions, :domain, :string\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170716191202_add_hide_notifications_to_mute.rb",
    "content": "require Rails.root.join('lib', 'mastodon', 'migration_helpers')\n\nclass AddHideNotificationsToMute < ActiveRecord::Migration[5.1]\n  include Mastodon::MigrationHelpers\n\n  disable_ddl_transaction!\n\n  def up\n    add_column_with_default :mutes, :hide_notifications, :boolean, default: true, allow_null: false\n  end\n\n  def down\n    remove_column :mutes, :hide_notifications\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170718211102_add_activitypub_to_accounts.rb",
    "content": "class AddActivityPubToAccounts < ActiveRecord::Migration[5.1]\n  def change\n    add_column :accounts, :inbox_url, :string, null: false, default: ''\n    add_column :accounts, :outbox_url, :string, null: false, default: ''\n    add_column :accounts, :shared_inbox_url, :string, null: false, default: ''\n    add_column :accounts, :followers_url, :string, null: false, default: ''\n    add_column :accounts, :protocol, :integer, null: false, default: 0\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170720000000_add_index_favourites_on_account_id_and_id.rb",
    "content": "class AddIndexFavouritesOnAccountIdAndId < ActiveRecord::Migration[5.1]\n  def change\n    # Used to query favourites of an account ordered by id.\n    add_index :favourites, [:account_id, :id]\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170823162448_create_status_pins.rb",
    "content": "class CreateStatusPins < ActiveRecord::Migration[5.1]\n  def change\n    create_table :status_pins do |t|\n      t.belongs_to :account, foreign_key: { on_delete: :cascade }, null: false\n      t.belongs_to :status, foreign_key: { on_delete: :cascade }, null: false\n    end\n\n    add_index :status_pins, [:account_id, :status_id], unique: true\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170824103029_add_timestamps_to_status_pins.rb",
    "content": "class AddTimestampsToStatusPins < ActiveRecord::Migration[5.1]\n  def change\n    add_timestamps :status_pins, null: false, default: -> { 'CURRENT_TIMESTAMP' }\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170829215220_remove_status_pins_account_index.rb",
    "content": "class RemoveStatusPinsAccountIndex < ActiveRecord::Migration[5.1]\n  def change\n    remove_index :status_pins, :account_id\n    remove_index :status_pins, :status_id\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170901141119_truncate_preview_cards.rb",
    "content": "class TruncatePreviewCards < ActiveRecord::Migration[5.1]\n  def up\n    rename_table :preview_cards, :deprecated_preview_cards\n\n    create_table :preview_cards do |t|\n      t.string     :url, default: '', null: false, index: { unique: true }\n      t.string     :title, default: '', null: false\n      t.string     :description, default: '', null: false\n      t.attachment :image\n      t.integer    :type, default: 0, null: false\n      t.text       :html, default: '', null: false\n      t.string     :author_name, default: '', null: false\n      t.string     :author_url, default: '', null: false\n      t.string     :provider_name, default: '', null: false\n      t.string     :provider_url, default: '', null: false\n      t.integer    :width, default: 0, null: false\n      t.integer    :height, default: 0, null: false\n      t.timestamps\n    end\n  end\n\n  def down\n    if ActiveRecord::Base.connection.table_exists? 'deprecated_preview_cards'\n      drop_table :preview_cards\n      rename_table :deprecated_preview_cards, :preview_cards\n    else\n      raise ActiveRecord::IrreversibleMigration, 'Previous preview cards table has already been removed'\n    end\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170901142658_create_join_table_preview_cards_statuses.rb",
    "content": "class CreateJoinTablePreviewCardsStatuses < ActiveRecord::Migration[5.1]\n  def change\n    create_join_table :preview_cards, :statuses do |t|\n      t.index [:status_id, :preview_card_id]\n    end\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170905044538_add_index_id_account_id_activity_type_on_notifications.rb",
    "content": "class AddIndexIdAccountIdActivityTypeOnNotifications < ActiveRecord::Migration[5.1]\n  def change\n    add_index :notifications, [:id, :account_id, :activity_type], order: { id: :desc }\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170905165803_add_local_to_statuses.rb",
    "content": "class AddLocalToStatuses < ActiveRecord::Migration[5.1]\n  def change\n    add_column :statuses, :local, :boolean, null: true, default: nil\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170913000752_create_site_uploads.rb",
    "content": "class CreateSiteUploads < ActiveRecord::Migration[5.1]\n  def change\n    create_table :site_uploads do |t|\n      t.string :var, default: '', null: false, index: { unique: true }\n      t.attachment :file\n      t.json :meta\n      t.timestamps\n    end\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170917153509_create_custom_emojis.rb",
    "content": "class CreateCustomEmojis < ActiveRecord::Migration[5.1]\n  def change\n    create_table :custom_emojis do |t|\n      t.string :shortcode, null: false, default: ''\n      t.string :domain\n      t.attachment :image\n\n      t.timestamps\n    end\n\n    add_index :custom_emojis, [:shortcode, :domain], unique: true\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170918125918_ids_to_bigints.rb",
    "content": "require Rails.root.join('lib', 'mastodon', 'migration_helpers')\n\nclass IdsToBigints < ActiveRecord::Migration[5.1]\n  include Mastodon::MigrationHelpers\n\n  disable_ddl_transaction!\n\n  INCLUDED_COLUMNS = [\n    [:account_domain_blocks, :account_id],\n    [:account_domain_blocks, :id],\n    [:accounts, :id],\n    [:blocks, :account_id],\n    [:blocks, :id],\n    [:blocks, :target_account_id],\n    [:conversation_mutes, :account_id],\n    [:conversation_mutes, :id],\n    [:domain_blocks, :id],\n    [:favourites, :account_id],\n    [:favourites, :id],\n    [:favourites, :status_id],\n    [:follow_requests, :account_id],\n    [:follow_requests, :id],\n    [:follow_requests, :target_account_id],\n    [:follows, :account_id],\n    [:follows, :id],\n    [:follows, :target_account_id],\n    [:imports, :account_id],\n    [:imports, :id],\n    [:media_attachments, :account_id],\n    [:media_attachments, :id],\n    [:mentions, :account_id],\n    [:mentions, :id],\n    [:mutes, :account_id],\n    [:mutes, :id],\n    [:mutes, :target_account_id],\n    [:notifications, :account_id],\n    [:notifications, :from_account_id],\n    [:notifications, :id],\n    [:oauth_access_grants, :application_id],\n    [:oauth_access_grants, :id],\n    [:oauth_access_grants, :resource_owner_id],\n    [:oauth_access_tokens, :application_id],\n    [:oauth_access_tokens, :id],\n    [:oauth_access_tokens, :resource_owner_id],\n    [:oauth_applications, :id],\n    [:oauth_applications, :owner_id],\n    [:reports, :account_id],\n    [:reports, :action_taken_by_account_id],\n    [:reports, :id],\n    [:reports, :target_account_id],\n    [:session_activations, :access_token_id],\n    [:session_activations, :user_id],\n    [:session_activations, :web_push_subscription_id],\n    [:settings, :id],\n    [:settings, :thing_id],\n    [:statuses, :account_id],\n    [:statuses, :application_id],\n    [:statuses, :in_reply_to_account_id],\n    [:stream_entries, :account_id],\n    [:stream_entries, :id],\n    [:subscriptions, :account_id],\n    [:subscriptions, :id],\n    [:tags, :id],\n    [:users, :account_id],\n    [:users, :id],\n    [:web_settings, :id],\n    [:web_settings, :user_id],\n  ]\n  INCLUDED_COLUMNS << [:deprecated_preview_cards, :id] if table_exists?(:deprecated_preview_cards)\n\n  def migrate_columns(to_type)\n    # Print out a warning that this will probably take a while.\n    say ''\n    say 'WARNING: This migration may take a *long* time for large instances'\n    say 'It will *not* lock tables for any significant time, but it may run'\n    say 'for a very long time. We will pause for 10 seconds to allow you to'\n    say 'interrupt this migration if you are not ready.'\n    say ''\n    say 'This migration has some sections that can be safely interrupted'\n    say 'and restarted later, and will tell you when those are occurring.'\n    say ''\n    say 'For more information, see https://github.com/tootsuite/mastodon/pull/5088'\n\n    10.downto(1) do |i|\n      say \"Continuing in #{i} second#{i == 1 ? '' : 's'}...\", true\n      sleep 1\n    end\n\n    tables = INCLUDED_COLUMNS.map(&:first).uniq\n    table_sizes = {}\n\n    # Sort tables by their size\n    tables.each do |table|\n      table_sizes[table] = estimate_rows_in_table(table)\n    end\n\n    ordered_columns = INCLUDED_COLUMNS.sort_by do |col_parts|\n      [-table_sizes[col_parts.first], col_parts.last]\n    end\n\n    ordered_columns.each do |column_parts|\n      table, column = column_parts\n\n      # Skip this if we're resuming and already did this one.\n      next if column_for(table, column).sql_type == to_type.to_s\n\n      change_column_type_concurrently table, column, to_type\n      cleanup_concurrent_column_type_change table, column\n    end\n  end\n\n  def up\n    migrate_columns(:bigint)\n  end\n\n  def down\n    migrate_columns(:integer)\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170920024819_status_ids_to_timestamp_ids.rb",
    "content": "class StatusIdsToTimestampIds < ActiveRecord::Migration[5.1]\n  def up\n    # Prepare the function we will use to generate IDs.\n    Rake::Task['db:define_timestamp_id'].execute\n\n    # Set up the statuses.id column to use our timestamp-based IDs.\n    ActiveRecord::Base.connection.execute(<<~SQL)\n      ALTER TABLE statuses\n      ALTER COLUMN id\n      SET DEFAULT timestamp_id('statuses')\n    SQL\n\n    # Make sure we have a sequence to use.\n    Rake::Task['db:ensure_id_sequences_exist'].execute\n  end\n\n  def down\n    # Revert the column to the old method of just using the sequence\n    # value for new IDs. Set the current ID sequence to the maximum\n    # existing ID, such that the next sequence will be one higher.\n\n    # We lock the table during this so that the ID won't get clobbered,\n    # but ID is indexed, so this should be a fast operation.\n    ActiveRecord::Base.connection.execute(<<~SQL)\n      LOCK statuses;\n      SELECT setval('statuses_id_seq', (SELECT MAX(id) FROM statuses));\n      ALTER TABLE statuses\n        ALTER COLUMN id\n        SET DEFAULT nextval('statuses_id_seq');\n    SQL\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170920032311_fix_reblogs_in_feeds.rb",
    "content": "class FixReblogsInFeeds < ActiveRecord::Migration[5.1]\n  def up\n    redis = Redis.current\n    fm = FeedManager.instance\n\n    # Old scheme:\n    # Each user's feed zset had a series of score:value entries,\n    # where \"regular\" statuses had the same score and value (their\n    # ID). Reblogs had a score of the reblogging status' ID, and a\n    # value of the reblogged status' ID.\n\n    # New scheme:\n    # The feed contains only entries with the same score and value.\n    # Reblogs result in the reblogging status being added to the\n    # feed, with an entry in a reblog tracking zset (where the score\n    # is once again set to the reblogging status' ID, and the value\n    # is set to the reblogged status' ID). This is safe for Redis'\n    # float coersion because in this reblog tracking zset, we only\n    # need the rebloggging status' ID to be able to stop tracking\n    # entries after they have gotten too far down the feed, which\n    # does not require an exact value.\n\n    # This process reads all feeds and writes 3 times for each reblogs.\n    # So we use Lua script to avoid overhead between Ruby and Redis.\n    script = <<-LUA\n      local timeline_key = KEYS[1]\n      local reblog_key = KEYS[2]\n\n      -- So, first, we iterate over the user's feed to find any reblogs.\n      local items = redis.call('zrange', timeline_key, 0, -1, 'withscores')\n\n      for i = 1, #items, 2 do\n        local reblogged_id = items[i]\n        local reblogging_id = items[i + 1]\n        if (reblogged_id ~= reblogging_id) then\n\n          -- The score and value don't match, so this is a reblog.\n          -- (note that we're transitioning from IDs < 53 bits so we\n          -- don't have to worry about the loss of precision)\n\n          -- Remove the old entry\n          redis.call('zrem', timeline_key, reblogged_id)\n\n          -- Add a new one for the reblogging status\n          redis.call('zadd', timeline_key, reblogging_id, reblogging_id)\n\n          -- Track the fact that this was a reblog\n          redis.call('zadd', reblog_key, reblogging_id, reblogged_id)\n        end\n      end\n    LUA\n    script_hash = redis.script(:load, script)\n\n    # find_each is batched on the database side.\n    User.includes(:account).find_each do |user|\n      account = user.account\n\n      timeline_key = fm.key(:home, account.id)\n      reblog_key = fm.key(:home, account.id, 'reblogs')\n\n      redis.evalsha(script_hash, [timeline_key, reblog_key])\n    end\n  end\n\n  def down\n    # We *deliberately* do nothing here. This means that reverting\n    # this and the associated changes to the FeedManager code could\n    # allow one superfluous reblog of any given status, but in the case\n    # where things have gone wrong and a revert is necessary, this\n    # appears preferable to requiring a database hit for every status\n    # in every users' feed simply to revert.\n\n    # Note that this is operating under the assumption that entries\n    # with >53-bit IDs have already been entered. Otherwise, we could\n    # just use the data in Redis to reverse this transition.\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170924022025_ids_to_bigints2.rb",
    "content": "class IdsToBigints2 < ActiveRecord::Migration[5.1]\n  def up\n    change_column :statuses_tags, :tag_id, :bigint\n  end\n\n  def down\n    change_column :statuses_tags, :tag_id, :integer\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170927215609_add_description_to_media_attachments.rb",
    "content": "class AddDescriptionToMediaAttachments < ActiveRecord::Migration[5.1]\n  def change\n    add_column :media_attachments, :description, :text\n  end\nend\n"
  },
  {
    "path": "db/migrate/20170928082043_create_email_domain_blocks.rb",
    "content": "class CreateEmailDomainBlocks < ActiveRecord::Migration[5.1]\n  def change\n    create_table :email_domain_blocks do |t|\n      t.string :domain, null: false\n\n      t.timestamps\n    end\n  end\nend\n"
  },
  {
    "path": "db/migrate/20171005102658_create_account_moderation_notes.rb",
    "content": "class CreateAccountModerationNotes < ActiveRecord::Migration[5.1]\n  def change\n    create_table :account_moderation_notes do |t|\n      t.text :content, null: false\n      t.references :account\n      t.references :target_account\n\n      t.timestamps\n    end\n\n    safety_assured { add_foreign_key :account_moderation_notes, :accounts, column: :target_account_id }\n  end\nend\n"
  },
  {
    "path": "db/migrate/20171005171936_add_disabled_to_custom_emojis.rb",
    "content": "require Rails.root.join('lib', 'mastodon', 'migration_helpers')\n\nclass AddDisabledToCustomEmojis < ActiveRecord::Migration[5.1]\n  include Mastodon::MigrationHelpers\n\n  disable_ddl_transaction!\n\n  def up\n    safety_assured { add_column_with_default :custom_emojis, :disabled, :bool, default: false }\n  end\n\n  def down\n    remove_column :custom_emojis, :disabled\n  end\nend\n"
  },
  {
    "path": "db/migrate/20171006142024_add_uri_to_custom_emojis.rb",
    "content": "class AddUriToCustomEmojis < ActiveRecord::Migration[5.1]\n  def change\n    add_column :custom_emojis, :uri, :string\n    add_column :custom_emojis, :image_remote_url, :string\n  end\nend\n"
  },
  {
    "path": "db/migrate/20171010023049_add_foreign_key_to_account_moderation_notes.rb",
    "content": "class AddForeignKeyToAccountModerationNotes < ActiveRecord::Migration[5.1]\n  def change\n    safety_assured { add_foreign_key :account_moderation_notes, :accounts }\n  end\nend\n"
  },
  {
    "path": "db/migrate/20171010025614_change_accounts_nonnullable_in_account_moderation_notes.rb",
    "content": "class ChangeAccountsNonnullableInAccountModerationNotes < ActiveRecord::Migration[5.1]\n  def change\n    change_column_null :account_moderation_notes, :account_id, false\n    change_column_null :account_moderation_notes, :target_account_id, false\n  end\nend\n"
  },
  {
    "path": "db/migrate/20171020084748_add_visible_in_picker_to_custom_emoji.rb",
    "content": "class AddVisibleInPickerToCustomEmoji < ActiveRecord::Migration[5.1]\n  def change\n    safety_assured {\n      add_column :custom_emojis, :visible_in_picker, :boolean, default: true, null: false\n    }\n  end\nend\n"
  },
  {
    "path": "db/migrate/20171028221157_add_reblogs_to_follows.rb",
    "content": "require Rails.root.join('lib', 'mastodon', 'migration_helpers')\n\nclass AddReblogsToFollows < ActiveRecord::Migration[5.1]\n  include Mastodon::MigrationHelpers\n\n  disable_ddl_transaction!\n\n  def up\n    safety_assured do\n      add_column_with_default :follows, :show_reblogs, :boolean, default: true, allow_null: false\n      add_column_with_default :follow_requests, :show_reblogs, :boolean, default: true, allow_null: false\n    end\n  end\n\n  def down\n    remove_column :follows, :show_reblogs\n    remove_column :follow_requests, :show_reblogs\n  end\nend\n"
  },
  {
    "path": "db/migrate/20171107143332_add_memorial_to_accounts.rb",
    "content": "require Rails.root.join('lib', 'mastodon', 'migration_helpers')\n\nclass AddMemorialToAccounts < ActiveRecord::Migration[5.1]\n  include Mastodon::MigrationHelpers\n\n  disable_ddl_transaction!\n\n  def up\n    safety_assured { add_column_with_default :accounts, :memorial, :bool, default: false }\n  end\n\n  def down\n    remove_column :accounts, :memorial\n  end\nend\n"
  },
  {
    "path": "db/migrate/20171107143624_add_disabled_to_users.rb",
    "content": "require Rails.root.join('lib', 'mastodon', 'migration_helpers')\n\nclass AddDisabledToUsers < ActiveRecord::Migration[5.1]\n  include Mastodon::MigrationHelpers\n\n  disable_ddl_transaction!\n\n  def up\n    safety_assured { add_column_with_default :users, :disabled, :bool, default: false }\n  end\n\n  def down\n    remove_column :users, :disabled\n  end\nend\n"
  },
  {
    "path": "db/migrate/20171109012327_add_moderator_to_accounts.rb",
    "content": "require Rails.root.join('lib', 'mastodon', 'migration_helpers')\n\nclass AddModeratorToAccounts < ActiveRecord::Migration[5.1]\n  include Mastodon::MigrationHelpers\n\n  disable_ddl_transaction!\n\n  def up\n    safety_assured { add_column_with_default :users, :moderator, :bool, default: false }\n  end\n\n  def down\n    remove_column :users, :moderator\n  end\nend\n"
  },
  {
    "path": "db/migrate/20171114080328_add_index_domain_to_email_domain_blocks.rb",
    "content": "class AddIndexDomainToEmailDomainBlocks < ActiveRecord::Migration[5.1]\n  disable_ddl_transaction!\n\n  def change\n    add_index :email_domain_blocks, :domain, algorithm: :concurrently, unique: true\n    change_column_default :email_domain_blocks, :domain, from: nil, to: ''\n  end\nend\n"
  },
  {
    "path": "db/migrate/20171114231651_create_lists.rb",
    "content": "class CreateLists < ActiveRecord::Migration[5.1]\n  def change\n    create_table :lists do |t|\n      t.references :account, foreign_key: { on_delete: :cascade }\n      t.string :title, null: false, default: ''\n\n      t.timestamps\n    end\n  end\nend\n"
  },
  {
    "path": "db/migrate/20171116161857_create_list_accounts.rb",
    "content": "class CreateListAccounts < ActiveRecord::Migration[5.1]\n  def change\n    create_table :list_accounts do |t|\n      t.belongs_to :list, foreign_key: { on_delete: :cascade }, null: false\n      t.belongs_to :account, foreign_key: { on_delete: :cascade }, null: false\n      t.belongs_to :follow, foreign_key: { on_delete: :cascade }, null: false\n    end\n\n    add_index :list_accounts, [:account_id, :list_id], unique: true\n    add_index :list_accounts, [:list_id, :account_id]\n  end\nend\n"
  },
  {
    "path": "db/migrate/20171118012443_add_moved_to_account_id_to_accounts.rb",
    "content": "class AddMovedToAccountIdToAccounts < ActiveRecord::Migration[5.1]\n  def change\n    add_column :accounts, :moved_to_account_id, :bigint, null: true, default: nil\n    safety_assured { add_foreign_key :accounts, :accounts, column: :moved_to_account_id, on_delete: :nullify }\n  end\nend\n"
  },
  {
    "path": "db/migrate/20171119172437_create_admin_action_logs.rb",
    "content": "class CreateAdminActionLogs < ActiveRecord::Migration[5.1]\n  def change\n    create_table :admin_action_logs do |t|\n      t.belongs_to :account, foreign_key: { on_delete: :cascade }\n      t.string :action, null: false, default: ''\n      t.references :target, polymorphic: true\n      t.text :recorded_changes, null: false, default: ''\n\n      t.timestamps\n    end\n  end\nend\n"
  },
  {
    "path": "db/migrate/20171122120436_add_index_account_and_reblog_of_id_to_statuses.rb",
    "content": "class AddIndexAccountAndReblogOfIdToStatuses < ActiveRecord::Migration[5.1]\n  disable_ddl_transaction!\n\n  def up\n    # This index has been superseded by migration 20171125185353\n    # add_index :statuses, [:account_id, :reblog_of_id], algorithm: :concurrently\n  end\n\n  def down\n    remove_index :statuses, [:account_id, :reblog_of_id] if index_exists?(:statuses, [:account_id, :reblog_of_id])\n  end\nend\n"
  },
  {
    "path": "db/migrate/20171125024930_create_invites.rb",
    "content": "class CreateInvites < ActiveRecord::Migration[5.1]\n  def change\n    create_table :invites do |t|\n      t.belongs_to :user, foreign_key: { on_delete: :cascade }\n      t.string :code, null: false, default: ''\n      t.datetime :expires_at, null: true, default: nil\n      t.integer :max_uses, null: true, default: nil\n      t.integer :uses, null: false, default: 0\n\n      t.timestamps\n    end\n\n    add_index :invites, :code, unique: true\n  end\nend\n"
  },
  {
    "path": "db/migrate/20171125031751_add_invite_id_to_users.rb",
    "content": "class AddInviteIdToUsers < ActiveRecord::Migration[5.1]\n  def change\n    add_reference :users, :invite, null: true, default: nil, foreign_key: { on_delete: :nullify }, index: false\n  end\nend\n"
  },
  {
    "path": "db/migrate/20171125185353_add_index_reblog_of_id_and_account_to_statuses.rb",
    "content": "class AddIndexReblogOfIdAndAccountToStatuses < ActiveRecord::Migration[5.1]\n  disable_ddl_transaction!\n\n  def change\n    add_index :statuses, [:reblog_of_id, :account_id], algorithm: :concurrently\n  end\nend\n"
  },
  {
    "path": "db/migrate/20171125190735_remove_old_reblog_index_on_statuses.rb",
    "content": "class RemoveOldReblogIndexOnStatuses < ActiveRecord::Migration[5.1]\n  disable_ddl_transaction!\n\n  def up\n    # This index may not exists (see migration 20171122120436)\n    remove_index :statuses, [:account_id, :reblog_of_id] if index_exists?(:statuses, [:account_id, :reblog_of_id])\n\n    remove_index :statuses, :reblog_of_id\n  end\n\n  def down\n    add_index :statuses, :reblog_of_id, algorithm: :concurrently\n  end\nend\n"
  },
  {
    "path": "db/migrate/20171129172043_add_index_on_stream_entries.rb",
    "content": "class AddIndexOnStreamEntries < ActiveRecord::Migration[5.1]\n  disable_ddl_transaction!\n\n  def change\n    add_index :stream_entries, [:account_id, :activity_type, :id], algorithm: :concurrently\n    remove_index :stream_entries, name: :index_stream_entries_on_account_id\n  end\nend\n"
  },
  {
    "path": "db/migrate/20171130000000_add_embed_url_to_preview_cards.rb",
    "content": "require Rails.root.join('lib', 'mastodon', 'migration_helpers')\n\nclass AddEmbedUrlToPreviewCards < ActiveRecord::Migration[5.1]\n  include Mastodon::MigrationHelpers\n\n  disable_ddl_transaction!\n\n  def up\n    safety_assured do\n      add_column_with_default :preview_cards, :embed_url, :string, default: '', allow_null: false\n    end\n  end\n\n  def down\n    execute \"UPDATE preview_cards SET url=embed_url WHERE embed_url!=''\"\n    remove_column :preview_cards, :embed_url\n  end\nend\n"
  },
  {
    "path": "db/migrate/20171201000000_change_account_id_nonnullable_in_lists.rb",
    "content": "class ChangeAccountIdNonnullableInLists < ActiveRecord::Migration[5.1]\n  def change\n    change_column_null :lists, :account_id, false\n  end\nend\n"
  },
  {
    "path": "db/migrate/20171212195226_remove_duplicate_indexes_in_lists.rb",
    "content": "class RemoveDuplicateIndexesInLists < ActiveRecord::Migration[5.1]\n  def change\n    remove_index :list_accounts, name: \"index_list_accounts_on_account_id\"\n    remove_index :list_accounts, name: \"index_list_accounts_on_list_id\"\n  end\nend\n"
  },
  {
    "path": "db/migrate/20171226094803_more_faster_index_on_notifications.rb",
    "content": "class MoreFasterIndexOnNotifications < ActiveRecord::Migration[5.1]\n  disable_ddl_transaction!\n\n  def change\n    add_index :notifications, [:account_id, :id], order: { id: :desc }, algorithm: :concurrently\n    remove_index :notifications, name: :index_notifications_on_id_and_account_id_and_activity_type\n  end\nend\n"
  },
  {
    "path": "db/migrate/20180106000232_add_index_on_statuses_for_api_v1_accounts_account_id_statuses.rb",
    "content": "class AddIndexOnStatusesForApiV1AccountsAccountIdStatuses < ActiveRecord::Migration[5.1]\n  disable_ddl_transaction!\n\n  def change\n    safety_assured do\n      add_index :statuses, [:account_id, :id, :visibility, :updated_at], order: { id: :desc }, algorithm: :concurrently, name: :index_statuses_20180106\n    end\n    remove_index :statuses, name: :index_statuses_on_account_id_id\n  end\nend\n"
  },
  {
    "path": "db/migrate/20180109143959_add_remember_token_to_users.rb",
    "content": "class AddRememberTokenToUsers < ActiveRecord::Migration[5.1]\n  def change\n    add_column :users, :remember_token, :string, null: true\n  end\nend\n"
  },
  {
    "path": "db/migrate/20180204034416_create_identities.rb",
    "content": "class CreateIdentities < ActiveRecord::Migration[5.0]\n  def change\n    create_table :identities do |t|\n      t.references :user, foreign_key: { on_delete: :cascade }\n      t.string :provider, null: false, default: ''\n      t.string :uid, null: false, default: ''\n\n      t.timestamps\n    end\n  end\nend\n"
  },
  {
    "path": "db/migrate/20180206000000_change_user_id_nonnullable.rb",
    "content": "class ChangeUserIdNonnullable < ActiveRecord::Migration[5.1]\n  def change\n    change_column_null :invites, :user_id, false\n    change_column_null :web_settings, :user_id, false\n  end\nend\n"
  },
  {
    "path": "db/migrate/20180211015820_create_backups.rb",
    "content": "class CreateBackups < ActiveRecord::Migration[5.1]\n  def change\n    create_table :backups do |t|\n      t.references :user, foreign_key: { on_delete: :nullify }\n      t.attachment :dump\n      t.boolean :processed, null: false, default: false\n\n      t.timestamps\n    end\n  end\nend\n"
  },
  {
    "path": "db/migrate/20180304013859_add_featured_collection_url_to_accounts.rb",
    "content": "class AddFeaturedCollectionUrlToAccounts < ActiveRecord::Migration[5.1]\n  def change\n    add_column :accounts, :featured_collection_url, :string\n  end\nend\n"
  },
  {
    "path": "db/migrate/20180310000000_change_columns_in_notifications_nonnullable.rb",
    "content": "class ChangeColumnsInNotificationsNonnullable < ActiveRecord::Migration[5.1]\n  def change\n    change_column_null :notifications, :activity_id, false\n    change_column_null :notifications, :activity_type, false\n    change_column_null :notifications, :account_id, false\n    change_column_null :notifications, :from_account_id, false\n  end\nend\n"
  },
  {
    "path": "db/migrate/20180402031200_add_assigned_account_id_to_reports.rb",
    "content": "class AddAssignedAccountIdToReports < ActiveRecord::Migration[5.1]\n  def change\n    add_reference :reports, :assigned_account, null: true, default: nil, foreign_key: { on_delete: :nullify, to_table: :accounts }, index: false\n  end\nend\n"
  },
  {
    "path": "db/migrate/20180402040909_create_report_notes.rb",
    "content": "class CreateReportNotes < ActiveRecord::Migration[5.1]\n  def change\n    create_table :report_notes do |t|\n      t.text :content, null: false\n      t.references :report, null: false\n      t.references :account, null: false\n\n      t.timestamps\n    end\n\n    safety_assured { add_foreign_key :report_notes, :reports, column: :report_id, on_delete: :cascade }\n    safety_assured { add_foreign_key :report_notes, :accounts, column: :account_id, on_delete: :cascade }\n  end\nend\n"
  },
  {
    "path": "db/migrate/20180410204633_add_fields_to_accounts.rb",
    "content": "class AddFieldsToAccounts < ActiveRecord::Migration[5.1]\n  def change\n    add_column :accounts, :fields, :jsonb\n  end\nend\n"
  },
  {
    "path": "db/migrate/20180416210259_add_uri_to_relationships.rb",
    "content": "class AddUriToRelationships < ActiveRecord::Migration[5.2]\n  def change\n    add_column :follows, :uri, :string\n    add_column :follow_requests, :uri, :string\n    add_column :blocks, :uri, :string\n  end\nend\n"
  },
  {
    "path": "db/migrate/20180506221944_add_actor_type_to_accounts.rb",
    "content": "class AddActorTypeToAccounts < ActiveRecord::Migration[5.2]\n  def change\n    add_column :accounts, :actor_type, :string\n  end\nend\n"
  },
  {
    "path": "db/migrate/20180510214435_add_access_token_id_to_web_push_subscriptions.rb",
    "content": "class AddAccessTokenIdToWebPushSubscriptions < ActiveRecord::Migration[5.2]\n  def change\n    add_reference :web_push_subscriptions, :access_token, null: true, default: nil, foreign_key: { on_delete: :cascade, to_table: :oauth_access_tokens }, index: false\n    add_reference :web_push_subscriptions, :user, null: true, default: nil, foreign_key: { on_delete: :cascade }, index: false\n  end\nend\n"
  },
  {
    "path": "db/migrate/20180510230049_migrate_web_push_subscriptions.rb",
    "content": "class MigrateWebPushSubscriptions < ActiveRecord::Migration[5.2]\n  disable_ddl_transaction!\n\n  def up\n    add_index :web_push_subscriptions, :user_id, algorithm: :concurrently\n    add_index :web_push_subscriptions, :access_token_id, algorithm: :concurrently\n  end\n\n  def down\n    remove_index :web_push_subscriptions, :user_id\n    remove_index :web_push_subscriptions, :access_token_id\n  end\nend\n"
  },
  {
    "path": "db/migrate/20180514130000_improve_index_on_statuses_for_api_v1_accounts_account_id_statuses.rb",
    "content": "# frozen_string_literal: true\n\nclass ImproveIndexOnStatusesForApiV1AccountsAccountIdStatuses < ActiveRecord::Migration[5.1]\n  disable_ddl_transaction!\n\n  def change\n  #  These changes ware reverted by migration 20180514140000.\n  #  add_index :statuses, [:account_id, :id, :visibility], where: 'visibility IN (0, 1, 2)', algorithm: :concurrently\n  #  add_index :statuses, [:account_id, :id], where: 'visibility = 3', algorithm: :concurrently\n  #  remove_index :statuses, column: [:account_id, :id, :visibility, :updated_at], order: { id: :desc }, algorithm: :concurrently, name: :index_statuses_20180106\n  end\nend\n"
  },
  {
    "path": "db/migrate/20180514140000_revert_index_change_on_statuses_for_api_v1_accounts_account_id_statuses.rb",
    "content": "# frozen_string_literal: true\n\nclass RevertIndexChangeOnStatusesForApiV1AccountsAccountIdStatuses < ActiveRecord::Migration[5.1]\n  disable_ddl_transaction!\n\n  def change\n    safety_assured do\n      add_index :statuses, [:account_id, :id, :visibility, :updated_at], order: { id: :desc }, algorithm: :concurrently, name: :index_statuses_20180106 unless index_name_exists?(:statuses, \"index_statuses_20180106\")\n    end\n\n    # These index may not exists (see migration 20180514130000)\n    remove_index :statuses, column: [:account_id, :id, :visibility], where: 'visibility IN (0, 1, 2)', algorithm: :concurrently if index_exists?(:statuses, [:account_id, :id, :visibility], where: 'visibility IN (0, 1, 2)')\n    remove_index :statuses, column: [:account_id, :id], where: 'visibility = 3', algorithm: :concurrently if index_exists?(:statuses, [\"account_id\", \"id\"], where: \"(visibility = 3)\")\n  end\nend\n"
  },
  {
    "path": "db/migrate/20180528141303_fix_accounts_unique_index.rb",
    "content": "class FixAccountsUniqueIndex < ActiveRecord::Migration[5.2]\n  class Account < ApplicationRecord\n    # Dummy class, to make migration possible across version changes\n    has_one :user, inverse_of: :account\n\n    def local?\n      domain.nil?\n    end\n\n    def acct\n      local? ? username : \"#{username}@#{domain}\"\n    end\n  end\n\n  disable_ddl_transaction!\n\n  def up\n    say ''\n    say 'WARNING: This migration may take a *long* time for large instances'\n    say 'It will *not* lock tables for any significant time, but it may run'\n    say 'for a very long time. We will pause for 10 seconds to allow you to'\n    say 'interrupt this migration if you are not ready.'\n    say ''\n    say 'This migration will irreversibly delete user accounts with duplicate'\n    say 'usernames. You may use the `rake mastodon:maintenance:find_duplicate_usernames`'\n    say 'task to manually deal with such accounts before running this migration.'\n\n    10.downto(1) do |i|\n      say \"Continuing in #{i} second#{i == 1 ? '' : 's'}...\", true\n      sleep 1\n    end\n\n    duplicates = Account.connection.select_all('SELECT string_agg(id::text, \\',\\') AS ids FROM accounts GROUP BY lower(username), lower(domain) HAVING count(*) > 1').to_hash\n\n    duplicates.each do |row|\n      deduplicate_account!(row['ids'].split(','))\n    end\n\n    remove_index :accounts, name: 'index_accounts_on_username_and_domain_lower' if index_name_exists?(:accounts, 'index_accounts_on_username_and_domain_lower')\n    safety_assured { execute 'CREATE UNIQUE INDEX CONCURRENTLY index_accounts_on_username_and_domain_lower ON accounts (lower(username), lower(domain))' }\n    remove_index :accounts, name: 'index_accounts_on_username_and_domain' if index_name_exists?(:accounts, 'index_accounts_on_username_and_domain')\n  end\n\n  def down\n    raise ActiveRecord::IrreversibleMigration\n  end\n\n  private\n\n  def deduplicate_account!(account_ids)\n    accounts          = Account.where(id: account_ids).to_a\n    accounts          = accounts.first.local? ? accounts.sort_by(&:created_at) : accounts.sort_by(&:updated_at).reverse\n    reference_account = accounts.shift\n\n    say_with_time \"Deduplicating @#{reference_account.acct} (#{accounts.size} duplicates)...\" do\n      accounts.each do |other_account|\n        if other_account.public_key == reference_account.public_key\n          # The accounts definitely point to the same resource, so\n          # it's safe to re-attribute content and relationships\n          merge_accounts!(reference_account, other_account)\n        elsif other_account.local?\n          # Since domain is in the GROUP BY clause, both accounts\n          # are always either going to be local or not local, so only\n          # one check is needed. Since we cannot support two users with\n          # the same username locally, one has to go. 😢\n          other_account.user&.destroy\n        end\n\n        other_account.destroy\n      end\n    end\n  end\n\n  def merge_accounts!(main_account, duplicate_account)\n    [Status, Mention, StatusPin, StreamEntry].each do |klass|\n      klass.where(account_id: duplicate_account.id).in_batches.update_all(account_id: main_account.id)\n    end\n\n    # Since it's the same remote resource, the remote resource likely\n    # already believes we are following/blocking, so it's safe to\n    # re-attribute the relationships too. However, during the presence\n    # of the index bug users could have *also* followed the reference\n    # account already, therefore mass update will not work and we need\n    # to check for (and skip past) uniqueness errors\n    [Favourite, Follow, FollowRequest, Block, Mute].each do |klass|\n      klass.where(account_id: duplicate_account.id).find_each do |record|\n        begin\n          record.update_attribute(:account_id, main_account.id)\n        rescue ActiveRecord::RecordNotUnique\n          next\n        end\n      end\n    end\n\n    [Follow, FollowRequest, Block, Mute].each do |klass|\n      klass.where(target_account_id: duplicate_account.id).find_each do |record|\n        begin\n          record.update_attribute(:target_account_id, main_account.id)\n        rescue ActiveRecord::RecordNotUnique\n          next\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "db/migrate/20180608213548_reject_following_blocked_users.rb",
    "content": "class RejectFollowingBlockedUsers < ActiveRecord::Migration[5.2]\n  disable_ddl_transaction!\n\n  def up\n    blocked_follows = Follow.find_by_sql(<<-SQL)\n      select f.* from follows f\n      inner join blocks b on\n        f.account_id = b.target_account_id and\n        f.target_account_id = b.account_id\n    SQL\n\n    domain_blocked_follows = Follow.find_by_sql(<<-SQL)\n      select f.* from follows f\n      inner join accounts following on f.account_id = following.id\n      inner join account_domain_blocks b on\n        lower(b.domain) = lower(following.domain) and\n        f.target_account_id = b.account_id\n    SQL\n\n    follows = (blocked_follows + domain_blocked_follows).uniq\n    say \"Destroying #{follows.size} blocked follow relationships...\"\n\n    follows.each do |follow|\n      blocked_account = follow.account\n      followed_acccount = follow.target_account\n\n      next follow.destroy! if blocked_account.local?\n\n      reject_follow_json = Oj.dump(ActivityPub::LinkedDataSignature.new(ActiveModelSerializers::SerializableResource.new(follow, serializer: ActivityPub::RejectFollowSerializer, adapter: ActivityPub::Adapter).as_json).sign!(followed_acccount))\n\n      ActivityPub::DeliveryWorker.perform_async(reject_follow_json, followed_acccount, blocked_account.inbox_url)\n\n      follow.destroy!\n    end\n  end\n\n  def down\n    raise ActiveRecord::IrreversibleMigration\n  end\nend\n"
  },
  {
    "path": "db/migrate/20180609104432_migrate_web_push_subscriptions2.rb",
    "content": "class MigrateWebPushSubscriptions2 < ActiveRecord::Migration[5.2]\n  disable_ddl_transaction!\n\n  def up\n    Web::PushSubscription.where(user_id: nil).select(:id).includes(:session_activation).find_each do |subscription|\n      if subscription.session_activation.nil?\n        subscription.delete\n      else\n        subscription.update_attribute(:user_id, subscription.session_activation.user_id)\n      end\n    end\n  end\n\n  def down\n    # Nothing to do\n  end\nend\n"
  },
  {
    "path": "db/migrate/20180615122121_add_autofollow_to_invites.rb",
    "content": "require Rails.root.join('lib', 'mastodon', 'migration_helpers')\n\nclass AddAutofollowToInvites < ActiveRecord::Migration[5.2]\n  include Mastodon::MigrationHelpers\n\n  disable_ddl_transaction!\n\n  def change\n    safety_assured do\n      add_column_with_default :invites, :autofollow, :bool, default: false, allow_null: false\n    end\n  end\n\n  def down\n    remove_column :invites, :autofollow\n  end\nend\n"
  },
  {
    "path": "db/migrate/20180616192031_add_chosen_languages_to_users.rb",
    "content": "class AddChosenLanguagesToUsers < ActiveRecord::Migration[5.2]\n  def change\n    add_column :users, :chosen_languages, :string, array: true, null: true, default: nil\n  end\nend\n"
  },
  {
    "path": "db/migrate/20180617162849_remove_unused_indexes.rb",
    "content": "class RemoveUnusedIndexes < ActiveRecord::Migration[5.2]\n  def change\n    remove_index :statuses, name: \"index_statuses_on_conversation_id\"\n    remove_index :users, name: \"index_users_on_filtered_languages\"\n    remove_index :backups, name: \"index_backups_on_user_id\"\n  end\nend\n"
  },
  {
    "path": "db/migrate/20180628181026_create_custom_filters.rb",
    "content": "class CreateCustomFilters < ActiveRecord::Migration[5.2]\n  def change\n    create_table :custom_filters do |t|\n      t.belongs_to :account, foreign_key: { on_delete: :cascade }\n      t.datetime :expires_at\n      t.text :phrase, null: false, default: ''\n      t.string :context, array: true, null: false, default: []\n      t.boolean :irreversible, null: false, default: false\n\n      t.timestamps\n    end\n  end\nend\n"
  },
  {
    "path": "db/migrate/20180707154237_add_whole_word_to_custom_filter.rb",
    "content": "require Rails.root.join('lib', 'mastodon', 'migration_helpers')\n\nclass AddWholeWordToCustomFilter < ActiveRecord::Migration[5.2]\n  include Mastodon::MigrationHelpers\n\n  disable_ddl_transaction!\n\n  def change\n    safety_assured do\n      add_column_with_default :custom_filters, :whole_word, :boolean, default: true, allow_null: false\n    end\n  end\n\n  def down\n    remove_column :custom_filters, :whole_word\n  end\nend\n"
  },
  {
    "path": "db/migrate/20180711152640_create_relays.rb",
    "content": "class CreateRelays < ActiveRecord::Migration[5.2]\n  def change\n    create_table :relays do |t|\n      t.string :inbox_url, default: '', null: false\n      t.boolean :enabled, default: false, null: false, index: true\n\n      t.string :follow_activity_id\n\n      t.timestamps\n    end\n  end\nend\n"
  },
  {
    "path": "db/migrate/20180808175627_create_account_pins.rb",
    "content": "class CreateAccountPins < ActiveRecord::Migration[5.2]\n  def change\n    create_table :account_pins do |t|\n      t.belongs_to :account, foreign_key: { on_delete: :cascade }\n      t.belongs_to :target_account, foreign_key: { on_delete: :cascade, to_table: :accounts }\n\n      t.timestamps\n    end\n\n    add_index :account_pins, [:account_id, :target_account_id], unique: true\n  end\nend\n"
  },
  {
    "path": "db/migrate/20180812123222_change_relays_enabled.rb",
    "content": "class ChangeRelaysEnabled < ActiveRecord::Migration[5.2]\n  def up\n    # The relays table is supposed to be very small,\n    # single-digit number of rows, so this should be fine\n    safety_assured do\n      add_column :relays, :state, :integer, default: 0, null: false\n\n      # At the time of this migration, no relays reject anyone, so if\n      # there are enabled ones, they are accepted\n      execute 'UPDATE relays SET state = 2 WHERE enabled = true'\n      remove_column :relays, :enabled\n    end\n  end\n\n  def down\n    remove_column :relays, :state\n    add_column :relays, :enabled, :boolean, default: false, null: false\n  end\nend\n"
  },
  {
    "path": "db/migrate/20180812162710_create_status_stats.rb",
    "content": "class CreateStatusStats < ActiveRecord::Migration[5.2]\n  def change\n    create_table :status_stats do |t|\n      t.belongs_to :status, null: false, foreign_key: { on_delete: :cascade }, index: { unique: true }\n      t.bigint :replies_count, null: false, default: 0\n      t.bigint :reblogs_count, null: false, default: 0\n      t.bigint :favourites_count, null: false, default: 0\n\n      t.timestamps\n    end\n  end\nend\n"
  },
  {
    "path": "db/migrate/20180812173710_copy_status_stats.rb",
    "content": "class CopyStatusStats < ActiveRecord::Migration[5.2]\n  disable_ddl_transaction!\n\n  def up\n    safety_assured do\n      if supports_upsert?\n        up_fast\n      else\n        up_slow\n      end\n    end\n  end\n\n  def down\n    # Nothing\n  end\n\n  private\n\n  def supports_upsert?\n    version = select_one(\"SELECT current_setting('server_version_num') AS v\")['v'].to_i\n    version >= 90500\n  end\n\n  def up_fast\n    say 'Upsert is available, importing counters using the fast method'\n\n    Status.unscoped.select('id').find_in_batches(batch_size: 5_000) do |statuses|\n      execute <<-SQL.squish\n        INSERT INTO status_stats (status_id, reblogs_count, favourites_count, created_at, updated_at)\n        SELECT id, reblogs_count, favourites_count, created_at, updated_at\n        FROM statuses\n        WHERE id IN (#{statuses.map(&:id).join(', ')})\n        ON CONFLICT (status_id) DO UPDATE\n        SET reblogs_count = EXCLUDED.reblogs_count, favourites_count = EXCLUDED.favourites_count\n      SQL\n    end\n  end\n\n  def up_slow\n    say 'Upsert is not available in PostgreSQL below 9.5, falling back to slow import of counters'\n\n    # We cannot use bulk INSERT or overarching transactions here because of possible\n    # uniqueness violations that we need to skip over\n    Status.unscoped.select('id, reblogs_count, favourites_count, created_at, updated_at').find_each do |status|\n      begin\n        params = [[nil, status.id], [nil, status.reblogs_count], [nil, status.favourites_count], [nil, status.created_at], [nil, status.updated_at]]\n        exec_insert('INSERT INTO status_stats (status_id, reblogs_count, favourites_count, created_at, updated_at) VALUES ($1, $2, $3, $4, $5)', nil, params)\n      rescue ActiveRecord::RecordNotUnique\n        next\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "db/migrate/20180814171349_add_confidential_to_doorkeeper_application.rb",
    "content": "require Rails.root.join('lib', 'mastodon', 'migration_helpers')\n\nclass AddConfidentialToDoorkeeperApplication < ActiveRecord::Migration[5.2]\n  include Mastodon::MigrationHelpers\n\n  disable_ddl_transaction!\n\n  def up\n    safety_assured do\n      add_column_with_default(\n        :oauth_applications,\n        :confidential,\n        :boolean,\n        allow_null: false,\n        default: true # maintaining backwards compatibility: require secrets\n      )\n    end\n  end\n\n  def down\n    remove_column :oauth_applications, :confidential\n  end\nend\n"
  },
  {
    "path": "db/migrate/20180820232245_add_foreign_key_indices.rb",
    "content": "# frozen_string_literal: true\n\nclass AddForeignKeyIndices < ActiveRecord::Migration[5.2]\n  disable_ddl_transaction!\n\n  def change\n    add_index :follows, :target_account_id, algorithm: :concurrently\n    add_index :blocks, :target_account_id, algorithm: :concurrently\n    add_index :mutes, :target_account_id, algorithm: :concurrently\n    add_index :notifications, :from_account_id, algorithm: :concurrently\n    add_index :accounts, :moved_to_account_id, algorithm: :concurrently\n    add_index :statuses, :in_reply_to_account_id, algorithm: :concurrently\n    add_index :session_activations, :access_token_id, algorithm: :concurrently\n    add_index :oauth_access_grants, :resource_owner_id, algorithm: :concurrently\n  end\nend\n"
  },
  {
    "path": "db/migrate/20180929222014_create_account_conversations.rb",
    "content": "class CreateAccountConversations < ActiveRecord::Migration[5.2]\n  def change\n    create_table :account_conversations do |t|\n      t.belongs_to :account, foreign_key: { on_delete: :cascade }\n      t.belongs_to :conversation, foreign_key: { on_delete: :cascade }\n      t.bigint :participant_account_ids, array: true, null: false, default: []\n      t.bigint :status_ids, array: true, null: false, default: []\n      t.bigint :last_status_id, null: true, default: nil\n      t.integer :lock_version, null: false, default: 0\n    end\n\n    add_index :account_conversations, [:account_id, :conversation_id, :participant_account_ids], unique: true, name: 'index_unique_conversations'\n  end\nend\n"
  },
  {
    "path": "db/migrate/20181007025445_create_pghero_space_stats.rb",
    "content": "class CreatePgheroSpaceStats < ActiveRecord::Migration[5.2]\n  def change\n    create_table :pghero_space_stats do |t|\n      t.text :database\n      t.text :schema\n      t.text :relation\n      t.integer :size, limit: 8\n      t.timestamp :captured_at\n    end\n\n    add_index :pghero_space_stats, [:database, :captured_at]\n  end\nend\n"
  },
  {
    "path": "db/migrate/20181010141500_add_silent_to_mentions.rb",
    "content": "require Rails.root.join('lib', 'mastodon', 'migration_helpers')\n\nclass AddSilentToMentions < ActiveRecord::Migration[5.2]\n  include Mastodon::MigrationHelpers\n\n  disable_ddl_transaction!\n\n  def up\n    safety_assured do\n      add_column_with_default(\n        :mentions,\n        :silent,\n        :boolean,\n        allow_null: false,\n        default: false\n      )\n    end\n  end\n\n  def down\n    remove_column :mentions, :silent\n  end\nend\n"
  },
  {
    "path": "db/migrate/20181017170937_add_reject_reports_to_domain_blocks.rb",
    "content": "require Rails.root.join('lib', 'mastodon', 'migration_helpers')\n\nclass AddRejectReportsToDomainBlocks < ActiveRecord::Migration[5.2]\n  include Mastodon::MigrationHelpers\n\n  disable_ddl_transaction!\n\n  def up\n    safety_assured do\n      add_column_with_default :domain_blocks, :reject_reports, :boolean, default: false, allow_null: false\n    end\n  end\n\n  def down\n    remove_column :domain_blocks, :reject_reports\n  end\nend\n"
  },
  {
    "path": "db/migrate/20181018205649_add_unread_to_account_conversations.rb",
    "content": "require Rails.root.join('lib', 'mastodon', 'migration_helpers')\n\nclass AddUnreadToAccountConversations < ActiveRecord::Migration[5.2]\n  include Mastodon::MigrationHelpers\n\n  disable_ddl_transaction!\n\n  def up\n    safety_assured do\n      add_column_with_default(\n        :account_conversations,\n        :unread,\n        :boolean,\n        allow_null: false,\n        default: false\n      )\n    end\n  end\n\n  def down\n    remove_column :account_conversations, :unread, :boolean\n  end\nend\n"
  },
  {
    "path": "db/migrate/20181024224956_migrate_account_conversations.rb",
    "content": "class MigrateAccountConversations < ActiveRecord::Migration[5.2]\n  disable_ddl_transaction!\n\n  def up\n    say ''\n    say 'WARNING: This migration may take a *long* time for large instances'\n    say 'It will *not* lock tables for any significant time, but it may run'\n    say 'for a very long time. We will pause for 10 seconds to allow you to'\n    say 'interrupt this migration if you are not ready.'\n    say ''\n\n    10.downto(1) do |i|\n      say \"Continuing in #{i} second#{i == 1 ? '' : 's'}...\", true\n      sleep 1\n    end\n\n    migrated  = 0\n    last_time = Time.zone.now\n\n    local_direct_statuses.includes(:account, mentions: :account).find_each do |status|\n      AccountConversation.add_status(status.account, status)\n      migrated += 1\n\n      if Time.zone.now - last_time > 1\n        say_progress(migrated)\n        last_time = Time.zone.now\n      end\n    end\n\n    notifications_about_direct_statuses.includes(:account, mention: { status: [:account, mentions: :account] }).find_each do |notification|\n      AccountConversation.add_status(notification.account, notification.target_status)\n      migrated += 1\n\n      if Time.zone.now - last_time > 1\n        say_progress(migrated)\n        last_time = Time.zone.now\n      end\n    end\n  end\n\n  def down\n  end\n\n  private\n\n  def say_progress(migrated)\n    say \"Migrated #{migrated} rows\", true\n  end\n\n  def local_direct_statuses\n    Status.unscoped.local.where(visibility: :direct)\n  end\n\n  def notifications_about_direct_statuses\n    Notification.joins(mention: :status).where(activity_type: 'Mention', statuses: { visibility: :direct })\n  end\nend\n"
  },
  {
    "path": "db/migrate/20181026034033_remove_faux_remote_account_duplicates.rb",
    "content": "class RemoveFauxRemoteAccountDuplicates < ActiveRecord::Migration[5.2]\n  disable_ddl_transaction!\n\n  def up\n    local_domain = Rails.configuration.x.local_domain\n\n    # Just a safety measure to ensure that under no circumstance\n    # we will query `domain IS NULL` because that would return\n    # actually local accounts, the originals\n    return if local_domain.nil?\n\n    Account.where(domain: local_domain).in_batches.destroy_all\n  end\n\n  def down; end\nend\n"
  },
  {
    "path": "db/migrate/20181116165755_create_account_stats.rb",
    "content": "class CreateAccountStats < ActiveRecord::Migration[5.2]\n  def change\n    create_table :account_stats do |t|\n      t.belongs_to :account, null: false, foreign_key: { on_delete: :cascade }, index: { unique: true }\n      t.bigint :statuses_count, null: false, default: 0\n      t.bigint :following_count, null: false, default: 0\n      t.bigint :followers_count, null: false, default: 0\n\n      t.timestamps\n    end\n  end\nend\n"
  },
  {
    "path": "db/migrate/20181116173541_copy_account_stats.rb",
    "content": "class CopyAccountStats < ActiveRecord::Migration[5.2]\n  disable_ddl_transaction!\n\n  def up\n    safety_assured do\n      if supports_upsert?\n        up_fast\n      else\n        up_slow\n      end\n    end\n  end\n\n  def down\n    # Nothing\n  end\n\n  private\n\n  def supports_upsert?\n    version = select_one(\"SELECT current_setting('server_version_num') AS v\")['v'].to_i\n    version >= 90500\n  end\n\n  def up_fast\n    say 'Upsert is available, importing counters using the fast method'\n\n    Account.unscoped.select('id').find_in_batches(batch_size: 5_000) do |accounts|\n      execute <<-SQL.squish\n        INSERT INTO account_stats (account_id, statuses_count, following_count, followers_count, created_at, updated_at)\n        SELECT id, statuses_count, following_count, followers_count, created_at, updated_at\n        FROM accounts\n        WHERE id IN (#{accounts.map(&:id).join(', ')})\n        ON CONFLICT (account_id) DO UPDATE\n        SET statuses_count = EXCLUDED.statuses_count, following_count = EXCLUDED.following_count, followers_count = EXCLUDED.followers_count\n      SQL\n    end\n  end\n\n  def up_slow\n    say 'Upsert is not available in PostgreSQL below 9.5, falling back to slow import of counters'\n\n    # We cannot use bulk INSERT or overarching transactions here because of possible\n    # uniqueness violations that we need to skip over\n    Account.unscoped.select('id, statuses_count, following_count, followers_count, created_at, updated_at').find_each do |account|\n      begin\n        params = [[nil, account.id], [nil, account[:statuses_count]], [nil, account[:following_count]], [nil, account[:followers_count]], [nil, account.created_at], [nil, account.updated_at]]\n        exec_insert('INSERT INTO account_stats (account_id, statuses_count, following_count, followers_count, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6)', nil, params)\n      rescue ActiveRecord::RecordNotUnique\n        next\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "db/migrate/20181127130500_identity_id_to_bigint.rb",
    "content": "require Rails.root.join('lib', 'mastodon', 'migration_helpers')\n\nclass IdentityIdToBigint < ActiveRecord::Migration[5.2]\n  include Mastodon::MigrationHelpers\n\n  disable_ddl_transaction!\n\n  def up\n    safety_assured do\n      change_column_type_concurrently :identities, :id, :bigint\n      cleanup_concurrent_column_type_change :identities, :id\n\n      change_column_type_concurrently :identities, :user_id, :bigint\n      cleanup_concurrent_column_type_change :identities, :user_id\n    end\n  end\n\n  def down\n    safety_assured do\n      change_column_type_concurrently :identities, :id, :integer\n      cleanup_concurrent_column_type_change :identities, :id\n\n      change_column_type_concurrently :identities, :user_id, :integer\n      cleanup_concurrent_column_type_change :identities, :user_id\n    end\n  end\nend\n"
  },
  {
    "path": "db/migrate/20181203003808_create_accounts_tags_join_table.rb",
    "content": "class CreateAccountsTagsJoinTable < ActiveRecord::Migration[5.2]\n  def change\n    create_join_table :accounts, :tags do |t|\n      t.index [:account_id, :tag_id]\n      t.index [:tag_id, :account_id], unique: true\n    end\n  end\nend\n"
  },
  {
    "path": "db/migrate/20181203021853_add_discoverable_to_accounts.rb",
    "content": "class AddDiscoverableToAccounts < ActiveRecord::Migration[5.2]\n  def change\n    add_column :accounts, :discoverable, :boolean\n  end\nend\n"
  },
  {
    "path": "db/migrate/20181204193439_add_last_status_at_to_account_stats.rb",
    "content": "class AddLastStatusAtToAccountStats < ActiveRecord::Migration[5.2]\n  def change\n    add_column :account_stats, :last_status_at, :datetime\n  end\nend\n"
  },
  {
    "path": "db/migrate/20181204215309_create_account_tag_stats.rb",
    "content": "class CreateAccountTagStats < ActiveRecord::Migration[5.2]\n  def change\n    create_table :account_tag_stats do |t|\n      t.belongs_to :tag, null: false, foreign_key: { on_delete: :cascade }, index: { unique: true }\n      t.bigint :accounts_count, default: 0, null: false\n      t.boolean :hidden, default: false, null: false\n\n      t.timestamps\n    end\n  end\nend\n"
  },
  {
    "path": "db/migrate/20181207011115_downcase_custom_emoji_domains.rb",
    "content": "class DowncaseCustomEmojiDomains < ActiveRecord::Migration[5.2]\n  disable_ddl_transaction!\n\n  def up\n    duplicates = CustomEmoji.connection.select_all('SELECT string_agg(id::text, \\',\\') AS ids FROM custom_emojis GROUP BY shortcode, lower(domain) HAVING count(*) > 1').to_hash\n\n    duplicates.each do |row|\n      CustomEmoji.where(id: row['ids'].split(',')[0...-1]).destroy_all\n    end\n\n    CustomEmoji.in_batches.update_all('domain = lower(domain)')\n  end\n\n  def down; end\nend\n"
  },
  {
    "path": "db/migrate/20181213184704_create_account_warnings.rb",
    "content": "class CreateAccountWarnings < ActiveRecord::Migration[5.2]\n  def change\n    create_table :account_warnings do |t|\n      t.belongs_to :account, foreign_key: { on_delete: :nullify }\n      t.belongs_to :target_account, foreign_key: { to_table: 'accounts', on_delete: :cascade }\n      t.integer :action, null: false, default: 0\n      t.text :text, null: false, default: ''\n\n      t.timestamps\n    end\n  end\nend\n"
  },
  {
    "path": "db/migrate/20181213185533_create_account_warning_presets.rb",
    "content": "class CreateAccountWarningPresets < ActiveRecord::Migration[5.2]\n  def change\n    create_table :account_warning_presets do |t|\n      t.text :text, null: false, default: ''\n\n      t.timestamps\n    end\n  end\nend\n"
  },
  {
    "path": "db/migrate/20181219235220_add_created_by_application_id_to_users.rb",
    "content": "class AddCreatedByApplicationIdToUsers < ActiveRecord::Migration[5.2]\n  disable_ddl_transaction!\n\n  def change\n    add_reference :users, :created_by_application, foreign_key: { to_table: 'oauth_applications', on_delete: :nullify }, index: false\n    add_index :users, :created_by_application_id, algorithm: :concurrently\n  end\nend\n"
  },
  {
    "path": "db/migrate/20181226021420_add_also_known_as_to_accounts.rb",
    "content": "class AddAlsoKnownAsToAccounts < ActiveRecord::Migration[5.2]\n  def change\n    add_column :accounts, :also_known_as, :string, array: true\n  end\nend\n"
  },
  {
    "path": "db/migrate/20190103124649_create_scheduled_statuses.rb",
    "content": "class CreateScheduledStatuses < ActiveRecord::Migration[5.2]\n  def change\n    create_table :scheduled_statuses do |t|\n      t.belongs_to :account, foreign_key: { on_delete: :cascade }\n      t.datetime :scheduled_at, index: true\n      t.jsonb :params\n    end\n  end\nend\n"
  },
  {
    "path": "db/migrate/20190103124754_add_scheduled_status_id_to_media_attachments.rb",
    "content": "class AddScheduledStatusIdToMediaAttachments < ActiveRecord::Migration[5.2]\n  disable_ddl_transaction!\n\n  def change\n    add_reference :media_attachments, :scheduled_status, foreign_key: { on_delete: :nullify }, index: false\n    add_index :media_attachments, :scheduled_status_id, algorithm: :concurrently\n  end\nend\n"
  },
  {
    "path": "db/migrate/20190117114553_create_tombstones.rb",
    "content": "class CreateTombstones < ActiveRecord::Migration[5.2]\n  def change\n    create_table :tombstones do |t|\n      t.belongs_to :account, foreign_key: { on_delete: :cascade }\n      t.string :uri, null: false\n\n      t.timestamps\n    end\n\n    add_index :tombstones, :uri\n  end\nend\n"
  },
  {
    "path": "db/migrate/20190201012802_add_overwrite_to_imports.rb",
    "content": "require Rails.root.join('lib', 'mastodon', 'migration_helpers')\n\nclass AddOverwriteToImports < ActiveRecord::Migration[5.2]\n  include Mastodon::MigrationHelpers\n\n  disable_ddl_transaction!\n\n  def up\n    safety_assured do\n      add_column_with_default :imports, :overwrite, :boolean, default: false, allow_null: false\n    end\n  end\n\n  def down\n    remove_column :imports, :overwrite, :boolean\n  end\nend\n"
  },
  {
    "path": "db/migrate/20190203180359_create_featured_tags.rb",
    "content": "class CreateFeaturedTags < ActiveRecord::Migration[5.2]\n  def change\n    create_table :featured_tags do |t|\n      t.references :account, foreign_key: { on_delete: :cascade }\n      t.references :tag, foreign_key: { on_delete: :cascade }\n      t.bigint :statuses_count, default: 0, null: false\n      t.datetime :last_status_at\n\n      t.timestamps\n    end\n  end\nend\n"
  },
  {
    "path": "db/migrate/20190225031541_create_polls.rb",
    "content": "class CreatePolls < ActiveRecord::Migration[5.2]\n  def change\n    create_table :polls do |t|\n      t.belongs_to :account, foreign_key: { on_delete: :cascade }\n      t.belongs_to :status, foreign_key: { on_delete: :cascade }\n      t.datetime :expires_at\n      t.string :options, null: false, array: true, default: []\n      t.bigint :cached_tallies, null: false, array: true, default: []\n      t.boolean :multiple, null: false, default: false\n      t.boolean :hide_totals, null: false, default: false\n      t.bigint :votes_count, null: false, default: 0\n      t.datetime :last_fetched_at\n\n      t.timestamps\n    end\n  end\nend\n"
  },
  {
    "path": "db/migrate/20190225031625_create_poll_votes.rb",
    "content": "class CreatePollVotes < ActiveRecord::Migration[5.2]\n  def change\n    create_table :poll_votes do |t|\n      t.belongs_to :account, foreign_key: { on_delete: :cascade }\n      t.belongs_to :poll, foreign_key: { on_delete: :cascade }\n      t.integer :choice, null: false, default: 0\n\n      t.timestamps\n    end\n  end\nend\n"
  },
  {
    "path": "db/migrate/20190226003449_add_poll_id_to_statuses.rb",
    "content": "class AddPollIdToStatuses < ActiveRecord::Migration[5.2]\n  def change\n    add_column :statuses, :poll_id, :bigint\n  end\nend\n"
  },
  {
    "path": "db/migrate/20190304152020_add_uri_to_poll_votes.rb",
    "content": "class AddUriToPollVotes < ActiveRecord::Migration[5.2]\n  def change\n    add_column :poll_votes, :uri, :string\n  end\nend\n"
  },
  {
    "path": "db/migrate/20190306145741_add_lock_version_to_polls.rb",
    "content": "require Rails.root.join('lib', 'mastodon', 'migration_helpers')\n\nclass AddLockVersionToPolls < ActiveRecord::Migration[5.2]\n  include Mastodon::MigrationHelpers\n\n  disable_ddl_transaction!\n\n  def up\n    safety_assured do\n      add_column_with_default(\n        :polls,\n        :lock_version,\n        :integer,\n        allow_null: false,\n        default: 0\n      )\n    end\n  end\n\n  def down\n    remove_column :polls, :lock_version\n  end\nend\n\n"
  },
  {
    "path": "db/migrate/20190307234537_add_approved_to_users.rb",
    "content": "require Rails.root.join('lib', 'mastodon', 'migration_helpers')\n\nclass AddApprovedToUsers < ActiveRecord::Migration[5.2]\n  include Mastodon::MigrationHelpers\n\n  disable_ddl_transaction!\n\n  def up\n    safety_assured do\n      add_column_with_default(\n        :users,\n        :approved,\n        :bool,\n        allow_null: false,\n        default: true\n      )\n    end\n  end\n\n  def down\n    remove_column :users, :approved\n  end\nend\n"
  },
  {
    "path": "db/migrate/20190314181829_migrate_open_registrations_setting.rb",
    "content": "class MigrateOpenRegistrationsSetting < ActiveRecord::Migration[5.2]\n  def up\n    open_registrations = Setting.find_by(var: 'open_registrations')\n    return if open_registrations.nil? || open_registrations.value\n    setting = Setting.where(var: 'registrations_mode').first_or_initialize(var: 'registrations_mode')\n    setting.update(value: 'none')\n  end\n\n  def down\n    registrations_mode = Setting.find_by(var: 'registrations_mode')\n    return if registrations_mode.nil?\n    setting = Setting.where(var: 'open_registrations').first_or_initialize(var: 'open_registrations')\n    setting.update(value: registrations_mode.value == 'open')\n  end\nend\n"
  },
  {
    "path": "db/migrate/20190316190352_create_account_identity_proofs.rb",
    "content": "class CreateAccountIdentityProofs < ActiveRecord::Migration[5.2]\n  def change\n    create_table :account_identity_proofs do |t|\n      t.belongs_to :account, foreign_key: { on_delete: :cascade }\n      t.string :provider, null: false, default: ''\n      t.string :provider_username, null: false, default: ''\n      t.text :token, null: false, default: ''\n      t.boolean :verified, null: false, default: false\n      t.boolean :live, null: false, default: false\n\n      t.timestamps null: false\n    end\n\n    add_index :account_identity_proofs, [:account_id, :provider, :provider_username], unique: true, name: :index_account_proofs_on_account_and_provider_and_username\n  end\nend\n"
  },
  {
    "path": "db/migrate/20190317135723_add_uri_to_reports.rb",
    "content": "class AddUriToReports < ActiveRecord::Migration[5.2]\n  def change\n    add_column :reports, :uri, :string\n  end\nend\n"
  },
  {
    "path": "db/migrate/20190409054914_create_user_invite_requests.rb",
    "content": "class CreateUserInviteRequests < ActiveRecord::Migration[5.2]\n  def change\n    create_table :user_invite_requests do |t|\n      t.belongs_to :user, foreign_key: { on_delete: :cascade }\n      t.text :text\n\n      t.timestamps\n    end\n  end\nend\n"
  },
  {
    "path": "db/migrate/20190420025523_add_blurhash_to_media_attachments.rb",
    "content": "class AddBlurhashToMediaAttachments < ActiveRecord::Migration[5.2]\n  def change\n    add_column :media_attachments, :blurhash, :string\n  end\nend\n"
  },
  {
    "path": "db/migrate/20190509164208_add_by_moderator_to_tombstone.rb",
    "content": "class AddByModeratorToTombstone < ActiveRecord::Migration[5.2]\n  def change\n    add_column :tombstones, :by_moderator, :boolean\n  end\nend\n"
  },
  {
    "path": "db/migrate/20190511134027_add_silenced_at_suspended_at_to_accounts.rb",
    "content": "class AddSilencedAtSuspendedAtToAccounts < ActiveRecord::Migration[5.2]\n  class Account < ApplicationRecord\n    # Dummy class, to make migration possible across version changes\n  end\n\n  class DomainBlock < ApplicationRecord\n    # Dummy class, to make migration possible across version changes\n    enum severity: [:silence, :suspend, :noop]\n\n    has_many :accounts, foreign_key: :domain, primary_key: :domain\n  end\n\n  def up\n    add_column :accounts, :silenced_at, :datetime\n    add_column :accounts, :suspended_at, :datetime\n\n    # Record suspend date of blocks and silences for users whose limitations match\n    # a domain block\n    DomainBlock.where(severity: [:silence, :suspend]).find_each do |block|\n      scope = block.accounts\n      if block.suspend?\n        block.accounts.where(suspended: true).in_batches.update_all(suspended_at: block.created_at)\n      else\n        block.accounts.where(silenced: true).in_batches.update_all(silenced_at: block.created_at)\n      end\n    end\n\n    # Set dates for accounts which have limitations not related to a domain block\n    Account.where(suspended: true, suspended_at: nil).in_batches.update_all(suspended_at: Time.now.utc)\n    Account.where(silenced: true, silenced_at: nil).in_batches.update_all(silenced_at: Time.now.utc)\n  end\n\n  def down\n    # Block or silence accounts that have a date set\n    Account.where(suspended: false).where.not(suspended_at: nil).in_batches.update_all(suspended: true)\n    Account.where(silenced: false).where.not(silenced_at: nil).in_batches.update_all(silenced: true)\n\n    remove_column :accounts, :silenced_at\n    remove_column :accounts, :suspended_at\n  end\nend\n"
  },
  {
    "path": "db/migrate/20190529143559_preserve_old_layout_for_existing_users.rb",
    "content": "class PreserveOldLayoutForExistingUsers < ActiveRecord::Migration[5.2]\n  disable_ddl_transaction!\n\n  def up\n    # Assume that currently active users are already using the layout that they\n    # want to use, therefore ensure that it is saved explicitly and not based\n    # on the to-be-changed default\n\n    User.where(User.arel_table[:current_sign_in_at].gteq(1.month.ago)).find_each do |user|\n      next if Setting.unscoped.where(thing_type: 'User', thing_id: user.id, var: 'advanced_layout').exists?\n      user.settings.advanced_layout = true\n    end\n  end\n\n  def down\n  end\nend\n"
  },
  {
    "path": "db/post_migrate/.gitkeep",
    "content": ""
  },
  {
    "path": "db/post_migrate/20180813113448_copy_status_stats_cleanup.rb",
    "content": "# frozen_string_literal: true\n\nclass CopyStatusStatsCleanup < ActiveRecord::Migration[5.2]\n  disable_ddl_transaction!\n\n  def change\n    safety_assured do\n      remove_column :statuses, :reblogs_count, :integer, default: 0, null: false\n      remove_column :statuses, :favourites_count, :integer, default: 0, null: false\n    end\n  end\nend\n"
  },
  {
    "path": "db/post_migrate/20181116184611_copy_account_stats_cleanup.rb",
    "content": "# frozen_string_literal: true\n\nclass CopyAccountStatsCleanup < ActiveRecord::Migration[5.2]\n  disable_ddl_transaction!\n\n  def change\n    safety_assured do\n      remove_column :accounts, :statuses_count, :integer, default: 0, null: false\n      remove_column :accounts, :following_count, :integer, default: 0, null: false\n      remove_column :accounts, :followers_count, :integer, default: 0, null: false\n    end\n  end\nend\n"
  },
  {
    "path": "db/post_migrate/20190511152737_remove_suspended_silenced_account_fields.rb",
    "content": "# frozen_string_literal: true\n\nclass RemoveSuspendedSilencedAccountFields < ActiveRecord::Migration[5.2]\n  class Account < ApplicationRecord\n    # Dummy class, to make migration possible across version changes\n  end\n\n  class DomainBlock < ApplicationRecord\n    # Dummy class, to make migration possible across version changes\n    enum severity: [:silence, :suspend, :noop]\n\n    has_many :accounts, foreign_key: :domain, primary_key: :domain\n  end\n\n  disable_ddl_transaction!\n\n  def up\n    # Record suspend date of blocks and silences for users whose limitations match\n    # a domain block\n    DomainBlock.where(severity: [:silence, :suspend]).find_each do |block|\n      scope = block.accounts\n      if block.suspend?\n        block.accounts.where(suspended: true).in_batches.update_all(suspended_at: block.created_at)\n      else\n        block.accounts.where(silenced: true).in_batches.update_all(silenced_at: block.created_at)\n      end\n    end\n\n    # Set dates for accounts which have limitations not related to a domain block\n    Account.where(suspended: true, suspended_at: nil).in_batches.update_all(suspended_at: Time.now.utc)\n    Account.where(silenced: true, silenced_at: nil).in_batches.update_all(silenced_at: Time.now.utc)\n\n    safety_assured do\n      remove_column :accounts, :suspended, :boolean, null: false, default: false\n      remove_column :accounts, :silenced, :boolean, null: false, default: false\n    end\n  end\n\n  def down\n    safety_assured do\n      add_column :accounts, :suspended, :boolean, null: false, default: false\n      add_column :accounts, :silenced, :boolean, null: false, default: false\n    end\n  end\nend\n"
  },
  {
    "path": "db/post_migrate/20190519130537_remove_boosts_widening_audience.rb",
    "content": "class RemoveBoostsWideningAudience < ActiveRecord::Migration[5.2]\n  disable_ddl_transaction!\n\n  def up\n    public_boosts = Status.find_by_sql(<<-SQL)\n      SELECT boost.id\n      FROM statuses AS boost\n      LEFT JOIN statuses AS boosted ON boost.reblog_of_id = boosted.id\n      WHERE\n        boost.id > 101746055577600000\n        AND (boost.local = TRUE OR boost.uri IS NULL)\n        AND boost.visibility IN (0, 1)\n        AND boost.reblog_of_id IS NOT NULL\n        AND boosted.visibility = 2\n    SQL\n\n    RemovalWorker.push_bulk(public_boosts.pluck(:id))\n  end\n\n  def down\n    raise ActiveRecord::IrreversibleMigration\n  end\nend\n"
  },
  {
    "path": "db/schema.rb",
    "content": "# This file is auto-generated from the current state of the database. Instead\n# of editing this file, please use the migrations feature of Active Record to\n# incrementally modify your database, and then regenerate this schema definition.\n#\n# Note that this schema.rb definition is the authoritative source for your\n# database schema. If you need to create the application database on another\n# system, you should be using db:schema:load, not running all the migrations\n# from scratch. The latter is a flawed and unsustainable approach (the more migrations\n# you'll amass, the slower it'll run and the greater likelihood for issues).\n#\n# It's strongly recommended that you check this file into your version control system.\n\nActiveRecord::Schema.define(version: 2019_05_29_143559) do\n\n  # These are extensions that must be enabled in order to support this database\n  enable_extension \"plpgsql\"\n\n  create_table \"account_conversations\", force: :cascade do |t|\n    t.bigint \"account_id\"\n    t.bigint \"conversation_id\"\n    t.bigint \"participant_account_ids\", default: [], null: false, array: true\n    t.bigint \"status_ids\", default: [], null: false, array: true\n    t.bigint \"last_status_id\"\n    t.integer \"lock_version\", default: 0, null: false\n    t.boolean \"unread\", default: false, null: false\n    t.index [\"account_id\", \"conversation_id\", \"participant_account_ids\"], name: \"index_unique_conversations\", unique: true\n    t.index [\"account_id\"], name: \"index_account_conversations_on_account_id\"\n    t.index [\"conversation_id\"], name: \"index_account_conversations_on_conversation_id\"\n  end\n\n  create_table \"account_domain_blocks\", force: :cascade do |t|\n    t.string \"domain\"\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.bigint \"account_id\"\n    t.index [\"account_id\", \"domain\"], name: \"index_account_domain_blocks_on_account_id_and_domain\", unique: true\n  end\n\n  create_table \"account_identity_proofs\", force: :cascade do |t|\n    t.bigint \"account_id\"\n    t.string \"provider\", default: \"\", null: false\n    t.string \"provider_username\", default: \"\", null: false\n    t.text \"token\", default: \"\", null: false\n    t.boolean \"verified\", default: false, null: false\n    t.boolean \"live\", default: false, null: false\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.index [\"account_id\", \"provider\", \"provider_username\"], name: \"index_account_proofs_on_account_and_provider_and_username\", unique: true\n    t.index [\"account_id\"], name: \"index_account_identity_proofs_on_account_id\"\n  end\n\n  create_table \"account_moderation_notes\", force: :cascade do |t|\n    t.text \"content\", null: false\n    t.bigint \"account_id\", null: false\n    t.bigint \"target_account_id\", null: false\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.index [\"account_id\"], name: \"index_account_moderation_notes_on_account_id\"\n    t.index [\"target_account_id\"], name: \"index_account_moderation_notes_on_target_account_id\"\n  end\n\n  create_table \"account_pins\", force: :cascade do |t|\n    t.bigint \"account_id\"\n    t.bigint \"target_account_id\"\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.index [\"account_id\", \"target_account_id\"], name: \"index_account_pins_on_account_id_and_target_account_id\", unique: true\n    t.index [\"account_id\"], name: \"index_account_pins_on_account_id\"\n    t.index [\"target_account_id\"], name: \"index_account_pins_on_target_account_id\"\n  end\n\n  create_table \"account_stats\", force: :cascade do |t|\n    t.bigint \"account_id\", null: false\n    t.bigint \"statuses_count\", default: 0, null: false\n    t.bigint \"following_count\", default: 0, null: false\n    t.bigint \"followers_count\", default: 0, null: false\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.datetime \"last_status_at\"\n    t.index [\"account_id\"], name: \"index_account_stats_on_account_id\", unique: true\n  end\n\n  create_table \"account_tag_stats\", force: :cascade do |t|\n    t.bigint \"tag_id\", null: false\n    t.bigint \"accounts_count\", default: 0, null: false\n    t.boolean \"hidden\", default: false, null: false\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.index [\"tag_id\"], name: \"index_account_tag_stats_on_tag_id\", unique: true\n  end\n\n  create_table \"account_warning_presets\", force: :cascade do |t|\n    t.text \"text\", default: \"\", null: false\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n  end\n\n  create_table \"account_warnings\", force: :cascade do |t|\n    t.bigint \"account_id\"\n    t.bigint \"target_account_id\"\n    t.integer \"action\", default: 0, null: false\n    t.text \"text\", default: \"\", null: false\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.index [\"account_id\"], name: \"index_account_warnings_on_account_id\"\n    t.index [\"target_account_id\"], name: \"index_account_warnings_on_target_account_id\"\n  end\n\n  create_table \"accounts\", force: :cascade do |t|\n    t.string \"username\", default: \"\", null: false\n    t.string \"domain\"\n    t.string \"secret\", default: \"\", null: false\n    t.text \"private_key\"\n    t.text \"public_key\", default: \"\", null: false\n    t.string \"remote_url\", default: \"\", null: false\n    t.string \"salmon_url\", default: \"\", null: false\n    t.string \"hub_url\", default: \"\", null: false\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.text \"note\", default: \"\", null: false\n    t.string \"display_name\", default: \"\", null: false\n    t.string \"uri\", default: \"\", null: false\n    t.string \"url\"\n    t.string \"avatar_file_name\"\n    t.string \"avatar_content_type\"\n    t.integer \"avatar_file_size\"\n    t.datetime \"avatar_updated_at\"\n    t.string \"header_file_name\"\n    t.string \"header_content_type\"\n    t.integer \"header_file_size\"\n    t.datetime \"header_updated_at\"\n    t.string \"avatar_remote_url\"\n    t.datetime \"subscription_expires_at\"\n    t.boolean \"locked\", default: false, null: false\n    t.string \"header_remote_url\", default: \"\", null: false\n    t.datetime \"last_webfingered_at\"\n    t.string \"inbox_url\", default: \"\", null: false\n    t.string \"outbox_url\", default: \"\", null: false\n    t.string \"shared_inbox_url\", default: \"\", null: false\n    t.string \"followers_url\", default: \"\", null: false\n    t.integer \"protocol\", default: 0, null: false\n    t.boolean \"memorial\", default: false, null: false\n    t.bigint \"moved_to_account_id\"\n    t.string \"featured_collection_url\"\n    t.jsonb \"fields\"\n    t.string \"actor_type\"\n    t.boolean \"discoverable\"\n    t.string \"also_known_as\", array: true\n    t.datetime \"silenced_at\"\n    t.datetime \"suspended_at\"\n    t.index \"(((setweight(to_tsvector('simple'::regconfig, (display_name)::text), 'A'::\\\"char\\\") || setweight(to_tsvector('simple'::regconfig, (username)::text), 'B'::\\\"char\\\")) || setweight(to_tsvector('simple'::regconfig, (COALESCE(domain, ''::character varying))::text), 'C'::\\\"char\\\")))\", name: \"search_index\", using: :gin\n    t.index \"lower((username)::text), lower((domain)::text)\", name: \"index_accounts_on_username_and_domain_lower\", unique: true\n    t.index [\"moved_to_account_id\"], name: \"index_accounts_on_moved_to_account_id\"\n    t.index [\"uri\"], name: \"index_accounts_on_uri\"\n    t.index [\"url\"], name: \"index_accounts_on_url\"\n  end\n\n  create_table \"accounts_tags\", id: false, force: :cascade do |t|\n    t.bigint \"account_id\", null: false\n    t.bigint \"tag_id\", null: false\n    t.index [\"account_id\", \"tag_id\"], name: \"index_accounts_tags_on_account_id_and_tag_id\"\n    t.index [\"tag_id\", \"account_id\"], name: \"index_accounts_tags_on_tag_id_and_account_id\", unique: true\n  end\n\n  create_table \"admin_action_logs\", force: :cascade do |t|\n    t.bigint \"account_id\"\n    t.string \"action\", default: \"\", null: false\n    t.string \"target_type\"\n    t.bigint \"target_id\"\n    t.text \"recorded_changes\", default: \"\", null: false\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.index [\"account_id\"], name: \"index_admin_action_logs_on_account_id\"\n    t.index [\"target_type\", \"target_id\"], name: \"index_admin_action_logs_on_target_type_and_target_id\"\n  end\n\n  create_table \"backups\", force: :cascade do |t|\n    t.bigint \"user_id\"\n    t.string \"dump_file_name\"\n    t.string \"dump_content_type\"\n    t.integer \"dump_file_size\"\n    t.datetime \"dump_updated_at\"\n    t.boolean \"processed\", default: false, null: false\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n  end\n\n  create_table \"blocks\", force: :cascade do |t|\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.bigint \"account_id\", null: false\n    t.bigint \"target_account_id\", null: false\n    t.string \"uri\"\n    t.index [\"account_id\", \"target_account_id\"], name: \"index_blocks_on_account_id_and_target_account_id\", unique: true\n    t.index [\"target_account_id\"], name: \"index_blocks_on_target_account_id\"\n  end\n\n  create_table \"conversation_mutes\", force: :cascade do |t|\n    t.bigint \"conversation_id\", null: false\n    t.bigint \"account_id\", null: false\n    t.index [\"account_id\", \"conversation_id\"], name: \"index_conversation_mutes_on_account_id_and_conversation_id\", unique: true\n  end\n\n  create_table \"conversations\", force: :cascade do |t|\n    t.string \"uri\"\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.index [\"uri\"], name: \"index_conversations_on_uri\", unique: true\n  end\n\n  create_table \"custom_emojis\", force: :cascade do |t|\n    t.string \"shortcode\", default: \"\", null: false\n    t.string \"domain\"\n    t.string \"image_file_name\"\n    t.string \"image_content_type\"\n    t.integer \"image_file_size\"\n    t.datetime \"image_updated_at\"\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.boolean \"disabled\", default: false, null: false\n    t.string \"uri\"\n    t.string \"image_remote_url\"\n    t.boolean \"visible_in_picker\", default: true, null: false\n    t.index [\"shortcode\", \"domain\"], name: \"index_custom_emojis_on_shortcode_and_domain\", unique: true\n  end\n\n  create_table \"custom_filters\", force: :cascade do |t|\n    t.bigint \"account_id\"\n    t.datetime \"expires_at\"\n    t.text \"phrase\", default: \"\", null: false\n    t.string \"context\", default: [], null: false, array: true\n    t.boolean \"irreversible\", default: false, null: false\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.boolean \"whole_word\", default: true, null: false\n    t.index [\"account_id\"], name: \"index_custom_filters_on_account_id\"\n  end\n\n  create_table \"domain_blocks\", force: :cascade do |t|\n    t.string \"domain\", default: \"\", null: false\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.integer \"severity\", default: 0\n    t.boolean \"reject_media\", default: false, null: false\n    t.boolean \"reject_reports\", default: false, null: false\n    t.index [\"domain\"], name: \"index_domain_blocks_on_domain\", unique: true\n  end\n\n  create_table \"email_domain_blocks\", force: :cascade do |t|\n    t.string \"domain\", default: \"\", null: false\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.index [\"domain\"], name: \"index_email_domain_blocks_on_domain\", unique: true\n  end\n\n  create_table \"favourites\", force: :cascade do |t|\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.bigint \"account_id\", null: false\n    t.bigint \"status_id\", null: false\n    t.index [\"account_id\", \"id\"], name: \"index_favourites_on_account_id_and_id\"\n    t.index [\"account_id\", \"status_id\"], name: \"index_favourites_on_account_id_and_status_id\", unique: true\n    t.index [\"status_id\"], name: \"index_favourites_on_status_id\"\n  end\n\n  create_table \"featured_tags\", force: :cascade do |t|\n    t.bigint \"account_id\"\n    t.bigint \"tag_id\"\n    t.bigint \"statuses_count\", default: 0, null: false\n    t.datetime \"last_status_at\"\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.index [\"account_id\"], name: \"index_featured_tags_on_account_id\"\n    t.index [\"tag_id\"], name: \"index_featured_tags_on_tag_id\"\n  end\n\n  create_table \"follow_requests\", force: :cascade do |t|\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.bigint \"account_id\", null: false\n    t.bigint \"target_account_id\", null: false\n    t.boolean \"show_reblogs\", default: true, null: false\n    t.string \"uri\"\n    t.index [\"account_id\", \"target_account_id\"], name: \"index_follow_requests_on_account_id_and_target_account_id\", unique: true\n  end\n\n  create_table \"follows\", force: :cascade do |t|\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.bigint \"account_id\", null: false\n    t.bigint \"target_account_id\", null: false\n    t.boolean \"show_reblogs\", default: true, null: false\n    t.string \"uri\"\n    t.index [\"account_id\", \"target_account_id\"], name: \"index_follows_on_account_id_and_target_account_id\", unique: true\n    t.index [\"target_account_id\"], name: \"index_follows_on_target_account_id\"\n  end\n\n  create_table \"identities\", force: :cascade do |t|\n    t.string \"provider\", default: \"\", null: false\n    t.string \"uid\", default: \"\", null: false\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.bigint \"user_id\"\n    t.index [\"user_id\"], name: \"index_identities_on_user_id\"\n  end\n\n  create_table \"imports\", force: :cascade do |t|\n    t.integer \"type\", null: false\n    t.boolean \"approved\", default: false, null: false\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.string \"data_file_name\"\n    t.string \"data_content_type\"\n    t.integer \"data_file_size\"\n    t.datetime \"data_updated_at\"\n    t.bigint \"account_id\", null: false\n    t.boolean \"overwrite\", default: false, null: false\n  end\n\n  create_table \"invites\", force: :cascade do |t|\n    t.bigint \"user_id\", null: false\n    t.string \"code\", default: \"\", null: false\n    t.datetime \"expires_at\"\n    t.integer \"max_uses\"\n    t.integer \"uses\", default: 0, null: false\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.boolean \"autofollow\", default: false, null: false\n    t.index [\"code\"], name: \"index_invites_on_code\", unique: true\n    t.index [\"user_id\"], name: \"index_invites_on_user_id\"\n  end\n\n  create_table \"list_accounts\", force: :cascade do |t|\n    t.bigint \"list_id\", null: false\n    t.bigint \"account_id\", null: false\n    t.bigint \"follow_id\", null: false\n    t.index [\"account_id\", \"list_id\"], name: \"index_list_accounts_on_account_id_and_list_id\", unique: true\n    t.index [\"follow_id\"], name: \"index_list_accounts_on_follow_id\"\n    t.index [\"list_id\", \"account_id\"], name: \"index_list_accounts_on_list_id_and_account_id\"\n  end\n\n  create_table \"lists\", force: :cascade do |t|\n    t.bigint \"account_id\", null: false\n    t.string \"title\", default: \"\", null: false\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.index [\"account_id\"], name: \"index_lists_on_account_id\"\n  end\n\n  create_table \"media_attachments\", force: :cascade do |t|\n    t.bigint \"status_id\"\n    t.string \"file_file_name\"\n    t.string \"file_content_type\"\n    t.integer \"file_file_size\"\n    t.datetime \"file_updated_at\"\n    t.string \"remote_url\", default: \"\", null: false\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.string \"shortcode\"\n    t.integer \"type\", default: 0, null: false\n    t.json \"file_meta\"\n    t.bigint \"account_id\"\n    t.text \"description\"\n    t.bigint \"scheduled_status_id\"\n    t.string \"blurhash\"\n    t.index [\"account_id\"], name: \"index_media_attachments_on_account_id\"\n    t.index [\"scheduled_status_id\"], name: \"index_media_attachments_on_scheduled_status_id\"\n    t.index [\"shortcode\"], name: \"index_media_attachments_on_shortcode\", unique: true\n    t.index [\"status_id\"], name: \"index_media_attachments_on_status_id\"\n  end\n\n  create_table \"mentions\", force: :cascade do |t|\n    t.bigint \"status_id\"\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.bigint \"account_id\"\n    t.boolean \"silent\", default: false, null: false\n    t.index [\"account_id\", \"status_id\"], name: \"index_mentions_on_account_id_and_status_id\", unique: true\n    t.index [\"status_id\"], name: \"index_mentions_on_status_id\"\n  end\n\n  create_table \"mutes\", force: :cascade do |t|\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.boolean \"hide_notifications\", default: true, null: false\n    t.bigint \"account_id\", null: false\n    t.bigint \"target_account_id\", null: false\n    t.index [\"account_id\", \"target_account_id\"], name: \"index_mutes_on_account_id_and_target_account_id\", unique: true\n    t.index [\"target_account_id\"], name: \"index_mutes_on_target_account_id\"\n  end\n\n  create_table \"notifications\", force: :cascade do |t|\n    t.bigint \"activity_id\", null: false\n    t.string \"activity_type\", null: false\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.bigint \"account_id\", null: false\n    t.bigint \"from_account_id\", null: false\n    t.index [\"account_id\", \"activity_id\", \"activity_type\"], name: \"account_activity\", unique: true\n    t.index [\"account_id\", \"id\"], name: \"index_notifications_on_account_id_and_id\", order: { id: :desc }\n    t.index [\"activity_id\", \"activity_type\"], name: \"index_notifications_on_activity_id_and_activity_type\"\n    t.index [\"from_account_id\"], name: \"index_notifications_on_from_account_id\"\n  end\n\n  create_table \"oauth_access_grants\", force: :cascade do |t|\n    t.string \"token\", null: false\n    t.integer \"expires_in\", null: false\n    t.text \"redirect_uri\", null: false\n    t.datetime \"created_at\", null: false\n    t.datetime \"revoked_at\"\n    t.string \"scopes\"\n    t.bigint \"application_id\", null: false\n    t.bigint \"resource_owner_id\", null: false\n    t.index [\"resource_owner_id\"], name: \"index_oauth_access_grants_on_resource_owner_id\"\n    t.index [\"token\"], name: \"index_oauth_access_grants_on_token\", unique: true\n  end\n\n  create_table \"oauth_access_tokens\", force: :cascade do |t|\n    t.string \"token\", null: false\n    t.string \"refresh_token\"\n    t.integer \"expires_in\"\n    t.datetime \"revoked_at\"\n    t.datetime \"created_at\", null: false\n    t.string \"scopes\"\n    t.bigint \"application_id\"\n    t.bigint \"resource_owner_id\"\n    t.index [\"refresh_token\"], name: \"index_oauth_access_tokens_on_refresh_token\", unique: true\n    t.index [\"resource_owner_id\"], name: \"index_oauth_access_tokens_on_resource_owner_id\"\n    t.index [\"token\"], name: \"index_oauth_access_tokens_on_token\", unique: true\n  end\n\n  create_table \"oauth_applications\", force: :cascade do |t|\n    t.string \"name\", null: false\n    t.string \"uid\", null: false\n    t.string \"secret\", null: false\n    t.text \"redirect_uri\", null: false\n    t.string \"scopes\", default: \"\", null: false\n    t.datetime \"created_at\"\n    t.datetime \"updated_at\"\n    t.boolean \"superapp\", default: false, null: false\n    t.string \"website\"\n    t.string \"owner_type\"\n    t.bigint \"owner_id\"\n    t.boolean \"confidential\", default: true, null: false\n    t.index [\"owner_id\", \"owner_type\"], name: \"index_oauth_applications_on_owner_id_and_owner_type\"\n    t.index [\"uid\"], name: \"index_oauth_applications_on_uid\", unique: true\n  end\n\n  create_table \"pghero_space_stats\", force: :cascade do |t|\n    t.text \"database\"\n    t.text \"schema\"\n    t.text \"relation\"\n    t.bigint \"size\"\n    t.datetime \"captured_at\"\n    t.index [\"database\", \"captured_at\"], name: \"index_pghero_space_stats_on_database_and_captured_at\"\n  end\n\n  create_table \"poll_votes\", force: :cascade do |t|\n    t.bigint \"account_id\"\n    t.bigint \"poll_id\"\n    t.integer \"choice\", default: 0, null: false\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.string \"uri\"\n    t.index [\"account_id\"], name: \"index_poll_votes_on_account_id\"\n    t.index [\"poll_id\"], name: \"index_poll_votes_on_poll_id\"\n  end\n\n  create_table \"polls\", force: :cascade do |t|\n    t.bigint \"account_id\"\n    t.bigint \"status_id\"\n    t.datetime \"expires_at\"\n    t.string \"options\", default: [], null: false, array: true\n    t.bigint \"cached_tallies\", default: [], null: false, array: true\n    t.boolean \"multiple\", default: false, null: false\n    t.boolean \"hide_totals\", default: false, null: false\n    t.bigint \"votes_count\", default: 0, null: false\n    t.datetime \"last_fetched_at\"\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.integer \"lock_version\", default: 0, null: false\n    t.index [\"account_id\"], name: \"index_polls_on_account_id\"\n    t.index [\"status_id\"], name: \"index_polls_on_status_id\"\n  end\n\n  create_table \"preview_cards\", force: :cascade do |t|\n    t.string \"url\", default: \"\", null: false\n    t.string \"title\", default: \"\", null: false\n    t.string \"description\", default: \"\", null: false\n    t.string \"image_file_name\"\n    t.string \"image_content_type\"\n    t.integer \"image_file_size\"\n    t.datetime \"image_updated_at\"\n    t.integer \"type\", default: 0, null: false\n    t.text \"html\", default: \"\", null: false\n    t.string \"author_name\", default: \"\", null: false\n    t.string \"author_url\", default: \"\", null: false\n    t.string \"provider_name\", default: \"\", null: false\n    t.string \"provider_url\", default: \"\", null: false\n    t.integer \"width\", default: 0, null: false\n    t.integer \"height\", default: 0, null: false\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.string \"embed_url\", default: \"\", null: false\n    t.index [\"url\"], name: \"index_preview_cards_on_url\", unique: true\n  end\n\n  create_table \"preview_cards_statuses\", id: false, force: :cascade do |t|\n    t.bigint \"preview_card_id\", null: false\n    t.bigint \"status_id\", null: false\n    t.index [\"status_id\", \"preview_card_id\"], name: \"index_preview_cards_statuses_on_status_id_and_preview_card_id\"\n  end\n\n  create_table \"relays\", force: :cascade do |t|\n    t.string \"inbox_url\", default: \"\", null: false\n    t.string \"follow_activity_id\"\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.integer \"state\", default: 0, null: false\n  end\n\n  create_table \"report_notes\", force: :cascade do |t|\n    t.text \"content\", null: false\n    t.bigint \"report_id\", null: false\n    t.bigint \"account_id\", null: false\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.index [\"account_id\"], name: \"index_report_notes_on_account_id\"\n    t.index [\"report_id\"], name: \"index_report_notes_on_report_id\"\n  end\n\n  create_table \"reports\", force: :cascade do |t|\n    t.bigint \"status_ids\", default: [], null: false, array: true\n    t.text \"comment\", default: \"\", null: false\n    t.boolean \"action_taken\", default: false, null: false\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.bigint \"account_id\", null: false\n    t.bigint \"action_taken_by_account_id\"\n    t.bigint \"target_account_id\", null: false\n    t.bigint \"assigned_account_id\"\n    t.string \"uri\"\n    t.index [\"account_id\"], name: \"index_reports_on_account_id\"\n    t.index [\"target_account_id\"], name: \"index_reports_on_target_account_id\"\n  end\n\n  create_table \"scheduled_statuses\", force: :cascade do |t|\n    t.bigint \"account_id\"\n    t.datetime \"scheduled_at\"\n    t.jsonb \"params\"\n    t.index [\"account_id\"], name: \"index_scheduled_statuses_on_account_id\"\n    t.index [\"scheduled_at\"], name: \"index_scheduled_statuses_on_scheduled_at\"\n  end\n\n  create_table \"session_activations\", force: :cascade do |t|\n    t.string \"session_id\", null: false\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.string \"user_agent\", default: \"\", null: false\n    t.inet \"ip\"\n    t.bigint \"access_token_id\"\n    t.bigint \"user_id\", null: false\n    t.bigint \"web_push_subscription_id\"\n    t.index [\"access_token_id\"], name: \"index_session_activations_on_access_token_id\"\n    t.index [\"session_id\"], name: \"index_session_activations_on_session_id\", unique: true\n    t.index [\"user_id\"], name: \"index_session_activations_on_user_id\"\n  end\n\n  create_table \"settings\", force: :cascade do |t|\n    t.string \"var\", null: false\n    t.text \"value\"\n    t.string \"thing_type\"\n    t.datetime \"created_at\"\n    t.datetime \"updated_at\"\n    t.bigint \"thing_id\"\n    t.index [\"thing_type\", \"thing_id\", \"var\"], name: \"index_settings_on_thing_type_and_thing_id_and_var\", unique: true\n  end\n\n  create_table \"site_uploads\", force: :cascade do |t|\n    t.string \"var\", default: \"\", null: false\n    t.string \"file_file_name\"\n    t.string \"file_content_type\"\n    t.integer \"file_file_size\"\n    t.datetime \"file_updated_at\"\n    t.json \"meta\"\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.index [\"var\"], name: \"index_site_uploads_on_var\", unique: true\n  end\n\n  create_table \"status_pins\", force: :cascade do |t|\n    t.bigint \"account_id\", null: false\n    t.bigint \"status_id\", null: false\n    t.datetime \"created_at\", default: -> { \"now()\" }, null: false\n    t.datetime \"updated_at\", default: -> { \"now()\" }, null: false\n    t.index [\"account_id\", \"status_id\"], name: \"index_status_pins_on_account_id_and_status_id\", unique: true\n  end\n\n  create_table \"status_stats\", force: :cascade do |t|\n    t.bigint \"status_id\", null: false\n    t.bigint \"replies_count\", default: 0, null: false\n    t.bigint \"reblogs_count\", default: 0, null: false\n    t.bigint \"favourites_count\", default: 0, null: false\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.index [\"status_id\"], name: \"index_status_stats_on_status_id\", unique: true\n  end\n\n  create_table \"statuses\", id: :bigint, default: -> { \"timestamp_id('statuses'::text)\" }, force: :cascade do |t|\n    t.string \"uri\"\n    t.text \"text\", default: \"\", null: false\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.bigint \"in_reply_to_id\"\n    t.bigint \"reblog_of_id\"\n    t.string \"url\"\n    t.boolean \"sensitive\", default: false, null: false\n    t.integer \"visibility\", default: 0, null: false\n    t.text \"spoiler_text\", default: \"\", null: false\n    t.boolean \"reply\", default: false, null: false\n    t.string \"language\"\n    t.bigint \"conversation_id\"\n    t.boolean \"local\"\n    t.bigint \"account_id\", null: false\n    t.bigint \"application_id\"\n    t.bigint \"in_reply_to_account_id\"\n    t.bigint \"poll_id\"\n    t.index [\"account_id\", \"id\", \"visibility\", \"updated_at\"], name: \"index_statuses_20180106\", order: { id: :desc }\n    t.index [\"in_reply_to_account_id\"], name: \"index_statuses_on_in_reply_to_account_id\"\n    t.index [\"in_reply_to_id\"], name: \"index_statuses_on_in_reply_to_id\"\n    t.index [\"reblog_of_id\", \"account_id\"], name: \"index_statuses_on_reblog_of_id_and_account_id\"\n    t.index [\"uri\"], name: \"index_statuses_on_uri\", unique: true\n  end\n\n  create_table \"statuses_tags\", id: false, force: :cascade do |t|\n    t.bigint \"status_id\", null: false\n    t.bigint \"tag_id\", null: false\n    t.index [\"status_id\"], name: \"index_statuses_tags_on_status_id\"\n    t.index [\"tag_id\", \"status_id\"], name: \"index_statuses_tags_on_tag_id_and_status_id\", unique: true\n  end\n\n  create_table \"stream_entries\", force: :cascade do |t|\n    t.bigint \"activity_id\"\n    t.string \"activity_type\"\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.boolean \"hidden\", default: false, null: false\n    t.bigint \"account_id\"\n    t.index [\"account_id\", \"activity_type\", \"id\"], name: \"index_stream_entries_on_account_id_and_activity_type_and_id\"\n    t.index [\"activity_id\", \"activity_type\"], name: \"index_stream_entries_on_activity_id_and_activity_type\"\n  end\n\n  create_table \"subscriptions\", force: :cascade do |t|\n    t.string \"callback_url\", default: \"\", null: false\n    t.string \"secret\"\n    t.datetime \"expires_at\"\n    t.boolean \"confirmed\", default: false, null: false\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.datetime \"last_successful_delivery_at\"\n    t.string \"domain\"\n    t.bigint \"account_id\", null: false\n    t.index [\"account_id\", \"callback_url\"], name: \"index_subscriptions_on_account_id_and_callback_url\", unique: true\n  end\n\n  create_table \"tags\", force: :cascade do |t|\n    t.string \"name\", default: \"\", null: false\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.index \"lower((name)::text) text_pattern_ops\", name: \"hashtag_search_index\"\n    t.index [\"name\"], name: \"index_tags_on_name\", unique: true\n  end\n\n  create_table \"tombstones\", force: :cascade do |t|\n    t.bigint \"account_id\"\n    t.string \"uri\", null: false\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.boolean \"by_moderator\"\n    t.index [\"account_id\"], name: \"index_tombstones_on_account_id\"\n    t.index [\"uri\"], name: \"index_tombstones_on_uri\"\n  end\n\n  create_table \"user_invite_requests\", force: :cascade do |t|\n    t.bigint \"user_id\"\n    t.text \"text\"\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.index [\"user_id\"], name: \"index_user_invite_requests_on_user_id\"\n  end\n\n  create_table \"users\", force: :cascade do |t|\n    t.string \"email\", default: \"\", null: false\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.string \"encrypted_password\", default: \"\", null: false\n    t.string \"reset_password_token\"\n    t.datetime \"reset_password_sent_at\"\n    t.datetime \"remember_created_at\"\n    t.integer \"sign_in_count\", default: 0, null: false\n    t.datetime \"current_sign_in_at\"\n    t.datetime \"last_sign_in_at\"\n    t.inet \"current_sign_in_ip\"\n    t.inet \"last_sign_in_ip\"\n    t.boolean \"admin\", default: false, null: false\n    t.string \"confirmation_token\"\n    t.datetime \"confirmed_at\"\n    t.datetime \"confirmation_sent_at\"\n    t.string \"unconfirmed_email\"\n    t.string \"locale\"\n    t.string \"encrypted_otp_secret\"\n    t.string \"encrypted_otp_secret_iv\"\n    t.string \"encrypted_otp_secret_salt\"\n    t.integer \"consumed_timestep\"\n    t.boolean \"otp_required_for_login\", default: false, null: false\n    t.datetime \"last_emailed_at\"\n    t.string \"otp_backup_codes\", array: true\n    t.string \"filtered_languages\", default: [], null: false, array: true\n    t.bigint \"account_id\", null: false\n    t.boolean \"disabled\", default: false, null: false\n    t.boolean \"moderator\", default: false, null: false\n    t.bigint \"invite_id\"\n    t.string \"remember_token\"\n    t.string \"chosen_languages\", array: true\n    t.bigint \"created_by_application_id\"\n    t.boolean \"approved\", default: true, null: false\n    t.index [\"account_id\"], name: \"index_users_on_account_id\"\n    t.index [\"confirmation_token\"], name: \"index_users_on_confirmation_token\", unique: true\n    t.index [\"created_by_application_id\"], name: \"index_users_on_created_by_application_id\"\n    t.index [\"email\"], name: \"index_users_on_email\", unique: true\n    t.index [\"reset_password_token\"], name: \"index_users_on_reset_password_token\", unique: true\n  end\n\n  create_table \"web_push_subscriptions\", force: :cascade do |t|\n    t.string \"endpoint\", null: false\n    t.string \"key_p256dh\", null: false\n    t.string \"key_auth\", null: false\n    t.json \"data\"\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.bigint \"access_token_id\"\n    t.bigint \"user_id\"\n    t.index [\"access_token_id\"], name: \"index_web_push_subscriptions_on_access_token_id\"\n    t.index [\"user_id\"], name: \"index_web_push_subscriptions_on_user_id\"\n  end\n\n  create_table \"web_settings\", force: :cascade do |t|\n    t.json \"data\"\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.bigint \"user_id\", null: false\n    t.index [\"user_id\"], name: \"index_web_settings_on_user_id\", unique: true\n  end\n\n  add_foreign_key \"account_conversations\", \"accounts\", on_delete: :cascade\n  add_foreign_key \"account_conversations\", \"conversations\", on_delete: :cascade\n  add_foreign_key \"account_domain_blocks\", \"accounts\", name: \"fk_206c6029bd\", on_delete: :cascade\n  add_foreign_key \"account_identity_proofs\", \"accounts\", on_delete: :cascade\n  add_foreign_key \"account_moderation_notes\", \"accounts\"\n  add_foreign_key \"account_moderation_notes\", \"accounts\", column: \"target_account_id\"\n  add_foreign_key \"account_pins\", \"accounts\", column: \"target_account_id\", on_delete: :cascade\n  add_foreign_key \"account_pins\", \"accounts\", on_delete: :cascade\n  add_foreign_key \"account_stats\", \"accounts\", on_delete: :cascade\n  add_foreign_key \"account_tag_stats\", \"tags\", on_delete: :cascade\n  add_foreign_key \"account_warnings\", \"accounts\", column: \"target_account_id\", on_delete: :cascade\n  add_foreign_key \"account_warnings\", \"accounts\", on_delete: :nullify\n  add_foreign_key \"accounts\", \"accounts\", column: \"moved_to_account_id\", on_delete: :nullify\n  add_foreign_key \"admin_action_logs\", \"accounts\", on_delete: :cascade\n  add_foreign_key \"backups\", \"users\", on_delete: :nullify\n  add_foreign_key \"blocks\", \"accounts\", column: \"target_account_id\", name: \"fk_9571bfabc1\", on_delete: :cascade\n  add_foreign_key \"blocks\", \"accounts\", name: \"fk_4269e03e65\", on_delete: :cascade\n  add_foreign_key \"conversation_mutes\", \"accounts\", name: \"fk_225b4212bb\", on_delete: :cascade\n  add_foreign_key \"conversation_mutes\", \"conversations\", on_delete: :cascade\n  add_foreign_key \"custom_filters\", \"accounts\", on_delete: :cascade\n  add_foreign_key \"favourites\", \"accounts\", name: \"fk_5eb6c2b873\", on_delete: :cascade\n  add_foreign_key \"favourites\", \"statuses\", name: \"fk_b0e856845e\", on_delete: :cascade\n  add_foreign_key \"featured_tags\", \"accounts\", on_delete: :cascade\n  add_foreign_key \"featured_tags\", \"tags\", on_delete: :cascade\n  add_foreign_key \"follow_requests\", \"accounts\", column: \"target_account_id\", name: \"fk_9291ec025d\", on_delete: :cascade\n  add_foreign_key \"follow_requests\", \"accounts\", name: \"fk_76d644b0e7\", on_delete: :cascade\n  add_foreign_key \"follows\", \"accounts\", column: \"target_account_id\", name: \"fk_745ca29eac\", on_delete: :cascade\n  add_foreign_key \"follows\", \"accounts\", name: \"fk_32ed1b5560\", on_delete: :cascade\n  add_foreign_key \"identities\", \"users\", name: \"fk_bea040f377\", on_delete: :cascade\n  add_foreign_key \"imports\", \"accounts\", name: \"fk_6db1b6e408\", on_delete: :cascade\n  add_foreign_key \"invites\", \"users\", on_delete: :cascade\n  add_foreign_key \"list_accounts\", \"accounts\", on_delete: :cascade\n  add_foreign_key \"list_accounts\", \"follows\", on_delete: :cascade\n  add_foreign_key \"list_accounts\", \"lists\", on_delete: :cascade\n  add_foreign_key \"lists\", \"accounts\", on_delete: :cascade\n  add_foreign_key \"media_attachments\", \"accounts\", name: \"fk_96dd81e81b\", on_delete: :nullify\n  add_foreign_key \"media_attachments\", \"scheduled_statuses\", on_delete: :nullify\n  add_foreign_key \"media_attachments\", \"statuses\", on_delete: :nullify\n  add_foreign_key \"mentions\", \"accounts\", name: \"fk_970d43f9d1\", on_delete: :cascade\n  add_foreign_key \"mentions\", \"statuses\", on_delete: :cascade\n  add_foreign_key \"mutes\", \"accounts\", column: \"target_account_id\", name: \"fk_eecff219ea\", on_delete: :cascade\n  add_foreign_key \"mutes\", \"accounts\", name: \"fk_b8d8daf315\", on_delete: :cascade\n  add_foreign_key \"notifications\", \"accounts\", column: \"from_account_id\", name: \"fk_fbd6b0bf9e\", on_delete: :cascade\n  add_foreign_key \"notifications\", \"accounts\", name: \"fk_c141c8ee55\", on_delete: :cascade\n  add_foreign_key \"oauth_access_grants\", \"oauth_applications\", column: \"application_id\", name: \"fk_34d54b0a33\", on_delete: :cascade\n  add_foreign_key \"oauth_access_grants\", \"users\", column: \"resource_owner_id\", name: \"fk_63b044929b\", on_delete: :cascade\n  add_foreign_key \"oauth_access_tokens\", \"oauth_applications\", column: \"application_id\", name: \"fk_f5fc4c1ee3\", on_delete: :cascade\n  add_foreign_key \"oauth_access_tokens\", \"users\", column: \"resource_owner_id\", name: \"fk_e84df68546\", on_delete: :cascade\n  add_foreign_key \"oauth_applications\", \"users\", column: \"owner_id\", name: \"fk_b0988c7c0a\", on_delete: :cascade\n  add_foreign_key \"poll_votes\", \"accounts\", on_delete: :cascade\n  add_foreign_key \"poll_votes\", \"polls\", on_delete: :cascade\n  add_foreign_key \"polls\", \"accounts\", on_delete: :cascade\n  add_foreign_key \"polls\", \"statuses\", on_delete: :cascade\n  add_foreign_key \"report_notes\", \"accounts\", on_delete: :cascade\n  add_foreign_key \"report_notes\", \"reports\", on_delete: :cascade\n  add_foreign_key \"reports\", \"accounts\", column: \"action_taken_by_account_id\", name: \"fk_bca45b75fd\", on_delete: :nullify\n  add_foreign_key \"reports\", \"accounts\", column: \"assigned_account_id\", on_delete: :nullify\n  add_foreign_key \"reports\", \"accounts\", column: \"target_account_id\", name: \"fk_eb37af34f0\", on_delete: :cascade\n  add_foreign_key \"reports\", \"accounts\", name: \"fk_4b81f7522c\", on_delete: :cascade\n  add_foreign_key \"scheduled_statuses\", \"accounts\", on_delete: :cascade\n  add_foreign_key \"session_activations\", \"oauth_access_tokens\", column: \"access_token_id\", name: \"fk_957e5bda89\", on_delete: :cascade\n  add_foreign_key \"session_activations\", \"users\", name: \"fk_e5fda67334\", on_delete: :cascade\n  add_foreign_key \"status_pins\", \"accounts\", name: \"fk_d4cb435b62\", on_delete: :cascade\n  add_foreign_key \"status_pins\", \"statuses\", on_delete: :cascade\n  add_foreign_key \"status_stats\", \"statuses\", on_delete: :cascade\n  add_foreign_key \"statuses\", \"accounts\", column: \"in_reply_to_account_id\", name: \"fk_c7fa917661\", on_delete: :nullify\n  add_foreign_key \"statuses\", \"accounts\", name: \"fk_9bda1543f7\", on_delete: :cascade\n  add_foreign_key \"statuses\", \"statuses\", column: \"in_reply_to_id\", on_delete: :nullify\n  add_foreign_key \"statuses\", \"statuses\", column: \"reblog_of_id\", on_delete: :cascade\n  add_foreign_key \"statuses_tags\", \"statuses\", on_delete: :cascade\n  add_foreign_key \"statuses_tags\", \"tags\", name: \"fk_3081861e21\", on_delete: :cascade\n  add_foreign_key \"stream_entries\", \"accounts\", name: \"fk_5659b17554\", on_delete: :cascade\n  add_foreign_key \"subscriptions\", \"accounts\", name: \"fk_9847d1cbb5\", on_delete: :cascade\n  add_foreign_key \"tombstones\", \"accounts\", on_delete: :cascade\n  add_foreign_key \"user_invite_requests\", \"users\", on_delete: :cascade\n  add_foreign_key \"users\", \"accounts\", name: \"fk_50500f500d\", on_delete: :cascade\n  add_foreign_key \"users\", \"invites\", on_delete: :nullify\n  add_foreign_key \"users\", \"oauth_applications\", column: \"created_by_application_id\", on_delete: :nullify\n  add_foreign_key \"web_push_subscriptions\", \"oauth_access_tokens\", column: \"access_token_id\", on_delete: :cascade\n  add_foreign_key \"web_push_subscriptions\", \"users\", on_delete: :cascade\n  add_foreign_key \"web_settings\", \"users\", name: \"fk_11910667b2\", on_delete: :cascade\nend\n"
  },
  {
    "path": "db/seeds.rb",
    "content": "Doorkeeper::Application.create!(name: 'Web', superapp: true, redirect_uri: Doorkeeper.configuration.native_redirect_uri, scopes: 'read write follow')\n\nif Rails.env.development?\n  domain = ENV['LOCAL_DOMAIN'] || Rails.configuration.x.local_domain\n  admin  = Account.where(username: 'admin').first_or_initialize(username: 'admin')\n  admin.save(validate: false)\n  User.where(email: \"admin@#{domain}\").first_or_initialize(email: \"admin@#{domain}\", password: 'mastodonadmin', password_confirmation: 'mastodonadmin', confirmed_at: Time.now.utc, admin: true, account: admin, agreement: true, approved: true).save!\nend\n"
  },
  {
    "path": "dist/mastodon-sidekiq.service",
    "content": "[Unit]\nDescription=mastodon-sidekiq\nAfter=network.target\n\n[Service]\nType=simple\nUser=mastodon\nWorkingDirectory=/home/mastodon/live\nEnvironment=\"RAILS_ENV=production\"\nEnvironment=\"DB_POOL=25\"\nEnvironment=\"MALLOC_ARENA_MAX=2\"\nExecStart=/home/mastodon/.rbenv/shims/bundle exec sidekiq -c 25\nTimeoutSec=15\nRestart=always\n\n[Install]\nWantedBy=multi-user.target\n"
  },
  {
    "path": "dist/mastodon-streaming.service",
    "content": "[Unit]\nDescription=mastodon-streaming\nAfter=network.target\n\n[Service]\nType=simple\nUser=mastodon\nWorkingDirectory=/home/mastodon/live\nEnvironment=\"NODE_ENV=production\"\nEnvironment=\"PORT=4000\"\nEnvironment=\"STREAMING_CLUSTER_NUM=1\"\nExecStart=/usr/bin/node ./streaming\nTimeoutSec=15\nRestart=always\n\n[Install]\nWantedBy=multi-user.target\n"
  },
  {
    "path": "dist/mastodon-web.service",
    "content": "[Unit]\nDescription=mastodon-web\nAfter=network.target\n\n[Service]\nType=simple\nUser=mastodon\nWorkingDirectory=/home/mastodon/live\nEnvironment=\"RAILS_ENV=production\"\nEnvironment=\"PORT=3000\"\nExecStart=/home/mastodon/.rbenv/shims/bundle exec puma -C config/puma.rb\nExecReload=/bin/kill -SIGUSR1 $MAINPID\nTimeoutSec=15\nRestart=always\n\n[Install]\nWantedBy=multi-user.target\n"
  },
  {
    "path": "dist/nginx.conf",
    "content": "map $http_upgrade $connection_upgrade {\n  default upgrade;\n  ''      close;\n}\n\nproxy_cache_path /var/cache/nginx levels=1:2 keys_zone=CACHE:10m inactive=7d max_size=1g;\n\nserver {\n  listen 80;\n  listen [::]:80;\n  server_name example.com;\n  root /home/mastodon/live/public;\n  location /.well-known/acme-challenge/ { allow all; }\n  location / { return 301 https://$host$request_uri; }\n}\n\nserver {\n  listen 443 ssl http2;\n  listen [::]:443 ssl http2;\n  server_name example.com;\n\n  ssl_protocols TLSv1.2;\n  ssl_ciphers HIGH:!MEDIUM:!LOW:!aNULL:!NULL:!SHA;\n  ssl_prefer_server_ciphers on;\n  ssl_session_cache shared:SSL:10m;\n\n  # Uncomment these lines once you acquire a certificate:\n  # ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;\n  # ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;\n\n  keepalive_timeout    70;\n  sendfile             on;\n  client_max_body_size 80m;\n\n  root /home/mastodon/live/public;\n\n  gzip on;\n  gzip_disable \"msie6\";\n  gzip_vary on;\n  gzip_proxied any;\n  gzip_comp_level 6;\n  gzip_buffers 16 8k;\n  gzip_http_version 1.1;\n  gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;\n\n  add_header Strict-Transport-Security \"max-age=31536000\";\n\n  location / {\n    try_files $uri @proxy;\n  }\n\n  location ~ ^/(emoji|packs|system/accounts/avatars|system/media_attachments/files) {\n    add_header Cache-Control \"public, max-age=31536000, immutable\";\n    add_header Strict-Transport-Security \"max-age=31536000\";\n    try_files $uri @proxy;\n  }\n\n  location /sw.js {\n    add_header Cache-Control \"public, max-age=0\";\n    add_header Strict-Transport-Security \"max-age=31536000\";\n    try_files $uri @proxy;\n  }\n\n  location @proxy {\n    proxy_set_header Host $host;\n    proxy_set_header X-Real-IP $remote_addr;\n    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n    proxy_set_header X-Forwarded-Proto https;\n    proxy_set_header Proxy \"\";\n    proxy_pass_header Server;\n\n    proxy_pass http://127.0.0.1:3000;\n    proxy_buffering on;\n    proxy_redirect off;\n    proxy_http_version 1.1;\n    proxy_set_header Upgrade $http_upgrade;\n    proxy_set_header Connection $connection_upgrade;\n\n    proxy_cache CACHE;\n    proxy_cache_valid 200 7d;\n    proxy_cache_valid 410 24h;\n    proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;\n    add_header X-Cached $upstream_cache_status;\n    add_header Strict-Transport-Security \"max-age=31536000\";\n\n    tcp_nodelay on;\n  }\n\n  location /api/v1/streaming {\n    proxy_set_header Host $host;\n    proxy_set_header X-Real-IP $remote_addr;\n    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n    proxy_set_header X-Forwarded-Proto https;\n    proxy_set_header Proxy \"\";\n\n    proxy_pass http://127.0.0.1:4000;\n    proxy_buffering off;\n    proxy_redirect off;\n    proxy_http_version 1.1;\n    proxy_set_header Upgrade $http_upgrade;\n    proxy_set_header Connection $connection_upgrade;\n\n    tcp_nodelay on;\n  }\n\n  error_page 500 501 502 503 504 /500.html;\n}\n"
  },
  {
    "path": "docker-compose.yml",
    "content": "version: '3'\nservices:\n\n  db:\n    restart: always\n    image: postgres:9.6-alpine\n    networks:\n      - internal_network\n    healthcheck:\n      test: [\"CMD\", \"pg_isready\", \"-U\", \"postgres\"]\n    volumes:\n      - ./postgres:/var/lib/postgresql/data\n\n  redis:\n    restart: always\n    image: redis:5.0-alpine\n    networks:\n      - internal_network\n    healthcheck:\n      test: [\"CMD\", \"redis-cli\", \"ping\"]\n    volumes:\n      - ./redis:/data\n\n#  es:\n#    restart: always\n#    image: docker.elastic.co/elasticsearch/elasticsearch-oss:6.1.3\n#    environment:\n#      - \"ES_JAVA_OPTS=-Xms512m -Xmx512m\"\n#    networks:\n#      - internal_network\n#    healthcheck:\n#      test: [\"CMD-SHELL\", \"curl --silent --fail localhost:9200/_cluster/health || exit 1\"]\n#    volumes:\n#      - ./elasticsearch:/usr/share/elasticsearch/data\n\n  web:\n    build: .\n    image: florencesoc/mastodon-fork\n    restart: always\n    env_file: .env.production\n    command: bash -c \"rm -f /mastodon/tmp/pids/server.pid; bundle exec rails s -p 3000 -b '0.0.0.0'\"\n    networks:\n      - external_network\n      - internal_network\n    healthcheck:\n      test: [\"CMD-SHELL\", \"wget -q --spider --header 'x-forwarded-proto: https' --proxy=off localhost:3000/api/v1/instance || exit 1\"]\n    ports:\n      - \"127.0.0.1:3000:3000\"\n    depends_on:\n      - db\n      - redis\n#      - es\n    volumes:\n      - ./public/system:/mastodon/public/system\n\n  streaming:\n    build: .\n    image: florencesoc/mastodon-fork\n    restart: always\n    env_file: .env.production\n    command: yarn start\n    networks:\n      - external_network\n      - internal_network\n    healthcheck:\n      test: [\"CMD-SHELL\", \"wget -q --spider --header 'x-forwarded-proto: https' --proxy=off localhost:4000/api/v1/streaming/health || exit 1\"]\n    ports:\n      - \"127.0.0.1:4000:4000\"\n    depends_on:\n      - db\n      - redis\n\n  sidekiq:\n    build: .\n    image: florencesoc/mastodon-fork\n    restart: always\n    env_file: .env.production\n    command: bundle exec sidekiq\n    depends_on:\n      - db\n      - redis\n    networks:\n      - external_network\n      - internal_network\n    volumes:\n      - ./public/system:/mastodon/public/system\n## Uncomment to enable federation with tor instances along with adding the following ENV variables\n## http_proxy=http://privoxy:8118\n## ALLOW_ACCESS_TO_HIDDEN_SERVICE=true\n#  tor:\n#    image: sirboops/tor\n#    networks:\n#      - external_network\n#      - internal_network\n#\n#  privoxy:\n#    image: sirboops/privoxy\n#    volumes:\n#      - ./priv-config:/opt/config\n#    networks:\n#      - external_network\n#      - internal_network\n\nnetworks:\n  external_network:\n  internal_network:\n    internal: true\n"
  },
  {
    "path": "lib/assets/.keep",
    "content": ""
  },
  {
    "path": "lib/cli.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'thor'\nrequire_relative 'mastodon/media_cli'\nrequire_relative 'mastodon/emoji_cli'\nrequire_relative 'mastodon/accounts_cli'\nrequire_relative 'mastodon/feeds_cli'\nrequire_relative 'mastodon/search_cli'\nrequire_relative 'mastodon/settings_cli'\nrequire_relative 'mastodon/statuses_cli'\nrequire_relative 'mastodon/domains_cli'\nrequire_relative 'mastodon/cache_cli'\nrequire_relative 'mastodon/version'\n\nmodule Mastodon\n  class CLI < Thor\n    def self.exit_on_failure?\n      true\n    end\n\n    desc 'media SUBCOMMAND ...ARGS', 'Manage media files'\n    subcommand 'media', Mastodon::MediaCLI\n\n    desc 'emoji SUBCOMMAND ...ARGS', 'Manage custom emoji'\n    subcommand 'emoji', Mastodon::EmojiCLI\n\n    desc 'accounts SUBCOMMAND ...ARGS', 'Manage accounts'\n    subcommand 'accounts', Mastodon::AccountsCLI\n\n    desc 'feeds SUBCOMMAND ...ARGS', 'Manage feeds'\n    subcommand 'feeds', Mastodon::FeedsCLI\n\n    desc 'search SUBCOMMAND ...ARGS', 'Manage the search engine'\n    subcommand 'search', Mastodon::SearchCLI\n\n    desc 'settings SUBCOMMAND ...ARGS', 'Manage dynamic settings'\n    subcommand 'settings', Mastodon::SettingsCLI\n\n    desc 'statuses SUBCOMMAND ...ARGS', 'Manage statuses'\n    subcommand 'statuses', Mastodon::StatusesCLI\n\n    desc 'domains SUBCOMMAND ...ARGS', 'Manage account domains'\n    subcommand 'domains', Mastodon::DomainsCLI\n\n    desc 'cache SUBCOMMAND ...ARGS', 'Manage cache'\n    subcommand 'cache', Mastodon::CacheCLI\n\n    option :dry_run, type: :boolean\n    desc 'self-destruct', 'Erase the server from the federation'\n    long_desc <<~LONG_DESC\n      Erase the server from the federation by broadcasting account delete\n      activities to all known other servers. This allows a \"clean exit\" from\n      running a Mastodon server, as it leaves next to no cache behind on\n      other servers.\n\n      This command is always interactive and requires confirmation twice.\n\n      No local data is actually deleted, because emptying the\n      database or removing files is much faster through other, external\n      means, such as e.g. deleting the entire VPS. However, because other\n      servers will delete data about local users, but no local data will be\n      updated (such as e.g. followers), there will be a state mismatch\n      that will lead to glitches and issues if you then continue to run and use\n      the server.\n\n      So either you know exactly what you are doing, or you are starting\n      from a blank slate afterwards by manually clearing out all the local\n      data!\n    LONG_DESC\n    def self_destruct\n      require 'tty-prompt'\n\n      prompt = TTY::Prompt.new\n\n      exit(1) unless prompt.ask('Type in the domain of the server to confirm:', required: true) == Rails.configuration.x.local_domain\n\n      prompt.warn('This operation WILL NOT be reversible. It can also take a long time.')\n      prompt.warn('While the data won\\'t be erased locally, the server will be in a BROKEN STATE afterwards.')\n      prompt.warn('A running Sidekiq process is required. Do not shut it down until queues clear.')\n\n      exit(1) if prompt.no?('Are you sure you want to proceed?')\n\n      inboxes   = Account.inboxes\n      processed = 0\n      dry_run   = options[:dry_run] ? ' (DRY RUN)' : ''\n\n      if inboxes.empty?\n        prompt.ok('It seems like your server has not federated with anything')\n        prompt.ok('You can shut it down and delete it any time')\n        return\n      end\n\n      prompt.warn('Do NOT interrupt this process...')\n\n      Account.local.without_suspended.find_each do |account|\n        payload = ActiveModelSerializers::SerializableResource.new(\n          account,\n          serializer: ActivityPub::DeleteActorSerializer,\n          adapter: ActivityPub::Adapter\n        ).as_json\n\n        json = Oj.dump(ActivityPub::LinkedDataSignature.new(payload).sign!(account))\n\n        unless options[:dry_run]\n          ActivityPub::DeliveryWorker.push_bulk(inboxes) do |inbox_url|\n            [json, account.id, inbox_url]\n          end\n\n          account.suspend!\n        end\n\n        processed += 1\n      end\n\n      prompt.ok(\"Queued #{inboxes.size * processed} items into Sidekiq for #{processed} accounts#{dry_run}\")\n      prompt.ok('Wait until Sidekiq processes all items, then you can shut everything down and delete the data')\n    rescue TTY::Reader::InputInterrupt\n      exit(1)\n    end\n\n    map %w(--version -v) => :version\n\n    desc 'version', 'Show version'\n    def version\n      say(\"#{Florence::Version} (equiv: Mastodon #{Mastodon::Version})\")\n    end\n  end\nend\n"
  },
  {
    "path": "lib/devise/ldap_authenticatable.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'net/ldap'\nrequire 'devise/strategies/authenticatable'\n\nmodule Devise\n  module Strategies\n    class LdapAuthenticatable < Authenticatable\n      def authenticate!\n        if params[:user]\n          ldap = Net::LDAP.new(\n            host: Devise.ldap_host,\n            port: Devise.ldap_port,\n            base: Devise.ldap_base,\n            encryption: {\n              method: Devise.ldap_method,\n              tls_options: tls_options,\n            },\n            auth: {\n              method: :simple,\n              username: Devise.ldap_bind_dn,\n              password: Devise.ldap_password,\n            },\n            connect_timeout: 10\n          )\n\n          filter = format(Devise.ldap_search_filter, uid: Devise.ldap_uid, email: email)\n\n          if (user_info = ldap.bind_as(base: Devise.ldap_base, filter: filter, password: password))\n            user = User.ldap_get_user(user_info.first)\n            success!(user)\n          else\n            return fail(:invalid)\n          end\n        end\n      end\n\n      def email\n        params[:user][:email]\n      end\n\n      def password\n        params[:user][:password]\n      end\n\n      def tls_options\n        OpenSSL::SSL::SSLContext::DEFAULT_PARAMS.tap do |options|\n          options[:verify_mode] = OpenSSL::SSL::VERIFY_NONE if Devise.ldap_tls_no_verify\n        end\n      end\n    end\n  end\nend\n\nWarden::Strategies.add(:ldap_authenticatable, Devise::Strategies::LdapAuthenticatable)\n"
  },
  {
    "path": "lib/florence/version.rb",
    "content": "# frozen_string_literal: true\n\nmodule Florence\n  module Version\n    module_function\n\n    def compatibility\n      0\n    end\n\n    def feel\n      0\n    end\n\n    def feature\n      1\n    end\n\n    def hotfix\n      1\n    end\n\n    def suffix\n      ''\n    end\n\n    def to_a\n      [compatibility, feel, feature, hotfix]\n    end\n\n    def to_s\n      [to_a.join('.'), suffix].join\n    end\n  end\nend\n\n"
  },
  {
    "path": "lib/generators/post_deployment_migration_generator.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails/generators'\n\nmodule Rails\n  class PostDeploymentMigrationGenerator < Rails::Generators::NamedBase\n    def create_migration_file\n      timestamp = Time.zone.now.strftime('%Y%m%d%H%M%S')\n\n      template 'migration.rb', \"db/post_migrate/#{timestamp}_#{file_name}.rb\"\n    end\n\n    def migration_class_name\n      file_name.camelize\n    end\n  end\nend\n"
  },
  {
    "path": "lib/json_ld/security.rb",
    "content": "# -*- encoding: utf-8 -*-\n# frozen_string_literal: true\n# This file generated automatically from https://w3id.org/security/v1\nrequire 'json/ld'\nclass JSON::LD::Context\n  add_preloaded(\"https://w3id.org/security/v1\") do\n    new(processingMode: \"json-ld-1.0\", term_definitions: {\n      \"CryptographicKey\" => TermDefinition.new(\"CryptographicKey\", id: \"https://w3id.org/security#Key\", simple: true),\n      \"EcdsaKoblitzSignature2016\" => TermDefinition.new(\"EcdsaKoblitzSignature2016\", id: \"https://w3id.org/security#EcdsaKoblitzSignature2016\", simple: true),\n      \"EncryptedMessage\" => TermDefinition.new(\"EncryptedMessage\", id: \"https://w3id.org/security#EncryptedMessage\", simple: true),\n      \"GraphSignature2012\" => TermDefinition.new(\"GraphSignature2012\", id: \"https://w3id.org/security#GraphSignature2012\", simple: true),\n      \"LinkedDataSignature2015\" => TermDefinition.new(\"LinkedDataSignature2015\", id: \"https://w3id.org/security#LinkedDataSignature2015\", simple: true),\n      \"LinkedDataSignature2016\" => TermDefinition.new(\"LinkedDataSignature2016\", id: \"https://w3id.org/security#LinkedDataSignature2016\", simple: true),\n      \"authenticationTag\" => TermDefinition.new(\"authenticationTag\", id: \"https://w3id.org/security#authenticationTag\", simple: true),\n      \"canonicalizationAlgorithm\" => TermDefinition.new(\"canonicalizationAlgorithm\", id: \"https://w3id.org/security#canonicalizationAlgorithm\", simple: true),\n      \"cipherAlgorithm\" => TermDefinition.new(\"cipherAlgorithm\", id: \"https://w3id.org/security#cipherAlgorithm\", simple: true),\n      \"cipherData\" => TermDefinition.new(\"cipherData\", id: \"https://w3id.org/security#cipherData\", simple: true),\n      \"cipherKey\" => TermDefinition.new(\"cipherKey\", id: \"https://w3id.org/security#cipherKey\", simple: true),\n      \"created\" => TermDefinition.new(\"created\", id: \"http://purl.org/dc/terms/created\", type_mapping: \"http://www.w3.org/2001/XMLSchema#dateTime\"),\n      \"creator\" => TermDefinition.new(\"creator\", id: \"http://purl.org/dc/terms/creator\", type_mapping: \"@id\"),\n      \"dc\" => TermDefinition.new(\"dc\", id: \"http://purl.org/dc/terms/\", simple: true, prefix: true),\n      \"digestAlgorithm\" => TermDefinition.new(\"digestAlgorithm\", id: \"https://w3id.org/security#digestAlgorithm\", simple: true),\n      \"digestValue\" => TermDefinition.new(\"digestValue\", id: \"https://w3id.org/security#digestValue\", simple: true),\n      \"domain\" => TermDefinition.new(\"domain\", id: \"https://w3id.org/security#domain\", simple: true),\n      \"encryptionKey\" => TermDefinition.new(\"encryptionKey\", id: \"https://w3id.org/security#encryptionKey\", simple: true),\n      \"expiration\" => TermDefinition.new(\"expiration\", id: \"https://w3id.org/security#expiration\", type_mapping: \"http://www.w3.org/2001/XMLSchema#dateTime\"),\n      \"expires\" => TermDefinition.new(\"expires\", id: \"https://w3id.org/security#expiration\", type_mapping: \"http://www.w3.org/2001/XMLSchema#dateTime\"),\n      \"id\" => TermDefinition.new(\"id\", id: \"@id\", simple: true),\n      \"initializationVector\" => TermDefinition.new(\"initializationVector\", id: \"https://w3id.org/security#initializationVector\", simple: true),\n      \"iterationCount\" => TermDefinition.new(\"iterationCount\", id: \"https://w3id.org/security#iterationCount\", simple: true),\n      \"nonce\" => TermDefinition.new(\"nonce\", id: \"https://w3id.org/security#nonce\", simple: true),\n      \"normalizationAlgorithm\" => TermDefinition.new(\"normalizationAlgorithm\", id: \"https://w3id.org/security#normalizationAlgorithm\", simple: true),\n      \"owner\" => TermDefinition.new(\"owner\", id: \"https://w3id.org/security#owner\", type_mapping: \"@id\"),\n      \"password\" => TermDefinition.new(\"password\", id: \"https://w3id.org/security#password\", simple: true),\n      \"privateKey\" => TermDefinition.new(\"privateKey\", id: \"https://w3id.org/security#privateKey\", type_mapping: \"@id\"),\n      \"privateKeyPem\" => TermDefinition.new(\"privateKeyPem\", id: \"https://w3id.org/security#privateKeyPem\", simple: true),\n      \"publicKey\" => TermDefinition.new(\"publicKey\", id: \"https://w3id.org/security#publicKey\", type_mapping: \"@id\"),\n      \"publicKeyPem\" => TermDefinition.new(\"publicKeyPem\", id: \"https://w3id.org/security#publicKeyPem\", simple: true),\n      \"publicKeyService\" => TermDefinition.new(\"publicKeyService\", id: \"https://w3id.org/security#publicKeyService\", type_mapping: \"@id\"),\n      \"revoked\" => TermDefinition.new(\"revoked\", id: \"https://w3id.org/security#revoked\", type_mapping: \"http://www.w3.org/2001/XMLSchema#dateTime\"),\n      \"salt\" => TermDefinition.new(\"salt\", id: \"https://w3id.org/security#salt\", simple: true),\n      \"sec\" => TermDefinition.new(\"sec\", id: \"https://w3id.org/security#\", simple: true, prefix: true),\n      \"signature\" => TermDefinition.new(\"signature\", id: \"https://w3id.org/security#signature\", simple: true),\n      \"signatureAlgorithm\" => TermDefinition.new(\"signatureAlgorithm\", id: \"https://w3id.org/security#signingAlgorithm\", simple: true),\n      \"signatureValue\" => TermDefinition.new(\"signatureValue\", id: \"https://w3id.org/security#signatureValue\", simple: true),\n      \"type\" => TermDefinition.new(\"type\", id: \"@type\", simple: true),\n      \"xsd\" => TermDefinition.new(\"xsd\", id: \"http://www.w3.org/2001/XMLSchema#\", simple: true, prefix: true)\n    })\n  end\nend\n"
  },
  {
    "path": "lib/mastodon/accounts_cli.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'set'\nrequire_relative '../../config/boot'\nrequire_relative '../../config/environment'\nrequire_relative 'cli_helper'\n\nmodule Mastodon\n  class AccountsCLI < Thor\n    def self.exit_on_failure?\n      true\n    end\n\n    option :all, type: :boolean\n    desc 'rotate [USERNAME]', 'Generate and broadcast new keys'\n    long_desc <<-LONG_DESC\n      Generate and broadcast new RSA keys as part of security\n      maintenance.\n\n      With the --all option, all local accounts will be subject\n      to the rotation. Otherwise, and by default, only a single\n      account specified by the USERNAME argument will be\n      processed.\n    LONG_DESC\n    def rotate(username = nil)\n      if options[:all]\n        processed = 0\n        delay     = 0\n\n        Account.local.without_suspended.find_in_batches do |accounts|\n          accounts.each do |account|\n            rotate_keys_for_account(account, delay)\n            processed += 1\n            say('.', :green, false)\n          end\n\n          delay += 5.minutes\n        end\n\n        say\n        say(\"OK, rotated keys for #{processed} accounts\", :green)\n      elsif username.present?\n        rotate_keys_for_account(Account.find_local(username))\n        say('OK', :green)\n      else\n        say('No account(s) given', :red)\n        exit(1)\n      end\n    end\n\n    option :email, required: true\n    option :confirmed, type: :boolean\n    option :role, default: 'user'\n    option :reattach, type: :boolean\n    option :force, type: :boolean\n    desc 'create USERNAME', 'Create a new user'\n    long_desc <<-LONG_DESC\n      Create a new user account with a given USERNAME and an\n      e-mail address provided with --email.\n\n      With the --confirmed option, the confirmation e-mail will\n      be skipped and the account will be active straight away.\n\n      With the --role option one of  \"user\", \"admin\" or \"moderator\"\n      can be supplied. Defaults to \"user\"\n\n      With the --reattach option, the new user will be reattached\n      to a given existing username of an old account. If the old\n      account is still in use by someone else, you can supply\n      the --force option to delete the old record and reattach the\n      username to the new account anyway.\n    LONG_DESC\n    def create(username)\n      account  = Account.new(username: username)\n      password = SecureRandom.hex\n      user     = User.new(email: options[:email], password: password, agreement: true, approved: true, admin: options[:role] == 'admin', moderator: options[:role] == 'moderator', confirmed_at: options[:confirmed] ? Time.now.utc : nil)\n\n      if options[:reattach]\n        account = Account.find_local(username) || Account.new(username: username)\n\n        if account.user.present? && !options[:force]\n          say('The chosen username is currently in use', :red)\n          say('Use --force to reattach it anyway and delete the other user')\n          return\n        elsif account.user.present?\n          account.user.destroy!\n        end\n      end\n\n      account.suspended_at = nil\n      user.account         = account\n\n      if user.save\n        if options[:confirmed]\n          user.confirmed_at = nil\n          user.confirm!\n        end\n\n        say('OK', :green)\n        say(\"New password: #{password}\")\n      else\n        user.errors.to_h.each do |key, error|\n          say('Failure/Error: ', :red)\n          say(key)\n          say('    ' + error, :red)\n        end\n\n        exit(1)\n      end\n    end\n\n    option :role\n    option :email\n    option :confirm, type: :boolean\n    option :enable, type: :boolean\n    option :disable, type: :boolean\n    option :disable_2fa, type: :boolean\n    option :approve, type: :boolean\n    desc 'modify USERNAME', 'Modify a user'\n    long_desc <<-LONG_DESC\n      Modify a user account.\n\n      With the --role option, update the user's role to one of \"user\",\n      \"moderator\" or \"admin\".\n\n      With the --email option, update the user's e-mail address. With\n      the --confirm option, mark the user's e-mail as confirmed.\n\n      With the --disable option, lock the user out of their account. The\n      --enable option is the opposite.\n\n      With the --approve option, the account will be approved, if it was\n      previously not due to not having open registrations.\n\n      With the --disable-2fa option, the two-factor authentication\n      requirement for the user can be removed.\n    LONG_DESC\n    def modify(username)\n      user = Account.find_local(username)&.user\n\n      if user.nil?\n        say('No user with such username', :red)\n        exit(1)\n      end\n\n      if options[:role]\n        user.admin = options[:role] == 'admin'\n        user.moderator = options[:role] == 'moderator'\n      end\n\n      user.email = options[:email] if options[:email]\n      user.disabled = false if options[:enable]\n      user.disabled = true if options[:disable]\n      user.approved = true if options[:approve]\n      user.otp_required_for_login = false if options[:disable_2fa]\n      user.confirm if options[:confirm]\n\n      if user.save\n        say('OK', :green)\n      else\n        user.errors.to_h.each do |key, error|\n          say('Failure/Error: ', :red)\n          say(key)\n          say('    ' + error, :red)\n        end\n\n        exit(1)\n      end\n    end\n\n    desc 'delete USERNAME', 'Delete a user'\n    long_desc <<-LONG_DESC\n      Remove a user account with a given USERNAME.\n    LONG_DESC\n    def delete(username)\n      account = Account.find_local(username)\n\n      if account.nil?\n        say('No user with such username', :red)\n        exit(1)\n      end\n\n      say(\"Deleting user with #{account.statuses_count} statuses, this might take a while...\")\n      SuspendAccountService.new.call(account, including_user: true)\n      say('OK', :green)\n    end\n\n    desc 'backup USERNAME', 'Request a backup for a user'\n    long_desc <<-LONG_DESC\n      Request a new backup for an account with a given USERNAME.\n\n      The backup will be created in Sidekiq asynchronously, and\n      the user will receive an e-mail with a link to it once\n      it's done.\n    LONG_DESC\n    def backup(username)\n      account = Account.find_local(username)\n\n      if account.nil?\n        say('No user with such username', :red)\n        exit(1)\n      end\n\n      backup = account.user.backups.create!\n      BackupWorker.perform_async(backup.id)\n      say('OK', :green)\n    end\n\n    option :dry_run, type: :boolean\n    desc 'cull', 'Remove remote accounts that no longer exist'\n    long_desc <<-LONG_DESC\n      Query every single remote account in the database to determine\n      if it still exists on the origin server, and if it doesn't,\n      remove it from the database.\n\n      Accounts that have had confirmed activity within the last week\n      are excluded from the checks.\n\n      Domains that are unreachable are not checked.\n\n      With the --dry-run option, no deletes will actually be carried\n      out.\n    LONG_DESC\n    def cull\n      skip_threshold = 7.days.ago\n      culled         = 0\n      dry_run_culled = []\n      skip_domains   = Set.new\n      dry_run        = options[:dry_run] ? ' (DRY RUN)' : ''\n\n      Account.remote.where(protocol: :activitypub).partitioned.find_each do |account|\n        next if account.updated_at >= skip_threshold || (account.last_webfingered_at.present? && account.last_webfingered_at >= skip_threshold)\n\n        code = 0\n        unless skip_domains.include?(account.domain)\n          begin\n            code = Request.new(:head, account.uri).perform(&:code)\n          rescue HTTP::ConnectionError\n            skip_domains << account.domain\n          rescue StandardError\n            next\n          end\n        end\n\n        if [404, 410].include?(code)\n          if options[:dry_run]\n            dry_run_culled << account.acct\n          else\n            SuspendAccountService.new.call(account, destroy: true)\n          end\n          culled += 1\n          say('+', :green, false)\n        else\n          account.touch # Touch account even during dry run to avoid getting the account into the window again\n          say('.', nil, false)\n        end\n      end\n\n      say\n      say(\"Removed #{culled} accounts. #{skip_domains.size} servers skipped#{dry_run}\", skip_domains.empty? ? :green : :yellow)\n\n      unless skip_domains.empty?\n        say('The following servers were not available during the check:', :yellow)\n        skip_domains.each { |domain| say('    ' + domain) }\n      end\n\n      unless dry_run_culled.empty?\n        say('The following accounts would have been deleted:', :green)\n        dry_run_culled.each { |account| say('    ' + account) }\n      end\n    end\n\n    option :all, type: :boolean\n    option :domain\n    desc 'refresh [USERNAME]', 'Fetch remote user data and files'\n    long_desc <<-LONG_DESC\n      Fetch remote user data and files for one or multiple accounts.\n\n      With the --all option, all remote accounts will be processed.\n      Through the --domain option, this can be narrowed down to a\n      specific domain only. Otherwise, a single remote account must\n      be specified with USERNAME.\n\n      All processing is done in the background through Sidekiq.\n    LONG_DESC\n    def refresh(username = nil)\n      if options[:domain] || options[:all]\n        queued = 0\n        scope  = Account.remote\n        scope  = scope.where(domain: options[:domain]) if options[:domain]\n\n        scope.select(:id).reorder(nil).find_in_batches do |accounts|\n          Maintenance::RedownloadAccountMediaWorker.push_bulk(accounts.map(&:id))\n          queued += accounts.size\n        end\n\n        say(\"Scheduled refreshment of #{queued} accounts\", :green, true)\n      elsif username.present?\n        username, domain = username.split('@')\n        account = Account.find_remote(username, domain)\n\n        if account.nil?\n          say('No such account', :red)\n          exit(1)\n        end\n\n        Maintenance::RedownloadAccountMediaWorker.perform_async(account.id)\n        say('OK', :green)\n      else\n        say('No account(s) given', :red)\n        exit(1)\n      end\n    end\n\n    desc 'follow ACCT', 'Make all local accounts follow account specified by ACCT'\n    long_desc <<-LONG_DESC\n      Make all local accounts follow an account specified by ACCT. ACCT can be\n      a simple username, in case of a local user. It can also be in the format\n      username@domain, in case of a remote user.\n    LONG_DESC\n    def follow(acct)\n      target_account = ResolveAccountService.new.call(acct)\n      processed      = 0\n      failed         = 0\n\n      if target_account.nil?\n        say(\"Target account (#{acct}) could not be resolved\", :red)\n        exit(1)\n      end\n\n      Account.local.without_suspended.find_each do |account|\n        begin\n          FollowService.new.call(account, target_account)\n          processed += 1\n          say('.', :green, false)\n        rescue StandardError\n          failed += 1\n          say('.', :red, false)\n        end\n      end\n\n      say(\"OK, followed target from #{processed} accounts, skipped #{failed}\", :green)\n    end\n\n    desc 'unfollow ACCT', 'Make all local accounts unfollow account specified by ACCT'\n    long_desc <<-LONG_DESC\n      Make all local accounts unfollow an account specified by ACCT. ACCT can be\n      a simple username, in case of a local user. It can also be in the format\n      username@domain, in case of a remote user.\n    LONG_DESC\n    def unfollow(acct)\n      target_account = Account.find_remote(*acct.split('@'))\n      processed      = 0\n      failed         = 0\n\n      if target_account.nil?\n        say(\"Target account (#{acct}) was not found\", :red)\n        exit(1)\n      end\n\n      target_account.followers.local.find_each do |account|\n        begin\n          UnfollowService.new.call(account, target_account)\n          processed += 1\n          say('.', :green, false)\n        rescue StandardError\n          failed += 1\n          say('.', :red, false)\n        end\n      end\n\n      say(\"OK, unfollowed target from #{processed} accounts, skipped #{failed}\", :green)\n    end\n\n    option :follows, type: :boolean, default: false\n    option :followers, type: :boolean, default: false\n    desc 'reset-relationships USERNAME', 'Reset all follows and/or followers for a user'\n    long_desc <<-LONG_DESC\n      Reset all follows and/or followers for a user specified by USERNAME.\n\n      With the --follows option, the command unfollows everyone that the account follows,\n      and then re-follows the users that would be followed by a brand new account.\n\n      With the --followers option, the command removes all followers of the account.\n    LONG_DESC\n    def reset_relationships(username)\n      unless options[:follows] || options[:followers]\n        say('Please specify either --follows or --followers, or both', :red)\n        exit(1)\n      end\n\n      account = Account.find_local(username)\n\n      if account.nil?\n        say('No user with such username', :red)\n        exit(1)\n      end\n\n      if options[:follows]\n        processed = 0\n        failed    = 0\n\n        say(\"Unfollowing #{account.username}'s followees, this might take a while...\")\n\n        Account.where(id: ::Follow.where(account: account).select(:target_account_id)).find_each do |target_account|\n          begin\n            UnfollowService.new.call(account, target_account)\n            processed += 1\n            say('.', :green, false)\n          rescue StandardError\n            failed += 1\n            say('.', :red, false)\n          end\n        end\n\n        BootstrapTimelineWorker.perform_async(account.id)\n\n        say(\"OK, unfollowed #{processed} followees, skipped #{failed}\", :green)\n      end\n\n      if options[:followers]\n        processed = 0\n        failed    = 0\n\n        say(\"Removing #{account.username}'s followers, this might take a while...\")\n\n        Account.where(id: ::Follow.where(target_account: account).select(:account_id)).find_each do |target_account|\n          begin\n            UnfollowService.new.call(target_account, account)\n            processed += 1\n            say('.', :green, false)\n          rescue StandardError\n            failed += 1\n            say('.', :red, false)\n          end\n        end\n\n        say(\"OK, removed #{processed} followers, skipped #{failed}\", :green)\n      end\n    end\n\n    option :number, type: :numeric, aliases: [:n]\n    option :all, type: :boolean\n    desc 'approve [USERNAME]', 'Approve pending accounts'\n    long_desc <<~LONG_DESC\n      When registrations require review from staff, approve pending accounts,\n      either all of them with the --all option, or a specific number of them\n      specified with the --number (-n) option, or only a single specific\n      account identified by its username.\n    LONG_DESC\n    def approve(username = nil)\n      if options[:all]\n        User.pending.find_each(&:approve!)\n        say('OK', :green)\n      elsif options[:number]\n        User.pending.limit(options[:number]).each(&:approve!)\n        say('OK', :green)\n      elsif username.present?\n        account = Account.find_local(username)\n\n        if account.nil?\n          say('No such account', :red)\n          exit(1)\n        end\n\n        account.user&.approve!\n        say('OK', :green)\n      else\n        exit(1)\n      end\n    end\n\n    private\n\n    def rotate_keys_for_account(account, delay = 0)\n      if account.nil?\n        say('No such account', :red)\n        exit(1)\n      end\n\n      old_key = account.private_key\n      new_key = OpenSSL::PKey::RSA.new(2048)\n      account.update(private_key: new_key.to_pem, public_key: new_key.public_key.to_pem)\n      ActivityPub::UpdateDistributionWorker.perform_in(delay, account.id, sign_with: old_key)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mastodon/cache_cli.rb",
    "content": "# frozen_string_literal: true\n\nrequire_relative '../../config/boot'\nrequire_relative '../../config/environment'\nrequire_relative 'cli_helper'\n\nmodule Mastodon\n  class CacheCLI < Thor\n    def self.exit_on_failure?\n      true\n    end\n\n    desc 'clear', 'Clear out the cache storage'\n    def clear\n      Rails.cache.clear\n      say('OK', :green)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mastodon/cli_helper.rb",
    "content": "# frozen_string_literal: true\n\ndev_null = Logger.new('/dev/null')\n\nRails.logger                 = dev_null\nActiveRecord::Base.logger    = dev_null\nActiveJob::Base.logger       = dev_null\nHttpLog.configuration.logger = dev_null\nPaperclip.options[:log]      = false\n"
  },
  {
    "path": "lib/mastodon/domains_cli.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'concurrent'\nrequire_relative '../../config/boot'\nrequire_relative '../../config/environment'\nrequire_relative 'cli_helper'\n\nmodule Mastodon\n  class DomainsCLI < Thor\n    def self.exit_on_failure?\n      true\n    end\n\n    option :dry_run, type: :boolean\n    desc 'purge DOMAIN', 'Remove accounts from a DOMAIN without a trace'\n    long_desc <<-LONG_DESC\n      Remove all accounts from a given DOMAIN without leaving behind any\n      records. Unlike a suspension, if the DOMAIN still exists in the wild,\n      it means the accounts could return if they are resolved again.\n    LONG_DESC\n    def purge(domain)\n      removed = 0\n      dry_run = options[:dry_run] ? ' (DRY RUN)' : ''\n\n      Account.where(domain: domain).find_each do |account|\n        SuspendAccountService.new.call(account, destroy: true) unless options[:dry_run]\n        removed += 1\n        say('.', :green, false)\n      end\n\n      DomainBlock.where(domain: domain).destroy_all unless options[:dry_run]\n\n      say\n      say(\"Removed #{removed} accounts#{dry_run}\", :green)\n\n      custom_emojis = CustomEmoji.where(domain: domain)\n      custom_emojis_count = custom_emojis.count\n      custom_emojis.destroy_all unless options[:dry_run]\n      say(\"Removed #{custom_emojis_count} custom emojis\", :green)\n    end\n\n    option :concurrency, type: :numeric, default: 50, aliases: [:c]\n    option :silent, type: :boolean, default: false, aliases: [:s]\n    option :format, type: :string, default: 'summary', aliases: [:f]\n    desc 'crawl [START]', 'Crawl all known peers, optionally beginning at START'\n    long_desc <<-LONG_DESC\n      Crawl the fediverse by using the Mastodon REST API endpoints that expose\n      all known peers, and collect statistics from those peers, as long as those\n      peers support those API endpoints. When no START is given, the command uses\n      this server's own database of known peers to seed the crawl.\n\n      The --concurrency (-c) option controls the number of threads performing HTTP\n      requests at the same time. More threads means the crawl may complete faster.\n\n      The --silent (-s) option controls progress output.\n\n      The --format (-f) option controls how the data is displayed at the end. By\n      default (`summary`), a summary of the statistics is returned. The other options\n      are `domains`, which returns a newline-delimited list of all discovered peers,\n      and `json`, which dumps all the aggregated data raw.\n    LONG_DESC\n    def crawl(start = nil)\n      stats     = Concurrent::Hash.new\n      processed = Concurrent::AtomicFixnum.new(0)\n      failed    = Concurrent::AtomicFixnum.new(0)\n      start_at  = Time.now.to_f\n      seed      = start ? [start] : Account.remote.domains\n\n      pool = Concurrent::ThreadPoolExecutor.new(min_threads: 0, max_threads: options[:concurrency], idletime: 10, auto_terminate: true, max_queue: 0)\n\n      work_unit = ->(domain) do\n        next if stats.key?(domain)\n        stats[domain] = nil\n        processed.increment\n\n        begin\n          Request.new(:get, \"https://#{domain}/api/v1/instance\").perform do |res|\n            next unless res.code == 200\n            stats[domain] = Oj.load(res.to_s)\n          end\n\n          Request.new(:get, \"https://#{domain}/api/v1/instance/peers\").perform do |res|\n            next unless res.code == 200\n\n            Oj.load(res.to_s).reject { |peer| stats.key?(peer) }.each do |peer|\n              pool.post(peer, &work_unit)\n            end\n          end\n\n          Request.new(:get, \"https://#{domain}/api/v1/instance/activity\").perform do |res|\n            next unless res.code == 200\n            stats[domain]['activity'] = Oj.load(res.to_s)\n          end\n\n          say('.', :green, false) unless options[:silent]\n        rescue StandardError\n          failed.increment\n          say('.', :red, false) unless options[:silent]\n        end\n      end\n\n      seed.each do |domain|\n        pool.post(domain, &work_unit)\n      end\n\n      sleep 20\n      sleep 20 until pool.queue_length.zero?\n\n      pool.shutdown\n      pool.wait_for_termination(20)\n    ensure\n      pool.shutdown\n\n      say unless options[:silent]\n\n      case options[:format]\n      when 'summary'\n        stats_to_summary(stats, processed, failed, start_at)\n      when 'domains'\n        stats_to_domains(stats)\n      when 'json'\n        stats_to_json(stats)\n      end\n    end\n\n    private\n\n    def stats_to_summary(stats, processed, failed, start_at)\n      stats.compact!\n\n      total_domains = stats.size\n      total_users   = stats.reduce(0) { |sum, (_key, val)| val.is_a?(Hash) && val['stats'].is_a?(Hash) ? sum + val['stats']['user_count'].to_i : sum }\n      total_active  = stats.reduce(0) { |sum, (_key, val)| val.is_a?(Hash) && val['activity'].is_a?(Array) && val['activity'].size > 2 && val['activity'][1].is_a?(Hash) ? sum + val['activity'][1]['logins'].to_i : sum }\n      total_joined  = stats.reduce(0) { |sum, (_key, val)| val.is_a?(Hash) && val['activity'].is_a?(Array) && val['activity'].size > 2 && val['activity'][1].is_a?(Hash) ? sum + val['activity'][1]['registrations'].to_i : sum }\n\n      say(\"Visited #{processed.value} domains, #{failed.value} failed (#{(Time.now.to_f - start_at).round}s elapsed)\", :green)\n      say(\"Total servers: #{total_domains}\", :green)\n      say(\"Total registered: #{total_users}\", :green)\n      say(\"Total active last week: #{total_active}\", :green)\n      say(\"Total joined last week: #{total_joined}\", :green)\n    end\n\n    def stats_to_domains(stats)\n      say(stats.keys.join(\"\\n\"))\n    end\n\n    def stats_to_json(stats)\n      stats.compact!\n      say(Oj.dump(stats))\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mastodon/emoji_cli.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rubygems/package'\nrequire_relative '../../config/boot'\nrequire_relative '../../config/environment'\nrequire_relative 'cli_helper'\n\nmodule Mastodon\n  class EmojiCLI < Thor\n    def self.exit_on_failure?\n      true\n    end\n\n    option :prefix\n    option :suffix\n    option :overwrite, type: :boolean\n    option :unlisted, type: :boolean\n    desc 'import PATH', 'Import emoji from a TAR GZIP archive at PATH'\n    long_desc <<-LONG_DESC\n      Imports custom emoji from a TAR GZIP archive specified by PATH.\n\n      Existing emoji will be skipped unless the --overwrite option\n      is provided, in which case they will be overwritten.\n\n      With the --prefix option, a prefix can be added to all\n      generated shortcodes. Likewise, the --suffix option controls\n      the suffix of all shortcodes.\n\n      With the --unlisted option, the processed emoji will not be\n      visible in the emoji picker (but still usable via other means)\n    LONG_DESC\n    def import(path)\n      imported = 0\n      skipped  = 0\n      failed   = 0\n\n      Gem::Package::TarReader.new(Zlib::GzipReader.open(path)) do |tar|\n        tar.each do |entry|\n          next unless entry.file? && entry.full_name.end_with?('.png')\n\n          shortcode    = [options[:prefix], File.basename(entry.full_name, '.*'), options[:suffix]].compact.join\n          custom_emoji = CustomEmoji.local.find_by(shortcode: shortcode)\n\n          if custom_emoji && !options[:overwrite]\n            skipped += 1\n            next\n          end\n\n          custom_emoji ||= CustomEmoji.new(shortcode: shortcode, domain: nil)\n          custom_emoji.image = StringIO.new(entry.read)\n          custom_emoji.image_file_name = File.basename(entry.full_name)\n          custom_emoji.visible_in_picker = !options[:unlisted]\n\n          if custom_emoji.save\n            imported += 1\n          else\n            failed += 1\n            say('Failure/Error: ', :red)\n            say(entry.full_name)\n            say('    ' + custom_emoji.errors[:image].join(', '), :red)\n          end\n        end\n      end\n\n      puts\n      say(\"Imported #{imported}, skipped #{skipped}, failed to import #{failed}\", color(imported, skipped, failed))\n    end\n\n    desc 'purge', 'Remove all custom emoji'\n    def purge\n      CustomEmoji.in_batches.destroy_all\n      say('OK', :green)\n    end\n\n    private\n\n    def color(green, _yellow, red)\n      if !green.zero? && red.zero?\n        :green\n      elsif red.zero?\n        :yellow\n      else\n        :red\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mastodon/feeds_cli.rb",
    "content": "# frozen_string_literal: true\n\nrequire_relative '../../config/boot'\nrequire_relative '../../config/environment'\nrequire_relative 'cli_helper'\n\nmodule Mastodon\n  class FeedsCLI < Thor\n    def self.exit_on_failure?\n      true\n    end\n\n    option :all, type: :boolean, default: false\n    option :background, type: :boolean, default: false\n    option :dry_run, type: :boolean, default: false\n    option :verbose, type: :boolean, default: false\n    desc 'build [USERNAME]', 'Build home and list feeds for one or all users'\n    long_desc <<-LONG_DESC\n      Build home and list feeds that are stored in Redis from the database.\n\n      With the --all option, all active users will be processed.\n      Otherwise, a single user specified by USERNAME.\n\n      With the --background option, regeneration will be queued into Sidekiq,\n      and the command will exit as soon as possible.\n\n      With the --dry-run option, no work will be done.\n\n      With the --verbose option, when accounts are processed sequentially in the\n      foreground, the IDs of the accounts will be printed.\n    LONG_DESC\n    def build(username = nil)\n      dry_run = options[:dry_run] ? '(DRY RUN)' : ''\n\n      if options[:all] || username.nil?\n        processed = 0\n        queued    = 0\n\n        User.active.select(:id, :account_id).reorder(nil).find_in_batches do |users|\n          if options[:background]\n            RegenerationWorker.push_bulk(users.map(&:account_id)) unless options[:dry_run]\n            queued += users.size\n          else\n            users.each do |user|\n              RegenerationWorker.new.perform(user.account_id) unless options[:dry_run]\n              options[:verbose] ? say(user.account_id) : say('.', :green, false)\n              processed += 1\n            end\n          end\n        end\n\n        if options[:background]\n          say(\"Scheduled feed regeneration for #{queued} accounts #{dry_run}\", :green, true)\n        else\n          say\n          say(\"Regenerated feeds for #{processed} accounts #{dry_run}\", :green, true)\n        end\n      elsif username.present?\n        account = Account.find_local(username)\n\n        if account.nil?\n          say('No such account', :red)\n          exit(1)\n        end\n\n        if options[:background]\n          RegenerationWorker.perform_async(account.id) unless options[:dry_run]\n        else\n          RegenerationWorker.new.perform(account.id) unless options[:dry_run]\n        end\n\n        say(\"OK #{dry_run}\", :green, true)\n      else\n        say('No account(s) given', :red)\n        exit(1)\n      end\n    end\n\n    desc 'clear', 'Remove all home and list feeds from Redis'\n    def clear\n      keys = Redis.current.keys('feed:*')\n\n      Redis.current.pipelined do\n        keys.each { |key| Redis.current.del(key) }\n      end\n\n      say('OK', :green)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mastodon/media_cli.rb",
    "content": "# frozen_string_literal: true\n\nrequire_relative '../../config/boot'\nrequire_relative '../../config/environment'\nrequire_relative 'cli_helper'\n\nmodule Mastodon\n  class MediaCLI < Thor\n    include ActionView::Helpers::NumberHelper\n\n    def self.exit_on_failure?\n      true\n    end\n\n    option :days, type: :numeric, default: 7\n    option :background, type: :boolean, default: false\n    option :verbose, type: :boolean, default: false\n    option :dry_run, type: :boolean, default: false\n    desc 'remove', 'Remove remote media files'\n    long_desc <<-DESC\n      Removes locally cached copies of media attachments from other servers.\n\n      The --days option specifies how old media attachments have to be before\n      they are removed. It defaults to 7 days.\n\n      With the --background option, instead of deleting the files sequentially,\n      they will be queued into Sidekiq and the command will exit as soon as\n      possible. In Sidekiq they will be processed with higher concurrency, but\n      it may impact other operations of the Mastodon server, and it may overload\n      the underlying file storage.\n\n      With the --dry-run option, no work will be done.\n\n      With the --verbose option, when media attachments are processed sequentially in the\n      foreground, the IDs of the media attachments will be printed.\n    DESC\n    def remove\n      time_ago  = options[:days].days.ago\n      queued    = 0\n      processed = 0\n      size      = 0\n      dry_run   = options[:dry_run] ? '(DRY RUN)' : ''\n\n      if options[:background]\n        MediaAttachment.where.not(remote_url: '').where.not(file_file_name: nil).where('created_at < ?', time_ago).select(:id, :file_file_size).reorder(nil).find_in_batches do |media_attachments|\n          queued += media_attachments.size\n          size   += media_attachments.reduce(0) { |sum, m| sum + (m.file_file_size || 0) }\n          Maintenance::UncacheMediaWorker.push_bulk(media_attachments.map(&:id)) unless options[:dry_run]\n        end\n      else\n        MediaAttachment.where.not(remote_url: '').where.not(file_file_name: nil).where('created_at < ?', time_ago).reorder(nil).find_in_batches do |media_attachments|\n          media_attachments.each do |m|\n            size += m.file_file_size || 0\n            Maintenance::UncacheMediaWorker.new.perform(m) unless options[:dry_run]\n            options[:verbose] ? say(m.id) : say('.', :green, false)\n            processed += 1\n          end\n        end\n      end\n\n      say\n\n      if options[:background]\n        say(\"Scheduled the deletion of #{queued} media attachments (approx. #{number_to_human_size(size)}) #{dry_run}\", :green, true)\n      else\n        say(\"Removed #{processed} media attachments (approx. #{number_to_human_size(size)}) #{dry_run}\", :green, true)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mastodon/migration_helpers.rb",
    "content": "# frozen_string_literal: true\n\n# This file is copied almost entirely from GitLab, which has done a large\n# amount of work to ensure that migrations can happen with minimal downtime.\n# Many thanks to those engineers.\n\n# Changes have been made to remove dependencies on other GitLab files and to\n# shorten temporary column names.\n\n# Documentation on using these functions (and why one might do so):\n# https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/development/what_requires_downtime.md\n\n# The file itself:\n# https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/database/migration_helpers.rb\n\n# It is licensed as follows:\n\n# Copyright (c) 2011-2017 GitLab B.V.\n\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n# THE SOFTWARE.\n\n# This is bad form, but there are enough differences that it's impractical to do\n# otherwise:\n# rubocop:disable all\n\nmodule Mastodon\n  module MigrationHelpers\n    # Stub for Database.postgresql? from GitLab\n    def self.postgresql?\n      ActiveRecord::Base.configurations[Rails.env]['adapter'].casecmp('postgresql').zero?\n    end\n\n    # Stub for Database.mysql? from GitLab\n    def self.mysql?\n      ActiveRecord::Base.configurations[Rails.env]['adapter'].casecmp('mysql2').zero?\n    end\n\n    # Model that can be used for querying permissions of a SQL user.\n    class Grant < ActiveRecord::Base\n      self.table_name =\n        if Mastodon::MigrationHelpers.postgresql?\n          'information_schema.role_table_grants'\n        else\n          'mysql.user'\n        end\n\n      def self.scope_to_current_user\n        if Mastodon::MigrationHelpers.postgresql?\n          where('grantee = user')\n        else\n          where(\"CONCAT(User, '@', Host) = current_user()\")\n        end\n      end\n\n      # Returns true if the current user can create and execute triggers on the\n      # given table.\n      def self.create_and_execute_trigger?(table)\n        priv =\n          if Mastodon::MigrationHelpers.postgresql?\n            where(privilege_type: 'TRIGGER', table_name: table)\n          else\n            where(Trigger_priv: 'Y')\n          end\n\n        priv.scope_to_current_user.any?\n      end\n    end\n\n    BACKGROUND_MIGRATION_BATCH_SIZE = 1000 # Number of rows to process per job\n    BACKGROUND_MIGRATION_JOB_BUFFER_SIZE = 1000 # Number of jobs to bulk queue at a time\n\n    # Gets an estimated number of rows for a table\n    def estimate_rows_in_table(table_name)\n      exec_query('SELECT reltuples FROM pg_class WHERE relname = ' +\n        \"'#{table_name}'\").to_a.first['reltuples']\n    end\n\n    # Adds `created_at` and `updated_at` columns with timezone information.\n    #\n    # This method is an improved version of Rails' built-in method `add_timestamps`.\n    #\n    # Available options are:\n    # default - The default value for the column.\n    # null - When set to `true` the column will allow NULL values.\n    #        The default is to not allow NULL values.\n    def add_timestamps_with_timezone(table_name, **options)\n      options[:null] = false if options[:null].nil?\n\n      [:created_at, :updated_at].each do |column_name|\n        if options[:default] && transaction_open?\n          raise '`add_timestamps_with_timezone` with default value cannot be run inside a transaction. ' \\\n            'You can disable transactions by calling `disable_ddl_transaction!` ' \\\n            'in the body of your migration class'\n        end\n\n        # If default value is presented, use `add_column_with_default` method instead.\n        if options[:default]\n          add_column_with_default(\n            table_name,\n            column_name,\n            :datetime_with_timezone,\n            default: options[:default],\n            allow_null: options[:null]\n          )\n        else\n          add_column(table_name, column_name, :datetime_with_timezone, options)\n        end\n      end\n    end\n\n    # Creates a new index, concurrently when supported\n    #\n    # On PostgreSQL this method creates an index concurrently, on MySQL this\n    # creates a regular index.\n    #\n    # Example:\n    #\n    #     add_concurrent_index :users, :some_column\n    #\n    # See Rails' `add_index` for more info on the available arguments.\n    def add_concurrent_index(table_name, column_name, **options)\n      if transaction_open?\n        raise 'add_concurrent_index can not be run inside a transaction, ' \\\n          'you can disable transactions by calling disable_ddl_transaction! ' \\\n          'in the body of your migration class'\n      end\n\n      if MigrationHelpers.postgresql?\n        options = options.merge({ algorithm: :concurrently })\n        disable_statement_timeout\n      end\n\n      add_index(table_name, column_name, options)\n    end\n\n    # Removes an existed index, concurrently when supported\n    #\n    # On PostgreSQL this method removes an index concurrently.\n    #\n    # Example:\n    #\n    #     remove_concurrent_index :users, :some_column\n    #\n    # See Rails' `remove_index` for more info on the available arguments.\n    def remove_concurrent_index(table_name, column_name, **options)\n      if transaction_open?\n        raise 'remove_concurrent_index can not be run inside a transaction, ' \\\n          'you can disable transactions by calling disable_ddl_transaction! ' \\\n          'in the body of your migration class'\n      end\n\n      if supports_drop_index_concurrently?\n        options = options.merge({ algorithm: :concurrently })\n        disable_statement_timeout\n      end\n\n      remove_index(table_name, options.merge({ column: column_name }))\n    end\n\n    # Removes an existing index, concurrently when supported\n    #\n    # On PostgreSQL this method removes an index concurrently.\n    #\n    # Example:\n    #\n    #     remove_concurrent_index :users, \"index_X_by_Y\"\n    #\n    # See Rails' `remove_index` for more info on the available arguments.\n    def remove_concurrent_index_by_name(table_name, index_name, **options)\n      if transaction_open?\n        raise 'remove_concurrent_index_by_name can not be run inside a transaction, ' \\\n          'you can disable transactions by calling disable_ddl_transaction! ' \\\n          'in the body of your migration class'\n      end\n\n      if supports_drop_index_concurrently?\n        options = options.merge({ algorithm: :concurrently })\n        disable_statement_timeout\n      end\n\n      remove_index(table_name, options.merge({ name: index_name }))\n    end\n\n    # Only available on Postgresql >= 9.2\n    def supports_drop_index_concurrently?\n      return false unless MigrationHelpers.postgresql?\n\n      version = select_one(\"SELECT current_setting('server_version_num') AS v\")['v'].to_i\n\n      version >= 90200\n    end\n\n    # Adds a foreign key with only minimal locking on the tables involved.\n    #\n    # This method only requires minimal locking when using PostgreSQL. When\n    # using MySQL this method will use Rails' default `add_foreign_key`.\n    #\n    # source - The source table containing the foreign key.\n    # target - The target table the key points to.\n    # column - The name of the column to create the foreign key on.\n    # on_delete - The action to perform when associated data is removed,\n    #             defaults to \"CASCADE\".\n    def add_concurrent_foreign_key(source, target, column:, on_delete: :cascade, target_col: 'id')\n      # Transactions would result in ALTER TABLE locks being held for the\n      # duration of the transaction, defeating the purpose of this method.\n      if transaction_open?\n        raise 'add_concurrent_foreign_key can not be run inside a transaction'\n      end\n\n      # While MySQL does allow disabling of foreign keys it has no equivalent\n      # of PostgreSQL's \"VALIDATE CONSTRAINT\". As a result we'll just fall\n      # back to the normal foreign key procedure.\n      if MigrationHelpers.mysql?\n        return add_foreign_key(source, target,\n                               column: column,\n                               on_delete: on_delete)\n      else\n        on_delete = 'SET NULL' if on_delete == :nullify\n      end\n\n      disable_statement_timeout\n\n      key_name = concurrent_foreign_key_name(source, column, target_col)\n\n      # Using NOT VALID allows us to create a key without immediately\n      # validating it. This means we keep the ALTER TABLE lock only for a\n      # short period of time. The key _is_ enforced for any newly created\n      # data.\n      execute <<-EOF.strip_heredoc\n      ALTER TABLE #{source}\n      ADD CONSTRAINT #{key_name}\n      FOREIGN KEY (#{column})\n      REFERENCES #{target} (#{target_col})\n      #{on_delete ? \"ON DELETE #{on_delete.upcase}\" : ''}\n      NOT VALID;\n      EOF\n\n      # Validate the existing constraint. This can potentially take a very\n      # long time to complete, but fortunately does not lock the source table\n      # while running.\n      execute(\"ALTER TABLE #{source} VALIDATE CONSTRAINT #{key_name};\")\n    end\n\n    # Returns the name for a concurrent foreign key.\n    #\n    # PostgreSQL constraint names have a limit of 63 bytes. The logic used\n    # here is based on Rails' foreign_key_name() method, which unfortunately\n    # is private so we can't rely on it directly.\n    def concurrent_foreign_key_name(table, column, target_col)\n      \"fk_#{Digest::SHA256.hexdigest(\"#{table}_#{column}_#{target_col}_fk\").first(10)}\"\n    end\n\n    # Long-running migrations may take more than the timeout allowed by\n    # the database. Disable the session's statement timeout to ensure\n    # migrations don't get killed prematurely. (PostgreSQL only)\n    def disable_statement_timeout\n      execute('SET statement_timeout TO 0') if MigrationHelpers.postgresql?\n    end\n\n    # Updates the value of a column in batches.\n    #\n    # This method updates the table in batches of 5% of the total row count.\n    # This method will continue updating rows until no rows remain.\n    #\n    # When given a block this method will yield two values to the block:\n    #\n    # 1. An instance of `Arel::Table` for the table that is being updated.\n    # 2. The query to run as an Arel object.\n    #\n    # By supplying a block one can add extra conditions to the queries being\n    # executed. Note that the same block is used for _all_ queries.\n    #\n    # Example:\n    #\n    #     update_column_in_batches(:projects, :foo, 10) do |table, query|\n    #       query.where(table[:some_column].eq('hello'))\n    #     end\n    #\n    # This would result in this method updating only rows where\n    # `projects.some_column` equals \"hello\".\n    #\n    # table - The name of the table.\n    # column - The name of the column to update.\n    # value - The value for the column.\n    #\n    # Rubocop's Metrics/AbcSize metric is disabled for this method as Rubocop\n    # determines this method to be too complex while there's no way to make it\n    # less \"complex\" without introducing extra methods (which actually will\n    # make things _more_ complex).\n    #\n    # rubocop: disable Metrics/AbcSize\n    def update_column_in_batches(table_name, column, value)\n      if transaction_open?\n        raise 'update_column_in_batches can not be run inside a transaction, ' \\\n          'you can disable transactions by calling disable_ddl_transaction! ' \\\n          'in the body of your migration class'\n      end\n\n      table = Arel::Table.new(table_name)\n\n      total = estimate_rows_in_table(table_name).to_i\n      if total == 0\n        count_arel = table.project(Arel.star.count.as('count'))\n        count_arel = yield table, count_arel if block_given?\n\n        total = exec_query(count_arel.to_sql).to_hash.first['count'].to_i\n\n        return if total == 0\n      end\n\n      # Update in batches of 5% until we run out of any rows to update.\n      batch_size = ((total / 100.0) * 5.0).ceil\n      max_size = 1000\n\n      # The upper limit is 1000 to ensure we don't lock too many rows. For\n      # example, for \"merge_requests\" even 1% of the table is around 35 000\n      # rows for GitLab.com.\n      batch_size = max_size if batch_size > max_size\n\n      start_arel = table.project(table[:id]).order(table[:id].asc).take(1)\n      start_arel = yield table, start_arel if block_given?\n      first_row = exec_query(start_arel.to_sql).to_hash.first\n      # In case there are no rows but we didn't catch it in the estimated size:\n      return unless first_row\n      start_id = first_row['id'].to_i\n\n      say \"Migrating #{table_name}.#{column} (~#{total.to_i} rows)\"\n\n      started_time = Time.zone.now\n      last_time = Time.zone.now\n      migrated = 0\n      loop do\n        stop_row = nil\n\n        suppress_messages do\n          stop_arel = table.project(table[:id])\n            .where(table[:id].gteq(start_id))\n            .order(table[:id].asc)\n            .take(1)\n            .skip(batch_size)\n\n          stop_arel = yield table, stop_arel if block_given?\n          stop_row = exec_query(stop_arel.to_sql).to_hash.first\n\n          update_arel = Arel::UpdateManager.new\n            .table(table)\n            .set([[table[column], value]])\n            .where(table[:id].gteq(start_id))\n\n          if stop_row\n            stop_id = stop_row['id'].to_i\n            start_id = stop_id\n            update_arel = update_arel.where(table[:id].lt(stop_id))\n          end\n\n          update_arel = yield table, update_arel if block_given?\n\n          execute(update_arel.to_sql)\n        end\n\n        migrated += batch_size\n        if Time.zone.now - last_time > 1\n          status = \"Migrated #{migrated} rows\"\n\n          percentage = 100.0 * migrated / total\n          status += \" (~#{sprintf('%.2f', percentage)}%, \"\n\n          remaining_time = (100.0 - percentage) * (Time.zone.now - started_time) / percentage\n\n          status += \"#{(remaining_time / 60).to_i}:\"\n          status += sprintf('%02d', remaining_time.to_i % 60)\n          status += ' remaining, '\n\n          # Tell users not to interrupt if we're almost done.\n          if remaining_time > 10\n            status += 'safe to interrupt'\n          else\n            status += 'DO NOT interrupt'\n          end\n\n          status += ')'\n\n          say status, true\n          last_time = Time.zone.now\n        end\n\n        # There are no more rows left to update.\n        break unless stop_row\n      end\n    end\n\n    # Adds a column with a default value without locking an entire table.\n    #\n    # This method runs the following steps:\n    #\n    # 1. Add the column with a default value of NULL.\n    # 2. Change the default value of the column to the specified value.\n    # 3. Update all existing rows in batches.\n    # 4. Set a `NOT NULL` constraint on the column if desired (the default).\n    #\n    # These steps ensure a column can be added to a large and commonly used\n    # table without locking the entire table for the duration of the table\n    # modification.\n    #\n    # table - The name of the table to update.\n    # column - The name of the column to add.\n    # type - The column type (e.g. `:integer`).\n    # default - The default value for the column.\n    # limit - Sets a column limit. For example, for :integer, the default is\n    #         4-bytes. Set `limit: 8` to allow 8-byte integers.\n    # allow_null - When set to `true` the column will allow NULL values, the\n    #              default is to not allow NULL values.\n    #\n    # This method can also take a block which is passed directly to the\n    # `update_column_in_batches` method.\n    def add_column_with_default(table, column, type, default:, limit: nil, allow_null: false, &block)\n      if transaction_open?\n        raise 'add_column_with_default can not be run inside a transaction, ' \\\n          'you can disable transactions by calling disable_ddl_transaction! ' \\\n          'in the body of your migration class'\n      end\n\n      disable_statement_timeout\n\n      transaction do\n        if limit\n          add_column(table, column, type, default: nil, limit: limit)\n        else\n          add_column(table, column, type, default: nil)\n        end\n\n        # Changing the default before the update ensures any newly inserted\n        # rows already use the proper default value.\n        change_column_default(table, column, default)\n      end\n\n      begin\n        update_column_in_batches(table, column, default, &block)\n\n        change_column_null(table, column, false) unless allow_null\n      # We want to rescue _all_ exceptions here, even those that don't inherit\n      # from StandardError.\n      rescue Exception => error # rubocop: disable all\n        remove_column(table, column)\n\n        raise error\n      end\n    end\n\n    # Renames a column without requiring downtime.\n    #\n    # Concurrent renames work by using database triggers to ensure both the\n    # old and new column are in sync. However, this method will _not_ remove\n    # the triggers or the old column automatically; this needs to be done\n    # manually in a post-deployment migration. This can be done using the\n    # method `cleanup_concurrent_column_rename`.\n    #\n    # table - The name of the database table containing the column.\n    # old - The old column name.\n    # new - The new column name.\n    # type - The type of the new column. If no type is given the old column's\n    #        type is used.\n    def rename_column_concurrently(table, old, new, type: nil)\n      if transaction_open?\n        raise 'rename_column_concurrently can not be run inside a transaction'\n      end\n\n      check_trigger_permissions!(table)\n      trigger_name = rename_trigger_name(table, old, new)\n\n      # If we were in the middle of update_column_in_batches, we should remove\n      # the old column and start over, as we have no idea where we were.\n      if column_for(table, new)\n        if MigrationHelpers.postgresql?\n          remove_rename_triggers_for_postgresql(table, trigger_name)\n        else\n          remove_rename_triggers_for_mysql(trigger_name)\n        end\n\n        remove_column(table, new)\n      end\n\n      old_col = column_for(table, old)\n      new_type = type || old_col.type\n\n      col_opts = {\n        precision: old_col.precision,\n        scale: old_col.scale,\n      }\n\n      # We may be trying to reset the limit on an integer column type, so let\n      # Rails handle that.\n      unless [:bigint, :integer].include?(new_type)\n        col_opts[:limit] = old_col.limit\n      end\n\n      add_column(table, new, new_type, col_opts)\n\n      # We set the default value _after_ adding the column so we don't end up\n      # updating any existing data with the default value. This isn't\n      # necessary since we copy over old values further down.\n      change_column_default(table, new, old_col.default) if old_col.default\n\n      quoted_table = quote_table_name(table)\n      quoted_old = quote_column_name(old)\n      quoted_new = quote_column_name(new)\n\n      if MigrationHelpers.postgresql?\n        install_rename_triggers_for_postgresql(trigger_name, quoted_table,\n                                               quoted_old, quoted_new)\n      else\n        install_rename_triggers_for_mysql(trigger_name, quoted_table,\n                                          quoted_old, quoted_new)\n      end\n\n      update_column_in_batches(table, new, Arel::Table.new(table)[old])\n\n      change_column_null(table, new, false) unless old_col.null\n\n      copy_indexes(table, old, new)\n      copy_foreign_keys(table, old, new)\n    end\n\n    # Changes the type of a column concurrently.\n    #\n    # table - The table containing the column.\n    # column - The name of the column to change.\n    # new_type - The new column type.\n    def change_column_type_concurrently(table, column, new_type)\n      temp_column = rename_column_name(column)\n\n      rename_column_concurrently(table, column, temp_column, type: new_type)\n\n      # Primary keys don't necessarily have an associated index.\n      if ActiveRecord::Base.get_primary_key(table) == column.to_s\n        old_pk_index_name = \"index_#{table}_on_#{column}\"\n        new_pk_index_name = \"index_#{table}_on_#{column}_cm\"\n\n        unless indexes_for(table, column).find{|i| i.name == old_pk_index_name}\n          add_concurrent_index(table, [temp_column], {\n            unique: true,\n            name: new_pk_index_name\n          })\n        end\n      end\n    end\n\n    # Performs cleanup of a concurrent type change.\n    #\n    # table - The table containing the column.\n    # column - The name of the column to change.\n    # new_type - The new column type.\n    def cleanup_concurrent_column_type_change(table, column)\n      temp_column = rename_column_name(column)\n\n      # Wait for the indices to be built\n      indexes_for(table, column).each do |index|\n        expected_name = index.name + '_cm'\n\n        puts \"Waiting for index #{expected_name}\"\n        sleep 1 until indexes_for(table, temp_column).find {|i| i.name == expected_name }\n      end\n\n      was_primary = (ActiveRecord::Base.get_primary_key(table) == column.to_s)\n      old_default_fn = column_for(table, column).default_function\n\n      old_fks = []\n      if was_primary\n        # Get any foreign keys pointing at this column we need to recreate, and\n        # remove the old ones.\n        # Based on code from:\n        # http://errorbank.blogspot.com/2011/03/list-all-foreign-keys-references-for.html\n        old_fks_res = execute <<-EOF.strip_heredoc\n          select m.relname as src_table,\n            (select a.attname\n              from pg_attribute a\n              where a.attrelid = m.oid\n                and a.attnum = o.conkey[1]\n                and a.attisdropped = false) as src_col,\n            o.conname as name,\n            o.confdeltype as on_delete\n          from pg_constraint o\n          left join pg_class f on f.oid = o.confrelid \n          left join pg_class c on c.oid = o.conrelid\n          left join pg_class m on m.oid = o.conrelid\n          where o.contype = 'f'\n            and o.conrelid in (\n              select oid from pg_class c where c.relkind = 'r')\n            and f.relname = '#{table}';\n          EOF\n        old_fks = old_fks_res.to_a\n        old_fks.each do |old_fk|\n          add_concurrent_foreign_key(\n            old_fk['src_table'],\n            table,\n            column: old_fk['src_col'],\n            target_col: temp_column,\n            on_delete: extract_foreign_key_action(old_fk['on_delete'])\n          )\n\n          remove_foreign_key(old_fk['src_table'], name: old_fk['name'])\n        end\n      end\n\n      # If there was a sequence owned by the old column, make it owned by the\n      # new column, as it will otherwise be deleted when we get rid of the\n      # old column.\n      if (seq_match = /^nextval\\('([^']*)'(::text|::regclass)?\\)/.match(old_default_fn))\n        seq_name = seq_match[1]\n        execute(\"ALTER SEQUENCE #{seq_name} OWNED BY #{table}.#{temp_column}\")\n      end\n\n      transaction do\n        # This has to be performed in a transaction as otherwise we might have\n        # inconsistent data.\n\n        cleanup_concurrent_column_rename(table, column, temp_column)\n        rename_column(table, temp_column, column)\n\n        # If there was an old default function, we didn't copy it. Do that now\n        # in the transaction, so we don't miss anything.\n        change_column_default(table, column, -> { old_default_fn }) if old_default_fn\n      end\n\n      # Rename any indices back to what they should be.\n      indexes_for(table, column).each do |index|\n        next unless index.name.end_with?('_cm')\n\n        real_index_name = index.name.sub(/_cm$/, '')\n        rename_index(table, index.name, real_index_name)\n      end\n\n      # Rename any foreign keys back to names based on the real column.\n      foreign_keys_for(table, column).each do |fk|\n        old_fk_name = concurrent_foreign_key_name(fk.from_table, temp_column, 'id')\n        new_fk_name = concurrent_foreign_key_name(fk.from_table, column, 'id')\n        execute(\"ALTER TABLE #{fk.from_table} RENAME CONSTRAINT \" +\n          \"#{old_fk_name} TO #{new_fk_name}\")\n      end\n\n      # Rename any foreign keys from other tables to names based on the real\n      # column.\n      old_fks.each do |old_fk|\n        old_fk_name = concurrent_foreign_key_name(old_fk['src_table'],\n          old_fk['src_col'], temp_column)\n        new_fk_name = concurrent_foreign_key_name(old_fk['src_table'],\n          old_fk['src_col'], column)\n        execute(\"ALTER TABLE #{old_fk['src_table']} RENAME CONSTRAINT \" +\n          \"#{old_fk_name} TO #{new_fk_name}\")\n      end\n\n      # If the old column was a primary key, mark the new one as a primary key.\n      if was_primary\n        execute(\"ALTER TABLE #{table} ADD PRIMARY KEY USING INDEX \" +\n          \"index_#{table}_on_#{column}\")\n      end\n    end\n\n    # Cleans up a concurrent column name.\n    #\n    # This method takes care of removing previously installed triggers as well\n    # as removing the old column.\n    #\n    # table - The name of the database table.\n    # old - The name of the old column.\n    # new - The name of the new column.\n    def cleanup_concurrent_column_rename(table, old, new)\n      trigger_name = rename_trigger_name(table, old, new)\n\n      check_trigger_permissions!(table)\n\n      if MigrationHelpers.postgresql?\n        remove_rename_triggers_for_postgresql(table, trigger_name)\n      else\n        remove_rename_triggers_for_mysql(trigger_name)\n      end\n\n      remove_column(table, old)\n    end\n\n    # Performs a concurrent column rename when using PostgreSQL.\n    def install_rename_triggers_for_postgresql(trigger, table, old, new)\n      execute <<-EOF.strip_heredoc\n      CREATE OR REPLACE FUNCTION #{trigger}()\n      RETURNS trigger AS\n      $BODY$\n      BEGIN\n        NEW.#{new} := NEW.#{old};\n        RETURN NEW;\n      END;\n      $BODY$\n      LANGUAGE 'plpgsql'\n      VOLATILE\n      EOF\n\n      execute <<-EOF.strip_heredoc\n      CREATE TRIGGER #{trigger}\n      BEFORE INSERT OR UPDATE\n      ON #{table}\n      FOR EACH ROW\n      EXECUTE PROCEDURE #{trigger}()\n      EOF\n    end\n\n    # Installs the triggers necessary to perform a concurrent column rename on\n    # MySQL.\n    def install_rename_triggers_for_mysql(trigger, table, old, new)\n      execute <<-EOF.strip_heredoc\n      CREATE TRIGGER #{trigger}_insert\n      BEFORE INSERT\n      ON #{table}\n      FOR EACH ROW\n      SET NEW.#{new} = NEW.#{old}\n      EOF\n\n      execute <<-EOF.strip_heredoc\n      CREATE TRIGGER #{trigger}_update\n      BEFORE UPDATE\n      ON #{table}\n      FOR EACH ROW\n      SET NEW.#{new} = NEW.#{old}\n      EOF\n    end\n\n    # Removes the triggers used for renaming a PostgreSQL column concurrently.\n    def remove_rename_triggers_for_postgresql(table, trigger)\n      execute(\"DROP TRIGGER IF EXISTS #{trigger} ON #{table}\")\n      execute(\"DROP FUNCTION IF EXISTS #{trigger}()\")\n    end\n\n    # Removes the triggers used for renaming a MySQL column concurrently.\n    def remove_rename_triggers_for_mysql(trigger)\n      execute(\"DROP TRIGGER IF EXISTS #{trigger}_insert\")\n      execute(\"DROP TRIGGER IF EXISTS #{trigger}_update\")\n    end\n\n    # Returns the (base) name to use for triggers when renaming columns.\n    def rename_trigger_name(table, old, new)\n      'trigger_' + Digest::SHA256.hexdigest(\"#{table}_#{old}_#{new}\").first(12)\n    end\n\n    # Returns the name to use for temporary rename columns.\n    def rename_column_name(base)\n      base.to_s + '_cm'\n    end\n\n    # Returns an Array containing the indexes for the given column\n    def indexes_for(table, column)\n      column = column.to_s\n\n      indexes(table).select { |index| index.columns.include?(column) }\n    end\n\n    # Returns an Array containing the foreign keys for the given column.\n    def foreign_keys_for(table, column)\n      column = column.to_s\n\n      foreign_keys(table).select { |fk| fk.column == column }\n    end\n\n    # Copies all indexes for the old column to a new column.\n    #\n    # table - The table containing the columns and indexes.\n    # old - The old column.\n    # new - The new column.\n    def copy_indexes(table, old, new)\n      old = old.to_s\n      new = new.to_s\n\n      indexes_for(table, old).each do |index|\n        new_columns = index.columns.map do |column|\n          column == old ? new : column\n        end\n\n        # This is necessary as we can't properly rename indexes such as\n        # \"ci_taggings_idx\".\n        name = index.name + '_cm'\n\n        # If the order contained the old column, map it to the new one.\n        order = index.orders\n        if order.key?(old)\n          order[new] = order.delete(old)\n        end\n\n        options = {\n          unique: index.unique,\n          name: name,\n          length: index.lengths,\n          order: order\n        }\n\n        # These options are not supported by MySQL, so we only add them if\n        # they were previously set.\n        options[:using] = index.using if index.using\n        options[:where] = index.where if index.where\n\n        add_concurrent_index(table, new_columns, options)\n      end\n    end\n\n    # Copies all foreign keys for the old column to the new column.\n    #\n    # table - The table containing the columns and indexes.\n    # old - The old column.\n    # new - The new column.\n    def copy_foreign_keys(table, old, new)\n      foreign_keys_for(table, old).each do |fk|\n        add_concurrent_foreign_key(fk.from_table,\n                                   fk.to_table,\n                                   column: new,\n                                   on_delete: fk.on_delete)\n      end\n    end\n\n    # Returns the column for the given table and column name.\n    def column_for(table, name)\n      name = name.to_s\n\n      columns(table).find { |column| column.name == name }\n    end\n\n    # This will replace the first occurrence of a string in a column with\n    # the replacement\n    # On postgresql we can use `regexp_replace` for that.\n    # On mysql we find the location of the pattern, and overwrite it\n    # with the replacement\n    def replace_sql(column, pattern, replacement)\n      quoted_pattern = Arel::Nodes::Quoted.new(pattern.to_s)\n      quoted_replacement = Arel::Nodes::Quoted.new(replacement.to_s)\n\n      if MigrationHelpers.mysql?\n        locate = Arel::Nodes::NamedFunction\n          .new('locate', [quoted_pattern, column])\n        insert_in_place = Arel::Nodes::NamedFunction\n          .new('insert', [column, locate, pattern.size, quoted_replacement])\n\n        Arel::Nodes::SqlLiteral.new(insert_in_place.to_sql)\n      else\n        replace = Arel::Nodes::NamedFunction\n          .new(\"regexp_replace\", [column, quoted_pattern, quoted_replacement])\n        Arel::Nodes::SqlLiteral.new(replace.to_sql)\n      end\n    end\n\n    def remove_foreign_key_without_error(*args)\n      remove_foreign_key(*args)\n    rescue ArgumentError\n    end\n\n    def sidekiq_queue_migrate(queue_from, to:)\n      while sidekiq_queue_length(queue_from) > 0\n        Sidekiq.redis do |conn|\n          conn.rpoplpush \"queue:#{queue_from}\", \"queue:#{to}\"\n        end\n      end\n    end\n\n    def sidekiq_queue_length(queue_name)\n      Sidekiq.redis do |conn|\n        conn.llen(\"queue:#{queue_name}\")\n      end\n    end\n\n    def check_trigger_permissions!(table)\n      unless Grant.create_and_execute_trigger?(table)\n        dbname = ActiveRecord::Base.configurations[Rails.env]['database']\n        user = ActiveRecord::Base.configurations[Rails.env]['username'] || ENV['USER']\n\n        raise <<-EOF\nYour database user is not allowed to create, drop, or execute triggers on the\ntable #{table}.\n\nIf you are using PostgreSQL you can solve this by logging in to the GitLab\ndatabase (#{dbname}) using a super user and running:\n\n    ALTER USER #{user} WITH SUPERUSER\n\nFor MySQL you instead need to run:\n\n    GRANT ALL PRIVILEGES ON *.* TO #{user}@'%'\n\nBoth queries will grant the user super user permissions, ensuring you don't run\ninto similar problems in the future (e.g. when new tables are created).\n        EOF\n      end\n    end\n\n    # Bulk queues background migration jobs for an entire table, batched by ID range.\n    # \"Bulk\" meaning many jobs will be pushed at a time for efficiency.\n    # If you need a delay interval per job, then use `queue_background_migration_jobs_by_range_at_intervals`.\n    #\n    # model_class - The table being iterated over\n    # job_class_name - The background migration job class as a string\n    # batch_size - The maximum number of rows per job\n    #\n    # Example:\n    #\n    #     class Route < ActiveRecord::Base\n    #       include EachBatch\n    #       self.table_name = 'routes'\n    #     end\n    #\n    #     bulk_queue_background_migration_jobs_by_range(Route, 'ProcessRoutes')\n    #\n    # Where the model_class includes EachBatch, and the background migration exists:\n    #\n    #     class Gitlab::BackgroundMigration::ProcessRoutes\n    #       def perform(start_id, end_id)\n    #         # do something\n    #       end\n    #     end\n    def bulk_queue_background_migration_jobs_by_range(model_class, job_class_name, batch_size: BACKGROUND_MIGRATION_BATCH_SIZE)\n      raise \"#{model_class} does not have an ID to use for batch ranges\" unless model_class.column_names.include?('id')\n\n      jobs = []\n\n      model_class.each_batch(of: batch_size) do |relation|\n        start_id, end_id = relation.pluck('MIN(id), MAX(id)').first\n\n        if jobs.length >= BACKGROUND_MIGRATION_JOB_BUFFER_SIZE\n          # Note: This code path generally only helps with many millions of rows\n          # We push multiple jobs at a time to reduce the time spent in\n          # Sidekiq/Redis operations. We're using this buffer based approach so we\n          # don't need to run additional queries for every range.\n          BackgroundMigrationWorker.perform_bulk(jobs)\n          jobs.clear\n        end\n\n        jobs << [job_class_name, [start_id, end_id]]\n      end\n\n      BackgroundMigrationWorker.perform_bulk(jobs) unless jobs.empty?\n    end\n\n    # Queues background migration jobs for an entire table, batched by ID range.\n    # Each job is scheduled with a `delay_interval` in between.\n    # If you use a small interval, then some jobs may run at the same time.\n    #\n    # model_class - The table being iterated over\n    # job_class_name - The background migration job class as a string\n    # delay_interval - The duration between each job's scheduled time (must respond to `to_f`)\n    # batch_size - The maximum number of rows per job\n    #\n    # Example:\n    #\n    #     class Route < ActiveRecord::Base\n    #       include EachBatch\n    #       self.table_name = 'routes'\n    #     end\n    #\n    #     queue_background_migration_jobs_by_range_at_intervals(Route, 'ProcessRoutes', 1.minute)\n    #\n    # Where the model_class includes EachBatch, and the background migration exists:\n    #\n    #     class Gitlab::BackgroundMigration::ProcessRoutes\n    #       def perform(start_id, end_id)\n    #         # do something\n    #       end\n    #     end\n    def queue_background_migration_jobs_by_range_at_intervals(model_class, job_class_name, delay_interval, batch_size: BACKGROUND_MIGRATION_BATCH_SIZE)\n      raise \"#{model_class} does not have an ID to use for batch ranges\" unless model_class.column_names.include?('id')\n\n      model_class.each_batch(of: batch_size) do |relation, index|\n        start_id, end_id = relation.pluck('MIN(id), MAX(id)').first\n\n        # `BackgroundMigrationWorker.bulk_perform_in` schedules all jobs for\n        # the same time, which is not helpful in most cases where we wish to\n        # spread the work over time.\n        BackgroundMigrationWorker.perform_in(delay_interval * index, job_class_name, [start_id, end_id])\n      end\n    end\n\n    private\n\n    # https://github.com/rails/rails/blob/v5.2.0/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb#L678-L684\n    def extract_foreign_key_action(specifier)\n      case specifier\n      when 'c'; :cascade\n      when 'n'; :nullify\n      when 'r'; :restrict\n      end\n    end\n  end\nend\n\n# rubocop:enable all\n"
  },
  {
    "path": "lib/mastodon/premailer_webpack_strategy.rb",
    "content": "# frozen_string_literal: true\n\nmodule PremailerWebpackStrategy\n  def load(url)\n    asset_host = ENV['CDN_HOST'] || ENV['WEB_DOMAIN'] || ENV['LOCAL_DOMAIN']\n\n    if Webpacker.dev_server.running?\n      asset_host = \"#{Webpacker.dev_server.protocol}://#{Webpacker.dev_server.host_with_port}\"\n      url        = File.join(asset_host, url)\n    end\n\n    css = if url.start_with?('http')\n            HTTP.get(url).to_s\n          else\n            url = url[1..-1] if url.start_with?('/')\n            File.read(Rails.root.join('public', url))\n          end\n\n    css.gsub(/url\\(\\//, \"url(#{asset_host}/\")\n  end\n\n  module_function :load\nend\n"
  },
  {
    "path": "lib/mastodon/redis_config.rb",
    "content": "# frozen_string_literal: true\n\ndef setup_redis_env_url(prefix = nil, defaults = true)\n  prefix = prefix.to_s.upcase + '_' unless prefix.nil?\n  prefix = '' if prefix.nil?\n\n  return if ENV[prefix + 'REDIS_URL'].present?\n\n  password = ENV.fetch(prefix + 'REDIS_PASSWORD') { '' if defaults }\n  host     = ENV.fetch(prefix + 'REDIS_HOST') { 'localhost' if defaults }\n  port     = ENV.fetch(prefix + 'REDIS_PORT') { 6379 if defaults }\n  db       = ENV.fetch(prefix + 'REDIS_DB') { 0 if defaults }\n\n  ENV[prefix + 'REDIS_URL'] = if [password, host, port, db].all?(&:nil?)\n                                ENV['REDIS_URL']\n                              else\n                                \"redis://#{password.blank? ? '' : \":#{password}@\"}#{host}:#{port}/#{db}\"\n                              end\nend\n\nsetup_redis_env_url\nsetup_redis_env_url(:cache, false)\n\nnamespace       = ENV.fetch('REDIS_NAMESPACE') { nil }\ncache_namespace = namespace ? namespace + '_cache' : 'cache'\n\nREDIS_CACHE_PARAMS = {\n  expires_in: 10.minutes,\n  namespace: cache_namespace,\n}.freeze\n"
  },
  {
    "path": "lib/mastodon/search_cli.rb",
    "content": "# frozen_string_literal: true\n\nrequire_relative '../../config/boot'\nrequire_relative '../../config/environment'\nrequire_relative 'cli_helper'\n\nmodule Mastodon\n  class SearchCLI < Thor\n    desc 'deploy', 'Create or update an ElasticSearch index and populate it'\n    long_desc <<~LONG_DESC\n      If ElasticSearch is empty, this command will create the necessary indices\n      and then import data from the database into those indices.\n\n      This command will also upgrade indices if the underlying schema has been\n      changed since the last run.\n    LONG_DESC\n    def deploy\n      processed = Chewy::RakeHelper.upgrade\n      Chewy::RakeHelper.sync(except: processed)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mastodon/settings_cli.rb",
    "content": "# frozen_string_literal: true\n\nrequire_relative '../../config/boot'\nrequire_relative '../../config/environment'\nrequire_relative 'cli_helper'\n\nmodule Mastodon\n  class RegistrationsCLI < Thor\n    def self.exit_on_failure?\n      true\n    end\n\n    desc 'open', 'Open registrations'\n    def open\n      Setting.registrations_mode = 'open'\n      say('OK', :green)\n    end\n\n    desc 'close', 'Close registrations'\n    def close\n      Setting.registrations_mode = 'none'\n      say('OK', :green)\n    end\n  end\n\n  class SettingsCLI < Thor\n    desc 'registrations SUBCOMMAND ...ARGS', 'Manage state of registrations'\n    subcommand 'registrations', RegistrationsCLI\n  end\nend\n"
  },
  {
    "path": "lib/mastodon/snowflake.rb",
    "content": "# frozen_string_literal: true\n\nmodule Mastodon::Snowflake\n  DEFAULT_REGEX = /timestamp_id\\('(?<seq_prefix>\\w+)'/\n\n  class Callbacks\n    def self.around_create(record)\n      now = Time.now.utc\n\n      if record.created_at.nil? || record.created_at >= now || record.created_at == record.updated_at || record.override_timestamps\n        yield\n      else\n        record.id = Mastodon::Snowflake.id_at(record.created_at)\n        tries     = 0\n\n        begin\n          yield\n        rescue ActiveRecord::RecordNotUnique\n          raise if tries > 100\n\n          tries     += 1\n          record.id += rand(100)\n\n          retry\n        end\n      end\n    end\n  end\n\n  class << self\n    # Our ID will be composed of the following:\n    # 6 bytes (48 bits) of millisecond-level timestamp\n    # 2 bytes (16 bits) of sequence data\n    #\n    # The 'sequence data' is intended to be unique within a\n    # given millisecond, yet obscure the 'serial number' of\n    # this row.\n    #\n    # To do this, we hash the following data:\n    # * Table name (if provided, skipped if not)\n    # * Secret salt (should not be guessable)\n    # * Timestamp (again, millisecond-level granularity)\n    #\n    # We then take the first two bytes of that value, and add\n    # the lowest two bytes of the table ID sequence number\n    # (`table_name`_id_seq). This means that even if we insert\n    # two rows at the same millisecond, they will have\n    # distinct 'sequence data' portions.\n    #\n    # If this happens, and an attacker can see both such IDs,\n    # they can determine which of the two entries was inserted\n    # first, but not the total number of entries in the table\n    # (even mod 2**16).\n    #\n    # The table name is included in the hash to ensure that\n    # different tables derive separate sequence bases so rows\n    # inserted in the same millisecond in different tables do\n    # not reveal the table ID sequence number for one another.\n    #\n    # The secret salt is included in the hash to ensure that\n    # external users cannot derive the sequence base given the\n    # timestamp and table name, which would allow them to\n    # compute the table ID sequence number.\n    def define_timestamp_id\n      return if already_defined?\n\n      connection.execute(<<~SQL)\n        CREATE OR REPLACE FUNCTION timestamp_id(table_name text)\n        RETURNS bigint AS\n        $$\n          DECLARE\n            time_part bigint;\n            sequence_base bigint;\n            tail bigint;\n          BEGIN\n            time_part := (\n              -- Get the time in milliseconds\n              ((date_part('epoch', now()) * 1000))::bigint\n              -- And shift it over two bytes\n              << 16);\n\n            sequence_base := (\n              'x' ||\n              -- Take the first two bytes (four hex characters)\n              substr(\n                -- Of the MD5 hash of the data we documented\n                md5(table_name ||\n                  '#{SecureRandom.hex(16)}' ||\n                  time_part::text\n                ),\n                1, 4\n              )\n            -- And turn it into a bigint\n            )::bit(16)::bigint;\n\n            -- Finally, add our sequence number to our base, and chop\n            -- it to the last two bytes\n            tail := (\n              (sequence_base + nextval(table_name || '_id_seq'))\n              & 65535);\n\n            -- Return the time part and the sequence part. OR appears\n            -- faster here than addition, but they're equivalent:\n            -- time_part has no trailing two bytes, and tail is only\n            -- the last two bytes.\n            RETURN time_part | tail;\n          END\n        $$ LANGUAGE plpgsql VOLATILE;\n      SQL\n    end\n\n    def ensure_id_sequences_exist\n      # Find tables using timestamp IDs.\n      connection.tables.each do |table|\n        # We're only concerned with \"id\" columns.\n        next unless (id_col = connection.columns(table).find { |col| col.name == 'id' })\n\n        # And only those that are using timestamp_id.\n        next unless (data = DEFAULT_REGEX.match(id_col.default_function))\n\n        seq_name = data[:seq_prefix] + '_id_seq'\n\n        # If we were on Postgres 9.5+, we could do CREATE SEQUENCE IF\n        # NOT EXISTS, but we can't depend on that. Instead, catch the\n        # possible exception and ignore it.\n        # Note that seq_name isn't a column name, but it's a\n        # relation, like a column, and follows the same quoting rules\n        # in Postgres.\n        connection.execute(<<~SQL)\n          DO $$\n            BEGIN\n              CREATE SEQUENCE #{connection.quote_column_name(seq_name)};\n            EXCEPTION WHEN duplicate_table THEN\n              -- Do nothing, we have the sequence already.\n            END\n          $$ LANGUAGE plpgsql;\n        SQL\n      end\n    end\n\n    def id_at(timestamp)\n      id  = timestamp.to_i * 1000 + rand(1000)\n      id  = id << 16\n      id += rand(2**16)\n      id\n    end\n\n    private\n\n    def already_defined?\n      connection.execute(<<~SQL).values.first.first\n        SELECT EXISTS(\n          SELECT * FROM pg_proc WHERE proname = 'timestamp_id'\n        );\n      SQL\n    end\n\n    def connection\n      ActiveRecord::Base.connection\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mastodon/statuses_cli.rb",
    "content": "# frozen_string_literal: true\n\nrequire_relative '../../config/boot'\nrequire_relative '../../config/environment'\nrequire_relative 'cli_helper'\n\nmodule Mastodon\n  class StatusesCLI < Thor\n    include ActionView::Helpers::NumberHelper\n\n    def self.exit_on_failure?\n      true\n    end\n\n    option :days, type: :numeric, default: 90\n    desc 'remove', 'Remove unreferenced statuses'\n    long_desc <<~LONG_DESC\n      Remove statuses that are not referenced by local user activity, such as\n      ones that came from relays, or belonging to users that were once followed\n      by someone locally but no longer are.\n\n      This is a computationally heavy procedure that creates extra database\n      indicides before commencing, and removes them afterward.\n    LONG_DESC\n    def remove\n      say('Creating temporary database indices...')\n\n      ActiveRecord::Base.connection.add_index(:accounts, :id, name: :index_accounts_local, where: 'domain is null', algorithm: :concurrently) unless ActiveRecord::Base.connection.index_name_exists?(:accounts, :index_accounts_local)\n      ActiveRecord::Base.connection.add_index(:status_pins, :status_id, name: :index_status_pins_status_id, algorithm: :concurrently) unless ActiveRecord::Base.connection.index_name_exists?(:status_pins, :index_status_pins_status_id)\n      ActiveRecord::Base.connection.add_index(:media_attachments, :remote_url, name: :index_media_attachments_remote_url, where: 'remote_url is not null', algorithm: :concurrently) unless ActiveRecord::Base.connection.index_name_exists?(:media_attachments, :index_media_attachments_remote_url)\n\n      max_id   = Mastodon::Snowflake.id_at(options[:days].days.ago)\n      start_at = Time.now.to_f\n\n      say('Beginning removal... This might take a while...')\n\n      Status.remote\n            .where('id < ?', max_id)\n            .where(reblog_of_id: nil)                                                                                                                                                                                              # Skip reblogs\n            .where(in_reply_to_id: nil)                                                                                                                                                                                            # Skip replies\n            .where('id NOT IN (SELECT status_pins.status_id FROM status_pins WHERE statuses.id = status_id)')                                                                                                                      # Skip statuses that are pinned on profiles\n            .where('id NOT IN (SELECT mentions.status_id FROM mentions WHERE statuses.id = mentions.status_id AND mentions.account_id IN (SELECT accounts.id FROM accounts WHERE domain IS NULL))')                                # Skip statuses that mention local accounts\n            .where('id NOT IN (SELECT statuses1.in_reply_to_id FROM statuses AS statuses1 WHERE statuses.id = statuses1.in_reply_to_id)')                                                                                          # Skip statuses favourited by local accounts\n            .where('id NOT IN (SELECT statuses1.reblog_of_id FROM statuses AS statuses1 WHERE statuses.id = statuses1.reblog_of_id AND statuses1.account_id IN (SELECT accounts.id FROM accounts WHERE accounts.domain IS NULL))') # Skip statuses reblogged by local accounts\n            .where('account_id NOT IN (SELECT follows.target_account_id FROM follows WHERE statuses.account_id = follows.target_account_id)')                                                                                      # Skip accounts followed by local accounts\n            .in_batches\n            .delete_all\n\n      say('Beginning removal of now-orphaned media attachments to free up disk space...')\n\n      Scheduler::MediaCleanupScheduler.new.perform\n\n      say(\"Done after #{Time.now.to_f - start_at}s\", :green)\n    ensure\n      say('Removing temporary database indices to restore write performance...')\n\n      ActiveRecord::Base.connection.remove_index(:accounts, name: :index_accounts_local) if ActiveRecord::Base.connection.index_name_exists?(:accounts, :index_accounts_local)\n      ActiveRecord::Base.connection.remove_index(:status_pins, name: :index_status_pins_status_id) if ActiveRecord::Base.connection.index_name_exists?(:status_pins, :index_status_pins_status_id)\n      ActiveRecord::Base.connection.remove_index(:media_attachments, name: :index_media_attachments_remote_url) if ActiveRecord::Base.connection.index_name_exists?(:media_attachments, :index_media_attachments_remote_url)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mastodon/version.rb",
    "content": "# frozen_string_literal: true\n\nmodule Mastodon\n  module Version\n    module_function\n\n    def major\n      2\n    end\n\n    def minor\n      9\n    end\n\n    def patch\n      0\n    end\n\n    def pre\n      nil\n    end\n\n    def flags\n      ''\n    end\n\n    def to_a\n      [major, minor, patch, pre].compact\n    end\n\n    def suffix\n      '+florence'\n    end\n\n    def to_s\n      [to_a.join('.'), flags, suffix].join\n    end\n\n    def repository\n      ENV.fetch('GITHUB_REPOSITORY') { 'florence-social/mastodon-fork' }\n    end\n\n    def source_base_url\n      ENV.fetch('SOURCE_BASE_URL') { \"https://github.com/#{repository}\" }\n    end\n\n    # specify git tag or commit hash here\n    def source_tag\n      ENV.fetch('SOURCE_TAG') { nil }\n    end\n\n    def source_url\n      if source_tag\n        \"#{source_base_url}/tree/#{source_tag}\"\n      else\n        source_base_url\n      end\n    end\n\n    def user_agent\n      @user_agent ||= \"#{HTTP::Request::USER_AGENT} (FlorenceMastodon/#{Version}; +http#{Rails.configuration.x.use_https ? 's' : ''}://#{Rails.configuration.x.web_domain}/)\"\n    end\n  end\nend\n"
  },
  {
    "path": "lib/paperclip/blurhash_transcoder.rb",
    "content": "# frozen_string_literal: true\n\nmodule Paperclip\n  class BlurhashTranscoder < Paperclip::Processor\n    def make\n      return @file unless options[:style] == :small\n\n      pixels   = convert(':source RGB:-', source: File.expand_path(@file.path)).unpack('C*')\n      geometry = options.fetch(:file_geometry_parser).from_file(@file)\n\n      attachment.instance.blurhash = Blurhash.encode(geometry.width, geometry.height, pixels, options[:blurhash] || {})\n\n      @file\n    end\n  end\nend\n"
  },
  {
    "path": "lib/paperclip/gif_transcoder.rb",
    "content": "# frozen_string_literal: true\n\nmodule Paperclip\n  # This transcoder is only to be used for the MediaAttachment model\n  # to convert animated gifs to webm\n  class GifTranscoder < Paperclip::Processor\n    def make\n      return File.open(@file.path) unless needs_convert?\n\n      final_file = Paperclip::Transcoder.make(file, options, attachment)\n\n      attachment.instance.file_file_name    = File.basename(attachment.instance.file_file_name, '.*') + '.mp4'\n      attachment.instance.file_content_type = 'video/mp4'\n      attachment.instance.type              = MediaAttachment.types[:gifv]\n\n      final_file\n    end\n\n    private\n\n    def needs_convert?\n      num_frames = identify('-format %n :file', file: file.path).to_i\n      options[:style] == :original && num_frames > 1\n    end\n  end\nend\n"
  },
  {
    "path": "lib/paperclip/lazy_thumbnail.rb",
    "content": "# frozen_string_literal: true\n\nmodule Paperclip\n  class LazyThumbnail < Paperclip::Thumbnail\n    def make\n      return File.open(@file.path) unless needs_convert?\n\n      if options[:geometry]\n        min_side = [@current_geometry.width, @current_geometry.height].min.to_i\n        options[:geometry] = \"#{min_side}x#{min_side}#\" if @target_geometry.square? && min_side < @target_geometry.width\n      elsif options[:pixels]\n        width  = Math.sqrt(options[:pixels] * (@current_geometry.width.to_f / @current_geometry.height.to_f)).round.to_i\n        height = Math.sqrt(options[:pixels] * (@current_geometry.height.to_f / @current_geometry.width.to_f)).round.to_i\n        options[:geometry] = \"#{width}x#{height}>\"\n      end\n\n      Paperclip::Thumbnail.make(file, options, attachment)\n    end\n\n    private\n\n    def needs_convert?\n      needs_different_geometry? || needs_different_format? || needs_metadata_stripping?\n    end\n\n    def needs_different_geometry?\n      (options[:geometry] && @current_geometry.width != @target_geometry.width && @current_geometry.height != @target_geometry.height) ||\n        (options[:pixels] && @current_geometry.width * @current_geometry.height > options[:pixels])\n    end\n\n    def needs_different_format?\n      @format.present? && @current_format != @format\n    end\n\n    def needs_metadata_stripping?\n      @attachment.instance.respond_to?(:local?) && @attachment.instance.local?\n    end\n  end\nend\n"
  },
  {
    "path": "lib/paperclip/video_transcoder.rb",
    "content": "# frozen_string_literal: true\n\nmodule Paperclip\n  # This transcoder is only to be used for the MediaAttachment model\n  # to check when uploaded videos are actually gifv's\n  class VideoTranscoder < Paperclip::Processor\n    def make\n      meta = ::Av.cli.identify(@file.path)\n      attachment.instance.type = MediaAttachment.types[:gifv] unless meta[:audio_encode]\n\n      Paperclip::Transcoder.make(file, options, attachment)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/tasks/assets.rake",
    "content": "# frozen_string_literal: true\n\ndef render_static_page(action, dest:, **opts)\n  html = ApplicationController.render(action, opts)\n  File.write(dest, html)\nend\n\nnamespace :assets do\n  desc 'Generate static pages'\n  task generate_static_pages: :environment do\n    render_static_page 'errors/500', layout: 'error', dest: Rails.root.join('public', 'assets', '500.html')\n  end\nend\n\nif Rake::Task.task_defined?('assets:precompile')\n  Rake::Task['assets:precompile'].enhance do\n    Webpacker.manifest.refresh\n    Rake::Task['assets:generate_static_pages'].invoke\n  end\nend\n"
  },
  {
    "path": "lib/tasks/auto_annotate_models.rake",
    "content": "# frozen_string_literal: true\n\nif Rails.env.development?\n  task :set_annotation_options do\n    Annotate.set_defaults(\n      'routes'                  => 'false',\n      'position_in_routes'      => 'before',\n      'position_in_class'       => 'before',\n      'position_in_test'        => 'before',\n      'position_in_fixture'     => 'before',\n      'position_in_factory'     => 'before',\n      'position_in_serializer'  => 'before',\n      'show_foreign_keys'       => 'false',\n      'show_indexes'            => 'false',\n      'simple_indexes'          => 'false',\n      'model_dir'               => 'app/models',\n      'root_dir'                => '',\n      'include_version'         => 'false',\n      'require'                 => '',\n      'exclude_tests'           => 'true',\n      'exclude_fixtures'        => 'true',\n      'exclude_factories'       => 'true',\n      'exclude_serializers'     => 'true',\n      'exclude_scaffolds'       => 'true',\n      'exclude_controllers'     => 'true',\n      'exclude_helpers'         => 'true',\n      'ignore_model_sub_dir'    => 'false',\n      'ignore_columns'          => nil,\n      'ignore_routes'           => nil,\n      'ignore_unknown_models'   => 'false',\n      'hide_limit_column_types' => 'integer,boolean',\n      'skip_on_db_migrate'      => 'false',\n      'format_bare'             => 'true',\n      'format_rdoc'             => 'false',\n      'format_markdown'         => 'false',\n      'sort'                    => 'false',\n      'force'                   => 'false',\n      'trace'                   => 'false',\n      'wrapper_open'            => nil,\n      'wrapper_close'           => nil\n    )\n  end\n\n  Annotate.load_tasks\nend\n"
  },
  {
    "path": "lib/tasks/db.rake",
    "content": "# frozen_string_literal: true\n\nrequire_relative '../mastodon/snowflake'\n\ndef each_schema_load_environment\n  # If we're in development, also run this for the test environment.\n  # This is a somewhat hacky way to do this, so here's why:\n  # 1. We have to define this before we load the schema, or we won't\n  #    have a timestamp_id function when we get to it in the schema.\n  # 2. db:setup calls db:schema:load_if_ruby, which calls\n  #    db:schema:load, which we define above as having a prerequisite\n  #    of this task.\n  # 3. db:schema:load ends up running\n  #    ActiveRecord::Tasks::DatabaseTasks.load_schema_current, which\n  #    calls a private method `each_current_configuration`, which\n  #    explicitly also does the loading for the `test` environment\n  #    if the current environment is `development`, so we end up\n  #    needing to do the same, and we can't even use the same method\n  #    to do it.\n\n  if Rails.env.development?\n    test_conf = ActiveRecord::Base.configurations['test']\n\n    if test_conf['database']&.present?\n      ActiveRecord::Base.establish_connection(:test)\n      yield\n      ActiveRecord::Base.establish_connection(Rails.env.to_sym)\n    end\n  end\n\n  yield\nend\n\nnamespace :db do\n  namespace :migrate do\n    desc 'Setup the db or migrate depending on state of db'\n    task setup: :environment do\n      begin\n        if ActiveRecord::Migrator.current_version.zero?\n          Rake::Task['db:migrate'].invoke\n          Rake::Task['db:seed'].invoke\n        end\n      rescue ActiveRecord::NoDatabaseError\n        Rake::Task['db:setup'].invoke\n      else\n        Rake::Task['db:migrate'].invoke\n      end\n    end\n  end\n\n  # Before we load the schema, define the timestamp_id function.\n  # Idiomatically, we might do this in a migration, but then it\n  # wouldn't end up in schema.rb, so we'd need to figure out a way to\n  # get it in before doing db:setup as well. This is simpler, and\n  # ensures it's always in place.\n  Rake::Task['db:schema:load'].enhance ['db:define_timestamp_id']\n\n  # After we load the schema, make sure we have sequences for each\n  # table using timestamp IDs.\n  Rake::Task['db:schema:load'].enhance do\n    Rake::Task['db:ensure_id_sequences_exist'].invoke\n  end\n\n  task :define_timestamp_id do\n    each_schema_load_environment do\n      Mastodon::Snowflake.define_timestamp_id\n    end\n  end\n\n  task :ensure_id_sequences_exist do\n    each_schema_load_environment do\n      Mastodon::Snowflake.ensure_id_sequences_exist\n    end\n  end\nend\n"
  },
  {
    "path": "lib/tasks/emojis.rake",
    "content": "# frozen_string_literal: true\n\ndef codepoints_to_filename(codepoints)\n  codepoints.downcase.gsub(/\\A[0]+/, '').tr(' ', '-')\nend\n\ndef codepoints_to_unicode(codepoints)\n  if codepoints.include?(' ')\n    codepoints.split(' ').map(&:hex).pack('U*')\n  else\n    [codepoints.hex].pack('U')\n  end\nend\n\nnamespace :emojis do\n  desc 'Generate a unicode to filename mapping'\n  task :generate do\n    source = 'http://www.unicode.org/Public/emoji/11.0/emoji-test.txt'\n    codes  = []\n    dest   = Rails.root.join('app', 'javascript', 'mastodon', 'features', 'emoji', 'emoji_map.json')\n\n    puts \"Downloading emojos from source... (#{source})\"\n\n    HTTP.get(source).to_s.split(\"\\n\").each do |line|\n      next if line.start_with? '#'\n      parts = line.split(';').map(&:strip)\n      next if parts.size < 2\n      codes << [parts[0], parts[1].start_with?('fully-qualified')]\n    end\n\n    grouped_codes = codes.reduce([]) do |agg, current|\n      if current[1]\n        agg << [current[0]]\n      else\n        agg.last << current[0]\n        agg\n      end\n    end\n\n    existence_maps = grouped_codes.map { |c| c.map { |cc| [cc, File.exist?(Rails.root.join('public', 'emoji', codepoints_to_filename(cc) + '.svg'))] }.to_h }\n    map = {}\n\n    existence_maps.each do |group|\n      existing_one = group.key(true)\n\n      next if existing_one.nil?\n\n      group.each_key do |key|\n        map[codepoints_to_unicode(key)] = codepoints_to_filename(existing_one)\n      end\n    end\n\n    map = map.sort { |a, b| a[0].size <=> b[0].size }.to_h\n\n    File.write(dest, Oj.dump(map))\n    puts \"Wrote emojo to destination! (#{dest})\"\n  end\nend\n"
  },
  {
    "path": "lib/tasks/mastodon.rake",
    "content": "# frozen_string_literal: true\n\nrequire 'tty-command'\nrequire 'tty-prompt'\n\nnamespace :mastodon do\n  desc 'Configure the instance for production use'\n  task :setup do\n    prompt = TTY::Prompt.new\n    env    = {}\n\n    begin\n      prompt.say('Your instance is identified by its domain name. Changing it afterward will break things.')\n      env['LOCAL_DOMAIN'] = prompt.ask('Domain name:') do |q|\n        q.required true\n        q.modify :strip\n        q.validate(/\\A[a-z0-9\\.\\-]+\\z/i)\n        q.messages[:valid?] = 'Invalid domain. If you intend to use unicode characters, enter punycode here'\n      end\n\n      prompt.say \"\\n\"\n\n      prompt.say('Single user mode disables registrations and redirects the landing page to your public profile.')\n      env['SINGLE_USER_MODE'] = prompt.yes?('Do you want to enable single user mode?', default: false)\n\n      %w(SECRET_KEY_BASE OTP_SECRET).each do |key|\n        env[key] = SecureRandom.hex(64)\n      end\n\n      vapid_key = Webpush.generate_key\n\n      env['VAPID_PRIVATE_KEY'] = vapid_key.private_key\n      env['VAPID_PUBLIC_KEY']  = vapid_key.public_key\n\n      prompt.say \"\\n\"\n\n      using_docker        = prompt.yes?('Are you using Docker to run Mastodon?')\n      db_connection_works = false\n\n      prompt.say \"\\n\"\n\n      loop do\n        env['DB_HOST'] = prompt.ask('PostgreSQL host:') do |q|\n          q.required true\n          q.default using_docker ? 'db' : '/var/run/postgresql'\n          q.modify :strip\n        end\n\n        env['DB_PORT'] = prompt.ask('PostgreSQL port:') do |q|\n          q.required true\n          q.default 5432\n          q.convert :int\n        end\n\n        env['DB_NAME'] = prompt.ask('Name of PostgreSQL database:') do |q|\n          q.required true\n          q.default using_docker ? 'postgres' : 'mastodon_production'\n          q.modify :strip\n        end\n\n        env['DB_USER'] = prompt.ask('Name of PostgreSQL user:') do |q|\n          q.required true\n          q.default using_docker ? 'postgres' : 'mastodon'\n          q.modify :strip\n        end\n\n        env['DB_PASS'] = prompt.ask('Password of PostgreSQL user:') do |q|\n          q.echo false\n        end\n\n        # The chosen database may not exist yet. Connect to default database\n        # to avoid \"database does not exist\" error.\n        db_options = {\n          adapter: :postgresql,\n          database: 'postgres',\n          host: env['DB_HOST'],\n          port: env['DB_PORT'],\n          user: env['DB_USER'],\n          password: env['DB_PASS'],\n        }\n\n        begin\n          ActiveRecord::Base.establish_connection(db_options)\n          ActiveRecord::Base.connection\n          prompt.ok 'Database configuration works! 🎆'\n          db_connection_works = true\n          break\n        rescue StandardError => e\n          prompt.error 'Database connection could not be established with this configuration, try again.'\n          prompt.error e.message\n          break unless prompt.yes?('Try again?')\n        end\n      end\n\n      prompt.say \"\\n\"\n\n      loop do\n        env['REDIS_HOST'] = prompt.ask('Redis host:') do |q|\n          q.required true\n          q.default using_docker ? 'redis' : 'localhost'\n          q.modify :strip\n        end\n\n        env['REDIS_PORT'] = prompt.ask('Redis port:') do |q|\n          q.required true\n          q.default 6379\n          q.convert :int\n        end\n\n        env['REDIS_PASSWORD'] = prompt.ask('Redis password:') do |q|\n          q.required false\n          q.default nil\n          q.modify :strip\n        end\n\n        redis_options = {\n          host: env['REDIS_HOST'],\n          port: env['REDIS_PORT'],\n          password: env['REDIS_PASSWORD'],\n          driver: :hiredis,\n        }\n\n        begin\n          redis = Redis.new(redis_options)\n          redis.ping\n          prompt.ok 'Redis configuration works! 🎆'\n          break\n        rescue StandardError => e\n          prompt.error 'Redis connection could not be established with this configuration, try again.'\n          prompt.error e.message\n          break unless prompt.yes?('Try again?')\n        end\n      end\n\n      prompt.say \"\\n\"\n\n      if prompt.yes?('Do you want to store uploaded files on the cloud?', default: false)\n        case prompt.select('Provider', ['Amazon S3', 'Wasabi', 'Minio'])\n        when 'Amazon S3'\n          env['S3_ENABLED']  = 'true'\n          env['S3_PROTOCOL'] = 'https'\n\n          env['S3_BUCKET'] = prompt.ask('S3 bucket name:') do |q|\n            q.required true\n            q.default \"files.#{env['LOCAL_DOMAIN']}\"\n            q.modify :strip\n          end\n\n          env['S3_REGION'] = prompt.ask('S3 region:') do |q|\n            q.required true\n            q.default 'us-east-1'\n            q.modify :strip\n          end\n\n          env['S3_HOSTNAME'] = prompt.ask('S3 hostname:') do |q|\n            q.required true\n            q.default 's3-us-east-1.amazonaws.com'\n            q.modify :strip\n          end\n\n          env['AWS_ACCESS_KEY_ID'] = prompt.ask('S3 access key:') do |q|\n            q.required true\n            q.modify :strip\n          end\n\n          env['AWS_SECRET_ACCESS_KEY'] = prompt.ask('S3 secret key:') do |q|\n            q.required true\n            q.modify :strip\n          end\n        when 'Wasabi'\n          env['S3_ENABLED']  = 'true'\n          env['S3_PROTOCOL'] = 'https'\n          env['S3_REGION']   = 'us-east-1'\n          env['S3_HOSTNAME'] = 's3.wasabisys.com'\n          env['S3_ENDPOINT'] = 'https://s3.wasabisys.com/'\n\n          env['S3_BUCKET'] = prompt.ask('Wasabi bucket name:') do |q|\n            q.required true\n            q.default \"files.#{env['LOCAL_DOMAIN']}\"\n            q.modify :strip\n          end\n\n          env['AWS_ACCESS_KEY_ID'] = prompt.ask('Wasabi access key:') do |q|\n            q.required true\n            q.modify :strip\n          end\n\n          env['AWS_SECRET_ACCESS_KEY'] = prompt.ask('Wasabi secret key:') do |q|\n            q.required true\n            q.modify :strip\n          end\n        when 'Minio'\n          env['S3_ENABLED']  = 'true'\n          env['S3_PROTOCOL'] = 'https'\n          env['S3_REGION']   = 'us-east-1'\n\n          env['S3_ENDPOINT'] = prompt.ask('Minio endpoint URL:') do |q|\n            q.required true\n            q.modify :strip\n          end\n\n          env['S3_PROTOCOL'] = env['S3_ENDPOINT'].start_with?('https') ? 'https' : 'http'\n          env['S3_HOSTNAME'] = env['S3_ENDPOINT'].gsub(/\\Ahttps?:\\/\\//, '')\n\n          env['S3_BUCKET'] = prompt.ask('Minio bucket name:') do |q|\n            q.required true\n            q.default \"files.#{env['LOCAL_DOMAIN']}\"\n            q.modify :strip\n          end\n\n          env['AWS_ACCESS_KEY_ID'] = prompt.ask('Minio access key:') do |q|\n            q.required true\n            q.modify :strip\n          end\n\n          env['AWS_SECRET_ACCESS_KEY'] = prompt.ask('Minio secret key:') do |q|\n            q.required true\n            q.modify :strip\n          end\n        end\n\n        if prompt.yes?('Do you want to access the uploaded files from your own domain?')\n          env['S3_ALIAS_HOST'] = prompt.ask('Domain for uploaded files:') do |q|\n            q.required true\n            q.default \"files.#{env['LOCAL_DOMAIN']}\"\n            q.modify :strip\n          end\n        end\n      end\n\n      prompt.say \"\\n\"\n\n      loop do\n        if prompt.yes?('Do you want to send e-mails from localhost?', default: false)\n          env['SMTP_SERVER'] = 'localhost'\n          env['SMTP_PORT'] = 25\n          env['SMTP_AUTH_METHOD'] = 'none'\n          env['SMTP_OPENSSL_VERIFY_MODE'] = 'none'\n        else\n          env['SMTP_SERVER'] = prompt.ask('SMTP server:') do |q|\n            q.required true\n            q.default 'smtp.mailgun.org'\n            q.modify :strip\n          end\n\n          env['SMTP_PORT'] = prompt.ask('SMTP port:') do |q|\n            q.required true\n            q.default 587\n            q.convert :int\n          end\n\n          env['SMTP_LOGIN'] = prompt.ask('SMTP username:') do |q|\n            q.modify :strip\n          end\n\n          env['SMTP_PASSWORD'] = prompt.ask('SMTP password:') do |q|\n            q.echo false\n          end\n\n          env['SMTP_AUTH_METHOD'] = prompt.ask('SMTP authentication:') do |q|\n            q.required\n            q.default 'plain'\n            q.modify :strip\n          end\n\n          env['SMTP_OPENSSL_VERIFY_MODE'] = prompt.select('SMTP OpenSSL verify mode:', %w(none peer client_once fail_if_no_peer_cert))\n        end\n\n        env['SMTP_FROM_ADDRESS'] = prompt.ask('E-mail address to send e-mails \"from\":') do |q|\n          q.required true\n          q.default \"Mastodon <notifications@#{env['LOCAL_DOMAIN']}>\"\n          q.modify :strip\n        end\n\n        break unless prompt.yes?('Send a test e-mail with this configuration right now?')\n\n        send_to = prompt.ask('Send test e-mail to:', required: true)\n\n        begin\n          ActionMailer::Base.smtp_settings = {\n            port:                 env['SMTP_PORT'],\n            address:              env['SMTP_SERVER'],\n            user_name:            env['SMTP_LOGIN'].presence,\n            password:             env['SMTP_PASSWORD'].presence,\n            domain:               env['LOCAL_DOMAIN'],\n            authentication:       env['SMTP_AUTH_METHOD'] == 'none' ? nil : env['SMTP_AUTH_METHOD'] || :plain,\n            openssl_verify_mode:  env['SMTP_OPENSSL_VERIFY_MODE'],\n            enable_starttls_auto: true,\n          }\n\n          ActionMailer::Base.default_options = {\n            from: env['SMTP_FROM_ADDRESS'],\n          }\n\n          mail = ActionMailer::Base.new.mail to: send_to, subject: 'Test', body: 'Mastodon SMTP configuration works!'\n          mail.deliver\n          break\n        rescue StandardError => e\n          prompt.error 'E-mail could not be sent with this configuration, try again.'\n          prompt.error e.message\n          break unless prompt.yes?('Try again?')\n        end\n      end\n\n      prompt.say \"\\n\"\n      prompt.say 'This configuration will be written to .env.production'\n\n      if prompt.yes?('Save configuration?')\n        cmd = TTY::Command.new(printer: :quiet)\n\n        File.write(Rails.root.join('.env.production'), \"# Generated with mastodon:setup on #{Time.now.utc}\\n\\n\" + env.each_pair.map { |key, value| \"#{key}=#{value}\" }.join(\"\\n\") + \"\\n\")\n\n        if using_docker\n          prompt.ok 'Below is your configuration, save it to an .env.production file outside Docker:'\n          prompt.say \"\\n\"\n          prompt.say File.read(Rails.root.join('.env.production'))\n          prompt.say \"\\n\"\n          prompt.ok 'It is also saved within this container so you can proceed with this wizard.'\n        end\n\n        prompt.say \"\\n\"\n        prompt.say 'Now that configuration is saved, the database schema must be loaded.'\n        prompt.warn 'If the database already exists, this will erase its contents.'\n\n        if prompt.yes?('Prepare the database now?')\n          prompt.say 'Running `RAILS_ENV=production rails db:setup` ...'\n          prompt.say \"\\n\\n\"\n\n          if cmd.run!({ RAILS_ENV: 'production', SAFETY_ASSURED: 1 }, :rails, 'db:setup').failure?\n            prompt.error 'That failed! Perhaps your configuration is not right'\n          else\n            prompt.ok 'Done!'\n          end\n        end\n\n        prompt.say \"\\n\"\n        prompt.say 'The final step is compiling CSS/JS assets.'\n        prompt.say 'This may take a while and consume a lot of RAM.'\n\n        if prompt.yes?('Compile the assets now?')\n          prompt.say 'Running `RAILS_ENV=production rails assets:precompile` ...'\n          prompt.say \"\\n\\n\"\n\n          if cmd.run!({ RAILS_ENV: 'production' }, :rails, 'assets:precompile').failure?\n            prompt.error 'That failed! Maybe you need swap space?'\n          else\n            prompt.say 'Done!'\n          end\n        end\n\n        prompt.say \"\\n\"\n        prompt.ok 'All done! You can now power on the Mastodon server 🐘'\n        prompt.say \"\\n\"\n\n        if db_connection_works && prompt.yes?('Do you want to create an admin user straight away?')\n          env.each_pair do |key, value|\n            ENV[key] = value.to_s\n          end\n\n          require_relative '../../config/environment'\n          disable_log_stdout!\n\n          username = prompt.ask('Username:') do |q|\n            q.required true\n            q.default 'admin'\n            q.validate(/\\A[a-z0-9_]+\\z/i)\n            q.modify :strip\n          end\n\n          email = prompt.ask('E-mail:') do |q|\n            q.required true\n            q.modify :strip\n          end\n\n          password = SecureRandom.hex(16)\n\n          user = User.new(admin: true, email: email, password: password, confirmed_at: Time.now.utc, account_attributes: { username: username })\n          user.save(validate: false)\n\n          prompt.ok \"You can login with the password: #{password}\"\n          prompt.warn 'You can change your password once you login.'\n        end\n      else\n        prompt.warn 'Nothing saved. Bye!'\n      end\n    rescue TTY::Reader::InputInterrupt\n      prompt.ok 'Aborting. Bye!'\n    end\n  end\n\n  namespace :webpush do\n    desc 'Generate VAPID key'\n    task generate_vapid_key: :environment do\n      vapid_key = Webpush.generate_key\n      puts \"VAPID_PRIVATE_KEY=#{vapid_key.private_key}\"\n      puts \"VAPID_PUBLIC_KEY=#{vapid_key.public_key}\"\n    end\n  end\nend\n\ndef disable_log_stdout!\n  dev_null = Logger.new('/dev/null')\n\n  Rails.logger                 = dev_null\n  ActiveRecord::Base.logger    = dev_null\n  HttpLog.configuration.logger = dev_null\n  Paperclip.options[:log]      = false\nend\n"
  },
  {
    "path": "lib/tasks/repo.rake",
    "content": "# frozen_string_literal: true\n\nnamespace :repo do\n  desc 'Generate the AUTHORS.md file'\n  task :authors do\n    file = File.open(Rails.root.join('AUTHORS.md'), 'w')\n    file << <<~HEADER\n      Authors\n      =======\n\n      Mastodon is available on [GitHub](https://github.com/tootsuite/mastodon)\n      and provided thanks to the work of the following contributors:\n\n    HEADER\n\n    url = 'https://api.github.com/repos/tootsuite/mastodon/contributors?anon=1'\n    HttpLog.config.compact_log = true\n    while url.present?\n      response = HTTP.get(url)\n      contributors = Oj.load(response.body)\n      contributors.each do |c|\n        file << \"* [#{c['login']}](#{c['html_url']})\\n\" if c['login']\n        file << \"* [#{c['name']}](mailto:#{c['email']})\\n\" if c['name']\n      end\n      url = LinkHeader.parse(response.headers['Link']).find_link(%w(rel next))&.href\n    end\n\n    file << <<~FOOTER\n\n      This document is provided for informational purposes only. Since it is only updated once per release, the version you are looking at may be currently out of date. To see the full list of contributors, consider looking at the [git history](https://github.com/tootsuite/mastodon/graphs/contributors) instead.\n    FOOTER\n  end\n\n  desc 'Replace pull requests with authors in the CHANGELOG.md file'\n  task :changelog do\n    path = Rails.root.join('CHANGELOG.md')\n    tmp  = Tempfile.new\n\n    HttpLog.config.compact_log = true\n\n    begin\n      File.open(path, 'r') do |file|\n        file.each_line do |line|\n          if line.start_with?('-')\n            new_line = line.gsub(/#([[:digit:]]+)*/) do |pull_request_reference|\n              pull_request_number = pull_request_reference[1..-1]\n              response = nil\n\n              loop do\n                response = HTTP.headers('Authorization' => \"token #{ENV['GITHUB_API_TOKEN']}\").get(\"https://api.github.com/repos/tootsuite/mastodon/pulls/#{pull_request_number}\")\n\n                if response.code == 403\n                  sleep_for = (response.headers['X-RateLimit-Reset'].to_i - Time.now.to_i).abs\n                  puts \"Sleeping for #{sleep_for} seconds to get over rate limit\"\n                  sleep sleep_for\n                else\n                  break\n                end\n              end\n\n              pull_request = Oj.load(response.to_s)\n              \"[#{pull_request['user']['login']}](#{pull_request['html_url']})\"\n            end\n\n            tmp.puts new_line\n          else\n            tmp.puts line\n          end\n        end\n      end\n\n      tmp.close\n      FileUtils.mv(tmp.path, path)\n    ensure\n      tmp.close\n      tmp.unlink\n    end\n  end\nend\n"
  },
  {
    "path": "lib/tasks/statistics.rake",
    "content": "# frozen_string_literal: true\n\ntask stats: 'mastodon:stats'\n\nnamespace :mastodon do\n  desc 'Report code statistics (KLOCs, etc)'\n  task :stats do\n    require 'rails/code_statistics'\n    [\n      %w(App\\ Libraries app/lib),\n      %w(Presenters app/presenters),\n      %w(Services app/services),\n      %w(Validators app/validators),\n      %w(Workers app/workers),\n    ].each do |name, dir|\n      ::STATS_DIRECTORIES << [name, Rails.root.join(dir)]\n    end\n  end\nend\n"
  },
  {
    "path": "lib/templates/haml/scaffold/_form.html.haml",
    "content": "= simple_form_for(@<%= singular_table_name %>) do |f|\n  = f.error_notification\n\n  .form-inputs\n  <%- attributes.each do |attribute| -%>\n    = f.<%= attribute.reference? ? :association : :input %> :<%= attribute.name %>\n  <%- end -%>\n\n  .form-actions\n    = f.button :submit\n"
  },
  {
    "path": "lib/templates/rails/post_deployment_migration/migration.rb",
    "content": "# frozen_string_literal: true\n\nclass <%= migration_class_name %> < ActiveRecord::Migration[5.2]\n  disable_ddl_transaction!\n\n  def change\n  end\nend\n"
  },
  {
    "path": "log/.keep",
    "content": ""
  },
  {
    "path": "nanobox/nginx-local.conf",
    "content": "worker_processes 1;\ndaemon off;\n\nevents {\n    worker_connections 1024;\n}\n\nhttp {\n    include /data/etc/nginx/mime.types;\n    sendfile on;\n\n    gzip on;\n    gzip_disable \"MSIE [1-6]\\.\";\n    gzip_vary on;\n    gzip_proxied any;\n    gzip_comp_level 6;\n    gzip_buffers 16 8k;\n    gzip_min_length 500;\n    gzip_http_version 1.1;\n    gzip_types text/plain text/xml text/javascript text/css text/comma-separated-values application/xml+rss application/xml application/x-javascript application/json application/javascript application/atom+xml;\n\n    # Proxy upstream to the puma process\n    upstream rails {\n        server 127.0.0.1:3000;\n    }\n\n    # Proxy upstream to the node process\n    upstream node {\n        server 127.0.0.1:4000;\n    }\n\n    map $http_upgrade $connection_upgrade {\n        default upgrade;\n        ''      close;\n    }\n\n    # Configuration for Nginx\n    server {\n        # Listen on port 8080\n        listen 8080;\n\n        keepalive_timeout    70;\n        client_max_body_size 80M;\n\n        root /app/public;\n\n        add_header Strict-Transport-Security \"max-age=31536000\";\n\n        location / {\n            try_files $uri @rails;\n        }\n\n        # Proxy connections to rails\n        location @rails {\n            proxy_set_header Host $host;\n            proxy_set_header X-Real-IP $remote_addr;\n            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n            proxy_set_header X-Forwarded-Proto https;\n            proxy_set_header Proxy \"\";\n            proxy_pass_header Server;\n\n            proxy_pass http://rails;\n            proxy_buffering off;\n            proxy_redirect off;\n            proxy_http_version 1.1;\n            proxy_set_header Upgrade $http_upgrade;\n            proxy_set_header Connection $connection_upgrade;\n\n            tcp_nodelay on;\n        }\n\n        # Proxy connections to node\n        location /api/v1/streaming {\n            proxy_set_header Host $host;\n            proxy_set_header X-Real-IP $remote_addr;\n            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n            proxy_set_header X-Forwarded-Proto https;\n            proxy_set_header Proxy \"\";\n\n            proxy_pass http://node;\n            proxy_buffering off;\n            proxy_redirect off;\n            proxy_http_version 1.1;\n            proxy_set_header Upgrade $http_upgrade;\n            proxy_set_header Connection $connection_upgrade;\n\n            tcp_nodelay on;\n        }\n    }\n\n    error_page 500 501 502 503 504 /500.html;\n}\n"
  },
  {
    "path": "nanobox/nginx-stream.conf.erb",
    "content": "worker_processes 1;\ndaemon off;\n\nevents {\n    worker_connections 1024;\n}\n\nhttp {\n    include /data/etc/nginx/mime.types;\n    sendfile on;\n\n    gzip on;\n    gzip_disable \"MSIE [1-6]\\.\";\n    gzip_vary on;\n    gzip_proxied any;\n    gzip_comp_level 6;\n    gzip_buffers 16 8k;\n    gzip_min_length 500;\n    gzip_http_version 1.1;\n    gzip_types text/plain text/xml text/javascript text/css text/comma-separated-values application/xml+rss application/xml application/x-javascript application/json application/javascript application/atom+xml;\n\n    # Proxy upstream to the node process\n    upstream node {\n        server 127.0.0.1:4000;\n    }\n\n    map $http_upgrade $connection_upgrade {\n        default upgrade;\n        ''      close;\n    }\n\n    # Configuration for Nginx\n    server {\n        # Listen on port 8080\n        listen 8080;\n\n        keepalive_timeout    70;\n        client_max_body_size 80M;\n\n        root /app/public;\n\n        add_header Strict-Transport-Security \"max-age=31536000\";\n\n        location / {\n            try_files $uri @node;\n        }\n\n        # Proxy connections to node\n        location @node {\n            proxy_set_header Host $host;\n            proxy_set_header X-Real-IP $remote_addr;\n            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n            proxy_set_header X-Forwarded-Proto https;\n            proxy_set_header Proxy \"\";\n\n            proxy_pass http://node;\n            proxy_buffering off;\n            proxy_redirect off;\n            proxy_http_version 1.1;\n            proxy_set_header Upgrade $http_upgrade;\n            proxy_set_header Connection $connection_upgrade;\n\n            tcp_nodelay on;\n        }\n    }\n}\n"
  },
  {
    "path": "nanobox/nginx-web.conf.erb",
    "content": "worker_processes 1;\ndaemon off;\n\nevents {\n    worker_connections 1024;\n}\n\nhttp {\n    include /data/etc/nginx/mime.types;\n    sendfile on;\n\n    gzip on;\n    gzip_disable \"MSIE [1-6]\\.\";\n    gzip_vary on;\n    gzip_proxied any;\n    gzip_comp_level 6;\n    gzip_buffers 16 8k;\n    gzip_min_length 500;\n    gzip_http_version 1.1;\n    gzip_types text/plain text/xml text/javascript text/css text/comma-separated-values application/xml+rss application/xml application/x-javascript application/json application/javascript application/atom+xml;\n\n    # Proxy upstream to the puma process\n    upstream rails {\n        server 127.0.0.1:3000;\n    }\n\n    map $http_upgrade $connection_upgrade {\n        default upgrade;\n        ''      close;\n    }\n\n    # Configuration for Nginx\n    server {\n        # Listen on port 8080\n        listen 8080;\n\n        keepalive_timeout    70;\n        client_max_body_size 80M;\n\n        root /app/public;\n\n        add_header Strict-Transport-Security \"max-age=31536000\";\n\n        location / {\n            try_files $uri @rails;\n        }\n\n        location /sw.js {\n            add_header Cache-Control \"public, max-age=0\";\n            add_header Strict-Transport-Security \"max-age=31536000\";\n            try_files $uri @rails;\n        }\n\n        location ~ ^/(emoji|packs|system/media_attachments/files|system/accounts/avatars) {\n            add_header Cache-Control \"public, max-age=31536000, immutable\";\n            add_header Strict-Transport-Security \"max-age=31536000\";\n            try_files $uri @rails;\n        }\n\n        # Proxy connections to rails\n        location @rails {\n            proxy_set_header Host $host;\n            proxy_set_header X-Real-IP $remote_addr;\n            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n            proxy_set_header X-Forwarded-Proto https;\n            proxy_set_header Proxy \"\";\n            proxy_pass_header Server;\n\n            proxy_pass http://rails;\n            proxy_buffering on;\n            proxy_redirect off;\n            proxy_http_version 1.1;\n            proxy_set_header Upgrade $http_upgrade;\n            proxy_set_header Connection $connection_upgrade;\n\n            proxy_cache CACHE;\n            proxy_cache_valid 200 7d;\n            proxy_cache_valid 410 24h;\n            proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;\n            add_header Strict-Transport-Security \"max-age=31536000\";\n            add_header X-Cached $upstream_cache_status;\n\n            tcp_nodelay on;\n        }\n    }\n\n    proxy_cache_path /data/var/cache/nginx levels=1:2 keys_zone=CACHE:10m inactive=7d max_size=1g;\n\n    error_page 500 501 502 503 504 /500.html;\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"florence-mastodon\",\n  \"license\": \"AGPL-3.0-or-later\",\n  \"engines\": {\n    \"node\": \">=8.12 <12\"\n  },\n  \"scripts\": {\n    \"postversion\": \"git push --tags\",\n    \"build:development\": \"cross-env RAILS_ENV=development NODE_ENV=development ./bin/webpack\",\n    \"build:production\": \"cross-env RAILS_ENV=production NODE_ENV=production ./bin/webpack\",\n    \"manage:translations\": \"node ./config/webpack/translationRunner.js\",\n    \"start\": \"node ./streaming/index.js\",\n    \"test\": \"${npm_execpath} run test:lint:js && ${npm_execpath} run test:jest\",\n    \"test:lint\": \"${npm_execpath} run test:lint:js && ${npm_execpath} run test:lint:sass\",\n    \"test:lint:js\": \"eslint --ext=js .\",\n    \"test:lint:sass\": \"sass-lint -v\",\n    \"test:jest\": \"cross-env NODE_ENV=test jest --coverage\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/florence-social/mastodon-fork.git\"\n  },\n  \"browserslist\": [\n    \"last 2 versions\",\n    \"IE >= 11\",\n    \"iOS >= 9\",\n    \"not dead\"\n  ],\n  \"jest\": {\n    \"projects\": [\n      \"<rootDir>/app/javascript/mastodon\"\n    ],\n    \"testPathIgnorePatterns\": [\n      \"<rootDir>/node_modules/\",\n      \"<rootDir>/vendor/\",\n      \"<rootDir>/config/\",\n      \"<rootDir>/log/\",\n      \"<rootDir>/public/\",\n      \"<rootDir>/tmp/\"\n    ],\n    \"setupFiles\": [\n      \"raf/polyfill\"\n    ],\n    \"setupFilesAfterEnv\": [\n      \"<rootDir>/app/javascript/mastodon/test_setup.js\"\n    ],\n    \"collectCoverageFrom\": [\n      \"app/javascript/mastodon/**/*.js\",\n      \"!app/javascript/mastodon/features/emoji/emoji_compressed.js\",\n      \"!app/javascript/mastodon/locales/locale-data/*.js\",\n      \"!app/javascript/mastodon/service_worker/entry.js\",\n      \"!app/javascript/mastodon/test_setup.js\"\n    ],\n    \"coverageDirectory\": \"<rootDir>/coverage\",\n    \"moduleDirectories\": [\n      \"<rootDir>/node_modules\",\n      \"<rootDir>/app/javascript\"\n    ]\n  },\n  \"private\": true,\n  \"dependencies\": {\n    \"@babel/core\": \"^7.4.5\",\n    \"@babel/plugin-proposal-class-properties\": \"^7.4.4\",\n    \"@babel/plugin-proposal-decorators\": \"^7.4.4\",\n    \"@babel/plugin-proposal-object-rest-spread\": \"^7.4.4\",\n    \"@babel/plugin-syntax-dynamic-import\": \"^7.2.0\",\n    \"@babel/plugin-transform-react-inline-elements\": \"^7.2.0\",\n    \"@babel/plugin-transform-react-jsx-self\": \"^7.2.0\",\n    \"@babel/plugin-transform-react-jsx-source\": \"^7.2.0\",\n    \"@babel/plugin-transform-runtime\": \"^7.4.4\",\n    \"@babel/preset-env\": \"^7.4.5\",\n    \"@babel/preset-react\": \"^7.0.0\",\n    \"@babel/runtime\": \"^7.4.5\",\n    \"@clusterws/cws\": \"^0.14.0\",\n    \"array-includes\": \"^3.0.3\",\n    \"autoprefixer\": \"^9.5.1\",\n    \"axios\": \"^0.19.0\",\n    \"babel-loader\": \"^8.0.5\",\n    \"babel-plugin-lodash\": \"^3.3.4\",\n    \"babel-plugin-preval\": \"^3.0.1\",\n    \"babel-plugin-react-intl\": \"^3.1.3\",\n    \"babel-plugin-transform-react-remove-prop-types\": \"^0.4.24\",\n    \"babel-runtime\": \"^6.26.0\",\n    \"blurhash\": \"^1.0.0\",\n    \"classnames\": \"^2.2.5\",\n    \"compression-webpack-plugin\": \"^2.0.0\",\n    \"cross-env\": \"^5.1.4\",\n    \"css-loader\": \"^2.1.1\",\n    \"cssnano\": \"^4.1.10\",\n    \"detect-passive-events\": \"^1.0.2\",\n    \"dotenv\": \"^8.0.0\",\n    \"emoji-mart\": \"Gargron/emoji-mart#build\",\n    \"es6-symbol\": \"^3.1.1\",\n    \"escape-html\": \"^1.0.3\",\n    \"exif-js\": \"^2.3.0\",\n    \"express\": \"^4.17.1\",\n    \"file-loader\": \"^3.0.1\",\n    \"font-awesome\": \"^4.7.0\",\n    \"glob\": \"^7.1.1\",\n    \"http-link-header\": \"^1.0.2\",\n    \"immutable\": \"^3.8.2\",\n    \"imports-loader\": \"^0.8.0\",\n    \"intersection-observer\": \"^0.7.0\",\n    \"intl\": \"^1.2.5\",\n    \"intl-messageformat\": \"^2.2.0\",\n    \"intl-relativeformat\": \"^2.2.0\",\n    \"is-nan\": \"^1.2.1\",\n    \"js-yaml\": \"^3.13.1\",\n    \"lodash\": \"^4.17.13\",\n    \"mark-loader\": \"^0.1.6\",\n    \"marky\": \"^1.2.1\",\n    \"mini-css-extract-plugin\": \"^0.5.0\",\n    \"mkdirp\": \"^0.5.1\",\n    \"npmlog\": \"^4.1.2\",\n    \"object-assign\": \"^4.1.1\",\n    \"object-fit-images\": \"^3.2.3\",\n    \"object.values\": \"^1.1.0\",\n    \"offline-plugin\": \"^5.0.7\",\n    \"path-complete-extname\": \"^1.0.0\",\n    \"pg\": \"^6.4.0\",\n    \"postcss-loader\": \"^3.0.0\",\n    \"postcss-object-fit-images\": \"^1.1.2\",\n    \"prop-types\": \"^15.5.10\",\n    \"punycode\": \"^2.1.0\",\n    \"rails-ujs\": \"^5.2.3\",\n    \"react\": \"^16.8.6\",\n    \"react-dom\": \"^16.8.6\",\n    \"react-hotkeys\": \"^1.1.4\",\n    \"react-immutable-proptypes\": \"^2.1.0\",\n    \"react-immutable-pure-component\": \"^1.1.1\",\n    \"react-intl\": \"^2.9.0\",\n    \"react-masonry-infinite\": \"^1.2.2\",\n    \"react-motion\": \"^0.5.2\",\n    \"react-notification\": \"^6.8.4\",\n    \"react-overlays\": \"^0.8.3\",\n    \"react-redux\": \"^6.0.1\",\n    \"react-redux-loading-bar\": \"^4.0.8\",\n    \"react-router-dom\": \"^4.1.1\",\n    \"react-router-scroll-4\": \"^1.0.0-beta.1\",\n    \"react-select\": \"^2.4.4\",\n    \"react-sparklines\": \"^1.7.0\",\n    \"react-swipeable-views\": \"^0.13.3\",\n    \"react-textarea-autosize\": \"^7.1.0\",\n    \"react-toggle\": \"^4.0.1\",\n    \"redis\": \"^2.7.1\",\n    \"redux\": \"^4.0.1\",\n    \"redux-immutable\": \"^4.0.0\",\n    \"redux-thunk\": \"^2.2.0\",\n    \"rellax\": \"^1.7.1\",\n    \"requestidlecallback\": \"^0.3.0\",\n    \"reselect\": \"^4.0.0\",\n    \"rimraf\": \"^2.6.3\",\n    \"sass\": \"^1.20.3\",\n    \"sass-loader\": \"^7.0.3\",\n    \"stringz\": \"^1.0.0\",\n    \"substring-trie\": \"^1.0.2\",\n    \"terser-webpack-plugin\": \"^1.3.0\",\n    \"throng\": \"^4.0.0\",\n    \"tiny-queue\": \"^0.2.1\",\n    \"uuid\": \"^3.1.0\",\n    \"webpack\": \"^4.29.6\",\n    \"webpack-assets-manifest\": \"^3.1.1\",\n    \"webpack-bundle-analyzer\": \"^3.1.0\",\n    \"webpack-cli\": \"^3.3.2\",\n    \"webpack-merge\": \"^4.2.1\",\n    \"websocket.js\": \"^0.1.12\"\n  },\n  \"devDependencies\": {\n    \"babel-eslint\": \"^10.0.1\",\n    \"babel-jest\": \"^24.8.0\",\n    \"enzyme\": \"^3.8.0\",\n    \"enzyme-adapter-react-16\": \"^1.7.1\",\n    \"eslint\": \"^5.11.1\",\n    \"eslint-plugin-import\": \"~2.14.0\",\n    \"eslint-plugin-jsx-a11y\": \"~6.2.1\",\n    \"eslint-plugin-promise\": \"~4.1.1\",\n    \"eslint-plugin-react\": \"~7.12.1\",\n    \"jest\": \"^24.8.0\",\n    \"raf\": \"^3.4.1\",\n    \"react-intl-translations-manager\": \"^5.0.3\",\n    \"react-test-renderer\": \"^16.8.6\",\n    \"sass-lint\": \"^1.13.1\",\n    \"webpack-dev-server\": \"^3.5.1\",\n    \"yargs\": \"^12.0.5\"\n  }\n}\n"
  },
  {
    "path": "postcss.config.js",
    "content": "module.exports = ({ env }) => ({\n  plugins: {\n    autoprefixer: {},\n    'postcss-object-fit-images': {},\n    cssnano: env === 'production' ? {} : false,\n  },\n});\n"
  },
  {
    "path": "priv-config",
    "content": "listen-address  0.0.0.0:8118\n\nforward .   .\nforward-socks5t .onion  tor:9050    ."
  },
  {
    "path": "public/browserconfig.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<browserconfig>\n  <msapplication>\n    <tile>\n      <square150x150logo src=\"/mstile-150x150.png\"/>\n      <TileColor>#282c37</TileColor>\n    </tile>\n  </msapplication>\n</browserconfig>\n"
  },
  {
    "path": "public/embed.js",
    "content": "(function() {\n  'use strict';\n\n  var ready = function(loaded) {\n    if (['interactive', 'complete'].indexOf(document.readyState) !== -1) {\n      loaded();\n    } else {\n      document.addEventListener('DOMContentLoaded', loaded);\n    }\n  };\n\n  ready(function() {\n    var iframes = [];\n\n    window.addEventListener('message', function(e) {\n      var data = e.data || {};\n\n      if (data.type !== 'setHeight' || !iframes[data.id]) {\n        return;\n      }\n\n      iframes[data.id].height = data.height;\n    });\n\n    [].forEach.call(document.querySelectorAll('iframe.mastodon-embed'), function(iframe) {\n      iframe.scrolling      = 'no';\n      iframe.style.overflow = 'hidden';\n\n      iframes.push(iframe);\n\n      var id = iframes.length - 1;\n\n      iframe.onload = function() {\n        iframe.contentWindow.postMessage({\n          type: 'setHeight',\n          id: id,\n        }, '*');\n      };\n\n      iframe.onload();\n    });\n  });\n})();\n"
  },
  {
    "path": "public/robots.txt",
    "content": "# See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file\n\nUser-agent: *\nDisallow: /media_proxy/\nDisallow: /interact/\n"
  },
  {
    "path": "scalingo.json",
    "content": "{\n  \"name\": \"Florence Mastodon\",\n  \"description\": \"A GNU Social-compatible microblogging server\",\n  \"repository\": \"https://github.com/florence-social/mastodon-fork\",\n  \"logo\": \"https://github.com/tootsuite.png\",\n  \"env\": {\n    \"LOCAL_DOMAIN\": {\n      \"description\": \"The domain that your Mastodon instance will run on (this can be appname.scalingo.io or a custom domain)\",\n      \"required\": true\n    },\n    \"LOCAL_HTTPS\": {\n      \"description\": \"Will your domain support HTTPS? (Automatic for *.scalingo.io, requires manual configuration for custom domains)\",\n      \"value\": \"true\",\n      \"required\": true\n    },\n    \"PAPERCLIP_SECRET\": {\n      \"description\": \"The secret key for storing media files\",\n      \"generator\": \"secret\"\n    },\n    \"SECRET_KEY_BASE\": {\n      \"description\": \"The secret key base\",\n      \"generator\": \"secret\"\n    },\n    \"OTP_SECRET\": {\n      \"description\": \"One-time password secret\",\n      \"generator\": \"secret\"\n    },\n    \"SINGLE_USER_MODE\": {\n      \"description\": \"Should the instance run in single user mode? (Disable registrations, redirect to front page)\",\n      \"value\": \"false\",\n      \"required\": true\n    },\n    \"S3_ENABLED\": {\n      \"description\": \"Should Mastodon use Amazon S3 for storage? This is highly recommended, as Scalingo does not have persistent file storage (files will be lost).\",\n      \"value\": \"true\",\n      \"required\": false\n    },\n    \"S3_BUCKET\": {\n      \"description\": \"Amazon S3 Bucket\",\n      \"required\": false\n    },\n    \"S3_REGION\": {\n      \"description\": \"Amazon S3 region that the bucket is located in\",\n      \"required\": false\n    },\n    \"AWS_ACCESS_KEY_ID\": {\n      \"description\": \"Amazon S3 Access Key\",\n      \"required\": false\n    },\n    \"AWS_SECRET_ACCESS_KEY\": {\n      \"description\": \"Amazon S3 Secret Key\",\n      \"required\": false\n    },\n    \"SMTP_SERVER\": {\n      \"description\": \"Hostname for SMTP server, if you want to enable email\",\n      \"required\": false\n    },\n    \"SMTP_PORT\": {\n      \"description\": \"Port for SMTP server\",\n      \"required\": false\n    },\n    \"SMTP_LOGIN\": {\n      \"description\": \"Username for SMTP server\",\n      \"required\": false\n    },\n    \"SMTP_PASSWORD\": {\n      \"description\": \"Password for SMTP server\",\n      \"required\": false\n    },\n    \"SMTP_DOMAIN\": {\n      \"description\": \"Domain for SMTP server. Will default to instance domain if blank.\",\n      \"required\": false\n    },\n    \"SMTP_FROM_ADDRESS\": {\n      \"description\": \"Address to send emails from\",\n      \"required\": false\n    },\n    \"SMTP_AUTH_METHOD\": {\n      \"description\": \"Authentication method to use with SMTP server. Default is 'plain'.\",\n      \"required\": false\n    },\n    \"SMTP_OPENSSL_VERIFY_MODE\": {\n      \"description\": \"SMTP server certificate verification mode. Defaults is 'peer'.\",\n      \"required\": false\n    },\n    \"SMTP_ENABLE_STARTTLS_AUTO\": {\n      \"description\": \"Enable STARTTLS if SMTP server supports it? Default is true.\",\n      \"required\": false\n    },\n    \"BUILDPACK_URL\": {\n      \"description\": \"Internal scalingo configuration\",\n      \"required\": true,\n      \"value\": \"https://github.com/Scalingo/multi-buildpack.git\"\n    },\n    \"WITH_FFPROBE\": {\n      \"description\": \"Internal scalingo configuration to install ffprobe\",\n      \"required\": true,\n      \"value\": \"true\"\n    }\n  },\n  \"scripts\": {\n    \"postdeploy\": \"bundle exec rails db:migrate && bundle exec rails db:seed\"\n  },\n  \"addons\": [\n    \"postgresql\",\n    \"redis\"\n  ]\n}\n"
  },
  {
    "path": "spec/controllers/about_controller_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe AboutController, type: :controller do\n  render_views\n\n  describe 'GET #show' do\n    before do\n      get :show\n    end\n\n    it 'assigns @instance_presenter' do\n      expect(assigns(:instance_presenter)).to be_kind_of InstancePresenter\n    end\n\n    it 'returns http success' do\n      expect(response).to have_http_status(200)\n    end\n  end\n\n  describe 'GET #more' do\n    before do\n      get :more\n    end\n\n    it 'assigns @instance_presenter' do\n      expect(assigns(:instance_presenter)).to be_kind_of InstancePresenter\n    end\n\n    it 'returns http success' do\n      expect(response).to have_http_status(200)\n    end\n  end\n\n  describe 'GET #terms' do\n    before do\n      get :terms\n    end\n\n    it 'returns http success' do\n      expect(response).to have_http_status(200)\n    end\n  end\n\n  describe 'helper_method :new_user' do\n    it 'returns a new User' do\n      user = @controller.view_context.new_user\n      expect(user).to be_kind_of User\n      expect(user.account).to be_kind_of Account\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/account_follow_controller_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe AccountFollowController do\n  render_views\n\n  let(:user) { Fabricate(:user) }\n  let(:alice) { Fabricate(:account, username: 'alice') }\n\n  describe 'POST #create' do\n    let(:service) { double }\n\n    subject { post :create, params: { account_username: alice.username } }\n\n    before do\n      allow(FollowService).to receive(:new).and_return(service)\n      allow(service).to receive(:call)\n    end\n\n    it 'does not create for user who is not signed in' do\n      subject\n      expect(FollowService).not_to receive(:new)\n    end\n\n    it 'redirects to account path' do\n      sign_in(user)\n      subject\n\n      expect(service).to have_received(:call).with(user.account, 'alice')\n      expect(response).to redirect_to(account_path(alice))\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/account_unfollow_controller_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe AccountUnfollowController do\n  render_views\n\n  let(:user) { Fabricate(:user) }\n  let(:alice) { Fabricate(:account, username: 'alice') }\n\n  describe 'POST #create' do\n    let(:service) { double }\n\n    subject { post :create, params: { account_username: alice.username } }\n\n    before do\n      allow(UnfollowService).to receive(:new).and_return(service)\n      allow(service).to receive(:call)\n    end\n\n    it 'does not create for user who is not signed in' do\n      subject\n      expect(UnfollowService).not_to receive(:new)\n    end\n\n    it 'redirects to account path' do\n      sign_in(user)\n      subject\n\n      expect(service).to have_received(:call).with(user.account, alice)\n      expect(response).to redirect_to(account_path(alice))\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/accounts_controller_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe AccountsController, type: :controller do\n  render_views\n\n  let(:alice) { Fabricate(:account, username: 'alice', user: Fabricate(:user)) }\n  let(:eve) { Fabricate(:user) }\n\n  describe 'GET #show' do\n    let!(:status1) { Status.create!(account: alice, text: 'Hello world') }\n    let!(:status2) { Status.create!(account: alice, text: 'Boop', thread: status1) }\n    let!(:status3) { Status.create!(account: alice, text: 'Picture!') }\n    let!(:status4) { Status.create!(account: alice, text: 'Mentioning @alice') }\n    let!(:status5) { Status.create!(account: alice, text: 'Kitsune') }\n    let!(:status6) { Status.create!(account: alice, text: 'Neko') }\n    let!(:status7) { Status.create!(account: alice, text: 'Tanuki') }\n\n    let!(:status_pin1) { StatusPin.create!(account: alice, status: status5, created_at: 5.days.ago) }\n    let!(:status_pin2) { StatusPin.create!(account: alice, status: status6, created_at: 2.years.ago) }\n    let!(:status_pin3) { StatusPin.create!(account: alice, status: status7, created_at: 10.minutes.ago) }\n\n    before do\n      alice.block!(eve.account)\n      status3.media_attachments.create!(account: alice, file: fixture_file_upload('files/attachment.jpg', 'image/jpeg'))\n    end\n\n    shared_examples 'responses' do\n      before do\n        sign_in(current_user) if defined? current_user\n        get :show, params: {\n          username: alice.username,\n          max_id: (max_id if defined? max_id),\n          since_id: (since_id if defined? since_id),\n          current_user: (current_user if defined? current_user),\n        }, format: format\n      end\n\n      it 'assigns @account' do\n        expect(assigns(:account)).to eq alice\n      end\n\n      it 'returns http success' do\n        expect(response).to have_http_status(200)\n      end\n\n      it 'returns correct format' do\n        expect(response.content_type).to eq content_type\n      end\n    end\n\n    context 'atom' do\n      let(:format) { 'atom' }\n      let(:content_type) { 'application/atom+xml' }\n\n      shared_examples 'responsed streams' do\n        it 'assigns @entries' do\n          entries = assigns(:entries).to_a\n          expect(entries.size).to eq expected_statuses.size\n          entries.each.zip(expected_statuses.each) do |entry, expected_status|\n            expect(entry.status).to eq expected_status\n          end\n        end\n      end\n\n      include_examples 'responses'\n\n      context 'without max_id nor since_id' do\n        let(:expected_statuses) { [status7, status6, status5, status4, status3, status2, status1] }\n\n        include_examples 'responsed streams'\n      end\n\n      context 'with max_id and since_id' do\n        let(:max_id) { status4.stream_entry.id }\n        let(:since_id) { status1.stream_entry.id }\n        let(:expected_statuses) { [status3, status2] }\n\n        include_examples 'responsed streams'\n      end\n    end\n\n    context 'activitystreams2' do\n      let(:format) { 'json' }\n      let(:content_type) { 'application/activity+json' }\n\n      include_examples 'responses'\n    end\n\n    context 'html' do\n      let(:format) { nil }\n      let(:content_type) { 'text/html' }\n\n      shared_examples 'responsed statuses' do\n        it 'assigns @pinned_statuses' do\n          pinned_statuses = assigns(:pinned_statuses).to_a\n          expect(pinned_statuses.size).to eq expected_pinned_statuses.size\n          pinned_statuses.each.zip(expected_pinned_statuses.each) do |pinned_status, expected_pinned_status|\n            expect(pinned_status).to eq expected_pinned_status\n          end\n        end\n\n        it 'assigns @statuses' do\n          statuses = assigns(:statuses).to_a\n          expect(statuses.size).to eq expected_statuses.size\n          statuses.each.zip(expected_statuses.each) do |status, expected_status|\n            expect(status).to eq expected_status\n          end\n        end\n      end\n\n      include_examples 'responses'\n\n      context 'with anonymous visitor' do\n        context 'without since_id nor max_id' do\n          let(:expected_statuses) { [status7, status6, status5, status4, status3, status2, status1] }\n          let(:expected_pinned_statuses) { [status7, status5, status6] }\n\n          include_examples 'responsed statuses'\n        end\n\n        context 'with since_id nor max_id' do\n          let(:max_id) { status4.id }\n          let(:since_id) { status1.id }\n          let(:expected_statuses) { [status3, status2] }\n          let(:expected_pinned_statuses) { [] }\n\n          include_examples 'responsed statuses'\n        end\n      end\n\n      context 'with blocked visitor' do\n        let(:current_user) { eve }\n\n        context 'without since_id nor max_id' do\n          let(:expected_statuses) { [] }\n          let(:expected_pinned_statuses) { [] }\n\n          include_examples 'responsed statuses'\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/activitypub/collections_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe ActivityPub::CollectionsController, type: :controller do\n  describe 'POST #show' do\n    let(:account) { Fabricate(:account) }\n\n    context 'id is \"featured\"' do\n      it 'returns 200 with \"application/activity+json\"' do\n        post :show, params: { id: 'featured', account_username: account.username }\n\n        expect(response).to have_http_status(200)\n        expect(response.content_type).to eq 'application/activity+json'\n      end\n    end\n\n    context 'id is not \"featured\"' do\n      it 'returns 404' do\n        post :show, params: { id: 'hoge', account_username: account.username }\n        expect(response).to have_http_status(404)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/activitypub/inboxes_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe ActivityPub::InboxesController, type: :controller do\n  describe 'POST #create' do\n    context 'if signed_request_account' do\n      it 'returns 202' do\n        allow(controller).to receive(:signed_request_account) do\n          Fabricate(:account)\n        end\n\n        post :create, body: '{}'\n        expect(response).to have_http_status(202)\n      end\n    end\n\n    context 'not signed_request_account' do\n      it 'returns 401' do\n        allow(controller).to receive(:signed_request_account) do\n          false\n        end\n\n        post :create, body: '{}'\n        expect(response).to have_http_status(401)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/activitypub/outboxes_controller_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe ActivityPub::OutboxesController, type: :controller do\n  let!(:account) { Fabricate(:account) }\n\n  before do\n    Fabricate(:status, account: account)\n  end\n\n  describe 'GET #show' do\n    before do\n      get :show, params: { account_username: account.username }\n    end\n\n    it 'returns http success' do\n      expect(response).to have_http_status(200)\n    end\n\n    it 'returns application/activity+json' do\n      expect(response.content_type).to eq 'application/activity+json'\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/admin/account_moderation_notes_controller_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Admin::AccountModerationNotesController, type: :controller do\n  render_views\n\n  let(:user) { Fabricate(:user, admin: true) }\n  let(:target_account) { Fabricate(:account) }\n\n  before do\n    sign_in user, scope: :user\n  end\n\n  describe 'POST #create' do\n    subject { post :create, params: params }\n\n    context 'when parameters are valid' do\n      let(:params) { { account_moderation_note: { target_account_id: target_account.id, content: 'test content' } } }\n\n      it 'successfully creates a note' do\n        expect { subject }.to change { AccountModerationNote.count }.by(1)\n        expect(subject).to redirect_to admin_account_path(target_account.id)\n      end\n    end\n\n    context 'when parameters are invalid' do\n      let(:params) { { account_moderation_note: { target_account_id: target_account.id, content: '' } } }\n\n      it 'falls to create a note' do\n        expect { subject }.not_to change { AccountModerationNote.count }\n        expect(subject).to render_template 'admin/accounts/show'\n      end\n    end\n  end\n\n  describe 'DELETE #destroy' do\n    subject { delete :destroy, params: { id: note.id } }\n\n    let!(:note) { Fabricate(:account_moderation_note, account: account, target_account: target_account) }\n    let(:account) { Fabricate(:account) }\n\n    it 'destroys note' do\n      expect { subject }.to change { AccountModerationNote.count }.by(-1)\n      expect(subject).to redirect_to admin_account_path(target_account.id)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/admin/accounts_controller_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Admin::AccountsController, type: :controller do\n  render_views\n\n  before { sign_in current_user, scope: :user }\n\n  describe 'GET #index' do\n    let(:current_user) { Fabricate(:user, admin: true) }\n\n    around do |example|\n      default_per_page = Account.default_per_page\n      Account.paginates_per 1\n      example.run\n      Account.paginates_per default_per_page\n    end\n\n    it 'filters with parameters' do\n      new = AccountFilter.method(:new)\n\n      expect(AccountFilter).to receive(:new) do |params|\n        h = params.to_h\n\n        expect(h[:local]).to eq '1'\n        expect(h[:remote]).to eq '1'\n        expect(h[:by_domain]).to eq 'domain'\n        expect(h[:active]).to eq '1'\n        expect(h[:silenced]).to eq '1'\n        expect(h[:suspended]).to eq '1'\n        expect(h[:username]).to eq 'username'\n        expect(h[:display_name]).to eq 'display name'\n        expect(h[:email]).to eq 'local-part@domain'\n        expect(h[:ip]).to eq '0.0.0.42'\n\n        new.call({})\n      end\n\n      get :index, params: {\n        local: '1',\n        remote: '1',\n        by_domain: 'domain',\n        active: '1',\n        silenced: '1',\n        suspended: '1',\n        username: 'username',\n        display_name: 'display name',\n        email: 'local-part@domain',\n        ip: '0.0.0.42'\n      }\n    end\n\n    it 'paginates accounts' do\n      Fabricate(:account)\n\n      get :index, params: { page: 2 }\n\n      accounts = assigns(:accounts)\n      expect(accounts.count).to eq 1\n      expect(accounts.klass).to be Account\n    end\n\n    it 'returns http success' do\n      get :index\n      expect(response).to have_http_status(200)\n    end\n  end\n\n  describe 'GET #show' do\n    let(:current_user) { Fabricate(:user, admin: true) }\n    let(:account) { Fabricate(:account, username: 'bob') }\n\n    it 'returns http success' do\n      get :show, params: { id: account.id }\n      expect(response).to have_http_status(200)\n    end\n  end\n\n  describe 'POST #subscribe' do\n    subject { post :subscribe, params: { id: account.id } }\n\n    let(:current_user) { Fabricate(:user, admin: admin) }\n    let(:account) { Fabricate(:account) }\n\n    context 'when user is admin' do\n      let(:admin) { true }\n\n      it { is_expected.to redirect_to admin_account_path(account.id) }\n    end\n\n    context 'when user is not admin' do\n      let(:admin) { false }\n\n      it { is_expected.to have_http_status :forbidden }\n    end\n  end\n\n  describe 'POST #unsubscribe' do\n    subject { post :unsubscribe, params: { id: account.id } }\n\n    let(:current_user) { Fabricate(:user, admin: admin) }\n    let(:account) { Fabricate(:account) }\n\n    context 'when user is admin' do\n      let(:admin) { true }\n\n      it { is_expected.to redirect_to admin_account_path(account.id) }\n    end\n\n    context 'when user is not admin' do\n      let(:admin) { false }\n\n      it { is_expected.to have_http_status :forbidden }\n    end\n  end\n\n  describe 'POST #memorialize' do\n    subject { post :memorialize, params: { id: account.id } }\n\n    let(:current_user) { Fabricate(:user, admin: current_user_admin) }\n    let(:account) { Fabricate(:account, user: user) }\n    let(:user) { Fabricate(:user, admin: target_user_admin) }\n\n    context 'when user is admin' do\n      let(:current_user_admin) { true }\n\n      context 'when target user is admin' do\n        let(:target_user_admin) { true }\n\n        it 'fails to memorialize account' do\n          is_expected.to have_http_status :forbidden\n          expect(account.reload).not_to be_memorial\n        end\n      end\n\n      context 'when target user is not admin' do\n        let(:target_user_admin) { false }\n\n        it 'succeeds in memorializing account' do\n          is_expected.to redirect_to admin_account_path(account.id)\n          expect(account.reload).to be_memorial\n        end\n      end\n    end\n\n    context 'when user is not admin' do\n      let(:current_user_admin) { false }\n\n      context 'when target user is admin' do\n        let(:target_user_admin) { true }\n\n        it 'fails to memorialize account' do\n          is_expected.to have_http_status :forbidden\n          expect(account.reload).not_to be_memorial\n        end\n      end\n\n      context 'when target user is not admin' do\n        let(:target_user_admin) { false }\n\n        it 'fails to memorialize account' do\n          is_expected.to have_http_status :forbidden\n          expect(account.reload).not_to be_memorial\n        end\n      end\n    end\n  end\n\n  describe 'POST #enable' do\n    subject { post :enable, params: { id: account.id } }\n\n    let(:current_user) { Fabricate(:user, admin: admin) }\n    let(:account) { Fabricate(:account, user: user) }\n    let(:user) { Fabricate(:user, disabled: true) }\n\n    context 'when user is admin' do\n      let(:admin) { true }\n\n      it 'succeeds in enabling account' do\n        is_expected.to redirect_to admin_account_path(account.id)\n        expect(user.reload).not_to be_disabled\n      end\n    end\n\n    context 'when user is not admin' do\n      let(:admin) { false }\n\n      it 'fails to enable account' do\n        is_expected.to have_http_status :forbidden\n        expect(user.reload).to be_disabled\n      end\n    end\n  end\n\n  describe 'POST #redownload' do\n    subject { post :redownload, params: { id: account.id } }\n\n    let(:current_user) { Fabricate(:user, admin: admin) }\n    let(:account) { Fabricate(:account) }\n\n    context 'when user is admin' do\n      let(:admin) { true }\n\n      it 'succeeds in redownloadin' do\n        is_expected.to redirect_to admin_account_path(account.id)\n      end\n    end\n\n    context 'when user is not admin' do\n      let(:admin) { false }\n\n      it 'fails to redownload' do\n        is_expected.to have_http_status :forbidden\n      end\n    end\n  end\n\n  describe 'POST #remove_avatar' do\n    subject { post :remove_avatar, params: { id: account.id } }\n\n    let(:current_user) { Fabricate(:user, admin: admin) }\n    let(:account) { Fabricate(:account) }\n\n    context 'when user is admin' do\n      let(:admin) { true }\n\n      it 'succeeds in removing avatar' do\n        is_expected.to redirect_to admin_account_path(account.id)\n      end\n    end\n\n    context 'when user is not admin' do\n      let(:admin) { false }\n\n      it 'fails to remove avatar' do\n        is_expected.to have_http_status :forbidden\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/admin/action_logs_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe Admin::ActionLogsController, type: :controller do\n  describe 'GET #index' do\n    it 'returns 200' do\n      sign_in Fabricate(:user, admin: true)\n      get :index, params: { page: 1 }\n\n      expect(response).to have_http_status(200)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/admin/base_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe Admin::BaseController, type: :controller do\n  controller do\n    def success\n      render 'admin/reports/show'\n    end\n  end\n\n  it 'requires administrator or moderator' do\n    routes.draw { get 'success' => 'admin/base#success' }\n    sign_in(Fabricate(:user, admin: false, moderator: false))\n    get :success\n\n    expect(response).to have_http_status(:forbidden)\n  end\n\n  it 'renders admin layout as a moderator' do\n    routes.draw { get 'success' => 'admin/base#success' }\n    sign_in(Fabricate(:user, moderator: true))\n    get :success\n    expect(response).to render_template layout: 'admin'\n  end\n\n  it 'renders admin layout as an admin' do\n    routes.draw { get 'success' => 'admin/base#success' }\n    sign_in(Fabricate(:user, admin: true))\n    get :success\n    expect(response).to render_template layout: 'admin'\n  end\nend\n"
  },
  {
    "path": "spec/controllers/admin/change_email_controller_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Admin::ChangeEmailsController, type: :controller do\n  render_views\n\n  let(:admin) { Fabricate(:user, admin: true) }\n\n  before do\n    sign_in admin\n  end\n\n  describe \"GET #show\" do\n    it \"returns http success\" do\n      account = Fabricate(:account)\n      user = Fabricate(:user, account: account)\n\n      get :show, params: { account_id: account.id }\n\n      expect(response).to have_http_status(200)\n    end\n  end\n\n  describe \"GET #update\" do\n    before do\n      allow(UserMailer).to receive(:confirmation_instructions).and_return(double('email', deliver_later: nil))\n    end\n\n    it \"returns http success\" do\n      account = Fabricate(:account)\n      user = Fabricate(:user, account: account)\n\n      previous_email = user.email\n\n      post :update, params: { account_id: account.id, user: { unconfirmed_email: 'test@example.com' } }\n\n      user.reload\n\n      expect(user.email).to eq previous_email\n      expect(user.unconfirmed_email).to eq 'test@example.com'\n      expect(user.confirmation_token).not_to be_nil\n\n      expect(UserMailer).to have_received(:confirmation_instructions).with(user, user.confirmation_token, { to: 'test@example.com' })\n\n      expect(response).to redirect_to(admin_account_path(account.id))\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/admin/confirmations_controller_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Admin::ConfirmationsController, type: :controller do\n  render_views\n\n  before do\n    sign_in Fabricate(:user, admin: true), scope: :user\n  end\n\n  describe 'POST #create' do\n    it 'confirms the user' do\n      account = Fabricate(:account)\n      user = Fabricate(:user, confirmed_at: false, account: account)\n      post :create, params: { account_id: account.id }\n\n      expect(response).to redirect_to(admin_accounts_path)\n      expect(user.reload).to be_confirmed\n    end\n\n    it 'raises an error when there is no account' do\n      post :create, params: { account_id: 'fake' }\n\n      expect(response).to have_http_status(404)\n    end\n\n    it 'raises an error when there is no user' do\n      account = Fabricate(:account, user: nil)\n      post :create, params: { account_id: account.id }\n\n      expect(response).to have_http_status(404)\n    end\n  end\n\n  describe 'POST #resernd' do\n    subject { post :resend, params: { account_id: account.id } }\n\n    let(:account) { Fabricate(:account) }\n    let!(:user) { Fabricate(:user, confirmed_at: confirmed_at, account: account) }\n\n    before do\n      allow(UserMailer).to receive(:confirmation_instructions) { double(:email, deliver_later: nil) }\n    end\n\n    context 'when email is not confirmed' do\n      let(:confirmed_at) { nil }\n\n      it 'resends confirmation mail' do\n        expect(subject).to redirect_to admin_accounts_path\n        expect(flash[:notice]).to eq I18n.t('admin.accounts.resend_confirmation.success')\n        expect(UserMailer).to have_received(:confirmation_instructions).once\n      end\n    end\n\n    context 'when email is confirmed' do\n      let(:confirmed_at) { Time.zone.now }\n\n      it 'does not resend confirmation mail' do\n        expect(subject).to redirect_to admin_accounts_path\n        expect(flash[:error]).to eq I18n.t('admin.accounts.resend_confirmation.already_confirmed')\n        expect(UserMailer).not_to have_received(:confirmation_instructions)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/admin/custom_emojis_controller_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe Admin::CustomEmojisController do\n  render_views\n\n  let(:user) { Fabricate(:user, admin: true) }\n\n  before do\n    sign_in user, scope: :user\n  end\n\n  describe 'GET #index' do\n    subject { get :index }\n\n    before do\n      Fabricate(:custom_emoji)\n    end\n\n    it 'renders index page' do\n      expect(subject).to have_http_status 200\n      expect(subject).to render_template :index\n    end\n  end\n\n  describe 'GET #new' do\n    subject { get :new }\n\n    it 'renders new page' do\n      expect(subject).to have_http_status 200\n      expect(subject).to render_template :new\n    end\n  end\n\n  describe 'POST #create' do\n    subject { post :create, params: { custom_emoji: params } }\n\n    let(:image) { fixture_file_upload(Rails.root.join('spec', 'fixtures', 'files', 'emojo.png'), 'image/png') }\n\n    context 'when parameter is valid' do\n      let(:params) { { shortcode: 'test', image: image } }\n\n      it 'creates custom emoji' do\n        expect { subject }.to change { CustomEmoji.count }.by(1)\n      end\n    end\n\n    context 'when parameter is invalid' do\n      let(:params) { { shortcode: 't', image: image } }\n\n      it 'renders new' do\n        expect(subject).to render_template :new\n      end\n    end\n  end\n\n  describe 'PUT #update' do\n    let(:custom_emoji) { Fabricate(:custom_emoji, shortcode: 'test') }\n    let(:image) { fixture_file_upload(Rails.root.join('spec', 'fixtures', 'files', 'emojo.png'), 'image/png') }\n\n    before do\n      put :update, params: { id: custom_emoji.id, custom_emoji: params }\n    end\n\n    context 'when parameter is valid' do\n      let(:params) { { shortcode: 'updated', image: image } }\n\n      it 'succeeds in updating custom emoji' do\n        expect(flash[:notice]).to eq I18n.t('admin.custom_emojis.updated_msg')\n        expect(custom_emoji.reload).to have_attributes(shortcode: 'updated')\n      end\n    end\n\n    context 'when parameter is invalid' do\n      let(:params) { { shortcode: 'u', image: image } }\n\n      it 'fails to update custom emoji' do\n        expect(flash[:alert]).to eq I18n.t('admin.custom_emojis.update_failed_msg')\n        expect(custom_emoji.reload).to have_attributes(shortcode: 'test')\n      end\n    end\n  end\n\n  describe 'POST #copy' do\n    subject { post :copy, params: { id: custom_emoji.id } }\n\n    let(:custom_emoji) { Fabricate(:custom_emoji, shortcode: 'test') }\n\n    it 'copies custom emoji' do\n      expect { subject }.to change { CustomEmoji.where(shortcode: 'test').count }.by(1)\n      expect(flash[:notice]).to eq I18n.t('admin.custom_emojis.copied_msg')\n    end\n  end\n\n  describe 'POST #enable' do\n    let(:custom_emoji) { Fabricate(:custom_emoji, shortcode: 'test', disabled: true) }\n\n    before { post :enable, params: { id: custom_emoji.id } }\n\n    it 'enables custom emoji' do\n      expect(response).to redirect_to admin_custom_emojis_path\n      expect(custom_emoji.reload).to have_attributes(disabled: false)\n    end\n  end\n\n  describe 'POST #disable' do\n    let(:custom_emoji) { Fabricate(:custom_emoji, shortcode: 'test', disabled: false) }\n\n    before { post :disable, params: { id: custom_emoji.id } }\n\n    it 'enables custom emoji' do\n      expect(response).to redirect_to admin_custom_emojis_path\n      expect(custom_emoji.reload).to have_attributes(disabled: true)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/admin/dashboard_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe Admin::DashboardController, type: :controller do\n  describe 'GET #index' do\n    it 'returns 200' do\n      sign_in Fabricate(:user, admin: true)\n      get :index\n\n      expect(response).to have_http_status(200)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/admin/domain_blocks_controller_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Admin::DomainBlocksController, type: :controller do\n  render_views\n\n  before do\n    sign_in Fabricate(:user, admin: true), scope: :user\n  end\n\n  describe 'GET #new' do\n    it 'assigns a new domain block' do\n      get :new\n\n      expect(assigns(:domain_block)).to be_instance_of(DomainBlock)\n      expect(response).to have_http_status(200)\n    end\n  end\n\n  describe 'GET #show' do\n    it 'returns http success' do\n      domain_block = Fabricate(:domain_block)\n      get :show, params: { id: domain_block.id }\n\n      expect(response).to have_http_status(200)\n    end\n  end\n\n  describe 'POST #create' do\n    it 'blocks the domain when succeeded to save' do\n      allow(DomainBlockWorker).to receive(:perform_async).and_return(true)\n\n      post :create, params: { domain_block: { domain: 'example.com', severity: 'silence' } }\n\n      expect(DomainBlockWorker).to have_received(:perform_async)\n      expect(flash[:notice]).to eq I18n.t('admin.domain_blocks.created_msg')\n      expect(response).to redirect_to(admin_instances_path(limited: '1'))\n    end\n\n    it 'renders new when failed to save' do\n      Fabricate(:domain_block, domain: 'example.com', severity: 'suspend')\n      allow(DomainBlockWorker).to receive(:perform_async).and_return(true)\n\n      post :create, params: { domain_block: { domain: 'example.com', severity: 'silence' } }\n\n      expect(DomainBlockWorker).not_to have_received(:perform_async)\n      expect(response).to render_template :new\n    end\n\n    it 'allows upgrading a block' do\n      Fabricate(:domain_block, domain: 'example.com', severity: 'silence')\n      allow(DomainBlockWorker).to receive(:perform_async).and_return(true)\n\n      post :create, params: { domain_block: { domain: 'example.com', severity: 'silence', reject_media: true, reject_reports: true } }\n\n      expect(DomainBlockWorker).to have_received(:perform_async)\n      expect(flash[:notice]).to eq I18n.t('admin.domain_blocks.created_msg')\n      expect(response).to redirect_to(admin_instances_path(limited: '1'))\n    end\n  end\n\n  describe 'DELETE #destroy' do\n    it 'unblocks the domain' do\n      service = double(call: true)\n      allow(UnblockDomainService).to receive(:new).and_return(service)\n      domain_block = Fabricate(:domain_block)\n      delete :destroy, params: { id: domain_block.id }\n\n      expect(service).to have_received(:call).with(domain_block)\n      expect(flash[:notice]).to eq I18n.t('admin.domain_blocks.destroyed_msg')\n      expect(response).to redirect_to(admin_instances_path(limited: '1'))\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/admin/email_domain_blocks_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe Admin::EmailDomainBlocksController, type: :controller do\n  render_views\n\n  before do\n    sign_in Fabricate(:user, admin: true), scope: :user\n  end\n\n  describe 'GET #index' do\n    around do |example|\n      default_per_page = EmailDomainBlock.default_per_page\n      EmailDomainBlock.paginates_per 1\n      example.run\n      EmailDomainBlock.paginates_per default_per_page\n    end\n\n    it 'renders email blacks' do\n      2.times { Fabricate(:email_domain_block) }\n\n      get :index, params: { page: 2 }\n\n      assigned = assigns(:email_domain_blocks)\n      expect(assigned.count).to eq 1\n      expect(assigned.klass).to be EmailDomainBlock\n      expect(response).to have_http_status(200)\n    end\n  end\n\n  describe 'GET #new' do\n    it 'assigns a new email black' do\n      get :new\n\n      expect(assigns(:email_domain_block)).to be_instance_of(EmailDomainBlock)\n      expect(response).to have_http_status(200)\n    end\n  end\n\n  describe 'POST #create' do\n    it 'blocks the domain when succeeded to save' do\n      post :create, params: { email_domain_block: { domain: 'example.com' } }\n\n      expect(flash[:notice]).to eq I18n.t('admin.email_domain_blocks.created_msg')\n      expect(response).to redirect_to(admin_email_domain_blocks_path)\n    end\n  end\n\n  describe 'DELETE #destroy' do\n    it 'unblocks the domain' do\n      email_domain_block = Fabricate(:email_domain_block)\n      delete :destroy, params: { id: email_domain_block.id }\n\n      expect(flash[:notice]).to eq I18n.t('admin.email_domain_blocks.destroyed_msg')\n      expect(response).to redirect_to(admin_email_domain_blocks_path)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/admin/instances_controller_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Admin::InstancesController, type: :controller do\n  render_views\n\n  before do\n    sign_in Fabricate(:user, admin: true), scope: :user\n  end\n\n  describe 'GET #index' do\n    around do |example|\n      default_per_page = Account.default_per_page\n      Account.paginates_per 1\n      example.run\n      Account.paginates_per default_per_page\n    end\n\n    it 'renders instances' do\n      Fabricate(:account, domain: 'popular')\n      Fabricate(:account, domain: 'popular')\n      Fabricate(:account, domain: 'less.popular')\n\n      get :index, params: { page: 2 }\n\n      instances = assigns(:instances).to_a\n      expect(instances.size).to eq 1\n      expect(instances[0].domain).to eq 'less.popular'\n\n      expect(response).to have_http_status(200)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/admin/invites_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe Admin::InvitesController do\n  render_views\n\n  let(:user) { Fabricate(:user, admin: true) }\n\n  before do\n    sign_in user, scope: :user\n  end\n\n  describe 'GET #index' do\n    subject { get :index, params: { available: true } }\n\n    let!(:invite) { Fabricate(:invite) }\n\n    it 'renders index page' do\n      expect(subject).to render_template :index\n      expect(assigns(:invites)).to include invite\n    end\n  end\n\n  describe 'POST #create' do\n    subject { post :create, params: { invite: { max_uses: '10', expires_in: 1800 } } }\n\n    it 'succeeds to create a invite' do\n      expect { subject }.to change { Invite.count }.by(1)\n      expect(subject).to redirect_to admin_invites_path\n      expect(Invite.last).to have_attributes(user_id: user.id, max_uses: 10)\n    end\n  end\n\n  describe 'DELETE #destroy' do\n    let!(:invite) { Fabricate(:invite, expires_at: nil) }\n\n    subject { delete :destroy, params: { id: invite.id } }\n\n    it 'expires invite' do\n      expect(subject).to redirect_to admin_invites_path\n      expect(invite.reload).to be_expired\n    end\n  end\n\n  describe 'POST #deactivate_all' do\n    it 'expires all invites, then redirects to admin_invites_path' do\n      invites = Fabricate.times(2, :invite, expires_at: nil)\n\n      post :deactivate_all\n\n      invites.each do |invite|\n        expect(invite.reload).to be_expired\n      end\n\n      expect(response).to redirect_to admin_invites_path\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/admin/report_notes_controller_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe Admin::ReportNotesController do\n  render_views\n\n  let(:user) { Fabricate(:user, admin: true) }\n\n  before do\n    sign_in user, scope: :user\n  end\n\n  describe 'POST #create' do\n    subject { post :create, params: params }\n\n    let(:report) { Fabricate(:report, action_taken: action_taken, action_taken_by_account_id: account_id) }\n\n    context 'when parameter is valid' do\n      context 'when report is unsolved' do\n        let(:action_taken) { false }\n        let(:account_id) { nil }\n\n        context 'when create_and_resolve flag is on' do\n          let(:params) { { report_note: { content: 'test content', report_id: report.id }, create_and_resolve: nil } }\n\n          it 'creates a report note and resolves report' do\n            expect { subject }.to change { ReportNote.count }.by(1)\n            expect(report.reload).to be_action_taken\n            expect(subject).to redirect_to admin_reports_path\n          end\n        end\n\n        context 'when create_and_resolve flag is false' do\n          let(:params) { { report_note: { content: 'test content', report_id: report.id } } }\n\n          it 'creates a report note and does not resolve report' do\n            expect { subject }.to change { ReportNote.count }.by(1)\n            expect(report.reload).not_to be_action_taken\n            expect(subject).to redirect_to admin_report_path(report)\n          end\n        end\n      end\n\n      context 'when report is resolved' do\n        let(:action_taken) { true }\n        let(:account_id) { user.account.id }\n\n        context 'when create_and_unresolve flag is on' do\n          let(:params) { { report_note: { content: 'test content', report_id: report.id }, create_and_unresolve: nil } }\n\n          it 'creates a report note and unresolves report' do\n            expect { subject }.to change { ReportNote.count }.by(1)\n            expect(report.reload).not_to be_action_taken\n            expect(subject).to redirect_to admin_report_path(report)\n          end\n        end\n\n        context 'when create_and_unresolve flag is false' do\n          let(:params) { { report_note: { content: 'test content', report_id: report.id } } }\n\n          it 'creates a report note and does not unresolve report' do\n            expect { subject }.to change { ReportNote.count }.by(1)\n            expect(report.reload).to be_action_taken\n            expect(subject).to redirect_to admin_report_path(report)\n          end\n        end\n      end\n    end\n\n    context 'when parameter is invalid' do\n      let(:params) { { report_note: { content: '', report_id: report.id } } }\n      let(:action_taken) { false }\n      let(:account_id) { nil }\n\n      it 'renders admin/reports/show' do\n        expect(subject).to render_template 'admin/reports/show'\n      end\n    end\n  end\n\n  describe 'DELETE #destroy' do\n    subject { delete :destroy, params: { id: report_note.id } }\n\n    let!(:report_note) { Fabricate(:report_note) }\n\n    it 'deletes note' do\n      expect { subject }.to change { ReportNote.count }.by(-1)\n      expect(subject).to redirect_to admin_report_path(report_note.report)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/admin/reported_statuses_controller_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe Admin::ReportedStatusesController do\n  render_views\n\n  let(:user) { Fabricate(:user, admin: true) }\n  let(:report) { Fabricate(:report, status_ids: [status.id]) }\n  let(:status) { Fabricate(:status) }\n\n  before do\n    sign_in user, scope: :user\n  end\n\n  describe 'POST #create' do\n    subject do\n      -> { post :create, params: { :report_id => report, action => '', :form_status_batch => { status_ids: status_ids } } }\n    end\n\n    let(:action) { 'nsfw_on' }\n    let(:status_ids) { [status.id] }\n    let(:status) { Fabricate(:status, sensitive: !sensitive) }\n    let(:sensitive) { true }\n    let!(:media_attachment) { Fabricate(:media_attachment, status: status) }\n\n    context 'when action is nsfw_on' do\n      it 'updates sensitive column' do\n        is_expected.to change {\n          status.reload.sensitive\n        }.from(false).to(true)\n      end\n    end\n\n    context 'when action is nsfw_off' do\n      let(:action) { 'nsfw_off' }\n      let(:sensitive) { false }\n\n      it 'updates sensitive column' do\n        is_expected.to change {\n          status.reload.sensitive\n        }.from(true).to(false)\n      end\n    end\n\n    context 'when action is delete' do\n      let(:action) { 'delete' }\n\n      it 'removes a status' do\n        allow(RemovalWorker).to receive(:perform_async)\n        subject.call\n        expect(RemovalWorker).to have_received(:perform_async).with(status_ids.first)\n      end\n    end\n\n    it 'redirects to report page' do\n      subject.call\n      expect(response).to redirect_to(admin_report_path(report))\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/admin/reports_controller_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe Admin::ReportsController do\n  render_views\n\n  let(:user) { Fabricate(:user, admin: true) }\n  before do\n    sign_in user, scope: :user\n  end\n\n  describe 'GET #index' do\n    it 'returns http success with no filters' do\n      specified = Fabricate(:report, action_taken: false)\n      Fabricate(:report, action_taken: true)\n\n      get :index\n\n      reports = assigns(:reports).to_a\n      expect(reports.size).to eq 1\n      expect(reports[0]).to eq specified\n      expect(response).to have_http_status(200)\n    end\n\n    it 'returns http success with resolved filter' do\n      specified = Fabricate(:report, action_taken: true)\n      Fabricate(:report, action_taken: false)\n\n      get :index, params: { resolved: 1 }\n\n      reports = assigns(:reports).to_a\n      expect(reports.size).to eq 1\n      expect(reports[0]).to eq specified\n\n      expect(response).to have_http_status(200)\n    end\n  end\n\n  describe 'GET #show' do\n    it 'renders report' do\n      report = Fabricate(:report)\n\n      get :show, params: { id: report }\n\n      expect(assigns(:report)).to eq report\n      expect(response).to have_http_status(200)\n    end\n  end\n\n  describe 'POST #reopen' do\n    it 'reopens the report' do\n      report = Fabricate(:report)\n\n      put :reopen, params: { id: report }\n      expect(response).to redirect_to(admin_report_path(report))\n      report.reload\n      expect(report.action_taken_by_account).to eq nil\n      expect(report.action_taken).to eq false\n    end\n  end\n\n  describe 'POST #assign_to_self' do\n    it 'reopens the report' do\n      report = Fabricate(:report)\n\n      put :assign_to_self, params: { id: report }\n      expect(response).to redirect_to(admin_report_path(report))\n      report.reload\n      expect(report.assigned_account).to eq user.account\n    end\n  end\n\n  describe 'POST #unassign' do\n    it 'reopens the report' do\n      report = Fabricate(:report)\n\n      put :unassign, params: { id: report }\n      expect(response).to redirect_to(admin_report_path(report))\n      report.reload\n      expect(report.assigned_account).to eq nil\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/admin/resets_controller_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe Admin::ResetsController do\n  render_views\n\n  let(:account) { Fabricate(:account, user: Fabricate(:user)) }\n  before do\n    sign_in Fabricate(:user, admin: true), scope: :user\n  end\n\n  describe 'POST #create' do\n    it 'redirects to admin accounts page' do\n      expect_any_instance_of(User).to receive(:send_reset_password_instructions) do |value|\n        expect(value.account_id).to eq account.id\n      end\n\n      post :create, params: { account_id: account.id }\n\n      expect(response).to redirect_to(admin_accounts_path)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/admin/roles_controller_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe Admin::RolesController do\n  render_views\n\n  let(:admin) { Fabricate(:user, admin: true) }\n\n  before do\n    sign_in admin, scope: :user\n  end\n\n  describe 'POST #promote' do\n    subject { post :promote, params: { account_id: user.account_id } }\n\n    let(:user) { Fabricate(:user, moderator: false, admin: false) }\n\n    it 'promotes user' do\n      expect(subject).to redirect_to admin_account_path(user.account_id)\n      expect(user.reload).to be_moderator\n    end\n  end\n\n  describe 'POST #demote' do\n    subject { post :demote, params: { account_id: user.account_id } }\n\n    let(:user) { Fabricate(:user, moderator: true, admin: false) }\n\n    it 'demotes user' do\n      expect(subject).to redirect_to admin_account_path(user.account_id)\n      expect(user.reload).not_to be_moderator\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/admin/settings_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe Admin::SettingsController, type: :controller do\n  render_views\n\n  describe 'When signed in as an admin' do\n    before do\n      sign_in Fabricate(:user, admin: true), scope: :user\n    end\n\n    describe 'GET #edit' do\n      it 'returns http success' do\n        get :edit\n\n        expect(response).to have_http_status(200)\n      end\n    end\n\n    describe 'PUT #update' do\n      before do\n        allow_any_instance_of(Form::AdminSettings).to receive(:valid?).and_return(true)\n      end\n\n      describe 'for a record that doesnt exist' do\n        around do |example|\n          before = Setting.site_extended_description\n          Setting.site_extended_description = nil\n          example.run\n          Setting.site_extended_description = before\n          Setting.new_setting_key = nil\n        end\n\n        it 'cannot create a setting value for a non-admin key' do\n          expect(Setting.new_setting_key).to be_blank\n\n          patch :update, params: { form_admin_settings: { new_setting_key: 'New key value' } }\n\n          expect(response).to redirect_to(edit_admin_settings_path)\n          expect(Setting.new_setting_key).to be_nil\n        end\n\n        it 'creates a settings value that didnt exist before for eligible key' do\n          expect(Setting.site_extended_description).to be_blank\n\n          patch :update, params: { form_admin_settings: { site_extended_description: 'New key value' } }\n\n          expect(response).to redirect_to(edit_admin_settings_path)\n          expect(Setting.site_extended_description).to eq 'New key value'\n        end\n      end\n\n      context do\n        around do |example|\n          site_title = Setting.site_title\n          example.run\n          Setting.site_title = site_title\n        end\n\n        it 'updates a settings value' do\n          Setting.site_title = 'Original'\n          patch :update, params: { form_admin_settings: { site_title: 'New title' } }\n\n          expect(response).to redirect_to(edit_admin_settings_path)\n          expect(Setting.site_title).to eq 'New title'\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/admin/statuses_controller_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe Admin::StatusesController do\n  render_views\n\n  let(:user) { Fabricate(:user, admin: true) }\n  let(:account) { Fabricate(:account) }\n  let!(:status) { Fabricate(:status, account: account) }\n  let(:media_attached_status) { Fabricate(:status, account: account, sensitive: !sensitive) }\n  let!(:media_attachment) { Fabricate(:media_attachment, account: account, status: media_attached_status) }\n  let(:sensitive) { true }\n\n  before do\n    sign_in user, scope: :user\n  end\n\n  describe 'GET #index' do\n    it 'returns http success with no media' do\n      get :index, params: { account_id: account.id }\n\n      statuses = assigns(:statuses).to_a\n      expect(statuses.size).to eq 2\n      expect(response).to have_http_status(200)\n    end\n\n    it 'returns http success with media' do\n      get :index, params: { account_id: account.id, media: true }\n\n      statuses = assigns(:statuses).to_a\n      expect(statuses.size).to eq 1\n      expect(response).to have_http_status(200)\n    end\n  end\n\n  describe 'POST #create' do\n    subject do\n      -> { post :create, params: { :account_id => account.id, action => '', :form_status_batch => { status_ids: status_ids } } }\n    end\n\n    let(:action) { 'nsfw_on' }\n    let(:status_ids) { [media_attached_status.id] }\n\n    context 'when action is nsfw_on' do\n      it 'updates sensitive column' do\n        is_expected.to change {\n          media_attached_status.reload.sensitive\n        }.from(false).to(true)\n      end\n    end\n\n    context 'when action is nsfw_off' do\n      let(:action) { 'nsfw_off' }\n      let(:sensitive) { false }\n\n      it 'updates sensitive column' do\n        is_expected.to change {\n          media_attached_status.reload.sensitive\n        }.from(true).to(false)\n      end\n    end\n\n    context 'when action is delete' do\n      let(:action) { 'delete' }\n\n      it 'removes a status' do\n        allow(RemovalWorker).to receive(:perform_async)\n        subject.call\n        expect(RemovalWorker).to have_received(:perform_async).with(status_ids.first)\n      end\n    end\n\n    it 'redirects to account statuses page' do\n      subject.call\n      expect(response).to redirect_to(admin_account_statuses_path(account.id))\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/admin/subscriptions_controller_spec.rb",
    "content": "# frozen_string_literal: true\nrequire 'rails_helper'\n\nRSpec.describe Admin::SubscriptionsController, type: :controller do\n  render_views\n\n  describe 'GET #index' do\n    around do |example|\n      default_per_page = Subscription.default_per_page\n      Subscription.paginates_per 1\n      example.run\n      Subscription.paginates_per default_per_page\n    end\n\n    before do\n      sign_in Fabricate(:user, admin: true), scope: :user\n    end\n\n    it 'renders subscriptions' do\n      Fabricate(:subscription)\n      specified = Fabricate(:subscription)\n\n      get :index\n\n      subscriptions = assigns(:subscriptions)\n      expect(subscriptions.count).to eq 1\n      expect(subscriptions[0]).to eq specified\n\n      expect(response).to have_http_status(200)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/admin/tags_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe Admin::TagsController, type: :controller do\n  render_views\n\n  before do\n    sign_in Fabricate(:user, admin: true)\n  end\n\n  describe 'GET #index' do\n    before do\n      account_tag_stat = Fabricate(:tag).account_tag_stat\n      account_tag_stat.update(hidden: hidden, accounts_count: 1)\n      get :index, params: { hidden: hidden }\n    end\n\n    context 'with hidden tags' do\n      let(:hidden) { true }\n\n      it 'returns status 200' do\n        expect(response).to have_http_status(200)\n      end\n    end\n\n    context 'without hidden tags' do\n      let(:hidden) { false }\n\n      it 'returns status 200' do\n        expect(response).to have_http_status(200)\n      end\n    end\n  end\n\n  describe 'POST #hide' do\n    let(:tag) { Fabricate(:tag) }\n\n    before do\n      tag.account_tag_stat.update(hidden: false)\n      post :hide, params: { id: tag.id }\n    end\n\n    it 'hides tag' do\n      tag.reload\n      expect(tag).to be_hidden\n    end\n\n    it 'redirects to admin_tags_path' do\n      expect(response).to redirect_to(admin_tags_path(controller.instance_variable_get(:@filter_params)))\n    end\n  end\n\n  describe 'POST #unhide' do\n    let(:tag) { Fabricate(:tag) }\n\n    before do\n      tag.account_tag_stat.update(hidden: true)\n      post :unhide, params: { id: tag.id }\n    end\n\n    it 'unhides tag' do\n      tag.reload\n      expect(tag).not_to be_hidden\n    end\n\n    it 'redirects to admin_tags_path' do\n      expect(response).to redirect_to(admin_tags_path(controller.instance_variable_get(:@filter_params)))\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/admin/two_factor_authentications_controller_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe Admin::TwoFactorAuthenticationsController do\n  render_views\n\n  let(:user) { Fabricate(:user, otp_required_for_login: true) }\n  before do\n    sign_in Fabricate(:user, admin: true), scope: :user\n  end\n\n  describe 'DELETE #destroy' do\n    it 'redirects to admin accounts page' do\n      delete :destroy, params: { user_id: user.id }\n\n      user.reload\n      expect(user.otp_required_for_login).to eq false\n      expect(response).to redirect_to(admin_accounts_path)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/base_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nclass FakeService; end\n\ndescribe Api::BaseController do\n  controller do\n    def success\n      head 200\n    end\n\n    def error\n      FakeService.new\n    end\n  end\n\n  describe 'Forgery protection' do\n    before do\n      routes.draw { post 'success' => 'api/base#success' }\n    end\n\n    it 'does not protect from forgery' do\n      ActionController::Base.allow_forgery_protection = true\n      post 'success'\n      expect(response).to have_http_status(200)\n    end\n  end\n\n  describe 'Error handling' do\n    ERRORS_WITH_CODES = {\n      ActiveRecord::RecordInvalid => 422,\n      Mastodon::ValidationError => 422,\n      ActiveRecord::RecordNotFound => 404,\n      Mastodon::UnexpectedResponseError => 503,\n      HTTP::Error => 503,\n      OpenSSL::SSL::SSLError => 503,\n      Mastodon::NotPermittedError => 403,\n    }\n\n    before do\n      routes.draw { get 'error' => 'api/base#error' }\n    end\n\n    ERRORS_WITH_CODES.each do |error, code|\n      it \"Handles error class of #{error}\" do\n        expect(FakeService).to receive(:new).and_raise(error)\n\n        get 'error'\n        expect(response).to have_http_status(code)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/oembed_controller_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Api::OEmbedController, type: :controller do\n  render_views\n\n  let(:alice)  { Fabricate(:account, username: 'alice') }\n  let(:status) { Fabricate(:status, text: 'Hello world', account: alice) }\n\n  describe 'GET #show' do\n    before do\n      request.host = Rails.configuration.x.local_domain\n      get :show, params: { url: account_stream_entry_url(alice, status.stream_entry) }, format: :json\n    end\n\n    it 'returns http success' do\n      expect(response).to have_http_status(200)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/proofs_controller_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe Api::ProofsController do\n  let(:alice) { Fabricate(:account, username: 'alice') }\n\n  before do\n    stub_request(:get, 'https://keybase.io/_/api/1.0/sig/proof_valid.json?domain=cb6e6126.ngrok.io&kb_username=crypto_alice&sig_hash=111111111111111111111111111111111111111111111111111111111111111111&username=alice').to_return(status: 200, body: '{\"proof_valid\":true,\"proof_live\":false}')\n    stub_request(:get, 'https://keybase.io/_/api/1.0/sig/proof_live.json?domain=cb6e6126.ngrok.io&kb_username=crypto_alice&sig_hash=111111111111111111111111111111111111111111111111111111111111111111&username=alice').to_return(status: 200, body: '{\"proof_valid\":true,\"proof_live\":true}')\n    stub_request(:get, 'https://keybase.io/_/api/1.0/sig/proof_valid.json?domain=cb6e6126.ngrok.io&kb_username=hidden_alice&sig_hash=222222222222222222222222222222222222222222222222222222222222222222&username=alice').to_return(status: 200, body: '{\"proof_valid\":true,\"proof_live\":true}')\n    stub_request(:get, 'https://keybase.io/_/api/1.0/sig/proof_live.json?domain=cb6e6126.ngrok.io&kb_username=hidden_alice&sig_hash=222222222222222222222222222222222222222222222222222222222222222222&username=alice').to_return(status: 200, body: '{\"proof_valid\":true,\"proof_live\":true}')\n  end\n\n  describe 'GET #index' do\n    describe 'with a non-existent username' do\n      it '404s' do\n        get :index, params: { username: 'nonexistent', provider: 'keybase' }\n\n        expect(response).to have_http_status(:not_found)\n      end\n    end\n\n    describe 'with a user that has no proofs' do\n      it 'is an empty list of signatures' do\n        get :index, params: { username: alice.username, provider: 'keybase' }\n\n        expect(body_as_json[:signatures]).to eq []\n      end\n    end\n\n    describe 'with a user that has a live, valid proof' do\n      let(:token1) { '111111111111111111111111111111111111111111111111111111111111111111' }\n      let(:kb_name1) { 'crypto_alice' }\n\n      before do\n        Fabricate(:account_identity_proof, account: alice, verified: true, live: true, token: token1, provider_username: kb_name1)\n      end\n\n      it 'is a list with that proof in it' do\n        get :index, params: { username: alice.username, provider: 'keybase' }\n\n        expect(body_as_json[:signatures]).to eq [\n          { kb_username: kb_name1, sig_hash: token1 },\n        ]\n      end\n\n      describe 'add one that is neither live nor valid' do\n        let(:token2) { '222222222222222222222222222222222222222222222222222222222222222222' }\n        let(:kb_name2) { 'hidden_alice' }\n\n        before do\n          Fabricate(:account_identity_proof, account: alice, verified: false, live: false, token: token2, provider_username: kb_name2)\n        end\n\n        it 'is a list with both proofs' do\n          get :index, params: { username: alice.username, provider: 'keybase' }\n\n          expect(body_as_json[:signatures]).to eq [\n            { kb_username: kb_name1, sig_hash: token1 },\n            { kb_username: kb_name2, sig_hash: token2 },\n          ]\n        end\n      end\n    end\n\n    describe 'a user that has an avatar' do\n      let(:alice) { Fabricate(:account, username: 'alice', avatar: attachment_fixture('avatar.gif')) }\n\n      context 'and a proof' do\n        let(:token1) { '111111111111111111111111111111111111111111111111111111111111111111' }\n        let(:kb_name1) { 'crypto_alice' }\n\n        before do\n          Fabricate(:account_identity_proof, account: alice, verified: true, live: true, token: token1, provider_username: kb_name1)\n          get :index, params: { username: alice.username, provider: 'keybase' }\n        end\n\n        it 'has two keys: signatures and avatar' do\n          expect(body_as_json.keys).to match_array [:signatures, :avatar]\n        end\n\n        it 'has the correct signatures' do\n          expect(body_as_json[:signatures]).to eq [\n            { kb_username: kb_name1, sig_hash: token1 },\n          ]\n        end\n\n        it 'has the correct avatar url' do\n          first_part = 'https://cb6e6126.ngrok.io/system/accounts/avatars/'\n          last_part  = 'original/avatar.gif'\n\n          expect(body_as_json[:avatar]).to match /#{Regexp.quote(first_part)}(?:\\d{3,5}\\/){3}#{Regexp.quote(last_part)}/\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/push_controller_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Api::PushController, type: :controller do\n  describe 'POST #update' do\n    context 'with hub.mode=subscribe' do\n      it 'creates a subscription' do\n        service = double(call: ['', 202])\n        allow(Pubsubhubbub::SubscribeService).to receive(:new).and_return(service)\n        account = Fabricate(:account)\n        account_topic_url = \"https://#{Rails.configuration.x.local_domain}/users/#{account.username}.atom\"\n        post :update, params: {\n          'hub.mode' => 'subscribe',\n          'hub.topic' => account_topic_url,\n          'hub.callback' => 'https://callback.host/api',\n          'hub.lease_seconds' => '3600',\n          'hub.secret' => 'as1234df',\n        }\n\n        expect(service).to have_received(:call).with(\n          account,\n          'https://callback.host/api',\n          'as1234df',\n          '3600',\n          nil\n        )\n        expect(response).to have_http_status(202)\n      end\n    end\n\n    context 'with hub.mode=unsubscribe' do\n      it 'unsubscribes the account' do\n        service = double(call: ['', 202])\n        allow(Pubsubhubbub::UnsubscribeService).to receive(:new).and_return(service)\n        account = Fabricate(:account)\n        account_topic_url = \"https://#{Rails.configuration.x.local_domain}/users/#{account.username}.atom\"\n        post :update, params: {\n          'hub.mode' => 'unsubscribe',\n          'hub.topic' => account_topic_url,\n          'hub.callback' => 'https://callback.host/api',\n        }\n\n        expect(service).to have_received(:call).with(\n          account,\n          'https://callback.host/api',\n        )\n        expect(response).to have_http_status(202)\n      end\n    end\n\n    context 'with unknown mode' do\n      it 'returns an unknown mode error' do\n        post :update, params: { 'hub.mode' => 'fake' }\n\n        expect(response).to have_http_status(422)\n        expect(response.body).to match(/Unknown mode/)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/salmon_controller_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Api::SalmonController, type: :controller do\n  render_views\n\n  let(:account) { Fabricate(:user, account: Fabricate(:account, username: 'catsrgr8')).account }\n\n  before do\n    stub_request(:get, \"https://quitter.no/.well-known/host-meta\").to_return(request_fixture('.host-meta.txt'))\n    stub_request(:get, \"https://quitter.no/.well-known/webfinger?resource=acct:gargron@quitter.no\").to_return(request_fixture('webfinger.txt'))\n    stub_request(:get, \"https://quitter.no/api/statuses/user_timeline/7477.atom\").to_return(request_fixture('feed.txt'))\n    stub_request(:get, \"https://quitter.no/avatar/7477-300-20160211190340.png\").to_return(request_fixture('avatar.txt'))\n  end\n\n  describe 'POST #update' do\n    context 'with valid post data' do\n      before do\n        post :update, params: { id: account.id }, body: File.read(Rails.root.join('spec', 'fixtures', 'salmon', 'mention.xml'))\n      end\n\n      it 'contains XML in the request body' do\n        expect(request.body.read).to be_a String\n      end\n\n      it 'returns http success' do\n        expect(response).to have_http_status(202)\n      end\n\n      it 'creates remote account' do\n        expect(Account.find_by(username: 'gargron', domain: 'quitter.no')).to_not be_nil\n      end\n\n      it 'creates status' do\n        expect(Status.find_by(uri: 'tag:quitter.no,2016-03-20:noticeId=1276923:objectType=note')).to_not be_nil\n      end\n\n      it 'creates mention for target account' do\n        expect(account.mentions.count).to eq 1\n      end\n    end\n\n    context 'with empty post data' do\n      before do\n        post :update, params: { id: account.id }, body: ''\n      end\n\n      it 'returns http client error' do\n        expect(response).to have_http_status(400)\n      end\n    end\n\n    context 'with invalid post data' do\n      before do\n        service = double(call: false)\n        allow(VerifySalmonService).to receive(:new).and_return(service)\n\n        post :update, params: { id: account.id }, body: File.read(Rails.root.join('spec', 'fixtures', 'salmon', 'mention.xml'))\n      end\n\n      it 'returns http client error' do\n        expect(response).to have_http_status(401)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/subscriptions_controller_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Api::SubscriptionsController, type: :controller do\n  render_views\n\n  let(:account) { Fabricate(:account, username: 'gargron', domain: 'quitter.no', remote_url: 'topic_url', secret: 'abc') }\n\n  describe 'GET #show' do\n    context 'with valid subscription' do\n      before do\n        get :show, params: { :id => account.id, 'hub.topic' => 'topic_url', 'hub.challenge' => '456', 'hub.lease_seconds' => \"#{86400 * 30}\" }\n      end\n\n      it 'returns http success' do\n        expect(response).to have_http_status(200)\n      end\n\n      it 'echoes back the challenge' do\n        expect(response.body).to match '456'\n      end\n    end\n\n    context 'with invalid subscription' do\n      before do\n        expect_any_instance_of(Account).to receive_message_chain(:subscription, :valid?).and_return(false)\n        get :show, params: { :id => account.id }\n      end\n\n      it 'returns http success' do\n        expect(response).to have_http_status(404)\n      end\n    end\n  end\n\n  describe 'POST #update' do\n    let(:feed) { File.read(Rails.root.join('spec', 'fixtures', 'push', 'feed.atom')) }\n\n    before do\n      stub_request(:post, \"https://quitter.no/main/push/hub\").to_return(:status => 200, :body => \"\", :headers => {})\n      stub_request(:get, \"https://quitter.no/avatar/7477-300-20160211190340.png\").to_return(request_fixture('avatar.txt'))\n      stub_request(:get, \"https://quitter.no/notice/1269244\").to_return(status: 404)\n      stub_request(:get, \"https://quitter.no/notice/1265331\").to_return(status: 404)\n      stub_request(:get, \"https://community.highlandarrow.com/notice/54411\").to_return(status: 404)\n      stub_request(:get, \"https://community.highlandarrow.com/notice/53857\").to_return(status: 404)\n      stub_request(:get, \"https://community.highlandarrow.com/notice/51852\").to_return(status: 404)\n      stub_request(:get, \"https://social.umeahackerspace.se/notice/424348\").to_return(status: 404)\n      stub_request(:get, \"https://community.highlandarrow.com/notice/50467\").to_return(status: 404)\n      stub_request(:get, \"https://quitter.no/notice/1243309\").to_return(status: 404)\n      stub_request(:get, \"https://quitter.no/user/7477\").to_return(status: 404)\n      stub_request(:any, \"https://community.highlandarrow.com/user/1\").to_return(status: 404)\n      stub_request(:any, \"https://social.umeahackerspace.se/user/2\").to_return(status: 404)\n      stub_request(:any, \"https://gs.kawa-kun.com/user/2\").to_return(status: 404)\n      stub_request(:any, \"https://mastodon.social/users/Gargron\").to_return(status: 404)\n\n      request.env['HTTP_X_HUB_SIGNATURE'] = \"sha1=#{OpenSSL::HMAC.hexdigest('sha1', 'abc', feed)}\"\n\n      post :update, params: { id: account.id }, body: feed\n    end\n\n    it 'returns http success' do\n      expect(response).to have_http_status(200)\n    end\n\n    it 'creates statuses for feed' do\n      expect(account.statuses.count).to_not eq 0\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/accounts/credentials_controller_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe Api::V1::Accounts::CredentialsController do\n  render_views\n\n  let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }\n  let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }\n\n  context 'with an oauth token' do\n    before do\n      allow(controller).to receive(:doorkeeper_token) { token }\n    end\n\n    describe 'GET #show' do\n      let(:scopes) { 'read:accounts' }\n\n      it 'returns http success' do\n        get :show\n        expect(response).to have_http_status(200)\n      end\n    end\n\n    describe 'PATCH #update' do\n      let(:scopes) { 'write:accounts' }\n\n      describe 'with valid data' do\n        before do\n          allow(ActivityPub::UpdateDistributionWorker).to receive(:perform_async)\n\n          patch :update, params: {\n            display_name: \"Alice Isn't Dead\",\n            note: \"Hi!\\n\\nToot toot!\",\n            avatar: fixture_file_upload('files/avatar.gif', 'image/gif'),\n            header: fixture_file_upload('files/attachment.jpg', 'image/jpeg'),\n            source: {\n              privacy: 'unlisted',\n              sensitive: true,\n            }\n          }\n        end\n\n        it 'returns http success' do\n          expect(response).to have_http_status(200)\n        end\n\n        it 'updates account info' do\n          user.account.reload\n\n          expect(user.account.display_name).to eq(\"Alice Isn't Dead\")\n          expect(user.account.note).to eq(\"Hi!\\n\\nToot toot!\")\n          expect(user.account.avatar).to exist\n          expect(user.account.header).to exist\n          expect(user.setting_default_privacy).to eq('unlisted')\n          expect(user.setting_default_sensitive).to eq(true)\n        end\n\n        it 'queues up an account update distribution' do\n          expect(ActivityPub::UpdateDistributionWorker).to have_received(:perform_async).with(user.account_id)\n        end\n      end\n\n      describe 'with invalid data' do\n        before do\n          patch :update, params: { note: 'This is too long. ' * 30 }\n        end\n\n        it 'returns http unprocessable entity' do\n          expect(response).to have_http_status(:unprocessable_entity)\n        end\n      end\n    end\n  end\n\n  context 'without an oauth token' do\n    before do\n      allow(controller).to receive(:doorkeeper_token) { nil }\n    end\n\n    describe 'GET #show' do\n      it 'returns http unauthorized' do\n        get :show\n        expect(response).to have_http_status(:unauthorized)\n      end\n    end\n\n    describe 'PATCH #update' do\n      it 'returns http unauthorized' do\n        patch :update, params: { note: 'Foo' }\n        expect(response).to have_http_status(:unauthorized)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/accounts/follower_accounts_controller_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe Api::V1::Accounts::FollowerAccountsController do\n  render_views\n\n  let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }\n  let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:accounts') }\n\n  before do\n    Fabricate(:follow, target_account: user.account)\n    allow(controller).to receive(:doorkeeper_token) { token }\n  end\n\n  describe 'GET #index' do\n    it 'returns http success' do\n      get :index, params: { account_id: user.account.id, limit: 1 }\n\n      expect(response).to have_http_status(200)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/accounts/following_accounts_controller_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe Api::V1::Accounts::FollowingAccountsController do\n  render_views\n\n  let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }\n  let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:accounts') }\n\n  before do\n    Fabricate(:follow, account: user.account)\n    allow(controller).to receive(:doorkeeper_token) { token }\n  end\n\n  describe 'GET #index' do\n    it 'returns http success' do\n      get :index, params: { account_id: user.account.id, limit: 1 }\n\n      expect(response).to have_http_status(200)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/accounts/lists_controller_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe Api::V1::Accounts::ListsController do\n  render_views\n\n  let(:user)    { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }\n  let(:token)   { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:lists') }\n  let(:account) { Fabricate(:account) }\n  let(:list)    { Fabricate(:list, account: user.account) }\n\n  before do\n    allow(controller).to receive(:doorkeeper_token) { token }\n    user.account.follow!(account)\n    list.accounts << account\n  end\n\n  describe 'GET #index' do\n    it 'returns http success' do\n      get :index, params: { account_id: account.id }\n      expect(response).to have_http_status(200)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/accounts/pins_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe Api::V1::Accounts::PinsController, type: :controller do\n  let(:john)  { Fabricate(:user, account: Fabricate(:account, username: 'john')) }\n  let(:kevin) { Fabricate(:user, account: Fabricate(:account, username: 'kevin')) }\n  let(:token) { Fabricate(:accessible_access_token, resource_owner_id: john.id, scopes: 'write:accounts') }\n\n  before do\n    kevin.account.followers << john.account\n    allow(controller).to receive(:doorkeeper_token) { token }\n  end\n\n  describe 'POST #create' do\n    subject { post :create, params: { account_id: kevin.account.id } }\n\n    it 'returns 200' do\n      expect(response).to have_http_status(200)\n    end\n\n    it 'creates account_pin' do\n      expect do\n        subject\n      end.to change { AccountPin.where(account: john.account, target_account: kevin.account).count }.by(1)\n    end\n  end\n\n  describe 'DELETE #destroy' do\n    subject { delete :destroy, params: { account_id: kevin.account.id } }\n\n    before do\n      Fabricate(:account_pin, account: john.account, target_account: kevin.account)\n    end\n\n    it 'returns 200' do\n      expect(response).to have_http_status(200)\n    end\n\n    it 'destroys account_pin' do\n      expect do\n        subject\n      end.to change { AccountPin.where(account: john.account, target_account: kevin.account).count }.by(-1)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/accounts/relationships_controller_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe Api::V1::Accounts::RelationshipsController do\n  render_views\n\n  let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }\n  let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:follows') }\n\n  before do\n    allow(controller).to receive(:doorkeeper_token) { token }\n  end\n\n  describe 'GET #index' do\n    let(:simon) { Fabricate(:user, email: 'simon@example.com', account: Fabricate(:account, username: 'simon')).account }\n    let(:lewis) { Fabricate(:user, email: 'lewis@example.com', account: Fabricate(:account, username: 'lewis')).account }\n\n    before do\n      user.account.follow!(simon)\n      lewis.follow!(user.account)\n    end\n\n    context 'provided only one ID' do\n      before do\n        get :index, params: { id: simon.id }\n      end\n\n      it 'returns http success' do\n        expect(response).to have_http_status(200)\n      end\n\n      it 'returns JSON with correct data' do\n        json = body_as_json\n\n        expect(json).to be_a Enumerable\n        expect(json.first[:following]).to be true\n        expect(json.first[:followed_by]).to be false\n      end\n    end\n\n    context 'provided multiple IDs' do\n      before do\n        get :index, params: { id: [simon.id, lewis.id] }\n      end\n\n      it 'returns http success' do\n        expect(response).to have_http_status(200)\n      end\n\n      it 'returns JSON with correct data' do\n        json = body_as_json\n\n        expect(json).to be_a Enumerable\n        expect(json.first[:id]).to eq simon.id.to_s\n        expect(json.first[:following]).to be true\n        expect(json.first[:showing_reblogs]).to be true\n        expect(json.first[:followed_by]).to be false\n        expect(json.first[:muting]).to be false\n        expect(json.first[:requested]).to be false\n        expect(json.first[:domain_blocking]).to be false\n\n        expect(json.second[:id]).to eq lewis.id.to_s\n        expect(json.second[:following]).to be false\n        expect(json.second[:showing_reblogs]).to be false\n        expect(json.second[:followed_by]).to be true\n        expect(json.second[:muting]).to be false\n        expect(json.second[:requested]).to be false\n        expect(json.second[:domain_blocking]).to be false\n      end\n\n      it 'returns JSON with correct data on cached requests too' do\n        get :index, params: { id: [simon.id] }\n\n        json = body_as_json\n\n        expect(json).to be_a Enumerable\n        expect(json.first[:following]).to be true\n        expect(json.first[:showing_reblogs]).to be true\n      end\n\n      it 'returns JSON with correct data after change too' do\n        user.account.unfollow!(simon)\n\n        get :index, params: { id: [simon.id] }\n\n        json = body_as_json\n\n        expect(json).to be_a Enumerable\n        expect(json.first[:following]).to be false\n        expect(json.first[:showing_reblogs]).to be false\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/accounts/search_controller_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Api::V1::Accounts::SearchController, type: :controller do\n  render_views\n\n  let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }\n  let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:accounts') }\n\n  before do\n    allow(controller).to receive(:doorkeeper_token) { token }\n  end\n\n  describe 'GET #show' do\n    it 'returns http success' do\n      get :show, params: { q: 'query' }\n\n      expect(response).to have_http_status(200)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/accounts/statuses_controller_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe Api::V1::Accounts::StatusesController do\n  render_views\n\n  let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }\n  let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:statuses') }\n\n  before do\n    allow(controller).to receive(:doorkeeper_token) { token }\n    Fabricate(:status, account: user.account)\n  end\n\n  describe 'GET #index' do\n    it 'returns http success' do\n      get :index, params: { account_id: user.account.id, limit: 1 }\n\n      expect(response).to have_http_status(200)\n      expect(response.headers['Link'].links.size).to eq(2)\n    end\n\n    context 'with only media' do\n      it 'returns http success' do\n        get :index, params: { account_id: user.account.id, only_media: true }\n\n        expect(response).to have_http_status(200)\n      end\n    end\n\n    context 'with exclude replies' do\n      before do\n        Fabricate(:status, account: user.account, thread: Fabricate(:status))\n      end\n\n      it 'returns http success' do\n        get :index, params: { account_id: user.account.id, exclude_replies: true }\n\n        expect(response).to have_http_status(200)\n      end\n    end\n\n    context 'with only pinned' do\n      before do\n        Fabricate(:status_pin, account: user.account, status: Fabricate(:status, account: user.account))\n      end\n\n      it 'returns http success' do\n        get :index, params: { account_id: user.account.id, pinned: true }\n\n        expect(response).to have_http_status(200)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/accounts_controller_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Api::V1::AccountsController, type: :controller do\n  render_views\n\n  let(:user)   { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }\n  let(:scopes) { '' }\n  let(:token)  { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }\n\n  before do\n    allow(controller).to receive(:doorkeeper_token) { token }\n  end\n\n  shared_examples 'forbidden for wrong scope' do |wrong_scope|\n    let(:scopes) { wrong_scope }\n\n    it 'returns http forbidden' do\n      expect(response).to have_http_status(403)\n    end\n  end\n\n  describe 'POST #create' do\n    let(:app) { Fabricate(:application) }\n    let(:token) { Doorkeeper::AccessToken.find_or_create_for(app, nil, 'read write', nil, false) }\n    let(:agreement) { nil }\n\n    before do\n      post :create, params: { username: 'test', password: '12345678', email: 'hello@world.tld', agreement: agreement }\n    end\n\n    context 'given truthy agreement' do\n      let(:agreement) { 'true' }\n\n      it 'returns http success' do\n        expect(response).to have_http_status(200)\n      end\n\n      it 'returns a new access token as JSON' do\n        expect(body_as_json[:access_token]).to_not be_blank\n      end\n\n      it 'creates a user' do\n        user = User.find_by(email: 'hello@world.tld')\n        expect(user).to_not be_nil\n        expect(user.created_by_application_id).to eq app.id\n      end\n    end\n\n    context 'given no agreement' do\n      it 'returns http unprocessable entity' do\n        expect(response).to have_http_status(422)\n      end\n    end\n  end\n\n  describe 'GET #show' do\n    let(:scopes) { 'read:accounts' }\n\n    before do\n      get :show, params: { id: user.account.id }\n    end\n\n    it 'returns http success' do\n      expect(response).to have_http_status(200)\n    end\n\n    it_behaves_like 'forbidden for wrong scope', 'write:statuses'\n  end\n\n  describe 'POST #follow' do\n    let(:scopes) { 'write:follows' }\n    let(:other_account) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob', locked: locked)).account }\n\n    before do\n      post :follow, params: { id: other_account.id }\n    end\n\n    context 'with unlocked account' do\n      let(:locked) { false }\n\n      it 'returns http success' do\n        expect(response).to have_http_status(200)\n      end\n\n      it 'returns JSON with following=true and requested=false' do\n        json = body_as_json\n\n        expect(json[:following]).to be true\n        expect(json[:requested]).to be false\n      end\n\n      it 'creates a following relation between user and target user' do\n        expect(user.account.following?(other_account)).to be true\n      end\n\n      it_behaves_like 'forbidden for wrong scope', 'read:accounts'\n    end\n\n    context 'with locked account' do\n      let(:locked) { true }\n\n      it 'returns http success' do\n        expect(response).to have_http_status(200)\n      end\n\n      it 'returns JSON with following=false and requested=true' do\n        json = body_as_json\n\n        expect(json[:following]).to be false\n        expect(json[:requested]).to be true\n      end\n\n      it 'creates a follow request relation between user and target user' do\n        expect(user.account.requested?(other_account)).to be true\n      end\n\n      it_behaves_like 'forbidden for wrong scope', 'read:accounts'\n    end\n  end\n\n  describe 'POST #unfollow' do\n    let(:scopes) { 'write:follows' }\n    let(:other_account) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account }\n\n    before do\n      user.account.follow!(other_account)\n      post :unfollow, params: { id: other_account.id }\n    end\n\n    it 'returns http success' do\n      expect(response).to have_http_status(200)\n    end\n\n    it 'removes the following relation between user and target user' do\n      expect(user.account.following?(other_account)).to be false\n    end\n\n    it_behaves_like 'forbidden for wrong scope', 'read:accounts'\n  end\n\n  describe 'POST #block' do\n    let(:scopes) { 'write:blocks' }\n    let(:other_account) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account }\n\n    before do\n      user.account.follow!(other_account)\n      post :block, params: { id: other_account.id }\n    end\n\n    it 'returns http success' do\n      expect(response).to have_http_status(200)\n    end\n\n    it 'removes the following relation between user and target user' do\n      expect(user.account.following?(other_account)).to be false\n    end\n\n    it 'creates a blocking relation' do\n      expect(user.account.blocking?(other_account)).to be true\n    end\n\n    it_behaves_like 'forbidden for wrong scope', 'read:accounts'\n  end\n\n  describe 'POST #unblock' do\n    let(:scopes) { 'write:blocks' }\n    let(:other_account) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account }\n\n    before do\n      user.account.block!(other_account)\n      post :unblock, params: { id: other_account.id }\n    end\n\n    it 'returns http success' do\n      expect(response).to have_http_status(200)\n    end\n\n    it 'removes the blocking relation between user and target user' do\n      expect(user.account.blocking?(other_account)).to be false\n    end\n\n    it_behaves_like 'forbidden for wrong scope', 'read:accounts'\n  end\n\n  describe 'POST #mute' do\n    let(:scopes) { 'write:mutes' }\n    let(:other_account) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account }\n\n    before do\n      user.account.follow!(other_account)\n      post :mute, params: { id: other_account.id }\n    end\n\n    it 'returns http success' do\n      expect(response).to have_http_status(200)\n    end\n\n    it 'does not remove the following relation between user and target user' do\n      expect(user.account.following?(other_account)).to be true\n    end\n\n    it 'creates a muting relation' do\n      expect(user.account.muting?(other_account)).to be true\n    end\n\n    it 'mutes notifications' do\n      expect(user.account.muting_notifications?(other_account)).to be true\n    end\n\n    it_behaves_like 'forbidden for wrong scope', 'read:accounts'\n  end\n\n  describe 'POST #mute with notifications set to false' do\n    let(:scopes) { 'write:mutes' }\n    let(:other_account) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account }\n\n    before do\n      user.account.follow!(other_account)\n      post :mute, params: { id: other_account.id, notifications: false }\n    end\n\n    it 'returns http success' do\n      expect(response).to have_http_status(200)\n    end\n\n    it 'does not remove the following relation between user and target user' do\n      expect(user.account.following?(other_account)).to be true\n    end\n\n    it 'creates a muting relation' do\n      expect(user.account.muting?(other_account)).to be true\n    end\n\n    it 'does not mute notifications' do\n      expect(user.account.muting_notifications?(other_account)).to be false\n    end\n\n    it_behaves_like 'forbidden for wrong scope', 'read:accounts'\n  end\n\n  describe 'POST #unmute' do\n    let(:scopes) { 'write:mutes' }\n    let(:other_account) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account }\n\n    before do\n      user.account.mute!(other_account)\n      post :unmute, params: { id: other_account.id }\n    end\n\n    it 'returns http success' do\n      expect(response).to have_http_status(200)\n    end\n\n    it 'removes the muting relation between user and target user' do\n      expect(user.account.muting?(other_account)).to be false\n    end\n\n    it_behaves_like 'forbidden for wrong scope', 'read:accounts'\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/apps/credentials_controller_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe Api::V1::Apps::CredentialsController do\n  render_views\n\n  let(:token) { Fabricate(:accessible_access_token, scopes: 'read', application: Fabricate(:application)) }\n\n  context 'with an oauth token' do\n    before do\n      allow(controller).to receive(:doorkeeper_token) { token }\n    end\n\n    describe 'GET #show' do\n      before do\n        get :show\n      end\n\n      it 'returns http success' do\n        expect(response).to have_http_status(200)\n      end\n\n      it 'does not contain client credentials' do\n        json = body_as_json\n\n        expect(json).to_not have_key(:client_secret)\n        expect(json).to_not have_key(:client_id)\n      end\n    end\n  end\n\n  context 'without an oauth token' do\n    before do\n      allow(controller).to receive(:doorkeeper_token) { nil }\n    end\n\n    describe 'GET #show' do\n      it 'returns http unauthorized' do\n        get :show\n        expect(response).to have_http_status(:unauthorized)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/apps_controller_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Api::V1::AppsController, type: :controller do\n  render_views\n\n  describe 'POST #create' do\n    before do\n      post :create, params: { client_name: 'Test app', redirect_uris: 'urn:ietf:wg:oauth:2.0:oob' }\n    end\n\n    it 'returns http success' do\n      expect(response).to have_http_status(200)\n    end\n\n    it 'creates an OAuth app' do\n      expect(Doorkeeper::Application.find_by(name: 'Test app')).to_not be nil\n    end\n\n    it 'returns client ID and client secret' do\n      json = body_as_json\n\n      expect(json[:client_id]).to_not be_blank\n      expect(json[:client_secret]).to_not be_blank\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/blocks_controller_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Api::V1::BlocksController, type: :controller do\n  render_views\n\n  let(:user)   { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }\n  let(:scopes) { 'read:blocks' }\n  let(:token)  { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }\n\n  before { allow(controller).to receive(:doorkeeper_token) { token } }\n\n  describe 'GET #index' do\n    it 'limits according to limit parameter' do\n      2.times.map { Fabricate(:block, account: user.account) }\n      get :index, params: { limit: 1 }\n      expect(body_as_json.size).to eq 1\n    end\n\n    it 'queries blocks in range according to max_id' do\n      blocks = 2.times.map { Fabricate(:block, account: user.account) }\n\n      get :index, params: { max_id: blocks[1] }\n\n      expect(body_as_json.size).to eq 1\n      expect(body_as_json[0][:id]).to eq blocks[0].target_account_id.to_s\n    end\n\n    it 'queries blocks in range according to since_id' do\n      blocks = 2.times.map { Fabricate(:block, account: user.account) }\n\n      get :index, params: { since_id: blocks[0] }\n\n      expect(body_as_json.size).to eq 1\n      expect(body_as_json[0][:id]).to eq blocks[1].target_account_id.to_s\n    end\n\n    it 'sets pagination header for next path' do\n      blocks = 2.times.map { Fabricate(:block, account: user.account) }\n      get :index, params: { limit: 1, since_id: blocks[0] }\n      expect(response.headers['Link'].find_link(['rel', 'next']).href).to eq api_v1_blocks_url(limit: 1, max_id: blocks[1])\n    end\n\n    it 'sets pagination header for previous path' do\n      block = Fabricate(:block, account: user.account)\n      get :index\n      expect(response.headers['Link'].find_link(['rel', 'prev']).href).to eq api_v1_blocks_url(since_id: block)\n    end\n\n    it 'returns http success' do\n      get :index\n      expect(response).to have_http_status(200)\n    end\n\n    context 'with wrong scopes' do\n      let(:scopes) { 'write:blocks' }\n\n      it 'returns http forbidden' do\n        get :index\n        expect(response).to have_http_status(403)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/conversations_controller_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Api::V1::ConversationsController, type: :controller do\n  render_views\n\n  let!(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }\n  let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }\n  let(:other) { Fabricate(:user, account: Fabricate(:account, username: 'bob')) }\n\n  before do\n    allow(controller).to receive(:doorkeeper_token) { token }\n  end\n\n  describe 'GET #index' do\n    let(:scopes) { 'read:statuses' }\n\n    before do\n      PostStatusService.new.call(other.account, text: 'Hey @alice', visibility: 'direct')\n    end\n\n    it 'returns http success' do\n      get :index\n      expect(response).to have_http_status(200)\n    end\n\n    it 'returns pagination headers' do\n      get :index, params: { limit: 1 }\n      expect(response.headers['Link'].links.size).to eq(2)\n    end\n\n    it 'returns conversations' do\n      get :index\n      json = body_as_json\n      expect(json.size).to eq 1\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/custom_emojis_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe Api::V1::CustomEmojisController, type: :controller do\n  render_views\n\n  describe 'GET #index' do\n    before do\n      Fabricate(:custom_emoji)\n      get :index\n    end\n\n    it 'returns http success' do\n      expect(response).to have_http_status(200)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/domain_blocks_controller_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Api::V1::DomainBlocksController, type: :controller do\n  render_views\n\n  let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }\n  let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }\n\n  before do\n    user.account.block_domain!('example.com')\n    allow(controller).to receive(:doorkeeper_token) { token }\n  end\n\n  shared_examples 'forbidden for wrong scope' do |wrong_scope|\n    let(:scopes) { wrong_scope }\n\n    it 'returns http forbidden' do\n      expect(response).to have_http_status(403)\n    end\n  end\n\n  describe 'GET #show' do\n    let(:scopes) { 'read:blocks' }\n\n    before do\n      get :show, params: { limit: 1 }\n    end\n\n    it 'returns http success' do\n      expect(response).to have_http_status(200)\n    end\n\n    it 'returns blocked domains' do\n      expect(body_as_json.first).to eq 'example.com'\n    end\n\n    it_behaves_like 'forbidden for wrong scope', 'write:statuses'\n  end\n\n  describe 'POST #create' do\n    let(:scopes) { 'write:blocks' }\n\n    before do\n      post :create, params: { domain: 'example.org' }\n    end\n\n    it 'returns http success' do\n      expect(response).to have_http_status(200)\n    end\n\n    it 'creates a domain block' do\n      expect(user.account.domain_blocking?('example.org')).to be true\n    end\n\n    it_behaves_like 'forbidden for wrong scope', 'write:statuses'\n  end\n\n  describe 'DELETE #destroy' do\n    let(:scopes) { 'write:blocks' }\n\n    before do\n      delete :destroy, params: { domain: 'example.com' }\n    end\n\n    it 'returns http success' do\n      expect(response).to have_http_status(200)\n    end\n\n    it 'deletes a domain block' do\n      expect(user.account.domain_blocking?('example.com')).to be false\n    end\n\n    it_behaves_like 'forbidden for wrong scope', 'write:statuses'\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/endorsements_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe Api::V1::EndorsementsController, type: :controller do\n  let(:user)  { Fabricate(:user) }\n  let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:accounts') }\n\n  describe 'GET #index' do\n    it 'returns 200' do\n      allow(controller).to receive(:doorkeeper_token) { token }\n      get :index\n\n      expect(response).to have_http_status(200)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/favourites_controller_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Api::V1::FavouritesController, type: :controller do\n  render_views\n\n  let(:user)  { Fabricate(:user) }\n  let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read') }\n\n  describe 'GET #index' do\n    context 'without token' do\n      it 'returns http unauthorized' do\n        get :index\n        expect(response).to have_http_status :unauthorized\n      end\n    end\n\n    context 'with token' do\n      context 'without read scope' do\n        before do\n          allow(controller).to receive(:doorkeeper_token) do\n            Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: '')\n          end\n        end\n\n        it 'returns http forbidden' do\n          get :index\n          expect(response).to have_http_status :forbidden\n        end\n      end\n\n      context 'without valid resource owner' do\n        before do\n          token = Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read')\n          user.destroy!\n\n          allow(controller).to receive(:doorkeeper_token) { token }\n        end\n\n        it 'returns http unprocessable entity' do\n          get :index\n          expect(response).to have_http_status :unprocessable_entity\n        end\n      end\n\n      context 'with read scope and valid resource owner' do\n        before do\n          allow(controller).to receive(:doorkeeper_token) do\n            Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:favourites')\n          end\n        end\n\n        it 'shows favourites owned by the user' do\n          favourite_by_user = Fabricate(:favourite, account: user.account)\n          favourite_by_others = Fabricate(:favourite)\n\n          get :index\n\n          expect(assigns(:statuses)).to match_array [favourite_by_user.status]\n        end\n\n        it 'adds pagination headers if necessary' do\n          favourite = Fabricate(:favourite, account: user.account)\n\n          get :index, params: { limit: 1 }\n\n          expect(response.headers['Link'].find_link(['rel', 'next']).href).to eq \"http://test.host/api/v1/favourites?limit=1&max_id=#{favourite.id}\"\n          expect(response.headers['Link'].find_link(['rel', 'prev']).href).to eq \"http://test.host/api/v1/favourites?limit=1&min_id=#{favourite.id}\"\n        end\n\n        it 'does not add pagination headers if not necessary' do\n          get :index\n\n          expect(response.headers['Link']).to eq nil\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/filters_controller_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Api::V1::FiltersController, type: :controller do\n  render_views\n\n  let(:user)  { Fabricate(:user) }\n  let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }\n\n  before do\n    allow(controller).to receive(:doorkeeper_token) { token }\n  end\n\n  describe 'GET #index' do\n    let(:scopes) { 'read:filters' }\n    let!(:filter) { Fabricate(:custom_filter, account: user.account) }\n\n    it 'returns http success' do\n      get :index\n      expect(response).to have_http_status(200)\n    end\n  end\n\n  describe 'POST #create' do\n    let(:scopes) { 'write:filters' }\n\n    before do\n      post :create, params: { phrase: 'magic', context: %w(home), irreversible: true }\n    end\n\n    it 'returns http success' do\n      expect(response).to have_http_status(200)\n    end\n\n    it 'creates a filter' do\n      filter = user.account.custom_filters.first\n      expect(filter).to_not be_nil\n      expect(filter.phrase).to eq 'magic'\n      expect(filter.context).to eq %w(home)\n      expect(filter.irreversible?).to be true\n      expect(filter.expires_at).to be_nil\n    end\n  end\n\n  describe 'GET #show' do\n    let(:scopes) { 'read:filters' }\n    let(:filter) { Fabricate(:custom_filter, account: user.account) }\n\n    it 'returns http success' do\n      get :show, params: { id: filter.id }\n      expect(response).to have_http_status(200)\n    end\n  end\n\n  describe 'PUT #update' do\n    let(:scopes) { 'write:filters' }\n    let(:filter) { Fabricate(:custom_filter, account: user.account) }\n\n    before do\n      put :update, params: { id: filter.id, phrase: 'updated' }\n    end\n\n    it 'returns http success' do\n      expect(response).to have_http_status(200)\n    end\n\n    it 'updates the filter' do\n      expect(filter.reload.phrase).to eq 'updated'\n    end\n  end\n\n  describe 'DELETE #destroy' do\n    let(:scopes) { 'write:filters' }\n    let(:filter) { Fabricate(:custom_filter, account: user.account) }\n\n    before do\n      delete :destroy, params: { id: filter.id }\n    end\n\n    it 'returns http success' do\n      expect(response).to have_http_status(200)\n    end\n\n    it 'removes the filter' do\n      expect { filter.reload }.to raise_error ActiveRecord::RecordNotFound\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/follow_requests_controller_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Api::V1::FollowRequestsController, type: :controller do\n  render_views\n\n  let(:user)     { Fabricate(:user, account: Fabricate(:account, username: 'alice', locked: true)) }\n  let(:token)    { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }\n  let(:follower) { Fabricate(:account, username: 'bob') }\n\n  before do\n    FollowService.new.call(follower, user.account.acct)\n    allow(controller).to receive(:doorkeeper_token) { token }\n  end\n\n  describe 'GET #index' do\n    let(:scopes) { 'read:follows' }\n\n    before do\n      get :index, params: { limit: 1 }\n    end\n\n    it 'returns http success' do\n      expect(response).to have_http_status(200)\n    end\n  end\n\n  describe 'POST #authorize' do\n    let(:scopes) { 'write:follows' }\n\n    before do\n      post :authorize, params: { id: follower.id }\n    end\n\n    it 'returns http success' do\n      expect(response).to have_http_status(200)\n    end\n\n    it 'allows follower to follow' do\n      expect(follower.following?(user.account)).to be true\n    end\n  end\n\n  describe 'POST #reject' do\n    let(:scopes) { 'write:follows' }\n\n    before do\n      post :reject, params: { id: follower.id }\n    end\n\n    it 'returns http success' do\n      expect(response).to have_http_status(200)\n    end\n\n    it 'removes follow request' do\n      expect(FollowRequest.where(target_account: user.account, account: follower).count).to eq 0\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/follows_controller_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Api::V1::FollowsController, type: :controller do\n  render_views\n\n  let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }\n  let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write:follows') }\n\n  before do\n    allow(controller).to receive(:doorkeeper_token) { token }\n  end\n\n  describe 'POST #create' do\n    before do\n      stub_request(:get,  \"https://quitter.no/.well-known/host-meta\").to_return(request_fixture('.host-meta.txt'))\n      stub_request(:get,  \"https://quitter.no/.well-known/webfinger?resource=acct:gargron@quitter.no\").to_return(request_fixture('webfinger.txt'))\n      stub_request(:head, \"https://quitter.no/api/statuses/user_timeline/7477.atom\").to_return(:status => 405, :body => \"\", :headers => {})\n      stub_request(:get,  \"https://quitter.no/api/statuses/user_timeline/7477.atom\").to_return(request_fixture('feed.txt'))\n      stub_request(:get,  \"https://quitter.no/avatar/7477-300-20160211190340.png\").to_return(request_fixture('avatar.txt'))\n      stub_request(:post, \"https://quitter.no/main/push/hub\").to_return(:status => 200, :body => \"\", :headers => {})\n      stub_request(:post, \"https://quitter.no/main/salmon/user/7477\").to_return(:status => 200, :body => \"\", :headers => {})\n\n      post :create, params: { uri: 'gargron@quitter.no' }\n    end\n\n    it 'returns http success' do\n      expect(response).to have_http_status(200)\n    end\n\n    it 'creates account for remote user' do\n      expect(Account.find_by(username: 'gargron', domain: 'quitter.no')).to_not be_nil\n    end\n\n    it 'creates a follow relation between user and remote user' do\n      expect(user.account.following?(Account.find_by(username: 'gargron', domain: 'quitter.no'))).to be true\n    end\n\n    it 'sends a salmon slap to the remote user' do\n      expect(a_request(:post, \"https://quitter.no/main/salmon/user/7477\")).to have_been_made\n    end\n\n    it 'subscribes to remote hub' do\n      expect(a_request(:post, \"https://quitter.no/main/push/hub\")).to have_been_made\n    end\n\n    it 'returns http success if already following, too' do\n      post :create, params: { uri: 'gargron@quitter.no' }\n      expect(response).to have_http_status(200)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/instances/activity_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe Api::V1::Instances::ActivityController, type: :controller do\n  describe 'GET #show' do\n    it 'returns 200' do\n      get :show\n      expect(response).to have_http_status(200)\n    end\n\n    context '!Setting.activity_api_enabled' do\n      it 'returns 404' do\n        Setting.activity_api_enabled = false\n\n        get :show\n        expect(response).to have_http_status(404)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/instances/peers_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe Api::V1::Instances::PeersController, type: :controller do\n  describe 'GET #index' do\n    it 'returns 200' do\n      get :index\n      expect(response).to have_http_status(200)\n    end\n\n    context '!Setting.peers_api_enabled' do\n      it 'returns 404' do\n        Setting.peers_api_enabled = false\n\n        get :index\n        expect(response).to have_http_status(404)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/instances_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe Api::V1::InstancesController, type: :controller do\n  render_views\n\n  let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }\n  let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id) }\n\n  before do\n    allow(controller).to receive(:doorkeeper_token) { token }\n  end\n\n  describe 'GET #show' do\n    it 'returns http success' do\n      get :show\n\n      expect(response).to have_http_status(200)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/lists/accounts_controller_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe Api::V1::Lists::AccountsController do\n  render_views\n\n  let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }\n  let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }\n  let(:list)  { Fabricate(:list, account: user.account) }\n\n  before do\n    follow = Fabricate(:follow, account: user.account)\n    list.accounts << follow.target_account\n    allow(controller).to receive(:doorkeeper_token) { token }\n  end\n\n  describe 'GET #index' do\n    let(:scopes) { 'read:lists' }\n\n    it 'returns http success' do\n      get :show, params: { list_id: list.id }\n\n      expect(response).to have_http_status(200)\n    end\n  end\n\n  describe 'POST #create' do\n    let(:scopes) { 'write:lists' }\n    let(:bob) { Fabricate(:account, username: 'bob') }\n\n    before do\n      user.account.follow!(bob)\n      post :create, params: { list_id: list.id, account_ids: [bob.id] }\n    end\n\n    it 'returns http success' do\n      expect(response).to have_http_status(200)\n    end\n\n    it 'adds account to the list' do\n      expect(list.accounts.include?(bob)).to be true\n    end\n  end\n\n  describe 'DELETE #destroy' do\n    let(:scopes) { 'write:lists' }\n\n    before do\n      delete :destroy, params: { list_id: list.id, account_ids: [list.accounts.first.id] }\n    end\n\n    it 'returns http success' do\n      expect(response).to have_http_status(200)\n    end\n\n    it 'removes account from the list' do\n      expect(list.accounts.count).to eq 0\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/lists_controller_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Api::V1::ListsController, type: :controller do\n  render_views\n\n  let!(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }\n  let!(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }\n  let!(:list)  { Fabricate(:list, account: user.account) }\n\n  before { allow(controller).to receive(:doorkeeper_token) { token } }\n\n  describe 'GET #index' do\n    let(:scopes) { 'read:lists' }\n\n    it 'returns http success' do\n      get :index\n      expect(response).to have_http_status(200)\n    end\n  end\n\n  describe 'GET #show' do\n    let(:scopes) { 'read:lists' }\n\n    it 'returns http success' do\n      get :show, params: { id: list.id }\n      expect(response).to have_http_status(200)\n    end\n  end\n\n  describe 'POST #create' do\n    let(:scopes) { 'write:lists' }\n\n    before do\n      post :create, params: { title: 'Foo bar' }\n    end\n\n    it 'returns http success' do\n      expect(response).to have_http_status(200)\n    end\n\n    it 'creates list' do\n      expect(List.where(account: user.account).count).to eq 2\n      expect(List.last.title).to eq 'Foo bar'\n    end\n  end\n\n  describe 'PUT #update' do\n    let(:scopes) { 'write:lists' }\n\n    before do\n      put :update, params: { id: list.id, title: 'Updated title' }\n    end\n\n    it 'returns http success' do\n      expect(response).to have_http_status(200)\n    end\n\n    it 'updates the list' do\n      expect(list.reload.title).to eq 'Updated title'\n    end\n  end\n\n  describe 'DELETE #destroy' do\n    let(:scopes) { 'write:lists' }\n\n    before do\n      delete :destroy, params: { id: list.id }\n    end\n\n    it 'returns http success' do\n      expect(response).to have_http_status(200)\n    end\n\n    it 'deletes the list' do\n      expect(List.find_by(id: list.id)).to be_nil\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/media_controller_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Api::V1::MediaController, type: :controller do\n  render_views\n\n  let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }\n  let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write:media') }\n\n  before do\n    allow(controller).to receive(:doorkeeper_token) { token }\n  end\n\n  describe 'POST #create' do\n    describe 'with paperclip errors' do\n      context 'when imagemagick cant identify the file type' do\n        before do\n          expect_any_instance_of(Account).to receive_message_chain(:media_attachments, :create!).and_raise(Paperclip::Errors::NotIdentifiedByImageMagickError)\n          post :create, params: { file: fixture_file_upload('files/attachment.jpg', 'image/jpeg') }\n        end\n\n        it 'returns http 422' do\n          expect(response).to have_http_status(:unprocessable_entity)\n        end\n      end\n\n      context 'when there is a generic error' do\n        before do\n          expect_any_instance_of(Account).to receive_message_chain(:media_attachments, :create!).and_raise(Paperclip::Error)\n          post :create, params: { file: fixture_file_upload('files/attachment.jpg', 'image/jpeg') }\n        end\n\n        it 'returns http 422' do\n          expect(response).to have_http_status(500)\n        end\n      end\n    end\n\n    context 'image/jpeg' do\n      before do\n        post :create, params: { file: fixture_file_upload('files/attachment.jpg', 'image/jpeg') }\n      end\n\n      it 'returns http success' do\n        expect(response).to have_http_status(200)\n      end\n\n      it 'creates a media attachment' do\n        expect(MediaAttachment.first).to_not be_nil\n      end\n\n      it 'uploads a file' do\n        expect(MediaAttachment.first).to have_attached_file(:file)\n      end\n\n      it 'returns media ID in JSON' do\n        expect(body_as_json[:id]).to eq MediaAttachment.first.id.to_s\n      end\n    end\n\n    context 'image/gif' do\n      before do\n        post :create, params: { file: fixture_file_upload('files/attachment.gif', 'image/gif') }\n      end\n\n      it 'returns http success' do\n        expect(response).to have_http_status(200)\n      end\n\n      it 'creates a media attachment' do\n        expect(MediaAttachment.first).to_not be_nil\n      end\n\n      it 'uploads a file' do\n        expect(MediaAttachment.first).to have_attached_file(:file)\n      end\n\n      it 'returns media ID in JSON' do\n        expect(body_as_json[:id]).to eq MediaAttachment.first.id.to_s\n      end\n    end\n\n    context 'video/webm' do\n      before do\n        post :create, params: { file: fixture_file_upload('files/attachment.webm', 'video/webm') }\n      end\n\n      it do\n        # returns http success\n        expect(response).to have_http_status(200)\n\n        # creates a media attachment\n        expect(MediaAttachment.first).to_not be_nil\n\n        # uploads a file\n        expect(MediaAttachment.first).to have_attached_file(:file)\n\n        # returns media ID in JSON\n        expect(body_as_json[:id]).to eq MediaAttachment.first.id.to_s\n      end\n    end\n  end\n\n  describe 'PUT #update' do\n    context 'when somebody else\\'s' do\n      let(:media) { Fabricate(:media_attachment, status: nil) }\n\n      it 'returns http not found' do\n        put :update, params: { id: media.id, description: 'Lorem ipsum!!!' }\n        expect(response).to have_http_status(:not_found)\n      end\n    end\n\n    context 'when not attached to a status' do\n      let(:media) { Fabricate(:media_attachment, status: nil, account: user.account) }\n\n      it 'updates the description' do\n        put :update, params: { id: media.id, description: 'Lorem ipsum!!!' }\n        expect(media.reload.description).to eq 'Lorem ipsum!!!'\n      end\n    end\n\n    context 'when attached to a status' do\n      let(:media) { Fabricate(:media_attachment, status: Fabricate(:status), account: user.account) }\n\n      it 'returns http not found' do\n        put :update, params: { id: media.id, description: 'Lorem ipsum!!!' }\n        expect(response).to have_http_status(:not_found)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/mutes_controller_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Api::V1::MutesController, type: :controller do\n  render_views\n\n  let(:user)   { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }\n  let(:scopes) { 'read:mutes' }\n  let(:token)  { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }\n\n  before { allow(controller).to receive(:doorkeeper_token) { token } }\n\n  describe 'GET #index' do\n    it 'limits according to limit parameter' do\n      2.times.map { Fabricate(:mute, account: user.account) }\n      get :index, params: { limit: 1 }\n      expect(body_as_json.size).to eq 1\n    end\n\n    it 'queries mutes in range according to max_id' do\n      mutes = 2.times.map { Fabricate(:mute, account: user.account) }\n\n      get :index, params: { max_id: mutes[1] }\n\n      expect(body_as_json.size).to eq 1\n      expect(body_as_json[0][:id]).to eq mutes[0].target_account_id.to_s\n    end\n\n    it 'queries mutes in range according to since_id' do\n      mutes = 2.times.map { Fabricate(:mute, account: user.account) }\n\n      get :index, params: { since_id: mutes[0] }\n\n      expect(body_as_json.size).to eq 1\n      expect(body_as_json[0][:id]).to eq mutes[1].target_account_id.to_s\n    end\n\n    it 'sets pagination header for next path' do\n      mutes = 2.times.map { Fabricate(:mute, account: user.account) }\n      get :index, params: { limit: 1, since_id: mutes[0] }\n      expect(response.headers['Link'].find_link(['rel', 'next']).href).to eq api_v1_mutes_url(limit: 1, max_id: mutes[1])\n    end\n\n    it 'sets pagination header for previous path' do\n      mute = Fabricate(:mute, account: user.account)\n      get :index\n      expect(response.headers['Link'].find_link(['rel', 'prev']).href).to eq api_v1_mutes_url(since_id: mute)\n    end\n\n    it 'returns http success' do\n      get :index\n      expect(response).to have_http_status(200)\n    end\n\n    context 'with wrong scopes' do\n      let(:scopes) { 'write:mutes' }\n\n      it 'returns http forbidden' do\n        get :index\n        expect(response).to have_http_status(403)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/notifications_controller_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Api::V1::NotificationsController, type: :controller do\n  render_views\n\n  let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }\n  let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }\n  let(:other) { Fabricate(:user, account: Fabricate(:account, username: 'bob')) }\n  let(:third) { Fabricate(:user, account: Fabricate(:account, username: 'carol')) }\n\n  before do\n    allow(controller).to receive(:doorkeeper_token) { token }\n  end\n\n  describe 'GET #show' do\n    let(:scopes) { 'read:notifications' }\n\n    it 'returns http success' do\n      notification = Fabricate(:notification, account: user.account)\n      get :show, params: { id: notification.id }\n\n      expect(response).to have_http_status(200)\n    end\n  end\n\n  describe 'POST #dismiss' do\n    let(:scopes) { 'write:notifications' }\n\n    it 'destroys the notification' do\n      notification = Fabricate(:notification, account: user.account)\n      post :dismiss, params: { id: notification.id }\n\n      expect(response).to have_http_status(200)\n      expect { notification.reload }.to raise_error(ActiveRecord::RecordNotFound)\n    end\n  end\n\n  describe 'POST #clear' do\n    let(:scopes) { 'write:notifications' }\n\n    it 'clears notifications for the account' do\n      notification = Fabricate(:notification, account: user.account)\n      post :clear\n\n      expect(notification.account.reload.notifications).to be_empty\n      expect(response).to have_http_status(200)\n    end\n  end\n\n  describe 'GET #index' do\n    let(:scopes) { 'read:notifications' }\n\n    before do\n      first_status = PostStatusService.new.call(user.account, text: 'Test')\n      @reblog_of_first_status = ReblogService.new.call(other.account, first_status)\n      mentioning_status = PostStatusService.new.call(other.account, text: 'Hello @alice')\n      @mention_from_status = mentioning_status.mentions.first\n      @favourite = FavouriteService.new.call(other.account, first_status)\n      @second_favourite = FavouriteService.new.call(third.account, first_status)\n      @follow = FollowService.new.call(other.account, 'alice')\n    end\n\n    describe 'with no options' do\n      before do\n        get :index\n      end\n\n      it 'returns http success' do\n        expect(response).to have_http_status(200)\n      end\n\n      it 'includes reblog' do\n        expect(assigns(:notifications).map(&:activity)).to include(@reblog_of_first_status)\n      end\n\n      it 'includes mention' do\n        expect(assigns(:notifications).map(&:activity)).to include(@mention_from_status)\n      end\n\n      it 'includes favourite' do\n        expect(assigns(:notifications).map(&:activity)).to include(@favourite)\n      end\n\n      it 'includes follow' do\n        expect(assigns(:notifications).map(&:activity)).to include(@follow)\n      end\n    end\n\n    describe 'from specified user' do\n      before do\n        get :index, params: { account_id: third.account.id }\n      end\n\n      it 'returns http success' do\n        expect(response).to have_http_status(200)\n      end\n\n      it 'includes favourite' do\n        expect(assigns(:notifications).map(&:activity)).to include(@second_favourite)\n      end\n\n      it 'excludes favourite' do\n        expect(assigns(:notifications).map(&:activity)).to_not include(@favourite)\n      end\n\n      it 'excludes mention' do\n        expect(assigns(:notifications).map(&:activity)).to_not include(@mention_from_status)\n      end\n\n      it 'excludes reblog' do\n        expect(assigns(:notifications).map(&:activity)).to_not include(@reblog_of_first_status)\n      end\n\n      it 'excludes follow' do\n        expect(assigns(:notifications).map(&:activity)).to_not include(@follow)\n      end\n    end\n\n    describe 'from nonexistent user' do\n      before do\n        get :index, params: { account_id: 'foo' }\n      end\n\n      it 'returns http success' do\n        expect(response).to have_http_status(200)\n      end\n\n      it 'excludes favourite' do\n        expect(assigns(:notifications).map(&:activity)).to_not include(@favourite)\n      end\n\n      it 'excludes second favourite' do\n        expect(assigns(:notifications).map(&:activity)).to_not include(@second_favourite)\n      end\n\n      it 'excludes mention' do\n        expect(assigns(:notifications).map(&:activity)).to_not include(@mention_from_status)\n      end\n\n      it 'excludes reblog' do\n        expect(assigns(:notifications).map(&:activity)).to_not include(@reblog_of_first_status)\n      end\n\n      it 'excludes follow' do\n        expect(assigns(:notifications).map(&:activity)).to_not include(@follow)\n      end\n    end\n\n    describe 'with excluded mentions' do\n      before do\n        get :index, params: { exclude_types: ['mention'] }\n      end\n\n      it 'returns http success' do\n        expect(response).to have_http_status(200)\n      end\n\n      it 'includes reblog' do\n        expect(assigns(:notifications).map(&:activity)).to include(@reblog_of_first_status)\n      end\n\n      it 'excludes mention' do\n        expect(assigns(:notifications).map(&:activity)).to_not include(@mention_from_status)\n      end\n\n      it 'includes favourite' do\n        expect(assigns(:notifications).map(&:activity)).to include(@favourite)\n      end\n\n      it 'includes third favourite' do\n        expect(assigns(:notifications).map(&:activity)).to include(@second_favourite)\n      end\n\n      it 'includes follow' do\n        expect(assigns(:notifications).map(&:activity)).to include(@follow)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/polls/votes_controller_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Api::V1::Polls::VotesController, type: :controller do\n  render_views\n\n  let(:user)   { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }\n  let(:scopes) { 'write:statuses' }\n  let(:token)  { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }\n\n  before { allow(controller).to receive(:doorkeeper_token) { token } }\n\n  describe 'POST #create' do\n    let(:poll) { Fabricate(:poll) }\n\n    before do\n      post :create, params: { poll_id: poll.id, choices: %w(1) }\n    end\n\n    it 'returns http success' do\n      expect(response).to have_http_status(200)\n    end\n\n    it 'creates a vote' do\n      vote = poll.votes.where(account: user.account).first\n\n      expect(vote).to_not be_nil\n      expect(vote.choice).to eq 1\n    end\n\n    it 'updates poll tallies' do\n      expect(poll.reload.cached_tallies).to eq [0, 1]\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/polls_controller_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Api::V1::PollsController, type: :controller do\n  render_views\n\n  let(:user)   { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }\n  let(:scopes) { 'read:statuses' }\n  let(:token)  { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }\n\n  before { allow(controller).to receive(:doorkeeper_token) { token } }\n\n  describe 'GET #show' do\n    let(:poll) { Fabricate(:poll, status: Fabricate(:status, visibility: visibility)) }\n\n    before do\n      get :show, params: { id: poll.id }\n    end\n\n    context 'when parent status is public' do\n      let(:visibility) { 'public' }\n\n      it 'returns http success' do\n        expect(response).to have_http_status(200)\n      end\n    end\n\n    context 'when parent status is private' do\n      let(:visibility) { 'private' }\n\n      it 'returns http not found' do\n        expect(response).to have_http_status(404)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/push/subscriptions_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe Api::V1::Push::SubscriptionsController do\n  render_views\n\n  let(:user)  { Fabricate(:user) }\n  let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'push') }\n\n  before do\n    allow(controller).to receive(:doorkeeper_token) { token }\n  end\n\n  let(:create_payload) do\n    {\n      subscription: {\n        endpoint: 'https://fcm.googleapis.com/fcm/send/fiuH06a27qE:APA91bHnSiGcLwdaxdyqVXNDR9w1NlztsHb6lyt5WDKOC_Z_Q8BlFxQoR8tWFSXUIDdkyw0EdvxTu63iqamSaqVSevW5LfoFwojws8XYDXv_NRRLH6vo2CdgiN4jgHv5VLt2A8ah6lUX',\n        keys: {\n          p256dh: 'BEm_a0bdPDhf0SOsrnB2-ategf1hHoCnpXgQsFj5JCkcoMrMt2WHoPfEYOYPzOIs9mZE8ZUaD7VA5vouy0kEkr8=',\n          auth: 'eH_C8rq2raXqlcBVDa1gLg==',\n        },\n      }\n    }.with_indifferent_access\n  end\n\n  let(:alerts_payload) do\n    {\n      data: {\n        alerts: {\n          follow: true,\n          favourite: false,\n          reblog: true,\n          mention: false,\n        }\n      }\n    }.with_indifferent_access\n  end\n\n  describe 'POST #create' do\n    it 'saves push subscriptions' do\n      post :create, params: create_payload\n\n      push_subscription = Web::PushSubscription.find_by(endpoint: create_payload[:subscription][:endpoint])\n\n      expect(push_subscription.endpoint).to eq(create_payload[:subscription][:endpoint])\n      expect(push_subscription.key_p256dh).to eq(create_payload[:subscription][:keys][:p256dh])\n      expect(push_subscription.key_auth).to eq(create_payload[:subscription][:keys][:auth])\n      expect(push_subscription.user_id).to eq user.id\n      expect(push_subscription.access_token_id).to eq token.id\n    end\n\n    it 'replaces old subscription on repeat calls' do\n      post :create, params: create_payload\n      post :create, params: create_payload\n\n      expect(Web::PushSubscription.where(endpoint: create_payload[:subscription][:endpoint]).count).to eq 1\n    end\n  end\n\n  describe 'PUT #update' do\n    it 'changes alert settings' do\n      post :create, params: create_payload\n      put :update, params: alerts_payload\n\n      push_subscription = Web::PushSubscription.find_by(endpoint: create_payload[:subscription][:endpoint])\n\n      expect(push_subscription.data.dig('alerts', 'follow')).to eq(alerts_payload[:data][:alerts][:follow].to_s)\n      expect(push_subscription.data.dig('alerts', 'favourite')).to eq(alerts_payload[:data][:alerts][:favourite].to_s)\n      expect(push_subscription.data.dig('alerts', 'reblog')).to eq(alerts_payload[:data][:alerts][:reblog].to_s)\n      expect(push_subscription.data.dig('alerts', 'mention')).to eq(alerts_payload[:data][:alerts][:mention].to_s)\n    end\n  end\n\n  describe 'DELETE #destroy' do\n    it 'removes the subscription' do\n      post :create, params: create_payload\n      delete :destroy\n\n      expect(Web::PushSubscription.find_by(endpoint: create_payload[:subscription][:endpoint])).to be_nil\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/reports_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe Api::V1::ReportsController, type: :controller do\n  render_views\n\n  let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }\n  let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }\n\n  before do\n    allow(controller).to receive(:doorkeeper_token) { token }\n  end\n\n  describe 'POST #create' do\n    let(:scopes)  { 'write:reports' }\n    let!(:status) { Fabricate(:status) }\n    let!(:admin)  { Fabricate(:user, admin: true) }\n\n    before do\n      allow(AdminMailer).to receive(:new_report).and_return(double('email', deliver_later: nil))\n      post :create, params: { status_ids: [status.id], account_id: status.account.id, comment: 'reasons' }\n    end\n\n    it 'creates a report' do\n      expect(status.reload.account.targeted_reports).not_to be_empty\n      expect(response).to have_http_status(200)\n    end\n\n    it 'sends e-mails to admins' do\n      expect(AdminMailer).to have_received(:new_report).with(admin.account, Report)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/search_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe Api::V1::SearchController, type: :controller do\n  render_views\n\n  let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }\n  let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:search') }\n\n  before do\n    allow(controller).to receive(:doorkeeper_token) { token }\n  end\n\n  describe 'GET #index' do\n    it 'returns http success' do\n      get :index, params: { q: 'test' }\n\n      expect(response).to have_http_status(200)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/statuses/favourited_by_accounts_controller_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Api::V1::Statuses::FavouritedByAccountsController, type: :controller do\n  render_views\n\n  let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }\n  let(:app)   { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') }\n  let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, application: app, scopes: 'read:accounts') }\n\n  context 'with an oauth token' do\n    before do\n      allow(controller).to receive(:doorkeeper_token) { token }\n    end\n\n    describe 'GET #index' do\n      let(:status) { Fabricate(:status, account: user.account) }\n\n      before do\n        Fabricate(:favourite, status: status)\n      end\n\n      it 'returns http success' do\n        get :index, params: { status_id: status.id, limit: 1 }\n        expect(response).to have_http_status(200)\n        expect(response.headers['Link'].links.size).to eq(2)\n      end\n    end\n  end\n\n  context 'without an oauth token' do\n    before do\n      allow(controller).to receive(:doorkeeper_token) { nil }\n    end\n\n    context 'with a private status' do\n      let(:status) { Fabricate(:status, account: user.account, visibility: :private) }\n\n      describe 'GET #index' do\n        before do\n          Fabricate(:favourite, status: status)\n        end\n\n        it 'returns http unautharized' do\n          get :index, params: { status_id: status.id }\n          expect(response).to have_http_status(404)\n        end\n      end\n    end\n\n    context 'with a public status' do\n      let(:status) { Fabricate(:status, account: user.account, visibility: :public) }\n\n      describe 'GET #index' do\n        before do\n          Fabricate(:favourite, status: status)\n        end\n\n        it 'returns http success' do\n          get :index, params: { status_id: status.id }\n          expect(response).to have_http_status(200)\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/statuses/favourites_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe Api::V1::Statuses::FavouritesController do\n  render_views\n\n  let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }\n  let(:app)   { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') }\n  let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write:favourites', application: app) }\n\n  context 'with an oauth token' do\n    before do\n      allow(controller).to receive(:doorkeeper_token) { token }\n    end\n\n    describe 'POST #create' do\n      let(:status) { Fabricate(:status, account: user.account) }\n\n      before do\n        post :create, params: { status_id: status.id }\n      end\n\n      it 'returns http success' do\n        expect(response).to have_http_status(200)\n      end\n\n      it 'updates the favourites count' do\n        expect(status.favourites.count).to eq 1\n      end\n\n      it 'updates the favourited attribute' do\n        expect(user.account.favourited?(status)).to be true\n      end\n\n      it 'return json with updated attributes' do\n        hash_body = body_as_json\n\n        expect(hash_body[:id]).to eq status.id.to_s\n        expect(hash_body[:favourites_count]).to eq 1\n        expect(hash_body[:favourited]).to be true\n      end\n    end\n\n    describe 'POST #destroy' do\n      let(:status) { Fabricate(:status, account: user.account) }\n\n      before do\n        FavouriteService.new.call(user.account, status)\n        post :destroy, params: { status_id: status.id }\n      end\n\n      it 'returns http success' do\n        expect(response).to have_http_status(200)\n      end\n\n      it 'updates the favourites count' do\n        expect(status.favourites.count).to eq 0\n      end\n\n      it 'updates the favourited attribute' do\n        expect(user.account.favourited?(status)).to be false\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/statuses/mutes_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe Api::V1::Statuses::MutesController do\n  render_views\n\n  let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }\n  let(:app)   { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') }\n  let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write:mutes', application: app) }\n\n  context 'with an oauth token' do\n    before do\n      allow(controller).to receive(:doorkeeper_token) { token }\n    end\n\n    describe 'POST #create' do\n      let(:status) { Fabricate(:status, account: user.account) }\n\n      before do\n        post :create, params: { status_id: status.id }\n      end\n\n      it 'returns http success' do\n        expect(response).to have_http_status(200)\n      end\n\n      it 'creates a conversation mute' do\n        expect(ConversationMute.find_by(account: user.account, conversation_id: status.conversation_id)).to_not be_nil\n      end\n    end\n\n    describe 'POST #destroy' do\n      let(:status) { Fabricate(:status, account: user.account) }\n\n      before do\n        user.account.mute_conversation!(status.conversation)\n        post :destroy, params: { status_id: status.id }\n      end\n\n      it 'returns http success' do\n        expect(response).to have_http_status(200)\n      end\n\n      it 'destroys the conversation mute' do\n        expect(ConversationMute.find_by(account: user.account, conversation_id: status.conversation_id)).to be_nil\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/statuses/pins_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe Api::V1::Statuses::PinsController do\n  render_views\n\n  let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }\n  let(:app)   { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') }\n  let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write:accounts', application: app) }\n\n  context 'with an oauth token' do\n    before do\n      allow(controller).to receive(:doorkeeper_token) { token }\n    end\n\n    describe 'POST #create' do\n      let(:status) { Fabricate(:status, account: user.account) }\n\n      before do\n        post :create, params: { status_id: status.id }\n      end\n\n      it 'returns http success' do\n        expect(response).to have_http_status(200)\n      end\n\n      it 'updates the pinned attribute' do\n        expect(user.account.pinned?(status)).to be true\n      end\n\n      it 'return json with updated attributes' do\n        hash_body = body_as_json\n\n        expect(hash_body[:id]).to eq status.id.to_s\n        expect(hash_body[:pinned]).to be true\n      end\n    end\n\n    describe 'POST #destroy' do\n      let(:status) { Fabricate(:status, account: user.account) }\n\n      before do\n        Fabricate(:status_pin, status: status, account: user.account)\n        post :destroy, params: { status_id: status.id }\n      end\n\n      it 'returns http success' do\n        expect(response).to have_http_status(200)\n      end\n\n      it 'updates the pinned attribute' do\n        expect(user.account.pinned?(status)).to be false\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/statuses/reblogged_by_accounts_controller_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Api::V1::Statuses::RebloggedByAccountsController, type: :controller do\n  render_views\n\n  let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }\n  let(:app)   { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') }\n  let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, application: app, scopes: 'read:accounts') }\n\n  context 'with an oauth token' do\n    before do\n      allow(controller).to receive(:doorkeeper_token) { token }\n    end\n\n    describe 'GET #index' do\n      let(:status) { Fabricate(:status, account: user.account) }\n\n      before do\n        Fabricate(:status, reblog_of_id: status.id)\n      end\n\n      it 'returns http success' do\n        get :index, params: { status_id: status.id, limit: 1 }\n        expect(response).to have_http_status(200)\n        expect(response.headers['Link'].links.size).to eq(2)\n      end\n    end\n  end\n\n  context 'without an oauth token' do\n    before do\n      allow(controller).to receive(:doorkeeper_token) { nil }\n    end\n\n    context 'with a private status' do\n      let(:status) { Fabricate(:status, account: user.account, visibility: :private) }\n\n      describe 'GET #index' do\n        before do\n          Fabricate(:status, reblog_of_id: status.id)\n        end\n\n        it 'returns http unautharized' do\n          get :index, params: { status_id: status.id }\n          expect(response).to have_http_status(404)\n        end\n      end\n    end\n\n    context 'with a public status' do\n      let(:status) { Fabricate(:status, account: user.account, visibility: :public) }\n\n      describe 'GET #index' do\n        before do\n          Fabricate(:status, reblog_of_id: status.id)\n        end\n\n        it 'returns http success' do\n          get :index, params: { status_id: status.id }\n          expect(response).to have_http_status(200)\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/statuses/reblogs_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe Api::V1::Statuses::ReblogsController do\n  render_views\n\n  let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }\n  let(:app)   { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') }\n  let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write:statuses', application: app) }\n\n  context 'with an oauth token' do\n    before do\n      allow(controller).to receive(:doorkeeper_token) { token }\n    end\n\n    describe 'POST #create' do\n      let(:status) { Fabricate(:status, account: user.account) }\n\n      before do\n        post :create, params: { status_id: status.id }\n      end\n\n      it 'returns http success' do\n        expect(response).to have_http_status(200)\n      end\n\n      it 'updates the reblogs count' do\n        expect(status.reblogs.count).to eq 1\n      end\n\n      it 'updates the reblogged attribute' do\n        expect(user.account.reblogged?(status)).to be true\n      end\n\n      it 'return json with updated attributes' do\n        hash_body = body_as_json\n\n        expect(hash_body[:reblog][:id]).to eq status.id.to_s\n        expect(hash_body[:reblog][:reblogs_count]).to eq 1\n        expect(hash_body[:reblog][:reblogged]).to be true\n      end\n    end\n\n    describe 'POST #destroy' do\n      let(:status) { Fabricate(:status, account: user.account) }\n\n      before do\n        ReblogService.new.call(user.account, status)\n        post :destroy, params: { status_id: status.id }\n      end\n\n      it 'returns http success' do\n        expect(response).to have_http_status(200)\n      end\n\n      it 'updates the reblogs count' do\n        expect(status.reblogs.count).to eq 0\n      end\n\n      it 'updates the reblogged attribute' do\n        expect(user.account.reblogged?(status)).to be false\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/statuses_controller_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Api::V1::StatusesController, type: :controller do\n  render_views\n\n  let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }\n  let(:app)   { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') }\n  let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, application: app, scopes: scopes) }\n\n  context 'with an oauth token' do\n    before do\n      allow(controller).to receive(:doorkeeper_token) { token }\n    end\n\n    describe 'GET #show' do\n      let(:scopes) { 'read:statuses' }\n      let(:status) { Fabricate(:status, account: user.account) }\n\n      it 'returns http success' do\n        get :show, params: { id: status.id }\n        expect(response).to have_http_status(200)\n      end\n    end\n\n    describe 'GET #context' do\n      let(:scopes) { 'read:statuses' }\n      let(:status) { Fabricate(:status, account: user.account) }\n\n      before do\n        Fabricate(:status, account: user.account, thread: status)\n      end\n\n      it 'returns http success' do\n        get :context, params: { id: status.id }\n        expect(response).to have_http_status(200)\n      end\n    end\n\n    describe 'POST #create' do\n      let(:scopes) { 'write:statuses' }\n\n      before do\n        post :create, params: { status: 'Hello world' }\n      end\n\n      it 'returns http success' do\n        expect(response).to have_http_status(200)\n      end\n    end\n\n    describe 'DELETE #destroy' do\n      let(:scopes) { 'write:statuses' }\n      let(:status) { Fabricate(:status, account: user.account) }\n\n      before do\n        post :destroy, params: { id: status.id }\n      end\n\n      it 'returns http success' do\n        expect(response).to have_http_status(200)\n      end\n\n      it 'removes the status' do\n        expect(Status.find_by(id: status.id)).to be nil\n      end\n    end\n  end\n\n  context 'without an oauth token' do\n    before do\n      allow(controller).to receive(:doorkeeper_token) { nil }\n    end\n\n    context 'with a private status' do\n      let(:status) { Fabricate(:status, account: user.account, visibility: :private) }\n\n      describe 'GET #show' do\n        it 'returns http unautharized' do\n          get :show, params: { id: status.id }\n          expect(response).to have_http_status(404)\n        end\n      end\n\n      describe 'GET #context' do\n        before do\n          Fabricate(:status, account: user.account, thread: status)\n        end\n\n        it 'returns http unautharized' do\n          get :context, params: { id: status.id }\n          expect(response).to have_http_status(404)\n        end\n      end\n\n      describe 'GET #card' do\n        it 'returns http unautharized' do\n          get :card, params: { id: status.id }\n          expect(response).to have_http_status(404)\n        end\n      end\n    end\n\n    context 'with a public status' do\n      let(:status) { Fabricate(:status, account: user.account, visibility: :public) }\n\n      describe 'GET #show' do\n        it 'returns http success' do\n          get :show, params: { id: status.id }\n          expect(response).to have_http_status(200)\n        end\n      end\n\n      describe 'GET #context' do\n        before do\n          Fabricate(:status, account: user.account, thread: status)\n        end\n\n        it 'returns http success' do\n          get :context, params: { id: status.id }\n          expect(response).to have_http_status(200)\n        end\n      end\n\n      describe 'GET #card' do\n        it 'returns http success' do\n          get :card, params: { id: status.id }\n          expect(response).to have_http_status(200)\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/streaming_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe Api::V1::StreamingController do\n  around(:each) do |example|\n    before = Rails.configuration.x.streaming_api_base_url\n    Rails.configuration.x.streaming_api_base_url = Rails.configuration.x.web_domain\n    example.run\n    Rails.configuration.x.streaming_api_base_url = before\n  end\n\n  before(:each) do\n    request.headers.merge! Host: Rails.configuration.x.web_domain\n  end\n\n  context 'with streaming api on same host' do\n    describe 'GET #index' do\n      it 'raises ActiveRecord::RecordNotFound' do\n        get :index\n        expect(response).to have_http_status(404)\n      end\n    end\n  end\n\n  context 'with streaming api on different host' do\n    before(:each) do\n      Rails.configuration.x.streaming_api_base_url = 'wss://streaming-' + Rails.configuration.x.web_domain\n      @streaming_host = URI.parse(Rails.configuration.x.streaming_api_base_url).host\n    end\n\n    describe 'GET #index' do\n      it 'redirects to streaming host' do\n        get :index, params: { access_token: 'deadbeef', stream: 'public' }\n        expect(response).to have_http_status(301)\n        request_uri = URI.parse(request.url)\n        redirect_to_uri = URI.parse(response.location)\n        [:scheme, :path, :query, :fragment].each do |part|\n          expect(redirect_to_uri.send(part)).to eq(request_uri.send(part)), \"redirect target #{part}\"\n        end\n        expect(redirect_to_uri.host).to eq(@streaming_host), \"redirect target host\"\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/suggestions_controller_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Api::V1::SuggestionsController, type: :controller do\n  render_views\n\n  let(:user)  { Fabricate(:user) }\n  let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read write') }\n\n  before do\n    allow(controller).to receive(:doorkeeper_token) { token }\n  end\n\n  describe 'GET #index' do\n    let(:bob) { Fabricate(:account) }\n    let(:jeff) { Fabricate(:account) }\n\n    before do\n      PotentialFriendshipTracker.record(user.account_id, bob.id, :reblog)\n      PotentialFriendshipTracker.record(user.account_id, jeff.id, :favourite)\n\n      get :index\n    end\n\n    it 'returns http success' do\n      expect(response).to have_http_status(200)\n    end\n\n    it 'returns accounts' do\n      json = body_as_json\n\n      expect(json.size).to be >= 1\n      expect(json.map { |i| i[:id] }).to include *[bob, jeff].map { |i| i.id.to_s }\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/timelines/direct_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe Api::V1::Timelines::DirectController, type: :controller do\n  let(:user)  { Fabricate(:user) }\n  let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:statuses') }\n\n  describe 'GET #show' do\n    it 'returns 200' do\n      allow(controller).to receive(:doorkeeper_token) { token }\n      get :show\n\n      expect(response).to have_http_status(200)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/timelines/home_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe Api::V1::Timelines::HomeController do\n  render_views\n\n  let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice'), current_sign_in_at: 1.day.ago) }\n\n  before do\n    allow(controller).to receive(:doorkeeper_token) { token }\n  end\n\n  context 'with a user context' do\n    let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:statuses') }\n\n    describe 'GET #show' do\n      before do\n        follow = Fabricate(:follow, account: user.account)\n        PostStatusService.new.call(follow.target_account, text: 'New status for user home timeline.')\n      end\n\n      it 'returns http success' do\n        get :show\n\n        expect(response).to have_http_status(200)\n        expect(response.headers['Link'].links.size).to eq(2)\n      end\n    end\n  end\n\n  context 'without a user context' do\n    let(:token) { Fabricate(:accessible_access_token, resource_owner_id: nil, scopes: 'read') }\n\n    describe 'GET #show' do\n      it 'returns http unprocessable entity' do\n        get :show\n\n        expect(response).to have_http_status(:unprocessable_entity)\n        expect(response.headers['Link']).to be_nil\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/timelines/list_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe Api::V1::Timelines::ListController do\n  render_views\n\n  let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }\n  let(:list) { Fabricate(:list, account: user.account) }\n\n  before do\n    allow(controller).to receive(:doorkeeper_token) { token }\n  end\n\n  context 'with a user context' do\n    let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:lists') }\n\n    describe 'GET #show' do\n      before do\n        follow = Fabricate(:follow, account: user.account)\n        list.accounts << follow.target_account\n        PostStatusService.new.call(follow.target_account, text: 'New status for user home timeline.')\n      end\n\n      it 'returns http success' do\n        get :show, params: { id: list.id }\n        expect(response).to have_http_status(200)\n      end\n    end\n  end\n\n  context 'with the wrong user context' do\n    let(:other_user) { Fabricate(:user, account: Fabricate(:account, username: 'bob')) }\n    let(:token)      { Fabricate(:accessible_access_token, resource_owner_id: other_user.id, scopes: 'read') }\n\n    describe 'GET #show' do\n      it 'returns http not found' do\n        get :show, params: { id: list.id }\n        expect(response).to have_http_status(:not_found)\n      end\n    end\n  end\n\n  context 'without a user context' do\n    let(:token) { Fabricate(:accessible_access_token, resource_owner_id: nil, scopes: 'read') }\n\n    describe 'GET #show' do\n      it 'returns http unprocessable entity' do\n        get :show, params: { id: list.id }\n\n        expect(response).to have_http_status(:unprocessable_entity)\n        expect(response.headers['Link']).to be_nil\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/timelines/public_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe Api::V1::Timelines::PublicController do\n  render_views\n\n  let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }\n\n  before do\n    allow(controller).to receive(:doorkeeper_token) { token }\n  end\n\n  context 'with a user context' do\n    let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id) }\n\n    describe 'GET #show' do\n      before do\n        PostStatusService.new.call(user.account, text: 'New status from user for federated public timeline.')\n      end\n\n      it 'returns http success' do\n        get :show\n\n        expect(response).to have_http_status(200)\n        expect(response.headers['Link'].links.size).to eq(2)\n      end\n    end\n\n    describe 'GET #show with local only' do\n      before do\n        PostStatusService.new.call(user.account, text: 'New status from user for local public timeline.')\n      end\n\n      it 'returns http success' do\n        get :show, params: { local: true }\n\n        expect(response).to have_http_status(200)\n        expect(response.headers['Link'].links.size).to eq(2)\n      end\n    end\n  end\n\n  context 'without a user context' do\n    let(:token) { Fabricate(:accessible_access_token, resource_owner_id: nil) }\n\n    describe 'GET #show' do\n      it 'returns http success' do\n        get :show\n\n        expect(response).to have_http_status(200)\n        expect(response.headers['Link']).to be_nil\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v1/timelines/tag_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe Api::V1::Timelines::TagController do\n  render_views\n\n  let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }\n\n  before do\n    allow(controller).to receive(:doorkeeper_token) { token }\n  end\n\n  context 'with a user context' do\n    let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id) }\n\n    describe 'GET #show' do\n      before do\n        PostStatusService.new.call(user.account, text: 'It is a #test')\n      end\n\n      it 'returns http success' do\n        get :show, params: { id: 'test' }\n        expect(response).to have_http_status(200)\n        expect(response.headers['Link'].links.size).to eq(2)\n      end\n    end\n  end\n\n  context 'without a user context' do\n    let(:token) { Fabricate(:accessible_access_token, resource_owner_id: nil) }\n\n    describe 'GET #show' do\n      it 'returns http success' do\n        get :show, params: { id: 'test' }\n        expect(response).to have_http_status(200)\n        expect(response.headers['Link']).to be_nil\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/v2/search_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe Api::V2::SearchController, type: :controller do\n  render_views\n\n  let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }\n  let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:search') }\n\n  before do\n    allow(controller).to receive(:doorkeeper_token) { token }\n  end\n\n  describe 'GET #index' do\n    it 'returns http success' do\n      get :index, params: { q: 'test' }\n\n      expect(response).to have_http_status(200)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/web/embeds_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe Api::Web::EmbedsController do\n  render_views\n\n  let(:user) { Fabricate(:user) }\n  before { sign_in user }\n\n  describe 'POST #create' do\n    subject(:response) { post :create, params: { url: url } }\n    subject(:body) { JSON.parse(response.body, symbolize_names: true) }\n\n    context 'when successfully finds status' do\n      let(:status) { Fabricate(:status) }\n      let(:url) { \"http://#{Rails.configuration.x.web_domain}/@#{status.account.username}/#{status.id}\" }\n\n      it 'returns a right response' do\n        expect(response).to have_http_status :ok\n        expect(body[:author_name]).to eq status.account.username\n      end\n    end\n\n    context 'when fails to find status' do\n      let(:url) { 'https://host.test/oembed.html' }\n      let(:service_instance) { double('fetch_oembed_service') }\n\n      before do\n        allow(FetchOEmbedService).to receive(:new) { service_instance }\n        allow(service_instance).to receive(:call) { call_result }\n      end\n\n      context 'when successfully fetching oembed' do\n        let(:call_result) { { result: :ok } }\n\n        it 'returns a right response' do\n          expect(response).to have_http_status :ok\n          expect(body[:result]).to eq 'ok'\n        end\n      end\n\n      context 'when fails to fetch oembed' do\n        let(:call_result) { nil }\n\n        it 'returns a right response' do\n          expect(response).to have_http_status :not_found\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/web/push_subscriptions_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe Api::Web::PushSubscriptionsController do\n  render_views\n\n  let(:user) { Fabricate(:user) }\n\n  let(:create_payload) do\n    {\n      subscription: {\n        endpoint: 'https://fcm.googleapis.com/fcm/send/fiuH06a27qE:APA91bHnSiGcLwdaxdyqVXNDR9w1NlztsHb6lyt5WDKOC_Z_Q8BlFxQoR8tWFSXUIDdkyw0EdvxTu63iqamSaqVSevW5LfoFwojws8XYDXv_NRRLH6vo2CdgiN4jgHv5VLt2A8ah6lUX',\n        keys: {\n          p256dh: 'BEm_a0bdPDhf0SOsrnB2-ategf1hHoCnpXgQsFj5JCkcoMrMt2WHoPfEYOYPzOIs9mZE8ZUaD7VA5vouy0kEkr8=',\n          auth: 'eH_C8rq2raXqlcBVDa1gLg==',\n        },\n      }\n    }\n  end\n\n  let(:alerts_payload) do\n    {\n      data: {\n        alerts: {\n          follow: true,\n          favourite: false,\n          reblog: true,\n          mention: false,\n        }\n      }\n    }\n  end\n\n  describe 'POST #create' do\n    it 'saves push subscriptions' do\n      sign_in(user)\n\n      stub_request(:post, create_payload[:subscription][:endpoint]).to_return(status: 200)\n\n      post :create, format: :json, params: create_payload\n\n      user.reload\n\n      push_subscription = Web::PushSubscription.find_by(endpoint: create_payload[:subscription][:endpoint])\n\n      expect(push_subscription['endpoint']).to eq(create_payload[:subscription][:endpoint])\n      expect(push_subscription['key_p256dh']).to eq(create_payload[:subscription][:keys][:p256dh])\n      expect(push_subscription['key_auth']).to eq(create_payload[:subscription][:keys][:auth])\n    end\n\n    context 'with initial data' do\n      it 'saves alert settings' do\n        sign_in(user)\n\n        stub_request(:post, create_payload[:subscription][:endpoint]).to_return(status: 200)\n\n        post :create, format: :json, params: create_payload.merge(alerts_payload)\n\n        push_subscription = Web::PushSubscription.find_by(endpoint: create_payload[:subscription][:endpoint])\n\n        expect(push_subscription.data['alerts']['follow']).to eq(alerts_payload[:data][:alerts][:follow].to_s)\n        expect(push_subscription.data['alerts']['favourite']).to eq(alerts_payload[:data][:alerts][:favourite].to_s)\n        expect(push_subscription.data['alerts']['reblog']).to eq(alerts_payload[:data][:alerts][:reblog].to_s)\n        expect(push_subscription.data['alerts']['mention']).to eq(alerts_payload[:data][:alerts][:mention].to_s)\n      end\n    end\n  end\n\n  describe 'PUT #update' do\n    it 'changes alert settings' do\n      sign_in(user)\n\n      stub_request(:post, create_payload[:subscription][:endpoint]).to_return(status: 200)\n\n      post :create, format: :json, params: create_payload\n\n      alerts_payload[:id] = Web::PushSubscription.find_by(endpoint: create_payload[:subscription][:endpoint]).id\n\n      put :update, format: :json, params: alerts_payload\n\n      push_subscription = Web::PushSubscription.find_by(endpoint: create_payload[:subscription][:endpoint])\n\n      expect(push_subscription.data['alerts']['follow']).to eq(alerts_payload[:data][:alerts][:follow].to_s)\n      expect(push_subscription.data['alerts']['favourite']).to eq(alerts_payload[:data][:alerts][:favourite].to_s)\n      expect(push_subscription.data['alerts']['reblog']).to eq(alerts_payload[:data][:alerts][:reblog].to_s)\n      expect(push_subscription.data['alerts']['mention']).to eq(alerts_payload[:data][:alerts][:mention].to_s)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/api/web/settings_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe Api::Web::SettingsController do\n  render_views\n\n  let!(:user) { Fabricate(:user) }\n\n  describe 'PATCH #update' do\n    it 'redirects to about page' do\n      sign_in(user)\n      patch :update, format: :json, params: { data: { 'onboarded' => true } }\n\n      user.reload\n      expect(response).to have_http_status(200)\n      expect(user_web_setting.data['onboarded']).to eq('true')\n    end\n\n    def user_web_setting\n      Web::Setting.where(user: user).first\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/application_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe ApplicationController, type: :controller do\n  controller do\n    def success\n      head 200\n    end\n\n    def routing_error\n      raise ActionController::RoutingError, ''\n    end\n\n    def record_not_found\n      raise ActiveRecord::RecordNotFound, ''\n    end\n\n    def invalid_authenticity_token\n      raise ActionController::InvalidAuthenticityToken, ''\n    end\n  end\n\n  shared_examples 'respond_with_error' do |code|\n    it \"returns http #{code} for any\" do\n      subject\n      expect(response).to have_http_status(code)\n    end\n\n    it \"returns http #{code} for http\" do\n      subject\n      expect(response).to have_http_status(code)\n    end\n\n    it \"renders template for http\" do\n      is_expected.to render_template(\"errors/#{code}\", layout: 'error')\n    end\n  end\n\n  context 'forgery' do\n    subject do\n      ActionController::Base.allow_forgery_protection = true\n      routes.draw { post 'success' => 'anonymous#success' }\n      post 'success'\n    end\n\n    include_examples 'respond_with_error', 422\n  end\n\n  it \"does not force ssl if Rails.env.production? is not 'true'\" do\n    routes.draw { get 'success' => 'anonymous#success' }\n    allow(Rails.env).to receive(:production?).and_return(false)\n    get 'success'\n    expect(response).to have_http_status(200)\n  end\n\n  it \"forces ssl if Rails.env.production? is 'true'\" do\n    routes.draw { get 'success' => 'anonymous#success' }\n    allow(Rails.env).to receive(:production?).and_return(true)\n    get 'success'\n    expect(response).to redirect_to('https://test.host/success')\n  end\n\n  describe 'helper_method :current_account' do\n    it 'returns nil if not signed in' do\n      expect(controller.view_context.current_account).to be_nil\n    end\n\n    it 'returns account if signed in' do\n      account = Fabricate(:account)\n      sign_in(Fabricate(:user, account: account))\n      expect(controller.view_context.current_account).to eq account\n    end\n  end\n\n  describe 'helper_method :single_user_mode?' do\n    it 'returns false if it is in single_user_mode but there is no account' do\n      allow(Rails.configuration.x).to receive(:single_user_mode).and_return(true)\n      expect(controller.view_context.single_user_mode?).to eq false\n    end\n\n    it 'returns false if there is an account but it is not in single_user_mode' do\n      allow(Rails.configuration.x).to receive(:single_user_mode).and_return(false)\n      Fabricate(:account)\n      expect(controller.view_context.single_user_mode?).to eq false\n    end\n\n    it 'returns true if it is in single_user_mode and there is an account' do\n      allow(Rails.configuration.x).to receive(:single_user_mode).and_return(true)\n      Fabricate(:account)\n      expect(controller.view_context.single_user_mode?).to eq true\n    end\n  end\n\n  describe 'helper_method :current_theme' do\n    it 'returns \"default\" when theme wasn\\'t changed in admin settings' do\n      allow(Setting).to receive(:default_settings).and_return({ 'theme' => 'default' })\n\n      expect(controller.view_context.current_theme).to eq 'default'\n    end\n\n    it 'returns instances\\'s theme when user is not signed in' do\n      allow(Setting).to receive(:[]).with('theme').and_return 'contrast'\n\n      expect(controller.view_context.current_theme).to eq 'contrast'\n    end\n\n    it 'returns instances\\'s default theme when user didn\\'t set theme' do\n      current_user = Fabricate(:user)\n      sign_in current_user\n\n      allow(Setting).to receive(:[]).with('theme').and_return 'contrast'\n\n      expect(controller.view_context.current_theme).to eq 'contrast'\n    end\n\n    it 'returns user\\'s theme when it is set' do\n      current_user = Fabricate(:user)\n      current_user.settings['theme'] = 'mastodon-light'\n      sign_in current_user\n\n      allow(Setting).to receive(:[]).with('theme').and_return 'contrast'\n\n      expect(controller.view_context.current_theme).to eq 'mastodon-light'\n    end\n  end\n\n  context 'ActionController::RoutingError' do\n    subject do\n      routes.draw { get 'routing_error' => 'anonymous#routing_error' }\n      get 'routing_error'\n    end\n\n    include_examples 'respond_with_error', 404\n  end\n\n  context 'ActiveRecord::RecordNotFound' do\n    subject do\n      routes.draw { get 'record_not_found' => 'anonymous#record_not_found' }\n      get 'record_not_found'\n    end\n\n    include_examples 'respond_with_error', 404\n  end\n\n  context 'ActionController::InvalidAuthenticityToken' do\n    subject do\n      routes.draw { get 'invalid_authenticity_token' => 'anonymous#invalid_authenticity_token' }\n      get 'invalid_authenticity_token'\n    end\n\n    include_examples 'respond_with_error', 422\n  end\n\n  describe 'before_action :store_current_location' do\n    it 'stores location for user if it is not devise controller' do\n      routes.draw { get 'success' => 'anonymous#success' }\n      get 'success'\n      expect(controller.stored_location_for(:user)).to eq '/success'\n    end\n\n    context do\n      controller Devise::SessionsController do\n      end\n\n      it 'does not store location for user if it is devise controller' do\n        @request.env[\"devise.mapping\"] = Devise.mappings[:user]\n        get 'create'\n        expect(controller.stored_location_for(:user)).to be_nil\n      end\n    end\n  end\n\n  describe 'before_action :check_suspension' do\n    before do\n      routes.draw { get 'success' => 'anonymous#success' }\n    end\n\n    it 'does nothing if not signed in' do\n      get 'success'\n      expect(response).to have_http_status(200)\n    end\n\n    it 'does nothing if user who signed in is not suspended' do\n      sign_in(Fabricate(:user, account: Fabricate(:account, suspended: false)))\n      get 'success'\n      expect(response).to have_http_status(200)\n    end\n\n    it 'returns http 403 if user who signed in is suspended' do\n      sign_in(Fabricate(:user, account: Fabricate(:account, suspended: true)))\n      get 'success'\n      expect(response).to have_http_status(403)\n    end\n  end\n\n  describe 'raise_not_found' do\n    it 'raises error' do\n      controller.params[:unmatched_route] = 'unmatched'\n      expect { controller.raise_not_found }.to raise_error(ActionController::RoutingError, 'No route matches unmatched')\n    end\n  end\n\n  describe 'require_admin!' do\n    controller do\n      before_action :require_admin!\n\n      def sucesss\n        head 200\n      end\n    end\n\n    before do\n      routes.draw { get 'sucesss' => 'anonymous#sucesss' }\n    end\n\n    it 'returns a 403 if current user is not admin' do\n      sign_in(Fabricate(:user, admin: false))\n      get 'sucesss'\n      expect(response).to have_http_status(403)\n    end\n\n    it 'returns a 403 if current user is only a moderator' do\n      sign_in(Fabricate(:user, moderator: true))\n      get 'sucesss'\n      expect(response).to have_http_status(403)\n    end\n\n    it 'does nothing if current user is admin' do\n      sign_in(Fabricate(:user, admin: true))\n      get 'sucesss'\n      expect(response).to have_http_status(200)\n    end\n  end\n\n  describe 'require_staff!' do\n    controller do\n      before_action :require_staff!\n\n      def sucesss\n        head 200\n      end\n    end\n\n    before do\n      routes.draw { get 'sucesss' => 'anonymous#sucesss' }\n    end\n\n    it 'returns a 403 if current user is not admin or moderator' do\n      sign_in(Fabricate(:user, admin: false, moderator: false))\n      get 'sucesss'\n      expect(response).to have_http_status(403)\n    end\n\n    it 'does nothing if current user is moderator' do\n      sign_in(Fabricate(:user, moderator: true))\n      get 'sucesss'\n      expect(response).to have_http_status(200)\n    end\n\n    it 'does nothing if current user is admin' do\n      sign_in(Fabricate(:user, admin: true))\n      get 'sucesss'\n      expect(response).to have_http_status(200)\n    end\n  end\n\n  describe 'forbidden' do\n    controller do\n      def route_forbidden\n        forbidden\n      end\n    end\n\n    subject do\n      routes.draw { get 'route_forbidden' => 'anonymous#route_forbidden' }\n      get 'route_forbidden'\n    end\n\n    include_examples 'respond_with_error', 403\n  end\n\n  describe 'not_found' do\n    controller do\n      def route_not_found\n        not_found\n      end\n    end\n\n    subject do\n      routes.draw { get 'route_not_found' => 'anonymous#route_not_found' }\n      get 'route_not_found'\n    end\n\n    include_examples 'respond_with_error', 404\n  end\n\n  describe 'gone' do\n    controller do\n      def route_gone\n        gone\n      end\n    end\n\n    subject do\n      routes.draw { get 'route_gone' => 'anonymous#route_gone' }\n      get 'route_gone'\n    end\n\n    include_examples 'respond_with_error', 410\n  end\n\n  describe 'unprocessable_entity' do\n    controller do\n      def route_unprocessable_entity\n        unprocessable_entity\n      end\n    end\n\n    subject do\n      routes.draw { get 'route_unprocessable_entity' => 'anonymous#route_unprocessable_entity' }\n      get 'route_unprocessable_entity'\n    end\n\n    include_examples 'respond_with_error', 422\n  end\n\n  describe 'cache_collection' do\n    class C < ApplicationController\n      public :cache_collection\n    end\n\n    shared_examples 'receives :with_includes' do |fabricator, klass|\n      it 'uses raw if it is not an ActiveRecord::Relation' do\n        record = Fabricate(fabricator)\n        expect(C.new.cache_collection([record], klass)).to eq [record]\n      end\n    end\n\n    shared_examples 'cacheable' do |fabricator, klass|\n      include_examples 'receives :with_includes', fabricator, klass\n\n      it 'calls cache_ids of raw if it is an ActiveRecord::Relation' do\n        record = Fabricate(fabricator)\n        relation = klass.none\n        allow(relation).to receive(:cache_ids).and_return([record])\n        expect(C.new.cache_collection(relation, klass)).to eq [record]\n      end\n    end\n\n    it 'returns raw unless class responds to :with_includes' do\n      raw = Object.new\n      expect(C.new.cache_collection(raw, Object)).to eq raw\n    end\n\n    context 'Notification' do\n      include_examples 'cacheable', :notification, Notification\n    end\n\n    context 'Status' do\n      include_examples 'cacheable', :status, Status\n    end\n\n    context 'StreamEntry' do\n      include_examples 'receives :with_includes', :stream_entry, StreamEntry\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/auth/confirmations_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe Auth::ConfirmationsController, type: :controller do\n  render_views\n\n  describe 'GET #new' do\n    it 'returns http success' do\n      @request.env['devise.mapping'] = Devise.mappings[:user]\n      get :new\n      expect(response).to have_http_status(200)\n    end\n  end\n\n  describe 'GET #show' do\n    context 'when user is unconfirmed' do\n      let!(:user) { Fabricate(:user, confirmation_token: 'foobar', confirmed_at: nil) }\n\n      before do\n        allow(BootstrapTimelineWorker).to receive(:perform_async)\n        @request.env['devise.mapping'] = Devise.mappings[:user]\n        get :show, params: { confirmation_token: 'foobar' }\n      end\n\n      it 'redirects to login' do\n        expect(response).to redirect_to(new_user_session_path)\n      end\n\n      it 'queues up bootstrapping of home timeline' do\n        expect(BootstrapTimelineWorker).to have_received(:perform_async).with(user.account_id)\n      end\n    end\n\n    context 'when user is updating email' do\n      let!(:user) { Fabricate(:user, confirmation_token: 'foobar', unconfirmed_email: 'new-email@example.com') }\n\n      before do\n        allow(BootstrapTimelineWorker).to receive(:perform_async)\n        @request.env['devise.mapping'] = Devise.mappings[:user]\n        get :show, params: { confirmation_token: 'foobar' }\n      end\n\n      it 'redirects to login' do\n        expect(response).to redirect_to(new_user_session_path)\n      end\n\n      it 'does not queue up bootstrapping of home timeline' do\n        expect(BootstrapTimelineWorker).to_not have_received(:perform_async)\n      end\n    end\n  end\n\n  describe 'GET #finish_signup' do\n    subject { get :finish_signup }\n\n    let(:user) { Fabricate(:user) }\n    before do\n      sign_in user, scope: :user\n      @request.env['devise.mapping'] = Devise.mappings[:user]\n    end\n\n    it 'renders finish_signup' do\n      is_expected.to render_template :finish_signup\n      expect(assigns(:user)).to have_attributes id: user.id\n    end\n  end\n\n  describe 'PATCH #finish_signup' do\n    subject { patch :finish_signup, params: { user: { email: email } } }\n\n    let(:user) { Fabricate(:user) }\n    before do\n      sign_in user, scope: :user\n      @request.env['devise.mapping'] = Devise.mappings[:user]\n    end\n\n    context 'when email is valid' do\n      let(:email) { 'new_' + user.email }\n\n      it 'redirects to root_path' do\n        is_expected.to redirect_to root_path\n      end\n    end\n\n    context 'when email is invalid' do\n      let(:email) { '' }\n\n      it 'renders finish_signup' do\n        is_expected.to render_template :finish_signup\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/auth/passwords_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe Auth::PasswordsController, type: :controller do\n  include Devise::Test::ControllerHelpers\n\n  describe 'GET #new' do\n    it 'returns http success' do\n      @request.env['devise.mapping'] = Devise.mappings[:user]\n      get :new\n      expect(response).to have_http_status(200)\n    end\n  end\n\n  describe 'GET #edit' do\n    let(:user) { Fabricate(:user) }\n\n    before do\n      request.env['devise.mapping'] = Devise.mappings[:user]\n      @token = user.send_reset_password_instructions\n    end\n\n    context 'with valid reset_password_token' do\n      it 'returns http success' do\n        get :edit, params: { reset_password_token: @token }\n        expect(response).to have_http_status(200)\n      end\n    end\n\n    context 'with invalid reset_password_token' do\n      it 'redirects to #new' do\n        get :edit, params: { reset_password_token: 'some_invalid_value' }\n        expect(response).to redirect_to subject.new_password_path(subject.send(:resource_name))\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/auth/registrations_controller_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Auth::RegistrationsController, type: :controller do\n  render_views\n\n  shared_examples 'checks for enabled registrations' do |path|\n    around do |example|\n      registrations_mode = Setting.registrations_mode\n      example.run\n      Setting.registrations_mode = registrations_mode\n    end\n\n    it 'redirects if it is in single user mode while it is open for registration' do\n      Fabricate(:account)\n      Setting.registrations_mode = 'open'\n      expect(Rails.configuration.x).to receive(:single_user_mode).and_return(true)\n\n      get path\n\n      expect(response).to redirect_to '/'\n    end\n\n    it 'redirects if it is not open for registration while it is not in single user mode' do\n      Setting.registrations_mode = 'none'\n      expect(Rails.configuration.x).to receive(:single_user_mode).and_return(false)\n\n      get path\n\n      expect(response).to redirect_to '/'\n    end\n  end\n\n  describe 'GET #edit' do\n    it 'returns http success' do\n      request.env[\"devise.mapping\"] = Devise.mappings[:user]\n      sign_in(Fabricate(:user))\n      get :edit\n      expect(response).to have_http_status(200)\n    end\n  end\n\n  describe 'GET #update' do\n    it 'returns http success' do\n      request.env[\"devise.mapping\"] = Devise.mappings[:user]\n      sign_in(Fabricate(:user), scope: :user)\n      post :update\n      expect(response).to have_http_status(200)\n    end\n  end\n\n  describe 'GET #new' do\n    before do\n      request.env[\"devise.mapping\"] = Devise.mappings[:user]\n    end\n\n    context do\n      around do |example|\n        registrations_mode = Setting.registrations_mode\n        example.run\n        Setting.registrations_mode = registrations_mode\n      end\n\n      it 'returns http success' do\n        Setting.registrations_mode = 'open'\n        get :new\n        expect(response).to have_http_status(200)\n      end\n    end\n\n    include_examples 'checks for enabled registrations', :new\n  end\n\n  describe 'POST #create' do\n    let(:accept_language) { Rails.application.config.i18n.available_locales.sample.to_s }\n\n    around do |example|\n      current_locale = I18n.locale\n      example.run\n      I18n.locale = current_locale\n    end\n\n    before { request.env[\"devise.mapping\"] = Devise.mappings[:user] }\n\n    context do\n      around do |example|\n        registrations_mode = Setting.registrations_mode\n        example.run\n        Setting.registrations_mode = registrations_mode\n      end\n\n      subject do\n        Setting.registrations_mode = 'open'\n        request.headers[\"Accept-Language\"] = accept_language\n        post :create, params: { user: { account_attributes: { username: 'test' }, email: 'test@example.com', password: '12345678', password_confirmation: '12345678' } }\n      end\n\n      it 'redirects to login page' do\n        subject\n        expect(response).to redirect_to new_user_session_path\n      end\n\n      it 'creates user' do\n        subject\n        user = User.find_by(email: 'test@example.com')\n        expect(user).to_not be_nil\n        expect(user.locale).to eq(accept_language)\n      end\n    end\n\n    context 'approval-based registrations without invite' do\n      around do |example|\n        registrations_mode = Setting.registrations_mode\n        example.run\n        Setting.registrations_mode = registrations_mode\n      end\n\n      subject do\n        Setting.registrations_mode = 'approved'\n        request.headers[\"Accept-Language\"] = accept_language\n        post :create, params: { user: { account_attributes: { username: 'test' }, email: 'test@example.com', password: '12345678', password_confirmation: '12345678' } }\n      end\n\n      it 'redirects to login page' do\n        subject\n        expect(response).to redirect_to new_user_session_path\n      end\n\n      it 'creates user' do\n        subject\n        user = User.find_by(email: 'test@example.com')\n        expect(user).to_not be_nil\n        expect(user.locale).to eq(accept_language)\n        expect(user.approved).to eq(false)\n      end\n    end\n\n    context 'approval-based registrations with expired invite' do\n      around do |example|\n        registrations_mode = Setting.registrations_mode\n        example.run\n        Setting.registrations_mode = registrations_mode\n      end\n\n      subject do\n        Setting.registrations_mode = 'approved'\n        request.headers[\"Accept-Language\"] = accept_language\n        invite = Fabricate(:invite, max_uses: nil, expires_at: 1.hour.ago)\n        post :create, params: { user: { account_attributes: { username: 'test' }, email: 'test@example.com', password: '12345678', password_confirmation: '12345678', 'invite_code': invite.code } }\n      end\n\n      it 'redirects to login page' do\n        subject\n        expect(response).to redirect_to new_user_session_path\n      end\n\n      it 'creates user' do\n        subject\n        user = User.find_by(email: 'test@example.com')\n        expect(user).to_not be_nil\n        expect(user.locale).to eq(accept_language)\n        expect(user.approved).to eq(false)\n      end\n    end\n\n    context 'approval-based registrations with valid invite' do\n      around do |example|\n        registrations_mode = Setting.registrations_mode\n        example.run\n        Setting.registrations_mode = registrations_mode\n      end\n\n      subject do\n        Setting.registrations_mode = 'approved'\n        request.headers[\"Accept-Language\"] = accept_language\n        invite = Fabricate(:invite, max_uses: nil, expires_at: 1.hour.from_now)\n        post :create, params: { user: { account_attributes: { username: 'test' }, email: 'test@example.com', password: '12345678', password_confirmation: '12345678', 'invite_code': invite.code } }\n      end\n\n      it 'redirects to login page' do\n        subject\n        expect(response).to redirect_to new_user_session_path\n      end\n\n      it 'creates user' do\n        subject\n        user = User.find_by(email: 'test@example.com')\n        expect(user).to_not be_nil\n        expect(user.locale).to eq(accept_language)\n        expect(user.approved).to eq(true)\n      end\n    end\n\n    it 'does nothing if user already exists' do\n      Fabricate(:user, account: Fabricate(:account, username: 'test'))\n      subject\n    end\n\n    include_examples 'checks for enabled registrations', :create\n  end\n\n  describe 'DELETE #destroy' do\n    let(:user) { Fabricate(:user) }\n\n    before do\n      request.env['devise.mapping'] = Devise.mappings[:user]\n      sign_in(user, scope: :user)\n      delete :destroy\n    end\n\n    it 'returns http not found' do\n      expect(response).to have_http_status(:not_found)\n    end\n\n    it 'does not delete user' do\n      expect(User.find(user.id)).to_not be_nil\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/auth/sessions_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe Auth::SessionsController, type: :controller do\n  render_views\n\n  describe 'GET #new' do\n    before do\n      request.env['devise.mapping'] = Devise.mappings[:user]\n    end\n\n    it 'returns http success' do\n      get :new\n      expect(response).to have_http_status(200)\n    end\n  end\n\n  describe 'DELETE #destroy' do\n    let(:user) { Fabricate(:user) }\n\n    before do\n      request.env['devise.mapping'] = Devise.mappings[:user]\n    end\n\n    context 'with a regular user' do\n      it 'redirects to home after sign out' do\n        sign_in(user, scope: :user)\n        delete :destroy\n\n        expect(response).to redirect_to(new_user_session_path)\n      end\n\n      it 'does not delete redirect location with continue=true' do\n        sign_in(user, scope: :user)\n        controller.store_location_for(:user, '/authorize')\n        delete :destroy, params: { continue: 'true' }\n        expect(controller.stored_location_for(:user)).to eq '/authorize'\n      end\n    end\n\n    context 'with a suspended user' do\n      it 'redirects to home after sign out' do\n        Fabricate(:account, user: user, suspended: true)\n        sign_in(user, scope: :user)\n        delete :destroy\n\n        expect(response).to redirect_to(new_user_session_path)\n      end\n    end\n  end\n\n  describe 'POST #create' do\n    before do\n      request.env['devise.mapping'] = Devise.mappings[:user]\n    end\n\n    context 'using PAM authentication', if: ENV['PAM_ENABLED'] == 'true' do\n      context 'using a valid password' do\n        before do\n          post :create, params: { user: { email: \"pam_user1\", password: '123456' } }\n        end\n\n        it 'redirects to home' do\n          expect(response).to redirect_to(root_path)\n        end\n\n        it 'logs the user in' do\n          expect(controller.current_user).to be_instance_of(User)\n        end\n      end\n\n      context 'using an invalid password' do\n        before do\n          post :create, params: { user: { email: \"pam_user1\", password: 'WRONGPW' } }\n        end\n\n        it 'shows a login error' do\n          expect(flash[:alert]).to match I18n.t('devise.failure.invalid', authentication_keys: 'Email')\n        end\n\n        it \"doesn't log the user in\" do\n          expect(controller.current_user).to be_nil\n        end\n      end\n\n      context 'using a valid email and existing user' do\n        let(:user) do\n          account = Fabricate.build(:account, username: 'pam_user1')\n          account.save!(validate: false)\n          user = Fabricate(:user, email: 'pam@example.com', password: nil, account: account)\n          user\n        end\n\n        before do\n          post :create, params: { user: { email: user.email, password: '123456' } }\n        end\n\n        it 'redirects to home' do\n          expect(response).to redirect_to(root_path)\n        end\n\n        it 'logs the user in' do\n          expect(controller.current_user).to eq user\n        end\n      end\n    end\n\n    context 'using password authentication' do\n      let(:user) { Fabricate(:user, email: 'foo@bar.com', password: 'abcdefgh') }\n\n      context 'using a valid password' do\n        before do\n          post :create, params: { user: { email: user.email, password: user.password } }\n        end\n\n        it 'redirects to home' do\n          expect(response).to redirect_to(root_path)\n        end\n\n        it 'logs the user in' do\n          expect(controller.current_user).to eq user\n        end\n      end\n\n      context 'using email with uppercase letters' do\n        before do\n          post :create, params: { user: { email: user.email.upcase, password: user.password } }\n        end\n\n        it 'redirects to home' do\n          expect(response).to redirect_to(root_path)\n        end\n\n        it 'logs the user in' do\n          expect(controller.current_user).to eq user\n        end\n      end\n\n      context 'using an invalid password' do\n        before do\n          post :create, params: { user: { email: user.email, password: 'wrongpw' } }\n        end\n\n        it 'shows a login error' do\n          expect(flash[:alert]).to match I18n.t('devise.failure.invalid', authentication_keys: 'Email')\n        end\n\n        it \"doesn't log the user in\" do\n          expect(controller.current_user).to be_nil\n        end\n      end\n\n      context 'using an unconfirmed password' do\n        before do\n          request.headers['Accept-Language'] = accept_language\n          post :create, params: { user: { email: unconfirmed_user.email, password: unconfirmed_user.password } }\n        end\n\n        let(:unconfirmed_user) { user.tap { |u| u.update!(confirmed_at: nil) } }\n        let(:accept_language) { 'fr' }\n\n        it 'shows a translated login error' do\n          expect(flash[:alert]).to eq(I18n.t('devise.failure.unconfirmed', locale: accept_language))\n        end\n      end\n\n      context \"logging in from the user's page\" do\n        before do\n          allow(controller).to receive(:single_user_mode?).and_return(single_user_mode)\n          allow(controller).to receive(:stored_location_for).with(:user).and_return(\"/@#{user.account.username}\")\n          post :create, params: { user: { email: user.email, password: user.password } }\n        end\n\n        context \"in single user mode\" do\n          let(:single_user_mode) { true }\n\n          it 'redirects to home' do\n            expect(response).to redirect_to(root_path)\n          end\n        end\n\n        context \"in non-single user mode\" do\n          let(:single_user_mode) { false }\n\n          it \"redirects back to the user's page\" do\n            expect(response).to redirect_to(short_account_path(username: user.account))\n          end\n        end\n      end\n    end\n\n    context 'using two-factor authentication' do\n      let(:user) do\n        Fabricate(:user, email: 'x@y.com', password: 'abcdefgh',\n                         otp_required_for_login: true, otp_secret: User.generate_otp_secret(32))\n      end\n      let(:recovery_codes) do\n        codes = user.generate_otp_backup_codes!\n        user.save\n        return codes\n      end\n\n      context 'using email and password' do\n        before do\n          post :create, params: { user: { email: user.email, password: user.password } }\n        end\n\n        it 'renders two factor authentication page' do\n          expect(controller).to render_template(\"two_factor\")\n        end\n      end\n\n      context 'using upcase email and password' do\n        before do\n          post :create, params: { user: { email: user.email.upcase, password: user.password } }\n        end\n\n        it 'renders two factor authentication page' do\n          expect(controller).to render_template(\"two_factor\")\n        end\n      end\n\n      context 'using a valid OTP' do\n        before do\n          post :create, params: { user: { otp_attempt: user.current_otp } }, session: { otp_user_id: user.id }\n        end\n\n        it 'redirects to home' do\n          expect(response).to redirect_to(root_path)\n        end\n\n        it 'logs the user in' do\n          expect(controller.current_user).to eq user\n        end\n      end\n\n      context 'when the server has an decryption error' do\n        before do\n          allow_any_instance_of(User).to receive(:validate_and_consume_otp!).and_raise(OpenSSL::Cipher::CipherError)\n          post :create, params: { user: { otp_attempt: user.current_otp } }, session: { otp_user_id: user.id }\n        end\n\n        it 'shows a login error' do\n          expect(flash[:alert]).to match I18n.t('users.invalid_otp_token')\n        end\n\n        it \"doesn't log the user in\" do\n          expect(controller.current_user).to be_nil\n        end\n      end\n\n      context 'using a valid recovery code' do\n        before do\n          post :create, params: { user: { otp_attempt: recovery_codes.first } }, session: { otp_user_id: user.id }\n        end\n\n        it 'redirects to home' do\n          expect(response).to redirect_to(root_path)\n        end\n\n        it 'logs the user in' do\n          expect(controller.current_user).to eq user\n        end\n      end\n\n      context 'using an invalid OTP' do\n        before do\n          post :create, params: { user: { otp_attempt: 'wrongotp' } }, session: { otp_user_id: user.id }\n        end\n\n        it 'shows a login error' do\n          expect(flash[:alert]).to match I18n.t('users.invalid_otp_token')\n        end\n\n        it \"doesn't log the user in\" do\n          expect(controller.current_user).to be_nil\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/authorize_interactions_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe AuthorizeInteractionsController do\n  render_views\n\n  describe 'GET #show' do\n    describe 'when signed out' do\n      it 'redirects to sign in page' do\n        get :show\n\n        expect(response).to redirect_to(new_user_session_path)\n      end\n    end\n\n    describe 'when signed in' do\n      let(:user) { Fabricate(:user) }\n      let(:account) { Fabricate(:account, user: user) }\n\n      before do\n        sign_in(user)\n      end\n\n      it 'renders error without acct param' do\n        get :show\n\n        expect(response).to render_template(:error)\n      end\n\n      it 'renders error when account cant be found' do\n        service = double\n        allow(ResolveAccountService).to receive(:new).and_return(service)\n        allow(service).to receive(:call).with('missing@hostname').and_return(nil)\n\n        get :show, params: { acct: 'acct:missing@hostname' }\n\n        expect(response).to render_template(:error)\n        expect(service).to have_received(:call).with('missing@hostname')\n      end\n\n      it 'sets resource from url' do\n        account = Account.new\n        service = double\n        allow(ResolveURLService).to receive(:new).and_return(service)\n        allow(service).to receive(:call).with('http://example.com').and_return(account)\n\n        get :show, params: { acct: 'http://example.com' }\n\n        expect(response).to have_http_status(200)\n        expect(assigns(:resource)).to eq account\n      end\n\n      it 'sets resource from acct uri' do\n        account = Account.new\n        service = double\n        allow(ResolveAccountService).to receive(:new).and_return(service)\n        allow(service).to receive(:call).with('found@hostname').and_return(account)\n\n        get :show, params: { acct: 'acct:found@hostname' }\n\n        expect(response).to have_http_status(200)\n        expect(assigns(:resource)).to eq account\n      end\n    end\n  end\n\n  describe 'POST #create' do\n    describe 'when signed out' do\n      it 'redirects to sign in page' do\n        post :create\n\n        expect(response).to redirect_to(new_user_session_path)\n      end\n    end\n\n    describe 'when signed in' do\n      let!(:user) { Fabricate(:user) }\n      let!(:account) { user.account }\n\n      before do\n        sign_in(user)\n      end\n\n      it 'shows error when account not found' do\n        service = double\n\n        allow(ResolveAccountService).to receive(:new).and_return(service)\n        allow(service).to receive(:call).with('user@hostname').and_return(nil)\n\n        post :create, params: { acct: 'acct:user@hostname' }\n\n        expect(response).to render_template(:error)\n      end\n\n      it 'follows account when found' do\n        target_account = Fabricate(:account)\n        service = double\n\n        allow(ResolveAccountService).to receive(:new).and_return(service)\n        allow(service).to receive(:call).with('user@hostname').and_return(target_account)\n        allow(service).to receive(:call).with(target_account, skip_webfinger: true).and_return(target_account)\n\n\n        post :create, params: { acct: 'acct:user@hostname' }\n\n        expect(service).to have_received(:call).with(target_account, skip_webfinger: true)\n        expect(account.following?(target_account)).to be true\n        expect(response).to render_template(:success)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/concerns/account_controller_concern_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe ApplicationController, type: :controller do\n  controller do\n    include AccountControllerConcern\n\n    def success\n      head 200\n    end\n  end\n\n  before do\n    routes.draw { get 'success' => 'anonymous#success' }\n  end\n\n  context 'when account is suspended' do\n    it 'returns http gone' do\n      account = Fabricate(:account, suspended: true, user: Fabricate(:user))\n      get 'success', params: { account_username: account.username }\n      expect(response).to have_http_status(410)\n    end\n  end\n\n  context 'when account is deleted by owner' do\n    it 'returns http gone' do\n      account = Fabricate(:account, suspended: true, user: nil)\n      get 'success', params: { account_username: account.username }\n      expect(response).to have_http_status(410)\n    end\n  end\n\n  context 'when account is not suspended' do\n    it 'assigns @account' do\n      account = Fabricate(:account, user: Fabricate(:user))\n      get 'success', params: { account_username: account.username }\n      expect(assigns(:account)).to eq account\n    end\n\n    it 'sets link headers' do\n      account = Fabricate(:account, username: 'username', user: Fabricate(:user))\n      get 'success', params: { account_username: 'username' }\n      expect(response.headers['Link'].to_s).to eq '<http://test.host/.well-known/webfinger?resource=acct%3Ausername%40cb6e6126.ngrok.io>; rel=\"lrdd\"; type=\"application/xrd+xml\", <http://test.host/users/username.atom>; rel=\"alternate\"; type=\"application/atom+xml\", <https://cb6e6126.ngrok.io/users/username>; rel=\"alternate\"; type=\"application/activity+json\"'\n    end\n\n    it 'returns http success' do\n      account = Fabricate(:account, user: Fabricate(:user))\n      get 'success', params: { account_username: account.username }\n      expect(response).to have_http_status(200)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/concerns/accountable_concern_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe AccountableConcern do\n  class Hoge\n    include AccountableConcern\n    attr_reader :current_account\n\n    def initialize(current_account)\n      @current_account = current_account\n    end\n  end\n\n  let(:user)   { Fabricate(:user, account: Fabricate(:account)) }\n  let(:target) { Fabricate(:user, account: Fabricate(:account)) }\n  let(:hoge)   { Hoge.new(user.account) }\n\n  describe '#log_action' do\n    it 'creates Admin::ActionLog' do\n      expect do\n        hoge.log_action(:create, target.account)\n      end.to change { Admin::ActionLog.count }.by(1)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/concerns/export_controller_concern_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe ApplicationController, type: :controller do\n  controller do\n    include ExportControllerConcern\n    def index\n      send_export_file\n    end\n\n    def export_data\n      @export.account.username\n    end\n  end\n\n  describe 'GET #index' do\n    it 'returns a csv of the exported data when signed in' do\n      user = Fabricate(:user)\n      sign_in user\n      get :index, format: :csv\n\n      expect(response).to have_http_status(200)\n      expect(response.content_type).to eq 'text/csv'\n      expect(response.headers['Content-Disposition']).to eq 'attachment; filename=\"anonymous.csv\"'\n      expect(response.body).to eq user.account.username\n    end\n\n    it 'returns unauthorized when not signed in' do\n      get :index, format: :csv\n      expect(response).to have_http_status(:unauthorized)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/concerns/localized_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe ApplicationController, type: :controller do\n  controller do\n    include Localized\n\n    def success\n      head 200\n    end\n  end\n\n  around do |example|\n    current_locale = I18n.locale\n    example.run\n    I18n.locale = current_locale\n  end\n\n  before do\n    routes.draw { get 'success' => 'anonymous#success' }\n  end\n\n  shared_examples 'default locale' do\n    it 'sets available and preferred language' do\n      request.headers['Accept-Language'] = 'ca-ES, fa'\n      get 'success'\n      expect(I18n.locale).to eq :fa\n    end\n\n    it 'sets available and compatible language if none of available languages are preferred' do\n      request.headers['Accept-Language'] = 'fa-IR'\n      get 'success'\n      expect(I18n.locale).to eq :fa\n    end\n\n    it 'sets default locale if none of available languages are compatible' do\n      request.headers['Accept-Language'] = ''\n      get 'success'\n      expect(I18n.locale).to eq :en\n    end\n  end\n\n  context 'user with valid locale has signed in' do\n    it \"sets user's locale\" do\n      user = Fabricate(:user, locale: :ca)\n\n      sign_in(user)\n      get 'success'\n\n      expect(I18n.locale).to eq :ca\n    end\n  end\n\n  context 'user with invalid locale has signed in' do\n    before do\n      user = Fabricate.build(:user, locale: :invalid)\n      user.save!(validate: false)\n      sign_in(user)\n    end\n\n    include_examples 'default locale'\n  end\n\n  context 'user has not signed in' do\n    include_examples 'default locale'\n  end\nend\n"
  },
  {
    "path": "spec/controllers/concerns/obfuscate_filename_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe ApplicationController, type: :controller do\n  controller do\n    include ObfuscateFilename\n\n    obfuscate_filename :file\n\n    def file\n      render plain: params[:file]&.original_filename\n    end\n  end\n\n  before do\n    routes.draw { get 'file' => 'anonymous#file' }\n  end\n\n  it 'obfusticates filename if the given parameter is specified' do\n    file = fixture_file_upload('files/imports.txt', 'text/plain')\n    post 'file', params: { file: file }\n    expect(response.body).to end_with '.txt'\n    expect(response.body).not_to include 'imports'\n  end\n\n  it 'does nothing if the given parameter is not specified' do\n    post 'file'\n  end\nend\n"
  },
  {
    "path": "spec/controllers/concerns/rate_limit_headers_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe ApplicationController do\n  controller do\n    include RateLimitHeaders\n\n    def show\n      head 200\n    end\n  end\n\n  before do\n    routes.draw { get 'show' => 'anonymous#show' }\n  end\n\n  describe 'rate limiting' do\n    context 'throttling is off' do\n      before do\n        request.env['rack.attack.throttle_data'] = nil\n      end\n\n      it 'does not apply rate limiting' do\n        get 'show'\n\n        expect(response.headers['X-RateLimit-Limit']).to be_nil\n        expect(response.headers['X-RateLimit-Remaining']).to be_nil\n        expect(response.headers['X-RateLimit-Reset']).to be_nil\n      end\n    end\n\n    context 'throttling is on' do\n      let(:start_time) { DateTime.new(2017, 1, 1, 12, 0, 0).utc }\n\n      before do\n        request.env['rack.attack.throttle_data'] = { 'throttle_authenticated_api' => { limit: 100, count: 20, period: 10 } }\n        travel_to start_time do\n          get 'show'\n        end\n      end\n\n      it 'applies rate limiting limit header' do\n        expect(response.headers['X-RateLimit-Limit']).to eq '100'\n      end\n\n      it 'applies rate limiting remaining header' do\n        expect(response.headers['X-RateLimit-Remaining']).to eq '80'\n      end\n\n      it 'applies rate limiting reset header' do\n        expect(response.headers['X-RateLimit-Reset']).to eq (start_time + 10.seconds).iso8601(6)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/concerns/signature_verification_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe ApplicationController, type: :controller do\n  controller do\n    include SignatureVerification\n\n    def success\n      head 200\n    end\n\n    def alternative_success\n      head 200\n    end\n  end\n\n  before do\n    routes.draw { match via: [:get, :post], 'success' => 'anonymous#success' }\n  end\n\n  context 'without signature header' do\n    before do\n      get :success\n    end\n\n    describe '#signed_request?' do\n      it 'returns false' do\n        expect(controller.signed_request?).to be false\n      end\n    end\n\n    describe '#signed_request_account' do\n      it 'returns nil' do\n        expect(controller.signed_request_account).to be_nil\n      end\n    end\n  end\n\n  context 'with signature header' do\n    let!(:author) { Fabricate(:account) }\n\n    context 'without body' do\n      before do\n        get :success\n\n        fake_request = Request.new(:get, request.url)\n        fake_request.on_behalf_of(author)\n\n        request.headers.merge!(fake_request.headers)\n      end\n\n      describe '#signed_request?' do\n        it 'returns true' do\n          expect(controller.signed_request?).to be true\n        end\n      end\n\n      describe '#signed_request_account' do\n        it 'returns an account' do\n          expect(controller.signed_request_account).to eq author\n        end\n\n        it 'returns nil when path does not match' do\n          request.path = '/alternative-path'\n          expect(controller.signed_request_account).to be_nil\n        end\n\n        it 'returns nil when method does not match' do\n          post :success\n          expect(controller.signed_request_account).to be_nil\n        end\n      end\n    end\n\n    context 'with request older than a day' do\n      before do\n        get :success\n\n        fake_request = Request.new(:get, request.url)\n        fake_request.add_headers({ 'Date' => 2.days.ago.utc.httpdate })\n        fake_request.on_behalf_of(author)\n\n        request.headers.merge!(fake_request.headers)\n      end\n\n      describe '#signed_request?' do\n        it 'returns true' do\n          expect(controller.signed_request?).to be true\n        end\n      end\n\n      describe '#signed_request_account' do\n        it 'returns nil' do\n          expect(controller.signed_request_account).to be_nil\n        end\n      end\n    end\n\n    context 'with body' do\n      before do\n        post :success, body: 'Hello world'\n\n        fake_request = Request.new(:post, request.url, body: 'Hello world')\n        fake_request.on_behalf_of(author)\n\n        request.headers.merge!(fake_request.headers)\n      end\n\n      describe '#signed_request?' do\n        it 'returns true' do\n          expect(controller.signed_request?).to be true\n        end\n      end\n\n      describe '#signed_request_account' do\n        it 'returns an account' do\n          expect(controller.signed_request_account).to eq author\n        end\n\n        it 'returns nil when path does not match' do\n          request.path = '/alternative-path'\n          expect(controller.signed_request_account).to be_nil\n        end\n\n        it 'returns nil when method does not match' do\n          get :success\n          expect(controller.signed_request_account).to be_nil\n        end\n\n        it 'returns nil when body has been tampered' do\n          post :success, body: 'doo doo doo'\n          expect(controller.signed_request_account).to be_nil\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/concerns/user_tracking_concern_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe ApplicationController, type: :controller do\n  controller do\n    include UserTrackingConcern\n\n    def show\n      render plain: 'show'\n    end\n  end\n\n  before do\n    routes.draw { get 'show' => 'anonymous#show' }\n  end\n\n  describe 'when signed in' do\n    let(:user) { Fabricate(:user) }\n\n    it 'does not track when there is a recent sign in' do\n      user.update(current_sign_in_at: 60.minutes.ago)\n      prior = user.current_sign_in_at\n      sign_in user, scope: :user\n      get :show\n\n      expect(user.reload.current_sign_in_at).to be_within(1.0).of(prior)\n    end\n\n    it 'tracks when sign in is nil' do\n      user.update(current_sign_in_at: nil)\n      sign_in user, scope: :user\n      get :show\n\n      expect_updated_sign_in_at(user)\n    end\n\n    it 'tracks when sign in is older than one day' do\n      user.update(current_sign_in_at: 2.days.ago)\n      sign_in user, scope: :user\n      get :show\n\n      expect_updated_sign_in_at(user)\n    end\n\n    describe 'feed regeneration' do\n      before do\n        alice = Fabricate(:account)\n        bob   = Fabricate(:account)\n\n        user.account.follow!(alice)\n        user.account.follow!(bob)\n\n        Fabricate(:status, account: alice, text: 'hello world')\n        Fabricate(:status, account: bob, text: 'yes hello')\n        Fabricate(:status, account: user.account, text: 'test')\n\n        user.update(last_sign_in_at: 'Tue, 04 Jul 2017 14:45:56 UTC +00:00', current_sign_in_at: 'Wed, 05 Jul 2017 22:10:52 UTC +00:00')\n\n        sign_in user, scope: :user\n      end\n\n      it 'sets a regeneration marker while regenerating' do\n        allow(RegenerationWorker).to receive(:perform_async)\n        get :show\n\n        expect_updated_sign_in_at(user)\n        expect(Redis.current.get(\"account:#{user.account_id}:regeneration\")).to eq 'true'\n        expect(RegenerationWorker).to have_received(:perform_async)\n      end\n\n      it 'sets the regeneration marker to expire' do\n        allow(RegenerationWorker).to receive(:perform_async)\n        get :show\n        expect(Redis.current.ttl(\"account:#{user.account_id}:regeneration\")).to be >= 0\n      end\n\n      it 'regenerates feed when sign in is older than two weeks' do\n        get :show\n\n        expect_updated_sign_in_at(user)\n        expect(Redis.current.zcard(FeedManager.instance.key(:home, user.account_id))).to eq 3\n        expect(Redis.current.get(\"account:#{user.account_id}:regeneration\")).to be_nil\n      end\n    end\n\n    def expect_updated_sign_in_at(user)\n      expect(user.reload.current_sign_in_at).to be_within(1.0).of(Time.now.utc)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/emojis_controller_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe EmojisController do\n  render_views\n\n  let(:emoji) { Fabricate(:custom_emoji) }\n\n  describe 'GET #show' do\n    subject(:response) { get :show, params: { id: emoji.id, format: :json } }\n    subject(:body) { JSON.parse(response.body, symbolize_names: true) }\n\n    it 'returns the right response' do\n      expect(response).to have_http_status 200\n      expect(body[:name]).to eq ':coolcat:'\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/follower_accounts_controller_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe FollowerAccountsController do\n  render_views\n\n  let(:alice) { Fabricate(:account, username: 'alice') }\n  let(:follower0) { Fabricate(:account) }\n  let(:follower1) { Fabricate(:account) }\n\n  describe 'GET #index' do\n    let!(:follow0) { follower0.follow!(alice) }\n    let!(:follow1) { follower1.follow!(alice) }\n\n    context 'when format is html' do\n      subject(:response) { get :index, params: { account_username: alice.username, format: :html } }\n\n      it 'assigns follows' do\n        expect(response).to have_http_status(200)\n\n        assigned = assigns(:follows).to_a\n        expect(assigned.size).to eq 2\n        expect(assigned[0]).to eq follow1\n        expect(assigned[1]).to eq follow0\n      end\n    end\n\n    context 'when format is json' do\n      subject(:response) { get :index, params: { account_username: alice.username, page: page, format: :json } }\n      subject(:body) { JSON.parse(response.body) }\n\n      context 'with page' do\n        let(:page) { 1 }\n\n        it 'returns followers' do\n          expect(response).to have_http_status(200)\n          expect(body['totalItems']).to eq 2\n          expect(body['partOf']).to be_present\n        end\n      end\n\n      context 'without page' do\n        let(:page) { nil }\n\n        it 'returns followers' do\n          expect(response).to have_http_status(200)\n          expect(body['totalItems']).to eq 2\n          expect(body['partOf']).to be_blank\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/following_accounts_controller_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe FollowingAccountsController do\n  render_views\n\n  let(:alice) { Fabricate(:account, username: 'alice') }\n  let(:followee0) { Fabricate(:account) }\n  let(:followee1) { Fabricate(:account) }\n\n  describe 'GET #index' do\n    let!(:follow0) { alice.follow!(followee0) }\n    let!(:follow1) { alice.follow!(followee1) }\n\n    context 'when format is html' do\n      subject(:response) { get :index, params: { account_username: alice.username, format: :html } }\n\n      it 'assigns follows' do\n        expect(response).to have_http_status(200)\n\n        assigned = assigns(:follows).to_a\n        expect(assigned.size).to eq 2\n        expect(assigned[0]).to eq follow1\n        expect(assigned[1]).to eq follow0\n      end\n    end\n\n    context 'when format is json' do\n      subject(:response) { get :index, params: { account_username: alice.username, page: page, format: :json } }\n      subject(:body) { JSON.parse(response.body) }\n\n      context 'with page' do\n        let(:page) { 1 }\n\n        it 'returns followers' do\n          expect(response).to have_http_status(200)\n          expect(body['totalItems']).to eq 2\n          expect(body['partOf']).to be_present\n        end\n      end\n\n      context 'without page' do\n        let(:page) { nil }\n\n        it 'returns followers' do\n          expect(response).to have_http_status(200)\n          expect(body['totalItems']).to eq 2\n          expect(body['partOf']).to be_blank\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/home_controller_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe HomeController, type: :controller do\n  render_views\n\n  describe 'GET #index' do\n    subject { get :index }\n\n    context 'when not signed in' do\n      context 'when requested path is tag timeline' do\n        before { @request.path = '/web/timelines/tag/name' }\n        it { is_expected.to redirect_to '/tags/name' }\n      end\n\n      it 'redirects to about page' do\n        @request.path = '/'\n        is_expected.to redirect_to(about_path)\n      end\n    end\n\n    context 'when signed in' do\n      let(:user) { Fabricate(:user) }\n\n      before { sign_in(user) }\n\n      it 'assigns @body_classes' do\n        subject\n        expect(assigns(:body_classes)).to eq 'app-body'\n      end\n\n      it 'assigns @initial_state_json' do\n        subject\n        initial_state_json = json_str_to_hash(assigns(:initial_state_json))\n        expect(initial_state_json[:meta]).to_not be_nil\n        expect(initial_state_json[:compose]).to_not be_nil\n        expect(initial_state_json[:accounts]).to_not be_nil\n        expect(initial_state_json[:settings]).to_not be_nil\n        expect(initial_state_json[:media_attachments]).to_not be_nil\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/intents_controller_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe IntentsController, type: :controller do\n  render_views\n\n  let(:user) { Fabricate(:user) }\n  before { sign_in user, scope: :user }\n\n  describe 'GET #show' do\n    subject { get :show, params: { uri: uri } }\n\n    context 'when schema is web+mastodon' do\n      context 'when host is follow' do\n        let(:uri) { 'web+mastodon://follow?uri=test' }\n\n        it { is_expected.to redirect_to authorize_interaction_path(uri: 'test') }\n      end\n\n      context 'when host is share' do\n        let(:uri) { 'web+mastodon://share?text=test' }\n\n        it { is_expected.to redirect_to share_path(text: 'test') }\n      end\n\n      context 'when host is none of the above' do\n        let(:uri) { 'web+mastodon://test' }\n\n        it { is_expected.to have_http_status 404 }\n      end\n    end\n\n    context 'when schema is not web+mastodon' do\n      let(:uri) { 'api+mastodon://test.com' }\n\n      it { is_expected.to have_http_status 404 }\n    end\n\n    context 'when uri param is blank' do\n      let(:uri) { '' }\n\n      it { is_expected.to have_http_status 404 }\n    end\n\n    context 'when uri is invalid' do\n      let(:uri) { 'invalid uri://test.com' }\n\n      it { is_expected.to have_http_status 404 }\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/invites_controller_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe InvitesController do\n  render_views\n\n  before do\n    sign_in user\n  end\n\n  around do |example|\n    min_invite_role = Setting.min_invite_role\n    example.run\n    Setting.min_invite_role = min_invite_role\n  end\n\n  describe 'GET #index' do\n    subject { get :index }\n\n    let(:user) { Fabricate(:user, moderator: false, admin: false) }\n    let!(:invite) { Fabricate(:invite, user: user) }\n\n    context 'when user is a staff' do\n      it 'renders index page' do\n        Setting.min_invite_role = 'user'\n        expect(subject).to render_template :index\n        expect(assigns(:invites)).to include invite\n        expect(assigns(:invites).count).to eq 1\n      end\n    end\n\n    context 'when user is not a staff' do\n      it 'returns 403' do\n        Setting.min_invite_role = 'modelator'\n        expect(subject).to have_http_status 403\n      end\n    end\n  end\n\n  describe 'POST #create' do\n    subject { post :create, params: { invite: { max_uses: '10', expires_in: 1800 } } }\n\n    context 'when user is an admin' do\n      let(:user) { Fabricate(:user, moderator: false, admin: true) }\n\n      it 'succeeds to create a invite' do\n        expect { subject }.to change { Invite.count }.by(1)\n        expect(subject).to redirect_to invites_path\n        expect(Invite.last).to have_attributes(user_id: user.id, max_uses: 10)\n      end\n    end\n\n    context 'when user is not an admin' do\n      let(:user) { Fabricate(:user, moderator: true, admin: false) }\n\n      it 'returns 403' do\n        expect(subject).to have_http_status 403\n      end\n    end\n  end\n\n  describe 'DELETE #create' do\n    subject { delete :destroy, params: { id: invite.id } }\n\n    let!(:invite) { Fabricate(:invite, user: user, expires_at: nil) }\n    let(:user) { Fabricate(:user, moderator: false, admin: true) }\n\n    it 'expires invite' do\n      expect(subject).to redirect_to invites_path\n      expect(invite.reload).to be_expired\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/manifests_controller_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe ManifestsController do\n  render_views\n\n  describe 'GET #show' do\n    before do\n      get :show, format: :json\n    end\n\n    it 'returns http success' do\n      expect(response).to have_http_status(200)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/media_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe MediaController do\n  render_views\n\n  describe '#show' do\n    it 'redirects to the file url when attached to a status' do\n      status = Fabricate(:status)\n      media_attachment = Fabricate(:media_attachment, status: status)\n      get :show, params: { id: media_attachment.to_param }\n\n      expect(response).to redirect_to(media_attachment.file.url(:original))\n    end\n\n    it 'responds with missing when there is not an attached status' do\n      media_attachment = Fabricate(:media_attachment, status: nil)\n      get :show, params: { id: media_attachment.to_param }\n\n      expect(response).to have_http_status(404)\n    end\n\n    it 'raises when shortcode cant be found' do\n      get :show, params: { id: 'missing' }\n\n      expect(response).to have_http_status(404)\n    end\n\n    it 'raises when not permitted to view' do\n      status = Fabricate(:status)\n      media_attachment = Fabricate(:media_attachment, status: status)\n      allow_any_instance_of(MediaController).to receive(:authorize).and_raise(ActiveRecord::RecordNotFound)\n      get :show, params: { id: media_attachment.to_param }\n\n      expect(response).to have_http_status(404)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/oauth/authorizations_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe Oauth::AuthorizationsController, type: :controller do\n  render_views\n\n  let(:app) { Doorkeeper::Application.create!(name: 'test', redirect_uri: 'http://localhost/', scopes: 'read') }\n\n  describe 'GET #new' do\n    subject do\n      get :new, params: { client_id: app.uid, response_type: 'code', redirect_uri: 'http://localhost/', scope: 'read' }\n    end\n\n    shared_examples 'stores location for user' do\n      it 'stores location for user' do\n        subject\n        expect(controller.stored_location_for(:user)).to eq \"/oauth/authorize?client_id=#{app.uid}&redirect_uri=http%3A%2F%2Flocalhost%2F&response_type=code&scope=read\"\n      end\n    end\n\n    context 'when signed in' do\n      let!(:user) { Fabricate(:user) }\n\n      before do\n        sign_in user, scope: :user\n      end\n\n      it 'returns http success' do\n        subject\n        expect(response).to have_http_status(200)\n      end\n\n      it 'gives options to authorize and deny' do\n        subject\n        expect(response.body).to match(/Authorize/)\n      end\n\n      include_examples 'stores location for user'\n\n      context 'when app is already authorized' do\n        before do\n          Doorkeeper::AccessToken.find_or_create_for(\n            app,\n            user.id,\n            app.scopes,\n            Doorkeeper.configuration.access_token_expires_in,\n            Doorkeeper.configuration.refresh_token_enabled?\n          )\n        end\n\n        it 'redirects to callback' do\n          subject\n          expect(response).to redirect_to(/\\A#{app.redirect_uri}/)\n        end\n\n        it 'does not redirect to callback with force_login=true' do\n          get :new, params: { client_id: app.uid, response_type: 'code', redirect_uri: 'http://localhost/', scope: 'read', force_login: 'true' }\n          expect(response.body).to match(/Authorize/)\n        end\n      end\n    end\n\n    context 'when not signed in' do\n      it 'redirects' do\n        subject\n        expect(response).to redirect_to '/auth/sign_in'\n      end\n\n      include_examples 'stores location for user'\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/oauth/authorized_applications_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe Oauth::AuthorizedApplicationsController do\n  render_views\n\n  describe 'GET #index' do\n    subject do\n      get :index\n    end\n\n    shared_examples 'stores location for user' do\n      it 'stores location for user' do\n        subject\n        expect(controller.stored_location_for(:user)).to eq \"/oauth/authorized_applications\"\n      end\n    end\n\n    context 'when signed in' do\n      before do\n        sign_in Fabricate(:user), scope: :user\n      end\n\n      it 'returns http success' do\n        subject\n        expect(response).to have_http_status(200)\n      end\n\n      include_examples 'stores location for user'\n    end\n\n    context 'when not signed in' do\n      it 'redirects' do\n        subject\n        expect(response).to redirect_to '/auth/sign_in'\n      end\n\n      include_examples 'stores location for user'\n    end\n  end\n\n  describe 'DELETE #destroy' do\n    let!(:user) { Fabricate(:user) }\n    let!(:application) { Fabricate(:application) }\n    let!(:access_token) { Fabricate(:accessible_access_token, application: application, resource_owner_id: user.id) }\n    let!(:web_push_subscription) { Fabricate(:web_push_subscription, user: user, access_token: access_token) }\n\n    before do\n      sign_in user, scope: :user\n      post :destroy, params: { id: application.id }\n    end\n\n    it 'revokes access tokens for the application' do\n      expect(Doorkeeper::AccessToken.where(application: application).first.revoked_at).to_not be_nil\n    end\n\n    it 'removes subscriptions for the application\\'s access tokens' do\n      expect(Web::PushSubscription.where(user: user).count).to eq 0\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/oauth/tokens_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe Oauth::TokensController, type: :controller do\n  describe 'POST #revoke' do\n    let!(:user) { Fabricate(:user) }\n    let!(:access_token) { Fabricate(:accessible_access_token, resource_owner_id: user.id) }\n    let!(:web_push_subscription) { Fabricate(:web_push_subscription, user: user, access_token: access_token) }\n\n    before do\n      post :revoke, params: { token: access_token.token }\n    end\n\n    it 'revokes the token' do\n      expect(access_token.reload.revoked_at).to_not be_nil\n    end\n\n    it 'removes web push subscription for token' do\n      expect(Web::PushSubscription.where(access_token: access_token).count).to eq 0\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/relationships_controller_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe RelationshipsController do\n  render_views\n\n  let(:user) { Fabricate(:user) }\n\n  shared_examples 'authenticate user' do\n    it 'redirects when not signed in' do\n      is_expected.to redirect_to '/auth/sign_in'\n    end\n  end\n\n  describe 'GET #show' do\n    subject { get :show, params: { page: 2, relationship: 'followed_by' } }\n\n    it 'assigns @accounts' do\n      Fabricate(:account, domain: 'old').follow!(user.account)\n      Fabricate(:account, domain: 'recent').follow!(user.account)\n\n      sign_in user, scope: :user\n      subject\n\n      assigned = assigns(:accounts).per(1).to_a\n      expect(assigned.size).to eq 1\n      expect(assigned[0].domain).to eq 'old'\n    end\n\n    it 'returns http success' do\n      sign_in user, scope: :user\n      subject\n      expect(response).to have_http_status(200)\n    end\n\n    include_examples 'authenticate user'\n  end\n\n  describe 'PATCH #update' do\n    let(:poopfeast) { Fabricate(:account, username: 'poopfeast', domain: 'example.com', salmon_url: 'http://example.com/salmon') }\n\n    before do\n      stub_request(:post, 'http://example.com/salmon').to_return(status: 200)\n    end\n\n    shared_examples 'redirects back to followers page' do\n      it 'redirects back to followers page' do\n        poopfeast.follow!(user.account)\n\n        sign_in user, scope: :user\n        subject\n\n        expect(response).to redirect_to(relationships_path)\n      end\n    end\n\n    context 'when select parameter is not provided' do\n      subject { patch :update }\n      include_examples 'redirects back to followers page'\n    end\n\n    context 'when select parameter is provided' do\n      subject { patch :update, params: { form_account_batch: { account_ids: [poopfeast.id] }, block_domains: '' } }\n\n      it 'soft-blocks followers from selected domains' do\n        poopfeast.follow!(user.account)\n\n        sign_in user, scope: :user\n        subject\n\n        expect(poopfeast.following?(user.account)).to be false\n      end\n\n      include_examples 'authenticate user'\n      include_examples 'redirects back to followers page'\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/remote_follow_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe RemoteFollowController do\n  render_views\n\n  describe '#new' do\n    it 'returns success when session is empty' do\n      account = Fabricate(:account)\n      get :new, params: { account_username: account.to_param }\n\n      expect(response).to have_http_status(200)\n      expect(response).to render_template(:new)\n      expect(assigns(:remote_follow).acct).to be_nil\n    end\n\n    it 'populates the remote follow with session data when session exists' do\n      session[:remote_follow] = 'user@example.com'\n      account = Fabricate(:account)\n      get :new, params: { account_username: account.to_param }\n\n      expect(response).to have_http_status(200)\n      expect(response).to render_template(:new)\n      expect(assigns(:remote_follow).acct).to eq 'user@example.com'\n    end\n  end\n\n  describe '#create' do\n    before do\n      @account = Fabricate(:account, username: 'test_user')\n    end\n\n    context 'with a valid acct' do\n      context 'when webfinger values are wrong' do\n        it 'renders new when redirect url is nil' do\n          resource_with_nil_link = double(link: nil)\n          allow(Goldfinger).to receive(:finger).with('acct:user@example.com').and_return(resource_with_nil_link)\n          post :create, params: { account_username: @account.to_param, remote_follow: { acct: 'user@example.com' } }\n\n          expect(response).to render_template(:new)\n          expect(response.body).to include(I18n.t('remote_follow.missing_resource'))\n        end\n\n        it 'renders new when template is nil' do\n          link_with_nil_template = double(template: nil)\n          resource_with_link = double(link: link_with_nil_template)\n          allow(Goldfinger).to receive(:finger).with('acct:user@example.com').and_return(resource_with_link)\n          post :create, params: { account_username: @account.to_param, remote_follow: { acct: 'user@example.com' } }\n\n          expect(response).to render_template(:new)\n          expect(response.body).to include(I18n.t('remote_follow.missing_resource'))\n        end\n      end\n\n      context 'when webfinger values are good' do\n        before do\n          link_with_template = double(template: 'http://example.com/follow_me?acct={uri}')\n          resource_with_link = double(link: link_with_template)\n          allow(Goldfinger).to receive(:finger).with('acct:user@example.com').and_return(resource_with_link)\n          post :create, params: { account_username: @account.to_param, remote_follow: { acct: 'user@example.com' } }\n        end\n\n        it 'saves the session' do\n          expect(session[:remote_follow]).to eq 'user@example.com'\n        end\n\n        it 'redirects to the remote location' do\n          address = \"http://example.com/follow_me?acct=test_user%40#{Rails.configuration.x.local_domain}\"\n\n          expect(response).to redirect_to(address)\n        end\n      end\n    end\n\n    context 'with an invalid acct' do\n      it 'renders new when acct is missing' do\n        post :create, params: { account_username: @account.to_param, remote_follow: { acct: '' } }\n\n        expect(response).to render_template(:new)\n      end\n\n      it 'renders new with error when goldfinger fails' do\n        allow(Goldfinger).to receive(:finger).with('acct:user@example.com').and_raise(Goldfinger::Error)\n        post :create, params: { account_username: @account.to_param, remote_follow: { acct: 'user@example.com' } }\n\n        expect(response).to render_template(:new)\n        expect(response.body).to include(I18n.t('remote_follow.missing_resource'))\n      end\n\n      it 'renders new when occur HTTP::ConnectionError' do\n        allow(Goldfinger).to receive(:finger).with('acct:user@unknown').and_raise(HTTP::ConnectionError)\n        post :create, params: { account_username: @account.to_param, remote_follow: { acct: 'user@unknown' } }\n\n        expect(response).to render_template(:new)\n        expect(response.body).to include(I18n.t('remote_follow.missing_resource'))\n      end\n    end\n  end\n\n  describe 'with a suspended account' do\n    before do\n      @account = Fabricate(:account, suspended: true)\n    end\n\n    it 'returns 410 gone on GET to #new' do\n      get :new, params: { account_username: @account.to_param }\n\n      expect(response).to have_http_status(:gone)\n    end\n\n    it 'returns 410 gone on POST to #create' do\n      post :create, params: { account_username: @account.to_param }\n\n      expect(response).to have_http_status(:gone)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/remote_interaction_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe RemoteInteractionController, type: :controller do\n  render_views\n\n  let(:status) { Fabricate(:status) }\n\n  describe 'GET #new' do\n    it 'returns 200' do\n      get :new, params: { id: status.id }\n      expect(response).to have_http_status(200)\n    end\n  end\n\n  describe 'POST #create' do\n    context '@remote_follow is valid' do\n      it 'returns 302' do\n        allow_any_instance_of(RemoteFollow).to receive(:valid?) { true }\n        allow_any_instance_of(RemoteFollow).to receive(:addressable_template) do\n          Addressable::Template.new('https://hoge.com')\n        end\n\n        post :create, params: { id: status.id, remote_follow: { acct: '@hoge' } }\n        expect(response).to have_http_status(302)\n      end\n    end\n\n    context '@remote_follow is invalid' do\n      it 'returns 200' do\n        allow_any_instance_of(RemoteFollow).to receive(:valid?) { false }\n        post :create, params: { id: status.id, remote_follow: { acct: '@hoge' } }\n\n        expect(response).to have_http_status(200)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/remote_unfollows_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe RemoteUnfollowsController do\n  render_views\n\n  describe '#create' do\n    subject { post :create, params: { acct: acct } }\n\n    let(:current_user) { Fabricate(:user, account: current_account) }\n    let(:current_account) { Fabricate(:account) }\n    let(:remote_account) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox')).account }\n    before do\n      sign_in current_user\n      current_account.follow!(remote_account)\n      stub_request(:post, 'http://example.com/inbox') { { status: 200 } }\n    end\n\n    context 'when successfully unfollow remote account' do\n      let(:acct) { \"acct:#{remote_account.username}@#{remote_account.domain}\" }\n\n      it do\n        is_expected.to render_template :success\n        expect(current_account.following?(remote_account)).to be false\n      end\n    end\n\n    context 'when fails to unfollow remote account' do\n      let(:acct) { \"acct:#{remote_account.username + '_test'}@#{remote_account.domain}\" }\n\n      it do\n        is_expected.to render_template :error\n        expect(current_account.following?(remote_account)).to be true\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/settings/applications_controller_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe Settings::ApplicationsController do\n  render_views\n\n  let!(:user) { Fabricate(:user) }\n  let!(:app) { Fabricate(:application, owner: user) }\n\n  before do\n    sign_in user, scope: :user\n  end\n\n  describe 'GET #index' do\n    let!(:other_app) { Fabricate(:application) }\n\n    it 'shows apps' do\n      get :index\n      expect(response).to have_http_status(200)\n      expect(assigns(:applications)).to include(app)\n      expect(assigns(:applications)).to_not include(other_app)\n    end\n  end\n\n  describe 'GET #show' do\n    it 'returns http success' do\n      get :show, params: { id: app.id }\n      expect(response).to have_http_status(200)\n      expect(assigns[:application]).to eql(app)\n    end\n\n    it 'returns 404 if you dont own app' do\n      app.update!(owner: nil)\n\n      get :show, params: { id: app.id }\n      expect(response.status).to eq 404\n    end\n  end\n\n  describe 'GET #new' do\n    it 'works' do\n      get :new\n      expect(response).to have_http_status(200)\n    end\n  end\n\n  describe 'POST #create' do\n    context 'success (passed scopes as a String)' do\n      def call_create\n        post :create, params: {\n          doorkeeper_application: {\n            name: 'My New App',\n            redirect_uri: 'urn:ietf:wg:oauth:2.0:oob',\n            website: 'http://google.com',\n            scopes: 'read write follow'\n          }\n        }\n        response\n      end\n\n      it 'creates an entry in the database' do\n        expect { call_create }.to change(Doorkeeper::Application, :count)\n      end\n\n      it 'redirects back to applications page' do\n        expect(call_create).to redirect_to(settings_applications_path)\n      end\n    end\n\n    context 'success (passed scopes as an Array)' do\n      def call_create\n        post :create, params: {\n          doorkeeper_application: {\n            name: 'My New App',\n            redirect_uri: 'urn:ietf:wg:oauth:2.0:oob',\n            website: 'http://google.com',\n            scopes: [ 'read', 'write', 'follow' ]\n          }\n        }\n        response\n      end\n\n      it 'creates an entry in the database' do\n        expect { call_create }.to change(Doorkeeper::Application, :count)\n      end\n\n      it 'redirects back to applications page' do\n        expect(call_create).to redirect_to(settings_applications_path)\n      end\n    end\n\n    context 'failure' do\n      before do\n        post :create, params: {\n          doorkeeper_application: {\n            name: '',\n            redirect_uri: '',\n            website: '',\n            scopes: []\n          }\n        }\n      end\n\n      it 'returns http success' do\n        expect(response).to have_http_status(200)\n      end\n\n      it 'renders form again' do\n        expect(response).to render_template(:new)\n      end\n    end\n  end\n\n  describe 'PATCH #update' do\n    context 'success' do\n      let(:opts) {\n        {\n          website: 'https://foo.bar/'\n        }\n      }\n\n      def call_update\n        patch :update, params: {\n          id: app.id,\n          doorkeeper_application: opts\n        }\n        response\n      end\n\n      it 'updates existing application' do\n        call_update\n        expect(app.reload.website).to eql(opts[:website])\n      end\n\n      it 'redirects back to applications page' do\n        expect(call_update).to redirect_to(settings_applications_path)\n      end\n    end\n\n    context 'failure' do\n      before do\n        patch :update, params: {\n          id: app.id,\n          doorkeeper_application: {\n            name: '',\n            redirect_uri: '',\n            website: '',\n            scopes: []\n          }\n        }\n      end\n\n      it 'returns http success' do\n        expect(response).to have_http_status(200)\n      end\n\n      it 'renders form again' do\n        expect(response).to render_template(:show)\n      end\n    end\n  end\n\n  describe 'destroy' do\n    before do\n      post :destroy, params: { id: app.id }\n    end\n\n    it 'redirects back to applications page' do\n      expect(response).to redirect_to(settings_applications_path)\n    end\n\n    it 'removes the app' do\n      expect(Doorkeeper::Application.find_by(id: app.id)).to be_nil\n    end\n  end\n\n  describe 'regenerate' do\n    let(:token) { user.token_for_app(app) }\n    before do\n      expect(token).to_not be_nil\n      post :regenerate, params: { id: app.id }\n    end\n\n    it 'should create new token' do\n      expect(user.token_for_app(app)).to_not eql(token)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/settings/deletes_controller_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe Settings::DeletesController do\n  render_views\n\n  describe 'GET #show' do\n    context 'when signed in' do\n      let(:user) { Fabricate(:user) }\n\n      before do\n        sign_in user, scope: :user\n      end\n\n      it 'renders confirmation page' do\n        get :show\n        expect(response).to have_http_status(200)\n      end\n    end\n\n    context 'when not signed in' do\n      it 'redirects' do\n        get :show\n        expect(response).to redirect_to '/auth/sign_in'\n      end\n    end\n  end\n\n  describe 'DELETE #destroy' do\n    context 'when signed in' do\n      let(:user) { Fabricate(:user, password: 'petsmoldoggos') }\n\n      before do\n        sign_in user, scope: :user\n      end\n\n      context 'with correct password' do\n        before do\n          delete :destroy, params: { form_delete_confirmation: { password: 'petsmoldoggos' } }\n        end\n\n        it 'redirects to sign in page' do\n          expect(response).to redirect_to '/auth/sign_in'\n        end\n\n        it 'removes user record' do\n          expect(User.find_by(id: user.id)).to be_nil\n        end\n\n        it 'marks account as suspended' do\n          expect(user.account.reload).to be_suspended\n        end\n      end\n\n      context 'with incorrect password' do\n        before do\n          delete :destroy, params: { form_delete_confirmation: { password: 'blaze420' } }\n        end\n\n        it 'redirects back to confirmation page' do\n          expect(response).to redirect_to settings_delete_path\n        end\n      end\n    end\n\n    context 'when not signed in' do\n      it 'redirects' do\n        delete :destroy\n        expect(response).to redirect_to '/auth/sign_in'\n      end\n    end\n\n    context do\n      around do |example|\n        open_deletion = Setting.open_deletion\n        example.run\n        Setting.open_deletion = open_deletion\n      end\n\n      it 'redirects' do\n        Setting.open_deletion = false\n        delete :destroy\n        expect(response).to redirect_to root_path\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/settings/exports/blocked_accounts_controller_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe Settings::Exports::BlockedAccountsController do\n  render_views\n\n  describe 'GET #index' do\n    it 'returns a csv of the blocking accounts' do\n      user = Fabricate(:user)\n      user.account.block!(Fabricate(:account, username: 'username', domain: 'domain'))\n\n      sign_in user, scope: :user\n      get :index, format: :csv\n\n      expect(response.body).to eq \"username@domain\\n\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/settings/exports/following_accounts_controller_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe Settings::Exports::FollowingAccountsController do\n  render_views\n\n  describe 'GET #index' do\n    it 'returns a csv of the following accounts' do\n      user = Fabricate(:user)\n      user.account.follow!(Fabricate(:account, username: 'username', domain: 'domain'))\n\n      sign_in user, scope: :user\n      get :index, format: :csv\n\n      expect(response.body).to eq \"Account address,Show boosts\\nusername@domain,true\\n\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/settings/exports/muted_accounts_controller_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe Settings::Exports::MutedAccountsController do\n  render_views\n\n  describe 'GET #index' do\n    it 'returns a csv of the muting accounts' do\n      user = Fabricate(:user)\n      user.account.mute!(Fabricate(:account, username: 'username', domain: 'domain'))\n\n      sign_in user, scope: :user\n      get :index, format: :csv\n\n      expect(response.body).to eq \"Account address,Hide notifications\\nusername@domain,true\\n\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/settings/exports_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe Settings::ExportsController do\n  render_views\n\n  describe 'GET #show' do\n    context 'when signed in' do\n      let(:user) { Fabricate(:user) }\n\n      before do\n        sign_in user, scope: :user\n      end\n\n      it 'renders export' do\n        get :show\n\n        export = assigns(:export)\n        expect(export).to be_instance_of Export\n        expect(export.account).to eq user.account\n        expect(response).to have_http_status(200)\n      end\n    end\n\n    context 'when not signed in' do\n      it 'redirects' do\n        get :show\n        expect(response).to redirect_to '/auth/sign_in'\n      end\n    end\n  end\n\n  describe 'POST #create' do\n    before do\n      sign_in Fabricate(:user), scope: :user\n    end\n\n    it 'redirects to settings_export_path' do\n      post :create\n      expect(response).to redirect_to(settings_export_path)\n    end\n\n    it 'queues BackupWorker job by 1' do\n      Sidekiq::Testing.fake! do\n        expect do\n          post :create\n        end.to change(BackupWorker.jobs, :size).by(1)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/settings/identity_proofs_controller_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe Settings::IdentityProofsController do\n  include RoutingHelper\n  render_views\n\n  let(:user) { Fabricate(:user) }\n  let(:valid_token) { '1'*66 }\n  let(:kbname) { 'kbuser' }\n  let(:provider) { 'keybase' }\n  let(:findable_id) { Faker::Number.number(5) }\n  let(:unfindable_id) { Faker::Number.number(5) }\n  let(:new_proof_params) do\n    { provider: provider, provider_username: kbname, token: valid_token, username: user.account.username }\n  end\n  let(:status_text) { \"i just proved that i am also #{kbname} on #{provider}.\" }\n  let(:status_posting_params) do\n    { post_status: '0', status_text: status_text }\n  end\n  let(:postable_params) do\n    { account_identity_proof: new_proof_params.merge(status_posting_params) }\n  end\n\n  before do\n    allow_any_instance_of(ProofProvider::Keybase::Verifier).to receive(:status) { { 'proof_valid' => true, 'proof_live' => true } }\n    sign_in user, scope: :user\n  end\n\n  describe 'new proof creation' do\n    context 'GET #new' do\n      before do\n        allow_any_instance_of(ProofProvider::Keybase::Badge).to receive(:avatar_url) { full_pack_url('media/images/void.png') }\n      end\n\n      context 'with all of the correct params' do\n        it 'renders the template' do\n          get :new, params: new_proof_params\n          expect(response).to render_template(:new)\n        end\n      end\n\n      context 'without any params' do\n        it 'redirects to :index' do\n          get :new, params: {}\n          expect(response).to redirect_to settings_identity_proofs_path\n        end\n      end\n\n      context 'with params to prove a different, not logged-in user' do\n        let(:wrong_user_params) { new_proof_params.merge(username: 'someone_else') }\n\n        it 'shows a helpful alert' do\n          get :new, params: wrong_user_params\n          expect(flash[:alert]).to eq I18n.t('identity_proofs.errors.wrong_user', proving: 'someone_else', current: user.account.username)\n        end\n      end\n\n      context 'with params to prove the same username cased differently' do\n        let(:capitalized_username) { new_proof_params.merge(username: user.account.username.upcase) }\n\n        it 'renders the new template' do\n          get :new, params: capitalized_username\n          expect(response).to render_template(:new)\n        end\n      end\n    end\n\n    context 'POST #create' do\n      context 'when saving works' do\n        before do\n          allow(ProofProvider::Keybase::Worker).to receive(:perform_async)\n          allow_any_instance_of(ProofProvider::Keybase::Verifier).to receive(:valid?) { true }\n          allow_any_instance_of(AccountIdentityProof).to receive(:on_success_path) { root_url }\n        end\n\n        it 'serializes a ProofProvider::Keybase::Worker' do\n          expect(ProofProvider::Keybase::Worker).to receive(:perform_async)\n          post :create, params: postable_params\n        end\n\n        it 'delegates redirection to the proof provider' do\n          expect_any_instance_of(AccountIdentityProof).to receive(:on_success_path)\n          post :create, params: postable_params\n          expect(response).to redirect_to root_url\n        end\n\n        it 'does not post a status' do\n          expect(PostStatusService).not_to receive(:new)\n          post :create, params: postable_params\n        end\n\n        context 'and the user has requested to post a status' do\n          let(:postable_params_with_status) do\n            postable_params.tap { |p| p[:account_identity_proof][:post_status] = '1' }\n          end\n\n          it 'posts a status' do\n            expect_any_instance_of(PostStatusService).to receive(:call).with(user.account, text: status_text)\n\n            post :create, params: postable_params_with_status\n          end\n        end\n      end\n\n      context 'when saving fails' do\n        before do\n          allow_any_instance_of(ProofProvider::Keybase::Verifier).to receive(:valid?) { false }\n        end\n\n        it 'redirects to :index' do\n          post :create, params: postable_params\n          expect(response).to redirect_to settings_identity_proofs_path\n        end\n\n        it 'flashes a helpful message' do\n          post :create, params: postable_params\n          expect(flash[:alert]).to eq I18n.t('identity_proofs.errors.failed', provider: 'Keybase')\n        end\n      end\n\n      context 'it can also do an update if the provider and username match an existing proof' do\n        before do\n          allow_any_instance_of(ProofProvider::Keybase::Verifier).to receive(:valid?) { true }\n          allow(ProofProvider::Keybase::Worker).to receive(:perform_async)\n          Fabricate(:account_identity_proof, account: user.account, provider: provider, provider_username: kbname)\n          allow_any_instance_of(AccountIdentityProof).to receive(:on_success_path) { root_url }\n        end\n\n        it 'calls update with the new token' do\n          expect_any_instance_of(AccountIdentityProof).to receive(:save) do |proof|\n            expect(proof.token).to eq valid_token\n          end\n\n          post :create, params: postable_params\n        end\n      end\n    end\n  end\n\n  describe 'GET #index' do\n    context 'with no existing proofs' do\n      it 'shows the helpful explanation' do\n        get :index\n        expect(response.body).to match I18n.t('identity_proofs.explanation_html')\n      end\n    end\n\n    context 'with two proofs' do\n      before do\n        allow_any_instance_of(ProofProvider::Keybase::Verifier).to receive(:valid?) { true }\n        @proof1 = Fabricate(:account_identity_proof, account: user.account)\n        @proof2 = Fabricate(:account_identity_proof, account: user.account)\n        allow_any_instance_of(AccountIdentityProof).to receive(:badge) { double(avatar_url: '', profile_url: '', proof_url: '') }\n        allow_any_instance_of(AccountIdentityProof).to receive(:refresh!) { }\n      end\n\n      it 'has the first proof username on the page' do\n        get :index\n        expect(response.body).to match /#{Regexp.quote(@proof1.provider_username)}/\n      end\n\n      it 'has the second proof username on the page' do\n        get :index\n        expect(response.body).to match /#{Regexp.quote(@proof2.provider_username)}/\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/settings/imports_controller_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Settings::ImportsController, type: :controller do\n  render_views\n\n  before do\n    sign_in Fabricate(:user), scope: :user\n  end\n\n  describe \"GET #show\" do\n    it \"returns http success\" do\n      get :show\n      expect(response).to have_http_status(200)\n    end\n  end\n\n  describe 'POST #create' do\n    it 'redirects to settings path with successful following import' do\n      service = double(call: nil)\n      allow(ResolveAccountService).to receive(:new).and_return(service)\n      post :create, params: {\n        import: {\n          type: 'following',\n          data: fixture_file_upload('files/imports.txt')\n        }\n      }\n\n      expect(response).to redirect_to(settings_import_path)\n    end\n\n    it 'redirects to settings path with successful blocking import' do\n      service = double(call: nil)\n      allow(ResolveAccountService).to receive(:new).and_return(service)\n      post :create, params: {\n        import: {\n          type: 'blocking',\n          data: fixture_file_upload('files/imports.txt')\n        }\n      }\n\n      expect(response).to redirect_to(settings_import_path)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/settings/migrations_controller_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe Settings::MigrationsController do\n  render_views\n\n  shared_examples 'authenticate user' do\n    it 'redirects to sign_in page' do\n      is_expected.to redirect_to new_user_session_path\n    end\n  end\n\n  describe 'GET #show' do\n    context 'when user is not sign in' do\n      subject { get :show }\n\n      it_behaves_like 'authenticate user'\n    end\n\n    context 'when user is sign in' do\n      subject { get :show }\n\n      let(:user) { Fabricate(:user, account: account) }\n      let(:account) { Fabricate(:account, moved_to_account: moved_to_account) }\n      before { sign_in user, scope: :user }\n\n      context 'when user does not have moved to account' do\n        let(:moved_to_account) { nil }\n\n        it 'renders show page' do\n          is_expected.to have_http_status 200\n          is_expected.to render_template :show\n        end\n      end\n\n      context 'when user does not have moved to account' do\n        let(:moved_to_account) { Fabricate(:account) }\n\n        it 'renders show page' do\n          is_expected.to have_http_status 200\n          is_expected.to render_template :show\n        end\n      end\n    end\n  end\n\n  describe 'PUT #update' do\n    context 'when user is not sign in' do\n      subject { put :update }\n\n      it_behaves_like 'authenticate user'\n    end\n\n    context 'when user is sign in' do\n      subject { put :update, params: { migration: { acct: acct } } }\n\n      let(:user) { Fabricate(:user) }\n      before { sign_in user, scope: :user }\n\n      context 'when migration account is changed' do\n        let(:acct) { Fabricate(:account) }\n\n        it 'updates moved to account' do\n          is_expected.to redirect_to settings_migration_path\n          expect(user.account.reload.moved_to_account_id).to eq acct.id\n        end\n      end\n\n      context 'when acct is a current account' do\n        let(:acct) { user.account }\n\n        it 'renders show' do\n          is_expected.to render_template :show\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/settings/preferences/notifications_controller_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe Settings::Preferences::NotificationsController do\n  render_views\n\n  let(:user) { Fabricate(:user) }\n\n  before do\n    sign_in user, scope: :user\n  end\n\n  describe 'GET #show' do\n    it 'returns http success' do\n      get :show\n      expect(response).to have_http_status(200)\n    end\n  end\n\n  describe 'PUT #update' do\n    it 'updates notifications settings' do\n      user.settings['notification_emails'] = user.settings['notification_emails'].merge('follow' => false)\n      user.settings['interactions'] = user.settings['interactions'].merge('must_be_follower' => true)\n\n      put :update, params: {\n        user: {\n          notification_emails: { follow: '1' },\n          interactions: { must_be_follower: '0' },\n        }\n      }\n\n      expect(response).to redirect_to(settings_preferences_notifications_path)\n      user.reload\n      expect(user.settings['notification_emails']['follow']).to be true\n      expect(user.settings['interactions']['must_be_follower']).to be false\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/settings/preferences/other_controller_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe Settings::Preferences::OtherController do\n  render_views\n\n  let(:user) { Fabricate(:user, filtered_languages: []) }\n\n  before do\n    sign_in user, scope: :user\n  end\n\n  describe 'GET #show' do\n    it 'returns http success' do\n      get :show\n      expect(response).to have_http_status(200)\n    end\n  end\n\n  describe 'PUT #update' do\n    it 'updates the user record' do\n      put :update, params: { user: { locale: 'en', chosen_languages: ['es', 'fr', ''] } }\n\n      expect(response).to redirect_to(settings_preferences_other_path)\n      user.reload\n      expect(user.locale).to eq 'en'\n      expect(user.chosen_languages).to eq ['es', 'fr']\n    end\n\n    it 'updates user settings' do\n      user.settings['boost_modal'] = false\n      user.settings['delete_modal'] = true\n\n      put :update, params: {\n        user: {\n          setting_boost_modal: '1',\n          setting_delete_modal: '0',\n        }\n      }\n\n      expect(response).to redirect_to(settings_preferences_other_path)\n      user.reload\n      expect(user.settings['boost_modal']).to be true\n      expect(user.settings['delete_modal']).to be false\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/settings/profiles_controller_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Settings::ProfilesController, type: :controller do\n  render_views\n\n  before do\n    @user = Fabricate(:user)\n    sign_in @user, scope: :user\n  end\n\n  describe \"GET #show\" do\n    it \"returns http success\" do\n      get :show\n      expect(response).to have_http_status(200)\n    end\n  end\n\n  describe 'PUT #update' do\n    it 'updates the user profile' do\n      allow(ActivityPub::UpdateDistributionWorker).to receive(:perform_async)\n      account = Fabricate(:account, user: @user, display_name: 'Old name')\n\n      put :update, params: { account: { display_name: 'New name' } }\n      expect(account.reload.display_name).to eq 'New name'\n      expect(response).to redirect_to(settings_profile_path)\n      expect(ActivityPub::UpdateDistributionWorker).to have_received(:perform_async).with(account.id)\n    end\n  end\n\n  describe 'PUT #update with new profile image' do\n    it 'updates profile image' do\n      allow(ActivityPub::UpdateDistributionWorker).to receive(:perform_async)\n      account = Fabricate(:account, user: @user, display_name: 'AvatarTest')\n      expect(account.avatar.instance.avatar_file_name).to be_nil\n\n      put :update, params: { account: { avatar: fixture_file_upload('files/avatar.gif', 'image/gif') } }\n      expect(response).to redirect_to(settings_profile_path)\n      expect(account.reload.avatar.instance.avatar_file_name).not_to be_nil\n      expect(ActivityPub::UpdateDistributionWorker).to have_received(:perform_async).with(account.id)\n    end\n  end\n\n  describe 'PUT #update with oversized image' do\n    it 'gives the user an error message' do\n      allow(ActivityPub::UpdateDistributionWorker).to receive(:perform_async)\n      account = Fabricate(:account, user: @user, display_name: 'AvatarTest')\n      put :update, params: { account: { avatar: fixture_file_upload('files/4096x4097.png', 'image/png') } }\n      expect(response.body).to include('images are not supported')\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/settings/sessions_controller_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe Settings::SessionsController do\n  render_views\n\n  let(:user) { Fabricate(:user) }\n  let(:session_activation) { Fabricate(:session_activation, user: user) }\n  before { sign_in user, scope: :user }\n\n  describe 'DELETE #destroy' do\n    subject { delete :destroy, params: { id: id } }\n\n    context 'when session activation exists' do\n      let(:id) { session_activation.id }\n\n      it 'destroys session activation' do\n        is_expected.to redirect_to edit_user_registration_path\n        expect(SessionActivation.find_by(id: id)).to be_nil\n      end\n    end\n\n    context 'when session activation does not exist' do\n      let(:id) { session_activation.id + 1000 }\n\n      it 'destroys session activation' do\n        is_expected.to have_http_status :not_found\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe Settings::TwoFactorAuthentication::ConfirmationsController do\n  render_views\n\n  let(:user) { Fabricate(:user, email: 'local-part@domain', otp_secret: 'thisisasecretforthespecofnewview') }\n  let(:user_without_otp_secret) { Fabricate(:user, email: 'local-part@domain') }\n\n  shared_examples 'renders :new' do\n    it 'renders the new view' do\n      subject\n\n      expect(assigns(:confirmation)).to be_instance_of Form::TwoFactorConfirmation\n      expect(assigns(:provision_url)).to eq 'otpauth://totp/local-part@domain?secret=thisisasecretforthespecofnewview&issuer=cb6e6126.ngrok.io'\n      expect(assigns(:qrcode)).to be_instance_of RQRCode::QRCode\n      expect(response).to have_http_status(200)\n      expect(response).to render_template(:new)\n    end\n  end\n\n  describe 'GET #new' do\n    context 'when signed in' do\n      subject do\n        sign_in user, scope: :user\n        get :new\n      end\n\n      include_examples 'renders :new'\n    end\n\n    it 'redirects if not signed in' do\n      get :new\n      expect(response).to redirect_to('/auth/sign_in')\n    end\n\n    it 'redirects if user do not have otp_secret' do\n      sign_in user_without_otp_secret, scope: :user\n      get :new\n      expect(response).to redirect_to('/settings/two_factor_authentication')\n    end\n  end\n\n  describe 'POST #create' do\n    context 'when signed in' do\n      before do\n        sign_in user, scope: :user\n      end\n\n      describe 'when form_two_factor_confirmation parameter is not provided' do\n        it 'raises ActionController::ParameterMissing' do\n          expect { post :create, params: {} }.to raise_error(ActionController::ParameterMissing)\n        end\n      end\n\n      describe 'when creation succeeds' do\n        it 'renders page with success' do\n          otp_backup_codes = user.generate_otp_backup_codes!\n          expect_any_instance_of(User).to receive(:generate_otp_backup_codes!) do |value|\n            expect(value).to eq user\n            otp_backup_codes\n          end\n          expect_any_instance_of(User).to receive(:validate_and_consume_otp!) do |value, arg|\n            expect(value).to eq user\n            expect(arg).to eq '123456'\n            true\n          end\n\n          post :create, params: { form_two_factor_confirmation: { code: '123456' } }\n\n          expect(assigns(:recovery_codes)).to eq otp_backup_codes\n          expect(flash[:notice]).to eq 'Two-factor authentication successfully enabled'\n          expect(response).to have_http_status(200)\n          expect(response).to render_template('settings/two_factor_authentication/recovery_codes/index')\n        end\n      end\n\n      describe 'when creation fails' do\n        subject do\n          expect_any_instance_of(User).to receive(:validate_and_consume_otp!) do |value, arg|\n            expect(value).to eq user\n            expect(arg).to eq '123456'\n            false\n          end\n\n          post :create, params: { form_two_factor_confirmation: { code: '123456' } }\n        end\n\n        it 'renders the new view' do\n          subject\n          expect(response.body).to include 'The entered code was invalid! Are server time and device time correct?'\n        end\n\n        include_examples 'renders :new'\n      end\n    end\n\n    context 'when not signed in' do\n      it 'redirects if not signed in' do\n        post :create, params: { form_two_factor_confirmation: { code: '123456' } }\n        expect(response).to redirect_to('/auth/sign_in')\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/settings/two_factor_authentication/recovery_codes_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe Settings::TwoFactorAuthentication::RecoveryCodesController do\n  render_views\n\n  describe 'POST #create' do\n    it 'updates the codes and shows them on a view when signed in' do\n      user = Fabricate(:user)\n      otp_backup_codes = user.generate_otp_backup_codes!\n      expect_any_instance_of(User).to receive(:generate_otp_backup_codes!) do |value|\n        expect(value).to eq user\n        otp_backup_codes\n      end\n\n      sign_in user, scope: :user\n      post :create\n\n      expect(assigns(:recovery_codes)).to eq otp_backup_codes\n      expect(flash[:notice]).to eq 'Recovery codes successfully regenerated'\n      expect(response).to have_http_status(200)\n      expect(response).to render_template(:index)\n    end\n\n    it 'redirects when not signed in' do\n      post :create\n      expect(response).to redirect_to '/auth/sign_in'\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/settings/two_factor_authentications_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe Settings::TwoFactorAuthenticationsController do\n  render_views\n\n  let(:user) { Fabricate(:user) }\n\n  describe 'GET #show' do\n    context 'when signed in' do\n      before do\n        sign_in user, scope: :user\n      end\n\n      describe 'when user requires otp for login already' do\n        it 'returns http success' do\n          user.update(otp_required_for_login: true)\n          get :show\n\n          expect(response).to have_http_status(200)\n        end\n      end\n\n      describe 'when user does not require otp for login' do\n        it 'returns http success' do\n          user.update(otp_required_for_login: false)\n          get :show\n\n          expect(response).to have_http_status(200)\n        end\n      end\n    end\n\n    context 'when not signed in' do\n      it 'redirects' do\n        get :show\n        expect(response).to redirect_to '/auth/sign_in'\n      end\n    end\n  end\n\n  describe 'POST #create' do\n    context 'when signed in' do\n      before do\n        sign_in user, scope: :user\n      end\n\n      describe 'when user requires otp for login already' do\n        it 'redirects to show page' do\n          user.update(otp_required_for_login: true)\n          post :create\n\n          expect(response).to redirect_to(settings_two_factor_authentication_path)\n        end\n      end\n\n      describe 'when creation succeeds' do\n        it 'updates user secret' do\n          before = user.otp_secret\n          post :create\n\n          expect(user.reload.otp_secret).not_to eq(before)\n          expect(response).to redirect_to(new_settings_two_factor_authentication_confirmation_path)\n        end\n      end\n    end\n\n    context 'when not signed in' do\n      it 'redirects' do\n        get :show\n        expect(response).to redirect_to '/auth/sign_in'\n      end\n    end\n  end\n\n  describe 'POST #destroy' do\n    before do\n      user.update(otp_required_for_login: true)\n    end\n\n    context 'when signed in' do\n      before do\n        sign_in user, scope: :user\n      end\n\n      it 'turns off otp requirement with correct code' do\n        expect_any_instance_of(User).to receive(:validate_and_consume_otp!) do |value, arg|\n          expect(value).to eq user\n          expect(arg).to eq '123456'\n          true\n        end\n\n        post :destroy, params: { form_two_factor_confirmation: { code: '123456' } }\n\n        expect(response).to redirect_to(settings_two_factor_authentication_path)\n        user.reload\n        expect(user.otp_required_for_login).to eq(false)\n      end\n\n      it 'does not turn off otp if code is incorrect' do\n        expect_any_instance_of(User).to receive(:validate_and_consume_otp!) do |value, arg|\n          expect(value).to eq user\n          expect(arg).to eq '057772'\n          false\n        end\n\n        post :destroy, params: { form_two_factor_confirmation: { code: '057772' } }\n\n        user.reload\n        expect(user.otp_required_for_login).to eq(true)\n      end\n\n      it 'raises ActionController::ParameterMissing if code is missing' do\n        expect { post :destroy }.to raise_error(ActionController::ParameterMissing)\n      end\n    end\n\n    it 'redirects if not signed in' do\n      get :show\n      expect(response).to redirect_to '/auth/sign_in'\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/shares_controller_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe SharesController do\n  render_views\n\n  let(:user) { Fabricate(:user) }\n  before { sign_in user }\n\n  describe 'GTE #show' do\n    subject(:initial_state_json) { JSON.parse(assigns(:initial_state_json), symbolize_names: true) }\n    subject(:body_classes) { assigns(:body_classes) }\n\n    before { get :show, params: { title: 'test title', text: 'test text', url: 'url1 url2' } }\n\n    it 'assigns json' do\n      expect(response).to have_http_status :ok\n      expect(initial_state_json[:compose][:text]).to eq 'test title test text url1 url2'\n      expect(initial_state_json[:meta][:me]).to eq user.account.id.to_s\n      expect(body_classes).to eq 'modal-layout compose-standalone'\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/statuses_controller_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe StatusesController do\n  render_views\n\n  describe '#show' do\n    context 'account is suspended' do\n      it 'returns gone' do\n        account = Fabricate(:account, suspended: true)\n        status = Fabricate(:status, account: account)\n\n        get :show, params: { account_username: account.username, id: status.id }\n\n        expect(response).to have_http_status(410)\n      end\n    end\n\n    context 'status is not permitted' do\n      it 'raises ActiveRecord::RecordNotFound' do\n        user = Fabricate(:user)\n        status = Fabricate(:status)\n        status.account.block!(user.account)\n\n        sign_in(user)\n        get :show, params: { account_username: status.account.username, id: status.id }\n\n        expect(response).to have_http_status(404)\n      end\n    end\n\n    context 'status is a reblog' do\n      it 'redirects to the original status' do\n        original_account = Fabricate(:account, domain: 'example.com')\n        original_status = Fabricate(:status, account: original_account, uri: 'tag:example.com,2017:foo', url: 'https://example.com/123')\n        status = Fabricate(:status, reblog: original_status)\n\n        get :show, params: { account_username: status.account.username, id: status.id }\n\n        expect(response).to redirect_to(original_status.url)\n      end\n    end\n\n    context 'account is not suspended and status is permitted' do\n      it 'assigns @account' do\n        status = Fabricate(:status)\n        get :show, params: { account_username: status.account.username, id: status.id }\n        expect(assigns(:account)).to eq status.account\n      end\n\n      it 'assigns @status' do\n        status = Fabricate(:status)\n        get :show, params: { account_username: status.account.username, id: status.id }\n        expect(assigns(:status)).to eq status\n      end\n\n      it 'assigns @stream_entry' do\n        status = Fabricate(:status)\n        get :show, params: { account_username: status.account.username, id: status.id }\n        expect(assigns(:stream_entry)).to eq status.stream_entry\n      end\n\n      it 'assigns @type' do\n        status = Fabricate(:status)\n        get :show, params: { account_username: status.account.username, id: status.id }\n        expect(assigns(:type)).to eq 'status'\n      end\n\n      it 'assigns @ancestors for ancestors of the status if it is a reply' do\n        ancestor = Fabricate(:status)\n        status = Fabricate(:status, in_reply_to_id: ancestor.id)\n\n        get :show, params: { account_username: status.account.username, id: status.id }\n\n        expect(assigns(:ancestors)).to eq [ancestor]\n      end\n\n      it 'assigns @ancestors for [] if it is not a reply' do\n        status = Fabricate(:status)\n        get :show, params: { account_username: status.account.username, id: status.id }\n        expect(assigns(:ancestors)).to eq []\n      end\n\n      it 'assigns @descendant_threads for a thread with several statuses' do\n        status = Fabricate(:status)\n        child = Fabricate(:status, in_reply_to_id: status.id)\n        grandchild = Fabricate(:status, in_reply_to_id: child.id)\n\n        get :show, params: { account_username: status.account.username, id: status.id }\n\n        expect(assigns(:descendant_threads)[0][:statuses].pluck(:id)).to eq [child.id, grandchild.id]\n      end\n\n      it 'assigns @descendant_threads for several threads sharing the same descendant' do\n        status = Fabricate(:status)\n        child = Fabricate(:status, in_reply_to_id: status.id)\n        grandchildren = 2.times.map { Fabricate(:status, in_reply_to_id: child.id) }\n\n        get :show, params: { account_username: status.account.username, id: status.id }\n\n        expect(assigns(:descendant_threads)[0][:statuses].pluck(:id)).to eq [child.id, grandchildren[0].id]\n        expect(assigns(:descendant_threads)[1][:statuses].pluck(:id)).to eq [grandchildren[1].id]\n      end\n\n      it 'assigns @max_descendant_thread_id for the last thread if it is hitting the status limit' do\n        stub_const 'StatusesController::DESCENDANTS_LIMIT', 1\n        status = Fabricate(:status)\n        child = Fabricate(:status, in_reply_to_id: status.id)\n\n        get :show, params: { account_username: status.account.username, id: status.id }\n\n        expect(assigns(:descendant_threads)).to eq []\n        expect(assigns(:max_descendant_thread_id)).to eq child.id\n      end\n\n      it 'assigns @descendant_threads for threads with :next_status key if they are hitting the depth limit' do\n        stub_const 'StatusesController::DESCENDANTS_DEPTH_LIMIT', 2\n        status = Fabricate(:status)\n        child0 = Fabricate(:status, in_reply_to_id: status.id)\n        child1 = Fabricate(:status, in_reply_to_id: child0.id)\n        child2 = Fabricate(:status, in_reply_to_id: child0.id)\n\n        get :show, params: { account_username: status.account.username, id: status.id }\n\n        expect(assigns(:descendant_threads)[0][:statuses].pluck(:id)).not_to include child1.id\n        expect(assigns(:descendant_threads)[1][:statuses].pluck(:id)).not_to include child2.id\n        expect(assigns(:descendant_threads)[0][:next_status].id).to eq child1.id\n        expect(assigns(:descendant_threads)[1][:next_status].id).to eq child2.id\n      end\n\n      it 'returns a success' do\n        status = Fabricate(:status)\n        get :show, params: { account_username: status.account.username, id: status.id }\n        expect(response).to have_http_status(200)\n      end\n\n      it 'renders stream_entries/show' do\n        status = Fabricate(:status)\n        get :show, params: { account_username: status.account.username, id: status.id }\n        expect(response).to render_template 'stream_entries/show'\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/stream_entries_controller_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe StreamEntriesController, type: :controller do\n  render_views\n\n  shared_examples 'before_action' do |route|\n    context 'when account is not suspended and stream_entry is available' do\n      it 'assigns instance variables' do\n        status = Fabricate(:status)\n\n        get route, params: { account_username: status.account.username, id: status.stream_entry.id }\n\n        expect(assigns(:account)).to eq status.account\n        expect(assigns(:stream_entry)).to eq status.stream_entry\n        expect(assigns(:type)).to eq 'status'\n      end\n\n      it 'sets Link headers' do\n        alice = Fabricate(:account, username: 'alice')\n        status = Fabricate(:status, account: alice)\n\n        get route, params: { account_username: alice.username, id: status.stream_entry.id }\n\n        expect(response.headers['Link'].to_s).to eq \"<http://test.host/users/alice/updates/#{status.stream_entry.id}.atom>; rel=\\\"alternate\\\"; type=\\\"application/atom+xml\\\", <https://cb6e6126.ngrok.io/users/alice/statuses/#{status.id}>; rel=\\\"alternate\\\"; type=\\\"application/activity+json\\\"\"\n      end\n    end\n\n    context 'when account is suspended' do\n      it 'returns http status 410' do\n        account = Fabricate(:account, suspended: true)\n        status = Fabricate(:status, account: account)\n\n        get route, params: { account_username: account.username, id: status.stream_entry.id }\n\n        expect(response).to have_http_status(410)\n      end\n    end\n\n    context 'when activity is nil' do\n      it 'raises ActiveRecord::RecordNotFound' do\n        account = Fabricate(:account)\n        stream_entry = Fabricate.build(:stream_entry, account: account, activity: nil, activity_type: 'Status')\n        stream_entry.save!(validate: false)\n\n        get route, params: { account_username: account.username, id: stream_entry.id }\n\n        expect(response).to have_http_status(404)\n      end\n    end\n\n    context 'when it is hidden and it is not permitted' do\n      it 'raises ActiveRecord::RecordNotFound' do\n        status = Fabricate(:status)\n        user = Fabricate(:user)\n        status.account.block!(user.account)\n        status.stream_entry.update!(hidden: true)\n\n        sign_in(user)\n        get route, params: { account_username: status.account.username, id: status.stream_entry.id }\n\n        expect(response).to have_http_status(404)\n      end\n    end\n  end\n\n  describe 'GET #show' do\n    include_examples 'before_action', :show\n\n    it 'redirects to status page' do\n      status = Fabricate(:status)\n\n      get :show, params: { account_username: status.account.username, id: status.stream_entry.id }\n\n      expect(response).to redirect_to(short_account_status_url(status.account, status))\n    end\n\n    it 'returns http success with Atom' do\n      status = Fabricate(:status)\n      get :show, params: { account_username: status.account.username, id: status.stream_entry.id }, format: 'atom'\n      expect(response).to have_http_status(200)\n    end\n  end\n\n  describe 'GET #embed' do\n    include_examples 'before_action', :embed\n\n    it 'redirects to new embed page' do\n      status = Fabricate(:status)\n\n      get :embed, params: { account_username: status.account.username, id: status.stream_entry.id }\n\n      expect(response).to redirect_to(embed_short_account_status_url(status.account, status))\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/tags_controller_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe TagsController, type: :controller do\n  render_views\n\n  describe 'GET #show' do\n    let!(:tag)     { Fabricate(:tag, name: 'test') }\n    let!(:local)   { Fabricate(:status, tags: [tag], text: 'local #test') }\n    let!(:remote)  { Fabricate(:status, tags: [tag], text: 'remote #test', account: Fabricate(:account, domain: 'remote')) }\n    let!(:late)    { Fabricate(:status, tags: [tag], text: 'late #test') }\n\n    context 'when tag exists' do\n      it 'returns http success' do\n        get :show, params: { id: 'test', max_id: late.id }\n        expect(response).to have_http_status(200)\n      end\n\n      it 'renders application layout' do\n        get :show, params: { id: 'test', max_id: late.id }\n        expect(response).to render_template layout: 'public'\n      end\n    end\n\n    context 'when tag does not exist' do\n      it 'returns http missing for non-existent tag' do\n        get :show, params: { id: 'none' }\n\n        expect(response).to have_http_status(404)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/well_known/host_meta_controller_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe WellKnown::HostMetaController, type: :controller do\n  render_views\n\n  describe 'GET #show' do\n    it 'returns http success' do\n      get :show, format: :xml\n\n      expect(response).to have_http_status(200)\n      expect(response.content_type).to eq 'application/xrd+xml'\n      expect(response.body).to eq <<XML\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<XRD xmlns=\"http://docs.oasis-open.org/ns/xri/xrd-1.0\">\n  <Link rel=\"lrdd\" type=\"application/xrd+xml\" template=\"https://cb6e6126.ngrok.io/.well-known/webfinger?resource={uri}\"/>\n</XRD>\nXML\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/well_known/keybase_proof_config_controller_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe WellKnown::KeybaseProofConfigController, type: :controller do\n  render_views\n\n  describe 'GET #show' do\n    it 'renders json' do\n      get :show\n\n      expect(response).to have_http_status(200)\n      expect(response.content_type).to eq 'application/json'\n      expect { JSON.parse(response.body) }.not_to raise_exception\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/well_known/webfinger_controller_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe WellKnown::WebfingerController, type: :controller do\n  render_views\n\n  describe 'GET #show' do\n    let(:alice) do\n      Fabricate(:account, username: 'alice')\n    end\n\n    before do\n      alice.private_key = <<-PEM\n-----BEGIN RSA PRIVATE KEY-----\nMIICXQIBAAKBgQDHgPoPJlrfMZrVcuF39UbVssa8r4ObLP3dYl9Y17Mgp5K4mSYD\nR/Y2ag58tSi6ar2zM3Ze3QYsNfTq0NqN1g89eAu0MbSjWqpOsgntRPJiFuj3hai2\nX2Im8TBrkiM/UyfTRgn8q8WvMoKbXk8Lu6nqv420eyqhhLxfUoCpxuem1QIDAQAB\nAoGBAIKsOh2eM7spVI8mdgQKheEG/iEsnPkQ2R8ehfE9JzjmSbXbqghQJDaz9NU+\nG3Uu4R31QT0VbCudE9SSA/UPFl82GeQG4QLjrSE+PSjSkuslgSXelJHfAJ+ycGax\najtPyiQD0e4c2loagHNHPjqK9OhHx9mFnZWmoagjlZ+mQGEpAkEA8GtqfS65IaRQ\nuVhMzpp25rF1RWOwaaa+vBPkd7pGdJEQGFWkaR/a9UkU+2C4ZxGBkJDP9FApKVQI\nRANEwN3/hwJBANRuw5+es6BgBv4PD387IJvuruW2oUtYP+Lb2Z5k77J13hZTr0db\nOo9j1UbbR0/4g+vAcsDl4JD9c/9LrGYEpcMCQBon9Yvs+2M3lziy7JhFoc3zXIjS\nEa1M4M9hcqe78lJYPeIH3z04o/+vlcLLgQRlmSz7NESmO/QtGkEcAezhuh0CQHji\npzO4LeO/gXslut3eGcpiYuiZquOjToecMBRwv+5AIKd367Che4uJdh6iPcyGURvh\nIewfZFFdyZqnx20ui90CQQC1W2rK5Y30wAunOtSLVA30TLK/tKrTppMC3corjKlB\nFTX8IvYBNTbpEttc1VCf/0ccnNpfb0CrFNSPWxRj7t7D\n-----END RSA PRIVATE KEY-----\nPEM\n\n      alice.public_key = <<-PEM\n-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHgPoPJlrfMZrVcuF39UbVssa8\nr4ObLP3dYl9Y17Mgp5K4mSYDR/Y2ag58tSi6ar2zM3Ze3QYsNfTq0NqN1g89eAu0\nMbSjWqpOsgntRPJiFuj3hai2X2Im8TBrkiM/UyfTRgn8q8WvMoKbXk8Lu6nqv420\neyqhhLxfUoCpxuem1QIDAQAB\n-----END PUBLIC KEY-----\nPEM\n\n      alice.save!\n    end\n\n    around(:each) do |example|\n      before = Rails.configuration.x.alternate_domains\n      example.run\n      Rails.configuration.x.alternate_domains = before\n    end\n\n    it 'returns JSON when account can be found' do\n      get :show, params: { resource: alice.to_webfinger_s }, format: :json\n\n      json = body_as_json\n\n      expect(response).to have_http_status(200)\n      expect(response.content_type).to eq 'application/jrd+json'\n      expect(json[:subject]).to eq 'acct:alice@cb6e6126.ngrok.io'\n      expect(json[:aliases]).to include('https://cb6e6126.ngrok.io/@alice', 'https://cb6e6126.ngrok.io/users/alice')\n    end\n\n    it 'returns JSON when account can be found' do\n      get :show, params: { resource: alice.to_webfinger_s }, format: :xml\n\n      xml = Nokogiri::XML(response.body)\n\n      expect(response).to have_http_status(200)\n      expect(response.content_type).to eq 'application/xrd+xml'\n      expect(xml.at_xpath('//xmlns:Subject').content).to eq 'acct:alice@cb6e6126.ngrok.io'\n      expect(xml.xpath('//xmlns:Alias').map(&:content)).to include('https://cb6e6126.ngrok.io/@alice', 'https://cb6e6126.ngrok.io/users/alice')\n    end\n\n    it 'returns http not found when account cannot be found' do\n      get :show, params: { resource: 'acct:not@existing.com' }, format: :json\n\n      expect(response).to have_http_status(:not_found)\n    end\n\n    it 'returns JSON when account can be found with alternate domains' do\n      Rails.configuration.x.alternate_domains = ['foo.org']\n      username, = alice.to_webfinger_s.split('@')\n\n      get :show, params: { resource: \"#{username}@foo.org\" }, format: :json\n\n      json = body_as_json\n\n      expect(response).to have_http_status(200)\n      expect(response.content_type).to eq 'application/jrd+json'\n      expect(json[:subject]).to eq 'acct:alice@cb6e6126.ngrok.io'\n      expect(json[:aliases]).to include('https://cb6e6126.ngrok.io/@alice', 'https://cb6e6126.ngrok.io/users/alice')\n    end\n\n    it 'returns http not found when account can not be found with alternate domains' do\n      Rails.configuration.x.alternate_domains = ['foo.org']\n      username, = alice.to_webfinger_s.split('@')\n\n      get :show, params: { resource: \"#{username}@bar.org\" }, format: :json\n\n      expect(response).to have_http_status(:not_found)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/fabricators/access_token_fabricator.rb",
    "content": "Fabricator :access_token, from: 'Doorkeeper::AccessToken' do\nend\n"
  },
  {
    "path": "spec/fabricators/accessible_access_token_fabricator.rb",
    "content": "Fabricator :accessible_access_token, from: :access_token do\n  expires_in { nil }\n  revoked_at { nil }\nend\n"
  },
  {
    "path": "spec/fabricators/account_domain_block_fabricator.rb",
    "content": "Fabricator(:account_domain_block) do\n  account\n  domain 'example.com'\nend\n"
  },
  {
    "path": "spec/fabricators/account_fabricator.rb",
    "content": "keypair     = OpenSSL::PKey::RSA.new(2048)\npublic_key  = keypair.public_key.to_pem\nprivate_key = keypair.to_pem\n\nFabricator(:account) do\n  transient :suspended, :silenced\n  username            { sequence(:username) { |i| \"#{Faker::Internet.user_name(nil, %w(_))}#{i}\" } }\n  last_webfingered_at { Time.now.utc }\n  public_key          { public_key }\n  private_key         { private_key }\n  suspended_at        { |attrs| attrs[:suspended] ? Time.now.utc : nil }\n  silenced_at         { |attrs| attrs[:silenced] ? Time.now.utc : nil }\nend\n"
  },
  {
    "path": "spec/fabricators/account_identity_proof_fabricator.rb",
    "content": "Fabricator(:account_identity_proof) do\n  account\n  provider 'keybase'\n  provider_username { sequence(:provider_username) { |i| \"#{Faker::Lorem.characters(15)}\" } }\n  token { sequence(:token) { |i| \"#{i}#{Faker::Crypto.sha1()*2}\"[0..65] } }\n  verified false\n  live false\nend\n"
  },
  {
    "path": "spec/fabricators/account_moderation_note_fabricator.rb",
    "content": "Fabricator(:account_moderation_note) do\n  content \"MyText\"\n  account nil\nend\n"
  },
  {
    "path": "spec/fabricators/account_pin_fabricator.rb",
    "content": "Fabricator(:account_pin) do\n  account        nil\n  target_account nil\nend\n"
  },
  {
    "path": "spec/fabricators/account_stat_fabricator.rb",
    "content": "Fabricator(:account_stat) do\n  account         nil\n  statuses_count  \"\"\n  following_count \"\"\n  followers_count \"\"\nend\n"
  },
  {
    "path": "spec/fabricators/account_tag_stat_fabricator.rb",
    "content": "Fabricator(:account_tag_stat) do\n  accounts_count \"\"\nend\n"
  },
  {
    "path": "spec/fabricators/account_warning_fabricator.rb",
    "content": "Fabricator(:account_warning) do\n  account        nil\n  target_account nil\n  text           \"MyText\"\nend\n"
  },
  {
    "path": "spec/fabricators/account_warning_preset_fabricator.rb",
    "content": "Fabricator(:account_warning_preset) do\n  text \"MyText\"\nend\n"
  },
  {
    "path": "spec/fabricators/admin_action_log_fabricator.rb",
    "content": "Fabricator('Admin::ActionLog') do\n  account nil\n  action  \"MyString\"\n  target  nil\nend\n"
  },
  {
    "path": "spec/fabricators/application_fabricator.rb",
    "content": "Fabricator(:application, from: Doorkeeper::Application) do\n  name         'Example'\n  website      'http://example.com'\n  redirect_uri 'http://example.com/callback'\nend\n"
  },
  {
    "path": "spec/fabricators/assets/TEAPOT",
    "content": "This \"Utah teapot\" photograph is licensed under the Creative Commons\nAttribution-Share Alike 3.0 Unported license:\n  https://creativecommons.org/licenses/by-sa/3.0/deed.en\n\nOriginal source of work:\n  https://commons.wikimedia.org/wiki/File:Utah_teapot_simple_2.png\n"
  },
  {
    "path": "spec/fabricators/backup_fabricator.rb",
    "content": "Fabricator(:backup) do\n  user\nend\n"
  },
  {
    "path": "spec/fabricators/block_fabricator.rb",
    "content": "Fabricator(:block) do\n  account\n  target_account { Fabricate(:account) }\nend\n"
  },
  {
    "path": "spec/fabricators/conversation_account_fabricator.rb",
    "content": "Fabricator(:conversation_account) do\n  account                 nil\n  conversation            nil\n  participant_account_ids \"\"\n  last_status             nil\nend\n"
  },
  {
    "path": "spec/fabricators/conversation_fabricator.rb",
    "content": "Fabricator(:conversation) do\nend\n"
  },
  {
    "path": "spec/fabricators/conversation_mute_fabricator.rb",
    "content": "Fabricator(:conversation_mute) do\nend\n"
  },
  {
    "path": "spec/fabricators/custom_emoji_fabricator.rb",
    "content": "Fabricator(:custom_emoji) do\n  shortcode 'coolcat'\n  domain    nil\n  image     { File.open(Rails.root.join('spec', 'fixtures', 'files', 'emojo.png')) }\nend\n"
  },
  {
    "path": "spec/fabricators/custom_filter_fabricator.rb",
    "content": "Fabricator(:custom_filter) do\n  account\n  expires_at nil\n  phrase     'discourse'\n  context    %w(home notifications)\nend\n"
  },
  {
    "path": "spec/fabricators/domain_block_fabricator.rb",
    "content": "Fabricator(:domain_block) do\n  domain { sequence(:domain) { |i| \"#{i}#{Faker::Internet.domain_name}\" } }\nend\n"
  },
  {
    "path": "spec/fabricators/email_domain_block_fabricator.rb",
    "content": "Fabricator(:email_domain_block) do\n  domain { sequence(:domain) { |i| \"#{i}#{Faker::Internet.domain_name}\" } }\nend\n"
  },
  {
    "path": "spec/fabricators/favourite_fabricator.rb",
    "content": "Fabricator(:favourite) do\n  account\n  status\nend\n"
  },
  {
    "path": "spec/fabricators/featured_tag_fabricator.rb",
    "content": "Fabricator(:featured_tag) do\n  account\n  tag\n  statuses_count 1_337\n  last_status_at Time.now.utc\nend\n"
  },
  {
    "path": "spec/fabricators/follow_fabricator.rb",
    "content": "Fabricator(:follow) do\n  account\n  target_account { Fabricate(:account) }\nend\n"
  },
  {
    "path": "spec/fabricators/follow_request_fabricator.rb",
    "content": "Fabricator(:follow_request) do\n  account\n  target_account { Fabricate(:account, locked: true) }\nend\n"
  },
  {
    "path": "spec/fabricators/identity_fabricator.rb",
    "content": "Fabricator(:identity) do\n  user     nil\n  provider \"MyString\"\n  uid      \"MyString\"\nend\n"
  },
  {
    "path": "spec/fabricators/import_fabricator.rb",
    "content": "Fabricator(:import) do\nend\n"
  },
  {
    "path": "spec/fabricators/invite_fabricator.rb",
    "content": "Fabricator(:invite) do\n  user\n  expires_at nil\n  max_uses   nil\n  uses       0\nend\n"
  },
  {
    "path": "spec/fabricators/list_account_fabricator.rb",
    "content": "Fabricator(:list_account) do\n  list    nil\n  account nil\n  follow  nil\nend\n"
  },
  {
    "path": "spec/fabricators/list_fabricator.rb",
    "content": "Fabricator(:list) do\n  account\n  title \"MyString\"\nend\n"
  },
  {
    "path": "spec/fabricators/media_attachment_fabricator.rb",
    "content": "Fabricator(:media_attachment) do\n  account\n  file do |attrs|\n    [\n      case attrs[:type]\n      when :gifv\n        attachment_fixture ['attachment.gif', 'attachment.webm'].sample\n      when :image\n        attachment_fixture 'attachment.jpg'\n      when nil\n        attachment_fixture ['attachment.gif', 'attachment.jpg', 'attachment.webm'].sample\n      end,\n      nil\n    ].sample\n  end\nend\n"
  },
  {
    "path": "spec/fabricators/mention_fabricator.rb",
    "content": "Fabricator(:mention) do\n  account\n  status\nend\n"
  },
  {
    "path": "spec/fabricators/mute_fabricator.rb",
    "content": "Fabricator(:mute) do\n  account\n  target_account { Fabricate(:account) }\nend\n"
  },
  {
    "path": "spec/fabricators/notification_fabricator.rb",
    "content": "Fabricator(:notification) do\n  activity fabricator: [:mention, :status, :follow, :follow_request, :favourite].sample\n  account\nend\n"
  },
  {
    "path": "spec/fabricators/poll_fabricator.rb",
    "content": "Fabricator(:poll) do\n  account\n  status\n  expires_at  { 7.days.from_now }\n  options     %w(Foo Bar)\n  multiple    false\n  hide_totals false\nend\n"
  },
  {
    "path": "spec/fabricators/poll_vote_fabricator.rb",
    "content": "Fabricator(:poll_vote) do\n  account\n  poll\n  choice  0\nend\n"
  },
  {
    "path": "spec/fabricators/relay_fabricator.rb",
    "content": "Fabricator(:relay) do\n  inbox_url \"https://example.com/inbox\"\n  state :idle\nend\n"
  },
  {
    "path": "spec/fabricators/report_fabricator.rb",
    "content": "Fabricator(:report) do\n  account\n  target_account { Fabricate(:account) }\n  comment      \"You nasty\"\n  action_taken false\nend\n"
  },
  {
    "path": "spec/fabricators/report_note_fabricator.rb",
    "content": "Fabricator(:report_note) do\n  report\n  account { Fabricate(:account) }\n  content \"Test Content\"\nend\n"
  },
  {
    "path": "spec/fabricators/scheduled_status_fabricator.rb",
    "content": "Fabricator(:scheduled_status) do\n  account\n  scheduled_at { 20.hours.from_now }\nend\n"
  },
  {
    "path": "spec/fabricators/session_activation_fabricator.rb",
    "content": "Fabricator(:session_activation) do\n  user\n  session_id \"MyString\"\nend\n"
  },
  {
    "path": "spec/fabricators/setting_fabricator.rb",
    "content": "# frozen_string_literal: true\n\nFabricator(:setting) do\nend\n"
  },
  {
    "path": "spec/fabricators/site_upload_fabricator.rb",
    "content": "Fabricator(:site_upload) do\n  file { File.open(File.join(Rails.root, 'spec', 'fabricators', 'assets', 'utah_teapot.png')) }\nend\n"
  },
  {
    "path": "spec/fabricators/status_fabricator.rb",
    "content": "Fabricator(:status) do\n  account\n  text \"Lorem ipsum dolor sit amet\"\n\n  after_build do |status|\n    status.uri = Faker::Internet.device_token if !status.account.local? && status.uri.nil?\n  end\nend\n"
  },
  {
    "path": "spec/fabricators/status_pin_fabricator.rb",
    "content": "Fabricator(:status_pin) do\n  account\n  status\nend\n"
  },
  {
    "path": "spec/fabricators/status_stat_fabricator.rb",
    "content": "Fabricator(:status_stat) do\n  status_id        nil\n  replies_count    \"\"\n  reblogs_count    \"\"\n  favourites_count \"\"\nend\n"
  },
  {
    "path": "spec/fabricators/stream_entry_fabricator.rb",
    "content": "Fabricator(:stream_entry) do\n  account\n  activity { Fabricate(:status) }\n  hidden { [true, false].sample }\nend\n"
  },
  {
    "path": "spec/fabricators/subscription_fabricator.rb",
    "content": "Fabricator(:subscription) do\n  account\n  callback_url \"http://example.com/callback\"\n  secret       \"foobar\"\n  expires_at   \"2016-11-28 11:30:07\"\n  confirmed    false\nend\n"
  },
  {
    "path": "spec/fabricators/tag_fabricator.rb",
    "content": "Fabricator(:tag) do\n  name { sequence(:hashtag) { |i| \"#{Faker::Lorem.word}#{i}\" } }\nend\n"
  },
  {
    "path": "spec/fabricators/user_fabricator.rb",
    "content": "Fabricator(:user) do\n  account\n  email        { sequence(:email) { |i| \"#{i}#{Faker::Internet.email}\" } }\n  password     \"123456789\"\n  confirmed_at { Time.zone.now }\n  agreement    true\nend\n"
  },
  {
    "path": "spec/fabricators/user_invite_request_fabricator.rb",
    "content": "Fabricator(:user_invite_request) do\n  user\n  text { Faker::Lorem.sentence }\nend\n"
  },
  {
    "path": "spec/fabricators/web_push_subscription_fabricator.rb",
    "content": "Fabricator(:web_push_subscription, from: Web::PushSubscription) do\n  endpoint   Faker::Internet.url\n  key_p256dh Faker::Internet.password\n  key_auth   Faker::Internet.password\nend\n"
  },
  {
    "path": "spec/fabricators/web_setting_fabricator.rb",
    "content": "Fabricator(:web_setting, from: Web::Setting) do\nend\n"
  },
  {
    "path": "spec/features/log_in_spec.rb",
    "content": "require \"rails_helper\"\n\nfeature \"Log in\" do\n  given(:email)        { \"test@examle.com\" }\n  given(:password)     { \"password\" }\n  given(:confirmed_at) { Time.zone.now }\n\n  background do\n    Fabricate(:user, email: email, password: password, confirmed_at: confirmed_at)\n    visit new_user_session_path\n  end\n\n  subject { page }\n\n  scenario \"A valid email and password user is able to log in\" do\n    fill_in \"user_email\", with: email\n    fill_in \"user_password\", with: password\n    click_on I18n.t('auth.login')\n\n    is_expected.to have_css(\"div.app-holder\")\n  end\n\n  scenario \"A invalid email and password user is not able to log in\" do\n    fill_in \"user_email\", with: \"invalid_email\"\n    fill_in \"user_password\", with: \"invalid_password\"\n    click_on I18n.t('auth.login')\n\n    is_expected.to have_css(\".flash-message\", text: failure_message(\"invalid\"))\n  end\n\n  context do\n    given(:confirmed_at) { nil }\n\n    scenario \"A unconfirmed user is not able to log in\" do\n      fill_in \"user_email\", with: email\n      fill_in \"user_password\", with: password\n      click_on I18n.t('auth.login')\n\n      is_expected.to have_css(\".flash-message\", text: failure_message(\"unconfirmed\"))\n    end\n  end\n\n  def failure_message(message)\n    keys = User.authentication_keys.map { |key| User.human_attribute_name(key) }\n    I18n.t(\"devise.failure.#{message}\", authentication_keys: keys.join(\"support.array.words_connector\"))\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/files/imports.txt",
    "content": "user@example.com\n\nuser@test.com\n"
  },
  {
    "path": "spec/fixtures/files/mute-imports.txt",
    "content": "bob\n\neve@example.com\n\n"
  },
  {
    "path": "spec/fixtures/files/new-following-imports.txt",
    "content": "Account address,Show boosts\nbob,true\neve@example.com,false\n\n"
  },
  {
    "path": "spec/fixtures/files/new-mute-imports.txt",
    "content": "Account address,Hide notifications\nbob,true\neve@example.com,false\n\n"
  },
  {
    "path": "spec/fixtures/push/feed.atom",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<feed xml:lang=\"en-US\" xmlns=\"http://www.w3.org/2005/Atom\" xmlns:thr=\"http://purl.org/syndication/thread/1.0\" xmlns:georss=\"http://www.georss.org/georss\" xmlns:activity=\"http://activitystrea.ms/spec/1.0/\" xmlns:media=\"http://purl.org/syndication/atommedia\" xmlns:poco=\"http://portablecontacts.net/spec/1.0\" xmlns:ostatus=\"http://ostatus.org/schema/1.0\" xmlns:statusnet=\"http://status.net/schema/api/1/\">\n <generator uri=\"https://gnu.io/social\" version=\"1.2.0-beta4\">GNU social</generator>\n <id>https://quitter.no/api/statuses/user_timeline/7477.atom</id>\n <title>gargron timeline</title>\n <subtitle>Updates from gargron on Quitter.no!</subtitle>\n <logo>https://quitter.no/avatar/7477-96-20160211190340.png</logo>\n <updated>2016-03-20T12:42:58+01:00</updated>\n<author>\n <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>\n <uri>https://quitter.no/user/7477</uri>\n <name>gargron</name>\n <summary>Software engineer, free time musician and ＤＩＧＩＴＡＬ ＳＰＯＲＴＳ enthusiast. Likes cats. Warning: May contain memes</summary>\n <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/gargron\"/>\n <link rel=\"avatar\" type=\"image/png\" media:width=\"300\" media:height=\"300\" href=\"https://quitter.no/avatar/7477-300-20160211190340.png\"/>\n <link rel=\"avatar\" type=\"image/png\" media:width=\"96\" media:height=\"96\" href=\"https://quitter.no/avatar/7477-96-20160211190340.png\"/>\n <link rel=\"avatar\" type=\"image/png\" media:width=\"48\" media:height=\"48\" href=\"https://quitter.no/avatar/7477-48-20160211190449.png\"/>\n <link rel=\"avatar\" type=\"image/png\" media:width=\"24\" media:height=\"24\" href=\"https://quitter.no/avatar/7477-24-20160211190517.png\"/>\n <poco:preferredUsername>gargron</poco:preferredUsername>\n <poco:displayName>ＤＩＧＩＴＡＬ ＣＡＴ</poco:displayName>\n <poco:note>Software engineer, free time musician and ＤＩＧＩＴＡＬ ＳＰＯＲＴＳ enthusiast. Likes cats. Warning: May contain memes</poco:note>\n <poco:address>\n  <poco:formatted>Germany</poco:formatted>\n </poco:address>\n <poco:urls>\n  <poco:type>homepage</poco:type>\n  <poco:value>https://zeonfederated.com</poco:value>\n  <poco:primary>true</poco:primary>\n </poco:urls>\n <followers url=\"https://quitter.no/gargron/subscribers\"></followers>\n <statusnet:profile_info local_id=\"7477\"></statusnet:profile_info>\n</author>\n <link href=\"https://quitter.no/gargron\" rel=\"alternate\" type=\"text/html\"/>\n <link href=\"https://quitter.no/main/sup\" rel=\"http://api.friendfeed.com/2008/03#sup\" type=\"application/json\"/>\n <link href=\"https://quitter.no/api/statuses/user_timeline/7477.atom?max_id=1243309\" rel=\"next\" type=\"application/atom+xml\"/>\n <link href=\"https://quitter.no/main/push/hub\" rel=\"hub\"/>\n <link href=\"https://quitter.no/main/salmon/user/7477\" rel=\"salmon\"/>\n <link href=\"https://quitter.no/main/salmon/user/7477\" rel=\"http://salmon-protocol.org/ns/salmon-replies\"/>\n <link href=\"https://quitter.no/main/salmon/user/7477\" rel=\"http://salmon-protocol.org/ns/salmon-mention\"/>\n <link href=\"https://quitter.no/api/statuses/user_timeline/7477.atom\" rel=\"self\" type=\"application/atom+xml\"/>\n<entry>\n <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>\n <id>tag:quitter.no,2016-03-20:noticeId=1276923:objectType=note</id>\n <title>New note by gargron</title>\n <content type=\"html\">@&lt;a href=&quot;https://cb6e6126.ngrok.io/users/catsrgr8&quot; class=&quot;h-card mention&quot;&gt;catsrgr8&lt;/a&gt; this is a mention</content>\n <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1276923\"/>\n <status_net notice_id=\"1276923\"></status_net>\n <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>\n <published>2016-03-20T11:05:31+00:00</published>\n <updated>2016-03-20T11:05:31+00:00</updated>\n <link rel=\"ostatus:conversation\" href=\"tag:quitter.no,2016-03-20:objectType=thread:nonce=7c998112e39a6685\"/>\n <ostatus:conversation>tag:quitter.no,2016-03-20:objectType=thread:nonce=7c998112e39a6685</ostatus:conversation>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/person\" href=\"https://cb6e6126.ngrok.io/users/catsrgr8\"/>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/collection\" href=\"http://activityschema.org/collection/public\"/>\n <link rel=\"self\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1276923.atom\"/>\n <link rel=\"edit\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1276923.atom\"/>\n <statusnet:notice_info local_id=\"1276923\" source=\"Qvitter\"></statusnet:notice_info>\n</entry>\n<entry>\n <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>\n <id>tag:quitter.no,2016-03-19:noticeId=1273635:objectType=note</id>\n <title>New note by gargron</title>\n <content type=\"html\">Just testing a thing.</content>\n <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1273635\"/>\n <status_net notice_id=\"1273635\"></status_net>\n <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>\n <published>2016-03-19T20:35:53+00:00</published>\n <updated>2016-03-19T20:35:53+00:00</updated>\n <link rel=\"ostatus:conversation\" href=\"tag:quitter.no,2016-03-19:objectType=thread:nonce=c4a61886d5cad4c2\"/>\n <ostatus:conversation>tag:quitter.no,2016-03-19:objectType=thread:nonce=c4a61886d5cad4c2</ostatus:conversation>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/person\" href=\"https://mastodon.social/users/Gargron\"/>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/collection\" href=\"http://activityschema.org/collection/public\"/>\n <link rel=\"self\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1273635.atom\"/>\n <link rel=\"edit\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1273635.atom\"/>\n <statusnet:notice_info local_id=\"1273635\" source=\"web\"></statusnet:notice_info>\n</entry>\n<entry>\n <id>tag:quitter.no,2016-03-19:noticeId=1272988:objectType=note</id>\n <title>Delete</title>\n <content type=\"html\">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt;ＤＩＧＩＴＡＬ ＣＡＴ&lt;/a&gt; deleted notice &lt;a href=&quot;https://quitter.no/notice/1272988&quot;&gt;{{tag:quitter.no,2016-03-19:noticeId=1272988:objectType=note}}&lt;/a&gt;.</content>\n <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1273012\"/>\n <activity:verb>delete</activity:verb>\n <published>2016-03-19T18:16:58+00:00</published>\n <updated>2016-03-19T18:16:58+00:00</updated>\n <activity:object>\n  <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>\n  <id>tag:quitter.no,2016-03-19:noticeId=1272988:objectType=note</id>\n </activity:object>\n <link rel=\"ostatus:conversation\" href=\"tag:quitter.no,2016-03-19:objectType=thread:nonce=7913e6b6256b6d0b\"/>\n <ostatus:conversation>tag:quitter.no,2016-03-19:objectType=thread:nonce=7913e6b6256b6d0b</ostatus:conversation>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/collection\" href=\"http://activityschema.org/collection/public\"/>\n <activity:target>\n  <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>\n  <id>tag:quitter.no,2016-03-19:noticeId=1272988:objectType=note</id>\n </activity:target>\n <link rel=\"self\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1273012.atom\"/>\n <link rel=\"edit\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1273012.atom\"/>\n <statusnet:notice_info local_id=\"1273012\" source=\"unknown\"></statusnet:notice_info>\n</entry>\n<entry>\n <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>\n <id>tag:quitter.no,2016-03-19:noticeId=1269381:objectType=comment</id>\n <title>New comment by gargron</title>\n <content type=\"html\">@&lt;a href=&quot;https://mastodon.social/users/Gargron&quot; class=&quot;h-card mention&quot; title=&quot;Eugen&quot;&gt;gargron&lt;/a&gt; I have to wonder if this will appear as a reply to the right status, and not just a mention.</content>\n <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1269381\"/>\n <status_net notice_id=\"1269381\"></status_net>\n <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>\n <published>2016-03-19T00:10:14+00:00</published>\n <updated>2016-03-19T00:10:14+00:00</updated>\n <thr:in-reply-to ref=\"tag:mastodon.social,2016-03-18:objectId=60:objectType=Status\" href=\"https://quitter.no/notice/1269244\"></thr:in-reply-to>\n <link rel=\"related\" href=\"https://quitter.no/notice/1269244\"/>\n <link rel=\"ostatus:conversation\" href=\"tag:quitter.no,2016-03-18:objectType=thread:nonce=d05c6330fbe23fb9\"/>\n <ostatus:conversation>tag:quitter.no,2016-03-18:objectType=thread:nonce=d05c6330fbe23fb9</ostatus:conversation>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/person\" href=\"https://mastodon.social/users/Gargron\"/>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/collection\" href=\"http://activityschema.org/collection/public\"/>\n <link rel=\"self\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1269381.atom\"/>\n <link rel=\"edit\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1269381.atom\"/>\n <statusnet:notice_info local_id=\"1269381\" source=\"Qvitter\"></statusnet:notice_info>\n</entry>\n<entry>\n <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>\n <id>tag:quitter.no,2016-03-18:noticeId=1265337:objectType=comment</id>\n <title>New comment by gargron</title>\n <content type=\"html\">@&lt;a href=&quot;https://community.highlandarrow.com/user/1&quot; class=&quot;h-card mention&quot; title=&quot;Maiyannah Bishop&quot;&gt;maiyannah&lt;/a&gt; Plus, Android can hardly be considered free software given how many proprietary blobs are used. I'm speaking as a disappointed Android user.</content>\n <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1265337\"/>\n <status_net notice_id=\"1265337\"></status_net>\n <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>\n <published>2016-03-18T10:01:50+00:00</published>\n <updated>2016-03-18T10:01:50+00:00</updated>\n <thr:in-reply-to ref=\"tag:quitter.no,2016-03-18:noticeId=1265331:objectType=comment\" href=\"https://quitter.no/notice/1265331\"></thr:in-reply-to>\n <link rel=\"related\" href=\"https://quitter.no/notice/1265331\"/>\n <link rel=\"ostatus:conversation\" href=\"tag:community.highlandarrow.com,2016-03-18:objectType=thread:nonce=d61438407b882959\"/>\n <ostatus:conversation>tag:community.highlandarrow.com,2016-03-18:objectType=thread:nonce=d61438407b882959</ostatus:conversation>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/person\" href=\"https://quitter.no/user/7477\"/>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/person\" href=\"https://community.highlandarrow.com/user/1\"/>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/collection\" href=\"http://activityschema.org/collection/public\"/>\n <link rel=\"self\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1265337.atom\"/>\n <link rel=\"edit\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1265337.atom\"/>\n <statusnet:notice_info local_id=\"1265337\" source=\"Qvitter\"></statusnet:notice_info>\n</entry>\n<entry>\n <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>\n <id>tag:quitter.no,2016-03-18:noticeId=1265331:objectType=comment</id>\n <title>New comment by gargron</title>\n <content type=\"html\">@&lt;a href=&quot;https://community.highlandarrow.com/user/1&quot; class=&quot;h-card mention&quot; title=&quot;Maiyannah Bishop&quot;&gt;maiyannah&lt;/a&gt; Well as it turns out, Apple software is better than Android in terms of security, and Apple is fighting FBI while Google promised to build a messaging app that facilitates wire tapping. The whole free software thing should imo be considered a bonus and not overshadow other factors.</content>\n <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1265331\"/>\n <status_net notice_id=\"1265331\"></status_net>\n <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>\n <published>2016-03-18T10:01:01+00:00</published>\n <updated>2016-03-18T10:01:01+00:00</updated>\n <thr:in-reply-to ref=\"tag:community.highlandarrow.com,2016-03-18:noticeId=54411:objectType=note\" href=\"https://community.highlandarrow.com/notice/54411\"></thr:in-reply-to>\n <link rel=\"related\" href=\"https://community.highlandarrow.com/notice/54411\"/>\n <link rel=\"ostatus:conversation\" href=\"tag:community.highlandarrow.com,2016-03-18:objectType=thread:nonce=d61438407b882959\"/>\n <ostatus:conversation>tag:community.highlandarrow.com,2016-03-18:objectType=thread:nonce=d61438407b882959</ostatus:conversation>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/person\" href=\"https://community.highlandarrow.com/user/1\"/>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/collection\" href=\"http://activityschema.org/collection/public\"/>\n <link rel=\"self\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1265331.atom\"/>\n <link rel=\"edit\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1265331.atom\"/>\n <statusnet:notice_info local_id=\"1265331\" source=\"Qvitter\"></statusnet:notice_info>\n</entry>\n<entry>\n <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>\n <id>tag:quitter.no,2016-03-17:noticeId=1261358:objectType=comment</id>\n <title>New comment by gargron</title>\n <content type=\"html\">@&lt;a href=&quot;https://community.highlandarrow.com/user/1&quot; class=&quot;h-card mention&quot; title=&quot;Maiyannah Bishop&quot;&gt;maiyannah&lt;/a&gt; @&lt;a href=&quot;https://gs.kawa-kun.com/user/2&quot; class=&quot;h-card mention&quot; title=&quot;&amp;#x7AF9;&amp;#x4E0B;&amp;#x61B2;&amp;#x4E8C;&quot;&gt;takeshitakenji&lt;/a&gt; There is a reason that was deprecated and we don't use tables to design websites anymore. HTML needs to be semantic, i.e. tags need to describe the *kind* of content, not how it should *look*, which is a responsibility delegated to CSS. There are so many upsides to this separation of concerns, should I start listing?</content>\n <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1261358\"/>\n <status_net notice_id=\"1261358\"></status_net>\n <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>\n <published>2016-03-17T17:00:26+00:00</published>\n <updated>2016-03-17T17:00:26+00:00</updated>\n <thr:in-reply-to ref=\"tag:community.highlandarrow.com,2016-03-17:noticeId=53857:objectType=comment\" href=\"https://community.highlandarrow.com/notice/53857\"></thr:in-reply-to>\n <link rel=\"related\" href=\"https://community.highlandarrow.com/notice/53857\"/>\n <link rel=\"ostatus:conversation\" href=\"tag:gs.kawa-kun.com,2016-03-17:objectType=thread:nonce=a83963573a0520f1\"/>\n <ostatus:conversation>tag:gs.kawa-kun.com,2016-03-17:objectType=thread:nonce=a83963573a0520f1</ostatus:conversation>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/person\" href=\"https://community.highlandarrow.com/user/1\"/>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/person\" href=\"https://gs.kawa-kun.com/user/2\"/>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/collection\" href=\"http://activityschema.org/collection/public\"/>\n <link rel=\"self\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1261358.atom\"/>\n <link rel=\"edit\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1261358.atom\"/>\n <statusnet:notice_info local_id=\"1261358\" source=\"Qvitter\"></statusnet:notice_info>\n</entry>\n<entry>\n <id>tag:quitter.no,2016-03-16:subscription:7477:person:15743:2016-03-16T21:24:13+01:00</id>\n <title>ＤＩＧＩＴＡＬ ＣＡＴ (gargron)'s status on Wednesday, 16-Mar-2016 21:24:13 CET</title>\n <content type=\"html\">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt;ＤＩＧＩＴＡＬ ＣＡＴ&lt;/a&gt; started following &lt;a href=&quot;https://mastodon.social/users/Gargron&quot;&gt;Eugen&lt;/a&gt;.</content>\n <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1256972\"/>\n <activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb>\n <published>2016-03-16T20:24:13+00:00</published>\n <updated>2016-03-16T20:24:13+00:00</updated>\n <activity:object>\n  <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>\n  <id>https://mastodon.social/users/Gargron</id>\n  <title>Eugen</title>\n  <summary>Software engineer, free time musician and ＤＩＧＩＴＡＬ ＳＰＯＲＴＳ enthusiast. Likes cats. Warning: May contain memes</summary>\n  <link rel=\"alternate\" type=\"text/html\" href=\"https://mastodon.social/users/Gargron\"/>\n  <link rel=\"avatar\" type=\"image/gif\" media:width=\"96\" media:height=\"96\" href=\"https://quitter.no/avatar/15743-original-20160316180410.gif\"/>\n  <link rel=\"avatar\" type=\"image/gif\" media:width=\"96\" media:height=\"96\" href=\"https://quitter.no/avatar/15743-original-20160316180410.gif\"/>\n  <link rel=\"avatar\" type=\"image/gif\" media:width=\"48\" media:height=\"48\" href=\"https://quitter.no/avatar/15743-48-20160316180416.gif\"/>\n  <link rel=\"avatar\" type=\"image/gif\" media:width=\"24\" media:height=\"24\" href=\"https://quitter.no/avatar/15743-24-20160316180416.gif\"/>\n  <poco:preferredUsername>gargron</poco:preferredUsername>\n  <poco:displayName>Eugen</poco:displayName>\n  <poco:note>Software engineer, free time musician and ＤＩＧＩＴＡＬ ＳＰＯＲＴＳ enthusiast. Likes cats. Warning: May contain memes</poco:note>\n </activity:object>\n <link rel=\"ostatus:conversation\" href=\"tag:quitter.no,2016-03-16:objectType=thread:nonce=073bda8223dfcaa7\"/>\n <ostatus:conversation>tag:quitter.no,2016-03-16:objectType=thread:nonce=073bda8223dfcaa7</ostatus:conversation>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/collection\" href=\"http://activityschema.org/collection/public\"/>\n <link rel=\"self\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1256972.atom\"/>\n <link rel=\"edit\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1256972.atom\"/>\n <statusnet:notice_info local_id=\"1256972\" source=\"activity\"></statusnet:notice_info>\n</entry>\n<entry>\n <id>tag:quitter.no,2016-03-16:subscription:7477:person:15743:2016-03-16T21:22:38+01:00</id>\n <title></title>\n <content type=\"html\">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt;ＤＩＧＩＴＡＬ ＣＡＴ&lt;/a&gt; started following &lt;a href=&quot;https://mastodon.social/users/Gargron&quot;&gt;Eugen&lt;/a&gt;.</content>\n <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1256966\"/>\n <activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb>\n <published>2016-03-16T20:22:38+00:00</published>\n <updated>2016-03-16T20:22:38+00:00</updated>\n <activity:object>\n  <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>\n  <id>tag:quitter.no,2016-03-16:subscription:7477:person:15743:2016-03-16T21:22:38+01:00</id>\n  <title>New person by gargron</title>\n  <content type=\"html\">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt;ＤＩＧＩＴＡＬ ＣＡＴ&lt;/a&gt; started following &lt;a href=&quot;https://mastodon.social/users/Gargron&quot;&gt;Eugen&lt;/a&gt;.</content>\n  <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1256966\"/>\n  <status_net notice_id=\"1256966\"></status_net>\n </activity:object>\n <link rel=\"ostatus:conversation\" href=\"tag:quitter.no,2016-03-16:objectType=thread:nonce=b157f676181e0ecd\"/>\n <ostatus:conversation>tag:quitter.no,2016-03-16:objectType=thread:nonce=b157f676181e0ecd</ostatus:conversation>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/collection\" href=\"http://activityschema.org/collection/public\"/>\n <link rel=\"self\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1256966.atom\"/>\n <link rel=\"edit\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1256966.atom\"/>\n <statusnet:notice_info local_id=\"1256966\" source=\"activity\"></statusnet:notice_info>\n</entry>\n<entry>\n <id>tag:quitter.no,2016-03-16:subscription:7477:person:15743:2016-03-16T21:16:14+01:00</id>\n <title></title>\n <content type=\"html\">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt;ＤＩＧＩＴＡＬ ＣＡＴ&lt;/a&gt; started following &lt;a href=&quot;https://mastodon.social/users/Gargron&quot;&gt;Eugen&lt;/a&gt;.</content>\n <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1256939\"/>\n <activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb>\n <published>2016-03-16T20:16:15+00:00</published>\n <updated>2016-03-16T20:16:15+00:00</updated>\n <activity:object>\n  <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>\n  <id>tag:quitter.no,2016-03-16:subscription:7477:person:15743:2016-03-16T21:16:14+01:00</id>\n  <title>New person by gargron</title>\n  <content type=\"html\">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt;ＤＩＧＩＴＡＬ ＣＡＴ&lt;/a&gt; started following &lt;a href=&quot;https://mastodon.social/users/Gargron&quot;&gt;Eugen&lt;/a&gt;.</content>\n  <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1256939\"/>\n  <status_net notice_id=\"1256939\"></status_net>\n </activity:object>\n <link rel=\"ostatus:conversation\" href=\"tag:quitter.no,2016-03-16:objectType=thread:nonce=6a6ebd1ed6504a11\"/>\n <ostatus:conversation>tag:quitter.no,2016-03-16:objectType=thread:nonce=6a6ebd1ed6504a11</ostatus:conversation>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/collection\" href=\"http://activityschema.org/collection/public\"/>\n <link rel=\"self\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1256939.atom\"/>\n <link rel=\"edit\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1256939.atom\"/>\n <statusnet:notice_info local_id=\"1256939\" source=\"activity\"></statusnet:notice_info>\n</entry>\n<entry>\n <id>tag:quitter.no,2016-03-16:subscription:7477:person:15750:2016-03-16T21:13:06+01:00</id>\n <title></title>\n <content type=\"html\">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt;ＤＩＧＩＴＡＬ ＣＡＴ&lt;/a&gt; started following &lt;a href=&quot;https://acda7931.ngrok.io/users/catsrgr8&quot;&gt;Eugen&lt;/a&gt;.</content>\n <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1256929\"/>\n <activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb>\n <published>2016-03-16T20:13:06+00:00</published>\n <updated>2016-03-16T20:13:06+00:00</updated>\n <activity:object>\n  <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>\n  <id>tag:quitter.no,2016-03-16:subscription:7477:person:15750:2016-03-16T21:13:06+01:00</id>\n  <title>New person by gargron</title>\n  <content type=\"html\">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt;ＤＩＧＩＴＡＬ ＣＡＴ&lt;/a&gt; started following &lt;a href=&quot;https://acda7931.ngrok.io/users/catsrgr8&quot;&gt;Eugen&lt;/a&gt;.</content>\n  <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1256929\"/>\n  <status_net notice_id=\"1256929\"></status_net>\n </activity:object>\n <link rel=\"ostatus:conversation\" href=\"tag:quitter.no,2016-03-16:objectType=thread:nonce=8f5f92443584e8f0\"/>\n <ostatus:conversation>tag:quitter.no,2016-03-16:objectType=thread:nonce=8f5f92443584e8f0</ostatus:conversation>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/collection\" href=\"http://activityschema.org/collection/public\"/>\n <link rel=\"self\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1256929.atom\"/>\n <link rel=\"edit\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1256929.atom\"/>\n <statusnet:notice_info local_id=\"1256929\" source=\"activity\"></statusnet:notice_info>\n</entry>\n<entry>\n <id>tag:quitter.no,2016-03-16:subscription:7477:person:15750:2016-03-16T21:05:02+01:00</id>\n <title></title>\n <content type=\"html\">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt;ＤＩＧＩＴＡＬ ＣＡＴ&lt;/a&gt; started following &lt;a href=&quot;https://acda7931.ngrok.io/users/catsrgr8&quot;&gt;Eugen&lt;/a&gt;.</content>\n <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1256888\"/>\n <activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb>\n <published>2016-03-16T20:05:03+00:00</published>\n <updated>2016-03-16T20:05:03+00:00</updated>\n <activity:object>\n  <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>\n  <id>tag:quitter.no,2016-03-16:subscription:7477:person:15750:2016-03-16T21:05:02+01:00</id>\n  <title>New person by gargron</title>\n  <content type=\"html\">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt;ＤＩＧＩＴＡＬ ＣＡＴ&lt;/a&gt; started following &lt;a href=&quot;https://acda7931.ngrok.io/users/catsrgr8&quot;&gt;Eugen&lt;/a&gt;.</content>\n  <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1256888\"/>\n  <status_net notice_id=\"1256888\"></status_net>\n </activity:object>\n <link rel=\"ostatus:conversation\" href=\"tag:quitter.no,2016-03-16:objectType=thread:nonce=b630d235232fcff5\"/>\n <ostatus:conversation>tag:quitter.no,2016-03-16:objectType=thread:nonce=b630d235232fcff5</ostatus:conversation>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/collection\" href=\"http://activityschema.org/collection/public\"/>\n <link rel=\"self\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1256888.atom\"/>\n <link rel=\"edit\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1256888.atom\"/>\n <statusnet:notice_info local_id=\"1256888\" source=\"activity\"></statusnet:notice_info>\n</entry>\n<entry>\n <id>tag:quitter.no,2016-03-16:subscription:7477:person:15743:2016-03-16T19:04:16+01:00</id>\n <title></title>\n <content type=\"html\">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt;ＤＩＧＩＴＡＬ ＣＡＴ&lt;/a&gt; started following &lt;a href=&quot;https://mastodon.social/users/Gargron&quot;&gt;Eugen&lt;/a&gt;.</content>\n <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1256253\"/>\n <activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb>\n <published>2016-03-16T18:04:16+00:00</published>\n <updated>2016-03-16T18:04:16+00:00</updated>\n <activity:object>\n  <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>\n  <id>tag:quitter.no,2016-03-16:subscription:7477:person:15743:2016-03-16T19:04:16+01:00</id>\n  <title>New person by gargron</title>\n  <content type=\"html\">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt;ＤＩＧＩＴＡＬ ＣＡＴ&lt;/a&gt; started following &lt;a href=&quot;https://mastodon.social/users/Gargron&quot;&gt;Eugen&lt;/a&gt;.</content>\n  <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1256253\"/>\n  <status_net notice_id=\"1256253\"></status_net>\n </activity:object>\n <link rel=\"ostatus:conversation\" href=\"tag:quitter.no,2016-03-16:objectType=thread:nonce=40eb98e5f85c9908\"/>\n <ostatus:conversation>tag:quitter.no,2016-03-16:objectType=thread:nonce=40eb98e5f85c9908</ostatus:conversation>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/collection\" href=\"http://activityschema.org/collection/public\"/>\n <link rel=\"self\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1256253.atom\"/>\n <link rel=\"edit\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1256253.atom\"/>\n <statusnet:notice_info local_id=\"1256253\" source=\"activity\"></statusnet:notice_info>\n</entry>\n<entry>\n <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>\n <id>tag:quitter.no,2016-03-15:noticeId=1251422:objectType=comment</id>\n <title>New comment by gargron</title>\n <content type=\"html\">@&lt;a href=&quot;https://community.highlandarrow.com/user/1&quot; class=&quot;h-card mention&quot; title=&quot;Maiyannah Bishop&quot;&gt;maiyannah&lt;/a&gt; LGB, not LGBT?</content>\n <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1251422\"/>\n <status_net notice_id=\"1251422\"></status_net>\n <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>\n <published>2016-03-15T20:28:13+00:00</published>\n <updated>2016-03-15T20:28:13+00:00</updated>\n <thr:in-reply-to ref=\"tag:community.highlandarrow.com,2016-03-15:noticeId=51852:objectType=note\" href=\"https://community.highlandarrow.com/notice/51852\"></thr:in-reply-to>\n <link rel=\"related\" href=\"https://community.highlandarrow.com/notice/51852\"/>\n <link rel=\"ostatus:conversation\" href=\"tag:community.highlandarrow.com,2016-03-15:objectType=thread:nonce=70ff6886d69e5225\"/>\n <ostatus:conversation>tag:community.highlandarrow.com,2016-03-15:objectType=thread:nonce=70ff6886d69e5225</ostatus:conversation>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/person\" href=\"https://community.highlandarrow.com/user/1\"/>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/collection\" href=\"http://activityschema.org/collection/public\"/>\n <link rel=\"self\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1251422.atom\"/>\n <link rel=\"edit\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1251422.atom\"/>\n <statusnet:notice_info local_id=\"1251422\" source=\"Qvitter\"></statusnet:notice_info>\n</entry>\n<entry>\n <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>\n <id>tag:quitter.no,2016-03-15:noticeId=1250742:objectType=comment</id>\n <title>New comment by gargron</title>\n <content type=\"html\">@&lt;a href=&quot;https://social.umeahackerspace.se/user/2&quot; class=&quot;h-card mention&quot; title=&quot;&amp;lt;Mikael &amp;amp; Nordfeldth&amp;gt;&quot;&gt;mmn&lt;/a&gt; I'm like reeeeally close to actually deploying the first production instance of Mastodon, but it bugs me that there's gonna be that issue with avatars and profiles not updating :(</content>\n <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1250742\"/>\n <status_net notice_id=\"1250742\"></status_net>\n <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>\n <published>2016-03-15T18:44:54+00:00</published>\n <updated>2016-03-15T18:44:54+00:00</updated>\n <thr:in-reply-to ref=\"tag:social.umeahackerspace.se,2016-03-15:noticeId=424348:objectType=comment\" href=\"https://social.umeahackerspace.se/notice/424348\"></thr:in-reply-to>\n <link rel=\"related\" href=\"https://social.umeahackerspace.se/notice/424348\"/>\n <link rel=\"ostatus:conversation\" href=\"tag:quitter.no,2016-03-15:objectType=thread:nonce=2fbd771270b5da80\"/>\n <ostatus:conversation>tag:quitter.no,2016-03-15:objectType=thread:nonce=2fbd771270b5da80</ostatus:conversation>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/person\" href=\"https://social.umeahackerspace.se/user/2\"/>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/collection\" href=\"http://activityschema.org/collection/public\"/>\n <link rel=\"self\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1250742.atom\"/>\n <link rel=\"edit\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1250742.atom\"/>\n <statusnet:notice_info local_id=\"1250742\" source=\"Qvitter\"></statusnet:notice_info>\n</entry>\n<entry>\n <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>\n <id>tag:quitter.no,2016-03-15:noticeId=1250653:objectType=note</id>\n <title>New note by gargron</title>\n <content type=\"html\">@&lt;a href=&quot;https://social.umeahackerspace.se/user/2&quot; class=&quot;h-card mention&quot; title=&quot;&amp;lt;Mikael &amp;amp; Nordfeldth&amp;gt;&quot;&gt;mmn&lt;/a&gt; Any progress on the issues I created?</content>\n <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1250653\"/>\n <status_net notice_id=\"1250653\"></status_net>\n <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>\n <published>2016-03-15T18:27:00+00:00</published>\n <updated>2016-03-15T18:27:00+00:00</updated>\n <link rel=\"ostatus:conversation\" href=\"tag:quitter.no,2016-03-15:objectType=thread:nonce=2fbd771270b5da80\"/>\n <ostatus:conversation>tag:quitter.no,2016-03-15:objectType=thread:nonce=2fbd771270b5da80</ostatus:conversation>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/person\" href=\"https://social.umeahackerspace.se/user/2\"/>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/collection\" href=\"http://activityschema.org/collection/public\"/>\n <link rel=\"self\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1250653.atom\"/>\n <link rel=\"edit\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1250653.atom\"/>\n <statusnet:notice_info local_id=\"1250653\" source=\"Qvitter\"></statusnet:notice_info>\n</entry>\n<entry>\n <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>\n <id>tag:quitter.no,2016-03-14:noticeId=1243566:objectType=comment</id>\n <title>New comment by gargron</title>\n <content type=\"html\">@&lt;a href=&quot;https://community.highlandarrow.com/user/1&quot; class=&quot;h-card mention&quot; title=&quot;Maiyannah Bishop&quot;&gt;maiyannah&lt;/a&gt; I heard Piwik is also good.</content>\n <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1243566\"/>\n <status_net notice_id=\"1243566\"></status_net>\n <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>\n <published>2016-03-14T15:35:23+00:00</published>\n <updated>2016-03-14T15:35:23+00:00</updated>\n <thr:in-reply-to ref=\"tag:community.highlandarrow.com,2016-03-14:noticeId=50467:objectType=note\" href=\"https://community.highlandarrow.com/notice/50467\"></thr:in-reply-to>\n <link rel=\"related\" href=\"https://community.highlandarrow.com/notice/50467\"/>\n <link rel=\"ostatus:conversation\" href=\"tag:community.highlandarrow.com,2016-03-14:objectType=thread:nonce=8fbf00e7f76866d3\"/>\n <ostatus:conversation>tag:community.highlandarrow.com,2016-03-14:objectType=thread:nonce=8fbf00e7f76866d3</ostatus:conversation>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/person\" href=\"https://community.highlandarrow.com/user/1\"/>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/collection\" href=\"http://activityschema.org/collection/public\"/>\n <link rel=\"self\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1243566.atom\"/>\n <link rel=\"edit\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1243566.atom\"/>\n <statusnet:notice_info local_id=\"1243566\" source=\"Qvitter\"></statusnet:notice_info>\n</entry>\n<entry>\n <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>\n <id>tag:quitter.no,2016-03-14:noticeId=1243331:objectType=comment</id>\n <title>New comment by gargron</title>\n <content type=\"html\">I do wish I had somebody else partake in the development process if only to give me feedback on my decisions</content>\n <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1243331\"/>\n <status_net notice_id=\"1243331\"></status_net>\n <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>\n <published>2016-03-14T14:52:03+00:00</published>\n <updated>2016-03-14T14:52:03+00:00</updated>\n <thr:in-reply-to ref=\"tag:quitter.no,2016-03-14:noticeId=1243309:objectType=comment\" href=\"https://quitter.no/notice/1243309\"></thr:in-reply-to>\n <link rel=\"related\" href=\"https://quitter.no/notice/1243309\"/>\n <link rel=\"ostatus:conversation\" href=\"tag:quitter.no,2016-03-14:objectType=thread:nonce=46e8a2abc1839d01\"/>\n <ostatus:conversation>tag:quitter.no,2016-03-14:objectType=thread:nonce=46e8a2abc1839d01</ostatus:conversation>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/person\" href=\"https://quitter.no/user/7477\"/>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/collection\" href=\"http://activityschema.org/collection/public\"/>\n <link rel=\"self\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1243331.atom\"/>\n <link rel=\"edit\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1243331.atom\"/>\n <statusnet:notice_info local_id=\"1243331\" source=\"Qvitter\"></statusnet:notice_info>\n</entry>\n</feed>\n"
  },
  {
    "path": "spec/fixtures/push/reblog.atom",
    "content": "<entry xmlns=\"http://www.w3.org/2005/Atom\" xmlns:thr=\"http://purl.org/syndication/thread/1.0\" xmlns:activity=\"http://activitystrea.ms/spec/1.0/\" xmlns:georss=\"http://www.georss.org/georss\" xmlns:ostatus=\"http://ostatus.org/schema/1.0\" xmlns:poco=\"http://portablecontacts.net/spec/1.0\" xmlns:media=\"http://purl.org/syndication/atommedia\" xmlns:statusnet=\"http://status.net/schema/api/1/\">\n <id>tag:gs.smuglo.li,2016-09-03:noticeId=661684:objectType=note</id>\n <title>dtluna repeated a notice by gargron</title>\n <content type=\"html\">RT @&lt;a href=&quot;https://mastodon.social/users/Gargron&quot; class=&quot;h-card mention&quot; title=&quot;Eugen&quot;&gt;gargron&lt;/a&gt; Stormbending from Devin Townsend's upcoming album Transcendence is now on YouTube &lt;a href=&quot;https://www.youtube.com/watch?v=8s9qh77gj6Y&quot; title=&quot;https://www.youtube.com/watch?v=8s9qh77gj6Y&quot; class=&quot;attachment thumbnail&quot; id=&quot;attachment-122081&quot; rel=&quot;nofollow external&quot;&gt;https://www.youtube.com/watch?v=8s9qh77gj6Y&lt;/a&gt;</content>\n <link rel=\"alternate\" type=\"text/html\" href=\"https://gs.smuglo.li/notice/661684\"/>\n <activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb>\n <published>2016-09-03T13:48:19+00:00</published>\n <updated>2016-09-03T13:48:19+00:00</updated>\n <author>\n  <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>\n  <uri>https://gs.smuglo.li/user/537</uri>\n  <name>dtluna</name>\n  <summary>Sex Goddess of Fediverse. Parabola GNU/Linux-libre user. PGP: 0xA490DBE4 XMPP and email: dtluna@memeware.net</summary>\n  <link rel=\"alternate\" type=\"text/html\" href=\"https://gs.smuglo.li/dtluna\"/>\n  <link rel=\"avatar\" type=\"image/jpeg\" media:width=\"385\" media:height=\"385\" href=\"https://gs.smuglo.li/avatar/537-original-20160807184048.jpeg\"/>\n  <link rel=\"avatar\" type=\"image/jpeg\" media:width=\"96\" media:height=\"96\" href=\"https://gs.smuglo.li/avatar/537-96-20160807184048.jpeg\"/>\n  <link rel=\"avatar\" type=\"image/jpeg\" media:width=\"48\" media:height=\"48\" href=\"https://gs.smuglo.li/avatar/537-48-20160807184048.jpeg\"/>\n  <link rel=\"avatar\" type=\"image/jpeg\" media:width=\"24\" media:height=\"24\" href=\"https://gs.smuglo.li/avatar/537-24-20160807184049.jpeg\"/>\n  <poco:preferredUsername>dtluna</poco:preferredUsername>\n  <poco:displayName>dtluna</poco:displayName>\n  <poco:note>Sex Goddess of Fediverse. Parabola GNU/Linux-libre user. PGP: 0xA490DBE4 XMPP and email: dtluna@memeware.net</poco:note>\n  <poco:address>\n   <poco:formatted>Minsk, Belarus</poco:formatted>\n  </poco:address>\n  <poco:urls>\n   <poco:type>homepage</poco:type>\n   <poco:value>https://liberapay.com/dtluna/</poco:value>\n   <poco:primary>true</poco:primary>\n  </poco:urls>\n  <followers url=\"https://gs.smuglo.li/dtluna/subscribers\"></followers>\n  <statusnet:profile_info local_id=\"537\"></statusnet:profile_info>\n </author>\n <activity:object>\n  <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type>\n  <id>tag:mastodon.social,2016-09-03:objectId=5984:objectType=Status</id>\n  <title></title>\n  <content type=\"html\">Stormbending from Devin Townsend's upcoming album Transcendence is now on YouTube &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.youtube.com/watch?v=8s9qh77gj6Y&quot;&gt;https://www.youtube.com/watch?v=8s9qh77gj6Y&lt;/a&gt;</content>\n  <link rel=\"alternate\" type=\"text/html\" href=\"https://mastodon.social/users/Gargron/updates/6066\"/>\n  <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>\n  <published>2016-09-03T13:47:59+00:00</published>\n  <updated>2016-09-03T13:47:59+00:00</updated>\n  <author>\n   <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>\n   <uri>https://mastodon.social/users/Gargron</uri>\n   <name>gargron</name>\n   <summary>Software engineer, free time musician and ＤＩＧＩＴＡＬ ＳＰＯＲＴＳ enthusiast. Likes cats. Warning: May contain memes</summary>\n   <link rel=\"alternate\" type=\"text/html\" href=\"https://mastodon.social/users/Gargron\"/>\n   <link rel=\"avatar\" type=\"image/gif\" media:width=\"96\" media:height=\"96\" href=\"https://gs.smuglo.li/avatar/1292-original-20160903122640.gif\"/>\n   <link rel=\"avatar\" type=\"image/gif\" media:width=\"96\" media:height=\"96\" href=\"https://gs.smuglo.li/avatar/1292-original-20160903122640.gif\"/>\n   <link rel=\"avatar\" type=\"image/gif\" media:width=\"48\" media:height=\"48\" href=\"https://gs.smuglo.li/avatar/1292-48-20160903122642.gif\"/>\n   <link rel=\"avatar\" type=\"image/gif\" media:width=\"24\" media:height=\"24\" href=\"https://gs.smuglo.li/avatar/1292-24-20160903122736.gif\"/>\n   <poco:preferredUsername>gargron</poco:preferredUsername>\n   <poco:displayName>Eugen</poco:displayName>\n   <poco:note>Software engineer, free time musician and ＤＩＧＩＴＡＬ ＳＰＯＲＴＳ enthusiast. Likes cats. Warning: May contain memes</poco:note>\n   <statusnet:profile_info local_id=\"1292\"></statusnet:profile_info>\n  </author>\n  <activity:object>\n   <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>\n   <id>tag:mastodon.social,2016-09-03:objectId=5984:objectType=Status</id>\n   <title>New note by gargron</title>\n   <content type=\"html\">Stormbending from Devin Townsend's upcoming album Transcendence is now on YouTube &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.youtube.com/watch?v=8s9qh77gj6Y&quot;&gt;https://www.youtube.com/watch?v=8s9qh77gj6Y&lt;/a&gt;</content>\n   <link rel=\"alternate\" type=\"text/html\" href=\"https://mastodon.social/users/Gargron/updates/6066\"/>\n   <status_net notice_id=\"661682\"></status_net>\n  </activity:object>\n  <link rel=\"ostatus:conversation\" href=\"tag:gs.smuglo.li,2016-09-03:objectType=thread:nonce=aec0feafff16e2cf\"/>\n  <ostatus:conversation>tag:gs.smuglo.li,2016-09-03:objectType=thread:nonce=aec0feafff16e2cf</ostatus:conversation>\n  <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/collection\" href=\"http://activityschema.org/collection/public\"/>\n  <source>\n   <id>https://mastodon.social/users/Gargron.atom</id>\n   <title>Eugen</title>\n   <link rel=\"alternate\" type=\"text/html\" href=\"https://mastodon.social/users/Gargron\"/>\n   <link rel=\"self\" type=\"application/atom+xml\" href=\"https://mastodon.social/users/Gargron.atom\"/>\n   <icon>https://gs.smuglo.li/avatar/1292-original-20160903122640.gif</icon>\n   <updated>2016-09-04T12:10:44+00:00</updated>\n  </source>\n </activity:object>\n <link rel=\"ostatus:conversation\" href=\"tag:gs.smuglo.li,2016-09-03:objectType=thread:nonce=aec0feafff16e2cf\"/>\n <ostatus:conversation>tag:gs.smuglo.li,2016-09-03:objectType=thread:nonce=aec0feafff16e2cf</ostatus:conversation>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/collection\" href=\"http://activityschema.org/collection/public\"/>\n <source>\n  <id>https://gs.smuglo.li/api/statuses/user_timeline/537.atom</id>\n  <title>dtluna</title>\n  <link rel=\"alternate\" type=\"text/html\" href=\"https://gs.smuglo.li/dtluna\"/>\n  <link rel=\"self\" type=\"application/atom+xml\" href=\"https://gs.smuglo.li/api/statuses/user_timeline/537.atom\"/>\n  <link rel=\"license\" href=\"https://creativecommons.org/licenses/by/3.0/\"/>\n  <icon>https://gs.smuglo.li/avatar/537-96-20160807184048.jpeg</icon>\n  <updated>2016-09-04T01:48:58+00:00</updated>\n </source>\n <link rel=\"self\" type=\"application/atom+xml\" href=\"https://gs.smuglo.li/api/statuses/show/661684.atom\"/>\n <link rel=\"edit\" type=\"application/atom+xml\" href=\"https://gs.smuglo.li/api/statuses/show/661684.atom\"/>\n <statusnet:notice_info local_id=\"661684\" source=\"Qvitter\" repeat_of=\"661682\"></statusnet:notice_info>\n</entry>\n"
  },
  {
    "path": "spec/fixtures/requests/.host-meta.txt",
    "content": "HTTP/1.1 200 OK\r\nServer: nginx/1.6.2\r\nDate: Sun, 20 Mar 2016 11:11:00 GMT\r\nContent-Type: application/xrd+xml\r\nTransfer-Encoding: chunked\r\nConnection: keep-alive\r\nAccess-Control-Allow-Origin: *\r\nVary: Accept-Encoding,Cookie\r\nStrict-Transport-Security: max-age=31536000; includeSubdomains;\r\n\r\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<XRD xmlns=\"http://docs.oasis-open.org/ns/xri/xrd-1.0\">\n <Link rel=\"lrdd\" type=\"application/jrd+json\" template=\"https://quitter.no/.well-known/webfinger?resource={uri}\"/>\n <Link rel=\"lrdd\" type=\"application/json\" template=\"https://quitter.no/.well-known/webfinger?resource={uri}\"/>\n <Link rel=\"lrdd\" type=\"application/xrd+xml\" template=\"https://quitter.no/.well-known/webfinger?resource={uri}\"/>\n <Link rel=\"http://apinamespace.org/oauth/access_token\" href=\"https://quitter.no/api/oauth/access_token\"/>\n <Link rel=\"http://apinamespace.org/oauth/request_token\" href=\"https://quitter.no/api/oauth/request_token\"/>\n <Link rel=\"http://apinamespace.org/oauth/authorize\" href=\"https://quitter.no/api/oauth/authorize\"/>\n</XRD>\n"
  },
  {
    "path": "spec/fixtures/requests/activitypub-actor-individual.txt",
    "content": "HTTP/1.1 200 OK\nCache-Control: max-age=0, private, must-revalidate\nContent-Type: application/activity+json; charset=utf-8\nLink: <https://ap.example.com/.well-known/webfinger?resource=acct%3Afoo%40ap.example.com>; rel=\"lrdd\"; type=\"application/xrd+xml\", <https://ap.example.com/users/foo.atom>; rel=\"alternate\"; type=\"application/atom+xml\", <https://ap.example.com/users/foo>; rel=\"alternate\"; type=\"application/activity+json\"\nVary: Accept-Encoding\nX-Content-Type-Options: nosniff\nX-Xss-Protection: 1; mode=block\n\n{\"@context\":[\"https://www.w3.org/ns/activitystreams\",\"https://w3id.org/security/v1\",{\"vcard\": \"http://www.w3.org/2006/vcard/ns#\"},{\"manuallyApprovesFollowers\":\"as:manuallyApprovesFollowers\",\"sensitive\":\"as:sensitive\",\"Hashtag\":\"as:Hashtag\",\"ostatus\":\"http://ostatus.org#\",\"atomUri\":\"ostatus:atomUri\",\"inReplyToAtomUri\":\"ostatus:inReplyToAtomUri\",\"conversation\":\"ostatus:conversation\"}],\"id\":\"https://ap.example.com/users/foo\",\"type\":[\"Person\",\"vcard:individual\"],\"following\":\"https://ap.example.com/users/foo/following\",\"followers\":\"https://ap.example.com/users/foo/followers\",\"inbox\":\"https://ap.example.com/users/foo/inbox\",\"outbox\":\"https://ap.example.com/users/foo/outbox\",\"preferredUsername\":\"foo\",\"vcard:fn\":\"foo\",\"name\":\"\",\"summary\":\"\\u003cp\\u003etest\\u003c/p\\u003e\",\"url\":\"https://ap.example.com/@foo\",\"manuallyApprovesFollowers\":false,\"publicKey\":{\"id\":\"https://ap.example.com/users/foo#main-key\",\"owner\":\"https://ap.example.com/users/foo\",\"publicKeyPem\":\"-----BEGIN PUBLIC KEY-----\\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu3L4vnpNLzVH31MeWI39\\n4F0wKeJFsLDAsNXGeOu0QF2x+h1zLWZw/agqD2R3JPU9/kaDJGPIV2Sn5zLyUA9S\\n6swCCMOtn7BBR9g9sucgXJmUFB0tACH2QSgHywMAybGfmSb3LsEMNKsGJ9VsvYoh\\n8lDET6X4Pyw+ZJU0/OLo/41q9w+OrGtlsTm/PuPIeXnxa6BLqnDaxC+4IcjG/FiP\\nahNCTINl/1F/TgSSDZ4Taf4U9XFEIFw8wmgploELozzIzKq+t8nhQYkgAkt64euW\\npva3qL5KD1mTIZQEP+LZvh3s2WHrLi3fhbdRuwQ2c0KkJA2oSTFPDpqqbPGZ3Qvu\\nHQIDAQAB\\n-----END PUBLIC KEY-----\\n\"},\"endpoints\":{\"sharedInbox\":\"https://ap.example.com/inbox\"},\"icon\":{\"type\":\"Image\",\"url\":\"https://quitter.no/avatar/7477-300-20160211190340.png\"}}"
  },
  {
    "path": "spec/fixtures/requests/activitypub-actor-noinbox.txt",
    "content": "HTTP/1.1 200 OK\nDate: Sun, 17 Sep 2017 06:51:23 GMT\nContent-Type: application/json; charset=utf-8\nX-XSS-Protection: 1; mode=block\nLink: <https://ap.example.com/.well-known/webfinger?resource=acct%3Afoo%40ap.example.com>; rel=\"lrdd\"; type=\"application/xrd+xml\", <https://ap.example.com/users/foo.atom>; rel=\"alternate\"; type=\"application/atom+xml\"\nVary: Accept-Encoding\nCache-Control: max-age=0, private, must-revalidate\n\n{\"@context\":\"https://www.w3.org/ns/activitystreams\",\"id\":\"https://ap.example.com/users/foo\",\"type\":\"Person\",\"following\":\"https://ap.example.com/users/foo/following\",\"followers\":\"https://ap.example.com/users/foo/followers\",\"inbox\":null,\"outbox\":\"https://ap.example.com/users/foo/outbox\",\"preferredUsername\":\"foo\",\"name\":\"\",\"summary\":\"\\u003cp\\u003etest\\u003c/p\\u003e\",\"icon\":\"https://quitter.no/avatar/7477-300-20160211190340.png\",\"image\":\"/headers/original/missing.png\",\"publicKey\":{\"id\":\"https://ap.example.com/users/foo#main-key\",\"owner\":\"https://ap.example.com/users/foo\",\"publicKeyPem\":\"-----BEGIN PUBLIC KEY-----\\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu3L4vnpNLzVH31MeWI39\\n4F0wKeJFsLDAsNXGeOu0QF2x+h1zLWZw/agqD2R3JPU9/kaDJGPIV2Sn5zLyUA9S\\n6swCCMOtn7BBR9g9sucgXJmUFB0tACH2QSgHywMAybGfmSb3LsEMNKsGJ9VsvYoh\\n8lDET6X4Pyw+ZJU0/OLo/41q9w+OrGtlsTm/PuPIeXnxa6BLqnDaxC+4IcjG/FiP\\nahNCTINl/1F/TgSSDZ4Taf4U9XFEIFw8wmgploELozzIzKq+t8nhQYkgAkt64euW\\npva3qL5KD1mTIZQEP+LZvh3s2WHrLi3fhbdRuwQ2c0KkJA2oSTFPDpqqbPGZ3Qvu\\nHQIDAQAB\\n-----END PUBLIC KEY-----\\n\"}}"
  },
  {
    "path": "spec/fixtures/requests/activitypub-actor.txt",
    "content": "HTTP/1.1 200 OK\nCache-Control: max-age=0, private, must-revalidate\nContent-Type: application/activity+json; charset=utf-8\nLink: <https://ap.example.com/.well-known/webfinger?resource=acct%3Afoo%40ap.example.com>; rel=\"lrdd\"; type=\"application/xrd+xml\", <https://ap.example.com/users/foo.atom>; rel=\"alternate\"; type=\"application/atom+xml\", <https://ap.example.com/users/foo>; rel=\"alternate\"; type=\"application/activity+json\"\nVary: Accept-Encoding\nX-Content-Type-Options: nosniff\nX-Xss-Protection: 1; mode=block\n\n{\"@context\":[\"https://www.w3.org/ns/activitystreams\",\"https://w3id.org/security/v1\",{\"manuallyApprovesFollowers\":\"as:manuallyApprovesFollowers\",\"sensitive\":\"as:sensitive\",\"Hashtag\":\"as:Hashtag\",\"ostatus\":\"http://ostatus.org#\",\"atomUri\":\"ostatus:atomUri\",\"inReplyToAtomUri\":\"ostatus:inReplyToAtomUri\",\"conversation\":\"ostatus:conversation\"}],\"id\":\"https://ap.example.com/users/foo\",\"type\":\"Person\",\"following\":\"https://ap.example.com/users/foo/following\",\"followers\":\"https://ap.example.com/users/foo/followers\",\"inbox\":\"https://ap.example.com/users/foo/inbox\",\"outbox\":\"https://ap.example.com/users/foo/outbox\",\"preferredUsername\":\"foo\",\"name\":\"\",\"summary\":\"\\u003cp\\u003etest\\u003c/p\\u003e\",\"url\":\"https://ap.example.com/@foo\",\"manuallyApprovesFollowers\":false,\"publicKey\":{\"id\":\"https://ap.example.com/users/foo#main-key\",\"owner\":\"https://ap.example.com/users/foo\",\"publicKeyPem\":\"-----BEGIN PUBLIC KEY-----\\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu3L4vnpNLzVH31MeWI39\\n4F0wKeJFsLDAsNXGeOu0QF2x+h1zLWZw/agqD2R3JPU9/kaDJGPIV2Sn5zLyUA9S\\n6swCCMOtn7BBR9g9sucgXJmUFB0tACH2QSgHywMAybGfmSb3LsEMNKsGJ9VsvYoh\\n8lDET6X4Pyw+ZJU0/OLo/41q9w+OrGtlsTm/PuPIeXnxa6BLqnDaxC+4IcjG/FiP\\nahNCTINl/1F/TgSSDZ4Taf4U9XFEIFw8wmgploELozzIzKq+t8nhQYkgAkt64euW\\npva3qL5KD1mTIZQEP+LZvh3s2WHrLi3fhbdRuwQ2c0KkJA2oSTFPDpqqbPGZ3Qvu\\nHQIDAQAB\\n-----END PUBLIC KEY-----\\n\"},\"endpoints\":{\"sharedInbox\":\"https://ap.example.com/inbox\"},\"icon\":{\"type\":\"Image\",\"url\":\"https://quitter.no/avatar/7477-300-20160211190340.png\"}}"
  },
  {
    "path": "spec/fixtures/requests/activitypub-feed.txt",
    "content": "HTTP/1.1 200 OK\nCache-Control: max-age=0, private, must-revalidate\nContent-Type: application/atom+xml; charset=utf-8\nLink: <https://ap.example.com/.well-known/webfinger?resource=acct%3Afoo%40ap.example.com>; rel=\"lrdd\"; type=\"application/xrd+xml\", <https://ap.example.com/users/foo.atom>; rel=\"alternate\"; type=\"application/atom+xml\", <https://ap.example.com/users/foo>; rel=\"alternate\"; type=\"application/activity+json\"\nVary: Accept-Encoding\nDate: Sun, 17 Sep 2017 06:33:53 GMT\n\n<?xml version=\"1.0\"?>\n<feed xmlns=\"http://www.w3.org/2005/Atom\" xmlns:thr=\"http://purl.org/syndication/thread/1.0\" xmlns:activity=\"http://activitystrea.ms/spec/1.0/\" xmlns:poco=\"http://portablecontacts.net/spec/1.0\" xmlns:media=\"http://purl.org/syndication/atommedia\" xmlns:ostatus=\"http://ostatus.org/schema/1.0\" xmlns:mastodon=\"http://mastodon.social/schema/1.0\">\n  <id>https://ap.example.com/users/foo.atom</id>\n  <title>foo</title>\n  <subtitle>test</subtitle>\n  <updated>2017-09-16T18:50:09Z</updated>\n  <logo>https://ap.example.com/system/accounts/avatars/000/000/001/original/141ee5846d159cba.png?1505587809</logo>\n  <author>\n    <id>https://ap.example.com/users/foo</id>\n    <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>\n    <uri>https://ap.example.com/users/foo</uri>\n    <name>foo</name>\n    <email>foo@ap.example.com</email>\n    <summary type=\"html\">&lt;p&gt;test&lt;/p&gt;</summary>\n    <link rel=\"alternate\" type=\"text/html\" href=\"https://ap.example.com/@foo\"/>\n    <link rel=\"avatar\" type=\"image/jpeg\" media:width=\"120\" media:height=\"120\" href=\"https://quitter.no/avatar/7477-300-20160211190340.png\"/>\n    <poco:preferredUsername>foo</poco:preferredUsername>\n    <poco:note>test</poco:note>\n    <mastodon:scope>public</mastodon:scope>\n  </author>\n  <link rel=\"alternate\" type=\"text/html\" href=\"https://ap.example.com/@foo\"/>\n  <link rel=\"self\" type=\"application/atom+xml\" href=\"https://ap.example.com/users/foo.atom\"/>\n  <link rel=\"hub\" href=\"https://ap.example.com/api/push\"/>\n  <link rel=\"salmon\" href=\"https://ap.example.com/api/salmon/1\"/>\n  <entry>\n    <id>https://ap.example.com/users/foo/statuses/11076</id>\n    <published>2017-09-13T01:23:19Z</published>\n    <updated>2017-09-13T01:23:19Z</updated>\n    <title>New status by foo</title>\n    <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>\n    <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>\n    <link rel=\"alternate\" type=\"application/activity+json\" href=\"https://ap.example.com/users/foo/statuses/11076\"/>\n    <content type=\"html\" xml:lang=\"ja\">&lt;p&gt;test&lt;/p&gt;</content>\n    <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/collection\" href=\"http://activityschema.org/collection/public\"/>\n    <mastodon:scope>public</mastodon:scope>\n    <link rel=\"alternate\" type=\"text/html\" href=\"https://ap.example.com/@foo/11076\"/>\n    <link rel=\"self\" type=\"application/atom+xml\" href=\"https://ap.example.com/users/foo/updates/11015.atom\"/>\n    <ostatus:conversation ref=\"tag:ap.example.com,2017-09-13:objectId=7412:objectType=Conversation\"/>\n  </entry>\n</feed>\n"
  },
  {
    "path": "spec/fixtures/requests/activitypub-webfinger.txt",
    "content": "HTTP/1.1 200 OK\nCache-Control: max-age=0, private, must-revalidate\nContent-Type: application/jrd+json; charset=utf-8\nX-Content-Type-Options: nosniff\nDate: Sun, 17 Sep 2017 06:22:50 GMT\n\n{\"subject\":\"acct:foo@ap.example.com\",\"aliases\":[\"https://ap.example.com/@foo\",\"https://ap.example.com/users/foo\"],\"links\":[{\"rel\":\"http://webfinger.net/rel/profile-page\",\"type\":\"text/html\",\"href\":\"https://ap.example.com/@foo\"},{\"rel\":\"http://schemas.google.com/g/2010#updates-from\",\"type\":\"application/atom+xml\",\"href\":\"https://ap.example.com/users/foo.atom\"},{\"rel\":\"self\",\"type\":\"application/activity+json\",\"href\":\"https://ap.example.com/users/foo\"},{\"rel\":\"salmon\",\"href\":\"https://ap.example.com/api/salmon/1\"},{\"rel\":\"magic-public-key\",\"href\":\"data:application/magic-public-key,RSA.u3L4vnpNLzVH31MeWI394F0wKeJFsLDAsNXGeOu0QF2x-h1zLWZw_agqD2R3JPU9_kaDJGPIV2Sn5zLyUA9S6swCCMOtn7BBR9g9sucgXJmUFB0tACH2QSgHywMAybGfmSb3LsEMNKsGJ9VsvYoh8lDET6X4Pyw-ZJU0_OLo_41q9w-OrGtlsTm_PuPIeXnxa6BLqnDaxC-4IcjG_FiPahNCTINl_1F_TgSSDZ4Taf4U9XFEIFw8wmgploELozzIzKq-t8nhQYkgAkt64euWpva3qL5KD1mTIZQEP-LZvh3s2WHrLi3fhbdRuwQ2c0KkJA2oSTFPDpqqbPGZ3QvuHQ==.AQAB\"},{\"rel\":\"http://ostatus.org/schema/1.0/subscribe\",\"template\":\"https://ap.example.com/authorize_follow?acct={uri}\"}]}"
  },
  {
    "path": "spec/fixtures/requests/feed.txt",
    "content": "HTTP/1.1 200 OK\r\nServer: nginx/1.6.2\r\nDate: Sun, 20 Mar 2016 11:15:03 GMT\r\nContent-Type: application/atom+xml; charset=utf-8\r\nTransfer-Encoding: chunked\r\nConnection: keep-alive\r\nAccess-Control-Allow-Origin: *\r\nVary: Accept-Encoding,Cookie\r\nETag: \"ApiTimelineUser:0:en:7477:1458471931:1457967123\"\r\nLast-Modified: Sun, 20 Mar 2016 11:05:31 +0000\r\nExpires: Thu, 01 Jan 1970 00:00:00 GMT\r\nCache-Control: private, must-revalidate, max-age=0\r\nPragma: \r\nX-SUP-ID: https://quitter.no/main/sup\r\nStrict-Transport-Security: max-age=31536000; includeSubdomains;\r\n\r\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<feed xml:lang=\"en-US\" xmlns=\"http://www.w3.org/2005/Atom\" xmlns:thr=\"http://purl.org/syndication/thread/1.0\" xmlns:georss=\"http://www.georss.org/georss\" xmlns:activity=\"http://activitystrea.ms/spec/1.0/\" xmlns:media=\"http://purl.org/syndication/atommedia\" xmlns:poco=\"http://portablecontacts.net/spec/1.0\" xmlns:ostatus=\"http://ostatus.org/schema/1.0\" xmlns:statusnet=\"http://status.net/schema/api/1/\">\n <generator uri=\"https://gnu.io/social\" version=\"1.2.0-beta4\">GNU social</generator>\n <id>https://quitter.no/api/statuses/user_timeline/7477.atom</id>\n <title>gargron timeline</title>\n <subtitle>Updates from gargron on Quitter.no!</subtitle>\n <logo>https://quitter.no/avatar/7477-96-20160211190340.png</logo>\n <updated>2016-03-20T12:15:03+01:00</updated>\n<author>\n <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>\n <uri>https://quitter.no/user/7477</uri>\n <name>gargron</name>\n <summary>Software engineer, free time musician and ＤＩＧＩＴＡＬ ＳＰＯＲＴＳ enthusiast. Likes cats. Warning: May contain memes</summary>\n <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/gargron\"/>\n <link rel=\"avatar\" type=\"image/png\" media:width=\"300\" media:height=\"300\" href=\"https://quitter.no/avatar/7477-300-20160211190340.png\"/>\n <link rel=\"avatar\" type=\"image/png\" media:width=\"96\" media:height=\"96\" href=\"https://quitter.no/avatar/7477-96-20160211190340.png\"/>\n <link rel=\"avatar\" type=\"image/png\" media:width=\"48\" media:height=\"48\" href=\"https://quitter.no/avatar/7477-48-20160211190449.png\"/>\n <link rel=\"avatar\" type=\"image/png\" media:width=\"24\" media:height=\"24\" href=\"https://quitter.no/avatar/7477-24-20160211190517.png\"/>\n <poco:preferredUsername>gargron</poco:preferredUsername>\n <poco:displayName>ＤＩＧＩＴＡＬ ＣＡＴ</poco:displayName>\n <poco:note>Software engineer, free time musician and ＤＩＧＩＴＡＬ ＳＰＯＲＴＳ enthusiast. Likes cats. Warning: May contain memes</poco:note>\n <poco:address>\n  <poco:formatted>Germany</poco:formatted>\n </poco:address>\n <poco:urls>\n  <poco:type>homepage</poco:type>\n  <poco:value>https://zeonfederated.com</poco:value>\n  <poco:primary>true</poco:primary>\n </poco:urls>\n <followers url=\"https://quitter.no/gargron/subscribers\"></followers>\n <statusnet:profile_info local_id=\"7477\"></statusnet:profile_info>\n</author>\n <link href=\"https://quitter.no/gargron\" rel=\"alternate\" type=\"text/html\"/>\n <link href=\"https://quitter.no/main/sup\" rel=\"http://api.friendfeed.com/2008/03#sup\" type=\"application/json\"/>\n <link href=\"https://quitter.no/api/statuses/user_timeline/7477.atom?max_id=1243309\" rel=\"next\" type=\"application/atom+xml\"/>\n <link href=\"https://quitter.no/main/push/hub\" rel=\"hub\"/>\n <link href=\"https://quitter.no/main/salmon/user/7477\" rel=\"salmon\"/>\n <link href=\"https://quitter.no/main/salmon/user/7477\" rel=\"http://salmon-protocol.org/ns/salmon-replies\"/>\n <link href=\"https://quitter.no/main/salmon/user/7477\" rel=\"http://salmon-protocol.org/ns/salmon-mention\"/>\n <link href=\"https://quitter.no/api/statuses/user_timeline/7477.atom\" rel=\"self\" type=\"application/atom+xml\"/>\n<entry>\n <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>\n <id>tag:quitter.no,2016-03-20:noticeId=1276923:objectType=note</id>\n <title>New note by gargron</title>\n <content type=\"html\">@&lt;a href=&quot;https://cb6e6126.ngrok.io/users/catsrgr8&quot; class=&quot;h-card mention&quot;&gt;catsrgr8&lt;/a&gt; this is a mention</content>\n <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1276923\"/>\n <status_net notice_id=\"1276923\"></status_net>\n <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>\n <published>2016-03-20T11:05:31+00:00</published>\n <updated>2016-03-20T11:05:31+00:00</updated>\n <link rel=\"ostatus:conversation\" href=\"tag:quitter.no,2016-03-20:objectType=thread:nonce=7c998112e39a6685\"/>\n <ostatus:conversation>tag:quitter.no,2016-03-20:objectType=thread:nonce=7c998112e39a6685</ostatus:conversation>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/person\" href=\"https://cb6e6126.ngrok.io/users/catsrgr8\"/>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/collection\" href=\"http://activityschema.org/collection/public\"/>\n <link rel=\"self\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1276923.atom\"/>\n <link rel=\"edit\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1276923.atom\"/>\n <statusnet:notice_info local_id=\"1276923\" source=\"Qvitter\"></statusnet:notice_info>\n</entry>\n<entry>\n <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>\n <id>tag:quitter.no,2016-03-19:noticeId=1273635:objectType=note</id>\n <title>New note by gargron</title>\n <content type=\"html\">Just testing a thing.</content>\n <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1273635\"/>\n <status_net notice_id=\"1273635\"></status_net>\n <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>\n <published>2016-03-19T20:35:53+00:00</published>\n <updated>2016-03-19T20:35:53+00:00</updated>\n <link rel=\"ostatus:conversation\" href=\"tag:quitter.no,2016-03-19:objectType=thread:nonce=c4a61886d5cad4c2\"/>\n <ostatus:conversation>tag:quitter.no,2016-03-19:objectType=thread:nonce=c4a61886d5cad4c2</ostatus:conversation>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/person\" href=\"https://mastodon.social/users/Gargron\"/>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/collection\" href=\"http://activityschema.org/collection/public\"/>\n <link rel=\"self\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1273635.atom\"/>\n <link rel=\"edit\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1273635.atom\"/>\n <statusnet:notice_info local_id=\"1273635\" source=\"web\"></statusnet:notice_info>\n</entry>\n<entry>\n <id>tag:quitter.no,2016-03-19:noticeId=1272988:objectType=note</id>\n <title>Delete</title>\n <content type=\"html\">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt;ＤＩＧＩＴＡＬ ＣＡＴ&lt;/a&gt; deleted notice &lt;a href=&quot;https://quitter.no/notice/1272988&quot;&gt;{{tag:quitter.no,2016-03-19:noticeId=1272988:objectType=note}}&lt;/a&gt;.</content>\n <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1273012\"/>\n <activity:verb>delete</activity:verb>\n <published>2016-03-19T18:16:58+00:00</published>\n <updated>2016-03-19T18:16:58+00:00</updated>\n <activity:object>\n  <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>\n  <id>tag:quitter.no,2016-03-19:noticeId=1272988:objectType=note</id>\n </activity:object>\n <link rel=\"ostatus:conversation\" href=\"tag:quitter.no,2016-03-19:objectType=thread:nonce=7913e6b6256b6d0b\"/>\n <ostatus:conversation>tag:quitter.no,2016-03-19:objectType=thread:nonce=7913e6b6256b6d0b</ostatus:conversation>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/collection\" href=\"http://activityschema.org/collection/public\"/>\n <activity:target>\n  <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>\n  <id>tag:quitter.no,2016-03-19:noticeId=1272988:objectType=note</id>\n </activity:target>\n <link rel=\"self\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1273012.atom\"/>\n <link rel=\"edit\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1273012.atom\"/>\n <statusnet:notice_info local_id=\"1273012\" source=\"unknown\"></statusnet:notice_info>\n</entry>\n<entry>\n <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>\n <id>tag:quitter.no,2016-03-19:noticeId=1269381:objectType=comment</id>\n <title>New comment by gargron</title>\n <content type=\"html\">@&lt;a href=&quot;https://mastodon.social/users/Gargron&quot; class=&quot;h-card mention&quot; title=&quot;Eugen&quot;&gt;gargron&lt;/a&gt; I have to wonder if this will appear as a reply to the right status, and not just a mention.</content>\n <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1269381\"/>\n <status_net notice_id=\"1269381\"></status_net>\n <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>\n <published>2016-03-19T00:10:14+00:00</published>\n <updated>2016-03-19T00:10:14+00:00</updated>\n <thr:in-reply-to ref=\"tag:mastodon.social,2016-03-18:objectId=60:objectType=Status\" href=\"https://quitter.no/notice/1269244\"></thr:in-reply-to>\n <link rel=\"related\" href=\"https://quitter.no/notice/1269244\"/>\n <link rel=\"ostatus:conversation\" href=\"tag:quitter.no,2016-03-18:objectType=thread:nonce=d05c6330fbe23fb9\"/>\n <ostatus:conversation>tag:quitter.no,2016-03-18:objectType=thread:nonce=d05c6330fbe23fb9</ostatus:conversation>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/person\" href=\"https://mastodon.social/users/Gargron\"/>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/collection\" href=\"http://activityschema.org/collection/public\"/>\n <link rel=\"self\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1269381.atom\"/>\n <link rel=\"edit\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1269381.atom\"/>\n <statusnet:notice_info local_id=\"1269381\" source=\"Qvitter\"></statusnet:notice_info>\n</entry>\n<entry>\n <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>\n <id>tag:quitter.no,2016-03-18:noticeId=1265337:objectType=comment</id>\n <title>New comment by gargron</title>\n <content type=\"html\">@&lt;a href=&quot;https://community.highlandarrow.com/user/1&quot; class=&quot;h-card mention&quot; title=&quot;Maiyannah Bishop&quot;&gt;maiyannah&lt;/a&gt; Plus, Android can hardly be considered free software given how many proprietary blobs are used. I'm speaking as a disappointed Android user.</content>\n <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1265337\"/>\n <status_net notice_id=\"1265337\"></status_net>\n <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>\n <published>2016-03-18T10:01:50+00:00</published>\n <updated>2016-03-18T10:01:50+00:00</updated>\n <thr:in-reply-to ref=\"tag:quitter.no,2016-03-18:noticeId=1265331:objectType=comment\" href=\"https://quitter.no/notice/1265331\"></thr:in-reply-to>\n <link rel=\"related\" href=\"https://quitter.no/notice/1265331\"/>\n <link rel=\"ostatus:conversation\" href=\"tag:community.highlandarrow.com,2016-03-18:objectType=thread:nonce=d61438407b882959\"/>\n <ostatus:conversation>tag:community.highlandarrow.com,2016-03-18:objectType=thread:nonce=d61438407b882959</ostatus:conversation>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/person\" href=\"https://quitter.no/user/7477\"/>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/person\" href=\"https://community.highlandarrow.com/user/1\"/>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/collection\" href=\"http://activityschema.org/collection/public\"/>\n <link rel=\"self\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1265337.atom\"/>\n <link rel=\"edit\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1265337.atom\"/>\n <statusnet:notice_info local_id=\"1265337\" source=\"Qvitter\"></statusnet:notice_info>\n</entry>\n<entry>\n <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>\n <id>tag:quitter.no,2016-03-18:noticeId=1265331:objectType=comment</id>\n <title>New comment by gargron</title>\n <content type=\"html\">@&lt;a href=&quot;https://community.highlandarrow.com/user/1&quot; class=&quot;h-card mention&quot; title=&quot;Maiyannah Bishop&quot;&gt;maiyannah&lt;/a&gt; Well as it turns out, Apple software is better than Android in terms of security, and Apple is fighting FBI while Google promised to build a messaging app that facilitates wire tapping. The whole free software thing should imo be considered a bonus and not overshadow other factors.</content>\n <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1265331\"/>\n <status_net notice_id=\"1265331\"></status_net>\n <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>\n <published>2016-03-18T10:01:01+00:00</published>\n <updated>2016-03-18T10:01:01+00:00</updated>\n <thr:in-reply-to ref=\"tag:community.highlandarrow.com,2016-03-18:noticeId=54411:objectType=note\" href=\"https://community.highlandarrow.com/notice/54411\"></thr:in-reply-to>\n <link rel=\"related\" href=\"https://community.highlandarrow.com/notice/54411\"/>\n <link rel=\"ostatus:conversation\" href=\"tag:community.highlandarrow.com,2016-03-18:objectType=thread:nonce=d61438407b882959\"/>\n <ostatus:conversation>tag:community.highlandarrow.com,2016-03-18:objectType=thread:nonce=d61438407b882959</ostatus:conversation>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/person\" href=\"https://community.highlandarrow.com/user/1\"/>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/collection\" href=\"http://activityschema.org/collection/public\"/>\n <link rel=\"self\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1265331.atom\"/>\n <link rel=\"edit\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1265331.atom\"/>\n <statusnet:notice_info local_id=\"1265331\" source=\"Qvitter\"></statusnet:notice_info>\n</entry>\n<entry>\n <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>\n <id>tag:quitter.no,2016-03-17:noticeId=1261358:objectType=comment</id>\n <title>New comment by gargron</title>\n <content type=\"html\">@&lt;a href=&quot;https://community.highlandarrow.com/user/1&quot; class=&quot;h-card mention&quot; title=&quot;Maiyannah Bishop&quot;&gt;maiyannah&lt;/a&gt; @&lt;a href=&quot;https://gs.kawa-kun.com/user/2&quot; class=&quot;h-card mention&quot; title=&quot;&amp;#x7AF9;&amp;#x4E0B;&amp;#x61B2;&amp;#x4E8C;&quot;&gt;takeshitakenji&lt;/a&gt; There is a reason that was deprecated and we don't use tables to design websites anymore. HTML needs to be semantic, i.e. tags need to describe the *kind* of content, not how it should *look*, which is a responsibility delegated to CSS. There are so many upsides to this separation of concerns, should I start listing?</content>\n <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1261358\"/>\n <status_net notice_id=\"1261358\"></status_net>\n <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>\n <published>2016-03-17T17:00:26+00:00</published>\n <updated>2016-03-17T17:00:26+00:00</updated>\n <thr:in-reply-to ref=\"tag:community.highlandarrow.com,2016-03-17:noticeId=53857:objectType=comment\" href=\"https://community.highlandarrow.com/notice/53857\"></thr:in-reply-to>\n <link rel=\"related\" href=\"https://community.highlandarrow.com/notice/53857\"/>\n <link rel=\"ostatus:conversation\" href=\"tag:gs.kawa-kun.com,2016-03-17:objectType=thread:nonce=a83963573a0520f1\"/>\n <ostatus:conversation>tag:gs.kawa-kun.com,2016-03-17:objectType=thread:nonce=a83963573a0520f1</ostatus:conversation>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/person\" href=\"https://community.highlandarrow.com/user/1\"/>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/person\" href=\"https://gs.kawa-kun.com/user/2\"/>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/collection\" href=\"http://activityschema.org/collection/public\"/>\n <link rel=\"self\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1261358.atom\"/>\n <link rel=\"edit\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1261358.atom\"/>\n <statusnet:notice_info local_id=\"1261358\" source=\"Qvitter\"></statusnet:notice_info>\n</entry>\n<entry>\n <id>tag:quitter.no,2016-03-16:subscription:7477:person:15743:2016-03-16T21:24:13+01:00</id>\n <title>ＤＩＧＩＴＡＬ ＣＡＴ (gargron)'s status on Wednesday, 16-Mar-2016 21:24:13 CET</title>\n <content type=\"html\">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt;ＤＩＧＩＴＡＬ ＣＡＴ&lt;/a&gt; started following &lt;a href=&quot;https://mastodon.social/users/Gargron&quot;&gt;Eugen&lt;/a&gt;.</content>\n <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1256972\"/>\n <activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb>\n <published>2016-03-16T20:24:13+00:00</published>\n <updated>2016-03-16T20:24:13+00:00</updated>\n <activity:object>\n  <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>\n  <id>https://mastodon.social/users/Gargron</id>\n  <title>Eugen</title>\n  <summary>Software engineer, free time musician and ＤＩＧＩＴＡＬ ＳＰＯＲＴＳ enthusiast. Likes cats. Warning: May contain memes</summary>\n  <link rel=\"alternate\" type=\"text/html\" href=\"https://mastodon.social/users/Gargron\"/>\n  <link rel=\"avatar\" type=\"image/gif\" media:width=\"96\" media:height=\"96\" href=\"https://quitter.no/avatar/15743-original-20160316180410.gif\"/>\n  <link rel=\"avatar\" type=\"image/gif\" media:width=\"96\" media:height=\"96\" href=\"https://quitter.no/avatar/15743-original-20160316180410.gif\"/>\n  <link rel=\"avatar\" type=\"image/gif\" media:width=\"48\" media:height=\"48\" href=\"https://quitter.no/avatar/15743-48-20160316180416.gif\"/>\n  <link rel=\"avatar\" type=\"image/gif\" media:width=\"24\" media:height=\"24\" href=\"https://quitter.no/avatar/15743-24-20160316180416.gif\"/>\n  <poco:preferredUsername>gargron</poco:preferredUsername>\n  <poco:displayName>Eugen</poco:displayName>\n  <poco:note>Software engineer, free time musician and ＤＩＧＩＴＡＬ ＳＰＯＲＴＳ enthusiast. Likes cats. Warning: May contain memes</poco:note>\n </activity:object>\n <link rel=\"ostatus:conversation\" href=\"tag:quitter.no,2016-03-16:objectType=thread:nonce=073bda8223dfcaa7\"/>\n <ostatus:conversation>tag:quitter.no,2016-03-16:objectType=thread:nonce=073bda8223dfcaa7</ostatus:conversation>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/collection\" href=\"http://activityschema.org/collection/public\"/>\n <link rel=\"self\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1256972.atom\"/>\n <link rel=\"edit\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1256972.atom\"/>\n <statusnet:notice_info local_id=\"1256972\" source=\"activity\"></statusnet:notice_info>\n</entry>\n<entry>\n <id>tag:quitter.no,2016-03-16:subscription:7477:person:15743:2016-03-16T21:22:38+01:00</id>\n <title></title>\n <content type=\"html\">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt;ＤＩＧＩＴＡＬ ＣＡＴ&lt;/a&gt; started following &lt;a href=&quot;https://mastodon.social/users/Gargron&quot;&gt;Eugen&lt;/a&gt;.</content>\n <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1256966\"/>\n <activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb>\n <published>2016-03-16T20:22:38+00:00</published>\n <updated>2016-03-16T20:22:38+00:00</updated>\n <activity:object>\n  <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>\n  <id>tag:quitter.no,2016-03-16:subscription:7477:person:15743:2016-03-16T21:22:38+01:00</id>\n  <title>New person by gargron</title>\n  <content type=\"html\">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt;ＤＩＧＩＴＡＬ ＣＡＴ&lt;/a&gt; started following &lt;a href=&quot;https://mastodon.social/users/Gargron&quot;&gt;Eugen&lt;/a&gt;.</content>\n  <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1256966\"/>\n  <status_net notice_id=\"1256966\"></status_net>\n </activity:object>\n <link rel=\"ostatus:conversation\" href=\"tag:quitter.no,2016-03-16:objectType=thread:nonce=b157f676181e0ecd\"/>\n <ostatus:conversation>tag:quitter.no,2016-03-16:objectType=thread:nonce=b157f676181e0ecd</ostatus:conversation>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/collection\" href=\"http://activityschema.org/collection/public\"/>\n <link rel=\"self\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1256966.atom\"/>\n <link rel=\"edit\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1256966.atom\"/>\n <statusnet:notice_info local_id=\"1256966\" source=\"activity\"></statusnet:notice_info>\n</entry>\n<entry>\n <id>tag:quitter.no,2016-03-16:subscription:7477:person:15743:2016-03-16T21:16:14+01:00</id>\n <title></title>\n <content type=\"html\">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt;ＤＩＧＩＴＡＬ ＣＡＴ&lt;/a&gt; started following &lt;a href=&quot;https://mastodon.social/users/Gargron&quot;&gt;Eugen&lt;/a&gt;.</content>\n <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1256939\"/>\n <activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb>\n <published>2016-03-16T20:16:15+00:00</published>\n <updated>2016-03-16T20:16:15+00:00</updated>\n <activity:object>\n  <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>\n  <id>tag:quitter.no,2016-03-16:subscription:7477:person:15743:2016-03-16T21:16:14+01:00</id>\n  <title>New person by gargron</title>\n  <content type=\"html\">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt;ＤＩＧＩＴＡＬ ＣＡＴ&lt;/a&gt; started following &lt;a href=&quot;https://mastodon.social/users/Gargron&quot;&gt;Eugen&lt;/a&gt;.</content>\n  <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1256939\"/>\n  <status_net notice_id=\"1256939\"></status_net>\n </activity:object>\n <link rel=\"ostatus:conversation\" href=\"tag:quitter.no,2016-03-16:objectType=thread:nonce=6a6ebd1ed6504a11\"/>\n <ostatus:conversation>tag:quitter.no,2016-03-16:objectType=thread:nonce=6a6ebd1ed6504a11</ostatus:conversation>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/collection\" href=\"http://activityschema.org/collection/public\"/>\n <link rel=\"self\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1256939.atom\"/>\n <link rel=\"edit\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1256939.atom\"/>\n <statusnet:notice_info local_id=\"1256939\" source=\"activity\"></statusnet:notice_info>\n</entry>\n<entry>\n <id>tag:quitter.no,2016-03-16:subscription:7477:person:15750:2016-03-16T21:13:06+01:00</id>\n <title></title>\n <content type=\"html\">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt;ＤＩＧＩＴＡＬ ＣＡＴ&lt;/a&gt; started following &lt;a href=&quot;https://acda7931.ngrok.io/users/catsrgr8&quot;&gt;Eugen&lt;/a&gt;.</content>\n <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1256929\"/>\n <activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb>\n <published>2016-03-16T20:13:06+00:00</published>\n <updated>2016-03-16T20:13:06+00:00</updated>\n <activity:object>\n  <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>\n  <id>tag:quitter.no,2016-03-16:subscription:7477:person:15750:2016-03-16T21:13:06+01:00</id>\n  <title>New person by gargron</title>\n  <content type=\"html\">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt;ＤＩＧＩＴＡＬ ＣＡＴ&lt;/a&gt; started following &lt;a href=&quot;https://acda7931.ngrok.io/users/catsrgr8&quot;&gt;Eugen&lt;/a&gt;.</content>\n  <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1256929\"/>\n  <status_net notice_id=\"1256929\"></status_net>\n </activity:object>\n <link rel=\"ostatus:conversation\" href=\"tag:quitter.no,2016-03-16:objectType=thread:nonce=8f5f92443584e8f0\"/>\n <ostatus:conversation>tag:quitter.no,2016-03-16:objectType=thread:nonce=8f5f92443584e8f0</ostatus:conversation>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/collection\" href=\"http://activityschema.org/collection/public\"/>\n <link rel=\"self\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1256929.atom\"/>\n <link rel=\"edit\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1256929.atom\"/>\n <statusnet:notice_info local_id=\"1256929\" source=\"activity\"></statusnet:notice_info>\n</entry>\n<entry>\n <id>tag:quitter.no,2016-03-16:subscription:7477:person:15750:2016-03-16T21:05:02+01:00</id>\n <title></title>\n <content type=\"html\">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt;ＤＩＧＩＴＡＬ ＣＡＴ&lt;/a&gt; started following &lt;a href=&quot;https://acda7931.ngrok.io/users/catsrgr8&quot;&gt;Eugen&lt;/a&gt;.</content>\n <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1256888\"/>\n <activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb>\n <published>2016-03-16T20:05:03+00:00</published>\n <updated>2016-03-16T20:05:03+00:00</updated>\n <activity:object>\n  <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>\n  <id>tag:quitter.no,2016-03-16:subscription:7477:person:15750:2016-03-16T21:05:02+01:00</id>\n  <title>New person by gargron</title>\n  <content type=\"html\">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt;ＤＩＧＩＴＡＬ ＣＡＴ&lt;/a&gt; started following &lt;a href=&quot;https://acda7931.ngrok.io/users/catsrgr8&quot;&gt;Eugen&lt;/a&gt;.</content>\n  <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1256888\"/>\n  <status_net notice_id=\"1256888\"></status_net>\n </activity:object>\n <link rel=\"ostatus:conversation\" href=\"tag:quitter.no,2016-03-16:objectType=thread:nonce=b630d235232fcff5\"/>\n <ostatus:conversation>tag:quitter.no,2016-03-16:objectType=thread:nonce=b630d235232fcff5</ostatus:conversation>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/collection\" href=\"http://activityschema.org/collection/public\"/>\n <link rel=\"self\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1256888.atom\"/>\n <link rel=\"edit\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1256888.atom\"/>\n <statusnet:notice_info local_id=\"1256888\" source=\"activity\"></statusnet:notice_info>\n</entry>\n<entry>\n <id>tag:quitter.no,2016-03-16:subscription:7477:person:15743:2016-03-16T19:04:16+01:00</id>\n <title></title>\n <content type=\"html\">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt;ＤＩＧＩＴＡＬ ＣＡＴ&lt;/a&gt; started following &lt;a href=&quot;https://mastodon.social/users/Gargron&quot;&gt;Eugen&lt;/a&gt;.</content>\n <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1256253\"/>\n <activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb>\n <published>2016-03-16T18:04:16+00:00</published>\n <updated>2016-03-16T18:04:16+00:00</updated>\n <activity:object>\n  <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>\n  <id>tag:quitter.no,2016-03-16:subscription:7477:person:15743:2016-03-16T19:04:16+01:00</id>\n  <title>New person by gargron</title>\n  <content type=\"html\">&lt;a href=&quot;https://quitter.no/gargron&quot;&gt;ＤＩＧＩＴＡＬ ＣＡＴ&lt;/a&gt; started following &lt;a href=&quot;https://mastodon.social/users/Gargron&quot;&gt;Eugen&lt;/a&gt;.</content>\n  <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1256253\"/>\n  <status_net notice_id=\"1256253\"></status_net>\n </activity:object>\n <link rel=\"ostatus:conversation\" href=\"tag:quitter.no,2016-03-16:objectType=thread:nonce=40eb98e5f85c9908\"/>\n <ostatus:conversation>tag:quitter.no,2016-03-16:objectType=thread:nonce=40eb98e5f85c9908</ostatus:conversation>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/collection\" href=\"http://activityschema.org/collection/public\"/>\n <link rel=\"self\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1256253.atom\"/>\n <link rel=\"edit\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1256253.atom\"/>\n <statusnet:notice_info local_id=\"1256253\" source=\"activity\"></statusnet:notice_info>\n</entry>\n<entry>\n <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>\n <id>tag:quitter.no,2016-03-15:noticeId=1251422:objectType=comment</id>\n <title>New comment by gargron</title>\n <content type=\"html\">@&lt;a href=&quot;https://community.highlandarrow.com/user/1&quot; class=&quot;h-card mention&quot; title=&quot;Maiyannah Bishop&quot;&gt;maiyannah&lt;/a&gt; LGB, not LGBT?</content>\n <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1251422\"/>\n <status_net notice_id=\"1251422\"></status_net>\n <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>\n <published>2016-03-15T20:28:13+00:00</published>\n <updated>2016-03-15T20:28:13+00:00</updated>\n <thr:in-reply-to ref=\"tag:community.highlandarrow.com,2016-03-15:noticeId=51852:objectType=note\" href=\"https://community.highlandarrow.com/notice/51852\"></thr:in-reply-to>\n <link rel=\"related\" href=\"https://community.highlandarrow.com/notice/51852\"/>\n <link rel=\"ostatus:conversation\" href=\"tag:community.highlandarrow.com,2016-03-15:objectType=thread:nonce=70ff6886d69e5225\"/>\n <ostatus:conversation>tag:community.highlandarrow.com,2016-03-15:objectType=thread:nonce=70ff6886d69e5225</ostatus:conversation>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/person\" href=\"https://community.highlandarrow.com/user/1\"/>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/collection\" href=\"http://activityschema.org/collection/public\"/>\n <link rel=\"self\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1251422.atom\"/>\n <link rel=\"edit\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1251422.atom\"/>\n <statusnet:notice_info local_id=\"1251422\" source=\"Qvitter\"></statusnet:notice_info>\n</entry>\n<entry>\n <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>\n <id>tag:quitter.no,2016-03-15:noticeId=1250742:objectType=comment</id>\n <title>New comment by gargron</title>\n <content type=\"html\">@&lt;a href=&quot;https://social.umeahackerspace.se/user/2&quot; class=&quot;h-card mention&quot; title=&quot;&amp;lt;Mikael &amp;amp; Nordfeldth&amp;gt;&quot;&gt;mmn&lt;/a&gt; I'm like reeeeally close to actually deploying the first production instance of Mastodon, but it bugs me that there's gonna be that issue with avatars and profiles not updating :(</content>\n <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1250742\"/>\n <status_net notice_id=\"1250742\"></status_net>\n <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>\n <published>2016-03-15T18:44:54+00:00</published>\n <updated>2016-03-15T18:44:54+00:00</updated>\n <thr:in-reply-to ref=\"tag:social.umeahackerspace.se,2016-03-15:noticeId=424348:objectType=comment\" href=\"https://social.umeahackerspace.se/notice/424348\"></thr:in-reply-to>\n <link rel=\"related\" href=\"https://social.umeahackerspace.se/notice/424348\"/>\n <link rel=\"ostatus:conversation\" href=\"tag:quitter.no,2016-03-15:objectType=thread:nonce=2fbd771270b5da80\"/>\n <ostatus:conversation>tag:quitter.no,2016-03-15:objectType=thread:nonce=2fbd771270b5da80</ostatus:conversation>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/person\" href=\"https://social.umeahackerspace.se/user/2\"/>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/collection\" href=\"http://activityschema.org/collection/public\"/>\n <link rel=\"self\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1250742.atom\"/>\n <link rel=\"edit\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1250742.atom\"/>\n <statusnet:notice_info local_id=\"1250742\" source=\"Qvitter\"></statusnet:notice_info>\n</entry>\n<entry>\n <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>\n <id>tag:quitter.no,2016-03-15:noticeId=1250653:objectType=note</id>\n <title>New note by gargron</title>\n <content type=\"html\">@&lt;a href=&quot;https://social.umeahackerspace.se/user/2&quot; class=&quot;h-card mention&quot; title=&quot;&amp;lt;Mikael &amp;amp; Nordfeldth&amp;gt;&quot;&gt;mmn&lt;/a&gt; Any progress on the issues I created?</content>\n <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1250653\"/>\n <status_net notice_id=\"1250653\"></status_net>\n <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>\n <published>2016-03-15T18:27:00+00:00</published>\n <updated>2016-03-15T18:27:00+00:00</updated>\n <link rel=\"ostatus:conversation\" href=\"tag:quitter.no,2016-03-15:objectType=thread:nonce=2fbd771270b5da80\"/>\n <ostatus:conversation>tag:quitter.no,2016-03-15:objectType=thread:nonce=2fbd771270b5da80</ostatus:conversation>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/person\" href=\"https://social.umeahackerspace.se/user/2\"/>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/collection\" href=\"http://activityschema.org/collection/public\"/>\n <link rel=\"self\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1250653.atom\"/>\n <link rel=\"edit\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1250653.atom\"/>\n <statusnet:notice_info local_id=\"1250653\" source=\"Qvitter\"></statusnet:notice_info>\n</entry>\n<entry>\n <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>\n <id>tag:quitter.no,2016-03-14:noticeId=1243566:objectType=comment</id>\n <title>New comment by gargron</title>\n <content type=\"html\">@&lt;a href=&quot;https://community.highlandarrow.com/user/1&quot; class=&quot;h-card mention&quot; title=&quot;Maiyannah Bishop&quot;&gt;maiyannah&lt;/a&gt; I heard Piwik is also good.</content>\n <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1243566\"/>\n <status_net notice_id=\"1243566\"></status_net>\n <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>\n <published>2016-03-14T15:35:23+00:00</published>\n <updated>2016-03-14T15:35:23+00:00</updated>\n <thr:in-reply-to ref=\"tag:community.highlandarrow.com,2016-03-14:noticeId=50467:objectType=note\" href=\"https://community.highlandarrow.com/notice/50467\"></thr:in-reply-to>\n <link rel=\"related\" href=\"https://community.highlandarrow.com/notice/50467\"/>\n <link rel=\"ostatus:conversation\" href=\"tag:community.highlandarrow.com,2016-03-14:objectType=thread:nonce=8fbf00e7f76866d3\"/>\n <ostatus:conversation>tag:community.highlandarrow.com,2016-03-14:objectType=thread:nonce=8fbf00e7f76866d3</ostatus:conversation>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/person\" href=\"https://community.highlandarrow.com/user/1\"/>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/collection\" href=\"http://activityschema.org/collection/public\"/>\n <link rel=\"self\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1243566.atom\"/>\n <link rel=\"edit\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1243566.atom\"/>\n <statusnet:notice_info local_id=\"1243566\" source=\"Qvitter\"></statusnet:notice_info>\n</entry>\n<entry>\n <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>\n <id>tag:quitter.no,2016-03-14:noticeId=1243331:objectType=comment</id>\n <title>New comment by gargron</title>\n <content type=\"html\">I do wish I had somebody else partake in the development process if only to give me feedback on my decisions</content>\n <link rel=\"alternate\" type=\"text/html\" href=\"https://quitter.no/notice/1243331\"/>\n <status_net notice_id=\"1243331\"></status_net>\n <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>\n <published>2016-03-14T14:52:03+00:00</published>\n <updated>2016-03-14T14:52:03+00:00</updated>\n <thr:in-reply-to ref=\"tag:quitter.no,2016-03-14:noticeId=1243309:objectType=comment\" href=\"https://quitter.no/notice/1243309\"></thr:in-reply-to>\n <link rel=\"related\" href=\"https://quitter.no/notice/1243309\"/>\n <link rel=\"ostatus:conversation\" href=\"tag:quitter.no,2016-03-14:objectType=thread:nonce=46e8a2abc1839d01\"/>\n <ostatus:conversation>tag:quitter.no,2016-03-14:objectType=thread:nonce=46e8a2abc1839d01</ostatus:conversation>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/person\" href=\"https://quitter.no/user/7477\"/>\n <link rel=\"mentioned\" ostatus:object-type=\"http://activitystrea.ms/schema/1.0/collection\" href=\"http://activityschema.org/collection/public\"/>\n <link rel=\"self\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1243331.atom\"/>\n <link rel=\"edit\" type=\"application/atom+xml\" href=\"https://quitter.no/api/statuses/show/1243331.atom\"/>\n <statusnet:notice_info local_id=\"1243331\" source=\"Qvitter\"></statusnet:notice_info>\n</entry>\n</feed>\n"
  },
  {
    "path": "spec/fixtures/requests/idn.txt",
    "content": "HTTP/1.1 200 OK\r\nServer: nginx\r\nDate: Sun, 23 Apr 2017 19:37:13 GMT\r\nContent-Type: text/html\r\nContent-Length: 38111\r\nLast-Modified: Wed, 20 Jul 2016 02:50:52 GMT\r\nConnection: keep-alive\r\nAccept-Ranges: bytes\r\n\n<!DOCTYPE html>\r\n<html>\r\n\t<head>\r\n\t\t<meta charset=\"UTF-8\">\r\n\t\t<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge, chrome=1\" />\r\n\t\t<meta name=\"viewport\" content=\"initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no\">\r\n\t\t<script>\r\n          var _hmt = _hmt || [];\r\n          (function() {\r\n            var hm = document.createElement(\"script\");\r\n            hm.src = \"http://hm.baidu.com/hm.js?746c3f6346fae8612933e5921803ee32\";\r\n            var s = document.getElementsByTagName(\"script\")[0]; \r\n            s.parentNode.insertBefore(hm, s);\r\n          })();\r\n\n    \t</script>\r\n\n\n\t\t<link rel=\"stylesheet\" type=\"text/css\" href=\"css/common.css\"/>\r\n\t\t<script src=\"js/jquery-1.11.1.min.js\" type=\"text/javascript\" charset=\"utf-8\"></script>\r\n\t\t<script src=\"js/common.js\" type=\"text/javascript\" charset=\"utf-8\"></script>\r\n\t\t<script src=\"js/carousel.js\" type=\"text/javascript\" charset=\"utf-8\"></script>\r\n\t\t<title>中国域名网站</title>\r\n\n\t</head>\r\n\t<body>\r\n\t\t<div class=\"head-tips\" id=\"headTip\">\r\n\t\t\t<span class=\"close\" id=\"headtips-close\"><img src=\"css/img/close.png\" alt=\"\" /></span>\r\n\t\t</div>\r\n\t\t<div class=\"banner-bg\"></div>\r\n\t\t<div class=\"container\">\r\n\t\t\t<div class=\"banner\">\r\n\t\t\t\t<img src=\"css/img/banner.png\" alt=\"\" />\r\n\t\t\t</div>\r\n\t\t\t<div class=\"nav\">\r\n\t\t\t\t<h1>名站导航</h1>\r\n\t\t\t\t<div class=\"left-btn\" id=\"pre\">\r\n\t\t\t\t\t<img src=\"css/img/arrow-left.png\" alt=\"\" />\r\n\t\t\t\t</div>\r\n\t\t\t\t<div class=\"carousel\">\r\n\t\t\t\t\t<ul class=\"carousel-content\">\r\n\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t<a href=\"http://中央电视台.中国\"  target=\"_blank\">\r\n\t\t\t\t\t\t\t\t<img src=\"css/img/p10.png\" alt=\"\" />\r\n\t\t\t\t\t\t\t\t<p>中央电视台.中国</p>\r\n\t\t\t\t\t\t\t</a><a href=\"http://平安北京.中国\"  target=\"_blank\" class=\"mt-4\">\r\n\t\t\t\t\t\t\t\t<img src=\"css/img/p5.png\" alt=\"\" />\r\n\t\t\t\t\t\t\t\t<p>平安北京.中国</p>\r\n\t\t\t\t\t\t\t</a>\r\n\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t<a href=\"http://人民网.中国\"  target=\"_blank\">\r\n\t\t\t\t\t\t\t\t<img src=\"css/img/p6.png\" alt=\"\" />\r\n\t\t\t\t\t\t\t\t<p>人民网.中国</p>\r\n\t\t\t\t\t\t\t</a><a href=\"http://招商银行.中国\"  target=\"_blank\" class=\"mt-4\">\r\n\t\t\t\t\t\t\t\t<img src=\"css/img/p8.png\" alt=\"\" />\r\n\t\t\t\t\t\t\t\t<p>招商银行.中国</p>\r\n\t\t\t\t\t\t\t</a>\r\n\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t<a href=\"http://必胜客宅急送.中国\"  target=\"_blank\">\r\n\t\t\t\t\t\t\t\t<img src=\"css/img/p1.png\" alt=\"\" />\r\n\t\t\t\t\t\t\t\t<p>必胜客宅急送.中国</p>\r\n\t\t\t\t\t\t\t</a><a href=\"http://创业咖啡.中国\"  target=\"_blank\" class=\"mt-4\">\r\n\t\t\t\t\t\t\t\t<img src=\"css/img/p2.png\" alt=\"\" />\r\n\t\t\t\t\t\t\t\t<p>创业咖啡.中国</p>\r\n\t\t\t\t\t\t\t</a>\r\n\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t<a href=\"http://中国移动.中国\"  target=\"_blank\">\r\n\t\t\t\t\t\t\t\t<img src=\"css/img/p9.png\" alt=\"\" />\r\n\t\t\t\t\t\t\t\t<p>中国移动.中国</p>\r\n\t\t\t\t\t\t\t</a><a href=\"http://海盟.中国\"  target=\"_blank\" class=\"mt-4\">\r\n\t\t\t\t\t\t\t\t<img src=\"css/img/p3.png\" alt=\"\" />\r\n\t\t\t\t\t\t\t\t<p>海盟.中国</p>\r\n\t\t\t\t\t\t\t</a>\r\n\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t<a href=\"http://艺龙.中国\"  target=\"_blank\">\r\n\t\t\t\t\t\t\t\t<img src=\"css/img/p7.png\" alt=\"\" />\r\n\t\t\t\t\t\t\t\t<p>艺龙.中国</p>\r\n\t\t\t\t\t\t\t</a><a href=\"http://和讯.中国\"  target=\"_blank\" class=\"mt-4\">\r\n\t\t\t\t\t\t\t\t<img src=\"css/img/p4.png\" alt=\"\" />\r\n\t\t\t\t\t\t\t\t<p>和讯.中国</p>\r\n\t\t\t\t\t\t\t</a>\r\n\t\t\t\t\t\t</li>\r\n\t\t\t\t\t</ul>\r\n\t\t\t\t</div>\r\n\t\t\t\t<div class=\"right-btn\" id=\"next\">\r\n\t\t\t\t\t<img src=\"css/img/arrow-right.png\" alt=\"\" />\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t\t<div class=\"all-url\">\r\n\t\t\t<div class=\"container\">\r\n\t\t\t\t<h1>网址大全</h1>\r\n\t\t\t\t<ul class=\"url\">\r\n\t\t\t\t\t<li><a href=\"http://人民网.中国\" target=\"_blank\">人民网.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://新华网.中国\" target=\"_blank\">新华网.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://中央电视台.中国\" target=\"_blank\">中央电视台.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://光明网.中国\" target=\"_blank\">光明网.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://平安北京.中国\" target=\"_blank\">平安北京.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://联想微博.中国\" target=\"_blank\">联想微博.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://首都网警.中国\" target=\"_blank\">首都网警.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://北京消防.中国\" target=\"_blank\">北京消防.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://海淀公安.中国\" target=\"_blank\">海淀公安.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://通州警方.中国\" target=\"_blank\">通州警方.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://门头沟禁毒.中国\" target=\"_blank\">门头沟禁毒.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://西部数码.中国\" target=\"_blank\">西部数码.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://中央电视台.中国\" target=\"_blank\">中央电视台.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://中国移动.中国\" target=\"_blank\">中国移动.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://必胜宅急送.中国\" target=\"_blank\">必胜宅急送.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://老正兴.中国\" target=\"_blank\">老正兴.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://广州酒家.中国\" target=\"_blank\">广州酒家.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://格力.中国\" target=\"_blank\">格力.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://福建金爵.中国\" target=\"_blank\">福建金爵.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://和信房产.中国\" target=\"_blank\">和信房产.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://金爵房地产.中国\" target=\"_blank\">金爵房地产.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://联泰地产.中国\" target=\"_blank\">联泰地产.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://鲁商置业.中国\" target=\"_blank\">鲁商置业.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://鲁商置业股份.中国\" target=\"_blank\">鲁商置业股份.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://美佳华.中国\" target=\"_blank\">美佳华.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://金世纪工程.中国\" target=\"_blank\">金世纪工程.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://金世纪集团.中国\" target=\"_blank\">金世纪集团.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://深圳金世纪.中国\" target=\"_blank\">深圳金世纪.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://总部基地.中国\" target=\"_blank\">总部基地.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://德律风.中国\" target=\"_blank\">德律风.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://德律风物业.中国\" target=\"_blank\">德律风物业.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://柯林.中国\" target=\"_blank\">柯林.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://上海德律风物业.中国\" target=\"_blank\">上海德律风物业.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://广东海印集团股份.中国\" target=\"_blank\">广东海印集团股份.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://广东海印集团股份有限公司.中国\" target=\"_blank\">广东海印集团股份有限公司.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://艺龙.中国\" target=\"_blank\">艺龙.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://北京旅游信息网.中国\" target=\"_blank\">北京旅游信息网.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://北京故宫博物院.中国\" target=\"_blank\">北京故宫博物院.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://旅行张家界.中国\" target=\"_blank\">旅行张家界.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://张家界旅游.中国\" target=\"_blank\">张家界旅游.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://广州市旅游局.中国\" target=\"_blank\">广州市旅游局.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://旅游在线.中国\" target=\"_blank\">旅游在线.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://威海旅游集散中心.中国\" target=\"_blank\">威海旅游集散中心.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://锦州旅游.中国\" target=\"_blank\">锦州旅游.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://金牛湖风景旅游度假区.中国\" target=\"_blank\">金牛湖风景旅游度假区.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://环球旅行社.中国\" target=\"_blank\">环球旅行社.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://养鹿场.中国\" target=\"_blank\">养鹿场.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://东瀛游.中国\" target=\"_blank\">东瀛游.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://东瀛游旅行社.中国\" target=\"_blank\">东瀛游旅行社.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://桂林游.中国\" target=\"_blank\">桂林游.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://桂林之旅.中国\" target=\"_blank\">桂林之旅.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://美国环球旅行社.中国\" target=\"_blank\">美国环球旅行社.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://东天目山.中国\" target=\"_blank\">东天目山.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://凤山寺.中国\" target=\"_blank\">凤山寺.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://黄沙古渡.中国\" target=\"_blank\">黄沙古渡.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://城头山.中国\" target=\"_blank\">城头山.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://港游网.中国\" target=\"_blank\">港游网.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://一起游.中国\" target=\"_blank\">一起游.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://山水家园.中国\" target=\"_blank\">山水家园.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://蒋巷村.中国\" target=\"_blank\">蒋巷村.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://蒋巷村农业生态旅游.中国\" target=\"_blank\">蒋巷村农业生态旅游.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://厦门海峡旅行社.中国\" target=\"_blank\">厦门海峡旅行社.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://姜堰宾馆.中国\" target=\"_blank\">姜堰宾馆.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://上海远洋宾馆.中国\" target=\"_blank\">上海远洋宾馆.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://红栌山庄.中国\" target=\"_blank\">红栌山庄.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://金牛湖风景旅游度假区.中国\" target=\"_blank\">金牛湖风景旅游度假区.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://金牛湖风景区.中国\" target=\"_blank\">金牛湖风景区.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://北京半岛酒店.中国\" target=\"_blank\">北京半岛酒店.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://比华利山半岛酒店.中国\" target=\"_blank\">比华利山半岛酒店.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://东京半岛酒店.中国\" target=\"_blank\">东京半岛酒店.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://君乐酒店.中国\" target=\"_blank\">君乐酒店.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://凯迪威酒店.中国\" target=\"_blank\">凯迪威酒店.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://莱州酒店.中国\" target=\"_blank\">莱州酒店.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://曼谷半岛酒店.中国\" target=\"_blank\">曼谷半岛酒店.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://上海半岛酒店.中国\" target=\"_blank\">上海半岛酒店.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://上虞国际大酒店.中国\" target=\"_blank\">上虞国际大酒店.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://王府半島酒店.中国\" target=\"_blank\">王府半島酒店.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://香港半岛酒店.中国\" target=\"_blank\">香港半岛酒店.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://银河大酒店.中国\" target=\"_blank\">银河大酒店.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://健康365.中国\" target=\"_blank\">健康365.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://家天下.中国\" target=\"_blank\">家天下.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://北京大学第三医院.中国\" target=\"_blank\">北京大学第三医院.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://西藏阜康医药.中国\" target=\"_blank\">西藏阜康医药.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://沈阳妇婴医院.中国\" target=\"_blank\">沈阳妇婴医院.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://福建医科大学附属第一医院.中国\" target=\"_blank\">福建医科大学附属第一医院.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://北方药业.中国\" target=\"_blank\">北方药业.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://医药导报.中国\" target=\"_blank\">医药导报.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://中国医药导报.中国\" target=\"_blank\">中国医药导报.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://云南省医药有限公司.中国\" target=\"_blank\">云南省医药有限公司.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://云南省医药.中国\" target=\"_blank\">云南省医药.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://必胜宅急送.中国\" target=\"_blank\">必胜宅急送.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://青岛啤酒股份有限公司.中国\" target=\"_blank\">青岛啤酒股份有限公司.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://火锅面.中国\" target=\"_blank\">火锅面.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://57度湘.中国\" target=\"_blank\">57度湘.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://澳門佳景集團.中国\" target=\"_blank\">澳門佳景集團.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://澳門佳景飲食集團.中国\" target=\"_blank\">澳門佳景飲食集團.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://赤峰陈曲.中国\" target=\"_blank\">赤峰陈曲.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://春宝.中国\" target=\"_blank\">春宝.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://富农水稻.中国\" target=\"_blank\">富农水稻.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://功德林.中国\" target=\"_blank\">功德林.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://古船.中国\" target=\"_blank\">古船.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://古船食品.中国\" target=\"_blank\">古船食品.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://红岩村.中国\" target=\"_blank\">红岩村.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://佳景飲食集團.中国\" target=\"_blank\">佳景飲食集團.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://赖永初酒业.中国\" target=\"_blank\">赖永初酒业.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://厉家菜.中国\" target=\"_blank\">厉家菜.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://莲花岛.中国\" target=\"_blank\">莲花岛.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://廖平一两酒.中国\" target=\"_blank\">廖平一两酒.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://龙轩.中国\" target=\"_blank\">龙轩.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://迈德乐.中国\" target=\"_blank\">迈德乐.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://明记炖品.中国\" target=\"_blank\">明记炖品.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://明记炖品世家.中国\" target=\"_blank\">明记炖品世家.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://黔江鸡杂.中国\" target=\"_blank\">黔江鸡杂.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://聖安娜餅屋.中国\" target=\"_blank\">聖安娜餅屋.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://华夏茶业网.中国\" target=\"_blank\">华夏茶业网.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://宅香锅.中国\" target=\"_blank\">宅香锅.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://荞麦面.中国\" target=\"_blank\">荞麦面.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://宅面坊.中国\" target=\"_blank\">宅面坊.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://宅豆坊.中国\" target=\"_blank\">宅豆坊.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://草原羔羊肉.中国\" target=\"_blank\">草原羔羊肉.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://火锅饺.中国\" target=\"_blank\">火锅饺.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://鸟鸡蛋.中国\" target=\"_blank\">鸟鸡蛋.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://宅米饭.中国\" target=\"_blank\">宅米饭.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://白野猪肉.中国\" target=\"_blank\">白野猪肉.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://黑野猪肉.中国\" target=\"_blank\">黑野猪肉.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://特色野猪肉.中国\" target=\"_blank\">特色野猪肉.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://生态畜牧.中国\" target=\"_blank\">生态畜牧.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://野豆坊.中国\" target=\"_blank\">野豆坊.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://野猪牧.中国\" target=\"_blank\">野猪牧.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://野猪网.中国\" target=\"_blank\">野猪网.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://酷牛肉.中国\" target=\"_blank\">酷牛肉.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://羔羊网.中国\" target=\"_blank\">羔羊网.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://野猪肉.中国\" target=\"_blank\">野猪肉.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://鸟鸡肉.中国\" target=\"_blank\">鸟鸡肉.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://藏羔羊.中国\" target=\"_blank\">藏羔羊.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://酷牛牧场.中国\" target=\"_blank\">酷牛牧场.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://鸟鸡牧场.中国\" target=\"_blank\">鸟鸡牧场.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://鸟鸡网.中国\" target=\"_blank\">鸟鸡网.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://家餐馆.中国\" target=\"_blank\">家餐馆.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://宅火锅.中国\" target=\"_blank\">宅火锅.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://食品饮料网.中国\" target=\"_blank\">食品饮料网.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://中国湿巾.中国\" target=\"_blank\">中国湿巾.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://海特果菜.中国\" target=\"_blank\">海特果菜.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://果菜.中国\" target=\"_blank\">果菜.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://宏鑫德.中国\" target=\"_blank\">宏鑫德.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://北方烧酒.中国\" target=\"_blank\">北方烧酒.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://欧兰娑曼.中国\" target=\"_blank\">欧兰娑曼.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://威尔富.中国\" target=\"_blank\">威尔富.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://虎林老窖.中国\" target=\"_blank\">虎林老窖.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://唐记食品.中国\" target=\"_blank\">唐记食品.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://津恺食品.中国\" target=\"_blank\">津恺食品.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://津恺.中国\" target=\"_blank\">津恺.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://老中医养生.中国\" target=\"_blank\">老中医养生.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://山东伟龙食品公司.中国\" target=\"_blank\">山东伟龙食品公司.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://太泉蜂业.中国\" target=\"_blank\">太泉蜂业.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://天鹅肉.中国\" target=\"_blank\">天鹅肉.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://望湘园.中国\" target=\"_blank\">望湘园.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://伟龙饼干.中国\" target=\"_blank\">伟龙饼干.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://沃根葡萄酒.中国\" target=\"_blank\">沃根葡萄酒.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://亚坤集团.中国\" target=\"_blank\">亚坤集团.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://鱼丸.中国\" target=\"_blank\">鱼丸.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://真美集团.中国\" target=\"_blank\">真美集团.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://真美食品.中国\" target=\"_blank\">真美食品.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://中国餐饮标识.中国\" target=\"_blank\">中国餐饮标识.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://迷奇.中国\" target=\"_blank\">迷奇.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://乐隆隆.中国\" target=\"_blank\">乐隆隆.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://绞股蓝.中国\" target=\"_blank\">绞股蓝.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://瀑布仙茗.中国\" target=\"_blank\">瀑布仙茗.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://金记食品.中国\" target=\"_blank\">金记食品.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://朱老六.中国\" target=\"_blank\">朱老六.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://嘉太.中国\" target=\"_blank\">嘉太.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://顺德堂.中国\" target=\"_blank\">顺德堂.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://广味源.中国\" target=\"_blank\">广味源.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://德辉食品.中国\" target=\"_blank\">德辉食品.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://金龙船.中国\" target=\"_blank\">金龙船.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://东方即白.中国\" target=\"_blank\">东方即白.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://中山华美实业.中国\" target=\"_blank\">中山华美实业.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://富士亭.中国\" target=\"_blank\">富士亭.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://三安科技.中国\" target=\"_blank\">三安科技.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://供美香食品.中国\" target=\"_blank\">供美香食品.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://丰德天元.中国\" target=\"_blank\">丰德天元.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://老藏医.中国\" target=\"_blank\">老藏医.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://新农仓.中国\" target=\"_blank\">新农仓.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://濠吉.中国\" target=\"_blank\">濠吉.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://品味爽.中国\" target=\"_blank\">品味爽.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://坤育.中国\" target=\"_blank\">坤育.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://皇宫食品.中国\" target=\"_blank\">皇宫食品.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://依海.中国\" target=\"_blank\">依海.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://广州凯虹.中国\" target=\"_blank\">广州凯虹.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://宝姿日化.中国\" target=\"_blank\">宝姿日化.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://乐高乐.中国\" target=\"_blank\">乐高乐.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://茂华食品.中国\" target=\"_blank\">茂华食品.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://白鹿集团.中国\" target=\"_blank\">白鹿集团.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://好丽友集团.中国\" target=\"_blank\">好丽友集团.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://法兰红.中国\" target=\"_blank\">法兰红.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://教育部.中国\" target=\"_blank\">教育部.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://国家民委.中国\" target=\"_blank\">国家民委.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://人口计生委.中国\" target=\"_blank\">人口计生委.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://工商总局.中国\" target=\"_blank\">工商总局.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://监察部.中国\" target=\"_blank\">监察部.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://农业部.中国\" target=\"_blank\">农业部.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://人民银行.中国\" target=\"_blank\">人民银行.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://侨办.中国\" target=\"_blank\">侨办.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://食品药品监督局.中国\" target=\"_blank\">食品药品监督局.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://科技部.中国\" target=\"_blank\">科技部.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://财政部.中国\" target=\"_blank\">财政部.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://文化部.中国\" target=\"_blank\">文化部.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://审计署.中国\" target=\"_blank\">审计署.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://体育总局.中国\" target=\"_blank\">体育总局.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://知识产权局.中国\" target=\"_blank\">知识产权局.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://国研网.中国\" target=\"_blank\">国研网.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://电监会.中国\" target=\"_blank\">电监会.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://民航总局.中国\" target=\"_blank\">民航总局.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://卫生部.中国\" target=\"_blank\">卫生部.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://安全监察总局.中国\" target=\"_blank\">安全监察总局.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://国家行政学院.中国\" target=\"_blank\">国家行政学院.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://申银万国.中国\" target=\"_blank\">申银万国.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://保定保险协会.中国\" target=\"_blank\">保定保险协会.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://和讯.中国\" target=\"_blank\">和讯.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://招商证券.中国\" target=\"_blank\">招商证券.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://中投证券.中国\" target=\"_blank\">中投证券.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://鹏元征信.中国\" target=\"_blank\">鹏元征信.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://中融联合.中国\" target=\"_blank\">中融联合.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://长城资产.中国\" target=\"_blank\">长城资产.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://周生生證券.中国\" target=\"_blank\">周生生證券.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://福建湄洲湾控股.中国\" target=\"_blank\">福建湄洲湾控股.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://中安现金.中国\" target=\"_blank\">中安现金.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://中安信业.中国\" target=\"_blank\">中安信业.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://聯訊證券.中国\" target=\"_blank\">聯訊證券.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://元富理財网.中国\" target=\"_blank\">元富理財网.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://金立方资本.中国\" target=\"_blank\">金立方资本.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://安信证券.中国\" target=\"_blank\">安信证券.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://中国创业投资网.中国\" target=\"_blank\">中国创业投资网.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://進邦匯理.中国\" target=\"_blank\">進邦匯理.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://中再集团.中国\" target=\"_blank\">中再集团.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://交通银行.中国\" target=\"_blank\">交通银行.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://农业银行.中国\" target=\"_blank\">农业银行.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://民生银行.中国\" target=\"_blank\">民生银行.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://招商银行.中国\" target=\"_blank\">招商银行.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://黄河银行.中国\" target=\"_blank\">黄河银行.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://周口市商业银行.中国\" target=\"_blank\">周口市商业银行.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://金融快线.中国\" target=\"_blank\">金融快线.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://农信银.中国\" target=\"_blank\">农信银.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://乐pad微博.中国\" target=\"_blank\">乐pad微博.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://联想显示器.中国\" target=\"_blank\">联想显示器.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://联想打印.中国\" target=\"_blank\">联想打印.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://联想Z流行.中国\" target=\"_blank\">联想Z流行.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://中国国际新闻网.中国\" target=\"_blank\">中国国际新闻网.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://洛阳电视台.中国\" target=\"_blank\">洛阳电视台.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://崇左新闻网.中国\" target=\"_blank\">崇左新闻网.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://超越之路.中国\" target=\"_blank\">超越之路.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://长安教育网.中国\" target=\"_blank\">长安教育网.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://唐密茶道.中国\" target=\"_blank\">唐密茶道.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://雷峰陪练.中国\" target=\"_blank\">雷峰陪练.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://考研.中国\" target=\"_blank\">考研.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://世界大学城.中国\" target=\"_blank\">世界大学城.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://路正驾校.中国\" target=\"_blank\">路正驾校.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://比特威.中国\" target=\"_blank\">比特威.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://吉林省农业科学院.中国\" target=\"_blank\">吉林省农业科学院.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://普通话审音.中国\" target=\"_blank\">普通话审音.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://童帅国际教育.中国\" target=\"_blank\">童帅国际教育.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://成功之钥.中国\" target=\"_blank\">成功之钥.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://西安理工大学.中国\" target=\"_blank\">西安理工大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://贵阳电脑学校.中国\" target=\"_blank\">贵阳电脑学校.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://黑龙江省实验中学.中国\" target=\"_blank\">黑龙江省实验中学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://浙江艺术职业学院.中国\" target=\"_blank\">浙江艺术职业学院.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://萃忆学堂.中国\" target=\"_blank\">萃忆学堂.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://闽南科技学院.中国\" target=\"_blank\">闽南科技学院.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://普通话语音.中国\" target=\"_blank\">普通话语音.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://鞍山师范大学.中国\" target=\"_blank\">鞍山师范大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://北京电影学院.中国\" target=\"_blank\">北京电影学院.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://成都理工大学.中国\" target=\"_blank\">成都理工大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://东北大学.中国\" target=\"_blank\">东北大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://赣南师范学院.中国\" target=\"_blank\">赣南师范学院.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://广州大学.中国\" target=\"_blank\">广州大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://河北大学.中国\" target=\"_blank\">河北大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://河北科技师范学院.中国\" target=\"_blank\">河北科技师范学院.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://河南农业大学.中国\" target=\"_blank\">河南农业大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://江西师范大学.中国\" target=\"_blank\">江西师范大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://辽宁大学.中国\" target=\"_blank\">辽宁大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://南昌大学.中国\" target=\"_blank\">南昌大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://南京理工大学.中国\" target=\"_blank\">南京理工大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://青岛大学.中国\" target=\"_blank\">青岛大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://山东大学.中国\" target=\"_blank\">山东大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://汕头大学.中国\" target=\"_blank\">汕头大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://上海交通大学.中国\" target=\"_blank\">上海交通大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://首都经济贸易大学.中国\" target=\"_blank\">首都经济贸易大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://四川文理学院.中国\" target=\"_blank\">四川文理学院.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://天津大学.中国\" target=\"_blank\">天津大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://五邑大学.中国\" target=\"_blank\">五邑大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://百色学院.中国\" target=\"_blank\">百色学院.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://北京化工大学.中国\" target=\"_blank\">北京化工大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://大连理工大学.中国\" target=\"_blank\">大连理工大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://福建医科大学.中国\" target=\"_blank\">福建医科大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://广东工业大学.中国\" target=\"_blank\">广东工业大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://海南师范大学.中国\" target=\"_blank\">海南师范大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://淮海工学院.中国\" target=\"_blank\">淮海工学院.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://辽宁对外经贸学院.中国\" target=\"_blank\">辽宁对外经贸学院.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://青海师范大学.中国\" target=\"_blank\">青海师范大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://山东农业大学.中国\" target=\"_blank\">山东农业大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://上海财经大学.中国\" target=\"_blank\">上海财经大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://上海中医药大学.中国\" target=\"_blank\">上海中医药大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://首都师范大学.中国\" target=\"_blank\">首都师范大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://塔里木大学.中国\" target=\"_blank\">塔里木大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://西安电子科技大学.中国\" target=\"_blank\">西安电子科技大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://清华大学.中国\" target=\"_blank\">清华大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://大连医科大学.中国\" target=\"_blank\">大连医科大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://贵州大学.中国\" target=\"_blank\">贵州大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://哈尔滨学院.中国\" target=\"_blank\">哈尔滨学院.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://海南医学院.中国\" target=\"_blank\">海南医学院.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://黑龙江大学.中国\" target=\"_blank\">黑龙江大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://集美大学.中国\" target=\"_blank\">集美大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://南京邮电大学.中国\" target=\"_blank\">南京邮电大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://上海大学.中国\" target=\"_blank\">上海大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://深圳大学.中国\" target=\"_blank\">深圳大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://四川大学.中国\" target=\"_blank\">四川大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://天津师范大学.中国\" target=\"_blank\">天津师范大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://西安工业大学.中国\" target=\"_blank\">西安工业大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://北华大学.中国\" target=\"_blank\">北华大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://防灾科技学院.中国\" target=\"_blank\">防灾科技学院.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://甘肃农业大学.中国\" target=\"_blank\">甘肃农业大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://广西师范学院.中国\" target=\"_blank\">广西师范学院.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://哈尔滨医科大学.中国\" target=\"_blank\">哈尔滨医科大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://河北科技大学.中国\" target=\"_blank\">河北科技大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://内蒙古大学.中国\" target=\"_blank\">内蒙古大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://宁夏大学.中国\" target=\"_blank\">宁夏大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://山东财经大学.中国\" target=\"_blank\">山东财经大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://陕西师范大学.中国\" target=\"_blank\">陕西师范大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://上海对外贸易学院.中国\" target=\"_blank\">上海对外贸易学院.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://四川警察学院.中国\" target=\"_blank\">四川警察学院.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://西华大学.中国\" target=\"_blank\">西华大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://许昌学院.中国\" target=\"_blank\">许昌学院.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://扬州大学.中国\" target=\"_blank\">扬州大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://中国矿业大学.中国\" target=\"_blank\">中国矿业大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://中南大学.中国\" target=\"_blank\">中南大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://西安理工大学.中国\" target=\"_blank\">西安理工大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://烟台大学.中国\" target=\"_blank\">烟台大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://漳州师范学院.中国\" target=\"_blank\">漳州师范学院.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://郑州大学.中国\" target=\"_blank\">郑州大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://中国农业大学.中国\" target=\"_blank\">中国农业大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://中国医药大学.中国\" target=\"_blank\">中国医药大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://西安邮电学院.中国\" target=\"_blank\">西安邮电学院.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://新疆大学.中国\" target=\"_blank\">新疆大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://云南师范大学.中国\" target=\"_blank\">云南师范大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://中国政法大学.中国\" target=\"_blank\">中国政法大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://西昌学院.中国\" target=\"_blank\">西昌学院.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://新疆农业大学.中国\" target=\"_blank\">新疆农业大学.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://浙江万里学院.中国\" target=\"_blank\">浙江万里学院.中国</a></li>\r\n\t\t\t\t\t<li><a href=\"http://重庆大学.中国\" target=\"_blank\">重庆大学.中国</a></li>\r\n\n\t\t\t\t</ul>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t\t<div class=\"open\">\r\n\t\t</div>\r\n\t\t<div class=\"container\">\r\n\t\t\t<h1 class=\"Chinese-domain\">中文域名简介</h1>\r\n\t\t\t<p class=\"Chinese-domain-content\">\r\n\t\t\t\t“中国域名”是中文域名的一种，特指以“中国”为后缀的中文域名，是我国域名体系和全球互联网域名体系的重要组成部分。“中国”是在全球互联网上代表中国的中文顶级域名，于2010年7月正式纳入全球互联网域名体系，全球互联网域名体系，全球网民可通过联网计算机在世界任何国家和地区实现无障碍访问。“中国”域名在使用上和 .CN，相似属于互联网上的基础服务，基于域名可以提供WWW.EMAIL FTP等应用服务。\r\n\t\t\t</p>\r\n\t\t</div>\r\n\t\t<div class=\"footer\">\r\n\t\t\t<p>ICP备案编号：京ICP 备09112257号－68  版权所有中国互联网信息中心</p>\r\n\t\t</div>\r\n\t</body>\r\n\t<script>\r\n\t$(\"#headTip\").hide()\r\n\tvar hostname = window.location.hostname || \"\";\r\n\n\tvar tips =  \"您所访问的域名 <font size='' color='#ff0000'>\" + hostname +\"</font> 无法到达，您可以尝试重新访问，或使用搜索相关信息\"\r\n\tif (hostname != \"导航.中国\") {\r\n\t\t$(\"#headTip\").html(tips);\r\n\t\t$(\"#headTip\").delay(500).slideDown();\r\n\t\t$('#headTip').delay(5000).slideUp();\r\n\t}\r\n\t</script>\r\n</html>\r\n"
  },
  {
    "path": "spec/fixtures/requests/json-ld.activitystreams.txt",
    "content": "HTTP/1.1 200 OK\r\nDate: Tue, 01 May 2018 23:25:57 GMT\r\nContent-Location: activitystreams.jsonld\r\nVary: negotiate,accept\r\nTCN: choice\r\nLast-Modified: Mon, 16 Apr 2018 00:28:23 GMT\r\nETag: \"1eb0-569ec4caa97c0;d3-540ee27e0eec0\"\r\nAccept-Ranges: bytes\r\nContent-Length: 7856\r\nCache-Control: max-age=21600\r\nExpires: Wed, 02 May 2018 05:25:57 GMT\r\nP3P: policyref=\"http://www.w3.org/2014/08/p3p.xml\"\r\nAccess-Control-Allow-Origin: *\r\nContent-Type: application/ld+json\r\nStrict-Transport-Security: max-age=15552000; includeSubdomains; preload\r\nContent-Security-Policy: upgrade-insecure-requests\r\n\r\n{\n  \"@context\": {\n    \"@vocab\": \"_:\",\n    \"xsd\": \"http://www.w3.org/2001/XMLSchema#\",\n    \"as\": \"https://www.w3.org/ns/activitystreams#\",\n    \"ldp\": \"http://www.w3.org/ns/ldp#\",\n    \"id\": \"@id\",\n    \"type\": \"@type\",\n    \"Accept\": \"as:Accept\",\n    \"Activity\": \"as:Activity\",\n    \"IntransitiveActivity\": \"as:IntransitiveActivity\",\n    \"Add\": \"as:Add\",\n    \"Announce\": \"as:Announce\",\n    \"Application\": \"as:Application\",\n    \"Arrive\": \"as:Arrive\",\n    \"Article\": \"as:Article\",\n    \"Audio\": \"as:Audio\",\n    \"Block\": \"as:Block\",\n    \"Collection\": \"as:Collection\",\n    \"CollectionPage\": \"as:CollectionPage\",\n    \"Relationship\": \"as:Relationship\",\n    \"Create\": \"as:Create\",\n    \"Delete\": \"as:Delete\",\n    \"Dislike\": \"as:Dislike\",\n    \"Document\": \"as:Document\",\n    \"Event\": \"as:Event\",\n    \"Follow\": \"as:Follow\",\n    \"Flag\": \"as:Flag\",\n    \"Group\": \"as:Group\",\n    \"Ignore\": \"as:Ignore\",\n    \"Image\": \"as:Image\",\n    \"Invite\": \"as:Invite\",\n    \"Join\": \"as:Join\",\n    \"Leave\": \"as:Leave\",\n    \"Like\": \"as:Like\",\n    \"Link\": \"as:Link\",\n    \"Mention\": \"as:Mention\",\n    \"Note\": \"as:Note\",\n    \"Object\": \"as:Object\",\n    \"Offer\": \"as:Offer\",\n    \"OrderedCollection\": \"as:OrderedCollection\",\n    \"OrderedCollectionPage\": \"as:OrderedCollectionPage\",\n    \"Organization\": \"as:Organization\",\n    \"Page\": \"as:Page\",\n    \"Person\": \"as:Person\",\n    \"Place\": \"as:Place\",\n    \"Profile\": \"as:Profile\",\n    \"Question\": \"as:Question\",\n    \"Reject\": \"as:Reject\",\n    \"Remove\": \"as:Remove\",\n    \"Service\": \"as:Service\",\n    \"TentativeAccept\": \"as:TentativeAccept\",\n    \"TentativeReject\": \"as:TentativeReject\",\n    \"Tombstone\": \"as:Tombstone\",\n    \"Undo\": \"as:Undo\",\n    \"Update\": \"as:Update\",\n    \"Video\": \"as:Video\",\n    \"View\": \"as:View\",\n    \"Listen\": \"as:Listen\",\n    \"Read\": \"as:Read\",\n    \"Move\": \"as:Move\",\n    \"Travel\": \"as:Travel\",\n    \"IsFollowing\": \"as:IsFollowing\",\n    \"IsFollowedBy\": \"as:IsFollowedBy\",\n    \"IsContact\": \"as:IsContact\",\n    \"IsMember\": \"as:IsMember\",\n    \"subject\": {\n      \"@id\": \"as:subject\",\n      \"@type\": \"@id\"\n    },\n    \"relationship\": {\n      \"@id\": \"as:relationship\",\n      \"@type\": \"@id\"\n    },\n    \"actor\": {\n      \"@id\": \"as:actor\",\n      \"@type\": \"@id\"\n    },\n    \"attributedTo\": {\n      \"@id\": \"as:attributedTo\",\n      \"@type\": \"@id\"\n    },\n    \"attachment\": {\n      \"@id\": \"as:attachment\",\n      \"@type\": \"@id\"\n    },\n    \"bcc\": {\n      \"@id\": \"as:bcc\",\n      \"@type\": \"@id\"\n    },\n    \"bto\": {\n      \"@id\": \"as:bto\",\n      \"@type\": \"@id\"\n    },\n    \"cc\": {\n      \"@id\": \"as:cc\",\n      \"@type\": \"@id\"\n    },\n    \"context\": {\n      \"@id\": \"as:context\",\n      \"@type\": \"@id\"\n    },\n    \"current\": {\n      \"@id\": \"as:current\",\n      \"@type\": \"@id\"\n    },\n    \"first\": {\n      \"@id\": \"as:first\",\n      \"@type\": \"@id\"\n    },\n    \"generator\": {\n      \"@id\": \"as:generator\",\n      \"@type\": \"@id\"\n    },\n    \"icon\": {\n      \"@id\": \"as:icon\",\n      \"@type\": \"@id\"\n    },\n    \"image\": {\n      \"@id\": \"as:image\",\n      \"@type\": \"@id\"\n    },\n    \"inReplyTo\": {\n      \"@id\": \"as:inReplyTo\",\n      \"@type\": \"@id\"\n    },\n    \"items\": {\n      \"@id\": \"as:items\",\n      \"@type\": \"@id\"\n    },\n    \"instrument\": {\n      \"@id\": \"as:instrument\",\n      \"@type\": \"@id\"\n    },\n    \"orderedItems\": {\n      \"@id\": \"as:items\",\n      \"@type\": \"@id\",\n      \"@container\": \"@list\"\n    },\n    \"last\": {\n      \"@id\": \"as:last\",\n      \"@type\": \"@id\"\n    },\n    \"location\": {\n      \"@id\": \"as:location\",\n      \"@type\": \"@id\"\n    },\n    \"next\": {\n      \"@id\": \"as:next\",\n      \"@type\": \"@id\"\n    },\n    \"object\": {\n      \"@id\": \"as:object\",\n      \"@type\": \"@id\"\n    },\n    \"oneOf\": {\n      \"@id\": \"as:oneOf\",\n      \"@type\": \"@id\"\n    },\n    \"anyOf\": {\n      \"@id\": \"as:anyOf\",\n      \"@type\": \"@id\"\n    },\n    \"closed\": {\n      \"@id\": \"as:closed\",\n      \"@type\": \"xsd:dateTime\"\n    },\n    \"origin\": {\n      \"@id\": \"as:origin\",\n      \"@type\": \"@id\"\n    },\n    \"accuracy\": {\n      \"@id\": \"as:accuracy\",\n      \"@type\": \"xsd:float\"\n    },\n    \"prev\": {\n      \"@id\": \"as:prev\",\n      \"@type\": \"@id\"\n    },\n    \"preview\": {\n      \"@id\": \"as:preview\",\n      \"@type\": \"@id\"\n    },\n    \"replies\": {\n      \"@id\": \"as:replies\",\n      \"@type\": \"@id\"\n    },\n    \"result\": {\n      \"@id\": \"as:result\",\n      \"@type\": \"@id\"\n    },\n    \"audience\": {\n      \"@id\": \"as:audience\",\n      \"@type\": \"@id\"\n    },\n    \"partOf\": {\n      \"@id\": \"as:partOf\",\n      \"@type\": \"@id\"\n    },\n    \"tag\": {\n      \"@id\": \"as:tag\",\n      \"@type\": \"@id\"\n    },\n    \"target\": {\n      \"@id\": \"as:target\",\n      \"@type\": \"@id\"\n    },\n    \"to\": {\n      \"@id\": \"as:to\",\n      \"@type\": \"@id\"\n    },\n    \"url\": {\n      \"@id\": \"as:url\",\n      \"@type\": \"@id\"\n    },\n    \"altitude\": {\n      \"@id\": \"as:altitude\",\n      \"@type\": \"xsd:float\"\n    },\n    \"content\": \"as:content\",\n    \"contentMap\": {\n      \"@id\": \"as:content\",\n      \"@container\": \"@language\"\n    },\n    \"name\": \"as:name\",\n    \"nameMap\": {\n      \"@id\": \"as:name\",\n      \"@container\": \"@language\"\n    },\n    \"duration\": {\n      \"@id\": \"as:duration\",\n      \"@type\": \"xsd:duration\"\n    },\n    \"endTime\": {\n      \"@id\": \"as:endTime\",\n      \"@type\": \"xsd:dateTime\"\n    },\n    \"height\": {\n      \"@id\": \"as:height\",\n      \"@type\": \"xsd:nonNegativeInteger\"\n    },\n    \"href\": {\n      \"@id\": \"as:href\",\n      \"@type\": \"@id\"\n    },\n    \"hreflang\": \"as:hreflang\",\n    \"latitude\": {\n      \"@id\": \"as:latitude\",\n      \"@type\": \"xsd:float\"\n    },\n    \"longitude\": {\n      \"@id\": \"as:longitude\",\n      \"@type\": \"xsd:float\"\n    },\n    \"mediaType\": \"as:mediaType\",\n    \"published\": {\n      \"@id\": \"as:published\",\n      \"@type\": \"xsd:dateTime\"\n    },\n    \"radius\": {\n      \"@id\": \"as:radius\",\n      \"@type\": \"xsd:float\"\n    },\n    \"rel\": \"as:rel\",\n    \"startIndex\": {\n      \"@id\": \"as:startIndex\",\n      \"@type\": \"xsd:nonNegativeInteger\"\n    },\n    \"startTime\": {\n      \"@id\": \"as:startTime\",\n      \"@type\": \"xsd:dateTime\"\n    },\n    \"summary\": \"as:summary\",\n    \"summaryMap\": {\n      \"@id\": \"as:summary\",\n      \"@container\": \"@language\"\n    },\n    \"totalItems\": {\n      \"@id\": \"as:totalItems\",\n      \"@type\": \"xsd:nonNegativeInteger\"\n    },\n    \"units\": \"as:units\",\n    \"updated\": {\n      \"@id\": \"as:updated\",\n      \"@type\": \"xsd:dateTime\"\n    },\n    \"width\": {\n      \"@id\": \"as:width\",\n      \"@type\": \"xsd:nonNegativeInteger\"\n    },\n    \"describes\": {\n      \"@id\": \"as:describes\",\n      \"@type\": \"@id\"\n    },\n    \"formerType\": {\n      \"@id\": \"as:formerType\",\n      \"@type\": \"@id\"\n    },\n    \"deleted\": {\n      \"@id\": \"as:deleted\",\n      \"@type\": \"xsd:dateTime\"\n    },\n    \"inbox\": {\n      \"@id\": \"ldp:inbox\",\n      \"@type\": \"@id\"\n    },\n    \"outbox\": {\n      \"@id\": \"as:outbox\",\n      \"@type\": \"@id\"\n    },\n    \"following\": {\n      \"@id\": \"as:following\",\n      \"@type\": \"@id\"\n    },\n    \"followers\": {\n      \"@id\": \"as:followers\",\n      \"@type\": \"@id\"\n    },\n    \"streams\": {\n      \"@id\": \"as:streams\",\n      \"@type\": \"@id\"\n    },\n    \"preferredUsername\": \"as:preferredUsername\",\n    \"endpoints\": {\n      \"@id\": \"as:endpoints\",\n      \"@type\": \"@id\"\n    },\n    \"uploadMedia\": {\n      \"@id\": \"as:uploadMedia\",\n      \"@type\": \"@id\"\n    },\n    \"proxyUrl\": {\n      \"@id\": \"as:proxyUrl\",\n      \"@type\": \"@id\"\n    },\n    \"liked\": {\n      \"@id\": \"as:liked\",\n      \"@type\": \"@id\"\n    },\n    \"oauthAuthorizationEndpoint\": {\n      \"@id\": \"as:oauthAuthorizationEndpoint\",\n      \"@type\": \"@id\"\n    },\n    \"oauthTokenEndpoint\": {\n      \"@id\": \"as:oauthTokenEndpoint\",\n      \"@type\": \"@id\"\n    },\n    \"provideClientKey\": {\n      \"@id\": \"as:provideClientKey\",\n      \"@type\": \"@id\"\n    },\n    \"signClientKey\": {\n      \"@id\": \"as:signClientKey\",\n      \"@type\": \"@id\"\n    },\n    \"sharedInbox\": {\n      \"@id\": \"as:sharedInbox\",\n      \"@type\": \"@id\"\n    },\n    \"Public\": {\n      \"@id\": \"as:Public\",\n      \"@type\": \"@id\"\n    },\n    \"source\": \"as:source\",\n    \"likes\": {\n      \"@id\": \"as:likes\",\n      \"@type\": \"@id\"\n    },\n    \"shares\": {\n      \"@id\": \"as:shares\",\n      \"@type\": \"@id\"\n    }\n  }\n}\n"
  },
  {
    "path": "spec/fixtures/requests/json-ld.identity.txt",
    "content": "HTTP/1.1 200 OK\r\nAccept-Ranges: bytes\r\nAccess-Control-Allow-Headers: DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Accept-Encoding\r\nAccess-Control-Allow-Origin: *\r\nContent-Type: application/ld+json\r\nDate: Tue, 01 May 2018 23:28:21 GMT\r\nEtag: \"e26-547a6fc75b04a-gzip\"\r\nLast-Modified: Fri, 03 Feb 2017 21:30:09 GMT\r\nServer: Apache/2.4.7 (Ubuntu)\r\nVary: Accept-Encoding\r\nTransfer-Encoding: chunked\r\n\r\n{\n  \"@context\": {\n    \"id\": \"@id\",\n    \"type\": \"@type\",\n\n    \"cred\": \"https://w3id.org/credentials#\",\n    \"dc\": \"http://purl.org/dc/terms/\",\n    \"identity\": \"https://w3id.org/identity#\",\n    \"perm\": \"https://w3id.org/permissions#\",\n    \"ps\": \"https://w3id.org/payswarm#\",\n    \"rdf\": \"http://www.w3.org/1999/02/22-rdf-syntax-ns#\",\n    \"rdfs\": \"http://www.w3.org/2000/01/rdf-schema#\",\n    \"sec\": \"https://w3id.org/security#\",\n    \"schema\": \"http://schema.org/\",\n    \"xsd\": \"http://www.w3.org/2001/XMLSchema#\",\n\n    \"Group\": \"https://www.w3.org/ns/activitystreams#Group\",\n\n    \"claim\": {\"@id\": \"cred:claim\", \"@type\": \"@id\"},\n    \"credential\": {\"@id\": \"cred:credential\", \"@type\": \"@id\"},\n    \"issued\": {\"@id\": \"cred:issued\", \"@type\": \"xsd:dateTime\"},\n    \"issuer\": {\"@id\": \"cred:issuer\", \"@type\": \"@id\"},\n    \"recipient\": {\"@id\": \"cred:recipient\", \"@type\": \"@id\"},\n    \"Credential\": \"cred:Credential\",\n    \"CryptographicKeyCredential\": \"cred:CryptographicKeyCredential\",\n\n    \"about\": {\"@id\": \"schema:about\", \"@type\": \"@id\"},\n    \"address\": {\"@id\": \"schema:address\", \"@type\": \"@id\"},\n    \"addressCountry\": \"schema:addressCountry\",\n    \"addressLocality\": \"schema:addressLocality\",\n    \"addressRegion\": \"schema:addressRegion\",\n    \"comment\": \"rdfs:comment\",\n    \"created\": {\"@id\": \"dc:created\", \"@type\": \"xsd:dateTime\"},\n    \"creator\": {\"@id\": \"dc:creator\", \"@type\": \"@id\"},\n    \"description\": \"schema:description\",\n    \"email\": \"schema:email\",\n    \"familyName\": \"schema:familyName\",\n    \"givenName\": \"schema:givenName\",\n    \"image\": {\"@id\": \"schema:image\", \"@type\": \"@id\"},\n    \"label\": \"rdfs:label\",\n    \"name\": \"schema:name\",\n    \"postalCode\": \"schema:postalCode\",\n    \"streetAddress\": \"schema:streetAddress\",\n    \"title\": \"dc:title\",\n    \"url\": {\"@id\": \"schema:url\", \"@type\": \"@id\"},\n    \"Person\": \"schema:Person\",\n    \"PostalAddress\": \"schema:PostalAddress\",\n    \"Organization\": \"schema:Organization\",\n\n    \"identityService\": {\"@id\": \"identity:identityService\", \"@type\": \"@id\"},\n    \"idp\": {\"@id\": \"identity:idp\", \"@type\": \"@id\"},\n    \"Identity\": \"identity:Identity\",\n\n    \"paymentProcessor\": \"ps:processor\",\n    \"preferences\": {\"@id\": \"ps:preferences\", \"@type\": \"@vocab\"},\n\n    \"cipherAlgorithm\": \"sec:cipherAlgorithm\",\n    \"cipherData\": \"sec:cipherData\",\n    \"cipherKey\": \"sec:cipherKey\",\n    \"digestAlgorithm\": \"sec:digestAlgorithm\",\n    \"digestValue\": \"sec:digestValue\",\n    \"domain\": \"sec:domain\",\n    \"expires\": {\"@id\": \"sec:expiration\", \"@type\": \"xsd:dateTime\"},\n    \"initializationVector\": \"sec:initializationVector\",\n    \"member\": {\"@id\": \"schema:member\", \"@type\": \"@id\"},\n    \"memberOf\": {\"@id\": \"schema:memberOf\", \"@type\": \"@id\"},\n    \"nonce\": \"sec:nonce\",\n    \"normalizationAlgorithm\": \"sec:normalizationAlgorithm\",\n    \"owner\": {\"@id\": \"sec:owner\", \"@type\": \"@id\"},\n    \"password\": \"sec:password\",\n    \"privateKey\": {\"@id\": \"sec:privateKey\", \"@type\": \"@id\"},\n    \"privateKeyPem\": \"sec:privateKeyPem\",\n    \"publicKey\": {\"@id\": \"sec:publicKey\", \"@type\": \"@id\"},\n    \"publicKeyPem\": \"sec:publicKeyPem\",\n    \"publicKeyService\": {\"@id\": \"sec:publicKeyService\", \"@type\": \"@id\"},\n    \"revoked\": {\"@id\": \"sec:revoked\", \"@type\": \"xsd:dateTime\"},\n    \"signature\": \"sec:signature\",\n    \"signatureAlgorithm\": \"sec:signatureAlgorithm\",\n    \"signatureValue\": \"sec:signatureValue\",\n    \"CryptographicKey\": \"sec:Key\",\n    \"EncryptedMessage\": \"sec:EncryptedMessage\",\n    \"GraphSignature2012\": \"sec:GraphSignature2012\",\n    \"LinkedDataSignature2015\": \"sec:LinkedDataSignature2015\",\n\n    \"accessControl\": {\"@id\": \"perm:accessControl\", \"@type\": \"@id\"},\n    \"writePermission\": {\"@id\": \"perm:writePermission\", \"@type\": \"@id\"}\n  }\n}\n"
  },
  {
    "path": "spec/fixtures/requests/json-ld.security.txt",
    "content": "HTTP/1.1 200 OK\r\nAccept-Ranges: bytes\r\nAccess-Control-Allow-Headers: DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Accept-Encoding\r\nAccess-Control-Allow-Origin: *\r\nContent-Type: application/ld+json\r\nDate: Wed, 02 May 2018 16:25:32 GMT\r\nEtag: \"7e3-5651ec0f7c5ed-gzip\"\r\nLast-Modified: Tue, 13 Feb 2018 21:34:04 GMT\r\nServer: Apache/2.4.7 (Ubuntu)\r\nVary: Accept-Encoding\r\nContent-Length: 2019\r\n\r\n{\n  \"@context\": {\n    \"id\": \"@id\",\n    \"type\": \"@type\",\n\n    \"dc\": \"http://purl.org/dc/terms/\",\n    \"sec\": \"https://w3id.org/security#\",\n    \"xsd\": \"http://www.w3.org/2001/XMLSchema#\",\n\n    \"EcdsaKoblitzSignature2016\": \"sec:EcdsaKoblitzSignature2016\",\n    \"Ed25519Signature2018\": \"sec:Ed25519Signature2018\",\n    \"EncryptedMessage\": \"sec:EncryptedMessage\",\n    \"GraphSignature2012\": \"sec:GraphSignature2012\",\n    \"LinkedDataSignature2015\": \"sec:LinkedDataSignature2015\",\n    \"LinkedDataSignature2016\": \"sec:LinkedDataSignature2016\",\n    \"CryptographicKey\": \"sec:Key\",\n\n    \"authenticationTag\": \"sec:authenticationTag\",\n    \"canonicalizationAlgorithm\": \"sec:canonicalizationAlgorithm\",\n    \"cipherAlgorithm\": \"sec:cipherAlgorithm\",\n    \"cipherData\": \"sec:cipherData\",\n    \"cipherKey\": \"sec:cipherKey\",\n    \"created\": {\"@id\": \"dc:created\", \"@type\": \"xsd:dateTime\"},\n    \"creator\": {\"@id\": \"dc:creator\", \"@type\": \"@id\"},\n    \"digestAlgorithm\": \"sec:digestAlgorithm\",\n    \"digestValue\": \"sec:digestValue\",\n    \"domain\": \"sec:domain\",\n    \"encryptionKey\": \"sec:encryptionKey\",\n    \"expiration\": {\"@id\": \"sec:expiration\", \"@type\": \"xsd:dateTime\"},\n    \"expires\": {\"@id\": \"sec:expiration\", \"@type\": \"xsd:dateTime\"},\n    \"initializationVector\": \"sec:initializationVector\",\n    \"iterationCount\": \"sec:iterationCount\",\n    \"nonce\": \"sec:nonce\",\n    \"normalizationAlgorithm\": \"sec:normalizationAlgorithm\",\n    \"owner\": {\"@id\": \"sec:owner\", \"@type\": \"@id\"},\n    \"password\": \"sec:password\",\n    \"privateKey\": {\"@id\": \"sec:privateKey\", \"@type\": \"@id\"},\n    \"privateKeyPem\": \"sec:privateKeyPem\",\n    \"publicKey\": {\"@id\": \"sec:publicKey\", \"@type\": \"@id\"},\n    \"publicKeyBase58\": \"sec:publicKeyBase58\",\n    \"publicKeyPem\": \"sec:publicKeyPem\",\n    \"publicKeyService\": {\"@id\": \"sec:publicKeyService\", \"@type\": \"@id\"},\n    \"revoked\": {\"@id\": \"sec:revoked\", \"@type\": \"xsd:dateTime\"},\n    \"salt\": \"sec:salt\",\n    \"signature\": \"sec:signature\",\n    \"signatureAlgorithm\": \"sec:signingAlgorithm\",\n    \"signatureValue\": \"sec:signatureValue\"\n  }\n}\n"
  },
  {
    "path": "spec/fixtures/requests/koi8-r.txt",
    "content": "HTTP/1.1 200 OK\nServer: nginx/1.11.10\nDate: Tue, 04 Jul 2017 16:43:39 GMT\nContent-Type: text/html\nContent-Length: 273\nConnection: keep-alive\nLast-Modified: Tue, 04 Jul 2017 16:41:34 GMT\nAccept-Ranges: bytes\n\n<HTML>\n<HEAD>\n  <META NAME=\"GENERATOR\" CONTENT=\"Adobe PageMill 3.0J Mac\">\n  <META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html;CHARSET=koi8-r\">\n  <TITLE>    XVI .   .</TITLE>\n</HEAD>\n<BODY>\n<P><CENTER><B><FONT SIZE=\"+2\">    XVI .   .</FONT></B><BR>\n<HR><BR>\n</BODY>\n</HTML>\n"
  },
  {
    "path": "spec/fixtures/requests/localdomain-feed.txt",
    "content": "HTTP/1.1 200 OK\nDate: Thu, 20 Apr 2017 07:36:08 GMT\nContent-Type: application/atom+xml; charset=utf-8\nTransfer-Encoding: chunked\nConnection: keep-alive\nServer: Mastodon\nX-Frame-Options: DENY\nX-Content-Type-Options: nosniff\nX-XSS-Protection: 1; mode=block\nLink: <https://social.sitedethib.com/.well-known/webfinger?resource=acct%3AThib%40sitedethib.com>; rel=\"lrdd\"; type=\"application/xrd+xml\", <https://social.sitedethib.com/users/Thib.atom>; rel=\"alternate\"; type=\"application/atom+xml\"\nVary: Accept-Encoding\nETag: W/\"1fa54baac599205a1e54c136dea2b671\"\nCache-Control: max-age=0, private, must-revalidate\nSet-Cookie: _mastodon_session=Vk5XbERyQ0NscjJhdEw1eVEyY3JwQTlBVThObUJ1N3NFcVlJaCtpNU5FSmZlTzFIZ2FqSzhVY1lneFlLQ1haNkh1SDM5L0FSdnFLTGwwTnhJMy9qWWI5aWRnM1NOU1NLTmtuamR5cG5Ebm8vekFNL20ydGkxYXFXU2FwVTF1NnctLXdxdFhNVFA2VmlFVm5BY25QU2N1clE9PQ%3D%3D--47e86fed56f94d3998bfc3837af8de93ec8c104e; path=/; secure; HttpOnly\nX-Request-Id: 071ec889-04fb-4efa-b55e-81eb90772b50\nX-Runtime: 1.173933\nStrict-Transport-Security: max-age=31536000; includeSubDomains\n\n<?xml version=\"1.0\"?>\n<feed xmlns=\"http://www.w3.org/2005/Atom\" xmlns:thr=\"http://purl.org/syndication/thread/1.0\" xmlns:activity=\"http://activitystrea.ms/spec/1.0/\" xmlns:poco=\"http://portablecontacts.net/spec/1.0\" xmlns:media=\"http://purl.org/syndication/atommedia\" xmlns:ostatus=\"http://ostatus.org/schema/1.0\" xmlns:mastodon=\"http://mastodon.social/schema/1.0\">\n  <id>https://webdomain.com/users/foo.atom</id>\n  <title>foo</title>\n  <subtitle>foo</subtitle>\n  <updated>2017-04-08T15:38:58Z</updated>\n  <logo>https://quitter.no/avatar/7477-300-20160211190340.png</logo>\n  <author>\n    <id>https://webdomain.com/users/foo</id>\n    <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>\n    <uri>https://webdomain.com/users/foo</uri>\n    <name>foo</name>\n    <email>foo@localdomain.com</email>\n    <summary>foo</summary>\n    <link rel=\"alternate\" type=\"text/html\" href=\"https://webdomain.com/@foo\"/>\n    <link rel=\"avatar\" type=\"image/jpeg\" media:width=\"120\" media:height=\"120\" href=\"https://quitter.no/avatar/7477-300-20160211190340.png\"/>\n    <poco:preferredUsername>foo</poco:preferredUsername>\n    <poco:displayName>foo</poco:displayName>\n    <poco:note>foo</poco:note>\n    <mastodon:scope>public</mastodon:scope>\n  </author>\n  <link rel=\"alternate\" type=\"text/html\" href=\"https://webdomain.com/@foo\"/>\n  <link rel=\"self\" type=\"application/atom+xml\" href=\"https://webdomain.com/users/foo.atom\"/>\n  <link rel=\"hub\" href=\"https://webdomain.com/api/push\"/>\n  <link rel=\"salmon\" href=\"https://webdomain.com/api/salmon/1\"/>\n  <entry>\n    <id>tag:localdomain.com,2017-04-19:objectId=12774:objectType=Status</id>\n    <published>2017-04-19T22:28:01Z</published>\n    <updated>2017-04-19T22:28:01Z</updated>\n    <title>New status by foo</title>\n    <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>\n    <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>\n    <content type=\"html\" xml:lang=\"fr\">&lt;p&gt;Meh, ça foire l&amp;apos;attribution des boosts.&lt;br /&gt;Faudra que je corrige ça…&lt;/p&gt;</content>\n    <mastodon:scope>unlisted</mastodon:scope>\n    <link rel=\"alternate\" type=\"text/html\" href=\"https://webdomain.com/users/foo/updates/93\"/>\n    <link rel=\"self\" type=\"application/atom+xml\" href=\"https://webdomain.com/users/foo/updates/93.atom\"/>\n    <thr:in-reply-to ref=\"tag:localdomain.com,2017-04-19:objectId=12658:objectType=Status\" href=\"https://webdomain.com/@foo/12658\"/>\n  </entry>\n</feed>\n"
  },
  {
    "path": "spec/fixtures/requests/localdomain-hostmeta.txt",
    "content": "HTTP/1.1 200 OK\nServer: nginx/1.6.2\nDate: Sun, 20 Mar 2016 11:11:00 GMT\nContent-Type: application/xrd+xml\nTransfer-Encoding: chunked\nConnection: keep-alive\nAccess-Control-Allow-Origin: *\nVary: Accept-Encoding,Cookie\nStrict-Transport-Security: max-age=31536000; includeSubdomains;\n\n<?xml version=\"1.0\"?>\n<XRD xmlns=\"http://docs.oasis-open.org/ns/xri/xrd-1.0\">\n  <Link rel=\"lrdd\" type=\"application/xrd+xml\" template=\"https://webdomain.com/.well-known/webfinger?resource={uri}\"/>\n</XRD>\n"
  },
  {
    "path": "spec/fixtures/requests/localdomain-webfinger.txt",
    "content": "HTTP/1.1 200 OK\nServer: nginx/1.6.2\nDate: Sun, 20 Mar 2016 11:11:00 GMT\nContent-Type: application/xrd+xml\nTransfer-Encoding: chunked\nConnection: keep-alive\nAccess-Control-Allow-Origin: *\nVary: Accept-Encoding,Cookie\nStrict-Transport-Security: max-age=31536000; includeSubdomains;\n\n<?xml version=\"1.0\"?>\n<XRD xmlns=\"http://docs.oasis-open.org/ns/xri/xrd-1.0\">\n  <Subject>acct:foo@localdomain.com</Subject>\n  <Alias>https://webdomain.com/@foo</Alias>\n  <Link rel=\"http://webfinger.net/rel/profile-page\" type=\"text/html\" href=\"https://webdomain.com/@foo\"/>\n  <Link rel=\"http://schemas.google.com/g/2010#updates-from\" type=\"application/atom+xml\" href=\"https://webdomain.com/users/foo.atom\"/>\n  <Link rel=\"salmon\" href=\"https://webdomain.com/api/salmon/1\"/>\n  <Link rel=\"magic-public-key\" href=\"data:application/magic-public-key,RSA.wnIYUQp-jMqH8tzStBoVriiGtbMvH12IU125p-3shZHxJNDi7RHwseKi5ADEGwGwpXLMxqiyNlgCff1hG9DBc8MzHZi1V93F2hCOXK0bqZm2lbsWfjkpsDIdBZ8TltwSejuQCt_rqL-K5XCfknd94P7tHOCBnizQRBanj0IdcSSqh7CmRS5wa1UjwflXVMsgbDc2io1knMeMkXsl0jzwt-CFHprmITzWy9X6Ia4QevkntiXdMlwUf_UoJC7BRns-J-j_dz2LqFl1QfspMhR2R9p8plDSD-jjk8DUVSBFZ7GLWVHEd6dWkLncEVEeRLliCaQQBqF1huSuMDtYWfukWQ==.AQAB\"/>\n  <Link rel=\"http://ostatus.org/schema/1.0/subscribe\" template=\"https://webdomain.com/authorize_follow?acct={uri}\"/>\n</XRD>\n"
  },
  {
    "path": "spec/fixtures/requests/oembed_invalid_xml.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <link href=':' rel='alternate' type='application/xml+oembed'>\n  </head>\n  <body></body>\n</html>\n"
  },
  {
    "path": "spec/fixtures/requests/oembed_json.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <link href='https://host.test/provider.json' rel='alternate' type='application/json+oembed'>\n  </head>\n  <body></body>\n</html>\n"
  },
  {
    "path": "spec/fixtures/requests/oembed_json_empty.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <link href='https://host.test/empty_provider.json' rel='alternate' type='application/json+oembed'>\n  </head>\n  <body></body>\n</html>\n"
  },
  {
    "path": "spec/fixtures/requests/oembed_json_xml.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <!--\n      oEmbed\n      https://oembed.com/\n      > The type attribute must contain either application/json+oembed for JSON\n      > responses, or text/xml+oembed for XML.\n    -->\n    <link href='https://host.test/provider.json' rel='alternate' type='application/json+oembed'>\n    <link href='https://host.test/provider.xml' rel='alternate' type='text/xml+oembed'>\n  </head>\n  <body></body>\n</html>\n"
  },
  {
    "path": "spec/fixtures/requests/oembed_undiscoverable.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head></head>\n  <body></body>\n</html>\n"
  },
  {
    "path": "spec/fixtures/requests/oembed_xml.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <!--\n      oEmbed\n      https://oembed.com/\n      > The type attribute must contain either application/json+oembed for JSON\n      > responses, or text/xml+oembed for XML.\n    -->\n    <link href='https://host.test/provider.xml' rel='alternate' type='text/xml+oembed'>\n  </head>\n  <body></body>\n</html>\n"
  },
  {
    "path": "spec/fixtures/requests/redirected.host-meta.txt",
    "content": "HTTP/1.1 200 OK\r\nServer: nginx/1.6.2\r\nDate: Sun, 20 Mar 2016 11:11:00 GMT\r\nContent-Type: application/xrd+xml\r\nTransfer-Encoding: chunked\r\nConnection: keep-alive\r\nAccess-Control-Allow-Origin: *\r\nVary: Accept-Encoding,Cookie\r\nStrict-Transport-Security: max-age=31536000; includeSubdomains;\r\n\r\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<XRD xmlns=\"http://docs.oasis-open.org/ns/xri/xrd-1.0\">\r\n <Link rel=\"lrdd\" type=\"application/jrd+json\" template=\"https://redirected.com/.well-known/webfinger?resource={uri}\"/>\r\n <Link rel=\"lrdd\" type=\"application/json\" template=\"https://redirected.com/.well-known/webfinger?resource={uri}\"/>\r\n</XRD>\r\n"
  },
  {
    "path": "spec/fixtures/requests/sjis.txt",
    "content": "HTTP/1.1 200 OK\nServer: nginx/1.11.10\nDate: Tue, 04 Jul 2017 16:43:39 GMT\nContent-Type: text/html\nContent-Length: 273\nConnection: keep-alive\nLast-Modified: Tue, 04 Jul 2017 16:41:34 GMT\nAccept-Ranges: bytes\n\n<HTML>\n<HEAD>\n  <META NAME=\"GENERATOR\" CONTENT=\"Adobe PageMill 3.0J Mac\">\n  <META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html;CHARSET=x-sjis\">\n  <TITLE>SJIS̃y[W</TITLE>\n</HEAD>\n<BODY>\n<P><CENTER><B><FONT SIZE=\"+2\">N܂ĂLOlĂ̂̎łłBԂɈӖ҂͐ǂȔ܂܂ł\\グ邽ɂ͎QlA邽Aɂ܂ȂB炢Ȃ̂͂ǂ㌎ł邾BĉcɔRKɉ]ł͂͂Ȃw}ƂoȂȂāA͎͉̐̂A{炩Av̂̂̂ɂ]ƌ΂manɂ֎Q悤ɓɂłȂ̂ŁA\\ɕςĂłōlBႦ΂Ƃǂ܂̂ۂނ݂ƂłāA̎ł͐\\ĂƂĐԂɕׂ̂ɍsȂȁB</FONT></B><BR>\n<HR><BR>\n</BODY>\n</HTML>\n"
  },
  {
    "path": "spec/fixtures/requests/sjis_with_wrong_charset.txt",
    "content": "HTTP/1.1 200 OK\nServer: nginx/1.11.10\nDate: Tue, 04 Jul 2017 16:43:39 GMT\nContent-Type: text/html; charset=utf-8\nContent-Length: 273\nConnection: keep-alive\nLast-Modified: Tue, 04 Jul 2017 16:41:34 GMT\nAccept-Ranges: bytes\n\n<HTML>\n<HEAD>\n  <META NAME=\"GENERATOR\" CONTENT=\"Adobe PageMill 3.0J Mac\">\n  <META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html;CHARSET=x-sjis\">\n  <TITLE>SJIS̃y[W</TITLE>\n</HEAD>\n<BODY>\n<P><CENTER><B><FONT SIZE=\"+2\">N܂ĂLOlĂ̂̎łłBԂɈӖ҂͐ǂȔ܂܂ł\\グ邽ɂ͎QlA邽Aɂ܂ȂB炢Ȃ̂͂ǂ㌎ł邾BĉcɔRKɉ]ł͂͂Ȃw}ƂoȂȂāA͎͉̐̂A{炩Av̂̂̂ɂ]ƌ΂manɂ֎Q悤ɓɂłȂ̂ŁA\\ɕςĂłōlBႦ΂Ƃǂ܂̂ۂނ݂ƂłāA̎ł͐\\ĂƂĐԂɕׂ̂ɍsȂȁB</FONT></B><BR>\n<HR><BR>\n</BODY>\n</HTML>\n"
  },
  {
    "path": "spec/fixtures/requests/webfinger-hacker1.txt",
    "content": "HTTP/1.1 200 OK\r\nServer: nginx/1.6.2\r\nDate: Sun, 20 Mar 2016 11:13:16 GMT\r\nContent-Type: application/jrd+json\r\nTransfer-Encoding: chunked\r\nConnection: keep-alive\r\nAccess-Control-Allow-Origin: *\r\nVary: Accept-Encoding,Cookie\r\nStrict-Transport-Security: max-age=31536000; includeSubdomains;\r\n\r\n{\"subject\":\"acct:gargron@quitter.no\",\"aliases\":[\"https:\\/\\/quitter.no\\/user\\/7477\",\"https:\\/\\/quitter.no\\/gargron\",\"https:\\/\\/quitter.no\\/index.php\\/user\\/7477\",\"https:\\/\\/quitter.no\\/index.php\\/gargron\"],\"links\":[{\"rel\":\"http:\\/\\/webfinger.net\\/rel\\/profile-page\",\"type\":\"text\\/html\",\"href\":\"https:\\/\\/quitter.no\\/gargron\"},{\"rel\":\"http:\\/\\/gmpg.org\\/xfn\\/11\",\"type\":\"text\\/html\",\"href\":\"https:\\/\\/quitter.no\\/gargron\"},{\"rel\":\"describedby\",\"type\":\"application\\/rdf+xml\",\"href\":\"https:\\/\\/quitter.no\\/gargron\\/foaf\"},{\"rel\":\"http:\\/\\/apinamespace.org\\/atom\",\"type\":\"application\\/atomsvc+xml\",\"href\":\"https:\\/\\/quitter.no\\/api\\/statusnet\\/app\\/service\\/gargron.xml\"},{\"rel\":\"http:\\/\\/apinamespace.org\\/twitter\",\"href\":\"https:\\/\\/quitter.no\\/api\\/\"},{\"rel\":\"http:\\/\\/specs.openid.net\\/auth\\/2.0\\/provider\",\"href\":\"https:\\/\\/quitter.no\\/gargron\"},{\"rel\":\"http:\\/\\/schemas.google.com\\/g\\/2010#updates-from\",\"type\":\"application\\/atom+xml\",\"href\":\"https:\\/\\/quitter.no\\/api\\/statuses\\/user_timeline\\/7477.atom\"},{\"rel\":\"magic-public-key\",\"href\":\"data:application\\/magic-public-key,RSA.1ZBkHTavLvxH3FzlKv4O6WtlILKRFfNami3_Rcu8EuogtXSYiS-bB6hElZfUCSHbC4uLemOA34PEhz__CDMozax1iI_t8dzjDnh1x0iFSup7pSfW9iXk_WU3Dm74yWWW2jildY41vWgrEstuQ1dJ8vVFfSJ9T_tO4c-T9y8vDI8=.AQAB\"},{\"rel\":\"salmon\",\"href\":\"https:\\/\\/hacker.com\\/main\\/salmon\\/user\\/7477\"},{\"rel\":\"http:\\/\\/salmon-protocol.org\\/ns\\/salmon-replies\",\"href\":\"https:\\/\\/quitter.no\\/main\\/salmon\\/user\\/7477\"},{\"rel\":\"http:\\/\\/salmon-protocol.org\\/ns\\/salmon-mention\",\"href\":\"https:\\/\\/quitter.no\\/main\\/salmon\\/user\\/7477\"},{\"rel\":\"http:\\/\\/ostatus.org\\/schema\\/1.0\\/subscribe\",\"template\":\"https:\\/\\/quitter.no\\/main\\/ostatussub?profile={uri}\"}]}\r\n"
  },
  {
    "path": "spec/fixtures/requests/webfinger-hacker2.txt",
    "content": "HTTP/1.1 200 OK\r\nServer: nginx/1.6.2\r\nDate: Sun, 20 Mar 2016 11:13:16 GMT\r\nContent-Type: application/jrd+json\r\nTransfer-Encoding: chunked\r\nConnection: keep-alive\r\nAccess-Control-Allow-Origin: *\r\nVary: Accept-Encoding,Cookie\r\nStrict-Transport-Security: max-age=31536000; includeSubdomains;\r\n\r\n{\"subject\":\"acct:catsrgr8@quitter.no\",\"aliases\":[\"https:\\/\\/quitter.no\\/user\\/7477\",\"https:\\/\\/quitter.no\\/gargron\",\"https:\\/\\/quitter.no\\/index.php\\/user\\/7477\",\"https:\\/\\/quitter.no\\/index.php\\/gargron\"],\"links\":[{\"rel\":\"http:\\/\\/webfinger.net\\/rel\\/profile-page\",\"type\":\"text\\/html\",\"href\":\"https:\\/\\/quitter.no\\/gargron\"},{\"rel\":\"http:\\/\\/gmpg.org\\/xfn\\/11\",\"type\":\"text\\/html\",\"href\":\"https:\\/\\/quitter.no\\/gargron\"},{\"rel\":\"describedby\",\"type\":\"application\\/rdf+xml\",\"href\":\"https:\\/\\/quitter.no\\/gargron\\/foaf\"},{\"rel\":\"http:\\/\\/apinamespace.org\\/atom\",\"type\":\"application\\/atomsvc+xml\",\"href\":\"https:\\/\\/quitter.no\\/api\\/statusnet\\/app\\/service\\/gargron.xml\"},{\"rel\":\"http:\\/\\/apinamespace.org\\/twitter\",\"href\":\"https:\\/\\/quitter.no\\/api\\/\"},{\"rel\":\"http:\\/\\/specs.openid.net\\/auth\\/2.0\\/provider\",\"href\":\"https:\\/\\/quitter.no\\/gargron\"},{\"rel\":\"http:\\/\\/schemas.google.com\\/g\\/2010#updates-from\",\"type\":\"application\\/atom+xml\",\"href\":\"https:\\/\\/quitter.no\\/api\\/statuses\\/user_timeline\\/7477.atom\"},{\"rel\":\"magic-public-key\",\"href\":\"data:application\\/magic-public-key,RSA.1ZBkHTavLvxH3FzlKv4O6WtlILKRFfNami3_Rcu8EuogtXSYiS-bB6hElZfUCSHbC4uLemOA34PEhz__CDMozax1iI_t8dzjDnh1x0iFSup7pSfW9iXk_WU3Dm74yWWW2jildY41vWgrEstuQ1dJ8vVFfSJ9T_tO4c-T9y8vDI8=.AQAB\"},{\"rel\":\"salmon\",\"href\":\"https:\\/\\/quitter.no\\/main\\/salmon\\/user\\/7477\"},{\"rel\":\"http:\\/\\/salmon-protocol.org\\/ns\\/salmon-replies\",\"href\":\"https:\\/\\/quitter.no\\/main\\/salmon\\/user\\/7477\"},{\"rel\":\"http:\\/\\/salmon-protocol.org\\/ns\\/salmon-mention\",\"href\":\"https:\\/\\/quitter.no\\/main\\/salmon\\/user\\/7477\"},{\"rel\":\"http:\\/\\/ostatus.org\\/schema\\/1.0\\/subscribe\",\"template\":\"https:\\/\\/quitter.no\\/main\\/ostatussub?profile={uri}\"}]}\r\n"
  },
  {
    "path": "spec/fixtures/requests/webfinger-hacker3.txt",
    "content": "HTTP/1.1 200 OK\r\nServer: nginx/1.6.2\r\nDate: Sun, 20 Mar 2016 11:13:16 GMT\r\nContent-Type: application/jrd+json\r\nTransfer-Encoding: chunked\r\nConnection: keep-alive\r\nAccess-Control-Allow-Origin: *\r\nVary: Accept-Encoding,Cookie\r\nStrict-Transport-Security: max-age=31536000; includeSubdomains;\r\n\r\n{\"subject\":\"acct:localhost@kickass.zone\",\"aliases\":[\"https:\\/\\/kickass.zone\\/user\\/7477\",\"https:\\/\\/kickass.zone\\/gargron\",\"https:\\/\\/kickass.zone\\/index.php\\/user\\/7477\",\"https:\\/\\/kickass.zone\\/index.php\\/gargron\"],\"links\":[{\"rel\":\"http:\\/\\/webfinger.net\\/rel\\/profile-page\",\"type\":\"text\\/html\",\"href\":\"https:\\/\\/kickass.zone\\/gargron\"},{\"rel\":\"http:\\/\\/gmpg.org\\/xfn\\/11\",\"type\":\"text\\/html\",\"href\":\"https:\\/\\/kickass.zone\\/gargron\"},{\"rel\":\"describedby\",\"type\":\"application\\/rdf+xml\",\"href\":\"https:\\/\\/kickass.zone\\/gargron\\/foaf\"},{\"rel\":\"http:\\/\\/apinamespace.org\\/atom\",\"type\":\"application\\/atomsvc+xml\",\"href\":\"https:\\/\\/kickass.zone\\/api\\/statusnet\\/app\\/service\\/gargron.xml\"},{\"rel\":\"http:\\/\\/apinamespace.org\\/twitter\",\"href\":\"https:\\/\\/kickass.zone\\/api\\/\"},{\"rel\":\"http:\\/\\/specs.openid.net\\/auth\\/2.0\\/provider\",\"href\":\"https:\\/\\/kickass.zone\\/gargron\"},{\"rel\":\"http:\\/\\/schemas.google.com\\/g\\/2010#updates-from\",\"type\":\"application\\/atom+xml\",\"href\":\"https:\\/\\/kickass.zone\\/api\\/statuses\\/user_timeline\\/7477.atom\"},{\"rel\":\"magic-public-key\",\"href\":\"data:application\\/magic-public-key,RSA.1ZBkHTavLvxH3FzlKv4O6WtlILKRFfNami3_Rcu8EuogtXSYiS-bB6hElZfUCSHbC4uLemOA34PEhz__CDMozax1iI_t8dzjDnh1x0iFSup7pSfW9iXk_WU3Dm74yWWW2jildY41vWgrEstuQ1dJ8vVFfSJ9T_tO4c-T9y8vDI8=.AQAB\"},{\"rel\":\"salmon\",\"href\":\"https:\\/\\/kickass.zone\\/main\\/salmon\\/user\\/7477\"},{\"rel\":\"http:\\/\\/salmon-protocol.org\\/ns\\/salmon-replies\",\"href\":\"https:\\/\\/kickass.zone\\/main\\/salmon\\/user\\/7477\"},{\"rel\":\"http:\\/\\/salmon-protocol.org\\/ns\\/salmon-mention\",\"href\":\"https:\\/\\/kickass.zone\\/main\\/salmon\\/user\\/7477\"},{\"rel\":\"http:\\/\\/ostatus.org\\/schema\\/1.0\\/subscribe\",\"template\":\"https:\\/\\/kickass.zone\\/main\\/ostatussub?profile={uri}\"}]}\r\n"
  },
  {
    "path": "spec/fixtures/requests/webfinger.txt",
    "content": "HTTP/1.1 200 OK\r\nServer: nginx/1.6.2\r\nDate: Sun, 20 Mar 2016 11:13:16 GMT\r\nContent-Type: application/jrd+json\r\nTransfer-Encoding: chunked\r\nConnection: keep-alive\r\nAccess-Control-Allow-Origin: *\r\nVary: Accept-Encoding,Cookie\r\nStrict-Transport-Security: max-age=31536000; includeSubdomains;\r\n\r\n{\"subject\":\"acct:gargron@quitter.no\",\"aliases\":[\"https:\\/\\/quitter.no\\/user\\/7477\",\"https:\\/\\/quitter.no\\/gargron\",\"https:\\/\\/quitter.no\\/index.php\\/user\\/7477\",\"https:\\/\\/quitter.no\\/index.php\\/gargron\"],\"links\":[{\"rel\":\"http:\\/\\/webfinger.net\\/rel\\/profile-page\",\"type\":\"text\\/html\",\"href\":\"https:\\/\\/quitter.no\\/gargron\"},{\"rel\":\"http:\\/\\/gmpg.org\\/xfn\\/11\",\"type\":\"text\\/html\",\"href\":\"https:\\/\\/quitter.no\\/gargron\"},{\"rel\":\"describedby\",\"type\":\"application\\/rdf+xml\",\"href\":\"https:\\/\\/quitter.no\\/gargron\\/foaf\"},{\"rel\":\"http:\\/\\/apinamespace.org\\/atom\",\"type\":\"application\\/atomsvc+xml\",\"href\":\"https:\\/\\/quitter.no\\/api\\/statusnet\\/app\\/service\\/gargron.xml\"},{\"rel\":\"http:\\/\\/apinamespace.org\\/twitter\",\"href\":\"https:\\/\\/quitter.no\\/api\\/\"},{\"rel\":\"http:\\/\\/specs.openid.net\\/auth\\/2.0\\/provider\",\"href\":\"https:\\/\\/quitter.no\\/gargron\"},{\"rel\":\"http:\\/\\/schemas.google.com\\/g\\/2010#updates-from\",\"type\":\"application\\/atom+xml\",\"href\":\"https:\\/\\/quitter.no\\/api\\/statuses\\/user_timeline\\/7477.atom\"},{\"rel\":\"magic-public-key\",\"href\":\"data:application\\/magic-public-key,RSA.1ZBkHTavLvxH3FzlKv4O6WtlILKRFfNami3_Rcu8EuogtXSYiS-bB6hElZfUCSHbC4uLemOA34PEhz__CDMozax1iI_t8dzjDnh1x0iFSup7pSfW9iXk_WU3Dm74yWWW2jildY41vWgrEstuQ1dJ8vVFfSJ9T_tO4c-T9y8vDI8=.AQAB\"},{\"rel\":\"salmon\",\"href\":\"https:\\/\\/quitter.no\\/main\\/salmon\\/user\\/7477\"},{\"rel\":\"http:\\/\\/salmon-protocol.org\\/ns\\/salmon-replies\",\"href\":\"https:\\/\\/quitter.no\\/main\\/salmon\\/user\\/7477\"},{\"rel\":\"http:\\/\\/salmon-protocol.org\\/ns\\/salmon-mention\",\"href\":\"https:\\/\\/quitter.no\\/main\\/salmon\\/user\\/7477\"},{\"rel\":\"http:\\/\\/ostatus.org\\/schema\\/1.0\\/subscribe\",\"template\":\"https:\\/\\/quitter.no\\/main\\/ostatussub?profile={uri}\"}]}"
  },
  {
    "path": "spec/fixtures/requests/windows-1251.txt",
    "content": "HTTP/1.1 200 OK\r\nserver: nginx\r\ndate: Wed, 12 Dec 2018 13:14:03 GMT\r\ncontent-type: text/html\r\ncontent-length: 190\r\naccept-ranges: bytes\r\n\r\n<!DOCTYPE html>\r\n<html>\r\n<head>\r\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=windows-1251\" />\r\n  <title> </title>\r\n</head>\r\n<body>\r\n  <p> </p>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "spec/fixtures/salmon/mention.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<me:env xmlns:me=\"http://salmon-protocol.org/ns/magic-env\"><me:data type=\"application/atom+xml\">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiID8-PGVudHJ5IHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDA1L0F0b20iIHhtbG5zOnRocj0iaHR0cDovL3B1cmwub3JnL3N5bmRpY2F0aW9uL3RocmVhZC8xLjAiIHhtbG5zOmFjdGl2aXR5PSJodHRwOi8vYWN0aXZpdHlzdHJlYS5tcy9zcGVjLzEuMC8iIHhtbG5zOmdlb3Jzcz0iaHR0cDovL3d3dy5nZW9yc3Mub3JnL2dlb3JzcyIgeG1sbnM6b3N0YXR1cz0iaHR0cDovL29zdGF0dXMub3JnL3NjaGVtYS8xLjAiIHhtbG5zOnBvY289Imh0dHA6Ly9wb3J0YWJsZWNvbnRhY3RzLm5ldC9zcGVjLzEuMCIgeG1sbnM6bWVkaWE9Imh0dHA6Ly9wdXJsLm9yZy9zeW5kaWNhdGlvbi9hdG9tbWVkaWEiIHhtbG5zOnN0YXR1c25ldD0iaHR0cDovL3N0YXR1cy5uZXQvc2NoZW1hL2FwaS8xLyI-CiA8YWN0aXZpdHk6b2JqZWN0LXR5cGU-aHR0cDovL2FjdGl2aXR5c3RyZWEubXMvc2NoZW1hLzEuMC9ub3RlPC9hY3Rpdml0eTpvYmplY3QtdHlwZT4KIDxpZD50YWc6cXVpdHRlci5ubywyMDE2LTAzLTIwOm5vdGljZUlkPTEyNzY5MjM6b2JqZWN0VHlwZT1ub3RlPC9pZD4KIDx0aXRsZT5OZXcgbm90ZSBieSBnYXJncm9uPC90aXRsZT4KIDxjb250ZW50IHR5cGU9Imh0bWwiPkAmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vY2I2ZTYxMjYubmdyb2suaW8vdXNlcnMvY2F0c3JncjgmcXVvdDsgY2xhc3M9JnF1b3Q7aC1jYXJkIG1lbnRpb24mcXVvdDsmZ3Q7Y2F0c3JncjgmbHQ7L2EmZ3Q7IHRoaXMgaXMgYSBtZW50aW9uPC9jb250ZW50PgogPGxpbmsgcmVsPSJhbHRlcm5hdGUiIHR5cGU9InRleHQvaHRtbCIgaHJlZj0iaHR0cHM6Ly9xdWl0dGVyLm5vL25vdGljZS8xMjc2OTIzIi8-CiA8c3RhdHVzX25ldCBub3RpY2VfaWQ9IjEyNzY5MjMiPjwvc3RhdHVzX25ldD4KIDxhY3Rpdml0eTp2ZXJiPmh0dHA6Ly9hY3Rpdml0eXN0cmVhLm1zL3NjaGVtYS8xLjAvcG9zdDwvYWN0aXZpdHk6dmVyYj4KIDxwdWJsaXNoZWQ-MjAxNi0wMy0yMFQxMTowNTozMSswMDowMDwvcHVibGlzaGVkPgogPHVwZGF0ZWQ-MjAxNi0wMy0yMFQxMTowNTozMSswMDowMDwvdXBkYXRlZD4KIDxhdXRob3I-CiAgPGFjdGl2aXR5Om9iamVjdC10eXBlPmh0dHA6Ly9hY3Rpdml0eXN0cmVhLm1zL3NjaGVtYS8xLjAvcGVyc29uPC9hY3Rpdml0eTpvYmplY3QtdHlwZT4KICA8dXJpPmh0dHBzOi8vcXVpdHRlci5uby91c2VyLzc0Nzc8L3VyaT4KICA8bmFtZT5nYXJncm9uPC9uYW1lPgogIDxzdW1tYXJ5PlNvZnR3YXJlIGVuZ2luZWVyLCBmcmVlIHRpbWUgbXVzaWNpYW4gYW5kIO-8pO-8qe-8p--8qe-8tO-8oe-8rCDvvLPvvLDvvK_vvLLvvLTvvLMgZW50aHVzaWFzdC4gTGlrZXMgY2F0cy4gV2FybmluZzogTWF5IGNvbnRhaW4gbWVtZXM8L3N1bW1hcnk-CiAgPGxpbmsgcmVsPSJhbHRlcm5hdGUiIHR5cGU9InRleHQvaHRtbCIgaHJlZj0iaHR0cHM6Ly9xdWl0dGVyLm5vL2dhcmdyb24iLz4KICA8bGluayByZWw9ImF2YXRhciIgdHlwZT0iaW1hZ2UvcG5nIiBtZWRpYTp3aWR0aD0iMzAwIiBtZWRpYTpoZWlnaHQ9IjMwMCIgaHJlZj0iaHR0cHM6Ly9xdWl0dGVyLm5vL2F2YXRhci83NDc3LTMwMC0yMDE2MDIxMTE5MDM0MC5wbmciLz4KICA8bGluayByZWw9ImF2YXRhciIgdHlwZT0iaW1hZ2UvcG5nIiBtZWRpYTp3aWR0aD0iOTYiIG1lZGlhOmhlaWdodD0iOTYiIGhyZWY9Imh0dHBzOi8vcXVpdHRlci5uby9hdmF0YXIvNzQ3Ny05Ni0yMDE2MDIxMTE5MDM0MC5wbmciLz4KICA8bGluayByZWw9ImF2YXRhciIgdHlwZT0iaW1hZ2UvcG5nIiBtZWRpYTp3aWR0aD0iNDgiIG1lZGlhOmhlaWdodD0iNDgiIGhyZWY9Imh0dHBzOi8vcXVpdHRlci5uby9hdmF0YXIvNzQ3Ny00OC0yMDE2MDIxMTE5MDQ0OS5wbmciLz4KICA8bGluayByZWw9ImF2YXRhciIgdHlwZT0iaW1hZ2UvcG5nIiBtZWRpYTp3aWR0aD0iMjQiIG1lZGlhOmhlaWdodD0iMjQiIGhyZWY9Imh0dHBzOi8vcXVpdHRlci5uby9hdmF0YXIvNzQ3Ny0yNC0yMDE2MDIxMTE5MDUxNy5wbmciLz4KICA8cG9jbzpwcmVmZXJyZWRVc2VybmFtZT5nYXJncm9uPC9wb2NvOnByZWZlcnJlZFVzZXJuYW1lPgogIDxwb2NvOmRpc3BsYXlOYW1lPu-8pO-8qe-8p--8qe-8tO-8oe-8rCDvvKPvvKHvvLQ8L3BvY286ZGlzcGxheU5hbWU-CiAgPHBvY286bm90ZT5Tb2Z0d2FyZSBlbmdpbmVlciwgZnJlZSB0aW1lIG11c2ljaWFuIGFuZCDvvKTvvKnvvKfvvKnvvLTvvKHvvKwg77yz77yw77yv77yy77y077yzIGVudGh1c2lhc3QuIExpa2VzIGNhdHMuIFdhcm5pbmc6IE1heSBjb250YWluIG1lbWVzPC9wb2NvOm5vdGU-CiAgPHBvY286YWRkcmVzcz4KICAgPHBvY286Zm9ybWF0dGVkPkdlcm1hbnk8L3BvY286Zm9ybWF0dGVkPgogIDwvcG9jbzphZGRyZXNzPgogIDxwb2NvOnVybHM-CiAgIDxwb2NvOnR5cGU-aG9tZXBhZ2U8L3BvY286dHlwZT4KICAgPHBvY286dmFsdWU-aHR0cHM6Ly96ZW9uZmVkZXJhdGVkLmNvbTwvcG9jbzp2YWx1ZT4KICAgPHBvY286cHJpbWFyeT50cnVlPC9wb2NvOnByaW1hcnk-CiAgPC9wb2NvOnVybHM-CiAgPGZvbGxvd2VycyB1cmw9Imh0dHBzOi8vcXVpdHRlci5uby9nYXJncm9uL3N1YnNjcmliZXJzIj48L2ZvbGxvd2Vycz4KICA8c3RhdHVzbmV0OnByb2ZpbGVfaW5mbyBsb2NhbF9pZD0iNzQ3NyI-PC9zdGF0dXNuZXQ6cHJvZmlsZV9pbmZvPgogPC9hdXRob3I-CiA8bGluayByZWw9Im9zdGF0dXM6Y29udmVyc2F0aW9uIiBocmVmPSJ0YWc6cXVpdHRlci5ubywyMDE2LTAzLTIwOm9iamVjdFR5cGU9dGhyZWFkOm5vbmNlPTdjOTk4MTEyZTM5YTY2ODUiLz4KIDxvc3RhdHVzOmNvbnZlcnNhdGlvbj50YWc6cXVpdHRlci5ubywyMDE2LTAzLTIwOm9iamVjdFR5cGU9dGhyZWFkOm5vbmNlPTdjOTk4MTEyZTM5YTY2ODU8L29zdGF0dXM6Y29udmVyc2F0aW9uPgogPGxpbmsgcmVsPSJtZW50aW9uZWQiIG9zdGF0dXM6b2JqZWN0LXR5cGU9Imh0dHA6Ly9hY3Rpdml0eXN0cmVhLm1zL3NjaGVtYS8xLjAvcGVyc29uIiBocmVmPSJodHRwczovL2NiNmU2MTI2Lm5ncm9rLmlvL3VzZXJzL2NhdHNyZ3I4Ii8-CiA8bGluayByZWw9Im1lbnRpb25lZCIgb3N0YXR1czpvYmplY3QtdHlwZT0iaHR0cDovL2FjdGl2aXR5c3RyZWEubXMvc2NoZW1hLzEuMC9jb2xsZWN0aW9uIiBocmVmPSJodHRwOi8vYWN0aXZpdHlzY2hlbWEub3JnL2NvbGxlY3Rpb24vcHVibGljIi8-CiA8c291cmNlPgogIDxpZD5odHRwczovL3F1aXR0ZXIubm8vYXBpL3N0YXR1c2VzL3VzZXJfdGltZWxpbmUvNzQ3Ny5hdG9tPC9pZD4KICA8dGl0bGU-77yk77yp77yn77yp77y077yh77ysIO-8o--8oe-8tDwvdGl0bGU-CiAgPGxpbmsgcmVsPSJhbHRlcm5hdGUiIHR5cGU9InRleHQvaHRtbCIgaHJlZj0iaHR0cHM6Ly9xdWl0dGVyLm5vL2dhcmdyb24iLz4KICA8bGluayByZWw9InNlbGYiIHR5cGU9ImFwcGxpY2F0aW9uL2F0b20reG1sIiBocmVmPSJodHRwczovL3F1aXR0ZXIubm8vYXBpL3N0YXR1c2VzL3VzZXJfdGltZWxpbmUvNzQ3Ny5hdG9tIi8-CiAgPGxpbmsgcmVsPSJsaWNlbnNlIiBocmVmPSJodHRwczovL2NyZWF0aXZlY29tbW9ucy5vcmcvbGljZW5zZXMvYnkvMy4wLyIvPgogIDxpY29uPmh0dHBzOi8vcXVpdHRlci5uby9hdmF0YXIvNzQ3Ny05Ni0yMDE2MDIxMTE5MDM0MC5wbmc8L2ljb24-CiAgPHVwZGF0ZWQ-MjAxNi0wMy0yMFQxMTowNTozMSswMDowMDwvdXBkYXRlZD4KIDwvc291cmNlPgogPGxpbmsgcmVsPSJzZWxmIiB0eXBlPSJhcHBsaWNhdGlvbi9hdG9tK3htbCIgaHJlZj0iaHR0cHM6Ly9xdWl0dGVyLm5vL2FwaS9zdGF0dXNlcy9zaG93LzEyNzY5MjMuYXRvbSIvPgogPGxpbmsgcmVsPSJlZGl0IiB0eXBlPSJhcHBsaWNhdGlvbi9hdG9tK3htbCIgaHJlZj0iaHR0cHM6Ly9xdWl0dGVyLm5vL2FwaS9zdGF0dXNlcy9zaG93LzEyNzY5MjMuYXRvbSIvPgogPHN0YXR1c25ldDpub3RpY2VfaW5mbyBsb2NhbF9pZD0iMTI3NjkyMyIgc291cmNlPSJRdml0dGVyIj48L3N0YXR1c25ldDpub3RpY2VfaW5mbz4KPC9lbnRyeT4K</me:data><me:encoding>base64url</me:encoding><me:alg>RSA-SHA256</me:alg><me:sig>XOSdsku4Tq6zLxmOv0KtTpyG-UKOnlYzEoDXyPl_lkZzcZYm8Jc7ao50swJE1NFIw4uW8PfTTlqnz0pC62MVOVRxOUtiPTTJicux5W__HWf0j_ymUre87VF0Wdt1BoZYR9HeLnx2SGALDc6_ib-eabHA0O3AtSdm0JLq2pprtpA=</me:sig></me:env>\n"
  },
  {
    "path": "spec/fixtures/xml/mastodon.atom",
    "content": "<?xml version=\"1.0\"?>\n<feed xmlns=\"http://www.w3.org/2005/Atom\" xmlns:thr=\"http://purl.org/syndication/thread/1.0\" xmlns:activity=\"http://activitystrea.ms/spec/1.0/\" xmlns:poco=\"http://portablecontacts.net/spec/1.0\" xmlns:media=\"http://purl.org/syndication/atommedia\">\n  <id>http://kickass.zone/users/localhost.atom</id>\n  <title>::1</title>\n  <updated>2016-10-10T13:29:56Z</updated>\n  <logo>http://kickass.zone/system/accounts/avatars/000/000/001/medium/eris.png</logo>\n  <author>\n    <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>\n    <uri>http://kickass.zone/users/localhost</uri>\n    <name>localhost</name>\n    <email>localhost@kickass.zone</email>\n    <link rel=\"alternate\" type=\"text/html\" href=\"http://kickass.zone/users/localhost\"/>\n    <link rel=\"avatar\" type=\"image/png\" media:width=\"300\" media:height=\"300\" href=\"http://kickass.zone/system/accounts/avatars/000/000/001/large/eris.png\"/>\n    <link rel=\"avatar\" type=\"image/png\" media:width=\"96\" media:height=\"96\" href=\"http://kickass.zone/system/accounts/avatars/000/000/001/medium/eris.png\"/>\n    <link rel=\"avatar\" type=\"image/png\" media:width=\"48\" media:height=\"48\" href=\"http://kickass.zone/system/accounts/avatars/000/000/001/small/eris.png\"/>\n    <poco:preferredUsername>localhost</poco:preferredUsername>\n    <poco:displayName>::1</poco:displayName>\n  </author>\n  <link rel=\"alternate\" type=\"text/html\" href=\"http://kickass.zone/users/localhost\"/>\n  <link rel=\"self\" type=\"application/atom+xml\" href=\"http://kickass.zone/users/localhost.atom\"/>\n  <link rel=\"hub\" href=\"https://pubsubhubbub.superfeedr.com\"/>\n  <link rel=\"salmon\" href=\"http://kickass.zone/api/salmon/1\"/>\n  <entry>\n    <id>tag:kickass.zone,2016-10-10:objectId=7:objectType=Follow</id>\n    <published>2016-10-10T13:29:56Z</published>\n    <updated>2016-10-10T13:29:56Z</updated>\n    <title>localhost started following kat@mastodon.social</title>\n    <content type=\"html\">localhost started following kat@mastodon.social</content>\n    <activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb>\n    <link rel=\"self\" type=\"application/atom+xml\" href=\"http://kickass.zone/users/localhost/updates/12.atom\"/>\n    <link rel=\"alternate\" type=\"text/html\" href=\"http://kickass.zone/users/localhost/updates/12\"/>\n    <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type>\n    <activity:object>\n      <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>\n      <uri>https://mastodon.social/users/kat</uri>\n      <name>kat</name>\n      <email>kat@mastodon.social</email>\n      <summary>#trans #queer</summary>\n      <link rel=\"alternate\" type=\"text/html\" href=\"https://mastodon.social/users/kat\"/>\n      <link rel=\"avatar\" type=\"image/jpeg\" media:width=\"300\" media:height=\"300\" href=\"http://kickass.zone/system/accounts/avatars/000/000/016/large/kat-20150403T124737-b2mbt44.jpg\"/>\n      <link rel=\"avatar\" type=\"image/jpeg\" media:width=\"96\" media:height=\"96\" href=\"http://kickass.zone/system/accounts/avatars/000/000/016/medium/kat-20150403T124737-b2mbt44.jpg\"/>\n      <link rel=\"avatar\" type=\"image/jpeg\" media:width=\"48\" media:height=\"48\" href=\"http://kickass.zone/system/accounts/avatars/000/000/016/small/kat-20150403T124737-b2mbt44.jpg\"/>\n      <poco:preferredUsername>kat</poco:preferredUsername>\n      <poco:displayName>Kat</poco:displayName>\n      <poco:note>#trans #queer</poco:note>\n    </activity:object>\n  </entry>\n  <entry>\n    <id>tag:kickass.zone,2016-10-10:objectId=3:objectType=Favourite</id>\n    <published>2016-10-10T13:29:26Z</published>\n    <updated>2016-10-10T13:29:26Z</updated>\n    <title>localhost favourited a status by kat@mastodon.social</title>\n    <content type=\"html\">localhost favourited a status by kat@mastodon.social</content>\n    <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>\n    <link rel=\"self\" type=\"application/atom+xml\" href=\"http://kickass.zone/users/localhost/updates/11.atom\"/>\n    <link rel=\"alternate\" type=\"text/html\" href=\"http://kickass.zone/users/localhost/updates/11\"/>\n    <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type>\n    <thr:in-reply-to ref=\"tag:mastodon.social,2016-10-10:objectId=22833:objectType=Status\" href=\"https://mastodon.social/users/kat/updates/16543\" type=\"text/html\"/>\n    <activity:object>\n      <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>\n      <id>tag:mastodon.social,2016-10-10:objectId=22833:objectType=Status</id>\n      <title>@localhost  oooh more mastodons \t&#x2764;</title>\n      <link rel=\"alternate\" type=\"text/html\" href=\"https://mastodon.social/users/kat/updates/16543\"/>\n      <content type=\"html\">&lt;p&gt;&lt;a href=\"http://kickass.zone/users/localhost\"&gt;@localhost&lt;/a&gt;  oooh more mastodons \t&#x2764;&lt;/p&gt;</content>\n      <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>\n      <published>2016-10-10T13:23:35Z</published>\n      <updated>2016-10-10T13:23:35Z</updated>\n      <author>\n        <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>\n        <uri>https://mastodon.social/users/kat</uri>\n        <name>kat</name>\n        <email>kat@mastodon.social</email>\n        <summary>#trans #queer</summary>\n        <link rel=\"alternate\" type=\"text/html\" href=\"https://mastodon.social/users/kat\"/>\n        <link rel=\"avatar\" type=\"image/jpeg\" media:width=\"300\" media:height=\"300\" href=\"http://kickass.zone/system/accounts/avatars/000/000/016/large/kat-20150403T124737-b2mbt44.jpg\"/>\n        <link rel=\"avatar\" type=\"image/jpeg\" media:width=\"96\" media:height=\"96\" href=\"http://kickass.zone/system/accounts/avatars/000/000/016/medium/kat-20150403T124737-b2mbt44.jpg\"/>\n        <link rel=\"avatar\" type=\"image/jpeg\" media:width=\"48\" media:height=\"48\" href=\"http://kickass.zone/system/accounts/avatars/000/000/016/small/kat-20150403T124737-b2mbt44.jpg\"/>\n        <poco:preferredUsername>kat</poco:preferredUsername>\n        <poco:displayName>Kat</poco:displayName>\n        <poco:note>#trans #queer</poco:note>\n      </author>\n      <link rel=\"mentioned\" href=\"http://kickass.zone/users/localhost\"/>\n    </activity:object>\n  </entry>\n  <entry>\n    <id>tag:kickass.zone,2016-10-10:objectId=2:objectType=Favourite</id>\n    <published>2016-10-10T13:13:15Z</published>\n    <updated>2016-10-10T13:13:15Z</updated>\n    <title>localhost favourited a status by Gargron@mastodon.social</title>\n    <content type=\"html\">localhost favourited a status by Gargron@mastodon.social</content>\n    <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>\n    <link rel=\"self\" type=\"application/atom+xml\" href=\"http://kickass.zone/users/localhost/updates/10.atom\"/>\n    <link rel=\"alternate\" type=\"text/html\" href=\"http://kickass.zone/users/localhost/updates/10\"/>\n    <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type>\n    <thr:in-reply-to ref=\"tag:mastodon.social,2016-10-10:objectId=22825:objectType=Status\" href=\"https://mastodon.social/users/Gargron/updates/16538\" type=\"text/html\"/>\n    <activity:object>\n      <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>\n      <id>tag:mastodon.social,2016-10-10:objectId=22825:objectType=Status</id>\n      <title>Deployed some fixes</title>\n      <link rel=\"alternate\" type=\"text/html\" href=\"https://mastodon.social/users/Gargron/updates/16538\"/>\n      <content type=\"html\">&lt;p&gt;Deployed some fixes&lt;/p&gt;</content>\n      <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>\n      <published>2016-10-10T13:10:37Z</published>\n      <updated>2016-10-10T13:10:37Z</updated>\n      <author>\n        <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>\n        <uri>https://mastodon.social/users/Gargron</uri>\n        <name>Gargron</name>\n        <email>Gargron@mastodon.social</email>\n        <summary>Developer of Mastodon, a GNU social alternative: https://github.com/tootsuite/mastodon</summary>\n        <link rel=\"alternate\" type=\"text/html\" href=\"https://mastodon.social/users/Gargron\"/>\n        <link rel=\"avatar\" type=\"image/png\" media:width=\"300\" media:height=\"300\" href=\"http://kickass.zone/system/accounts/avatars/000/000/003/large/4375_eugencommish.png\"/>\n        <link rel=\"avatar\" type=\"image/png\" media:width=\"96\" media:height=\"96\" href=\"http://kickass.zone/system/accounts/avatars/000/000/003/medium/4375_eugencommish.png\"/>\n        <link rel=\"avatar\" type=\"image/png\" media:width=\"48\" media:height=\"48\" href=\"http://kickass.zone/system/accounts/avatars/000/000/003/small/4375_eugencommish.png\"/>\n        <poco:preferredUsername>Gargron</poco:preferredUsername>\n        <poco:displayName>Eugen</poco:displayName>\n        <poco:note>Developer of Mastodon, a GNU social alternative: https://github.com/tootsuite/mastodon</poco:note>\n      </author>\n    </activity:object>\n  </entry>\n  <entry>\n    <id>tag:kickass.zone,2016-10-10:objectId=17:objectType=Status</id>\n    <published>2016-10-10T00:41:31Z</published>\n    <updated>2016-10-10T00:41:31Z</updated>\n    <title>Social media needs MOAR cats! http://kickass.zone/media/3</title>\n    <content type=\"html\">&lt;p&gt;Social media needs MOAR cats! &lt;a rel=\"nofollow noopener\" href=\"http://kickass.zone/media/3\"&gt;http://kickass.zone/media/3&lt;/a&gt;&lt;/p&gt;</content>\n    <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>\n    <link rel=\"self\" type=\"application/atom+xml\" href=\"http://kickass.zone/users/localhost/updates/9.atom\"/>\n    <link rel=\"alternate\" type=\"text/html\" href=\"http://kickass.zone/users/localhost/updates/9\"/>\n    <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>\n    <link rel=\"enclosure\" href=\"http://kickass.zone/system/media_attachments/files/000/000/003/original/gizmo.jpg?1476060065\" type=\"image/jpeg\" length=\"108841\"/>\n  </entry>\n  <entry>\n    <id>tag:kickass.zone,2016-10-10:objectId=14:objectType=Status</id>\n    <published>2016-10-10T00:38:39Z</published>\n    <updated>2016-10-10T00:38:39Z</updated>\n    <title>http://kickass.zone/media/2</title>\n    <content type=\"html\">&lt;p&gt;&lt;a rel=\"nofollow noopener\" href=\"http://kickass.zone/media/2\"&gt;http://kickass.zone/media/2&lt;/a&gt;&lt;/p&gt;</content>\n    <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>\n    <link rel=\"self\" type=\"application/atom+xml\" href=\"http://kickass.zone/users/localhost/updates/8.atom\"/>\n    <link rel=\"alternate\" type=\"text/html\" href=\"http://kickass.zone/users/localhost/updates/8\"/>\n    <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>\n    <link rel=\"enclosure\" href=\"http://kickass.zone/system/media_attachments/files/000/000/002/original/morpheus_linux.jpg?1476059910\" type=\"image/jpeg\" length=\"191816\"/>\n  </entry>\n  <entry>\n    <id>tag:kickass.zone,2016-10-10:objectId=12:objectType=Status</id>\n    <published>2016-10-10T00:37:49Z</published>\n    <updated>2016-10-10T00:37:49Z</updated>\n    <title/>\n    <activity:verb>http://activitystrea.ms/schema/1.0/delete</activity:verb>\n    <link rel=\"self\" type=\"application/atom+xml\" href=\"http://kickass.zone/users/localhost/updates/7.atom\"/>\n    <link rel=\"alternate\" type=\"text/html\" href=\"http://kickass.zone/users/localhost/updates/7\"/>\n    <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type>\n  </entry>\n  <entry>\n    <id>tag:kickass.zone,2016-10-10:objectId=4:objectType=Follow</id>\n    <published>2016-10-10T00:23:07Z</published>\n    <updated>2016-10-10T00:23:07Z</updated>\n    <title>localhost started following bignimbus@mastodon.social</title>\n    <content type=\"html\">localhost started following bignimbus@mastodon.social</content>\n    <activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb>\n    <link rel=\"self\" type=\"application/atom+xml\" href=\"http://kickass.zone/users/localhost/updates/6.atom\"/>\n    <link rel=\"alternate\" type=\"text/html\" href=\"http://kickass.zone/users/localhost/updates/6\"/>\n    <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type>\n    <activity:object>\n      <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>\n      <uri>https://mastodon.social/users/bignimbus</uri>\n      <name>bignimbus</name>\n      <email>bignimbus@mastodon.social</email>\n      <summary>jdauriemma.com</summary>\n      <link rel=\"alternate\" type=\"text/html\" href=\"https://mastodon.social/users/bignimbus\"/>\n      <link rel=\"avatar\" type=\"image/png\" media:width=\"300\" media:height=\"300\" href=\"http://kickass.zone/system/accounts/avatars/000/000/004/large/jeff_avatar.png\"/>\n      <link rel=\"avatar\" type=\"image/png\" media:width=\"96\" media:height=\"96\" href=\"http://kickass.zone/system/accounts/avatars/000/000/004/medium/jeff_avatar.png\"/>\n      <link rel=\"avatar\" type=\"image/png\" media:width=\"48\" media:height=\"48\" href=\"http://kickass.zone/system/accounts/avatars/000/000/004/small/jeff_avatar.png\"/>\n      <poco:preferredUsername>bignimbus</poco:preferredUsername>\n      <poco:displayName>Jeff Auriemma</poco:displayName>\n      <poco:note>jdauriemma.com</poco:note>\n    </activity:object>\n  </entry>\n  <entry>\n    <id>tag:kickass.zone,2016-10-10:objectId=2:objectType=Follow</id>\n    <published>2016-10-10T00:14:18Z</published>\n    <updated>2016-10-10T00:14:18Z</updated>\n    <title>localhost started following Gargron@mastodon.social</title>\n    <content type=\"html\">localhost started following Gargron@mastodon.social</content>\n    <activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb>\n    <link rel=\"self\" type=\"application/atom+xml\" href=\"http://kickass.zone/users/localhost/updates/5.atom\"/>\n    <link rel=\"alternate\" type=\"text/html\" href=\"http://kickass.zone/users/localhost/updates/5\"/>\n    <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type>\n    <activity:object>\n      <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>\n      <uri>https://mastodon.social/users/Gargron</uri>\n      <name>Gargron</name>\n      <email>Gargron@mastodon.social</email>\n      <summary>Developer of Mastodon, a GNU social alternative: https://github.com/tootsuite/mastodon</summary>\n      <link rel=\"alternate\" type=\"text/html\" href=\"https://mastodon.social/users/Gargron\"/>\n      <link rel=\"avatar\" type=\"image/png\" media:width=\"300\" media:height=\"300\" href=\"http://kickass.zone/system/accounts/avatars/000/000/003/large/4375_eugencommish.png\"/>\n      <link rel=\"avatar\" type=\"image/png\" media:width=\"96\" media:height=\"96\" href=\"http://kickass.zone/system/accounts/avatars/000/000/003/medium/4375_eugencommish.png\"/>\n      <link rel=\"avatar\" type=\"image/png\" media:width=\"48\" media:height=\"48\" href=\"http://kickass.zone/system/accounts/avatars/000/000/003/small/4375_eugencommish.png\"/>\n      <poco:preferredUsername>Gargron</poco:preferredUsername>\n      <poco:displayName>Eugen</poco:displayName>\n      <poco:note>Developer of Mastodon, a GNU social alternative: https://github.com/tootsuite/mastodon</poco:note>\n    </activity:object>\n  </entry>\n  <entry>\n    <id>tag:kickass.zone,2016-10-10:objectId=1:objectType=Follow</id>\n    <published>2016-10-10T00:09:09Z</published>\n    <updated>2016-10-10T00:09:09Z</updated>\n    <title>localhost started following abc@mastodon.social</title>\n    <content type=\"html\">localhost started following abc@mastodon.social</content>\n    <activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb>\n    <link rel=\"self\" type=\"application/atom+xml\" href=\"http://kickass.zone/users/localhost/updates/4.atom\"/>\n    <link rel=\"alternate\" type=\"text/html\" href=\"http://kickass.zone/users/localhost/updates/4\"/>\n    <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type>\n    <activity:object>\n      <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>\n      <uri>https://mastodon.social/users/abc</uri>\n      <name>abc</name>\n      <email>abc@mastodon.social</email>\n      <link rel=\"alternate\" type=\"text/html\" href=\"https://mastodon.social/users/abc\"/>\n      <link rel=\"avatar\" type=\"image/jpeg\" media:width=\"300\" media:height=\"300\" href=\"http://kickass.zone/system/accounts/avatars/000/000/002/large/cbm64_80x80.jpg\"/>\n      <link rel=\"avatar\" type=\"image/jpeg\" media:width=\"96\" media:height=\"96\" href=\"http://kickass.zone/system/accounts/avatars/000/000/002/medium/cbm64_80x80.jpg\"/>\n      <link rel=\"avatar\" type=\"image/jpeg\" media:width=\"48\" media:height=\"48\" href=\"http://kickass.zone/system/accounts/avatars/000/000/002/small/cbm64_80x80.jpg\"/>\n      <poco:preferredUsername>abc</poco:preferredUsername>\n      <poco:displayName>abc</poco:displayName>\n    </activity:object>\n  </entry>\n  <entry>\n    <id>tag:kickass.zone,2016-10-10:objectId=3:objectType=Status</id>\n    <published>2016-10-10T00:02:47Z</published>\n    <updated>2016-10-10T00:02:47Z</updated>\n    <title/>\n    <activity:verb>http://activitystrea.ms/schema/1.0/delete</activity:verb>\n    <link rel=\"self\" type=\"application/atom+xml\" href=\"http://kickass.zone/users/localhost/updates/3.atom\"/>\n    <link rel=\"alternate\" type=\"text/html\" href=\"http://kickass.zone/users/localhost/updates/3\"/>\n    <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type>\n  </entry>\n  <entry>\n    <id>tag:kickass.zone,2016-10-10:objectId=2:objectType=Status</id>\n    <published>2016-10-10T00:02:18Z</published>\n    <updated>2016-10-10T00:02:18Z</updated>\n    <title>Yes, that was the obligatory first post. :)</title>\n    <content type=\"html\">&lt;p&gt;Yes, that was the obligatory first post. :)&lt;/p&gt;</content>\n    <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>\n    <link rel=\"self\" type=\"application/atom+xml\" href=\"http://kickass.zone/users/localhost/updates/2.atom\"/>\n    <link rel=\"alternate\" type=\"text/html\" href=\"http://kickass.zone/users/localhost/updates/2\"/>\n    <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>\n    <thr:in-reply-to ref=\"tag:kickass.zone,2016-10-10:objectId=1:objectType=Status\" href=\"http://kickass.zone/users/localhost/updates/1\" type=\"text/html\"/>\n  </entry>\n  <entry>\n    <id>tag:kickass.zone,2016-10-10:objectId=1:objectType=Status</id>\n    <published>2016-10-10T00:01:56Z</published>\n    <updated>2016-10-10T00:01:56Z</updated>\n    <title>Hello, world!</title>\n    <content type=\"html\">&lt;p&gt;Hello, world!&lt;/p&gt;</content>\n    <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>\n    <link rel=\"self\" type=\"application/atom+xml\" href=\"http://kickass.zone/users/localhost/updates/1.atom\"/>\n    <link rel=\"alternate\" type=\"text/html\" href=\"http://kickass.zone/users/localhost/updates/1\"/>\n    <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>\n  </entry>\n</feed>\n"
  },
  {
    "path": "spec/helpers/admin/account_moderation_notes_helper_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe Admin::AccountModerationNotesHelper, type: :helper do\n  include StreamEntriesHelper\n\n  describe '#admin_account_link_to' do\n    context 'account is nil' do\n      let(:account) { nil }\n\n      it 'returns nil' do\n        expect(helper.admin_account_link_to(account)).to be_nil\n      end\n    end\n\n    context 'with account' do\n      let(:account) { Fabricate(:account) }\n\n      it 'calls #link_to' do\n        expect(helper).to receive(:link_to).with(\n          admin_account_path(account.id),\n          class: name_tag_classes(account),\n          title: account.acct\n        )\n\n        helper.admin_account_link_to(account)\n      end\n    end\n  end\n\n  describe '#admin_account_inline_link_to' do\n    context 'account is nil' do\n      let(:account) { nil }\n\n      it 'returns nil' do\n        expect(helper.admin_account_inline_link_to(account)).to be_nil\n      end\n    end\n\n    context 'with account' do\n      let(:account) { Fabricate(:account) }\n\n      it 'calls #link_to' do\n        expect(helper).to receive(:link_to).with(\n          admin_account_path(account.id),\n          class: name_tag_classes(account, true),\n          title: account.acct\n        )\n\n        helper.admin_account_inline_link_to(account)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/helpers/admin/action_log_helper_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe Admin::ActionLogsHelper, type: :helper do\n  klass = Class.new do\n    include ActionView::Helpers\n    include Admin::ActionLogsHelper\n  end\n\n  let(:hoge) { klass.new }\n\n  describe '#log_target' do\n    after do\n      hoge.log_target(log)\n    end\n\n    context 'log.target' do\n      let(:log) { double(target: true) }\n\n      it 'calls linkable_log_target' do\n        expect(hoge).to receive(:linkable_log_target).with(log.target)\n      end\n    end\n\n    context '!log.target' do\n      let(:log) { double(target: false, target_type: :type, recorded_changes: :change) }\n\n      it 'calls log_target_from_history' do\n        expect(hoge).to receive(:log_target_from_history).with(log.target_type, log.recorded_changes)\n      end\n    end\n  end\n\n  describe '#relevant_log_changes' do\n    let(:log) { double(target_type: target_type, action: log_action, recorded_changes: recorded_changes) }\n    let(:recorded_changes) { double }\n\n    after do\n      hoge.relevant_log_changes(log)\n    end\n\n    context \"log.target_type == 'CustomEmoji' && [:enable, :disable, :destroy].include?(log.action)\" do\n      let(:target_type) { 'CustomEmoji' }\n      let(:log_action)  { :enable }\n\n      it \"calls log.recorded_changes.slice('domain')\" do\n        expect(recorded_changes).to receive(:slice).with('domain')\n      end\n    end\n\n    context \"log.target_type == 'CustomEmoji' && log.action == :update\" do\n      let(:target_type) { 'CustomEmoji' }\n      let(:log_action)  { :update }\n\n      it \"calls log.recorded_changes.slice('domain', 'visible_in_picker')\" do\n        expect(recorded_changes).to receive(:slice).with('domain', 'visible_in_picker')\n      end\n    end\n\n    context \"log.target_type == 'User' && [:promote, :demote].include?(log.action)\" do\n      let(:target_type) { 'User' }\n      let(:log_action)  { :promote }\n\n      it \"calls log.recorded_changes.slice('moderator', 'admin')\" do\n        expect(recorded_changes).to receive(:slice).with('moderator', 'admin')\n      end\n    end\n\n    context \"log.target_type == 'User' && [:change_email].include?(log.action)\" do\n      let(:target_type) { 'User' }\n      let(:log_action)  { :change_email }\n\n      it \"calls log.recorded_changes.slice('email', 'unconfirmed_email')\" do\n        expect(recorded_changes).to receive(:slice).with('email', 'unconfirmed_email')\n      end\n    end\n\n    context \"log.target_type == 'DomainBlock'\" do\n      let(:target_type) { 'DomainBlock' }\n      let(:log_action)  { nil }\n\n      it \"calls log.recorded_changes.slice('severity', 'reject_media')\" do\n        expect(recorded_changes).to receive(:slice).with('severity', 'reject_media')\n      end\n    end\n\n    context \"log.target_type == 'Status' && log.action == :update\" do\n      let(:target_type) { 'Status' }\n      let(:log_action)  { :update }\n\n      it \"log.recorded_changes.slice('sensitive')\" do\n        expect(recorded_changes).to receive(:slice).with('sensitive')\n      end\n    end\n  end\n\n  describe '#log_extra_attributes' do\n    after do\n      hoge.log_extra_attributes(hoge: 'hoge')\n    end\n\n    it \"calls content_tag(:span, key, class: 'diff-key')\" do\n      allow(hoge).to receive(:log_change).with(anything)\n      expect(hoge).to receive(:content_tag).with(:span, :hoge, class: 'diff-key')\n    end\n\n    it 'calls safe_join twice' do\n      expect(hoge).to receive(:safe_join).with(\n        ['<span class=\"diff-key\">hoge</span>',\n         '=',\n         '<span class=\"diff-neutral\">hoge</span>']\n      )\n\n      expect(hoge).to receive(:safe_join).with([nil], ' ')\n    end\n  end\n\n  describe '#log_change' do\n    after do\n      hoge.log_change(val)\n    end\n\n    context '!val.is_a?(Array)' do\n      let(:val) { 'hoge' }\n\n      it \"calls content_tag(:span, val, class: 'diff-neutral')\" do\n        expect(hoge).to receive(:content_tag).with(:span, val, class: 'diff-neutral')\n      end\n    end\n\n    context 'val.is_a?(Array)' do\n      let(:val) { %w(foo bar) }\n\n      it 'calls #content_tag twice and #safe_join' do\n        expect(hoge).to receive(:content_tag).with(:span, 'foo', class: 'diff-old')\n        expect(hoge).to receive(:content_tag).with(:span, 'bar', class: 'diff-new')\n        expect(hoge).to receive(:safe_join).with([nil, nil], '→')\n      end\n    end\n  end\n\n  describe '#icon_for_log' do\n    subject   { hoge.icon_for_log(log) }\n\n    context \"log.target_type == 'Account'\" do\n      let(:log) { double(target_type: 'Account') }\n\n      it 'returns \"user\"' do\n        expect(subject).to be 'user'\n      end\n    end\n\n    context \"log.target_type == 'User'\" do\n      let(:log) { double(target_type: 'User') }\n\n      it 'returns \"user\"' do\n        expect(subject).to be 'user'\n      end\n    end\n\n    context \"log.target_type == 'CustomEmoji'\" do\n      let(:log) { double(target_type: 'CustomEmoji') }\n\n      it 'returns \"file\"' do\n        expect(subject).to be 'file'\n      end\n    end\n\n    context \"log.target_type == 'Report'\" do\n      let(:log) { double(target_type: 'Report') }\n\n      it 'returns \"flag\"' do\n        expect(subject).to be 'flag'\n      end\n    end\n\n    context \"log.target_type == 'DomainBlock'\" do\n      let(:log) { double(target_type: 'DomainBlock') }\n\n      it 'returns \"lock\"' do\n        expect(subject).to be 'lock'\n      end\n    end\n\n    context \"log.target_type == 'EmailDomainBlock'\" do\n      let(:log) { double(target_type: 'EmailDomainBlock') }\n\n      it 'returns \"envelope\"' do\n        expect(subject).to be 'envelope'\n      end\n    end\n\n    context \"log.target_type == 'Status'\" do\n      let(:log) { double(target_type: 'Status') }\n\n      it 'returns \"pencil\"' do\n        expect(subject).to be 'pencil'\n      end\n    end\n  end\n\n  describe '#class_for_log_icon' do\n    subject   { hoge.class_for_log_icon(log) }\n\n    %i(enable unsuspend unsilence confirm promote resolve).each do |action|\n      context \"log.action == #{action}\" do\n        let(:log) { double(action: action) }\n\n        it 'returns \"positive\"' do\n          expect(subject).to be 'positive'\n        end\n      end\n    end\n\n    context 'log.action == :create' do\n      context 'opposite_verbs?(log)' do\n        let(:log) { double(action: :create, target_type: 'DomainBlock') }\n\n        it 'returns \"negative\"' do\n          expect(subject).to be 'negative'\n        end\n      end\n\n      context '!opposite_verbs?(log)' do\n        let(:log) { double(action: :create, target_type: '') }\n\n        it 'returns \"positive\"' do\n          expect(subject).to be 'positive'\n        end\n      end\n    end\n\n    %i(update reset_password disable_2fa memorialize change_email).each do |action|\n      context \"log.action == #{action}\" do\n        let(:log) { double(action: action) }\n\n        it 'returns \"neutral\"' do\n          expect(subject).to be 'neutral'\n        end\n      end\n    end\n\n    %i(demote silence disable suspend remove_avatar remove_header reopen).each do |action|\n      context \"log.action == #{action}\" do\n        let(:log) { double(action: action) }\n\n        it 'returns \"negative\"' do\n          expect(subject).to be 'negative'\n        end\n      end\n    end\n\n    context 'log.action == :destroy' do\n      context 'opposite_verbs?(log)' do\n        let(:log) { double(action: :destroy, target_type: 'DomainBlock') }\n\n        it 'returns \"positive\"' do\n          expect(subject).to be 'positive'\n        end\n      end\n\n      context '!opposite_verbs?(log)' do\n        let(:log) { double(action: :destroy, target_type: '') }\n\n        it 'returns \"negative\"' do\n          expect(subject).to be 'negative'\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/helpers/admin/filter_helper_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe Admin::FilterHelper do\n  it 'Uses filter_link_to to create filter links' do\n    params = ActionController::Parameters.new(\n      { test: 'test' }\n    )\n    allow(helper).to receive(:params).and_return(params)\n    allow(helper).to receive(:url_for).and_return('/test')\n    result = helper.filter_link_to('text', { resolved: true })\n\n    expect(result).to match(/text/)\n  end\n\n  it 'Uses table_link_to to create icon links' do\n    result = helper.table_link_to 'icon', 'text', 'path'\n\n    expect(result).to match(/text/)\n  end\nend\n"
  },
  {
    "path": "spec/helpers/application_helper_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe ApplicationHelper do\n  describe 'active_nav_class' do\n    it 'returns active when on the current page' do\n      allow(helper).to receive(:current_page?).and_return(true)\n\n      result = helper.active_nav_class(\"/test\")\n      expect(result).to eq \"active\"\n    end\n\n    it 'returns active when on a current page' do\n      allow(helper).to receive(:current_page?).with('/foo').and_return(false)\n      allow(helper).to receive(:current_page?).with('/test').and_return(true)\n\n      result = helper.active_nav_class('/foo', '/test')\n      expect(result).to eq \"active\"\n    end\n\n    it 'returns empty string when not on current page' do\n      allow(helper).to receive(:current_page?).and_return(false)\n\n      result = helper.active_nav_class(\"/test\")\n      expect(result).to eq \"\"\n    end\n  end\n\n  describe 'locale_direction' do\n    around do |example|\n      current_locale = I18n.locale\n      example.run\n      I18n.locale = current_locale\n    end\n\n    it 'adds rtl body class if locale is Arabic' do\n      I18n.locale = :ar\n      expect(helper.locale_direction).to eq 'rtl'\n    end\n\n    it 'adds rtl body class if locale is Farsi' do\n      I18n.locale = :fa\n      expect(helper.locale_direction).to eq 'rtl'\n    end\n\n    it 'adds rtl if locale is Hebrew' do\n      I18n.locale = :he\n      expect(helper.locale_direction).to eq 'rtl'\n    end\n\n    it 'does not add rtl if locale is Thai' do\n      I18n.locale = :th\n      expect(helper.locale_direction).to_not eq 'rtl'\n    end\n  end\n\n  describe 'fa_icon' do\n    it 'returns a tag of fixed-width cog' do\n      expect(helper.fa_icon('cog fw')).to eq '<i class=\"fa fa-cog fa-fw\"></i>'\n    end\n  end\n\n  describe 'favicon_path' do\n    it 'returns /favicon.ico on production enviromnent' do\n      expect(Rails.env).to receive(:production?).and_return(true)\n      expect(helper.favicon_path).to eq '/favicon.ico'\n    end\n  end\n\n  describe 'open_registrations?' do\n    it 'returns true when open for registrations' do\n      without_partial_double_verification do\n        expect(Setting).to receive(:registrations_mode).and_return('open')\n      end\n\n      expect(helper.open_registrations?).to eq true\n    end\n\n    it 'returns false when closed for registrations' do\n      without_partial_double_verification do\n        expect(Setting).to receive(:registrations_mode).and_return('none')\n      end\n\n      expect(helper.open_registrations?).to eq false\n    end\n  end\n\n  describe 'show_landing_strip?', without_verify_partial_doubles: true do\n    describe 'when signed in' do\n      before do\n        allow(helper).to receive(:user_signed_in?).and_return(true)\n      end\n      it 'does not show landing strip' do\n        expect(helper.show_landing_strip?).to eq false\n      end\n    end\n\n    describe 'when signed out' do\n      before do\n        allow(helper).to receive(:user_signed_in?).and_return(false)\n      end\n\n      it 'does not show landing strip on single user instance' do\n        allow(helper).to receive(:single_user_mode?).and_return(true)\n\n        expect(helper.show_landing_strip?).to eq false\n      end\n\n      it 'shows landing strip on multi user instance' do\n        allow(helper).to receive(:single_user_mode?).and_return(false)\n\n        expect(helper.show_landing_strip?).to eq true\n      end\n    end\n  end\n\n  describe 'title' do\n    around do |example|\n      site_title = Setting.site_title\n      example.run\n      Setting.site_title = site_title\n    end\n\n    it 'returns site title on production enviroment' do\n      Setting.site_title = 'site title'\n      expect(Rails.env).to receive(:production?).and_return(true)\n      expect(helper.title).to eq 'site title'\n    end\n  end\nend\n"
  },
  {
    "path": "spec/helpers/flashes_helper_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe FlashesHelper, type: :helper do\n  describe 'user_facing_flashes' do\n    it 'returns user facing flashes' do\n      flash[:alert] = 'an alert'\n      flash[:error] = 'an error'\n      flash[:notice] = 'a notice'\n      flash[:success] = 'a success'\n      flash[:not_user_facing] = 'a not user facing flash'\n      expect(helper.user_facing_flashes).to eq 'alert' => 'an alert',\n                                               'error' => 'an error',\n                                               'notice' => 'a notice',\n                                               'success' => 'a success'\n    end\n  end\nend\n"
  },
  {
    "path": "spec/helpers/home_helper_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe HomeHelper, type: :helper do\n  describe 'default_props' do\n    it 'returns default properties according to the context' do\n      expect(helper.default_props).to eq locale: I18n.locale\n    end\n  end\nend\n"
  },
  {
    "path": "spec/helpers/instance_helper_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe InstanceHelper do\n  describe 'site_title' do\n    around do |example|\n      site_title = Setting.site_title\n      example.run\n      Setting.site_title = site_title\n    end\n\n    it 'Uses the Setting.site_title value when it exists' do\n      Setting.site_title = 'New site title'\n\n      expect(helper.site_title).to eq 'New site title'\n    end\n  end\n\n  describe 'site_hostname' do\n    around(:each) do |example|\n      before = Rails.configuration.x.local_domain\n      example.run\n      Rails.configuration.x.local_domain = before\n    end\n\n    it 'returns the local domain value' do\n      Rails.configuration.x.local_domain = 'example.com'\n\n      expect(helper.site_hostname).to eq 'example.com'\n    end\n  end\nend\n"
  },
  {
    "path": "spec/helpers/jsonld_helper_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe JsonLdHelper do\n  describe '#equals_or_includes?' do\n    it 'returns true when value equals' do\n      expect(helper.equals_or_includes?('foo', 'foo')).to be true\n    end\n\n    it 'returns false when value does not equal' do\n      expect(helper.equals_or_includes?('foo', 'bar')).to be false\n    end\n\n    it 'returns true when value is included' do\n      expect(helper.equals_or_includes?(%w(foo baz), 'foo')).to be true\n    end\n\n    it 'returns false when value is not included' do\n      expect(helper.equals_or_includes?(%w(foo baz), 'bar')).to be false\n    end\n  end\n\n  describe '#first_of_value' do\n    context 'value.is_a?(Array)' do\n      it 'returns value.first' do\n        value = ['a']\n        expect(helper.first_of_value(value)).to be 'a'\n      end\n    end\n\n    context '!value.is_a?(Array)' do\n      it 'returns value' do\n        value = 'a'\n        expect(helper.first_of_value(value)).to be 'a'\n      end\n    end\n  end\n\n  describe '#supported_context?' do\n    context \"!json.nil? && equals_or_includes?(json['@context'], ActivityPub::TagManager::CONTEXT)\" do\n      it 'returns true' do\n        json = { '@context' => ActivityPub::TagManager::CONTEXT }.as_json\n        expect(helper.supported_context?(json)).to be true\n      end\n    end\n\n    context 'else' do\n      it 'returns false' do\n        json = nil\n        expect(helper.supported_context?(json)).to be false\n      end\n    end\n  end\n\n  describe '#fetch_resource' do\n    context 'when the second argument is false' do\n      it 'returns resource even if the retrieved ID and the given URI does not match' do\n        stub_request(:get, 'https://bob.test/').to_return body: '{\"id\": \"https://alice.test/\"}'\n        stub_request(:get, 'https://alice.test/').to_return body: '{\"id\": \"https://alice.test/\"}'\n\n        expect(fetch_resource('https://bob.test/', false)).to eq({ 'id' => 'https://alice.test/' })\n      end\n\n      it 'returns nil if the object identified by the given URI and the object identified by the retrieved ID does not match' do\n        stub_request(:get, 'https://mallory.test/').to_return body: '{\"id\": \"https://marvin.test/\"}'\n        stub_request(:get, 'https://marvin.test/').to_return body: '{\"id\": \"https://alice.test/\"}'\n\n        expect(fetch_resource('https://mallory.test/', false)).to eq nil\n      end\n    end\n\n    context 'when the second argument is true' do\n      it 'returns nil if the retrieved ID and the given URI does not match' do\n        stub_request(:get, 'https://mallory.test/').to_return body: '{\"id\": \"https://alice.test/\"}'\n        expect(fetch_resource('https://mallory.test/', true)).to eq nil\n      end\n    end\n  end\n\n  describe '#fetch_resource_without_id_validation' do\n    it 'returns nil if the status code is not 200' do\n      stub_request(:get, 'https://host.test/').to_return status: 400, body: '{}'\n      expect(fetch_resource_without_id_validation('https://host.test/')).to eq nil\n    end\n\n    it 'returns hash' do\n      stub_request(:get, 'https://host.test/').to_return status: 200, body: '{}'\n      expect(fetch_resource_without_id_validation('https://host.test/')).to eq({})\n    end\n  end\nend\n"
  },
  {
    "path": "spec/helpers/routing_helper_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe RoutingHelper, type: :helper do\n  describe '.full_asset_url' do\n    around do |example|\n      use_s3 = Rails.configuration.x.use_s3\n      example.run\n      Rails.configuration.x.use_s3 = use_s3\n    end\n\n    shared_examples 'returns full path URL' do\n      it 'with host' do\n        url = helper.full_asset_url('https://example.com/avatars/000/000/002/original/icon.png')\n\n        expect(url).to eq 'https://example.com/avatars/000/000/002/original/icon.png'\n      end\n\n      it 'without host' do\n        url = helper.full_asset_url('/avatars/original/missing.png', skip_pipeline: true)\n\n        expect(url).to eq 'http://test.host/avatars/original/missing.png'\n      end\n    end\n\n    context 'Do not use S3' do\n      before do\n        Rails.configuration.x.use_s3 = false\n      end\n\n      it_behaves_like 'returns full path URL'\n    end\n\n    context 'Use S3' do\n      before do\n        Rails.configuration.x.use_s3 = true\n      end\n\n      it_behaves_like 'returns full path URL'\n    end\n  end\nend\n"
  },
  {
    "path": "spec/helpers/settings_helper_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe SettingsHelper do\n  describe 'the HUMAN_LOCALES constant' do\n    it 'includes all I18n locales' do\n      options = I18n.available_locales\n\n      expect(described_class::HUMAN_LOCALES.keys).to include(*options)\n    end\n  end\n\n  describe 'human_locale' do\n    it 'finds the human readable local description from a key' do\n      # Ensure the value is as we expect\n      expect(described_class::HUMAN_LOCALES[:en]).to eq('English')\n\n      expect(helper.human_locale(:en)).to eq('English')\n    end\n  end\nend\n"
  },
  {
    "path": "spec/helpers/stream_entries_helper_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe StreamEntriesHelper, type: :helper do\n  describe '#display_name' do\n    it 'uses the display name when it exists' do\n      account = Account.new(display_name: \"Display\", username: \"Username\")\n\n      expect(helper.display_name(account)).to eq \"Display\"\n    end\n\n    it 'uses the username when display name is nil' do\n      account = Account.new(display_name: nil, username: \"Username\")\n\n      expect(helper.display_name(account)).to eq \"Username\"\n    end\n  end\n\n  describe '#stream_link_target' do\n    it 'returns nil if it is not an embedded view' do\n      set_not_embedded_view\n\n      expect(helper.stream_link_target).to be_nil\n    end\n\n    it 'returns _blank if it is an embedded view' do\n      set_embedded_view\n\n      expect(helper.stream_link_target).to eq '_blank'\n    end\n  end\n\n  describe '#acct' do\n    it 'is fully qualified for embedded local accounts' do\n      allow(Rails.configuration.x).to receive(:local_domain).and_return('local_domain')\n      set_embedded_view\n      account = Account.new(domain: nil, username: 'user')\n\n      acct = helper.acct(account)\n\n      expect(acct).to eq '@user@local_domain'\n    end\n\n    it 'is fully qualified for embedded foreign accounts' do\n      set_embedded_view\n      account = Account.new(domain: 'foreign_server.com', username: 'user')\n\n      acct = helper.acct(account)\n\n      expect(acct).to eq '@user@foreign_server.com'\n    end\n\n    it 'is fully qualified for non embedded foreign accounts' do\n      set_not_embedded_view\n      account = Account.new(domain: 'foreign_server.com', username: 'user')\n\n      acct = helper.acct(account)\n\n      expect(acct).to eq '@user@foreign_server.com'\n    end\n\n    it 'is fully qualified for non embedded local accounts' do\n      allow(Rails.configuration.x).to receive(:local_domain).and_return('local_domain')\n      set_not_embedded_view\n      account = Account.new(domain: nil, username: 'user')\n\n      acct = helper.acct(account)\n\n      expect(acct).to eq '@user@local_domain'\n    end\n  end\n\n  def set_not_embedded_view\n    params[:controller] = \"not_#{StreamEntriesHelper::EMBEDDED_CONTROLLER}\"\n    params[:action] = \"not_#{StreamEntriesHelper::EMBEDDED_ACTION}\"\n  end\n\n  def set_embedded_view\n    params[:controller] = StreamEntriesHelper::EMBEDDED_CONTROLLER\n    params[:action] = StreamEntriesHelper::EMBEDDED_ACTION\n  end\n\n  describe '#style_classes' do\n    it do\n      status = double(reblog?: false)\n      classes = helper.style_classes(status, false, false, false)\n\n      expect(classes).to eq 'entry'\n    end\n\n    it do\n      status = double(reblog?: true)\n      classes = helper.style_classes(status, false, false, false)\n\n      expect(classes).to eq 'entry entry-reblog'\n    end\n\n    it do\n      status = double(reblog?: false)\n      classes = helper.style_classes(status, true, false, false)\n\n      expect(classes).to eq 'entry entry-predecessor'\n    end\n\n    it do\n      status = double(reblog?: false)\n      classes = helper.style_classes(status, false, true, false)\n\n      expect(classes).to eq 'entry entry-successor'\n    end\n\n    it do\n      status = double(reblog?: false)\n      classes = helper.style_classes(status, false, false, true)\n\n      expect(classes).to eq 'entry entry-center'\n    end\n\n    it do\n      status = double(reblog?: true)\n      classes = helper.style_classes(status, true, true, true)\n\n      expect(classes).to eq 'entry entry-predecessor entry-reblog entry-successor entry-center'\n    end\n  end\n\n  describe '#microformats_classes' do\n    it do\n      status = double(reblog?: false)\n      classes = helper.microformats_classes(status, false, false)\n\n      expect(classes).to eq ''\n    end\n\n    it do\n      status = double(reblog?: false)\n      classes = helper.microformats_classes(status, true, false)\n\n      expect(classes).to eq 'p-in-reply-to'\n    end\n\n    it do\n      status = double(reblog?: false)\n      classes = helper.microformats_classes(status, false, true)\n\n      expect(classes).to eq 'p-comment'\n    end\n\n    it do\n      status = double(reblog?: true)\n      classes = helper.microformats_classes(status, true, false)\n\n      expect(classes).to eq 'p-in-reply-to p-repost-of'\n    end\n\n    it do\n      status = double(reblog?: true)\n      classes = helper.microformats_classes(status, true, true)\n\n      expect(classes).to eq 'p-in-reply-to p-repost-of p-comment'\n    end\n  end\n\n  describe '#microformats_h_class' do\n    it do\n      status = double(reblog?: false)\n      css_class = helper.microformats_h_class(status, false, false, false)\n\n      expect(css_class).to eq 'h-entry'\n    end\n\n    it do\n      status = double(reblog?: true)\n      css_class = helper.microformats_h_class(status, false, false, false)\n\n      expect(css_class).to eq 'h-cite'\n    end\n\n    it do\n      status = double(reblog?: false)\n      css_class = helper.microformats_h_class(status, true, false, false)\n\n      expect(css_class).to eq 'h-cite'\n    end\n\n    it do\n      status = double(reblog?: false)\n      css_class = helper.microformats_h_class(status, false, true, false)\n\n      expect(css_class).to eq 'h-cite'\n    end\n\n    it do\n      status = double(reblog?: false)\n      css_class = helper.microformats_h_class(status, false, false, true)\n\n      expect(css_class).to eq ''\n    end\n\n    it do\n      status = double(reblog?: true)\n      css_class = helper.microformats_h_class(status, true, true, true)\n\n      expect(css_class).to eq 'h-cite'\n    end\n  end\n\n  describe '#rtl?' do\n    it 'is false if text is empty' do\n      expect(helper).not_to be_rtl ''\n    end\n\n    it 'is false if there are no right to left characters' do\n      expect(helper).not_to be_rtl 'hello world'\n    end\n\n    it 'is false if right to left characters are fewer than 1/3 of total text' do\n      expect(helper).not_to be_rtl 'hello ݟ world'\n    end\n\n    it 'is true if right to left characters are greater than 1/3 of total text' do\n      expect(helper).to be_rtl 'aaݟaaݟ'\n    end\n  end\nend\n"
  },
  {
    "path": "spec/lib/activitypub/activity/accept_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe ActivityPub::Activity::Accept do\n  let(:sender)    { Fabricate(:account) }\n  let(:recipient) { Fabricate(:account) }\n\n  let(:json) do\n    {\n      '@context': 'https://www.w3.org/ns/activitystreams',\n      id: 'foo',\n      type: 'Accept',\n      actor: ActivityPub::TagManager.instance.uri_for(sender),\n      object: {\n        id: 'bar',\n        type: 'Follow',\n        actor: ActivityPub::TagManager.instance.uri_for(recipient),\n        object: ActivityPub::TagManager.instance.uri_for(sender),\n      },\n    }.with_indifferent_access\n  end\n\n  describe '#perform' do\n    subject { described_class.new(json, sender) }\n\n    before do\n      Fabricate(:follow_request, account: recipient, target_account: sender)\n      subject.perform\n    end\n\n    it 'creates a follow relationship' do\n      expect(recipient.following?(sender)).to be true\n    end\n\n    it 'removes the follow request' do\n      expect(recipient.requested?(sender)).to be false\n    end\n  end\n\n  context 'given a relay' do\n    let!(:relay) { Fabricate(:relay, state: :pending, follow_activity_id: 'https://abc-123/456') }\n\n    let(:json) do\n      {\n        '@context': 'https://www.w3.org/ns/activitystreams',\n        id: 'foo',\n        type: 'Accept',\n        actor: ActivityPub::TagManager.instance.uri_for(sender),\n        object: {\n          id: 'https://abc-123/456',\n          type: 'Follow',\n          actor: ActivityPub::TagManager.instance.uri_for(recipient),\n          object: ActivityPub::TagManager.instance.uri_for(sender),\n        },\n      }.with_indifferent_access\n    end\n\n    subject { described_class.new(json, sender) }\n\n    it 'marks the relay as accepted' do\n      subject.perform\n      expect(relay.reload.accepted?).to be true\n    end\n  end\nend\n"
  },
  {
    "path": "spec/lib/activitypub/activity/add_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe ActivityPub::Activity::Add do\n  let(:sender) { Fabricate(:account, featured_collection_url: 'https://example.com/featured') }\n  let(:status) { Fabricate(:status, account: sender) }\n\n  let(:json) do\n    {\n      '@context': 'https://www.w3.org/ns/activitystreams',\n      id: 'foo',\n      type: 'Add',\n      actor: ActivityPub::TagManager.instance.uri_for(sender),\n      object: ActivityPub::TagManager.instance.uri_for(status),\n      target: sender.featured_collection_url,\n    }.with_indifferent_access\n  end\n\n  describe '#perform' do\n    subject { described_class.new(json, sender) }\n\n    it 'creates a pin' do\n      subject.perform\n      expect(sender.pinned?(status)).to be true\n    end\n\n    context 'when status was not known before' do\n      let(:json) do\n        {\n          '@context': 'https://www.w3.org/ns/activitystreams',\n          id: 'foo',\n          type: 'Add',\n          actor: ActivityPub::TagManager.instance.uri_for(sender),\n          object: 'https://example.com/unknown',\n          target: sender.featured_collection_url,\n        }.with_indifferent_access\n      end\n\n      before do\n        stub_request(:get, 'https://example.com/unknown').to_return(status: 410)\n      end\n\n      it 'fetches the status' do\n        subject.perform\n        expect(a_request(:get, 'https://example.com/unknown')).to have_been_made.at_least_once\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/lib/activitypub/activity/announce_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe ActivityPub::Activity::Announce do\n  let(:sender)    { Fabricate(:account, followers_url: 'http://example.com/followers', uri: 'https://example.com/actor') }\n  let(:recipient) { Fabricate(:account) }\n  let(:status)    { Fabricate(:status, account: recipient) }\n\n  let(:json) do\n    {\n      '@context': 'https://www.w3.org/ns/activitystreams',\n      id: 'foo',\n      type: 'Announce',\n      actor: 'https://example.com/actor',\n      object: object_json,\n      to: 'http://example.com/followers',\n    }.with_indifferent_access\n  end\n\n  let(:unknown_object_json) do\n    {\n      '@context': 'https://www.w3.org/ns/activitystreams',\n      id: 'https://example.com/actor/hello-world',\n      type: 'Note',\n      attributedTo: 'https://example.com/actor',\n      content: 'Hello world',\n      to: 'http://example.com/followers',\n    }\n  end\n\n  subject { described_class.new(json, sender) }\n\n  describe '#perform' do\n    context 'when sender is followed by a local account' do\n      before do\n        Fabricate(:account).follow!(sender)\n        stub_request(:get, 'https://example.com/actor/hello-world').to_return(body: Oj.dump(unknown_object_json))\n        subject.perform\n      end\n\n      context 'a known status' do\n        let(:object_json) do\n          ActivityPub::TagManager.instance.uri_for(status)\n        end\n\n        it 'creates a reblog by sender of status' do\n          expect(sender.reblogged?(status)).to be true\n        end\n      end\n\n      context 'an unknown status' do\n        let(:object_json) { 'https://example.com/actor/hello-world' }\n\n        it 'creates a reblog by sender of status' do\n          reblog = sender.statuses.first\n\n          expect(reblog).to_not be_nil\n          expect(reblog.reblog.text).to eq 'Hello world'\n        end\n      end\n\n      context 'self-boost of a previously unknown status with correct attributedTo' do\n        let(:object_json) do\n          {\n            id: 'https://example.com/actor#bar',\n            type: 'Note',\n            content: 'Lorem ipsum',\n            attributedTo: 'https://example.com/actor',\n            to: 'http://example.com/followers',\n          }\n        end\n\n        it 'creates a reblog by sender of status' do\n          expect(sender.reblogged?(sender.statuses.first)).to be true\n        end\n      end\n    end\n\n    context 'when the status belongs to a local user' do\n      before do\n        subject.perform\n      end\n\n      let(:object_json) do\n        ActivityPub::TagManager.instance.uri_for(status)\n      end\n\n      it 'creates a reblog by sender of status' do\n        expect(sender.reblogged?(status)).to be true\n      end\n    end\n\n    context 'when the sender is relayed' do\n      let!(:relay_account) { Fabricate(:account, inbox_url: 'https://relay.example.com/inbox') }\n      let!(:relay) { Fabricate(:relay, inbox_url: 'https://relay.example.com/inbox') }\n\n      subject { described_class.new(json, sender, relayed_through_account: relay_account) }\n\n      context 'and the relay is enabled' do\n        before do\n          relay.update(state: :accepted)\n          subject.perform\n        end\n\n        let(:object_json) do\n          {\n            id: 'https://example.com/actor#bar',\n            type: 'Note',\n            content: 'Lorem ipsum',\n            to: 'http://example.com/followers',\n            attributedTo: 'https://example.com/actor',\n          }\n        end\n\n        it 'creates a reblog by sender of status' do\n          expect(sender.statuses.count).to eq 2\n        end\n      end\n\n      context 'and the relay is disabled' do\n        before do\n          subject.perform\n        end\n\n        let(:object_json) do\n          {\n            id: 'https://example.com/actor#bar',\n            type: 'Note',\n            content: 'Lorem ipsum',\n            to: 'http://example.com/followers',\n            attributedTo: 'https://example.com/actor',\n          }\n        end\n\n        it 'does not create anything' do\n          expect(sender.statuses.count).to eq 0\n        end\n      end\n    end\n\n    context 'when the sender has no relevance to local activity' do\n      before do\n        subject.perform\n      end\n\n      let(:object_json) do\n        {\n          id: 'https://example.com/actor#bar',\n          type: 'Note',\n          content: 'Lorem ipsum',\n          to: 'http://example.com/followers',\n          attributedTo: 'https://example.com/actor',\n        }\n      end\n\n      it 'does not create anything' do\n        expect(sender.statuses.count).to eq 0\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/lib/activitypub/activity/block_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe ActivityPub::Activity::Block do\n  let(:sender)    { Fabricate(:account) }\n  let(:recipient) { Fabricate(:account) }\n\n  let(:json) do\n    {\n      '@context': 'https://www.w3.org/ns/activitystreams',\n      id: 'foo',\n      type: 'Block',\n      actor: ActivityPub::TagManager.instance.uri_for(sender),\n      object: ActivityPub::TagManager.instance.uri_for(recipient),\n    }.with_indifferent_access\n  end\n\n  context 'when the recipient does not follow the sender' do\n    describe '#perform' do\n      subject { described_class.new(json, sender) }\n\n      before do\n        subject.perform\n      end\n\n      it 'creates a block from sender to recipient' do\n        expect(sender.blocking?(recipient)).to be true\n      end\n    end\n  end\n\n  context 'when the recipient follows the sender' do\n    before do\n      recipient.follow!(sender)\n    end\n\n    describe '#perform' do\n      subject { described_class.new(json, sender) }\n\n      before do\n        subject.perform\n      end\n\n      it 'creates a block from sender to recipient' do\n        expect(sender.blocking?(recipient)).to be true\n      end\n\n      it 'ensures recipient is not following sender' do\n        expect(recipient.following?(sender)).to be false\n      end\n    end\n  end\n\n  context 'when a matching undo has been received first' do\n    let(:undo_json) do\n      {\n        '@context': 'https://www.w3.org/ns/activitystreams',\n        id: 'bar',\n        type: 'Undo',\n        actor: ActivityPub::TagManager.instance.uri_for(sender),\n        object: json,\n      }.with_indifferent_access\n    end\n\n    before do\n      recipient.follow!(sender)\n      ActivityPub::Activity::Undo.new(undo_json, sender).perform\n    end\n\n    describe '#perform' do\n      subject { described_class.new(json, sender) }\n\n      before do\n        subject.perform\n      end\n\n      it 'does not create a block from sender to recipient' do\n        expect(sender.blocking?(recipient)).to be false\n      end\n\n      it 'ensures recipient is not following sender' do\n        expect(recipient.following?(sender)).to be false\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/lib/activitypub/activity/create_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe ActivityPub::Activity::Create do\n  let(:sender) { Fabricate(:account, followers_url: 'http://example.com/followers', domain: 'example.com', uri: 'https://example.com/actor') }\n\n  let(:json) do\n    {\n      '@context': 'https://www.w3.org/ns/activitystreams',\n      id: [ActivityPub::TagManager.instance.uri_for(sender), '#foo'].join,\n      type: 'Create',\n      actor: ActivityPub::TagManager.instance.uri_for(sender),\n      object: object_json,\n    }.with_indifferent_access\n  end\n\n  before do\n    sender.update(uri: ActivityPub::TagManager.instance.uri_for(sender))\n\n    stub_request(:get, 'http://example.com/attachment.png').to_return(request_fixture('avatar.txt'))\n    stub_request(:get, 'http://example.com/emoji.png').to_return(body: attachment_fixture('emojo.png'))\n  end\n\n  describe '#perform' do\n    context 'when fetching' do\n      subject { described_class.new(json, sender) }\n\n      before do\n        subject.perform\n      end\n\n      context 'unknown object type' do\n        let(:object_json) do\n          {\n            id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,\n            type: 'Banana',\n            content: 'Lorem ipsum',\n          }\n        end\n\n        it 'does not create a status' do\n          expect(sender.statuses.count).to be_zero\n        end\n      end\n\n      context 'standalone' do\n        let(:object_json) do\n          {\n            id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,\n            type: 'Note',\n            content: 'Lorem ipsum',\n          }\n        end\n\n        it 'creates status' do\n          status = sender.statuses.first\n\n          expect(status).to_not be_nil\n          expect(status.text).to eq 'Lorem ipsum'\n        end\n\n        it 'missing to/cc defaults to direct privacy' do\n          status = sender.statuses.first\n\n          expect(status).to_not be_nil\n          expect(status.visibility).to eq 'direct'\n        end\n      end\n\n      context 'public' do\n        let(:object_json) do\n          {\n            id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,\n            type: 'Note',\n            content: 'Lorem ipsum',\n            to: 'https://www.w3.org/ns/activitystreams#Public',\n          }\n        end\n\n        it 'creates status' do\n          status = sender.statuses.first\n\n          expect(status).to_not be_nil\n          expect(status.visibility).to eq 'public'\n        end\n      end\n\n      context 'unlisted' do\n        let(:object_json) do\n          {\n            id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,\n            type: 'Note',\n            content: 'Lorem ipsum',\n            cc: 'https://www.w3.org/ns/activitystreams#Public',\n          }\n        end\n\n        it 'creates status' do\n          status = sender.statuses.first\n\n          expect(status).to_not be_nil\n          expect(status.visibility).to eq 'unlisted'\n        end\n      end\n\n      context 'private' do\n        let(:object_json) do\n          {\n            id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,\n            type: 'Note',\n            content: 'Lorem ipsum',\n            to: 'http://example.com/followers',\n          }\n        end\n\n        it 'creates status' do\n          status = sender.statuses.first\n\n          expect(status).to_not be_nil\n          expect(status.visibility).to eq 'private'\n        end\n      end\n\n      context 'limited' do\n        let(:recipient) { Fabricate(:account) }\n\n        let(:object_json) do\n          {\n            id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,\n            type: 'Note',\n            content: 'Lorem ipsum',\n            to: ActivityPub::TagManager.instance.uri_for(recipient),\n          }\n        end\n\n        it 'creates status' do\n          status = sender.statuses.first\n\n          expect(status).to_not be_nil\n          expect(status.visibility).to eq 'limited'\n        end\n\n        it 'creates silent mention' do\n          status = sender.statuses.first\n          expect(status.mentions.first).to be_silent\n        end\n      end\n\n      context 'direct' do\n        let(:recipient) { Fabricate(:account) }\n\n        let(:object_json) do\n          {\n            id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,\n            type: 'Note',\n            content: 'Lorem ipsum',\n            to: ActivityPub::TagManager.instance.uri_for(recipient),\n            tag: {\n              type: 'Mention',\n              href: ActivityPub::TagManager.instance.uri_for(recipient),\n            },\n          }\n        end\n\n        it 'creates status' do\n          status = sender.statuses.first\n\n          expect(status).to_not be_nil\n          expect(status.visibility).to eq 'direct'\n        end\n      end\n\n      context 'as a reply' do\n        let(:original_status) { Fabricate(:status) }\n\n        let(:object_json) do\n          {\n            id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,\n            type: 'Note',\n            content: 'Lorem ipsum',\n            inReplyTo: ActivityPub::TagManager.instance.uri_for(original_status),\n          }\n        end\n\n        it 'creates status' do\n          status = sender.statuses.first\n\n          expect(status).to_not be_nil\n          expect(status.thread).to eq original_status\n          expect(status.reply?).to be true\n          expect(status.in_reply_to_account).to eq original_status.account\n          expect(status.conversation).to eq original_status.conversation\n        end\n      end\n\n      context 'with mentions' do\n        let(:recipient) { Fabricate(:account) }\n\n        let(:object_json) do\n          {\n            id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,\n            type: 'Note',\n            content: 'Lorem ipsum',\n            tag: [\n              {\n                type: 'Mention',\n                href: ActivityPub::TagManager.instance.uri_for(recipient),\n              },\n            ],\n          }\n        end\n\n        it 'creates status' do\n          status = sender.statuses.first\n\n          expect(status).to_not be_nil\n          expect(status.mentions.map(&:account)).to include(recipient)\n        end\n      end\n\n      context 'with mentions missing href' do\n        let(:object_json) do\n          {\n            id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,\n            type: 'Note',\n            content: 'Lorem ipsum',\n            tag: [\n              {\n                type: 'Mention',\n              },\n            ],\n          }\n        end\n\n        it 'creates status' do\n          status = sender.statuses.first\n          expect(status).to_not be_nil\n        end\n      end\n\n      context 'with media attachments' do\n        let(:object_json) do\n          {\n            id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,\n            type: 'Note',\n            content: 'Lorem ipsum',\n            attachment: [\n              {\n                type: 'Document',\n                mediaType: 'image/png',\n                url: 'http://example.com/attachment.png',\n              },\n            ],\n          }\n        end\n\n        it 'creates status' do\n          status = sender.statuses.first\n\n          expect(status).to_not be_nil\n          expect(status.media_attachments.map(&:remote_url)).to include('http://example.com/attachment.png')\n        end\n      end\n\n      context 'with media attachments with focal points' do\n        let(:object_json) do\n          {\n            id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,\n            type: 'Note',\n            content: 'Lorem ipsum',\n            attachment: [\n              {\n                type: 'Document',\n                mediaType: 'image/png',\n                url: 'http://example.com/attachment.png',\n                focalPoint: [0.5, -0.7],\n              },\n            ],\n          }\n        end\n\n        it 'creates status' do\n          status = sender.statuses.first\n\n          expect(status).to_not be_nil\n          expect(status.media_attachments.map(&:focus)).to include('0.5,-0.7')\n        end\n      end\n\n      context 'with media attachments missing url' do\n        let(:object_json) do\n          {\n            id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,\n            type: 'Note',\n            content: 'Lorem ipsum',\n            attachment: [\n              {\n                type: 'Document',\n                mediaType: 'image/png',\n              },\n            ],\n          }\n        end\n\n        it 'creates status' do\n          status = sender.statuses.first\n          expect(status).to_not be_nil\n        end\n      end\n\n      context 'with hashtags' do\n        let(:object_json) do\n          {\n            id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,\n            type: 'Note',\n            content: 'Lorem ipsum',\n            tag: [\n              {\n                type: 'Hashtag',\n                href: 'http://example.com/blah',\n                name: '#test',\n              },\n            ],\n          }\n        end\n\n        it 'creates status' do\n          status = sender.statuses.first\n\n          expect(status).to_not be_nil\n          expect(status.tags.map(&:name)).to include('test')\n        end\n      end\n\n      context 'with hashtags missing name' do\n        let(:object_json) do\n          {\n            id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,\n            type: 'Note',\n            content: 'Lorem ipsum',\n            tag: [\n              {\n                type: 'Hashtag',\n                href: 'http://example.com/blah',\n              },\n            ],\n          }\n        end\n\n        it 'creates status' do\n          status = sender.statuses.first\n          expect(status).to_not be_nil\n        end\n      end\n\n      context 'with emojis' do\n        let(:object_json) do\n          {\n            id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,\n            type: 'Note',\n            content: 'Lorem ipsum :tinking:',\n            tag: [\n              {\n                type: 'Emoji',\n                icon: {\n                  url: 'http://example.com/emoji.png',\n                },\n                name: 'tinking',\n              },\n            ],\n          }\n        end\n\n        it 'creates status' do\n          status = sender.statuses.first\n\n          expect(status).to_not be_nil\n          expect(status.emojis.map(&:shortcode)).to include('tinking')\n        end\n      end\n\n      context 'with emojis missing name' do\n        let(:object_json) do\n          {\n            id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,\n            type: 'Note',\n            content: 'Lorem ipsum :tinking:',\n            tag: [\n              {\n                type: 'Emoji',\n                icon: {\n                  url: 'http://example.com/emoji.png',\n                },\n              },\n            ],\n          }\n        end\n\n        it 'creates status' do\n          status = sender.statuses.first\n          expect(status).to_not be_nil\n        end\n      end\n\n      context 'with emojis missing icon' do\n        let(:object_json) do\n          {\n            id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,\n            type: 'Note',\n            content: 'Lorem ipsum :tinking:',\n            tag: [\n              {\n                type: 'Emoji',\n                name: 'tinking',\n              },\n            ],\n          }\n        end\n\n        it 'creates status' do\n          status = sender.statuses.first\n          expect(status).to_not be_nil\n        end\n      end\n\n      context 'with poll' do\n        let(:object_json) do\n          {\n            id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,\n            type: 'Question',\n            content: 'Which color was the submarine?',\n            oneOf: [\n              {\n                name: 'Yellow',\n                replies: {\n                  type: 'Collection',\n                  totalItems: 10,\n                },\n              },\n              {\n                name: 'Blue',\n                replies: {\n                  type: 'Collection',\n                  totalItems: 3,\n                }\n              },\n            ],\n          }\n        end\n\n        it 'creates status' do\n          status = sender.statuses.first\n          expect(status).to_not be_nil\n          expect(status.poll).to_not be_nil\n        end\n\n        it 'creates a poll' do\n          poll = sender.polls.first\n          expect(poll).to_not be_nil\n          expect(poll.status).to_not be_nil\n          expect(poll.options).to eq %w(Yellow Blue)\n          expect(poll.cached_tallies).to eq [10, 3]\n        end\n      end\n\n      context 'when a vote to a local poll' do\n        let(:poll) { Fabricate(:poll, options: %w(Yellow Blue)) }\n        let!(:local_status) { Fabricate(:status, poll: poll) }\n\n        let(:object_json) do\n          {\n            id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,\n            type: 'Note',\n            name: 'Yellow',\n            inReplyTo: ActivityPub::TagManager.instance.uri_for(local_status)\n          }\n        end\n\n        it 'adds a vote to the poll with correct uri' do\n          vote = poll.votes.first\n          expect(vote).to_not be_nil\n          expect(vote.uri).to eq object_json[:id]\n          expect(poll.reload.cached_tallies).to eq [1, 0]\n        end\n      end\n\n      context 'when a vote to an expired local poll' do\n        let(:poll) do\n          poll = Fabricate.build(:poll, options: %w(Yellow Blue), expires_at: 1.day.ago)\n          poll.save(validate: false)\n          poll\n        end\n        let!(:local_status) { Fabricate(:status, poll: poll) }\n\n        let(:object_json) do\n          {\n            id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,\n            type: 'Note',\n            name: 'Yellow',\n            inReplyTo: ActivityPub::TagManager.instance.uri_for(local_status)\n          }\n        end\n\n        it 'does not add a vote to the poll' do\n          expect(poll.votes.first).to be_nil\n        end\n      end\n    end\n\n    context 'when sender is followed by local users' do\n      subject { described_class.new(json, sender, delivery: true) }\n\n      before do\n        Fabricate(:account).follow!(sender)\n        subject.perform\n      end\n\n      let(:object_json) do\n        {\n          id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,\n          type: 'Note',\n          content: 'Lorem ipsum',\n        }\n      end\n\n      it 'creates status' do\n        status = sender.statuses.first\n\n        expect(status).to_not be_nil\n        expect(status.text).to eq 'Lorem ipsum'\n      end\n    end\n\n    context 'when sender replies to local status' do\n      let!(:local_status) { Fabricate(:status) }\n\n      subject { described_class.new(json, sender, delivery: true) }\n\n      before do\n        subject.perform\n      end\n\n      let(:object_json) do\n        {\n          id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,\n          type: 'Note',\n          content: 'Lorem ipsum',\n          inReplyTo: ActivityPub::TagManager.instance.uri_for(local_status),\n        }\n      end\n\n      it 'creates status' do\n        status = sender.statuses.first\n\n        expect(status).to_not be_nil\n        expect(status.text).to eq 'Lorem ipsum'\n      end\n    end\n\n    context 'when sender targets a local user' do\n      let!(:local_account) { Fabricate(:account) }\n\n      subject { described_class.new(json, sender, delivery: true) }\n\n      before do\n        subject.perform\n      end\n\n      let(:object_json) do\n        {\n          id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,\n          type: 'Note',\n          content: 'Lorem ipsum',\n          to: ActivityPub::TagManager.instance.uri_for(local_account),\n        }\n      end\n\n      it 'creates status' do\n        status = sender.statuses.first\n\n        expect(status).to_not be_nil\n        expect(status.text).to eq 'Lorem ipsum'\n      end\n    end\n\n    context 'when sender cc\\'s a local user' do\n      let!(:local_account) { Fabricate(:account) }\n\n      subject { described_class.new(json, sender, delivery: true) }\n\n      before do\n        subject.perform\n      end\n\n      let(:object_json) do\n        {\n          id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,\n          type: 'Note',\n          content: 'Lorem ipsum',\n          cc: ActivityPub::TagManager.instance.uri_for(local_account),\n        }\n      end\n\n      it 'creates status' do\n        status = sender.statuses.first\n\n        expect(status).to_not be_nil\n        expect(status.text).to eq 'Lorem ipsum'\n      end\n    end\n\n    context 'when the sender has no relevance to local activity' do\n      subject { described_class.new(json, sender, delivery: true) }\n\n      before do\n        subject.perform\n      end\n\n      let(:object_json) do\n        {\n          id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,\n          type: 'Note',\n          content: 'Lorem ipsum',\n        }\n      end\n\n      it 'does not create anything' do\n        expect(sender.statuses.count).to eq 0\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/lib/activitypub/activity/delete_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe ActivityPub::Activity::Delete do\n  let(:sender) { Fabricate(:account, domain: 'example.com') }\n  let(:status) { Fabricate(:status, account: sender, uri: 'foobar') }\n\n  let(:json) do\n    {\n      '@context': 'https://www.w3.org/ns/activitystreams',\n      id: 'foo',\n      type: 'Delete',\n      actor: ActivityPub::TagManager.instance.uri_for(sender),\n      object: ActivityPub::TagManager.instance.uri_for(status),\n      signature: 'foo',\n    }.with_indifferent_access\n  end\n\n  describe '#perform' do\n    subject { described_class.new(json, sender) }\n\n    before do\n      subject.perform\n    end\n\n    it 'deletes sender\\'s status' do\n      expect(Status.find_by(id: status.id)).to be_nil\n    end\n  end\n\n  context 'when the status has been reblogged' do\n    describe '#perform' do\n      subject { described_class.new(json, sender) }\n      let!(:reblogger) { Fabricate(:account) }\n      let!(:follower)  { Fabricate(:account, username: 'follower', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') }\n      let!(:reblog)    { Fabricate(:status, account: reblogger, reblog: status) }\n\n      before do\n        stub_request(:post, 'http://example.com/inbox').to_return(status: 200)\n        follower.follow!(reblogger)\n        subject.perform\n      end\n\n      it 'deletes sender\\'s status' do\n        expect(Status.find_by(id: status.id)).to be_nil\n      end\n\n      it 'sends delete activity to followers of rebloggers' do\n        expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/lib/activitypub/activity/flag_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe ActivityPub::Activity::Flag do\n  let(:sender)  { Fabricate(:account, domain: 'example.com', uri: 'http://example.com/account') }\n  let(:flagged) { Fabricate(:account) }\n  let(:status)  { Fabricate(:status, account: flagged, uri: 'foobar') }\n  let(:flag_id) { nil }\n\n  let(:json) do\n    {\n      '@context': 'https://www.w3.org/ns/activitystreams',\n      id: flag_id,\n      type: 'Flag',\n      content: 'Boo!!',\n      actor: ActivityPub::TagManager.instance.uri_for(sender),\n      object: [\n        ActivityPub::TagManager.instance.uri_for(flagged),\n        ActivityPub::TagManager.instance.uri_for(status),\n      ],\n    }.with_indifferent_access\n  end\n\n  describe '#perform' do\n    subject { described_class.new(json, sender) }\n\n    before do\n      subject.perform\n    end\n\n    it 'creates a report' do\n      report = Report.find_by(account: sender, target_account: flagged)\n\n      expect(report).to_not be_nil\n      expect(report.comment).to eq 'Boo!!'\n      expect(report.status_ids).to eq [status.id]\n    end\n  end\n\n  describe '#perform with a defined uri' do\n    subject { described_class.new(json, sender) }\n    let (:flag_id) { 'http://example.com/reports/1' }\n\n    before do\n      subject.perform\n    end\n\n    it 'creates a report' do\n      report = Report.find_by(account: sender, target_account: flagged)\n\n      expect(report).to_not be_nil\n      expect(report.comment).to eq 'Boo!!'\n      expect(report.status_ids).to eq [status.id]\n      expect(report.uri).to eq flag_id\n    end\n  end\nend\n"
  },
  {
    "path": "spec/lib/activitypub/activity/follow_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe ActivityPub::Activity::Follow do\n  let(:sender)    { Fabricate(:account) }\n  let(:recipient) { Fabricate(:account) }\n\n  let(:json) do\n    {\n      '@context': 'https://www.w3.org/ns/activitystreams',\n      id: 'foo',\n      type: 'Follow',\n      actor: ActivityPub::TagManager.instance.uri_for(sender),\n      object: ActivityPub::TagManager.instance.uri_for(recipient),\n    }.with_indifferent_access\n  end\n\n  describe '#perform' do\n    subject { described_class.new(json, sender) }\n\n    context 'unlocked account' do\n      before do\n        subject.perform\n      end\n\n      it 'creates a follow from sender to recipient' do\n        expect(sender.following?(recipient)).to be true\n      end\n\n      it 'does not create a follow request' do\n        expect(sender.requested?(recipient)).to be false\n      end\n    end\n\n    context 'locked account' do\n      before do\n        recipient.update(locked: true)\n        subject.perform\n      end\n\n      it 'does not create a follow from sender to recipient' do\n        expect(sender.following?(recipient)).to be false\n      end\n\n      it 'creates a follow request' do\n        expect(sender.requested?(recipient)).to be true\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/lib/activitypub/activity/like_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe ActivityPub::Activity::Like do\n  let(:sender)    { Fabricate(:account) }\n  let(:recipient) { Fabricate(:account) }\n  let(:status)    { Fabricate(:status, account: recipient) }\n\n  let(:json) do\n    {\n      '@context': 'https://www.w3.org/ns/activitystreams',\n      id: 'foo',\n      type: 'Like',\n      actor: ActivityPub::TagManager.instance.uri_for(sender),\n      object: ActivityPub::TagManager.instance.uri_for(status),\n    }.with_indifferent_access\n  end\n\n  describe '#perform' do\n    subject { described_class.new(json, sender) }\n\n    before do\n      subject.perform\n    end\n\n    it 'creates a favourite from sender to status' do\n      expect(sender.favourited?(status)).to be true\n    end\n  end\nend\n"
  },
  {
    "path": "spec/lib/activitypub/activity/move_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe ActivityPub::Activity::Move do\n  let(:follower)    { Fabricate(:account) }\n  let(:old_account) { Fabricate(:account) }\n  let(:new_account) { Fabricate(:account) }\n\n  before do\n    follower.follow!(old_account)\n\n    old_account.update!(uri: 'https://example.org/alice', domain: 'example.org', protocol: :activitypub, inbox_url: 'https://example.org/inbox')\n    new_account.update!(uri: 'https://example.com/alice', domain: 'example.com', protocol: :activitypub, inbox_url: 'https://example.com/inbox', also_known_as: [old_account.uri])\n\n    stub_request(:post, 'https://example.org/inbox').to_return(status: 200)\n    stub_request(:post, 'https://example.com/inbox').to_return(status: 200)\n\n    service_stub = double\n    allow(ActivityPub::FetchRemoteAccountService).to receive(:new).and_return(service_stub)\n    allow(service_stub).to receive(:call).and_return(new_account)\n  end\n\n  let(:json) do\n    {\n      '@context': 'https://www.w3.org/ns/activitystreams',\n      id: 'foo',\n      type: 'Move',\n      actor: old_account.uri,\n      object: old_account.uri,\n      target: new_account.uri,\n    }.with_indifferent_access\n  end\n\n  describe '#perform' do\n    subject { described_class.new(json, old_account) }\n\n    before do\n      subject.perform\n    end\n\n    it 'sets moved account on old account' do\n      expect(old_account.reload.moved_to_account_id).to eq new_account.id\n    end\n\n    it 'makes followers unfollow old account' do\n      expect(follower.following?(old_account)).to be false\n    end\n\n    it 'makes followers follow-request the new account' do\n      expect(follower.requested?(new_account)).to be true\n    end\n  end\nend\n"
  },
  {
    "path": "spec/lib/activitypub/activity/reject_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe ActivityPub::Activity::Reject do\n  let(:sender)    { Fabricate(:account) }\n  let(:recipient) { Fabricate(:account) }\n\n  let(:json) do\n    {\n      '@context': 'https://www.w3.org/ns/activitystreams',\n      id: 'foo',\n      type: 'Reject',\n      actor: ActivityPub::TagManager.instance.uri_for(sender),\n      object: {\n        id: 'bar',\n        type: 'Follow',\n        actor: ActivityPub::TagManager.instance.uri_for(recipient),\n        object: ActivityPub::TagManager.instance.uri_for(sender),\n      },\n    }.with_indifferent_access\n  end\n\n  describe '#perform' do\n    subject { described_class.new(json, sender) }\n\n    before do\n      Fabricate(:follow_request, account: recipient, target_account: sender)\n      subject.perform\n    end\n\n    it 'does not create a follow relationship' do\n      expect(recipient.following?(sender)).to be false\n    end\n\n    it 'removes the follow request' do\n      expect(recipient.requested?(sender)).to be false\n    end\n  end\n\n  context 'given a relay' do\n    let!(:relay) { Fabricate(:relay, state: :pending, follow_activity_id: 'https://abc-123/456') }\n\n    let(:json) do\n      {\n        '@context': 'https://www.w3.org/ns/activitystreams',\n        id: 'foo',\n        type: 'Reject',\n        actor: ActivityPub::TagManager.instance.uri_for(sender),\n        object: {\n          id: 'https://abc-123/456',\n          type: 'Follow',\n          actor: ActivityPub::TagManager.instance.uri_for(recipient),\n          object: ActivityPub::TagManager.instance.uri_for(sender),\n        },\n      }.with_indifferent_access\n    end\n\n    subject { described_class.new(json, sender) }\n\n    it 'marks the relay as rejected' do\n      subject.perform\n      expect(relay.reload.rejected?).to be true\n    end\n  end\nend\n"
  },
  {
    "path": "spec/lib/activitypub/activity/remove_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe ActivityPub::Activity::Remove do\n  let(:sender) { Fabricate(:account, featured_collection_url: 'https://example.com/featured') }\n  let(:status) { Fabricate(:status, account: sender) }\n\n  let(:json) do\n    {\n      '@context': 'https://www.w3.org/ns/activitystreams',\n      id: 'foo',\n      type: 'Add',\n      actor: ActivityPub::TagManager.instance.uri_for(sender),\n      object: ActivityPub::TagManager.instance.uri_for(status),\n      target: sender.featured_collection_url,\n    }.with_indifferent_access\n  end\n\n  describe '#perform' do\n    subject { described_class.new(json, sender) }\n\n    before do\n      StatusPin.create!(account: sender, status: status)\n      subject.perform\n    end\n\n    it 'removes a pin' do\n      expect(sender.pinned?(status)).to be false\n    end\n  end\nend\n"
  },
  {
    "path": "spec/lib/activitypub/activity/undo_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe ActivityPub::Activity::Undo do\n  let(:sender) { Fabricate(:account, domain: 'example.com') }\n\n  let(:json) do\n    {\n      '@context': 'https://www.w3.org/ns/activitystreams',\n      id: 'foo',\n      type: 'Undo',\n      actor: ActivityPub::TagManager.instance.uri_for(sender),\n      object: object_json,\n    }.with_indifferent_access\n  end\n\n  subject { described_class.new(json, sender) }\n\n  describe '#perform' do\n    context 'with Announce' do\n      let(:status) { Fabricate(:status) }\n\n      let(:object_json) do\n        {\n          id: 'bar',\n          type: 'Announce',\n          actor: ActivityPub::TagManager.instance.uri_for(sender),\n          object: ActivityPub::TagManager.instance.uri_for(status),\n          atomUri: 'barbar',\n        }\n      end\n\n      context do\n        before do\n          Fabricate(:status, reblog: status, account: sender, uri: 'bar')\n        end\n\n        it 'deletes the reblog' do\n          subject.perform\n          expect(sender.reblogged?(status)).to be false\n        end\n      end\n\n      context 'with atomUri' do\n        before do\n          Fabricate(:status, reblog: status, account: sender, uri: 'barbar')\n        end\n\n        it 'deletes the reblog by atomUri' do\n          subject.perform\n          expect(sender.reblogged?(status)).to be false\n        end\n      end\n    end\n\n    context 'with Accept' do\n      let(:recipient) { Fabricate(:account) }\n      let(:object_json) do\n        {\n          id: 'bar',\n          type: 'Accept',\n          actor: ActivityPub::TagManager.instance.uri_for(sender),\n          object: 'follow-to-revoke',\n        }\n      end\n\n      before do\n        recipient.follow!(sender, uri: 'follow-to-revoke')\n      end\n\n      it 'deletes follow from recipient to sender' do\n        subject.perform\n        expect(recipient.following?(sender)).to be false\n      end\n\n      it 'creates a follow request from recipient to sender' do\n        subject.perform\n        expect(recipient.requested?(sender)).to be true\n      end\n    end\n\n    context 'with Block' do\n      let(:recipient) { Fabricate(:account) }\n\n      let(:object_json) do\n        {\n          id: 'bar',\n          type: 'Block',\n          actor: ActivityPub::TagManager.instance.uri_for(sender),\n          object: ActivityPub::TagManager.instance.uri_for(recipient),\n        }\n      end\n\n      before do\n        sender.block!(recipient)\n      end\n\n      it 'deletes block from sender to recipient' do\n        subject.perform\n        expect(sender.blocking?(recipient)).to be false\n      end\n    end\n\n    context 'with Follow' do\n      let(:recipient) { Fabricate(:account) }\n\n      let(:object_json) do\n        {\n          id: 'bar',\n          type: 'Follow',\n          actor: ActivityPub::TagManager.instance.uri_for(sender),\n          object: ActivityPub::TagManager.instance.uri_for(recipient),\n        }\n      end\n\n      before do\n        sender.follow!(recipient)\n      end\n\n      it 'deletes follow from sender to recipient' do\n        subject.perform\n        expect(sender.following?(recipient)).to be false\n      end\n    end\n\n    context 'with Like' do\n      let(:status) { Fabricate(:status) }\n\n      let(:object_json) do\n        {\n          id: 'bar',\n          type: 'Like',\n          actor: ActivityPub::TagManager.instance.uri_for(sender),\n          object: ActivityPub::TagManager.instance.uri_for(status),\n        }\n      end\n\n      before do\n        Fabricate(:favourite, account: sender, status: status)\n      end\n\n      it 'deletes favourite from sender to status' do\n        subject.perform\n        expect(sender.favourited?(status)).to be false\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/lib/activitypub/activity/update_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe ActivityPub::Activity::Update do\n  let!(:sender) { Fabricate(:account) }\n\n  before do\n    stub_request(:get, actor_json[:outbox]).to_return(status: 404)\n    stub_request(:get, actor_json[:followers]).to_return(status: 404)\n    stub_request(:get, actor_json[:following]).to_return(status: 404)\n    stub_request(:get, actor_json[:featured]).to_return(status: 404)\n\n    sender.update!(uri: ActivityPub::TagManager.instance.uri_for(sender))\n  end\n\n  let(:modified_sender) do\n    sender.dup.tap do |modified_sender|\n      modified_sender.display_name = 'Totally modified now'\n    end\n  end\n\n  let(:actor_json) do\n    ActiveModelSerializers::SerializableResource.new(modified_sender, serializer: ActivityPub::ActorSerializer, key_transform: :camel_lower).as_json\n  end\n\n  let(:json) do\n    {\n      '@context': 'https://www.w3.org/ns/activitystreams',\n      id: 'foo',\n      type: 'Update',\n      actor: ActivityPub::TagManager.instance.uri_for(sender),\n      object: actor_json,\n    }.with_indifferent_access\n  end\n\n  describe '#perform' do\n    subject { described_class.new(json, sender) }\n\n    before do\n      subject.perform\n    end\n\n    it 'updates profile' do\n      expect(sender.reload.display_name).to eq 'Totally modified now'\n    end\n  end\nend\n"
  },
  {
    "path": "spec/lib/activitypub/adapter_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe ActivityPub::Adapter do\n  class TestObject < ActiveModelSerializers::Model\n    attributes :foo\n  end\n\n  class TestWithBasicContextSerializer < ActivityPub::Serializer\n    attributes :foo\n  end\n\n  class TestWithNamedContextSerializer < ActivityPub::Serializer\n    context :security\n    attributes :foo\n  end\n\n  class TestWithNestedNamedContextSerializer < ActivityPub::Serializer\n    attributes :foo\n\n    has_one :virtual_object, key: :baz, serializer: TestWithNamedContextSerializer\n\n    def virtual_object\n      object\n    end\n  end\n\n  class TestWithContextExtensionSerializer < ActivityPub::Serializer\n    context_extensions :sensitive\n    attributes :foo\n  end\n\n  class TestWithNestedContextExtensionSerializer < ActivityPub::Serializer\n    context_extensions :manually_approves_followers\n    attributes :foo\n\n    has_one :virtual_object, key: :baz, serializer: TestWithContextExtensionSerializer\n\n    def virtual_object\n      object\n    end\n  end\n\n  describe '#serializable_hash' do\n    let(:serializer_class) {}\n\n    subject { ActiveModelSerializers::SerializableResource.new(TestObject.new(foo: 'bar'), serializer: serializer_class, adapter: described_class).as_json }\n\n    context 'when serializer defines no context' do\n      let(:serializer_class) { TestWithBasicContextSerializer }\n\n      it 'renders a basic @context' do\n        expect(subject).to include({ '@context' => 'https://www.w3.org/ns/activitystreams' })\n      end\n    end\n\n    context 'when serializer defines a named context' do\n      let(:serializer_class) { TestWithNamedContextSerializer }\n\n      it 'renders a @context with both items' do\n        expect(subject).to include({ '@context' => ['https://www.w3.org/ns/activitystreams', 'https://w3id.org/security/v1'] })\n      end\n    end\n\n    context 'when serializer has children that define a named context' do\n      let(:serializer_class) { TestWithNestedNamedContextSerializer }\n\n      it 'renders a @context with both items' do\n        expect(subject).to include({ '@context' => ['https://www.w3.org/ns/activitystreams', 'https://w3id.org/security/v1'] })\n      end\n    end\n\n    context 'when serializer defines context extensions' do\n      let(:serializer_class) { TestWithContextExtensionSerializer }\n\n      it 'renders a @context with the extension' do\n        expect(subject).to include({ '@context' => ['https://www.w3.org/ns/activitystreams', { 'sensitive' => 'as:sensitive' }] })\n      end\n    end\n\n    context 'when serializer has children that define context extensions' do\n      let(:serializer_class) { TestWithNestedContextExtensionSerializer }\n\n      it 'renders a @context with both extensions' do\n        expect(subject).to include({ '@context' => ['https://www.w3.org/ns/activitystreams', { 'manuallyApprovesFollowers' => 'as:manuallyApprovesFollowers', 'sensitive' => 'as:sensitive' }] })\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/lib/activitypub/linked_data_signature_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe ActivityPub::LinkedDataSignature do\n  include JsonLdHelper\n\n  let!(:sender) { Fabricate(:account, uri: 'http://example.com/alice') }\n\n  let(:raw_json) do\n    {\n      '@context' => 'https://www.w3.org/ns/activitystreams',\n      'id' => 'http://example.com/hello-world',\n    }\n  end\n\n  let(:json) { raw_json.merge('signature' => signature) }\n\n  subject { described_class.new(json) }\n\n  before do\n    stub_jsonld_contexts!\n  end\n\n  describe '#verify_account!' do\n    context 'when signature matches' do\n      let(:raw_signature) do\n        {\n          'creator' => 'http://example.com/alice',\n          'created' => '2017-09-23T20:21:34Z',\n        }\n      end\n\n      let(:signature) { raw_signature.merge('type' => 'RsaSignature2017', 'signatureValue' => sign(sender, raw_signature, raw_json)) }\n\n      it 'returns creator' do\n        expect(subject.verify_account!).to eq sender\n      end\n    end\n\n    context 'when signature is missing' do\n      let(:signature) { nil }\n\n      it 'returns nil' do\n        expect(subject.verify_account!).to be_nil\n      end\n    end\n\n    context 'when signature is tampered' do\n      let(:raw_signature) do\n        {\n          'creator' => 'http://example.com/alice',\n          'created' => '2017-09-23T20:21:34Z',\n        }\n      end\n\n      let(:signature) { raw_signature.merge('type' => 'RsaSignature2017', 'signatureValue' => 's69F3mfddd99dGjmvjdjjs81e12jn121Gkm1') }\n\n      it 'returns nil' do\n        expect(subject.verify_account!).to be_nil\n      end\n    end\n  end\n\n  describe '#sign!' do\n    subject { described_class.new(raw_json).sign!(sender) }\n\n    it 'returns a hash' do\n      expect(subject).to be_a Hash\n    end\n\n    it 'contains signature' do\n      expect(subject['signature']).to be_a Hash\n      expect(subject['signature']['signatureValue']).to be_present\n    end\n\n    it 'can be verified again' do\n      expect(described_class.new(subject).verify_account!).to eq sender\n    end\n  end\n\n  def sign(from_account, options, document)\n    options_hash   = Digest::SHA256.hexdigest(canonicalize(options.merge('@context' => ActivityPub::LinkedDataSignature::CONTEXT)))\n    document_hash  = Digest::SHA256.hexdigest(canonicalize(document))\n    to_be_verified = options_hash + document_hash\n    Base64.strict_encode64(from_account.keypair.sign(OpenSSL::Digest::SHA256.new, to_be_verified))\n  end\nend\n"
  },
  {
    "path": "spec/lib/activitypub/tag_manager_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe ActivityPub::TagManager do\n  include RoutingHelper\n\n  subject { described_class.instance }\n\n  describe '#url_for' do\n    it 'returns a string' do\n      account = Fabricate(:account)\n      expect(subject.url_for(account)).to be_a String\n    end\n  end\n\n  describe '#uri_for' do\n    it 'returns a string' do\n      account = Fabricate(:account)\n      expect(subject.uri_for(account)).to be_a String\n    end\n  end\n\n  describe '#to' do\n    it 'returns public collection for public status' do\n      status = Fabricate(:status, visibility: :public)\n      expect(subject.to(status)).to eq ['https://www.w3.org/ns/activitystreams#Public']\n    end\n\n    it 'returns followers collection for unlisted status' do\n      status = Fabricate(:status, visibility: :unlisted)\n      expect(subject.to(status)).to eq [account_followers_url(status.account)]\n    end\n\n    it 'returns followers collection for private status' do\n      status = Fabricate(:status, visibility: :private)\n      expect(subject.to(status)).to eq [account_followers_url(status.account)]\n    end\n\n    it 'returns URIs of mentions for direct status' do\n      status    = Fabricate(:status, visibility: :direct)\n      mentioned = Fabricate(:account)\n      status.mentions.create(account: mentioned)\n      expect(subject.to(status)).to eq [subject.uri_for(mentioned)]\n    end\n\n    it \"returns URIs of mentions for direct silenced author's status only if they are followers or requesting to be\" do\n      bob    = Fabricate(:account, username: 'bob')\n      alice  = Fabricate(:account, username: 'alice')\n      foo    = Fabricate(:account)\n      author = Fabricate(:account, username: 'author', silenced: true)\n      status = Fabricate(:status, visibility: :direct, account: author)\n      bob.follow!(author)\n      FollowRequest.create!(account: foo, target_account: author)\n      status.mentions.create(account: alice)\n      status.mentions.create(account: bob)\n      status.mentions.create(account: foo)\n      expect(subject.to(status)).to include(subject.uri_for(bob))\n      expect(subject.to(status)).to include(subject.uri_for(foo))\n      expect(subject.to(status)).to_not include(subject.uri_for(alice))\n    end\n  end\n\n  describe '#cc' do\n    it 'returns followers collection for public status' do\n      status = Fabricate(:status, visibility: :public)\n      expect(subject.cc(status)).to eq [account_followers_url(status.account)]\n    end\n\n    it 'returns public collection for unlisted status' do\n      status = Fabricate(:status, visibility: :unlisted)\n      expect(subject.cc(status)).to eq ['https://www.w3.org/ns/activitystreams#Public']\n    end\n\n    it 'returns empty array for private status' do\n      status = Fabricate(:status, visibility: :private)\n      expect(subject.cc(status)).to eq []\n    end\n\n    it 'returns empty array for direct status' do\n      status = Fabricate(:status, visibility: :direct)\n      expect(subject.cc(status)).to eq []\n    end\n\n    it 'returns URIs of mentions for non-direct status' do\n      status    = Fabricate(:status, visibility: :public)\n      mentioned = Fabricate(:account)\n      status.mentions.create(account: mentioned)\n      expect(subject.cc(status)).to include(subject.uri_for(mentioned))\n    end\n\n    it \"returns URIs of mentions for silenced author's non-direct status only if they are followers or requesting to be\" do\n      bob    = Fabricate(:account, username: 'bob')\n      alice  = Fabricate(:account, username: 'alice')\n      foo    = Fabricate(:account)\n      author = Fabricate(:account, username: 'author', silenced: true)\n      status = Fabricate(:status, visibility: :public, account: author)\n      bob.follow!(author)\n      FollowRequest.create!(account: foo, target_account: author)\n      status.mentions.create(account: alice)\n      status.mentions.create(account: bob)\n      status.mentions.create(account: foo)\n      expect(subject.cc(status)).to include(subject.uri_for(bob))\n      expect(subject.cc(status)).to include(subject.uri_for(foo))\n      expect(subject.cc(status)).to_not include(subject.uri_for(alice))\n    end\n  end\n\n  describe '#local_uri?' do\n    it 'returns false for non-local URI' do\n      expect(subject.local_uri?('http://example.com/123')).to be false\n    end\n\n    it 'returns true for local URIs' do\n      account = Fabricate(:account)\n      expect(subject.local_uri?(subject.uri_for(account))).to be true\n    end\n  end\n\n  describe '#uri_to_local_id' do\n    it 'returns the local ID' do\n      account = Fabricate(:account)\n      expect(subject.uri_to_local_id(subject.uri_for(account), :username)).to eq account.username\n    end\n  end\n\n  describe '#uri_to_resource' do\n    it 'returns the local account' do\n      account = Fabricate(:account)\n      expect(subject.uri_to_resource(subject.uri_for(account), Account)).to eq account\n    end\n\n    it 'returns the remote account by matching URI without fragment part' do\n      account = Fabricate(:account, uri: 'https://example.com/123')\n      expect(subject.uri_to_resource('https://example.com/123#456', Account)).to eq account\n    end\n\n    it 'returns the local status for ActivityPub URI' do\n      status = Fabricate(:status)\n      expect(subject.uri_to_resource(subject.uri_for(status), Status)).to eq status\n    end\n\n    it 'returns the local status for OStatus tag: URI' do\n      status = Fabricate(:status)\n      expect(subject.uri_to_resource(OStatus::TagManager.instance.uri_for(status), Status)).to eq status\n    end\n\n    it 'returns the local status for OStatus StreamEntry URL' do\n      status = Fabricate(:status)\n      stream_entry_url = account_stream_entry_url(status.account, status.stream_entry)\n      expect(subject.uri_to_resource(stream_entry_url, Status)).to eq status\n    end\n\n    it 'returns the remote status by matching URI without fragment part' do\n      status = Fabricate(:status, uri: 'https://example.com/123')\n      expect(subject.uri_to_resource('https://example.com/123#456', Status)).to eq status\n    end\n  end\nend\n"
  },
  {
    "path": "spec/lib/delivery_failure_tracker_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe DeliveryFailureTracker do\n  subject { described_class.new('http://example.com/inbox') }\n\n  describe '#track_success!' do\n    before do\n      subject.track_failure!\n      subject.track_success!\n    end\n\n    it 'marks URL as available again' do\n      expect(described_class.available?('http://example.com/inbox')).to be true\n    end\n\n    it 'resets days to 0' do\n      expect(subject.days).to be_zero\n    end\n  end\n\n  describe '#track_failure!' do\n    it 'marks URL as unavailable after 7 days of being called' do\n      6.times { |i| Redis.current.sadd('exhausted_deliveries:http://example.com/inbox', i) }\n      subject.track_failure!\n\n      expect(subject.days).to eq 7\n      expect(described_class.unavailable?('http://example.com/inbox')).to be true\n    end\n\n    it 'repeated calls on the same day do not count' do\n      subject.track_failure!\n      subject.track_failure!\n\n      expect(subject.days).to eq 1\n    end\n  end\n\n  describe '.filter' do\n    before do\n      Redis.current.sadd('unavailable_inboxes', 'http://example.com/unavailable/inbox')\n    end\n\n    it 'removes URLs that are unavailable' do\n      result = described_class.filter(['http://example.com/good/inbox', 'http://example.com/unavailable/inbox'])\n\n      expect(result).to include('http://example.com/good/inbox')\n      expect(result).to_not include('http://example.com/unavailable/inbox')\n    end\n  end\n\n  describe '.track_inverse_success!' do\n    let(:from_account) { Fabricate(:account, inbox_url: 'http://example.com/inbox', shared_inbox_url: 'http://example.com/shared/inbox') }\n\n    before do\n      Redis.current.sadd('unavailable_inboxes', 'http://example.com/inbox')\n      Redis.current.sadd('unavailable_inboxes', 'http://example.com/shared/inbox')\n\n      described_class.track_inverse_success!(from_account)\n    end\n\n    it 'marks inbox URL as available again' do\n      expect(described_class.available?('http://example.com/inbox')).to be true\n    end\n\n    it 'marks shared inbox URL as available again' do\n      expect(described_class.available?('http://example.com/shared/inbox')).to be true\n    end\n  end\nend\n"
  },
  {
    "path": "spec/lib/extractor_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe Extractor do\n  describe 'extract_mentions_or_lists_with_indices' do\n    it 'returns an empty array if the given string does not have at signs' do\n      text = 'a string without at signs'\n      extracted = Extractor.extract_mentions_or_lists_with_indices(text)\n      expect(extracted).to eq []\n    end\n\n    it 'does not extract mentions which ends with particular characters' do\n      text = '@screen_name@'\n      extracted = Extractor.extract_mentions_or_lists_with_indices(text)\n      expect(extracted).to eq []\n    end\n\n    it 'returns mentions as an array' do\n      text = '@screen_name'\n      extracted = Extractor.extract_mentions_or_lists_with_indices(text)\n      expect(extracted).to eq [\n        { screen_name: 'screen_name', indices: [ 0, 12 ] }\n      ]\n    end\n\n    it 'yields mentions if a block is given' do\n      text = '@screen_name'\n      Extractor.extract_mentions_or_lists_with_indices(text) do |screen_name, start_position, end_position|\n        expect(screen_name).to eq 'screen_name'\n        expect(start_position).to eq 0\n        expect(end_position).to eq 12\n      end\n    end\n  end\n\n  describe 'extract_hashtags_with_indices' do\n    it 'returns an empty array if it does not have #' do\n      text = 'a string without hash sign'\n      extracted = Extractor.extract_hashtags_with_indices(text)\n      expect(extracted).to eq []\n    end\n\n    it 'does not exclude normal hash text before ://' do\n      text = '#hashtag://'\n      extracted = Extractor.extract_hashtags_with_indices(text)\n      expect(extracted).to eq [ { hashtag: 'hashtag', indices: [ 0, 8 ] } ]\n    end\n\n    it 'excludes http://' do\n      text = '#hashtaghttp://'\n      extracted = Extractor.extract_hashtags_with_indices(text)\n      expect(extracted).to eq [ { hashtag: 'hashtag', indices: [ 0, 8 ] } ]\n    end\n\n    it 'excludes https://' do\n      text = '#hashtaghttps://'\n      extracted = Extractor.extract_hashtags_with_indices(text)\n      expect(extracted).to eq [ { hashtag: 'hashtag', indices: [ 0, 8 ] } ]\n    end\n\n    it 'yields hashtags if a block is given' do\n      text = '#hashtag'\n      Extractor.extract_hashtags_with_indices(text) do |hashtag, start_position, end_position|\n        expect(hashtag).to eq 'hashtag'\n        expect(start_position).to eq 0\n        expect(end_position).to eq 8\n      end\n    end\n  end\n\n  describe 'extract_cashtags_with_indices' do\n    it 'returns []' do\n      text = '$cashtag'\n      extracted = Extractor.extract_cashtags_with_indices(text)\n      expect(extracted).to eq []\n    end\n  end\nend\n"
  },
  {
    "path": "spec/lib/feed_manager_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe FeedManager do\n  before do |example|\n    unless example.metadata[:skip_stub]\n      stub_const 'FeedManager::MAX_ITEMS', 10\n      stub_const 'FeedManager::REBLOG_FALLOFF', 4\n    end\n  end\n\n  it 'tracks at least as many statuses as reblogs', skip_stub: true do\n    expect(FeedManager::REBLOG_FALLOFF).to be <= FeedManager::MAX_ITEMS\n  end\n\n  describe '#key' do\n    subject { FeedManager.instance.key(:home, 1) }\n\n    it 'returns a string' do\n      expect(subject).to be_a String\n    end\n  end\n\n  describe '#filter?' do\n    let(:alice) { Fabricate(:account, username: 'alice') }\n    let(:bob)   { Fabricate(:account, username: 'bob', domain: 'example.com') }\n    let(:jeff)  { Fabricate(:account, username: 'jeff') }\n\n    context 'for home feed' do\n      it 'returns false for followee\\'s status' do\n        status = Fabricate(:status, text: 'Hello world', account: alice)\n        bob.follow!(alice)\n        expect(FeedManager.instance.filter?(:home, status, bob.id)).to be false\n      end\n\n      it 'returns false for reblog by followee' do\n        status = Fabricate(:status, text: 'Hello world', account: jeff)\n        reblog = Fabricate(:status, reblog: status, account: alice)\n        bob.follow!(alice)\n        expect(FeedManager.instance.filter?(:home, reblog, bob.id)).to be false\n      end\n\n      it 'returns true for reblog by followee of blocked account' do\n        status = Fabricate(:status, text: 'Hello world', account: jeff)\n        reblog = Fabricate(:status, reblog: status, account: alice)\n        bob.follow!(alice)\n        bob.block!(jeff)\n        expect(FeedManager.instance.filter?(:home, reblog, bob.id)).to be true\n      end\n\n      it 'returns true for reblog by followee of muted account' do\n        status = Fabricate(:status, text: 'Hello world', account: jeff)\n        reblog = Fabricate(:status, reblog: status, account: alice)\n        bob.follow!(alice)\n        bob.mute!(jeff)\n        expect(FeedManager.instance.filter?(:home, reblog, bob.id)).to be true\n      end\n\n      it 'returns true for reblog by followee of someone who is blocking recipient' do\n        status = Fabricate(:status, text: 'Hello world', account: jeff)\n        reblog = Fabricate(:status, reblog: status, account: alice)\n        bob.follow!(alice)\n        jeff.block!(bob)\n        expect(FeedManager.instance.filter?(:home, reblog, bob.id)).to be true\n      end\n\n      it 'returns true for reblog from account with reblogs disabled' do\n        status = Fabricate(:status, text: 'Hello world', account: jeff)\n        reblog = Fabricate(:status, reblog: status, account: alice)\n        bob.follow!(alice, reblogs: false)\n        expect(FeedManager.instance.filter?(:home, reblog, bob.id)).to be true\n      end\n\n      it 'returns false for reply by followee to another followee' do\n        status = Fabricate(:status, text: 'Hello world', account: jeff)\n        reply  = Fabricate(:status, text: 'Nay', thread: status, account: alice)\n        bob.follow!(alice)\n        bob.follow!(jeff)\n        expect(FeedManager.instance.filter?(:home, reply, bob.id)).to be false\n      end\n\n      it 'returns false for reply by followee to recipient' do\n        status = Fabricate(:status, text: 'Hello world', account: bob)\n        reply  = Fabricate(:status, text: 'Nay', thread: status, account: alice)\n        bob.follow!(alice)\n        expect(FeedManager.instance.filter?(:home, reply, bob.id)).to be false\n      end\n\n      it 'returns false for reply by followee to self' do\n        status = Fabricate(:status, text: 'Hello world', account: alice)\n        reply  = Fabricate(:status, text: 'Nay', thread: status, account: alice)\n        bob.follow!(alice)\n        expect(FeedManager.instance.filter?(:home, reply, bob.id)).to be false\n      end\n\n      it 'returns true for reply by followee to non-followed account' do\n        status = Fabricate(:status, text: 'Hello world', account: jeff)\n        reply  = Fabricate(:status, text: 'Nay', thread: status, account: alice)\n        bob.follow!(alice)\n        expect(FeedManager.instance.filter?(:home, reply, bob.id)).to be true\n      end\n\n      it 'returns true for the second reply by followee to a non-federated status' do\n        reply        = Fabricate(:status, text: 'Reply 1', reply: true, account: alice)\n        second_reply = Fabricate(:status, text: 'Reply 2', thread: reply, account: alice)\n        bob.follow!(alice)\n        expect(FeedManager.instance.filter?(:home, second_reply, bob.id)).to be true\n      end\n\n      it 'returns false for status by followee mentioning another account' do\n        bob.follow!(alice)\n        status = PostStatusService.new.call(alice, text: 'Hey @jeff')\n        expect(FeedManager.instance.filter?(:home, status, bob.id)).to be false\n      end\n\n      it 'returns true for status by followee mentioning blocked account' do\n        bob.block!(jeff)\n        bob.follow!(alice)\n        status = PostStatusService.new.call(alice, text: 'Hey @jeff')\n        expect(FeedManager.instance.filter?(:home, status, bob.id)).to be true\n      end\n\n      it 'returns true for reblog of a personally blocked domain' do\n        alice.block_domain!('example.com')\n        alice.follow!(jeff)\n        status = Fabricate(:status, text: 'Hello world', account: bob)\n        reblog = Fabricate(:status, reblog: status, account: jeff)\n        expect(FeedManager.instance.filter?(:home, reblog, alice.id)).to be true\n      end\n\n      context 'for irreversibly muted phrases' do\n        it 'considers word boundaries when matching' do\n          alice.custom_filters.create!(phrase: 'bob', context: %w(home), irreversible: true)\n          alice.follow!(jeff)\n          status = Fabricate(:status, text: 'bobcats', account: jeff)\n          expect(FeedManager.instance.filter?(:home, status, alice.id)).to be_falsy\n        end\n\n        it 'returns true if phrase is contained' do\n          alice.custom_filters.create!(phrase: 'farts', context: %w(home public), irreversible: true)\n          alice.custom_filters.create!(phrase: 'pop tarts', context: %w(home), irreversible: true)\n          alice.follow!(jeff)\n          status = Fabricate(:status, text: 'i sure like POP TARts', account: jeff)\n          expect(FeedManager.instance.filter?(:home, status, alice.id)).to be true\n        end\n\n        it 'matches substrings if whole_word is false' do\n          alice.custom_filters.create!(phrase: 'take', context: %w(home), whole_word: false, irreversible: true)\n          alice.follow!(jeff)\n          status = Fabricate(:status, text: 'shiitake', account: jeff)\n          expect(FeedManager.instance.filter?(:home, status, alice.id)).to be true\n        end\n      end\n    end\n\n    context 'for mentions feed' do\n      it 'returns true for status that mentions blocked account' do\n        bob.block!(jeff)\n        status = PostStatusService.new.call(alice, text: 'Hey @jeff')\n        expect(FeedManager.instance.filter?(:mentions, status, bob.id)).to be true\n      end\n\n      it 'returns true for status that replies to a blocked account' do\n        status = Fabricate(:status, text: 'Hello world', account: jeff)\n        reply  = Fabricate(:status, text: 'Nay', thread: status, account: alice)\n        bob.block!(jeff)\n        expect(FeedManager.instance.filter?(:mentions, reply, bob.id)).to be true\n      end\n\n      it 'returns true for status by silenced account who recipient is not following' do\n        status = Fabricate(:status, text: 'Hello world', account: alice)\n        alice.silence!\n        expect(FeedManager.instance.filter?(:mentions, status, bob.id)).to be true\n      end\n\n      it 'returns false for status by followed silenced account' do\n        status = Fabricate(:status, text: 'Hello world', account: alice)\n        alice.silence!\n        bob.follow!(alice)\n        expect(FeedManager.instance.filter?(:mentions, status, bob.id)).to be false\n      end\n    end\n  end\n\n  describe '#push_to_home' do\n    it 'trims timelines if they will have more than FeedManager::MAX_ITEMS' do\n      account = Fabricate(:account)\n      status = Fabricate(:status)\n      members = FeedManager::MAX_ITEMS.times.map { |count| [count, count] }\n      Redis.current.zadd(\"feed:home:#{account.id}\", members)\n\n      FeedManager.instance.push_to_home(account, status)\n\n      expect(Redis.current.zcard(\"feed:home:#{account.id}\")).to eq FeedManager::MAX_ITEMS\n    end\n\n    context 'reblogs' do\n      it 'saves reblogs of unseen statuses' do\n        account = Fabricate(:account)\n        reblogged = Fabricate(:status)\n        reblog = Fabricate(:status, reblog: reblogged)\n\n        expect(FeedManager.instance.push_to_home(account, reblog)).to be true\n      end\n\n      it 'does not save a new reblog of a recent status' do\n        account = Fabricate(:account)\n        reblogged = Fabricate(:status)\n        reblog = Fabricate(:status, reblog: reblogged)\n\n        FeedManager.instance.push_to_home(account, reblogged)\n\n        expect(FeedManager.instance.push_to_home(account, reblog)).to be false\n      end\n\n      it 'saves a new reblog of an old status' do\n        account = Fabricate(:account)\n        reblogged = Fabricate(:status)\n        reblog = Fabricate(:status, reblog: reblogged)\n\n        FeedManager.instance.push_to_home(account, reblogged)\n\n        # Fill the feed with intervening statuses\n        FeedManager::REBLOG_FALLOFF.times do\n          FeedManager.instance.push_to_home(account, Fabricate(:status))\n        end\n\n        expect(FeedManager.instance.push_to_home(account, reblog)).to be true\n      end\n\n      it 'does not save a new reblog of a recently-reblogged status' do\n        account = Fabricate(:account)\n        reblogged = Fabricate(:status)\n        reblogs = 2.times.map { Fabricate(:status, reblog: reblogged) }\n\n        # The first reblog will be accepted\n        FeedManager.instance.push_to_home(account, reblogs.first)\n\n        # The second reblog should be ignored\n        expect(FeedManager.instance.push_to_home(account, reblogs.last)).to be false\n      end\n\n      it 'does not save a new reblog of a multiply-reblogged-then-unreblogged status' do\n        account   = Fabricate(:account)\n        reblogged = Fabricate(:status)\n        reblogs = 3.times.map { Fabricate(:status, reblog: reblogged) }\n\n        # Accept the reblogs\n        FeedManager.instance.push_to_home(account, reblogs[0])\n        FeedManager.instance.push_to_home(account, reblogs[1])\n\n        # Unreblog the first one\n        FeedManager.instance.unpush_from_home(account, reblogs[0])\n\n        # The last reblog should still be ignored\n        expect(FeedManager.instance.push_to_home(account, reblogs.last)).to be false\n      end\n\n      it 'saves a new reblog of a long-ago-reblogged status' do\n        account = Fabricate(:account)\n        reblogged = Fabricate(:status)\n        reblogs = 2.times.map { Fabricate(:status, reblog: reblogged) }\n\n        # The first reblog will be accepted\n        FeedManager.instance.push_to_home(account, reblogs.first)\n\n        # Fill the feed with intervening statuses\n        FeedManager::REBLOG_FALLOFF.times do\n          FeedManager.instance.push_to_home(account, Fabricate(:status))\n        end\n\n        # The second reblog should also be accepted\n        expect(FeedManager.instance.push_to_home(account, reblogs.last)).to be true\n      end\n    end\n\n    it \"does not push when the given status's reblog is already inserted\" do\n      account = Fabricate(:account)\n      reblog = Fabricate(:status)\n      status = Fabricate(:status, reblog: reblog)\n      FeedManager.instance.push_to_home(account, status)\n\n      expect(FeedManager.instance.push_to_home(account, reblog)).to eq false\n    end\n  end\n\n  describe '#push_to_list' do\n    it \"does not push when the given status's reblog is already inserted\" do\n      list = Fabricate(:list)\n      reblog = Fabricate(:status)\n      status = Fabricate(:status, reblog: reblog)\n      FeedManager.instance.push_to_list(list, status)\n\n      expect(FeedManager.instance.push_to_list(list, reblog)).to eq false\n    end\n  end\n\n  describe '#merge_into_timeline' do\n    it \"does not push source account's statuses whose reblogs are already inserted\" do\n      account = Fabricate(:account, id: 0)\n      reblog = Fabricate(:status)\n      status = Fabricate(:status, reblog: reblog)\n      FeedManager.instance.push_to_home(account, status)\n\n      FeedManager.instance.merge_into_timeline(account, reblog.account)\n\n      expect(Redis.current.zscore(\"feed:home:0\", reblog.id)).to eq nil\n    end\n\n    it \"does not push direct messages into home timeline if the user has home_dms false\" do\n      status    = Fabricate(:status, visibility: :direct)\n      mentioned = Fabricate(:account, id: 1)\n      mentioned.user = Fabricate(:user)\n      mentioned.user.settings.home_dms = false\n      status.mentions.create(account: mentioned)\n\n      FeedManager.instance.merge_into_timeline(status.account, mentioned)\n      expect(Redis.current.zscore(\"feed:home:1\",status.id)).to be_nil\n    end\n\n    it \"pushes direct messages into home timeline if the user has home_dms true\" do\n      status    = Fabricate(:status, visibility: :direct)\n      mentioned = Fabricate(:account, id: 1)\n      mentioned.user = Fabricate(:user)\n      mentioned.user.settings.home_dms = true\n      status.mentions.create(account: mentioned)\n\n      FeedManager.instance.merge_into_timeline(status.account, mentioned)\n      expect(Redis.current.zscore(\"feed:home:1\",status.id)).to_not be_nil\n    end\n  end\n\n  describe '#trim' do\n    let(:receiver) { Fabricate(:account) }\n\n    it 'cleans up reblog tracking keys' do\n      reblogged      = Fabricate(:status)\n      status         = Fabricate(:status, reblog: reblogged)\n      another_status = Fabricate(:status, reblog: reblogged)\n      reblogs_key    = FeedManager.instance.key('home', receiver.id, 'reblogs')\n      reblog_set_key = FeedManager.instance.key('home', receiver.id, \"reblogs:#{reblogged.id}\")\n\n      FeedManager.instance.push_to_home(receiver, status)\n      FeedManager.instance.push_to_home(receiver, another_status)\n\n      # We should have a tracking set and an entry in reblogs.\n      expect(Redis.current.exists(reblog_set_key)).to be true\n      expect(Redis.current.zrange(reblogs_key, 0, -1)).to eq [reblogged.id.to_s]\n\n      # Push everything off the end of the feed.\n      FeedManager::MAX_ITEMS.times do\n        FeedManager.instance.push_to_home(receiver, Fabricate(:status))\n      end\n\n      # `trim` should be called automatically, but do it anyway, as\n      # we're testing `trim`, not side effects of `push`.\n      FeedManager.instance.trim('home', receiver.id)\n\n      # We should not have any reblog tracking data.\n      expect(Redis.current.exists(reblog_set_key)).to be false\n      expect(Redis.current.zrange(reblogs_key, 0, -1)).to be_empty\n    end\n  end\n\n  describe '#unpush' do\n    let(:receiver) { Fabricate(:account) }\n\n    it 'leaves a reblogged status if original was on feed' do\n      reblogged = Fabricate(:status)\n      status    = Fabricate(:status, reblog: reblogged)\n\n      FeedManager.instance.push_to_home(receiver, reblogged)\n      FeedManager::REBLOG_FALLOFF.times { FeedManager.instance.push_to_home(receiver, Fabricate(:status)) }\n      FeedManager.instance.push_to_home(receiver, status)\n\n      # The reblogging status should show up under normal conditions.\n      expect(Redis.current.zrange(\"feed:home:#{receiver.id}\", 0, -1)).to include(status.id.to_s)\n\n      FeedManager.instance.unpush_from_home(receiver, status)\n\n      # Restore original status\n      expect(Redis.current.zrange(\"feed:home:#{receiver.id}\", 0, -1)).to_not include(status.id.to_s)\n      expect(Redis.current.zrange(\"feed:home:#{receiver.id}\", 0, -1)).to include(reblogged.id.to_s)\n    end\n\n    it 'removes a reblogged status if it was only reblogged once' do\n      reblogged = Fabricate(:status)\n      status    = Fabricate(:status, reblog: reblogged)\n\n      FeedManager.instance.push_to_home(receiver, status)\n\n      # The reblogging status should show up under normal conditions.\n      expect(Redis.current.zrange(\"feed:home:#{receiver.id}\", 0, -1)).to eq [status.id.to_s]\n\n      FeedManager.instance.unpush_from_home(receiver, status)\n\n      expect(Redis.current.zrange(\"feed:home:#{receiver.id}\", 0, -1)).to be_empty\n    end\n\n    it 'leaves a multiply-reblogged status if another reblog was in feed' do\n      reblogged = Fabricate(:status)\n      reblogs   = 3.times.map { Fabricate(:status, reblog: reblogged) }\n\n      reblogs.each do |reblog|\n        FeedManager.instance.push_to_home(receiver, reblog)\n      end\n\n      # The reblogging status should show up under normal conditions.\n      expect(Redis.current.zrange(\"feed:home:#{receiver.id}\", 0, -1)).to eq [reblogs.first.id.to_s]\n\n      reblogs[0...-1].each do |reblog|\n        FeedManager.instance.unpush_from_home(receiver, reblog)\n      end\n\n      expect(Redis.current.zrange(\"feed:home:#{receiver.id}\", 0, -1)).to eq [reblogs.last.id.to_s]\n    end\n\n    it 'sends push updates' do\n      status = Fabricate(:status)\n\n      FeedManager.instance.push_to_home(receiver, status)\n\n      allow(Redis.current).to receive_messages(publish: nil)\n      FeedManager.instance.unpush_from_home(receiver, status)\n\n      deletion = Oj.dump(event: :delete, payload: status.id.to_s)\n      expect(Redis.current).to have_received(:publish).with(\"timeline:#{receiver.id}\", deletion)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/lib/formatter_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Formatter do\n  let(:local_account)  { Fabricate(:account, domain: nil, username: 'alice') }\n  let(:remote_account) { Fabricate(:account, domain: 'remote.test', username: 'bob', url: 'https://remote.test/') }\n\n  shared_examples 'encode and link URLs' do\n    context 'given a stand-alone medium URL' do\n      let(:text) { 'https://hackernoon.com/the-power-to-build-communities-a-response-to-mark-zuckerberg-3f2cac9148a4' }\n\n      it 'matches the full URL' do\n        is_expected.to include 'href=\"https://hackernoon.com/the-power-to-build-communities-a-response-to-mark-zuckerberg-3f2cac9148a4\"'\n      end\n    end\n\n    context 'given a stand-alone google URL' do\n      let(:text) { 'http://google.com' }\n\n      it 'matches the full URL' do\n        is_expected.to include 'href=\"http://google.com\"'\n      end\n    end\n\n    context 'given a stand-alone IDN URL' do\n      let(:text) { 'https://nic.みんな/' }\n\n      it 'matches the full URL' do\n        is_expected.to include 'href=\"https://nic.みんな/\"'\n      end\n\n      it 'has display URL' do\n        is_expected.to include '<span class=\"\">nic.みんな/</span>'\n      end\n    end\n\n    context 'given a URL with a trailing period' do\n      let(:text) { 'http://www.mcmansionhell.com/post/156408871451/50-states-of-mcmansion-hell-scottsdale-arizona. ' }\n\n      it 'matches the full URL but not the period' do\n        is_expected.to include 'href=\"http://www.mcmansionhell.com/post/156408871451/50-states-of-mcmansion-hell-scottsdale-arizona\"'\n      end\n    end\n\n    context 'given a URL enclosed with parentheses' do\n      let(:text) { '(http://google.com/)' }\n\n      it 'matches the full URL but not the parentheses' do\n        is_expected.to include 'href=\"http://google.com/\"'\n      end\n    end\n\n    context 'given a URL with a trailing exclamation point' do\n      let(:text) { 'http://www.google.com!' }\n\n      it 'matches the full URL but not the exclamation point' do\n        is_expected.to include 'href=\"http://www.google.com\"'\n      end\n    end\n\n    context 'given a URL with a trailing single quote' do\n      let(:text) { \"http://www.google.com'\" }\n\n      it 'matches the full URL but not the single quote' do\n        is_expected.to include 'href=\"http://www.google.com\"'\n      end\n    end\n\n    context 'given a URL with a trailing angle bracket' do\n      let(:text) { 'http://www.google.com>' }\n\n      it 'matches the full URL but not the angle bracket' do\n        is_expected.to include 'href=\"http://www.google.com\"'\n      end\n    end\n\n    context 'given a URL with a query string' do\n      context 'with escaped unicode character' do\n        let(:text) { 'https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&q=autolink' }\n\n        it 'matches the full URL' do\n          is_expected.to include 'href=\"https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&amp;q=autolink\"'\n        end\n      end\n\n      context 'with unicode character' do\n        let(:text) { 'https://www.ruby-toolbox.com/search?utf8=✓&q=autolink' }\n\n        it 'matches the full URL' do\n          is_expected.to include 'href=\"https://www.ruby-toolbox.com/search?utf8=✓&amp;q=autolink\"'\n        end\n      end\n\n      context 'with unicode character at the end' do\n        let(:text) { 'https://www.ruby-toolbox.com/search?utf8=✓' }\n\n        it 'matches the full URL' do\n          is_expected.to include 'href=\"https://www.ruby-toolbox.com/search?utf8=✓\"'\n        end\n      end\n\n      context 'with escaped and not escaped unicode characters' do\n        let(:text) { 'https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&utf81=✓&q=autolink' }\n\n        it 'preserves escaped unicode characters' do\n          is_expected.to include 'href=\"https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&amp;utf81=✓&amp;q=autolink\"'\n        end\n      end\n    end\n\n    context 'given a URL with parentheses in it' do\n      let(:text) { 'https://en.wikipedia.org/wiki/Diaspora_(software)' }\n\n      it 'matches the full URL' do\n        is_expected.to include 'href=\"https://en.wikipedia.org/wiki/Diaspora_(software)\"'\n      end\n    end\n\n    context 'given a URL in quotation marks' do\n      let(:text) { '\"https://example.com/\"' }\n\n      it 'does not match the quotation marks' do\n        is_expected.to include 'href=\"https://example.com/\"'\n      end\n    end\n\n    context 'given a URL in angle brackets' do\n      let(:text) { '<https://example.com/>' }\n\n      it 'does not match the angle brackets' do\n        is_expected.to include 'href=\"https://example.com/\"'\n      end\n    end\n\n    context 'given a URL with Japanese path string' do\n      let(:text) { 'https://ja.wikipedia.org/wiki/日本' }\n\n      it 'matches the full URL' do\n        is_expected.to include 'href=\"https://ja.wikipedia.org/wiki/日本\"'\n      end\n    end\n\n    context 'given a URL with Korean path string' do\n      let(:text) { 'https://ko.wikipedia.org/wiki/대한민국' }\n\n      it 'matches the full URL' do\n        is_expected.to include 'href=\"https://ko.wikipedia.org/wiki/대한민국\"'\n      end\n    end\n\n    context 'given a URL with a full-width space' do\n      let(:text) { 'https://example.com/　abc123' }\n\n      it 'does not match the full-width space' do\n        is_expected.to include 'href=\"https://example.com/\"'\n      end\n    end\n\n    context 'given a URL in Japanese quotation marks' do\n      let(:text) { '「[https://example.org/」' }\n\n      it 'does not match the quotation marks' do\n        is_expected.to include 'href=\"https://example.org/\"'\n      end\n    end\n\n    context 'given a URL with Simplified Chinese path string' do\n      let(:text) { 'https://baike.baidu.com/item/中华人民共和国' }\n\n      it 'matches the full URL' do\n        is_expected.to include 'href=\"https://baike.baidu.com/item/中华人民共和国\"'\n      end\n    end\n\n    context 'given a URL with Traditional Chinese path string' do\n      let(:text) { 'https://zh.wikipedia.org/wiki/臺灣' }\n\n      it 'matches the full URL' do\n        is_expected.to include 'href=\"https://zh.wikipedia.org/wiki/臺灣\"'\n      end\n    end\n\n    context 'given a URL containing unsafe code (XSS attack, visible part)' do\n      let(:text) { %q{http://example.com/b<del>b</del>} }\n\n      it 'does not include the HTML in the URL' do\n        is_expected.to include '\"http://example.com/b\"'\n      end\n\n      it 'escapes the HTML' do\n        is_expected.to include '&lt;del&gt;b&lt;/del&gt;'\n      end\n    end\n\n    context 'given a URL containing unsafe code (XSS attack, invisible part)' do\n      let(:text) { %q{http://example.com/blahblahblahblah/a<script>alert(\"Hello\")</script>} }\n\n      it 'does not include the HTML in the URL' do\n        is_expected.to include '\"http://example.com/blahblahblahblah/a\"'\n      end\n\n      it 'escapes the HTML' do\n        is_expected.to include '&lt;script&gt;alert(&quot;Hello&quot;)&lt;/script&gt;'\n      end\n    end\n\n    context 'given text containing HTML code (script tag)' do\n      let(:text) { '<script>alert(\"Hello\")</script>' }\n\n      it 'escapes the HTML' do\n        is_expected.to include '<p>&lt;script&gt;alert(&quot;Hello&quot;)&lt;/script&gt;</p>'\n      end\n    end\n\n    context 'given text containing HTML (XSS attack)' do\n      let(:text) { %q{<img src=\"javascript:alert('XSS');\">} }\n\n      it 'escapes the HTML' do\n        is_expected.to include '<p>&lt;img src=&quot;javascript:alert(&apos;XSS&apos;);&quot;&gt;</p>'\n      end\n    end\n\n    context 'given an invalid URL' do\n      let(:text) { 'http://www\\.google\\.com' }\n\n      it 'outputs the raw URL' do\n        is_expected.to eq '<p>http://www\\.google\\.com</p>'\n      end\n    end\n\n    context 'given text containing a hashtag' do\n      let(:text)  { '#hashtag' }\n\n      it 'creates a hashtag link' do\n        is_expected.to include '/tags/hashtag\" class=\"mention hashtag\" rel=\"tag\">#<span>hashtag</span></a>'\n      end\n    end\n\n    context 'given text containing a hashtag with Unicode chars' do\n      let(:text)  { '#hashtagタグ' }\n\n      it 'creates a hashtag link' do\n        is_expected.to include '/tags/hashtag%E3%82%BF%E3%82%B0\" class=\"mention hashtag\" rel=\"tag\">#<span>hashtagタグ</span></a>'\n      end\n    end\n  end\n\n  describe '#format_spoiler' do\n    subject { Formatter.instance.format_spoiler(status) }\n\n    context 'given a post containing plain text' do\n      let(:status) { Fabricate(:status, text: 'text', spoiler_text: 'Secret!', uri: nil) }\n\n      it 'Returns the spoiler text' do\n        is_expected.to eq 'Secret!'\n      end\n    end\n\n    context 'given a post with an emoji shortcode at the start' do\n      let!(:emoji) { Fabricate(:custom_emoji) }\n      let(:status) { Fabricate(:status, text: 'text', spoiler_text: ':coolcat: Secret!', uri: nil) }\n      let(:text) { ':coolcat: Beep boop' }\n\n      it 'converts the shortcode to an image tag' do\n        is_expected.to match(/<img draggable=\"false\" class=\"emojione\" alt=\":coolcat:\"/)\n      end\n    end\n  end\n\n  describe '#format' do\n    subject { Formatter.instance.format(status) }\n\n    context 'given a post with local status' do\n      context 'given a reblogged post' do\n        let(:reblog) { Fabricate(:status, account: local_account, text: 'Hello world', uri: nil) }\n        let(:status) { Fabricate(:status, reblog: reblog) }\n\n        it 'returns original status with credit to its author' do\n          is_expected.to include 'RT <span class=\"h-card\"><a href=\"https://cb6e6126.ngrok.io/@alice\" class=\"u-url mention\">@<span>alice</span></a></span> Hello world'\n        end\n      end\n\n      context 'given a post containing plain text' do\n        let(:status) { Fabricate(:status, text: 'text', uri: nil) }\n\n        it 'paragraphizes the text' do\n          is_expected.to eq '<p>text</p>'\n        end\n      end\n\n      context 'given a post containing line feeds' do\n        let(:status) { Fabricate(:status, text: \"line\\nfeed\", uri: nil) }\n\n        it 'removes line feeds' do\n          is_expected.not_to include \"\\n\"\n        end\n      end\n\n      context 'given a post containing linkable mentions' do\n        let(:status) { Fabricate(:status, mentions: [ Fabricate(:mention, account: local_account) ], text: '@alice') }\n\n        it 'creates a mention link' do\n          is_expected.to include '<a href=\"https://cb6e6126.ngrok.io/@alice\" class=\"u-url mention\">@<span>alice</span></a></span>'\n        end\n      end\n\n      context 'given a post containing unlinkable mentions' do\n        let(:status) { Fabricate(:status, text: '@alice', uri: nil) }\n\n        it 'does not create a mention link' do\n          is_expected.to include '@alice'\n        end\n      end\n\n      context do\n        subject do\n          status = Fabricate(:status, text: text, uri: nil)\n          Formatter.instance.format(status)\n        end\n\n        include_examples 'encode and link URLs'\n      end\n\n      context 'given a post with custom_emojify option' do\n        let!(:emoji) { Fabricate(:custom_emoji) }\n        let(:status) { Fabricate(:status, account: local_account, text: text) }\n\n        subject { Formatter.instance.format(status, custom_emojify: true) }\n\n        context 'given a post with an emoji shortcode at the start' do\n          let(:text) { ':coolcat: Beep boop' }\n\n          it 'converts the shortcode to an image tag' do\n            is_expected.to match(/<p><img draggable=\"false\" class=\"emojione\" alt=\":coolcat:\"/)\n          end\n        end\n\n        context 'given a post with an emoji shortcode in the middle' do\n          let(:text) { 'Beep :coolcat: boop' }\n\n          it 'converts the shortcode to an image tag' do\n            is_expected.to match(/Beep <img draggable=\"false\" class=\"emojione\" alt=\":coolcat:\"/)\n          end\n        end\n\n        context 'given a post with concatenated emoji shortcodes' do\n          let(:text) { ':coolcat::coolcat:' }\n\n          it 'does not touch the shortcodes' do\n            is_expected.to match(/:coolcat::coolcat:/)\n          end\n        end\n\n        context 'given a post with an emoji shortcode at the end' do\n          let(:text) { 'Beep boop :coolcat:' }\n\n          it 'converts the shortcode to an image tag' do\n            is_expected.to match(/boop <img draggable=\"false\" class=\"emojione\" alt=\":coolcat:\"/)\n          end\n        end\n      end\n    end\n\n    context 'given a post with remote status' do\n      let(:status) { Fabricate(:status, account: remote_account, text: 'Beep boop') }\n\n      it 'reformats the post' do\n        is_expected.to eq 'Beep boop'\n      end\n\n      context 'given a post with custom_emojify option' do\n        let!(:emoji) { Fabricate(:custom_emoji, domain: remote_account.domain) }\n        let(:status) { Fabricate(:status, account: remote_account, text: text) }\n\n        subject { Formatter.instance.format(status, custom_emojify: true) }\n\n        context 'given a post with an emoji shortcode at the start' do\n          let(:text) { '<p>:coolcat: Beep boop<br />' }\n\n          it 'converts the shortcode to an image tag' do\n            is_expected.to match(/<p><img draggable=\"false\" class=\"emojione\" alt=\":coolcat:\"/)\n          end\n        end\n\n        context 'given a post with an emoji shortcode in the middle' do\n          let(:text) { '<p>Beep :coolcat: boop</p>' }\n\n          it 'converts the shortcode to an image tag' do\n            is_expected.to match(/Beep <img draggable=\"false\" class=\"emojione\" alt=\":coolcat:\"/)\n          end\n        end\n\n        context 'given a post with concatenated emoji' do\n          let(:text) { '<p>:coolcat::coolcat:</p>' }\n\n          it 'does not touch the shortcodes' do\n            is_expected.to match(/<p>:coolcat::coolcat:<\\/p>/)\n          end\n        end\n\n        context 'given a post with an emoji shortcode at the end' do\n          let(:text) { '<p>Beep boop<br />:coolcat:</p>' }\n\n          it 'converts the shortcode to an image tag' do\n            is_expected.to match(/<br><img draggable=\"false\" class=\"emojione\" alt=\":coolcat:\"/)\n          end\n        end\n      end\n    end\n  end\n\n  describe '#reformat' do\n    subject { Formatter.instance.reformat(text) }\n\n    context 'given a post containing plain text' do\n      let(:text) { 'Beep boop' }\n\n      it 'keeps the plain text' do\n        is_expected.to include 'Beep boop'\n      end\n    end\n\n    context 'given a post containing script tags' do\n      let(:text) { '<script>alert(\"Hello\")</script>' }\n\n      it 'strips the scripts' do\n        is_expected.to_not include '<script>alert(\"Hello\")</script>'\n      end\n    end\n\n    context 'given a post containing malicious classes' do\n      let(:text) { '<span class=\"mention\tstatus__content__spoiler-link\">Show more</span>' }\n\n      it 'strips the malicious classes' do\n        is_expected.to_not include 'status__content__spoiler-link'\n      end\n    end\n  end\n\n  describe '#plaintext' do\n    subject { Formatter.instance.plaintext(status) }\n\n    context 'given a post with local status' do\n      let(:status) { Fabricate(:status, text: '<p>a text by a nerd who uses an HTML tag in text</p>', uri: nil) }\n\n      it 'returns the raw text' do\n        is_expected.to eq '<p>a text by a nerd who uses an HTML tag in text</p>'\n      end\n    end\n\n    context 'given a post with remote status' do\n      let(:status) { Fabricate(:status, account: remote_account, text: '<script>alert(\"Hello\")</script>') }\n\n      it 'returns tag-stripped text' do\n        is_expected.to eq ''\n      end\n    end\n  end\n\n  describe '#simplified_format' do\n    subject { Formatter.instance.simplified_format(account) }\n\n    context 'given a post with local status' do\n      let(:account) { Fabricate(:account, domain: nil, note: text) }\n\n      context 'given a post containing linkable mentions for local accounts' do\n        let(:text) { '@alice' }\n\n        before { local_account }\n\n        it 'creates a mention link' do\n          is_expected.to eq '<p><span class=\"h-card\"><a href=\"https://cb6e6126.ngrok.io/@alice\" class=\"u-url mention\">@<span>alice</span></a></span></p>'\n        end\n      end\n\n      context 'given a post containing linkable mentions for remote accounts' do\n        let(:text) { '@bob@remote.test' }\n\n        before { remote_account }\n\n        it 'creates a mention link' do\n          is_expected.to eq '<p><span class=\"h-card\"><a href=\"https://remote.test/\" class=\"u-url mention\">@<span>bob</span></a></span></p>'\n        end\n      end\n\n      context 'given a post containing unlinkable mentions' do\n        let(:text) { '@alice' }\n\n        it 'does not create a mention link' do\n          is_expected.to eq '<p>@alice</p>'\n        end\n      end\n\n      context 'given a post with custom_emojify option' do\n        let!(:emoji) { Fabricate(:custom_emoji) }\n\n        before { account.note = text }\n        subject { Formatter.instance.simplified_format(account, custom_emojify: true) }\n\n        context 'given a post with an emoji shortcode at the start' do\n          let(:text) { ':coolcat: Beep boop' }\n\n          it 'converts the shortcode to an image tag' do\n            is_expected.to match(/<p><img draggable=\"false\" class=\"emojione\" alt=\":coolcat:\"/)\n          end\n        end\n\n        context 'given a post with an emoji shortcode in the middle' do\n          let(:text) { 'Beep :coolcat: boop' }\n\n          it 'converts the shortcode to an image tag' do\n            is_expected.to match(/Beep <img draggable=\"false\" class=\"emojione\" alt=\":coolcat:\"/)\n          end\n        end\n\n        context 'given a post with concatenated emoji shortcodes' do\n          let(:text) { ':coolcat::coolcat:' }\n\n          it 'does not touch the shortcodes' do\n            is_expected.to match(/:coolcat::coolcat:/)\n          end\n        end\n\n        context 'given a post with an emoji shortcode at the end' do\n          let(:text) { 'Beep boop :coolcat:' }\n\n          it 'converts the shortcode to an image tag' do\n            is_expected.to match(/boop <img draggable=\"false\" class=\"emojione\" alt=\":coolcat:\"/)\n          end\n        end\n      end\n\n      include_examples 'encode and link URLs'\n    end\n\n    context 'given a post with remote status' do\n      let(:text) { '<script>alert(\"Hello\")</script>' }\n      let(:account) { Fabricate(:account, domain: 'remote', note: text) }\n\n      it 'reformats' do\n        is_expected.to_not include '<script>alert(\"Hello\")</script>'\n      end\n\n      context 'with custom_emojify option' do\n        let!(:emoji) { Fabricate(:custom_emoji, domain: remote_account.domain) }\n\n        before { remote_account.note = text }\n\n        subject { Formatter.instance.simplified_format(remote_account, custom_emojify: true) }\n\n        context 'given a post with an emoji shortcode at the start' do\n          let(:text) { '<p>:coolcat: Beep boop<br />' }\n\n          it 'converts shortcode to image tag' do\n            is_expected.to match(/<p><img draggable=\"false\" class=\"emojione\" alt=\":coolcat:\"/)\n          end\n        end\n\n        context 'given a post with an emoji shortcode in the middle' do\n          let(:text) { '<p>Beep :coolcat: boop</p>' }\n\n          it 'converts shortcode to image tag' do\n            is_expected.to match(/Beep <img draggable=\"false\" class=\"emojione\" alt=\":coolcat:\"/)\n          end\n        end\n\n        context 'given a post with concatenated emoji shortcodes' do\n          let(:text) { '<p>:coolcat::coolcat:</p>' }\n\n          it 'does not touch the shortcodes' do\n            is_expected.to match(/<p>:coolcat::coolcat:<\\/p>/)\n          end\n        end\n\n        context 'given a post with an emoji shortcode at the end' do\n          let(:text) { '<p>Beep boop<br />:coolcat:</p>' }\n\n          it 'converts shortcode to image tag' do\n            is_expected.to match(/<br><img draggable=\"false\" class=\"emojione\" alt=\":coolcat:\"/)\n          end\n        end\n      end\n    end\n  end\n\n  describe '#sanitize' do\n    let(:html) { '<script>alert(\"Hello\")</script>' }\n\n    subject { Formatter.instance.sanitize(html, Sanitize::Config::MASTODON_STRICT) }\n\n    it 'sanitizes' do\n      is_expected.to eq ''\n    end\n  end\nend\n"
  },
  {
    "path": "spec/lib/hash_object_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe HashObject do\n  it 'has methods corresponding to hash properties' do\n    expect(HashObject.new(key: 'value').key).to eq 'value'\n  end\nend\n"
  },
  {
    "path": "spec/lib/language_detector_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe LanguageDetector do\n  describe 'prepare_text' do\n    it 'returns unmodified string without special cases' do\n      string = 'just a regular string'\n      result = described_class.instance.send(:prepare_text, string)\n\n      expect(result).to eq string\n    end\n\n    it 'collapses spacing in strings' do\n      string = 'The formatting   in    this is very        odd'\n\n      result = described_class.instance.send(:prepare_text, string)\n      expect(result).to eq 'The formatting in this is very odd'\n    end\n\n    it 'strips usernames from strings before detection' do\n      string = '@username Yeah, very surreal...! also @friend'\n\n      result = described_class.instance.send(:prepare_text, string)\n      expect(result).to eq 'Yeah, very surreal...! also'\n    end\n\n    it 'strips URLs from strings before detection' do\n      string = 'Our website is https://example.com and also http://localhost.dev'\n\n      result = described_class.instance.send(:prepare_text, string)\n      expect(result).to eq 'Our website is and also'\n    end\n\n    it 'strips #hashtags from strings before detection' do\n      string = 'Hey look at all the #animals and #fish'\n\n      result = described_class.instance.send(:prepare_text, string)\n      expect(result).to eq 'Hey look at all the and'\n    end\n  end\n\n  describe 'detect' do\n    let(:account_without_user_locale) { Fabricate(:user, locale: nil).account }\n    let(:account_remote) { Fabricate(:account, domain: 'joinmastodon.org') }\n\n    it 'detects english language for basic strings' do\n      strings = [\n        \"Hello and welcome to mastodon how are you today?\",\n        \"I'd rather not!\",\n        \"a lot of people just want to feel righteous all the time and that's all that matters\",\n      ]\n      strings.each do |string|\n        result = described_class.instance.detect(string, account_without_user_locale)\n\n        expect(result).to eq(:en), string\n      end\n    end\n\n    it 'detects spanish language' do\n      string = 'Obtener un Hola y bienvenidos a Mastodon. Obtener un Hola y bienvenidos a Mastodon. Obtener un Hola y bienvenidos a Mastodon. Obtener un Hola y bienvenidos a Mastodon'\n      result = described_class.instance.detect(string, account_without_user_locale)\n\n      expect(result).to eq :es\n    end\n\n    describe 'when language can\\'t be detected' do\n      it 'uses nil when sent an empty document' do\n        result = described_class.instance.detect('', account_without_user_locale)\n        expect(result).to eq nil\n      end\n\n      describe 'because of a URL' do\n        it 'uses nil when sent just a URL' do\n          string = 'http://example.com/media/2kFTgOJLXhQf0g2nKB4'\n          cld_result = CLD3::NNetLanguageIdentifier.new(0, 2048).find_language(string)\n          expect(cld_result).not_to eq :en\n\n          result = described_class.instance.detect(string, account_without_user_locale)\n\n          expect(result).to eq nil\n        end\n      end\n\n      describe 'with an account' do\n        it 'uses the account locale when present' do\n          account = double(user_locale: 'fr')\n          result  = described_class.instance.detect('', account)\n\n          expect(result).to eq nil\n        end\n\n        it 'uses nil when account is present but has no locale' do\n          result = described_class.instance.detect('', account_without_user_locale)\n\n          expect(result).to eq nil\n        end\n      end\n\n      describe 'with an `en` default locale' do\n        it 'uses nil for undetectable string' do\n          result = described_class.instance.detect('', account_without_user_locale)\n\n          expect(result).to eq nil\n        end\n      end\n\n      describe 'remote user' do\n        it 'detects Korean language' do\n          string = '안녕하세요'\n          result = described_class.instance.detect(string, account_remote)\n\n          expect(result).to eq :ko\n        end\n      end\n\n      describe 'with a non-`en` default locale' do\n        around(:each) do |example|\n          before = I18n.default_locale\n          I18n.default_locale = :ja\n          example.run\n          I18n.default_locale = before\n        end\n\n        it 'uses nil for undetectable string' do\n          string = ''\n          result = described_class.instance.detect(string, account_without_user_locale)\n\n          expect(result).to eq nil\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/lib/ostatus/atom_serializer_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe OStatus::AtomSerializer do\n  shared_examples 'follow request salmon' do\n    it 'appends author element with account' do\n      account = Fabricate(:account, domain: nil, username: 'username')\n      follow_request = Fabricate(:follow_request, account: account)\n\n      follow_request_salmon = serialize(follow_request)\n\n      expect(follow_request_salmon.author.id.text).to eq 'https://cb6e6126.ngrok.io/users/username'\n    end\n\n    it 'appends activity:object-type element with activity type' do\n      follow_request = Fabricate(:follow_request)\n\n      follow_request_salmon = serialize(follow_request)\n\n      object_type = follow_request_salmon.nodes.find { |node| node.name == 'activity:object-type' }\n      expect(object_type.text).to eq OStatus::TagManager::TYPES[:activity]\n    end\n\n    it 'appends activity:verb element with request_friend type' do\n      follow_request = Fabricate(:follow_request)\n\n      follow_request_salmon = serialize(follow_request)\n\n      verb = follow_request_salmon.nodes.find { |node| node.name == 'activity:verb' }\n      expect(verb.text).to eq OStatus::TagManager::VERBS[:request_friend]\n    end\n\n    it 'appends activity:object with target account' do\n      target_account = Fabricate(:account, domain: 'domain.test', uri: 'https://domain.test/id')\n      follow_request = Fabricate(:follow_request, target_account: target_account)\n\n      follow_request_salmon = serialize(follow_request)\n\n      object = follow_request_salmon.nodes.find { |node| node.name == 'activity:object' }\n      expect(object.id.text).to eq 'https://domain.test/id'\n    end\n  end\n\n  shared_examples 'namespaces' do\n    it 'adds namespaces' do\n      element = serialize\n\n      expect(element['xmlns']).to eq OStatus::TagManager::XMLNS\n      expect(element['xmlns:thr']).to eq OStatus::TagManager::THR_XMLNS\n      expect(element['xmlns:activity']).to eq OStatus::TagManager::AS_XMLNS\n      expect(element['xmlns:poco']).to eq OStatus::TagManager::POCO_XMLNS\n      expect(element['xmlns:media']).to eq OStatus::TagManager::MEDIA_XMLNS\n      expect(element['xmlns:ostatus']).to eq OStatus::TagManager::OS_XMLNS\n      expect(element['xmlns:mastodon']).to eq OStatus::TagManager::MTDN_XMLNS\n    end\n  end\n\n  shared_examples 'no namespaces' do\n    it 'does not add namespaces' do\n      expect(serialize['xmlns']).to eq nil\n    end\n  end\n\n  shared_examples 'status attributes' do\n    it 'appends summary element with spoiler text if present' do\n      status = Fabricate(:status, language: :ca, spoiler_text: 'spoiler text')\n\n      element = serialize(status)\n\n      summary = element.summary\n      expect(summary['xml:lang']).to eq 'ca'\n      expect(summary.text).to eq 'spoiler text'\n    end\n\n    it 'does not append summary element with spoiler text if not present' do\n      status = Fabricate(:status, spoiler_text: '')\n      element = serialize(status)\n      element.nodes.each { |node| expect(node.name).not_to eq 'summary' }\n    end\n\n    it 'appends content element with formatted status' do\n      status = Fabricate(:status, language: :ca, text: 'text')\n\n      element = serialize(status)\n\n      content = element.content\n      expect(content[:type]).to eq 'html'\n      expect(content['xml:lang']).to eq 'ca'\n      expect(content.text).to eq '<p>text</p>'\n    end\n\n    it 'appends link elements for mentioned accounts' do\n      account = Fabricate(:account, username: 'username')\n      status = Fabricate(:status)\n      Fabricate(:mention, account: account, status: status)\n\n      element = serialize(status)\n\n      mentioned = element.nodes.find do |node|\n        node.name == 'link' &&\n          node[:rel] == 'mentioned' &&\n          node['ostatus:object-type'] == OStatus::TagManager::TYPES[:person]\n      end\n\n      expect(mentioned[:href]).to eq 'https://cb6e6126.ngrok.io/users/username'\n    end\n\n    it 'appends link elements for emojis' do\n      Fabricate(:custom_emoji)\n\n      status  = Fabricate(:status, text: ':coolcat:')\n      element = serialize(status)\n      emoji   = element.nodes.find { |node| node.name == 'link' && node[:rel] == 'emoji' }\n\n      expect(emoji[:name]).to eq 'coolcat'\n      expect(emoji[:href]).to_not be_blank\n    end\n  end\n\n  describe 'render' do\n    it 'returns XML with emojis' do\n      element = Ox::Element.new('tag')\n      element << '💩'\n      xml = OStatus::AtomSerializer.render(element)\n\n      expect(xml).to eq \"<?xml version=\\\"1.0\\\"?>\\n<tag>💩</tag>\\n\"\n    end\n\n    it 'returns XML, stripping invalid characters like \\b and \\v' do\n      element = Ox::Element.new('tag')\n      element << \"im l33t\\b haxo\\b\\vr\"\n      xml = OStatus::AtomSerializer.render(element)\n\n      expect(xml).to eq \"<?xml version=\\\"1.0\\\"?>\\n<tag>im l33t haxor</tag>\\n\"\n    end\n  end\n\n  describe '#author' do\n    context 'when note is present' do\n      it 'appends poco:note element with note for local account' do\n        account = Fabricate(:account, domain: nil, note: '<p>note</p>')\n\n        author = OStatus::AtomSerializer.new.author(account)\n\n        note = author.nodes.find { |node| node.name == 'poco:note' }\n        expect(note.text).to eq '<p>note</p>'\n      end\n\n      it 'appends poco:note element with tags-stripped note for remote account' do\n        account = Fabricate(:account, domain: 'remote', note: '<p>note</p>')\n\n        author = OStatus::AtomSerializer.new.author(account)\n\n        note = author.nodes.find { |node| node.name == 'poco:note' }\n        expect(note.text).to eq 'note'\n      end\n\n      it 'appends summary element with type attribute and simplified note if present' do\n        account = Fabricate(:account, note: 'note')\n        author = OStatus::AtomSerializer.new.author(account)\n        expect(author.summary.text).to eq '<p>note</p>'\n        expect(author.summary[:type]).to eq 'html'\n      end\n    end\n\n    context 'when note is not present' do\n      it 'does not append poco:note element' do\n        account = Fabricate(:account, note: '')\n        author = OStatus::AtomSerializer.new.author(account)\n        author.nodes.each { |node| expect(node.name).not_to eq 'poco:note' }\n      end\n\n      it 'does not append summary element' do\n        account = Fabricate(:account, note: '')\n        author = OStatus::AtomSerializer.new.author(account)\n        author.nodes.each { |node| expect(node.name).not_to eq 'summary' }\n      end\n    end\n\n    it 'returns author element' do\n      account = Fabricate(:account)\n      author = OStatus::AtomSerializer.new.author(account)\n      expect(author.name).to eq 'author'\n    end\n\n    it 'appends activity:object-type element with person type' do\n      account = Fabricate(:account, domain: nil, username: 'username')\n\n      author = OStatus::AtomSerializer.new.author(account)\n\n      object_type = author.nodes.find { |node| node.name == 'activity:object-type' }\n      expect(object_type.text).to eq OStatus::TagManager::TYPES[:person]\n    end\n\n    it 'appends email element with username and domain for local account' do\n      account = Fabricate(:account, username: 'username')\n      author = OStatus::AtomSerializer.new.author(account)\n      expect(author.email.text).to eq 'username@cb6e6126.ngrok.io'\n    end\n\n    it 'appends email element with username and domain for remote user' do\n      account = Fabricate(:account, domain: 'domain', username: 'username')\n      author = OStatus::AtomSerializer.new.author(account)\n      expect(author.email.text).to eq 'username@domain'\n    end\n\n    it 'appends link element for an alternative' do\n      account = Fabricate(:account, domain: nil, username: 'username')\n\n      author = OStatus::AtomSerializer.new.author(account)\n\n      link = author.nodes.find { |node| node.name == 'link' && node[:rel] == 'alternate' && node[:type] == 'text/html' }\n      expect(link[:type]).to eq 'text/html'\n      expect(link[:rel]).to eq 'alternate'\n      expect(link[:href]).to eq 'https://cb6e6126.ngrok.io/@username'\n    end\n\n    it 'has link element for avatar if present' do\n      account = Fabricate(:account, avatar: attachment_fixture('avatar.gif'))\n\n      author = OStatus::AtomSerializer.new.author(account)\n\n      link = author.nodes.find { |node| node.name == 'link' && node[:rel] == 'avatar' }\n      expect(link[:type]).to eq 'image/gif'\n      expect(link['media:width']).to eq '120'\n      expect(link['media:height']).to eq '120'\n      expect(link[:href]).to match  /^https:\\/\\/cb6e6126.ngrok.io\\/system\\/accounts\\/avatars\\/.+\\/original\\/avatar.gif/\n    end\n\n    it 'does not have link element for avatar if not present' do\n      account = Fabricate(:account, avatar: nil)\n\n      author = OStatus::AtomSerializer.new.author(account)\n\n      author.nodes.each do |node|\n        expect(node[:rel]).not_to eq 'avatar' if node.name == 'link'\n      end\n    end\n\n    it 'appends link element for header if present' do\n      account = Fabricate(:account, header: attachment_fixture('avatar.gif'))\n\n      author = OStatus::AtomSerializer.new.author(account)\n\n      link = author.nodes.find { |node| node.name == 'link' && node[:rel] == 'header' }\n      expect(link[:type]).to eq 'image/gif'\n      expect(link['media:width']).to eq '700'\n      expect(link['media:height']).to eq '335'\n      expect(link[:href]).to match  /^https:\\/\\/cb6e6126.ngrok.io\\/system\\/accounts\\/headers\\/.+\\/original\\/avatar.gif/\n    end\n\n    it 'does not append link element for header if not present' do\n      account = Fabricate(:account, header: nil)\n\n      author = OStatus::AtomSerializer.new.author(account)\n\n      author.nodes.each do |node|\n        expect(node[:rel]).not_to eq 'header' if node.name == 'link'\n      end\n    end\n\n    it 'appends poco:displayName element with display name if present' do\n      account = Fabricate(:account, display_name: 'display name')\n\n      author = OStatus::AtomSerializer.new.author(account)\n\n      display_name = author.nodes.find { |node| node.name == 'poco:displayName' }\n      expect(display_name.text).to eq 'display name'\n    end\n\n    it 'does not append poco:displayName element with display name if not present' do\n      account = Fabricate(:account, display_name: '')\n      author = OStatus::AtomSerializer.new.author(account)\n      author.nodes.each { |node| expect(node.name).not_to eq 'poco:displayName' }\n    end\n\n    it \"appends mastodon:scope element with 'private' if locked\" do\n      account = Fabricate(:account, locked: true)\n\n      author = OStatus::AtomSerializer.new.author(account)\n\n      scope = author.nodes.find { |node| node.name == 'mastodon:scope' }\n      expect(scope.text).to eq 'private'\n    end\n\n    it \"appends mastodon:scope element with 'public' if unlocked\" do\n      account = Fabricate(:account, locked: false)\n\n      author = OStatus::AtomSerializer.new.author(account)\n\n      scope = author.nodes.find { |node| node.name == 'mastodon:scope' }\n      expect(scope.text).to eq 'public'\n    end\n\n    it 'includes URI' do\n      account = Fabricate(:account, domain: nil, username: 'username')\n\n      author = OStatus::AtomSerializer.new.author(account)\n\n      expect(author.id.text).to eq 'https://cb6e6126.ngrok.io/users/username'\n      expect(author.uri.text).to eq 'https://cb6e6126.ngrok.io/users/username'\n    end\n\n    it 'includes username' do\n      account = Fabricate(:account, username: 'username')\n\n      author = OStatus::AtomSerializer.new.author(account)\n\n      name = author.nodes.find { |node| node.name == 'name' }\n      username = author.nodes.find { |node| node.name == 'poco:preferredUsername' }\n      expect(name.text).to eq 'username'\n      expect(username.text).to eq 'username'\n    end\n  end\n\n  describe '#entry' do\n    shared_examples 'not root' do\n      include_examples 'no namespaces' do\n        def serialize\n          subject\n        end\n      end\n\n      it 'does not append author element' do\n        subject.nodes.each { |node| expect(node.name).not_to eq 'author' }\n      end\n    end\n\n    context 'it is root' do\n      include_examples 'namespaces' do\n        def serialize\n          stream_entry = Fabricate(:stream_entry)\n          OStatus::AtomSerializer.new.entry(stream_entry, true)\n        end\n      end\n\n      it 'appends author element' do\n        account = Fabricate(:account, username: 'username')\n        status = Fabricate(:status, account: account)\n\n        entry = OStatus::AtomSerializer.new.entry(status.stream_entry, true)\n\n        expect(entry.author.id.text).to eq 'https://cb6e6126.ngrok.io/users/username'\n      end\n    end\n\n    context 'if status is present' do\n      include_examples 'status attributes' do\n        def serialize(status)\n          OStatus::AtomSerializer.new.entry(status.stream_entry, true)\n        end\n      end\n\n      it 'appends link element for the public collection if status is publicly visible' do\n        status = Fabricate(:status, visibility: :public)\n\n        entry = OStatus::AtomSerializer.new.entry(status.stream_entry)\n\n        mentioned_person = entry.nodes.find do |node|\n          node.name == 'link' &&\n          node[:rel] == 'mentioned' &&\n          node['ostatus:object-type'] == OStatus::TagManager::TYPES[:collection]\n        end\n        expect(mentioned_person[:href]).to eq OStatus::TagManager::COLLECTIONS[:public]\n      end\n\n      it 'does not append link element for the public collection if status is not publicly visible' do\n        status = Fabricate(:status, visibility: :private)\n\n        entry = OStatus::AtomSerializer.new.entry(status.stream_entry)\n\n        entry.nodes.each do |node|\n          if node.name == 'link' &&\n             node[:rel] == 'mentioned' &&\n             node['ostatus:object-type'] == OStatus::TagManager::TYPES[:collection]\n            expect(mentioned_collection[:href]).not_to eq OStatus::TagManager::COLLECTIONS[:public]\n          end\n        end\n      end\n\n      it 'appends category elements for tags' do\n        tag = Fabricate(:tag, name: 'tag')\n        status = Fabricate(:status, tags: [ tag ])\n\n        entry = OStatus::AtomSerializer.new.entry(status.stream_entry)\n\n        expect(entry.category[:term]).to eq 'tag'\n      end\n\n      it 'appends link elements for media attachments' do\n        file = attachment_fixture('attachment.jpg')\n        media_attachment = Fabricate(:media_attachment, file: file)\n        status = Fabricate(:status, media_attachments: [ media_attachment ])\n\n        entry = OStatus::AtomSerializer.new.entry(status.stream_entry)\n\n        enclosure = entry.nodes.find { |node| node.name == 'link' && node[:rel] == 'enclosure' }\n        expect(enclosure[:type]).to eq 'image/jpeg'\n        expect(enclosure[:href]).to match /^https:\\/\\/cb6e6126.ngrok.io\\/system\\/media_attachments\\/files\\/.+\\/original\\/attachment.jpg$/\n      end\n\n      it 'appends mastodon:scope element with visibility' do\n        status = Fabricate(:status, visibility: :public)\n\n        entry = OStatus::AtomSerializer.new.entry(status.stream_entry)\n\n        scope = entry.nodes.find { |node| node.name == 'mastodon:scope' }\n        expect(scope.text).to eq 'public'\n      end\n\n      it 'returns element whose rendered view triggers creation when processed' do\n        remote_account = Account.create!(username: 'username')\n        remote_status = Fabricate(:status, account: remote_account, created_at: '2000-01-01T00:00:00Z')\n\n        entry = OStatus::AtomSerializer.new.entry(remote_status.stream_entry, true)\n        entry.nodes.delete_if { |node| node[:type] == 'application/activity+json' } # Remove ActivityPub link to simplify test\n        xml = OStatus::AtomSerializer.render(entry).gsub('cb6e6126.ngrok.io', 'remote.test')\n\n        remote_status.destroy!\n        remote_account.destroy!\n\n        account = Account.create!(\n          domain: 'remote.test',\n          username: 'username',\n          last_webfingered_at: Time.now.utc\n        )\n\n        ProcessFeedService.new.call(xml, account)\n\n        expect(Status.find_by(uri: \"https://remote.test/users/#{remote_status.account.to_param}/statuses/#{remote_status.id}\")).to be_instance_of Status\n      end\n    end\n\n    context 'if status is not present' do\n      it 'appends content element saying status is deleted' do\n        status = Fabricate(:status)\n        status.destroy!\n\n        entry = OStatus::AtomSerializer.new.entry(status.stream_entry)\n\n        expect(entry.content.text).to eq 'Deleted status'\n      end\n\n      it 'appends title element saying the status is deleted' do\n        account = Fabricate(:account, username: 'username')\n        status = Fabricate(:status, account: account)\n        status.destroy!\n\n        entry = OStatus::AtomSerializer.new.entry(status.stream_entry)\n\n        expect(entry.title.text).to eq 'username deleted status'\n      end\n    end\n\n    context 'it is not root' do\n      let(:stream_entry) { Fabricate(:stream_entry) }\n      subject { OStatus::AtomSerializer.new.entry(stream_entry, false) }\n      include_examples 'not root'\n    end\n\n    context 'without root parameter' do\n      let(:stream_entry) { Fabricate(:stream_entry) }\n      subject { OStatus::AtomSerializer.new.entry(stream_entry) }\n      include_examples 'not root'\n    end\n\n    it 'returns entry element' do\n      stream_entry = Fabricate(:stream_entry)\n      entry = OStatus::AtomSerializer.new.entry(stream_entry)\n      expect(entry.name).to eq 'entry'\n    end\n\n    it 'appends id element with unique tag' do\n      status = Fabricate(:status, reblog_of_id: nil, created_at: '2000-01-01T00:00:00Z')\n\n      entry = OStatus::AtomSerializer.new.entry(status.stream_entry)\n\n      expect(entry.id.text).to eq \"https://cb6e6126.ngrok.io/users/#{status.account.to_param}/statuses/#{status.id}\"\n    end\n\n    it 'appends published element with created date' do\n      stream_entry = Fabricate(:stream_entry, created_at: '2000-01-01T00:00:00Z')\n      entry = OStatus::AtomSerializer.new.entry(stream_entry)\n      expect(entry.published.text).to eq '2000-01-01T00:00:00Z'\n    end\n\n    it 'appends updated element with updated date' do\n      stream_entry = Fabricate(:stream_entry, updated_at: '2000-01-01T00:00:00Z')\n      entry = OStatus::AtomSerializer.new.entry(stream_entry)\n      expect(entry.updated.text).to eq '2000-01-01T00:00:00Z'\n    end\n\n    it 'appends title element with status title' do\n      account = Fabricate(:account, username: 'username')\n      status = Fabricate(:status, account: account, reblog_of_id: nil)\n      entry = OStatus::AtomSerializer.new.entry(status.stream_entry)\n      expect(entry.title.text).to eq 'New status by username'\n    end\n\n    it 'appends activity:object-type element with object type' do\n      status = Fabricate(:status)\n      entry = OStatus::AtomSerializer.new.entry(status.stream_entry)\n      object_type = entry.nodes.find { |node| node.name == 'activity:object-type' }\n      expect(object_type.text).to eq OStatus::TagManager::TYPES[:note]\n    end\n\n    it 'appends activity:verb element with object type' do\n      status = Fabricate(:status)\n\n      entry = OStatus::AtomSerializer.new.entry(status.stream_entry)\n\n      object_type = entry.nodes.find { |node| node.name == 'activity:verb' }\n      expect(object_type.text).to eq OStatus::TagManager::VERBS[:post]\n    end\n\n    it 'appends activity:object element with target if present' do\n      reblogged = Fabricate(:status, created_at: '2000-01-01T00:00:00Z')\n      reblog = Fabricate(:status, reblog: reblogged)\n\n      entry = OStatus::AtomSerializer.new.entry(reblog.stream_entry)\n\n      object = entry.nodes.find { |node| node.name == 'activity:object' }\n      expect(object.id.text).to eq \"https://cb6e6126.ngrok.io/users/#{reblogged.account.to_param}/statuses/#{reblogged.id}\"\n    end\n\n    it 'does not append activity:object element if target is not present' do\n      status = Fabricate(:status, reblog_of_id: nil)\n      entry = OStatus::AtomSerializer.new.entry(status.stream_entry)\n      entry.nodes.each { |node| expect(node.name).not_to eq 'activity:object' }\n    end\n\n    it 'appends link element for an alternative' do\n      account = Fabricate(:account, username: 'username')\n      status = Fabricate(:status, account: account)\n\n      entry = OStatus::AtomSerializer.new.entry(status.stream_entry)\n\n      link = entry.nodes.find { |node| node.name == 'link' && node[:rel] == 'alternate' && node[:type] == 'text/html' }\n      expect(link[:type]).to eq 'text/html'\n      expect(link[:href]).to eq \"https://cb6e6126.ngrok.io/@username/#{status.id}\"\n    end\n\n    it 'appends link element for itself' do\n      account = Fabricate(:account, username: 'username')\n      status = Fabricate(:status, account: account)\n\n      entry = OStatus::AtomSerializer.new.entry(status.stream_entry)\n\n      link = entry.nodes.find { |node| node.name == 'link' && node[:rel] == 'self' }\n      expect(link[:type]).to eq 'application/atom+xml'\n      expect(link[:href]).to eq \"https://cb6e6126.ngrok.io/users/username/updates/#{status.stream_entry.id}.atom\"\n    end\n\n    it 'appends thr:in-reply-to element if threaded' do\n      in_reply_to_status = Fabricate(:status, created_at: '2000-01-01T00:00:00Z', reblog_of_id: nil)\n      reply_status = Fabricate(:status, in_reply_to_id: in_reply_to_status.id)\n\n      entry = OStatus::AtomSerializer.new.entry(reply_status.stream_entry)\n\n      in_reply_to = entry.nodes.find { |node| node.name == 'thr:in-reply-to' }\n      expect(in_reply_to[:ref]).to eq \"https://cb6e6126.ngrok.io/users/#{in_reply_to_status.account.to_param}/statuses/#{in_reply_to_status.id}\"\n    end\n\n    it 'does not append thr:in-reply-to element if not threaded' do\n      status = Fabricate(:status)\n      entry = OStatus::AtomSerializer.new.entry(status.stream_entry)\n      entry.nodes.each { |node| expect(node.name).not_to eq 'thr:in-reply-to' }\n    end\n\n    it 'appends ostatus:conversation if conversation id is present' do\n      status = Fabricate(:status)\n      status.conversation.update!(created_at: '2000-01-01T00:00:00Z')\n\n      entry = OStatus::AtomSerializer.new.entry(status.stream_entry)\n\n      conversation = entry.nodes.find { |node| node.name == 'ostatus:conversation' }\n      expect(conversation[:ref]).to eq \"tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{status.conversation_id}:objectType=Conversation\"\n    end\n\n    it 'does not append ostatus:conversation if conversation id is not present' do\n      status = Fabricate.build(:status, conversation_id: nil)\n      status.save!(validate: false)\n\n      entry = OStatus::AtomSerializer.new.entry(status.stream_entry)\n\n      entry.nodes.each { |node| expect(node.name).not_to eq 'ostatus:conversation' }\n    end\n  end\n\n  describe '#feed' do\n    include_examples 'namespaces' do\n      def serialize\n        account = Fabricate(:account)\n        OStatus::AtomSerializer.new.feed(account, [])\n      end\n    end\n\n    it 'returns feed element' do\n      account = Fabricate(:account)\n      feed = OStatus::AtomSerializer.new.feed(account, [])\n      expect(feed.name).to eq 'feed'\n    end\n\n    it 'appends id element with account Atom URL' do\n      account = Fabricate(:account, username: 'username')\n      feed = OStatus::AtomSerializer.new.feed(account, [])\n      expect(feed.id.text).to eq 'https://cb6e6126.ngrok.io/users/username.atom'\n    end\n\n    it 'appends title element with account display name if present' do\n      account = Fabricate(:account, display_name: 'display name')\n      feed = OStatus::AtomSerializer.new.feed(account, [])\n      expect(feed.title.text).to eq 'display name'\n    end\n\n    it 'does not append title element with account username if account display name is not present' do\n      account = Fabricate(:account, display_name: '', username: 'username')\n      feed = OStatus::AtomSerializer.new.feed(account, [])\n      expect(feed.title.text).to eq 'username'\n    end\n\n    it 'appends subtitle element with account note' do\n      account = Fabricate(:account, note: 'note')\n      feed = OStatus::AtomSerializer.new.feed(account, [])\n      expect(feed.subtitle.text).to eq 'note'\n    end\n\n    it 'appends updated element with date account got updated' do\n      account = Fabricate(:account, updated_at: '2000-01-01T00:00:00Z')\n      feed = OStatus::AtomSerializer.new.feed(account, [])\n      expect(feed.updated.text).to eq '2000-01-01T00:00:00Z'\n    end\n\n    it 'appends logo element with full asset URL for original account avatar' do\n      account = Fabricate(:account, avatar: attachment_fixture('avatar.gif'))\n      feed = OStatus::AtomSerializer.new.feed(account, [])\n      expect(feed.logo.text).to match /^https:\\/\\/cb6e6126.ngrok.io\\/system\\/accounts\\/avatars\\/.+\\/original\\/avatar.gif/\n    end\n\n    it 'appends author element' do\n      account = Fabricate(:account, username: 'username')\n      feed = OStatus::AtomSerializer.new.feed(account, [])\n      expect(feed.author.id.text).to eq 'https://cb6e6126.ngrok.io/users/username'\n    end\n\n    it 'appends link element for an alternative' do\n      account = Fabricate(:account, username: 'username')\n\n      feed = OStatus::AtomSerializer.new.feed(account, [])\n\n      link = feed.nodes.find { |node| node.name == 'link' && node[:rel] == 'alternate' && node[:type] == 'text/html' }\n      expect(link[:type]).to eq 'text/html'\n      expect(link[:href]).to eq 'https://cb6e6126.ngrok.io/@username'\n    end\n\n    it 'appends link element for itself' do\n      account = Fabricate(:account, username: 'username')\n\n      feed = OStatus::AtomSerializer.new.feed(account, [])\n\n      link = feed.nodes.find { |node| node.name == 'link' && node[:rel] == 'self' }\n      expect(link[:type]).to eq 'application/atom+xml'\n      expect(link[:href]).to eq 'https://cb6e6126.ngrok.io/users/username.atom'\n    end\n\n    it 'appends link element for the next if it has 20 stream entries' do\n      account = Fabricate(:account, username: 'username')\n      stream_entry = Fabricate(:stream_entry)\n\n      feed = OStatus::AtomSerializer.new.feed(account, Array.new(20, stream_entry))\n\n      link = feed.nodes.find { |node| node.name == 'link' && node[:rel] == 'next' }\n      expect(link[:type]).to eq 'application/atom+xml'\n      expect(link[:href]).to eq \"https://cb6e6126.ngrok.io/users/username.atom?max_id=#{stream_entry.id}\"\n    end\n\n    it 'does not append link element for the next if it does not have 20 stream entries' do\n      account = Fabricate(:account, username: 'username')\n\n      feed = OStatus::AtomSerializer.new.feed(account, [])\n\n      feed.nodes.each do |node|\n        expect(node[:rel]).not_to eq 'next' if node.name == 'link'\n      end\n    end\n\n    it 'appends link element for hub' do\n      account = Fabricate(:account, username: 'username')\n\n      feed = OStatus::AtomSerializer.new.feed(account, [])\n\n      link = feed.nodes.find { |node| node.name == 'link' && node[:rel] == 'hub' }\n      expect(link[:href]).to eq 'https://cb6e6126.ngrok.io/api/push'\n    end\n\n    it 'appends link element for Salmon' do\n      account = Fabricate(:account, username: 'username')\n\n      feed = OStatus::AtomSerializer.new.feed(account, [])\n\n      link = feed.nodes.find { |node| node.name == 'link' && node[:rel] == 'salmon' }\n      expect(link[:href]).to start_with 'https://cb6e6126.ngrok.io/api/salmon/'\n    end\n\n    it 'appends stream entries' do\n      account = Fabricate(:account, username: 'username')\n      status = Fabricate(:status, account: account)\n\n      feed = OStatus::AtomSerializer.new.feed(account, [status.stream_entry])\n\n      expect(feed.entry.title.text).to eq 'New status by username'\n    end\n  end\n\n  describe '#block_salmon' do\n    include_examples 'namespaces' do\n      def serialize\n        block = Fabricate(:block)\n        OStatus::AtomSerializer.new.block_salmon(block)\n      end\n    end\n\n    it 'returns entry element' do\n      block = Fabricate(:block)\n      block_salmon = OStatus::AtomSerializer.new.block_salmon(block)\n      expect(block_salmon.name).to eq 'entry'\n    end\n\n    it 'appends id element with unique tag' do\n      block = Fabricate(:block)\n\n      time_before = Time.zone.now\n      block_salmon = OStatus::AtomSerializer.new.block_salmon(block)\n      time_after = Time.zone.now\n\n      expect(block_salmon.id.text).to(\n        eq(OStatus::TagManager.instance.unique_tag(time_before.utc, block.id, 'Block'))\n          .or(eq(OStatus::TagManager.instance.unique_tag(time_after.utc, block.id, 'Block')))\n      )\n    end\n\n    it 'appends title element with description' do\n      account = Fabricate(:account, domain: nil, username: 'account')\n      target_account = Fabricate(:account, domain: 'remote', username: 'target_account')\n      block = Fabricate(:block, account: account, target_account: target_account)\n\n      block_salmon = OStatus::AtomSerializer.new.block_salmon(block)\n\n      expect(block_salmon.title.text).to eq 'account no longer wishes to interact with target_account@remote'\n    end\n\n    it 'appends author element with account' do\n      account = Fabricate(:account, domain: nil, username: 'account')\n      block = Fabricate(:block, account: account)\n\n      block_salmon = OStatus::AtomSerializer.new.block_salmon(block)\n\n      expect(block_salmon.author.id.text).to eq 'https://cb6e6126.ngrok.io/users/account'\n    end\n\n    it 'appends activity:object-type element with activity type' do\n      block = Fabricate(:block)\n\n      block_salmon = OStatus::AtomSerializer.new.block_salmon(block)\n\n      object_type = block_salmon.nodes.find { |node| node.name == 'activity:object-type' }\n      expect(object_type.text).to eq OStatus::TagManager::TYPES[:activity]\n    end\n\n    it 'appends activity:verb element with block' do\n      block = Fabricate(:block)\n\n      block_salmon = OStatus::AtomSerializer.new.block_salmon(block)\n\n      verb = block_salmon.nodes.find { |node| node.name == 'activity:verb' }\n      expect(verb.text).to eq OStatus::TagManager::VERBS[:block]\n    end\n\n    it 'appends activity:object element with target account' do\n      target_account = Fabricate(:account, domain: 'domain.test', uri: 'https://domain.test/id')\n      block = Fabricate(:block, target_account: target_account)\n\n      block_salmon = OStatus::AtomSerializer.new.block_salmon(block)\n\n      object = block_salmon.nodes.find { |node| node.name == 'activity:object' }\n      expect(object.id.text).to eq 'https://domain.test/id'\n    end\n\n    it 'returns element whose rendered view triggers block when processed' do\n      block = Fabricate(:block)\n      block_salmon = OStatus::AtomSerializer.new.block_salmon(block)\n      xml = OStatus::AtomSerializer.render(block_salmon)\n      envelope = OStatus2::Salmon.new.pack(xml, block.account.keypair)\n      block.destroy!\n\n      ProcessInteractionService.new.call(envelope, block.target_account)\n\n      expect(block.account.blocking?(block.target_account)).to be true\n    end\n  end\n\n  describe '#unblock_salmon' do\n    include_examples 'namespaces' do\n      def serialize\n        block = Fabricate(:block)\n        OStatus::AtomSerializer.new.unblock_salmon(block)\n      end\n    end\n\n    it 'returns entry element' do\n      block = Fabricate(:block)\n      unblock_salmon = OStatus::AtomSerializer.new.unblock_salmon(block)\n      expect(unblock_salmon.name).to eq 'entry'\n    end\n\n    it 'appends id element with unique tag' do\n      block = Fabricate(:block)\n\n      time_before = Time.zone.now\n      unblock_salmon = OStatus::AtomSerializer.new.unblock_salmon(block)\n      time_after = Time.zone.now\n\n      expect(unblock_salmon.id.text).to(\n        eq(OStatus::TagManager.instance.unique_tag(time_before.utc, block.id, 'Block'))\n          .or(eq(OStatus::TagManager.instance.unique_tag(time_after.utc, block.id, 'Block')))\n      )\n    end\n\n    it 'appends title element with description' do\n      account = Fabricate(:account, domain: nil, username: 'account')\n      target_account = Fabricate(:account, domain: 'remote', username: 'target_account')\n      block = Fabricate(:block, account: account, target_account: target_account)\n\n      unblock_salmon = OStatus::AtomSerializer.new.unblock_salmon(block)\n\n      expect(unblock_salmon.title.text).to eq 'account no longer blocks target_account@remote'\n    end\n\n    it 'appends author element with account' do\n      account = Fabricate(:account, domain: nil, username: 'account')\n      block = Fabricate(:block, account: account)\n\n      unblock_salmon = OStatus::AtomSerializer.new.unblock_salmon(block)\n\n      expect(unblock_salmon.author.id.text).to eq 'https://cb6e6126.ngrok.io/users/account'\n    end\n\n    it 'appends activity:object-type element with activity type' do\n      block = Fabricate(:block)\n\n      unblock_salmon = OStatus::AtomSerializer.new.unblock_salmon(block)\n\n      object_type = unblock_salmon.nodes.find { |node| node.name == 'activity:object-type' }\n      expect(object_type.text).to eq OStatus::TagManager::TYPES[:activity]\n    end\n\n    it 'appends activity:verb element with block' do\n      block = Fabricate(:block)\n\n      unblock_salmon = OStatus::AtomSerializer.new.unblock_salmon(block)\n\n      verb = unblock_salmon.nodes.find { |node| node.name == 'activity:verb' }\n      expect(verb.text).to eq OStatus::TagManager::VERBS[:unblock]\n    end\n\n    it 'appends activity:object element with target account' do\n      target_account = Fabricate(:account, domain: 'domain.test', uri: 'https://domain.test/id')\n      block = Fabricate(:block, target_account: target_account)\n\n      unblock_salmon = OStatus::AtomSerializer.new.unblock_salmon(block)\n\n      object = unblock_salmon.nodes.find { |node| node.name == 'activity:object' }\n      expect(object.id.text).to eq 'https://domain.test/id'\n    end\n\n    it 'returns element whose rendered view triggers block when processed' do\n      block = Fabricate(:block)\n      unblock_salmon = OStatus::AtomSerializer.new.unblock_salmon(block)\n      xml = OStatus::AtomSerializer.render(unblock_salmon)\n      envelope = OStatus2::Salmon.new.pack(xml, block.account.keypair)\n\n      ProcessInteractionService.new.call(envelope, block.target_account)\n\n      expect { block.reload }.to raise_error ActiveRecord::RecordNotFound\n    end\n  end\n\n  describe '#favourite_salmon' do\n    include_examples 'namespaces' do\n      def serialize\n        favourite = Fabricate(:favourite)\n        OStatus::AtomSerializer.new.favourite_salmon(favourite)\n      end\n    end\n\n    it 'returns entry element' do\n      favourite = Fabricate(:favourite)\n      favourite_salmon = OStatus::AtomSerializer.new.favourite_salmon(favourite)\n      expect(favourite_salmon.name).to eq 'entry'\n    end\n\n    it 'appends id element with unique tag' do\n      favourite = Fabricate(:favourite, created_at: '2000-01-01T00:00:00Z')\n      favourite_salmon = OStatus::AtomSerializer.new.favourite_salmon(favourite)\n      expect(favourite_salmon.id.text).to eq \"tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{favourite.id}:objectType=Favourite\"\n    end\n\n    it 'appends author element with account' do\n      account = Fabricate(:account, domain: nil, username: 'username')\n      favourite = Fabricate(:favourite, account: account)\n\n      favourite_salmon = OStatus::AtomSerializer.new.favourite_salmon(favourite)\n\n      expect(favourite_salmon.author.id.text).to eq 'https://cb6e6126.ngrok.io/users/username'\n    end\n\n    it 'appends activity:object-type element with activity type' do\n      favourite = Fabricate(:favourite)\n\n      favourite_salmon = OStatus::AtomSerializer.new.favourite_salmon(favourite)\n\n      object_type = favourite_salmon.nodes.find { |node| node.name == 'activity:object-type' }\n      expect(object_type.text).to eq 'http://activitystrea.ms/schema/1.0/activity'\n    end\n\n    it 'appends activity:verb element with favorite' do\n      favourite = Fabricate(:favourite)\n\n      favourite_salmon = OStatus::AtomSerializer.new.favourite_salmon(favourite)\n\n      verb = favourite_salmon.nodes.find { |node| node.name == 'activity:verb' }\n      expect(verb.text).to eq OStatus::TagManager::VERBS[:favorite]\n    end\n\n    it 'appends activity:object element with status' do\n      status = Fabricate(:status, created_at: '2000-01-01T00:00:00Z')\n      favourite = Fabricate(:favourite, status: status)\n\n      favourite_salmon = OStatus::AtomSerializer.new.favourite_salmon(favourite)\n\n      object = favourite_salmon.nodes.find { |node| node.name == 'activity:object' }\n      expect(object.id.text).to eq \"https://cb6e6126.ngrok.io/users/#{status.account.to_param}/statuses/#{status.id}\"\n    end\n\n    it 'appends thr:in-reply-to element for status' do\n      status_account = Fabricate(:account, username: 'username')\n      status = Fabricate(:status, account: status_account, created_at: '2000-01-01T00:00:00Z')\n      favourite = Fabricate(:favourite, status: status)\n\n      favourite_salmon = OStatus::AtomSerializer.new.favourite_salmon(favourite)\n\n      in_reply_to = favourite_salmon.nodes.find { |node| node.name == 'thr:in-reply-to' }\n      expect(in_reply_to.ref).to eq \"https://cb6e6126.ngrok.io/users/#{status.account.to_param}/statuses/#{status.id}\"\n      expect(in_reply_to.href).to eq \"https://cb6e6126.ngrok.io/@username/#{status.id}\"\n    end\n\n    it 'includes description' do\n      account = Fabricate(:account, domain: nil, username: 'account')\n      status_account = Fabricate(:account, domain: 'remote', username: 'status_account')\n      status = Fabricate(:status, account: status_account)\n      favourite = Fabricate(:favourite, account: account, status: status)\n\n      favourite_salmon = OStatus::AtomSerializer.new.favourite_salmon(favourite)\n\n      expect(favourite_salmon.title.text).to eq 'account favourited a status by status_account@remote'\n      expect(favourite_salmon.content.text).to eq 'account favourited a status by status_account@remote'\n    end\n\n    it 'returns element whose rendered view triggers favourite when processed' do\n      favourite = Fabricate(:favourite)\n      favourite_salmon = OStatus::AtomSerializer.new.favourite_salmon(favourite)\n      xml = OStatus::AtomSerializer.render(favourite_salmon)\n      envelope = OStatus2::Salmon.new.pack(xml, favourite.account.keypair)\n      favourite.destroy!\n\n      ProcessInteractionService.new.call(envelope, favourite.status.account)\n      expect(favourite.account.favourited?(favourite.status)).to be true\n    end\n  end\n\n  describe '#unfavourite_salmon' do\n    include_examples 'namespaces' do\n      def serialize\n        favourite = Fabricate(:favourite)\n        OStatus::AtomSerializer.new.favourite_salmon(favourite)\n      end\n    end\n\n    it 'returns entry element' do\n      favourite = Fabricate(:favourite)\n      unfavourite_salmon = OStatus::AtomSerializer.new.unfavourite_salmon(favourite)\n      expect(unfavourite_salmon.name).to eq 'entry'\n    end\n\n    it 'appends id element with unique tag' do\n      favourite = Fabricate(:favourite)\n\n      time_before = Time.zone.now\n      unfavourite_salmon = OStatus::AtomSerializer.new.unfavourite_salmon(favourite)\n      time_after = Time.zone.now\n\n      expect(unfavourite_salmon.id.text).to(\n        eq(OStatus::TagManager.instance.unique_tag(time_before.utc, favourite.id, 'Favourite'))\n          .or(eq(OStatus::TagManager.instance.unique_tag(time_after.utc, favourite.id, 'Favourite')))\n      )\n    end\n\n    it 'appends author element with account' do\n      account = Fabricate(:account, domain: nil, username: 'username')\n      favourite = Fabricate(:favourite, account: account)\n\n      unfavourite_salmon = OStatus::AtomSerializer.new.unfavourite_salmon(favourite)\n\n      expect(unfavourite_salmon.author.id.text).to eq 'https://cb6e6126.ngrok.io/users/username'\n    end\n\n    it 'appends activity:object-type element with activity type' do\n      favourite = Fabricate(:favourite)\n\n      unfavourite_salmon = OStatus::AtomSerializer.new.unfavourite_salmon(favourite)\n\n      object_type = unfavourite_salmon.nodes.find { |node| node.name == 'activity:object-type' }\n      expect(object_type.text).to eq 'http://activitystrea.ms/schema/1.0/activity'\n    end\n\n    it 'appends activity:verb element with favorite' do\n      favourite = Fabricate(:favourite)\n\n      unfavourite_salmon = OStatus::AtomSerializer.new.unfavourite_salmon(favourite)\n\n      verb = unfavourite_salmon.nodes.find { |node| node.name == 'activity:verb' }\n      expect(verb.text).to eq OStatus::TagManager::VERBS[:unfavorite]\n    end\n\n    it 'appends activity:object element with status' do\n      status = Fabricate(:status, created_at: '2000-01-01T00:00:00Z')\n      favourite = Fabricate(:favourite, status: status)\n\n      unfavourite_salmon = OStatus::AtomSerializer.new.unfavourite_salmon(favourite)\n\n      object = unfavourite_salmon.nodes.find { |node| node.name == 'activity:object' }\n      expect(object.id.text).to eq \"https://cb6e6126.ngrok.io/users/#{status.account.to_param}/statuses/#{status.id}\"\n    end\n\n    it 'appends thr:in-reply-to element for status' do\n      status_account = Fabricate(:account, username: 'username')\n      status = Fabricate(:status, account: status_account, created_at: '2000-01-01T00:00:00Z')\n      favourite = Fabricate(:favourite, status: status)\n\n      unfavourite_salmon = OStatus::AtomSerializer.new.unfavourite_salmon(favourite)\n\n      in_reply_to = unfavourite_salmon.nodes.find { |node| node.name == 'thr:in-reply-to' }\n      expect(in_reply_to.ref).to eq \"https://cb6e6126.ngrok.io/users/#{status.account.to_param}/statuses/#{status.id}\"\n      expect(in_reply_to.href).to eq \"https://cb6e6126.ngrok.io/@username/#{status.id}\"\n    end\n\n    it 'includes description' do\n      account = Fabricate(:account, domain: nil, username: 'account')\n      status_account = Fabricate(:account, domain: 'remote', username: 'status_account')\n      status = Fabricate(:status, account: status_account)\n      favourite = Fabricate(:favourite, account: account, status: status)\n\n      unfavourite_salmon = OStatus::AtomSerializer.new.unfavourite_salmon(favourite)\n\n      expect(unfavourite_salmon.title.text).to eq 'account no longer favourites a status by status_account@remote'\n      expect(unfavourite_salmon.content.text).to eq 'account no longer favourites a status by status_account@remote'\n    end\n\n    it 'returns element whose rendered view triggers unfavourite when processed' do\n      favourite = Fabricate(:favourite)\n      unfavourite_salmon = OStatus::AtomSerializer.new.unfavourite_salmon(favourite)\n      xml = OStatus::AtomSerializer.render(unfavourite_salmon)\n      envelope = OStatus2::Salmon.new.pack(xml, favourite.account.keypair)\n\n      ProcessInteractionService.new.call(envelope, favourite.status.account)\n      expect { favourite.reload }.to raise_error ActiveRecord::RecordNotFound\n    end\n  end\n\n  describe '#follow_salmon' do\n    include_examples 'namespaces' do\n      def serialize\n        follow = Fabricate(:follow)\n        OStatus::AtomSerializer.new.follow_salmon(follow)\n      end\n    end\n\n    it 'returns entry element' do\n      follow = Fabricate(:follow)\n      follow_salmon = OStatus::AtomSerializer.new.follow_salmon(follow)\n      expect(follow_salmon.name).to eq 'entry'\n    end\n\n    it 'appends id element with unique tag' do\n      follow = Fabricate(:follow, created_at: '2000-01-01T00:00:00Z')\n      follow_salmon = OStatus::AtomSerializer.new.follow_salmon(follow)\n      expect(follow_salmon.id.text).to eq \"tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{follow.id}:objectType=Follow\"\n    end\n\n    it 'appends author element with account' do\n      account = Fabricate(:account, domain: nil, username: 'username')\n      follow = Fabricate(:follow, account: account)\n\n      follow_salmon = OStatus::AtomSerializer.new.follow_salmon(follow)\n\n      expect(follow_salmon.author.id.text).to eq 'https://cb6e6126.ngrok.io/users/username'\n    end\n\n    it 'appends activity:object-type element with activity type' do\n      follow = Fabricate(:follow)\n\n      follow_salmon = OStatus::AtomSerializer.new.follow_salmon(follow)\n\n      object_type = follow_salmon.nodes.find { |node| node.name == 'activity:object-type' }\n      expect(object_type.text).to eq OStatus::TagManager::TYPES[:activity]\n    end\n\n    it 'appends activity:verb element with follow' do\n      follow = Fabricate(:follow)\n\n      follow_salmon = OStatus::AtomSerializer.new.follow_salmon(follow)\n\n      verb = follow_salmon.nodes.find { |node| node.name == 'activity:verb' }\n      expect(verb.text).to eq OStatus::TagManager::VERBS[:follow]\n    end\n\n    it 'appends activity:object element with target account' do\n      target_account = Fabricate(:account, domain: 'domain.test', uri: 'https://domain.test/id')\n      follow = Fabricate(:follow, target_account: target_account)\n\n      follow_salmon = OStatus::AtomSerializer.new.follow_salmon(follow)\n\n      object = follow_salmon.nodes.find { |node| node.name == 'activity:object' }\n      expect(object.id.text).to eq 'https://domain.test/id'\n    end\n\n    it 'includes description' do\n      account = Fabricate(:account, domain: nil, username: 'account')\n      target_account = Fabricate(:account, domain: 'remote', username: 'target_account')\n      follow = Fabricate(:follow, account: account, target_account: target_account)\n\n      follow_salmon = OStatus::AtomSerializer.new.follow_salmon(follow)\n\n      expect(follow_salmon.title.text).to eq 'account started following target_account@remote'\n      expect(follow_salmon.content.text).to eq 'account started following target_account@remote'\n    end\n\n    it 'returns element whose rendered view triggers follow when processed' do\n      follow = Fabricate(:follow)\n      follow_salmon = OStatus::AtomSerializer.new.follow_salmon(follow)\n      xml = OStatus::AtomSerializer.render(follow_salmon)\n      follow.destroy!\n      envelope = OStatus2::Salmon.new.pack(xml, follow.account.keypair)\n\n      ProcessInteractionService.new.call(envelope, follow.target_account)\n\n      expect(follow.account.following?(follow.target_account)).to be true\n    end\n  end\n\n  describe '#unfollow_salmon' do\n    include_examples 'namespaces' do\n      def serialize\n        follow = Fabricate(:follow)\n        follow.destroy!\n        OStatus::AtomSerializer.new.unfollow_salmon(follow)\n      end\n    end\n\n    it 'returns entry element' do\n      follow = Fabricate(:follow)\n      follow.destroy!\n\n      unfollow_salmon = OStatus::AtomSerializer.new.unfollow_salmon(follow)\n\n      expect(unfollow_salmon.name).to eq 'entry'\n    end\n\n    it 'appends id element with unique tag' do\n      follow = Fabricate(:follow)\n      follow.destroy!\n\n      time_before = Time.zone.now\n      unfollow_salmon = OStatus::AtomSerializer.new.unfollow_salmon(follow)\n      time_after = Time.zone.now\n\n      expect(unfollow_salmon.id.text).to(\n        eq(OStatus::TagManager.instance.unique_tag(time_before.utc, follow.id, 'Follow'))\n          .or(eq(OStatus::TagManager.instance.unique_tag(time_after.utc, follow.id, 'Follow')))\n      )\n    end\n\n    it 'appends title element with description' do\n      account = Fabricate(:account, domain: nil, username: 'account')\n      target_account = Fabricate(:account, domain: 'remote', username: 'target_account')\n      follow = Fabricate(:follow, account: account, target_account: target_account)\n      follow.destroy!\n\n      unfollow_salmon = OStatus::AtomSerializer.new.unfollow_salmon(follow)\n\n      expect(unfollow_salmon.title.text).to eq 'account is no longer following target_account@remote'\n    end\n\n    it 'appends content element with description' do\n      account = Fabricate(:account, domain: nil, username: 'account')\n      target_account = Fabricate(:account, domain: 'remote', username: 'target_account')\n      follow = Fabricate(:follow, account: account, target_account: target_account)\n      follow.destroy!\n\n      unfollow_salmon = OStatus::AtomSerializer.new.unfollow_salmon(follow)\n\n      expect(unfollow_salmon.content.text).to eq 'account is no longer following target_account@remote'\n    end\n\n    it 'appends author element with account' do\n      account = Fabricate(:account, domain: nil, username: 'username')\n      follow = Fabricate(:follow, account: account)\n      follow.destroy!\n\n      unfollow_salmon = OStatus::AtomSerializer.new.unfollow_salmon(follow)\n\n      expect(unfollow_salmon.author.id.text).to eq 'https://cb6e6126.ngrok.io/users/username'\n    end\n\n    it 'appends activity:object-type element with activity type' do\n      follow = Fabricate(:follow)\n      follow.destroy!\n\n      unfollow_salmon = OStatus::AtomSerializer.new.unfollow_salmon(follow)\n\n      object_type = unfollow_salmon.nodes.find { |node| node.name == 'activity:object-type' }\n      expect(object_type.text).to eq OStatus::TagManager::TYPES[:activity]\n    end\n\n    it 'appends activity:verb element with follow' do\n      follow = Fabricate(:follow)\n      follow.destroy!\n\n      unfollow_salmon = OStatus::AtomSerializer.new.unfollow_salmon(follow)\n\n      verb = unfollow_salmon.nodes.find { |node| node.name == 'activity:verb' }\n      expect(verb.text).to eq OStatus::TagManager::VERBS[:unfollow]\n    end\n\n    it 'appends activity:object element with target account' do\n      target_account = Fabricate(:account, domain: 'domain.test', uri: 'https://domain.test/id')\n      follow = Fabricate(:follow, target_account: target_account)\n      follow.destroy!\n\n      unfollow_salmon = OStatus::AtomSerializer.new.unfollow_salmon(follow)\n\n      object = unfollow_salmon.nodes.find { |node| node.name == 'activity:object' }\n      expect(object.id.text).to eq 'https://domain.test/id'\n    end\n\n    it 'returns element whose rendered view triggers unfollow when processed' do\n      follow = Fabricate(:follow)\n      follow.destroy!\n      unfollow_salmon = OStatus::AtomSerializer.new.unfollow_salmon(follow)\n      xml = OStatus::AtomSerializer.render(unfollow_salmon)\n      follow.account.follow!(follow.target_account)\n      envelope = OStatus2::Salmon.new.pack(xml, follow.account.keypair)\n\n      ProcessInteractionService.new.call(envelope, follow.target_account)\n\n      expect(follow.account.following?(follow.target_account)).to be false\n    end\n  end\n\n  describe '#follow_request_salmon' do\n    include_examples 'namespaces' do\n      def serialize\n        follow_request = Fabricate(:follow_request)\n        OStatus::AtomSerializer.new.follow_request_salmon(follow_request)\n      end\n    end\n\n    context do\n      def serialize(follow_request)\n        OStatus::AtomSerializer.new.follow_request_salmon(follow_request)\n      end\n\n      it_behaves_like 'follow request salmon'\n\n      it 'appends id element with unique tag' do\n        follow_request = Fabricate(:follow_request, created_at: '2000-01-01T00:00:00Z')\n        follow_request_salmon = serialize(follow_request)\n        expect(follow_request_salmon.id.text).to eq \"tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{follow_request.id}:objectType=FollowRequest\"\n      end\n\n      it 'appends title element with description' do\n        account = Fabricate(:account, domain: nil, username: 'account')\n        target_account = Fabricate(:account, domain: 'remote', username: 'target_account')\n        follow_request = Fabricate(:follow_request, account: account, target_account: target_account)\n        follow_request_salmon = serialize(follow_request)\n        expect(follow_request_salmon.title.text).to eq 'account requested to follow target_account@remote'\n      end\n\n      it 'returns element whose rendered view triggers follow request when processed' do\n        follow_request = Fabricate(:follow_request)\n        follow_request_salmon = serialize(follow_request)\n        xml = OStatus::AtomSerializer.render(follow_request_salmon)\n        envelope = OStatus2::Salmon.new.pack(xml, follow_request.account.keypair)\n        follow_request.destroy!\n\n        ProcessInteractionService.new.call(envelope, follow_request.target_account)\n\n        expect(follow_request.account.requested?(follow_request.target_account)).to eq true\n      end\n    end\n  end\n\n  describe '#authorize_follow_request_salmon' do\n    include_examples 'namespaces' do\n      def serialize\n        follow_request = Fabricate(:follow_request)\n        OStatus::AtomSerializer.new.authorize_follow_request_salmon(follow_request)\n      end\n    end\n\n    it_behaves_like 'follow request salmon' do\n      def serialize(follow_request)\n        authorize_follow_request_salmon = OStatus::AtomSerializer.new.authorize_follow_request_salmon(follow_request)\n        authorize_follow_request_salmon.nodes.find { |node| node.name == 'activity:object' }\n      end\n    end\n\n    it 'appends id element with unique tag' do\n      follow_request = Fabricate(:follow_request)\n\n      time_before = Time.zone.now\n      authorize_follow_request_salmon = OStatus::AtomSerializer.new.authorize_follow_request_salmon(follow_request)\n      time_after = Time.zone.now\n\n      expect(authorize_follow_request_salmon.id.text).to(\n        eq(OStatus::TagManager.instance.unique_tag(time_before.utc, follow_request.id, 'FollowRequest'))\n          .or(eq(OStatus::TagManager.instance.unique_tag(time_after.utc, follow_request.id, 'FollowRequest')))\n      )\n    end\n\n    it 'appends title element with description' do\n      account = Fabricate(:account, domain: 'remote', username: 'account')\n      target_account = Fabricate(:account, domain: nil, username: 'target_account')\n      follow_request = Fabricate(:follow_request, account: account, target_account: target_account)\n\n      authorize_follow_request_salmon = OStatus::AtomSerializer.new.authorize_follow_request_salmon(follow_request)\n\n      expect(authorize_follow_request_salmon.title.text).to eq 'target_account authorizes follow request by account@remote'\n    end\n\n    it 'appends activity:object-type element with activity type' do\n      follow_request = Fabricate(:follow_request)\n\n      authorize_follow_request_salmon = OStatus::AtomSerializer.new.authorize_follow_request_salmon(follow_request)\n\n      object_type = authorize_follow_request_salmon.nodes.find { |node| node.name == 'activity:object-type' }\n      expect(object_type.text).to eq OStatus::TagManager::TYPES[:activity]\n    end\n\n    it 'appends activity:verb element with authorize' do\n      follow_request = Fabricate(:follow_request)\n\n      authorize_follow_request_salmon = OStatus::AtomSerializer.new.authorize_follow_request_salmon(follow_request)\n\n      verb = authorize_follow_request_salmon.nodes.find { |node| node.name == 'activity:verb' }\n      expect(verb.text).to eq OStatus::TagManager::VERBS[:authorize]\n    end\n\n    it 'returns element whose rendered view creates follow from follow request when processed' do\n      follow_request = Fabricate(:follow_request)\n      authorize_follow_request_salmon = OStatus::AtomSerializer.new.authorize_follow_request_salmon(follow_request)\n      xml = OStatus::AtomSerializer.render(authorize_follow_request_salmon)\n      envelope = OStatus2::Salmon.new.pack(xml, follow_request.target_account.keypair)\n\n      ProcessInteractionService.new.call(envelope, follow_request.account)\n\n      expect(follow_request.account.following?(follow_request.target_account)).to eq true\n      expect { follow_request.reload }.to raise_error ActiveRecord::RecordNotFound\n    end\n  end\n\n  describe '#reject_follow_request_salmon' do\n    include_examples 'namespaces' do\n      def serialize\n        follow_request = Fabricate(:follow_request)\n        OStatus::AtomSerializer.new.reject_follow_request_salmon(follow_request)\n      end\n    end\n\n    it_behaves_like 'follow request salmon' do\n      def serialize(follow_request)\n        reject_follow_request_salmon = OStatus::AtomSerializer.new.reject_follow_request_salmon(follow_request)\n        reject_follow_request_salmon.nodes.find { |node| node.name == 'activity:object' }\n      end\n    end\n\n    it 'appends id element with unique tag' do\n      follow_request = Fabricate(:follow_request)\n\n      time_before = Time.zone.now\n      reject_follow_request_salmon = OStatus::AtomSerializer.new.reject_follow_request_salmon(follow_request)\n      time_after = Time.zone.now\n\n      expect(reject_follow_request_salmon.id.text).to(\n        eq(OStatus::TagManager.instance.unique_tag(time_before.utc, follow_request.id, 'FollowRequest'))\n          .or(OStatus::TagManager.instance.unique_tag(time_after.utc, follow_request.id, 'FollowRequest'))\n      )\n    end\n\n    it 'appends title element with description' do\n      account = Fabricate(:account, domain: 'remote', username: 'account')\n      target_account = Fabricate(:account, domain: nil, username: 'target_account')\n      follow_request = Fabricate(:follow_request, account: account, target_account: target_account)\n      reject_follow_request_salmon = OStatus::AtomSerializer.new.reject_follow_request_salmon(follow_request)\n      expect(reject_follow_request_salmon.title.text).to eq 'target_account rejects follow request by account@remote'\n    end\n\n    it 'appends activity:object-type element with activity type' do\n      follow_request = Fabricate(:follow_request)\n      reject_follow_request_salmon = OStatus::AtomSerializer.new.reject_follow_request_salmon(follow_request)\n      object_type = reject_follow_request_salmon.nodes.find { |node| node.name == 'activity:object-type' }\n      expect(object_type.text).to eq OStatus::TagManager::TYPES[:activity]\n    end\n\n    it 'appends activity:verb element with authorize' do\n      follow_request = Fabricate(:follow_request)\n      reject_follow_request_salmon = OStatus::AtomSerializer.new.reject_follow_request_salmon(follow_request)\n      verb = reject_follow_request_salmon.nodes.find { |node| node.name == 'activity:verb' }\n      expect(verb.text).to eq OStatus::TagManager::VERBS[:reject]\n    end\n\n    it 'returns element whose rendered view deletes follow request when processed' do\n      follow_request = Fabricate(:follow_request)\n      reject_follow_request_salmon = OStatus::AtomSerializer.new.reject_follow_request_salmon(follow_request)\n      xml = OStatus::AtomSerializer.render(reject_follow_request_salmon)\n      envelope = OStatus2::Salmon.new.pack(xml, follow_request.target_account.keypair)\n\n      ProcessInteractionService.new.call(envelope, follow_request.account)\n\n      expect(follow_request.account.following?(follow_request.target_account)).to eq false\n      expect { follow_request.reload }.to raise_error ActiveRecord::RecordNotFound\n    end\n  end\n\n  describe '#object' do\n    include_examples 'status attributes' do\n      def serialize(status)\n        OStatus::AtomSerializer.new.object(status)\n      end\n    end\n\n    it 'returns activity:object element' do\n      status = Fabricate(:status)\n      object = OStatus::AtomSerializer.new.object(status)\n      expect(object.name).to eq 'activity:object'\n    end\n\n    it 'appends id element with URL for status' do\n      status = Fabricate(:status, created_at: '2000-01-01T00:00:00Z')\n      object = OStatus::AtomSerializer.new.object(status)\n      expect(object.id.text).to eq \"https://cb6e6126.ngrok.io/users/#{status.account.to_param}/statuses/#{status.id}\"\n    end\n\n    it 'appends published element with created date' do\n      status = Fabricate(:status, created_at: '2000-01-01T00:00:00Z')\n      object = OStatus::AtomSerializer.new.object(status)\n      expect(object.published.text).to eq '2000-01-01T00:00:00Z'\n    end\n\n    it 'appends updated element with updated date' do\n      status = Fabricate(:status)\n      status.updated_at = '2000-01-01T00:00:00Z'\n      object = OStatus::AtomSerializer.new.object(status)\n      expect(object.updated.text).to eq '2000-01-01T00:00:00Z'\n    end\n\n    it 'appends title element with title' do\n      account = Fabricate(:account, username: 'username')\n      status = Fabricate(:status, account: account)\n\n      object = OStatus::AtomSerializer.new.object(status)\n\n      expect(object.title.text).to eq 'New status by username'\n    end\n\n    it 'appends author element with account' do\n      account = Fabricate(:account, username: 'username')\n      status = Fabricate(:status, account: account)\n\n      entry = OStatus::AtomSerializer.new.object(status)\n\n      expect(entry.author.id.text).to eq 'https://cb6e6126.ngrok.io/users/username'\n    end\n\n    it 'appends activity:object-type element with object type' do\n      status = Fabricate(:status)\n\n      entry = OStatus::AtomSerializer.new.object(status)\n\n      object_type = entry.nodes.find { |node| node.name == 'activity:object-type' }\n      expect(object_type.text).to eq OStatus::TagManager::TYPES[:note]\n    end\n\n    it 'appends activity:verb element with verb' do\n      status = Fabricate(:status)\n\n      entry = OStatus::AtomSerializer.new.object(status)\n\n      object_type = entry.nodes.find { |node| node.name == 'activity:verb' }\n      expect(object_type.text).to eq OStatus::TagManager::VERBS[:post]\n    end\n\n    it 'appends link element for an alternative' do\n      account = Fabricate(:account, username: 'username')\n      status = Fabricate(:status, account: account)\n\n      entry = OStatus::AtomSerializer.new.object(status)\n\n      link = entry.nodes.find { |node| node.name == 'link' && node[:rel] == 'alternate' && node[:type] == 'text/html' }\n      expect(link[:type]).to eq 'text/html'\n      expect(link[:href]).to eq \"https://cb6e6126.ngrok.io/@username/#{status.id}\"\n    end\n\n    it 'appends thr:in-reply-to element if it is a reply and thread is not nil' do\n      account = Fabricate(:account, username: 'username')\n      thread = Fabricate(:status, account: account, created_at: '2000-01-01T00:00:00Z')\n      reply = Fabricate(:status, thread: thread)\n\n      entry = OStatus::AtomSerializer.new.object(reply)\n\n      in_reply_to = entry.nodes.find { |node| node.name == 'thr:in-reply-to' }\n      expect(in_reply_to.ref).to eq \"https://cb6e6126.ngrok.io/users/#{thread.account.to_param}/statuses/#{thread.id}\"\n      expect(in_reply_to.href).to eq \"https://cb6e6126.ngrok.io/@username/#{thread.id}\"\n    end\n\n    it 'does not append thr:in-reply-to element if thread is nil' do\n      status = Fabricate(:status, thread: nil)\n      entry = OStatus::AtomSerializer.new.object(status)\n      entry.nodes.each { |node| expect(node.name).not_to eq 'thr:in-reply-to' }\n    end\n\n    it 'does not append ostatus:conversation element if conversation_id is nil' do\n      status = Fabricate.build(:status, conversation_id: nil)\n      status.save!(validate: false)\n\n      entry = OStatus::AtomSerializer.new.object(status)\n\n      entry.nodes.each { |node| expect(node.name).not_to eq 'ostatus:conversation' }\n    end\n\n    it 'appends ostatus:conversation element if conversation_id is not nil' do\n      status = Fabricate(:status)\n      status.conversation.update!(created_at: '2000-01-01T00:00:00Z')\n\n      entry = OStatus::AtomSerializer.new.object(status)\n\n      conversation = entry.nodes.find { |node| node.name == 'ostatus:conversation' }\n      expect(conversation[:ref]).to eq \"tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{status.conversation.id}:objectType=Conversation\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/lib/ostatus/tag_manager_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe OStatus::TagManager do\n  describe '#unique_tag' do\n    it 'returns a unique tag' do\n      expect(OStatus::TagManager.instance.unique_tag(Time.utc(2000), 12, 'Status')).to eq 'tag:cb6e6126.ngrok.io,2000-01-01:objectId=12:objectType=Status'\n    end\n  end\n\n  describe '#unique_tag_to_local_id' do\n    it 'returns the ID part' do\n      expect(OStatus::TagManager.instance.unique_tag_to_local_id('tag:cb6e6126.ngrok.io,2000-01-01:objectId=12:objectType=Status', 'Status')).to eql '12'\n    end\n\n    it 'returns nil if it is not local id' do\n      expect(OStatus::TagManager.instance.unique_tag_to_local_id('tag:remote,2000-01-01:objectId=12:objectType=Status', 'Status')).to eq nil\n    end\n\n    it 'returns nil if it is not expected type' do\n      expect(OStatus::TagManager.instance.unique_tag_to_local_id('tag:cb6e6126.ngrok.io,2000-01-01:objectId=12:objectType=Block', 'Status')).to eq nil\n    end\n\n    it 'returns nil if it does not have object ID' do\n      expect(OStatus::TagManager.instance.unique_tag_to_local_id('tag:cb6e6126.ngrok.io,2000-01-01:objectType=Status', 'Status')).to eq nil\n    end\n  end\n\n  describe '#local_id?' do\n    it 'returns true for a local ID' do\n      expect(OStatus::TagManager.instance.local_id?('tag:cb6e6126.ngrok.io;objectId=12:objectType=Status')).to be true\n    end\n\n    it 'returns false for a foreign ID' do\n      expect(OStatus::TagManager.instance.local_id?('tag:foreign.tld;objectId=12:objectType=Status')).to be false\n    end\n  end\n\n  describe '#uri_for' do\n    subject { OStatus::TagManager.instance.uri_for(target) }\n\n    context 'comment object' do\n      let(:target) { Fabricate(:status, created_at: '2000-01-01T00:00:00Z', reply: true) }\n\n      it 'returns the unique tag for status' do\n        expect(target.object_type).to eq :comment\n        is_expected.to eq target.uri\n      end\n    end\n\n    context 'note object' do\n      let(:target) { Fabricate(:status, created_at: '2000-01-01T00:00:00Z', reply: false, thread: nil) }\n\n      it 'returns the unique tag for status' do\n        expect(target.object_type).to eq :note\n        is_expected.to eq target.uri\n      end\n    end\n\n    context 'person object' do\n      let(:target) { Fabricate(:account, username: 'alice') }\n\n      it 'returns the URL for account' do\n        expect(target.object_type).to eq :person\n        is_expected.to eq 'https://cb6e6126.ngrok.io/users/alice'\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/lib/proof_provider/keybase/verifier_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe ProofProvider::Keybase::Verifier do\n  let(:my_domain) { Rails.configuration.x.local_domain }\n\n  let(:keybase_proof) do\n    local_proof = AccountIdentityProof.new(\n      provider: 'Keybase',\n      provider_username: 'cryptoalice',\n      token: '11111111111111111111111111'\n    )\n\n    described_class.new('alice', 'cryptoalice', '11111111111111111111111111', my_domain)\n  end\n\n  let(:query_params) do\n    \"domain=#{my_domain}&kb_username=cryptoalice&sig_hash=11111111111111111111111111&username=alice\"\n  end\n\n  describe '#valid?' do\n    let(:base_url) { 'https://keybase.io/_/api/1.0/sig/proof_valid.json' }\n\n    context 'when valid' do\n      before do\n        json_response_body = '{\"status\":{\"code\":0,\"name\":\"OK\"},\"proof_valid\":true}'\n        stub_request(:get, \"#{base_url}?#{query_params}\").to_return(status: 200, body: json_response_body)\n      end\n\n      it 'calls out to keybase and returns true' do\n        expect(keybase_proof.valid?).to eq true\n      end\n    end\n\n    context 'when invalid' do\n      before do\n        json_response_body = '{\"status\":{\"code\":0,\"name\":\"OK\"},\"proof_valid\":false}'\n        stub_request(:get, \"#{base_url}?#{query_params}\").to_return(status: 200, body: json_response_body)\n      end\n\n      it 'calls out to keybase and returns false' do\n        expect(keybase_proof.valid?).to eq false\n      end\n    end\n\n    context 'with an unexpected api response' do\n      before do\n        json_response_body = '{\"status\":{\"code\":100,\"desc\":\"wrong size hex_id\",\"fields\":{\"sig_hash\":\"wrong size hex_id\"},\"name\":\"INPUT_ERROR\"}}'\n        stub_request(:get, \"#{base_url}?#{query_params}\").to_return(status: 200, body: json_response_body)\n      end\n\n      it 'swallows the error and returns false' do\n        expect(keybase_proof.valid?).to eq false\n      end\n    end\n  end\n\n  describe '#status' do\n    let(:base_url) { 'https://keybase.io/_/api/1.0/sig/proof_live.json' }\n\n    context 'with a normal response' do\n      before do\n        json_response_body = '{\"status\":{\"code\":0,\"name\":\"OK\"},\"proof_live\":false,\"proof_valid\":true}'\n        stub_request(:get, \"#{base_url}?#{query_params}\").to_return(status: 200, body: json_response_body)\n      end\n\n      it 'calls out to keybase and returns the status fields as proof_valid and proof_live' do\n        expect(keybase_proof.status).to include({ 'proof_valid' => true, 'proof_live' => false })\n      end\n    end\n\n    context 'with an unexpected keybase response' do\n      before do\n        json_response_body = '{\"status\":{\"code\":100,\"desc\":\"missing non-optional field sig_hash\",\"fields\":{\"sig_hash\":\"missing non-optional field sig_hash\"},\"name\":\"INPUT_ERROR\"}}'\n        stub_request(:get, \"#{base_url}?#{query_params}\").to_return(status: 200, body: json_response_body)\n      end\n\n      it 'raises a ProofProvider::Keybase::UnexpectedResponseError' do\n        expect { keybase_proof.status }.to raise_error ProofProvider::Keybase::UnexpectedResponseError\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/lib/request_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\nrequire 'securerandom'\n\ndescribe Request do\n  subject { Request.new(:get, 'http://example.com') }\n\n  describe '#headers' do\n    it 'returns user agent' do\n      expect(subject.headers['User-Agent']).to be_present\n    end\n\n    it 'returns the date header' do\n      expect(subject.headers['Date']).to be_present\n    end\n\n    it 'returns the host header' do\n      expect(subject.headers['Host']).to be_present\n    end\n\n    it 'does not return virtual request-target header' do\n      expect(subject.headers['(request-target)']).to be_nil\n    end\n  end\n\n  describe '#on_behalf_of' do\n    it 'when used, adds signature header' do\n      subject.on_behalf_of(Fabricate(:account))\n      expect(subject.headers['Signature']).to be_present\n    end\n  end\n\n  describe '#add_headers' do\n    it 'adds headers to the request' do\n      subject.add_headers('Test' => 'Foo')\n      expect(subject.headers['Test']).to eq 'Foo'\n    end\n  end\n\n  describe '#perform' do\n    context 'with valid host' do\n      before { stub_request(:get, 'http://example.com') }\n\n      it 'executes a HTTP request' do\n        expect { |block| subject.perform &block }.to yield_control\n        expect(a_request(:get, 'http://example.com')).to have_been_made.once\n      end\n\n      it 'executes a HTTP request when the first address is private' do\n        resolver = double\n\n        allow(resolver).to receive(:getaddresses).with('example.com').and_return(%w(0.0.0.0 2001:4860:4860::8844))\n        allow(resolver).to receive(:timeouts=).and_return(nil)\n        allow(Resolv::DNS).to receive(:open).and_yield(resolver)\n\n        expect { |block| subject.perform &block }.to yield_control\n        expect(a_request(:get, 'http://example.com')).to have_been_made.once\n      end\n\n      it 'sets headers' do\n        expect { |block| subject.perform &block }.to yield_control\n        expect(a_request(:get, 'http://example.com').with(headers: subject.headers)).to have_been_made\n      end\n\n      it 'closes underlaying connection' do\n        expect_any_instance_of(HTTP::Client).to receive(:close)\n        expect { |block| subject.perform &block }.to yield_control\n      end\n\n      it 'returns response which implements body_with_limit' do\n        subject.perform do |response|\n          expect(response).to respond_to :body_with_limit\n        end\n      end\n    end\n\n    context 'with private host' do\n      around do |example|\n        WebMock.disable!\n        example.run\n        WebMock.enable!\n      end\n\n      it 'raises Mastodon::ValidationError' do\n        resolver = double\n\n        allow(resolver).to receive(:getaddresses).with('example.com').and_return(%w(0.0.0.0 2001:db8::face))\n        allow(resolver).to receive(:timeouts=).and_return(nil)\n        allow(Resolv::DNS).to receive(:open).and_yield(resolver)\n\n        expect { subject.perform }.to raise_error Mastodon::ValidationError\n      end\n    end\n  end\n\n  describe \"response's body_with_limit method\" do\n    it 'rejects body more than 1 megabyte by default' do\n      stub_request(:any, 'http://example.com').to_return(body: SecureRandom.random_bytes(2.megabytes))\n      expect { subject.perform { |response| response.body_with_limit } }.to raise_error Mastodon::LengthValidationError\n    end\n\n    it 'accepts body less than 1 megabyte by default' do\n      stub_request(:any, 'http://example.com').to_return(body: SecureRandom.random_bytes(2.kilobytes))\n      expect { subject.perform { |response| response.body_with_limit } }.not_to raise_error\n    end\n\n    it 'rejects body by given size' do\n      stub_request(:any, 'http://example.com').to_return(body: SecureRandom.random_bytes(2.kilobytes))\n      expect { subject.perform { |response| response.body_with_limit(1.kilobyte) } }.to raise_error Mastodon::LengthValidationError\n    end\n\n    it 'rejects too large chunked body' do\n      stub_request(:any, 'http://example.com').to_return(body: SecureRandom.random_bytes(2.megabytes), headers: { 'Transfer-Encoding' => 'chunked' })\n      expect { subject.perform { |response| response.body_with_limit } }.to raise_error Mastodon::LengthValidationError\n    end\n\n    it 'rejects too large monolithic body' do\n      stub_request(:any, 'http://example.com').to_return(body: SecureRandom.random_bytes(2.megabytes), headers: { 'Content-Length' => 2.megabytes })\n      expect { subject.perform { |response| response.body_with_limit } }.to raise_error Mastodon::LengthValidationError\n    end\n\n    it 'uses binary encoding if Content-Type does not tell encoding' do\n      stub_request(:any, 'http://example.com').to_return(body: '', headers: { 'Content-Type' => 'text/html' })\n      expect(subject.perform { |response| response.body_with_limit.encoding }).to eq Encoding::BINARY\n    end\n\n    it 'uses binary encoding if Content-Type tells unknown encoding' do\n      stub_request(:any, 'http://example.com').to_return(body: '', headers: { 'Content-Type' => 'text/html; charset=unknown' })\n      expect(subject.perform { |response| response.body_with_limit.encoding }).to eq Encoding::BINARY\n    end\n\n    it 'uses encoding specified by Content-Type' do\n      stub_request(:any, 'http://example.com').to_return(body: '', headers: { 'Content-Type' => 'text/html; charset=UTF-8' })\n      expect(subject.perform { |response| response.body_with_limit.encoding }).to eq Encoding::UTF_8\n    end\n  end\nend\n"
  },
  {
    "path": "spec/lib/settings/extend_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe Settings::Extend do\n  class User\n    include Settings::Extend\n  end\n\n  describe '#settings' do\n    it 'sets @settings as an instance of Settings::ScopedSettings' do\n      user = Fabricate(:user)\n      expect(user.settings).to be_kind_of Settings::ScopedSettings\n    end\n  end\nend\n"
  },
  {
    "path": "spec/lib/settings/scoped_settings_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe Settings::ScopedSettings do\n  let(:object)         { Fabricate(:user) }\n  let(:scoped_setting) { described_class.new(object) }\n  let(:val)            { 'whatever' }\n  let(:methods)        { %i(auto_play_gif default_sensitive unfollow_modal boost_modal delete_modal reduce_motion system_font_ui noindex theme) }\n\n  describe '.initialize' do\n    it 'sets @object' do\n      scoped_setting = described_class.new(object)\n      expect(scoped_setting.instance_variable_get(:@object)).to be object\n    end\n  end\n\n  describe '#method_missing' do\n    it 'sets scoped_setting.method_name = val' do\n      methods.each do |key|\n        scoped_setting.send(\"#{key}=\", val)\n        expect(scoped_setting.send(key)).to eq val\n      end\n    end\n  end\n\n  describe '#[]= and #[]' do\n    it 'sets [key] = val' do\n      methods.each do |key|\n        scoped_setting[key] = val\n        expect(scoped_setting[key]).to eq val\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/lib/status_filter_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe StatusFilter do\n  describe '#filtered?' do\n    let(:status) { Fabricate(:status) }\n\n    context 'without an account' do\n      subject { described_class.new(status, nil) }\n\n      context 'when there are no connections' do\n        it { is_expected.not_to be_filtered }\n      end\n\n      context 'when status account is silenced' do\n        before do\n          status.account.silence!\n        end\n\n        it { is_expected.to be_filtered }\n      end\n\n      context 'when status policy does not allow show' do\n        before do\n          expect_any_instance_of(StatusPolicy).to receive(:show?).and_return(false)\n        end\n\n        it { is_expected.to be_filtered }\n      end\n    end\n\n    context 'with real account' do\n      let(:account) { Fabricate(:account) }\n      subject { described_class.new(status, account) }\n\n      context 'when there are no connections' do\n        it { is_expected.not_to be_filtered }\n      end\n\n      context 'when status account is blocked' do\n        before do\n          Fabricate(:block, account: account, target_account: status.account)\n        end\n\n        it { is_expected.to be_filtered }\n      end\n\n      context 'when status account domain is blocked' do\n        before do\n          status.account.update(domain: 'example.com')\n          Fabricate(:account_domain_block, account: account, domain: status.account_domain)\n        end\n\n        it { is_expected.to be_filtered }\n      end\n\n      context 'when status account is muted' do\n        before do\n          Fabricate(:mute, account: account, target_account: status.account)\n        end\n\n        it { is_expected.to be_filtered }\n      end\n\n      context 'when status account is silenced' do\n        before do\n          status.account.silence!\n        end\n\n        it { is_expected.to be_filtered }\n      end\n\n      context 'when status policy does not allow show' do\n        before do\n          expect_any_instance_of(StatusPolicy).to receive(:show?).and_return(false)\n        end\n\n        it { is_expected.to be_filtered }\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/lib/status_finder_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe StatusFinder do\n  include RoutingHelper\n\n  describe '#status' do\n    subject { described_class.new(url) }\n\n    context 'with a status url' do\n      let(:status) { Fabricate(:status) }\n      let(:url) { short_account_status_url(account_username: status.account.username, id: status.id) }\n\n      it 'finds the stream entry' do\n        expect(subject.status).to eq(status)\n      end\n\n      it 'raises an error if action is not :show' do\n        recognized = Rails.application.routes.recognize_path(url)\n        expect(recognized).to receive(:[]).with(:action).and_return(:create)\n        expect(Rails.application.routes).to receive(:recognize_path).with(url).and_return(recognized)\n\n        expect { subject.status }.to raise_error(ActiveRecord::RecordNotFound)\n      end\n    end\n\n    context 'with a stream entry url' do\n      let(:stream_entry) { Fabricate(:stream_entry) }\n      let(:url) { account_stream_entry_url(stream_entry.account, stream_entry) }\n\n      it 'finds the stream entry' do\n        expect(subject.status).to eq(stream_entry.status)\n      end\n    end\n\n    context 'with a remote url even if id exists on local' do\n      let(:status) { Fabricate(:status) }\n      let(:url) { \"https://example.com/users/test/statuses/#{status.id}\" }\n\n      it 'raises an error' do\n        expect { subject.status }.to raise_error(ActiveRecord::RecordNotFound)\n      end\n    end\n\n    context 'with a plausible url' do\n      let(:url) { 'https://example.com/users/test/updates/123/embed' }\n\n      it 'raises an error' do\n        expect { subject.status }.to raise_error(ActiveRecord::RecordNotFound)\n      end\n    end\n\n    context 'with an unrecognized url' do\n      let(:url) { 'https://example.com/about' }\n\n      it 'raises an error' do\n        expect { subject.status }.to raise_error(ActiveRecord::RecordNotFound)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/lib/tag_manager_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe TagManager do\n  describe '#local_domain?' do\n    # The following comparisons MUST be case-insensitive.\n\n    around do |example|\n      original_local_domain = Rails.configuration.x.local_domain\n      Rails.configuration.x.local_domain = 'domain.test'\n\n      example.run\n\n      Rails.configuration.x.local_domain = original_local_domain\n    end\n\n    it 'returns true for nil' do\n      expect(TagManager.instance.local_domain?(nil)).to eq true\n    end\n\n    it 'returns true if the slash-stripped string equals to local domain' do\n      expect(TagManager.instance.local_domain?('DoMaIn.Test/')).to eq true\n    end\n\n    it 'returns false for irrelevant string' do\n      expect(TagManager.instance.local_domain?('DoMaIn.Test!')).to eq false\n    end\n  end\n\n  describe '#web_domain?' do\n    # The following comparisons MUST be case-insensitive.\n\n    around do |example|\n      original_web_domain = Rails.configuration.x.web_domain\n      Rails.configuration.x.web_domain = 'domain.test'\n\n      example.run\n\n      Rails.configuration.x.web_domain = original_web_domain\n    end\n\n    it 'returns true for nil' do\n      expect(TagManager.instance.web_domain?(nil)).to eq true\n    end\n\n    it 'returns true if the slash-stripped string equals to web domain' do\n      expect(TagManager.instance.web_domain?('DoMaIn.Test/')).to eq true\n    end\n\n    it 'returns false for string with irrelevant characters' do\n      expect(TagManager.instance.web_domain?('DoMaIn.Test!')).to eq false\n    end\n  end\n\n  describe '#normalize_domain' do\n    it 'returns nil if the given parameter is nil' do\n      expect(TagManager.instance.normalize_domain(nil)).to eq nil\n    end\n\n    it 'returns normalized domain' do\n      expect(TagManager.instance.normalize_domain('DoMaIn.Test/')).to eq 'domain.test'\n    end\n  end\n\n  describe '#local_url?' do\n    around do |example|\n      original_web_domain = Rails.configuration.x.web_domain\n      example.run\n      Rails.configuration.x.web_domain = original_web_domain\n    end\n\n    it 'returns true if the normalized string with port is local URL' do\n      Rails.configuration.x.web_domain = 'domain.test:42'\n      expect(TagManager.instance.local_url?('https://DoMaIn.Test:42/')).to eq true\n    end\n\n    it 'returns true if the normalized string without port is local URL' do\n      Rails.configuration.x.web_domain = 'domain.test'\n      expect(TagManager.instance.local_url?('https://DoMaIn.Test/')).to eq true\n    end\n\n    it 'returns false for string with irrelevant characters' do\n      Rails.configuration.x.web_domain = 'domain.test'\n      expect(TagManager.instance.local_url?('https://domainn.test/')).to eq false\n    end\n  end\n\n  describe '#same_acct?' do\n    # The following comparisons MUST be case-insensitive.\n\n    it 'returns true if the needle has a correct username and domain for remote user' do\n      expect(TagManager.instance.same_acct?('username@domain.test', 'UsErNaMe@DoMaIn.Test')).to eq true\n    end\n\n    it 'returns false if the needle is missing a domain for remote user' do\n      expect(TagManager.instance.same_acct?('username@domain.test', 'UsErNaMe')).to eq false\n    end\n\n    it 'returns false if the needle has an incorrect domain for remote user' do\n      expect(TagManager.instance.same_acct?('username@domain.test', 'UsErNaMe@incorrect.test')).to eq false\n    end\n\n    it 'returns false if the needle has an incorrect username for remote user' do\n      expect(TagManager.instance.same_acct?('username@domain.test', 'incorrect@DoMaIn.test')).to eq false\n    end\n\n    it 'returns true if the needle has a correct username and domain for local user' do\n      expect(TagManager.instance.same_acct?('username', 'UsErNaMe@Cb6E6126.nGrOk.Io')).to eq true\n    end\n\n    it 'returns true if the needle is missing a domain for local user' do\n      expect(TagManager.instance.same_acct?('username', 'UsErNaMe')).to eq true\n    end\n\n    it 'returns false if the needle has an incorrect username for local user' do\n      expect(TagManager.instance.same_acct?('username', 'UsErNaM@Cb6E6126.nGrOk.Io')).to eq false\n    end\n\n    it 'returns false if the needle has an incorrect domain for local user' do\n      expect(TagManager.instance.same_acct?('username', 'incorrect@Cb6E6126.nGrOk.Io')).to eq false\n    end\n  end\n\n  describe '#url_for' do\n    let(:alice) { Fabricate(:account, username: 'alice') }\n\n    subject { TagManager.instance.url_for(target) }\n\n    context 'activity object' do\n      let(:target) { Fabricate(:status, account: alice, reblog: Fabricate(:status)).stream_entry }\n\n      it 'returns the unique tag for status' do\n        expect(target.object_type).to eq :activity\n        is_expected.to eq \"https://cb6e6126.ngrok.io/@alice/#{target.id}\"\n      end\n    end\n\n    context 'comment object' do\n      let(:target) { Fabricate(:status, account: alice, reply: true) }\n\n      it 'returns the unique tag for status' do\n        expect(target.object_type).to eq :comment\n        is_expected.to eq \"https://cb6e6126.ngrok.io/@alice/#{target.id}\"\n      end\n    end\n\n    context 'note object' do\n      let(:target) { Fabricate(:status, account: alice, reply: false, thread: nil) }\n\n      it 'returns the unique tag for status' do\n        expect(target.object_type).to eq :note\n        is_expected.to eq \"https://cb6e6126.ngrok.io/@alice/#{target.id}\"\n      end\n    end\n\n    context 'person object' do\n      let(:target) { alice }\n\n      it 'returns the URL for account' do\n        expect(target.object_type).to eq :person\n        is_expected.to eq 'https://cb6e6126.ngrok.io/@alice'\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/lib/user_settings_decorator_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe UserSettingsDecorator do\n  describe 'update' do\n    let(:user) { Fabricate(:user) }\n    let(:settings) { described_class.new(user) }\n\n    it 'updates the user settings value for email notifications' do\n      values = { 'notification_emails' => { 'follow' => '1' } }\n\n      settings.update(values)\n      expect(user.settings['notification_emails']['follow']).to eq true\n    end\n\n    it 'updates the user settings value for interactions' do\n      values = { 'interactions' => { 'must_be_follower' => '0' } }\n\n      settings.update(values)\n      expect(user.settings['interactions']['must_be_follower']).to eq false\n    end\n\n    it 'updates the user settings value for privacy' do\n      values = { 'setting_default_privacy' => 'public' }\n\n      settings.update(values)\n      expect(user.settings['default_privacy']).to eq 'public'\n    end\n\n    it 'updates the user settings value for sensitive' do\n      values = { 'setting_default_sensitive' => '1' }\n\n      settings.update(values)\n      expect(user.settings['default_sensitive']).to eq true\n    end\n\n    it 'updates the user settings value for unfollow modal' do\n      values = { 'setting_unfollow_modal' => '0' }\n\n      settings.update(values)\n      expect(user.settings['unfollow_modal']).to eq false\n    end\n\n    it 'updates the user settings value for boost modal' do\n      values = { 'setting_boost_modal' => '1' }\n\n      settings.update(values)\n      expect(user.settings['boost_modal']).to eq true\n    end\n\n    it 'updates the user settings value for delete toot modal' do\n      values = { 'setting_delete_modal' => '0' }\n\n      settings.update(values)\n      expect(user.settings['delete_modal']).to eq false\n    end\n\n    it 'updates the user settings value for gif auto play' do\n      values = { 'setting_auto_play_gif' => '0' }\n\n      settings.update(values)\n      expect(user.settings['auto_play_gif']).to eq false\n    end\n\n    it 'updates the user settings value for system font in UI' do\n      values = { 'setting_system_font_ui' => '0' }\n\n      settings.update(values)\n      expect(user.settings['system_font_ui']).to eq false\n    end\n\n    it 'decoerces setting values before applying' do\n      values = {\n        'setting_delete_modal' => 'false',\n        'setting_boost_modal' => 'true',\n      }\n\n      settings.update(values)\n      expect(user.settings['delete_modal']).to eq false\n      expect(user.settings['boost_modal']).to eq true\n    end\n  end\nend\n"
  },
  {
    "path": "spec/lib/webfinger_resource_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe WebfingerResource do\n  around do |example|\n    before_local = Rails.configuration.x.local_domain\n    before_web = Rails.configuration.x.web_domain\n    example.run\n    Rails.configuration.x.local_domain = before_local\n    Rails.configuration.x.web_domain = before_web\n  end\n\n  describe '#username' do\n    describe 'with a URL value' do\n      it 'raises with a route whose controller is not AccountsController' do\n        resource = 'https://example.com/users/alice/other'\n\n        expect {\n          WebfingerResource.new(resource).username\n        }.to raise_error(ActiveRecord::RecordNotFound)\n      end\n\n      it 'raises with a route whose action is not show' do\n        resource = 'https://example.com/users/alice'\n\n        recognized = Rails.application.routes.recognize_path(resource)\n        allow(recognized).to receive(:[]).with(:controller).and_return('accounts')\n        allow(recognized).to receive(:[]).with(:username).and_return('alice')\n        expect(recognized).to receive(:[]).with(:action).and_return('create')\n\n        expect(Rails.application.routes).to receive(:recognize_path).with(resource).and_return(recognized).at_least(:once)\n\n        expect {\n          WebfingerResource.new(resource).username\n        }.to raise_error(ActiveRecord::RecordNotFound)\n      end\n\n      it 'raises with a string that doesnt start with URL' do\n        resource = 'website for http://example.com/users/alice/other'\n\n        expect {\n          WebfingerResource.new(resource).username\n        }.to raise_error(ActiveRecord::RecordNotFound)\n      end\n\n      it 'finds the username in a valid https route' do\n        resource = 'https://example.com/users/alice'\n\n        result = WebfingerResource.new(resource).username\n        expect(result).to eq 'alice'\n      end\n\n      it 'finds the username in a mixed case http route' do\n        resource = 'HTTp://exAMPLEe.com/users/alice'\n\n        result = WebfingerResource.new(resource).username\n        expect(result).to eq 'alice'\n      end\n\n      it 'finds the username in a valid http route' do\n        resource = 'http://example.com/users/alice'\n\n        result = WebfingerResource.new(resource).username\n        expect(result).to eq 'alice'\n      end\n    end\n\n    describe 'with a username and hostname value' do\n      it 'raises on a non-local domain' do\n        resource = 'user@remote-host.com'\n\n        expect {\n          WebfingerResource.new(resource).username\n        }.to raise_error(ActiveRecord::RecordNotFound)\n      end\n\n      it 'finds username for a local domain' do\n        Rails.configuration.x.local_domain = 'example.com'\n        resource = 'alice@example.com'\n\n        result = WebfingerResource.new(resource).username\n        expect(result).to eq 'alice'\n      end\n\n      it 'finds username for a web domain' do\n        Rails.configuration.x.web_domain = 'example.com'\n        resource = 'alice@example.com'\n\n        result = WebfingerResource.new(resource).username\n        expect(result).to eq 'alice'\n      end\n    end\n\n    describe 'with an acct value' do\n      it 'raises on a non-local domain' do\n        resource = 'acct:user@remote-host.com'\n\n        expect {\n          WebfingerResource.new(resource).username\n        }.to raise_error(ActiveRecord::RecordNotFound)\n      end\n\n      it 'raises on a nonsense domain' do\n        resource = 'acct:user@remote-host@remote-hostess.remote.local@remote'\n\n        expect {\n          WebfingerResource.new(resource).username\n        }.to raise_error(ActiveRecord::RecordNotFound)\n      end\n\n      it 'finds the username for a local account if the domain is the local one' do\n        Rails.configuration.x.local_domain = 'example.com'\n        resource = 'acct:alice@example.com'\n\n        result = WebfingerResource.new(resource).username\n        expect(result).to eq 'alice'\n      end\n\n      it 'finds the username for a local account if the domain is the Web one' do\n        Rails.configuration.x.web_domain = 'example.com'\n        resource = 'acct:alice@example.com'\n\n        result = WebfingerResource.new(resource).username\n        expect(result).to eq 'alice'\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/mailers/admin_mailer_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe AdminMailer, type: :mailer do\n  describe '.new_report' do\n    let(:sender)    { Fabricate(:account, username: 'John', user: Fabricate(:user)) }\n    let(:recipient) { Fabricate(:account, username: 'Mike', user: Fabricate(:user, locale: :en)) }\n    let(:report)    { Fabricate(:report, account: sender, target_account: recipient) }\n    let(:mail)      { described_class.new_report(recipient, report) }\n\n    it 'renders the headers' do\n      expect(mail.subject).to eq(\"New report for cb6e6126.ngrok.io (##{report.id})\")\n      expect(mail.to).to eq [recipient.user_email]\n      expect(mail.from).to eq ['notifications@localhost']\n    end\n\n    it 'renders the body' do\n      expect(mail.body.encoded).to eq(\"Mike,\\r\\n\\r\\nJohn has reported Mike\\r\\n\\r\\nView: https://cb6e6126.ngrok.io/admin/reports/#{report.id}\\r\\n\")\n    end\n  end\nend\n"
  },
  {
    "path": "spec/mailers/notification_mailer_spec.rb",
    "content": "require \"rails_helper\"\n\nRSpec.describe NotificationMailer, type: :mailer do\n  let(:receiver)       { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }\n  let(:sender)         { Fabricate(:account, username: 'bob') }\n  let(:foreign_status) { Fabricate(:status, account: sender, text: 'The body of the foreign status') }\n  let(:own_status)     { Fabricate(:status, account: receiver.account, text: 'The body of the own status') }\n\n  shared_examples 'localized subject' do |*args, **kwrest|\n    it 'renders subject localized for the locale of the receiver' do\n      locale = %i(de en).sample\n      receiver.update!(locale: locale)\n      expect(mail.subject).to eq I18n.t(*args, kwrest.merge(locale: locale))\n    end\n\n    it 'renders subject localized for the default locale if the locale of the receiver is unavailable' do\n      receiver.update!(locale: nil)\n      expect(mail.subject).to eq I18n.t(*args, kwrest.merge(locale: I18n.default_locale))\n    end\n  end\n\n  describe \"mention\" do\n    let(:mention) { Mention.create!(account: receiver.account, status: foreign_status) }\n    let(:mail) { NotificationMailer.mention(receiver.account, Notification.create!(account: receiver.account, activity: mention)) }\n\n    include_examples 'localized subject', 'notification_mailer.mention.subject', name: 'bob'\n\n    it \"renders the headers\" do\n      expect(mail.subject).to eq(\"You were mentioned by bob\")\n      expect(mail.to).to eq([receiver.email])\n    end\n\n    it \"renders the body\" do\n      expect(mail.body.encoded).to match(\"You were mentioned by bob\")\n      expect(mail.body.encoded).to include 'The body of the foreign status'\n    end\n  end\n\n  describe \"follow\" do\n    let(:follow) { sender.follow!(receiver.account) }\n    let(:mail) { NotificationMailer.follow(receiver.account, Notification.create!(account: receiver.account, activity: follow)) }\n\n    include_examples 'localized subject', 'notification_mailer.follow.subject', name: 'bob'\n\n    it \"renders the headers\" do\n      expect(mail.subject).to eq(\"bob is now following you\")\n      expect(mail.to).to eq([receiver.email])\n    end\n\n    it \"renders the body\" do\n      expect(mail.body.encoded).to match(\"bob is now following you\")\n    end\n  end\n\n  describe \"favourite\" do\n    let(:favourite) { Favourite.create!(account: sender, status: own_status) }\n    let(:mail) { NotificationMailer.favourite(own_status.account, Notification.create!(account: receiver.account, activity: favourite)) }\n\n    include_examples 'localized subject', 'notification_mailer.favourite.subject', name: 'bob'\n\n    it \"renders the headers\" do\n      expect(mail.subject).to eq(\"bob favourited your status\")\n      expect(mail.to).to eq([receiver.email])\n    end\n\n    it \"renders the body\" do\n      expect(mail.body.encoded).to match(\"Your status was favourited by bob\")\n      expect(mail.body.encoded).to include 'The body of the own status'\n    end\n  end\n\n  describe \"reblog\" do\n    let(:reblog) { Status.create!(account: sender, reblog: own_status) }\n    let(:mail) { NotificationMailer.reblog(own_status.account, Notification.create!(account: receiver.account, activity: reblog)) }\n\n    include_examples 'localized subject', 'notification_mailer.reblog.subject', name: 'bob'\n\n    it \"renders the headers\" do\n      expect(mail.subject).to eq(\"bob boosted your status\")\n      expect(mail.to).to eq([receiver.email])\n    end\n\n    it \"renders the body\" do\n      expect(mail.body.encoded).to match(\"Your status was boosted by bob\")\n      expect(mail.body.encoded).to include 'The body of the own status'\n    end\n  end\n\n  describe 'follow_request' do\n    let(:follow_request) { Fabricate(:follow_request, account: sender, target_account: receiver.account) }\n    let(:mail) { NotificationMailer.follow_request(receiver.account, Notification.create!(account: receiver.account, activity: follow_request)) }\n\n    include_examples 'localized subject', 'notification_mailer.follow_request.subject', name: 'bob'\n\n    it 'renders the headers' do\n      expect(mail.subject).to eq('Pending follower: bob')\n      expect(mail.to).to eq([receiver.email])\n    end\n\n    it 'renders the body' do\n      expect(mail.body.encoded).to match(\"bob has requested to follow you\")\n    end\n  end\n\n  describe 'digest' do\n    before do\n      mention = Fabricate(:mention, account: receiver.account, status: foreign_status)\n      Fabricate(:notification, account: receiver.account, activity: mention)\n      sender.follow!(receiver.account)\n    end\n\n    context do\n      let!(:mail) { NotificationMailer.digest(receiver.account, since: 5.days.ago) }\n\n      include_examples 'localized subject', 'notification_mailer.digest.subject', count: 1, name: 'bob'\n\n      it 'renders the headers' do\n        expect(mail.subject).to match('notification since your last')\n        expect(mail.to).to eq([receiver.email])\n      end\n\n      it 'renders the body' do\n        expect(mail.body.encoded).to match('brief summary')\n        expect(mail.body.encoded).to include 'The body of the foreign status'\n        expect(mail.body.encoded).to include sender.username\n      end\n    end\n\n    it 'includes activities since the receiver last signed in' do\n      receiver.update!(last_emailed_at: nil, current_sign_in_at: '2000-03-01T00:00:00Z')\n      mail = NotificationMailer.digest(receiver.account)\n      expect(mail.body.encoded).to include 'Mar 01, 2000, 00:00'\n    end\n  end\nend\n"
  },
  {
    "path": "spec/mailers/previews/admin_mailer_preview.rb",
    "content": "# Preview all emails at http://localhost:3000/rails/mailers/admin_mailer\n\nclass AdminMailerPreview < ActionMailer::Preview\n  # Preview this email at http://localhost:3000/rails/mailers/admin_mailer/new_pending_account\n  def new_pending_account\n    AdminMailer.new_pending_account(Account.first, User.pending.first)\n  end\nend\n"
  },
  {
    "path": "spec/mailers/previews/notification_mailer_preview.rb",
    "content": "# Preview all emails at http://localhost:3000/rails/mailers/notification_mailer\n\nclass NotificationMailerPreview < ActionMailer::Preview\n  # Preview this email at http://localhost:3000/rails/mailers/notification_mailer/mention\n  def mention\n    m = Mention.last\n    NotificationMailer.mention(m.account, Notification.find_by(activity: m))\n  end\n\n  # Preview this email at http://localhost:3000/rails/mailers/notification_mailer/follow\n  def follow\n    f = Follow.last\n    NotificationMailer.follow(f.target_account, Notification.find_by(activity: f))\n  end\n\n  # Preview this email at http://localhost:3000/rails/mailers/notification_mailer/follow_request\n  def follow_request\n    f = Follow.last\n    NotificationMailer.follow_request(f.target_account, Notification.find_by(activity: f))\n  end\n\n  # Preview this email at http://localhost:3000/rails/mailers/notification_mailer/favourite\n  def favourite\n    f = Favourite.last\n    NotificationMailer.favourite(f.status.account, Notification.find_by(activity: f))\n  end\n\n  # Preview this email at http://localhost:3000/rails/mailers/notification_mailer/reblog\n  def reblog\n    r = Status.where.not(reblog_of_id: nil).first\n    NotificationMailer.reblog(r.reblog.account, Notification.find_by(activity: r))\n  end\n\n  # Preview this email at http://localhost:3000/rails/mailers/notification_mailer/digest\n  def digest\n    NotificationMailer.digest(Account.first, since: 90.days.ago)\n  end\nend\n"
  },
  {
    "path": "spec/mailers/previews/user_mailer_preview.rb",
    "content": "# Preview all emails at http://localhost:3000/rails/mailers/user_mailer\n\nclass UserMailerPreview < ActionMailer::Preview\n  # Preview this email at http://localhost:3000/rails/mailers/user_mailer/confirmation_instructions\n  def confirmation_instructions\n    UserMailer.confirmation_instructions(User.first, 'spec')\n  end\n\n  # Preview this email at http://localhost:3000/rails/mailers/user_mailer/email_changed\n  def email_changed\n    user = User.first\n    user.unconfirmed_email = 'foo@bar.com'\n    UserMailer.email_changed(user)\n  end\n\n  # Preview this email at http://localhost:3000/rails/mailers/user_mailer/password_change\n  def password_change\n    UserMailer.password_change(User.first)\n  end\n\n  # Preview this email at http://localhost:3000/rails/mailers/user_mailer/reconfirmation_instructions\n  def reconfirmation_instructions\n    user = User.first\n    user.unconfirmed_email = 'foo@bar.com'\n    UserMailer.confirmation_instructions(user, 'spec')\n  end\n\n  # Preview this email at http://localhost:3000/rails/mailers/user_mailer/reset_password_instructions\n  def reset_password_instructions\n    UserMailer.reset_password_instructions(User.first, 'spec')\n  end\n\n  # Preview this email at http://localhost:3000/rails/mailers/user_mailer/welcome\n  def welcome\n    UserMailer.welcome(User.first)\n  end\n\n  # Preview this email at http://localhost:3000/rails/mailers/user_mailer/backup_ready\n  def backup_ready\n    UserMailer.backup_ready(User.first, Backup.first)\n  end\n\n  # Preview this email at http://localhost:3000/rails/mailers/user_mailer/warning\n  def warning\n    UserMailer.warning(User.first, AccountWarning.new(text: '', action: :silence))\n  end\nend\n"
  },
  {
    "path": "spec/mailers/user_mailer_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe UserMailer, type: :mailer do\n  let(:receiver) { Fabricate(:user) }\n\n  shared_examples 'localized subject' do |*args, **kwrest|\n    it 'renders subject localized for the locale of the receiver' do\n      locale = I18n.available_locales.sample\n      receiver.update!(locale: locale)\n      expect(mail.subject).to eq I18n.t(*args, kwrest.merge(locale: locale))\n    end\n\n    it 'renders subject localized for the default locale if the locale of the receiver is unavailable' do\n      receiver.update!(locale: nil)\n      expect(mail.subject).to eq I18n.t(*args, kwrest.merge(locale: I18n.default_locale))\n    end\n  end\n\n  describe 'confirmation_instructions' do\n    let(:mail) { UserMailer.confirmation_instructions(receiver, 'spec') }\n\n    it 'renders confirmation instructions' do\n      receiver.update!(locale: nil)\n      expect(mail.body.encoded).to include I18n.t('devise.mailer.confirmation_instructions.title')\n      expect(mail.body.encoded).to include 'spec'\n      expect(mail.body.encoded).to include Rails.configuration.x.local_domain\n    end\n\n    include_examples 'localized subject',\n                     'devise.mailer.confirmation_instructions.subject',\n                     instance: Rails.configuration.x.local_domain\n  end\n\n  describe 'reconfirmation_instructions' do\n    let(:mail) { UserMailer.confirmation_instructions(receiver, 'spec') }\n\n    it 'renders reconfirmation instructions' do\n      receiver.update!(email: 'new-email@example.com', locale: nil)\n      expect(mail.body.encoded).to include I18n.t('devise.mailer.reconfirmation_instructions.title')\n      expect(mail.body.encoded).to include 'spec'\n      expect(mail.body.encoded).to include Rails.configuration.x.local_domain\n      expect(mail.subject).to eq I18n.t('devise.mailer.reconfirmation_instructions.subject',\n                                        instance: Rails.configuration.x.local_domain,\n                                        locale: I18n.default_locale)\n    end\n  end\n\n  describe 'reset_password_instructions' do\n    let(:mail) { UserMailer.reset_password_instructions(receiver, 'spec') }\n\n    it 'renders reset password instructions' do\n      receiver.update!(locale: nil)\n      expect(mail.body.encoded).to include I18n.t('devise.mailer.reset_password_instructions.title')\n      expect(mail.body.encoded).to include 'spec'\n    end\n\n    include_examples 'localized subject',\n                     'devise.mailer.reset_password_instructions.subject'\n  end\n\n  describe 'password_change' do\n    let(:mail) { UserMailer.password_change(receiver) }\n\n    it 'renders password change notification' do\n      receiver.update!(locale: nil)\n      expect(mail.body.encoded).to include I18n.t('devise.mailer.password_change.title')\n    end\n\n    include_examples 'localized subject',\n                     'devise.mailer.password_change.subject'\n  end\n\n  describe 'email_changed' do\n    let(:mail) { UserMailer.email_changed(receiver) }\n\n    it 'renders email change notification' do\n      receiver.update!(locale: nil)\n      expect(mail.body.encoded).to include I18n.t('devise.mailer.email_changed.title')\n    end\n\n    include_examples 'localized subject',\n                     'devise.mailer.email_changed.subject'\n  end\nend\n"
  },
  {
    "path": "spec/models/account_conversation_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe AccountConversation, type: :model do\n  let!(:alice) { Fabricate(:account, username: 'alice') }\n  let!(:bob)   { Fabricate(:account, username: 'bob') }\n  let!(:mark)  { Fabricate(:account, username: 'mark') }\n\n  describe '.add_status' do\n    it 'creates new record when no others exist' do\n      status = Fabricate(:status, account: alice, visibility: :direct)\n      status.mentions.create(account: bob)\n\n      conversation = AccountConversation.add_status(alice, status)\n\n      expect(conversation.participant_accounts).to include(bob)\n      expect(conversation.last_status).to eq status\n      expect(conversation.status_ids).to eq [status.id]\n    end\n\n    it 'appends to old record when there is a match' do\n      last_status  = Fabricate(:status, account: alice, visibility: :direct)\n      conversation = AccountConversation.create!(account: alice, conversation: last_status.conversation, participant_account_ids: [bob.id], status_ids: [last_status.id])\n\n      status = Fabricate(:status, account: bob, visibility: :direct, thread: last_status)\n      status.mentions.create(account: alice)\n\n      new_conversation = AccountConversation.add_status(alice, status)\n\n      expect(new_conversation.id).to eq conversation.id\n      expect(new_conversation.participant_accounts).to include(bob)\n      expect(new_conversation.last_status).to eq status\n      expect(new_conversation.status_ids).to eq [last_status.id, status.id]\n    end\n\n    it 'creates new record when new participants are added' do\n      last_status  = Fabricate(:status, account: alice, visibility: :direct)\n      conversation = AccountConversation.create!(account: alice, conversation: last_status.conversation, participant_account_ids: [bob.id], status_ids: [last_status.id])\n\n      status = Fabricate(:status, account: bob, visibility: :direct, thread: last_status)\n      status.mentions.create(account: alice)\n      status.mentions.create(account: mark)\n\n      new_conversation = AccountConversation.add_status(alice, status)\n\n      expect(new_conversation.id).to_not eq conversation.id\n      expect(new_conversation.participant_accounts).to include(bob, mark)\n      expect(new_conversation.last_status).to eq status\n      expect(new_conversation.status_ids).to eq [status.id]\n    end\n  end\n\n  describe '.remove_status' do\n    it 'updates last status to a previous value' do\n      last_status  = Fabricate(:status, account: alice, visibility: :direct)\n      status       = Fabricate(:status, account: alice, visibility: :direct)\n      conversation = AccountConversation.create!(account: alice, conversation: last_status.conversation, participant_account_ids: [bob.id], status_ids: [status.id, last_status.id])\n      last_status.mentions.create(account: bob)\n      last_status.destroy!\n      conversation.reload\n      expect(conversation.last_status).to eq status\n      expect(conversation.status_ids).to eq [status.id]\n    end\n\n    it 'removes the record if no other statuses are referenced' do\n      last_status  = Fabricate(:status, account: alice, visibility: :direct)\n      conversation = AccountConversation.create!(account: alice, conversation: last_status.conversation, participant_account_ids: [bob.id], status_ids: [last_status.id])\n      last_status.mentions.create(account: bob)\n      last_status.destroy!\n      expect(AccountConversation.where(id: conversation.id).count).to eq 0\n    end\n  end\nend\n"
  },
  {
    "path": "spec/models/account_domain_block_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe AccountDomainBlock, type: :model do\n  it 'removes blocking cache after creation' do\n    account = Fabricate(:account)\n    Rails.cache.write(\"exclude_domains_for:#{account.id}\", 'a.domain.already.blocked')\n\n    AccountDomainBlock.create!(account: account, domain: 'a.domain.blocked.later')\n\n    expect(Rails.cache.exist?(\"exclude_domains_for:#{account.id}\")).to eq false\n  end\n\n  it 'removes blocking cache after destruction' do\n    account = Fabricate(:account)\n    block = AccountDomainBlock.create!(account: account, domain: 'domain')\n    Rails.cache.write(\"exclude_domains_for:#{account.id}\", 'domain')\n\n    block.destroy!\n\n    expect(Rails.cache.exist?(\"exclude_domains_for:#{account.id}\")).to eq false\n  end\nend\n"
  },
  {
    "path": "spec/models/account_filter_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe AccountFilter do\n  describe 'with empty params' do\n    it 'defaults to recent local not-suspended account list' do\n      filter = described_class.new({})\n\n      expect(filter.results).to eq Account.local.recent.without_suspended\n    end\n  end\n\n  describe 'with invalid params' do\n    it 'raises with key error' do\n      filter = described_class.new(wrong: true)\n\n      expect { filter.results }.to raise_error(/wrong/)\n    end\n  end\n\n  describe 'with valid params' do\n    it 'combines filters on Account' do\n      filter = described_class.new(\n        by_domain: 'test.com',\n        silenced: true,\n        username: 'test',\n        display_name: 'name',\n        email: 'user@example.com',\n      )\n\n      allow(Account).to receive(:where).and_return(Account.none)\n      allow(Account).to receive(:silenced).and_return(Account.none)\n      allow(Account).to receive(:matches_display_name).and_return(Account.none)\n      allow(Account).to receive(:matches_username).and_return(Account.none)\n      allow(User).to receive(:matches_email).and_return(User.none)\n\n      filter.results\n\n      expect(Account).to have_received(:where).with(domain: 'test.com')\n      expect(Account).to have_received(:silenced)\n      expect(Account).to have_received(:matches_username).with('test')\n      expect(Account).to have_received(:matches_display_name).with('name')\n      expect(User).to have_received(:matches_email).with('user@example.com')\n    end\n\n    describe 'that call account methods' do\n      %i(local remote silenced suspended).each do |option|\n        it \"delegates the #{option} option\" do\n          allow(Account).to receive(option).and_return(Account.none)\n          filter = described_class.new({ option => true })\n          filter.results\n\n          expect(Account).to have_received(option).at_least(1)\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/models/account_moderation_note_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe AccountModerationNote, type: :model do\nend\n"
  },
  {
    "path": "spec/models/account_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Account, type: :model do\n  context do\n    let(:bob) { Fabricate(:account, username: 'bob') }\n    subject { Fabricate(:account) }\n\n    describe '#follow!' do\n      it 'creates a follow' do\n        follow = subject.follow!(bob)\n\n        expect(follow).to be_instance_of Follow\n        expect(follow.account).to eq subject\n        expect(follow.target_account).to eq bob\n      end\n    end\n\n    describe '#unfollow!' do\n      before do\n        subject.follow!(bob)\n      end\n\n      it 'destroys a follow' do\n        unfollow = subject.unfollow!(bob)\n\n        expect(unfollow).to be_instance_of Follow\n        expect(unfollow.account).to eq subject\n        expect(unfollow.target_account).to eq bob\n        expect(unfollow.destroyed?).to be true\n      end\n    end\n\n    describe '#following?' do\n      it 'returns true when the target is followed' do\n        subject.follow!(bob)\n        expect(subject.following?(bob)).to be true\n      end\n\n      it 'returns false if the target is not followed' do\n        expect(subject.following?(bob)).to be false\n      end\n    end\n  end\n\n  describe '#local?' do\n    it 'returns true when the account is local' do\n      account = Fabricate(:account, domain: nil)\n      expect(account.local?).to be true\n    end\n\n    it 'returns false when the account is on a different domain' do\n      account = Fabricate(:account, domain: 'foreign.tld')\n      expect(account.local?).to be false\n    end\n  end\n\n  describe 'Local domain user methods' do\n    around do |example|\n      before = Rails.configuration.x.local_domain\n      example.run\n      Rails.configuration.x.local_domain = before\n    end\n\n    subject { Fabricate(:account, domain: nil, username: 'alice') }\n\n    describe '#to_webfinger_s' do\n      it 'returns a webfinger string for the account' do\n        Rails.configuration.x.local_domain = 'example.com'\n\n        expect(subject.to_webfinger_s).to eq 'acct:alice@example.com'\n      end\n    end\n\n    describe '#local_username_and_domain' do\n      it 'returns the username and local domain for the account' do\n        Rails.configuration.x.local_domain = 'example.com'\n\n        expect(subject.local_username_and_domain).to eq 'alice@example.com'\n      end\n    end\n  end\n\n  describe '#acct' do\n    it 'returns username for local users' do\n      account = Fabricate(:account, domain: nil, username: 'alice')\n      expect(account.acct).to eql 'alice'\n    end\n\n    it 'returns username@domain for foreign users' do\n      account = Fabricate(:account, domain: 'foreign.tld', username: 'alice')\n      expect(account.acct).to eql 'alice@foreign.tld'\n    end\n  end\n\n  describe '#save_with_optional_media!' do\n    before do\n      stub_request(:get, 'https://remote.test/valid_avatar').to_return(request_fixture('avatar.txt'))\n      stub_request(:get, 'https://remote.test/invalid_avatar').to_return(request_fixture('feed.txt'))\n    end\n\n    let(:account) do\n      Fabricate(:account,\n                avatar_remote_url: 'https://remote.test/valid_avatar',\n                header_remote_url: 'https://remote.test/valid_avatar')\n    end\n\n    let!(:expectation) { account.dup }\n\n    context 'with valid properties' do\n      before do\n        account.save_with_optional_media!\n      end\n\n      it 'unchanges avatar, header, avatar_remote_url, and header_remote_url' do\n        expect(account.avatar_remote_url).to eq expectation.avatar_remote_url\n        expect(account.header_remote_url).to eq expectation.header_remote_url\n        expect(account.avatar_file_name).to  eq expectation.avatar_file_name\n        expect(account.header_file_name).to  eq expectation.header_file_name\n      end\n    end\n\n    context 'with invalid properties' do\n      before do\n        account.avatar_remote_url = 'https://remote.test/invalid_avatar'\n        account.save_with_optional_media!\n      end\n\n      it 'sets default avatar, header, avatar_remote_url, and header_remote_url' do\n        expect(account.avatar_remote_url).to eq ''\n        expect(account.header_remote_url).to eq ''\n        expect(account.avatar_file_name).to  eq nil\n        expect(account.header_file_name).to  eq nil\n      end\n    end\n  end\n\n  describe '#subscribed?' do\n    it 'returns false when no subscription expiration information is present' do\n      account = Fabricate(:account, subscription_expires_at: nil)\n      expect(account.subscribed?).to be false\n    end\n\n    it 'returns true when subscription expiration has been set' do\n      account = Fabricate(:account, subscription_expires_at: 30.days.from_now)\n      expect(account.subscribed?).to be true\n    end\n  end\n\n  describe '#possibly_stale?' do\n    let(:account) { Fabricate(:account, last_webfingered_at: last_webfingered_at) }\n\n    context 'last_webfingered_at is nil' do\n      let(:last_webfingered_at) { nil }\n\n      it 'returns true' do\n        expect(account.possibly_stale?).to be true\n      end\n    end\n\n    context 'last_webfingered_at is more than 24 hours before' do\n      let(:last_webfingered_at) { 25.hours.ago }\n\n      it 'returns true' do\n        expect(account.possibly_stale?).to be true\n      end\n    end\n\n    context 'last_webfingered_at is less than 24 hours before' do\n      let(:last_webfingered_at) { 23.hours.ago }\n\n      it 'returns false' do\n        expect(account.possibly_stale?).to be false\n      end\n    end\n  end\n\n  describe '#refresh!' do\n    let(:account) { Fabricate(:account, domain: domain) }\n    let(:acct)    { account.acct }\n\n    context 'domain is nil' do\n      let(:domain) { nil }\n\n      it 'returns nil' do\n        expect(account.refresh!).to be_nil\n      end\n\n      it 'calls not ResolveAccountService#call' do\n        expect_any_instance_of(ResolveAccountService).not_to receive(:call).with(acct)\n        account.refresh!\n      end\n    end\n\n    context 'domain is present' do\n      let(:domain) { 'example.com' }\n\n      it 'calls ResolveAccountService#call' do\n        expect_any_instance_of(ResolveAccountService).to receive(:call).with(acct).once\n        account.refresh!\n      end\n    end\n  end\n\n  describe '#to_param' do\n    it 'returns username' do\n      account = Fabricate(:account, username: 'alice')\n      expect(account.to_param).to eq 'alice'\n    end\n  end\n\n  describe '#keypair' do\n    it 'returns an RSA key pair' do\n      account = Fabricate(:account)\n      expect(account.keypair).to be_instance_of OpenSSL::PKey::RSA\n    end\n  end\n\n  describe '#subscription' do\n    it 'returns an OStatus subscription' do\n      account = Fabricate(:account)\n      expect(account.subscription('')).to be_instance_of OStatus2::Subscription\n    end\n  end\n\n  describe '#object_type' do\n    it 'is always a person' do\n      account = Fabricate(:account)\n      expect(account.object_type).to be :person\n    end\n  end\n\n  describe '#favourited?' do\n    let(:original_status) do\n      author = Fabricate(:account, username: 'original')\n      Fabricate(:status, account: author)\n    end\n\n    subject { Fabricate(:account) }\n\n    context 'when the status is a reblog of another status' do\n      let(:original_reblog) do\n        author = Fabricate(:account, username: 'original_reblogger')\n        Fabricate(:status, reblog: original_status, account: author)\n      end\n\n      it 'is is true when this account has favourited it' do\n        Fabricate(:favourite, status: original_reblog, account: subject)\n\n        expect(subject.favourited?(original_status)).to eq true\n      end\n\n      it 'is false when this account has not favourited it' do\n        expect(subject.favourited?(original_status)).to eq false\n      end\n    end\n\n    context 'when the status is an original status' do\n      it 'is is true when this account has favourited it' do\n        Fabricate(:favourite, status: original_status, account: subject)\n\n        expect(subject.favourited?(original_status)).to eq true\n      end\n\n      it 'is false when this account has not favourited it' do\n        expect(subject.favourited?(original_status)).to eq false\n      end\n    end\n  end\n\n  describe '#reblogged?' do\n    let(:original_status) do\n      author = Fabricate(:account, username: 'original')\n      Fabricate(:status, account: author)\n    end\n\n    subject { Fabricate(:account) }\n\n    context 'when the status is a reblog of another status' do\n      let(:original_reblog) do\n        author = Fabricate(:account, username: 'original_reblogger')\n        Fabricate(:status, reblog: original_status, account: author)\n      end\n\n      it 'is true when this account has reblogged it' do\n        Fabricate(:status, reblog: original_reblog, account: subject)\n\n        expect(subject.reblogged?(original_reblog)).to eq true\n      end\n\n      it 'is false when this account has not reblogged it' do\n        expect(subject.reblogged?(original_reblog)).to eq false\n      end\n    end\n\n    context 'when the status is an original status' do\n      it 'is true when this account has reblogged it' do\n        Fabricate(:status, reblog: original_status, account: subject)\n\n        expect(subject.reblogged?(original_status)).to eq true\n      end\n\n      it 'is false when this account has not reblogged it' do\n        expect(subject.reblogged?(original_status)).to eq false\n      end\n    end\n  end\n\n  describe '#excluded_from_timeline_account_ids' do\n    it 'includes account ids of blockings, blocked_bys and mutes' do\n      account = Fabricate(:account)\n      block = Fabricate(:block, account: account)\n      mute = Fabricate(:mute, account: account)\n      block_by = Fabricate(:block, target_account: account)\n\n      results = account.excluded_from_timeline_account_ids\n      expect(results.size).to eq 3\n      expect(results).to include(block.target_account.id)\n      expect(results).to include(mute.target_account.id)\n      expect(results).to include(block_by.account.id)\n    end\n  end\n\n  describe '#excluded_from_timeline_domains' do\n    it 'returns the domains blocked by the account' do\n      account = Fabricate(:account)\n      account.block_domain!('domain')\n      expect(account.excluded_from_timeline_domains).to match_array ['domain']\n    end\n  end\n\n  describe '.search_for' do\n    before do\n      _missing = Fabricate(\n        :account,\n        display_name: \"Missing\",\n        username: \"missing\",\n        domain: \"missing.com\"\n      )\n    end\n\n    it 'accepts ?, \\, : and space as delimiter' do\n      match = Fabricate(\n        :account,\n        display_name: 'A & l & i & c & e',\n        username: 'username',\n        domain: 'example.com'\n      )\n\n      results = Account.search_for('A?l\\i:c e')\n      expect(results).to eq [match]\n    end\n\n    it 'finds accounts with matching display_name' do\n      match = Fabricate(\n        :account,\n        display_name: \"Display Name\",\n        username: \"username\",\n        domain: \"example.com\"\n      )\n\n      results = Account.search_for(\"display\")\n      expect(results).to eq [match]\n    end\n\n    it 'finds accounts with matching username' do\n      match = Fabricate(\n        :account,\n        display_name: \"Display Name\",\n        username: \"username\",\n        domain: \"example.com\"\n      )\n\n      results = Account.search_for(\"username\")\n      expect(results).to eq [match]\n    end\n\n    it 'finds accounts with matching domain' do\n      match = Fabricate(\n        :account,\n        display_name: \"Display Name\",\n        username: \"username\",\n        domain: \"example.com\"\n      )\n\n      results = Account.search_for(\"example\")\n      expect(results).to eq [match]\n    end\n\n    it 'limits by 10 by default' do\n      11.times.each { Fabricate(:account, display_name: \"Display Name\") }\n      results = Account.search_for(\"display\")\n      expect(results.size).to eq 10\n    end\n\n    it 'accepts arbitrary limits' do\n      2.times.each { Fabricate(:account, display_name: \"Display Name\") }\n      results = Account.search_for(\"display\", 1)\n      expect(results.size).to eq 1\n    end\n\n    it 'ranks multiple matches higher' do\n      matches = [\n        { username: \"username\", display_name: \"username\" },\n        { display_name: \"Display Name\", username: \"username\", domain: \"example.com\" },\n      ].map(&method(:Fabricate).curry(2).call(:account))\n\n      results = Account.search_for(\"username\")\n      expect(results).to eq matches\n    end\n  end\n\n  describe '.advanced_search_for' do\n    it 'accepts ?, \\, : and space as delimiter' do\n      account = Fabricate(:account)\n      match = Fabricate(\n        :account,\n        display_name: 'A & l & i & c & e',\n        username: 'username',\n        domain: 'example.com'\n      )\n\n      results = Account.advanced_search_for('A?l\\i:c e', account)\n      expect(results).to eq [match]\n    end\n\n    it 'limits by 10 by default' do\n      11.times { Fabricate(:account, display_name: \"Display Name\") }\n      results = Account.search_for(\"display\")\n      expect(results.size).to eq 10\n    end\n\n    it 'accepts arbitrary limits' do\n      2.times { Fabricate(:account, display_name: \"Display Name\") }\n      results = Account.search_for(\"display\", 1)\n      expect(results.size).to eq 1\n    end\n\n    it 'ranks followed accounts higher' do\n      account = Fabricate(:account)\n      match = Fabricate(:account, username: \"Matching\")\n      followed_match = Fabricate(:account, username: \"Matcher\")\n      Fabricate(:follow, account: account, target_account: followed_match)\n\n      results = Account.advanced_search_for(\"match\", account)\n      expect(results).to eq [followed_match, match]\n      expect(results.first.rank).to be > results.last.rank\n    end\n  end\n\n  describe '.domains' do\n    it 'returns domains' do\n      Fabricate(:account, domain: 'domain')\n      expect(Account.domains).to match_array(['domain'])\n    end\n  end\n\n  describe '#statuses_count' do\n    subject { Fabricate(:account) }\n\n    it 'counts statuses' do\n      Fabricate(:status, account: subject)\n      Fabricate(:status, account: subject)\n      expect(subject.statuses_count).to eq 2\n    end\n\n    it 'does not count direct statuses' do\n      Fabricate(:status, account: subject, visibility: :direct)\n      expect(subject.statuses_count).to eq 0\n    end\n\n    it 'is decremented when status is removed' do\n      status = Fabricate(:status, account: subject)\n      expect(subject.statuses_count).to eq 1\n      status.destroy\n      expect(subject.statuses_count).to eq 0\n    end\n\n    it 'is decremented when status is removed when account is not preloaded' do\n      status = Fabricate(:status, account: subject)\n      expect(subject.reload.statuses_count).to eq 1\n      clean_status = Status.find(status.id)\n      expect(clean_status.association(:account).loaded?).to be false\n      clean_status.destroy\n      expect(subject.reload.statuses_count).to eq 0\n    end\n  end\n\n  describe '.following_map' do\n    it 'returns an hash' do\n      expect(Account.following_map([], 1)).to be_a Hash\n    end\n  end\n\n  describe '.followed_by_map' do\n    it 'returns an hash' do\n      expect(Account.followed_by_map([], 1)).to be_a Hash\n    end\n  end\n\n  describe '.blocking_map' do\n    it 'returns an hash' do\n      expect(Account.blocking_map([], 1)).to be_a Hash\n    end\n  end\n\n  describe '.requested_map' do\n    it 'returns an hash' do\n      expect(Account.requested_map([], 1)).to be_a Hash\n    end\n  end\n\n  describe 'MENTION_RE' do\n    subject { Account::MENTION_RE }\n\n    it 'matches usernames in the middle of a sentence' do\n      expect(subject.match('Hello to @alice from me')[1]).to eq 'alice'\n    end\n\n    it 'matches usernames in the beginning of status' do\n      expect(subject.match('@alice Hey how are you?')[1]).to eq 'alice'\n    end\n\n    it 'matches full usernames' do\n      expect(subject.match('@alice@example.com')[1]).to eq 'alice@example.com'\n    end\n\n    it 'matches full usernames with a dot at the end' do\n      expect(subject.match('Hello @alice@example.com.')[1]).to eq 'alice@example.com'\n    end\n\n    it 'matches dot-prepended usernames' do\n      expect(subject.match('.@alice I want everybody to see this')[1]).to eq 'alice'\n    end\n\n    it 'does not match e-mails' do\n      expect(subject.match('Drop me an e-mail at alice@example.com')).to be_nil\n    end\n\n    it 'does not match URLs' do\n      expect(subject.match('Check this out https://medium.com/@alice/some-article#.abcdef123')).to be_nil\n    end\n\n    xit 'does not match URL querystring' do\n      expect(subject.match('https://example.com/?x=@alice')).to be_nil\n    end\n  end\n\n  describe 'validations' do\n    it 'has a valid fabricator' do\n      account = Fabricate.build(:account)\n      account.valid?\n      expect(account).to be_valid\n    end\n\n    it 'is invalid without a username' do\n      account = Fabricate.build(:account, username: nil)\n      account.valid?\n      expect(account).to model_have_error_on_field(:username)\n    end\n\n    it 'squishes the username before validation' do\n      account = Fabricate(:account, domain: nil, username: \" \\u3000bob \\t \\u00a0 \\n \")\n      expect(account.username).to eq 'bob'\n    end\n\n    context 'when is local' do\n      it 'is invalid if the username is not unique in case-insensitive comparison among local accounts' do\n        account_1 = Fabricate(:account, username: 'the_doctor')\n        account_2 = Fabricate.build(:account, username: 'the_Doctor')\n        account_2.valid?\n        expect(account_2).to model_have_error_on_field(:username)\n      end\n\n      it 'is invalid if the username is reserved' do\n        account = Fabricate.build(:account, username: 'support')\n        account.valid?\n        expect(account).to model_have_error_on_field(:username)\n      end\n\n      it 'is valid when username is reserved but record has already been created' do\n        account = Fabricate.build(:account, username: 'support')\n        account.save(validate: false)\n        expect(account.valid?).to be true\n      end\n\n      it 'is invalid if the username doesn\\'t only contains letters, numbers and underscores' do\n        account = Fabricate.build(:account, username: 'the-doctor')\n        account.valid?\n        expect(account).to model_have_error_on_field(:username)\n      end\n\n      it 'is invalid if the username is longer then 30 characters' do\n        account = Fabricate.build(:account, username: Faker::Lorem.characters(31))\n        account.valid?\n        expect(account).to model_have_error_on_field(:username)\n      end\n\n      it 'is invalid if the display name is longer than 30 characters' do\n        account = Fabricate.build(:account, display_name: Faker::Lorem.characters(31))\n        account.valid?\n        expect(account).to model_have_error_on_field(:display_name)\n      end\n\n      it 'is invalid if the note is longer than 500 characters' do\n        account = Fabricate.build(:account, note: Faker::Lorem.characters(501))\n        account.valid?\n        expect(account).to model_have_error_on_field(:note)\n      end\n    end\n\n    context 'when is remote' do\n      it 'is invalid if the username is not unique in case-sensitive comparison among accounts in the same normalized domain' do\n        Fabricate(:account, domain: 'にゃん', username: 'username')\n        account = Fabricate.build(:account, domain: 'xn--r9j5b5b', username: 'username')\n        account.valid?\n        expect(account).to model_have_error_on_field(:username)\n      end\n\n      it 'is valid even if the username is unique only in case-sensitive comparison among accounts in the same normalized domain' do\n        Fabricate(:account, domain: 'にゃん', username: 'username')\n        account = Fabricate.build(:account, domain: 'xn--r9j5b5b', username: 'Username')\n        account.valid?\n        expect(account).not_to model_have_error_on_field(:username)\n      end\n\n      it 'is valid even if the username contains hyphens' do\n        account = Fabricate.build(:account, domain: 'domain', username: 'the-doctor')\n        account.valid?\n        expect(account).to_not model_have_error_on_field(:username)\n      end\n\n      it 'is invalid if the username doesn\\'t only contains letters, numbers, underscores and hyphens' do\n        account = Fabricate.build(:account, domain: 'domain', username: 'the doctor')\n        account.valid?\n        expect(account).to model_have_error_on_field(:username)\n      end\n\n      it 'is valid even if the username is longer then 30 characters' do\n        account = Fabricate.build(:account, domain: 'domain', username: Faker::Lorem.characters(31))\n        account.valid?\n        expect(account).not_to model_have_error_on_field(:username)\n      end\n\n      it 'is valid even if the display name is longer than 30 characters' do\n        account = Fabricate.build(:account, domain: 'domain', display_name: Faker::Lorem.characters(31))\n        account.valid?\n        expect(account).not_to model_have_error_on_field(:display_name)\n      end\n\n      it 'is valid even if the note is longer than 500 characters' do\n        account = Fabricate.build(:account, domain: 'domain', note: Faker::Lorem.characters(501))\n        account.valid?\n        expect(account).not_to model_have_error_on_field(:note)\n      end\n    end\n  end\n\n  describe 'scopes' do\n    describe 'alphabetic' do\n      it 'sorts by alphabetic order of domain and username' do\n        matches = [\n          { username: 'a', domain: 'a' },\n          { username: 'b', domain: 'a' },\n          { username: 'a', domain: 'b' },\n          { username: 'b', domain: 'b' },\n        ].map(&method(:Fabricate).curry(2).call(:account))\n\n        expect(Account.alphabetic).to eq matches\n      end\n    end\n\n    describe 'matches_display_name' do\n      it 'matches display name which starts with the given string' do\n        match = Fabricate(:account, display_name: 'pattern and suffix')\n        Fabricate(:account, display_name: 'prefix and pattern')\n\n        expect(Account.matches_display_name('pattern')).to eq [match]\n      end\n    end\n\n    describe 'matches_username' do\n      it 'matches display name which starts with the given string' do\n        match = Fabricate(:account, username: 'pattern_and_suffix')\n        Fabricate(:account, username: 'prefix_and_pattern')\n\n        expect(Account.matches_username('pattern')).to eq [match]\n      end\n    end\n\n    describe 'expiring' do\n      it 'returns remote accounts with followers whose subscription expiration date is past or not given' do\n        local = Fabricate(:account, domain: nil)\n        matches = [\n          { domain: 'remote', subscription_expires_at: '2000-01-01T00:00:00Z' },\n        ].map(&method(:Fabricate).curry(2).call(:account))\n        matches.each(&local.method(:follow!))\n        Fabricate(:account, domain: 'remote', subscription_expires_at: nil)\n        local.follow!(Fabricate(:account, domain: 'remote', subscription_expires_at: '2000-01-03T00:00:00Z'))\n        local.follow!(Fabricate(:account, domain: nil, subscription_expires_at: nil))\n\n        expect(Account.expiring('2000-01-02T00:00:00Z').recent).to eq matches.reverse\n      end\n    end\n\n    describe 'remote' do\n      it 'returns an array of accounts who have a domain' do\n        account_1 = Fabricate(:account, domain: nil)\n        account_2 = Fabricate(:account, domain: 'example.com')\n        expect(Account.remote).to match_array([account_2])\n      end\n    end\n\n    describe 'by_domain_accounts' do\n      it 'returns accounts grouped by domain sorted by accounts' do\n        2.times { Fabricate(:account, domain: 'example.com') }\n        Fabricate(:account, domain: 'example2.com')\n\n        results = Account.by_domain_accounts\n        expect(results.length).to eq 2\n        expect(results.first.domain).to eq 'example.com'\n        expect(results.first.accounts_count).to eq 2\n        expect(results.last.domain).to eq 'example2.com'\n        expect(results.last.accounts_count).to eq 1\n      end\n    end\n\n    describe 'local' do\n      it 'returns an array of accounts who do not have a domain' do\n        account_1 = Fabricate(:account, domain: nil)\n        account_2 = Fabricate(:account, domain: 'example.com')\n        expect(Account.local).to match_array([account_1])\n      end\n    end\n\n    describe 'partitioned' do\n      it 'returns a relation of accounts partitioned by domain' do\n        matches = ['a', 'b', 'a', 'b']\n        matches.size.times.to_a.shuffle.each do |index|\n          matches[index] = Fabricate(:account, domain: matches[index])\n        end\n\n        expect(Account.partitioned).to match_array(matches)\n      end\n    end\n\n    describe 'recent' do\n      it 'returns a relation of accounts sorted by recent creation' do\n        matches = 2.times.map { Fabricate(:account) }\n        expect(Account.recent).to match_array(matches)\n      end\n    end\n\n    describe 'silenced' do\n      it 'returns an array of accounts who are silenced' do\n        account_1 = Fabricate(:account, silenced: true)\n        account_2 = Fabricate(:account, silenced: false)\n        expect(Account.silenced).to match_array([account_1])\n      end\n    end\n\n    describe 'suspended' do\n      it 'returns an array of accounts who are suspended' do\n        account_1 = Fabricate(:account, suspended: true)\n        account_2 = Fabricate(:account, suspended: false)\n        expect(Account.suspended).to match_array([account_1])\n      end\n    end\n  end\n\n  context 'when is local' do\n    # Test disabled because test environment omits autogenerating keys for performance\n    xit 'generates keys' do\n      account = Account.create!(domain: nil, username: Faker::Internet.user_name(nil, ['_']))\n      expect(account.keypair.private?).to eq true\n    end\n  end\n\n  context 'when is remote' do\n    it 'does not generate keys' do\n      key = OpenSSL::PKey::RSA.new(1024).public_key\n      account = Account.create!(domain: 'remote', username: Faker::Internet.user_name(nil, ['_']), public_key: key.to_pem)\n      expect(account.keypair.params).to eq key.params\n    end\n\n    it 'normalizes domain' do\n      account = Account.create!(domain: 'にゃん', username: Faker::Internet.user_name(nil, ['_']))\n      expect(account.domain).to eq 'xn--r9j5b5b'\n    end\n  end\n\n  include_examples 'AccountAvatar', :account\nend\n"
  },
  {
    "path": "spec/models/account_stat_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe AccountStat, type: :model do\nend\n"
  },
  {
    "path": "spec/models/account_tag_stat_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe AccountTagStat, type: :model do\n  key = 'accounts_count'\n  let(:account_tag_stat) { Fabricate(:tag).account_tag_stat }\n\n  describe '#increment_count!' do\n    it 'calls #update' do\n      args = { key => account_tag_stat.public_send(key) + 1 }\n      expect(account_tag_stat).to receive(:update).with(args)\n      account_tag_stat.increment_count!(key)\n    end\n\n    it 'increments value by 1' do\n      expect do\n        account_tag_stat.increment_count!(key)\n      end.to change { account_tag_stat.accounts_count }.by(1)\n    end\n  end\n\n  describe '#decrement_count!' do\n    it 'calls #update' do\n      args = { key => [account_tag_stat.public_send(key) - 1, 0].max }\n      expect(account_tag_stat).to receive(:update).with(args)\n      account_tag_stat.decrement_count!(key)\n    end\n\n    it 'decrements value by 1' do\n      account_tag_stat.update(key => 1)\n\n      expect do\n        account_tag_stat.decrement_count!(key)\n      end.to change { account_tag_stat.accounts_count }.by(-1)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/models/admin/account_action_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Admin::AccountAction, type: :model do\n  let(:account_action) { described_class.new }\n\n  describe '#save!' do\n    subject              { account_action.save! }\n    let(:account)        { Fabricate(:account, user: Fabricate(:user, admin: true)) }\n    let(:target_account) { Fabricate(:account, user: Fabricate(:user)) }\n    let(:type)           { 'disable' }\n\n    before do\n      account_action.assign_attributes(\n        type:            type,\n        current_account: account,\n        target_account:  target_account\n      )\n    end\n\n    context 'type is \"disable\"' do\n      let(:type) { 'disable' }\n\n      it 'disable user' do\n        subject\n        expect(target_account.user).to be_disabled\n      end\n    end\n\n    context 'type is \"silence\"' do\n      let(:type) { 'silence' }\n\n      it 'silences account' do\n        subject\n        expect(target_account).to be_silenced\n      end\n    end\n\n    context 'type is \"suspend\"' do\n      let(:type) { 'suspend' }\n\n      it 'suspends account' do\n        subject\n        expect(target_account).to be_suspended\n      end\n\n      it 'queues Admin::SuspensionWorker by 1' do\n        Sidekiq::Testing.fake! do\n          expect do\n            subject\n          end.to change { Admin::SuspensionWorker.jobs.size }.by 1\n        end\n      end\n    end\n\n    it 'creates Admin::ActionLog' do\n      expect do\n        subject\n      end.to change { Admin::ActionLog.count }.by 1\n    end\n\n    it 'calls queue_email!' do\n      expect(account_action).to receive(:queue_email!)\n      subject\n    end\n\n    it 'calls process_reports!' do\n      expect(account_action).to receive(:process_reports!)\n      subject\n    end\n  end\n\n  describe '#report' do\n    subject { account_action.report }\n\n    context 'report_id.present?' do\n      before do\n        account_action.report_id = Fabricate(:report).id\n      end\n\n      it 'returns Report' do\n        expect(subject).to be_instance_of Report\n      end\n    end\n\n    context '!report_id.present?' do\n      it 'returns nil' do\n        expect(subject).to be_nil\n      end\n    end\n  end\n\n  describe '#with_report?' do\n    subject { account_action.with_report? }\n\n    context '!report.nil?' do\n      before do\n        account_action.report_id = Fabricate(:report).id\n      end\n\n      it 'returns true' do\n        expect(subject).to be true\n      end\n    end\n\n    context '!(!report.nil?)' do\n      it 'returns false' do\n        expect(subject).to be false\n      end\n    end\n  end\n\n  describe '.types_for_account' do\n    subject { described_class.types_for_account(account) }\n\n    context 'account.local?' do\n      let(:account) { Fabricate(:account, domain: nil) }\n\n      it 'returns [\"none\", \"disable\", \"silence\", \"suspend\"]' do\n        expect(subject).to eq %w(none disable silence suspend)\n      end\n    end\n\n    context '!account.local?' do\n      let(:account) { Fabricate(:account, domain: 'hoge.com') }\n\n      it 'returns [\"silence\", \"suspend\"]' do\n        expect(subject).to eq %w(silence suspend)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/models/admin/action_log_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe Admin::ActionLog, type: :model do\n  describe '#action' do\n    it 'returns action' do\n      action_log = described_class.new(action: 'hoge')\n      expect(action_log.action).to be :hoge\n    end\n  end\nend\n"
  },
  {
    "path": "spec/models/backup_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Backup, type: :model do\nend\n"
  },
  {
    "path": "spec/models/block_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Block, type: :model do\n  describe 'validations' do\n    it 'has a valid fabricator' do\n      block = Fabricate.build(:block)\n      expect(block).to be_valid\n    end\n\n    it 'is invalid without an account' do\n      block = Fabricate.build(:block, account: nil)\n      block.valid?\n      expect(block).to model_have_error_on_field(:account)\n    end\n\n    it 'is invalid without a target_account' do\n      block = Fabricate.build(:block, target_account: nil)\n      block.valid?\n      expect(block).to model_have_error_on_field(:target_account)\n    end\n  end\n\n  it 'removes blocking cache after creation' do\n    account = Fabricate(:account)\n    target_account = Fabricate(:account)\n    Rails.cache.write(\"exclude_account_ids_for:#{account.id}\", [])\n    Rails.cache.write(\"exclude_account_ids_for:#{target_account.id}\", [])\n\n    Block.create!(account: account, target_account: target_account)\n\n    expect(Rails.cache.exist?(\"exclude_account_ids_for:#{account.id}\")).to eq false\n    expect(Rails.cache.exist?(\"exclude_account_ids_for:#{target_account.id}\")).to eq false\n  end\n\n  it 'removes blocking cache after destruction' do\n    account = Fabricate(:account)\n    target_account = Fabricate(:account)\n    block = Block.create!(account: account, target_account: target_account)\n    Rails.cache.write(\"exclude_account_ids_for:#{account.id}\", [target_account.id])\n    Rails.cache.write(\"exclude_account_ids_for:#{target_account.id}\", [account.id])\n\n    block.destroy!\n\n    expect(Rails.cache.exist?(\"exclude_account_ids_for:#{account.id}\")).to eq false\n    expect(Rails.cache.exist?(\"exclude_account_ids_for:#{target_account.id}\")).to eq false\n  end\nend\n"
  },
  {
    "path": "spec/models/concerns/account_finder_concern_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe AccountFinderConcern do\n  describe 'local finders' do\n    before do\n      @account = Fabricate(:account, username: 'Alice')\n    end\n\n    describe '.find_local' do\n      it 'returns case-insensitive result' do\n        expect(Account.find_local('alice')).to eq(@account)\n      end\n\n      it 'returns correctly cased result' do\n        expect(Account.find_local('Alice')).to eq(@account)\n      end\n\n      it 'returns nil without a match' do\n        expect(Account.find_local('a_ice')).to be_nil\n      end\n\n      it 'returns nil for regex style username value' do\n        expect(Account.find_local('al%')).to be_nil\n      end\n\n      it 'returns nil for nil username value' do\n        expect(Account.find_local(nil)).to be_nil\n      end\n\n      it 'returns nil for blank username value' do\n        expect(Account.find_local('')).to be_nil\n      end\n    end\n\n    describe '.find_local!' do\n      it 'returns matching result' do\n        expect(Account.find_local!('alice')).to eq(@account)\n      end\n\n      it 'raises on non-matching result' do\n        expect { Account.find_local!('missing') }.to raise_error(ActiveRecord::RecordNotFound)\n      end\n\n      it 'raises with blank username' do\n        expect { Account.find_local!('') }.to raise_error(ActiveRecord::RecordNotFound)\n      end\n\n      it 'raises with nil username' do\n        expect { Account.find_local!(nil) }.to raise_error(ActiveRecord::RecordNotFound)\n      end\n    end\n  end\n\n  describe 'remote finders' do\n    before do\n      @account = Fabricate(:account, username: 'Alice', domain: 'mastodon.social')\n    end\n\n    describe '.find_remote' do\n      it 'returns exact match result' do\n        expect(Account.find_remote('alice', 'mastodon.social')).to eq(@account)\n      end\n\n      it 'returns case-insensitive result' do\n        expect(Account.find_remote('ALICE', 'MASTODON.SOCIAL')).to eq(@account)\n      end\n\n      it 'returns nil when username does not match' do\n        expect(Account.find_remote('a_ice', 'mastodon.social')).to be_nil\n      end\n\n      it 'returns nil when domain does not match' do\n        expect(Account.find_remote('alice', 'm_stodon.social')).to be_nil\n      end\n\n      it 'returns nil for regex style domain value' do\n        expect(Account.find_remote('alice', 'm%')).to be_nil\n      end\n\n      it 'returns nil for nil username value' do\n        expect(Account.find_remote(nil, 'domain')).to be_nil\n      end\n\n      it 'returns nil for blank username value' do\n        expect(Account.find_remote('', 'domain')).to be_nil\n      end\n    end\n\n    describe '.find_remote!' do\n      it 'returns matching result' do\n        expect(Account.find_remote!('alice', 'mastodon.social')).to eq(@account)\n      end\n\n      it 'raises on non-matching result' do\n        expect { Account.find_remote!('missing', 'mastodon.host') }.to raise_error(ActiveRecord::RecordNotFound)\n      end\n\n      it 'raises with blank username' do\n        expect { Account.find_remote!('', '') }.to raise_error(ActiveRecord::RecordNotFound)\n      end\n\n      it 'raises with nil username' do\n        expect { Account.find_remote!(nil, nil) }.to raise_error(ActiveRecord::RecordNotFound)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/models/concerns/account_interactions_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe AccountInteractions do\n  let(:account)            { Fabricate(:account, username: 'account') }\n  let(:account_id)         { account.id }\n  let(:account_ids)        { [account_id] }\n  let(:target_account)     { Fabricate(:account, username: 'target') }\n  let(:target_account_id)  { target_account.id }\n  let(:target_account_ids) { [target_account_id] }\n\n  describe '.following_map' do\n    subject { Account.following_map(target_account_ids, account_id) }\n\n    context 'account with Follow' do\n      it 'returns { target_account_id => true }' do\n        Fabricate(:follow, account: account, target_account: target_account)\n        is_expected.to eq(target_account_id => { reblogs: true })\n      end\n    end\n\n    context 'account without Follow' do\n      it 'returns {}' do\n        is_expected.to eq({})\n      end\n    end\n  end\n\n  describe '.followed_by_map' do\n    subject { Account.followed_by_map(target_account_ids, account_id) }\n\n    context 'account with Follow' do\n      it 'returns { target_account_id => true }' do\n        Fabricate(:follow, account: target_account, target_account: account)\n        is_expected.to eq(target_account_id => true)\n      end\n    end\n\n    context 'account without Follow' do\n      it 'returns {}' do\n        is_expected.to eq({})\n      end\n    end\n  end\n\n  describe '.blocking_map' do\n    subject { Account.blocking_map(target_account_ids, account_id) }\n\n    context 'account with Block' do\n      it 'returns { target_account_id => true }' do\n        Fabricate(:block, account: account, target_account: target_account)\n        is_expected.to eq(target_account_id => true)\n      end\n    end\n\n    context 'account without Block' do\n      it 'returns {}' do\n        is_expected.to eq({})\n      end\n    end\n  end\n\n  describe '.muting_map' do\n    subject { Account.muting_map(target_account_ids, account_id) }\n\n    context 'account with Mute' do\n      before do\n        Fabricate(:mute, target_account: target_account, account: account, hide_notifications: hide)\n      end\n\n      context 'if Mute#hide_notifications?' do\n        let(:hide) { true }\n\n        it 'returns { target_account_id => { notifications: true } }' do\n          is_expected.to eq(target_account_id => { notifications: true })\n        end\n      end\n\n      context 'unless Mute#hide_notifications?' do\n        let(:hide) { false }\n\n        it 'returns { target_account_id => { notifications: false } }' do\n          is_expected.to eq(target_account_id => { notifications: false })\n        end\n      end\n    end\n\n    context 'account without Mute' do\n      it 'returns {}' do\n        is_expected.to eq({})\n      end\n    end\n  end\n\n  describe '#follow!' do\n    it 'creates and returns Follow' do\n      expect do\n        expect(account.follow!(target_account)).to be_kind_of Follow\n      end.to change { account.following.count }.by 1\n    end\n  end\n\n  describe '#block' do\n    it 'creates and returns Block' do\n      expect do\n        expect(account.block!(target_account)).to be_kind_of Block\n      end.to change { account.block_relationships.count }.by 1\n    end\n  end\n\n  describe '#mute!' do\n    subject { account.mute!(target_account, notifications: arg_notifications) }\n\n    context 'Mute does not exist yet' do\n      context 'arg :notifications is nil' do\n        let(:arg_notifications) { nil }\n\n        it 'creates Mute, and returns Mute' do\n          expect do\n            expect(subject).to be_kind_of Mute\n          end.to change { account.mute_relationships.count }.by 1\n        end\n      end\n\n      context 'arg :notifications is false' do\n        let(:arg_notifications) { false }\n\n        it 'creates Mute, and returns Mute' do\n          expect do\n            expect(subject).to be_kind_of Mute\n          end.to change { account.mute_relationships.count }.by 1\n        end\n      end\n\n      context 'arg :notifications is true' do\n        let(:arg_notifications) { true }\n\n        it 'creates Mute, and returns Mute' do\n          expect do\n            expect(subject).to be_kind_of Mute\n          end.to change { account.mute_relationships.count }.by 1\n        end\n      end\n    end\n\n    context 'Mute already exists' do\n      before do\n        account.mute_relationships << mute\n      end\n\n      let(:mute) do\n        Fabricate(:mute,\n                  account:            account,\n                  target_account:     target_account,\n                  hide_notifications: hide_notifications)\n      end\n\n      context 'mute.hide_notifications is true' do\n        let(:hide_notifications) { true }\n\n        context 'arg :notifications is nil' do\n          let(:arg_notifications) { nil }\n\n          it 'returns Mute without updating mute.hide_notifications' do\n            expect do\n              expect(subject).to be_kind_of Mute\n            end.not_to change { mute.reload.hide_notifications? }.from(true)\n          end\n        end\n\n        context 'arg :notifications is false' do\n          let(:arg_notifications) { false }\n\n          it 'returns Mute, and updates mute.hide_notifications false' do\n            expect do\n              expect(subject).to be_kind_of Mute\n            end.to change { mute.reload.hide_notifications? }.from(true).to(false)\n          end\n        end\n\n        context 'arg :notifications is true' do\n          let(:arg_notifications) { true }\n\n          it 'returns Mute without updating mute.hide_notifications' do\n            expect do\n              expect(subject).to be_kind_of Mute\n            end.not_to change { mute.reload.hide_notifications? }.from(true)\n          end\n        end\n      end\n\n      context 'mute.hide_notifications is false' do\n        let(:hide_notifications) { false }\n\n        context 'arg :notifications is nil' do\n          let(:arg_notifications) { nil }\n\n          it 'returns Mute, and updates mute.hide_notifications true' do\n            expect do\n              expect(subject).to be_kind_of Mute\n            end.to change { mute.reload.hide_notifications? }.from(false).to(true)\n          end\n        end\n\n        context 'arg :notifications is false' do\n          let(:arg_notifications) { false }\n\n          it 'returns Mute without updating mute.hide_notifications' do\n            expect do\n              expect(subject).to be_kind_of Mute\n            end.not_to change { mute.reload.hide_notifications? }.from(false)\n          end\n        end\n\n        context 'arg :notifications is true' do\n          let(:arg_notifications) { true }\n\n          it 'returns Mute, and updates mute.hide_notifications true' do\n            expect do\n              expect(subject).to be_kind_of Mute\n            end.to change { mute.reload.hide_notifications? }.from(false).to(true)\n          end\n        end\n      end\n    end\n  end\n\n  describe '#mute_conversation!' do\n    let(:conversation) { Fabricate(:conversation) }\n\n    subject { account.mute_conversation!(conversation) }\n\n    it 'creates and returns ConversationMute' do\n      expect do\n        is_expected.to be_kind_of ConversationMute\n      end.to change { account.conversation_mutes.count }.by 1\n    end\n  end\n\n  describe '#block_domain!' do\n    let(:domain) { 'example.com' }\n\n    subject { account.block_domain!(domain) }\n\n    it 'creates and returns AccountDomainBlock' do\n      expect do\n        is_expected.to be_kind_of AccountDomainBlock\n      end.to change { account.domain_blocks.count }.by 1\n    end\n  end\n\n  describe '#unfollow!' do\n    subject { account.unfollow!(target_account) }\n\n    context 'following target_account' do\n      it 'returns destroyed Follow' do\n        account.active_relationships.create(target_account: target_account)\n        is_expected.to be_kind_of Follow\n        expect(subject).to be_destroyed\n      end\n    end\n\n    context 'not following target_account' do\n      it 'returns nil' do\n        is_expected.to be_nil\n      end\n    end\n  end\n\n  describe '#unblock!' do\n    subject { account.unblock!(target_account) }\n\n    context 'blocking target_account' do\n      it 'returns destroyed Block' do\n        account.block_relationships.create(target_account: target_account)\n        is_expected.to be_kind_of Block\n        expect(subject).to be_destroyed\n      end\n    end\n\n    context 'not blocking target_account' do\n      it 'returns nil' do\n        is_expected.to be_nil\n      end\n    end\n  end\n\n  describe '#unmute!' do\n    subject { account.unmute!(target_account) }\n\n    context 'muting target_account' do\n      it 'returns destroyed Mute' do\n        account.mute_relationships.create(target_account: target_account)\n        is_expected.to be_kind_of Mute\n        expect(subject).to be_destroyed\n      end\n    end\n\n    context 'not muting target_account' do\n      it 'returns nil' do\n        is_expected.to be_nil\n      end\n    end\n  end\n\n  describe '#unmute_conversation!' do\n    let(:conversation) { Fabricate(:conversation) }\n\n    subject { account.unmute_conversation!(conversation) }\n\n    context 'muting the conversation' do\n      it 'returns destroyed ConversationMute' do\n        account.conversation_mutes.create(conversation: conversation)\n        is_expected.to be_kind_of ConversationMute\n        expect(subject).to be_destroyed\n      end\n    end\n\n    context 'not muting the conversation' do\n      it 'returns nil' do\n        is_expected.to be nil\n      end\n    end\n  end\n\n  describe '#unblock_domain!' do\n    let(:domain) { 'example.com' }\n\n    subject { account.unblock_domain!(domain) }\n\n    context 'blocking the domain' do\n      it 'returns destroyed AccountDomainBlock' do\n        account_domain_block = Fabricate(:account_domain_block, domain: domain)\n        account.domain_blocks << account_domain_block\n        is_expected.to be_kind_of AccountDomainBlock\n        expect(subject).to be_destroyed\n      end\n    end\n\n    context 'unblocking the domain' do\n      it 'returns nil' do\n        is_expected.to be_nil\n      end\n    end\n  end\n\n  describe '#following?' do\n    subject { account.following?(target_account) }\n\n    context 'following target_account' do\n      it 'returns true' do\n        account.active_relationships.create(target_account: target_account)\n        is_expected.to be true\n      end\n    end\n\n    context 'not following target_account' do\n      it 'returns false' do\n        is_expected.to be false\n      end\n    end\n  end\n\n  describe '#blocking?' do\n    subject { account.blocking?(target_account) }\n\n    context 'blocking target_account' do\n      it 'returns true' do\n        account.block_relationships.create(target_account: target_account)\n        is_expected.to be true\n      end\n    end\n\n    context 'not blocking target_account' do\n      it 'returns false' do\n        is_expected.to be false\n      end\n    end\n  end\n\n  describe '#domain_blocking?' do\n    let(:domain)               { 'example.com' }\n\n    subject { account.domain_blocking?(domain) }\n\n    context 'blocking the domain' do\n      it' returns true' do\n        account_domain_block = Fabricate(:account_domain_block, domain: domain)\n        account.domain_blocks << account_domain_block\n        is_expected.to be true\n      end\n    end\n\n    context 'not blocking the domain' do\n      it 'returns false' do\n        is_expected.to be false\n      end\n    end\n  end\n\n  describe '#muting?' do\n    subject { account.muting?(target_account) }\n\n    context 'muting target_account' do\n      it 'returns true' do\n        mute = Fabricate(:mute, account: account, target_account: target_account)\n        account.mute_relationships << mute\n        is_expected.to be true\n      end\n    end\n\n    context 'not muting target_account' do\n      it 'returns false' do\n        is_expected.to be false\n      end\n    end\n  end\n\n  describe '#muting_conversation?' do\n    let(:conversation) { Fabricate(:conversation) }\n\n    subject { account.muting_conversation?(conversation) }\n\n    context 'muting the conversation' do\n      it 'returns true' do\n        account.conversation_mutes.create(conversation: conversation)\n        is_expected.to be true\n      end\n    end\n\n    context 'not muting the conversation' do\n      it 'returns false' do\n        is_expected.to be false\n      end\n    end\n  end\n\n  describe '#muting_notifications?' do\n    before do\n      mute = Fabricate(:mute, target_account: target_account, account: account, hide_notifications: hide)\n      account.mute_relationships << mute\n    end\n\n    subject { account.muting_notifications?(target_account) }\n\n    context 'muting notifications of target_account' do\n      let(:hide) { true }\n\n      it 'returns true' do\n        is_expected.to be true\n      end\n    end\n\n    context 'not muting notifications of target_account' do\n      let(:hide) { false }\n\n      it 'returns false' do\n        is_expected.to be false\n      end\n    end\n  end\n\n  describe '#requested?' do\n    subject { account.requested?(target_account) }\n\n    context 'requested by target_account' do\n      it 'returns true' do\n        Fabricate(:follow_request, account: account, target_account: target_account)\n        is_expected.to be true\n      end\n    end\n\n    context 'not requested by target_account' do\n      it 'returns false' do\n        is_expected.to be false\n      end\n    end\n  end\n\n  describe '#favourited?' do\n    let(:status) { Fabricate(:status, account: account, favourites: favourites) }\n\n    subject { account.favourited?(status) }\n\n    context 'favorited' do\n      let(:favourites) { [Fabricate(:favourite, account: account)] }\n\n      it 'returns true' do\n        is_expected.to be true\n      end\n    end\n\n    context 'not favorited' do\n      let(:favourites) { [] }\n\n      it 'returns false' do\n        is_expected.to be false\n      end\n    end\n  end\n\n  describe '#reblogged?' do\n    let(:status) { Fabricate(:status, account: account, reblogs: reblogs) }\n\n    subject { account.reblogged?(status) }\n\n    context 'reblogged' do\n      let(:reblogs) { [Fabricate(:status, account: account)] }\n\n      it 'returns true' do\n        is_expected.to be true\n      end\n    end\n\n    context 'not reblogged' do\n      let(:reblogs) { [] }\n\n      it 'returns false' do\n        is_expected.to be false\n      end\n    end\n  end\n\n  describe '#pinned?' do\n    let(:status) { Fabricate(:status, account: account) }\n\n    subject { account.pinned?(status) }\n\n    context 'pinned' do\n      it 'returns true' do\n        Fabricate(:status_pin, account: account, status: status)\n        is_expected.to be true\n      end\n    end\n\n    context 'not pinned' do\n      it 'returns false' do\n        is_expected.to be false\n      end\n    end\n  end\n\n  describe 'muting an account' do\n    let(:me) { Fabricate(:account, username: 'Me') }\n    let(:you) { Fabricate(:account, username: 'You') }\n\n    context 'with the notifications option unspecified' do\n      before do\n        me.mute!(you)\n      end\n\n      it 'defaults to muting notifications' do\n        expect(me.muting_notifications?(you)).to be true\n      end\n    end\n\n    context 'with the notifications option set to false' do\n      before do\n        me.mute!(you, notifications: false)\n      end\n\n      it 'does not mute notifications' do\n        expect(me.muting_notifications?(you)).to be false\n      end\n    end\n\n    context 'with the notifications option set to true' do\n      before do\n        me.mute!(you, notifications: true)\n      end\n\n      it 'does mute notifications' do\n        expect(me.muting_notifications?(you)).to be true\n      end\n    end\n  end\n\n  describe 'ignoring reblogs from an account' do\n    before do\n      @me = Fabricate(:account, username: 'Me')\n      @you = Fabricate(:account, username: 'You')\n    end\n\n    context 'with the reblogs option unspecified' do\n      before do\n        @me.follow!(@you)\n      end\n\n      it 'defaults to showing reblogs' do\n        expect(@me.muting_reblogs?(@you)).to be(false)\n      end\n    end\n\n    context 'with the reblogs option set to false' do\n      before do\n        @me.follow!(@you, reblogs: false)\n      end\n\n      it 'does mute reblogs' do\n        expect(@me.muting_reblogs?(@you)).to be(true)\n      end\n    end\n\n    context 'with the reblogs option set to true' do\n      before do\n        @me.follow!(@you, reblogs: true)\n      end\n\n      it 'does not mute reblogs' do\n        expect(@me.muting_reblogs?(@you)).to be(false)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/models/concerns/remotable_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe Remotable do\n  class Foo\n    def initialize\n      @attrs = {}\n    end\n\n    def [](arg)\n      @attrs[arg]\n    end\n\n    def []=(arg1, arg2)\n      @attrs[arg1] = arg2\n    end\n\n    def hoge=(arg); end\n\n    def hoge_file_name=(arg); end\n\n    def has_attribute?(arg); end\n\n    def self.attachment_definitions\n      { hoge: nil }\n    end\n  end\n\n  context 'Remotable module is included' do\n    before do\n      class Foo\n        include Remotable\n        remotable_attachment :hoge, 1.kilobyte\n      end\n    end\n\n    let(:attribute_name) { \"#{hoge}_remote_url\".to_sym }\n    let(:code)           { 200 }\n    let(:file)           { 'filename=\"foo.txt\"' }\n    let(:foo)            { Foo.new }\n    let(:headers)        { { 'content-disposition' => file } }\n    let(:hoge)           { :hoge }\n    let(:url)            { 'https://google.com' }\n\n    let(:request) do\n      stub_request(:get, url)\n        .to_return(status: code, headers: headers)\n    end\n\n    it 'defines a method #hoge_remote_url=' do\n      expect(foo).to respond_to(:hoge_remote_url=)\n    end\n\n    it 'defines a method #reset_hoge!' do\n      expect(foo).to respond_to(:reset_hoge!)\n    end\n\n    describe '#hoge_remote_url' do\n      before do\n        request\n      end\n\n      it 'always returns arg' do\n        [nil, '', [], {}].each do |arg|\n          expect(foo.hoge_remote_url = arg).to be arg\n        end\n      end\n\n      context 'Addressable::URI::InvalidURIError raised' do\n        it 'makes no request' do\n          allow(Addressable::URI).to receive_message_chain(:parse, :normalize)\n            .with(url).with(no_args).and_raise(Addressable::URI::InvalidURIError)\n\n          foo.hoge_remote_url = url\n          expect(request).not_to have_been_requested\n        end\n      end\n\n      context 'scheme is neither http nor https' do\n        let(:url) { 'ftp://google.com' }\n\n        it 'makes no request' do\n          foo.hoge_remote_url = url\n          expect(request).not_to have_been_requested\n        end\n      end\n\n      context 'parsed_url.host is empty' do\n        it 'makes no request' do\n          parsed_url = double(scheme: 'https', host: double(blank?: true))\n          allow(Addressable::URI).to receive_message_chain(:parse, :normalize)\n            .with(url).with(no_args).and_return(parsed_url)\n\n          foo.hoge_remote_url = url\n          expect(request).not_to have_been_requested\n        end\n      end\n\n      context 'parsed_url.host is nil' do\n        it 'makes no request' do\n          parsed_url = Addressable::URI.parse('https:https://example.com/path/file.png')\n          allow(Addressable::URI).to receive_message_chain(:parse, :normalize)\n            .with(url).with(no_args).and_return(parsed_url)\n\n          foo.hoge_remote_url = url\n          expect(request).not_to have_been_requested\n        end\n      end\n\n      context 'foo[attribute_name] == url' do\n        it 'makes no request' do\n          allow(foo).to receive(:[]).with(attribute_name).and_return(url)\n\n          foo.hoge_remote_url = url\n          expect(request).not_to have_been_requested\n        end\n      end\n\n      context \"scheme is https, parsed_url.host isn't empty, and foo[attribute_name] != url\" do\n        it 'makes a request' do\n          foo.hoge_remote_url = url\n          expect(request).to have_been_requested\n        end\n\n        context 'response.code != 200' do\n          let(:code) { 500 }\n\n          it 'calls not send' do\n            expect(foo).not_to receive(:send).with(\"#{hoge}=\", any_args)\n            expect(foo).not_to receive(:send).with(\"#{hoge}_file_name=\", any_args)\n            foo.hoge_remote_url = url\n          end\n        end\n\n        context 'response.code == 200' do\n          let(:code) { 200 }\n\n          context 'response contains headers[\"content-disposition\"]' do\n            let(:file)      { 'filename=\"foo.txt\"' }\n            let(:headers)   { { 'content-disposition' => file } }\n\n            it 'calls send' do\n              string_io = StringIO.new('')\n              extname   = '.txt'\n              basename  = '0123456789abcdef'\n\n              allow(SecureRandom).to receive(:hex).and_return(basename)\n              allow(StringIO).to receive(:new).with(anything).and_return(string_io)\n\n              expect(foo).to receive(:send).with(\"#{hoge}=\", string_io)\n              expect(foo).to receive(:send).with(\"#{hoge}_file_name=\", basename + extname)\n              foo.hoge_remote_url = url\n            end\n          end\n\n          context 'if has_attribute?' do\n            it 'calls foo[attribute_name] = url' do\n              allow(foo).to receive(:has_attribute?).with(attribute_name).and_return(true)\n              expect(foo).to receive('[]=').with(attribute_name, url)\n              foo.hoge_remote_url = url\n            end\n          end\n\n          context 'unless has_attribute?' do\n            it 'calls not foo[attribute_name] = url' do\n              allow(foo).to receive(:has_attribute?)\n                .with(attribute_name).and_return(false)\n              expect(foo).not_to receive('[]=').with(attribute_name, url)\n              foo.hoge_remote_url = url\n            end\n          end\n        end\n\n        context 'an error raised during the request' do\n          let(:request) { stub_request(:get, url).to_raise(error_class) }\n\n          error_classes = [\n            HTTP::TimeoutError,\n            HTTP::ConnectionError,\n            OpenSSL::SSL::SSLError,\n            Paperclip::Errors::NotIdentifiedByImageMagickError,\n            Addressable::URI::InvalidURIError,\n          ]\n\n          error_classes.each do |error_class|\n            let(:error_class) { error_class }\n\n            it 'calls Rails.logger.debug' do\n              expect(Rails.logger).to receive(:debug).with(/^Error fetching remote #{hoge}: /)\n              foo.hoge_remote_url = url\n            end\n          end\n        end\n      end\n    end\n\n    describe '#reset_hoge!' do\n      context 'if url.blank?' do\n        it 'returns nil, without clearing foo[attribute_name] and calling #hoge_remote_url=' do\n          url = nil\n          expect(foo).not_to receive(:send).with(:hoge_remote_url=, url)\n          foo[attribute_name] = url\n          expect(foo.reset_hoge!).to be_nil\n          expect(foo[attribute_name]).to be_nil\n        end\n      end\n\n      context 'unless url.blank?' do\n        it 'clears foo[attribute_name] and calls #hoge_remote_url=' do\n          foo[attribute_name] = url\n          expect(foo).to receive(:send).with(:hoge_remote_url=, url)\n          foo.reset_hoge!\n          expect(foo[attribute_name]).to be ''\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/models/concerns/status_threading_concern_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe StatusThreadingConcern do\n  describe '#ancestors' do\n    let!(:alice)  { Fabricate(:account, username: 'alice') }\n    let!(:bob)    { Fabricate(:account, username: 'bob', domain: 'example.com') }\n    let!(:jeff)   { Fabricate(:account, username: 'jeff') }\n    let!(:status) { Fabricate(:status, account: alice) }\n    let!(:reply1) { Fabricate(:status, thread: status, account: jeff) }\n    let!(:reply2) { Fabricate(:status, thread: reply1, account: bob) }\n    let!(:reply3) { Fabricate(:status, thread: reply2, account: alice) }\n    let!(:viewer) { Fabricate(:account, username: 'viewer') }\n\n    it 'returns conversation history' do\n      expect(reply3.ancestors(4)).to include(status, reply1, reply2)\n    end\n\n    it 'does not return conversation history user is not allowed to see' do\n      reply1.update(visibility: :private)\n      status.update(visibility: :direct)\n\n      expect(reply3.ancestors(4, viewer)).to_not include(reply1, status)\n    end\n\n    it 'does not return conversation history from blocked users' do\n      viewer.block!(jeff)\n      expect(reply3.ancestors(4, viewer)).to_not include(reply1)\n    end\n\n    it 'does not return conversation history from muted users' do\n      viewer.mute!(jeff)\n      expect(reply3.ancestors(4, viewer)).to_not include(reply1)\n    end\n\n    it 'does not return conversation history from silenced and not followed users' do\n      jeff.silence!\n      expect(reply3.ancestors(4, viewer)).to_not include(reply1)\n    end\n\n    it 'does not return conversation history from blocked domains' do\n      viewer.block_domain!('example.com')\n      expect(reply3.ancestors(4, viewer)).to_not include(reply2)\n    end\n\n    it 'ignores deleted records' do\n      first_status  = Fabricate(:status, account: bob)\n      second_status = Fabricate(:status, thread: first_status, account: alice)\n\n      # Create cache and delete cached record\n      second_status.ancestors(4)\n      first_status.destroy\n\n      expect(second_status.ancestors(4)).to eq([])\n    end\n\n    it 'can return more records than previously requested' do\n      first_status  = Fabricate(:status, account: bob)\n      second_status = Fabricate(:status, thread: first_status, account: alice)\n      third_status = Fabricate(:status, thread: second_status, account: alice)\n\n      # Create cache\n      second_status.ancestors(1)\n\n      expect(third_status.ancestors(2)).to eq([first_status, second_status])\n    end\n\n    it 'can return fewer records than previously requested' do\n      first_status  = Fabricate(:status, account: bob)\n      second_status = Fabricate(:status, thread: first_status, account: alice)\n      third_status = Fabricate(:status, thread: second_status, account: alice)\n\n      # Create cache\n      second_status.ancestors(2)\n\n      expect(third_status.ancestors(1)).to eq([second_status])\n    end\n  end\n\n  describe '#descendants' do\n    let!(:alice)  { Fabricate(:account, username: 'alice') }\n    let!(:bob)    { Fabricate(:account, username: 'bob', domain: 'example.com') }\n    let!(:jeff)   { Fabricate(:account, username: 'jeff') }\n    let!(:status) { Fabricate(:status, account: alice) }\n    let!(:reply1) { Fabricate(:status, thread: status, account: alice) }\n    let!(:reply2) { Fabricate(:status, thread: status, account: bob) }\n    let!(:reply3) { Fabricate(:status, thread: reply1, account: jeff) }\n    let!(:viewer) { Fabricate(:account, username: 'viewer') }\n\n    it 'returns replies' do\n      expect(status.descendants(4)).to include(reply1, reply2, reply3)\n    end\n\n    it 'does not return replies user is not allowed to see' do\n      reply1.update(visibility: :private)\n      reply3.update(visibility: :direct)\n\n      expect(status.descendants(4, viewer)).to_not include(reply1, reply3)\n    end\n\n    it 'does not return replies from blocked users' do\n      viewer.block!(jeff)\n      expect(status.descendants(4, viewer)).to_not include(reply3)\n    end\n\n    it 'does not return replies from muted users' do\n      viewer.mute!(jeff)\n      expect(status.descendants(4, viewer)).to_not include(reply3)\n    end\n\n    it 'does not return replies from silenced and not followed users' do\n      jeff.silence!\n      expect(status.descendants(4, viewer)).to_not include(reply3)\n    end\n\n    it 'does not return replies from blocked domains' do\n      viewer.block_domain!('example.com')\n      expect(status.descendants(4, viewer)).to_not include(reply2)\n    end\n\n    it 'promotes self-replies to the top while leaving the rest in order' do\n      a = Fabricate(:status, account: alice)\n      d = Fabricate(:status, account: jeff, thread: a)\n      e = Fabricate(:status, account: bob, thread: d)\n      c = Fabricate(:status, account: alice, thread: a)\n      f = Fabricate(:status, account: bob, thread: c)\n\n      expect(a.descendants(20)).to eq [c, d, e, f]\n    end\n  end\nend\n"
  },
  {
    "path": "spec/models/concerns/streamable_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe Streamable do\n  class Parent\n    def title; end\n\n    def target; end\n\n    def thread; end\n\n    def self.has_one(*); end\n\n    def self.after_create; end\n  end\n\n  class Child < Parent\n    include Streamable\n  end\n\n  child = Child.new\n\n  describe '#title' do\n    it 'calls Parent#title' do\n      expect_any_instance_of(Parent).to receive(:title)\n      child.title\n    end\n  end\n\n  describe '#content' do\n    it 'calls #title' do\n      expect_any_instance_of(Parent).to receive(:title)\n      child.content\n    end\n  end\n\n  describe '#target' do\n    it 'calls Parent#target' do\n      expect_any_instance_of(Parent).to receive(:target)\n      child.target\n    end\n  end\n\n  describe '#object_type' do\n    it 'returns :activity' do\n      expect(child.object_type).to eq :activity\n    end\n  end\n\n  describe '#thread' do\n    it 'calls Parent#thread' do\n      expect_any_instance_of(Parent).to receive(:thread)\n      child.thread\n    end\n  end\n\n  describe '#hidden?' do\n    it 'returns false' do\n      expect(child.hidden?).to be false\n    end\n  end\nend\n"
  },
  {
    "path": "spec/models/conversation_mute_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe ConversationMute, type: :model do\nend\n"
  },
  {
    "path": "spec/models/conversation_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Conversation, type: :model do\n  describe '#local?' do\n    it 'returns true when URI is nil' do\n      expect(Fabricate(:conversation).local?).to be true\n    end\n\n    it 'returns false when URI is not nil' do\n      expect(Fabricate(:conversation, uri: 'abc').local?).to be false\n    end\n  end\nend\n"
  },
  {
    "path": "spec/models/custom_emoji_filter_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe CustomEmojiFilter do\n  describe '#results' do\n    let!(:custom_emoji_0) { Fabricate(:custom_emoji, domain: 'a') }\n    let!(:custom_emoji_1) { Fabricate(:custom_emoji, domain: 'b') }\n    let!(:custom_emoji_2) { Fabricate(:custom_emoji, domain: nil, shortcode: 'hoge') }\n\n    subject { described_class.new(params).results }\n\n    context 'params have values' do\n      context 'local' do\n        let(:params) { { local: true } }\n\n        it 'returns ActiveRecord::Relation' do\n          expect(subject).to be_kind_of(ActiveRecord::Relation)\n          expect(subject).to match_array([custom_emoji_2])\n        end\n      end\n\n      context 'remote' do\n        let(:params) { { remote: true } }\n\n        it 'returns ActiveRecord::Relation' do\n          expect(subject).to be_kind_of(ActiveRecord::Relation)\n          expect(subject).to match_array([custom_emoji_0, custom_emoji_1])\n        end\n      end\n\n      context 'by_domain' do\n        let(:params) { { by_domain: 'a' } }\n\n        it 'returns ActiveRecord::Relation' do\n          expect(subject).to be_kind_of(ActiveRecord::Relation)\n          expect(subject).to match_array([custom_emoji_0])\n        end\n      end\n\n      context 'shortcode' do\n        let(:params) { { shortcode: 'hoge' } }\n\n        it 'returns ActiveRecord::Relation' do\n          expect(subject).to be_kind_of(ActiveRecord::Relation)\n          expect(subject).to match_array([custom_emoji_2])\n        end\n      end\n\n      context 'else' do\n        let(:params) { { else: 'else' } }\n\n        it 'raises RuntimeError' do\n          expect do\n            subject\n          end.to raise_error(RuntimeError, /Unknown filter: else/)\n        end\n      end\n    end\n\n    context 'params without value' do\n      let(:params) { { hoge: nil } }\n\n      it 'returns ActiveRecord::Relation' do\n        expect(subject).to be_kind_of(ActiveRecord::Relation)\n        expect(subject).to match_array([custom_emoji_0, custom_emoji_1, custom_emoji_2])\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/models/custom_emoji_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe CustomEmoji, type: :model do\n  describe '#search' do\n    let(:custom_emoji) { Fabricate(:custom_emoji, shortcode: shortcode) }\n\n    subject { described_class.search(search_term) }\n\n    context 'shortcode is exact' do\n      let(:shortcode) { 'blobpats' }\n      let(:search_term) { 'blobpats' }\n\n      it 'finds emoji' do\n        is_expected.to include(custom_emoji)\n      end\n    end\n\n    context 'shortcode is partial' do\n      let(:shortcode) { 'blobpats' }\n      let(:search_term) { 'blob' }\n\n      it 'finds emoji' do\n        is_expected.to include(custom_emoji)\n      end\n    end\n  end\n\n  describe '#local?' do\n    let(:custom_emoji) { Fabricate(:custom_emoji, domain: domain) }\n\n    subject { custom_emoji.local? }\n\n    context 'domain is nil' do\n      let(:domain) { nil }\n\n      it 'returns true' do\n        is_expected.to be true\n      end\n    end\n\n    context 'domain is present' do\n      let(:domain) { 'example.com' }\n\n      it 'returns false' do\n        is_expected.to be false\n      end\n    end\n  end\n\n  describe '#object_type' do\n    it 'returns :emoji' do\n      custom_emoji = Fabricate(:custom_emoji)\n      expect(custom_emoji.object_type).to be :emoji\n    end\n  end\n\n  describe '.from_text' do\n    let!(:emojo) { Fabricate(:custom_emoji) }\n\n    subject { described_class.from_text(text, nil) }\n\n    context 'with plain text' do\n      let(:text) { 'Hello :coolcat:' }\n\n      it 'returns records used via shortcodes in text' do\n        is_expected.to include(emojo)\n      end\n    end\n\n    context 'with html' do\n      let(:text) { '<p>Hello :coolcat:</p>' }\n\n      it 'returns records used via shortcodes in text' do\n        is_expected.to include(emojo)\n      end\n    end\n  end\n\n  describe 'pre_validation' do\n    let(:custom_emoji) { Fabricate(:custom_emoji, domain: 'wWw.MaStOdOn.CoM') }\n\n    it 'should downcase' do\n      custom_emoji.valid?\n      expect(custom_emoji.domain).to eq('www.mastodon.com')\n    end\n  end\nend\n"
  },
  {
    "path": "spec/models/custom_filter_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe CustomFilter, type: :model do\nend\n"
  },
  {
    "path": "spec/models/domain_block_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe DomainBlock, type: :model do\n  describe 'validations' do\n    it 'has a valid fabricator' do\n      domain_block = Fabricate.build(:domain_block)\n      expect(domain_block).to be_valid\n    end\n\n    it 'is invalid without a domain' do\n      domain_block = Fabricate.build(:domain_block, domain: nil)\n      domain_block.valid?\n      expect(domain_block).to model_have_error_on_field(:domain)\n    end\n\n    it 'is invalid if the same normalized domain already exists' do\n      domain_block_1 = Fabricate(:domain_block, domain: 'にゃん')\n      domain_block_2 = Fabricate.build(:domain_block, domain: 'xn--r9j5b5b')\n      domain_block_2.valid?\n      expect(domain_block_2).to model_have_error_on_field(:domain)\n    end\n  end\n\n  describe 'blocked?' do\n    it 'returns true if the domain is suspended' do\n      Fabricate(:domain_block, domain: 'domain', severity: :suspend)\n      expect(DomainBlock.blocked?('domain')).to eq true\n    end\n\n    it 'returns false even if the domain is silenced' do\n      Fabricate(:domain_block, domain: 'domain', severity: :silence)\n      expect(DomainBlock.blocked?('domain')).to eq false\n    end\n\n    it 'returns false if the domain is not suspended nor silenced' do\n      expect(DomainBlock.blocked?('domain')).to eq false\n    end\n  end\n\n  describe 'stricter_than?' do\n    it 'returns true if the new block has suspend severity while the old has lower severity' do\n      suspend = DomainBlock.new(domain: 'domain', severity: :suspend)\n      silence = DomainBlock.new(domain: 'domain', severity: :silence)\n      noop = DomainBlock.new(domain: 'domain', severity: :noop)\n      expect(suspend.stricter_than?(silence)).to be true\n      expect(suspend.stricter_than?(noop)).to be true\n    end\n\n    it 'returns false if the new block has lower severity than the old one' do\n      suspend = DomainBlock.new(domain: 'domain', severity: :suspend)\n      silence = DomainBlock.new(domain: 'domain', severity: :silence)\n      noop = DomainBlock.new(domain: 'domain', severity: :noop)\n      expect(silence.stricter_than?(suspend)).to be false\n      expect(noop.stricter_than?(suspend)).to be false\n      expect(noop.stricter_than?(silence)).to be false\n    end\n\n    it 'returns false if the new block does is less strict regarding reports' do\n      older = DomainBlock.new(domain: 'domain', severity: :silence, reject_reports: true)\n      newer = DomainBlock.new(domain: 'domain', severity: :silence, reject_reports: false)\n      expect(newer.stricter_than?(older)).to be false\n    end\n\n    it 'returns false if the new block does is less strict regarding media' do\n      older = DomainBlock.new(domain: 'domain', severity: :silence, reject_media: true)\n      newer = DomainBlock.new(domain: 'domain', severity: :silence, reject_media: false)\n      expect(newer.stricter_than?(older)).to be false\n    end\n  end\nend\n"
  },
  {
    "path": "spec/models/email_domain_block_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe EmailDomainBlock, type: :model do\n  describe 'validations' do\n    it 'has a valid fabricator' do\n      email_domain_block = Fabricate.build(:email_domain_block)\n      expect(email_domain_block).to be_valid\n    end\n  end\n\n  describe 'block?' do\n    it 'returns true if the domain is registed' do\n      Fabricate(:email_domain_block, domain: 'example.com')\n      expect(EmailDomainBlock.block?('nyarn@example.com')).to eq true\n    end\n\n    it 'returns true if the domain is not registed' do\n      Fabricate(:email_domain_block, domain: 'example.com')\n      expect(EmailDomainBlock.block?('nyarn@example.net')).to eq false\n    end\n  end\nend\n"
  },
  {
    "path": "spec/models/export_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe Export do\n  let(:account) { Fabricate(:account) }\n  let(:target_accounts) do\n    [ {}, { username: 'one', domain: 'local.host' } ].map(&method(:Fabricate).curry(2).call(:account))\n  end\n\n  describe 'to_csv' do\n    it 'returns a csv of the blocked accounts' do\n      target_accounts.each(&account.method(:block!))\n\n      export = Export.new(account).to_blocked_accounts_csv\n      results = export.strip.split\n\n      expect(results.size).to eq 2\n      expect(results.first).to eq 'one@local.host'\n    end\n\n    it 'returns a csv of the muted accounts' do\n      target_accounts.each(&account.method(:mute!))\n\n      export = Export.new(account).to_muted_accounts_csv\n      results = export.strip.split(\"\\n\")\n\n      expect(results.size).to eq 3\n      expect(results.first).to eq 'Account address,Hide notifications'\n      expect(results.second).to eq 'one@local.host,true'\n    end\n\n    it 'returns a csv of the following accounts' do\n      target_accounts.each(&account.method(:follow!))\n\n      export = Export.new(account).to_following_accounts_csv\n      results = export.strip.split(\"\\n\")\n\n      expect(results.size).to eq 3\n      expect(results.first).to eq 'Account address,Show boosts'\n      expect(results.second).to eq 'one@local.host,true'\n    end\n  end\n\n  describe 'total_storage' do\n    it 'returns the total size of the media attachments' do\n      media_attachment = Fabricate(:media_attachment, account: account)\n      expect(Export.new(account).total_storage).to eq media_attachment.file_file_size || 0\n    end\n  end\n\n  describe 'total_follows' do\n    it 'returns the total number of the followed accounts' do\n      target_accounts.each(&account.method(:follow!))\n      expect(Export.new(account.reload).total_follows).to eq 2\n    end\n\n    it 'returns the total number of the blocked accounts' do\n      target_accounts.each(&account.method(:block!))\n      expect(Export.new(account.reload).total_blocks).to eq 2\n    end\n\n    it 'returns the total number of the muted accounts' do\n      target_accounts.each(&account.method(:mute!))\n      expect(Export.new(account.reload).total_mutes).to eq 2\n    end\n  end\nend\n"
  },
  {
    "path": "spec/models/favourite_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Favourite, type: :model do\n  let(:account) { Fabricate(:account) }\n\n  context 'when status is a reblog' do\n    let(:reblog) { Fabricate(:status, reblog: nil) }\n    let(:status) { Fabricate(:status, reblog: reblog) }\n\n    it 'invalidates if the reblogged status is already a favourite' do\n      Favourite.create!(account: account, status: reblog)\n      expect(Favourite.new(account: account, status: status).valid?).to eq false\n    end\n\n    it 'replaces status with the reblogged one if it is a reblog' do\n      favourite = Favourite.create!(account: account, status: status)\n      expect(favourite.status).to eq reblog\n    end\n  end\n\n  context 'when status is not a reblog' do\n    let(:status) { Fabricate(:status, reblog: nil) }\n\n    it 'saves with the specified status' do\n      favourite = Favourite.create!(account: account, status: status)\n      expect(favourite.status).to eq status\n    end\n  end\nend\n"
  },
  {
    "path": "spec/models/featured_tag_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe FeaturedTag, type: :model do\nend\n"
  },
  {
    "path": "spec/models/follow_request_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe FollowRequest, type: :model do\n  describe '#authorize!' do\n    let(:follow_request) { Fabricate(:follow_request, account: account, target_account: target_account) }\n    let(:account)        { Fabricate(:account) }\n    let(:target_account) { Fabricate(:account) }\n\n    it 'calls Account#follow!, MergeWorker.perform_async, and #destroy!' do\n      expect(account).to        receive(:follow!).with(target_account, reblogs: true, uri: follow_request.uri)\n      expect(MergeWorker).to    receive(:perform_async).with(target_account.id, account.id)\n      expect(follow_request).to receive(:destroy!)\n      follow_request.authorize!\n    end\n\n    it 'correctly passes show_reblogs when true' do\n      follow_request = Fabricate.create(:follow_request, show_reblogs: true)\n      follow_request.authorize!\n      target = follow_request.target_account\n      expect(follow_request.account.muting_reblogs?(target)).to be false\n    end\n\n    it 'correctly passes show_reblogs when false' do\n      follow_request = Fabricate.create(:follow_request, show_reblogs: false)\n      follow_request.authorize!\n      target = follow_request.target_account\n      expect(follow_request.account.muting_reblogs?(target)).to be true\n    end\n  end\nend\n"
  },
  {
    "path": "spec/models/follow_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Follow, type: :model do\n  let(:alice) { Fabricate(:account, username: 'alice') }\n  let(:bob)   { Fabricate(:account, username: 'bob') }\n\n  describe 'validations' do\n    subject { Follow.new(account: alice, target_account: bob) }\n\n    it 'has a valid fabricator' do\n      follow = Fabricate.build(:follow)\n      expect(follow).to be_valid\n    end\n\n    it 'is invalid without an account' do\n      follow = Fabricate.build(:follow, account: nil)\n      follow.valid?\n      expect(follow).to model_have_error_on_field(:account)\n    end\n\n    it 'is invalid without a target_account' do\n      follow = Fabricate.build(:follow, target_account: nil)\n      follow.valid?\n      expect(follow).to model_have_error_on_field(:target_account)\n    end\n\n    it 'is invalid if account already follows too many people' do\n      alice.update(following_count: FollowLimitValidator::LIMIT)\n\n      expect(subject).to_not be_valid\n      expect(subject).to model_have_error_on_field(:base)\n    end\n\n    it 'is valid if account is only on the brink of following too many people' do\n      alice.update(following_count: FollowLimitValidator::LIMIT - 1)\n\n      expect(subject).to be_valid\n      expect(subject).to_not model_have_error_on_field(:base)\n    end\n  end\n\n  describe 'recent' do\n    it 'sorts so that more recent follows comes earlier' do\n      follow0 = Follow.create!(account: alice, target_account: bob)\n      follow1 = Follow.create!(account: bob, target_account: alice)\n\n      a = Follow.recent.to_a\n\n      expect(a.size).to eq 2\n      expect(a[0]).to eq follow1\n      expect(a[1]).to eq follow0\n    end\n  end\n\n  describe 'revoke_request!' do\n    let(:follow)         { Fabricate(:follow, account: account, target_account: target_account) }\n    let(:account)        { Fabricate(:account) }\n    let(:target_account) { Fabricate(:account) }\n\n    it 'revokes the follow relation' do\n      follow.revoke_request!\n      expect(account.following?(target_account)).to be false\n    end\n\n    it 'creates a follow request' do\n      follow.revoke_request!\n      expect(account.requested?(target_account)).to be true\n    end\n  end\nend\n"
  },
  {
    "path": "spec/models/form/status_batch_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe Form::StatusBatch do\n  let(:form) { Form::StatusBatch.new(action: action, status_ids: status_ids) }\n  let(:status) { Fabricate(:status) }\n\n  describe 'with nsfw action' do\n    let(:status_ids) { [status.id, nonsensitive_status.id, sensitive_status.id] }\n    let(:nonsensitive_status) { Fabricate(:status, sensitive: false) }\n    let(:sensitive_status) { Fabricate(:status, sensitive: true) }\n    let!(:shown_media_attachment) { Fabricate(:media_attachment, status: nonsensitive_status) }\n    let!(:hidden_media_attachment) { Fabricate(:media_attachment, status: sensitive_status) }\n\n    context 'nsfw_on' do\n      let(:action) { 'nsfw_on' }\n\n      it { expect(form.save).to be true }\n      it { expect { form.save }.to change { nonsensitive_status.reload.sensitive }.from(false).to(true) }\n      it { expect { form.save }.not_to change { sensitive_status.reload.sensitive } }\n      it { expect { form.save }.not_to change { status.reload.sensitive } }\n    end\n\n    context 'nsfw_off' do\n      let(:action) { 'nsfw_off' }\n\n      it { expect(form.save).to be true }\n      it { expect { form.save }.to change { sensitive_status.reload.sensitive }.from(true).to(false) }\n      it { expect { form.save }.not_to change { nonsensitive_status.reload.sensitive } }\n      it { expect { form.save }.not_to change { status.reload.sensitive } }\n    end\n  end\n\n  describe 'with delete action' do\n    let(:status_ids) { [status.id] }\n    let(:action) { 'delete' }\n    let!(:another_status) { Fabricate(:status) }\n\n    before do\n      allow(RemovalWorker).to receive(:perform_async)\n    end\n\n    it 'call RemovalWorker' do\n      form.save\n      expect(RemovalWorker).to have_received(:perform_async).with(status.id)\n    end\n\n    it 'do not call RemovalWorker' do\n      form.save\n      expect(RemovalWorker).not_to have_received(:perform_async).with(another_status.id)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/models/home_feed_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe HomeFeed, type: :model do\n  let(:account) { Fabricate(:account) }\n\n  subject { described_class.new(account) }\n\n  describe '#get' do\n    before do\n      Fabricate(:status, account: account, id: 1)\n      Fabricate(:status, account: account, id: 2)\n      Fabricate(:status, account: account, id: 3)\n      Fabricate(:status, account: account, id: 10)\n    end\n\n    context 'when feed is generated' do\n      before do\n        Redis.current.zadd(\n          FeedManager.instance.key(:home, account.id),\n          [[4, 4], [3, 3], [2, 2], [1, 1]]\n        )\n      end\n\n      it 'gets statuses with ids in the range from redis' do\n        results = subject.get(3)\n\n        expect(results.map(&:id)).to eq [3, 2]\n        expect(results.first.attributes.keys).to eq %w(id updated_at)\n      end\n    end\n\n    context 'when feed is being generated' do\n      before do\n        Redis.current.set(\"account:#{account.id}:regeneration\", true)\n      end\n\n      it 'gets statuses with ids in the range from database' do\n        results = subject.get(3)\n\n        expect(results.map(&:id)).to eq [10, 3, 2]\n        expect(results.first.attributes.keys).to include('id', 'updated_at')\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/models/identity_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Identity, type: :model do\n  describe '.find_for_oauth' do\n    let(:auth) { Fabricate(:identity, user: Fabricate(:user)) }\n\n    it 'calls .find_or_create_by' do\n      expect(described_class).to receive(:find_or_create_by).with(uid: auth.uid, provider: auth.provider)\n      described_class.find_for_oauth(auth)\n    end\n\n    it 'returns an instance of Identity' do\n      expect(described_class.find_for_oauth(auth)).to be_instance_of Identity\n    end\n  end\nend\n"
  },
  {
    "path": "spec/models/import_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Import, type: :model do\n  let (:account) { Fabricate(:account) }\n  let (:type) { 'following' }\n  let (:data) { attachment_fixture('imports.txt') }\n\n  describe 'validations' do\n    it 'has a valid parameters' do\n      import = Import.create(account: account, type: type, data: data)\n      expect(import).to be_valid\n    end\n\n    it 'is invalid without an type' do\n      import = Import.create(account: account, data: data)\n      expect(import).to model_have_error_on_field(:type)\n    end\n\n    it 'is invalid without a data' do\n      import = Import.create(account: account, type: type)\n      expect(import).to model_have_error_on_field(:data)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/models/invite_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Invite, type: :model do\n  describe '#valid_for_use?' do\n    it 'returns true when there are no limitations' do\n      invite = Invite.new(max_uses: nil, expires_at: nil)\n      expect(invite.valid_for_use?).to be true\n    end\n\n    it 'returns true when not expired' do\n      invite = Invite.new(max_uses: nil, expires_at: 1.hour.from_now)\n      expect(invite.valid_for_use?).to be true\n    end\n\n    it 'returns false when expired' do\n      invite = Invite.new(max_uses: nil, expires_at: 1.hour.ago)\n      expect(invite.valid_for_use?).to be false\n    end\n\n    it 'returns true when uses still available' do\n      invite = Invite.new(max_uses: 250, uses: 249, expires_at: nil)\n      expect(invite.valid_for_use?).to be true\n    end\n\n    it 'returns false when maximum uses reached' do\n      invite = Invite.new(max_uses: 250, uses: 250, expires_at: nil)\n      expect(invite.valid_for_use?).to be false\n    end\n  end\nend\n"
  },
  {
    "path": "spec/models/list_account_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe ListAccount, type: :model do\nend\n"
  },
  {
    "path": "spec/models/list_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe List, type: :model do\nend\n"
  },
  {
    "path": "spec/models/media_attachment_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe MediaAttachment, type: :model do\n  describe 'local?' do\n    let(:media_attachment) { Fabricate(:media_attachment, remote_url: remote_url) }\n\n    subject { media_attachment.local? }\n\n    context 'remote_url is blank' do\n      let(:remote_url) { '' }\n\n      it 'returns true' do\n        is_expected.to be true\n      end\n    end\n\n    context 'remote_url is present' do\n      let(:remote_url) { 'remote_url' }\n\n      it 'returns false' do\n        is_expected.to be false\n      end\n    end\n  end\n\n  describe 'needs_redownload?' do\n    let(:media_attachment) { Fabricate(:media_attachment, remote_url: remote_url, file: file) }\n\n    subject { media_attachment.needs_redownload? }\n\n    context 'file is blank' do\n      let(:file) { nil }\n\n      context 'remote_url is blank' do\n        let(:remote_url) { '' }\n\n        it 'returns false' do\n          is_expected.to be false\n        end\n      end\n\n      context 'remote_url is present' do\n        let(:remote_url) { 'remote_url' }\n\n        it 'returns true' do\n          is_expected.to be true\n        end\n      end\n    end\n\n    context 'file is present' do\n      let(:file) { attachment_fixture('avatar.gif') }\n\n      context 'remote_url is blank' do\n        let(:remote_url) { '' }\n\n        it 'returns false' do\n          is_expected.to be false\n        end\n      end\n\n      context 'remote_url is present' do\n        let(:remote_url) { 'remote_url' }\n\n        it 'returns true' do\n          is_expected.to be false\n        end\n      end\n    end\n  end\n\n  describe '#to_param' do\n    let(:media_attachment) { Fabricate(:media_attachment) }\n    let(:shortcode)        { media_attachment.shortcode }\n\n    it 'returns shortcode' do\n      expect(media_attachment.to_param).to eq shortcode\n    end\n  end\n\n  describe 'animated gif conversion' do\n    let(:media) { MediaAttachment.create(account: Fabricate(:account), file: attachment_fixture('avatar.gif')) }\n\n    it 'sets type to gifv' do\n      expect(media.type).to eq 'gifv'\n    end\n\n    it 'converts original file to mp4' do\n      expect(media.file_content_type).to eq 'video/mp4'\n    end\n\n    it 'sets meta' do\n      expect(media.file.meta[\"original\"][\"width\"]).to eq 128\n      expect(media.file.meta[\"original\"][\"height\"]).to eq 128\n    end\n  end\n\n  describe 'non-animated gif non-conversion' do\n    fixtures = [\n      { filename: 'attachment.gif', width: 600, height: 400, aspect: 1.5 },\n      { filename: 'mini-static.gif', width: 32, height: 32, aspect: 1.0 },\n    ]\n\n    fixtures.each do |fixture|\n      context fixture[:filename] do\n        let(:media) { MediaAttachment.create(account: Fabricate(:account), file: attachment_fixture(fixture[:filename])) }\n\n        it 'sets type to image' do\n          expect(media.type).to eq 'image'\n        end\n\n        it 'leaves original file as-is' do\n          expect(media.file_content_type).to eq 'image/gif'\n        end\n\n        it 'sets meta' do\n          expect(media.file.meta[\"original\"][\"width\"]).to eq fixture[:width]\n          expect(media.file.meta[\"original\"][\"height\"]).to eq fixture[:height]\n          expect(media.file.meta[\"original\"][\"aspect\"]).to eq fixture[:aspect]\n        end\n      end\n    end\n  end\n\n  describe 'jpeg' do\n    let(:media) { MediaAttachment.create(account: Fabricate(:account), file: attachment_fixture('attachment.jpg')) }\n\n    it 'sets meta for different style' do\n      expect(media.file.meta[\"original\"][\"width\"]).to eq 600\n      expect(media.file.meta[\"original\"][\"height\"]).to eq 400\n      expect(media.file.meta[\"original\"][\"aspect\"]).to eq 1.5\n      expect(media.file.meta[\"small\"][\"width\"]).to eq 490\n      expect(media.file.meta[\"small\"][\"height\"]).to eq 327\n      expect(media.file.meta[\"small\"][\"aspect\"]).to eq 490.0 / 327\n    end\n  end\n\n  describe 'descriptions for remote attachments' do\n    it 'are cut off at 140 characters' do\n      media = Fabricate(:media_attachment, description: 'foo' * 1000, remote_url: 'http://example.com/blah.jpg')\n\n      expect(media.description.size).to be <= 420\n    end\n  end\nend\n"
  },
  {
    "path": "spec/models/mention_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Mention, type: :model do\n  describe 'validations' do\n    it 'has a valid fabricator' do\n      mention = Fabricate.build(:mention)\n      expect(mention).to be_valid\n    end\n\n    it 'is invalid without an account' do\n      mention = Fabricate.build(:mention, account: nil)\n      mention.valid?\n      expect(mention).to model_have_error_on_field(:account)\n    end\n\n    it 'is invalid without a status' do\n      mention = Fabricate.build(:mention, status: nil)\n      mention.valid?\n      expect(mention).to model_have_error_on_field(:status)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/models/mute_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Mute, type: :model do\nend\n"
  },
  {
    "path": "spec/models/notification_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Notification, type: :model do\n  describe '#target_status' do\n    let(:notification) { Fabricate(:notification, activity: activity) }\n    let(:status)       { Fabricate(:status) }\n    let(:reblog)       { Fabricate(:status, reblog: status) }\n    let(:favourite)    { Fabricate(:favourite, status: status) }\n    let(:mention)      { Fabricate(:mention, status: status) }\n\n    context 'activity is reblog' do\n      let(:activity) { reblog }\n\n      it 'returns status' do\n        expect(notification.target_status).to eq status\n      end\n    end\n\n    context 'activity is favourite' do\n      let(:type)     { :favourite }\n      let(:activity) { favourite }\n\n      it 'returns status' do\n        expect(notification.target_status).to eq status\n      end\n    end\n\n    context 'activity is mention' do\n      let(:activity) { mention }\n\n      it 'returns status' do\n        expect(notification.target_status).to eq status\n      end\n    end\n  end\n\n  describe '#browserable?' do\n    let(:notification) { Fabricate(:notification) }\n\n    subject { notification.browserable? }\n\n    context 'type is :follow_request' do\n      before do\n        allow(notification).to receive(:type).and_return(:follow_request)\n      end\n\n      it 'returns false' do\n        is_expected.to be false\n      end\n    end\n\n    context 'type is not :follow_request' do\n      before do\n        allow(notification).to receive(:type).and_return(:else)\n      end\n\n      it 'returns true' do\n        is_expected.to be true\n      end\n    end\n  end\n\n  describe '#type' do\n    it 'returns :reblog for a Status' do\n      notification = Notification.new(activity: Status.new)\n      expect(notification.type).to eq :reblog\n    end\n\n    it 'returns :mention for a Mention' do\n      notification = Notification.new(activity: Mention.new)\n      expect(notification.type).to eq :mention\n    end\n\n    it 'returns :favourite for a Favourite' do\n      notification = Notification.new(activity: Favourite.new)\n      expect(notification.type).to eq :favourite\n    end\n\n    it 'returns :follow for a Follow' do\n      notification = Notification.new(activity: Follow.new)\n      expect(notification.type).to eq :follow\n    end\n  end\n\n  describe '.reload_stale_associations!' do\n    context 'account_ids are empty' do\n      let(:cached_items) { [] }\n\n      subject { described_class.reload_stale_associations!(cached_items) }\n\n      it 'returns nil' do\n        is_expected.to be nil\n      end\n    end\n\n    context 'account_ids are present' do\n      before do\n        allow(accounts_with_ids).to receive(:[]).with(stale_account1.id).and_return(account1)\n        allow(accounts_with_ids).to receive(:[]).with(stale_account2.id).and_return(account2)\n        allow(Account).to receive_message_chain(:where, :includes, :each_with_object).and_return(accounts_with_ids)\n      end\n\n      let(:cached_items) do\n        [\n          Fabricate(:notification, activity: Fabricate(:status)),\n          Fabricate(:notification, activity: Fabricate(:follow)),\n        ]\n      end\n\n      let(:stale_account1) { cached_items[0].from_account }\n      let(:stale_account2) { cached_items[1].from_account }\n\n      let(:account1) { Fabricate(:account) }\n      let(:account2) { Fabricate(:account) }\n\n      let(:accounts_with_ids) { { account1.id => account1, account2.id => account2 } }\n\n      it 'reloads associations' do\n        expect(cached_items[0].from_account).to be stale_account1\n        expect(cached_items[1].from_account).to be stale_account2\n\n        described_class.reload_stale_associations!(cached_items)\n\n        expect(cached_items[0].from_account).to be account1\n        expect(cached_items[1].from_account).to be account2\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/models/poll_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Poll, type: :model do\n  pending \"add some examples to (or delete) #{__FILE__}\"\nend\n"
  },
  {
    "path": "spec/models/poll_vote_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe PollVote, type: :model do\n  pending \"add some examples to (or delete) #{__FILE__}\"\nend\n"
  },
  {
    "path": "spec/models/preview_card_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe PreviewCard, type: :model do\nend\n"
  },
  {
    "path": "spec/models/relay_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Relay, type: :model do\nend\n"
  },
  {
    "path": "spec/models/remote_follow_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe RemoteFollow do\n  before do\n    stub_request(:get, 'https://quitter.no/.well-known/webfinger?resource=acct:gargron@quitter.no').to_return(request_fixture('webfinger.txt'))\n  end\n\n  let(:attrs)         { nil }\n  let(:remote_follow) { described_class.new(attrs) }\n\n  describe '.initialize' do\n    subject { remote_follow.acct }\n\n    context 'attrs with acct' do\n      let(:attrs) { { acct: 'gargron@quitter.no' } }\n\n      it 'returns acct' do\n        is_expected.to eq 'gargron@quitter.no'\n      end\n    end\n\n    context 'attrs without acct' do\n      let(:attrs) { {} }\n\n      it do\n        is_expected.to be_nil\n      end\n    end\n  end\n\n  describe '#valid?' do\n    subject { remote_follow.valid? }\n\n    context 'attrs with acct' do\n      let(:attrs) { { acct: 'gargron@quitter.no' } }\n\n      it do\n        is_expected.to be true\n      end\n    end\n\n    context 'attrs without acct' do\n      let(:attrs) { {} }\n\n      it do\n        is_expected.to be false\n      end\n    end\n  end\n\n  describe '#subscribe_address_for' do\n    before do\n      remote_follow.valid?\n    end\n\n    let(:attrs)   { { acct: 'gargron@quitter.no' } }\n    let(:account) { Fabricate(:account, username: 'alice') }\n\n    subject { remote_follow.subscribe_address_for(account) }\n\n    it 'returns subscribe address' do\n      is_expected.to eq 'https://quitter.no/main/ostatussub?profile=alice%40cb6e6126.ngrok.io'\n    end\n  end\nend\n"
  },
  {
    "path": "spec/models/remote_profile_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe RemoteProfile do\n  let(:remote_profile) { RemoteProfile.new(body) }\n  let(:body) do\n    <<-XML\n      <feed xmlns=\"http://www.w3.org/2005/Atom\">\n      <author>John</author>\n    XML\n  end\n\n  describe '.initialize' do\n    it 'calls Nokogiri::XML.parse' do\n      expect(Nokogiri::XML).to receive(:parse).with(body, nil, 'utf-8')\n      RemoteProfile.new(body)\n    end\n\n    it 'sets document' do\n      remote_profile = RemoteProfile.new(body)\n      expect(remote_profile).not_to be nil\n    end\n  end\n\n  describe '#root' do\n    let(:document) { remote_profile.document }\n\n    it 'callse document.at_xpath' do\n      expect(document).to receive(:at_xpath).with(\n        '/atom:feed|/atom:entry',\n        atom: OStatus::TagManager::XMLNS\n      )\n\n      remote_profile.root\n    end\n  end\n\n  describe '#author' do\n    let(:root) { remote_profile.root }\n\n    it 'calls root.at_xpath' do\n      expect(root).to receive(:at_xpath).with(\n        './atom:author|./dfrn:owner',\n        atom: OStatus::TagManager::XMLNS,\n        dfrn: OStatus::TagManager::DFRN_XMLNS\n      )\n\n      remote_profile.author\n    end\n  end\n\n  describe '#hub_link' do\n    let(:root) { remote_profile.root }\n\n    it 'calls #link_href_from_xml' do\n      expect(remote_profile).to receive(:link_href_from_xml).with(root, 'hub')\n      remote_profile.hub_link\n    end\n  end\n\n  describe '#display_name' do\n    let(:author) { remote_profile.author }\n\n    it 'calls author.at_xpath.content' do\n      expect(author).to receive_message_chain(:at_xpath, :content).with(\n        './poco:displayName',\n        poco: OStatus::TagManager::POCO_XMLNS\n      ).with(no_args)\n\n      remote_profile.display_name\n    end\n  end\n\n  describe '#note' do\n    let(:author) { remote_profile.author }\n\n    it 'calls author.at_xpath.content' do\n      expect(author).to receive_message_chain(:at_xpath, :content).with(\n        './atom:summary|./poco:note',\n        atom: OStatus::TagManager::XMLNS,\n        poco: OStatus::TagManager::POCO_XMLNS\n      ).with(no_args)\n\n      remote_profile.note\n    end\n  end\n\n  describe '#scope' do\n    let(:author) { remote_profile.author }\n\n    it 'calls author.at_xpath.content' do\n      expect(author).to receive_message_chain(:at_xpath, :content).with(\n        './mastodon:scope',\n        mastodon: OStatus::TagManager::MTDN_XMLNS\n      ).with(no_args)\n\n      remote_profile.scope\n    end\n  end\n\n  describe '#avatar' do\n    let(:author) { remote_profile.author }\n\n    it 'calls #link_href_from_xml' do\n      expect(remote_profile).to receive(:link_href_from_xml).with(author, 'avatar')\n      remote_profile.avatar\n    end\n  end\n\n  describe '#header' do\n    let(:author) { remote_profile.author }\n\n    it 'calls #link_href_from_xml' do\n      expect(remote_profile).to receive(:link_href_from_xml).with(author, 'header')\n      remote_profile.header\n    end\n  end\n\n  describe '#locked?' do\n    before do\n      allow(remote_profile).to receive(:scope).and_return(scope)\n    end\n\n    subject { remote_profile.locked? }\n\n    context 'scope is private' do\n      let(:scope) { 'private' }\n\n      it 'returns true' do\n        is_expected.to be true\n      end\n    end\n\n    context 'scope is not private' do\n      let(:scope) { 'public' }\n\n      it 'returns false' do\n        is_expected.to be false\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/models/report_filter_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe ReportFilter do\n  describe 'with empty params' do\n    it 'defaults to unresolved reports list' do\n      filter = ReportFilter.new({})\n\n      expect(filter.results).to eq Report.unresolved\n    end\n  end\n\n  describe 'with invalid params' do\n    it 'raises with key error' do\n      filter = ReportFilter.new(wrong: true)\n\n      expect { filter.results }.to raise_error(/wrong/)\n    end\n  end\n\n  describe 'with valid params' do\n    it 'combines filters on Report' do\n      filter = ReportFilter.new(account_id: '123', resolved: true, target_account_id: '456')\n\n      allow(Report).to receive(:where).and_return(Report.none)\n      allow(Report).to receive(:resolved).and_return(Report.none)\n      filter.results\n      expect(Report).to have_received(:where).with(account_id: '123')\n      expect(Report).to have_received(:where).with(target_account_id: '456')\n      expect(Report).to have_received(:resolved)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/models/report_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe Report do\n  describe 'statuses' do\n    it 'returns the statuses for the report' do\n      status = Fabricate(:status)\n      _other = Fabricate(:status)\n      report = Fabricate(:report, status_ids: [status.id])\n\n      expect(report.statuses).to eq [status]\n    end\n  end\n\n  describe 'media_attachments' do\n    it 'returns media attachments from statuses' do\n      status = Fabricate(:status)\n      media_attachment = Fabricate(:media_attachment, status: status)\n      _other_media_attachment = Fabricate(:media_attachment)\n      report = Fabricate(:report, status_ids: [status.id])\n\n      expect(report.media_attachments).to eq [media_attachment]\n    end\n  end\n\n  describe 'assign_to_self!' do\n    subject { report.assigned_account_id }\n\n    let(:report) { Fabricate(:report, assigned_account_id: original_account) }\n    let(:original_account) { Fabricate(:account) }\n    let(:current_account) { Fabricate(:account) }\n\n    before do\n      report.assign_to_self!(current_account)\n    end\n\n    it 'assigns to a given account' do\n      is_expected.to eq current_account.id\n    end\n  end\n\n  describe 'unassign!' do\n    subject { report.assigned_account_id }\n\n    let(:report) { Fabricate(:report, assigned_account_id: account.id) }\n    let(:account) { Fabricate(:account) }\n\n    before do\n      report.unassign!\n    end\n\n    it 'unassigns' do\n      is_expected.to be_nil\n    end\n  end\n\n  describe 'resolve!' do\n    subject(:report) { Fabricate(:report, action_taken: false, action_taken_by_account_id: nil) }\n\n    let(:acting_account) { Fabricate(:account) }\n\n    before do\n      report.resolve!(acting_account)\n    end\n\n    it 'records action taken' do\n      expect(report).to have_attributes(action_taken: true, action_taken_by_account_id: acting_account.id)\n    end\n  end\n\n  describe 'unresolve!' do\n    subject(:report) { Fabricate(:report, action_taken: true, action_taken_by_account_id: acting_account.id) }\n\n    let(:acting_account) { Fabricate(:account) }\n\n    before do\n      report.unresolve!\n    end\n\n    it 'unresolves' do\n      expect(report).to have_attributes(action_taken: false, action_taken_by_account_id: nil)\n    end\n  end\n\n  describe 'unresolved?' do\n    subject { report.unresolved? }\n\n    let(:report) { Fabricate(:report, action_taken: action_taken) }\n\n    context 'if action is taken' do\n      let(:action_taken) { true }\n\n      it { is_expected.to be false }\n    end\n\n    context 'if action not is taken' do\n      let(:action_taken) { false }\n\n      it { is_expected.to be true }\n    end\n  end\n\n  describe 'history' do\n    subject(:action_logs) { report.history }\n\n    let(:report) { Fabricate(:report, target_account_id: target_account.id, status_ids: [status.id], created_at: 3.days.ago, updated_at: 1.day.ago) }\n    let(:target_account) { Fabricate(:account) }\n    let(:status) { Fabricate(:status) }\n\n    before do\n      Fabricate('Admin::ActionLog', target_type: 'Report', account_id: target_account.id, target_id: report.id, created_at: 2.days.ago)\n      Fabricate('Admin::ActionLog', target_type: 'Account', account_id: target_account.id, target_id: report.target_account_id, created_at: 2.days.ago)\n      Fabricate('Admin::ActionLog', target_type: 'Status', account_id: target_account.id, target_id: status.id, created_at: 2.days.ago)\n    end\n\n    it 'returns right logs' do\n      expect(action_logs.count).to eq 3\n    end\n  end\n\n  describe 'validatiions' do\n    it 'has a valid fabricator' do\n      report = Fabricate(:report)\n      report.valid?\n      expect(report).to be_valid\n    end\n\n    it 'is invalid if comment is longer than 1000 characters' do\n      report = Fabricate.build(:report, comment: Faker::Lorem.characters(1001))\n      report.valid?\n      expect(report).to model_have_error_on_field(:comment)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/models/scheduled_status_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe ScheduledStatus, type: :model do\nend\n"
  },
  {
    "path": "spec/models/session_activation_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe SessionActivation, type: :model do\n  describe '#detection' do\n    let(:session_activation) { Fabricate(:session_activation, user_agent: 'Chrome/62.0.3202.89') }\n\n    it 'sets a Browser instance as detection' do\n      expect(session_activation.detection).to be_kind_of Browser::Chrome\n    end\n  end\n\n  describe '#browser' do\n    before do\n      allow(session_activation).to receive(:detection).and_return(detection)\n    end\n\n    let(:detection)          { double(id: 1) }\n    let(:session_activation) { Fabricate(:session_activation) }\n\n    it 'returns detection.id' do\n      expect(session_activation.browser).to be 1\n    end\n  end\n\n  describe '#platform' do\n    before do\n      allow(session_activation).to receive(:detection).and_return(detection)\n    end\n\n    let(:session_activation) { Fabricate(:session_activation) }\n    let(:detection)          { double(platform: double(id: 1)) }\n\n    it 'returns detection.platform.id' do\n      expect(session_activation.platform).to be 1\n    end\n  end\n\n  describe '.active?' do\n    subject { described_class.active?(id) }\n\n    context 'id is absent' do\n      let(:id) { nil }\n\n      it 'returns nil' do\n        is_expected.to be nil\n      end\n    end\n\n    context 'id is present' do\n      let(:id) { '1' }\n      let!(:session_activation) { Fabricate(:session_activation, session_id: id) }\n\n      context 'id exists as session_id' do\n        it 'returns true' do\n          is_expected.to be true\n        end\n      end\n\n      context 'id does not exist as session_id' do\n        before do\n          session_activation.update!(session_id: '2')\n        end\n\n        it 'returns false' do\n          is_expected.to be false\n        end\n      end\n    end\n  end\n\n  describe '.activate' do\n    let(:options) { { user: Fabricate(:user), session_id: '1' } }\n\n    it 'calls create! and purge_old' do\n      expect(described_class).to receive(:create!).with(options)\n      expect(described_class).to receive(:purge_old)\n      described_class.activate(options)\n    end\n\n    it 'returns an instance of SessionActivation' do\n      expect(described_class.activate(options)).to be_kind_of SessionActivation\n    end\n  end\n\n  describe '.deactivate' do\n    context 'id is absent' do\n      let(:id) { nil }\n\n      it 'returns nil' do\n        expect(described_class.deactivate(id)).to be nil\n      end\n    end\n\n    context 'id exists' do\n      let(:id) { '1' }\n\n      it 'calls where.destroy_all' do\n        expect(described_class).to receive_message_chain(:where, :destroy_all)\n          .with(session_id: id).with(no_args)\n\n        described_class.deactivate(id)\n      end\n    end\n  end\n\n  describe '.purge_old' do\n    it 'calls order.offset.destroy_all' do\n      expect(described_class).to receive_message_chain(:order, :offset, :destroy_all)\n        .with('created_at desc').with(Rails.configuration.x.max_session_activations).with(no_args)\n\n      described_class.purge_old\n    end\n  end\n\n  describe '.exclusive' do\n    let(:id) { '1' }\n\n    it 'calls where.destroy_all' do\n      expect(described_class).to receive_message_chain(:where, :destroy_all)\n        .with('session_id != ?', id).with(no_args)\n\n      described_class.exclusive(id)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/models/setting_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe Setting, type: :model do\n  describe '#to_param' do\n    let(:setting) { Fabricate(:setting, var: var) }\n    let(:var)     { 'var' }\n\n    it 'returns setting.var' do\n      expect(setting.to_param).to eq var\n    end\n  end\n\n  describe '.[]' do\n    before do\n      allow(described_class).to receive(:rails_initialized?).and_return(rails_initialized)\n    end\n\n    let(:key) { 'key' }\n\n    context 'rails_initialized? is falsey' do\n      let(:rails_initialized) { false }\n\n      it 'calls RailsSettings::Base#[]' do\n        expect(RailsSettings::Base).to receive(:[]).with(key)\n        described_class[key]\n      end\n    end\n\n    context 'rails_initialized? is truthy' do\n      before do\n        allow(RailsSettings::Base).to receive(:cache_key).with(key, nil).and_return(cache_key)\n      end\n\n      let(:rails_initialized) { true }\n      let(:cache_key)         { 'cache-key' }\n      let(:cache_value)       { 'cache-value' }\n\n      it 'calls not RailsSettings::Base#[]' do\n        expect(RailsSettings::Base).not_to receive(:[]).with(key)\n        described_class[key]\n      end\n\n      context 'Rails.cache does not exists' do\n        before do\n          allow(RailsSettings::Settings).to receive(:object).with(key).and_return(object)\n          allow(described_class).to receive(:default_settings).and_return(default_settings)\n          allow_any_instance_of(Settings::ScopedSettings).to receive(:thing_scoped).and_return(records)\n          Rails.cache.delete(cache_key)\n        end\n\n        let(:object)           { nil }\n        let(:default_value)    { 'default_value' }\n        let(:default_settings) { { key => default_value } }\n        let(:records)          { [Fabricate(:setting, var: key, value: nil)] }\n\n        it 'calls RailsSettings::Settings.object' do\n          expect(RailsSettings::Settings).to receive(:object).with(key)\n          described_class[key]\n        end\n\n        context 'RailsSettings::Settings.object returns truthy' do\n          let(:object) { db_val }\n          let(:db_val) { double(value: 'db_val') }\n\n          context 'default_value is a Hash' do\n            let(:default_value) { { default_value: 'default_value' } }\n\n            it 'calls default_value.with_indifferent_access.merge!' do\n              expect(default_value).to receive_message_chain(:with_indifferent_access, :merge!)\n                .with(db_val.value)\n\n              described_class[key]\n            end\n          end\n\n          context 'default_value is not a Hash' do\n            let(:default_value) { 'default_value' }\n\n            it 'returns db_val.value' do\n              expect(described_class[key]).to be db_val.value\n            end\n          end\n        end\n\n        context 'RailsSettings::Settings.object returns falsey' do\n          let(:object) { nil }\n\n          it 'returns default_settings[key]' do\n            expect(described_class[key]).to be default_settings[key]\n          end\n        end\n      end\n\n      context 'Rails.cache exists' do\n        before do\n          Rails.cache.write(cache_key, cache_value)\n        end\n\n        it 'does not query the database' do\n          expect do |callback|\n            ActiveSupport::Notifications.subscribed callback, 'sql.active_record' do\n              described_class[key]\n            end\n          end.not_to yield_control\n        end\n\n        it 'returns the cached value' do\n          expect(described_class[key]).to eq cache_value\n        end\n      end\n    end\n  end\n\n  describe '.all_as_records' do\n    before do\n      allow_any_instance_of(Settings::ScopedSettings).to receive(:thing_scoped).and_return(records)\n      allow(described_class).to receive(:default_settings).and_return(default_settings)\n    end\n\n    let(:key)              { 'key' }\n    let(:default_value)    { 'default_value' }\n    let(:default_settings) { { key => default_value } }\n    let(:original_setting) { Fabricate(:setting, var: key, value: nil) }\n    let(:records)          { [original_setting] }\n\n    it 'returns a Hash' do\n      expect(described_class.all_as_records).to be_kind_of Hash\n    end\n\n    context 'records includes Setting with var as the key' do\n      let(:records) { [original_setting] }\n\n      it 'includes the original Setting' do\n        setting = described_class.all_as_records[key]\n        expect(setting).to eq original_setting\n      end\n    end\n\n    context 'records includes nothing' do\n      let(:records) { [] }\n\n      context 'default_value is not a Hash' do\n        it 'includes Setting with value of default_value' do\n          setting = described_class.all_as_records[key]\n\n          expect(setting).to be_kind_of Setting\n          expect(setting).to have_attributes(var: key)\n          expect(setting).to have_attributes(value: 'default_value')\n        end\n      end\n\n      context 'default_value is a Hash' do\n        let(:default_value) { { 'foo' => 'fuga' } }\n\n        it 'returns {}' do\n          expect(described_class.all_as_records).to eq({})\n        end\n      end\n    end\n  end\n\n  describe '.default_settings' do\n    before do\n      allow(RailsSettings::Default).to receive(:enabled?).and_return(enabled)\n    end\n\n    subject { described_class.default_settings }\n\n    context 'RailsSettings::Default.enabled? is false' do\n      let(:enabled) { false }\n\n      it 'returns {}' do\n        is_expected.to eq({})\n      end\n    end\n\n    context 'RailsSettings::Settings.enabled? is true' do\n      let(:enabled) { true }\n\n      it 'returns instance of RailsSettings::Default' do\n        is_expected.to be_kind_of RailsSettings::Default\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/models/site_upload_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe SiteUpload, type: :model do\n  describe '#cache_key' do\n    let(:site_upload) { SiteUpload.new(var: 'var') }\n\n    it 'returns cache_key' do\n      expect(site_upload.cache_key).to eq 'site_uploads/var'\n    end\n  end\nend\n"
  },
  {
    "path": "spec/models/status_pin_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe StatusPin, type: :model do\n  describe 'validations' do\n    it 'allows pins of own statuses' do\n      account = Fabricate(:account)\n      status  = Fabricate(:status, account: account)\n\n      expect(StatusPin.new(account: account, status: status).save).to be true\n    end\n\n    it 'does not allow pins of statuses by someone else' do\n      account = Fabricate(:account)\n      status  = Fabricate(:status)\n\n      expect(StatusPin.new(account: account, status: status).save).to be false\n    end\n\n    it 'does not allow pins of reblogs' do\n      account = Fabricate(:account)\n      status  = Fabricate(:status, account: account)\n      reblog  = Fabricate(:status, reblog: status)\n\n      expect(StatusPin.new(account: account, status: reblog).save).to be false\n    end\n\n    it 'does not allow pins of private statuses' do\n      account = Fabricate(:account)\n      status  = Fabricate(:status, account: account, visibility: :private)\n\n      expect(StatusPin.new(account: account, status: status).save).to be false\n    end\n\n    it 'does not allow pins of direct statuses' do\n      account = Fabricate(:account)\n      status  = Fabricate(:status, account: account, visibility: :direct)\n\n      expect(StatusPin.new(account: account, status: status).save).to be false\n    end\n\n    max_pins = 5\n    it 'does not allow pins above the max' do\n      account = Fabricate(:account)\n      status = []\n\n      (max_pins + 1).times do |i|\n        status[i] = Fabricate(:status, account: account)\n      end\n\n      max_pins.times do |i|\n        expect(StatusPin.new(account: account, status: status[i]).save).to be true\n      end\n\n      expect(StatusPin.new(account: account, status: status[max_pins]).save).to be false\n    end\n\n    it 'allows pins above the max for remote accounts' do\n      account = Fabricate(:account, domain: 'remote.test', username: 'bob', url: 'https://remote.test/')\n      status = []\n\n      (max_pins + 1).times do |i|\n        status[i] = Fabricate(:status, account: account)\n      end\n\n      max_pins.times do |i|\n        expect(StatusPin.new(account: account, status: status[i]).save).to be true\n      end\n\n      expect(StatusPin.new(account: account, status: status[max_pins]).save).to be true\n    end\n  end\nend\n"
  },
  {
    "path": "spec/models/status_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Status, type: :model do\n  let(:alice) { Fabricate(:account, username: 'alice') }\n  let(:bob)   { Fabricate(:account, username: 'bob') }\n  let(:other) { Fabricate(:status, account: bob, text: 'Skulls for the skull god! The enemy\\'s gates are sideways!') }\n\n  subject { Fabricate(:status, account: alice) }\n\n  describe '#local?' do\n    it 'returns true when no remote URI is set' do\n      expect(subject.local?).to be true\n    end\n\n    it 'returns false if a remote URI is set' do\n      alice.update(domain: 'example.com')\n      subject.save\n      expect(subject.local?).to be false\n    end\n\n    it 'returns true if a URI is set and `local` is true' do\n      subject.update(uri: 'example.com', local: true)\n      expect(subject.local?).to be true\n    end\n  end\n\n  describe '#reblog?' do\n    it 'returns true when the status reblogs another status' do\n      subject.reblog = other\n      expect(subject.reblog?).to be true\n    end\n\n    it 'returns false if the status is self-contained' do\n      expect(subject.reblog?).to be false\n    end\n  end\n\n  describe '#reply?' do\n    it 'returns true if the status references another' do\n      subject.thread = other\n      expect(subject.reply?).to be true\n    end\n\n    it 'returns false if the status is self-contained' do\n      expect(subject.reply?).to be false\n    end\n  end\n\n  describe '#verb' do\n    context 'if destroyed?' do\n      it 'returns :delete' do\n        subject.destroy!\n        expect(subject.verb).to be :delete\n      end\n    end\n\n    context 'unless destroyed?' do\n      context 'if reblog?' do\n        it 'returns :share' do\n          subject.reblog = other\n          expect(subject.verb).to be :share\n        end\n      end\n\n      context 'unless reblog?' do\n        it 'returns :post' do\n          subject.reblog = nil\n          expect(subject.verb).to be :post\n        end\n      end\n    end\n  end\n\n  describe '#object_type' do\n    it 'is note when the status is self-contained' do\n      expect(subject.object_type).to be :note\n    end\n\n    it 'is comment when the status replies to another' do\n      subject.thread = other\n      expect(subject.object_type).to be :comment\n    end\n  end\n\n  describe '#title' do\n    # rubocop:disable Style/InterpolationCheck\n\n    let(:account) { subject.account }\n\n    context 'if destroyed?' do\n      it 'returns \"#{account.acct} deleted status\"' do\n        subject.destroy!\n        expect(subject.title).to eq \"#{account.acct} deleted status\"\n      end\n    end\n\n    context 'unless destroyed?' do\n      context 'if reblog?' do\n        it 'returns \"#{account.acct} shared a status by #{reblog.account.acct}\"' do\n          reblog = subject.reblog = other\n          expect(subject.title).to eq \"#{account.acct} shared a status by #{reblog.account.acct}\"\n        end\n      end\n\n      context 'unless reblog?' do\n        it 'returns \"New status by #{account.acct}\"' do\n          subject.reblog = nil\n          expect(subject.title).to eq \"New status by #{account.acct}\"\n        end\n      end\n    end\n  end\n\n  describe '#hidden?' do\n    context 'if private_visibility?' do\n      it 'returns true' do\n        subject.visibility = :private\n        expect(subject.hidden?).to be true\n      end\n    end\n\n    context 'if direct_visibility?' do\n      it 'returns true' do\n        subject.visibility = :direct\n        expect(subject.hidden?).to be true\n      end\n    end\n\n    context 'if public_visibility?' do\n      it 'returns false' do\n        subject.visibility = :public\n        expect(subject.hidden?).to be false\n      end\n    end\n\n    context 'if unlisted_visibility?' do\n      it 'returns false' do\n        subject.visibility = :unlisted\n        expect(subject.hidden?).to be false\n      end\n    end\n  end\n\n  describe '#content' do\n    it 'returns the text of the status if it is not a reblog' do\n      expect(subject.content).to eql subject.text\n    end\n\n    it 'returns the text of the reblogged status' do\n      subject.reblog = other\n      expect(subject.content).to eql other.text\n    end\n  end\n\n  describe '#target' do\n    it 'returns nil if the status is self-contained' do\n      expect(subject.target).to be_nil\n    end\n\n    it 'returns nil if the status is a reply' do\n      subject.thread = other\n      expect(subject.target).to be_nil\n    end\n\n    it 'returns the reblogged status' do\n      subject.reblog = other\n      expect(subject.target).to eq other\n    end\n  end\n\n  describe '#reblogs_count' do\n    it 'is the number of reblogs' do\n      Fabricate(:status, account: bob, reblog: subject)\n      Fabricate(:status, account: alice, reblog: subject)\n\n      expect(subject.reblogs_count).to eq 2\n    end\n\n    it 'is decremented when reblog is removed' do\n      reblog = Fabricate(:status, account: bob, reblog: subject)\n      expect(subject.reblogs_count).to eq 1\n      reblog.destroy\n      expect(subject.reblogs_count).to eq 0\n    end\n\n    it 'does not fail when original is deleted before reblog' do\n      reblog = Fabricate(:status, account: bob, reblog: subject)\n      expect(subject.reblogs_count).to eq 1\n      expect { subject.destroy }.to_not raise_error\n      expect(Status.find_by(id: reblog.id)).to be_nil\n    end\n  end\n\n  describe '#replies_count' do\n    it 'is the number of replies' do\n      reply = Fabricate(:status, account: bob, thread: subject)\n      expect(subject.replies_count).to eq 1\n    end\n\n    it 'is decremented when reply is removed' do\n      reply = Fabricate(:status, account: bob, thread: subject)\n      expect(subject.replies_count).to eq 1\n      reply.destroy\n      expect(subject.replies_count).to eq 0\n    end\n  end\n\n  describe '#favourites_count' do\n    it 'is the number of favorites' do\n      Fabricate(:favourite, account: bob, status: subject)\n      Fabricate(:favourite, account: alice, status: subject)\n\n      expect(subject.favourites_count).to eq 2\n    end\n\n    it 'is decremented when favourite is removed' do\n      favourite = Fabricate(:favourite, account: bob, status: subject)\n      expect(subject.favourites_count).to eq 1\n      favourite.destroy\n      expect(subject.favourites_count).to eq 0\n    end\n  end\n\n  describe '#proper' do\n    it 'is itself for original statuses' do\n      expect(subject.proper).to eq subject\n    end\n\n    it 'is the source status for reblogs' do\n      subject.reblog = other\n      expect(subject.proper).to eq other\n    end\n  end\n\n  describe '.mutes_map' do\n    let(:status)  { Fabricate(:status) }\n    let(:account) { Fabricate(:account) }\n\n    subject { Status.mutes_map([status.conversation.id], account) }\n\n    it 'returns a hash' do\n      expect(subject).to be_a Hash\n    end\n\n    it 'contains true value' do\n      account.mute_conversation!(status.conversation)\n      expect(subject[status.conversation.id]).to be true\n    end\n  end\n\n  describe '.favourites_map' do\n    let(:status)  { Fabricate(:status) }\n    let(:account) { Fabricate(:account) }\n\n    subject { Status.favourites_map([status], account) }\n\n    it 'returns a hash' do\n      expect(subject).to be_a Hash\n    end\n\n    it 'contains true value' do\n      Fabricate(:favourite, status: status, account: account)\n      expect(subject[status.id]).to be true\n    end\n  end\n\n  describe '.reblogs_map' do\n    let(:status)  { Fabricate(:status) }\n    let(:account) { Fabricate(:account) }\n\n    subject { Status.reblogs_map([status], account) }\n\n    it 'returns a hash' do\n      expect(subject).to be_a Hash\n    end\n\n    it 'contains true value' do\n      Fabricate(:status, account: account, reblog: status)\n      expect(subject[status.id]).to be true\n    end\n  end\n\n  describe '.in_chosen_languages' do\n    context 'for accounts with language filters' do\n      let(:user) { Fabricate(:user, chosen_languages: ['en']) }\n\n      it 'does not include statuses in not in chosen languages' do\n        status = Fabricate(:status, language: 'de')\n        expect(Status.in_chosen_languages(user.account)).not_to include status\n      end\n\n      it 'includes status with unknown language' do\n        status = Fabricate(:status, language: nil)\n        expect(Status.in_chosen_languages(user.account)).to include status\n      end\n    end\n  end\n\n  describe '.as_home_timeline' do\n    let(:account) { Fabricate(:account) }\n    let(:followed) { Fabricate(:account) }\n    let(:not_followed) { Fabricate(:account) }\n\n    before do\n      Fabricate(:follow, account: account, target_account: followed)\n\n      @self_status = Fabricate(:status, account: account, visibility: :public)\n      @self_direct_status = Fabricate(:status, account: account, visibility: :direct)\n      @followed_status = Fabricate(:status, account: followed, visibility: :public)\n      @followed_direct_status = Fabricate(:status, account: followed, visibility: :direct)\n      @not_followed_status = Fabricate(:status, account: not_followed, visibility: :public)\n\n      @results = Status.as_home_timeline(account)\n    end\n\n    it 'includes statuses from self' do\n      expect(@results).to include(@self_status)\n    end\n\n    it 'does not include direct statuses from self' do\n      expect(@results).to_not include(@self_direct_status)\n    end\n\n    it 'includes statuses from followed' do\n      expect(@results).to include(@followed_status)\n    end\n\n    it 'does not include direct statuses mentioning recipient from followed' do\n      Fabricate(:mention, account: account, status: @followed_direct_status)\n      expect(@results).to_not include(@followed_direct_status)\n    end\n\n    it 'does not include direct statuses not mentioning recipient from followed' do\n      expect(@results).not_to include(@followed_direct_status)\n    end\n\n    it 'does not include statuses from non-followed' do\n      expect(@results).not_to include(@not_followed_status)\n    end\n  end\n\n  describe '.as_direct_timeline' do\n    let(:account) { Fabricate(:account) }\n    let(:followed) { Fabricate(:account) }\n    let(:not_followed) { Fabricate(:account) }\n\n    before do\n      Fabricate(:follow, account: account, target_account: followed)\n\n      @self_public_status = Fabricate(:status, account: account, visibility: :public)\n      @self_direct_status = Fabricate(:status, account: account, visibility: :direct)\n      @followed_public_status = Fabricate(:status, account: followed, visibility: :public)\n      @followed_direct_status = Fabricate(:status, account: followed, visibility: :direct)\n      @not_followed_direct_status = Fabricate(:status, account: not_followed, visibility: :direct)\n\n      @results = Status.as_direct_timeline(account)\n    end\n\n    it 'does not include public statuses from self' do\n      expect(@results).to_not include(@self_public_status)\n    end\n\n    it 'includes direct statuses from self' do\n      expect(@results).to include(@self_direct_status)\n    end\n\n    it 'does not include public statuses from followed' do\n      expect(@results).to_not include(@followed_public_status)\n    end\n\n    it 'does not include direct statuses not mentioning recipient from followed' do\n      expect(@results).to_not include(@followed_direct_status)\n    end\n\n    it 'does not include direct statuses not mentioning recipient from non-followed' do\n      expect(@results).to_not include(@not_followed_direct_status)\n    end\n\n    it 'includes direct statuses mentioning recipient from followed' do\n      Fabricate(:mention, account: account, status: @followed_direct_status)\n      results2 = Status.as_direct_timeline(account)\n      expect(results2).to include(@followed_direct_status)\n    end\n\n    it 'includes direct statuses mentioning recipient from non-followed' do\n      Fabricate(:mention, account: account, status: @not_followed_direct_status)\n      results2 = Status.as_direct_timeline(account)\n      expect(results2).to include(@not_followed_direct_status)\n    end\n  end\n\n  describe '.as_public_timeline' do\n    it 'only includes statuses with public visibility' do\n      public_status = Fabricate(:status, visibility: :public)\n      private_status = Fabricate(:status, visibility: :private)\n\n      results = Status.as_public_timeline\n      expect(results).to include(public_status)\n      expect(results).not_to include(private_status)\n    end\n\n    it 'does not include replies' do\n      status = Fabricate(:status)\n      reply = Fabricate(:status, in_reply_to_id: status.id)\n\n      results = Status.as_public_timeline\n      expect(results).to include(status)\n      expect(results).not_to include(reply)\n    end\n\n    it 'does not include boosts' do\n      status = Fabricate(:status)\n      boost = Fabricate(:status, reblog_of_id: status.id)\n\n      results = Status.as_public_timeline\n      expect(results).to include(status)\n      expect(results).not_to include(boost)\n    end\n\n    it 'filters out silenced accounts' do\n      account = Fabricate(:account)\n      silenced_account = Fabricate(:account, silenced: true)\n      status = Fabricate(:status, account: account)\n      silenced_status = Fabricate(:status, account: silenced_account)\n\n      results = Status.as_public_timeline\n      expect(results).to include(status)\n      expect(results).not_to include(silenced_status)\n    end\n\n    context 'without local_only option' do\n      let(:viewer) { nil }\n\n      let!(:local_account)  { Fabricate(:account, domain: nil) }\n      let!(:remote_account) { Fabricate(:account, domain: 'test.com') }\n      let!(:local_status)   { Fabricate(:status, account: local_account) }\n      let!(:remote_status)  { Fabricate(:status, account: remote_account) }\n\n      subject { Status.as_public_timeline(viewer, false) }\n\n      context 'without a viewer' do\n        let(:viewer) { nil }\n\n        it 'includes remote instances statuses' do\n          expect(subject).to include(remote_status)\n        end\n\n        it 'includes local statuses' do\n          expect(subject).to include(local_status)\n        end\n      end\n\n      context 'with a viewer' do\n        let(:viewer) { Fabricate(:account, username: 'viewer') }\n\n        it 'includes remote instances statuses' do\n          expect(subject).to include(remote_status)\n        end\n\n        it 'includes local statuses' do\n          expect(subject).to include(local_status)\n        end\n      end\n    end\n\n    context 'with a local_only option set' do\n      let!(:local_account)  { Fabricate(:account, domain: nil) }\n      let!(:remote_account) { Fabricate(:account, domain: 'test.com') }\n      let!(:local_status)   { Fabricate(:status, account: local_account) }\n      let!(:remote_status)  { Fabricate(:status, account: remote_account) }\n\n      subject { Status.as_public_timeline(viewer, true) }\n\n      context 'without a viewer' do\n        let(:viewer) { nil }\n\n        it 'does not include remote instances statuses' do\n          expect(subject).to include(local_status)\n          expect(subject).not_to include(remote_status)\n        end\n      end\n\n      context 'with a viewer' do\n        let(:viewer) { Fabricate(:account, username: 'viewer') }\n\n        it 'does not include remote instances statuses' do\n          expect(subject).to include(local_status)\n          expect(subject).not_to include(remote_status)\n        end\n\n        it 'is not affected by personal domain blocks' do\n          viewer.block_domain!('test.com')\n          expect(subject).to include(local_status)\n          expect(subject).not_to include(remote_status)\n        end\n      end\n    end\n\n    describe 'with an account passed in' do\n      before do\n        @account = Fabricate(:account)\n      end\n\n      it 'excludes statuses from accounts blocked by the account' do\n        blocked = Fabricate(:account)\n        Fabricate(:block, account: @account, target_account: blocked)\n        blocked_status = Fabricate(:status, account: blocked)\n\n        results = Status.as_public_timeline(@account)\n        expect(results).not_to include(blocked_status)\n      end\n\n      it 'excludes statuses from accounts who have blocked the account' do\n        blocked = Fabricate(:account)\n        Fabricate(:block, account: blocked, target_account: @account)\n        blocked_status = Fabricate(:status, account: blocked)\n\n        results = Status.as_public_timeline(@account)\n        expect(results).not_to include(blocked_status)\n      end\n\n      it 'excludes statuses from accounts muted by the account' do\n        muted = Fabricate(:account)\n        Fabricate(:mute, account: @account, target_account: muted)\n        muted_status = Fabricate(:status, account: muted)\n\n        results = Status.as_public_timeline(@account)\n        expect(results).not_to include(muted_status)\n      end\n\n      it 'excludes statuses from accounts from personally blocked domains' do\n        blocked = Fabricate(:account, domain: 'example.com')\n        @account.block_domain!(blocked.domain)\n        blocked_status = Fabricate(:status, account: blocked)\n\n        results = Status.as_public_timeline(@account)\n        expect(results).not_to include(blocked_status)\n      end\n\n      context 'with language preferences' do\n        it 'excludes statuses in languages not allowed by the account user' do\n          user = Fabricate(:user, chosen_languages: [:en, :es])\n          @account.update(user: user)\n          en_status = Fabricate(:status, language: 'en')\n          es_status = Fabricate(:status, language: 'es')\n          fr_status = Fabricate(:status, language: 'fr')\n\n          results = Status.as_public_timeline(@account)\n          expect(results).to include(en_status)\n          expect(results).to include(es_status)\n          expect(results).not_to include(fr_status)\n        end\n\n        it 'includes all languages when user does not have a setting' do\n          user = Fabricate(:user, chosen_languages: nil)\n          @account.update(user: user)\n\n          en_status = Fabricate(:status, language: 'en')\n          es_status = Fabricate(:status, language: 'es')\n\n          results = Status.as_public_timeline(@account)\n          expect(results).to include(en_status)\n          expect(results).to include(es_status)\n        end\n\n        it 'includes all languages when account does not have a user' do\n          expect(@account.user).to be_nil\n          en_status = Fabricate(:status, language: 'en')\n          es_status = Fabricate(:status, language: 'es')\n\n          results = Status.as_public_timeline(@account)\n          expect(results).to include(en_status)\n          expect(results).to include(es_status)\n        end\n      end\n    end\n  end\n\n  describe '.as_tag_timeline' do\n    it 'includes statuses with a tag' do\n      tag = Fabricate(:tag)\n      status = Fabricate(:status, tags: [tag])\n      other = Fabricate(:status)\n\n      results = Status.as_tag_timeline(tag)\n      expect(results).to include(status)\n      expect(results).not_to include(other)\n    end\n\n    it 'allows replies to be included' do\n      original = Fabricate(:status)\n      tag = Fabricate(:tag)\n      status = Fabricate(:status, tags: [tag], in_reply_to_id: original.id)\n\n      results = Status.as_tag_timeline(tag)\n      expect(results).to include(status)\n    end\n  end\n\n  describe '.permitted_for' do\n    subject { described_class.permitted_for(target_account, account).pluck(:visibility) }\n\n    let(:target_account) { alice }\n    let(:account) { bob }\n    let!(:public_status) { Fabricate(:status, account: target_account, visibility: 'public') }\n    let!(:unlisted_status) { Fabricate(:status, account: target_account, visibility: 'unlisted') }\n    let!(:private_status) { Fabricate(:status, account: target_account, visibility: 'private') }\n\n    let!(:direct_status) do\n      Fabricate(:status, account: target_account, visibility: 'direct').tap do |status|\n        Fabricate(:mention, status: status, account: account)\n      end\n    end\n\n    let!(:other_direct_status) do\n      Fabricate(:status, account: target_account, visibility: 'direct').tap do |status|\n        Fabricate(:mention, status: status)\n      end\n    end\n\n    context 'given nil' do\n      let(:account) { nil }\n      let(:direct_status) { nil }\n      it { is_expected.to eq(%w(unlisted public)) }\n    end\n\n    context 'given blocked account' do\n      before do\n        target_account.block!(account)\n      end\n\n      it { is_expected.to be_empty }\n    end\n\n    context 'given same account' do\n      let(:account) { target_account }\n      it { is_expected.to eq(%w(direct direct private unlisted public)) }\n    end\n\n    context 'given followed account' do\n      before do\n        account.follow!(target_account)\n      end\n\n      it { is_expected.to eq(%w(direct private unlisted public)) }\n    end\n\n    context 'given unfollowed account' do\n      it { is_expected.to eq(%w(direct unlisted public)) }\n    end\n  end\n\n  describe 'before_validation' do\n    it 'sets account being replied to correctly over intermediary nodes' do\n      first_status = Fabricate(:status, account: bob)\n      intermediary = Fabricate(:status, thread: first_status, account: alice)\n      final        = Fabricate(:status, thread: intermediary, account: alice)\n\n      expect(final.in_reply_to_account_id).to eq bob.id\n    end\n\n    it 'creates new conversation for stand-alone status' do\n      expect(Status.create(account: alice, text: 'First').conversation_id).to_not be_nil\n    end\n\n    it 'keeps conversation of parent node' do\n      parent = Fabricate(:status, text: 'First')\n      expect(Status.create(account: alice, thread: parent, text: 'Response').conversation_id).to eq parent.conversation_id\n    end\n\n    it 'sets `local` to true for status by local account' do\n      expect(Status.create(account: alice, text: 'foo').local).to be true\n    end\n\n    it 'sets `local` to false for status by remote account' do\n      alice.update(domain: 'example.com')\n      expect(Status.create(account: alice, text: 'foo').local).to be false\n    end\n  end\n\n  describe 'validation' do\n    it 'disallow empty uri for remote status' do\n      alice.update(domain: 'example.com')\n      status = Fabricate.build(:status, uri: '', account: alice)\n      expect(status).to model_have_error_on_field(:uri)\n    end\n  end\n\n  describe 'after_create' do\n    it 'saves ActivityPub uri as uri for local status' do\n      status = Status.create(account: alice, text: 'foo')\n      status.reload\n      expect(status.uri).to start_with('https://')\n    end\n  end\nend\n"
  },
  {
    "path": "spec/models/status_stat_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe StatusStat, type: :model do\nend\n"
  },
  {
    "path": "spec/models/stream_entry_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe StreamEntry, type: :model do\n  let(:alice)     { Fabricate(:account, username: 'alice') }\n  let(:bob)       { Fabricate(:account, username: 'bob') }\n  let(:status)    { Fabricate(:status, account: alice) }\n  let(:reblog)    { Fabricate(:status, account: bob, reblog: status) }\n  let(:reply)     { Fabricate(:status, account: bob, thread: status) }\n  let(:stream_entry) { Fabricate(:stream_entry, activity: activity) }\n  let(:activity)     { reblog }\n\n  describe '#object_type' do\n    before do\n      allow(stream_entry).to receive(:orphaned?).and_return(orphaned)\n      allow(stream_entry).to receive(:targeted?).and_return(targeted)\n    end\n\n    subject { stream_entry.object_type }\n\n    context 'orphaned? is true' do\n      let(:orphaned) { true }\n      let(:targeted) { false }\n\n      it 'returns :activity' do\n        is_expected.to be :activity\n      end\n    end\n\n    context 'targeted? is true' do\n      let(:orphaned) { false }\n      let(:targeted) { true }\n\n      it 'returns :activity' do\n        is_expected.to be :activity\n      end\n    end\n\n    context 'orphaned? and targeted? are false' do\n      let(:orphaned) { false }\n      let(:targeted) { false }\n\n      context 'activity is reblog' do\n        let(:activity) { reblog }\n\n        it 'returns :note' do\n          is_expected.to be :note\n        end\n      end\n\n      context 'activity is reply' do\n        let(:activity) { reply }\n\n        it 'returns :comment' do\n          is_expected.to be :comment\n        end\n      end\n    end\n  end\n\n  describe '#verb' do\n    before do\n      allow(stream_entry).to receive(:orphaned?).and_return(orphaned)\n    end\n\n    subject { stream_entry.verb }\n\n    context 'orphaned? is true' do\n      let(:orphaned) { true }\n\n      it 'returns :delete' do\n        is_expected.to be :delete\n      end\n    end\n\n    context 'orphaned? is false' do\n      let(:orphaned) { false }\n\n      context 'activity is reblog' do\n        let(:activity) { reblog }\n\n        it 'returns :share' do\n          is_expected.to be :share\n        end\n      end\n\n      context 'activity is reply' do\n        let(:activity) { reply }\n\n        it 'returns :post' do\n          is_expected.to be :post\n        end\n      end\n    end\n  end\n\n  describe '#mentions' do\n    before do\n      allow(stream_entry).to receive(:orphaned?).and_return(orphaned)\n    end\n\n    subject { stream_entry.mentions }\n\n    context 'orphaned? is true' do\n      let(:orphaned) { true }\n\n      it 'returns []' do\n        is_expected.to eq []\n      end\n    end\n\n    context 'orphaned? is false' do\n      before do\n        reblog.mentions << Fabricate(:mention, account: alice)\n        reblog.mentions << Fabricate(:mention, account: bob)\n      end\n\n      let(:orphaned) { false }\n\n      it 'returns [Account] includes alice and bob' do\n        is_expected.to eq [alice, bob]\n      end\n    end\n  end\n\n  describe '#targeted?' do\n    it 'returns true for a reblog' do\n      expect(reblog.stream_entry.targeted?).to be true\n    end\n\n    it 'returns false otherwise' do\n      expect(status.stream_entry.targeted?).to be false\n    end\n  end\n\n  describe '#threaded?' do\n    it 'returns true for a reply' do\n      expect(reply.stream_entry.threaded?).to be true\n    end\n\n    it 'returns false otherwise' do\n      expect(status.stream_entry.threaded?).to be false\n    end\n  end\n\n  describe 'delegated methods' do\n    context 'with a nil status' do\n      subject { described_class.new(status: nil) }\n\n      it 'returns nil for target' do\n        expect(subject.target).to be_nil\n      end\n\n      it 'returns nil for title' do\n        expect(subject.title).to be_nil\n      end\n\n      it 'returns nil for content' do\n        expect(subject.content).to be_nil\n      end\n\n      it 'returns nil for thread' do\n        expect(subject.thread).to be_nil\n      end\n    end\n\n    context 'with a real status' do\n      let(:original) { Fabricate(:status, text: 'Test status') }\n      let(:status) { Fabricate(:status, reblog: original, thread: original) }\n      subject { described_class.new(status: status) }\n\n      it 'delegates target' do\n        expect(status.target).not_to be_nil\n        expect(subject.target).to eq(status.target)\n      end\n\n      it 'delegates title' do\n        expect(status.title).not_to be_nil\n        expect(subject.title).to eq(status.title)\n      end\n\n      it 'delegates content' do\n        expect(status.content).not_to be_nil\n        expect(subject.content).to eq(status.content)\n      end\n\n      it 'delegates thread' do\n        expect(status.thread).not_to be_nil\n        expect(subject.thread).to eq(status.thread)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/models/subscription_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Subscription, type: :model do\n  let(:alice) { Fabricate(:account, username: 'alice') }\n\n  subject { Fabricate(:subscription, account: alice) }\n\n  describe '#expired?' do\n    it 'return true when expires_at is past' do\n      subject.expires_at = 2.days.ago\n      expect(subject.expired?).to be true\n    end\n\n    it 'return false when expires_at is future' do\n      subject.expires_at = 2.days.from_now\n      expect(subject.expired?).to be false\n    end\n  end\n\n  describe 'lease_seconds' do\n    it 'returns the time remaining until expiration' do\n      datetime = 1.day.from_now\n      subscription = Subscription.new(expires_at: datetime)\n      travel_to(datetime - 12.hours) do\n        expect(subscription.lease_seconds).to eq(12.hours)\n      end\n    end\n  end\n\n  describe 'lease_seconds=' do\n    it 'sets expires_at to min expiration when small value is provided' do\n      subscription = Subscription.new\n      datetime = 1.day.from_now\n      too_low = Subscription::MIN_EXPIRATION - 1000\n      travel_to(datetime) do\n        subscription.lease_seconds = too_low\n      end\n\n      expected = datetime + Subscription::MIN_EXPIRATION.seconds\n      expect(subscription.expires_at).to be_within(1.0).of(expected)\n    end\n\n    it 'sets expires_at to value when valid value is provided' do\n      subscription = Subscription.new\n      datetime = 1.day.from_now\n      valid = Subscription::MIN_EXPIRATION + 1000\n      travel_to(datetime) do\n        subscription.lease_seconds = valid\n      end\n\n      expected = datetime + valid.seconds\n      expect(subscription.expires_at).to be_within(1.0).of(expected)\n    end\n\n    it 'sets expires_at to max expiration when large value is provided' do\n      subscription = Subscription.new\n      datetime = 1.day.from_now\n      too_high = Subscription::MAX_EXPIRATION + 1000\n      travel_to(datetime) do\n        subscription.lease_seconds = too_high\n      end\n\n      expected = datetime + Subscription::MAX_EXPIRATION.seconds\n      expect(subscription.expires_at).to be_within(1.0).of(expected)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/models/tag_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Tag, type: :model do\n  describe 'validations' do\n    it 'invalid with #' do\n      expect(Tag.new(name: '#hello_world')).to_not be_valid\n    end\n\n    it 'invalid with .' do\n      expect(Tag.new(name: '.abcdef123')).to_not be_valid\n    end\n\n    it 'invalid with spaces' do\n      expect(Tag.new(name: 'hello world')).to_not be_valid\n    end\n\n    it 'valid with ａｅｓｔｈｅｔｉｃ' do\n      expect(Tag.new(name: 'ａｅｓｔｈｅｔｉｃ')).to be_valid\n    end\n  end\n\n  describe 'HASHTAG_RE' do\n    subject { Tag::HASHTAG_RE }\n\n    it 'does not match URLs with anchors with non-hashtag characters' do\n      expect(subject.match('Check this out https://medium.com/@alice/some-article#.abcdef123')).to be_nil\n    end\n\n    it 'does not match URLs with hashtag-like anchors' do\n      expect(subject.match('https://en.wikipedia.org/wiki/Ghostbusters_(song)#Lawsuit')).to be_nil\n    end\n\n    it 'matches ﻿#ａｅｓｔｈｅｔｉｃ' do\n      expect(subject.match('﻿this is #ａｅｓｔｈｅｔｉｃ')).to_not be_nil\n    end\n  end\n\n  describe '#to_param' do\n    it 'returns name' do\n      tag = Fabricate(:tag, name: 'foo')\n      expect(tag.to_param).to eq 'foo'\n    end\n  end\n\n  describe '.search_for' do\n    it 'finds tag records with matching names' do\n      tag = Fabricate(:tag, name: \"match\")\n      _miss_tag = Fabricate(:tag, name: \"miss\")\n\n      results = Tag.search_for(\"match\")\n\n      expect(results).to eq [tag]\n    end\n\n    it 'finds tag records in case insensitive' do\n      tag = Fabricate(:tag, name: \"MATCH\")\n      _miss_tag = Fabricate(:tag, name: \"miss\")\n\n      results = Tag.search_for(\"match\")\n\n      expect(results).to eq [tag]\n    end\n\n    it 'finds the exact matching tag as the first item' do\n      similar_tag = Fabricate(:tag, name: \"matchlater\")\n      tag = Fabricate(:tag, name: \"match\")\n\n      results = Tag.search_for(\"match\")\n\n      expect(results).to eq [tag, similar_tag]\n    end\n  end\nend\n"
  },
  {
    "path": "spec/models/user_invite_request_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe UserInviteRequest, type: :model do\nend\n"
  },
  {
    "path": "spec/models/user_spec.rb",
    "content": "require 'rails_helper'\nrequire 'devise_two_factor/spec_helpers'\n\nRSpec.describe User, type: :model do\n  it_behaves_like 'two_factor_backupable'\n\n  describe 'otp_secret' do\n    it 'is encrypted with OTP_SECRET environment variable' do\n      user = Fabricate(:user,\n                       encrypted_otp_secret: \"Fttsy7QAa0edaDfdfSz094rRLAxc8cJweDQ4BsWH/zozcdVA8o9GLqcKhn2b\\nGi/V\\n\",\n                       encrypted_otp_secret_iv: 'rys3THICkr60BoWC',\n                       encrypted_otp_secret_salt: '_LMkAGvdg7a+sDIKjI3mR2Q==')\n\n      expect(user.otp_secret).to eq 'anotpsecretthatshouldbeencrypted'\n    end\n  end\n\n  describe 'validations' do\n    it 'is invalid without an account' do\n      user = Fabricate.build(:user, account: nil)\n      user.valid?\n      expect(user).to model_have_error_on_field(:account)\n    end\n\n    it 'is invalid without a valid locale' do\n      user = Fabricate.build(:user, locale: 'toto')\n      user.valid?\n      expect(user).to model_have_error_on_field(:locale)\n    end\n\n    it 'is invalid without a valid email' do\n      user = Fabricate.build(:user, email: 'john@')\n      user.valid?\n      expect(user).to model_have_error_on_field(:email)\n    end\n\n    it 'is valid with an invalid e-mail that has already been saved' do\n      user = Fabricate.build(:user, email: 'invalid-email')\n      user.save(validate: false)\n      expect(user.valid?).to be true\n    end\n\n    it 'cleans out empty string from languages' do\n      user = Fabricate.build(:user, chosen_languages: [''])\n      user.valid?\n      expect(user.chosen_languages).to eq nil\n    end\n  end\n\n  describe 'scopes' do\n    describe 'recent' do\n      it 'returns an array of recent users ordered by id' do\n        user_1 = Fabricate(:user)\n        user_2 = Fabricate(:user)\n        expect(User.recent).to eq [user_2, user_1]\n      end\n    end\n\n    describe 'admins' do\n      it 'returns an array of users who are admin' do\n        user_1 = Fabricate(:user, admin: false)\n        user_2 = Fabricate(:user, admin: true)\n        expect(User.admins).to match_array([user_2])\n      end\n    end\n\n    describe 'confirmed' do\n      it 'returns an array of users who are confirmed' do\n        user_1 = Fabricate(:user, confirmed_at: nil)\n        user_2 = Fabricate(:user, confirmed_at: Time.zone.now)\n        expect(User.confirmed).to match_array([user_2])\n      end\n    end\n\n    describe 'inactive' do\n      it 'returns a relation of inactive users' do\n        specified = Fabricate(:user, current_sign_in_at: 15.days.ago)\n        Fabricate(:user, current_sign_in_at: 6.days.ago)\n\n        expect(User.inactive).to match_array([specified])\n      end\n    end\n\n    describe 'matches_email' do\n      it 'returns a relation of users whose email starts with the given string' do\n        specified = Fabricate(:user, email: 'specified@spec')\n        Fabricate(:user, email: 'unspecified@spec')\n\n        expect(User.matches_email('specified')).to match_array([specified])\n      end\n    end\n  end\n\n  let(:account) { Fabricate(:account, username: 'alice') }\n  let(:password) { 'abcd1234' }\n\n  describe 'blacklist' do\n    around(:each) do |example|\n      old_blacklist = Rails.configuration.x.email_blacklist\n\n      Rails.configuration.x.email_domains_blacklist = 'mvrht.com'\n\n      example.run\n\n      Rails.configuration.x.email_domains_blacklist = old_blacklist\n    end\n\n    it 'should allow a non-blacklisted user to be created' do\n      user = User.new(email: 'foo@example.com', account: account, password: password, agreement: true)\n\n      expect(user.valid?).to be_truthy\n    end\n\n    it 'should not allow a blacklisted user to be created' do\n      user = User.new(email: 'foo@mvrht.com', account: account, password: password, agreement: true)\n\n      expect(user.valid?).to be_falsey\n    end\n\n    it 'should not allow a subdomain blacklisted user to be created' do\n      user = User.new(email: 'foo@mvrht.com.topdomain.tld', account: account, password: password, agreement: true)\n\n      expect(user.valid?).to be_falsey\n    end\n  end\n\n  describe '#confirmed?' do\n    it 'returns true when a confirmed_at is set' do\n      user = Fabricate.build(:user, confirmed_at: Time.now.utc)\n      expect(user.confirmed?).to be true\n    end\n\n    it 'returns false if a confirmed_at is nil' do\n      user = Fabricate.build(:user, confirmed_at: nil)\n      expect(user.confirmed?).to be false\n    end\n  end\n\n  describe '#confirm' do\n    it 'sets email to unconfirmed_email' do\n      user = Fabricate.build(:user, confirmed_at: Time.now.utc, unconfirmed_email: 'new-email@example.com')\n      user.confirm\n      expect(user.email).to eq 'new-email@example.com'\n    end\n  end\n\n  describe '#disable_two_factor!' do\n    it 'saves false for otp_required_for_login' do\n      user = Fabricate.build(:user, otp_required_for_login: true)\n      user.disable_two_factor!\n      expect(user.reload.otp_required_for_login).to be false\n    end\n\n    it 'saves cleared otp_backup_codes' do\n      user = Fabricate.build(:user, otp_backup_codes: %w(dummy dummy))\n      user.disable_two_factor!\n      expect(user.reload.otp_backup_codes.empty?).to be true\n    end\n  end\n\n  describe '#send_confirmation_instructions' do\n    around do |example|\n      queue_adapter = ActiveJob::Base.queue_adapter\n      example.run\n      ActiveJob::Base.queue_adapter = queue_adapter\n    end\n\n    it 'delivers confirmation instructions later' do\n      user = Fabricate(:user)\n      ActiveJob::Base.queue_adapter = :test\n\n      expect { user.send_confirmation_instructions }.to have_enqueued_job(ActionMailer::DeliveryJob)\n    end\n  end\n\n  describe 'settings' do\n    it 'is instance of Settings::ScopedSettings' do\n      user = Fabricate(:user)\n      expect(user.settings).to be_kind_of Settings::ScopedSettings\n    end\n  end\n\n  describe '#setting_default_privacy' do\n    it 'returns default privacy setting if user has configured' do\n      user = Fabricate(:user)\n      user.settings[:default_privacy] = 'unlisted'\n      expect(user.setting_default_privacy).to eq 'unlisted'\n    end\n\n    it \"returns 'private' if user has not configured default privacy setting and account is locked\" do\n      user = Fabricate(:user, account: Fabricate(:account, locked: true))\n      expect(user.setting_default_privacy).to eq 'private'\n    end\n\n    it \"returns 'public' if user has not configured default privacy setting and account is not locked\" do\n      user = Fabricate(:user, account: Fabricate(:account, locked: false))\n      expect(user.setting_default_privacy).to eq 'public'\n    end\n  end\n\n  describe 'whitelist' do\n    around(:each) do |example|\n      old_whitelist = Rails.configuration.x.email_whitelist\n\n      Rails.configuration.x.email_domains_whitelist = 'mastodon.space'\n\n      example.run\n\n      Rails.configuration.x.email_domains_whitelist = old_whitelist\n    end\n\n    it 'should not allow a user to be created unless they are whitelisted' do\n      user = User.new(email: 'foo@example.com', account: account, password: password, agreement: true)\n      expect(user.valid?).to be_falsey\n    end\n\n    it 'should allow a user to be created if they are whitelisted' do\n      user = User.new(email: 'foo@mastodon.space', account: account, password: password, agreement: true)\n      expect(user.valid?).to be_truthy\n    end\n\n    it 'should not allow a user with a whitelisted top domain as subdomain in their email address to be created' do\n      user = User.new(email: 'foo@mastodon.space.userdomain.com', account: account, password: password, agreement: true)\n      expect(user.valid?).to be_falsey\n    end\n\n    context do\n      around do |example|\n        old_blacklist = Rails.configuration.x.email_blacklist\n        example.run\n        Rails.configuration.x.email_domains_blacklist = old_blacklist\n      end\n\n      it 'should not allow a user to be created with a specific blacklisted subdomain even if the top domain is whitelisted' do\n        Rails.configuration.x.email_domains_blacklist = 'blacklisted.mastodon.space'\n\n        user = User.new(email: 'foo@blacklisted.mastodon.space', account: account, password: password)\n        expect(user.valid?).to be_falsey\n      end\n    end\n  end\n\n  it_behaves_like 'Settings-extended' do\n    def create!\n      User.create!(account: Fabricate(:account), email: 'foo@mastodon.space', password: 'abcd1234', agreement: true)\n    end\n\n    def fabricate\n      Fabricate(:user)\n    end\n  end\n\n  describe 'token_for_app' do\n    let(:user) { Fabricate(:user) }\n    let(:app) { Fabricate(:application, owner: user) }\n\n    it 'returns a token' do\n      expect(user.token_for_app(app)).to be_a(Doorkeeper::AccessToken)\n    end\n\n    it 'persists a token' do\n      t = user.token_for_app(app)\n      expect(user.token_for_app(app)).to eql(t)\n    end\n\n    it 'is nil if user does not own app' do\n      app.update!(owner: nil)\n\n      expect(user.token_for_app(app)).to be_nil\n    end\n  end\n\n  describe '#role' do\n    it 'returns admin for admin' do\n      user = User.new(admin: true)\n      expect(user.role).to eq 'admin'\n    end\n\n    it 'returns moderator for moderator' do\n      user = User.new(moderator: true)\n      expect(user.role).to eq 'moderator'\n    end\n\n    it 'returns user otherwise' do\n      user = User.new\n      expect(user.role).to eq 'user'\n    end\n  end\n\n  describe '#role?' do\n    it 'returns false when invalid role requested' do\n      user = User.new(admin: true)\n      expect(user.role?('disabled')).to be false\n    end\n\n    it 'returns true when exact role match' do\n      user  = User.new\n      mod   = User.new(moderator: true)\n      admin = User.new(admin: true)\n\n      expect(user.role?('user')).to be true\n      expect(mod.role?('moderator')).to be true\n      expect(admin.role?('admin')).to be true\n    end\n\n    it 'returns true when role higher than needed' do\n      mod   = User.new(moderator: true)\n      admin = User.new(admin: true)\n\n      expect(mod.role?('user')).to be true\n      expect(admin.role?('user')).to be true\n      expect(admin.role?('moderator')).to be true\n    end\n  end\n\n  describe '#disable!' do\n    subject(:user) { Fabricate(:user, disabled: false, current_sign_in_at: current_sign_in_at, last_sign_in_at: nil) }\n    let(:current_sign_in_at) { Time.zone.now }\n\n    before do\n      user.disable!\n    end\n\n    it 'disables user' do\n      expect(user).to have_attributes(disabled: true, current_sign_in_at: nil, last_sign_in_at: current_sign_in_at)\n    end\n  end\n\n  describe '#disable!' do\n    subject(:user) { Fabricate(:user, disabled: false, current_sign_in_at: current_sign_in_at, last_sign_in_at: nil) }\n    let(:current_sign_in_at) { Time.zone.now }\n\n    before do\n      user.disable!\n    end\n\n    it 'disables user' do\n      expect(user).to have_attributes(disabled: true, current_sign_in_at: nil, last_sign_in_at: current_sign_in_at)\n    end\n  end\n\n  describe '#enable!' do\n    subject(:user) { Fabricate(:user, disabled: true) }\n\n    before do\n      user.enable!\n    end\n\n    it 'enables user' do\n      expect(user).to have_attributes(disabled: false)\n    end\n  end\n\n  describe '#confirm!' do\n    subject(:user) { Fabricate(:user, confirmed_at: confirmed_at) }\n\n    before do\n      ActionMailer::Base.deliveries.clear\n      user.confirm!\n    end\n\n    after { ActionMailer::Base.deliveries.clear }\n\n    context 'when user is new' do\n      let(:confirmed_at) { nil }\n\n      it 'confirms user' do\n        expect(user.confirmed_at).to be_present\n      end\n\n      it 'delivers mails' do\n        expect(ActionMailer::Base.deliveries.count).to eq 2\n      end\n    end\n\n    context 'when user is not new' do\n      let(:confirmed_at) { Time.zone.now }\n\n      it 'confirms user' do\n        expect(user.confirmed_at).to be_present\n      end\n\n      it 'does not deliver mail' do\n        expect(ActionMailer::Base.deliveries.count).to eq 0\n      end\n    end\n  end\n\n  describe '#promote!' do\n    subject(:user) { Fabricate(:user, admin: is_admin, moderator: is_moderator) }\n\n    before do\n      user.promote!\n    end\n\n    context 'when user is an admin' do\n      let(:is_admin) { true }\n\n      context 'when user is a moderator' do\n        let(:is_moderator) { true }\n\n        it 'changes moderator filed false' do\n          expect(user).to be_admin\n          expect(user).not_to be_moderator\n        end\n      end\n\n      context 'when user is not a moderator' do\n        let(:is_moderator) { false }\n\n        it 'does not change status' do\n          expect(user).to be_admin\n          expect(user).not_to be_moderator\n        end\n      end\n    end\n\n    context 'when user is not admin' do\n      let(:is_admin) { false }\n\n      context 'when user is a moderator' do\n        let(:is_moderator) { true }\n\n        it 'changes user into an admin' do\n          expect(user).to be_admin\n          expect(user).not_to be_moderator\n        end\n      end\n\n      context 'when user is not a moderator' do\n        let(:is_moderator) { false }\n\n        it 'changes user into a moderator' do\n          expect(user).not_to be_admin\n          expect(user).to be_moderator\n        end\n      end\n    end\n  end\n\n  describe '#demote!' do\n    subject(:user) { Fabricate(:user, admin: admin, moderator: moderator) }\n\n    before do\n      user.demote!\n    end\n\n    context 'when user is an admin' do\n      let(:admin) { true }\n\n      context 'when user is a moderator' do\n        let(:moderator) { true }\n\n        it 'changes user into a moderator' do\n          expect(user).not_to be_admin\n          expect(user).to be_moderator\n        end\n      end\n\n      context 'when user is not a moderator' do\n        let(:moderator) { false }\n\n        it 'changes user into a moderator' do\n          expect(user).not_to be_admin\n          expect(user).to be_moderator\n        end\n      end\n    end\n\n    context 'when user is not an admin' do\n      let(:admin) { false }\n\n      context 'when user is a moderator' do\n        let(:moderator) { true }\n\n        it 'changes user into a plain user' do\n          expect(user).not_to be_admin\n          expect(user).not_to be_moderator\n        end\n      end\n\n      context 'when user is not a moderator' do\n        let(:moderator) { false }\n\n        it 'does not change any fields' do\n          expect(user).not_to be_admin\n          expect(user).not_to be_moderator\n        end\n      end\n    end\n  end\n\n  describe '#active_for_authentication?' do\n    subject { user.active_for_authentication? }\n    let(:user) { Fabricate(:user, disabled: disabled, confirmed_at: confirmed_at) }\n\n    context 'when user is disabled' do\n      let(:disabled) { true }\n\n      context 'when user is confirmed' do\n        let(:confirmed_at) { Time.zone.now }\n\n        it { is_expected.to be true }\n      end\n\n      context 'when user is not confirmed' do\n        let(:confirmed_at) { nil }\n\n        it { is_expected.to be false }\n      end\n    end\n\n    context 'when user is not disabled' do\n      let(:disabled) { false }\n\n      context 'when user is confirmed' do\n        let(:confirmed_at) { Time.zone.now }\n\n        it { is_expected.to be true }\n      end\n\n      context 'when user is not confirmed' do\n        let(:confirmed_at) { nil }\n\n        it { is_expected.to be false }\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/models/web/push_subscription_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Web::PushSubscription, type: :model do\n  let(:alerts) { { mention: true, reblog: false, follow: true, follow_request: false, favourite: true } }\n  let(:push_subscription) { Web::PushSubscription.new(data: { alerts: alerts }) }\n\n  describe '#pushable?' do\n    it 'obeys alert settings' do\n      expect(push_subscription.send(:pushable?, Notification.new(activity_type: 'Mention'))).to eq true\n      expect(push_subscription.send(:pushable?, Notification.new(activity_type: 'Status'))).to eq false\n      expect(push_subscription.send(:pushable?, Notification.new(activity_type: 'Follow'))).to eq true\n      expect(push_subscription.send(:pushable?, Notification.new(activity_type: 'FollowRequest'))).to eq false\n      expect(push_subscription.send(:pushable?, Notification.new(activity_type: 'Favourite'))).to eq true\n    end\n  end\nend\n"
  },
  {
    "path": "spec/models/web/setting_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe Web::Setting, type: :model do\nend\n"
  },
  {
    "path": "spec/policies/account_moderation_note_policy_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\nrequire 'pundit/rspec'\n\nRSpec.describe AccountModerationNotePolicy do\n  let(:subject) { described_class }\n  let(:admin)   { Fabricate(:user, admin: true).account }\n  let(:john)    { Fabricate(:user).account }\n\n  permissions :create? do\n    context 'staff' do\n      it 'grants to create' do\n        expect(subject).to permit(admin, AccountModerationNotePolicy)\n      end\n    end\n\n    context 'not staff' do\n      it 'denies to create' do\n        expect(subject).to_not permit(john, AccountModerationNotePolicy)\n      end\n    end\n  end\n\n  permissions :destroy? do\n    let(:account_moderation_note) do\n      Fabricate(:account_moderation_note,\n                account: john,\n                target_account: Fabricate(:account))\n    end\n\n    context 'admin' do\n      it 'grants to destroy' do\n        expect(subject).to permit(admin, AccountModerationNotePolicy)\n      end\n    end\n\n    context 'owner' do\n      it 'grants to destroy' do\n        expect(subject).to permit(john, account_moderation_note)\n      end\n    end\n\n    context 'neither admin nor owner' do\n      let(:kevin) { Fabricate(:user).account }\n\n      it 'denies to destroy' do\n        expect(subject).to_not permit(kevin, account_moderation_note)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/policies/account_policy_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\nrequire 'pundit/rspec'\n\nRSpec.describe AccountPolicy do\n  let(:subject) { described_class }\n  let(:admin)   { Fabricate(:user, admin: true).account }\n  let(:john)    { Fabricate(:user).account }\n\n  permissions :index?, :show?, :unsuspend?, :unsilence?, :remove_avatar?, :remove_header? do\n    context 'staff' do\n      it 'permits' do\n        expect(subject).to permit(admin)\n      end\n    end\n\n    context 'not staff' do\n      it 'denies' do\n        expect(subject).to_not permit(john)\n      end\n    end\n  end\n\n  permissions :redownload?, :subscribe?, :unsubscribe? do\n    context 'admin' do\n      it 'permits' do\n        expect(subject).to permit(admin)\n      end\n    end\n\n    context 'not admin' do\n      it 'denies' do\n        expect(subject).to_not permit(john)\n      end\n    end\n  end\n\n  permissions :suspend?, :silence? do\n    let(:staff) { Fabricate(:user, admin: true).account }\n\n    context 'staff' do\n      context 'record is staff' do\n        it 'denies' do\n          expect(subject).to_not permit(admin, staff)\n        end\n      end\n\n      context 'record is not staff' do\n        it 'permits' do\n          expect(subject).to permit(admin, john)\n        end\n      end\n    end\n\n    context 'not staff' do\n      it 'denies' do\n        expect(subject).to_not permit(john, Account)\n      end\n    end\n  end\n\n  permissions :memorialize? do\n    let(:other_admin) { Fabricate(:user, admin: true).account }\n\n    context 'admin' do\n      context 'record is admin' do\n        it 'denies' do\n          expect(subject).to_not permit(admin, other_admin)\n        end\n      end\n\n      context 'record is not admin' do\n        it 'permits' do\n          expect(subject).to permit(admin, john)\n        end\n      end\n    end\n\n    context 'not admin' do\n      it 'denies' do\n        expect(subject).to_not permit(john, Account)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/policies/backup_policy_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\nrequire 'pundit/rspec'\n\nRSpec.describe BackupPolicy do\n  let(:subject) { described_class }\n  let(:john)    { Fabricate(:user).account }\n\n  permissions :create? do\n    context 'not user_signed_in?' do\n      it 'denies' do\n        expect(subject).to_not permit(nil, Backup)\n      end\n    end\n\n    context 'user_signed_in?' do\n      context 'no backups' do\n        it 'permits' do\n          expect(subject).to permit(john, Backup)\n        end\n      end\n\n      context 'backups are too old' do\n        it 'permits' do\n          travel(-8.days) do\n            Fabricate(:backup, user: john.user)\n          end\n\n          expect(subject).to permit(john, Backup)\n        end\n      end\n\n      context 'backups are newer' do\n        it 'denies' do\n          travel(-3.days) do\n            Fabricate(:backup, user: john.user)\n          end\n\n          expect(subject).to_not permit(john, Backup)\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/policies/custom_emoji_policy_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\nrequire 'pundit/rspec'\n\nRSpec.describe CustomEmojiPolicy do\n  let(:subject) { described_class }\n  let(:admin)   { Fabricate(:user, admin: true).account }\n  let(:john)    { Fabricate(:user).account }\n\n  permissions :index?, :enable?, :disable? do\n    context 'staff' do\n      it 'permits' do\n        expect(subject).to permit(admin, CustomEmoji)\n      end\n    end\n\n    context 'not staff' do\n      it 'denies' do\n        expect(subject).to_not permit(john, CustomEmoji)\n      end\n    end\n  end\n\n  permissions :create?, :update?, :copy?, :destroy? do\n    context 'admin' do\n      it 'permits' do\n        expect(subject).to permit(admin, CustomEmoji)\n      end\n    end\n\n    context 'not admin' do\n      it 'denies' do\n        expect(subject).to_not permit(john, CustomEmoji)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/policies/domain_block_policy_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\nrequire 'pundit/rspec'\n\nRSpec.describe DomainBlockPolicy do\n  let(:subject) { described_class }\n  let(:admin)   { Fabricate(:user, admin: true).account }\n  let(:john)    { Fabricate(:user).account }\n\n  permissions :index?, :show?, :create?, :destroy? do\n    context 'admin' do\n      it 'permits' do\n        expect(subject).to permit(admin, DomainBlock)\n      end\n    end\n\n    context 'not admin' do\n      it 'denies' do\n        expect(subject).to_not permit(john, DomainBlock)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/policies/email_domain_block_policy_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\nrequire 'pundit/rspec'\n\nRSpec.describe EmailDomainBlockPolicy do\n  let(:subject) { described_class }\n  let(:admin)   { Fabricate(:user, admin: true).account }\n  let(:john)    { Fabricate(:user).account }\n\n  permissions :index?, :create?, :destroy? do\n    context 'admin' do\n      it 'permits' do\n        expect(subject).to permit(admin, EmailDomainBlock)\n      end\n    end\n\n    context 'not admin' do\n      it 'denies' do\n        expect(subject).to_not permit(john, EmailDomainBlock)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/policies/instance_policy_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\nrequire 'pundit/rspec'\n\nRSpec.describe InstancePolicy do\n  let(:subject) { described_class }\n  let(:admin)   { Fabricate(:user, admin: true).account }\n  let(:john)    { Fabricate(:user).account }\n\n  permissions :index? do\n    context 'admin' do\n      it 'permits' do\n        expect(subject).to permit(admin, Instance)\n      end\n    end\n\n    context 'not admin' do\n      it 'denies' do\n        expect(subject).to_not permit(john, Instance)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/policies/invite_policy_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\nrequire 'pundit/rspec'\n\nRSpec.describe InvitePolicy do\n  let(:subject) { described_class }\n  let(:admin)   { Fabricate(:user, admin: true).account }\n  let(:john)    { Fabricate(:user).account }\n\n  permissions :index? do\n    context 'staff?' do\n      it 'permits' do\n        expect(subject).to permit(admin, Invite)\n      end\n    end\n  end\n\n  permissions :create? do\n    context 'min_required_role?' do\n      it 'permits' do\n        allow_any_instance_of(described_class).to receive(:min_required_role?) { true }\n        expect(subject).to permit(john, Invite)\n      end\n    end\n\n    context 'not min_required_role?' do\n      it 'denies' do\n        allow_any_instance_of(described_class).to receive(:min_required_role?) { false }\n        expect(subject).to_not permit(john, Invite)\n      end\n    end\n  end\n\n  permissions :deactivate_all? do\n    context 'admin?' do\n      it 'permits' do\n        expect(subject).to permit(admin, Invite)\n      end\n    end\n\n    context 'not admin?' do\n      it 'denies' do\n        expect(subject).to_not permit(john, Invite)\n      end\n    end\n  end\n\n  permissions :destroy? do\n    context 'owner?' do\n      it 'permits' do\n        expect(subject).to permit(john, Fabricate(:invite, user: john.user))\n      end\n    end\n\n    context 'not owner?' do\n      context 'Setting.min_invite_role == \"admin\"' do\n        before do\n          Setting.min_invite_role = 'admin'\n        end\n\n        context 'admin?' do\n          it 'permits' do\n            expect(subject).to permit(admin, Fabricate(:invite))\n          end\n        end\n\n        context 'not admin?' do\n          it 'denies' do\n            expect(subject).to_not permit(john, Fabricate(:invite))\n          end\n        end\n      end\n\n      context 'Setting.min_invite_role != \"admin\"' do\n        before do\n          Setting.min_invite_role = 'else'\n        end\n\n        context 'staff?' do\n          it 'permits' do\n            expect(subject).to permit(admin, Fabricate(:invite))\n          end\n        end\n\n        context 'not staff?' do\n          it 'denies' do\n            expect(subject).to_not permit(john, Fabricate(:invite))\n          end\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/policies/relay_policy_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\nrequire 'pundit/rspec'\n\nRSpec.describe RelayPolicy do\n  let(:subject) { described_class }\n  let(:admin)   { Fabricate(:user, admin: true).account }\n  let(:john)    { Fabricate(:user).account }\n\n  permissions :update? do\n    context 'admin?' do\n      it 'permits' do\n        expect(subject).to permit(admin, Relay)\n      end\n    end\n\n    context '!admin?' do\n      it 'denies' do\n        expect(subject).to_not permit(john, Relay)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/policies/report_note_policy_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\nrequire 'pundit/rspec'\n\nRSpec.describe ReportNotePolicy do\n  let(:subject) { described_class }\n  let(:admin)   { Fabricate(:user, admin: true).account }\n  let(:john)    { Fabricate(:user).account }\n\n  permissions :create? do\n    context 'staff?' do\n      it 'permits' do\n        expect(subject).to permit(admin, ReportNote)\n      end\n    end\n\n    context '!staff?' do\n      it 'denies' do\n        expect(subject).to_not permit(john, ReportNote)\n      end\n    end\n  end\n\n  permissions :destroy? do\n    context 'admin?' do\n      it 'permit' do\n        expect(subject).to permit(admin, ReportNote)\n      end\n    end\n\n    context 'admin?' do\n      context 'owner?' do\n        it 'permit' do\n          report_note = Fabricate(:report_note, account: john)\n          expect(subject).to permit(john, report_note)\n        end\n      end\n\n      context '!owner?' do\n        it 'denies' do\n          report_note = Fabricate(:report_note)\n          expect(subject).to_not permit(john, report_note)\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/policies/report_policy_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\nrequire 'pundit/rspec'\n\nRSpec.describe ReportPolicy do\n  let(:subject) { described_class }\n  let(:admin)   { Fabricate(:user, admin: true).account }\n  let(:john)    { Fabricate(:user).account }\n\n  permissions :update?, :index?, :show? do\n    context 'staff?' do\n      it 'permits' do\n        expect(subject).to permit(admin, Report)\n      end\n    end\n\n    context '!staff?' do\n      it 'denies' do\n        expect(subject).to_not permit(john, Report)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/policies/settings_policy_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\nrequire 'pundit/rspec'\n\nRSpec.describe SettingsPolicy do\n  let(:subject) { described_class }\n  let(:admin)   { Fabricate(:user, admin: true).account }\n  let(:john)    { Fabricate(:user).account }\n\n  permissions :update?, :show? do\n    context 'admin?' do\n      it 'permits' do\n        expect(subject).to permit(admin, Settings)\n      end\n    end\n\n    context '!admin?' do\n      it 'denies' do\n        expect(subject).to_not permit(john, Settings)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/policies/status_policy_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\nrequire 'pundit/rspec'\n\nRSpec.describe StatusPolicy, type: :model do\n  subject { described_class }\n\n  let(:admin) { Fabricate(:user, admin: true) }\n  let(:alice) { Fabricate(:account, username: 'alice') }\n  let(:bob) { Fabricate(:account, username: 'bob') }\n  let(:status) { Fabricate(:status, account: alice) }\n\n  permissions :show?, :reblog? do\n    it 'grants access when no viewer' do\n      expect(subject).to permit(nil, status)\n    end\n\n    it 'denies access when viewer is blocked' do\n      block = Fabricate(:block)\n      status.visibility = :private\n      status.account = block.target_account\n\n      expect(subject).to_not permit(block.account, status)\n    end\n  end\n\n  permissions :show? do\n    it 'grants access when direct and account is viewer' do\n      status.visibility = :direct\n\n      expect(subject).to permit(status.account, status)\n    end\n\n    it 'grants access when direct and viewer is mentioned' do\n      status.visibility = :direct\n      status.mentions = [Fabricate(:mention, account: alice)]\n\n      expect(subject).to permit(alice, status)\n    end\n\n    it 'denies access when direct and viewer is not mentioned' do\n      viewer = Fabricate(:account)\n      status.visibility = :direct\n\n      expect(subject).to_not permit(viewer, status)\n    end\n\n    it 'grants access when private and account is viewer' do\n      status.visibility = :private\n\n      expect(subject).to permit(status.account, status)\n    end\n\n    it 'grants access when private and account is following viewer' do\n      follow = Fabricate(:follow)\n      status.visibility = :private\n      status.account = follow.target_account\n\n      expect(subject).to permit(follow.account, status)\n    end\n\n    it 'grants access when private and viewer is mentioned' do\n      status.visibility = :private\n      status.mentions = [Fabricate(:mention, account: alice)]\n\n      expect(subject).to permit(alice, status)\n    end\n\n    it 'denies access when private and viewer is not mentioned or followed' do\n      viewer = Fabricate(:account)\n      status.visibility = :private\n\n      expect(subject).to_not permit(viewer, status)\n    end\n  end\n\n  permissions :reblog? do\n    it 'denies access when private' do\n      viewer = Fabricate(:account)\n      status.visibility = :private\n\n      expect(subject).to_not permit(viewer, status)\n    end\n\n    it 'denies access when direct' do\n      viewer = Fabricate(:account)\n      status.visibility = :direct\n\n      expect(subject).to_not permit(viewer, status)\n    end\n  end\n\n  permissions :destroy?, :unreblog? do\n    it 'grants access when account is deleter' do\n      expect(subject).to permit(status.account, status)\n    end\n\n    it 'grants access when account is admin' do\n      expect(subject).to permit(admin.account, status)\n    end\n\n    it 'denies access when account is not deleter' do\n      expect(subject).to_not permit(bob, status)\n    end\n\n    it 'denies access when no deleter' do\n      expect(subject).to_not permit(nil, status)\n    end\n  end\n\n  permissions :favourite? do\n    it 'grants access when viewer is not blocked' do\n      follow         = Fabricate(:follow)\n      status.account = follow.target_account\n\n      expect(subject).to permit(follow.account, status)\n    end\n\n    it 'denies when viewer is blocked' do\n      block          = Fabricate(:block)\n      status.account = block.target_account\n\n      expect(subject).to_not permit(block.account, status)\n    end\n  end\n\n  permissions :index?, :update? do\n    it 'grants access if staff' do\n      expect(subject).to permit(admin.account)\n    end\n\n    it 'denies access unless staff' do\n      expect(subject).to_not permit(alice)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/policies/subscription_policy_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\nrequire 'pundit/rspec'\n\nRSpec.describe SubscriptionPolicy do\n  let(:subject) { described_class }\n  let(:admin)   { Fabricate(:user, admin: true).account }\n  let(:john)    { Fabricate(:user).account }\n\n  permissions :index? do\n    context 'admin?' do\n      it 'permits' do\n        expect(subject).to permit(admin, Subscription)\n      end\n    end\n\n    context '!admin?' do\n      it 'denies' do\n        expect(subject).to_not permit(john, Subscription)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/policies/tag_policy_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\nrequire 'pundit/rspec'\n\nRSpec.describe TagPolicy do\n  let(:subject) { described_class }\n  let(:admin)   { Fabricate(:user, admin: true).account }\n  let(:john)    { Fabricate(:user).account }\n\n  permissions :index?, :hide?, :unhide? do\n    context 'staff?' do\n      it 'permits' do\n        expect(subject).to permit(admin, Tag)\n      end\n    end\n\n    context '!staff?' do\n      it 'denies' do\n        expect(subject).to_not permit(john, Tag)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/policies/user_policy_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\nrequire 'pundit/rspec'\n\nRSpec.describe UserPolicy do\n  let(:subject) { described_class }\n  let(:admin)   { Fabricate(:user, admin: true).account }\n  let(:john)    { Fabricate(:user).account }\n\n  permissions :reset_password?, :change_email? do\n    context 'staff?' do\n      context '!record.staff?' do\n        it 'permits' do\n          expect(subject).to permit(admin, john.user)\n        end\n      end\n\n      context 'record.staff?' do\n        it 'denies' do\n          expect(subject).to_not permit(admin, admin.user)\n        end\n      end\n    end\n\n    context '!staff?' do\n      it 'denies' do\n        expect(subject).to_not permit(john, User)\n      end\n    end\n  end\n\n  permissions :disable_2fa? do\n    context 'admin?' do\n      context '!record.staff?' do\n        it 'permits' do\n          expect(subject).to permit(admin, john.user)\n        end\n      end\n\n      context 'record.staff?' do\n        it 'denies' do\n          expect(subject).to_not permit(admin, admin.user)\n        end\n      end\n    end\n\n    context '!admin?' do\n      it 'denies' do\n        expect(subject).to_not permit(john, User)\n      end\n    end\n  end\n\n  permissions :confirm? do\n    context 'staff?' do\n      context '!record.confirmed?' do\n        it 'permits' do\n          john.user.update(confirmed_at: nil)\n          expect(subject).to permit(admin, john.user)\n        end\n      end\n\n      context 'record.confirmed?' do\n        it 'denies' do\n          john.user.confirm!\n          expect(subject).to_not permit(admin, john.user)\n        end\n      end\n    end\n\n    context '!staff?' do\n      it 'denies' do\n        expect(subject).to_not permit(john, User)\n      end\n    end\n  end\n\n  permissions :enable? do\n    context 'staff?' do\n      it 'permits' do\n        expect(subject).to permit(admin, User)\n      end\n    end\n\n    context '!staff?' do\n      it 'denies' do\n        expect(subject).to_not permit(john, User)\n      end\n    end\n  end\n\n  permissions :disable? do\n    context 'staff?' do\n      context '!record.admin?' do\n        it 'permits' do\n          expect(subject).to permit(admin, john.user)\n        end\n      end\n\n      context 'record.admin?' do\n        it 'denies' do\n          expect(subject).to_not permit(admin, admin.user)\n        end\n      end\n    end\n\n    context '!staff?' do\n      it 'denies' do\n        expect(subject).to_not permit(john, User)\n      end\n    end\n  end\n\n  permissions :promote? do\n    context 'admin?' do\n      context 'promoteable?' do\n        it 'permits' do\n          expect(subject).to permit(admin, john.user)\n        end\n      end\n\n      context '!promoteable?' do\n        it 'denies' do\n          expect(subject).to_not permit(admin, admin.user)\n        end\n      end\n    end\n\n    context '!admin?' do\n      it 'denies' do\n        expect(subject).to_not permit(john, User)\n      end\n    end\n  end\n\n  permissions :demote? do\n    context 'admin?' do\n      context '!record.admin?' do\n        context 'demoteable?' do\n          it 'permits' do\n            john.user.update(moderator: true)\n            expect(subject).to permit(admin, john.user)\n          end\n        end\n\n        context '!demoteable?' do\n          it 'denies' do\n            expect(subject).to_not permit(admin, john.user)\n          end\n        end\n      end\n\n      context 'record.admin?' do\n        it 'denies' do\n          expect(subject).to_not permit(admin, admin.user)\n        end\n      end\n    end\n\n    context '!admin?' do\n      it 'denies' do\n        expect(subject).to_not permit(john, User)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/presenters/account_relationships_presenter_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe AccountRelationshipsPresenter do\n  describe '.initialize' do\n    before do\n      allow(Account).to receive(:following_map).with(account_ids, current_account_id).and_return(default_map)\n      allow(Account).to receive(:followed_by_map).with(account_ids, current_account_id).and_return(default_map)\n      allow(Account).to receive(:blocking_map).with(account_ids, current_account_id).and_return(default_map)\n      allow(Account).to receive(:muting_map).with(account_ids, current_account_id).and_return(default_map)\n      allow(Account).to receive(:requested_map).with(account_ids, current_account_id).and_return(default_map)\n      allow(Account).to receive(:domain_blocking_map).with(account_ids, current_account_id).and_return(default_map)\n    end\n\n    let(:presenter)          { AccountRelationshipsPresenter.new(account_ids, current_account_id, options) }\n    let(:current_account_id) { Fabricate(:account).id }\n    let(:account_ids)        { [Fabricate(:account).id] }\n    let(:default_map)        { { 1 => true } }\n\n    context 'options are not set' do\n      let(:options) { {} }\n\n      it 'sets default maps' do\n        expect(presenter.following).to       eq default_map\n        expect(presenter.followed_by).to     eq default_map\n        expect(presenter.blocking).to        eq default_map\n        expect(presenter.muting).to          eq default_map\n        expect(presenter.requested).to       eq default_map\n        expect(presenter.domain_blocking).to eq default_map\n      end\n    end\n\n    context 'options[:following_map] is set' do\n      let(:options) { { following_map: { 2 => true } } }\n\n      it 'sets @following merged with default_map and options[:following_map]' do\n        expect(presenter.following).to eq default_map.merge(options[:following_map])\n      end\n    end\n\n    context 'options[:followed_by_map] is set' do\n      let(:options) { { followed_by_map: { 3 => true } } }\n\n      it 'sets @followed_by merged with default_map and options[:followed_by_map]' do\n        expect(presenter.followed_by).to eq default_map.merge(options[:followed_by_map])\n      end\n    end\n\n    context 'options[:blocking_map] is set' do\n      let(:options) { { blocking_map: { 4 => true } } }\n\n      it 'sets @blocking merged with default_map and options[:blocking_map]' do\n        expect(presenter.blocking).to eq default_map.merge(options[:blocking_map])\n      end\n    end\n\n    context 'options[:muting_map] is set' do\n      let(:options) { { muting_map: { 5 => true } } }\n\n      it 'sets @muting merged with default_map and options[:muting_map]' do\n        expect(presenter.muting).to eq default_map.merge(options[:muting_map])\n      end\n    end\n\n    context 'options[:requested_map] is set' do\n      let(:options) { { requested_map: { 6 => true } } }\n\n      it 'sets @requested merged with default_map and options[:requested_map]' do\n        expect(presenter.requested).to eq default_map.merge(options[:requested_map])\n      end\n    end\n\n    context 'options[:domain_blocking_map] is set' do\n      let(:options) { { domain_blocking_map: { 7 => true } } }\n\n      it 'sets @domain_blocking merged with default_map and options[:domain_blocking_map]' do\n        expect(presenter.domain_blocking).to eq default_map.merge(options[:domain_blocking_map])\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/presenters/instance_presenter_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe InstancePresenter do\n  let(:instance_presenter) { InstancePresenter.new }\n\n  context do\n    around do |example|\n      site_description = Setting.site_description\n      example.run\n      Setting.site_description = site_description\n    end\n\n    it \"delegates site_description to Setting\" do\n      Setting.site_description = \"Site desc\"\n\n      expect(instance_presenter.site_description).to eq \"Site desc\"\n    end\n  end\n\n  context do\n    around do |example|\n      site_extended_description = Setting.site_extended_description\n      example.run\n      Setting.site_extended_description = site_extended_description\n    end\n\n    it \"delegates site_extended_description to Setting\" do\n      Setting.site_extended_description = \"Extended desc\"\n\n      expect(instance_presenter.site_extended_description).to eq \"Extended desc\"\n    end\n  end\n\n  context do\n    around do |example|\n      site_contact_email = Setting.site_contact_email\n      example.run\n      Setting.site_contact_email = site_contact_email\n    end\n\n    it \"delegates contact_email to Setting\" do\n      Setting.site_contact_email = \"admin@example.com\"\n\n      expect(instance_presenter.site_contact_email).to eq \"admin@example.com\"\n    end\n  end\n\n  describe \"contact_account\" do\n    around do |example|\n      site_contact_username = Setting.site_contact_username\n      example.run\n      Setting.site_contact_username = site_contact_username\n    end\n\n    it \"returns the account for the site contact username\" do\n      Setting.site_contact_username = \"aaa\"\n      account = Fabricate(:account, username: \"aaa\")\n\n      expect(instance_presenter.contact_account).to eq(account)\n    end\n  end\n\n  describe \"user_count\" do\n    it \"returns the number of site users\" do\n      Rails.cache.write 'user_count', 123\n\n      expect(instance_presenter.user_count).to eq(123)\n    end\n  end\n\n  describe \"status_count\" do\n    it \"returns the number of local statuses\" do\n      Rails.cache.write 'local_status_count', 234\n\n      expect(instance_presenter.status_count).to eq(234)\n    end\n  end\n\n  describe \"domain_count\" do\n    it \"returns the number of known domains\" do\n      Rails.cache.write 'distinct_domain_count', 345\n\n      expect(instance_presenter.domain_count).to eq(345)\n    end\n  end\n\n  describe '#version_number' do\n    it 'returns Florence::Version' do\n      expect(instance_presenter.version_number).to be(Florence::Version)\n    end\n  end\n\n  describe '#source_url' do\n    it 'returns \"https://github.com/florence-social/mastodon-fork\"' do\n      expect(instance_presenter.source_url).to eq('https://github.com/florence-social/mastodon-fork')\n    end\n  end\n\n  describe '#thumbnail' do\n    it 'returns SiteUpload' do\n      thumbnail = Fabricate(:site_upload, var: 'thumbnail')\n      expect(instance_presenter.thumbnail).to eq(thumbnail)\n    end\n  end\n\n  describe '#hero' do\n    it 'returns SiteUpload' do\n      hero = Fabricate(:site_upload, var: 'hero')\n      expect(instance_presenter.hero).to eq(hero)\n    end\n  end\n\n  describe '#mascot' do\n    it 'returns SiteUpload' do\n      mascot = Fabricate(:site_upload, var: 'mascot')\n      expect(instance_presenter.mascot).to eq(mascot)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/rails_helper.rb",
    "content": "ENV['RAILS_ENV'] ||= 'test'\nrequire File.expand_path('../../config/environment', __FILE__)\n\nabort(\"The Rails environment is running in production mode!\") if Rails.env.production?\n\nrequire 'spec_helper'\nrequire 'rspec/rails'\nrequire 'webmock/rspec'\nrequire 'paperclip/matchers'\nrequire 'capybara/rspec'\n\nDir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }\n\nActiveRecord::Migration.maintain_test_schema!\nWebMock.disable_net_connect!\nRedis.current = Redis::Namespace.new(\"mastodon_test#{ENV['TEST_ENV_NUMBER']}\", redis: Redis.current)\nSidekiq::Testing.inline!\nSidekiq::Logging.logger = nil\n\nDevise::Test::ControllerHelpers.module_eval do\n  alias_method :original_sign_in, :sign_in\n\n  def sign_in(resource, _deprecated = nil, scope: nil)\n    original_sign_in(resource, scope: scope)\n\n    SessionActivation.deactivate warden.cookies.signed['_session_id']\n\n    warden.cookies.signed['_session_id'] = {\n      value: resource.activate_session(warden.request),\n      expires: 1.year.from_now,\n      httponly: true,\n    }\n  end\nend\n\nRSpec.configure do |config|\n  config.fixture_path = \"#{::Rails.root}/spec/fixtures\"\n  config.use_transactional_fixtures = true\n  config.order = 'random'\n  config.infer_spec_type_from_file_location!\n  config.filter_rails_from_backtrace!\n\n  config.include Devise::Test::ControllerHelpers, type: :controller\n  config.include Devise::Test::ControllerHelpers, type: :view\n  config.include Paperclip::Shoulda::Matchers\n  config.include ActiveSupport::Testing::TimeHelpers\n\n  config.before :each, type: :feature do\n    https = ENV['LOCAL_HTTPS'] == 'true'\n    Capybara.app_host = \"http#{https ? 's' : ''}://#{ENV.fetch('LOCAL_DOMAIN')}\"\n  end\n\n  config.before :each, type: :controller do\n    stub_jsonld_contexts!\n  end\n\n  config.before :each, type: :service do\n    stub_jsonld_contexts!\n  end\n\n  config.after :each do\n    Rails.cache.clear\n\n    keys = Redis.current.keys\n    Redis.current.del(keys) if keys.any?\n  end\nend\n\nRSpec::Sidekiq.configure do |config|\n  config.warn_when_jobs_not_processed_by_sidekiq = false\nend\n\ndef request_fixture(name)\n  File.read(Rails.root.join('spec', 'fixtures', 'requests', name))\nend\n\ndef attachment_fixture(name)\n  File.open(Rails.root.join('spec', 'fixtures', 'files', name))\nend\n\ndef stub_jsonld_contexts!\n  stub_request(:get, 'https://www.w3.org/ns/activitystreams').to_return(request_fixture('json-ld.activitystreams.txt'))\n  stub_request(:get, 'https://w3id.org/identity/v1').to_return(request_fixture('json-ld.identity.txt'))\n  stub_request(:get, 'https://w3id.org/security/v1').to_return(request_fixture('json-ld.security.txt'))\nend\n"
  },
  {
    "path": "spec/requests/account_show_page_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe 'The account show page' do\n  it 'Has an h-feed with correct number of h-entry objects in it' do\n    alice = Fabricate(:account, username: 'alice', display_name: 'Alice')\n    _status = Fabricate(:status, account: alice, text: 'Hello World')\n    _status2 = Fabricate(:status, account: alice, text: 'Hello World Again')\n    _status3 = Fabricate(:status, account: alice, text: 'Are You Still There World?')\n\n    get '/@alice'\n\n    expect(h_feed_entries.size).to eq(3)\n  end\n\n  it 'has valid opengraph tags' do\n    alice = Fabricate(:account, username: 'alice', display_name: 'Alice')\n    _status = Fabricate(:status, account: alice, text: 'Hello World')\n\n    get '/@alice'\n\n    expect(head_meta_content('og:title')).to match alice.display_name\n    expect(head_meta_content('og:type')).to eq 'profile'\n    expect(head_meta_content('og:image')).to match '.+'\n    expect(head_meta_content('og:url')).to match 'http://.+'\n  end\n\n  def head_meta_content(property)\n    head_section.meta(\"[@property='#{property}']\")[:content]\n  end\n\n  def head_section\n    Nokogiri::Slop(response.body).html.head\n  end\n\n  def h_feed_entries\n    Nokogiri::HTML(response.body).search('.h-feed .h-entry')\n  end\nend\n"
  },
  {
    "path": "spec/requests/catch_all_route_request_spec.rb",
    "content": "require \"rails_helper\"\n\ndescribe \"The catch all route\" do\n  describe \"with a simple value\" do\n    it \"returns a 404 page as html\" do\n      get \"/test\"\n\n      expect(response.status).to eq 404\n      expect(response.content_type).to eq \"text/html\"\n    end\n  end\n\n  describe \"with an implied format\" do\n    it \"returns a 404 page as html\" do\n      get \"/test.test\"\n\n      expect(response.status).to eq 404\n      expect(response.content_type).to eq \"text/html\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/requests/host_meta_request_spec.rb",
    "content": "require \"rails_helper\"\n\ndescribe \"The host_meta route\" do\n  describe \"requested without accepts headers\" do\n    it \"returns an xml response\" do\n      get host_meta_url\n\n      expect(response).to have_http_status(200)\n      expect(response.content_type).to eq \"application/xrd+xml\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/requests/link_headers_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe 'Link headers' do\n  describe 'on the account show page' do\n    let(:account) { Fabricate(:account, username: 'test') }\n\n    before do\n      get short_account_path(username: account)\n    end\n\n    it 'contains webfinger url in link header' do\n      link_header = link_header_with_type('application/xrd+xml')\n\n      expect(link_header.href).to match 'http://www.example.com/.well-known/webfinger?resource=acct%3Atest%40cb6e6126.ngrok.io'\n      expect(link_header.attr_pairs.first).to eq %w(rel lrdd)\n    end\n\n    it 'contains atom url in link header' do\n      link_header = link_header_with_type('application/atom+xml')\n\n      expect(link_header.href).to eq 'http://www.example.com/users/test.atom'\n      expect(link_header.attr_pairs.first).to eq %w(rel alternate)\n    end\n\n    def link_header_with_type(type)\n      response.headers['Link'].links.find do |link|\n        link.attr_pairs.any? { |pair| pair == ['type', type] }\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/requests/localization_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe 'Localization' do\n  after(:all) do\n    I18n.locale = I18n.default_locale\n  end\n\n  it 'uses a specific region when provided' do\n    headers = { 'Accept-Language' => 'zh-HK' }\n\n    get \"/about\", headers: headers\n\n    expect(response.body).to include(\n      I18n.t('about.tagline', locale: 'zh-HK')\n    )\n  end\n\n  it 'falls back to a locale when region missing' do\n    headers = { 'Accept-Language' => 'es-FAKE' }\n\n    get \"/about\", headers: headers\n\n    expect(response.body).to include(\n      I18n.t('about.tagline', locale: 'es')\n    )\n  end\n  it 'falls back to english when locale is missing' do\n    headers = { 'Accept-Language' => '12-FAKE' }\n\n    get \"/about\", headers: headers\n\n    expect(response.body).to include(\n      I18n.t('about.tagline', locale: 'en')\n    )\n  end\nend\n"
  },
  {
    "path": "spec/requests/webfinger_request_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe 'The webfinger route' do\n  let(:alice) { Fabricate(:account, username: 'alice') }\n\n  describe 'requested with standard accepts headers' do\n    it 'returns a json response' do\n      get webfinger_url(resource: alice.to_webfinger_s)\n\n      expect(response).to have_http_status(200)\n      expect(response.content_type).to eq 'application/jrd+json'\n    end\n  end\n\n  describe 'asking for xml format' do\n    it 'returns an xml response for xml format' do\n      get webfinger_url(resource: alice.to_webfinger_s, format: :xml)\n\n      expect(response).to have_http_status(200)\n      expect(response.content_type).to eq 'application/xrd+xml'\n    end\n\n    it 'returns an xml response for xml accept header' do\n      headers = { 'HTTP_ACCEPT' => 'application/xrd+xml' }\n      get webfinger_url(resource: alice.to_webfinger_s), headers: headers\n\n      expect(response).to have_http_status(200)\n      expect(response.content_type).to eq 'application/xrd+xml'\n    end\n  end\n\n  describe 'asking for json format' do\n    it 'returns a json response for json format' do\n      get webfinger_url(resource: alice.to_webfinger_s, format: :json)\n\n      expect(response).to have_http_status(200)\n      expect(response.content_type).to eq 'application/jrd+json'\n    end\n\n    it 'returns a json response for json accept header' do\n      headers = { 'HTTP_ACCEPT' => 'application/jrd+json' }\n      get webfinger_url(resource: alice.to_webfinger_s), headers: headers\n\n      expect(response).to have_http_status(200)\n      expect(response.content_type).to eq 'application/jrd+json'\n    end\n  end\nend\n"
  },
  {
    "path": "spec/routing/accounts_routing_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe 'Routes under accounts/' do\n  describe 'the route for accounts who are followers of an account' do\n    it 'routes to the followers action with the right username' do\n      expect(get('/users/name/followers')).\n        to route_to('follower_accounts#index', account_username: 'name')\n    end\n  end\n\n  describe 'the route for accounts who are followed by an account' do\n    it 'routes to the following action with the right username' do\n      expect(get('/users/name/following')).\n        to route_to('following_accounts#index', account_username: 'name')\n    end\n  end\n\n  describe 'the route for following an account' do\n    it 'routes to the follow create action with the right username' do\n      expect(post('/users/name/follow')).\n        to route_to('account_follow#create', account_username: 'name')\n    end\n  end\n\n  describe 'the route for unfollowing an account' do\n    it 'routes to the unfollow create action with the right username' do\n      expect(post('/users/name/unfollow')).\n        to route_to('account_unfollow#create', account_username: 'name')\n    end\n  end\nend\n"
  },
  {
    "path": "spec/routing/api_routing_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe 'API routes' do\n  describe 'Credentials routes' do\n    it 'routes to verify credentials' do\n      expect(get('/api/v1/accounts/verify_credentials')).\n        to route_to('api/v1/accounts/credentials#show')\n    end\n\n    it 'routes to update credentials' do\n      expect(patch('/api/v1/accounts/update_credentials')).\n        to route_to('api/v1/accounts/credentials#update')\n    end\n  end\n\n  describe 'Account routes' do\n    it 'routes to statuses' do\n      expect(get('/api/v1/accounts/user/statuses')).\n        to route_to('api/v1/accounts/statuses#index', account_id: 'user')\n    end\n\n    it 'routes to followers' do\n      expect(get('/api/v1/accounts/user/followers')).\n        to route_to('api/v1/accounts/follower_accounts#index', account_id: 'user')\n    end\n\n    it 'routes to following' do\n      expect(get('/api/v1/accounts/user/following')).\n        to route_to('api/v1/accounts/following_accounts#index', account_id: 'user')\n    end\n\n    it 'routes to search' do\n      expect(get('/api/v1/accounts/search')).\n        to route_to('api/v1/accounts/search#show')\n    end\n\n    it 'routes to relationships' do\n      expect(get('/api/v1/accounts/relationships')).\n        to route_to('api/v1/accounts/relationships#index')\n    end\n  end\n\n  describe 'Statuses routes' do\n    it 'routes reblogged_by' do\n      expect(get('/api/v1/statuses/123/reblogged_by')).\n        to route_to('api/v1/statuses/reblogged_by_accounts#index', status_id: '123')\n    end\n\n    it 'routes favourited_by' do\n      expect(get('/api/v1/statuses/123/favourited_by')).\n        to route_to('api/v1/statuses/favourited_by_accounts#index', status_id: '123')\n    end\n\n    it 'routes reblog' do\n      expect(post('/api/v1/statuses/123/reblog')).\n        to route_to('api/v1/statuses/reblogs#create', status_id: '123')\n    end\n\n    it 'routes unreblog' do\n      expect(post('/api/v1/statuses/123/unreblog')).\n        to route_to('api/v1/statuses/reblogs#destroy', status_id: '123')\n    end\n\n    it 'routes favourite' do\n      expect(post('/api/v1/statuses/123/favourite')).\n        to route_to('api/v1/statuses/favourites#create', status_id: '123')\n    end\n\n    it 'routes unfavourite' do\n      expect(post('/api/v1/statuses/123/unfavourite')).\n        to route_to('api/v1/statuses/favourites#destroy', status_id: '123')\n    end\n\n    it 'routes mute' do\n      expect(post('/api/v1/statuses/123/mute')).\n        to route_to('api/v1/statuses/mutes#create', status_id: '123')\n    end\n\n    it 'routes unmute' do\n      expect(post('/api/v1/statuses/123/unmute')).\n        to route_to('api/v1/statuses/mutes#destroy', status_id: '123')\n    end\n  end\n\n  describe 'Timeline routes' do\n    it 'routes to home timeline' do\n      expect(get('/api/v1/timelines/home')).\n        to route_to('api/v1/timelines/home#show')\n    end\n\n    it 'routes to public timeline' do\n      expect(get('/api/v1/timelines/public')).\n        to route_to('api/v1/timelines/public#show')\n    end\n\n    it 'routes to tag timeline' do\n      expect(get('/api/v1/timelines/tag/test')).\n        to route_to('api/v1/timelines/tag#show', id: 'test')\n    end\n  end\nend\n"
  },
  {
    "path": "spec/routing/well_known_routes_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe 'the host-meta route' do\n  it 'routes to correct place with xml format' do\n    expect(get('/.well-known/host-meta')).\n      to route_to('well_known/host_meta#show', format: 'xml')\n  end\nend\n\ndescribe 'the webfinger route' do\n  it 'routes to correct place with json format' do\n    expect(get('/.well-known/webfinger')).\n      to route_to('well_known/webfinger#show')\n  end\nend\n"
  },
  {
    "path": "spec/serializers/activitypub/note_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe ActivityPub::NoteSerializer do\n  let!(:account) { Fabricate(:account) }\n  let!(:other)   { Fabricate(:account) }\n  let!(:parent)  { Fabricate(:status, account: account, visibility: :public) }\n  let!(:reply1)  { Fabricate(:status, account: account, thread: parent, visibility: :public) }\n  let!(:reply2)  { Fabricate(:status, account: account, thread: parent, visibility: :public) }\n  let!(:reply3)  { Fabricate(:status, account: other, thread: parent, visibility: :public) }\n  let!(:reply4)  { Fabricate(:status, account: account, thread: parent, visibility: :public) }\n  let!(:reply5)  { Fabricate(:status, account: account, thread: parent, visibility: :direct) }\n\n  before(:each) do\n    @serialization = ActiveModelSerializers::SerializableResource.new(parent, serializer: ActivityPub::NoteSerializer, adapter: ActivityPub::Adapter)\n  end\n\n  subject { JSON.parse(@serialization.to_json) }\n\n  it 'has a Note type' do\n    expect(subject['type']).to eql('Note')\n  end\n\n  it 'has a replies collection' do\n    expect(subject['replies']['type']).to eql('Collection')\n  end\n\n  it 'has a replies collection with a first Page' do\n    expect(subject['replies']['first']['type']).to eql('CollectionPage')\n  end\n\n  it 'includes public self-replies in its replies collection' do\n    expect(subject['replies']['first']['items']).to include(reply1.uri, reply2.uri, reply4.uri)\n  end\n\n  it 'does not include replies from others in its replies collection' do\n    expect(subject['replies']['first']['items']).to_not include(reply3.uri)\n  end\n\n  it 'does not include replies with direct visibility in its replies collection' do\n    expect(subject['replies']['first']['items']).to_not include(reply5.uri)\n  end\nend\n"
  },
  {
    "path": "spec/services/account_search_service_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe AccountSearchService, type: :service do\n  describe '.call' do\n    describe 'with a query to ignore' do\n      it 'returns empty array for missing query' do\n        results = subject.call('', nil, limit: 10)\n\n        expect(results).to eq []\n      end\n      it 'returns empty array for hashtag query' do\n        results = subject.call('#tag', nil, limit: 10)\n\n        expect(results).to eq []\n      end\n      it 'returns empty array for limit zero' do\n        Fabricate(:account, username: 'match')\n        results = subject.call('match', nil, limit: 0)\n\n        expect(results).to eq []\n      end\n    end\n\n    describe 'searching for a simple term that is not an exact match' do\n      it 'does not return a nil entry in the array for the exact match' do\n        match = Fabricate(:account, username: 'matchingusername')\n\n        results = subject.call('match', nil, limit: 5)\n        expect(results).to eq [match]\n      end\n    end\n\n    describe 'searching local and remote users' do\n      describe \"when only '@'\" do\n        before do\n          allow(Account).to receive(:find_local)\n          allow(Account).to receive(:search_for)\n          subject.call('@', nil, limit: 10)\n        end\n\n        it 'uses find_local with empty query to look for local accounts' do\n          expect(Account).to have_received(:find_local).with('')\n        end\n      end\n\n      describe 'when no domain' do\n        before do\n          allow(Account).to receive(:find_local)\n          allow(Account).to receive(:search_for)\n          subject.call('one', nil, limit: 10)\n        end\n\n        it 'uses find_local to look for local accounts' do\n          expect(Account).to have_received(:find_local).with('one')\n        end\n\n        it 'uses search_for to find matches' do\n          expect(Account).to have_received(:search_for).with('one', 10, 0)\n        end\n      end\n\n      describe 'when there is a domain' do\n        before do\n          allow(Account).to receive(:find_remote)\n        end\n\n        it 'uses find_remote to look for remote accounts' do\n          subject.call('two@example.com', nil, limit: 10)\n          expect(Account).to have_received(:find_remote).with('two', 'example.com')\n        end\n\n        describe 'and there is no account provided' do\n          it 'uses search_for to find matches' do\n            allow(Account).to receive(:search_for)\n            subject.call('two@example.com', nil, limit: 10, resolve: false)\n\n            expect(Account).to have_received(:search_for).with('two example.com', 10, 0)\n          end\n        end\n\n        describe 'and there is an account provided' do\n          it 'uses advanced_search_for to find matches' do\n            account = Fabricate(:account)\n            allow(Account).to receive(:advanced_search_for)\n            subject.call('two@example.com', account, limit: 10, resolve: false)\n\n            expect(Account).to have_received(:advanced_search_for).with('two example.com', account, 10, nil, 0)\n          end\n        end\n      end\n    end\n\n    describe 'with an exact match' do\n      it 'returns exact match first, and does not return duplicates' do\n        partial = Fabricate(:account, username: 'exactness')\n        exact = Fabricate(:account, username: 'exact')\n\n        results = subject.call('exact', nil, limit: 10)\n        expect(results.size).to eq 2\n        expect(results).to eq [exact, partial]\n      end\n    end\n\n    describe 'when there is a local domain' do\n      around do |example|\n        before = Rails.configuration.x.local_domain\n        example.run\n        Rails.configuration.x.local_domain = before\n      end\n\n      it 'returns exact match first' do\n        remote     = Fabricate(:account, username: 'a', domain: 'remote', display_name: 'e')\n        remote_too = Fabricate(:account, username: 'b', domain: 'remote', display_name: 'e')\n        exact = Fabricate(:account, username: 'e')\n        Rails.configuration.x.local_domain = 'example.com'\n\n        results = subject.call('e@example.com', nil, limit: 2)\n        expect(results.size).to eq 2\n        expect(results).to eq([exact, remote]).or eq([exact, remote_too])\n      end\n    end\n\n    describe 'when there is a domain but no exact match' do\n      it 'follows the remote account when resolve is true' do\n        service = double(call: nil)\n        allow(ResolveAccountService).to receive(:new).and_return(service)\n\n        results = subject.call('newuser@remote.com', nil, limit: 10, resolve: true)\n        expect(service).to have_received(:call).with('newuser@remote.com')\n      end\n\n      it 'does not follow the remote account when resolve is false' do\n        service = double(call: nil)\n        allow(ResolveAccountService).to receive(:new).and_return(service)\n\n        results = subject.call('newuser@remote.com', nil, limit: 10, resolve: false)\n        expect(service).not_to have_received(:call)\n      end\n    end\n\n    describe 'should not include suspended accounts' do\n      it 'returns the fuzzy match first, and does not return suspended exacts' do\n        partial = Fabricate(:account, username: 'exactness')\n        exact = Fabricate(:account, username: 'exact', suspended: true)\n\n        results = subject.call('exact', nil, limit: 10)\n        expect(results.size).to eq 1\n        expect(results).to eq [partial]\n      end\n\n      it \"does not return suspended remote accounts\" do\n        remote = Fabricate(:account, username: 'a', domain: 'remote', display_name: 'e', suspended: true)\n\n        results = subject.call('a@example.com', nil, limit: 2)\n        expect(results.size).to eq 0\n        expect(results).to eq []\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/services/activitypub/fetch_remote_account_service_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe ActivityPub::FetchRemoteAccountService, type: :service do\n  subject { ActivityPub::FetchRemoteAccountService.new }\n\n  let!(:actor) do\n    {\n      '@context': 'https://www.w3.org/ns/activitystreams',\n      id: 'https://example.com/alice',\n      type: 'Person',\n      preferredUsername: 'alice',\n      name: 'Alice',\n      summary: 'Foo bar',\n      inbox: 'http://example.com/alice/inbox',\n    }\n  end\n\n  describe '#call' do\n    let(:account) { subject.call('https://example.com/alice', id: true) }\n\n    shared_examples 'sets profile data' do\n      it 'returns an account' do\n        expect(account).to be_an Account\n      end\n\n      it 'sets display name' do\n        expect(account.display_name).to eq 'Alice'\n      end\n\n      it 'sets note' do\n        expect(account.note).to eq 'Foo bar'\n      end\n\n      it 'sets URL' do\n        expect(account.url).to eq 'https://example.com/alice'\n      end\n    end\n\n    context 'when the account does not have a inbox' do\n      let!(:webfinger) { { subject: 'acct:alice@example.com', links: [{ rel: 'self', href: 'https://example.com/alice' }] } }\n\n      before do\n        actor[:inbox] = nil\n\n        stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor))\n        stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })\n      end\n\n      it 'fetches resource' do\n        account\n        expect(a_request(:get, 'https://example.com/alice')).to have_been_made.once\n      end\n\n      it 'looks up webfinger' do\n        account\n        expect(a_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com')).to have_been_made.once\n      end\n\n      it 'returns nil' do\n        expect(account).to be_nil\n      end\n    end\n\n    context 'when URI and WebFinger share the same host' do\n      let!(:webfinger) { { subject: 'acct:alice@example.com', links: [{ rel: 'self', href: 'https://example.com/alice' }] } }\n\n      before do\n        stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor))\n        stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })\n      end\n\n      it 'fetches resource' do\n        account\n        expect(a_request(:get, 'https://example.com/alice')).to have_been_made.once\n      end\n\n      it 'looks up webfinger' do\n        account\n        expect(a_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com')).to have_been_made.once\n      end\n\n      it 'sets username and domain from webfinger' do\n        expect(account.username).to eq 'alice'\n        expect(account.domain).to eq 'example.com'\n      end\n\n      include_examples 'sets profile data'\n    end\n\n    context 'when WebFinger presents different domain than URI' do\n      let!(:webfinger) { { subject: 'acct:alice@iscool.af', links: [{ rel: 'self', href: 'https://example.com/alice' }] } }\n\n      before do\n        stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor))\n        stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })\n        stub_request(:get, 'https://iscool.af/.well-known/webfinger?resource=acct:alice@iscool.af').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })\n      end\n\n      it 'fetches resource' do\n        account\n        expect(a_request(:get, 'https://example.com/alice')).to have_been_made.once\n      end\n\n      it 'looks up webfinger' do\n        account\n        expect(a_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com')).to have_been_made.once\n      end\n\n      it 'looks up \"redirected\" webfinger' do\n        account\n        expect(a_request(:get, 'https://iscool.af/.well-known/webfinger?resource=acct:alice@iscool.af')).to have_been_made.once\n      end\n\n      it 'sets username and domain from final webfinger' do\n        expect(account.username).to eq 'alice'\n        expect(account.domain).to eq 'iscool.af'\n      end\n\n      include_examples 'sets profile data'\n    end\n\n    context 'with wrong id' do\n      it 'does not create account' do\n        expect(subject.call('https://fake.address/@foo', prefetched_body: Oj.dump(actor))).to be_nil\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/services/activitypub/fetch_remote_status_service_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe ActivityPub::FetchRemoteStatusService, type: :service do\n  include ActionView::Helpers::TextHelper\n\n  let(:sender) { Fabricate(:account) }\n  let(:recipient) { Fabricate(:account) }\n  let(:valid_domain) { Rails.configuration.x.local_domain }\n\n  let(:note) do\n    {\n      '@context': 'https://www.w3.org/ns/activitystreams',\n      id: \"https://#{valid_domain}/@foo/1234\",\n      type: 'Note',\n      content: 'Lorem ipsum',\n      attributedTo: ActivityPub::TagManager.instance.uri_for(sender),\n    }\n  end\n\n  subject { described_class.new }\n\n  describe '#call' do\n    before do\n      sender.update(uri: ActivityPub::TagManager.instance.uri_for(sender))\n\n      stub_request(:head, 'https://example.com/watch?v=12345').to_return(status: 404, body: '')\n      subject.call(object[:id], prefetched_body: Oj.dump(object))\n    end\n\n    context 'with Note object' do\n      let(:object) { note }\n\n      it 'creates status' do\n        status = sender.statuses.first\n\n        expect(status).to_not be_nil\n        expect(status.text).to eq 'Lorem ipsum'\n      end\n    end\n\n    context 'with Video object' do\n      let(:object) do\n        {\n          '@context': 'https://www.w3.org/ns/activitystreams',\n          id: \"https://#{valid_domain}/@foo/1234\",\n          type: 'Video',\n          name: 'Nyan Cat 10 hours remix',\n          attributedTo: ActivityPub::TagManager.instance.uri_for(sender),\n          url: [\n            {\n              type: 'Link',\n              mimeType: 'application/x-bittorrent',\n              href: \"https://#{valid_domain}/12345.torrent\",\n            },\n\n            {\n              type: 'Link',\n              mimeType: 'text/html',\n              href: \"https://#{valid_domain}/watch?v=12345\",\n            },\n          ],\n        }\n      end\n\n      it 'creates status' do\n        status = sender.statuses.first\n\n        expect(status).to_not be_nil\n        expect(status.url).to eq \"https://#{valid_domain}/watch?v=12345\"\n        expect(strip_tags(status.text)).to eq \"Nyan Cat 10 hours remix https://#{valid_domain}/watch?v=12345\"\n      end\n    end\n\n    context 'with wrong id' do\n      let(:note) do\n        {\n          '@context': 'https://www.w3.org/ns/activitystreams',\n          id: \"https://real.address/@foo/1234\",\n          type: 'Note',\n          content: 'Lorem ipsum',\n          attributedTo: ActivityPub::TagManager.instance.uri_for(sender),\n        }\n      end\n\n      let(:object) do\n        temp = note.dup\n        temp[:id] = 'https://fake.address/@foo/5678'\n        temp\n      end\n\n      it 'does not create status' do\n        expect(sender.statuses.first).to be_nil\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/services/activitypub/fetch_replies_service_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe ActivityPub::FetchRepliesService, type: :service do\n  let(:actor)          { Fabricate(:account, domain: 'example.com', uri: 'http://example.com/account') }\n  let(:status)         { Fabricate(:status, account: actor) }\n  let(:collection_uri) { 'http://example.com/replies/1' }\n\n  let(:items) do\n    [\n      'http://example.com/self-reply-1',\n      'http://example.com/self-reply-2',\n      'http://example.com/self-reply-3',\n      'http://other.com/other-reply-1',\n      'http://other.com/other-reply-2',\n      'http://other.com/other-reply-3',\n      'http://example.com/self-reply-4',\n      'http://example.com/self-reply-5',\n      'http://example.com/self-reply-6',\n    ]\n  end\n\n  let(:payload) do\n    {\n      '@context': 'https://www.w3.org/ns/activitystreams',\n      type: 'Collection',\n      id: collection_uri,\n      items: items,\n    }.with_indifferent_access\n  end\n\n  subject { described_class.new }\n\n  describe '#call' do\n    context 'when the payload is a Collection with inlined replies' do\n      context 'when passing the collection itself' do\n        it 'spawns workers for up to 5 replies on the same server' do\n          allow(FetchReplyWorker).to receive(:push_bulk)\n          subject.call(status, payload)\n          expect(FetchReplyWorker).to have_received(:push_bulk).with(['http://example.com/self-reply-1', 'http://example.com/self-reply-2', 'http://example.com/self-reply-3', 'http://example.com/self-reply-4', 'http://example.com/self-reply-5'])\n        end\n      end\n\n      context 'when passing the URL to the collection' do\n        before do\n          stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload))\n        end\n\n        it 'spawns workers for up to 5 replies on the same server' do\n          allow(FetchReplyWorker).to receive(:push_bulk)\n          subject.call(status, collection_uri)\n          expect(FetchReplyWorker).to have_received(:push_bulk).with(['http://example.com/self-reply-1', 'http://example.com/self-reply-2', 'http://example.com/self-reply-3', 'http://example.com/self-reply-4', 'http://example.com/self-reply-5'])\n        end\n      end\n    end\n\n    context 'when the payload is an OrderedCollection with inlined replies' do\n      let(:payload) do\n        {\n          '@context': 'https://www.w3.org/ns/activitystreams',\n          type: 'OrderedCollection',\n          id: collection_uri,\n          orderedItems: items,\n        }.with_indifferent_access\n      end\n\n      context 'when passing the collection itself' do\n        it 'spawns workers for up to 5 replies on the same server' do\n          allow(FetchReplyWorker).to receive(:push_bulk)\n          subject.call(status, payload)\n          expect(FetchReplyWorker).to have_received(:push_bulk).with(['http://example.com/self-reply-1', 'http://example.com/self-reply-2', 'http://example.com/self-reply-3', 'http://example.com/self-reply-4', 'http://example.com/self-reply-5'])\n        end\n      end\n\n      context 'when passing the URL to the collection' do\n        before do\n          stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload))\n        end\n\n        it 'spawns workers for up to 5 replies on the same server' do\n          allow(FetchReplyWorker).to receive(:push_bulk)\n          subject.call(status, collection_uri)\n          expect(FetchReplyWorker).to have_received(:push_bulk).with(['http://example.com/self-reply-1', 'http://example.com/self-reply-2', 'http://example.com/self-reply-3', 'http://example.com/self-reply-4', 'http://example.com/self-reply-5'])\n        end\n      end\n    end\n\n    context 'when the payload is a paginated Collection with inlined replies' do\n      let(:payload) do\n        {\n          '@context': 'https://www.w3.org/ns/activitystreams',\n          type: 'Collection',\n          id: collection_uri,\n          first: {\n            type: 'CollectionPage',\n            partOf: collection_uri,\n            items: items,\n          }\n        }.with_indifferent_access\n      end\n\n      context 'when passing the collection itself' do\n        it 'spawns workers for up to 5 replies on the same server' do\n          allow(FetchReplyWorker).to receive(:push_bulk)\n          subject.call(status, payload)\n          expect(FetchReplyWorker).to have_received(:push_bulk).with(['http://example.com/self-reply-1', 'http://example.com/self-reply-2', 'http://example.com/self-reply-3', 'http://example.com/self-reply-4', 'http://example.com/self-reply-5'])\n        end\n      end\n\n      context 'when passing the URL to the collection' do\n        before do\n          stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload))\n        end\n\n        it 'spawns workers for up to 5 replies on the same server' do\n          allow(FetchReplyWorker).to receive(:push_bulk)\n          subject.call(status, collection_uri)\n          expect(FetchReplyWorker).to have_received(:push_bulk).with(['http://example.com/self-reply-1', 'http://example.com/self-reply-2', 'http://example.com/self-reply-3', 'http://example.com/self-reply-4', 'http://example.com/self-reply-5'])\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/services/activitypub/process_account_service_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe ActivityPub::ProcessAccountService, type: :service do\n  subject { described_class.new }\n\n  context 'property values' do\n    let(:payload) do\n      {\n        id: 'https://foo.test',\n        type: 'Actor',\n        inbox: 'https://foo.test/inbox',\n        attachment: [\n          { type: 'PropertyValue', name: 'Pronouns', value: 'They/them' },\n          { type: 'PropertyValue', name: 'Occupation', value: 'Unit test' },\n        ],\n      }.with_indifferent_access\n    end\n\n    it 'parses out of attachment' do\n      account = subject.call('alice', 'example.com', payload)\n      expect(account.fields).to be_a Array\n      expect(account.fields.size).to eq 2\n      expect(account.fields[0]).to be_a Account::Field\n      expect(account.fields[0].name).to eq 'Pronouns'\n      expect(account.fields[0].value).to eq 'They/them'\n      expect(account.fields[1]).to be_a Account::Field\n      expect(account.fields[1].name).to eq 'Occupation'\n      expect(account.fields[1].value).to eq 'Unit test'\n    end\n  end\n\n  context 'identity proofs' do\n    let(:payload) do\n      {\n        id: 'https://foo.test',\n        type: 'Actor',\n        inbox: 'https://foo.test/inbox',\n        attachment: [\n          { type: 'IdentityProof', name: 'Alice', signatureAlgorithm: 'keybase', signatureValue: 'a' * 66 },\n        ],\n      }.with_indifferent_access\n    end\n\n    it 'parses out of attachment' do\n      allow(ProofProvider::Keybase::Worker).to receive(:perform_async)\n\n      account = subject.call('alice', 'example.com', payload)\n\n      expect(account.identity_proofs.count).to eq 1\n\n      proof = account.identity_proofs.first\n\n      expect(proof.provider).to eq 'keybase'\n      expect(proof.provider_username).to eq 'Alice'\n      expect(proof.token).to eq 'a' * 66\n    end\n\n    it 'removes no longer present proofs' do\n      allow(ProofProvider::Keybase::Worker).to receive(:perform_async)\n\n      account   = Fabricate(:account, username: 'alice', domain: 'example.com')\n      old_proof = Fabricate(:account_identity_proof, account: account, provider: 'keybase', provider_username: 'Bob', token: 'b' * 66)\n\n      subject.call('alice', 'example.com', payload)\n\n      expect(account.identity_proofs.count).to eq 1\n      expect(account.identity_proofs.find_by(id: old_proof.id)).to be_nil\n    end\n\n    it 'queues a validity check on the proof' do\n      allow(ProofProvider::Keybase::Worker).to receive(:perform_async)\n      account = subject.call('alice', 'example.com', payload)\n      expect(ProofProvider::Keybase::Worker).to have_received(:perform_async)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/services/activitypub/process_collection_service_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe ActivityPub::ProcessCollectionService, type: :service do\n  let(:actor) { Fabricate(:account, domain: 'example.com', uri: 'http://example.com/account') }\n\n  let(:payload) do\n    {\n      '@context': 'https://www.w3.org/ns/activitystreams',\n      id: 'foo',\n      type: 'Create',\n      actor: ActivityPub::TagManager.instance.uri_for(actor),\n      object: {\n        id: 'bar',\n        type: 'Note',\n        content: 'Lorem ipsum',\n      },\n    }\n  end\n\n  let(:json) { Oj.dump(payload) }\n\n  subject { described_class.new }\n\n  describe '#call' do\n    context 'when actor is the sender'\n    context 'when actor differs from sender' do\n      let(:forwarder) { Fabricate(:account, domain: 'example.com', uri: 'http://example.com/other_account') }\n\n      it 'does not process payload if no signature exists' do\n        expect_any_instance_of(ActivityPub::LinkedDataSignature).to receive(:verify_account!).and_return(nil)\n        expect(ActivityPub::Activity).not_to receive(:factory)\n\n        subject.call(json, forwarder)\n      end\n\n      it 'processes payload with actor if valid signature exists' do\n        payload['signature'] = { 'type' => 'RsaSignature2017' }\n\n        expect_any_instance_of(ActivityPub::LinkedDataSignature).to receive(:verify_account!).and_return(actor)\n        expect(ActivityPub::Activity).to receive(:factory).with(instance_of(Hash), actor, instance_of(Hash))\n\n        subject.call(json, forwarder)\n      end\n\n      it 'does not process payload if invalid signature exists' do\n        payload['signature'] = { 'type' => 'RsaSignature2017' }\n\n        expect_any_instance_of(ActivityPub::LinkedDataSignature).to receive(:verify_account!).and_return(nil)\n        expect(ActivityPub::Activity).not_to receive(:factory)\n\n        subject.call(json, forwarder)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/services/after_block_domain_from_account_service_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe AfterBlockDomainFromAccountService, type: :service do\n  let!(:wolf) { Fabricate(:account, username: 'wolf', domain: 'evil.org', inbox_url: 'https://evil.org/inbox', protocol: :activitypub) }\n  let!(:alice) { Fabricate(:account, username: 'alice') }\n\n  subject { AfterBlockDomainFromAccountService.new }\n\n  before do\n    stub_jsonld_contexts!\n    allow(ActivityPub::DeliveryWorker).to receive(:perform_async)\n  end\n\n  it 'purge followers from blocked domain' do\n    wolf.follow!(alice)\n    subject.call(alice, 'evil.org')\n    expect(wolf.following?(alice)).to be false\n  end\n\n  it 'sends Reject->Follow to followers from blocked domain' do\n    wolf.follow!(alice)\n    subject.call(alice, 'evil.org')\n    expect(ActivityPub::DeliveryWorker).to have_received(:perform_async).once\n  end\nend\n"
  },
  {
    "path": "spec/services/after_block_service_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe AfterBlockService, type: :service do\n  subject do\n    -> { described_class.new.call(account, target_account) }\n  end\n\n  let(:account) { Fabricate(:account) }\n  let(:target_account) { Fabricate(:account) }\n\n  describe 'home timeline' do\n    let(:status) { Fabricate(:status, account: target_account) }\n    let(:other_account_status) { Fabricate(:status) }\n    let(:home_timeline_key) { FeedManager.instance.key(:home, account.id) }\n\n    before do\n      Redis.current.del(home_timeline_key)\n    end\n\n    it \"clears account's statuses\" do\n      FeedManager.instance.push_to_home(account, status)\n      FeedManager.instance.push_to_home(account, other_account_status)\n\n      is_expected.to change {\n        Redis.current.zrange(home_timeline_key, 0, -1)\n      }.from([status.id.to_s, other_account_status.id.to_s]).to([other_account_status.id.to_s])\n    end\n  end\nend\n"
  },
  {
    "path": "spec/services/app_sign_up_service_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe AppSignUpService, type: :service do\n  let(:app) { Fabricate(:application, scopes: 'read write') }\n  let(:good_params) { { username: 'alice', password: '12345678', email: 'good@email.com', agreement: true } }\n\n  subject { described_class.new }\n\n  describe '#call' do\n    it 'returns nil when registrations are closed' do\n      tmp = Setting.registrations_mode\n      Setting.registrations_mode = 'none'\n      expect(subject.call(app, good_params)).to be_nil\n      Setting.registrations_mode = tmp\n    end\n\n    it 'raises an error when params are missing' do\n      expect { subject.call(app, {}) }.to raise_error ActiveRecord::RecordInvalid\n    end\n\n    it 'creates an unconfirmed user with access token' do\n      access_token = subject.call(app, good_params)\n      expect(access_token).to_not be_nil\n      user = User.find_by(id: access_token.resource_owner_id)\n      expect(user).to_not be_nil\n      expect(user.confirmed?).to be false\n    end\n\n    it 'creates access token with the app\\'s scopes' do\n      access_token = subject.call(app, good_params)\n      expect(access_token).to_not be_nil\n      expect(access_token.scopes.to_s).to eq 'read write'\n    end\n\n    it 'creates an account' do\n      access_token = subject.call(app, good_params)\n      expect(access_token).to_not be_nil\n      user = User.find_by(id: access_token.resource_owner_id)\n      expect(user).to_not be_nil\n      expect(user.account).to_not be_nil\n    end\n  end\nend\n"
  },
  {
    "path": "spec/services/authorize_follow_service_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe AuthorizeFollowService, type: :service do\n  let(:sender) { Fabricate(:account, username: 'alice') }\n\n  subject { AuthorizeFollowService.new }\n\n  describe 'local' do\n    let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account }\n\n    before do\n      FollowRequest.create(account: bob, target_account: sender)\n      subject.call(bob, sender)\n    end\n\n    it 'removes follow request' do\n      expect(bob.requested?(sender)).to be false\n    end\n\n    it 'creates follow relation' do\n      expect(bob.following?(sender)).to be true\n    end\n  end\n\n  describe 'remote OStatus' do\n    let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob', domain: 'example.com', salmon_url: 'http://salmon.example.com')).account }\n\n    before do\n      FollowRequest.create(account: bob, target_account: sender)\n      stub_request(:post, \"http://salmon.example.com/\").to_return(:status => 200, :body => \"\", :headers => {})\n      subject.call(bob, sender)\n    end\n\n    it 'removes follow request' do\n      expect(bob.requested?(sender)).to be false\n    end\n\n    it 'creates follow relation' do\n      expect(bob.following?(sender)).to be true\n    end\n\n    it 'sends a follow request authorization salmon slap' do\n      expect(a_request(:post, \"http://salmon.example.com/\").with { |req|\n        xml = OStatus2::Salmon.new.unpack(req.body)\n        xml.match(OStatus::TagManager::VERBS[:authorize])\n      }).to have_been_made.once\n    end\n  end\n\n  describe 'remote ActivityPub' do\n    let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob', domain: 'example.com', protocol: :activitypub, inbox_url: 'http://example.com/inbox')).account }\n\n    before do\n      FollowRequest.create(account: bob, target_account: sender)\n      stub_request(:post, bob.inbox_url).to_return(status: 200)\n      subject.call(bob, sender)\n    end\n\n    it 'removes follow request' do\n      expect(bob.requested?(sender)).to be false\n    end\n\n    it 'creates follow relation' do\n      expect(bob.following?(sender)).to be true\n    end\n\n    it 'sends an accept activity' do\n      expect(a_request(:post, bob.inbox_url)).to have_been_made.once\n    end\n  end\nend\n"
  },
  {
    "path": "spec/services/batched_remove_status_service_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe BatchedRemoveStatusService, type: :service do\n  subject { BatchedRemoveStatusService.new }\n\n  let!(:alice)  { Fabricate(:account) }\n  let!(:bob)    { Fabricate(:account, username: 'bob', domain: 'example.com', salmon_url: 'http://example.com/salmon') }\n  let!(:jeff)   { Fabricate(:user).account }\n  let!(:hank)   { Fabricate(:account, username: 'hank', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') }\n\n  let(:status1) { PostStatusService.new.call(alice, text: 'Hello @bob@example.com') }\n  let(:status2) { PostStatusService.new.call(alice, text: 'Another status') }\n\n  before do\n    allow(Redis.current).to receive_messages(publish: nil)\n\n    stub_request(:post, 'http://example.com/push').to_return(status: 200, body: '', headers: {})\n    stub_request(:post, 'http://example.com/salmon').to_return(status: 200, body: '', headers: {})\n    stub_request(:post, 'http://example.com/inbox').to_return(status: 200)\n\n    Fabricate(:subscription, account: alice, callback_url: 'http://example.com/push', confirmed: true, expires_at: 30.days.from_now)\n    jeff.user.update(current_sign_in_at: Time.zone.now)\n    jeff.follow!(alice)\n    hank.follow!(alice)\n\n    status1\n    status2\n\n    subject.call([status1, status2])\n  end\n\n  it 'removes statuses from author\\'s home feed' do\n    expect(HomeFeed.new(alice).get(10)).to_not include([status1.id, status2.id])\n  end\n\n  it 'removes statuses from local follower\\'s home feed' do\n    expect(HomeFeed.new(jeff).get(10)).to_not include([status1.id, status2.id])\n  end\n\n  it 'notifies streaming API of followers' do\n    expect(Redis.current).to have_received(:publish).with(\"timeline:#{jeff.id}\", any_args).at_least(:once)\n  end\n\n  it 'notifies streaming API of author' do\n    expect(Redis.current).to have_received(:publish).with(\"timeline:#{alice.id}\", any_args).at_least(:once)\n  end\n\n  it 'notifies streaming API of public timeline' do\n    expect(Redis.current).to have_received(:publish).with('timeline:public', any_args).at_least(:once)\n  end\n\n  it 'sends PuSH update to PuSH subscribers' do\n    expect(a_request(:post, 'http://example.com/push').with { |req|\n      matches = req.body.match(OStatus::TagManager::VERBS[:delete])\n    }).to have_been_made.at_least_once\n  end\n\n  it 'sends Salmon slap to previously mentioned users' do\n    expect(a_request(:post, \"http://example.com/salmon\").with { |req|\n      xml = OStatus2::Salmon.new.unpack(req.body)\n      xml.match(OStatus::TagManager::VERBS[:delete])\n    }).to have_been_made.once\n  end\n\n  it 'sends delete activity to followers' do\n    expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.at_least_once\n  end\nend\n"
  },
  {
    "path": "spec/services/block_domain_service_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe BlockDomainService, type: :service do\n  let!(:bad_account) { Fabricate(:account, username: 'badguy666', domain: 'evil.org') }\n  let!(:bad_status1) { Fabricate(:status, account: bad_account, text: 'You suck') }\n  let!(:bad_status2) { Fabricate(:status, account: bad_account, text: 'Hahaha') }\n  let!(:bad_attachment) { Fabricate(:media_attachment, account: bad_account, status: bad_status2, file: attachment_fixture('attachment.jpg')) }\n  let!(:already_banned_account) { Fabricate(:account, username: 'badguy', domain: 'evil.org', suspended: true, silenced: true) }\n\n  subject { BlockDomainService.new }\n\n  describe 'for a suspension' do\n    before do\n      subject.call(DomainBlock.create!(domain: 'evil.org', severity: :suspend))\n    end\n\n    it 'creates a domain block' do\n      expect(DomainBlock.blocked?('evil.org')).to be true\n    end\n\n    it 'removes remote accounts from that domain' do\n      expect(Account.find_remote('badguy666', 'evil.org').suspended?).to be true\n    end\n\n    it 'records suspension date appropriately' do\n      expect(Account.find_remote('badguy666', 'evil.org').suspended_at).to eq DomainBlock.find_by(domain: 'evil.org').created_at\n    end\n\n    it 'keeps already-banned accounts banned' do\n      expect(Account.find_remote('badguy', 'evil.org').suspended?).to be true\n    end\n\n    it 'does not overwrite suspension date of already-banned accounts' do\n      expect(Account.find_remote('badguy', 'evil.org').suspended_at).to_not eq DomainBlock.find_by(domain: 'evil.org').created_at\n    end\n\n    it 'removes the remote accounts\\'s statuses and media attachments' do\n      expect { bad_status1.reload }.to raise_exception ActiveRecord::RecordNotFound\n      expect { bad_status2.reload }.to raise_exception ActiveRecord::RecordNotFound\n      expect { bad_attachment.reload }.to raise_exception ActiveRecord::RecordNotFound\n    end\n  end\n\n  describe 'for a silence with reject media' do\n    before do\n      subject.call(DomainBlock.create!(domain: 'evil.org', severity: :silence, reject_media: true))\n    end\n\n    it 'does not create a domain block' do\n      expect(DomainBlock.blocked?('evil.org')).to be false\n    end\n\n    it 'silences remote accounts from that domain' do\n      expect(Account.find_remote('badguy666', 'evil.org').silenced?).to be true\n    end\n\n    it 'records suspension date appropriately' do\n      expect(Account.find_remote('badguy666', 'evil.org').silenced_at).to eq DomainBlock.find_by(domain: 'evil.org').created_at\n    end\n\n    it 'keeps already-banned accounts banned' do\n      expect(Account.find_remote('badguy', 'evil.org').silenced?).to be true\n    end\n\n    it 'does not overwrite suspension date of already-banned accounts' do\n      expect(Account.find_remote('badguy', 'evil.org').silenced_at).to_not eq DomainBlock.find_by(domain: 'evil.org').created_at\n    end\n\n    it 'leaves the domains status and attachements, but clears media' do\n      expect { bad_status1.reload }.not_to raise_error\n      expect { bad_status2.reload }.not_to raise_error\n      expect { bad_attachment.reload }.not_to raise_error\n      expect(bad_attachment.file.exists?).to be false\n    end\n  end\nend\n"
  },
  {
    "path": "spec/services/block_service_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe BlockService, type: :service do\n  let(:sender) { Fabricate(:account, username: 'alice') }\n\n  subject { BlockService.new }\n\n  describe 'local' do\n    let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account }\n\n    before do\n      subject.call(sender, bob)\n    end\n\n    it 'creates a blocking relation' do\n      expect(sender.blocking?(bob)).to be true\n    end\n  end\n\n  describe 'remote OStatus' do\n    let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob', domain: 'example.com', salmon_url: 'http://salmon.example.com')).account }\n\n    before do\n      stub_request(:post, \"http://salmon.example.com/\").to_return(:status => 200, :body => \"\", :headers => {})\n      subject.call(sender, bob)\n    end\n\n    it 'creates a blocking relation' do\n      expect(sender.blocking?(bob)).to be true\n    end\n\n    it 'sends a block salmon slap' do\n      expect(a_request(:post, \"http://salmon.example.com/\").with { |req|\n        xml = OStatus2::Salmon.new.unpack(req.body)\n        xml.match(OStatus::TagManager::VERBS[:block])\n      }).to have_been_made.once\n    end\n  end\n\n  describe 'remote ActivityPub' do\n    let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox')).account }\n\n    before do\n      stub_request(:post, 'http://example.com/inbox').to_return(status: 200)\n      subject.call(sender, bob)\n    end\n\n    it 'creates a blocking relation' do\n      expect(sender.blocking?(bob)).to be true\n    end\n\n    it 'sends a block activity' do\n      expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once\n    end\n  end\nend\n"
  },
  {
    "path": "spec/services/bootstrap_timeline_service_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe BootstrapTimelineService, type: :service do\n  subject { described_class.new }\n\n  describe '#call' do\n    let(:source_account) { Fabricate(:account) }\n\n    context 'when setting is empty' do\n      let!(:admin) { Fabricate(:user, admin: true) }\n\n      before do\n        Setting.bootstrap_timeline_accounts = nil\n        subject.call(source_account)\n      end\n\n      it 'follows admin accounts from account' do\n        expect(source_account.following?(admin.account)).to be true\n      end\n    end\n\n    context 'when setting is set' do\n      let!(:alice) { Fabricate(:account, username: 'alice') }\n      let!(:bob)   { Fabricate(:account, username: 'bob') }\n\n      before do\n        Setting.bootstrap_timeline_accounts = 'alice, bob'\n        subject.call(source_account)\n      end\n\n      it 'follows found accounts from account' do\n        expect(source_account.following?(alice)).to be true\n        expect(source_account.following?(bob)).to be true\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/services/fan_out_on_write_service_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe FanOutOnWriteService, type: :service do\n  let(:author)   { Fabricate(:account, username: 'tom') }\n  let(:status)   { Fabricate(:status, text: 'Hello @alice #test', account: author) }\n  let(:alice)    { Fabricate(:user, account: Fabricate(:account, username: 'alice')).account }\n  let(:follower) { Fabricate(:account, username: 'bob') }\n\n  subject { FanOutOnWriteService.new }\n\n  before do\n    alice\n    follower.follow!(author)\n\n    ProcessMentionsService.new.call(status)\n    ProcessHashtagsService.new.call(status)\n\n    subject.call(status)\n  end\n\n  it 'delivers status to home timeline' do\n    expect(HomeFeed.new(author).get(10).map(&:id)).to include status.id\n  end\n\n  it 'delivers status to local followers' do\n    pending 'some sort of problem in test environment causes this to sometimes fail'\n    expect(HomeFeed.new(follower).get(10).map(&:id)).to include status.id\n  end\n\n  it 'delivers status to hashtag' do\n    expect(Tag.find_by!(name: 'test').statuses.pluck(:id)).to include status.id\n  end\n\n  it 'delivers status to public timeline' do\n    expect(Status.as_public_timeline(alice).map(&:id)).to include status.id\n  end\nend\n"
  },
  {
    "path": "spec/services/favourite_service_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe FavouriteService, type: :service do\n  let(:sender) { Fabricate(:account, username: 'alice') }\n\n  subject { FavouriteService.new }\n\n  describe 'local' do\n    let(:bob)    { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account }\n    let(:status) { Fabricate(:status, account: bob) }\n\n    before do\n      subject.call(sender, status)\n    end\n\n    it 'creates a favourite' do\n      expect(status.favourites.first).to_not be_nil\n    end\n  end\n\n  describe 'remote OStatus' do\n    let(:bob)    { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob', protocol: :ostatus, domain: 'example.com', salmon_url: 'http://salmon.example.com')).account }\n    let(:status) { Fabricate(:status, account: bob, uri: 'tag:example.com:blahblah') }\n\n    before do\n      stub_request(:post, \"http://salmon.example.com/\").to_return(:status => 200, :body => \"\", :headers => {})\n      subject.call(sender, status)\n    end\n\n    it 'creates a favourite' do\n      expect(status.favourites.first).to_not be_nil\n    end\n\n    it 'sends a salmon slap' do\n      expect(a_request(:post, \"http://salmon.example.com/\").with { |req|\n        xml = OStatus2::Salmon.new.unpack(req.body)\n        xml.match(OStatus::TagManager::VERBS[:favorite])\n      }).to have_been_made.once\n    end\n  end\n\n  describe 'remote ActivityPub' do\n    let(:bob)    { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, protocol: :activitypub, username: 'bob', domain: 'example.com', inbox_url: 'http://example.com/inbox')).account }\n    let(:status) { Fabricate(:status, account: bob) }\n\n    before do\n      stub_request(:post, \"http://example.com/inbox\").to_return(:status => 200, :body => \"\", :headers => {})\n      subject.call(sender, status)\n    end\n\n    it 'creates a favourite' do\n      expect(status.favourites.first).to_not be_nil\n    end\n\n    it 'sends a like activity' do\n      expect(a_request(:post, \"http://example.com/inbox\")).to have_been_made.once\n    end\n  end\nend\n"
  },
  {
    "path": "spec/services/fetch_atom_service_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe FetchAtomService, type: :service do\n  describe '#call' do\n    let(:url) { 'http://example.com' }\n    subject { FetchAtomService.new.call(url) }\n\n    context 'url is blank' do\n      let(:url) { '' }\n      it { is_expected.to be_nil }\n    end\n\n    context 'request failed' do\n      before do\n        WebMock.stub_request(:get, url).to_return(status: 500, body: '', headers: {})\n      end\n\n      it { is_expected.to be_nil }\n    end\n\n    context 'raise OpenSSL::SSL::SSLError' do\n      before do\n        allow(Request).to receive_message_chain(:new, :add_headers, :perform).and_raise(OpenSSL::SSL::SSLError)\n      end\n\n      it 'output log and return nil' do\n        expect_any_instance_of(ActiveSupport::Logger).to receive(:debug).with('SSL error: OpenSSL::SSL::SSLError')\n        is_expected.to be_nil\n      end\n    end\n\n    context 'raise HTTP::ConnectionError' do\n      before do\n        allow(Request).to receive_message_chain(:new, :add_headers, :perform).and_raise(HTTP::ConnectionError)\n      end\n\n      it 'output log and return nil' do\n        expect_any_instance_of(ActiveSupport::Logger).to receive(:debug).with('HTTP ConnectionError: HTTP::ConnectionError')\n        is_expected.to be_nil\n      end\n    end\n\n    context 'response success' do\n      let(:body) { '' }\n      let(:headers) { { 'Content-Type' => content_type } }\n      let(:json) {\n        { id: 1,\n          '@context': ActivityPub::TagManager::CONTEXT,\n          type: 'Note',\n        }.to_json\n      }\n\n      before do\n        WebMock.stub_request(:get, url).to_return(status: 200, body: body, headers: headers)\n      end\n\n      context 'content type is application/atom+xml' do\n        let(:content_type) { 'application/atom+xml' }\n\n        it { is_expected.to eq [url, { :prefetched_body => \"\" }, :ostatus] }\n      end\n\n      context 'content_type is activity+json' do\n        let(:content_type) { 'application/activity+json; charset=utf-8' }\n        let(:body) { json }\n\n        it { is_expected.to eq [1, { prefetched_body: body, id: true }, :activitypub] }\n      end\n\n      context 'content_type is ld+json with profile' do\n        let(:content_type) { 'application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"' }\n        let(:body) { json }\n\n        it { is_expected.to eq [1, { prefetched_body: body, id: true }, :activitypub] }\n      end\n\n      before do\n        WebMock.stub_request(:get, url).to_return(status: 200, body: body, headers: headers)\n        WebMock.stub_request(:get, 'http://example.com/foo').to_return(status: 200, body: json, headers: { 'Content-Type' => 'application/activity+json' })\n      end\n\n      context 'has link header' do\n        let(:headers) { { 'Link' => '<http://example.com/foo>; rel=\"alternate\"; type=\"application/activity+json\"', } }\n\n        it { is_expected.to eq [1, { prefetched_body: json, id: true }, :activitypub] }\n      end\n\n      context 'content type is text/html' do\n        let(:content_type) { 'text/html' }\n        let(:body) { '<html><head><link rel=\"alternate\" href=\"http://example.com/foo\" type=\"application/activity+json\"/></head></html>' }\n\n        it { is_expected.to eq [1, { prefetched_body: json, id: true }, :activitypub] }\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/services/fetch_link_card_service_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe FetchLinkCardService, type: :service do\n  subject { FetchLinkCardService.new }\n\n  before do\n    stub_request(:head, 'http://example.xn--fiqs8s/').to_return(status: 200, headers: { 'Content-Type' => 'text/html' })\n    stub_request(:get, 'http://example.xn--fiqs8s/').to_return(request_fixture('idn.txt'))\n    stub_request(:head, 'http://example.com/sjis').to_return(status: 200, headers: { 'Content-Type' => 'text/html' })\n    stub_request(:get, 'http://example.com/sjis').to_return(request_fixture('sjis.txt'))\n    stub_request(:head, 'http://example.com/sjis_with_wrong_charset').to_return(status: 200, headers: { 'Content-Type' => 'text/html' })\n    stub_request(:get, 'http://example.com/sjis_with_wrong_charset').to_return(request_fixture('sjis_with_wrong_charset.txt'))\n    stub_request(:head, 'http://example.com/koi8-r').to_return(status: 200, headers: { 'Content-Type' => 'text/html' })\n    stub_request(:get, 'http://example.com/koi8-r').to_return(request_fixture('koi8-r.txt'))\n    stub_request(:head, 'http://example.com/日本語').to_return(status: 200, headers: { 'Content-Type' => 'text/html' })\n    stub_request(:get, 'http://example.com/日本語').to_return(request_fixture('sjis.txt'))\n    stub_request(:head, 'https://github.com/qbi/WannaCry').to_return(status: 404)\n    stub_request(:head, 'http://example.com/test-').to_return(status: 200, headers: { 'Content-Type' => 'text/html' })\n    stub_request(:get, 'http://example.com/test-').to_return(request_fixture('idn.txt'))\n    stub_request(:head, 'http://example.com/windows-1251').to_return(status: 200, headers: { 'Content-Type' => 'text/html' })\n    stub_request(:get, 'http://example.com/windows-1251').to_return(request_fixture('windows-1251.txt'))\n\n    subject.call(status)\n  end\n\n  context 'in a local status' do\n    context do\n      let(:status) { Fabricate(:status, text: 'Check out http://example.中国') }\n\n      it 'works with IDN URLs' do\n        expect(a_request(:get, 'http://example.xn--fiqs8s/')).to have_been_made.at_least_once\n      end\n    end\n\n    context do\n      let(:status) { Fabricate(:status, text: 'Check out http://example.com/sjis') }\n\n      it 'works with SJIS' do\n        expect(a_request(:get, 'http://example.com/sjis')).to have_been_made.at_least_once\n        expect(status.preview_cards.first.title).to eq(\"SJISのページ\")\n      end\n    end\n\n    context do\n      let(:status) { Fabricate(:status, text: 'Check out http://example.com/sjis_with_wrong_charset') }\n\n      it 'works with SJIS even with wrong charset header' do\n        expect(a_request(:get, 'http://example.com/sjis_with_wrong_charset')).to have_been_made.at_least_once\n        expect(status.preview_cards.first.title).to eq(\"SJISのページ\")\n      end\n    end\n\n    context do\n      let(:status) { Fabricate(:status, text: 'Check out http://example.com/koi8-r') }\n\n      it 'works with koi8-r' do\n        expect(a_request(:get, 'http://example.com/koi8-r')).to have_been_made.at_least_once\n        expect(status.preview_cards.first.title).to eq(\"Московя начинаетъ только въ XVI ст. привлекать внимане иностранцевъ.\")\n      end\n    end\n\n    context do\n      let(:status) { Fabricate(:status, text: 'Check out http://example.com/windows-1251') }\n\n      it 'works with windows-1251' do\n        expect(a_request(:get, 'http://example.com/windows-1251')).to have_been_made.at_least_once\n        expect(status.preview_cards.first.title).to eq('сэмпл текст')\n      end\n    end\n\n    context do\n      let(:status) { Fabricate(:status, text: 'テストhttp://example.com/日本語') }\n\n      it 'works with Japanese path string' do\n        expect(a_request(:get, 'http://example.com/日本語')).to have_been_made.at_least_once\n        expect(status.preview_cards.first.title).to eq(\"SJISのページ\")\n      end\n    end\n\n    context do\n      let(:status) { Fabricate(:status, text: 'test http://example.com/test-') }\n\n      it 'works with a URL ending with a hyphen' do\n        expect(a_request(:get, 'http://example.com/test-')).to have_been_made.at_least_once\n      end\n    end\n  end\n\n  context 'in a remote status' do\n    let(:status) { Fabricate(:status, account: Fabricate(:account, domain: 'example.com'), text: 'Habt ihr ein paar gute Links zu #<span class=\"tag\"><a href=\"https://quitter.se/tag/wannacry\" target=\"_blank\" rel=\"tag noopener\" title=\"https://quitter.se/tag/wannacry\">Wannacry</a></span> herumfliegen?   Ich will mal unter <br> <a href=\"https://github.com/qbi/WannaCry\" target=\"_blank\" rel=\"noopener\" title=\"https://github.com/qbi/WannaCry\">https://github.com/qbi/WannaCry</a> was sammeln. !<a href=\"http://sn.jonkman.ca/group/416/id\" target=\"_blank\" rel=\"noopener\" title=\"http://sn.jonkman.ca/group/416/id\">security</a>&nbsp;') }\n\n    it 'parses out URLs' do\n      expect(a_request(:head, 'https://github.com/qbi/WannaCry')).to have_been_made.at_least_once\n    end\n\n    it 'ignores URLs to hashtags' do\n      expect(a_request(:head, 'https://quitter.se/tag/wannacry')).to_not have_been_made\n    end\n  end\nend\n"
  },
  {
    "path": "spec/services/fetch_oembed_service_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe FetchOEmbedService, type: :service do\n  subject { described_class.new }\n\n  before do\n    stub_request(:get, \"https://host.test/provider.json\").to_return(status: 404)\n    stub_request(:get, \"https://host.test/provider.xml\").to_return(status: 404)\n    stub_request(:get, \"https://host.test/empty_provider.json\").to_return(status: 200)\n  end\n\n  describe 'discover_provider' do\n    context 'when status code is 200 and MIME type is text/html' do\n      context 'Both of JSON and XML provider are discoverable' do\n        before do\n          stub_request(:get, 'https://host.test/oembed.html').to_return(\n            status: 200,\n            headers: { 'Content-Type': 'text/html' },\n            body: request_fixture('oembed_json_xml.html')\n          )\n        end\n\n        it 'returns new OEmbed::Provider for JSON provider if :format option is set to :json' do\n          subject.call('https://host.test/oembed.html', format: :json)\n          expect(subject.endpoint_url).to eq 'https://host.test/provider.json'\n          expect(subject.format).to eq :json\n        end\n\n        it 'returns new OEmbed::Provider for XML provider if :format option is set to :xml' do\n          subject.call('https://host.test/oembed.html', format: :xml)\n          expect(subject.endpoint_url).to eq 'https://host.test/provider.xml'\n          expect(subject.format).to eq :xml\n        end\n      end\n\n      context 'JSON provider is discoverable while XML provider is not' do\n        before do\n          stub_request(:get, 'https://host.test/oembed.html').to_return(\n            status: 200,\n            headers: { 'Content-Type': 'text/html' },\n            body: request_fixture('oembed_json.html')\n          )\n        end\n\n        it 'returns new OEmbed::Provider for JSON provider' do\n          subject.call('https://host.test/oembed.html')\n          expect(subject.endpoint_url).to eq 'https://host.test/provider.json'\n          expect(subject.format).to eq :json\n        end\n      end\n\n      context 'XML provider is discoverable while JSON provider is not' do\n        before do\n          stub_request(:get, 'https://host.test/oembed.html').to_return(\n            status: 200,\n            headers: { 'Content-Type': 'text/html' },\n            body: request_fixture('oembed_xml.html')\n          )\n        end\n\n        it 'returns new OEmbed::Provider for XML provider' do\n          subject.call('https://host.test/oembed.html')\n          expect(subject.endpoint_url).to eq 'https://host.test/provider.xml'\n          expect(subject.format).to eq :xml\n        end\n      end\n\n      context 'Invalid XML provider is discoverable while JSON provider is not' do\n        before do\n          stub_request(:get, 'https://host.test/oembed.html').to_return(\n            status: 200,\n            headers: { 'Content-Type': 'text/html' },\n            body: request_fixture('oembed_invalid_xml.html')\n          )\n        end\n\n        it 'returns nil' do\n          expect(subject.call('https://host.test/oembed.html')).to be_nil\n        end\n      end\n\n      context 'Neither of JSON and XML provider is discoverable' do\n        before do\n          stub_request(:get, 'https://host.test/oembed.html').to_return(\n            status: 200,\n            headers: { 'Content-Type': 'text/html' },\n            body: request_fixture('oembed_undiscoverable.html')\n          )\n        end\n\n        it 'returns nil' do\n          expect(subject.call('https://host.test/oembed.html')).to be_nil\n        end\n      end\n\n      context 'Empty JSON provider is discoverable' do\n        before do\n          stub_request(:get, 'https://host.test/oembed.html').to_return(\n            status: 200,\n            headers: { 'Content-Type': 'text/html' },\n            body: request_fixture('oembed_json_empty.html')\n          )\n        end\n\n        it 'returns new OEmbed::Provider for JSON provider' do\n          subject.call('https://host.test/oembed.html')\n          expect(subject.endpoint_url).to eq 'https://host.test/empty_provider.json'\n          expect(subject.format).to eq :json\n        end\n      end\n\n    end\n\n    context 'when status code is not 200' do\n      before do\n        stub_request(:get, 'https://host.test/oembed.html').to_return(\n          status: 400,\n          headers: { 'Content-Type': 'text/html' },\n          body: request_fixture('oembed_xml.html')\n        )\n      end\n\n      it 'returns nil' do\n        expect(subject.call('https://host.test/oembed.html')).to be_nil\n      end\n    end\n\n    context 'when MIME type is not text/html' do\n      before do\n        stub_request(:get, 'https://host.test/oembed.html').to_return(\n          status: 200,\n          body: request_fixture('oembed_xml.html')\n        )\n      end\n\n      it 'returns nil' do\n        expect(subject.call('https://host.test/oembed.html')).to be_nil\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/services/fetch_remote_account_service_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe FetchRemoteAccountService, type: :service do\n  let(:url) { 'https://example.com/alice' }\n  let(:prefetched_body) { nil }\n  let(:protocol) { :ostatus }\n  subject { FetchRemoteAccountService.new.call(url, prefetched_body, protocol) }\n\n  let(:actor) do\n    {\n      '@context': 'https://www.w3.org/ns/activitystreams',\n      id: 'https://example.com/alice',\n      type: 'Person',\n      preferredUsername: 'alice',\n      name: 'Alice',\n      summary: 'Foo bar',\n      inbox: 'http://example.com/alice/inbox',\n    }\n  end\n\n  let(:webfinger) { { subject: 'acct:alice@example.com', links: [{ rel: 'self', href: 'https://example.com/alice' }] } }\n  let(:xml) { File.read(Rails.root.join('spec', 'fixtures', 'xml', 'mastodon.atom')) }\n\n  shared_examples 'return Account' do\n    it { is_expected.to be_an Account }\n  end\n\n  context 'protocol is :activitypub' do\n    let(:prefetched_body) { Oj.dump(actor) }\n    let(:protocol) { :activitypub }\n\n    before do\n      stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })\n    end\n\n    include_examples 'return Account'\n  end\n\n  context 'protocol is :ostatus' do\n    let(:prefetched_body) { xml }\n    let(:protocol) { :ostatus }\n\n    before do\n      stub_request(:get, \"https://kickass.zone/.well-known/webfinger?resource=acct:localhost@kickass.zone\").to_return(request_fixture('webfinger-hacker3.txt'))\n      stub_request(:get, \"https://kickass.zone/api/statuses/user_timeline/7477.atom\").to_return(request_fixture('feed.txt'))\n    end\n\n    include_examples 'return Account'\n\n    it 'does not update account information if XML comes from an unverified domain' do\n      feed_xml = <<-XML.squish\n        <?xml version=\"1.0\" encoding=\"UTF-8\"?>\n        <feed xml:lang=\"en-US\" xmlns=\"http://www.w3.org/2005/Atom\" xmlns:thr=\"http://purl.org/syndication/thread/1.0\" xmlns:georss=\"http://www.georss.org/georss\" xmlns:activity=\"http://activitystrea.ms/spec/1.0/\" xmlns:media=\"http://purl.org/syndication/atommedia\" xmlns:poco=\"http://portablecontacts.net/spec/1.0\" xmlns:ostatus=\"http://ostatus.org/schema/1.0\" xmlns:statusnet=\"http://status.net/schema/api/1/\">\n          <author>\n            <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>\n            <uri>http://kickass.zone/users/localhost</uri>\n            <name>localhost</name>\n            <poco:preferredUsername>localhost</poco:preferredUsername>\n            <poco:displayName>Villain!!!</poco:displayName>\n          </author>\n        </feed>\n      XML\n\n      returned_account = described_class.new.call('https://real-fake-domains.com/alice', feed_xml, :ostatus)\n      expect(returned_account.display_name).to_not eq 'Villain!!!'\n    end\n  end\n\n  context 'when prefetched_body is nil' do\n    context 'protocol is :activitypub' do\n      before do\n        stub_request(:get, url).to_return(status: 200, body: Oj.dump(actor), headers: { 'Content-Type' => 'application/activity+json' })\n        stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })\n      end\n\n      include_examples 'return Account'\n    end\n\n    context 'protocol is :ostatus' do\n      before do\n        stub_request(:get, url).to_return(status: 200, body: xml, headers: { 'Content-Type' => 'application/atom+xml' })\n        stub_request(:get, \"https://kickass.zone/.well-known/webfinger?resource=acct:localhost@kickass.zone\").to_return(request_fixture('webfinger-hacker3.txt'))\n        stub_request(:get, \"https://kickass.zone/api/statuses/user_timeline/7477.atom\").to_return(request_fixture('feed.txt'))\n      end\n\n      include_examples 'return Account'\n    end\n  end\nend\n"
  },
  {
    "path": "spec/services/fetch_remote_status_service_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe FetchRemoteStatusService, type: :service do\n  let(:account) { Fabricate(:account) }\n  let(:prefetched_body) { nil }\n  let(:valid_domain) { Rails.configuration.x.local_domain }\n\n  let(:note) do\n    {\n      '@context': 'https://www.w3.org/ns/activitystreams',\n      id: \"https://#{valid_domain}/@foo/1234\",\n      type: 'Note',\n      content: 'Lorem ipsum',\n      attributedTo: ActivityPub::TagManager.instance.uri_for(account),\n    }\n  end\n\n  context 'protocol is :activitypub' do\n    subject { described_class.new.call(note[:id], prefetched_body, protocol) }\n    let(:prefetched_body) { Oj.dump(note) }\n    let(:protocol) { :activitypub }\n\n    before do\n      account.update(uri: ActivityPub::TagManager.instance.uri_for(account))\n      subject\n    end\n\n    it 'creates status' do\n      status = account.statuses.first\n\n      expect(status).to_not be_nil\n      expect(status.text).to eq 'Lorem ipsum'\n    end\n  end\n\n  context 'protocol is :ostatus' do\n    subject { described_class.new }\n\n    before do\n      Fabricate(:account, username: 'tracer', domain: 'real.domain', remote_url: 'https://real.domain/users/tracer')\n    end\n\n    it 'does not create status with author at different domain' do\n      status_body = <<-XML.squish\n        <?xml version=\"1.0\"?>\n        <entry xmlns=\"http://www.w3.org/2005/Atom\" xmlns:thr=\"http://purl.org/syndication/thread/1.0\" xmlns:activity=\"http://activitystrea.ms/spec/1.0/\" xmlns:poco=\"http://portablecontacts.net/spec/1.0\" xmlns:media=\"http://purl.org/syndication/atommedia\" xmlns:ostatus=\"http://ostatus.org/schema/1.0\" xmlns:mastodon=\"http://mastodon.social/schema/1.0\">\n          <id>tag:real.domain,2017-04-27:objectId=4487555:objectType=Status</id>\n          <published>2017-04-27T13:49:25Z</published>\n          <updated>2017-04-27T13:49:25Z</updated>\n          <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>\n          <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>\n          <author>\n            <id>https://real.domain/users/tracer</id>\n            <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>\n            <uri>https://real.domain/users/tracer</uri>\n            <name>tracer</name>\n          </author>\n          <content type=\"html\">Overwatch rocks</content>\n        </entry>\n      XML\n\n      expect(subject.call('https://fake.domain/foo', status_body, :ostatus)).to be_nil\n    end\n\n    it 'does not create status with wrong id when id uses http format' do\n      status_body = <<-XML.squish\n        <?xml version=\"1.0\"?>\n        <entry xmlns=\"http://www.w3.org/2005/Atom\" xmlns:thr=\"http://purl.org/syndication/thread/1.0\" xmlns:activity=\"http://activitystrea.ms/spec/1.0/\" xmlns:poco=\"http://portablecontacts.net/spec/1.0\" xmlns:media=\"http://purl.org/syndication/atommedia\" xmlns:ostatus=\"http://ostatus.org/schema/1.0\" xmlns:mastodon=\"http://mastodon.social/schema/1.0\">\n          <id>https://other-real.domain/statuses/123</id>\n          <published>2017-04-27T13:49:25Z</published>\n          <updated>2017-04-27T13:49:25Z</updated>\n          <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>\n          <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>\n          <author>\n            <id>https://real.domain/users/tracer</id>\n            <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>\n            <uri>https://real.domain/users/tracer</uri>\n            <name>tracer</name>\n          </author>\n          <content type=\"html\">Overwatch rocks</content>\n        </entry>\n      XML\n\n      expect(subject.call('https://real.domain/statuses/456', status_body, :ostatus)).to be_nil\n    end\n  end\nend\n"
  },
  {
    "path": "spec/services/follow_service_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe FollowService, type: :service do\n  let(:sender) { Fabricate(:account, username: 'alice') }\n\n  subject { FollowService.new }\n\n  context 'local account' do\n    describe 'locked account' do\n      let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, locked: true, username: 'bob')).account }\n\n      before do\n        subject.call(sender, bob.acct)\n      end\n\n      it 'creates a follow request with reblogs' do\n        expect(FollowRequest.find_by(account: sender, target_account: bob, show_reblogs: true)).to_not be_nil\n      end\n    end\n\n    describe 'locked account, no reblogs' do\n      let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, locked: true, username: 'bob')).account }\n\n      before do\n        subject.call(sender, bob.acct, reblogs: false)\n      end\n\n      it 'creates a follow request without reblogs' do\n        expect(FollowRequest.find_by(account: sender, target_account: bob, show_reblogs: false)).to_not be_nil\n      end\n    end\n\n    describe 'unlocked account' do\n      let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account }\n\n      before do\n        subject.call(sender, bob.acct)\n      end\n\n      it 'creates a following relation with reblogs' do\n        expect(sender.following?(bob)).to be true\n        expect(sender.muting_reblogs?(bob)).to be false\n      end\n    end\n\n    describe 'unlocked account, no reblogs' do\n      let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account }\n\n      before do\n        subject.call(sender, bob.acct, reblogs: false)\n      end\n\n      it 'creates a following relation without reblogs' do\n        expect(sender.following?(bob)).to be true\n        expect(sender.muting_reblogs?(bob)).to be true\n      end\n    end\n\n    describe 'already followed account' do\n      let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account }\n\n      before do\n        sender.follow!(bob)\n        subject.call(sender, bob.acct)\n      end\n\n      it 'keeps a following relation' do\n        expect(sender.following?(bob)).to be true\n      end\n    end\n\n    describe 'already followed account, turning reblogs off' do\n      let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account }\n\n      before do\n        sender.follow!(bob, reblogs: true)\n        subject.call(sender, bob.acct, reblogs: false)\n      end\n\n      it 'disables reblogs' do\n        expect(sender.muting_reblogs?(bob)).to be true\n      end\n    end\n\n    describe 'already followed account, turning reblogs on' do\n      let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account }\n\n      before do\n        sender.follow!(bob, reblogs: false)\n        subject.call(sender, bob.acct, reblogs: true)\n      end\n\n      it 'disables reblogs' do\n        expect(sender.muting_reblogs?(bob)).to be false\n      end\n    end\n  end\n\n  context 'remote OStatus account' do\n    describe 'locked account' do\n      let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, protocol: :ostatus, locked: true, username: 'bob', domain: 'example.com', salmon_url: 'http://salmon.example.com')).account }\n\n      before do\n        stub_request(:post, \"http://salmon.example.com/\").to_return(:status => 200, :body => \"\", :headers => {})\n        subject.call(sender, bob.acct)\n      end\n\n      it 'creates a follow request' do\n        expect(FollowRequest.find_by(account: sender, target_account: bob)).to_not be_nil\n      end\n\n      it 'sends a follow request salmon slap' do\n        expect(a_request(:post, \"http://salmon.example.com/\").with { |req|\n          xml = OStatus2::Salmon.new.unpack(req.body)\n          xml.match(OStatus::TagManager::VERBS[:request_friend])\n        }).to have_been_made.once\n      end\n    end\n\n    describe 'unlocked account' do\n      let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, protocol: :ostatus, username: 'bob', domain: 'example.com', salmon_url: 'http://salmon.example.com', hub_url: 'http://hub.example.com')).account }\n\n      before do\n        stub_request(:post, \"http://salmon.example.com/\").to_return(:status => 200, :body => \"\", :headers => {})\n        stub_request(:post, \"http://hub.example.com/\").to_return(status: 202)\n        subject.call(sender, bob.acct)\n      end\n\n      it 'creates a following relation' do\n        expect(sender.following?(bob)).to be true\n      end\n\n      it 'sends a follow salmon slap' do\n        expect(a_request(:post, \"http://salmon.example.com/\").with { |req|\n          xml = OStatus2::Salmon.new.unpack(req.body)\n          xml.match(OStatus::TagManager::VERBS[:follow])\n        }).to have_been_made.once\n      end\n\n      it 'subscribes to PuSH' do\n        expect(a_request(:post, \"http://hub.example.com/\")).to have_been_made.once\n      end\n    end\n\n    describe 'already followed account' do\n      let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, protocol: :ostatus, username: 'bob', domain: 'example.com', salmon_url: 'http://salmon.example.com', hub_url: 'http://hub.example.com')).account }\n\n      before do\n        sender.follow!(bob)\n        subject.call(sender, bob.acct)\n      end\n\n      it 'keeps a following relation' do\n        expect(sender.following?(bob)).to be true\n      end\n\n      it 'does not send a follow salmon slap' do\n        expect(a_request(:post, \"http://salmon.example.com/\")).not_to have_been_made\n      end\n\n      it 'does not subscribe to PuSH' do\n        expect(a_request(:post, \"http://hub.example.com/\")).not_to have_been_made\n      end\n    end\n  end\n\n  context 'remote ActivityPub account' do\n    let(:bob) { Fabricate(:user, account: Fabricate(:account, username: 'bob', domain: 'example.com', protocol: :activitypub, inbox_url: 'http://example.com/inbox')).account }\n\n    before do\n      stub_request(:post, \"http://example.com/inbox\").to_return(:status => 200, :body => \"\", :headers => {})\n      subject.call(sender, bob.acct)\n    end\n\n    it 'creates follow request' do\n      expect(FollowRequest.find_by(account: sender, target_account: bob)).to_not be_nil\n    end\n\n    it 'sends a follow activity to the inbox' do\n      expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once\n    end\n  end\nend\n"
  },
  {
    "path": "spec/services/hashtag_query_service_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe HashtagQueryService, type: :service do\n  describe '.call' do\n    let(:account) { Fabricate(:account) }\n    let(:tag1) { Fabricate(:tag) }\n    let(:tag2) { Fabricate(:tag) }\n    let!(:status1) { Fabricate(:status, tags: [tag1]) }\n    let!(:status2) { Fabricate(:status, tags: [tag2]) }\n    let!(:both) { Fabricate(:status, tags: [tag1, tag2]) }\n\n    it 'can add tags in \"any\" mode' do\n      results = subject.call(tag1, { any: [tag2.name] })\n      expect(results).to include status1\n      expect(results).to include status2\n      expect(results).to include both\n    end\n\n    it 'can remove tags in \"all\" mode' do\n      results = subject.call(tag1, { all: [tag2.name] })\n      expect(results).to_not include status1\n      expect(results).to_not include status2\n      expect(results).to     include both\n    end\n\n    it 'can remove tags in \"none\" mode' do\n      results = subject.call(tag1, { none: [tag2.name] })\n      expect(results).to     include status1\n      expect(results).to_not include status2\n      expect(results).to_not include both\n    end\n\n    it 'ignores an invalid mode' do\n      results = subject.call(tag1, { wark: [tag2.name] })\n      expect(results).to     include status1\n      expect(results).to_not include status2\n      expect(results).to     include both\n    end\n\n    it 'handles being passed non existant tag names' do\n      results = subject.call(tag1, { any: ['wark'] })\n      expect(results).to     include status1\n      expect(results).to_not include status2\n      expect(results).to     include both\n    end\n\n    it 'can restrict to an account' do\n      BlockService.new.call(account, status1.account)\n      results = subject.call(tag1, { none: [tag2.name] }, account)\n      expect(results).to_not include status1\n    end\n\n    it 'can restrict to local' do\n      status1.account.update(domain: 'example.com')\n      status1.update(local: false, uri: 'example.com/toot')\n      results = subject.call(tag1, { any: [tag2.name] }, nil, true)\n      expect(results).to_not include status1\n    end\n  end\nend\n"
  },
  {
    "path": "spec/services/import_service_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe ImportService, type: :service do\n  let!(:account) { Fabricate(:account, locked: false) }\n  let!(:bob)     { Fabricate(:account, username: 'bob', locked: false) }\n  let!(:eve)     { Fabricate(:account, username: 'eve', domain: 'example.com', locked: false) }\n\n  context 'import old-style list of muted users' do\n    subject { ImportService.new }\n\n    let(:csv) { attachment_fixture('mute-imports.txt') }\n\n    describe 'when no accounts are muted' do\n      let(:import) { Import.create(account: account, type: 'muting', data: csv) }\n      it 'mutes the listed accounts, including notifications' do\n        subject.call(import)\n        expect(account.muting.count).to eq 2\n        expect(Mute.find_by(account: account, target_account: bob).hide_notifications).to be true\n      end\n    end\n\n    describe 'when some accounts are muted and overwrite is not set' do\n      let(:import) { Import.create(account: account, type: 'muting', data: csv) }\n\n      it 'mutes the listed accounts, including notifications' do\n        account.mute!(bob, notifications: false)\n        subject.call(import)\n        expect(account.muting.count).to eq 2\n        expect(Mute.find_by(account: account, target_account: bob).hide_notifications).to be true\n      end\n    end\n\n    describe 'when some accounts are muted and overwrite is set' do\n      let(:import) { Import.create(account: account, type: 'muting', data: csv, overwrite: true) }\n\n      it 'mutes the listed accounts, including notifications' do\n        account.mute!(bob, notifications: false)\n        subject.call(import)\n        expect(account.muting.count).to eq 2\n        expect(Mute.find_by(account: account, target_account: bob).hide_notifications).to be true\n      end\n    end\n  end\n\n  context 'import new-style list of muted users' do\n    subject { ImportService.new }\n\n    let(:csv) { attachment_fixture('new-mute-imports.txt') }\n\n    describe 'when no accounts are muted' do\n      let(:import) { Import.create(account: account, type: 'muting', data: csv) }\n      it 'mutes the listed accounts, respecting notifications' do\n        subject.call(import)\n        expect(account.muting.count).to eq 2\n        expect(Mute.find_by(account: account, target_account: bob).hide_notifications).to be true\n        expect(Mute.find_by(account: account, target_account: eve).hide_notifications).to be false\n      end\n    end\n\n    describe 'when some accounts are muted and overwrite is not set' do\n      let(:import) { Import.create(account: account, type: 'muting', data: csv) }\n\n      it 'mutes the listed accounts, respecting notifications' do\n        account.mute!(bob, notifications: true)\n        subject.call(import)\n        expect(account.muting.count).to eq 2\n        expect(Mute.find_by(account: account, target_account: bob).hide_notifications).to be true\n        expect(Mute.find_by(account: account, target_account: eve).hide_notifications).to be false\n      end\n    end\n\n    describe 'when some accounts are muted and overwrite is set' do\n      let(:import) { Import.create(account: account, type: 'muting', data: csv, overwrite: true) }\n\n      it 'mutes the listed accounts, respecting notifications' do\n        account.mute!(bob, notifications: true)\n        subject.call(import)\n        expect(account.muting.count).to eq 2\n        expect(Mute.find_by(account: account, target_account: bob).hide_notifications).to be true\n        expect(Mute.find_by(account: account, target_account: eve).hide_notifications).to be false\n      end\n    end\n  end\n\n  context 'import old-style list of followed users' do\n    subject { ImportService.new }\n\n    let(:csv) { attachment_fixture('mute-imports.txt') }\n\n    before do\n      allow(NotificationWorker).to receive(:perform_async)\n    end\n\n    describe 'when no accounts are followed' do\n      let(:import) { Import.create(account: account, type: 'following', data: csv) }\n      it 'follows the listed accounts, including boosts' do\n        subject.call(import)\n        expect(account.following.count).to eq 2\n        expect(Follow.find_by(account: account, target_account: bob).show_reblogs).to be true\n      end\n    end\n\n    describe 'when some accounts are already followed and overwrite is not set' do\n      let(:import) { Import.create(account: account, type: 'following', data: csv) }\n\n      it 'follows the listed accounts, including notifications' do\n        account.follow!(bob, reblogs: false)\n        subject.call(import)\n        expect(account.following.count).to eq 2\n        expect(Follow.find_by(account: account, target_account: bob).show_reblogs).to be true\n      end\n    end\n\n    describe 'when some accounts are already followed and overwrite is set' do\n      let(:import) { Import.create(account: account, type: 'following', data: csv, overwrite: true) }\n\n      it 'mutes the listed accounts, including notifications' do\n        account.follow!(bob, reblogs: false)\n        subject.call(import)\n        expect(account.following.count).to eq 2\n        expect(Follow.find_by(account: account, target_account: bob).show_reblogs).to be true\n      end\n    end\n  end\n\n  context 'import new-style list of followed users' do\n    subject { ImportService.new }\n\n    let(:csv) { attachment_fixture('new-following-imports.txt') }\n\n    before do\n      allow(NotificationWorker).to receive(:perform_async)\n    end\n\n    describe 'when no accounts are followed' do\n      let(:import) { Import.create(account: account, type: 'following', data: csv) }\n      it 'follows the listed accounts, respecting boosts' do\n        subject.call(import)\n        expect(account.following.count).to eq 2\n        expect(Follow.find_by(account: account, target_account: bob).show_reblogs).to be true\n        expect(Follow.find_by(account: account, target_account: eve).show_reblogs).to be false\n      end\n    end\n\n    describe 'when some accounts are already followed and overwrite is not set' do\n      let(:import) { Import.create(account: account, type: 'following', data: csv) }\n\n      it 'mutes the listed accounts, respecting notifications' do\n        account.follow!(bob, reblogs: true)\n        subject.call(import)\n        expect(account.following.count).to eq 2\n        expect(Follow.find_by(account: account, target_account: bob).show_reblogs).to be true\n        expect(Follow.find_by(account: account, target_account: eve).show_reblogs).to be false\n      end\n    end\n\n    describe 'when some accounts are already followed and overwrite is set' do\n      let(:import) { Import.create(account: account, type: 'following', data: csv, overwrite: true) }\n\n      it 'mutes the listed accounts, respecting notifications' do\n        account.follow!(bob, reblogs: true)\n        subject.call(import)\n        expect(account.following.count).to eq 2\n        expect(Follow.find_by(account: account, target_account: bob).show_reblogs).to be true\n        expect(Follow.find_by(account: account, target_account: eve).show_reblogs).to be false\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/services/mute_service_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe MuteService, type: :service do\n  subject do\n    -> { described_class.new.call(account, target_account) }\n  end\n\n  let(:account) { Fabricate(:account) }\n  let(:target_account) { Fabricate(:account) }\n\n  describe 'home timeline' do\n    let(:status) { Fabricate(:status, account: target_account) }\n    let(:other_account_status) { Fabricate(:status) }\n    let(:home_timeline_key) { FeedManager.instance.key(:home, account.id) }\n\n    before do\n      Redis.current.del(home_timeline_key)\n    end\n\n    it \"clears account's statuses\" do\n      FeedManager.instance.push_to_home(account, status)\n      FeedManager.instance.push_to_home(account, other_account_status)\n\n      is_expected.to change {\n        Redis.current.zrange(home_timeline_key, 0, -1)\n      }.from([status.id.to_s, other_account_status.id.to_s]).to([other_account_status.id.to_s])\n    end\n  end\n\n  it 'mutes account' do\n    is_expected.to change {\n      account.muting?(target_account)\n    }.from(false).to(true)\n  end\n\n  context 'without specifying a notifications parameter' do\n    it 'mutes notifications from the account' do\n      is_expected.to change {\n        account.muting_notifications?(target_account)\n      }.from(false).to(true)\n    end\n  end\n\n  context 'with a true notifications parameter' do\n    subject do\n      -> { described_class.new.call(account, target_account, notifications: true) }\n    end\n\n    it 'mutes notifications from the account' do\n      is_expected.to change {\n        account.muting_notifications?(target_account)\n      }.from(false).to(true)\n    end\n  end\n\n  context 'with a false notifications parameter' do\n    subject do\n      -> { described_class.new.call(account, target_account, notifications: false) }\n    end\n\n    it 'does not mute notifications from the account' do\n      is_expected.to_not change {\n        account.muting_notifications?(target_account)\n      }.from(false)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/services/notify_service_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe NotifyService, type: :service do\n  subject do\n    -> { described_class.new.call(recipient, activity) }\n  end\n\n  let(:user) { Fabricate(:user) }\n  let(:recipient) { user.account }\n  let(:sender) { Fabricate(:account, domain: 'example.com') }\n  let(:activity) { Fabricate(:follow, account: sender, target_account: recipient) }\n\n  it { is_expected.to change(Notification, :count).by(1) }\n\n  it 'does not notify when sender is blocked' do\n    recipient.block!(sender)\n    is_expected.to_not change(Notification, :count)\n  end\n\n  it 'does not notify when sender is muted with hide_notifications' do\n    recipient.mute!(sender, notifications: true)\n    is_expected.to_not change(Notification, :count)\n  end\n\n  it 'does notify when sender is muted without hide_notifications' do\n    recipient.mute!(sender, notifications: false)\n    is_expected.to change(Notification, :count)\n  end\n\n  it 'does not notify when sender\\'s domain is blocked' do\n    recipient.block_domain!(sender.domain)\n    is_expected.to_not change(Notification, :count)\n  end\n\n  it 'does still notify when sender\\'s domain is blocked but sender is followed' do\n    recipient.block_domain!(sender.domain)\n    recipient.follow!(sender)\n    is_expected.to change(Notification, :count)\n  end\n\n  it 'does not notify when sender is silenced and not followed' do\n    sender.silence!\n    is_expected.to_not change(Notification, :count)\n  end\n\n  it 'does not notify when recipient is suspended' do\n    recipient.suspend!\n    is_expected.to_not change(Notification, :count)\n  end\n\n  context 'for direct messages' do\n    let(:activity) { Fabricate(:mention, account: recipient, status: Fabricate(:status, account: sender, visibility: :direct)) }\n\n    before do\n      user.settings.interactions = user.settings.interactions.merge('must_be_following_dm' => enabled)\n    end\n\n    context 'if recipient is supposed to be following sender' do\n      let(:enabled) { true }\n\n      it 'does not notify' do\n        is_expected.to_not change(Notification, :count)\n      end\n\n      context 'if the message chain initiated by recipient, but is not direct message' do\n        let(:reply_to) { Fabricate(:status, account: recipient) }\n        let(:activity) { Fabricate(:mention, account: recipient, status: Fabricate(:status, account: sender, visibility: :direct, thread: reply_to)) }\n\n        it 'does not notify' do\n          is_expected.to_not change(Notification, :count)\n        end\n      end\n\n      context 'if the message chain initiated by recipient and is direct message' do\n        let(:reply_to) { Fabricate(:status, account: recipient, visibility: :direct) }\n        let(:activity) { Fabricate(:mention, account: recipient, status: Fabricate(:status, account: sender, visibility: :direct, thread: reply_to)) }\n\n        it 'does notify' do\n          is_expected.to change(Notification, :count)\n        end\n      end\n    end\n\n    context 'if recipient is NOT supposed to be following sender' do\n      let(:enabled) { false }\n\n      it 'does notify' do\n        is_expected.to change(Notification, :count)\n      end\n    end\n  end\n\n  describe 'reblogs' do\n    let(:status)   { Fabricate(:status, account: Fabricate(:account)) }\n    let(:activity) { Fabricate(:status, account: sender, reblog: status) }\n\n    it 'shows reblogs by default' do\n      recipient.follow!(sender)\n      is_expected.to change(Notification, :count)\n    end\n\n    it 'shows reblogs when explicitly enabled' do\n      recipient.follow!(sender, reblogs: true)\n      is_expected.to change(Notification, :count)\n    end\n\n    it 'shows reblogs when disabled' do\n      recipient.follow!(sender, reblogs: false)\n      is_expected.to change(Notification, :count)\n    end\n  end\n\n  context do\n    let(:asshole)  { Fabricate(:account, username: 'asshole') }\n    let(:reply_to) { Fabricate(:status, account: asshole) }\n    let(:activity) { Fabricate(:mention, account: recipient, status: Fabricate(:status, account: sender, thread: reply_to)) }\n\n    it 'does not notify when conversation is muted' do\n      recipient.mute_conversation!(activity.status.conversation)\n      is_expected.to_not change(Notification, :count)\n    end\n\n    it 'does not notify when it is a reply to a blocked user' do\n      recipient.block!(asshole)\n      is_expected.to_not change(Notification, :count)\n    end\n  end\n\n  context do\n    let(:sender) { recipient }\n\n    it 'does not notify when recipient is the sender' do\n      is_expected.to_not change(Notification, :count)\n    end\n  end\n\n  describe 'email' do\n    before do\n      ActionMailer::Base.deliveries.clear\n\n      notification_emails = user.settings.notification_emails\n      user.settings.notification_emails = notification_emails.merge('follow' => enabled)\n    end\n\n    context 'when email notification is enabled' do\n      let(:enabled) { true }\n\n      it 'sends email' do\n        is_expected.to change(ActionMailer::Base.deliveries, :count).by(1)\n      end\n    end\n\n    context 'when email notification is disabled' do\n      let(:enabled) { false }\n\n      it \"doesn't send email\" do\n        is_expected.to_not change(ActionMailer::Base.deliveries, :count).from(0)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/services/post_status_service_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe PostStatusService, type: :service do\n  subject { PostStatusService.new }\n\n  it 'creates a new status' do\n    account = Fabricate(:account)\n    text = \"test status update\"\n\n    status = subject.call(account, text: text)\n\n    expect(status).to be_persisted\n    expect(status.text).to eq text\n  end\n\n  it 'creates a new response status' do\n    in_reply_to_status = Fabricate(:status)\n    account = Fabricate(:account)\n    text = \"test status update\"\n\n    status = subject.call(account, text: text, thread: in_reply_to_status)\n\n    expect(status).to be_persisted\n    expect(status.text).to eq text\n    expect(status.thread).to eq in_reply_to_status\n  end\n\n  it 'schedules a status' do\n    account = Fabricate(:account)\n    future  = Time.now.utc + 2.hours\n\n    status = subject.call(account, text: 'Hi future!', scheduled_at: future)\n\n    expect(status).to be_a ScheduledStatus\n    expect(status.scheduled_at).to eq future\n    expect(status.params['text']).to eq 'Hi future!'\n  end\n\n  it 'does not immediately create a status when scheduling a status' do\n    account = Fabricate(:account)\n    media = Fabricate(:media_attachment)\n    future  = Time.now.utc + 2.hours\n\n    status = subject.call(account, text: 'Hi future!', media_ids: [media.id], scheduled_at: future)\n\n    expect(status).to be_a ScheduledStatus\n    expect(status.scheduled_at).to eq future\n    expect(status.params['text']).to eq 'Hi future!'\n    expect(media.reload.status).to be_nil\n    expect(Status.where(text: 'Hi future!').exists?).to be_falsey\n  end\n\n  it 'creates response to the original status of boost' do\n    boosted_status = Fabricate(:status)\n    in_reply_to_status = Fabricate(:status, reblog: boosted_status)\n    account = Fabricate(:account)\n    text = \"test status update\"\n\n    status = subject.call(account, text: text, thread: in_reply_to_status)\n\n    expect(status).to be_persisted\n    expect(status.text).to eq text\n    expect(status.thread).to eq boosted_status\n  end\n\n  it 'creates a sensitive status' do\n    status = create_status_with_options(sensitive: true)\n\n    expect(status).to be_persisted\n    expect(status).to be_sensitive\n  end\n\n  it 'creates a status with spoiler text' do\n    spoiler_text = \"spoiler text\"\n\n    status = create_status_with_options(spoiler_text: spoiler_text)\n\n    expect(status).to be_persisted\n    expect(status.spoiler_text).to eq spoiler_text\n  end\n\n  it 'creates a status with empty default spoiler text' do\n    status = create_status_with_options(spoiler_text: nil)\n\n    expect(status).to be_persisted\n    expect(status.spoiler_text).to eq ''\n  end\n\n  it 'creates a status with the given visibility' do\n    status = create_status_with_options(visibility: :private)\n\n    expect(status).to be_persisted\n    expect(status.visibility).to eq \"private\"\n  end\n\n  it 'creates a status with limited visibility for silenced users' do\n    status = subject.call(Fabricate(:account, silenced: true), text: 'test', visibility: :public)\n\n    expect(status).to be_persisted\n    expect(status.visibility).to eq \"unlisted\"\n  end\n\n  it 'creates a status for the given application' do\n    application = Fabricate(:application)\n\n    status = create_status_with_options(application: application)\n\n    expect(status).to be_persisted\n    expect(status.application).to eq application\n  end\n\n  it 'creates a status with a language set' do\n    account = Fabricate(:account)\n    text = 'This is an English text.'\n\n    status = subject.call(account, text: text)\n\n    expect(status.language).to eq 'en'\n  end\n\n  it 'processes mentions' do\n    mention_service = double(:process_mentions_service)\n    allow(mention_service).to receive(:call)\n    allow(ProcessMentionsService).to receive(:new).and_return(mention_service)\n    account = Fabricate(:account)\n\n    status = subject.call(account, text: \"test status update\")\n\n    expect(ProcessMentionsService).to have_received(:new)\n    expect(mention_service).to have_received(:call).with(status)\n  end\n\n  it 'processes hashtags' do\n    hashtags_service = double(:process_hashtags_service)\n    allow(hashtags_service).to receive(:call)\n    allow(ProcessHashtagsService).to receive(:new).and_return(hashtags_service)\n    account = Fabricate(:account)\n\n    status = subject.call(account, text: \"test status update\")\n\n    expect(ProcessHashtagsService).to have_received(:new)\n    expect(hashtags_service).to have_received(:call).with(status)\n  end\n\n  it 'gets distributed' do\n    allow(DistributionWorker).to receive(:perform_async)\n    allow(Pubsubhubbub::DistributionWorker).to receive(:perform_async)\n    allow(ActivityPub::DistributionWorker).to receive(:perform_async)\n\n    account = Fabricate(:account)\n\n    status = subject.call(account, text: \"test status update\")\n\n    expect(DistributionWorker).to have_received(:perform_async).with(status.id)\n    expect(Pubsubhubbub::DistributionWorker).to have_received(:perform_async).with(status.stream_entry.id)\n    expect(ActivityPub::DistributionWorker).to have_received(:perform_async).with(status.id)\n  end\n\n  it 'crawls links' do\n    allow(LinkCrawlWorker).to receive(:perform_async)\n    account = Fabricate(:account)\n\n    status = subject.call(account, text: \"test status update\")\n\n    expect(LinkCrawlWorker).to have_received(:perform_async).with(status.id)\n  end\n\n  it 'attaches the given media to the created status' do\n    account = Fabricate(:account)\n    media = Fabricate(:media_attachment, account: account)\n\n    status = subject.call(\n      account,\n      text: \"test status update\",\n      media_ids: [media.id],\n    )\n\n    expect(media.reload.status).to eq status\n  end\n\n  it 'does not attach media from another account to the created status' do\n    account = Fabricate(:account)\n    media = Fabricate(:media_attachment, account: Fabricate(:account))\n\n    status = subject.call(\n      account,\n      text: \"test status update\",\n      media_ids: [media.id],\n    )\n\n    expect(media.reload.status).to eq nil\n  end\n\n  it 'does not allow attaching more than 4 files' do\n    account = Fabricate(:account)\n\n    expect do\n      subject.call(\n        account,\n        text: \"test status update\",\n        media_ids: [\n          Fabricate(:media_attachment, account: account),\n          Fabricate(:media_attachment, account: account),\n          Fabricate(:media_attachment, account: account),\n          Fabricate(:media_attachment, account: account),\n          Fabricate(:media_attachment, account: account),\n        ].map(&:id),\n      )\n    end.to raise_error(\n      Mastodon::ValidationError,\n      I18n.t('media_attachments.validations.too_many'),\n    )\n  end\n\n  it 'does not allow attaching both videos and images' do\n    account = Fabricate(:account)\n\n    expect do\n      subject.call(\n        account,\n        text: \"test status update\",\n        media_ids: [\n          Fabricate(:media_attachment, type: :video, account: account),\n          Fabricate(:media_attachment, type: :image, account: account),\n        ].map(&:id),\n      )\n    end.to raise_error(\n      Mastodon::ValidationError,\n      I18n.t('media_attachments.validations.images_and_video'),\n    )\n  end\n\n  it 'returns existing status when used twice with idempotency key' do\n    account = Fabricate(:account)\n    status1 = subject.call(account, text: 'test', idempotency: 'meepmeep')\n    status2 = subject.call(account, text: 'test', idempotency: 'meepmeep')\n    expect(status2.id).to eq status1.id\n  end\n\n  def create_status_with_options(**options)\n    subject.call(Fabricate(:account), options.merge(text: 'test'))\n  end\nend\n"
  },
  {
    "path": "spec/services/precompute_feed_service_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe PrecomputeFeedService, type: :service do\n  subject { PrecomputeFeedService.new }\n\n  describe 'call' do\n    let(:account) { Fabricate(:account) }\n    it 'fills a user timeline with statuses' do\n      account = Fabricate(:account)\n      status = Fabricate(:status, account: account)\n\n      subject.call(account)\n\n      expect(Redis.current.zscore(FeedManager.instance.key(:home, account.id), status.id)).to be_within(0.1).of(status.id.to_f)\n    end\n\n    it 'does not raise an error even if it could not find any status' do\n      account = Fabricate(:account)\n      subject.call(account)\n    end\n\n    it 'filters statuses' do\n      account = Fabricate(:account)\n      muted_account = Fabricate(:account)\n      Fabricate(:mute, account: account, target_account: muted_account)\n      reblog = Fabricate(:status, account: muted_account)\n      status = Fabricate(:status, account: account, reblog: reblog)\n\n      subject.call(account)\n\n      expect(Redis.current.zscore(FeedManager.instance.key(:home, account.id), reblog.id)).to eq nil\n    end\n  end\nend\n"
  },
  {
    "path": "spec/services/process_feed_service_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe ProcessFeedService, type: :service do\n  subject { ProcessFeedService.new }\n\n  describe 'processing a feed' do\n    let(:body) { File.read(Rails.root.join('spec', 'fixtures', 'xml', 'mastodon.atom')) }\n    let(:account) { Fabricate(:account, username: 'localhost', domain: 'kickass.zone') }\n\n    before do\n      stub_request(:post, \"https://pubsubhubbub.superfeedr.com/\").to_return(:status => 200, :body => \"\", :headers => {})\n      stub_request(:head, \"http://kickass.zone/media/2\").to_return(:status => 404)\n      stub_request(:head, \"http://kickass.zone/media/3\").to_return(:status => 404)\n      stub_request(:get, \"http://kickass.zone/system/accounts/avatars/000/000/001/large/eris.png\").to_return(request_fixture('avatar.txt'))\n      stub_request(:get, \"http://kickass.zone/system/media_attachments/files/000/000/002/original/morpheus_linux.jpg?1476059910\").to_return(request_fixture('attachment1.txt'))\n      stub_request(:get, \"http://kickass.zone/system/media_attachments/files/000/000/003/original/gizmo.jpg?1476060065\").to_return(request_fixture('attachment2.txt'))\n    end\n\n    context 'when domain does not reject media' do\n      before do\n        subject.call(body, account)\n      end\n\n      it 'updates remote user\\'s account information' do\n        account.reload\n        expect(account.display_name).to eq '::1'\n        expect(account).to have_attached_file(:avatar)\n        expect(account.avatar_file_name).not_to be_nil\n      end\n\n      it 'creates posts' do\n        expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=1:objectType=Status')).to_not be_nil\n        expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=2:objectType=Status')).to_not be_nil\n      end\n\n      it 'marks replies as replies' do\n        status = Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=2:objectType=Status')\n        expect(status.reply?).to be true\n      end\n\n      it 'sets account being replied to when possible' do\n        status = Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=2:objectType=Status')\n        expect(status.in_reply_to_account_id).to eq status.account_id\n      end\n\n      it 'ignores delete statuses unless they existed before' do\n        expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=3:objectType=Status')).to be_nil\n        expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=12:objectType=Status')).to be_nil\n      end\n\n      it 'does not create statuses for follows' do\n        expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=1:objectType=Follow')).to be_nil\n        expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=2:objectType=Follow')).to be_nil\n        expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=4:objectType=Follow')).to be_nil\n        expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=7:objectType=Follow')).to be_nil\n      end\n\n      it 'does not create statuses for favourites' do\n        expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=2:objectType=Favourite')).to be_nil\n        expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=3:objectType=Favourite')).to be_nil\n      end\n\n      it 'creates posts with media' do\n        status = Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=14:objectType=Status')\n\n        expect(status).to_not be_nil\n        expect(status.media_attachments.first).to have_attached_file(:file)\n        expect(status.media_attachments.first.image?).to be true\n        expect(status.media_attachments.first.file_file_name).not_to be_nil\n      end\n    end\n\n    context 'when domain is set to reject media' do\n      let!(:domain_block) { Fabricate(:domain_block, domain: 'kickass.zone', reject_media: true) }\n\n      before do\n        subject.call(body, account)\n      end\n\n      it 'updates remote user\\'s account information' do\n        account.reload\n        expect(account.display_name).to eq '::1'\n      end\n\n      it 'rejects remote user\\'s avatar' do\n        account.reload\n        expect(account.display_name).to eq '::1'\n        expect(account.avatar_file_name).to be_nil\n      end\n\n      it 'creates posts' do\n        expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=1:objectType=Status')).to_not be_nil\n        expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=2:objectType=Status')).to_not be_nil\n      end\n\n      it 'creates posts with remote-only media' do\n        status = Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=14:objectType=Status')\n\n        expect(status).to_not be_nil\n        expect(status.media_attachments.first.file_file_name).to be_nil\n        expect(status.media_attachments.first.unknown?).to be true\n      end\n    end\n  end\n\n  it 'does not accept tampered reblogs' do\n    good_actor = Fabricate(:account, username: 'tracer', domain: 'overwatch.com')\n\n    real_body = <<XML\n<?xml version=\"1.0\"?>\n<entry xmlns=\"http://www.w3.org/2005/Atom\" xmlns:thr=\"http://purl.org/syndication/thread/1.0\" xmlns:activity=\"http://activitystrea.ms/spec/1.0/\" xmlns:poco=\"http://portablecontacts.net/spec/1.0\" xmlns:media=\"http://purl.org/syndication/atommedia\" xmlns:ostatus=\"http://ostatus.org/schema/1.0\" xmlns:mastodon=\"http://mastodon.social/schema/1.0\">\n  <id>tag:overwatch.com,2017-04-27:objectId=4467137:objectType=Status</id>\n  <published>2017-04-27T13:49:25Z</published>\n  <updated>2017-04-27T13:49:25Z</updated>\n  <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>\n  <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>\n  <author>\n    <id>https://overwatch.com/users/tracer</id>\n    <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>\n    <uri>https://overwatch.com/users/tracer</uri>\n    <name>tracer</name>\n  </author>\n  <content type=\"html\">Overwatch rocks</content>\n</entry>\nXML\n\n    stub_request(:get, 'https://overwatch.com/users/tracer/updates/1').to_return(status: 200, body: real_body, headers: { 'Content-Type' => 'application/atom+xml' })\n\n    bad_actor = Fabricate(:account, username: 'sombra', domain: 'talon.xyz')\n\n    body = <<XML\n<?xml version=\"1.0\"?>\n<entry xmlns=\"http://www.w3.org/2005/Atom\" xmlns:thr=\"http://purl.org/syndication/thread/1.0\" xmlns:activity=\"http://activitystrea.ms/spec/1.0/\" xmlns:poco=\"http://portablecontacts.net/spec/1.0\" xmlns:media=\"http://purl.org/syndication/atommedia\" xmlns:ostatus=\"http://ostatus.org/schema/1.0\" xmlns:mastodon=\"http://mastodon.social/schema/1.0\">\n  <id>tag:talon.xyz,2017-04-27:objectId=4467137:objectType=Status</id>\n  <published>2017-04-27T13:49:25Z</published>\n  <updated>2017-04-27T13:49:25Z</updated>\n  <author>\n    <id>https://talon.xyz/users/sombra</id>\n    <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>\n    <uri>https://talon.xyz/users/sombra</uri>\n    <name>sombra</name>\n  </author>\n  <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type>\n  <activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb>\n  <content type=\"html\">Overwatch SUCKS AHAHA</content>\n  <activity:object>\n    <id>tag:overwatch.com,2017-04-27:objectId=4467137:objectType=Status</id>\n    <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>\n    <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>\n    <author>\n      <id>https://overwatch.com/users/tracer</id>\n      <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>\n      <uri>https://overwatch.com/users/tracer</uri>\n      <name>tracer</name>\n    </author>\n    <content type=\"html\">Overwatch SUCKS AHAHA</content>\n    <link rel=\"alternate\" type=\"text/html\" href=\"https://overwatch.com/users/tracer/updates/1\" />\n  </activity:object>\n</entry>\nXML\n    created_statuses = subject.call(body, bad_actor)\n\n    expect(created_statuses.first.reblog?).to be true\n    expect(created_statuses.first.account_id).to eq bad_actor.id\n    expect(created_statuses.first.reblog.account_id).to eq good_actor.id\n    expect(created_statuses.first.reblog.text).to eq 'Overwatch rocks'\n  end\n\n  it 'ignores reblogs if it failed to retrieve reblogged statuses' do\n    stub_request(:get, 'https://overwatch.com/users/tracer/updates/1').to_return(status: 404)\n\n    actor = Fabricate(:account, username: 'tracer', domain: 'overwatch.com')\n\n    body = <<XML\n<?xml version=\"1.0\"?>\n<entry xmlns=\"http://www.w3.org/2005/Atom\" xmlns:thr=\"http://purl.org/syndication/thread/1.0\" xmlns:activity=\"http://activitystrea.ms/spec/1.0/\" xmlns:poco=\"http://portablecontacts.net/spec/1.0\" xmlns:media=\"http://purl.org/syndication/atommedia\" xmlns:ostatus=\"http://ostatus.org/schema/1.0\" xmlns:mastodon=\"http://mastodon.social/schema/1.0\">\n  <id>tag:overwatch.com,2017-04-27:objectId=4467137:objectType=Status</id>\n  <published>2017-04-27T13:49:25Z</published>\n  <updated>2017-04-27T13:49:25Z</updated>\n  <author>\n    <id>https://overwatch.com/users/tracer</id>\n    <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>\n    <uri>https://overwatch.com/users/tracer</uri>\n    <name>tracer</name>\n  </author>\n  <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type>\n  <activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb>\n  <content type=\"html\">Overwatch rocks</content>\n  <activity:object>\n    <id>tag:overwatch.com,2017-04-27:objectId=4467137:objectType=Status</id>\n    <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>\n    <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>\n    <author>\n      <id>https://overwatch.com/users/tracer</id>\n      <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>\n      <uri>https://overwatch.com/users/tracer</uri>\n      <name>tracer</name>\n    </author>\n    <content type=\"html\">Overwatch rocks</content>\n    <link rel=\"alternate\" type=\"text/html\" href=\"https://overwatch.com/users/tracer/updates/1\" />\n  </activity:object>\nXML\n\n    created_statuses = subject.call(body, actor)\n\n    expect(created_statuses).to eq []\n  end\n\n  it 'ignores statuses with an out-of-order delete' do\n    sender = Fabricate(:account, username: 'tracer', domain: 'overwatch.com')\n\n    delete_body = <<XML\n<?xml version=\"1.0\"?>\n<entry xmlns=\"http://www.w3.org/2005/Atom\" xmlns:thr=\"http://purl.org/syndication/thread/1.0\" xmlns:activity=\"http://activitystrea.ms/spec/1.0/\" xmlns:poco=\"http://portablecontacts.net/spec/1.0\" xmlns:media=\"http://purl.org/syndication/atommedia\" xmlns:ostatus=\"http://ostatus.org/schema/1.0\" xmlns:mastodon=\"http://mastodon.social/schema/1.0\">\n  <id>tag:overwatch.com,2017-04-27:objectId=4487555:objectType=Status</id>\n  <published>2017-04-27T13:49:25Z</published>\n  <updated>2017-04-27T13:49:25Z</updated>\n  <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>\n  <activity:verb>http://activitystrea.ms/schema/1.0/delete</activity:verb>\n  <author>\n    <id>https://overwatch.com/users/tracer</id>\n    <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>\n    <uri>https://overwatch.com/users/tracer</uri>\n    <name>tracer</name>\n  </author>\n</entry>\nXML\n\n    status_body = <<XML\n<?xml version=\"1.0\"?>\n<entry xmlns=\"http://www.w3.org/2005/Atom\" xmlns:thr=\"http://purl.org/syndication/thread/1.0\" xmlns:activity=\"http://activitystrea.ms/spec/1.0/\" xmlns:poco=\"http://portablecontacts.net/spec/1.0\" xmlns:media=\"http://purl.org/syndication/atommedia\" xmlns:ostatus=\"http://ostatus.org/schema/1.0\" xmlns:mastodon=\"http://mastodon.social/schema/1.0\">\n  <id>tag:overwatch.com,2017-04-27:objectId=4487555:objectType=Status</id>\n  <published>2017-04-27T13:49:25Z</published>\n  <updated>2017-04-27T13:49:25Z</updated>\n  <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>\n  <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>\n  <author>\n    <id>https://overwatch.com/users/tracer</id>\n    <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>\n    <uri>https://overwatch.com/users/tracer</uri>\n    <name>tracer</name>\n  </author>\n  <content type=\"html\">Overwatch rocks</content>\n</entry>\nXML\n\n    subject.call(delete_body, sender)\n    created_statuses = subject.call(status_body, sender)\n\n    expect(created_statuses).to be_empty\n  end\nend\n"
  },
  {
    "path": "spec/services/process_interaction_service_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe ProcessInteractionService, type: :service do\n  let(:receiver) { Fabricate(:user, email: 'alice@example.com', account: Fabricate(:account, username: 'alice')).account }\n  let(:sender)   { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account }\n  let(:remote_sender) { Fabricate(:account, username: 'carol', domain: 'localdomain.com', uri: 'https://webdomain.com/users/carol') }\n\n  subject { ProcessInteractionService.new }\n\n  describe 'status delete slap' do\n    let(:remote_status) { Fabricate(:status, account: remote_sender) }\n    let(:envelope) { OStatus2::Salmon.new.pack(payload, sender.keypair) }\n    let(:payload) {\n      <<~XML\n        <entry xmlns=\"http://www.w3.org/2005/Atom\" xmlns:activity=\"http://activitystrea.ms/spec/1.0/\">\n          <author>\n            <email>carol@localdomain.com</email>\n            <name>carol</name>\n            <uri>https://webdomain.com/users/carol</uri>\n          </author>\n\n          <id>#{remote_status.id}</id>\n          <activity:verb>http://activitystrea.ms/schema/1.0/delete</activity:verb>\n        </entry>\n      XML\n    }\n\n    before do\n      receiver.update(locked: true)\n      remote_sender.update(private_key: sender.private_key, public_key: remote_sender.public_key)\n    end\n\n    it 'deletes a record' do\n      expect(RemovalWorker).to receive(:perform_async).with(remote_status.id)\n      subject.call(envelope, receiver)\n    end\n  end\n\n  describe 'follow request slap' do\n    before do\n      receiver.update(locked: true)\n\n      payload = <<XML\n<entry xmlns=\"http://www.w3.org/2005/Atom\" xmlns:activity=\"http://activitystrea.ms/spec/1.0/\">\n  <author>\n    <name>bob</name>\n    <uri>https://cb6e6126.ngrok.io/users/bob</uri>\n  </author>\n\n  <id>someIdHere</id>\n  <activity:verb>http://activitystrea.ms/schema/1.0/request-friend</activity:verb>\n</entry>\nXML\n\n      envelope = OStatus2::Salmon.new.pack(payload, sender.keypair)\n      subject.call(envelope, receiver)\n    end\n\n    it 'creates a record' do\n      expect(FollowRequest.find_by(account: sender, target_account: receiver)).to_not be_nil\n    end\n  end\n\n  describe 'follow request slap from known remote user identified by email' do\n    before do\n      receiver.update(locked: true)\n      # Copy already-generated key\n      remote_sender.update(private_key: sender.private_key, public_key: remote_sender.public_key)\n\n      payload = <<XML\n<entry xmlns=\"http://www.w3.org/2005/Atom\" xmlns:activity=\"http://activitystrea.ms/spec/1.0/\">\n  <author>\n    <email>carol@localdomain.com</email>\n    <name>carol</name>\n    <uri>https://webdomain.com/users/carol</uri>\n  </author>\n\n  <id>someIdHere</id>\n  <activity:verb>http://activitystrea.ms/schema/1.0/request-friend</activity:verb>\n</entry>\nXML\n\n      envelope = OStatus2::Salmon.new.pack(payload, remote_sender.keypair)\n      subject.call(envelope, receiver)\n    end\n\n    it 'creates a record' do\n      expect(FollowRequest.find_by(account: remote_sender, target_account: receiver)).to_not be_nil\n    end\n  end\n\n  describe 'follow request authorization slap' do\n    before do\n      receiver.update(locked: true)\n      FollowRequest.create(account: sender, target_account: receiver)\n\n      payload = <<XML\n<entry xmlns=\"http://www.w3.org/2005/Atom\" xmlns:activity=\"http://activitystrea.ms/spec/1.0/\">\n  <author>\n    <name>alice</name>\n    <uri>https://cb6e6126.ngrok.io/users/alice</uri>\n  </author>\n\n  <id>someIdHere</id>\n  <activity:verb>http://activitystrea.ms/schema/1.0/authorize</activity:verb>\n</entry>\nXML\n\n      envelope = OStatus2::Salmon.new.pack(payload, receiver.keypair)\n      subject.call(envelope, sender)\n    end\n\n    it 'creates a follow relationship' do\n      expect(Follow.find_by(account: sender, target_account: receiver)).to_not be_nil\n    end\n\n    it 'removes the follow request' do\n      expect(FollowRequest.find_by(account: sender, target_account: receiver)).to be_nil\n    end\n  end\n\n  describe 'follow request rejection slap' do\n    before do\n      receiver.update(locked: true)\n      FollowRequest.create(account: sender, target_account: receiver)\n\n      payload = <<XML\n<entry xmlns=\"http://www.w3.org/2005/Atom\" xmlns:activity=\"http://activitystrea.ms/spec/1.0/\">\n  <author>\n    <name>alice</name>\n    <uri>https://cb6e6126.ngrok.io/users/alice</uri>\n  </author>\n\n  <id>someIdHere</id>\n  <activity:verb>http://activitystrea.ms/schema/1.0/reject</activity:verb>\n</entry>\nXML\n\n      envelope = OStatus2::Salmon.new.pack(payload, receiver.keypair)\n      subject.call(envelope, sender)\n    end\n\n    it 'does not create a follow relationship' do\n      expect(Follow.find_by(account: sender, target_account: receiver)).to be_nil\n    end\n\n    it 'removes the follow request' do\n      expect(FollowRequest.find_by(account: sender, target_account: receiver)).to be_nil\n    end\n  end\nend\n"
  },
  {
    "path": "spec/services/process_mentions_service_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe ProcessMentionsService, type: :service do\n  let(:account)    { Fabricate(:account, username: 'alice') }\n  let(:visibility) { :public }\n  let(:status)     { Fabricate(:status, account: account, text: \"Hello @#{remote_user.acct}\", visibility: visibility) }\n\n  context 'OStatus with public toot' do\n    let(:remote_user) { Fabricate(:account, username: 'remote_user', protocol: :ostatus, domain: 'example.com', salmon_url: 'http://salmon.example.com') }\n\n    subject { ProcessMentionsService.new }\n\n    before do\n      stub_request(:post, remote_user.salmon_url)\n      subject.call(status)\n    end\n\n    it 'creates a mention' do\n      expect(remote_user.mentions.where(status: status).count).to eq 1\n    end\n\n    it 'posts to remote user\\'s Salmon end point' do\n      expect(a_request(:post, remote_user.salmon_url)).to have_been_made.once\n    end\n  end\n\n  context 'OStatus with private toot' do\n    let(:visibility)  { :private }\n    let(:remote_user) { Fabricate(:account, username: 'remote_user', protocol: :ostatus, domain: 'example.com', salmon_url: 'http://salmon.example.com') }\n\n    subject { ProcessMentionsService.new }\n\n    before do\n      stub_request(:post, remote_user.salmon_url)\n      subject.call(status)\n    end\n\n    it 'does not create a mention' do\n      expect(remote_user.mentions.where(status: status).count).to eq 0\n    end\n\n    it 'does not post to remote user\\'s Salmon end point' do\n      expect(a_request(:post, remote_user.salmon_url)).to_not have_been_made\n    end\n  end\n\n  context 'ActivityPub' do\n    let(:remote_user) { Fabricate(:account, username: 'remote_user', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') }\n\n    subject { ProcessMentionsService.new }\n\n    before do\n      stub_request(:post, remote_user.inbox_url)\n      subject.call(status)\n    end\n\n    it 'creates a mention' do\n      expect(remote_user.mentions.where(status: status).count).to eq 1\n    end\n\n    it 'sends activity to the inbox' do\n      expect(a_request(:post, remote_user.inbox_url)).to have_been_made.once\n    end\n  end\n\n  context 'Temporarily-unreachable ActivityPub user' do\n    let(:remote_user) { Fabricate(:account, username: 'remote_user', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox', last_webfingered_at: nil) }\n\n    subject { ProcessMentionsService.new }\n\n    before do\n      stub_request(:get, \"https://example.com/.well-known/host-meta\").to_return(status: 404)\n      stub_request(:get, \"https://example.com/.well-known/webfinger?resource=acct:remote_user@example.com\").to_return(status: 500)\n      stub_request(:post, remote_user.inbox_url)\n      subject.call(status)\n    end\n\n    it 'creates a mention' do\n      expect(remote_user.mentions.where(status: status).count).to eq 1\n    end\n\n    it 'sends activity to the inbox' do\n      expect(a_request(:post, remote_user.inbox_url)).to have_been_made.once\n    end\n  end\nend\n"
  },
  {
    "path": "spec/services/pubsubhubbub/subscribe_service_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe Pubsubhubbub::SubscribeService, type: :service do\n  describe '#call' do\n    subject { described_class.new }\n    let(:user_account) { Fabricate(:account) }\n\n    context 'with a nil account' do\n      it 'returns the invalid topic status results' do\n        result = service_call(account: nil)\n\n        expect(result).to eq invalid_topic_status\n      end\n    end\n\n    context 'with an invalid callback url' do\n      it 'returns invalid callback status when callback is blank' do\n        result = service_call(callback: '')\n\n        expect(result).to eq invalid_callback_status\n      end\n      it 'returns invalid callback status when callback is not a URI' do\n        result = service_call(callback: 'invalid-hostname')\n\n        expect(result).to eq invalid_callback_status\n      end\n    end\n\n    context 'with a blocked domain in the callback' do\n      it 'returns callback not allowed' do\n        Fabricate(:domain_block, domain: 'test.host', severity: :suspend)\n        result = service_call(callback: 'https://test.host/api')\n\n        expect(result).to eq not_allowed_callback_status\n      end\n    end\n\n    context 'with a valid account and callback' do\n      it 'returns success status and confirms subscription' do\n        allow(Pubsubhubbub::ConfirmationWorker).to receive(:perform_async).and_return(nil)\n        subscription = Fabricate(:subscription, account: user_account)\n\n        result = service_call(callback: subscription.callback_url)\n        expect(result).to eq success_status\n        expect(Pubsubhubbub::ConfirmationWorker).to have_received(:perform_async).with(subscription.id, 'subscribe', 'asdf', 3600)\n      end\n    end\n  end\n\n  def service_call(account: user_account, callback: 'https://callback.host', secret: 'asdf', lease_seconds: 3600)\n    subject.call(account, callback, secret, lease_seconds)\n  end\n\n  def invalid_topic_status\n    ['Invalid topic URL', 422]\n  end\n\n  def invalid_callback_status\n    ['Invalid callback URL', 422]\n  end\n\n  def not_allowed_callback_status\n    ['Callback URL not allowed', 403]\n  end\n\n  def success_status\n    ['', 202]\n  end\nend\n"
  },
  {
    "path": "spec/services/pubsubhubbub/unsubscribe_service_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe Pubsubhubbub::UnsubscribeService, type: :service do\n  describe '#call' do\n    subject { described_class.new }\n\n    context 'with a nil account' do\n      it 'returns an invalid topic status' do\n        result = subject.call(nil, 'callback.host')\n\n        expect(result).to eq invalid_topic_status\n      end\n    end\n\n    context 'with a valid account' do\n      let(:account) { Fabricate(:account) }\n\n      it 'returns a valid topic status and does not run confirm when no subscription' do\n        allow(Pubsubhubbub::ConfirmationWorker).to receive(:perform_async).and_return(nil)\n        result = subject.call(account, 'callback.host')\n\n        expect(result).to eq valid_topic_status\n        expect(Pubsubhubbub::ConfirmationWorker).not_to have_received(:perform_async)\n      end\n\n      it 'returns a valid topic status and does run confirm when there is a subscription' do\n        subscription = Fabricate(:subscription, account: account, callback_url: 'callback.host')\n        allow(Pubsubhubbub::ConfirmationWorker).to receive(:perform_async).and_return(nil)\n        result = subject.call(account, 'callback.host')\n\n        expect(result).to eq valid_topic_status\n        expect(Pubsubhubbub::ConfirmationWorker).to have_received(:perform_async).with(subscription.id, 'unsubscribe')\n      end\n    end\n\n    def invalid_topic_status\n      ['Invalid topic URL', 422]\n    end\n\n    def valid_topic_status\n      ['', 202]\n    end\n  end\nend\n"
  },
  {
    "path": "spec/services/reblog_service_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe ReblogService, type: :service do\n  let(:alice)  { Fabricate(:account, username: 'alice') }\n\n  context 'creates a reblog with appropriate visibility' do\n    let(:visibility)        { :public }\n    let(:reblog_visibility) { :public }\n    let(:status)            { Fabricate(:status, account: alice, visibility: visibility) }\n\n    subject { ReblogService.new }\n\n    before do\n      subject.call(alice, status, visibility: reblog_visibility)\n    end\n\n    describe 'boosting privately' do\n      let(:reblog_visibility) { :private }\n\n      it 'reblogs privately' do\n        expect(status.reblogs.first.visibility).to eq 'private'\n      end\n    end\n\n    describe 'public reblogs of private toots should remain private' do\n      let(:visibility)        { :private }\n      let(:reblog_visibility) { :public }\n\n      it 'reblogs privately' do\n        expect(status.reblogs.first.visibility).to eq 'private'\n      end\n    end\n  end\n\n  context 'OStatus' do\n    let(:bob)    { Fabricate(:account, username: 'bob', domain: 'example.com', salmon_url: 'http://salmon.example.com') }\n    let(:status) { Fabricate(:status, account: bob, uri: 'tag:example.com;something:something') }\n\n    subject { ReblogService.new }\n\n    before do\n      stub_request(:post, 'http://salmon.example.com')\n      subject.call(alice, status)\n    end\n\n    it 'creates a reblog' do\n      expect(status.reblogs.count).to eq 1\n    end\n\n    it 'sends a Salmon slap for a remote reblog' do\n      expect(a_request(:post, 'http://salmon.example.com')).to have_been_made\n    end\n  end\n\n  context 'ActivityPub' do\n    let(:bob)    { Fabricate(:account, username: 'bob', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') }\n    let(:status) { Fabricate(:status, account: bob) }\n\n    subject { ReblogService.new }\n\n    before do\n      stub_request(:post, bob.inbox_url)\n      allow(ActivityPub::DistributionWorker).to receive(:perform_async)\n      subject.call(alice, status)\n    end\n\n    it 'creates a reblog' do\n      expect(status.reblogs.count).to eq 1\n    end\n\n    describe 'after_create_commit :store_uri' do\n      it 'keeps consistent reblog count' do\n        expect(status.reblogs.count).to eq 1\n      end\n    end\n\n    it 'distributes to followers' do\n      expect(ActivityPub::DistributionWorker).to have_received(:perform_async)\n    end\n\n    it 'sends an announce activity to the author' do\n      expect(a_request(:post, bob.inbox_url)).to have_been_made.once\n    end\n  end\nend\n"
  },
  {
    "path": "spec/services/reject_follow_service_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe RejectFollowService, type: :service do\n  let(:sender) { Fabricate(:account, username: 'alice') }\n\n  subject { RejectFollowService.new }\n\n  describe 'local' do\n    let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account }\n\n    before do\n      FollowRequest.create(account: bob, target_account: sender)\n      subject.call(bob, sender)\n    end\n\n    it 'removes follow request' do\n      expect(bob.requested?(sender)).to be false\n    end\n\n    it 'does not create follow relation' do\n      expect(bob.following?(sender)).to be false\n    end\n  end\n\n  describe 'remote OStatus' do\n    let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob', domain: 'example.com', salmon_url: 'http://salmon.example.com')).account }\n\n    before do\n      FollowRequest.create(account: bob, target_account: sender)\n      stub_request(:post, \"http://salmon.example.com/\").to_return(:status => 200, :body => \"\", :headers => {})\n      subject.call(bob, sender)\n    end\n\n    it 'removes follow request' do\n      expect(bob.requested?(sender)).to be false\n    end\n\n    it 'does not create follow relation' do\n      expect(bob.following?(sender)).to be false\n    end\n\n    it 'sends a follow request rejection salmon slap' do\n      expect(a_request(:post, \"http://salmon.example.com/\").with { |req|\n        xml = OStatus2::Salmon.new.unpack(req.body)\n        xml.match(OStatus::TagManager::VERBS[:reject])\n      }).to have_been_made.once\n    end\n  end\n\n  describe 'remote ActivityPub' do\n    let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob', domain: 'example.com', protocol: :activitypub, inbox_url: 'http://example.com/inbox')).account }\n\n    before do\n      FollowRequest.create(account: bob, target_account: sender)\n      stub_request(:post, bob.inbox_url).to_return(status: 200)\n      subject.call(bob, sender)\n    end\n\n    it 'removes follow request' do\n      expect(bob.requested?(sender)).to be false\n    end\n\n    it 'does not create follow relation' do\n      expect(bob.following?(sender)).to be false\n    end\n\n    it 'sends a reject activity' do\n      expect(a_request(:post, bob.inbox_url)).to have_been_made.once\n    end\n  end\nend\n"
  },
  {
    "path": "spec/services/remove_status_service_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe RemoveStatusService, type: :service do\n  subject { RemoveStatusService.new }\n\n  let!(:alice)  { Fabricate(:account) }\n  let!(:bob)    { Fabricate(:account, username: 'bob', domain: 'example.com', salmon_url: 'http://example.com/salmon') }\n  let!(:jeff)   { Fabricate(:account) }\n  let!(:hank)   { Fabricate(:account, username: 'hank', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') }\n  let!(:bill)   { Fabricate(:account, username: 'bill', protocol: :activitypub, domain: 'example2.com', inbox_url: 'http://example2.com/inbox') }\n\n  before do\n    stub_request(:post, 'http://example.com/push').to_return(status: 200, body: '', headers: {})\n    stub_request(:post, 'http://example.com/salmon').to_return(status: 200, body: '', headers: {})\n    stub_request(:post, 'http://example.com/inbox').to_return(status: 200)\n    stub_request(:post, 'http://example2.com/inbox').to_return(status: 200)\n\n    Fabricate(:subscription, account: alice, callback_url: 'http://example.com/push', confirmed: true, expires_at: 30.days.from_now)\n    jeff.follow!(alice)\n    hank.follow!(alice)\n\n    @status = PostStatusService.new.call(alice, text: 'Hello @bob@example.com')\n    Fabricate(:status, account: bill, reblog: @status, uri: 'hoge')\n    subject.call(@status)\n  end\n\n  it 'removes status from author\\'s home feed' do\n    expect(HomeFeed.new(alice).get(10)).to_not include(@status.id)\n  end\n\n  it 'removes status from local follower\\'s home feed' do\n    expect(HomeFeed.new(jeff).get(10)).to_not include(@status.id)\n  end\n\n  it 'sends PuSH update to PuSH subscribers' do\n    expect(a_request(:post, 'http://example.com/push').with { |req|\n      req.body.match(OStatus::TagManager::VERBS[:delete])\n    }).to have_been_made\n  end\n\n  it 'sends delete activity to followers' do\n    expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.twice\n  end\n\n  it 'sends Salmon slap to previously mentioned users' do\n    expect(a_request(:post, \"http://example.com/salmon\").with { |req|\n      xml = OStatus2::Salmon.new.unpack(req.body)\n      xml.match(OStatus::TagManager::VERBS[:delete])\n    }).to have_been_made.once\n  end\n\n  it 'sends delete activity to rebloggers' do\n    expect(a_request(:post, 'http://example2.com/inbox')).to have_been_made\n  end\nend\n"
  },
  {
    "path": "spec/services/report_service_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe ReportService, type: :service do\n  subject { described_class.new }\n\n  let(:source_account) { Fabricate(:user).account }\n\n  context 'for a remote account' do\n    let(:remote_account) { Fabricate(:account, domain: 'example.com', protocol: :activitypub, inbox_url: 'http://example.com/inbox') }\n\n    before do\n      stub_request(:post, 'http://example.com/inbox').to_return(status: 200)\n    end\n\n    it 'sends ActivityPub payload when forward is true' do\n      subject.call(source_account, remote_account, forward: true)\n      expect(a_request(:post, 'http://example.com/inbox')).to have_been_made\n    end\n\n    it 'does not send anything when forward is false' do\n      subject.call(source_account, remote_account, forward: false)\n      expect(a_request(:post, 'http://example.com/inbox')).to_not have_been_made\n    end\n\n    it 'has an uri' do\n      report = subject.call(source_account, remote_account, forward: true)\n      expect(report.uri).to_not be_nil\n    end\n  end\n\n  context 'when other reports already exist for the same target' do\n    let!(:target_account) { Fabricate(:account) }\n    let!(:other_report)   { Fabricate(:report, target_account: target_account) }\n\n    subject do\n      -> {  described_class.new.call(source_account, target_account) }\n    end\n\n    before do\n      ActionMailer::Base.deliveries.clear\n      source_account.user.settings.notification_emails['report'] = true\n    end\n\n    it 'does not send an e-mail' do\n      is_expected.to_not change(ActionMailer::Base.deliveries, :count).from(0)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/services/resolve_account_service_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe ResolveAccountService, type: :service do\n  subject { described_class.new }\n\n  before do\n    stub_request(:get, \"https://quitter.no/.well-known/host-meta\").to_return(request_fixture('.host-meta.txt'))\n    stub_request(:get, \"https://example.com/.well-known/webfinger?resource=acct:catsrgr8@example.com\").to_return(status: 404)\n    stub_request(:get, \"https://redirected.com/.well-known/host-meta\").to_return(request_fixture('redirected.host-meta.txt'))\n    stub_request(:get, \"https://example.com/.well-known/host-meta\").to_return(status: 404)\n    stub_request(:get, \"https://quitter.no/.well-known/webfinger?resource=acct:gargron@quitter.no\").to_return(request_fixture('webfinger.txt'))\n    stub_request(:get, \"https://redirected.com/.well-known/webfinger?resource=acct:gargron@redirected.com\").to_return(request_fixture('webfinger.txt'))\n    stub_request(:get, \"https://redirected.com/.well-known/webfinger?resource=acct:hacker1@redirected.com\").to_return(request_fixture('webfinger-hacker1.txt'))\n    stub_request(:get, \"https://redirected.com/.well-known/webfinger?resource=acct:hacker2@redirected.com\").to_return(request_fixture('webfinger-hacker2.txt'))\n    stub_request(:get, \"https://quitter.no/.well-known/webfinger?resource=acct:catsrgr8@quitter.no\").to_return(status: 404)\n    stub_request(:get, \"https://quitter.no/api/statuses/user_timeline/7477.atom\").to_return(request_fixture('feed.txt'))\n    stub_request(:get, \"https://quitter.no/avatar/7477-300-20160211190340.png\").to_return(request_fixture('avatar.txt'))\n    stub_request(:get, \"https://localdomain.com/.well-known/host-meta\").to_return(request_fixture('localdomain-hostmeta.txt'))\n    stub_request(:get, \"https://localdomain.com/.well-known/webfinger?resource=acct:foo@localdomain.com\").to_return(status: 404)\n    stub_request(:get, \"https://webdomain.com/.well-known/webfinger?resource=acct:foo@localdomain.com\").to_return(request_fixture('localdomain-webfinger.txt'))\n    stub_request(:get, \"https://webdomain.com/users/foo.atom\").to_return(request_fixture('localdomain-feed.txt'))\n  end\n\n  it 'raises error if no such user can be resolved via webfinger' do\n    expect(subject.call('catsrgr8@quitter.no')).to be_nil\n  end\n\n  it 'raises error if the domain does not have webfinger' do\n    expect(subject.call('catsrgr8@example.com')).to be_nil\n  end\n\n  it 'prevents hijacking existing accounts' do\n    account = subject.call('hacker1@redirected.com')\n    expect(account.salmon_url).to_not eq 'https://hacker.com/main/salmon/user/7477'\n  end\n\n  it 'prevents hijacking inexisting accounts' do\n    expect(subject.call('hacker2@redirected.com')).to be_nil\n  end\n\n  context 'with an OStatus account' do\n    it 'returns an already existing remote account' do\n      old_account      = Fabricate(:account, username: 'gargron', domain: 'quitter.no')\n      returned_account = subject.call('gargron@quitter.no')\n\n      expect(old_account.id).to eq returned_account.id\n    end\n\n    it 'returns a new remote account' do\n      account = subject.call('gargron@quitter.no')\n\n      expect(account.username).to eq 'gargron'\n      expect(account.domain).to eq 'quitter.no'\n      expect(account.remote_url).to eq 'https://quitter.no/api/statuses/user_timeline/7477.atom'\n    end\n\n    it 'follows a legitimate account redirection' do\n      account = subject.call('gargron@redirected.com')\n\n      expect(account.username).to eq 'gargron'\n      expect(account.domain).to eq 'quitter.no'\n      expect(account.remote_url).to eq 'https://quitter.no/api/statuses/user_timeline/7477.atom'\n    end\n\n    it 'returns a new remote account' do\n      account = subject.call('foo@localdomain.com')\n\n      expect(account.username).to eq 'foo'\n      expect(account.domain).to eq 'localdomain.com'\n      expect(account.remote_url).to eq 'https://webdomain.com/users/foo.atom'\n    end\n  end\n\n  context 'with an ActivityPub account' do\n    before do\n      stub_request(:get, \"https://ap.example.com/.well-known/webfinger?resource=acct:foo@ap.example.com\").to_return(request_fixture('activitypub-webfinger.txt'))\n      stub_request(:get, \"https://ap.example.com/users/foo\").to_return(request_fixture('activitypub-actor.txt'))\n      stub_request(:get, \"https://ap.example.com/users/foo.atom\").to_return(request_fixture('activitypub-feed.txt'))\n      stub_request(:get, %r{https://ap.example.com/users/foo/\\w+}).to_return(status: 404)\n    end\n\n    it 'fallback to OStatus if actor json could not be fetched' do\n      stub_request(:get, \"https://ap.example.com/users/foo\").to_return(status: 404)\n\n      account = subject.call('foo@ap.example.com')\n\n      expect(account.ostatus?).to eq true\n      expect(account.remote_url).to eq 'https://ap.example.com/users/foo.atom'\n    end\n\n    it 'fallback to OStatus if actor json did not have inbox_url' do\n      stub_request(:get, \"https://ap.example.com/users/foo\").to_return(request_fixture('activitypub-actor-noinbox.txt'))\n\n      account = subject.call('foo@ap.example.com')\n\n      expect(account.ostatus?).to eq true\n      expect(account.remote_url).to eq 'https://ap.example.com/users/foo.atom'\n    end\n\n    it 'returns new remote account' do\n      account = subject.call('foo@ap.example.com')\n\n      expect(account.activitypub?).to eq true\n      expect(account.domain).to eq 'ap.example.com'\n      expect(account.inbox_url).to eq 'https://ap.example.com/users/foo/inbox'\n    end\n\n    context 'with multiple types' do\n      before do\n        stub_request(:get, \"https://ap.example.com/users/foo\").to_return(request_fixture('activitypub-actor-individual.txt'))\n      end\n\n      it 'returns new remote account' do\n        account = subject.call('foo@ap.example.com')\n\n        expect(account.activitypub?).to eq true\n        expect(account.domain).to eq 'ap.example.com'\n        expect(account.inbox_url).to eq 'https://ap.example.com/users/foo/inbox'\n        expect(account.actor_type).to eq 'Person'\n      end\n    end\n  end\n\n  it 'processes one remote account at a time using locks' do\n    wait_for_start = true\n    fail_occurred  = false\n    return_values  = []\n\n    threads = Array.new(5) do\n      Thread.new do\n        true while wait_for_start\n        begin\n          return_values << described_class.new.call('foo@localdomain.com')\n        rescue ActiveRecord::RecordNotUnique\n          fail_occurred = true\n        end\n      end\n    end\n\n    wait_for_start = false\n    threads.each(&:join)\n\n    expect(fail_occurred).to be false\n    expect(return_values).to_not include(nil)\n  end\nend\n"
  },
  {
    "path": "spec/services/resolve_url_service_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe ResolveURLService, type: :service do\n  subject { described_class.new }\n\n  describe '#call' do\n    it 'returns nil when there is no atom url' do\n      url = 'http://example.com/missing-atom'\n      service = double\n      allow(FetchAtomService).to receive(:new).and_return service\n      allow(service).to receive(:call).with(url).and_return(nil)\n\n      result = subject.call(url)\n      expect(result).to be_nil\n    end\n\n    it 'fetches remote accounts for feed types' do\n      url = 'http://example.com/atom-feed'\n      service = double\n      allow(FetchAtomService).to receive(:new).and_return service\n      feed_url = 'http://feed-url'\n      feed_content = '<feed>contents</feed>'\n      allow(service).to receive(:call).with(url).and_return([feed_url, { prefetched_body: feed_content }])\n\n      account_service = double\n      allow(FetchRemoteAccountService).to receive(:new).and_return(account_service)\n      allow(account_service).to receive(:call)\n\n      _result = subject.call(url)\n\n      expect(account_service).to have_received(:call).with(feed_url, feed_content, nil)\n    end\n\n    it 'fetches remote statuses for entry types' do\n      url = 'http://example.com/atom-entry'\n      service = double\n      allow(FetchAtomService).to receive(:new).and_return service\n      feed_url = 'http://feed-url'\n      feed_content = '<entry>contents</entry>'\n      allow(service).to receive(:call).with(url).and_return([feed_url, { prefetched_body: feed_content }])\n\n      account_service = double\n      allow(FetchRemoteStatusService).to receive(:new).and_return(account_service)\n      allow(account_service).to receive(:call)\n\n      _result = subject.call(url)\n\n      expect(account_service).to have_received(:call).with(feed_url, feed_content, nil)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/services/search_service_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe SearchService, type: :service do\n  subject { described_class.new }\n\n  describe '#call' do\n    describe 'with a blank query' do\n      it 'returns empty results without searching' do\n        allow(AccountSearchService).to receive(:new)\n        allow(Tag).to receive(:search_for)\n        results = subject.call('', nil, 10)\n\n        expect(results).to eq(empty_results)\n        expect(AccountSearchService).not_to have_received(:new)\n        expect(Tag).not_to have_received(:search_for)\n      end\n    end\n\n    describe 'with an url query' do\n      before do\n        @query = 'http://test.host/query'\n      end\n\n      context 'that does not find anything' do\n        it 'returns the empty results' do\n          service = double(call: nil)\n          allow(ResolveURLService).to receive(:new).and_return(service)\n          results = subject.call(@query, nil, 10)\n\n          expect(service).to have_received(:call).with(@query, on_behalf_of: nil)\n          expect(results).to eq empty_results\n        end\n      end\n\n      context 'that finds an account' do\n        it 'includes the account in the results' do\n          account = Account.new\n          service = double(call: account)\n          allow(ResolveURLService).to receive(:new).and_return(service)\n\n          results = subject.call(@query, nil, 10)\n          expect(service).to have_received(:call).with(@query, on_behalf_of: nil)\n          expect(results).to eq empty_results.merge(accounts: [account])\n        end\n      end\n\n      context 'that finds a status' do\n        it 'includes the status in the results' do\n          status = Status.new\n          service = double(call: status)\n          allow(ResolveURLService).to receive(:new).and_return(service)\n\n          results = subject.call(@query, nil, 10)\n          expect(service).to have_received(:call).with(@query, on_behalf_of: nil)\n          expect(results).to eq empty_results.merge(statuses: [status])\n        end\n      end\n    end\n\n    describe 'with a non-url query' do\n      context 'that matches an account' do\n        it 'includes the account in the results' do\n          query = 'username'\n          account = Account.new\n          service = double(call: [account])\n          allow(AccountSearchService).to receive(:new).and_return(service)\n\n          results = subject.call(query, nil, 10)\n          expect(service).to have_received(:call).with(query, nil, limit: 10, offset: 0, resolve: false)\n          expect(results).to eq empty_results.merge(accounts: [account])\n        end\n      end\n\n      context 'that matches a tag' do\n        it 'includes the tag in the results' do\n          query = '#tag'\n          tag = Tag.new\n          allow(Tag).to receive(:search_for).with('tag', 10, 0).and_return([tag])\n\n          results = subject.call(query, nil, 10)\n          expect(Tag).to have_received(:search_for).with('tag', 10, 0)\n          expect(results).to eq empty_results.merge(hashtags: [tag])\n        end\n        it 'does not include tag when starts with @ character' do\n          query = '@username'\n          allow(Tag).to receive(:search_for)\n\n          results = subject.call(query, nil, 10)\n          expect(Tag).not_to have_received(:search_for)\n          expect(results).to eq empty_results\n        end\n      end\n    end\n  end\n\n  def empty_results\n    { accounts: [], hashtags: [], statuses: [] }\n  end\nend\n"
  },
  {
    "path": "spec/services/send_interaction_service_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe SendInteractionService, type: :service do\n  subject { SendInteractionService.new }\n\n  it 'sends an XML envelope to the Salmon end point of remote user'\nend\n"
  },
  {
    "path": "spec/services/subscribe_service_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe SubscribeService, type: :service do\n  let(:account) { Fabricate(:account, username: 'bob', domain: 'example.com', hub_url: 'http://hub.example.com') }\n  subject { SubscribeService.new }\n\n  it 'sends subscription request to PuSH hub' do\n    stub_request(:post, 'http://hub.example.com/').to_return(status: 202)\n    subject.call(account)\n    expect(a_request(:post, 'http://hub.example.com/')).to have_been_made.once\n  end\n\n  it 'generates and keeps PuSH secret on successful call' do\n    stub_request(:post, 'http://hub.example.com/').to_return(status: 202)\n    subject.call(account)\n    expect(account.secret).to_not be_blank\n  end\n\n  it 'fails silently if PuSH hub forbids subscription' do\n    stub_request(:post, 'http://hub.example.com/').to_return(status: 403)\n    subject.call(account)\n  end\n\n  it 'fails silently if PuSH hub is not found' do\n    stub_request(:post, 'http://hub.example.com/').to_return(status: 404)\n    subject.call(account)\n  end\n\n  it 'fails loudly if there is a network error' do\n    stub_request(:post, 'http://hub.example.com/').to_raise(HTTP::Error)\n    expect { subject.call(account) }.to raise_error HTTP::Error\n  end\n\n  it 'fails loudly if PuSH hub is unavailable' do\n    stub_request(:post, 'http://hub.example.com/').to_return(status: 503)\n    expect { subject.call(account) }.to raise_error Mastodon::UnexpectedResponseError\n  end\n\n  it 'fails loudly if rate limited' do\n    stub_request(:post, 'http://hub.example.com/').to_return(status: 429)\n    expect { subject.call(account) }.to raise_error Mastodon::UnexpectedResponseError\n  end\nend\n"
  },
  {
    "path": "spec/services/suspend_account_service_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe SuspendAccountService, type: :service do\n  describe '#call on local account' do\n    before do\n      stub_request(:post, \"https://alice.com/inbox\").to_return(status: 201)\n      stub_request(:post, \"https://bob.com/inbox\").to_return(status: 201)\n    end\n\n    subject do\n      -> { described_class.new.call(account) }\n    end\n\n    let!(:account) { Fabricate(:account) }\n    let!(:status) { Fabricate(:status, account: account) }\n    let!(:media_attachment) { Fabricate(:media_attachment, account: account) }\n    let!(:notification) { Fabricate(:notification, account: account) }\n    let!(:favourite) { Fabricate(:favourite, account: account) }\n    let!(:active_relationship) { Fabricate(:follow, account: account) }\n    let!(:passive_relationship) { Fabricate(:follow, target_account: account) }\n    let!(:subscription) { Fabricate(:subscription, account: account) }\n    let!(:remote_alice) { Fabricate(:account, inbox_url: 'https://alice.com/inbox', protocol: :activitypub) }\n    let!(:remote_bob) { Fabricate(:account, inbox_url: 'https://bob.com/inbox', protocol: :activitypub) }\n\n    it 'deletes associated records' do\n      is_expected.to change {\n        [\n          account.statuses,\n          account.media_attachments,\n          account.stream_entries,\n          account.notifications,\n          account.favourites,\n          account.active_relationships,\n          account.passive_relationships,\n          account.subscriptions\n        ].map(&:count)\n      }.from([1, 1, 1, 1, 1, 1, 1, 1]).to([0, 0, 0, 0, 0, 0, 0, 0])\n    end\n\n    it 'sends a delete actor activity to all known inboxes' do\n      subject.call\n      expect(a_request(:post, \"https://alice.com/inbox\")).to have_been_made.once\n      expect(a_request(:post, \"https://bob.com/inbox\")).to have_been_made.once\n    end\n  end\n\n  describe '#call on remote account' do\n    before do\n      stub_request(:post, \"https://alice.com/inbox\").to_return(status: 201)\n      stub_request(:post, \"https://bob.com/inbox\").to_return(status: 201)\n    end\n\n    subject do\n      -> { described_class.new.call(remote_bob) }\n    end\n\n    let!(:account) { Fabricate(:account) }\n    let!(:remote_alice) { Fabricate(:account, inbox_url: 'https://alice.com/inbox', protocol: :activitypub) }\n    let!(:remote_bob) { Fabricate(:account, inbox_url: 'https://bob.com/inbox', protocol: :activitypub) }\n    let!(:status) { Fabricate(:status, account: remote_bob) }\n    let!(:media_attachment) { Fabricate(:media_attachment, account: remote_bob) }\n    let!(:notification) { Fabricate(:notification, account: remote_bob) }\n    let!(:favourite) { Fabricate(:favourite, account: remote_bob) }\n    let!(:active_relationship) { Fabricate(:follow, account: remote_bob, target_account: account) }\n    let!(:passive_relationship) { Fabricate(:follow, target_account: remote_bob) }\n    let!(:subscription) { Fabricate(:subscription, account: remote_bob) }\n\n    it 'deletes associated records' do\n      is_expected.to change {\n        [\n          remote_bob.statuses,\n          remote_bob.media_attachments,\n          remote_bob.stream_entries,\n          remote_bob.notifications,\n          remote_bob.favourites,\n          remote_bob.active_relationships,\n          remote_bob.passive_relationships,\n          remote_bob.subscriptions\n        ].map(&:count)\n      }.from([1, 1, 1, 1, 1, 1, 1, 1]).to([0, 0, 0, 0, 0, 0, 0, 0])\n    end\n\n    it 'sends a reject follow to follwer inboxes' do\n      subject.call\n      expect(a_request(:post, remote_bob.inbox_url)).to have_been_made.once\n    end\n  end\nend\n"
  },
  {
    "path": "spec/services/unblock_domain_service_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe UnblockDomainService, type: :service do\n  subject { described_class.new }\n\n  describe 'call' do\n    before do\n      @independently_suspended = Fabricate(:account, domain: 'example.com', suspended_at: 1.hour.ago)\n      @independently_silenced = Fabricate(:account, domain: 'example.com', silenced_at: 1.hour.ago)\n      @domain_block = Fabricate(:domain_block, domain: 'example.com')\n      @silenced = Fabricate(:account, domain: 'example.com', silenced_at: @domain_block.created_at)\n      @suspended = Fabricate(:account, domain: 'example.com', suspended_at: @domain_block.created_at)\n    end\n\n    it 'unsilences accounts and removes block' do\n      @domain_block.update(severity: :silence)\n\n      subject.call(@domain_block)\n      expect_deleted_domain_block\n      expect(@silenced.reload.silenced?).to be false\n      expect(@suspended.reload.suspended?).to be true\n      expect(@independently_suspended.reload.suspended?).to be true\n      expect(@independently_silenced.reload.silenced?).to be true\n    end\n\n    it 'unsuspends accounts and removes block' do\n      @domain_block.update(severity: :suspend)\n\n      subject.call(@domain_block)\n      expect_deleted_domain_block\n      expect(@suspended.reload.suspended?).to be false\n      expect(@silenced.reload.silenced?).to be true\n      expect(@independently_suspended.reload.suspended?).to be true\n      expect(@independently_silenced.reload.silenced?).to be true\n    end\n  end\n\n  def expect_deleted_domain_block\n    expect { @domain_block.reload }.to raise_error(ActiveRecord::RecordNotFound)\n  end\nend\n"
  },
  {
    "path": "spec/services/unblock_service_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe UnblockService, type: :service do\n  let(:sender) { Fabricate(:account, username: 'alice') }\n\n  subject { UnblockService.new }\n\n  describe 'local' do\n    let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account }\n\n    before do\n      sender.block!(bob)\n      subject.call(sender, bob)\n    end\n\n    it 'destroys the blocking relation' do\n      expect(sender.blocking?(bob)).to be false\n    end\n  end\n\n  describe 'remote OStatus' do\n    let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob', domain: 'example.com', salmon_url: 'http://salmon.example.com')).account }\n\n    before do\n      sender.block!(bob)\n      stub_request(:post, \"http://salmon.example.com/\").to_return(:status => 200, :body => \"\", :headers => {})\n      subject.call(sender, bob)\n    end\n\n    it 'destroys the blocking relation' do\n      expect(sender.blocking?(bob)).to be false\n    end\n\n    it 'sends an unblock salmon slap' do\n      expect(a_request(:post, \"http://salmon.example.com/\").with { |req|\n        xml = OStatus2::Salmon.new.unpack(req.body)\n        xml.match(OStatus::TagManager::VERBS[:unblock])\n      }).to have_been_made.once\n    end\n  end\n\n  describe 'remote ActivityPub' do\n    let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox')).account }\n\n    before do\n      sender.block!(bob)\n      stub_request(:post, 'http://example.com/inbox').to_return(status: 200)\n      subject.call(sender, bob)\n    end\n\n    it 'destroys the blocking relation' do\n      expect(sender.blocking?(bob)).to be false\n    end\n\n    it 'sends an unblock activity' do\n      expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once\n    end\n  end\nend\n"
  },
  {
    "path": "spec/services/unfollow_service_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe UnfollowService, type: :service do\n  let(:sender) { Fabricate(:account, username: 'alice') }\n\n  subject { UnfollowService.new }\n\n  describe 'local' do\n    let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account }\n\n    before do\n      sender.follow!(bob)\n      subject.call(sender, bob)\n    end\n\n    it 'destroys the following relation' do\n      expect(sender.following?(bob)).to be false\n    end\n  end\n\n  describe 'remote OStatus' do\n    let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob', protocol: :ostatus, domain: 'example.com', salmon_url: 'http://salmon.example.com')).account }\n\n    before do\n      sender.follow!(bob)\n      stub_request(:post, \"http://salmon.example.com/\").to_return(:status => 200, :body => \"\", :headers => {})\n      subject.call(sender, bob)\n    end\n\n    it 'destroys the following relation' do\n      expect(sender.following?(bob)).to be false\n    end\n\n    it 'sends an unfollow salmon slap' do\n      expect(a_request(:post, \"http://salmon.example.com/\").with { |req|\n        xml = OStatus2::Salmon.new.unpack(req.body)\n        xml.match(OStatus::TagManager::VERBS[:unfollow])\n      }).to have_been_made.once\n    end\n  end\n\n  describe 'remote ActivityPub' do\n    let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox')).account }\n\n    before do\n      sender.follow!(bob)\n      stub_request(:post, 'http://example.com/inbox').to_return(status: 200)\n      subject.call(sender, bob)\n    end\n\n    it 'destroys the following relation' do\n      expect(sender.following?(bob)).to be false\n    end\n\n    it 'sends an unfollow activity' do\n      expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once\n    end\n  end\n\n  describe 'remote ActivityPub (reverse)' do\n    let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox')).account }\n\n    before do\n      bob.follow!(sender)\n      stub_request(:post, 'http://example.com/inbox').to_return(status: 200)\n      subject.call(bob, sender)\n    end\n\n    it 'destroys the following relation' do\n      expect(bob.following?(sender)).to be false\n    end\n\n    it 'sends a reject activity' do\n      expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once\n    end\n  end\nend\n"
  },
  {
    "path": "spec/services/unmute_service_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe UnmuteService, type: :service do\n  subject { UnmuteService.new }\nend\n"
  },
  {
    "path": "spec/services/unsubscribe_service_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe UnsubscribeService, type: :service do\n  let(:account) { Fabricate(:account, username: 'bob', domain: 'example.com', hub_url: 'http://hub.example.com') }\n  subject { UnsubscribeService.new }\n\n  it 'removes the secret and resets expiration on account' do\n    stub_request(:post, 'http://hub.example.com/').to_return(status: 204)\n    subject.call(account)\n    account.reload\n\n    expect(account.secret).to be_blank\n    expect(account.subscription_expires_at).to be_blank\n  end\n\n  it 'logs error on subscription failure' do\n    logger = stub_logger\n    stub_request(:post, 'http://hub.example.com/').to_return(status: 404)\n    subject.call(account)\n\n    expect(logger).to have_received(:debug).with(/unsubscribe for bob@example.com failed/)\n  end\n\n  it 'logs error on connection failure' do\n    logger = stub_logger\n    stub_request(:post, 'http://hub.example.com/').to_raise(HTTP::Error)\n    subject.call(account)\n\n    expect(logger).to have_received(:debug).with(/unsubscribe for bob@example.com failed/)\n  end\n\n  def stub_logger\n    double(debug: nil).tap do |logger|\n      allow(Rails).to receive(:logger).and_return(logger)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/services/update_remote_profile_service_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe UpdateRemoteProfileService, type: :service do\n  let(:xml) { File.read(Rails.root.join('spec', 'fixtures', 'push', 'feed.atom')) }\n\n  subject { UpdateRemoteProfileService.new }\n\n  before do\n    stub_request(:get, 'https://quitter.no/avatar/7477-300-20160211190340.png').to_return(request_fixture('avatar.txt'))\n  end\n\n  context 'with updated details' do\n    let(:remote_account) { Fabricate(:account, username: 'bob', domain: 'example.com') }\n\n    before do\n      subject.call(xml, remote_account)\n    end\n\n    it 'downloads new avatar' do\n      expect(a_request(:get, 'https://quitter.no/avatar/7477-300-20160211190340.png')).to have_been_made\n    end\n\n    it 'sets the avatar remote url' do\n      expect(remote_account.reload.avatar_remote_url).to eq 'https://quitter.no/avatar/7477-300-20160211190340.png'\n    end\n\n    it 'sets display name' do\n      expect(remote_account.reload.display_name).to eq 'ＤＩＧＩＴＡＬ ＣＡＴ'\n    end\n\n    it 'sets note' do\n      expect(remote_account.reload.note).to eq 'Software engineer, free time musician and ＤＩＧＩＴＡＬ ＳＰＯＲＴＳ enthusiast. Likes cats. Warning: May contain memes'\n    end\n  end\n\n  context 'with unchanged details' do\n    let(:remote_account) { Fabricate(:account, username: 'bob', domain: 'example.com', display_name: 'ＤＩＧＩＴＡＬ ＣＡＴ', note: 'Software engineer, free time musician and ＤＩＧＩＴＡＬ ＳＰＯＲＴＳ enthusiast. Likes cats. Warning: May contain memes', avatar_remote_url: 'https://quitter.no/avatar/7477-300-20160211190340.png') }\n\n    before do\n      subject.call(xml, remote_account)\n    end\n\n    it 'does not re-download avatar' do\n      expect(a_request(:get, 'https://quitter.no/avatar/7477-300-20160211190340.png')).to have_been_made.once\n    end\n\n    it 'sets the avatar remote url' do\n      expect(remote_account.reload.avatar_remote_url).to eq 'https://quitter.no/avatar/7477-300-20160211190340.png'\n    end\n\n    it 'sets display name' do\n      expect(remote_account.reload.display_name).to eq 'ＤＩＧＩＴＡＬ ＣＡＴ'\n    end\n\n    it 'sets note' do\n      expect(remote_account.reload.note).to eq 'Software engineer, free time musician and ＤＩＧＩＴＡＬ ＳＰＯＲＴＳ enthusiast. Likes cats. Warning: May contain memes'\n    end\n  end\n\n  context 'with updated details from a domain set to reject media' do\n    let(:remote_account) { Fabricate(:account, username: 'bob', domain: 'example.com') }\n    let!(:domain_block) { Fabricate(:domain_block, domain: 'example.com', reject_media: true) }\n\n    before do\n      subject.call(xml, remote_account)\n    end\n\n    it 'does not the avatar remote url' do\n      expect(remote_account.reload.avatar_remote_url).to be_nil\n    end\n\n    it 'sets display name' do\n      expect(remote_account.reload.display_name).to eq 'ＤＩＧＩＴＡＬ ＣＡＴ'\n    end\n\n    it 'sets note' do\n      expect(remote_account.reload.note).to eq 'Software engineer, free time musician and ＤＩＧＩＴＡＬ ＳＰＯＲＴＳ enthusiast. Likes cats. Warning: May contain memes'\n    end\n\n    it 'does not set store the avatar' do\n      expect(remote_account.reload.avatar_file_name).to be_nil\n    end\n  end\nend\n"
  },
  {
    "path": "spec/services/verify_link_service_spec.rb",
    "content": "require 'rails_helper'\n\nRSpec.describe VerifyLinkService, type: :service do\n  subject { described_class.new }\n\n  context 'given a local account' do\n    let(:account) { Fabricate(:account, username: 'alice') }\n    let(:field)   { Account::Field.new(account, 'name' => 'Website', 'value' => 'http://example.com') }\n\n    before do\n      stub_request(:head, 'https://redirect.me/abc').to_return(status: 301, headers: { 'Location' => ActivityPub::TagManager.instance.url_for(account) })\n      stub_request(:get, 'http://example.com').to_return(status: 200, body: html)\n      subject.call(field)\n    end\n\n    context 'when a link contains an <a> back' do\n      let(:html) do\n        <<-HTML\n          <!doctype html>\n          <body>\n            <a href=\"#{ActivityPub::TagManager.instance.url_for(account)}\" rel=\"me\">Follow me on Mastodon</a>\n          </body>\n        HTML\n      end\n\n      it 'marks the field as verified' do\n        expect(field.verified?).to be true\n      end\n    end\n\n    context 'when a link contains an <a rel=\"noopener\"> back' do\n      let(:html) do\n        <<-HTML\n          <!doctype html>\n          <body>\n            <a href=\"#{ActivityPub::TagManager.instance.url_for(account)}\" rel=\"noopener me\" target=\"_blank\">Follow me on Mastodon</a>\n          </body>\n        HTML\n      end\n\n      it 'marks the field as verified' do\n        expect(field.verified?).to be true\n      end\n    end\n\n    context 'when a link contains a <link> back' do\n      let(:html) do\n        <<-HTML\n          <!doctype html>\n          <head>\n            <link type=\"text/html\" href=\"#{ActivityPub::TagManager.instance.url_for(account)}\" rel=\"me\" />\n          </head>\n        HTML\n      end\n\n      it 'marks the field as verified' do\n        expect(field.verified?).to be true\n      end\n    end\n\n    context 'when a link goes through a redirect back' do\n      let(:html) do\n        <<-HTML\n          <!doctype html>\n          <head>\n            <link type=\"text/html\" href=\"https://redirect.me/abc\" rel=\"me\" />\n          </head>\n        HTML\n      end\n\n      it 'marks the field as verified' do\n        expect(field.verified?).to be true\n      end\n    end\n\n    context 'when a link does not contain a link back' do\n      let(:html) { '' }\n\n      it 'marks the field as verified' do\n        expect(field.verified?).to be false\n      end\n    end\n  end\n\n  context 'given a remote account' do\n    let(:account) { Fabricate(:account, username: 'alice', domain: 'example.com', url: 'https://profile.example.com/alice') }\n    let(:field)   { Account::Field.new(account, 'name' => 'Website', 'value' => '<a href=\"http://example.com\" rel=\"me\"><span class=\"invisible\">http://</span><span class=\"\">example.com</span><span class=\"invisible\"></span></a>') }\n\n    before do\n      stub_request(:get, 'http://example.com').to_return(status: 200, body: html)\n      subject.call(field)\n    end\n\n    context 'when a link contains an <a> back' do\n      let(:html) do\n        <<-HTML\n          <!doctype html>\n          <body>\n            <a href=\"https://profile.example.com/alice\" rel=\"me\">Follow me on Mastodon</a>\n          </body>\n        HTML\n      end\n\n      it 'marks the field as verified' do\n        expect(field.verified?).to be true\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/spec_helper.rb",
    "content": "GC.disable\n\nif ENV['DISABLE_SIMPLECOV'] != 'true'\n  require 'simplecov'\n  SimpleCov.start 'rails' do\n    add_group 'Services', 'app/services'\n    add_group 'Presenters', 'app/presenters'\n    add_group 'Validators', 'app/validators'\n  end\nend\n\ngc_counter = -1\n\nRSpec.configure do |config|\n  config.expect_with :rspec do |expectations|\n    expectations.include_chain_clauses_in_custom_matcher_descriptions = true\n  end\n\n  config.mock_with :rspec do |mocks|\n    mocks.verify_partial_doubles = true\n\n    config.around(:example, :without_verify_partial_doubles) do |example|\n      mocks.verify_partial_doubles = false\n      example.call\n      mocks.verify_partial_doubles = true\n    end\n  end\n\n  config.before :suite do\n    Chewy.strategy(:bypass)\n  end\n\n  config.after :suite do\n    gc_counter = 0\n    FileUtils.rm_rf(Dir[\"#{Rails.root}/spec/test_files/\"])\n  end\n\n  config.after :each do\n    gc_counter += 1\n\n    if gc_counter > 19\n      GC.enable\n      GC.start\n      GC.disable\n\n      gc_counter = 0\n    end\n  end\nend\n\ndef body_as_json\n  json_str_to_hash(response.body)\nend\n\ndef json_str_to_hash(str)\n  JSON.parse(str, symbolize_names: true)\nend\n"
  },
  {
    "path": "spec/support/examples/lib/settings/scoped_settings.rb",
    "content": "# frozen_string_literal: true\n\nshared_examples 'ScopedSettings' do\n  describe '[]' do\n    it 'inherits default settings' do\n      expect(Setting.boost_modal).to eq false\n      expect(Setting.interactions['must_be_follower']).to eq false\n\n      settings = create!\n\n      expect(settings['boost_modal']).to eq false\n      expect(settings['interactions']['must_be_follower']).to eq false\n    end\n  end\n\n  describe 'all_as_records' do\n    # expecting [] and []= works\n\n    it 'returns records merged with default values except hashes' do\n      expect(Setting.boost_modal).to eq false\n      expect(Setting.delete_modal).to eq true\n\n      settings = create!\n      settings['boost_modal'] = true\n\n      records = settings.all_as_records\n\n      expect(records['boost_modal'].value).to eq true\n      expect(records['delete_modal'].value).to eq true\n    end\n  end\n\n  describe 'missing methods' do\n    # expecting [] and []= works.\n\n    it 'reads settings' do\n      expect(Setting.boost_modal).to eq false\n      settings = create!\n      expect(settings.boost_modal).to eq false\n    end\n\n    it 'updates settings' do\n      settings = fabricate\n      settings.boost_modal = true\n      expect(settings['boost_modal']).to eq true\n    end\n  end\n\n  it 'can update settings with [] and can read with []=' do\n    settings = fabricate\n\n    settings['boost_modal'] = true\n    settings['interactions'] = settings['interactions'].merge('must_be_follower' => true)\n\n    Setting.save!\n\n    expect(settings['boost_modal']).to eq true\n    expect(settings['interactions']['must_be_follower']).to eq true\n\n    Rails.cache.clear\n\n    expect(settings['boost_modal']).to eq true\n    expect(settings['interactions']['must_be_follower']).to eq true\n  end\n\n  xit 'does not mutate defaults via the cache' do\n    fabricate['interactions']['must_be_follower'] = true\n    # TODO\n    # This mutates the global settings default such that future\n    # instances will inherit the incorrect starting values\n\n    expect(fabricate.settings['interactions']['must_be_follower']).to eq false\n  end\nend\n"
  },
  {
    "path": "spec/support/examples/lib/settings/settings_extended.rb",
    "content": "# frozen_string_literal: true\n\nshared_examples 'Settings-extended' do\n  describe 'settings' do\n    def fabricate\n      super.settings\n    end\n\n    def create!\n      super.settings\n    end\n\n    it_behaves_like 'ScopedSettings'\n  end\nend\n"
  },
  {
    "path": "spec/support/examples/models/concerns/account_avatar.rb",
    "content": "# frozen_string_literal: true\n\nshared_examples 'AccountAvatar' do |fabricator|\n  describe 'static avatars' do\n    describe 'when GIF' do\n      it 'creates a png static style' do\n        account = Fabricate(fabricator, avatar: attachment_fixture('avatar.gif'))\n        expect(account.avatar_static_url).to_not eq account.avatar_original_url\n      end\n    end\n\n    describe 'when non-GIF' do\n      it 'does not create extra static style' do\n        account = Fabricate(fabricator, avatar: attachment_fixture('attachment.jpg'))\n        expect(account.avatar_static_url).to eq account.avatar_original_url\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/support/matchers/model/model_have_error_on_field.rb",
    "content": "RSpec::Matchers.define :model_have_error_on_field do |expected|\n  match do |record|\n    if record.errors.empty?\n      record.valid?\n    end\n\n    record.errors.has_key?(expected)\n  end\n\n  failure_message do |record|\n    keys = record.errors.keys\n\n    \"expect record.errors(#{keys}) to include #{expected}\"\n  end\nend\n"
  },
  {
    "path": "spec/validators/blacklisted_email_validator_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe BlacklistedEmailValidator, type: :validator do\n  describe '#validate' do\n    let(:user)   { double(email: 'info@mail.com', errors: errors) }\n    let(:errors) { double(add: nil) }\n\n    before do\n      allow(user).to receive(:valid_invitation?) { false }\n      allow_any_instance_of(described_class).to receive(:blocked_email?) { blocked_email }\n      described_class.new.validate(user)\n    end\n\n    context 'blocked_email?' do\n      let(:blocked_email) { true }\n\n      it 'calls errors.add' do\n        expect(errors).to have_received(:add).with(:email, I18n.t('users.invalid_email'))\n      end\n    end\n\n    context '!blocked_email?' do\n      let(:blocked_email) { false }\n\n      it 'not calls errors.add' do\n        expect(errors).not_to have_received(:add).with(:email, I18n.t('users.invalid_email'))\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/validators/disallowed_hashtags_validator_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe DisallowedHashtagsValidator, type: :validator do\n  describe '#validate' do\n    before do\n      allow_any_instance_of(described_class).to receive(:select_tags) { tags }\n      described_class.new.validate(status)\n    end\n\n    let(:status) { double(errors: errors, local?: local, reblog?: reblog, text: '') }\n    let(:errors) { double(add: nil) }\n\n    context 'unless status.local? && !status.reblog?' do\n      let(:local)  { false }\n      let(:reblog) { true }\n\n      it 'not calls errors.add' do\n        expect(errors).not_to have_received(:add).with(:text, any_args)\n      end\n    end\n\n    context 'status.local? && !status.reblog?' do\n      let(:local)  { true }\n      let(:reblog) { false }\n\n      context 'tags.empty?' do\n        let(:tags) { [] }\n\n        it 'not calls errors.add' do\n          expect(errors).not_to have_received(:add).with(:text, any_args)\n        end\n      end\n\n      context '!tags.empty?' do\n        let(:tags) { %w(a b c) }\n\n        it 'calls errors.add' do\n          expect(errors).to have_received(:add)\n            .with(:text, I18n.t('statuses.disallowed_hashtags', tags: tags.join(', '), count: tags.size))\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/validators/email_mx_validator_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe EmailMxValidator do\n  describe '#validate' do\n    let(:user) { double(email: 'foo@example.com', errors: double(add: nil)) }\n\n    it 'adds an error if there are no DNS records for the e-mail domain' do\n      resolver = double\n\n      allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::MX).and_return([])\n      allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::A).and_return([])\n      allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::AAAA).and_return([])\n      allow(resolver).to receive(:timeouts=).and_return(nil)\n      allow(Resolv::DNS).to receive(:open).and_yield(resolver)\n\n      subject.validate(user)\n      expect(user.errors).to have_received(:add)\n    end\n\n    it 'adds an error if a MX record exists but does not lead to an IP' do\n      resolver = double\n\n      allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::MX).and_return([double(exchange: 'mail.example.com')])\n      allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::A).and_return([])\n      allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::AAAA).and_return([])\n      allow(resolver).to receive(:getresources).with('mail.example.com', Resolv::DNS::Resource::IN::A).and_return([])\n      allow(resolver).to receive(:getresources).with('mail.example.com', Resolv::DNS::Resource::IN::AAAA).and_return([])\n      allow(resolver).to receive(:timeouts=).and_return(nil)\n      allow(Resolv::DNS).to receive(:open).and_yield(resolver)\n\n      subject.validate(user)\n      expect(user.errors).to have_received(:add)\n    end\n\n    it 'adds an error if the A record is blacklisted' do\n      EmailDomainBlock.create!(domain: '1.2.3.4')\n      resolver = double\n\n      allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::MX).and_return([])\n      allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::A).and_return([double(address: '1.2.3.4')])\n      allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::AAAA).and_return([])\n      allow(resolver).to receive(:timeouts=).and_return(nil)\n      allow(Resolv::DNS).to receive(:open).and_yield(resolver)\n\n      subject.validate(user)\n      expect(user.errors).to have_received(:add)\n    end\n\n    it 'adds an error if the AAAA record is blacklisted' do\n      EmailDomainBlock.create!(domain: 'fd00::1')\n      resolver = double\n\n      allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::MX).and_return([])\n      allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::A).and_return([])\n      allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::AAAA).and_return([double(address: 'fd00::1')])\n      allow(resolver).to receive(:timeouts=).and_return(nil)\n      allow(Resolv::DNS).to receive(:open).and_yield(resolver)\n\n      subject.validate(user)\n      expect(user.errors).to have_received(:add)\n    end\n\n    it 'adds an error if the MX record is blacklisted' do\n      EmailDomainBlock.create!(domain: '2.3.4.5')\n      resolver = double\n\n      allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::MX).and_return([double(exchange: 'mail.example.com')])\n      allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::A).and_return([])\n      allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::AAAA).and_return([])\n      allow(resolver).to receive(:getresources).with('mail.example.com', Resolv::DNS::Resource::IN::A).and_return([double(address: '2.3.4.5')])\n      allow(resolver).to receive(:getresources).with('mail.example.com', Resolv::DNS::Resource::IN::AAAA).and_return([])\n      allow(resolver).to receive(:timeouts=).and_return(nil)\n      allow(Resolv::DNS).to receive(:open).and_yield(resolver)\n\n      subject.validate(user)\n      expect(user.errors).to have_received(:add)\n    end\n\n    it 'adds an error if the MX IPv6 record is blacklisted' do\n      EmailDomainBlock.create!(domain: 'fd00::2')\n      resolver = double\n\n      allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::MX).and_return([double(exchange: 'mail.example.com')])\n      allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::A).and_return([])\n      allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::AAAA).and_return([])\n      allow(resolver).to receive(:getresources).with('mail.example.com', Resolv::DNS::Resource::IN::A).and_return([])\n      allow(resolver).to receive(:getresources).with('mail.example.com', Resolv::DNS::Resource::IN::AAAA).and_return([double(address: 'fd00::2')])\n      allow(resolver).to receive(:timeouts=).and_return(nil)\n      allow(Resolv::DNS).to receive(:open).and_yield(resolver)\n\n      subject.validate(user)\n      expect(user.errors).to have_received(:add)\n    end\n\n    it 'adds an error if the MX hostname is blacklisted' do\n      EmailDomainBlock.create!(domain: 'mail.example.com')\n      resolver = double\n\n      allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::MX).and_return([double(exchange: 'mail.example.com')])\n      allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::A).and_return([])\n      allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::AAAA).and_return([])\n      allow(resolver).to receive(:getresources).with('mail.example.com', Resolv::DNS::Resource::IN::A).and_return([double(address: '2.3.4.5')])\n      allow(resolver).to receive(:getresources).with('mail.example.com', Resolv::DNS::Resource::IN::AAAA).and_return([double(address: 'fd00::2')])\n      allow(resolver).to receive(:timeouts=).and_return(nil)\n      allow(Resolv::DNS).to receive(:open).and_yield(resolver)\n\n      subject.validate(user)\n      expect(user.errors).to have_received(:add)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/validators/follow_limit_validator_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe FollowLimitValidator, type: :validator do\n  describe '#validate' do\n    before do\n      allow_any_instance_of(described_class).to receive(:limit_reached?).with(account) do\n        limit_reached\n      end\n\n      described_class.new.validate(follow)\n    end\n\n    let(:follow)  { double(account: account, errors: errors) }\n    let(:errors)  { double(add: nil) }\n    let(:account) { double(nil?: _nil, local?: local, following_count: 0, followers_count: 0) }\n    let(:_nil)    { true }\n    let(:local)   { false }\n\n    context 'follow.account.nil? || !follow.account.local?' do\n      let(:_nil)    { true }\n\n      it 'not calls errors.add' do\n        expect(errors).not_to have_received(:add).with(:base, any_args)\n      end\n    end\n\n    context '!(follow.account.nil? || !follow.account.local?)' do\n      let(:_nil)    { false }\n      let(:local)   { true }\n\n      context 'limit_reached?' do\n        let(:limit_reached) { true }\n\n        it 'calls errors.add' do\n          expect(errors).to have_received(:add)\n            .with(:base, I18n.t('users.follow_limit_reached', limit: FollowLimitValidator::LIMIT))\n        end\n      end\n\n      context '!limit_reached?' do\n        let(:limit_reached) { false }\n\n        it 'not calls errors.add' do\n          expect(errors).not_to have_received(:add).with(:base, any_args)\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/validators/poll_validator_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe PollValidator, type: :validator do\n  describe '#validate' do\n    before do\n      validator.validate(poll)\n    end\n\n    let(:validator) { described_class.new }\n    let(:poll) { double(options: options, expires_at: expires_at, errors: errors) }\n    let(:errors) { double(add: nil) }\n    let(:options) { %w(foo bar) }\n    let(:expires_at) { 1.day.from_now }\n\n    it 'have no errors' do\n      expect(errors).not_to have_received(:add)\n    end\n\n    context 'expires just 5 min ago' do\n      let(:expires_at) { 5.minutes.from_now }\n      it 'not calls errors add' do\n        expect(errors).not_to have_received(:add)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/validators/status_length_validator_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe StatusLengthValidator do\n  describe '#validate' do\n    it 'does not add errors onto remote statuses' do\n      status = double(local?: false)\n      subject.validate(status)\n      expect(status).not_to receive(:errors)\n    end\n\n    it 'does not add errors onto local reblogs' do\n      status = double(local?: false, reblog?: true)\n      subject.validate(status)\n      expect(status).not_to receive(:errors)\n    end\n\n    it 'adds an error when content warning is over 500 characters' do\n      status = double(spoiler_text: 'a' * 520, text: '', errors: double(add: nil), local?: true, reblog?: false)\n      subject.validate(status)\n      expect(status.errors).to have_received(:add)\n    end\n\n    it 'adds an error when text is over 500 characters' do\n      status = double(spoiler_text: '', text: 'a' * 520, errors: double(add: nil), local?: true, reblog?: false)\n      subject.validate(status)\n      expect(status.errors).to have_received(:add)\n    end\n\n    it 'adds an error when text and content warning are over 500 characters total' do\n      status = double(spoiler_text: 'a' * 250, text: 'b' * 251, errors: double(add: nil), local?: true, reblog?: false)\n      subject.validate(status)\n      expect(status.errors).to have_received(:add)\n    end\n\n    it 'counts URLs as 23 characters flat' do\n      text   = ('a' * 476) + \" http://#{'b' * 30}.com/example\"\n      status = double(spoiler_text: '', text: text, errors: double(add: nil), local?: true, reblog?: false)\n\n      subject.validate(status)\n      expect(status.errors).to_not have_received(:add)\n    end\n\n    it 'counts only the front part of remote usernames' do\n      text   = ('a' * 475) + \" @alice@#{'b' * 30}.com\"\n      status = double(spoiler_text: '', text: text, errors: double(add: nil), local?: true, reblog?: false)\n\n      subject.validate(status)\n      expect(status.errors).to_not have_received(:add)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/validators/status_pin_validator_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe StatusPinValidator, type: :validator do\n  describe '#validate' do\n    before do\n      subject.validate(pin)\n    end\n\n    let(:pin) { double(account: account, errors: errors, status: status, account_id: pin_account_id) }\n    let(:status) { double(reblog?: reblog, account_id: status_account_id, visibility: visibility) }\n    let(:account)     { double(status_pins: status_pins, local?: local) }\n    let(:status_pins) { double(count: count) }\n    let(:errors)      { double(add: nil) }\n    let(:pin_account_id)    { 1 }\n    let(:status_account_id) { 1 }\n    let(:visibility)  { 'public' }\n    let(:local)       { false }\n    let(:reblog)      { false }\n    let(:count)       { 0 }\n\n    context 'pin.status.reblog?' do\n      let(:reblog) { true }\n\n      it 'calls errors.add' do\n        expect(errors).to have_received(:add).with(:base, I18n.t('statuses.pin_errors.reblog'))\n      end\n    end\n\n    context 'pin.account_id != pin.status.account_id' do\n      let(:pin_account_id)    { 1 }\n      let(:status_account_id) { 2 }\n\n      it 'calls errors.add' do\n        expect(errors).to have_received(:add).with(:base, I18n.t('statuses.pin_errors.ownership'))\n      end\n    end\n\n    context 'unless %w(public unlisted).include?(pin.status.visibility)' do\n      let(:visibility) { '' }\n\n      it 'calls errors.add' do\n        expect(errors).to have_received(:add).with(:base, I18n.t('statuses.pin_errors.private'))\n      end\n    end\n\n    context 'pin.account.status_pins.count > 4 && pin.account.local?' do\n      let(:count) { 5 }\n      let(:local) { true }\n\n      it 'calls errors.add' do\n        expect(errors).to have_received(:add).with(:base, I18n.t('statuses.pin_errors.limit'))\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/validators/unique_username_validator_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe UniqueUsernameValidator do\n  describe '#validate' do\n    it 'does not add errors if username is nil' do\n      account = double(username: nil, persisted?: false, errors: double(add: nil))\n      subject.validate(account)\n      expect(account.errors).to_not have_received(:add)\n    end\n\n    it 'does not add errors when existing one is subject itself' do\n      account = Fabricate(:account, username: 'abcdef')\n      expect(account).to be_valid\n    end\n\n    it 'adds an error when the username is already used with ignoring cases' do\n      Fabricate(:account, username: 'ABCdef')\n      account = double(username: 'abcDEF', persisted?: false, errors: double(add: nil))\n      subject.validate(account)\n      expect(account.errors).to have_received(:add)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/validators/unreserved_username_validator_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe UnreservedUsernameValidator, type: :validator do\n  describe '#validate' do\n    before do\n      allow(validator).to receive(:reserved_username?) { reserved_username }\n      validator.validate(account)\n    end\n\n    let(:validator) { described_class.new }\n    let(:account)   { double(username: username, errors: errors) }\n    let(:errors )   { double(add: nil) }\n\n    context '@username.nil?' do\n      let(:username)  { nil }\n\n      it 'not calls errors.add' do\n        expect(errors).not_to have_received(:add).with(:username, any_args)\n      end\n    end\n\n    context '!@username.nil?' do\n      let(:username)  { '' }\n\n      context 'reserved_username?' do\n        let(:reserved_username) { true }\n\n        it 'calls erros.add' do\n          expect(errors).to have_received(:add).with(:username, I18n.t('accounts.reserved_username'))\n        end\n      end\n\n      context '!reserved_username?' do\n        let(:reserved_username) { false }\n\n        it 'not calls erros.add' do\n          expect(errors).not_to have_received(:add).with(:username, any_args)\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/validators/url_validator_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe UrlValidator, type: :validator do\n  describe '#validate_each' do\n    before do\n      allow(validator).to receive(:compliant?).with(value) { compliant }\n      validator.validate_each(record, attribute, value)\n    end\n\n    let(:validator) { described_class.new(attributes: [attribute]) }\n    let(:record)    { double(errors: errors) }\n    let(:errors)    { double(add: nil) }\n    let(:value)     { '' }\n    let(:attribute) { :foo }\n\n    context 'unless compliant?' do\n      let(:compliant) { false }\n\n      it 'calls errors.add' do\n        expect(errors).to have_received(:add).with(attribute, I18n.t('applications.invalid_url'))\n      end\n    end\n\n    context 'if compliant?' do\n      let(:compliant) { true }\n\n      it 'not calls errors.add' do\n        expect(errors).not_to have_received(:add).with(attribute, any_args)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/views/about/show.html.haml_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe 'about/show.html.haml', without_verify_partial_doubles: true do\n  before do\n    allow(view).to receive(:site_hostname).and_return('example.com')\n    allow(view).to receive(:site_title).and_return('example site')\n    allow(view).to receive(:new_user).and_return(User.new)\n    allow(view).to receive(:use_seamless_external_login?).and_return(false)\n  end\n\n  it 'has valid open graph tags' do\n    instance_presenter = double(\n      :instance_presenter,\n      site_title: 'something',\n      site_short_description: 'something',\n      site_description: 'something',\n      version_number: '1.0',\n      source_url: 'https://github.com/tootsuite/mastodon',\n      open_registrations: false,\n      thumbnail: nil,\n      hero: nil,\n      mascot: nil,\n      user_count: 420,\n      status_count: 69,\n      active_user_count: 420,\n      contact_account: nil,\n      sample_accounts: []\n    )\n\n    assign(:instance_presenter, instance_presenter)\n    render\n\n    header_tags = view.content_for(:header_tags)\n\n    expect(header_tags).to match(%r{<meta content=\".+\" property=\"og:title\" />})\n    expect(header_tags).to match(%r{<meta content=\"website\" property=\"og:type\" />})\n    expect(header_tags).to match(%r{<meta content=\".+\" property=\"og:image\" />})\n    expect(header_tags).to match(%r{<meta content=\"http://.+\" property=\"og:url\" />})\n  end\nend\n"
  },
  {
    "path": "spec/views/stream_entries/show.html.haml_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe 'stream_entries/show.html.haml', without_verify_partial_doubles: true do\n  before do\n    double(:api_oembed_url => '')\n    double(:account_stream_entry_url => '')\n    allow(view).to receive(:show_landing_strip?).and_return(true)\n    allow(view).to receive(:site_title).and_return('example site')\n    allow(view).to receive(:site_hostname).and_return('example.com')\n    allow(view).to receive(:full_asset_url).and_return('//asset.host/image.svg')\n    allow(view).to receive(:local_time)\n    allow(view).to receive(:local_time_ago)\n    allow(view).to receive(:current_account).and_return(nil)\n    assign(:instance_presenter, InstancePresenter.new)\n  end\n\n  it 'has valid author h-card and basic data for a detailed_status' do\n    alice  =  Fabricate(:account, username: 'alice', display_name: 'Alice')\n    bob    =  Fabricate(:account, username: 'bob', display_name: 'Bob')\n    status =  Fabricate(:status, account: alice, text: 'Hello World')\n    reply  =  Fabricate(:status, account: bob, thread: status, text: 'Hello Alice')\n\n    assign(:status, status)\n    assign(:stream_entry, status.stream_entry)\n    assign(:account, alice)\n    assign(:type, status.stream_entry.activity_type.downcase)\n    assign(:descendant_threads, [])\n\n    render\n\n    mf2 = Microformats.parse(rendered)\n\n    expect(mf2.entry.url.to_s).not_to be_empty\n    expect(mf2.entry.author.name.to_s).to eq alice.display_name\n    expect(mf2.entry.author.url.to_s).not_to be_empty\n  end\n\n  it 'has valid h-cites for p-in-reply-to and p-comment' do\n    alice   =  Fabricate(:account, username: 'alice', display_name: 'Alice')\n    bob     =  Fabricate(:account, username: 'bob', display_name: 'Bob')\n    carl    =  Fabricate(:account, username: 'carl', display_name: 'Carl')\n    status  =  Fabricate(:status, account: alice, text: 'Hello World')\n    reply   =  Fabricate(:status, account: bob, thread: status, text: 'Hello Alice')\n    comment =  Fabricate(:status, account: carl, thread: reply, text: 'Hello Bob')\n\n    assign(:status, reply)\n    assign(:stream_entry, reply.stream_entry)\n    assign(:account, alice)\n    assign(:type, reply.stream_entry.activity_type.downcase)\n    assign(:ancestors, reply.stream_entry.activity.ancestors(1, bob))\n    assign(:descendant_threads, [{ statuses: reply.stream_entry.activity.descendants(1) }])\n\n    render\n\n    mf2 = Microformats.parse(rendered)\n\n    expect(mf2.entry.url.to_s).not_to be_empty\n    expect(mf2.entry.comment.url.to_s).not_to be_empty\n    expect(mf2.entry.comment.author.name.to_s).to eq carl.display_name\n    expect(mf2.entry.comment.author.url.to_s).not_to be_empty\n\n    expect(mf2.entry.in_reply_to.url.to_s).not_to be_empty\n    expect(mf2.entry.in_reply_to.author.name.to_s).to eq alice.display_name\n    expect(mf2.entry.in_reply_to.author.url.to_s).not_to be_empty\n  end\n\n  it 'has valid opengraph tags' do\n    alice   =  Fabricate(:account, username: 'alice', display_name: 'Alice')\n    status  =  Fabricate(:status, account: alice, text: 'Hello World')\n\n    assign(:status, status)\n    assign(:stream_entry, status.stream_entry)\n    assign(:account, alice)\n    assign(:type, status.stream_entry.activity_type.downcase)\n    assign(:descendant_threads, [])\n\n    render\n\n    header_tags = view.content_for(:header_tags)\n\n    expect(header_tags).to match(%r{<meta content=\".+\" property=\"og:title\" />})\n    expect(header_tags).to match(%r{<meta content=\"article\" property=\"og:type\" />})\n    expect(header_tags).to match(%r{<meta content=\".+\" property=\"og:image\" />})\n    expect(header_tags).to match(%r{<meta content=\"http://.+\" property=\"og:url\" />})\n  end\nend\n"
  },
  {
    "path": "spec/workers/activitypub/delivery_worker_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe ActivityPub::DeliveryWorker do\n  subject { described_class.new }\n\n  let(:sender)  { Fabricate(:account) }\n  let(:payload) { 'test' }\n\n  describe 'perform' do\n    it 'performs a request' do\n      stub_request(:post, 'https://example.com/api').to_return(status: 200)\n      subject.perform(payload, sender.id, 'https://example.com/api')\n      expect(a_request(:post, 'https://example.com/api')).to have_been_made.once\n    end\n\n    it 'raises when request fails' do\n      stub_request(:post, 'https://example.com/api').to_return(status: 500)\n      expect { subject.perform(payload, sender.id, 'https://example.com/api') }.to raise_error Mastodon::UnexpectedResponseError\n    end\n  end\nend\n"
  },
  {
    "path": "spec/workers/activitypub/distribution_worker_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe ActivityPub::DistributionWorker do\n  subject { described_class.new }\n\n  let(:status)   { Fabricate(:status) }\n  let(:follower) { Fabricate(:account, protocol: :activitypub, inbox_url: 'http://example.com') }\n\n  describe '#perform' do\n    before do\n      allow(ActivityPub::DeliveryWorker).to receive(:push_bulk)\n      follower.follow!(status.account)\n    end\n\n    context 'with public status' do\n      before do\n        status.update(visibility: :public)\n      end\n\n      it 'delivers to followers' do\n        subject.perform(status.id)\n        expect(ActivityPub::DeliveryWorker).to have_received(:push_bulk).with(['http://example.com'])\n      end\n    end\n\n    context 'with private status' do\n      before do\n        status.update(visibility: :private)\n      end\n\n      it 'delivers to followers' do\n        subject.perform(status.id)\n        expect(ActivityPub::DeliveryWorker).to have_received(:push_bulk).with(['http://example.com'])\n      end\n    end\n\n    context 'with direct status' do\n      before do\n        status.update(visibility: :direct)\n      end\n\n      it 'does nothing' do\n        subject.perform(status.id)\n        expect(ActivityPub::DeliveryWorker).to_not have_received(:push_bulk)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/workers/activitypub/fetch_replies_worker_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe ActivityPub::FetchRepliesWorker do\n  subject { described_class.new }\n\n  let(:account) { Fabricate(:account, uri: 'https://example.com/user/1') }\n  let(:status)  { Fabricate(:status, account: account) }\n\n  let(:payload) do\n    {\n      '@context': 'https://www.w3.org/ns/activitystreams',\n      id: 'https://example.com/statuses_replies/1',\n      type: 'Collection',\n      items: [],\n    }\n  end\n\n  let(:json) { Oj.dump(payload) }\n\n  describe 'perform' do\n    it 'performs a request if the collection URI is from the same host' do\n      stub_request(:get, 'https://example.com/statuses_replies/1').to_return(status: 200, body: json)\n      subject.perform(status.id, 'https://example.com/statuses_replies/1')\n      expect(a_request(:get, 'https://example.com/statuses_replies/1')).to have_been_made.once\n    end\n\n    it 'does not perform a request if the collection URI is from a different host' do\n      stub_request(:get, 'https://other.com/statuses_replies/1').to_return(status: 200)\n      subject.perform(status.id, 'https://other.com/statuses_replies/1')\n      expect(a_request(:get, 'https://other.com/statuses_replies/1')).to_not have_been_made\n    end\n\n    it 'raises when request fails' do\n      stub_request(:get, 'https://example.com/statuses_replies/1').to_return(status: 500)\n      expect { subject.perform(status.id, 'https://example.com/statuses_replies/1') }.to raise_error Mastodon::UnexpectedResponseError\n    end\n  end\nend\n"
  },
  {
    "path": "spec/workers/activitypub/processing_worker_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe ActivityPub::ProcessingWorker do\n  subject { described_class.new }\n\n  let(:account) { Fabricate(:account) }\n\n  describe '#perform' do\n    it 'delegates to ActivityPub::ProcessCollectionService' do\n      allow(ActivityPub::ProcessCollectionService).to receive(:new).and_return(double(:service, call: nil))\n      subject.perform(account.id, '')\n      expect(ActivityPub::ProcessCollectionService).to have_received(:new)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/workers/activitypub/update_distribution_worker_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe ActivityPub::UpdateDistributionWorker do\n  subject { described_class.new }\n\n  let(:account)  { Fabricate(:account) }\n  let(:follower) { Fabricate(:account, protocol: :activitypub, inbox_url: 'http://example.com') }\n\n  describe '#perform' do\n    before do\n      allow(ActivityPub::DeliveryWorker).to receive(:push_bulk)\n      follower.follow!(account)\n    end\n\n    it 'delivers to followers' do\n      subject.perform(account.id)\n      expect(ActivityPub::DeliveryWorker).to have_received(:push_bulk).with(['http://example.com'])\n    end\n  end\nend\n"
  },
  {
    "path": "spec/workers/after_remote_follow_request_worker_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe AfterRemoteFollowRequestWorker do\n  subject { described_class.new }\n  let(:follow_request) { Fabricate(:follow_request) }\n  describe 'perform' do\n    context 'when the follow_request does not exist' do\n      it 'catches a raise and returns true' do\n        allow(FollowService).to receive(:new)\n        result = subject.perform('aaa')\n\n        expect(result).to eq(true)\n        expect(FollowService).not_to have_received(:new)\n      end\n    end\n\n    context 'when the account cannot be updated' do\n      it 'returns nil and does not call service when account is nil' do\n        allow(FollowService).to receive(:new)\n        service = double(call: nil)\n        allow(FetchRemoteAccountService).to receive(:new).and_return(service)\n\n        result = subject.perform(follow_request.id)\n\n        expect(result).to be_nil\n        expect(FollowService).not_to have_received(:new)\n      end\n\n      it 'returns nil and does not call service when account is locked' do\n        allow(FollowService).to receive(:new)\n        service = double(call: double(locked?: true))\n        allow(FetchRemoteAccountService).to receive(:new).and_return(service)\n\n        result = subject.perform(follow_request.id)\n\n        expect(result).to be_nil\n        expect(FollowService).not_to have_received(:new)\n      end\n    end\n\n    context 'when the account is updated' do\n      it 'calls the follow service and destroys the follow' do\n        follow_service = double(call: nil)\n        allow(FollowService).to receive(:new).and_return(follow_service)\n        account = Fabricate(:account, locked: false)\n        service = double(call: account)\n        allow(FetchRemoteAccountService).to receive(:new).and_return(service)\n\n        result = subject.perform(follow_request.id)\n\n        expect(result).to be_nil\n        expect(follow_service).to have_received(:call).with(follow_request.account, account.acct)\n        expect { follow_request.reload }.to raise_error(ActiveRecord::RecordNotFound)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/workers/after_remote_follow_worker_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe AfterRemoteFollowWorker do\n  subject { described_class.new }\n  let(:follow) { Fabricate(:follow) }\n  describe 'perform' do\n    context 'when the follow does not exist' do\n      it 'catches a raise and returns true' do\n        allow(FollowService).to receive(:new)\n        result = subject.perform('aaa')\n\n        expect(result).to eq(true)\n        expect(FollowService).not_to have_received(:new)\n      end\n    end\n\n    context 'when the account cannot be updated' do\n      it 'returns nil and does not call service when account is nil' do\n        allow(FollowService).to receive(:new)\n        service = double(call: nil)\n        allow(FetchRemoteAccountService).to receive(:new).and_return(service)\n\n        result = subject.perform(follow.id)\n\n        expect(result).to be_nil\n        expect(FollowService).not_to have_received(:new)\n      end\n\n      it 'returns nil and does not call service when account is not locked' do\n        allow(FollowService).to receive(:new)\n        service = double(call: double(locked?: false))\n        allow(FetchRemoteAccountService).to receive(:new).and_return(service)\n\n        result = subject.perform(follow.id)\n\n        expect(result).to be_nil\n        expect(FollowService).not_to have_received(:new)\n      end\n    end\n\n    context 'when the account is updated' do\n      it 'calls the follow service and destroys the follow' do\n        follow_service = double(call: nil)\n        allow(FollowService).to receive(:new).and_return(follow_service)\n        account = Fabricate(:account, locked: true)\n        service = double(call: account)\n        allow(FetchRemoteAccountService).to receive(:new).and_return(service)\n\n        result = subject.perform(follow.id)\n\n        expect(result).to be_nil\n        expect(follow_service).to have_received(:call).with(follow.account, account.acct)\n        expect { follow.reload }.to raise_error(ActiveRecord::RecordNotFound)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/workers/digest_mailer_worker_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe DigestMailerWorker do\n  describe 'perform' do\n    let(:user) { Fabricate(:user, last_emailed_at: 3.days.ago) }\n\n    context 'for a user who receives digests' do\n      it 'sends the email' do\n        service = double(deliver_now!: nil)\n        allow(NotificationMailer).to receive(:digest).and_return(service)\n        update_user_digest_setting(true)\n        described_class.perform_async(user.id)\n\n        expect(NotificationMailer).to have_received(:digest)\n        expect(user.reload.last_emailed_at).to be_within(1).of(Time.now.utc)\n      end\n    end\n\n    context 'for a user who does not receive digests' do\n      it 'does not send the email' do\n        allow(NotificationMailer).to receive(:digest)\n        update_user_digest_setting(false)\n        described_class.perform_async(user.id)\n\n        expect(NotificationMailer).not_to have_received(:digest)\n        expect(user.last_emailed_at).to be_within(1).of(3.days.ago)\n      end\n    end\n\n    def update_user_digest_setting(value)\n      user.settings['notification_emails'] = user.settings['notification_emails'].merge('digest' => value)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/workers/domain_block_worker_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe DomainBlockWorker do\n  subject { described_class.new }\n\n  describe 'perform' do\n    let(:domain_block) { Fabricate(:domain_block) }\n\n    it 'returns true for non-existent domain block' do\n      service = double(call: nil)\n      allow(BlockDomainService).to receive(:new).and_return(service)\n      result = subject.perform(domain_block.id)\n\n      expect(result).to be_nil\n      expect(service).to have_received(:call).with(domain_block)\n    end\n\n    it 'calls domain block service for relevant domain block' do\n      result = subject.perform('aaa')\n\n      expect(result).to eq(true)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/workers/feed_insert_worker_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe FeedInsertWorker do\n  subject { described_class.new }\n\n  describe 'perform' do\n    let(:follower) { Fabricate(:account) }\n    let(:status) { Fabricate(:status) }\n\n    context 'when there are no records' do\n      it 'skips push with missing status' do\n        instance = double(push_to_home: nil)\n        allow(FeedManager).to receive(:instance).and_return(instance)\n        result = subject.perform(nil, follower.id)\n\n        expect(result).to eq true\n        expect(instance).not_to have_received(:push_to_home)\n      end\n\n      it 'skips push with missing account' do\n        instance = double(push_to_home: nil)\n        allow(FeedManager).to receive(:instance).and_return(instance)\n        result = subject.perform(status.id, nil)\n\n        expect(result).to eq true\n        expect(instance).not_to have_received(:push_to_home)\n      end\n    end\n\n    context 'when there are real records' do\n      it 'skips the push when there is a filter' do\n        instance = double(push_to_home: nil, filter?: true)\n        allow(FeedManager).to receive(:instance).and_return(instance)\n        result = subject.perform(status.id, follower.id)\n\n        expect(result).to be_nil\n        expect(instance).not_to have_received(:push_to_home)\n      end\n\n      it 'pushes the status onto the home timeline without filter' do\n        instance = double(push_to_home: nil, filter?: false)\n        allow(FeedManager).to receive(:instance).and_return(instance)\n        result = subject.perform(status.id, follower.id)\n\n        expect(result).to be_nil\n        expect(instance).to have_received(:push_to_home).with(follower, status)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/workers/publish_scheduled_status_worker_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe PublishScheduledStatusWorker do\n  subject { described_class.new }\n\n  let(:scheduled_status) { Fabricate(:scheduled_status, params: { text: 'Hello world, future!' }) }\n\n  describe 'perform' do\n    before do\n      subject.perform(scheduled_status.id)\n    end\n\n    it 'creates a status' do\n      expect(scheduled_status.account.statuses.first.text).to eq 'Hello world, future!'\n    end\n\n    it 'removes the scheduled status' do\n      expect(ScheduledStatus.find_by(id: scheduled_status.id)).to be_nil\n    end\n  end\nend\n"
  },
  {
    "path": "spec/workers/pubsubhubbub/confirmation_worker_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe Pubsubhubbub::ConfirmationWorker do\n  include RoutingHelper\n\n  subject { described_class.new }\n\n  let!(:alice) { Fabricate(:account, username: 'alice') }\n  let!(:subscription) { Fabricate(:subscription, account: alice, callback_url: 'http://example.com/api', confirmed: false, expires_at: 3.days.from_now, secret: nil) }\n\n  describe 'perform' do\n    describe 'with subscribe mode' do\n      it 'confirms and updates subscription when challenge matches' do\n        stub_random_value\n        stub_request(:get, url_for_mode('subscribe'))\n          .with(headers: http_headers)\n          .to_return(status: 200, body: challenge_value, headers: {})\n\n        seconds = 10.days.seconds.to_i\n        subject.perform(subscription.id, 'subscribe', 'asdf', seconds)\n\n        subscription.reload\n        expect(subscription.secret).to eq 'asdf'\n        expect(subscription.confirmed).to eq true\n        expect(subscription.expires_at).to be_within(5).of(10.days.from_now)\n      end\n\n      it 'does not update subscription when challenge does not match' do\n        stub_random_value\n        stub_request(:get, url_for_mode('subscribe'))\n          .with(headers: http_headers)\n          .to_return(status: 200, body: 'wrong value', headers: {})\n\n        seconds = 10.days.seconds.to_i\n        subject.perform(subscription.id, 'subscribe', 'asdf', seconds)\n\n        subscription.reload\n        expect(subscription.secret).to be_blank\n        expect(subscription.confirmed).to eq false\n        expect(subscription.expires_at).to be_within(5).of(3.days.from_now)\n      end\n    end\n\n    describe 'with unsubscribe mode' do\n      it 'confirms and destroys subscription when challenge matches' do\n        stub_random_value\n        stub_request(:get, url_for_mode('unsubscribe'))\n          .with(headers: http_headers)\n          .to_return(status: 200, body: challenge_value, headers: {})\n\n        seconds = 10.days.seconds.to_i\n        subject.perform(subscription.id, 'unsubscribe', 'asdf', seconds)\n\n        expect { subscription.reload }.to raise_error(ActiveRecord::RecordNotFound)\n      end\n\n      it 'does not destroy subscription when challenge does not match' do\n        stub_random_value\n        stub_request(:get, url_for_mode('unsubscribe'))\n          .with(headers: http_headers)\n          .to_return(status: 200, body: 'wrong value', headers: {})\n\n        seconds = 10.days.seconds.to_i\n        subject.perform(subscription.id, 'unsubscribe', 'asdf', seconds)\n\n        expect { subscription.reload }.not_to raise_error\n      end\n    end\n  end\n\n  def url_for_mode(mode)\n    \"http://example.com/api?hub.challenge=#{challenge_value}&hub.lease_seconds=863999&hub.mode=#{mode}&hub.topic=https://#{Rails.configuration.x.local_domain}/users/alice.atom\"\n  end\n\n  def stub_random_value\n    allow(SecureRandom).to receive(:hex).and_return(challenge_value)\n  end\n\n  def challenge_value\n    '1a2s3d4f'\n  end\n\n  def http_headers\n    { 'Connection' => 'close', 'Host' => 'example.com' }\n  end\nend\n"
  },
  {
    "path": "spec/workers/pubsubhubbub/delivery_worker_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe Pubsubhubbub::DeliveryWorker do\n  include RoutingHelper\n  subject { described_class.new }\n\n  let(:payload) { 'test' }\n\n  describe 'perform' do\n    it 'raises when subscription does not exist' do\n      expect { subject.perform 123, payload }.to raise_error(ActiveRecord::RecordNotFound)\n    end\n\n    it 'does not attempt to deliver when domain blocked' do\n      _domain_block = Fabricate(:domain_block, domain: 'example.com', severity: :suspend)\n      subscription = Fabricate(:subscription, callback_url: 'https://example.com/api', last_successful_delivery_at: 2.days.ago)\n\n      subject.perform(subscription.id, payload)\n\n      expect(subscription.reload.last_successful_delivery_at).to be_within(2).of(2.days.ago)\n    end\n\n    it 'raises when request fails' do\n      subscription = Fabricate(:subscription)\n\n      stub_request_to_respond_with(subscription, 500)\n      expect { subject.perform(subscription.id, payload) }.to raise_error Mastodon::UnexpectedResponseError\n    end\n\n    it 'updates subscriptions when delivery succeeds' do\n      subscription = Fabricate(:subscription)\n\n      stub_request_to_respond_with(subscription, 200)\n      subject.perform(subscription.id, payload)\n\n      expect(subscription.reload.last_successful_delivery_at).to be_within(2).of(Time.now.utc)\n    end\n\n    it 'updates subscription without a secret when delivery succeeds' do\n      subscription = Fabricate(:subscription, secret: nil)\n\n      stub_request_to_respond_with(subscription, 200)\n      subject.perform(subscription.id, payload)\n\n      expect(subscription.reload.last_successful_delivery_at).to be_within(2).of(Time.now.utc)\n    end\n\n    def stub_request_to_respond_with(subscription, code)\n      stub_request(:post, 'http://example.com/callback')\n        .with(body: payload, headers: expected_headers(subscription))\n        .to_return(status: code, body: '', headers: {})\n    end\n\n    def expected_headers(subscription)\n      {\n        'Connection' => 'close',\n        'Content-Type' => 'application/atom+xml',\n        'Host' => 'example.com',\n        'Link' => \"<https://#{Rails.configuration.x.local_domain}/api/push>; rel=\\\"hub\\\", <https://#{Rails.configuration.x.local_domain}/users/#{subscription.account.username}.atom>; rel=\\\"self\\\"\",\n      }.tap do |basic|\n        known_digest = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha1'), subscription.secret.to_s, payload)\n        basic.merge('X-Hub-Signature' => \"sha1=#{known_digest}\") if subscription.secret?\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/workers/pubsubhubbub/distribution_worker_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe Pubsubhubbub::DistributionWorker do\n  subject { Pubsubhubbub::DistributionWorker.new }\n\n  let!(:alice) { Fabricate(:account, username: 'alice') }\n  let!(:bob) { Fabricate(:account, username: 'bob', domain: 'example2.com') }\n  let!(:anonymous_subscription) { Fabricate(:subscription, account: alice, callback_url: 'http://example1.com', confirmed: true, lease_seconds: 3600) }\n  let!(:subscription_with_follower) { Fabricate(:subscription, account: alice, callback_url: 'http://example2.com', confirmed: true, lease_seconds: 3600) }\n\n  before do\n    bob.follow!(alice)\n  end\n\n  describe 'with public status' do\n    let(:status) { Fabricate(:status, account: alice, text: 'Hello', visibility: :public) }\n\n    it 'delivers payload to all subscriptions' do\n      allow(Pubsubhubbub::DeliveryWorker).to receive(:push_bulk)\n      subject.perform(status.stream_entry.id)\n      expect(Pubsubhubbub::DeliveryWorker).to have_received(:push_bulk).with([anonymous_subscription.id, subscription_with_follower.id])\n    end\n  end\n\n  context 'when OStatus privacy is not used' do\n    describe 'with private status' do\n      let(:status) { Fabricate(:status, account: alice, text: 'Hello', visibility: :private) }\n\n      it 'does not deliver anything' do\n        allow(Pubsubhubbub::DeliveryWorker).to receive(:push_bulk)\n        subject.perform(status.stream_entry.id)\n        expect(Pubsubhubbub::DeliveryWorker).to_not have_received(:push_bulk)\n      end\n    end\n\n    describe 'with direct status' do\n      let(:status) { Fabricate(:status, account: alice, text: 'Hello', visibility: :direct) }\n\n      it 'does not deliver payload' do\n        allow(Pubsubhubbub::DeliveryWorker).to receive(:push_bulk)\n        subject.perform(status.stream_entry.id)\n        expect(Pubsubhubbub::DeliveryWorker).to_not have_received(:push_bulk)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/workers/regeneration_worker_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rails_helper'\n\ndescribe RegenerationWorker do\n  subject { described_class.new }\n\n  describe 'perform' do\n    let(:account) { Fabricate(:account) }\n\n    it 'calls the precompute feed service for the account' do\n      service = double(call: nil)\n      allow(PrecomputeFeedService).to receive(:new).and_return(service)\n      result = subject.perform(account.id)\n\n      expect(result).to be_nil\n      expect(service).to have_received(:call).with(account)\n    end\n\n    it 'fails when account does not exist' do\n      result = subject.perform('aaa')\n\n      expect(result).to eq(true)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/workers/scheduler/feed_cleanup_scheduler_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe Scheduler::FeedCleanupScheduler do\n  subject { described_class.new }\n\n  let!(:active_user) { Fabricate(:user, current_sign_in_at: 2.days.ago) }\n  let!(:inactive_user) { Fabricate(:user, current_sign_in_at: 22.days.ago) }\n\n  it 'clears feeds of inactives' do\n    Redis.current.zadd(feed_key_for(inactive_user), 1, 1)\n    Redis.current.zadd(feed_key_for(active_user), 1, 1)\n    Redis.current.zadd(feed_key_for(inactive_user, 'reblogs'), 2, 2)\n    Redis.current.sadd(feed_key_for(inactive_user, 'reblogs:2'), 3)\n\n    subject.perform\n\n    expect(Redis.current.zcard(feed_key_for(inactive_user))).to eq 0\n    expect(Redis.current.zcard(feed_key_for(active_user))).to eq 1\n    expect(Redis.current.exists(feed_key_for(inactive_user, 'reblogs'))).to be false\n    expect(Redis.current.exists(feed_key_for(inactive_user, 'reblogs:2'))).to be false\n  end\n\n  def feed_key_for(user, subtype = nil)\n    FeedManager.instance.key(:home, user.account_id, subtype)\n  end\nend\n"
  },
  {
    "path": "spec/workers/scheduler/media_cleanup_scheduler_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe Scheduler::MediaCleanupScheduler do\n  subject { described_class.new }\n\n  let!(:old_media) { Fabricate(:media_attachment, account_id: nil, created_at: 10.days.ago) }\n  let!(:new_media) { Fabricate(:media_attachment, account_id: nil, created_at: 1.hour.ago) }\n\n  it 'removes old media records' do\n    subject.perform\n\n    expect { old_media.reload }.to raise_error(ActiveRecord::RecordNotFound)\n    expect(new_media.reload).to be_persisted\n  end\nend\n"
  },
  {
    "path": "spec/workers/scheduler/subscriptions_scheduler_spec.rb",
    "content": "require 'rails_helper'\n\ndescribe Scheduler::SubscriptionsScheduler do\n  subject { Scheduler::SubscriptionsScheduler.new }\n\n  let!(:expiring_account1) { Fabricate(:account, subscription_expires_at: 20.minutes.from_now, domain: 'example.com', followers_count: 1, hub_url: 'http://hub.example.com') }\n  let!(:expiring_account2) { Fabricate(:account, subscription_expires_at: 4.hours.from_now, domain: 'example.org', followers_count: 1, hub_url: 'http://hub.example.org') }\n\n  before do\n    stub_request(:post, 'http://hub.example.com/').to_return(status: 202)\n    stub_request(:post, 'http://hub.example.org/').to_return(status: 202)\n  end\n\n  it 're-subscribes for all expiring accounts' do\n    subject.perform\n    expect(a_request(:post, 'http://hub.example.com/')).to have_been_made.once\n    expect(a_request(:post, 'http://hub.example.org/')).to have_been_made.once\n  end\nend\n"
  },
  {
    "path": "streaming/index.js",
    "content": "const os = require('os');\nconst throng = require('throng');\nconst dotenv = require('dotenv');\nconst express = require('express');\nconst http = require('http');\nconst redis = require('redis');\nconst pg = require('pg');\nconst log = require('npmlog');\nconst url = require('url');\nconst { WebSocketServer } = require('@clusterws/cws');\nconst uuid = require('uuid');\nconst fs = require('fs');\n\nconst env = process.env.NODE_ENV || 'development';\n\ndotenv.config({\n  path: env === 'production' ? '.env.production' : '.env',\n});\n\nlog.level = process.env.LOG_LEVEL || 'verbose';\n\nconst dbUrlToConfig = (dbUrl) => {\n  if (!dbUrl) {\n    return {};\n  }\n\n  const params = url.parse(dbUrl, true);\n  const config = {};\n\n  if (params.auth) {\n    [config.user, config.password] = params.auth.split(':');\n  }\n\n  if (params.hostname) {\n    config.host = params.hostname;\n  }\n\n  if (params.port) {\n    config.port = params.port;\n  }\n\n  if (params.pathname) {\n    config.database = params.pathname.split('/')[1];\n  }\n\n  const ssl = params.query && params.query.ssl;\n\n  if (ssl && ssl === 'true' || ssl === '1') {\n    config.ssl = true;\n  }\n\n  return config;\n};\n\nconst redisUrlToClient = (defaultConfig, redisUrl) => {\n  const config = defaultConfig;\n\n  if (!redisUrl) {\n    return redis.createClient(config);\n  }\n\n  if (redisUrl.startsWith('unix://')) {\n    return redis.createClient(redisUrl.slice(7), config);\n  }\n\n  return redis.createClient(Object.assign(config, {\n    url: redisUrl,\n  }));\n};\n\nconst numWorkers = +process.env.STREAMING_CLUSTER_NUM || (env === 'development' ? 1 : Math.max(os.cpus().length - 1, 1));\n\nconst startMaster = () => {\n  if (!process.env.SOCKET && process.env.PORT && isNaN(+process.env.PORT)) {\n    log.warn('UNIX domain socket is now supported by using SOCKET. Please migrate from PORT hack.');\n  }\n\n  log.info(`Starting streaming API server master with ${numWorkers} workers`);\n};\n\nconst startWorker = (workerId) => {\n  log.info(`Starting worker ${workerId}`);\n\n  const pgConfigs = {\n    development: {\n      user:     process.env.DB_USER || pg.defaults.user,\n      password: process.env.DB_PASS || pg.defaults.password,\n      database: process.env.DB_NAME || 'mastodon_development',\n      host:     process.env.DB_HOST || pg.defaults.host,\n      port:     process.env.DB_PORT || pg.defaults.port,\n      max:      10,\n    },\n\n    production: {\n      user:     process.env.DB_USER || 'mastodon',\n      password: process.env.DB_PASS || '',\n      database: process.env.DB_NAME || 'mastodon_production',\n      host:     process.env.DB_HOST || 'localhost',\n      port:     process.env.DB_PORT || 5432,\n      max:      10,\n    },\n  };\n\n  if (!!process.env.DB_SSLMODE && process.env.DB_SSLMODE !== 'disable') {\n    pgConfigs.development.ssl = true;\n    pgConfigs.production.ssl  = true;\n  }\n\n  const app = express();\n  app.set('trusted proxy', process.env.TRUSTED_PROXY_IP || 'loopback,uniquelocal');\n\n  const pgPool = new pg.Pool(Object.assign(pgConfigs[env], dbUrlToConfig(process.env.DATABASE_URL)));\n  const server = http.createServer(app);\n  const redisNamespace = process.env.REDIS_NAMESPACE || null;\n\n  const redisParams = {\n    host:     process.env.REDIS_HOST     || '127.0.0.1',\n    port:     process.env.REDIS_PORT     || 6379,\n    db:       process.env.REDIS_DB       || 0,\n    password: process.env.REDIS_PASSWORD,\n  };\n\n  if (redisNamespace) {\n    redisParams.namespace = redisNamespace;\n  }\n\n  const redisPrefix = redisNamespace ? `${redisNamespace}:` : '';\n\n  const redisSubscribeClient = redisUrlToClient(redisParams, process.env.REDIS_URL);\n  const redisClient = redisUrlToClient(redisParams, process.env.REDIS_URL);\n\n  const subs = {};\n\n  redisSubscribeClient.on('message', (channel, message) => {\n    const callbacks = subs[channel];\n\n    log.silly(`New message on channel ${channel}`);\n\n    if (!callbacks) {\n      return;\n    }\n\n    callbacks.forEach(callback => callback(message));\n  });\n\n  const subscriptionHeartbeat = (channel) => {\n    const interval = 6*60;\n    const tellSubscribed = () => {\n      redisClient.set(`${redisPrefix}subscribed:${channel}`, '1', 'EX', interval*3);\n    };\n    tellSubscribed();\n    const heartbeat = setInterval(tellSubscribed, interval*1000);\n    return () => {\n      clearInterval(heartbeat);\n    };\n  };\n\n  const subscribe = (channel, callback) => {\n    log.silly(`Adding listener for ${channel}`);\n    subs[channel] = subs[channel] || [];\n    if (subs[channel].length === 0) {\n      log.verbose(`Subscribe ${channel}`);\n      redisSubscribeClient.subscribe(channel);\n    }\n    subs[channel].push(callback);\n  };\n\n  const unsubscribe = (channel, callback) => {\n    log.silly(`Removing listener for ${channel}`);\n    subs[channel] = subs[channel].filter(item => item !== callback);\n    if (subs[channel].length === 0) {\n      log.verbose(`Unsubscribe ${channel}`);\n      redisSubscribeClient.unsubscribe(channel);\n    }\n  };\n\n  const allowCrossDomain = (req, res, next) => {\n    res.header('Access-Control-Allow-Origin', '*');\n    res.header('Access-Control-Allow-Headers', 'Authorization, Accept, Cache-Control');\n    res.header('Access-Control-Allow-Methods', 'GET, OPTIONS');\n\n    next();\n  };\n\n  const setRequestId = (req, res, next) => {\n    req.requestId = uuid.v4();\n    res.header('X-Request-Id', req.requestId);\n\n    next();\n  };\n\n  const setRemoteAddress = (req, res, next) => {\n    req.remoteAddress = req.connection.remoteAddress;\n\n    next();\n  };\n\n  const accountFromToken = (token, allowedScopes, req, next) => {\n    pgPool.connect((err, client, done) => {\n      if (err) {\n        next(err);\n        return;\n      }\n\n      client.query('SELECT oauth_access_tokens.resource_owner_id, users.account_id, users.chosen_languages, oauth_access_tokens.scopes FROM oauth_access_tokens INNER JOIN users ON oauth_access_tokens.resource_owner_id = users.id WHERE oauth_access_tokens.token = $1 AND oauth_access_tokens.revoked_at IS NULL LIMIT 1', [token], (err, result) => {\n        done();\n\n        if (err) {\n          next(err);\n          return;\n        }\n\n        if (result.rows.length === 0) {\n          err = new Error('Invalid access token');\n          err.statusCode = 401;\n\n          next(err);\n          return;\n        }\n\n        const scopes = result.rows[0].scopes.split(' ');\n\n        if (allowedScopes.size > 0 && !scopes.some(scope => allowedScopes.includes(scope))) {\n          err = new Error('Access token does not cover required scopes');\n          err.statusCode = 401;\n\n          next(err);\n          return;\n        }\n\n        req.accountId = result.rows[0].account_id;\n        req.chosenLanguages = result.rows[0].chosen_languages;\n        req.allowNotifications = scopes.some(scope => ['read', 'read:notifications'].includes(scope));\n\n        next();\n      });\n    });\n  };\n\n  const accountFromRequest = (req, next, required = true, allowedScopes = ['read']) => {\n    const authorization = req.headers.authorization;\n    const location = url.parse(req.url, true);\n    const accessToken = location.query.access_token || req.headers['sec-websocket-protocol'];\n\n    if (!authorization && !accessToken) {\n      if (required) {\n        const err = new Error('Missing access token');\n        err.statusCode = 401;\n\n        next(err);\n        return;\n      } else {\n        next();\n        return;\n      }\n    }\n\n    const token = authorization ? authorization.replace(/^Bearer /, '') : accessToken;\n\n    accountFromToken(token, allowedScopes, req, next);\n  };\n\n  const PUBLIC_STREAMS = [\n    'public',\n    'public:media',\n    'public:local',\n    'public:local:media',\n    'hashtag',\n    'hashtag:local',\n  ];\n\n  const wsVerifyClient = (info, cb) => {\n    const location = url.parse(info.req.url, true);\n    const authRequired = !PUBLIC_STREAMS.some(stream => stream === location.query.stream);\n    const allowedScopes = [];\n\n    if (authRequired) {\n      allowedScopes.push('read');\n      if (location.query.stream === 'user:notification') {\n        allowedScopes.push('read:notifications');\n      } else {\n        allowedScopes.push('read:statuses');\n      }\n    }\n\n    accountFromRequest(info.req, err => {\n      if (!err) {\n        cb(true, undefined, undefined);\n      } else {\n        log.error(info.req.requestId, err.toString());\n        cb(false, 401, 'Unauthorized');\n      }\n    }, authRequired, allowedScopes);\n  };\n\n  const PUBLIC_ENDPOINTS = [\n    '/api/v1/streaming/public',\n    '/api/v1/streaming/public/local',\n    '/api/v1/streaming/hashtag',\n    '/api/v1/streaming/hashtag/local',\n  ];\n\n  const authenticationMiddleware = (req, res, next) => {\n    if (req.method === 'OPTIONS') {\n      next();\n      return;\n    }\n\n    const authRequired = !PUBLIC_ENDPOINTS.some(endpoint => endpoint === req.path);\n    const allowedScopes = [];\n\n    if (authRequired) {\n      allowedScopes.push('read');\n      if (req.path === '/api/v1/streaming/user/notification') {\n        allowedScopes.push('read:notifications');\n      } else {\n        allowedScopes.push('read:statuses');\n      }\n    }\n\n    accountFromRequest(req, next, authRequired, allowedScopes);\n  };\n\n  const errorMiddleware = (err, req, res, {}) => {\n    log.error(req.requestId, err.toString());\n    res.writeHead(err.statusCode || 500, { 'Content-Type': 'application/json' });\n    res.end(JSON.stringify({ error: err.statusCode ? err.toString() : 'An unexpected error occurred' }));\n  };\n\n  const placeholders = (arr, shift = 0) => arr.map((_, i) => `$${i + 1 + shift}`).join(', ');\n\n  const authorizeListAccess = (id, req, next) => {\n    pgPool.connect((err, client, done) => {\n      if (err) {\n        next(false);\n        return;\n      }\n\n      client.query('SELECT id, account_id FROM lists WHERE id = $1 LIMIT 1', [id], (err, result) => {\n        done();\n\n        if (err || result.rows.length === 0 || result.rows[0].account_id !== req.accountId) {\n          next(false);\n          return;\n        }\n\n        next(true);\n      });\n    });\n  };\n\n  const streamFrom = (id, req, output, attachCloseHandler, needsFiltering = false, notificationOnly = false) => {\n    const accountId = req.accountId || req.remoteAddress;\n\n    const streamType = notificationOnly ? ' (notification)' : '';\n    log.verbose(req.requestId, `Starting stream from ${id} for ${accountId}${streamType}`);\n\n    const listener = message => {\n      const { event, payload, queued_at } = JSON.parse(message);\n\n      const transmit = () => {\n        const now            = new Date().getTime();\n        const delta          = now - queued_at;\n        const encodedPayload = typeof payload === 'object' ? JSON.stringify(payload) : payload;\n\n        log.silly(req.requestId, `Transmitting for ${accountId}: ${event} ${encodedPayload} Delay: ${delta}ms`);\n        output(event, encodedPayload);\n      };\n\n      if (notificationOnly && event !== 'notification') {\n        return;\n      }\n\n      if (event === 'notification' && !req.allowNotifications) {\n        return;\n      }\n\n      // Only messages that may require filtering are statuses, since notifications\n      // are already personalized and deletes do not matter\n      if (!needsFiltering || event !== 'update') {\n        transmit();\n        return;\n      }\n\n      const unpackedPayload  = payload;\n      const targetAccountIds = [unpackedPayload.account.id].concat(unpackedPayload.mentions.map(item => item.id));\n      const accountDomain    = unpackedPayload.account.acct.split('@')[1];\n\n      if (Array.isArray(req.chosenLanguages) && unpackedPayload.language !== null && req.chosenLanguages.indexOf(unpackedPayload.language) === -1) {\n        log.silly(req.requestId, `Message ${unpackedPayload.id} filtered by language (${unpackedPayload.language})`);\n        return;\n      }\n\n      // When the account is not logged in, it is not necessary to confirm the block or mute\n      if (!req.accountId) {\n        transmit();\n        return;\n      }\n\n      pgPool.connect((err, client, done) => {\n        if (err) {\n          log.error(err);\n          return;\n        }\n\n        const queries = [\n          client.query(`SELECT 1 FROM blocks WHERE (account_id = $1 AND target_account_id IN (${placeholders(targetAccountIds, 2)})) OR (account_id = $2 AND target_account_id = $1) UNION SELECT 1 FROM mutes WHERE account_id = $1 AND target_account_id IN (${placeholders(targetAccountIds, 2)})`, [req.accountId, unpackedPayload.account.id].concat(targetAccountIds)),\n        ];\n\n        if (accountDomain) {\n          queries.push(client.query('SELECT 1 FROM account_domain_blocks WHERE account_id = $1 AND domain = $2', [req.accountId, accountDomain]));\n        }\n\n        Promise.all(queries).then(values => {\n          done();\n\n          if (values[0].rows.length > 0 || (values.length > 1 && values[1].rows.length > 0)) {\n            return;\n          }\n\n          transmit();\n        }).catch(err => {\n          done();\n          log.error(err);\n        });\n      });\n    };\n\n    subscribe(`${redisPrefix}${id}`, listener);\n    attachCloseHandler(`${redisPrefix}${id}`, listener);\n  };\n\n  // Setup stream output to HTTP\n  const streamToHttp = (req, res) => {\n    const accountId = req.accountId || req.remoteAddress;\n\n    res.setHeader('Content-Type', 'text/event-stream');\n    res.setHeader('Transfer-Encoding', 'chunked');\n\n    const heartbeat = setInterval(() => res.write(':thump\\n'), 15000);\n\n    req.on('close', () => {\n      log.verbose(req.requestId, `Ending stream for ${accountId}`);\n      clearInterval(heartbeat);\n    });\n\n    return (event, payload) => {\n      res.write(`event: ${event}\\n`);\n      res.write(`data: ${payload}\\n\\n`);\n    };\n  };\n\n  // Setup stream end for HTTP\n  const streamHttpEnd = (req, closeHandler = false) => (id, listener) => {\n    req.on('close', () => {\n      unsubscribe(id, listener);\n      if (closeHandler) {\n        closeHandler();\n      }\n    });\n  };\n\n  // Setup stream output to WebSockets\n  const streamToWs = (req, ws) => (event, payload) => {\n    if (ws.readyState !== ws.OPEN) {\n      log.error(req.requestId, 'Tried writing to closed socket');\n      return;\n    }\n\n    ws.send(JSON.stringify({ event, payload }));\n  };\n\n  // Setup stream end for WebSockets\n  const streamWsEnd = (req, ws, closeHandler = false) => (id, listener) => {\n    const accountId = req.accountId || req.remoteAddress;\n\n    ws.on('close', () => {\n      log.verbose(req.requestId, `Ending stream for ${accountId}`);\n      unsubscribe(id, listener);\n      if (closeHandler) {\n        closeHandler();\n      }\n    });\n\n    ws.on('error', () => {\n      log.verbose(req.requestId, `Ending stream for ${accountId}`);\n      unsubscribe(id, listener);\n      if (closeHandler) {\n        closeHandler();\n      }\n    });\n  };\n\n  const httpNotFound = res => {\n    res.writeHead(404, { 'Content-Type': 'application/json' });\n    res.end(JSON.stringify({ error: 'Not found' }));\n  };\n\n  app.use(setRequestId);\n  app.use(setRemoteAddress);\n  app.use(allowCrossDomain);\n\n  app.get('/api/v1/streaming/health', (req, res) => {\n    res.writeHead(200, { 'Content-Type': 'text/plain' });\n    res.end('OK');\n  });\n\n  app.use(authenticationMiddleware);\n  app.use(errorMiddleware);\n\n  app.get('/api/v1/streaming/user', (req, res) => {\n    const channel = `timeline:${req.accountId}`;\n    streamFrom(channel, req, streamToHttp(req, res), streamHttpEnd(req, subscriptionHeartbeat(channel)));\n  });\n\n  app.get('/api/v1/streaming/user/notification', (req, res) => {\n    streamFrom(`timeline:${req.accountId}`, req, streamToHttp(req, res), streamHttpEnd(req), false, true);\n  });\n\n  app.get('/api/v1/streaming/public', (req, res) => {\n    const onlyMedia = req.query.only_media === '1' || req.query.only_media === 'true';\n    const channel   = onlyMedia ? 'timeline:public:media' : 'timeline:public';\n\n    streamFrom(channel, req, streamToHttp(req, res), streamHttpEnd(req), true);\n  });\n\n  app.get('/api/v1/streaming/public/local', (req, res) => {\n    const onlyMedia = req.query.only_media === '1' || req.query.only_media === 'true';\n    const channel   = onlyMedia ? 'timeline:public:local:media' : 'timeline:public:local';\n\n    streamFrom(channel, req, streamToHttp(req, res), streamHttpEnd(req), true);\n  });\n\n  app.get('/api/v1/streaming/direct', (req, res) => {\n    const channel = `timeline:direct:${req.accountId}`;\n    streamFrom(channel, req, streamToHttp(req, res), streamHttpEnd(req, subscriptionHeartbeat(channel)), true);\n  });\n\n  app.get('/api/v1/streaming/hashtag', (req, res) => {\n    const { tag } = req.query;\n\n    if (!tag || tag.length === 0) {\n      httpNotFound(res);\n      return;\n    }\n\n    streamFrom(`timeline:hashtag:${tag.toLowerCase()}`, req, streamToHttp(req, res), streamHttpEnd(req), true);\n  });\n\n  app.get('/api/v1/streaming/hashtag/local', (req, res) => {\n    const { tag } = req.query;\n\n    if (!tag || tag.length === 0) {\n      httpNotFound(res);\n      return;\n    }\n\n    streamFrom(`timeline:hashtag:${tag.toLowerCase()}:local`, req, streamToHttp(req, res), streamHttpEnd(req), true);\n  });\n\n  app.get('/api/v1/streaming/list', (req, res) => {\n    const listId = req.query.list;\n\n    authorizeListAccess(listId, req, authorized => {\n      if (!authorized) {\n        httpNotFound(res);\n        return;\n      }\n\n      const channel = `timeline:list:${listId}`;\n      streamFrom(channel, req, streamToHttp(req, res), streamHttpEnd(req, subscriptionHeartbeat(channel)));\n    });\n  });\n\n  const wss = new WebSocketServer({ server, verifyClient: wsVerifyClient });\n\n  wss.on('connection', (ws, req) => {\n    const location = url.parse(req.url, true);\n    req.requestId  = uuid.v4();\n    req.remoteAddress = ws._socket.remoteAddress;\n\n    let channel;\n\n    switch(location.query.stream) {\n    case 'user':\n      channel = `timeline:${req.accountId}`;\n      streamFrom(channel, req, streamToWs(req, ws), streamWsEnd(req, ws, subscriptionHeartbeat(channel)));\n      break;\n    case 'user:notification':\n      streamFrom(`timeline:${req.accountId}`, req, streamToWs(req, ws), streamWsEnd(req, ws), false, true);\n      break;\n    case 'public':\n      streamFrom('timeline:public', req, streamToWs(req, ws), streamWsEnd(req, ws), true);\n      break;\n    case 'public:local':\n      streamFrom('timeline:public:local', req, streamToWs(req, ws), streamWsEnd(req, ws), true);\n      break;\n    case 'public:media':\n      streamFrom('timeline:public:media', req, streamToWs(req, ws), streamWsEnd(req, ws), true);\n      break;\n    case 'public:local:media':\n      streamFrom('timeline:public:local:media', req, streamToWs(req, ws), streamWsEnd(req, ws), true);\n      break;\n    case 'direct':\n      channel = `timeline:direct:${req.accountId}`;\n      streamFrom(channel, req, streamToWs(req, ws), streamWsEnd(req, ws, subscriptionHeartbeat(channel)), true);\n      break;\n    case 'hashtag':\n      if (!location.query.tag || location.query.tag.length === 0) {\n        ws.close();\n        return;\n      }\n\n      streamFrom(`timeline:hashtag:${location.query.tag.toLowerCase()}`, req, streamToWs(req, ws), streamWsEnd(req, ws), true);\n      break;\n    case 'hashtag:local':\n      if (!location.query.tag || location.query.tag.length === 0) {\n        ws.close();\n        return;\n      }\n\n      streamFrom(`timeline:hashtag:${location.query.tag.toLowerCase()}:local`, req, streamToWs(req, ws), streamWsEnd(req, ws), true);\n      break;\n    case 'list':\n      const listId = location.query.list;\n\n      authorizeListAccess(listId, req, authorized => {\n        if (!authorized) {\n          ws.close();\n          return;\n        }\n\n        channel = `timeline:list:${listId}`;\n        streamFrom(channel, req, streamToWs(req, ws), streamWsEnd(req, ws, subscriptionHeartbeat(channel)));\n      });\n      break;\n    default:\n      ws.close();\n    }\n  });\n\n  wss.startAutoPing(30000);\n\n  attachServerWithConfig(server, address => {\n    log.info(`Worker ${workerId} now listening on ${address}`);\n  });\n\n  const onExit = () => {\n    log.info(`Worker ${workerId} exiting, bye bye`);\n    server.close();\n    process.exit(0);\n  };\n\n  const onError = (err) => {\n    log.error(err);\n    server.close();\n    process.exit(0);\n  };\n\n  process.on('SIGINT', onExit);\n  process.on('SIGTERM', onExit);\n  process.on('exit', onExit);\n  process.on('uncaughtException', onError);\n};\n\nconst attachServerWithConfig = (server, onSuccess) => {\n  if (process.env.SOCKET || process.env.PORT && isNaN(+process.env.PORT)) {\n    server.listen(process.env.SOCKET || process.env.PORT, () => {\n      if (onSuccess) {\n        fs.chmodSync(server.address(), 0o666);\n        onSuccess(server.address());\n      }\n    });\n  } else {\n    server.listen(+process.env.PORT || 4000, process.env.BIND || '0.0.0.0', () => {\n      if (onSuccess) {\n        onSuccess(`${server.address().address}:${server.address().port}`);\n      }\n    });\n  }\n};\n\nconst onPortAvailable = onSuccess => {\n  const testServer = http.createServer();\n\n  testServer.once('error', err => {\n    onSuccess(err);\n  });\n\n  testServer.once('listening', () => {\n    testServer.once('close', () => onSuccess());\n    testServer.close();\n  });\n\n  attachServerWithConfig(testServer);\n};\n\nonPortAvailable(err => {\n  if (err) {\n    log.error('Could not start server, the port or socket is in use');\n    return;\n  }\n\n  throng({\n    workers: numWorkers,\n    lifetime: Infinity,\n    start: startWorker,\n    master: startMaster,\n  });\n});\n"
  },
  {
    "path": "vendor/.keep",
    "content": ""
  }
]